diff --git a/Dockerfile b/Dockerfile index b266f05..23f2df1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,25 @@ -# This is an example operator. -# -# The standard name for its image is enj/example-operator -# -FROM openshift/origin-release:golang-1.10 -COPY . /go/src/github.com/enj/example-operator -RUN cd /go/src/github.com/enj/example-operator && go build ./cmd/example +FROM openshift/origin-release:golang-1.10 as builder +WORKDIR /go/src/github.com/openshift/console-operator +COPY . . +RUN make build FROM centos:7 -COPY --from=0 /go/src/github.com/enj/example-operator/example /usr/bin/example +RUN useradd console-operator +USER console-operator +COPY --from=builder /go/src/github.com/openshift/console-operator/_output/local/bin/linux/amd64/console /usr/bin + +# these manifests are necessary for the installer +COPY manifests /manifests/ + +LABEL io.k8s.display-name="OpenShift console-operator" \ + io.k8s.description="This is a component of OpenShift Container Platform and manages the lifecycle of the web console." \ + io.openshift.tags="openshift" \ + maintainer="Benjamin A. Petersen " + +LABEL io.openshift.release.operator true + +# entrypoint specified in 03-operator.yaml as `console-operator` +# CMD ["/usr/bin/console", "operator", "--kubeconfig", "path/to/config", "--config", "./install/config.yaml", "--v", "4"] +CMD ["/usr/bin/console", "operator", "--v", "4"] + + diff --git a/Dockerfile.osx b/Dockerfile.osx new file mode 100644 index 0000000..857a0cb --- /dev/null +++ b/Dockerfile.osx @@ -0,0 +1,27 @@ +FROM openshift/origin-release:golang-1.10 as builder +WORKDIR /go/src/github.com/openshift/console-operator +COPY . . +RUN make build + +FROM centos:7 +RUN useradd console-operator +USER console-operator +COPY --from=builder /go/src/github.com/openshift/console-operator/_output/local/bin/darwin/amd64/console /usr/bin + +# these manifests are necessary for the installer +COPY manifests /manifests/ + +LABEL io.k8s.display-name="OpenShift console-operator" \ + io.k8s.description="This is a component of OpenShift Container Platform and manages the lifecycle of the web console." \ + io.openshift.tags="openshift" \ + maintainer="Benjamin A. Petersen " + +LABEL io.openshift.release.operator true + +# entrypoint specified in 03-operator.yaml as `console-operator` +# CMD ["/usr/bin/console", "operator", "--kubeconfig", "path/to/config", "--config", "./install/config.yaml", "--v", "4"] +CMD ["/usr/bin/console", "operator", "--v", "4"] + + + + diff --git a/README.md b/README.md index bf6631f..a9b2c12 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,88 @@ -# Example Operator +# Console Operator -```shell -cd "${GOPATH}/src/github.com/enj/example-operator" +An operator for OpenShift Console. -oc new-project example-operator +The console-operator installs and maintains the web console on a cluster. -oc create -f manifests/00-crd.yaml -oc create -f install/cr.yaml +## Run on a 4.0.0 cluster +The console operator is installed by default and will automatically maintain a console. + +## Development Setup + +* Install Go -- https://golang.org/doc/install + + + + +## Development on a < 4.0.0 cluster + +If using `oc cluster up` on a `< 4.0.0` cluster you will need the `--public-hostname` flag +when you cluster up. The `--server-loglevel` flag is helpful for debugging. OAuth issues +will not be visible unless set to at least `3`. + +```bash +# there are a variety of ways to get your machine IP address +# this example works on OSX +oc cluster up --public-hostname=$(ipconfig getifaddr en0) --server-loglevel 3 +``` + +Then, create the manifests: + +```bash +# pre 4.0.0 needs this, but it is not part of the post 4.0.0 manifests payload +oc create -f ./examples/crd-clusteroperator.yaml +# standard 4.0.0 deploy of the operator +oc create -f ./manifests +# to run the operator locally, delete the deployment and follow instructions below +oc delete -f ./manifests/05-operator.yaml +``` + +If you don't know where your `kubeconfig` file is: + +```bash +# just a high number +oc whoami --loglevel=100 +# likely output will be $HOME/.kube/config +``` + +Build the console operator binary: + +```bash +make update-codegen make -export PATH="_output/local/bin/linux/amd64:${PATH}" -example operator --kubeconfig admin.kubeconfig --config install/config.yaml --v=4 +make verify +# add the binary to your path +# arc will be "linux" or "darwin", etc +export PATH="_output/local/bin//amd64:${PATH}" +``` + +Now, run the console operator locally: + +```bash +IMAGE=docker.io/openshift/origin-console:latest \ + console operator \ + --kubeconfig $HOME/.kube/config \ + --config examples/config.yaml \ + --create-default-console \ + --v 4 +``` + +Check for the existence of expected resources: -oc get exampleoperator example-operator-resource -o yaml -oc get secret example-operator-resource -o yaml +```bash +oc get console +# etc ``` + +Explanation: + +- The `IMAGE` env var is needed to declare what console image to deploy. The `manifests/05-operator.yaml` shows this var as well +- The `--operator-flags` flag is used to pass flags to the operator binary + - `--create-default-console true` tells the operator binary to create a console CR if one does not exist on startup. + +The `IMAGE` env var exists so that when the console-operator is packaged up for a release, we can replace the value +with a final image. See CVO documentation for details. + diff --git a/cmd/example/main.go b/cmd/console/main.go similarity index 53% rename from cmd/example/main.go rename to cmd/console/main.go index 984b5fa..73a73aa 100644 --- a/cmd/example/main.go +++ b/cmd/console/main.go @@ -1,40 +1,50 @@ package main import ( + // standard lib goflag "flag" "fmt" "math/rand" "os" "time" - + // 3rd party "github.com/spf13/cobra" "github.com/spf13/pflag" - + // kube / openshift utilflag "k8s.io/apiserver/pkg/util/flag" "k8s.io/apiserver/pkg/util/logs" - - "github.com/enj/example-operator/pkg/cmd/operator" + // us + "github.com/openshift/console-operator/pkg/cmd/operator" + "github.com/openshift/console-operator/pkg/cmd/version" ) func main() { + // random seed, set it & forget it rand.Seed(time.Now().UTC().UnixNano()) - + // normalize flags, if _ use - pflag.CommandLine.SetNormalizeFunc(utilflag.WordSepNormalizeFunc) + // add the default flag set for go pflag.CommandLine.AddGoFlagSet(goflag.CommandLine) logs.InitLogs() defer logs.FlushLogs() - command := NewExampleCommand() + // build a new cobra command + command := NewOperatorCommand() + // die on errors if err := command.Execute(); err != nil { fmt.Fprintf(os.Stderr, "%v\n", err) os.Exit(1) } } -func NewExampleCommand() *cobra.Command { +// create the root "console" command +// we will add subcommands to this +func NewOperatorCommand() *cobra.Command { + // "console" just prints help, then exists. It doesn't start + // the operator. cmd := &cobra.Command{ - Use: "example", + Use: "console", Short: "Top level command", Run: func(cmd *cobra.Command, args []string) { cmd.Help() @@ -43,6 +53,7 @@ func NewExampleCommand() *cobra.Command { } cmd.AddCommand(operator.NewOperator()) + cmd.AddCommand(version.NewVersion()) return cmd } diff --git a/dev_delete_all.sh b/dev_delete_all.sh new file mode 100755 index 0000000..ee299ef --- /dev/null +++ b/dev_delete_all.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +# this just deletes everything under /manifests, +# but tries to space them out a bit to avoid errors. +# in the end, it creates a custom resource to kick +# the operator into action + +FILE=examples/cr.yaml +echo "creating ${FILE}" +oc delete -f $FILE + +for FILE in `find ./manifests -name '05-*'` +do + echo "deleting ${FILE}" + oc delete -f $FILE +done + +for FILE in `find ./manifests -name '04-*'` +do + echo "deleting ${FILE}" + oc delete -f $FILE +done + +for FILE in `find ./manifests -name '03-*'` +do + echo "deleting ${FILE}" + oc delete -f $FILE +done + +for FILE in `find ./manifests -name '02-*'` +do + echo "deleting ${FILE}" + oc delete -f $FILE +done + +for FILE in `find ./manifests -name '01-*'` +do + echo "deleting ${FILE}" + oc delete -f $FILE +done + +for FILE in `find ./manifests -name '00-*'` +do + echo "deleting ${FILE}" + oc delete -f $FILE +done + + + diff --git a/dev_deploy_all.sh b/dev_deploy_all.sh new file mode 100755 index 0000000..3b93b97 --- /dev/null +++ b/dev_deploy_all.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +# this just deploys everything under /manifests, +# but tries to space them out a bit to avoid errors. +# in the end, it creates a custom resource to kick +# the operator into action + +echo "DEPLOYING REMOTE OPERATOR" +echo "(This does not build locally, nor does it push the image to dockerhub...)" + +for FILE in `find ./manifests -name '00-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 2 + +for FILE in `find ./manifests -name '01-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 2 + +for FILE in `find ./manifests -name '02-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 2 + +for FILE in `find ./manifests -name '03-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 2 + +for FILE in `find ./manifests -name '04-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 2 + +for FILE in `find ./manifests -name '05-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 2 + + +FILE=examples/cr.yaml +echo "creating ${FILE}" +oc create -f $FILE diff --git a/dev_run_local.sh b/dev_run_local.sh new file mode 100755 index 0000000..be800d1 --- /dev/null +++ b/dev_run_local.sh @@ -0,0 +1,101 @@ +#!/usr/bin/env bash + +# we need to be system admin to install these +oc login -u system:admin + +# this just deploys everything under /manifests, +# but tries to space them out a bit to avoid errors. +# in the end, it creates a custom resource to kick +# the operator into action + +# necessary if doing dev locally on a < 4.0.0 cluster +CLUSTER_OPERATOR_CRD_FILE="./examples/crd-clusteroperator.yaml" +echo "creating ${CLUSTER_OPERATOR_CRD_FILE}" +oc create -f "${CLUSTER_OPERATOR_CRD_FILE}" + +# examples/cr.yaml is not necessary as the operator will create +# an instance of a "console" by default. +# use it if customization is desired. + +for FILE in `find ./manifests -name '00-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 1 + +for FILE in `find ./manifests -name '01-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 2 + +# use the openshift-console project, for +# - when we create the CR (namespace: should be defined in the resource anyway) +# - when we run the operator locally. +oc project 'openshift-console' + +for FILE in `find ./manifests -name '02-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 1 + +for FILE in `find ./manifests -name '03-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 1 + +for FILE in `find ./manifests -name '04-*'` +do + echo "creating ${FILE}" + oc create -f $FILE +done + +sleep 1 + +# at this point, we should no longer be system:admin +# oc login -u developer -p 12345 + +# ensure the latest binary has been built +make build + +# Don't deploy the operator in `manifests` +# instead, we will instantiate the operator locally +# +#for FILE in `find ./manifests -name '05-*'` +#do +# echo "creating ${FILE}" +# oc create -f $FILE +#done + +# temporaily add the binary to path so we can call it below +export PATH="$PATH:$HOME/gopaths/consoleoperator/src/github.com/openshift/console-operator/_output/local/bin/darwin/amd64" + +IMAGE=docker.io/openshift/origin-console:latest \ + console operator \ + --kubeconfig $HOME/.kube/config \ + --config examples/config.yaml \ + --v 4 + +echo "TODO: support --create-default-console again!" +# TODO: GET BACK TO THIS: +#IMAGE=docker.io/openshift/origin-console:latest \ +# console operator \ +# --kubeconfig $HOME/.kube/config \ +# --config examples/config.yaml \ +# --create-default-console \ +# --v 4 + +# NOT creating the CR as the operator should create one automatically. +# echo "Creating the CR to activate the operator" +# oc create -f "./examples/cr.yaml" + diff --git a/dev_test_sync_loop.sh b/dev_test_sync_loop.sh new file mode 100755 index 0000000..04e6735 --- /dev/null +++ b/dev_test_sync_loop.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +# simply create one of each resource, with a sleep in between +# watch the logs and verify that the sync loop sees the events +# then delete each of the resources. +# these are generic resources, not specific. + +declare -a FILES_ARRAY=("secret.yaml" + "configmap.yaml" + "service.yaml" + "route.yaml" + "deployment.yaml" + "oauth.yaml" +) + +# create them all +for FILE in "${FILES_ARRAY[@]}" +do + echo "creating ${FILE}" + oc create -f "./examples/sync-loop/${FILE}" + sleep 3 +done + +# then, delete them all. + + +for FILE in "${FILES_ARRAY[@]}" +do + echo "deleting ${FILE}" + oc delete -f "./examples/sync-loop/${FILE}" + sleep 3 +done diff --git a/install/config.yaml b/examples/config.yaml similarity index 73% rename from install/config.yaml rename to examples/config.yaml index 54ae484..3eb2b1d 100644 --- a/install/config.yaml +++ b/examples/config.yaml @@ -1,4 +1,4 @@ apiVersion: operator.openshift.io/v1alpha1 kind: GenericOperatorConfig leaderElection: - namespace: example-operator + namespace: openshift-console diff --git a/examples/cr.yaml b/examples/cr.yaml new file mode 100644 index 0000000..265da4b --- /dev/null +++ b/examples/cr.yaml @@ -0,0 +1,26 @@ +# The console-operator will create a console automatically on startup if one does not exist. +# This file is an example of a console resource. +# You may edit this file and `oc apply -f cr.yaml` to make changes to the console. +apiVersion: "console.openshift.io/v1alpha1" +kind: "Console" +metadata: + # Do not change the name, the operator explicitly requires this name to match as the console is a singleton. + # must match name defined in pkg/controller/api.go + name: console-operator-resource + namespace: openshift-console +spec: + # openshift/api/operator/v1alpha1/types.go + # managementState indicates whether the operator is: + # - Managed indicates the operator fully manages the state of the console and its sub-resources + # - Unmanaged indicates that the operator should idle and ignore the console and its sub-resources + # - Removed indicates that the operator should delete all of the sub-resources of the console + managementState: Managed + # there should be only one console at this time + # this could be used to support leader election if desired + count: 1 + logging: + level: 0 + # artifact of base operator + version: 4.0.0 + # going away + value: "panda-bears-are-awesome-and-this-should-be-a-console-instead-woot" diff --git a/examples/crd-clusteroperator.yaml b/examples/crd-clusteroperator.yaml new file mode 100644 index 0000000..7490649 --- /dev/null +++ b/examples/crd-clusteroperator.yaml @@ -0,0 +1,20 @@ +# this CRD is for the ClusterOperator resource that is used to +# convey the operator status. It does NOT need to be a part of +# the manifests payload as it should be created early on, however, +# for local development, it may be necessary to `oc create -f` +# this file. +# to view the object: +# oc get clusteroperators openshift-console +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: clusteroperators.operatorstatus.openshift.io +spec: + group: operatorstatus.openshift.io + names: + kind: ClusterOperator + listKind: ClusterOperatorList + plural: clusteroperators + singular: clusteroperators + scope: Cluster + version: v1 diff --git a/glide.yaml b/glide.yaml index 9d75c2c..a7acb57 100644 --- a/glide.yaml +++ b/glide.yaml @@ -1,4 +1,4 @@ -package: github.com/enj/example-operator +package: github.com/enj/console-operator import: # kube diff --git a/hack/lib/constants.sh b/hack/lib/constants.sh index 94f2c99..4a8c96e 100755 --- a/hack/lib/constants.sh +++ b/hack/lib/constants.sh @@ -2,7 +2,7 @@ # This script provides constants for the Golang binary build process -readonly OS_GO_PACKAGE=github.com/enj/example-operator +readonly OS_GO_PACKAGE=github.com/openshift/console-operator readonly OS_BUILD_ENV_GOLANG="${OS_BUILD_ENV_GOLANG:-1.9}" readonly OS_BUILD_ENV_IMAGE="${OS_BUILD_ENV_IMAGE:-openshift/origin-release:golang-${OS_BUILD_ENV_GOLANG}}" @@ -25,7 +25,7 @@ readonly OS_GOFLAGS_TAGS="include_gcs include_oss containers_image_openpgp" readonly OS_IMAGE_COMPILE_BINARIES=( ) readonly OS_CROSS_COMPILE_TARGETS=( - cmd/example + cmd/console ) readonly OS_CROSS_COMPILE_BINARIES=("${OS_CROSS_COMPILE_TARGETS[@]##*/}") @@ -146,5 +146,5 @@ readonly OS_ALL_IMAGES=( # os::build::images builds all images in this repo. function os::build::images() { tag_prefix="${OS_IMAGE_PREFIX:-"openshift/origin"}" - os::build::image "${tag_prefix}-example" . + os::build::image "${tag_prefix}-console" . } diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index eeddda1..59fe669 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -29,8 +29,8 @@ verify="${VERIFY:-}" # k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir # instead of the $GOPATH directly. For normal projects this can be dropped. ${CODEGEN_PKG}/generate-groups.sh "all" \ - github.com/enj/example-operator/pkg/generated github.com/enj/example-operator/pkg/apis \ - example:v1alpha1 \ + github.com/openshift/console-operator/pkg/generated github.com/openshift/console-operator/pkg/apis \ + console:v1alpha1 \ --output-base "$(dirname ${BASH_SOURCE})/../../../.." \ --go-header-file ${SCRIPT_ROOT}/hack/boilerplate.txt \ ${verify} diff --git a/install/cr.yaml b/install/cr.yaml deleted file mode 100644 index e5a22da..0000000 --- a/install/cr.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: exampleoperator.crd.monis.app/v1alpha1 -kind: ExampleOperator -metadata: - name: example-operator-resource - namespace: example-operator -spec: - managementState: Managed - version: 3.10.0 - value: panda diff --git a/install/install-rbac.yaml b/install/install-rbac.yaml deleted file mode 100644 index 2ae48b8..0000000 --- a/install/install-rbac.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: List -items: - -# When we have an orchestrating operator, it will do this -- apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRoleBinding - metadata: - name: system:openshift:operator:service-cert-signer - roleRef: - kind: ClusterRole - name: cluster-admin - subjects: - - kind: ServiceAccount - namespace: openshift-core-operators - name: openshift-service-ca-operator diff --git a/install/install.yaml b/install/install.yaml deleted file mode 100644 index c26d21d..0000000 --- a/install/install.yaml +++ /dev/null @@ -1,96 +0,0 @@ -apiVersion: v1 -kind: List -items: - -- apiVersion: v1 - kind: Namespace - metadata: - labels: - openshift.io/run-level: "1" - name: openshift-core-operators - -- apiVersion: apiextensions.k8s.io/v1beta1 - kind: CustomResourceDefinition - metadata: - name: servicecertsigneroperatorconfigs.servicecertsigner.config.openshift.io - spec: - scope: Cluster - group: servicecertsigner.config.openshift.io - version: v1alpha1 - names: - kind: ServiceCertSignerOperatorConfig - plural: servicecertsigneroperatorconfigs - singular: servicecertsigneroperatorconfig - subresources: - status: {} - -- apiVersion: v1 - kind: ConfigMap - metadata: - namespace: openshift-core-operators - name: openshift-service-ca-operator-config - data: - operator-config.yaml: | - apiVersion: operator.openshift.io/v1alpha1 - kind: GenericOperatorConfig - -- apiVersion: apps/v1 - kind: Deployment - metadata: - namespace: openshift-core-operators - name: openshift-service-ca-operator - labels: - app: openshift-service-ca-operator - spec: - replicas: 1 - selector: - matchLabels: - app: openshift-service-ca-operator - template: - metadata: - name: openshift-service-ca-operator - labels: - app: openshift-service-ca-operator - spec: - serviceAccountName: openshift-service-ca-operator - containers: - - name: operator - image: openshift/origin-service-ca:latest - imagePullPolicy: IfNotPresent - command: ["service-ca", "operator"] - args: - - "--config=/var/run/configmaps/config/operator-config.yaml" - - "-v=4" - volumeMounts: - - mountPath: /var/run/configmaps/config - name: config - volumes: - - name: serving-cert - secret: - defaultMode: 400 - secretName: openshift-service-ca-operator-serving-cert - optional: true - - name: config - configMap: - defaultMode: 440 - name: openshift-service-ca-operator-config - -- apiVersion: v1 - kind: ServiceAccount - metadata: - namespace: openshift-core-operators - name: openshift-service-ca-operator - labels: - app: openshift-service-ca-operator - -- apiVersion: servicecertsigner.config.openshift.io/v1alpha1 - kind: ServiceCertSignerOperatorConfig - metadata: - name: instance - spec: - managementState: Managed - imagePullSpec: openshift/origin-service-ca:latest - version: 3.10.0 - logging: - level: 4 - replicas: 1 diff --git a/manifests/00-crd.yaml b/manifests/00-crd.yaml index 14b5210..c398805 100644 --- a/manifests/00-crd.yaml +++ b/manifests/00-crd.yaml @@ -1,13 +1,13 @@ apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - name: exampleoperators.exampleoperator.crd.monis.app + name: consoles.console.openshift.io spec: - group: exampleoperator.crd.monis.app + group: console.openshift.io names: - kind: ExampleOperator - listKind: ExampleOperatorList - plural: exampleoperators - singular: exampleoperator + kind: Console + listKind: ConsoleList + plural: consoles + singular: console scope: Namespaced version: v1alpha1 diff --git a/manifests/00-oauth.yaml b/manifests/00-oauth.yaml new file mode 100644 index 0000000..fc9c736 --- /dev/null +++ b/manifests/00-oauth.yaml @@ -0,0 +1,6 @@ +apiVersion: oauth.openshift.io/v1 +kind: OAuthClient +metadata: + name: openshift-console +grantMethod: auto +respondWithChallenges: false diff --git a/manifests/01-namespace.yaml b/manifests/01-namespace.yaml new file mode 100644 index 0000000..dd8e2d2 --- /dev/null +++ b/manifests/01-namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-console diff --git a/manifests/02-rbac-role.yaml b/manifests/02-rbac-role.yaml new file mode 100644 index 0000000..4402161 --- /dev/null +++ b/manifests/02-rbac-role.yaml @@ -0,0 +1,70 @@ +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: console-operator + namespace: openshift-console +rules: +# TODO: delete is needed for ownerRefs on older clusters +# should remove in the future. +- apiGroups: + - console.openshift.io + resources: + - consoles + verbs: + - get + - list + - watch + - create + - update + - delete +- apiGroups: + - "" + resources: + - services + - events + - configmaps + - secrets + verbs: + - get + - list + - watch + - create + - update + - delete +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch + - create + - update + - delete +- apiGroups: + - route.openshift.io + resources: + - routes + verbs: + - get + - list + - watch + - create + - update + - delete +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: console-operator +rules: +- apiGroups: + - oauth.openshift.io + resources: + - oauthclients + verbs: + - get + - update + resourceNames: + - openshift-console diff --git a/manifests/03-rbac-rolebinding.yaml b/manifests/03-rbac-rolebinding.yaml new file mode 100644 index 0000000..4cffffc --- /dev/null +++ b/manifests/03-rbac-rolebinding.yaml @@ -0,0 +1,25 @@ +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: console-operator + namespace: openshift-console +roleRef: + kind: Role + name: console-operator + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: ServiceAccount + name: console-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: console-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: console-operator +subjects: +- kind: ServiceAccount + name: console-operator + namespace: openshift-console diff --git a/manifests/04-sa.yaml b/manifests/04-sa.yaml new file mode 100644 index 0000000..55669f6 --- /dev/null +++ b/manifests/04-sa.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: console-operator + namespace: openshift-console diff --git a/manifests/05-operator.yaml b/manifests/05-operator.yaml new file mode 100644 index 0000000..2e5d280 --- /dev/null +++ b/manifests/05-operator.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: console-operator + namespace: openshift-console +spec: + replicas: 1 + selector: + matchLabels: + name: console-operator + template: + metadata: + labels: + name: console-operator + spec: + serviceAccountName: console-operator + containers: + - name: console-operator + image: docker.io/openshift/origin-console-operator:latest + ports: + - containerPort: 60000 + name: metrics + command: + - console-operator + args: + - "-create-default-console=true" + imagePullPolicy: Always + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: IMAGE + value: docker.io/openshift/origin-console:latest + - name: OPERATOR_NAME + value: "console-operator" diff --git a/manifests/clusterrole.yaml b/manifests/clusterrole.yaml deleted file mode 100644 index 6cd255f..0000000 --- a/manifests/clusterrole.yaml +++ /dev/null @@ -1,28 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: system:openshift:controller:service-ca -rules: -- apiGroups: - - "" - resources: - - secrets - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - deletecollection -- apiGroups: - - "" - resources: - - services - verbs: - - get - - list - - watch - - update - - patch diff --git a/manifests/clusterrolebinding.yaml b/manifests/clusterrolebinding.yaml deleted file mode 100644 index 7e8a77c..0000000 --- a/manifests/clusterrolebinding.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: system:openshift:controller:service-ca -roleRef: - kind: ClusterRole - name: system:openshift:controller:service-ca -subjects: -- kind: ServiceAccount - namespace: openshift-service-ca - name: service-ca-sa diff --git a/manifests/cm.yaml b/manifests/cm.yaml deleted file mode 100644 index 98d3063..0000000 --- a/manifests/cm.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - namespace: openshift-service-ca - name: service-ca-config -data: - controller-config.yaml: diff --git a/manifests/defaultconfig.yaml b/manifests/defaultconfig.yaml deleted file mode 100644 index f01ef8e..0000000 --- a/manifests/defaultconfig.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: servicecertsigner.config.openshift.io/v1alpha1 -kind: ServiceServingCertSignerConfig -signer: - certFile: /var/run/secrets/signing-key/tls.crt - keyFile: /var/run/secrets/signing-key/tls.key diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml deleted file mode 100644 index 5304dd0..0000000 --- a/manifests/deployment.yaml +++ /dev/null @@ -1,53 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - namespace: openshift-service-ca - name: service-ca - labels: - app: openshift-service-ca - service-ca: "true" -spec: - strategy: - type: Recreate - selector: - matchLabels: - app: openshift-service-ca - service-ca: "true" - template: - metadata: - name: service-ca - labels: - app: openshift-service-ca - service-ca: "true" - spec: - serviceAccountName: service-ca-sa - containers: - - name: service-ca-controller - image: ${IMAGE} - imagePullPolicy: IfNotPresent - command: ["service-ca", "serving-cert-signer"] - args: - - "--config=/var/run/configmaps/config/controller-config.yaml" - ports: - - containerPort: 8443 - volumeMounts: - - mountPath: /var/run/configmaps/config - name: config - - mountPath: /var/run/secrets/signing-key - name: signing-key - - mountPath: /var/run/secrets/serving-cert - name: serving-cert - volumes: - - name: serving-cert - secret: - secretName: service-ca-serving-cert - optional: true - - name: signing-key - secret: - secretName: service-ca-signing-key - - name: config - configMap: - name: service-ca-config - - - diff --git a/manifests/image-references b/manifests/image-references new file mode 100644 index 0000000..d5c9b30 --- /dev/null +++ b/manifests/image-references @@ -0,0 +1,13 @@ +kind: ImageStream +apiVersion: image.openshift.io/v1 +spec: + tags: + - name: console-operator + from: + kind: DockerImage + name: docker.io/openshift/origin-console-operator:latest + - name: console + from: + kind: DockerImage + name: docker.io/openshift/origin-console:latest + diff --git a/manifests/ns.yaml b/manifests/ns.yaml deleted file mode 100644 index c637fd0..0000000 --- a/manifests/ns.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: openshift-service-ca - labels: - openshift.io/run-level: "1" \ No newline at end of file diff --git a/manifests/sa.yaml b/manifests/sa.yaml deleted file mode 100644 index 99abb44..0000000 --- a/manifests/sa.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - namespace: openshift-service-ca - name: service-ca-sa diff --git a/manifests/signing-secret.yaml b/manifests/signing-secret.yaml deleted file mode 100644 index d4cc35a..0000000 --- a/manifests/signing-secret.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - namespace: openshift-service-ca - name: service-ca-signing-key -type: kubernetes.io/tls -data: - tls.crt: - tls.key: diff --git a/manifests/svc.yaml b/manifests/svc.yaml deleted file mode 100644 index 6e1d504..0000000 --- a/manifests/svc.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - namespace: openshift-service-ca - name: service-ca - annotations: - service.alpha.openshift.io/serving-cert-secret-name: service-ca-serving-cert - prometheus.io/scrape: "true" - prometheus.io/scheme: https -spec: - selector: - service-ca: "true" - ports: - - name: https - port: 443 - targetPort: 8443 diff --git a/pkg/apis/example/install.go b/pkg/apis/console/install.go similarity index 71% rename from pkg/apis/example/install.go rename to pkg/apis/console/install.go index f25dd3c..34ddade 100644 --- a/pkg/apis/example/install.go +++ b/pkg/apis/console/install.go @@ -4,15 +4,15 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - examplev1alpha1 "github.com/enj/example-operator/pkg/apis/example/v1alpha1" + consolev1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" ) const ( - GroupName = "exampleoperator.crd.monis.app" + GroupName = "console.openshift.io" ) var ( - schemeBuilder = runtime.NewSchemeBuilder(examplev1alpha1.Install) + schemeBuilder = runtime.NewSchemeBuilder(consolev1alpha1.Install) // Install is a function which adds every version of this group to a scheme Install = schemeBuilder.AddToScheme ) diff --git a/pkg/apis/example/v1alpha1/doc.go b/pkg/apis/console/v1alpha1/doc.go similarity index 71% rename from pkg/apis/example/v1alpha1/doc.go rename to pkg/apis/console/v1alpha1/doc.go index ba0f904..da4e40d 100644 --- a/pkg/apis/example/v1alpha1/doc.go +++ b/pkg/apis/console/v1alpha1/doc.go @@ -2,6 +2,6 @@ // +k8s:defaulter-gen=TypeMeta // +k8s:openapi-gen=true -// +groupName=exampleoperator.crd.monis.app +// +groupName=console.openshift.io package v1alpha1 diff --git a/pkg/apis/example/v1alpha1/register.go b/pkg/apis/console/v1alpha1/register.go similarity index 92% rename from pkg/apis/example/v1alpha1/register.go rename to pkg/apis/console/v1alpha1/register.go index 1d35dc2..15d4030 100644 --- a/pkg/apis/example/v1alpha1/register.go +++ b/pkg/apis/console/v1alpha1/register.go @@ -10,7 +10,7 @@ import ( ) var ( - GroupName = "exampleoperator.crd.monis.app" + GroupName = "console.openshift.io" GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"} schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, configv1.Install, operatorsv1alpha1api.Install) // Install is a function which adds this version to a scheme @@ -32,8 +32,8 @@ func Resource(resource string) schema.GroupResource { func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(GroupVersion, - &ExampleOperator{}, - &ExampleOperatorList{}, + &Console{}, + &ConsoleList{}, ) metav1.AddToGroupVersion(scheme, GroupVersion) diff --git a/pkg/apis/console/v1alpha1/types.go b/pkg/apis/console/v1alpha1/types.go new file mode 100644 index 0000000..bf81461 --- /dev/null +++ b/pkg/apis/console/v1alpha1/types.go @@ -0,0 +1,47 @@ +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/openshift/api/operator/v1alpha1" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type Console struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ConsoleSpec `json:"spec,omitempty"` + Status ConsoleStatus `json:"status,omitempty"` +} + +type ConsoleSpec struct { + v1alpha1.OperatorSpec + // TODO: delete this, its no longer needed + Value string `json:"value,omitempty"` + // Count is the number of Console replicas + Count int32 `json:"count,omitempty"` + // take a look @: + // https://github.com/openshift/cluster-image-registry-operator/blob/master/pkg/apis/imageregistry/v1alpha1/types.go#L91-L92 + // DefaultRoute: T|F + // additional routes config w/secrets + // Route[] +} + +type ConsoleStatus struct { + v1alpha1.OperatorStatus + // set once the router has a default host name + DefaultHostName string `json:"defaultHostName"` + OAuthSecret string `json""oauthSecret"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type ConsoleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + + Items []Console `json:"items"` +} diff --git a/pkg/apis/example/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/console/v1alpha1/zz_generated.deepcopy.go similarity index 66% rename from pkg/apis/example/v1alpha1/zz_generated.deepcopy.go rename to pkg/apis/console/v1alpha1/zz_generated.deepcopy.go index 7a65fde..a7afc85 100644 --- a/pkg/apis/example/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/console/v1alpha1/zz_generated.deepcopy.go @@ -9,7 +9,7 @@ import ( ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExampleOperator) DeepCopyInto(out *ExampleOperator) { +func (in *Console) DeepCopyInto(out *Console) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -18,18 +18,18 @@ func (in *ExampleOperator) DeepCopyInto(out *ExampleOperator) { return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExampleOperator. -func (in *ExampleOperator) DeepCopy() *ExampleOperator { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Console. +func (in *Console) DeepCopy() *Console { if in == nil { return nil } - out := new(ExampleOperator) + out := new(Console) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ExampleOperator) DeepCopyObject() runtime.Object { +func (in *Console) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -37,13 +37,13 @@ func (in *ExampleOperator) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExampleOperatorList) DeepCopyInto(out *ExampleOperatorList) { +func (in *ConsoleList) DeepCopyInto(out *ConsoleList) { *out = *in out.TypeMeta = in.TypeMeta out.ListMeta = in.ListMeta if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]ExampleOperator, len(*in)) + *out = make([]Console, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -51,18 +51,18 @@ func (in *ExampleOperatorList) DeepCopyInto(out *ExampleOperatorList) { return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExampleOperatorList. -func (in *ExampleOperatorList) DeepCopy() *ExampleOperatorList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConsoleList. +func (in *ConsoleList) DeepCopy() *ConsoleList { if in == nil { return nil } - out := new(ExampleOperatorList) + out := new(ConsoleList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ExampleOperatorList) DeepCopyObject() runtime.Object { +func (in *ConsoleList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -70,35 +70,35 @@ func (in *ExampleOperatorList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExampleOperatorSpec) DeepCopyInto(out *ExampleOperatorSpec) { +func (in *ConsoleSpec) DeepCopyInto(out *ConsoleSpec) { *out = *in out.OperatorSpec = in.OperatorSpec return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExampleOperatorSpec. -func (in *ExampleOperatorSpec) DeepCopy() *ExampleOperatorSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConsoleSpec. +func (in *ConsoleSpec) DeepCopy() *ConsoleSpec { if in == nil { return nil } - out := new(ExampleOperatorSpec) + out := new(ConsoleSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExampleOperatorStatus) DeepCopyInto(out *ExampleOperatorStatus) { +func (in *ConsoleStatus) DeepCopyInto(out *ConsoleStatus) { *out = *in in.OperatorStatus.DeepCopyInto(&out.OperatorStatus) return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExampleOperatorStatus. -func (in *ExampleOperatorStatus) DeepCopy() *ExampleOperatorStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConsoleStatus. +func (in *ConsoleStatus) DeepCopy() *ConsoleStatus { if in == nil { return nil } - out := new(ExampleOperatorStatus) + out := new(ConsoleStatus) in.DeepCopyInto(out) return out } diff --git a/pkg/apis/example/v1alpha1/types.go b/pkg/apis/example/v1alpha1/types.go deleted file mode 100644 index cd268a9..0000000 --- a/pkg/apis/example/v1alpha1/types.go +++ /dev/null @@ -1,37 +0,0 @@ -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/openshift/api/operator/v1alpha1" -) - -// +genclient -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -type ExampleOperator struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec ExampleOperatorSpec `json:"spec,omitempty"` - Status ExampleOperatorStatus `json:"status,omitempty"` -} - -type ExampleOperatorSpec struct { - v1alpha1.OperatorSpec - - Value string `json:"value,omitempty"` -} - -type ExampleOperatorStatus struct { - v1alpha1.OperatorStatus -} - -// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - -type ExampleOperatorList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []ExampleOperator `json:"items"` -} diff --git a/pkg/cmd/operator/cmd.go b/pkg/cmd/operator/cmd.go index ce82245..f123961 100644 --- a/pkg/cmd/operator/cmd.go +++ b/pkg/cmd/operator/cmd.go @@ -1,20 +1,28 @@ package operator import ( + // 3rd party "github.com/spf13/cobra" - + // kube / openshift "github.com/openshift/library-go/pkg/controller/controllercmd" - - "github.com/enj/example-operator/pkg/example/starter" - "github.com/enj/example-operator/pkg/example/version" + // us + "github.com/openshift/console-operator/pkg/console/starter" + "github.com/openshift/console-operator/pkg/console/version" ) func NewOperator() *cobra.Command { cmd := controllercmd. - NewControllerCommandConfig("example-operator", version.Get(), starter.RunOperator). + NewControllerCommandConfig( + "console-operator", + version.Get(), + starter.RunOperator). NewCommand() cmd.Use = "operator" - cmd.Short = "Start the Example Operator" - + cmd.Short = "Start the Console Operator" + // TODO: better docs on this + // should probably give example usage, etc + // https://github.com/spf13/cobra#create-rootcmd + cmd.Long = `An Operator for a web console for OpenShift. + ` return cmd } diff --git a/pkg/cmd/version/cmd.go b/pkg/cmd/version/cmd.go new file mode 100644 index 0000000..a45e77d --- /dev/null +++ b/pkg/cmd/version/cmd.go @@ -0,0 +1,28 @@ +package version + +import ( + "fmt" + "strings" + "github.com/blang/semver" + "github.com/spf13/cobra" +) + +var ( + Raw = "v0.0.1" + Version = semver.MustParse(strings.TrimLeft(Raw, "v")) + String = fmt.Sprintf("ConsoleOperator %s", Raw) +) + +func NewVersion() *cobra.Command { + // TODO: + // update & use the pkg/version/version.go to pull + // git information & present here. + cmd := &cobra.Command{ + Use: "version", + Short: "Display the Operator Version", + Run: func(command *cobra.Command, args []string) { + fmt.Println(String) + }, + } + return cmd +} diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go new file mode 100644 index 0000000..908ecde --- /dev/null +++ b/pkg/console/operator/operator.go @@ -0,0 +1,276 @@ +package operator + +import ( + // standard lib + "fmt" + "github.com/openshift/console-operator/pkg/console/subresource/configmap" + "github.com/openshift/console-operator/pkg/console/subresource/deployment" + "github.com/openshift/console-operator/pkg/console/subresource/oauthclient" + "github.com/openshift/console-operator/pkg/console/subresource/route" + "github.com/openshift/console-operator/pkg/console/subresource/secret" + "github.com/openshift/console-operator/pkg/console/subresource/service" + + // 3rd party + "github.com/blang/semver" + "github.com/sirupsen/logrus" + // kube + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/client-go/informers/core/v1" + appsv1 "k8s.io/client-go/kubernetes/typed/apps/v1" + coreclientv1 "k8s.io/client-go/kubernetes/typed/core/v1" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/util/workqueue" + // openshift + "github.com/openshift/console-operator/pkg/controller" + operatorsv1alpha1 "github.com/openshift/api/operator/v1alpha1" + oauthclientv1 "github.com/openshift/client-go/oauth/clientset/versioned/typed/oauth/v1" + oauthinformersv1 "github.com/openshift/client-go/oauth/informers/externalversions/oauth/v1" + routeclientv1 "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" + "github.com/openshift/library-go/pkg/operator/versioning" + // informers + routesinformersv1 "github.com/openshift/client-go/route/informers/externalversions/route/v1" + consolev1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + consoleinformers "github.com/openshift/console-operator/pkg/generated/informers/externalversions/console/v1alpha1" + appsinformersv1 "k8s.io/client-go/informers/apps/v1" + // clients + "github.com/openshift/console-operator/pkg/generated/clientset/versioned/typed/console/v1alpha1" +) + +const ( + // workQueueKey is the singleton key shared by all events + // the value is irrelevant + workQueueKey = "console-operator-queue-key" + controllerName = "Console" +) + + +// the ConsoleOperator uses specific, strongly-typed clients +// for each resource that it interacts with. +func NewConsoleOperator( + // informers + coi consoleinformers.ConsoleInformer, + coreV1 v1.Interface, + appsV1 appsinformersv1.Interface, + routesV1 routesinformersv1.Interface, + oauthV1 oauthinformersv1.Interface, + // clients + operatorClient v1alpha1.ConsoleInterface, + corev1Client coreclientv1.CoreV1Interface, + appsv1Client appsv1.AppsV1Interface, + routev1Client routeclientv1.RouteV1Interface, + oauthv1Client oauthclientv1.OauthV1Interface) *ConsoleOperator { + + + c := &ConsoleOperator{ + // operator + operatorClient: operatorClient, + // core kube + secretsClient: corev1Client, + configMapClient: corev1Client, + serviceClient: corev1Client, + deploymentClient: appsv1Client, + // openshift + routeClient: routev1Client, + oauthClient: oauthv1Client, + } + + operatorInformer := coi.Informer() + secretsInformer := coreV1.Secrets().Informer() + deploymentInformer := appsV1.Deployments().Informer() + configMapInformer := coreV1.ConfigMaps().Informer() + serviceInformer := coreV1.Services().Informer() + routeInformer := routesV1.Routes().Informer() + oauthInformer := oauthV1.OAuthClientAuthorizations().Informer() + + // we do not really need to wait for our informers to sync since we only watch a single resource + // and make live reads but it does not hurt anything and guarantees we have the correct behavior + internalController, queue := controller.New( + controllerName, + c.sync, + operatorInformer.HasSynced, + secretsInformer.HasSynced, + deploymentInformer.HasSynced, + configMapInformer.HasSynced, + serviceInformer.HasSynced, + routeInformer.HasSynced, + oauthInformer.HasSynced) + + c.controller = internalController + + operatorInformer.AddEventHandler(eventHandler(queue)) + secretsInformer.AddEventHandler(eventHandler(queue)) + deploymentInformer.AddEventHandler(eventHandler(queue)) + configMapInformer.AddEventHandler(eventHandler(queue)) + serviceInformer.AddEventHandler(eventHandler(queue)) + routeInformer.AddEventHandler(eventHandler(queue)) + oauthInformer.AddEventHandler(eventHandler(queue)) + + return c +} + +// eventHandler queues the operator to check spec and status +// TODO add filtering and more nuanced logic +// each informer's event handler could have specific logic based on the resource +// for now just rekicking the sync loop is enough since we only watch a single resource by name +func eventHandler(queue workqueue.RateLimitingInterface) cache.ResourceEventHandler { + return cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { queue.Add(workQueueKey) }, + UpdateFunc: func(old, new interface{}) { queue.Add(workQueueKey) }, + DeleteFunc: func(obj interface{}) { queue.Add(workQueueKey) }, + } +} + +type ConsoleOperator struct { + // for a performance sensitive operator, it would make sense to use informers + // to handle reads and clients to handle writes. since this operator works + // on a singleton resource, it has no performance requirements. + operatorClient v1alpha1.ConsoleInterface + // core kube + secretsClient coreclientv1.SecretsGetter + configMapClient coreclientv1.ConfigMapsGetter + serviceClient coreclientv1.ServicesGetter + deploymentClient appsv1.DeploymentsGetter + // openshift + routeClient routeclientv1.RoutesGetter + oauthClient oauthclientv1.OAuthClientsGetter + // controller + controller *controller.Controller +} + +func (c *ConsoleOperator) Run(stopCh <-chan struct{}) { + // only start one worker because we only have one key name in our queue + // since this operator works on a singleton, it does not make sense to ever run more than one worker + c.controller.Run(1, stopCh) +} + +// sync() is the handler() function equivalent from the sdk +// this is the big switch statement. +// TODO: clean this up a bit, its messy +func (c *ConsoleOperator) sync(_ interface{}) error { + // we ignore the passed in key because it will always be workQueueKey + // it does not matter how the sync loop was triggered + // all we need to worry about is reconciling the state back to what we expect + operatorConfig, err := c.operatorClient.Get(controller.ResourceName, metav1.GetOptions{}) + + if errors.IsNotFound(err) { + _, err := c.operatorClient.Create(c.defaultConsole()) + return err + } + if err != nil { + return err + } + + switch operatorConfig.Spec.ManagementState { + case operatorsv1alpha1.Managed: + fmt.Println("Console is in a managed state.") + // handled below + case operatorsv1alpha1.Unmanaged: + fmt.Println("Console is in an unmanaged state.") + return nil + // take a look @ https://github.com/openshift/service-serving-cert-signer/blob/master/pkg/operator/operator.go#L86 + case operatorsv1alpha1.Removed: + fmt.Println("Console has been removed.") + return c.deleteAllResources(operatorConfig) + default: + // TODO should update status + return fmt.Errorf("unknown state: %v", operatorConfig.Spec.ManagementState) + } + + var currentActualVersion *semver.Version + + // TODO: ca.yaml needs a version, update the v1alpha1.Console to include version field + if ca := operatorConfig.Status.CurrentAvailability; ca != nil { + ver, err := semver.Parse(ca.Version) + if err != nil { + utilruntime.HandleError(err) + } else { + currentActualVersion = &ver + } + } + // not yet using, we target only 4.0.0 + desiredVersion, err := semver.Parse(operatorConfig.Spec.Version) + if err != nil { + // TODO report failing status, we may actually attempt to do this in the "normal" error handling + return err + } + + // this is arbitrary, but we need a placeholder. we will have to handle versioning appropriately at some point + v311_to_401 := versioning.NewRangeOrDie("3.11.0", "4.0.1") + + outConfig := operatorConfig.DeepCopy() + var errs []error + + switch { + // v4.0.0 or nil + case v311_to_401.BetweenOrEmpty(currentActualVersion): + logrus.Println("Sync-4.0.0") + outConfig, err = sync_v400(c, outConfig) + errs = append(errs, err) + if err == nil { + outConfig.Status.TaskSummary = "sync-4.0.0" + outConfig.Status.CurrentAvailability = &operatorsv1alpha1.VersionAvailability{ + Version: desiredVersion.String(), + } + } + default: + logrus.Printf("Unrecognized version. Desired %s, Actual %s", desiredVersion, currentActualVersion) + outConfig.Status.TaskSummary = "unrecognized" + } + + // TODO: this should do better apply logic or similar, maybe use SetStatusFromAvailability + _, err = c.operatorClient.Update(outConfig) + errs = append(errs, err) + + return utilerrors.NewAggregate(errs) +} + +// this may need to move to sync_v400 if versions ever have custom delete logic +func (c *ConsoleOperator) deleteAllResources(cr *consolev1alpha1.Console) error { + var errs []error + // service + errs = append(errs, c.serviceClient.Services(controller.TargetNamespace).Delete(service.Stub().Name, &metav1.DeleteOptions{})) + // route + errs = append(errs, c.routeClient.Routes(controller.TargetNamespace).Delete(route.Stub().Name, &metav1.DeleteOptions{})) + // configmap + errs = append(errs, c.configMapClient.ConfigMaps(controller.TargetNamespace).Delete(configmap.Stub().Name, &metav1.DeleteOptions{})) + // secret + errs = append(errs, c.secretsClient.Secrets(controller.TargetNamespace).Delete(secret.Stub().Name, &metav1.DeleteOptions{})) + // existingOAuthClient is not a delete, it is a deregister/neutralize + existingOAuthClient, getAuthErr := c.oauthClient.OAuthClients().Get(oauthclient.Stub().Name, metav1.GetOptions{}) + errs = append(errs, getAuthErr) + _, updateAuthErr := c.oauthClient.OAuthClients().Update(oauthclient.DeRegisterConsoleFromOAuthClient(existingOAuthClient)) + errs = append(errs, updateAuthErr) + // deployment + errs = append(errs, c.deploymentClient.Deployments(controller.TargetNamespace).Delete(deployment.Stub().Name, &metav1.DeleteOptions{})) + + return utilerrors.FilterOut(utilerrors.NewAggregate(errs), errors.IsNotFound) +} + + +// this may need to eventually live under each sync version, depending on if there is +// custom sync logic +func (c *ConsoleOperator) defaultConsole() *consolev1alpha1.Console { + return &consolev1alpha1.Console{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.ResourceName, + Namespace: controller.OpenShiftConsoleNamespace, + }, + Spec: consolev1alpha1.ConsoleSpec{ + OperatorSpec: operatorsv1alpha1.OperatorSpec{ + // by default the console is managed + ManagementState: "Managed", + // if Verison is not 4.0.0 our reconcile loop will not pick it up + Version: "4.0.0", + }, + // one replica is created + Count: 1, + }, + } +} + + + + diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go new file mode 100644 index 0000000..766abb8 --- /dev/null +++ b/pkg/console/operator/sync_v400.go @@ -0,0 +1,187 @@ +package operator + +import ( + // 3rd party + "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + coreclientv1 "k8s.io/client-go/kubernetes/typed/core/v1" + // kube + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + errutil "k8s.io/apimachinery/pkg/util/errors" + oauthv1 "github.com/openshift/api/oauth/v1" + operatorv1alpha1 "github.com/openshift/api/operator/v1alpha1" + routev1 "github.com/openshift/api/route/v1" + oauthclientv1 "github.com/openshift/client-go/oauth/clientset/versioned/typed/oauth/v1" + // openshift + "github.com/openshift/console-operator/pkg/controller" + "github.com/openshift/console-operator/pkg/crypto" + "github.com/openshift/library-go/pkg/operator/resource/resourceapply" + "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" + // operator + "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + configmapsub "github.com/openshift/console-operator/pkg/console/subresource/configmap" + deploymentsub "github.com/openshift/console-operator/pkg/console/subresource/deployment" + oauthsub "github.com/openshift/console-operator/pkg/console/subresource/oauthclient" + routesub "github.com/openshift/console-operator/pkg/console/subresource/route" + secretsub "github.com/openshift/console-operator/pkg/console/subresource/secret" + servicesub "github.com/openshift/console-operator/pkg/console/subresource/service" +) + +func sync_v400(co *ConsoleOperator, consoleConfig *v1alpha1.Console) (*v1alpha1.Console, error) { + // aggregate + allErrors := []error{} + // track changes, may triggler ripples & update consoleConfig.Status + toUpdate := false + + + // apply service + _, svcChanged, svcErr := resourceapply.ApplyService(co.serviceClient, servicesub.DefaultService(consoleConfig)) + if svcErr != nil { + logrus.Errorf("%q: %v \n", "service", svcErr) + allErrors = append(allErrors, svcErr) + } + toUpdate = toUpdate || svcChanged + + + + // apply route + // - be sure to test that we don't trigger an infinite loop by stomping on the + // default host name set by the server, or any other values. The ApplyRoute() + // logic will have to be sound. + // - update to ApplyRoute() once the logic is settled + rt, rtIsNew, rtErr := routesub.GetOrCreate(co.routeClient, routesub.DefaultRoute(consoleConfig)) + // rt, rtChanged, rtErr := routesub.ApplyRoute(co.routeClient, routesub.DefaultRoute(consoleConfig)) + if rtErr != nil { + logrus.Errorf("%q: %v \n", "route", rtErr) + allErrors = append(allErrors, rtErr) + } + toUpdate = toUpdate || rtIsNew + + + + // apply configmap (needs route) + _, cmChanged, cmErr := resourceapply.ApplyConfigMap(co.configMapClient, configmapsub.DefaultConfigMap(consoleConfig, rt)) + if cmErr != nil { + logrus.Errorf("%q: %v \n", "configmap", cmErr) + allErrors = append(allErrors, cmErr) + } + toUpdate = toUpdate || cmChanged + + // TODO: clean up, not fond of the scoping issues here + // - the deployment needs to know about the change value in order to address updates, + // but the wrapper is needed to avoid triggering loops unnecessarily + secretChanged := false + // oauthChanged := false + if !secretsMatch(co.secretsClient, co.oauthClient) { + // shared secret bits + // sharedOAuthSecretBits := crypto.RandomBits(256) + sharedOAuthSecretBits := crypto.Random256BitsString() + + // apply oauth (needs route) + defaultOauthClient := oauthsub.RegisterConsoleToOAuthClient(oauthsub.DefaultOauthClient(), rt, sharedOAuthSecretBits) + _, oauthChanged, oauthErr := oauthsub.ApplyOAuth(co.oauthClient, defaultOauthClient) + if oauthErr != nil { + logrus.Errorf("%q: %v \n", "oauthclient", oauthErr) + allErrors = append(allErrors, oauthErr) + } + toUpdate = toUpdate || oauthChanged + + // apply secret + _, secretChanged, secErr := resourceapply.ApplySecret(co.secretsClient, secretsub.DefaultSecret(consoleConfig, sharedOAuthSecretBits)) + if secErr != nil { + logrus.Errorf("sec error: %v", secErr) + logrus.Errorf("%q: %v \n", "secret", secErr) + allErrors = append(allErrors, secErr) + } + toUpdate = toUpdate || secretChanged + } + + + // we don't want to thrash our deployment, but we also need to force rollout the pod whenever anything critical changes + defaultDeployment := deploymentsub.DefaultDeployment(consoleConfig) + versionAvailability := &operatorv1alpha1.VersionAvailability{ + Version: consoleConfig.Spec.Version, + } + deploymentGeneration := resourcemerge.ExpectedDeploymentGeneration(defaultDeployment, versionAvailability) + // if configMap or secrets change, we need to deploy a new pod + redeployPods := cmChanged || secretChanged + _, depChanged, depErr := resourceapply.ApplyDeployment(co.deploymentClient, defaultDeployment, deploymentGeneration, redeployPods) + if depErr != nil { + logrus.Errorf("%q: %v \n", "deployment", depErr) + allErrors = append(allErrors, depErr) + } + toUpdate = toUpdate || depChanged + + // handy debugging block + //logrus.Printf("service changed: %v \n", svcChanged) + //logrus.Printf("route is new: %v \n", rtIsNew) + //logrus.Printf("configMap changed: %v \n", cmChanged) + //logrus.Printf("secret changed: %v \n", secretChanged) + //logrus.Printf("oauth changed: %v \n", oauthChanged) + //logrus.Printf("deployment changed: %v \n", depChanged) + //logrus.Println("------------") + + // if any of our resources have changed, we should update the consoleConfig.Status. otherwise, skip this step. + if toUpdate { + logrus.Infof("Sync_v400: To update Spec? %v", toUpdate) + // TODO: set the status. + // setStatus(consoleConfig.Status, svc, rt, cm, dep, oa, sec) + } + + return consoleConfig, errutil.FilterOut(errutil.NewAggregate(allErrors), apierrors.IsNotFound) +} + + +func secretsMatch(secretGetter coreclientv1.SecretsGetter, clientsGetter oauthclientv1.OAuthClientsGetter) bool { + secret, err := secretGetter.Secrets(controller.TargetNamespace).Get(deploymentsub.ConsoleOauthConfigName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return false + } + oauthClient, err := clientsGetter.OAuthClients().Get(controller.OpenShiftConsoleName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return false + } + + return secretAndOauthMatch(secret, oauthClient) +} + +func secretAndOauthMatch(secret *corev1.Secret, client *oauthv1.OAuthClient) bool { + secretString := secretsub.GetSecretString(secret) + clientSecretString := oauthsub.GetSecretString(client) + return secretString == clientSecretString +} + + +// update status on CR +// pass in each of the above resources, possibly the +// boolean for "changed" as well, and then assign a status +// on the CR.Status. Be sure to account for a nil return value +// as some of our resources (oauthlient, configmap) may simply +// not be possible to create if they lack the appropriate inputs. +// in this case, the Status should CLEARLY indicate this to the user. +// Once the resource is correctly created, the status should be updated +// again. This should be pretty simple and straightforward work. +// update cluster operator status... i believe this +// should be automatic so long as the CR.Status is +// properly filled out with the appropriate values. +func setStatus(cs v1alpha1.ConsoleStatus, svc *corev1.Service, rt *routev1.Route, cm *corev1.ConfigMap, dep *appsv1.Deployment, oa *oauthv1.OAuthClient, sec *corev1.Secret) { + // TODO: handle custom hosts as well + if rt.Spec.Host != "" { + cs.DefaultHostName = rt.Spec.Host + logrus.Printf("stats.DefaultHostName set to %v", rt.Spec.Host) + } else { + cs.DefaultHostName = "" + logrus.Printf("stats.DefaultHostName set to %v", "") + } + + if secretAndOauthMatch(sec, oa) { + cs.OAuthSecret = "valid" + logrus.Printf("status.OAuthSecret is valid") + } else { + cs.OAuthSecret = "mismatch" + logrus.Printf("status.OAuthSecret is mismatch") + } + +} diff --git a/pkg/console/starter/starter.go b/pkg/console/starter/starter.go new file mode 100644 index 0000000..8a2947f --- /dev/null +++ b/pkg/console/starter/starter.go @@ -0,0 +1,165 @@ +package starter + +import ( + "fmt" + "github.com/openshift/console-operator/pkg/controller" + "time" + + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/cache" + // "k8s.io/apimachinery/pkg/fields" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/informers" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + + "github.com/openshift/library-go/pkg/operator/status" + + authclient "github.com/openshift/client-go/oauth/clientset/versioned" + // clients + routesclient "github.com/openshift/client-go/route/clientset/versioned" + "github.com/openshift/console-operator/pkg/generated/clientset/versioned" + // informers + oauthinformers "github.com/openshift/client-go/oauth/informers/externalversions" + routesinformers "github.com/openshift/client-go/route/informers/externalversions" + "github.com/openshift/console-operator/pkg/generated/informers/externalversions" + + operatorv1alpha1 "github.com/openshift/api/operator/v1alpha1" + "github.com/openshift/console-operator/pkg/console/operator" +) + + +func RunOperator(clientConfig *rest.Config, stopCh <-chan struct{}) error { + + // only for the ClusterStatus, everything else has a specific client + dynamicClient, err := dynamic.NewForConfig(clientConfig) + if err != nil { + return err + } + + // creates a new kube clientset + // clientConfig is a REST config + // a clientSet contains clients for groups. + // each group has one version included in the set. + kubeClient, err := kubernetes.NewForConfig(clientConfig) + if err != nil { + return err + } + + // pkg/apis/console/v1alpha1/types.go has a `genclient` annotation, + // that creates the expected functions for the type. + consoleOperatorClient, err := versioned.NewForConfig(clientConfig) + if err != nil { + return err + } + + routesClient, err := routesclient.NewForConfig(clientConfig) + if err != nil { + return err + } + + oauthClient, err := authclient.NewForConfig(clientConfig) + if err != nil { + return err + } + + const resync = 10 * time.Minute + + // NOOP for now + // TODO: can perhaps put this back the way it was, but may + // need to create a couple different version for + // resources w/different names + tweakListOptions := func(options *v1.ListOptions) { + // options.FieldSelector = fields.OneTermEqualSelector("metadata.name", operator.ResourceName).String() + } + + kubeInformersNamespaced := informers.NewSharedInformerFactoryWithOptions( + // takes a client + kubeClient, + resync, + // takes an unlimited number of additional "options" arguments, which are functions, + // that take a sharedInformerFactory and return a sharedInformerFactory + informers.WithNamespace(controller.TargetNamespace), + informers.WithTweakListOptions(tweakListOptions), + ) + + consoleOperatorInformers := externalversions.NewSharedInformerFactoryWithOptions( + // this is our generated client + consoleOperatorClient, + resync, + // and the same set of optional transform functions + externalversions.WithNamespace(controller.TargetNamespace), + externalversions.WithTweakListOptions(tweakListOptions), + ) + + routesInformersNamespaced := routesinformers.NewSharedInformerFactoryWithOptions( + routesClient, + resync, + routesinformers.WithNamespace(controller.TargetNamespace), + routesinformers.WithTweakListOptions(tweakListOptions), + ) + + // oauthclients are not namespaced + oauthInformers := oauthinformers.NewSharedInformerFactoryWithOptions( + oauthClient, + resync, + oauthinformers.WithTweakListOptions(tweakListOptions), + ) + + consoleOperator := operator.NewConsoleOperator( + // informers + consoleOperatorInformers.Console().V1alpha1().Consoles(), // Console + kubeInformersNamespaced.Core().V1(), // Secrets, ConfigMaps, Service + kubeInformersNamespaced.Apps().V1(), // Deployments + routesInformersNamespaced.Route().V1(), // Route + oauthInformers.Oauth().V1(), // oauth + // clients + consoleOperatorClient.ConsoleV1alpha1().Consoles(controller.TargetNamespace), + kubeClient.CoreV1(), // Secrets, ConfigMaps, Service + kubeClient.AppsV1(), + routesClient.RouteV1(), + oauthClient.OauthV1(), + ) + + kubeInformersNamespaced.Start(stopCh) + consoleOperatorInformers.Start(stopCh) + routesInformersNamespaced.Start(stopCh) + oauthInformers.Start(stopCh) + + go consoleOperator.Run(stopCh) + + + clusterOperatorStatus := status.NewClusterOperatorStatusController( + controller.TargetNamespace, + controller.ResourceName, + // no idea why this is dynamic & not a strongly typed client. + dynamicClient, + &operatorStatusProvider{informers: consoleOperatorInformers}, + ) + // TODO: will have a series of Run() funcs here + go clusterOperatorStatus.Run(1, stopCh) + + <-stopCh + + return fmt.Errorf("stopped") +} + + +// I'd prefer this in a /console/status/ package, but other operators keep it here. +type operatorStatusProvider struct { + informers externalversions.SharedInformerFactory +} + +func (p *operatorStatusProvider) Informer() cache.SharedIndexInformer { + return p.informers.Console().V1alpha1().Consoles().Informer() +} + +func (p *operatorStatusProvider) CurrentStatus() (operatorv1alpha1.OperatorStatus, error) { + instance, err := p.informers.Console().V1alpha1().Consoles().Lister().Consoles(controller.TargetNamespace).Get(controller.ResourceName) + if err != nil { + return operatorv1alpha1.OperatorStatus{}, err + } + + return instance.Status.OperatorStatus, nil +} + diff --git a/pkg/console/subresource/configmap/configmap.go b/pkg/console/subresource/configmap/configmap.go new file mode 100644 index 0000000..5407417 --- /dev/null +++ b/pkg/console/subresource/configmap/configmap.go @@ -0,0 +1,133 @@ +package configmap + +import ( + "fmt" + "github.com/openshift/api/route/v1" + "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + "github.com/openshift/console-operator/pkg/console/subresource/util" + "github.com/openshift/console-operator/pkg/controller" + "gopkg.in/yaml.v2" + corev1 "k8s.io/api/core/v1" +) + +const ( + ConsoleConfigMapName = "console-config" + consoleConfigYamlFile = "console-config.yaml" + clientSecretFilePath = "/var/oauth-config/clientSecret" + oauthEndpointCAFilePath = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" + // TODO: should this be configurable? likely so. + documentationBaseURL = "https://docs.okd.io/4.0/" + brandingDefault = "okd" + // serving info + certFilePath = "/var/serving-cert/tls.crt" + keyFilePath = "/var/serving-cert/tls.key" +) + +func DefaultConfigMap(cr *v1alpha1.Console, rt *v1.Route) *corev1.ConfigMap { + // NOTE: this should probably just take the route.Spec.Host string. + // without the host, the CR should not be created, it is essential for + // the deployment to be created correctly. + if rt == nil { + return nil + } + host := rt.Spec.Host + config := NewYamlConfigString(host) + configMap := Stub() + configMap.Data = map[string]string{ + consoleConfigYamlFile: config, + } + util.AddOwnerRef(configMap, util.OwnerRefFrom(cr)) + return configMap +} + +func Stub() *corev1.ConfigMap { + meta := util.SharedMeta() + meta.Name = ConsoleConfigMapName + configMap := &corev1.ConfigMap{ + ObjectMeta: meta, + } + return configMap +} + +func NewYamlConfigString(host string) string { + return string(NewYamlConfig(host)) +} + +func NewYamlConfig(host string) []byte { + conf := yaml.MapSlice{ + { + Key: "kind", Value: "ConsoleConfig", + }, { + Key: "apiVersion", Value: "console.openshift.io/v1beta1", + }, { + Key: "auth", Value: authServerYaml(), + }, { + Key: "clusterInfo", Value: clusterInfo(host), + }, { + Key: "customization", Value: customization(), + }, { + Key: "servingInfo", Value: servingInfo(), + }, + } + yml, err := yaml.Marshal(conf) + if err != nil { + fmt.Printf("Could not create config yaml %v", err) + return nil + } + return yml +} + +func servingInfo() yaml.MapSlice { + return yaml.MapSlice{ + { + Key: "bindAddress", Value: "https://0.0.0.0:8443", + }, { + Key: "certFile", Value: certFilePath, + }, { + Key: "keyFile", Value: keyFilePath, + }, + } +} + +func customization() yaml.MapSlice { + return yaml.MapSlice{ + { + // TODO: branding will need to be provided by higher level config. + // it should not be configurable in the CR, but needs to be configured somewhere. + Key: "branding", Value: brandingDefault, + }, { + Key: "documentationBaseURL", Value: documentationBaseURL, + }, + } +} + +func clusterInfo(host string) yaml.MapSlice { + return yaml.MapSlice{ + { + Key: "consoleBaseAddress", Value: consoleBaseAddr(host), + }, { + Key: "consoleBasePath", Value: "", + }, + } + +} + +func authServerYaml() yaml.MapSlice { + return yaml.MapSlice{ + { + Key: "clientID", Value: controller.OpenShiftConsoleName, + }, { + Key: "clientSecretFile", Value: clientSecretFilePath, + }, { + Key: "logoutRedirect", Value: "", + }, { + Key: "oauthEndpointCAFile", Value: oauthEndpointCAFilePath, + }, + } +} + +func consoleBaseAddr(host string) string { + return util.HTTPS(host) +} + + diff --git a/pkg/console/subresource/deployment/deployment.go b/pkg/console/subresource/deployment/deployment.go new file mode 100644 index 0000000..c0359f8 --- /dev/null +++ b/pkg/console/subresource/deployment/deployment.go @@ -0,0 +1,200 @@ +package deployment + +import ( + "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + "github.com/openshift/console-operator/pkg/console/subresource/util" + "github.com/openshift/console-operator/pkg/controller" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +const ( + consolePortName = "https" + consolePort = 443 + consoleTargetPort = 8443 + publicURLName = "BRIDGE_DEVELOPER_CONSOLE_URL" + ConsoleServingCertName = "console-serving-cert" + ConsoleOauthConfigName = "console-oauth-config" +) + +type volumeConfig struct { + name string + readOnly bool + path string + // isSecret or isConfigMap are mutually exclusive + isSecret bool + isConfigMap bool +} + +var volumeConfigList = []volumeConfig{ + { + name: ConsoleServingCertName, + readOnly: true, + path: "/var/serving-cert", + isSecret: true, + }, + { + name: ConsoleOauthConfigName, + readOnly: true, + path: "/var/oauth-config", + isSecret: true, + }, + { + name: "console-config", + readOnly: true, + path: "/var/console-config", + isConfigMap: true, + }, +} + +func DefaultDeployment(cr *v1alpha1.Console) *appsv1.Deployment { + labels := util.LabelsForConsole() + meta := util.SharedMeta() + meta.Labels = labels + replicas := cr.Spec.Count + gracePeriod := int64(30) + + deployment := &appsv1.Deployment{ + ObjectMeta: meta, + Spec: appsv1.DeploymentSpec{ + Replicas: &replicas, + Selector: &metav1.LabelSelector{ + MatchLabels: labels, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.OpenShiftConsoleShortName, + Labels: labels, + Annotations: map[string]string{}, + }, + Spec: corev1.PodSpec{ + // TODO: NodeSelector: corev1.NodeSelector{}, + RestartPolicy: corev1.RestartPolicyAlways, + SchedulerName: corev1.DefaultSchedulerName, + TerminationGracePeriodSeconds: &gracePeriod, + SecurityContext: &corev1.PodSecurityContext{}, + Containers: []corev1.Container{ + consoleContainer(cr), + }, + Volumes: consoleVolumes(volumeConfigList), + }, + }, + }, + } + util.AddOwnerRef(deployment, util.OwnerRefFrom(cr)) + return deployment +} + +func Stub() *appsv1.Deployment { + meta := util.SharedMeta() + dep := &appsv1.Deployment{ + ObjectMeta: meta, + } + return dep +} + + +// deduplication, use the same volume config to generate Volumes, and VolumeMounts +func consoleVolumes(vc []volumeConfig) []corev1.Volume { + vols := make([]corev1.Volume, len(vc)) + for i, item := range vc { + if item.isSecret { + vols[i] = corev1.Volume{ + Name: item.name, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: item.name, + }, + }, + } + } + if item.isConfigMap { + vols[i] = corev1.Volume{ + Name: item.name, + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: item.name, + }, + }, + }, + } + } + } + return vols +} + +func consoleVolumeMounts(vc []volumeConfig) []corev1.VolumeMount { + volMountList := make([]corev1.VolumeMount, len(vc)) + for i, item := range vc { + volMountList[i] = corev1.VolumeMount{ + Name: item.name, + ReadOnly: item.readOnly, + MountPath: item.path, + } + } + return volMountList +} + +func consoleContainer(cr *v1alpha1.Console) corev1.Container { + volumeMounts := consoleVolumeMounts(volumeConfigList) + + return corev1.Container{ + Image: util.GetImageEnv(), + ImagePullPolicy: corev1.PullPolicy("IfNotPresent"), + Name: controller.OpenShiftConsoleShortName, + Command: []string{ + "/opt/bridge/bin/bridge", + "--public-dir=/opt/bridge/static", + "--config=/var/console-config/console-config.yaml", + }, + // TODO: can probably remove, this is used for local dev + //Env: []corev1.EnvVar{{ + // Name: publicURLName, + // Value: consoleURL(), + //}}, + Ports: []corev1.ContainerPort{{ + Name: consolePortName, + Protocol: corev1.ProtocolTCP, + ContainerPort: consolePort, + }}, + VolumeMounts: volumeMounts, + ReadinessProbe: defaultProbe(), + LivenessProbe: livenessProbe(), + TerminationMessagePath: "/dev/termination-log", + TerminationMessagePolicy: corev1.TerminationMessagePolicy("File"), + Resources: corev1.ResourceRequirements{ + Limits: map[corev1.ResourceName]resource.Quantity{ + // TODO: fill these out + // "cpu": int64(100), + // "memory": int64(100) + }, + Requests: map[corev1.ResourceName]resource.Quantity{}, + }, + } +} + +func defaultProbe() *corev1.Probe { + return &corev1.Probe{ + Handler: corev1.Handler{ + HTTPGet: &corev1.HTTPGetAction{ + Path: "/health", + Port: intstr.FromInt(8443), + Scheme: corev1.URIScheme("HTTPS"), + }, + }, + TimeoutSeconds: 1, + PeriodSeconds: 10, + SuccessThreshold: 1, + FailureThreshold: 3, + } +} + +func livenessProbe() *corev1.Probe { + probe := defaultProbe() + probe.InitialDelaySeconds = 30 + return probe +} diff --git a/pkg/console/subresource/oauthclient/oauthclient.go b/pkg/console/subresource/oauthclient/oauthclient.go new file mode 100644 index 0000000..9b7e180 --- /dev/null +++ b/pkg/console/subresource/oauthclient/oauthclient.go @@ -0,0 +1,84 @@ +package oauthclient + +import ( + oauthv1 "github.com/openshift/api/oauth/v1" + "github.com/openshift/api/route/v1" + oauthclient "github.com/openshift/client-go/oauth/clientset/versioned/typed/oauth/v1" + "github.com/openshift/console-operator/pkg/console/subresource/util" + "github.com/openshift/console-operator/pkg/controller" + "github.com/openshift/console-operator/pkg/crypto" + "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TODO: ApplyOauth should be a generic Apply that could be used for any oauth-client +// - should look like resourceapply.ApplyService and the other Apply funcs +// once its in a trustworthy state, PR to library-go so it can live with +// the other Apply funcs +func ApplyOAuth(client oauthclient.OAuthClientsGetter, required *oauthv1.OAuthClient) (*oauthv1.OAuthClient, bool, error) { + existing, err := client.OAuthClients().Get(required.Name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + actual, err := client.OAuthClients().Create(required) + return actual, true, err + } + if err != nil { + return nil, false, err + } + // Unfortunately data is all top level so its a little more + // tedious to manually copy things over + modified := resourcemerge.BoolPtr(false) + resourcemerge.EnsureObjectMeta(modified, &existing.ObjectMeta, required.ObjectMeta) + existing.Secret = required.Secret + existing.AdditionalSecrets = required.AdditionalSecrets + existing.RespondWithChallenges = required.RespondWithChallenges + existing.RedirectURIs = required.RedirectURIs + existing.GrantMethod = required.GrantMethod + existing.ScopeRestrictions = required.ScopeRestrictions + existing.AccessTokenMaxAgeSeconds = required.AccessTokenMaxAgeSeconds + existing.AccessTokenInactivityTimeoutSeconds = required.AccessTokenInactivityTimeoutSeconds + + actual, err := client.OAuthClients().Update(existing) + return actual, true, err +} + +// registers the console on the oauth client as a valid application +func RegisterConsoleToOAuthClient(client *oauthv1.OAuthClient, route *v1.Route, randomBits string) *oauthv1.OAuthClient { + // without a route, we cannot create a usable oauth client + if route == nil { + return nil + } + // we are the only application for this client + // in the future we may accept multiple routes + client.RedirectURIs = []string{} + client.RedirectURIs = append(client.RedirectURIs, util.HTTPS(route.Spec.Host)) + // client.Secret = randomBits + client.Secret = string(randomBits) + return client +} + +// for ManagementState.Removed +// Console does not have create/delete priviledges on oauth clients, only update +func DeRegisterConsoleFromOAuthClient(client *oauthv1.OAuthClient) *oauthv1.OAuthClient { + client.RedirectURIs = []string{} + // changing the string to anything else will invalidate the client + client.Secret = crypto.Random256BitsString() + return client +} + +func DefaultOauthClient() *oauthv1.OAuthClient{ + return Stub() +} + +func Stub() *oauthv1.OAuthClient{ + // we cannot set an ownerRef on the OAuthClient as it is cluster scoped + return &oauthv1.OAuthClient{ + ObjectMeta: metav1.ObjectMeta{ + Name: controller.OpenShiftConsoleName, + }, + } +} + +func GetSecretString(client *oauthv1.OAuthClient) string { + return client.Secret +} diff --git a/pkg/console/subresource/route/route.go b/pkg/console/subresource/route/route.go new file mode 100644 index 0000000..9108045 --- /dev/null +++ b/pkg/console/subresource/route/route.go @@ -0,0 +1,111 @@ +package route + +import ( + // kube + "k8s.io/apimachinery/pkg/api/equality" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + // openshift + "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" + routev1 "github.com/openshift/api/route/v1" + routeclient "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" + // operator + "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + "github.com/openshift/console-operator/pkg/console/subresource/util" + "github.com/openshift/console-operator/pkg/controller" +) + +// We can't blindly ApplyRoute() as we need the server to annotate the +// route.Spec.Host, so we need this func +func GetOrCreate(client routeclient.RoutesGetter, required *routev1.Route) (*routev1.Route, bool, error) { + isNew := false + existing, err := client.Routes(required.Namespace).Get(required.Name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + isNew = true + actual, err := client.Routes(required.Namespace).Create(required) + return actual, isNew, err + } + if err != nil { + return nil, isNew, err + } + return existing, isNew, nil +} + +// TODO: ApplyRoute +// - Handle the nuance of ApplyRoute(), noting that Host and perhaps other +// fields are provided later by the server. Once we know its correct, +// PR to library-go so it can live with the other Apply* funcs +func ApplyRoute(client routeclient.RoutesGetter, required *routev1.Route) (*routev1.Route, bool, error) { + // first, get or create + existing, err := client.Routes(required.Namespace).Get(required.Name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + actual, err := client.Routes(required.Namespace).Create(required) + return actual, true, err + } + if err != nil { + return nil, false, err + } + + modified := resourcemerge.BoolPtr(false) + resourcemerge.EnsureObjectMeta(modified, &existing.ObjectMeta, required.ObjectMeta) + + // possibly this should just be a DeepEqual on Spec? + hostSame := equality.Semantic.DeepEqual(existing.Spec.Host, required.Spec.Host) + portSame := equality.Semantic.DeepEqual(existing.Spec.Port, required.Spec.Port) + tlsSame := equality.Semantic.DeepEqual(existing.Spec.TLS, required.Spec.TLS) + targetSame := equality.Semantic.DeepEqual(existing.Spec.To, required.Spec.To) + wildcardSame := equality.Semantic.DeepEqual(existing.Spec.WildcardPolicy, required.Spec.WildcardPolicy) + // if nothing we care about changed, do nothing. this would be good to + // PR to library-go and ensure we get it right + if hostSame && portSame && tlsSame && targetSame && wildcardSame { + return existing, false, nil + } + + // TODO: + // - we dont want to squash host, which is assigned by the server + // - figure out how to handle this properly, some props are assigned later + toWrite := existing + // - CAN we just squash the .Spec here? or is that incorrect? Apply should + // be careful, but simple, know nothing about the business logic of the + // operator itself. Therefore, if one does ApplyRoute(someRoute) would they + // expect it simply to set this, regardless of what is on the server already? + // at this point probably should assume the caller already did a .Get(route) + // and merged properties, if that path was desired. + toWrite.Spec = *required.Spec.DeepCopy() + + actual, err := client.Routes(required.Namespace).Update(toWrite) + return actual, true, err +} + +func DefaultRoute(cr *v1alpha1.Console) *routev1.Route { + meta := util.SharedMeta() + meta.Name = controller.OpenShiftConsoleShortName + weight := int32(100) + route := Stub() + route.Spec = routev1.RouteSpec{ + To: routev1.RouteTargetReference{ + Kind: "Service", + Name: meta.Name, + Weight: &weight, + }, + Port: &routev1.RoutePort{ + TargetPort: intstr.FromString("https"), + }, + TLS: &routev1.TLSConfig{ + Termination: routev1.TLSTerminationReencrypt, + InsecureEdgeTerminationPolicy: routev1.InsecureEdgeTerminationPolicyRedirect, + }, + WildcardPolicy: routev1.WildcardPolicyNone, + } + util.AddOwnerRef(route, util.OwnerRefFrom(cr)) + return route +} + +func Stub() *routev1.Route { + meta := util.SharedMeta() + meta.Name = controller.OpenShiftConsoleShortName + return &routev1.Route{ + ObjectMeta: meta, + } +} diff --git a/pkg/console/subresource/secret/secret.go b/pkg/console/subresource/secret/secret.go new file mode 100644 index 0000000..4cf0524 --- /dev/null +++ b/pkg/console/subresource/secret/secret.go @@ -0,0 +1,45 @@ +package secret + +import ( + // 3rd + "github.com/sirupsen/logrus" + // kube + corev1 "k8s.io/api/core/v1" + // openshift + "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + "github.com/openshift/console-operator/pkg/console/subresource/deployment" + "github.com/openshift/console-operator/pkg/console/subresource/util" +) + +const ClientSecretKey = "clientSecret" + +func DefaultSecret(cr *v1alpha1.Console, randomBits string) *corev1.Secret { + logrus.Printf("DefaultSecret() %v", randomBits) + + secret := Stub() + // TODO: client-go ignores the StringData field. Open a PR to fix this + //secret.StringData = map[string]string{ + // ClientSecretKey: randomBits, + //} + secret.Data = map[string][]byte{ + ClientSecretKey: []byte(randomBits), + } + + util.AddOwnerRef(secret, util.OwnerRefFrom(cr)) + return secret +} + +func Stub() *corev1.Secret { + meta := util.SharedMeta() + meta.Name = deployment.ConsoleOauthConfigName + + secret := &corev1.Secret{ + ObjectMeta: meta, + } + return secret +} + +func GetSecretString(secret *corev1.Secret) string { + return string(secret.Data[ClientSecretKey]) +} + diff --git a/pkg/console/subresource/service/service.go b/pkg/console/subresource/service/service.go new file mode 100644 index 0000000..8fe615c --- /dev/null +++ b/pkg/console/subresource/service/service.go @@ -0,0 +1,60 @@ +package service + +import ( + "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + "github.com/openshift/console-operator/pkg/console/subresource/util" + "github.com/openshift/console-operator/pkg/controller" + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +const ( + // this annotation should generate us a serving certificate + ServingCertSecretAnnotation = "service.alpha.openshift.io/serving-cert-secret-name" +) + +const ( + ConsoleServingCertName = "console-serving-cert" + consolePortName = "https" + consolePort = 443 + consoleTargetPort = 8443 +) + +func DefaultService(cr *v1alpha1.Console) *v1.Service { + labels := util.LabelsForConsole() + meta := util.SharedMeta() + meta.Name = controller.OpenShiftConsoleShortName + meta.Annotations = map[string]string{ + ServingCertSecretAnnotation: ConsoleServingCertName, + } + service := Stub() + service.Spec = v1.ServiceSpec{ + Ports: []v1.ServicePort{ + { + Name: consolePortName, + Protocol: v1.ProtocolTCP, + Port: consolePort, + TargetPort: intstr.FromInt(consoleTargetPort), + }, + }, + Selector: labels, + Type: "ClusterIP", + SessionAffinity: "None", + } + + util.AddOwnerRef(service, util.OwnerRefFrom(cr)) + return service +} + +func Stub() *v1.Service { + meta := util.SharedMeta() + meta.Name = controller.OpenShiftConsoleShortName + meta.Annotations = map[string]string{ + ServingCertSecretAnnotation: ConsoleServingCertName, + } + service := &v1.Service{ + ObjectMeta: meta, + } + return service +} + diff --git a/pkg/console/subresource/util/util.go b/pkg/console/subresource/util/util.go new file mode 100644 index 0000000..9ce8247 --- /dev/null +++ b/pkg/console/subresource/util/util.go @@ -0,0 +1,103 @@ +package util + +import ( + "fmt" + "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + "github.com/openshift/console-operator/pkg/controller" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v2" + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "os" + "strings" +) + +func SharedLabels() map[string]string { + return map[string]string{ + "app": controller.OpenShiftConsoleName, + } +} + +func LabelsForConsole() map[string]string { + baseLabels := SharedLabels() + + extraLabels := map[string]string{ + "component": "ui", + } + // we want to deduplicate, so doing these two loops. + allLabels := map[string]string{} + + for key, value := range baseLabels { + allLabels[key] = value + } + for key, value := range extraLabels { + allLabels[key] = value + } + return allLabels +} + +func SharedMeta() v1.ObjectMeta { + return v1.ObjectMeta{ + Name: controller.OpenShiftConsoleName, + Namespace: controller.OpenShiftConsoleName, + Labels: SharedLabels(), + } +} + +func LogYaml(obj runtime.Object) { + // REALLY NOISY, but handy for debugging: + // deployJSON, err := json.Marshal(d) + objYaml, err := yaml.Marshal(obj) + if err != nil { + logrus.Info("failed to show yaml in log") + } + logrus.Infof("%v", string(objYaml)) +} + +// objects can have more than one ownerRef, potentially +func AddOwnerRef(obj v1.Object, ownerRef *v1.OwnerReference) { + fmt.Println("AddOwnerRef() disabled.") + //if obj != nil { + // if ownerRef != nil { + // obj.SetOwnerReferences(append(obj.GetOwnerReferences(), *ownerRef)) + // } + //} +} + +// func RemoveOwnerRef + +func OwnerRefFrom(cr *v1alpha1.Console) *v1.OwnerReference { + if cr != nil { + truthy := true + return &v1.OwnerReference{ + APIVersion: cr.APIVersion, + Kind: cr.Kind, + Name: cr.Name, + UID: cr.UID, + Controller: &truthy, + } + } + return nil +} + +// borrowed from library-go +// https://github.com/openshift/library-go/blob/master/pkg/operator/v1alpha1helpers/helpers.go +func GetImageEnv() string { + return os.Getenv("IMAGE") +} + +// TODO: technically, this should take targetPort from route.spec.port.targetPort +func HTTPS(host string) string { + protocol := "https://" + if host == "" { + logrus.Infof("util.HTTPS() cannot accept an empty string.") + return "" + } + if strings.HasPrefix(host, protocol) { + return host + } + secured := fmt.Sprintf("%s%s", protocol, host) + logrus.Infof("util.HTTPS(): from %s to %s", host, secured) + return secured +} + diff --git a/pkg/example/version/version.go b/pkg/console/version/version.go similarity index 89% rename from pkg/example/version/version.go rename to pkg/console/version/version.go index 03fd54b..8793f42 100644 --- a/pkg/example/version/version.go +++ b/pkg/console/version/version.go @@ -36,8 +36,8 @@ func Get() version.Info { func init() { buildInfo := prometheus.NewGaugeVec( prometheus.GaugeOpts{ - Name: "openshift_service_serving_cert_signer_build_info", - Help: "A metric with a constant '1' value labeled by major, minor, git commit & git version from which OpenShift Service Serving Cert Signer was built.", + Name: "openshift_console_operator_build_info", + Help: "A metric with a constant '1' value labeled by major, minor, git commit & git version from which OpenShift Console Operator was built.", }, []string{"major", "minor", "gitCommit", "gitVersion"}, ) diff --git a/pkg/controller/api.go b/pkg/controller/api.go new file mode 100644 index 0000000..62e15e7 --- /dev/null +++ b/pkg/controller/api.go @@ -0,0 +1,20 @@ +package controller + +// atm dumping ground for consts + +const ( + // TargetNamespace could be made configurable if desired + TargetNamespace = "openshift-console" + // ResourceName could be made configurable if desired + // all resources share the same name to make it easier to reason about and to configure single item watches + // NOTE: this must match metadata.name in the CR.yaml else the CR will be ignored + ResourceName = "console-operator-resource" +) + +// consts to maintain existing names of various sub-resources +const ( + OpenShiftConsoleName = "openshift-console" + OpenShiftConsoleShortName = "console" + OpenShiftConsoleNamespace = "openshift-console" +) + diff --git a/pkg/crypto/random.go b/pkg/crypto/random.go new file mode 100644 index 0000000..7375601 --- /dev/null +++ b/pkg/crypto/random.go @@ -0,0 +1,36 @@ +// From @enj openshift/origin +// https://github.com/openshift/origin/tree/9a8a2fb3f9485bf88ebea61e4b5d8bf04dd3c459/pkg/oauthserver/server/crypto +package crypto + +import ( + "crypto/rand" + "encoding/base64" +) + +// RandomBits returns a random byte slice with at least the requested bits of entropy. +// Callers should avoid using a value less than 256 unless they have a very good reason. +func RandomBits(bits int) []byte { + size := bits / 8 + if bits%8 != 0 { + size++ + } + b := make([]byte, size) + if _, err := rand.Read(b); err != nil { + panic(err) // rand should never fail + } + return b +} + +// RandomBitsString returns a random string with at least the requested bits of entropy. +// It uses RawURLEncoding to ensure we do not get / characters or trailing ='s. +func RandomBitsString(bits int) string { + return base64.RawURLEncoding.EncodeToString(RandomBits(bits)) +} + +// Random256BitsString is a convenience function for calling RandomBitsString(256). +// Callers that need a random string should use this function unless they have a +// very good reason to need a different amount of entropy. +func Random256BitsString() string { + // 32 bytes (256 bits) = 43 base64-encoded characters + return RandomBitsString(256) +} diff --git a/pkg/example/operator/operator.go b/pkg/example/operator/operator.go deleted file mode 100644 index bb2c5d2..0000000 --- a/pkg/example/operator/operator.go +++ /dev/null @@ -1,164 +0,0 @@ -package operator - -import ( - "fmt" - - "github.com/blang/semver" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - utilerrors "k8s.io/apimachinery/pkg/util/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/client-go/informers/core/v1" - coreclientv1 "k8s.io/client-go/kubernetes/typed/core/v1" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/workqueue" - - operatorsv1alpha1 "github.com/openshift/api/operator/v1alpha1" - "github.com/openshift/library-go/pkg/operator/resource/resourceapply" - "github.com/openshift/library-go/pkg/operator/versioning" - - "github.com/enj/example-operator/pkg/controller" - "github.com/enj/example-operator/pkg/generated/clientset/versioned/typed/example/v1alpha1" - exampleinformers "github.com/enj/example-operator/pkg/generated/informers/externalversions/example/v1alpha1" -) - -const ( - // TargetNamespace could be made configurable if desired - TargetNamespace = "example-operator" - - // ResourceName could be made configurable if desired - // all resources share the same name to make it easier to reason about and to configure single item watches - ResourceName = "example-operator-resource" - - // workQueueKey is the singleton key shared by all events - // the value is irrelevant - workQueueKey = "key" -) - -func NewExampleOperator(eoi exampleinformers.ExampleOperatorInformer, si v1.SecretInformer, operatorClient v1alpha1.ExampleOperatorInterface, secretsClient coreclientv1.SecretsGetter) *ExampleOperator { - c := &ExampleOperator{ - operatorClient: operatorClient, - secretsClient: secretsClient, - } - - operatorInformer := eoi.Informer() - secretsInformer := si.Informer() - - // we do not really need to wait for our informers to sync since we only watch a single resource - // and make live reads but it does not hurt anything and guarantees we have the correct behavior - internalController, queue := controller.New("ExampleOperator", c.sync, operatorInformer.HasSynced, secretsInformer.HasSynced) - - c.controller = internalController - - operatorInformer.AddEventHandler(eventHandler(queue)) - secretsInformer.AddEventHandler(eventHandler(queue)) - - return c -} - -// eventHandler queues the operator to check spec and status -// TODO add filtering and more nuanced logic -// each informer's event handler could have specific logic based on the resource -// for now just rekicking the sync loop is enough since we only watch a single resource by name -func eventHandler(queue workqueue.RateLimitingInterface) cache.ResourceEventHandler { - return cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { queue.Add(workQueueKey) }, - UpdateFunc: func(old, new interface{}) { queue.Add(workQueueKey) }, - DeleteFunc: func(obj interface{}) { queue.Add(workQueueKey) }, - } -} - -type ExampleOperator struct { - // for a performance sensitive operator, it would make sense to use informers - // to handle reads and clients to handle writes. since this operator works - // on a singleton resource, it has no performance requirements. - operatorClient v1alpha1.ExampleOperatorInterface - secretsClient coreclientv1.SecretsGetter - - controller *controller.Controller -} - -func (c *ExampleOperator) Run(stopCh <-chan struct{}) { - // only start one worker because we only have one key name in our queue - // since this operator works on a singleton, it does not make sense to ever run more than one worker - c.controller.Run(1, stopCh) -} - -func (c *ExampleOperator) sync(_ interface{}) error { - // we ignore the passed in key because it will always be workQueueKey - // it does not matter how the sync loop was triggered - // all we need to worry about is reconciling the state back to what we expect - - config, err := c.operatorClient.Get(ResourceName, metav1.GetOptions{}) - if err != nil { - return err - } - - switch config.Spec.ManagementState { - case operatorsv1alpha1.Managed: - // handled below - - case operatorsv1alpha1.Unmanaged: - return nil - - case operatorsv1alpha1.Removed: - return utilerrors.FilterOut(c.secretsClient.Secrets(TargetNamespace).Delete(ResourceName, nil), errors.IsNotFound) - - default: - // TODO should update status - return fmt.Errorf("unknown state: %v", config.Spec.ManagementState) - } - - var currentActualVerion *semver.Version - - if ca := config.Status.CurrentAvailability; ca != nil { - ver, err := semver.Parse(ca.Version) - if err != nil { - utilruntime.HandleError(err) - } else { - currentActualVerion = &ver - } - } - desiredVersion, err := semver.Parse(config.Spec.Version) - if err != nil { - // TODO report failing status, we may actually attempt to do this in the "normal" error handling - return err - } - - v310_00_to_unknown := versioning.NewRangeOrDie("3.10.0", "3.10.1") - - outConfig := config.DeepCopy() - var errs []error - - switch { - case v310_00_to_unknown.BetweenOrEmpty(currentActualVerion) && v310_00_to_unknown.Between(&desiredVersion): - _, _, err := resourceapply.ApplySecret(c.secretsClient, &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: ResourceName, - Namespace: TargetNamespace, - }, - Data: map[string][]byte{ - config.Spec.Value: []byte("007"), - }, - }) - errs = append(errs, err) - - if err == nil { // this needs work, but good enough for now - outConfig.Status.TaskSummary = "sync-[3.10.0,3.10.1)" - outConfig.Status.CurrentAvailability = &operatorsv1alpha1.VersionAvailability{ - Version: desiredVersion.String(), - } - } - - default: - outConfig.Status.TaskSummary = "unrecognized" - } - - // TODO: this should do better apply logic or similar, maybe use SetStatusFromAvailability - _, err = c.operatorClient.Update(outConfig) - errs = append(errs, err) - - return utilerrors.NewAggregate(errs) -} diff --git a/pkg/example/starter/starter.go b/pkg/example/starter/starter.go deleted file mode 100644 index a9a1350..0000000 --- a/pkg/example/starter/starter.go +++ /dev/null @@ -1,61 +0,0 @@ -package starter - -import ( - "fmt" - "time" - - "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - - "github.com/enj/example-operator/pkg/example/operator" - "github.com/enj/example-operator/pkg/generated/clientset/versioned" - "github.com/enj/example-operator/pkg/generated/informers/externalversions" -) - -func RunOperator(clientConfig *rest.Config, stopCh <-chan struct{}) error { - kubeClient, err := kubernetes.NewForConfig(clientConfig) - if err != nil { - return err - } - - exampleOperatorClient, err := versioned.NewForConfig(clientConfig) - if err != nil { - return err - } - - const resync = 10 * time.Minute - - // only watch a specific resource name - tweakListOptions := func(options *v1.ListOptions) { - options.FieldSelector = fields.OneTermEqualSelector("metadata.name", operator.ResourceName).String() - } - - kubeInformersNamespaced := informers.NewSharedInformerFactoryWithOptions(kubeClient, resync, - informers.WithNamespace(operator.TargetNamespace), - informers.WithTweakListOptions(tweakListOptions), - ) - - exampleOperatorInformers := externalversions.NewSharedInformerFactoryWithOptions(exampleOperatorClient, resync, - externalversions.WithNamespace(operator.TargetNamespace), - externalversions.WithTweakListOptions(tweakListOptions), - ) - - exampleOperator := operator.NewExampleOperator( - exampleOperatorInformers.Exampleoperator().V1alpha1().ExampleOperators(), - kubeInformersNamespaced.Core().V1().Secrets(), - exampleOperatorClient.ExampleoperatorV1alpha1().ExampleOperators(operator.TargetNamespace), - kubeClient.CoreV1(), - ) - - kubeInformersNamespaced.Start(stopCh) - exampleOperatorInformers.Start(stopCh) - - go exampleOperator.Run(stopCh) - - <-stopCh - - return fmt.Errorf("stopped") -} diff --git a/pkg/generated/clientset/versioned/clientset.go b/pkg/generated/clientset/versioned/clientset.go index 54a7d42..b833cb6 100644 --- a/pkg/generated/clientset/versioned/clientset.go +++ b/pkg/generated/clientset/versioned/clientset.go @@ -3,7 +3,7 @@ package versioned import ( - exampleoperatorv1alpha1 "github.com/enj/example-operator/pkg/generated/clientset/versioned/typed/example/v1alpha1" + consolev1alpha1 "github.com/openshift/console-operator/pkg/generated/clientset/versioned/typed/console/v1alpha1" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" @@ -11,27 +11,27 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface - ExampleoperatorV1alpha1() exampleoperatorv1alpha1.ExampleoperatorV1alpha1Interface + ConsoleV1alpha1() consolev1alpha1.ConsoleV1alpha1Interface // Deprecated: please explicitly pick a version if possible. - Exampleoperator() exampleoperatorv1alpha1.ExampleoperatorV1alpha1Interface + Console() consolev1alpha1.ConsoleV1alpha1Interface } // Clientset contains the clients for groups. Each group has exactly one // version included in a Clientset. type Clientset struct { *discovery.DiscoveryClient - exampleoperatorV1alpha1 *exampleoperatorv1alpha1.ExampleoperatorV1alpha1Client + consoleV1alpha1 *consolev1alpha1.ConsoleV1alpha1Client } -// ExampleoperatorV1alpha1 retrieves the ExampleoperatorV1alpha1Client -func (c *Clientset) ExampleoperatorV1alpha1() exampleoperatorv1alpha1.ExampleoperatorV1alpha1Interface { - return c.exampleoperatorV1alpha1 +// ConsoleV1alpha1 retrieves the ConsoleV1alpha1Client +func (c *Clientset) ConsoleV1alpha1() consolev1alpha1.ConsoleV1alpha1Interface { + return c.consoleV1alpha1 } -// Deprecated: Exampleoperator retrieves the default version of ExampleoperatorClient. +// Deprecated: Console retrieves the default version of ConsoleClient. // Please explicitly pick a version. -func (c *Clientset) Exampleoperator() exampleoperatorv1alpha1.ExampleoperatorV1alpha1Interface { - return c.exampleoperatorV1alpha1 +func (c *Clientset) Console() consolev1alpha1.ConsoleV1alpha1Interface { + return c.consoleV1alpha1 } // Discovery retrieves the DiscoveryClient @@ -50,7 +50,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { } var cs Clientset var err error - cs.exampleoperatorV1alpha1, err = exampleoperatorv1alpha1.NewForConfig(&configShallowCopy) + cs.consoleV1alpha1, err = consolev1alpha1.NewForConfig(&configShallowCopy) if err != nil { return nil, err } @@ -66,7 +66,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset - cs.exampleoperatorV1alpha1 = exampleoperatorv1alpha1.NewForConfigOrDie(c) + cs.consoleV1alpha1 = consolev1alpha1.NewForConfigOrDie(c) cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) return &cs @@ -75,7 +75,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset - cs.exampleoperatorV1alpha1 = exampleoperatorv1alpha1.New(c) + cs.consoleV1alpha1 = consolev1alpha1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/pkg/generated/clientset/versioned/fake/clientset_generated.go b/pkg/generated/clientset/versioned/fake/clientset_generated.go index 4191e2c..2f30ffc 100644 --- a/pkg/generated/clientset/versioned/fake/clientset_generated.go +++ b/pkg/generated/clientset/versioned/fake/clientset_generated.go @@ -3,9 +3,9 @@ package fake import ( - clientset "github.com/enj/example-operator/pkg/generated/clientset/versioned" - exampleoperatorv1alpha1 "github.com/enj/example-operator/pkg/generated/clientset/versioned/typed/example/v1alpha1" - fakeexampleoperatorv1alpha1 "github.com/enj/example-operator/pkg/generated/clientset/versioned/typed/example/v1alpha1/fake" + clientset "github.com/openshift/console-operator/pkg/generated/clientset/versioned" + consolev1alpha1 "github.com/openshift/console-operator/pkg/generated/clientset/versioned/typed/console/v1alpha1" + fakeconsolev1alpha1 "github.com/openshift/console-operator/pkg/generated/clientset/versioned/typed/console/v1alpha1/fake" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/discovery" @@ -55,12 +55,12 @@ func (c *Clientset) Discovery() discovery.DiscoveryInterface { var _ clientset.Interface = &Clientset{} -// ExampleoperatorV1alpha1 retrieves the ExampleoperatorV1alpha1Client -func (c *Clientset) ExampleoperatorV1alpha1() exampleoperatorv1alpha1.ExampleoperatorV1alpha1Interface { - return &fakeexampleoperatorv1alpha1.FakeExampleoperatorV1alpha1{Fake: &c.Fake} +// ConsoleV1alpha1 retrieves the ConsoleV1alpha1Client +func (c *Clientset) ConsoleV1alpha1() consolev1alpha1.ConsoleV1alpha1Interface { + return &fakeconsolev1alpha1.FakeConsoleV1alpha1{Fake: &c.Fake} } -// Exampleoperator retrieves the ExampleoperatorV1alpha1Client -func (c *Clientset) Exampleoperator() exampleoperatorv1alpha1.ExampleoperatorV1alpha1Interface { - return &fakeexampleoperatorv1alpha1.FakeExampleoperatorV1alpha1{Fake: &c.Fake} +// Console retrieves the ConsoleV1alpha1Client +func (c *Clientset) Console() consolev1alpha1.ConsoleV1alpha1Interface { + return &fakeconsolev1alpha1.FakeConsoleV1alpha1{Fake: &c.Fake} } diff --git a/pkg/generated/clientset/versioned/fake/register.go b/pkg/generated/clientset/versioned/fake/register.go index 23c48de..311819f 100644 --- a/pkg/generated/clientset/versioned/fake/register.go +++ b/pkg/generated/clientset/versioned/fake/register.go @@ -3,7 +3,7 @@ package fake import ( - exampleoperatorv1alpha1 "github.com/enj/example-operator/pkg/apis/example/v1alpha1" + consolev1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -34,5 +34,5 @@ func init() { // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. func AddToScheme(scheme *runtime.Scheme) { - exampleoperatorv1alpha1.AddToScheme(scheme) + consolev1alpha1.AddToScheme(scheme) } diff --git a/pkg/generated/clientset/versioned/scheme/register.go b/pkg/generated/clientset/versioned/scheme/register.go index c8f435b..d33005b 100644 --- a/pkg/generated/clientset/versioned/scheme/register.go +++ b/pkg/generated/clientset/versioned/scheme/register.go @@ -3,7 +3,7 @@ package scheme import ( - exampleoperatorv1alpha1 "github.com/enj/example-operator/pkg/apis/example/v1alpha1" + consolev1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -34,5 +34,5 @@ func init() { // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. func AddToScheme(scheme *runtime.Scheme) { - exampleoperatorv1alpha1.AddToScheme(scheme) + consolev1alpha1.AddToScheme(scheme) } diff --git a/pkg/generated/clientset/versioned/typed/console/v1alpha1/console.go b/pkg/generated/clientset/versioned/typed/console/v1alpha1/console.go new file mode 100644 index 0000000..e60e7de --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/console/v1alpha1/console.go @@ -0,0 +1,158 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + scheme "github.com/openshift/console-operator/pkg/generated/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// ConsolesGetter has a method to return a ConsoleInterface. +// A group's client should implement this interface. +type ConsolesGetter interface { + Consoles(namespace string) ConsoleInterface +} + +// ConsoleInterface has methods to work with Console resources. +type ConsoleInterface interface { + Create(*v1alpha1.Console) (*v1alpha1.Console, error) + Update(*v1alpha1.Console) (*v1alpha1.Console, error) + UpdateStatus(*v1alpha1.Console) (*v1alpha1.Console, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.Console, error) + List(opts v1.ListOptions) (*v1alpha1.ConsoleList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Console, err error) + ConsoleExpansion +} + +// consoles implements ConsoleInterface +type consoles struct { + client rest.Interface + ns string +} + +// newConsoles returns a Consoles +func newConsoles(c *ConsoleV1alpha1Client, namespace string) *consoles { + return &consoles{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the console, and returns the corresponding console object, and an error if there is any. +func (c *consoles) Get(name string, options v1.GetOptions) (result *v1alpha1.Console, err error) { + result = &v1alpha1.Console{} + err = c.client.Get(). + Namespace(c.ns). + Resource("consoles"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Consoles that match those selectors. +func (c *consoles) List(opts v1.ListOptions) (result *v1alpha1.ConsoleList, err error) { + result = &v1alpha1.ConsoleList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("consoles"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested consoles. +func (c *consoles) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("consoles"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a console and creates it. Returns the server's representation of the console, and an error, if there is any. +func (c *consoles) Create(console *v1alpha1.Console) (result *v1alpha1.Console, err error) { + result = &v1alpha1.Console{} + err = c.client.Post(). + Namespace(c.ns). + Resource("consoles"). + Body(console). + Do(). + Into(result) + return +} + +// Update takes the representation of a console and updates it. Returns the server's representation of the console, and an error, if there is any. +func (c *consoles) Update(console *v1alpha1.Console) (result *v1alpha1.Console, err error) { + result = &v1alpha1.Console{} + err = c.client.Put(). + Namespace(c.ns). + Resource("consoles"). + Name(console.Name). + Body(console). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *consoles) UpdateStatus(console *v1alpha1.Console) (result *v1alpha1.Console, err error) { + result = &v1alpha1.Console{} + err = c.client.Put(). + Namespace(c.ns). + Resource("consoles"). + Name(console.Name). + SubResource("status"). + Body(console). + Do(). + Into(result) + return +} + +// Delete takes name of the console and deletes it. Returns an error if one occurs. +func (c *consoles) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("consoles"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *consoles) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("consoles"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched console. +func (c *consoles) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Console, err error) { + result = &v1alpha1.Console{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("consoles"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/generated/clientset/versioned/typed/console/v1alpha1/console_client.go b/pkg/generated/clientset/versioned/typed/console/v1alpha1/console_client.go new file mode 100644 index 0000000..c8276bb --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/console/v1alpha1/console_client.go @@ -0,0 +1,74 @@ +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + "github.com/openshift/console-operator/pkg/generated/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type ConsoleV1alpha1Interface interface { + RESTClient() rest.Interface + ConsolesGetter +} + +// ConsoleV1alpha1Client is used to interact with features provided by the console.openshift.io group. +type ConsoleV1alpha1Client struct { + restClient rest.Interface +} + +func (c *ConsoleV1alpha1Client) Consoles(namespace string) ConsoleInterface { + return newConsoles(c, namespace) +} + +// NewForConfig creates a new ConsoleV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*ConsoleV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ConsoleV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new ConsoleV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ConsoleV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ConsoleV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *ConsoleV1alpha1Client { + return &ConsoleV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ConsoleV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/generated/clientset/versioned/typed/example/v1alpha1/doc.go b/pkg/generated/clientset/versioned/typed/console/v1alpha1/doc.go similarity index 100% rename from pkg/generated/clientset/versioned/typed/example/v1alpha1/doc.go rename to pkg/generated/clientset/versioned/typed/console/v1alpha1/doc.go diff --git a/pkg/generated/clientset/versioned/typed/example/v1alpha1/fake/doc.go b/pkg/generated/clientset/versioned/typed/console/v1alpha1/fake/doc.go similarity index 100% rename from pkg/generated/clientset/versioned/typed/example/v1alpha1/fake/doc.go rename to pkg/generated/clientset/versioned/typed/console/v1alpha1/fake/doc.go diff --git a/pkg/generated/clientset/versioned/typed/console/v1alpha1/fake/fake_console.go b/pkg/generated/clientset/versioned/typed/console/v1alpha1/fake/fake_console.go new file mode 100644 index 0000000..cfde9de --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/console/v1alpha1/fake/fake_console.go @@ -0,0 +1,124 @@ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeConsoles implements ConsoleInterface +type FakeConsoles struct { + Fake *FakeConsoleV1alpha1 + ns string +} + +var consolesResource = schema.GroupVersionResource{Group: "console.openshift.io", Version: "v1alpha1", Resource: "consoles"} + +var consolesKind = schema.GroupVersionKind{Group: "console.openshift.io", Version: "v1alpha1", Kind: "Console"} + +// Get takes name of the console, and returns the corresponding console object, and an error if there is any. +func (c *FakeConsoles) Get(name string, options v1.GetOptions) (result *v1alpha1.Console, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(consolesResource, c.ns, name), &v1alpha1.Console{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Console), err +} + +// List takes label and field selectors, and returns the list of Consoles that match those selectors. +func (c *FakeConsoles) List(opts v1.ListOptions) (result *v1alpha1.ConsoleList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(consolesResource, consolesKind, c.ns, opts), &v1alpha1.ConsoleList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ConsoleList{ListMeta: obj.(*v1alpha1.ConsoleList).ListMeta} + for _, item := range obj.(*v1alpha1.ConsoleList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested consoles. +func (c *FakeConsoles) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(consolesResource, c.ns, opts)) + +} + +// Create takes the representation of a console and creates it. Returns the server's representation of the console, and an error, if there is any. +func (c *FakeConsoles) Create(console *v1alpha1.Console) (result *v1alpha1.Console, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(consolesResource, c.ns, console), &v1alpha1.Console{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Console), err +} + +// Update takes the representation of a console and updates it. Returns the server's representation of the console, and an error, if there is any. +func (c *FakeConsoles) Update(console *v1alpha1.Console) (result *v1alpha1.Console, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(consolesResource, c.ns, console), &v1alpha1.Console{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Console), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeConsoles) UpdateStatus(console *v1alpha1.Console) (*v1alpha1.Console, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(consolesResource, "status", c.ns, console), &v1alpha1.Console{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Console), err +} + +// Delete takes name of the console and deletes it. Returns an error if one occurs. +func (c *FakeConsoles) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(consolesResource, c.ns, name), &v1alpha1.Console{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeConsoles) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(consolesResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.ConsoleList{}) + return err +} + +// Patch applies the patch and returns the patched console. +func (c *FakeConsoles) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Console, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(consolesResource, c.ns, name, data, subresources...), &v1alpha1.Console{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Console), err +} diff --git a/pkg/generated/clientset/versioned/typed/console/v1alpha1/fake/fake_console_client.go b/pkg/generated/clientset/versioned/typed/console/v1alpha1/fake/fake_console_client.go new file mode 100644 index 0000000..7cc601a --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/console/v1alpha1/fake/fake_console_client.go @@ -0,0 +1,24 @@ +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/openshift/console-operator/pkg/generated/clientset/versioned/typed/console/v1alpha1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeConsoleV1alpha1 struct { + *testing.Fake +} + +func (c *FakeConsoleV1alpha1) Consoles(namespace string) v1alpha1.ConsoleInterface { + return &FakeConsoles{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeConsoleV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/generated/clientset/versioned/typed/example/v1alpha1/generated_expansion.go b/pkg/generated/clientset/versioned/typed/console/v1alpha1/generated_expansion.go similarity index 60% rename from pkg/generated/clientset/versioned/typed/example/v1alpha1/generated_expansion.go rename to pkg/generated/clientset/versioned/typed/console/v1alpha1/generated_expansion.go index 97fc64f..6ac17a0 100644 --- a/pkg/generated/clientset/versioned/typed/example/v1alpha1/generated_expansion.go +++ b/pkg/generated/clientset/versioned/typed/console/v1alpha1/generated_expansion.go @@ -2,4 +2,4 @@ package v1alpha1 -type ExampleOperatorExpansion interface{} +type ConsoleExpansion interface{} diff --git a/pkg/generated/clientset/versioned/typed/example/v1alpha1/example_client.go b/pkg/generated/clientset/versioned/typed/example/v1alpha1/example_client.go deleted file mode 100644 index 794e41b..0000000 --- a/pkg/generated/clientset/versioned/typed/example/v1alpha1/example_client.go +++ /dev/null @@ -1,74 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1alpha1 "github.com/enj/example-operator/pkg/apis/example/v1alpha1" - "github.com/enj/example-operator/pkg/generated/clientset/versioned/scheme" - serializer "k8s.io/apimachinery/pkg/runtime/serializer" - rest "k8s.io/client-go/rest" -) - -type ExampleoperatorV1alpha1Interface interface { - RESTClient() rest.Interface - ExampleOperatorsGetter -} - -// ExampleoperatorV1alpha1Client is used to interact with features provided by the exampleoperator.crd.monis.app group. -type ExampleoperatorV1alpha1Client struct { - restClient rest.Interface -} - -func (c *ExampleoperatorV1alpha1Client) ExampleOperators(namespace string) ExampleOperatorInterface { - return newExampleOperators(c, namespace) -} - -// NewForConfig creates a new ExampleoperatorV1alpha1Client for the given config. -func NewForConfig(c *rest.Config) (*ExampleoperatorV1alpha1Client, error) { - config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } - client, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - return &ExampleoperatorV1alpha1Client{client}, nil -} - -// NewForConfigOrDie creates a new ExampleoperatorV1alpha1Client for the given config and -// panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *ExampleoperatorV1alpha1Client { - client, err := NewForConfig(c) - if err != nil { - panic(err) - } - return client -} - -// New creates a new ExampleoperatorV1alpha1Client for the given RESTClient. -func New(c rest.Interface) *ExampleoperatorV1alpha1Client { - return &ExampleoperatorV1alpha1Client{c} -} - -func setConfigDefaults(config *rest.Config) error { - gv := v1alpha1.SchemeGroupVersion - config.GroupVersion = &gv - config.APIPath = "/apis" - config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} - - if config.UserAgent == "" { - config.UserAgent = rest.DefaultKubernetesUserAgent() - } - - return nil -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *ExampleoperatorV1alpha1Client) RESTClient() rest.Interface { - if c == nil { - return nil - } - return c.restClient -} diff --git a/pkg/generated/clientset/versioned/typed/example/v1alpha1/exampleoperator.go b/pkg/generated/clientset/versioned/typed/example/v1alpha1/exampleoperator.go deleted file mode 100644 index 61be1ab..0000000 --- a/pkg/generated/clientset/versioned/typed/example/v1alpha1/exampleoperator.go +++ /dev/null @@ -1,158 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1alpha1 "github.com/enj/example-operator/pkg/apis/example/v1alpha1" - scheme "github.com/enj/example-operator/pkg/generated/clientset/versioned/scheme" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - rest "k8s.io/client-go/rest" -) - -// ExampleOperatorsGetter has a method to return a ExampleOperatorInterface. -// A group's client should implement this interface. -type ExampleOperatorsGetter interface { - ExampleOperators(namespace string) ExampleOperatorInterface -} - -// ExampleOperatorInterface has methods to work with ExampleOperator resources. -type ExampleOperatorInterface interface { - Create(*v1alpha1.ExampleOperator) (*v1alpha1.ExampleOperator, error) - Update(*v1alpha1.ExampleOperator) (*v1alpha1.ExampleOperator, error) - UpdateStatus(*v1alpha1.ExampleOperator) (*v1alpha1.ExampleOperator, error) - Delete(name string, options *v1.DeleteOptions) error - DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error - Get(name string, options v1.GetOptions) (*v1alpha1.ExampleOperator, error) - List(opts v1.ListOptions) (*v1alpha1.ExampleOperatorList, error) - Watch(opts v1.ListOptions) (watch.Interface, error) - Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ExampleOperator, err error) - ExampleOperatorExpansion -} - -// exampleOperators implements ExampleOperatorInterface -type exampleOperators struct { - client rest.Interface - ns string -} - -// newExampleOperators returns a ExampleOperators -func newExampleOperators(c *ExampleoperatorV1alpha1Client, namespace string) *exampleOperators { - return &exampleOperators{ - client: c.RESTClient(), - ns: namespace, - } -} - -// Get takes name of the exampleOperator, and returns the corresponding exampleOperator object, and an error if there is any. -func (c *exampleOperators) Get(name string, options v1.GetOptions) (result *v1alpha1.ExampleOperator, err error) { - result = &v1alpha1.ExampleOperator{} - err = c.client.Get(). - Namespace(c.ns). - Resource("exampleoperators"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of ExampleOperators that match those selectors. -func (c *exampleOperators) List(opts v1.ListOptions) (result *v1alpha1.ExampleOperatorList, err error) { - result = &v1alpha1.ExampleOperatorList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("exampleoperators"). - VersionedParams(&opts, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested exampleOperators. -func (c *exampleOperators) Watch(opts v1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("exampleoperators"). - VersionedParams(&opts, scheme.ParameterCodec). - Watch() -} - -// Create takes the representation of a exampleOperator and creates it. Returns the server's representation of the exampleOperator, and an error, if there is any. -func (c *exampleOperators) Create(exampleOperator *v1alpha1.ExampleOperator) (result *v1alpha1.ExampleOperator, err error) { - result = &v1alpha1.ExampleOperator{} - err = c.client.Post(). - Namespace(c.ns). - Resource("exampleoperators"). - Body(exampleOperator). - Do(). - Into(result) - return -} - -// Update takes the representation of a exampleOperator and updates it. Returns the server's representation of the exampleOperator, and an error, if there is any. -func (c *exampleOperators) Update(exampleOperator *v1alpha1.ExampleOperator) (result *v1alpha1.ExampleOperator, err error) { - result = &v1alpha1.ExampleOperator{} - err = c.client.Put(). - Namespace(c.ns). - Resource("exampleoperators"). - Name(exampleOperator.Name). - Body(exampleOperator). - Do(). - Into(result) - return -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - -func (c *exampleOperators) UpdateStatus(exampleOperator *v1alpha1.ExampleOperator) (result *v1alpha1.ExampleOperator, err error) { - result = &v1alpha1.ExampleOperator{} - err = c.client.Put(). - Namespace(c.ns). - Resource("exampleoperators"). - Name(exampleOperator.Name). - SubResource("status"). - Body(exampleOperator). - Do(). - Into(result) - return -} - -// Delete takes name of the exampleOperator and deletes it. Returns an error if one occurs. -func (c *exampleOperators) Delete(name string, options *v1.DeleteOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("exampleoperators"). - Name(name). - Body(options). - Do(). - Error() -} - -// DeleteCollection deletes a collection of objects. -func (c *exampleOperators) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - return c.client.Delete(). - Namespace(c.ns). - Resource("exampleoperators"). - VersionedParams(&listOptions, scheme.ParameterCodec). - Body(options). - Do(). - Error() -} - -// Patch applies the patch and returns the patched exampleOperator. -func (c *exampleOperators) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ExampleOperator, err error) { - result = &v1alpha1.ExampleOperator{} - err = c.client.Patch(pt). - Namespace(c.ns). - Resource("exampleoperators"). - SubResource(subresources...). - Name(name). - Body(data). - Do(). - Into(result) - return -} diff --git a/pkg/generated/clientset/versioned/typed/example/v1alpha1/fake/fake_example_client.go b/pkg/generated/clientset/versioned/typed/example/v1alpha1/fake/fake_example_client.go deleted file mode 100644 index 3bf4045..0000000 --- a/pkg/generated/clientset/versioned/typed/example/v1alpha1/fake/fake_example_client.go +++ /dev/null @@ -1,24 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1alpha1 "github.com/enj/example-operator/pkg/generated/clientset/versioned/typed/example/v1alpha1" - rest "k8s.io/client-go/rest" - testing "k8s.io/client-go/testing" -) - -type FakeExampleoperatorV1alpha1 struct { - *testing.Fake -} - -func (c *FakeExampleoperatorV1alpha1) ExampleOperators(namespace string) v1alpha1.ExampleOperatorInterface { - return &FakeExampleOperators{c, namespace} -} - -// RESTClient returns a RESTClient that is used to communicate -// with API server by this client implementation. -func (c *FakeExampleoperatorV1alpha1) RESTClient() rest.Interface { - var ret *rest.RESTClient - return ret -} diff --git a/pkg/generated/clientset/versioned/typed/example/v1alpha1/fake/fake_exampleoperator.go b/pkg/generated/clientset/versioned/typed/example/v1alpha1/fake/fake_exampleoperator.go deleted file mode 100644 index 797240c..0000000 --- a/pkg/generated/clientset/versioned/typed/example/v1alpha1/fake/fake_exampleoperator.go +++ /dev/null @@ -1,124 +0,0 @@ -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - v1alpha1 "github.com/enj/example-operator/pkg/apis/example/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - schema "k8s.io/apimachinery/pkg/runtime/schema" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" -) - -// FakeExampleOperators implements ExampleOperatorInterface -type FakeExampleOperators struct { - Fake *FakeExampleoperatorV1alpha1 - ns string -} - -var exampleoperatorsResource = schema.GroupVersionResource{Group: "exampleoperator.crd.monis.app", Version: "v1alpha1", Resource: "exampleoperators"} - -var exampleoperatorsKind = schema.GroupVersionKind{Group: "exampleoperator.crd.monis.app", Version: "v1alpha1", Kind: "ExampleOperator"} - -// Get takes name of the exampleOperator, and returns the corresponding exampleOperator object, and an error if there is any. -func (c *FakeExampleOperators) Get(name string, options v1.GetOptions) (result *v1alpha1.ExampleOperator, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(exampleoperatorsResource, c.ns, name), &v1alpha1.ExampleOperator{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.ExampleOperator), err -} - -// List takes label and field selectors, and returns the list of ExampleOperators that match those selectors. -func (c *FakeExampleOperators) List(opts v1.ListOptions) (result *v1alpha1.ExampleOperatorList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(exampleoperatorsResource, exampleoperatorsKind, c.ns, opts), &v1alpha1.ExampleOperatorList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.ExampleOperatorList{ListMeta: obj.(*v1alpha1.ExampleOperatorList).ListMeta} - for _, item := range obj.(*v1alpha1.ExampleOperatorList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested exampleOperators. -func (c *FakeExampleOperators) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(exampleoperatorsResource, c.ns, opts)) - -} - -// Create takes the representation of a exampleOperator and creates it. Returns the server's representation of the exampleOperator, and an error, if there is any. -func (c *FakeExampleOperators) Create(exampleOperator *v1alpha1.ExampleOperator) (result *v1alpha1.ExampleOperator, err error) { - obj, err := c.Fake. - Invokes(testing.NewCreateAction(exampleoperatorsResource, c.ns, exampleOperator), &v1alpha1.ExampleOperator{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.ExampleOperator), err -} - -// Update takes the representation of a exampleOperator and updates it. Returns the server's representation of the exampleOperator, and an error, if there is any. -func (c *FakeExampleOperators) Update(exampleOperator *v1alpha1.ExampleOperator) (result *v1alpha1.ExampleOperator, err error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateAction(exampleoperatorsResource, c.ns, exampleOperator), &v1alpha1.ExampleOperator{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.ExampleOperator), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeExampleOperators) UpdateStatus(exampleOperator *v1alpha1.ExampleOperator) (*v1alpha1.ExampleOperator, error) { - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(exampleoperatorsResource, "status", c.ns, exampleOperator), &v1alpha1.ExampleOperator{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.ExampleOperator), err -} - -// Delete takes name of the exampleOperator and deletes it. Returns an error if one occurs. -func (c *FakeExampleOperators) Delete(name string, options *v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteAction(exampleoperatorsResource, c.ns, name), &v1alpha1.ExampleOperator{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeExampleOperators) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(exampleoperatorsResource, c.ns, listOptions) - - _, err := c.Fake.Invokes(action, &v1alpha1.ExampleOperatorList{}) - return err -} - -// Patch applies the patch and returns the patched exampleOperator. -func (c *FakeExampleOperators) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.ExampleOperator, err error) { - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(exampleoperatorsResource, c.ns, name, data, subresources...), &v1alpha1.ExampleOperator{}) - - if obj == nil { - return nil, err - } - return obj.(*v1alpha1.ExampleOperator), err -} diff --git a/pkg/generated/informers/externalversions/example/interface.go b/pkg/generated/informers/externalversions/console/interface.go similarity index 77% rename from pkg/generated/informers/externalversions/example/interface.go rename to pkg/generated/informers/externalversions/console/interface.go index 44207d6..40d7627 100644 --- a/pkg/generated/informers/externalversions/example/interface.go +++ b/pkg/generated/informers/externalversions/console/interface.go @@ -1,10 +1,10 @@ // Code generated by informer-gen. DO NOT EDIT. -package exampleoperator +package console import ( - v1alpha1 "github.com/enj/example-operator/pkg/generated/informers/externalversions/example/v1alpha1" - internalinterfaces "github.com/enj/example-operator/pkg/generated/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/openshift/console-operator/pkg/generated/informers/externalversions/console/v1alpha1" + internalinterfaces "github.com/openshift/console-operator/pkg/generated/informers/externalversions/internalinterfaces" ) // Interface provides access to each of this group's versions. diff --git a/pkg/generated/informers/externalversions/console/v1alpha1/console.go b/pkg/generated/informers/externalversions/console/v1alpha1/console.go new file mode 100644 index 0000000..afac47f --- /dev/null +++ b/pkg/generated/informers/externalversions/console/v1alpha1/console.go @@ -0,0 +1,73 @@ +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + console_v1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + versioned "github.com/openshift/console-operator/pkg/generated/clientset/versioned" + internalinterfaces "github.com/openshift/console-operator/pkg/generated/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/openshift/console-operator/pkg/generated/listers/console/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ConsoleInformer provides access to a shared informer and lister for +// Consoles. +type ConsoleInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.ConsoleLister +} + +type consoleInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewConsoleInformer constructs a new informer for Console type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewConsoleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredConsoleInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredConsoleInformer constructs a new informer for Console type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredConsoleInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConsoleV1alpha1().Consoles(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConsoleV1alpha1().Consoles(namespace).Watch(options) + }, + }, + &console_v1alpha1.Console{}, + resyncPeriod, + indexers, + ) +} + +func (f *consoleInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredConsoleInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *consoleInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&console_v1alpha1.Console{}, f.defaultInformer) +} + +func (f *consoleInformer) Lister() v1alpha1.ConsoleLister { + return v1alpha1.NewConsoleLister(f.Informer().GetIndexer()) +} diff --git a/pkg/generated/informers/externalversions/example/v1alpha1/interface.go b/pkg/generated/informers/externalversions/console/v1alpha1/interface.go similarity index 57% rename from pkg/generated/informers/externalversions/example/v1alpha1/interface.go rename to pkg/generated/informers/externalversions/console/v1alpha1/interface.go index ecb07b5..c663280 100644 --- a/pkg/generated/informers/externalversions/example/v1alpha1/interface.go +++ b/pkg/generated/informers/externalversions/console/v1alpha1/interface.go @@ -3,13 +3,13 @@ package v1alpha1 import ( - internalinterfaces "github.com/enj/example-operator/pkg/generated/informers/externalversions/internalinterfaces" + internalinterfaces "github.com/openshift/console-operator/pkg/generated/informers/externalversions/internalinterfaces" ) // Interface provides access to all the informers in this group version. type Interface interface { - // ExampleOperators returns a ExampleOperatorInformer. - ExampleOperators() ExampleOperatorInformer + // Consoles returns a ConsoleInformer. + Consoles() ConsoleInformer } type version struct { @@ -23,7 +23,7 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } -// ExampleOperators returns a ExampleOperatorInformer. -func (v *version) ExampleOperators() ExampleOperatorInformer { - return &exampleOperatorInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +// Consoles returns a ConsoleInformer. +func (v *version) Consoles() ConsoleInformer { + return &consoleInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } diff --git a/pkg/generated/informers/externalversions/example/v1alpha1/exampleoperator.go b/pkg/generated/informers/externalversions/example/v1alpha1/exampleoperator.go deleted file mode 100644 index 7aa66c6..0000000 --- a/pkg/generated/informers/externalversions/example/v1alpha1/exampleoperator.go +++ /dev/null @@ -1,73 +0,0 @@ -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - time "time" - - example_v1alpha1 "github.com/enj/example-operator/pkg/apis/example/v1alpha1" - versioned "github.com/enj/example-operator/pkg/generated/clientset/versioned" - internalinterfaces "github.com/enj/example-operator/pkg/generated/informers/externalversions/internalinterfaces" - v1alpha1 "github.com/enj/example-operator/pkg/generated/listers/example/v1alpha1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" -) - -// ExampleOperatorInformer provides access to a shared informer and lister for -// ExampleOperators. -type ExampleOperatorInformer interface { - Informer() cache.SharedIndexInformer - Lister() v1alpha1.ExampleOperatorLister -} - -type exampleOperatorInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewExampleOperatorInformer constructs a new informer for ExampleOperator type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewExampleOperatorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredExampleOperatorInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredExampleOperatorInformer constructs a new informer for ExampleOperator type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredExampleOperatorInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ExampleoperatorV1alpha1().ExampleOperators(namespace).List(options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.ExampleoperatorV1alpha1().ExampleOperators(namespace).Watch(options) - }, - }, - &example_v1alpha1.ExampleOperator{}, - resyncPeriod, - indexers, - ) -} - -func (f *exampleOperatorInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredExampleOperatorInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *exampleOperatorInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&example_v1alpha1.ExampleOperator{}, f.defaultInformer) -} - -func (f *exampleOperatorInformer) Lister() v1alpha1.ExampleOperatorLister { - return v1alpha1.NewExampleOperatorLister(f.Informer().GetIndexer()) -} diff --git a/pkg/generated/informers/externalversions/factory.go b/pkg/generated/informers/externalversions/factory.go index 905347e..19f2774 100644 --- a/pkg/generated/informers/externalversions/factory.go +++ b/pkg/generated/informers/externalversions/factory.go @@ -7,9 +7,9 @@ import ( sync "sync" time "time" - versioned "github.com/enj/example-operator/pkg/generated/clientset/versioned" - example "github.com/enj/example-operator/pkg/generated/informers/externalversions/example" - internalinterfaces "github.com/enj/example-operator/pkg/generated/informers/externalversions/internalinterfaces" + versioned "github.com/openshift/console-operator/pkg/generated/clientset/versioned" + console "github.com/openshift/console-operator/pkg/generated/informers/externalversions/console" + internalinterfaces "github.com/openshift/console-operator/pkg/generated/informers/externalversions/internalinterfaces" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" @@ -156,9 +156,9 @@ type SharedInformerFactory interface { ForResource(resource schema.GroupVersionResource) (GenericInformer, error) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool - Exampleoperator() example.Interface + Console() console.Interface } -func (f *sharedInformerFactory) Exampleoperator() example.Interface { - return example.New(f, f.namespace, f.tweakListOptions) +func (f *sharedInformerFactory) Console() console.Interface { + return console.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go index 649e87f..fad1a03 100644 --- a/pkg/generated/informers/externalversions/generic.go +++ b/pkg/generated/informers/externalversions/generic.go @@ -5,7 +5,7 @@ package externalversions import ( "fmt" - v1alpha1 "github.com/enj/example-operator/pkg/apis/example/v1alpha1" + v1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) @@ -36,9 +36,9 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=exampleoperator.crd.monis.app, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("exampleoperators"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Exampleoperator().V1alpha1().ExampleOperators().Informer()}, nil + // Group=console.openshift.io, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("consoles"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Console().V1alpha1().Consoles().Informer()}, nil } diff --git a/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go b/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go index 3ea1ad6..8585515 100644 --- a/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go +++ b/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -5,7 +5,7 @@ package internalinterfaces import ( time "time" - versioned "github.com/enj/example-operator/pkg/generated/clientset/versioned" + versioned "github.com/openshift/console-operator/pkg/generated/clientset/versioned" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" cache "k8s.io/client-go/tools/cache" diff --git a/pkg/generated/listers/console/v1alpha1/console.go b/pkg/generated/listers/console/v1alpha1/console.go new file mode 100644 index 0000000..b82b1f8 --- /dev/null +++ b/pkg/generated/listers/console/v1alpha1/console.go @@ -0,0 +1,78 @@ +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/openshift/console-operator/pkg/apis/console/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// ConsoleLister helps list Consoles. +type ConsoleLister interface { + // List lists all Consoles in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.Console, err error) + // Consoles returns an object that can list and get Consoles. + Consoles(namespace string) ConsoleNamespaceLister + ConsoleListerExpansion +} + +// consoleLister implements the ConsoleLister interface. +type consoleLister struct { + indexer cache.Indexer +} + +// NewConsoleLister returns a new ConsoleLister. +func NewConsoleLister(indexer cache.Indexer) ConsoleLister { + return &consoleLister{indexer: indexer} +} + +// List lists all Consoles in the indexer. +func (s *consoleLister) List(selector labels.Selector) (ret []*v1alpha1.Console, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Console)) + }) + return ret, err +} + +// Consoles returns an object that can list and get Consoles. +func (s *consoleLister) Consoles(namespace string) ConsoleNamespaceLister { + return consoleNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// ConsoleNamespaceLister helps list and get Consoles. +type ConsoleNamespaceLister interface { + // List lists all Consoles in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.Console, err error) + // Get retrieves the Console from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.Console, error) + ConsoleNamespaceListerExpansion +} + +// consoleNamespaceLister implements the ConsoleNamespaceLister +// interface. +type consoleNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Consoles in the indexer for a given namespace. +func (s consoleNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Console, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Console)) + }) + return ret, err +} + +// Get retrieves the Console from the indexer for a given namespace and name. +func (s consoleNamespaceLister) Get(name string) (*v1alpha1.Console, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("console"), name) + } + return obj.(*v1alpha1.Console), nil +} diff --git a/pkg/generated/listers/console/v1alpha1/expansion_generated.go b/pkg/generated/listers/console/v1alpha1/expansion_generated.go new file mode 100644 index 0000000..01fda3c --- /dev/null +++ b/pkg/generated/listers/console/v1alpha1/expansion_generated.go @@ -0,0 +1,11 @@ +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// ConsoleListerExpansion allows custom methods to be added to +// ConsoleLister. +type ConsoleListerExpansion interface{} + +// ConsoleNamespaceListerExpansion allows custom methods to be added to +// ConsoleNamespaceLister. +type ConsoleNamespaceListerExpansion interface{} diff --git a/pkg/generated/listers/example/v1alpha1/exampleoperator.go b/pkg/generated/listers/example/v1alpha1/exampleoperator.go deleted file mode 100644 index be471f4..0000000 --- a/pkg/generated/listers/example/v1alpha1/exampleoperator.go +++ /dev/null @@ -1,78 +0,0 @@ -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - v1alpha1 "github.com/enj/example-operator/pkg/apis/example/v1alpha1" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/tools/cache" -) - -// ExampleOperatorLister helps list ExampleOperators. -type ExampleOperatorLister interface { - // List lists all ExampleOperators in the indexer. - List(selector labels.Selector) (ret []*v1alpha1.ExampleOperator, err error) - // ExampleOperators returns an object that can list and get ExampleOperators. - ExampleOperators(namespace string) ExampleOperatorNamespaceLister - ExampleOperatorListerExpansion -} - -// exampleOperatorLister implements the ExampleOperatorLister interface. -type exampleOperatorLister struct { - indexer cache.Indexer -} - -// NewExampleOperatorLister returns a new ExampleOperatorLister. -func NewExampleOperatorLister(indexer cache.Indexer) ExampleOperatorLister { - return &exampleOperatorLister{indexer: indexer} -} - -// List lists all ExampleOperators in the indexer. -func (s *exampleOperatorLister) List(selector labels.Selector) (ret []*v1alpha1.ExampleOperator, err error) { - err = cache.ListAll(s.indexer, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ExampleOperator)) - }) - return ret, err -} - -// ExampleOperators returns an object that can list and get ExampleOperators. -func (s *exampleOperatorLister) ExampleOperators(namespace string) ExampleOperatorNamespaceLister { - return exampleOperatorNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// ExampleOperatorNamespaceLister helps list and get ExampleOperators. -type ExampleOperatorNamespaceLister interface { - // List lists all ExampleOperators in the indexer for a given namespace. - List(selector labels.Selector) (ret []*v1alpha1.ExampleOperator, err error) - // Get retrieves the ExampleOperator from the indexer for a given namespace and name. - Get(name string) (*v1alpha1.ExampleOperator, error) - ExampleOperatorNamespaceListerExpansion -} - -// exampleOperatorNamespaceLister implements the ExampleOperatorNamespaceLister -// interface. -type exampleOperatorNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all ExampleOperators in the indexer for a given namespace. -func (s exampleOperatorNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ExampleOperator, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ExampleOperator)) - }) - return ret, err -} - -// Get retrieves the ExampleOperator from the indexer for a given namespace and name. -func (s exampleOperatorNamespaceLister) Get(name string) (*v1alpha1.ExampleOperator, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) - if err != nil { - return nil, err - } - if !exists { - return nil, errors.NewNotFound(v1alpha1.Resource("exampleoperator"), name) - } - return obj.(*v1alpha1.ExampleOperator), nil -} diff --git a/pkg/generated/listers/example/v1alpha1/expansion_generated.go b/pkg/generated/listers/example/v1alpha1/expansion_generated.go deleted file mode 100644 index 518afa8..0000000 --- a/pkg/generated/listers/example/v1alpha1/expansion_generated.go +++ /dev/null @@ -1,11 +0,0 @@ -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -// ExampleOperatorListerExpansion allows custom methods to be added to -// ExampleOperatorLister. -type ExampleOperatorListerExpansion interface{} - -// ExampleOperatorNamespaceListerExpansion allows custom methods to be added to -// ExampleOperatorNamespaceLister. -type ExampleOperatorNamespaceListerExpansion interface{}