diff --git a/DEVELOPING.adoc b/DEVELOPING.adoc index c92f9c5b..6134cb17 100644 --- a/DEVELOPING.adoc +++ b/DEVELOPING.adoc @@ -44,9 +44,9 @@ If, however, a developer needs to make changes to the operator, because the Kial The link:https://github.com/kiali/kiali[Kiali git repo] has a link:https://github.com/kiali/kiali/blob/master/Makefile[Makefile] and a set of link:https://github.com/kiali/kiali/blob/master/make[Makefile targets] that are used in conjunction with the Kiali Operator so you can install and run the operator built from your local git clones. They use the Kiali Operator helm chart to install the operator, so you must link:https://github.com/kiali/kiali#building[clone the helm-chart git repo in the proper place as well]. -To install the operator that contains your local changes, run `make operator-create`. If you are using minikube, you will need to set the environment variable `CLUSTER_TYPE=minikube` and you need to also set `MINIKUBE_PROFILE` if your minikube profile name is not `minikube`. At this point you can create your own Kiali CR to trigger the operator to install Kiali, or use `make kiali-create` to install a sample Kiali CR for you. +To install the operator that contains your local changes, run `make operator-create`. If you are using minikube, you will need to set the environment variable `CLUSTER_TYPE=minikube` and you need to also set `MINIKUBE_PROFILE` if your minikube profile name is not `minikube`. At this point you can create your own Kiali CR to trigger the operator to install Kiali, or use `make kiali-create` to install a sample Kiali CR for you. Similarly, `make ossmconsole-create` will create an OSSMConsole CR to install the OSSMC OpenShift Console plugin. -To remove the operator (and the Kiali CR that may have also been created), run `make operator-delete`. +To remove the operator (and any CRs that may have also been created), run `make operator-delete`. ### Installing the Operator in a Cluster Using OLM @@ -56,17 +56,17 @@ If you do not have OLM installed, you can easily install it. First determine wha Once OLM is installed, you can install the Kiali Operator (and all the required resources such as the OLM catalog source and subscription) via `make olm-operator-create`. -Once the operator is running, you can install a Kiali CR normally. One way to do this is to first create a kiali-operator namespace and run the `kiali-create` make target: `kubectl create ns kiali-operator && make kiali-create`. +Once the operator is running, you can install a Kiali CR normally. One way to do this is to first create a kiali-operator namespace and run the `kiali-create` make target: `kubectl create ns kiali-operator && make kiali-create`. Similarly with the `ossmconsole-create` target for installing OSSMC. -To remove the Kiali operator and all the other OLM resources that came with it (including the Kiali CR if you created one via the `kiali-create` target), run `make olm-operator-delete`. +To remove the Kiali operator and all the other OLM resources that came with it (including the CRs if you created some via the `kiali-create` target or the `ossmconsole-create` target), run `make olm-operator-delete`. -NOTE: By default, you will test with the latest version of the metadata. You can specify a different version by setting the `BUNDLE_VERSION` env var on the make command line. If the OC env var points to an `oc` binary, the metadata from the kiali-community will be used; otherwise, the metadata from the kiali-upstream will be used. If you instead want to test with the OSSM metadata, set the env var `OLM_BUNDLE_PACKAGE` to `kiali-ossm` on the make command line. +NOTE: By default, you will test with the latest version of the "kiali-ossm" metadata. You can specify a different version by setting the `BUNDLE_VERSION` env var on the make command line. If the OC env var points to an `oc` binary, the metadata from the kiali-community will be used; otherwise, the metadata from the kiali-upstream will be used. If you want to do this, you also must set the env var `OLM_BUNDLE_PACKAGE` to `kiali` on the make command line. ### Running the Operator Playbook Without Installing in a Cluster -Sometimes you made simple changes to the operator playbook and roles that can be quickly tested by running the Ansible playbook on your local machine. This saves time because it doesn't require you to install the operator directly in your cluster. To do this, you must have Ansible installed (e.g. `ansible-playbook` must be in your $PATH). You can run the operator playbook via `make run-operator-playbook`. This will run both the kiali-deploy and kiali-remove playbooks so the operator will install and then immediately uninstall a Kiali Server. The operator playbook is configured via the files found in the link:dev-playbook-config[dev-playbook-config directory]. +Sometimes you made simple changes to the operator playbook and roles that can be quickly tested by running the Ansible playbook on your local machine. This saves time because it doesn't require you to install the operator directly in your cluster. To do this, you must have Ansible installed (e.g. `ansible-playbook` must be in your $PATH). You can run the operator playbook via `make run-operator-playbook-kiali` (to test the Kiali playbooks) or `make run-operator-playbook-ossmconsole` (to test the OSSMC playbooks). `run-operator-playbook-kiali` will run both the kiali-deploy and kiali-remove playbooks so the operator will install and then immediately uninstall a Kiali Server. `run-operator-playbook-ossmconsole` will run both the ossmconsole-deploy and ossmconsole-remove playbooks so the operator will install and then immediately uninstall a OSSMC plugin. The operator playbooks are configured via the files found in the link:dev-playbook-config[dev-playbook-config directory]. -In order to use this `run-operator-playbook` target, you must have Python3 in your PATH (having an alias is not enough). +In order to use these "run-operator-playbook" targets, you must have Python3 in your PATH (having an alias is not enough). You also must make sure your local Python and Ansible environment matches as closely as possible to the environment of the Kiali operator. To find out the different versions of software within the Kiali operator image, run the following: @@ -84,7 +84,7 @@ To install these, run `ansible-galaxy collection install -r operator/requirement ### Running the Operator Without Installing in a Cluster -The previous section tells you how to run the Ansible playbook directly on your local machine. If you want to run the actual operator on your local machine in the same manner in which it runs inside the cluster (that is, within the `ansible-operator` shell process) then use the `make run-operator` make target. This will run the ansible-operator executable and point it to the operator's Ansible playbooks and roles. This operator will watch for Kiali CRs in the cluster - when it sees one, it will process it just as if it was running in the cluster. This will allow you to test the Ansible operator infrastructure as well as the operator's Ansible playbooks themselves. +The previous section tells you how to run the Ansible playbook directly on your local machine. If you want to run the actual operator on your local machine in the same manner in which it runs inside the cluster (that is, within the `ansible-operator` shell process) then use the `make run-operator` make target. This will run the ansible-operator executable and point it to the operator's Ansible playbooks and roles. This operator will watch for Kiali CRs and OSSMConsole CRs in the cluster - when it sees one, it will process it just as if it was running in the cluster. This will allow you to test the Ansible operator infrastructure as well as the operator's Ansible playbooks themselves. ### Running the Operator With the Ansible Profiler diff --git a/Makefile b/Makefile index 28eaf033..5a8e3a97 100644 --- a/Makefile +++ b/Makefile @@ -95,12 +95,21 @@ validate: .ensure-operator-sdk-exists ## validate-cr: Ensures the example CR is valid according to the CRD schema validate-cr: + @printf "\n========== Validating the Kiali CR ==========\n" ${ROOTDIR}/crd-docs/bin/validate-kiali-cr.sh --kiali-cr-file ${ROOTDIR}/crd-docs/cr/kiali.io_v1alpha1_kiali.yaml + @printf "\n========== Validating the OSSMConsole CR ==========\n" + ${ROOTDIR}/crd-docs/bin/validate-ossmconsole-cr.sh --cr-file ${ROOTDIR}/crd-docs/cr/kiali.io_v1alpha1_ossmconsole.yaml -## gen-crd-doc: Generates documentation for the Kiali CR configuration -gen-crd-doc: +.gen-crd-doc-kiali: mkdir -p ${OUTDIR}/crd-docs - ${DORP} run -v ${OUTDIR}/crd-docs:/opt/crd-docs-generator/output -v ${ROOTDIR}/crd-docs/config:/opt/crd-docs-generator/config quay.io/giantswarm/crd-docs-generator:0.9.0 --config /opt/crd-docs-generator/config/apigen-config.yaml + ${DORP} run -v ${OUTDIR}/crd-docs:/opt/crd-docs-generator/output:z -v ${ROOTDIR}/crd-docs/config/kiali:/opt/crd-docs-generator/config:z quay.io/giantswarm/crd-docs-generator:0.9.0 --config /opt/crd-docs-generator/config/apigen-config.yaml + +.gen-crd-doc-ossmconsole: + mkdir -p ${OUTDIR}/crd-docs + ${DORP} run -v ${OUTDIR}/crd-docs:/opt/crd-docs-generator/output:z -v ${ROOTDIR}/crd-docs/config/ossmconsole:/opt/crd-docs-generator/config:z quay.io/giantswarm/crd-docs-generator:0.9.0 --config /opt/crd-docs-generator/config/apigen-config.yaml + +## gen-crd-doc: Generates documentation for the Kiali CR and OSSMConsole CR configuration +gen-crd-doc: .gen-crd-doc-kiali .gen-crd-doc-ossmconsole # Ensure "docker buildx" is available and enabled. For more details, see: https://github.com/docker/buildx/blob/master/README.md # This does a few things: diff --git a/crd-docs/bin/validate-ossmconsole-cr.sh b/crd-docs/bin/validate-ossmconsole-cr.sh new file mode 100755 index 00000000..cc1d9bd0 --- /dev/null +++ b/crd-docs/bin/validate-ossmconsole-cr.sh @@ -0,0 +1,182 @@ +#!/bin/bash + +############################################################################## +# validate-ossmconsole-cr.sh +# +# This script can be used to validate an OSSMConsole CR. +# +# To use this script, you must: +# * Have "oc" or "kubectl" +# * Be connected to a cluster +# * Have cluster-admin rights +# +############################################################################## + +set -u + +crd() { + local crd_file="" + + # if not specified, use the default location; otherwise, it is either a file or a URL + if [ -z "${OSSMCONSOLE_CRD_LOCATION:-}" ]; then + local script_root="$(cd "$(dirname "$0")" ; pwd -P)" + crd_file="${script_root}/../crd/kiali.io_ossmconsoles.yaml" + elif [ -f "${OSSMCONSOLE_CRD_LOCATION}" ]; then + crd_file="${OSSMCONSOLE_CRD_LOCATION}" + fi + ([ -n "${crd_file}" ] && cat "${crd_file}" || curl -sL "${OSSMCONSOLE_CRD_LOCATION}") | sed 's/ name: ossmconsoles.kiali.io/ name: testossmconsoles.kiali.io/g' | sed 's/ kind: OSSMConsole/ kind: TestOSSMConsole/g' | sed 's/ listKind: OSSMConsoleList/ listKind: TestOSSMConsoleList/g' | sed 's/ plural: ossmconsoles/ plural: testossmconsoles/g' | sed 's/ singular: ossmconsole/ singular: testossmconsole/g' +} + +# process command line args to override environment +_CMD="" +while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -ce|--client-exe) CLIENT_EXE="$2" ; shift;shift ;; + -crd|--crd-location) OSSMCONSOLE_CRD_LOCATION="$2" ; shift;shift ;; + -cf|--cr-file) OSSMCONSOLE_CR_FILE="$2" ; shift;shift ;; + -cn|--cr-name) OSSMCONSOLE_CR_NAME="$2" ; shift;shift ;; + -n|--namespace) NAMESPACE="$2" ; shift;shift ;; + -pc|--print-crd) PRINT_CRD="$2" ; shift;shift ;; + -h|--help) + cat </dev/null; then + CLIENT_EXE="$(which oc)" + echo "Using 'oc' located here: ${CLIENT_EXE}" + else + if which kubectl &>/dev/null; then + CLIENT_EXE="$(which kubectl)" + echo "Using 'kubectl' located here: ${CLIENT_EXE}" + else + echo "ERROR! You do not have 'oc' or 'kubectl' in your PATH. Please install it and retry." + exit 1 + fi + fi +else + echo "Client executable: ${CLIENT_EXE}" +fi + +if [ -z "${OSSMCONSOLE_CR_FILE:-}" -a -z "${OSSMCONSOLE_CR_NAME:-}" ]; then + echo "ERROR! You must specify one of either --cr-file or --cr-name" + exit 1 +fi + +if [ -n "${OSSMCONSOLE_CR_FILE:-}" -a -n "${OSSMCONSOLE_CR_NAME:-}" ]; then + echo "ERROR! You must specify only one of either --cr-file or --cr-name" + exit 1 +fi + +if [ -n "${OSSMCONSOLE_CR_FILE:-}" -a ! -f "${OSSMCONSOLE_CR_FILE:-}" ]; then + echo "ERROR! OSSMConsole CR file is not found: [${OSSMCONSOLE_CR_FILE:-}]" + exit 1 +fi + +if [ -n "${OSSMCONSOLE_CR_NAME:-}" ]; then + if ! ${CLIENT_EXE} get -n "${NAMESPACE}" ossmconsole "${OSSMCONSOLE_CR_NAME}" &> /dev/null; then + echo "ERROR! OSSMConsole CR [${OSSMCONSOLE_CR_NAME}] does not exist in namespace [${NAMESPACE}]" + exit 1 + fi +fi + +# Make sure we have admin rights to some cluster +if ! ${CLIENT_EXE} get namespaces &> /dev/null ; then + echo "ERROR! You must be connected to/logged into a cluster" + exit 1 +fi +if [ "$(${CLIENT_EXE} auth can-i create crd --all-namespaces)" != "yes" ]; then + echo "ERROR! You must have cluster-admin permissions" + exit 1 +fi + +# install the test CRD with the schema +if ! echo "$(crd)" | ${CLIENT_EXE} apply --validate=true --wait=true -f - &> /dev/null ; then + echo "ERROR! Failed to install the test CRD" + exit 1 +fi + +# wait for the test CRD to be established and then give k8s a few more seconds. +# if we don't do this, the validation test may report a false negative. +if ! ${CLIENT_EXE} wait --for condition=established --timeout=60s crd/testossmconsoles.kiali.io &> /dev/null ; then + echo "WARNING! Test CRD is not established yet. The validation test may not produce accurate results." +else + for s in 3 2 1; do echo -n "." ; sleep 1 ; done + echo +fi + +# validate the CR by creating a test version of it +echo "Validating the CR:" +echo "----------" +if [ -n "${OSSMCONSOLE_CR_FILE:-}" ]; then + if ! cat "${OSSMCONSOLE_CR_FILE}" | sed 's/kind: OSSMConsole/kind: TestOSSMConsole/g' | sed 's/- kiali.io\/finalizer//g' | kubectl apply -n ${NAMESPACE} -f - ; then + echo "----------" + echo "ERROR! Validation failed for OSSMConsole CR [${OSSMCONSOLE_CR_FILE}]" + exit 1 + else + echo "----------" + echo "OSSMConsole CR [${OSSMCONSOLE_CR_FILE}] is valid." + fi +else + if ! ${CLIENT_EXE} get -n "${NAMESPACE}" ossmconsole "${OSSMCONSOLE_CR_NAME}" -o yaml | sed 's/kind: OSSMConsole/kind: TestOSSMConsole/g' | sed 's/- kiali.io\/finalizer//g' | kubectl apply -n "${NAMESPACE}" -f - ; then + echo "----------" + echo "ERROR! Validation failed for OSSMConsole CR [${OSSMCONSOLE_CR_NAME}] in namespace [${NAMESPACE}]" + exit 1 + else + echo "----------" + echo "OSSMConsole CR [${OSSMCONSOLE_CR_NAME}] in namespace [${NAMESPACE}] is valid." + fi +fi + +# delete the test CRD (which deletes the test CR along with it) +if ! echo "$(crd)" | ${CLIENT_EXE} delete --wait=true -f - &> /dev/null ; then + echo "ERROR! Failed to delete the test CRD. You should remove it manually." + exit 1 +fi diff --git a/crd-docs/config/apigen-config.yaml b/crd-docs/config/kiali/apigen-config.yaml similarity index 100% rename from crd-docs/config/apigen-config.yaml rename to crd-docs/config/kiali/apigen-config.yaml diff --git a/crd-docs/config/apigen-crd.template b/crd-docs/config/kiali/apigen-crd.template similarity index 100% rename from crd-docs/config/apigen-crd.template rename to crd-docs/config/kiali/apigen-crd.template diff --git a/crd-docs/config/ossmconsole/apigen-config.yaml b/crd-docs/config/ossmconsole/apigen-config.yaml new file mode 100644 index 00000000..fbcf19ad --- /dev/null +++ b/crd-docs/config/ossmconsole/apigen-config.yaml @@ -0,0 +1,15 @@ +template_path: ./apigen-crd.template + +source_repositories: +- url: https://github.com/kiali/kiali-operator + organization: kiali + short_name: kiali-operator + commit_reference: master + crd_paths: + - crd-docs/crd + cr_paths: + - crd-docs/cr + metadata: + ossmconsoles.kiali.io: + owner: + - https://github.com/orgs/kiali/teams/maintainers diff --git a/crd-docs/config/ossmconsole/apigen-crd.template b/crd-docs/config/ossmconsole/apigen-crd.template new file mode 100644 index 00000000..7b8a010d --- /dev/null +++ b/crd-docs/config/ossmconsole/apigen-crd.template @@ -0,0 +1,99 @@ +--- +title: {{ .Title }} CR Reference +linkTitle: {{ .Title }} CR Reference +description: | +{{- if .Description }} +{{ .Description | indent 2 }} +{{- else }} + Reference page for the {{ .Title }} CR. + The Kiali Operator will watch for a resource of this type and install the OSSM Console plugin according to that resource's configuration. Only one resource of this type should exist at any one time. +{{- end }} +technical_name: {{ .NamePlural }}.{{ .Group }} +source_repository: {{ .SourceRepository }} +source_repository_ref: {{ .SourceRepositoryRef }} +--- + +{{ if .VersionSchemas }} +{{ range $versionName, $versionSchema := .VersionSchemas }} +
+ +{{with .ExampleCR}} +

Example CR

+(all values shown here are the defaults unless otherwise noted) + +```yaml +{{ .|raw -}} +``` +{{end}} + +### Validating your OSSMConsole CR + +A tool is available to allow you to check your own OSSMConsole CR to ensure it is valid. Simply download [the validation script](https://raw.githubusercontent.com/kiali/kiali-operator/master/crd-docs/bin/validate-ossmconsole-cr.sh) and run it, passing in the location of the OSSMConsole CRD you wish to validate with (e.g. the latest version is found [here](https://raw.githubusercontent.com/kiali/kiali-operator/master/crd-docs/crd/kiali.io_ossmconsoles.yaml)) and the location of your OSSMConsole CR. You must be connected to/logged into a cluster for this validation tool to work. + +For example, to validate an OSSMConsole CR named `ossmconsole` in the namespace `istio-system` using the latest version of the OSSMConsole CRD, run the following: +
+bash <(curl -sL https://raw.githubusercontent.com/kiali/kiali-operator/master/crd-docs/bin/validate-ossmconsole-cr.sh) \
+  -crd https://raw.githubusercontent.com/kiali/kiali-operator/master/crd-docs/crd/kiali.io_ossmconsoles.yaml \
+  --cr-name ossmconsole \
+  -n istio-system
+
+ +For additional help in using this validation tool, pass it the `--help` option. + +

Properties

+ +{{ range $versionSchema.Properties }} +
+
+
+

{{.Path}}

+
+
+
+{{with .Type}}({{.}}){{end}} +{{ if not .Required }} +{{ else -}} +*Required* +{{ end -}} +
+{{with .Description}} +
+{{.|markdown}} +
+{{end}} +
+
+{{ end }} + + +{{ if .Annotations }} +

Annotations

+ +{{ range $versionSchema.Annotations }} +
+
+

{{.Annotation}}

+
+
+
+{{with .Release}}{{.}}{{end}} +
+{{with .Documentation}} +
+{{.|markdown}} +
+{{end}} +
+
+{{ end }} +{{ end }} + +
+{{end}} + +{{ else }} +
+

We currently cannot show any schema information on this CRD. Sorry for the inconvenience!

+

Please refer to Kiali Documentation.

+
+{{ end }} diff --git a/crd-docs/cr/kiali.io_v1alpha1_ossmconsole.yaml b/crd-docs/cr/kiali.io_v1alpha1_ossmconsole.yaml new file mode 100644 index 00000000..678b7ec0 --- /dev/null +++ b/crd-docs/cr/kiali.io_v1alpha1_ossmconsole.yaml @@ -0,0 +1,24 @@ +apiVersion: kiali.io/v1alpha1 +kind: OSSMConsole +metadata: + name: ossmconsole + annotations: + ansible.sdk.operatorframework.io/verbosity: "1" +spec: + version: "default" + + deployment: + imageDigest: "" + imageName: "" + imagePullPolicy: "IfNotPresent" + # default: image_pull_secrets is an empty list + imagePullSecrets: ["image.pull.secret"] + imageVersion: "" + namespace: "" + + kiali: + graph: + impl: "pf" + serviceName: "" + serviceNamespace: "" + servicePort: 0 diff --git a/crd-docs/crd/kiali.io_kialis.yaml b/crd-docs/crd/kiali.io_kialis.yaml index 839c2729..4add24b6 100644 --- a/crd-docs/crd/kiali.io_kialis.yaml +++ b/crd-docs/crd/kiali.io_kialis.yaml @@ -68,7 +68,7 @@ spec: If not specified, a default version of Kiali will be installed which will be the most recent release of Kiali. Refer to this file to see where these values are defined in the master branch, - https://github.com/kiali/kiali-operator/tree/master/playbooks/default-supported-images.yml + https://github.com/kiali/kiali-operator/tree/master/playbooks/kiali-default-supported-images.yml This version setting affects the defaults of the deployment.image_name and deployment.image_version settings. See the comments for those settings diff --git a/crd-docs/crd/kiali.io_ossmconsoles.yaml b/crd-docs/crd/kiali.io_ossmconsoles.yaml new file mode 100644 index 00000000..e7e0e914 --- /dev/null +++ b/crd-docs/crd/kiali.io_ossmconsoles.yaml @@ -0,0 +1,102 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ossmconsoles.kiali.io +spec: + group: kiali.io + names: + kind: OSSMConsole + listKind: OSSMConsoleList + plural: ossmconsoles + singular: ossmconsole + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + subresources: + status: {} + schema: + openAPIV3Schema: + type: object + properties: + status: + description: "The processing status of this CR as reported by the OpenShift Service Mesh Console Operator." + type: object + x-kubernetes-preserve-unknown-fields: true + spec: + description: "This is the CRD for the resources called OSSMConsole CRs. The OpenShift Service Mesh Console Operator will watch for resources of this type and when it detects an OSSMConsole CR has been added, deleted, or modified, it will install, uninstall, and update the associated OSSM Console installation." + type: object + properties: + version: + description: | + The version of the Ansible playbook to execute in order to install that version of OSSM Console. + It is rare you will want to set this - if you are thinking of setting this, know what you are doing first. + The only supported value today is `default`. + If not specified, a default version of Kiali will be installed which will be the most recent release of Kiali. + Refer to this file to see where these values are defined in the master branch, + https://github.com/kiali/kiali-operator/tree/main/operator/playbooks/ossmconsole-default-supported-images.yml + This version setting affects the defaults of the deployment.imageName and + deployment.imageVersion settings. See the comments for those settings + below for additional details. But in short, this version setting will + dictate which version of the OSSM Console image will be deployed by default. + Note that if you explicitly set deployment.imageName and/or + deployment.imageVersion you are responsible for ensuring those settings + are compatible with this setting (i.e. the image must be compatible + with the rest of the configuration and resources the operator will install). + type: string + deployment: + type: object + properties: + imageDigest: + description: "If `deployment.imageVersion` is a digest hash, this value indicates what type of digest it is. A typical value would be 'sha256'. Note: do NOT prefix this value with a '@'." + type: string + imageName: + description: "Determines which OSSM Console image to download and install. If you set this to a specific name (i.e. you do not leave it as the default empty string), you must make sure that image is supported by the operator. If empty, the operator will use a known supported image name based on which `version` was defined. Note that, as a security measure, a cluster admin may have configured the OSSM Console operator to ignore this setting. A cluster admin may do this to ensure the OSSM Console operator only installs a single, specific OSSM Console version, thus this setting may have no effect depending on how the operator itself was configured." + type: string + imagePullPolicy: + description: "The Kubernetes pull policy for the OSSM Console deployment. This is overridden to be 'Always' if `deployment.imageVersion` is set to 'latest'." + type: string + imagePullSecrets: + description: "The names of the secrets to be used when container images are to be pulled." + type: array + items: + type: string + imageVersion: + description: | + Determines which version of OSSM Console to install. + Choose 'lastrelease' to use the last OSSM Console release. + Choose 'latest' to use the latest image (which may or may not be a released version of the OSSM Console). + Choose 'operator_version' to use the image whose version is the same as the operator version. + Otherwise, you can set this to any valid OSSM Console version (such as 'v1.0') or any valid OSSM Console + digest hash (if you set this to a digest hash, you must indicate the digest in `deployment.imageDigest`). + Note that if this is set to 'latest' then the `deployment.imagePullPolicy` will be set to 'Always'. + If you set this to a specific version (i.e. you do not leave it as the default empty string), + you must make sure that image is supported by the operator. + If empty, the operator will use a known supported image version based on which 'version' was defined. + Note that, as a security measure, a cluster admin may have configured the OSSM Console operator to + ignore this setting. A cluster admin may do this to ensure the OSSM Console operator only installs + a single, specific OSSM Console version, thus this setting may have no effect depending on how the + operator itself was configured. + type: string + namespace: + description: "The namespace into which OSSM Console is to be installed. If this is empty or not defined, the default will be the namespace where the OSSMConsole CR is located. Currently the only namespace supported is the namespace where the OSSMConsole CR is located." + type: string + kiali: + type: object + properties: + graph: + type: object + properties: + impl: + description: "The graph implementation used by OSSMC. Possible values are 'cy' (Cytoscape) and 'pf' (Patternfly). By default the patternfly graph is used." + type: string + serviceName: + description: "The internal Kiali service that the OpenShift Console will use to proxy API calls. If empty, an attempt will be made to auto-discover it from the Kiali OpenShift Route." + type: string + serviceNamespace: + description: "The namespace where the Kiali service is deployed. If empty, an attempt will be made to auto-discover it from the Kiali OpenShift Route. It will assume that the OpenShift Route and the Kiali service are deployed in the same namespace." + type: string + servicePort: + description: "The internal port used by the Kiali service for the API. If empty, an attempt will be made to auto-discover it from the Kiali OpenShift Route." + type: integer diff --git a/deploy/ossmconsole/ossmconsole_cr_dev.yaml b/deploy/ossmconsole/ossmconsole_cr_dev.yaml new file mode 100644 index 00000000..555985df --- /dev/null +++ b/deploy/ossmconsole/ossmconsole_cr_dev.yaml @@ -0,0 +1,20 @@ +apiVersion: kiali.io/v1alpha1 +kind: OSSMConsole +metadata: + name: ossmconsole + annotations: + ansible.sdk.operatorframework.io/verbosity: "1" +spec: + version: "default" + deployment: + imageName: ${DEPLOYMENT_IMAGE_NAME} + imageVersion: ${DEPLOYMENT_IMAGE_VERSION} + imagePullPolicy: "Always" + imagePullSecrets: + - ${PULL_SECRET_NAME} + kiali: + graph: + impl: "pf" + serviceName: "" + serviceNamespace: "" + servicePort: 0 diff --git a/dev-playbook-config/README.adoc b/dev-playbook-config/README.adoc index 71f1eab2..371fb7b0 100644 --- a/dev-playbook-config/README.adoc +++ b/dev-playbook-config/README.adoc @@ -1,7 +1,7 @@ -The files in this directory are used for the link:https://github.com/kiali/kiali/blob/master/make/Makefile.operator.mk[`make run-operator-playbook` target]. Configure these files to tell the operator playbook what to do when that target is executed. +The files in this directory are used for the link:https://github.com/kiali/kiali/blob/master/make/Makefile.operator.mk[`make run-operator-playbook-XXX` targets]. Configure these files to tell the operator playbook what to do when that target is executed. -* `dev-hosts.yaml` - the Ansible inventory file. This should contain variables that the operator SDK would normally set when triggering an operator reconciliation run. Note that most of the values here will be values that mimic the values in the Kiali CR. You typically will want to make sure the values in `dev-kiali-cr.yaml` match those in this `dev-hosts.yaml` file. +* `dev-hosts.yaml` - the Ansible inventory file. This should contain variables that the operator SDK would normally set when triggering an operator reconciliation run. Note that most of the values here will be values that mimic the values in the Kiali CR. You typically will want to make sure the values in `dev-cr.yaml` match those in this `dev-hosts.yaml` file. -* `dev-kiali-cr.yaml` - the "dummy" Kiali CR that will be created. This is needed because the operator will sometimes need to access the Kiali CR that is being reconciled, so one needs to be created in the cluster for the operator to run correctly. In particular, the operator will update the `status` field of the Kiali CR. +* `dev-cr.yaml` - the "dummy" CR that will be created (there is one for the Kiali CR and one for the OSSMConsole CR). This is needed because the operator will sometimes need to access the CR that is being reconciled, so one needs to be created in the cluster for the operator to run correctly. In particular, the operator will update the `status` field of the CR. -* `dev-playbook.yaml` - the main playbook that will be run. By default it will run the `kiali-deploy` playbook (which will install a Kiali server) and then immediately run the `kiali-remove` playbook (which will uninstall that Kiali server). You can comment out one or the other if you wish to test just one of those playbooks. +* `dev-playbook.yaml` - the main playbook that will be run. By default it will run the `kiali-deploy` playbook (or `ossmconsole-deploy`) (which will install a Kiali server or OSSMC plugin) and then immediately run the `kiali-remove` (or the `ossmconsole-remove`) playbook (which will uninstall that Kiali server or OSSMC plugin). You can comment out one or the other if you wish to test just one of those playbooks. diff --git a/dev-playbook-config/dev-playbook.yaml b/dev-playbook-config/dev-playbook.yaml deleted file mode 100644 index 5a824b53..00000000 --- a/dev-playbook-config/dev-playbook.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -- import_playbook: ../playbooks/kiali-deploy.yml -- import_playbook: ../playbooks/kiali-remove.yml diff --git a/dev-playbook-config/dev-kiali-cr.yaml b/dev-playbook-config/kiali/dev-cr.yaml similarity index 100% rename from dev-playbook-config/dev-kiali-cr.yaml rename to dev-playbook-config/kiali/dev-cr.yaml diff --git a/dev-playbook-config/dev-hosts.yaml b/dev-playbook-config/kiali/dev-hosts.yaml similarity index 100% rename from dev-playbook-config/dev-hosts.yaml rename to dev-playbook-config/kiali/dev-hosts.yaml diff --git a/dev-playbook-config/kiali/dev-playbook.yaml b/dev-playbook-config/kiali/dev-playbook.yaml new file mode 100644 index 00000000..6ca8395b --- /dev/null +++ b/dev-playbook-config/kiali/dev-playbook.yaml @@ -0,0 +1,3 @@ +--- +- import_playbook: ../../playbooks/kiali-deploy.yml +- import_playbook: ../../playbooks/kiali-remove.yml diff --git a/dev-playbook-config/ossmconsole/dev-cr.yaml b/dev-playbook-config/ossmconsole/dev-cr.yaml new file mode 100644 index 00000000..5b198805 --- /dev/null +++ b/dev-playbook-config/ossmconsole/dev-cr.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: dev-ossmconsole +--- +apiVersion: kiali.io/v1alpha1 +kind: OSSMConsole +metadata: + name: ossmconsole + namespace: dev-ossmconsole + annotations: + ansible.sdk.operatorframework.io/verbosity: "1" + labels: + kiali.dev: "run-operator-playbook" +spec: + + # Make sure the values below also match those in dev-hosts.yaml + + version: "default" + + deployment: + imageVersion: "dev" + + kiali: + graph: + impl: "pf" + serviceName: "" + serviceNamespace: "" + servicePort: 0 diff --git a/dev-playbook-config/ossmconsole/dev-hosts.yaml b/dev-playbook-config/ossmconsole/dev-hosts.yaml new file mode 100644 index 00000000..9e80ed9c --- /dev/null +++ b/dev-playbook-config/ossmconsole/dev-hosts.yaml @@ -0,0 +1,37 @@ +all: + vars: + + # Mimic OSSMConsole CR settings found in dev-ossmconsole-cr.yaml + + version: "default" + + deployment: + imageVersion: "dev" + + kiali: + graph: + impl: "pf" + serviceName: "" + serviceNamespace: "" + servicePort: 0 + + # The Operator SDK creates a "ansible_operator_meta" variable + # that contains the name and namespace of the CR. + # Most times you can just run with these defaults. + # Make sure these match those in dev-ossmconsole-cr.yaml. + + ansible_operator_meta: + name: ossmconsole + namespace: dev-ossmconsole + + # The Operator SDK creates a "_kiali_io_ossmconsole" variable that + # mimics the OSSMConsole CR but maintains camelCase in key names. + # The operator playbook expects this defined. + # Make sure these match those in dev-ossmconsole-cr.yaml. + + _kiali_io_ossmconsole: + apiVersion: kiali.io/v1alpha1 + kind: OSSMConsole + metadata: + name: ossmconsole + namespace: dev-ossmconsole diff --git a/dev-playbook-config/ossmconsole/dev-playbook.yaml b/dev-playbook-config/ossmconsole/dev-playbook.yaml new file mode 100644 index 00000000..4d61e005 --- /dev/null +++ b/dev-playbook-config/ossmconsole/dev-playbook.yaml @@ -0,0 +1,3 @@ +--- +- import_playbook: ../../playbooks/ossmconsole-deploy.yml +- import_playbook: ../../playbooks/ossmconsole-remove.yml diff --git a/manifests/kiali-community/1.76.0/manifests/kiali.v1.76.0.clusterserviceversion.yaml b/manifests/kiali-community/1.76.0/manifests/kiali.v1.76.0.clusterserviceversion.yaml index 08e6b3b0..d4fbcead 100644 --- a/manifests/kiali-community/1.76.0/manifests/kiali.v1.76.0.clusterserviceversion.yaml +++ b/manifests/kiali-community/1.76.0/manifests/kiali.v1.76.0.clusterserviceversion.yaml @@ -37,6 +37,20 @@ metadata: "web_root": "/mykiali" } } + }, + { + "apiVersion": "kiali.io/v1alpha1", + "kind": "OSSMConsole", + "metadata": { + "name": "ossmconsole" + }, + "spec": { + "kiali": { + "serviceName": "", + "serviceNamespace": "", + "servicePort": 0 + } + } } ] spec: @@ -73,6 +87,10 @@ spec: '/kiali' though you can change this by configuring the 'web_root' setting in the Kiali CR. + If on OpenShift, you can create an OSSMConsole CR to have the operator + install the OpenShift ServiceMesh Console plugin to the OpenShift Console + thus providing an interface directly integrated with the OpenShift Console. + ## About this Operator ### Kiali Custom Resource Configuration Settings @@ -175,6 +193,35 @@ spec: path: server.web_root x-descriptors: - 'urn:alm:descriptor:com.tectonic.ui:label' + - name: ossmconsoles.kiali.io + group: kiali.io + description: A configuration file for a OpenShift Service Mesh Console installation. + displayName: OpenShift Service Mesh Console + kind: OSSMConsole + version: v1alpha1 + resources: + - kind: Deployment + version: apps/v1 + - kind: Pod + version: v1 + - kind: ConfigMap + version: v1 + specDescriptors: + - displayName: Kiali Service Name + description: "The internal Kiali service that the OS Console will use to proxy API calls. If empty, an attempt will be made to auto-discover it from the Kiali OpenShift Route." + path: kiali.serviceName + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:text' + - displayName: Kiali Service Namespace + description: "The namespace where the Kiali service is deployed. If empty, an attempt will be made to auto-discover it from the Kiali OpenShift Route. It will assume that the OpenShift Route and the Kiali service are deployed in the same namespace." + path: kiali.serviceNamespace + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:text' + - displayName: Kiali Service Port + description: "The internal port used by the Kiali service for the API. If empty, an attempt will be made to auto-discover it from the Kiali OpenShift Route." + path: kiali.servicePort + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:text' apiservicedefinitions: {} install: strategy: deployment @@ -237,6 +284,8 @@ spec: value: "false" - name: ALLOW_AD_HOC_KIALI_IMAGE value: "false" + - name: ALLOW_AD_HOC_OSSMCONSOLE_IMAGE + value: "false" - name: ALLOW_SECURITY_CONTEXT_OVERRIDE value: "false" - name: ALLOW_ALL_ACCESSIBLE_NAMESPACES @@ -249,6 +298,8 @@ spec: value: "True" - name: ANSIBLE_VERBOSITY_KIALI_KIALI_IO value: "1" + - name: ANSIBLE_VERBOSITY_OSSMCONSOLE_KIALI_IO + value: "1" - name: ANSIBLE_CONFIG value: "/etc/ansible/ansible.cfg" ports: @@ -444,6 +495,27 @@ spec: - patch - update - watch + # The permissions below are for OSSMC operator capabilities + - apiGroups: ["console.openshift.io"] + resources: + - consoleplugins + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: ["operator.openshift.io"] + resources: + - consoles + verbs: + - get + - list + - patch + - update + - watch # The permissions below are for Kiali itself; operator needs these so it can escalate when creating Kiali's roles - apiGroups: [""] resources: diff --git a/manifests/kiali-community/1.76.0/manifests/ossmconsole.crd.yaml b/manifests/kiali-community/1.76.0/manifests/ossmconsole.crd.yaml new file mode 100644 index 00000000..9975b532 --- /dev/null +++ b/manifests/kiali-community/1.76.0/manifests/ossmconsole.crd.yaml @@ -0,0 +1,25 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ossmconsoles.kiali.io + labels: + app: kiali-operator + app.kubernetes.io/name: kiali-operator +spec: + group: kiali.io + names: + kind: OSSMConsole + listKind: OSSMConsoleList + plural: ossmconsoles + singular: ossmconsole + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + subresources: + status: {} + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true diff --git a/manifests/kiali-ossm/manifests/kiali.clusterserviceversion.yaml b/manifests/kiali-ossm/manifests/kiali.clusterserviceversion.yaml index 88b1fe19..6df19758 100644 --- a/manifests/kiali-ossm/manifests/kiali.clusterserviceversion.yaml +++ b/manifests/kiali-ossm/manifests/kiali.clusterserviceversion.yaml @@ -49,6 +49,20 @@ metadata: "view_only_mode": false } } + }, + { + "apiVersion": "kiali.io/v1alpha1", + "kind": "OSSMConsole", + "metadata": { + "name": "ossmconsole" + }, + "spec": { + "kiali": { + "serviceName": "", + "serviceNamespace": "", + "servicePort": 0 + } + } } ] spec: @@ -83,6 +97,10 @@ spec: The default root context path is '/' though you can change this by configuring the 'web_root' setting in the Kiali CR. + If on OpenShift, you can create an OSSMConsole CR to have the operator + install the OpenShift ServiceMesh Console plugin to the OpenShift Console + thus providing an interface directly integrated with the OpenShift Console. + ## About this Operator ### Kiali Custom Resource Configuration Settings @@ -175,6 +193,35 @@ spec: path: server.web_root x-descriptors: - 'urn:alm:descriptor:com.tectonic.ui:label' + - name: ossmconsoles.kiali.io + group: kiali.io + description: A configuration file for a OpenShift Service Mesh Console installation. + displayName: OpenShift Service Mesh Console + kind: OSSMConsole + version: v1alpha1 + resources: + - kind: Deployment + version: apps/v1 + - kind: Pod + version: v1 + - kind: ConfigMap + version: v1 + specDescriptors: + - displayName: Kiali Service Name + description: "The internal Kiali service that the OS Console will use to proxy API calls. If empty, an attempt will be made to auto-discover it from the Kiali OpenShift Route." + path: kiali.serviceName + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:text' + - displayName: Kiali Service Namespace + description: "The namespace where the Kiali service is deployed. If empty, an attempt will be made to auto-discover it from the Kiali OpenShift Route. It will assume that the OpenShift Route and the Kiali service are deployed in the same namespace." + path: kiali.serviceNamespace + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:text' + - displayName: Kiali Service Port + description: "The internal port used by the Kiali service for the API. If empty, an attempt will be made to auto-discover it from the Kiali OpenShift Route." + path: kiali.servicePort + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:text' apiservicedefinitions: {} install: strategy: deployment @@ -237,6 +284,8 @@ spec: value: "false" - name: ALLOW_AD_HOC_KIALI_IMAGE value: "false" + - name: ALLOW_AD_HOC_OSSMCONSOLE_IMAGE + value: "false" - name: ALLOW_SECURITY_CONTEXT_OVERRIDE value: "false" - name: ALLOW_ALL_ACCESSIBLE_NAMESPACES @@ -249,6 +298,8 @@ spec: value: "True" - name: ANSIBLE_VERBOSITY_KIALI_KIALI_IO value: "1" + - name: ANSIBLE_VERBOSITY_OSSMCONSOLE_KIALI_IO + value: "1" - name: ANSIBLE_CONFIG value: "/etc/ansible/ansible.cfg" - name: RELATED_IMAGE_kiali_default @@ -452,6 +503,27 @@ spec: - patch - update - watch + # The permissions below are for OSSMC operator capabilities + - apiGroups: ["console.openshift.io"] + resources: + - consoleplugins + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: ["operator.openshift.io"] + resources: + - consoles + verbs: + - get + - list + - patch + - update + - watch # The permissions below are for Kiali itself; operator needs these so it can escalate when creating Kiali's roles - apiGroups: [""] resources: diff --git a/manifests/kiali-ossm/manifests/ossmconsole.crd.yaml b/manifests/kiali-ossm/manifests/ossmconsole.crd.yaml new file mode 100644 index 00000000..9975b532 --- /dev/null +++ b/manifests/kiali-ossm/manifests/ossmconsole.crd.yaml @@ -0,0 +1,25 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: ossmconsoles.kiali.io + labels: + app: kiali-operator + app.kubernetes.io/name: kiali-operator +spec: + group: kiali.io + names: + kind: OSSMConsole + listKind: OSSMConsoleList + plural: ossmconsoles + singular: ossmconsole + scope: Namespaced + versions: + - name: v1alpha1 + served: true + storage: true + subresources: + status: {} + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml index f163b56c..7d3b059e 100644 --- a/molecule/default/prepare.yml +++ b/molecule/default/prepare.yml @@ -92,6 +92,8 @@ - "--set" - "allowAdHocKialiImage=true" - "--set" + - "allowAdHocOSSMConsoleImage=true" + - "--set" - "allowSecurityContextOverride=true" - "--set" - "cr.create=false" diff --git a/molecule/ossmconsole-common/confirm_openshift.yml b/molecule/ossmconsole-common/confirm_openshift.yml new file mode 100644 index 00000000..f3963b48 --- /dev/null +++ b/molecule/ossmconsole-common/confirm_openshift.yml @@ -0,0 +1,11 @@ +- name: Get information about the cluster + set_fact: + api_groups: "{{ lookup('kubernetes.core.k8s', cluster_info='api_groups') }}" + +- name: Determine the cluster type + set_fact: + is_openshift: "{{ True if 'route.openshift.io' in api_groups else False }}" + +# OSSM Console is only usable on OpenShift, skip the test if not on OpenShift platform +- meta: end_play + when: is_openshift == False \ No newline at end of file diff --git a/molecule/ossmconsole-common/set_ossmconsole_cr.yml b/molecule/ossmconsole-common/set_ossmconsole_cr.yml new file mode 100644 index 00000000..0eeebd09 --- /dev/null +++ b/molecule/ossmconsole-common/set_ossmconsole_cr.yml @@ -0,0 +1,4 @@ +- name: Change OSSMConsole CR with new OSSMConsole CR + k8s: + namespace: '{{ ossmconsole_cr_namespace }}' + definition: "{{ new_ossmconsole_cr }}" diff --git a/molecule/ossmconsole-common/tasks.yml b/molecule/ossmconsole-common/tasks.yml new file mode 100644 index 00000000..c54acc9c --- /dev/null +++ b/molecule/ossmconsole-common/tasks.yml @@ -0,0 +1,38 @@ +- name: Get OSSMConsole CR if present + set_fact: + ossmconsole_cr: "{{ lookup('kubernetes.core.k8s', api_version='kiali.io/v1alpha1', kind='OSSMConsole', namespace=ossmconsole_cr_namespace, resource_name=custom_resource.metadata.name) }}" + +- name: Get OSSMConsole Pod + k8s_info: + api_version: v1 + kind: Pod + namespace: "{{ ossmconsole.install_namespace }}" + label_selectors: + - "app.kubernetes.io/name=ossmconsole" + register: ossmconsole_pod + +- name: Get OSSMConsole Deployment + k8s_info: + api_version: apps/v1 + kind: Deployment + namespace: "{{ ossmconsole.install_namespace }}" + label_selectors: + - "app.kubernetes.io/name=ossmconsole" + register: ossmconsole_deployment + +- name: Get OSSMConsole ConfigMap + set_fact: + ossmconsole_configmap_resource: "{{ lookup('kubernetes.core.k8s', api_version='v1', kind='ConfigMap', namespace=ossmconsole.install_namespace, resource_name='plugin-conf') }}" +- name: Format OSSMConsole ConfigMap + set_fact: + ossmconsole_configmap: "{{ ossmconsole_configmap_resource.data['plugin-config.json'] | from_json }}" +- name: Dump OSSMConsole ConfigMap + debug: + msg: "{{ ossmconsole_configmap }}" + +- name: Get OSSMConsole ConsolePlugin + set_fact: + ossmconsole_consoleplugin: "{{ lookup('kubernetes.core.k8s', api_version='console.openshift.io/v1alpha1', kind='ConsolePlugin', namespace=ossmconsole.install_namespace, resource_name='ossmconsole') }}" +- name: Dump OSSMConsole ConsolePlugin + debug: + msg: "{{ ossmconsole_consoleplugin }}" diff --git a/molecule/ossmconsole-common/wait_for_ossmconsole_cr_changes.yml b/molecule/ossmconsole-common/wait_for_ossmconsole_cr_changes.yml new file mode 100644 index 00000000..bee94018 --- /dev/null +++ b/molecule/ossmconsole-common/wait_for_ossmconsole_cr_changes.yml @@ -0,0 +1,15 @@ +- name: Wait for OSSMConsole CR changes to take effect + k8s_info: + api_version: kiali.io/v1alpha1 + kind: OSSMConsole + name: "{{ custom_resource.metadata.name }}" + namespace: "{{ ossmconsole_cr_namespace }}" + register: ossmconsole_cr_list + until: + - ossmconsole_cr_list is success + - ossmconsole_cr_list.resources is defined + - ossmconsole_cr_list.resources | length > 0 + - ossmconsole_cr_list | json_query('resources[*].status.conditions[?message==`Awaiting next reconciliation`].status') | flatten | join == 'True' + - ossmconsole_cr_list | json_query('resources[*].status.conditions[?message==`Awaiting next reconciliation`].reason') | flatten | join == 'Successful' + retries: "{{ wait_retries }}" + delay: 5 diff --git a/molecule/ossmconsole-config-values-test/converge.yml b/molecule/ossmconsole-config-values-test/converge.yml new file mode 100644 index 00000000..9a61ec53 --- /dev/null +++ b/molecule/ossmconsole-config-values-test/converge.yml @@ -0,0 +1,61 @@ +- name: Tests + hosts: localhost + connection: local + collections: + - kubernetes.core + vars: + custom_resource: "{{ lookup('template', ossmconsole_cr_file_path) | from_yaml }}" + tasks: + - import_tasks: ../ossmconsole-common/confirm_openshift.yml + - import_tasks: ../ossmconsole-common/tasks.yml + - import_tasks: ../ossmconsole-common/wait_for_ossmconsole_cr_changes.yml + + - set_fact: + current_ossmconsole_cr: "{{ lookup('kubernetes.core.k8s', api_version='kiali.io/v1alpha1', kind='OSSMConsole', namespace=ossmconsole_cr_namespace, resource_name=custom_resource.metadata.name) }}" + + - name: The current CR to be used as the base of the test + debug: + msg: "{{ current_ossmconsole_cr }}" + + - name: Confirm the Kiali Service Name is as expected + assert: + that: "{{ ossmconsole_consoleplugin.spec.proxy[0].service.name == current_ossmconsole_cr.status.kiali.serviceName }}" + + - name: Confirm the Kiali Service Namespace is as expected + assert: + that: "{{ ossmconsole_consoleplugin.spec.proxy[0].service.namespace == current_ossmconsole_cr.status.kiali.serviceNamespace }}" + + - name: Confirm the Kiali Service Port is as expected + assert: + that: "{{ ossmconsole_consoleplugin.spec.proxy[0].service.port == (current_ossmconsole_cr.status.kiali.servicePort | int) }}" + + - name: Confirm the Kiali Graph Impl is the expected default in the ConfigMap + assert: + that: "{{ ossmconsole_configmap.graph.impl == 'pf' }}" + + # This test will change some config settings to make sure things work like we expect. + # We alter the current CR with new config and deploy that new CR. + + # Change the existing CR to get a new config + + - name: Set to use cy graph impl + vars: + new_graph_impl: "cy" + set_fact: + current_ossmconsole_cr: "{{ current_ossmconsole_cr | combine({'spec': {'kiali': {'graph': {'impl': new_graph_impl }}}}, recursive=True) }}" + + # Deploy the new CR and wait for the CR change to take effect + + - name: The new CR to be applied and tested + debug: + msg: "{{ current_ossmconsole_cr }}" + + - import_tasks: ../ossmconsole-common/set_ossmconsole_cr.yml + vars: + new_ossmconsole_cr: "{{ current_ossmconsole_cr }}" + - import_tasks: ../ossmconsole-common/wait_for_ossmconsole_cr_changes.yml + - import_tasks: ../ossmconsole-common/tasks.yml + + - name: Confirm the Kiali Graph Impl is now changed to use the "cy" impl + assert: + that: "{{ ossmconsole_configmap.graph.impl == 'cy' }}" diff --git a/molecule/ossmconsole-config-values-test/molecule.yml b/molecule/ossmconsole-config-values-test/molecule.yml new file mode 100644 index 00000000..1287f109 --- /dev/null +++ b/molecule/ossmconsole-config-values-test/molecule.yml @@ -0,0 +1,56 @@ +--- +dependency: + name: galaxy +driver: + name: $DORP +platforms: +- name: default + groups: + - k8s +provisioner: + name: ansible + config_options: + defaults: + callbacks_enabled: junit + playbooks: + destroy: ../ossmconsole-default/destroy.yml + prepare: ../ossmconsole-default/prepare.yml + cleanup: ../default/cleanup.yml + inventory: + group_vars: + all: + cr_file_path: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/molecule/kiali-cr.yaml" + cr_namespace: "{{ 'kiali-operator' if (lookup('env', 'MOLECULE_OPERATOR_INSTALLER') | default('helm', True) == 'helm') else 'istio-system' }}" # if external operator, assume CR will go in control plane namespace + wait_retries: "{{ lookup('env', 'MOLECULE_WAIT_RETRIES') | default('360', True) }}" + istio: + control_plane_namespace: istio-system + kiali: + spec_version: "{{ lookup('env', 'MOLECULE_KIALI_CR_SPEC_VERSION') | default('default', True) }}" + install_namespace: istio-system + accessible_namespaces: ["**"] + cluster_wide_access: true + auth_strategy: anonymous + operator_namespace: "{{ 'kiali-operator' if (lookup('env', 'MOLECULE_OPERATOR_INSTALLER') | default('helm', True) == 'helm') else ('openshift-operators' if (query('kubernetes.core.k8s', kind='Namespace', resource_name='openshift-operators') | length > 0) else 'operators') }}" # if external operator, assume operator is in OLM location + operator_image_name: "{{ 'image-registry.openshift-image-registry.svc:5000/kiali/kiali-operator' if lookup('env', 'MOLECULE_KIALI_OPERATOR_IMAGE_NAME') == 'dev' else (lookup('env', 'MOLECULE_KIALI_OPERATOR_IMAGE_NAME')|default('quay.io/kiali/kiali-operator', True)) }}" + operator_version: "{{ lookup('env', 'MOLECULE_KIALI_OPERATOR_IMAGE_VERSION')|default('latest', True) }}" + operator_watch_namespace: kiali-operator + operator_cluster_role_creator: "true" + image_name: "{{ 'image-registry.openshift-image-registry.svc:5000/kiali/kiali' if lookup('env', 'MOLECULE_KIALI_IMAGE_NAME') == 'dev' else ('quay.io/kiali/kiali' if ansible_env.MOLECULE_KIALI_IMAGE_NAME is not defined else lookup('env', 'MOLECULE_KIALI_IMAGE_NAME')) }}" + image_version: "{{ 'latest' if ansible_env.MOLECULE_KIALI_IMAGE_VERSION is not defined else lookup('env', 'MOLECULE_KIALI_IMAGE_VERSION') }}" + image_pull_policy: "{{ lookup('env', 'MOLECULE_KIALI_IMAGE_PULL_POLICY')|default('Always', True) }}" + operator_image_pull_policy: "{{ lookup('env', 'MOLECULE_KIALI_OPERATOR_IMAGE_PULL_POLICY')|default('Always', True) }}" + ossmconsole_cr_file_path: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/molecule/ossmconsole-cr.yaml" + ossmconsole_cr_namespace: "{{ 'kiali-operator' if (lookup('env', 'MOLECULE_OPERATOR_INSTALLER') | default('helm', True) == 'helm') else 'istio-system' }}" # if external operator, assume CR will go in control plane namespace + plugin_image_pull_secret_json: "{{ lookup('env', 'PLUGIN_IMAGE_PULL_SECRET_JSON') | default('') }}" + ossmconsole: + install_namespace: "{{ 'kiali-operator' if (lookup('env', 'MOLECULE_OPERATOR_INSTALLER') | default('helm', True) == 'helm') else 'istio-system' }}" # install namespace must be the same as the CR namespace today + spec_version: "{{ lookup('env', 'MOLECULE_OSSMCONSOLE_CR_SPEC_VERSION') | default('default', True) }}" + image_name: "{{ 'image-registry.openshift-image-registry.svc:5000/kiali/ossmconsole' if lookup('env', 'MOLECULE_PLUGIN_IMAGE_NAME') == 'dev' else ('quay.io/kiali/ossmconsole' if ansible_env.MOLECULE_PLUGIN_IMAGE_NAME is not defined else lookup('env', 'MOLECULE_PLUGIN_IMAGE_NAME')) }}" + image_version: "{{ 'latest' if ansible_env.MOLECULE_PLUGIN_IMAGE_VERSION is not defined else lookup('env', 'MOLECULE_PLUGIN_IMAGE_VERSION') }}" + image_pull_policy: "{{ lookup('env', 'MOLECULE_PLUGIN_IMAGE_PULL_POLICY')|default('Always', True) }}" +scenario: + name: ossmconsole-config-values-test + test_sequence: + - prepare + - converge + - destroy diff --git a/molecule/ossmconsole-cr.yaml b/molecule/ossmconsole-cr.yaml new file mode 100644 index 00000000..e03f5fef --- /dev/null +++ b/molecule/ossmconsole-cr.yaml @@ -0,0 +1,11 @@ +apiVersion: kiali.io/v1alpha1 +kind: OSSMConsole +metadata: + name: ossmconsole +spec: + version: "{{ ossmconsole.spec_version }}" + deployment: + imageName: "{{ ossmconsole.image_name }}" + imageVersion: "{{ ossmconsole.image_version }}" + imagePullPolicy: "{{ ossmconsole.image_pull_policy }}" + imagePullSecrets: [ {{ plugin_image_pull_secret_name | default('') }} ] diff --git a/molecule/ossmconsole-default/converge.yml b/molecule/ossmconsole-default/converge.yml new file mode 100644 index 00000000..04766381 --- /dev/null +++ b/molecule/ossmconsole-default/converge.yml @@ -0,0 +1,10 @@ +- name: Tests + hosts: localhost + connection: local + collections: + - kubernetes.core + vars: + custom_resource: "{{ lookup('template', ossmconsole_cr_file_path) | from_yaml }}" + tasks: + - import_tasks: ../ossmconsole-common/confirm_openshift.yml + - import_tasks: ../ossmconsole-common/tasks.yml diff --git a/molecule/ossmconsole-default/destroy.yml b/molecule/ossmconsole-default/destroy.yml new file mode 100644 index 00000000..47711819 --- /dev/null +++ b/molecule/ossmconsole-default/destroy.yml @@ -0,0 +1,14 @@ +- name: Destroy + hosts: localhost + connection: local + collections: + - kubernetes.core + tasks: + - name: Skip test if not on OpenShift + import_tasks: ../ossmconsole-common/confirm_openshift.yml + +- name: Uninstall the OSSM Console + import_playbook: remove_ossmconsole.yml + +- name: Include the base destroy play to destroy the kiali install + import_playbook: ../default/destroy.yml \ No newline at end of file diff --git a/molecule/ossmconsole-default/install_ossmconsole.yml b/molecule/ossmconsole-default/install_ossmconsole.yml new file mode 100644 index 00000000..f4abc914 --- /dev/null +++ b/molecule/ossmconsole-default/install_ossmconsole.yml @@ -0,0 +1,79 @@ +- name: Install OSSMConsole + hosts: localhost + connection: local + collections: + - kubernetes.core + tasks: + - import_tasks: ../ossmconsole-common/confirm_openshift.yml + + - name: Make sure the OSSMConsole CR namespace exists + k8s: + state: present + api_version: v1 + kind: Namespace + name: "{{ ossmconsole_cr_namespace }}" + + # This is really a no-op because today we know the CR namespace will always be the same as the install namespace + - name: Make sure the OSSMConsole install namespace exists + k8s: + state: present + api_version: v1 + kind: Namespace + name: "{{ ossmconsole.install_namespace }}" + when: + - ossmconsole.install_namespace != ossmconsole_cr_namespace + + - name: Define the name of the pull secret if a secret is needed to pull the plugin image from the internal image registry + set_fact: + plugin_image_pull_secret_name: "ossmconsole-pull-secret" + when: + - plugin_image_pull_secret_json != "" + + - name: Create the secret that will be used by the plugin pod to pull the image from the internal registry when needed + k8s: + state: present + definition: + apiVersion: v1 + kind: Secret + metadata: + name: "{{ plugin_image_pull_secret_name }}" + namespace: "{{ ossmconsole.install_namespace }}" + type: kubernetes.io/dockerconfigjson + data: + .dockerconfigjson: "{{ plugin_image_pull_secret_json }}" + when: + - plugin_image_pull_secret_name is defined + + - name: Wait for the OSSMConsole CRD to be established + k8s_info: + api_version: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + name: ossmconsoles.kiali.io + wait: yes + wait_condition: + type: Established + + - name: Prepare initial OSSMConsole CR definition based solely on the template + set_fact: + ossmconsole_cr_definition: "{{ lookup('template', ossmconsole_cr_file_path) }}" + + - name: Create OSSMConsole CR + k8s: + namespace: "{{ ossmconsole_cr_namespace }}" + definition: "{{ ossmconsole_cr_definition }}" + + - name: Asserting that OSSMConsole plugin is Deployed + k8s_info: + api_version: v1 + kind: Deployment + namespace: "{{ ossmconsole.install_namespace }}" + label_selectors: + - "app.kubernetes.io/name=ossmconsole" + register: ossmconsole_deployment + until: + - ossmconsole_deployment is success + - ossmconsole_deployment.resources | length == 1 + - ossmconsole_deployment.resources[0].status.availableReplicas is defined + - ossmconsole_deployment.resources[0].status.availableReplicas == 1 + retries: "{{ wait_retries }}" + delay: 5 diff --git a/molecule/ossmconsole-default/molecule.yml b/molecule/ossmconsole-default/molecule.yml new file mode 100644 index 00000000..ef831253 --- /dev/null +++ b/molecule/ossmconsole-default/molecule.yml @@ -0,0 +1,56 @@ +--- +dependency: + name: galaxy +driver: + name: $DORP +platforms: +- name: default + groups: + - k8s +provisioner: + name: ansible + config_options: + defaults: + callbacks_enabled: junit + playbooks: + destroy: ../ossmconsole-default/destroy.yml + prepare: ../ossmconsole-default/prepare.yml + cleanup: ../default/cleanup.yml + inventory: + group_vars: + all: + cr_file_path: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/molecule/kiali-cr.yaml" + cr_namespace: "{{ 'kiali-operator' if (lookup('env', 'MOLECULE_OPERATOR_INSTALLER') | default('helm', True) == 'helm') else 'istio-system' }}" # if external operator, assume CR will go in control plane namespace + wait_retries: "{{ lookup('env', 'MOLECULE_WAIT_RETRIES') | default('360', True) }}" + istio: + control_plane_namespace: istio-system + kiali: + spec_version: "{{ lookup('env', 'MOLECULE_KIALI_CR_SPEC_VERSION') | default('default', True) }}" + install_namespace: istio-system + accessible_namespaces: ["**"] + cluster_wide_access: true + auth_strategy: anonymous + operator_namespace: "{{ 'kiali-operator' if (lookup('env', 'MOLECULE_OPERATOR_INSTALLER') | default('helm', True) == 'helm') else ('openshift-operators' if (query('kubernetes.core.k8s', kind='Namespace', resource_name='openshift-operators') | length > 0) else 'operators') }}" # if external operator, assume operator is in OLM location + operator_image_name: "{{ 'image-registry.openshift-image-registry.svc:5000/kiali/kiali-operator' if lookup('env', 'MOLECULE_KIALI_OPERATOR_IMAGE_NAME') == 'dev' else (lookup('env', 'MOLECULE_KIALI_OPERATOR_IMAGE_NAME')|default('quay.io/kiali/kiali-operator', True)) }}" + operator_version: "{{ lookup('env', 'MOLECULE_KIALI_OPERATOR_IMAGE_VERSION')|default('latest', True) }}" + operator_watch_namespace: kiali-operator + operator_cluster_role_creator: "true" + image_name: "{{ 'image-registry.openshift-image-registry.svc:5000/kiali/kiali' if lookup('env', 'MOLECULE_KIALI_IMAGE_NAME') == 'dev' else ('quay.io/kiali/kiali' if ansible_env.MOLECULE_KIALI_IMAGE_NAME is not defined else lookup('env', 'MOLECULE_KIALI_IMAGE_NAME')) }}" + image_version: "{{ 'latest' if ansible_env.MOLECULE_KIALI_IMAGE_VERSION is not defined else lookup('env', 'MOLECULE_KIALI_IMAGE_VERSION') }}" + image_pull_policy: "{{ lookup('env', 'MOLECULE_KIALI_IMAGE_PULL_POLICY')|default('Always', True) }}" + operator_image_pull_policy: "{{ lookup('env', 'MOLECULE_KIALI_OPERATOR_IMAGE_PULL_POLICY')|default('Always', True) }}" + ossmconsole_cr_file_path: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') }}/molecule/ossmconsole-cr.yaml" + ossmconsole_cr_namespace: "{{ 'kiali-operator' if (lookup('env', 'MOLECULE_OPERATOR_INSTALLER') | default('helm', True) == 'helm') else 'istio-system' }}" # if external operator, assume CR will go in control plane namespace + plugin_image_pull_secret_json: "{{ lookup('env', 'PLUGIN_IMAGE_PULL_SECRET_JSON') | default('') }}" + ossmconsole: + install_namespace: "{{ 'kiali-operator' if (lookup('env', 'MOLECULE_OPERATOR_INSTALLER') | default('helm', True) == 'helm') else 'istio-system' }}" # install namespace must be the same as the CR namespace today + spec_version: "{{ lookup('env', 'MOLECULE_OSSMCONSOLE_CR_SPEC_VERSION') | default('default', True) }}" + image_name: "{{ 'image-registry.openshift-image-registry.svc:5000/kiali/ossmconsole' if lookup('env', 'MOLECULE_PLUGIN_IMAGE_NAME') == 'dev' else ('quay.io/kiali/ossmconsole' if ansible_env.MOLECULE_PLUGIN_IMAGE_NAME is not defined else lookup('env', 'MOLECULE_PLUGIN_IMAGE_NAME')) }}" + image_version: "{{ 'latest' if ansible_env.MOLECULE_PLUGIN_IMAGE_VERSION is not defined else lookup('env', 'MOLECULE_PLUGIN_IMAGE_VERSION') }}" + image_pull_policy: "{{ lookup('env', 'MOLECULE_PLUGIN_IMAGE_PULL_POLICY')|default('Always', True) }}" +scenario: + name: ossmconsole-default + test_sequence: + - prepare + - converge + - destroy diff --git a/molecule/ossmconsole-default/prepare.yml b/molecule/ossmconsole-default/prepare.yml new file mode 100644 index 00000000..6b48d2e1 --- /dev/null +++ b/molecule/ossmconsole-default/prepare.yml @@ -0,0 +1,14 @@ +- name: Prepare + hosts: localhost + connection: local + collections: + - kubernetes.core + tasks: + - name: Skip test if not on OpenShift + import_tasks: ../ossmconsole-common/confirm_openshift.yml + +- name: Include the base prepare play to create the kiali install + import_playbook: ../default/prepare.yml + +- name: Install OSSM Console + import_playbook: install_ossmconsole.yml \ No newline at end of file diff --git a/molecule/ossmconsole-default/remove_ossmconsole.yml b/molecule/ossmconsole-default/remove_ossmconsole.yml new file mode 100644 index 00000000..10e538e0 --- /dev/null +++ b/molecule/ossmconsole-default/remove_ossmconsole.yml @@ -0,0 +1,41 @@ +- name: Remove OSSMConsole + hosts: localhost + connection: local + collections: + - kubernetes.core + tasks: + - import_tasks: ../ossmconsole-common/confirm_openshift.yml + + - name: Remove OSSMConsole CR + vars: + custom_resource: "{{ lookup('template', ossmconsole_cr_file_path) | from_yaml }}" + k8s: + state: absent + api_version: kiali.io/v1alpha1 + kind: OSSMConsole + namespace: "{{ ossmconsole_cr_namespace }}" + name: "{{ custom_resource.metadata.name }}" + wait: yes + wait_timeout: 600 + ignore_errors: yes + +# NOTE: because we know the CR is placed in the same namespace as the Kiali Operator or the +# control plane namespace, we do not want to remove the namespace here. If in the future the +# tests will put the CR in a separate namespace, we can uncomment this to delete that namespace. +# - name: Remove the cr namespace +# k8s: +# state: absent +# api_version: v1 +# kind: Namespace +# name: "{{ ossmconsole_cr_namespace }}" +# +# NOTE: because we know the install namespace is always the same as the CR namespace, there is nothing to do. +# If in the future the plugin will be installed in a different namespace than where the CR is, we can uncomment this. +# - name: Remove the install namespace +# k8s: +# state: absent +# api_version: v1 +# kind: Namespace +# name: "{{ ossmconsole.install_namespace }}" +# when: +# - ossmconsole.install_namespace != ossmconsole_cr_namespace \ No newline at end of file diff --git a/playbooks/default-supported-images.yml b/playbooks/kiali-default-supported-images.yml similarity index 100% rename from playbooks/default-supported-images.yml rename to playbooks/kiali-default-supported-images.yml diff --git a/playbooks/kiali-deploy.yml b/playbooks/kiali-deploy.yml index 75b48d07..d486f4a4 100644 --- a/playbooks/kiali-deploy.yml +++ b/playbooks/kiali-deploy.yml @@ -41,7 +41,7 @@ - name: Determine the default supported images for all known versions include_vars: - file: "default-supported-images.yml" + file: "kiali-default-supported-images.yml" name: supported_kiali_images - name: Override the supported images if found in the environment diff --git a/playbooks/ossmconsole-default-supported-images.yml b/playbooks/ossmconsole-default-supported-images.yml new file mode 100644 index 00000000..a907b444 --- /dev/null +++ b/playbooks/ossmconsole-default-supported-images.yml @@ -0,0 +1 @@ +default: {"imageName": "quay.io/kiali/ossmconsole", "imageVersion": "operator_version"} diff --git a/playbooks/ossmconsole-deploy.yml b/playbooks/ossmconsole-deploy.yml new file mode 100644 index 00000000..826646bd --- /dev/null +++ b/playbooks/ossmconsole-deploy.yml @@ -0,0 +1,70 @@ +- hosts: localhost + gather_facts: no + collections: + - kubernetes.core + tasks: + + - debug: + msg: OSSMCONSOLE RECONCILIATION START + + - debug: + msg: "CR: name={{ ansible_operator_meta.name }}, namespace={{ ansible_operator_meta.namespace }}" + + - name: Playbook start time + set_fact: + playbook_time_start: "{{ '%Y-%m-%d %H:%M:%S' | strftime }}" + + - name: Determine the default playbook + include_vars: + file: "default-playbook.yml" + name: default_playbook + + - name: Determine the version that is to be installed + set_fact: + version: "{{ version | default(default_playbook.playbook) }}" + + - name: Determine the default supported images for all known versions + include_vars: + file: "ossmconsole-default-supported-images.yml" + name: supported_ossmconsole_images + + - name: Override the supported images if found in the environment + set_fact: + supported_ossmconsole_images: "{{ supported_ossmconsole_images | default({}) | combine({item.key: {'image_name': lookup('env', 'RELATED_IMAGE_ossmconsole_' + (item.key | replace('.','_'))) | regex_replace('(.+):.+', '\\1'), 'image_version': lookup('env', 'RELATED_IMAGE_ossmconsole_' + (item.key | replace('.','_'))) | regex_replace('.+:(.+)', '\\1')}}, recursive=True) }}" + loop: "{{ supported_ossmconsole_images | default({}) | dict2items }}" + when: + - lookup('env', 'RELATED_IMAGE_ossmconsole_' + (item.key | replace('.','_'))) + + - name: Examine environment and determine if supported image for the requested version is overridden even if no default is known + vars: + supported_image_env: "{{ lookup('env', 'RELATED_IMAGE_ossmconsole_' + (version | replace('.','_'))) }}" + set_fact: + supported_ossmconsole_images: "{{ supported_ossmconsole_images | default({}) | combine({version: {'image_name': supported_image_env | regex_replace('(.+):.+', '\\1'), 'image_version': supported_image_env | regex_replace('.+:(.+)', '\\1')}}, recursive=True) }}" + when: + - supported_image_env is defined + - supported_image_env != "" + + - name: Make sure a default supported image or an override image is known + fail: + msg: "Asked to install a version [{{ version }}] that does not have a known supported image." + when: + - supported_ossmconsole_images[version] is not defined + + - name: Run the version-specific deploy role + include_role: + name: "{{ version }}/ossmconsole-deploy" + when: + - skip_reconciliation is not defined or skip_reconciliation == False + + - name: Playbook end time + set_fact: + playbook_time_end: "{{ '%Y-%m-%d %H:%M:%S' | strftime }}" + + - name: Log reconciliation processing time + ignore_errors: yes + debug: + msg: "Processing time: [{{ (playbook_time_end|to_datetime - playbook_time_start|to_datetime).total_seconds() | int }}] seconds" + + - debug: + msg: OSSMCONSOLE RECONCILIATION IS DONE. + diff --git a/playbooks/ossmconsole-remove.yml b/playbooks/ossmconsole-remove.yml new file mode 100644 index 00000000..dd3c71a9 --- /dev/null +++ b/playbooks/ossmconsole-remove.yml @@ -0,0 +1,42 @@ +- hosts: localhost + gather_facts: no + collections: + - kubernetes.core + tasks: + + - ignore_errors: yes + debug: + msg: REMOVING OSSMCONSOLE + + - ignore_errors: yes + debug: + msg: "CR: name={{ ansible_operator_meta.name }}, namespace={{ ansible_operator_meta.namespace }}" + + - ignore_errors: yes + name: Playbook start time + set_fact: + playbook_time_start: "{{ '%Y-%m-%d %H:%M:%S' | strftime }}" + + - ignore_errors: yes + name: Determine the default playbook + include_vars: + file: "default-playbook.yml" + name: default_playbook + + - ignore_errors: yes + include_role: + name: "{{ version | default(default_playbook.playbook) }}/ossmconsole-remove" + + - ignore_errors: yes + name: Playbook end time + set_fact: + playbook_time_end: "{{ '%Y-%m-%d %H:%M:%S' | strftime }}" + + - ignore_errors: yes + name: Log removal processing time + debug: + msg: "Processing time: [{{ (playbook_time_end|to_datetime - playbook_time_start|to_datetime).total_seconds() | int }}] seconds" + + - ignore_errors: yes + debug: + msg: OSSMCONSOLE REMOVAL IS DONE. diff --git a/roles/default/ossmconsole-deploy/defaults/main.yml b/roles/default/ossmconsole-deploy/defaults/main.yml new file mode 100644 index 00000000..8dc928ce --- /dev/null +++ b/roles/default/ossmconsole-deploy/defaults/main.yml @@ -0,0 +1,26 @@ +# Defaults for all user-facing OSSM Console settings. +# +# Note that these are under the main dictionary group "ossmconsole_defaults". +# The actual vars used by the role are found in the vars/ directory. +# These defaults (the dictionaries under "ossmconsole_defaults") are merged into the vars such that the values +# below (e.g. deployment) are merged in rather than completely replaced by user-supplied values. +# +# If new groups are added to these defaults, you must remember to add the merge code to vars/main.yml. + +ossmconsole_defaults: + version: "default" + + deployment: + imageDigest: "" + imageName: "" + imagePullPolicy: "IfNotPresent" + imagePullSecrets: [] + imageVersion: "" + namespace: "" + + kiali: + graph: + impl: "pf" + serviceName: "" + serviceNamespace: "" + servicePort: 0 diff --git a/roles/default/ossmconsole-deploy/filter_plugins/stripnone.py b/roles/default/ossmconsole-deploy/filter_plugins/stripnone.py new file mode 100644 index 00000000..4dbd5303 --- /dev/null +++ b/roles/default/ossmconsole-deploy/filter_plugins/stripnone.py @@ -0,0 +1,28 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} + +# Process recursively the given value if it is a dict and remove all keys that have a None value +def strip_none(value): + if isinstance(value, dict): + dicts = {} + for k,v in value.items(): + if isinstance(v, dict): + dicts[k] = strip_none(v) + elif v is not None: + dicts[k] = v + return dicts + else: + return value + +# ---- Ansible filters ---- +class FilterModule(object): + def filters(self): + return { + 'stripnone': strip_none + } diff --git a/roles/default/ossmconsole-deploy/meta/main.yml b/roles/default/ossmconsole-deploy/meta/main.yml new file mode 100644 index 00000000..e9334e3c --- /dev/null +++ b/roles/default/ossmconsole-deploy/meta/main.yml @@ -0,0 +1,2 @@ +collections: +- kubernetes.core diff --git a/roles/default/ossmconsole-deploy/tasks/main.yml b/roles/default/ossmconsole-deploy/tasks/main.yml new file mode 100644 index 00000000..281f3cb0 --- /dev/null +++ b/roles/default/ossmconsole-deploy/tasks/main.yml @@ -0,0 +1,343 @@ +- set_fact: + k8s_plugin: kubernetes.core.k8s + +- name: Get the original CR as-is + set_fact: + current_cr: "{{ _kiali_io_ossmconsole }}" + +- include_tasks: update-status-progress.yml + vars: + status_progress_message: "Initializing" + status_vars: + specVersion: "{{ ossmconsole_vars.version }}" + deployment: + namespace: null + kiali: + serviceName: null + serviceNamespace: null + servicePort: null + +- name: Get information about the cluster + set_fact: + api_groups: "{{ lookup(k8s_plugin, cluster_info='api_groups') }}" + +- name: Determine the Kubernetes version + set_fact: + k8s_version: "{{ lookup(k8s_plugin, cluster_info='version').kubernetes.gitVersion | regex_replace('^v', '') }}" + ignore_errors: yes + +- name: Determine the OpenShift version + vars: + kube_apiserver_cluster_op_raw: "{{ lookup(k8s_plugin, api_version='config.openshift.io/v1', kind='ClusterOperator', resource_name='kube-apiserver') | default({}) }}" + ri_query: "status.versions[?name == 'raw-internal'].version" + set_fact: + openshift_version: "{{ kube_apiserver_cluster_op_raw | json_query(ri_query) | join }}" + +- name: Determine the Istio implementation + set_fact: + is_maistra: "{{ True if 'maistra.io' in api_groups else False }}" + +- name: Get information about the operator + k8s_info: + api_version: v1 + kind: Pod + namespace: "{{ lookup('env', 'POD_NAMESPACE') }}" + name: "{{ lookup('env', 'POD_NAME') }}" + register: operator_pod_raw + ignore_errors: yes +- name: Determine the version of the operator based on the version label + set_fact: + operator_version: "{{ operator_pod_raw.resources[0].metadata.labels.version }}" + when: + - operator_pod_raw is defined + - operator_pod_raw.resources[0] is defined + - operator_pod_raw.resources[0].metadata is defined + - operator_pod_raw.resources[0].metadata.labels is defined + - operator_pod_raw.resources[0].metadata.labels.version is defined +- set_fact: + operator_version: "unknown" + when: + - operator_version is not defined +- debug: + msg: "OPERATOR VERSION: [{{ operator_version }}]" + +- name: Print some debug information + vars: + msg: | + OSSM Console Variables: + -------------------------------- + {{ ossmconsole_vars | to_nice_yaml }} + debug: + msg: "{{ msg.split('\n') }}" + +- name: Set default deployment namespace to the same namespace where the CR lives + set_fact: + ossmconsole_vars: "{{ ossmconsole_vars | combine({'deployment': {'namespace': current_cr.metadata.namespace}}, recursive=True) }}" + when: + - ossmconsole_vars.deployment.namespace is not defined or ossmconsole_vars.deployment.namespace == "" + +- name: Do not support installing in any namespace other than where the CR lives + fail: + msg: "The operator currently does not support installing the plugin in any namespace other than the namespace where the CR was created." + when: + - ossmconsole_vars.deployment.namespace != current_cr.metadata.namespace + +# Never allow deployment.namespace to change to avoid leaking resources - to uninstall resources you must delete the OSSMConsole CR +- name: Ensure the deployment.namespace has not changed + fail: + msg: "The deployment.namespace cannot be changed to a different value. It was [{{ current_cr.status.deployment.namespace }}] but is now [{{ ossmconsole_vars.deployment.namespace }}]. In order to install OSSM Console with a different deployment.namespace, please uninstall OSSM Console first." + when: + - current_cr.status is defined + - current_cr.status.deployment is defined + - current_cr.status.deployment.namespace is defined + - current_cr.status.deployment.namespace != ossmconsole_vars.deployment.namespace + +# If we need to auto-discover some things that require the Kiali Route, get the route now - first look in the CR's namespace then anywhere else. If Kiali is not found, abort. +- name: Auto-discover the Kiali Route - preference goes to a Kiali installed in the same namespace as the CR + vars: + kiali_in_namespace: "{{ query(k8s_plugin, label_selector='app.kubernetes.io/name=kiali', api_version='route.openshift.io/v1', kind='Route', namespace=current_cr.metadata.namespace) }}" + kiali_anywhere: "{{ query(k8s_plugin, label_selector='app.kubernetes.io/name=kiali', api_version='route.openshift.io/v1', kind='Route') }}" + set_fact: + kiali_route: "{{ kiali_in_namespace[0] if kiali_in_namespace | length > 0 else (kiali_anywhere[0] if kiali_anywhere | length > 0 else '') }}" + when: + - ossmconsole_vars.kiali.serviceName == "" or ossmconsole_vars.kiali.serviceNamespace == "" or ossmconsole_vars.kiali.servicePort == 0 + ignore_errors: yes + +- fail: + msg: "Failed to auto-discover the Kiali Route. Make sure Kiali is installed. You can specify the full 'kiali' section in the CR if there is a Kiali installed but cannot be auto-discovered by this operator." + when: + - kiali_route is defined + - kiali_route == "" + +- name: Auto-discover the Kiali Service Name + set_fact: + kiali_service_name: "{{ kiali_route.spec.to.name }}" + when: + - ossmconsole_vars.kiali.serviceName == "" + ignore_errors: yes + +- name: Auto-discover the Kiali Service Namespace + set_fact: + kiali_service_namespace: "{{ kiali_route.metadata.namespace }}" + when: + - ossmconsole_vars.kiali.serviceNamespace == "" + ignore_errors: yes + +- name: Auto-discover the Kiali Service Port + set_fact: + kiali_service_port: "{{ kiali_route.spec.port.targetPort }}" + when: + - ossmconsole_vars.kiali.servicePort == 0 + ignore_errors: yes + +- fail: + msg: "Failed to auto-discover the Kiali Service Name. Make sure Kiali is installed. You can specify 'kiali.serviceName' in the CR if there is a Kiali Service the plugin can use but cannot be auto-discovered by this operator." + when: + - ossmconsole_vars.kiali.serviceName == "" + - kiali_service_name is not defined or kiali_service_name == "" + +- fail: + msg: "Failed to auto-discover the Kiali Service Namespace. Make sure Kiali is installed. You can specify 'kiali.serviceNamespace' in the CR if there is a Kiali Service the plugin can use but cannot be auto-discovered by this operator." + when: + - ossmconsole_vars.kiali.serviceNamespace == "" + - kiali_service_namespace is not defined or kiali_service_namespace == "" + +- fail: + msg: "Failed to auto-discover the Kiali Service Port. Make sure Kiali is installed. You can specify 'kiali.servicePort' in the CR if there is a Kiali Service the plugin can use but cannot be auto-discovered by this operator." + when: + - ossmconsole_vars.kiali.servicePort == 0 + - kiali_service_port is not defined or kiali_service_port == "" + +# Set the auto-discovered values that we found +- set_fact: + ossmconsole_vars: "{{ ossmconsole_vars | combine({'kiali': {'serviceName': kiali_service_name}}, recursive=True) }}" + when: + - ossmconsole_vars.kiali.serviceName == "" +- set_fact: + ossmconsole_vars: "{{ ossmconsole_vars | combine({'kiali': {'serviceNamespace': kiali_service_namespace}}, recursive=True) }}" + when: + - ossmconsole_vars.kiali.serviceNamespace == "" +- set_fact: + ossmconsole_vars: "{{ ossmconsole_vars | combine({'kiali': {'servicePort': kiali_service_port}}, recursive=True) }}" + when: + - ossmconsole_vars.kiali.servicePort == 0 + +- name: Determine Kiali version + set_fact: + kiali_version: "{{ lookup('url', version_url, split_lines='no', validate_certs='no') | from_json | json_query(q) }}" + vars: + q: status."Kiali version" + version_url: "{{ 'https://' + ossmconsole_vars.kiali.serviceName + '.' + ossmconsole_vars.kiali.serviceNamespace + '.svc.cluster.local:' + ossmconsole_vars.kiali.servicePort + '/api' }}" + ignore_errors: yes + +- name: "Determine environment to store in status" + set_fact: + status_environment: "{{ status_environment | default({}) | combine({item.0: item.1}) }}" + loop: "{{ data[0] | zip(data[1]) | list }}" + vars: + data: + - ['isMaistra', 'kialiVersion', 'kubernetesVersion', 'openshiftVersion', 'operatorVersion'] + - ["{{is_maistra}}", "{{kiali_version|default('unknown')}}", "{{k8s_version|default('')}}", "{{openshift_version|default('')}}", "{{operator_version}}"] + when: + - item.1 != "" + - item.1 != "false" + - item.1 != False + +- include_tasks: update-status-progress.yml + vars: + status_progress_message: "Setting up configuration" + status_vars: + environment: "{{ status_environment | default({}) }}" + deployment: + namespace: "{{ ossmconsole_vars.deployment.namespace }}" + kiali: + serviceName: "{{ ossmconsole_vars.kiali.serviceName }}" + serviceNamespace: "{{ ossmconsole_vars.kiali.serviceNamespace }}" + servicePort: "{{ ossmconsole_vars.kiali.servicePort }}" + +- name: Only allow ad-hoc OSSM Console image when appropriate + fail: + msg: "The operator is forbidden from accepting an OSSMConsole CR that defines an ad hoc OSSM Console image [{{ ossmconsole_vars.deployment.imageName }}{{ '@' + ossmconsole_vars.deployment.imageDigest if ossmconsole_vars.deployment.imageDigest != '' else '' }}:{{ ossmconsole_vars.deployment.imageVersion }}]. Remove spec.deployment.imageName, spec.deployment.imageVersion, and spec.deployment.imageDigest from the OSSMConsole CR." + when: + - ossmconsole_vars.deployment.imageName != "" or ossmconsole_vars.deployment.imageVersion != "" or ossmconsole_vars.deployment.imageDigest != "" + - lookup('env', 'ALLOW_AD_HOC_OSSMCONSOLE_IMAGE') | default('false', True) != "true" + +- name: Default the image name to a known supported image. + set_fact: + ossmconsole_vars: "{{ ossmconsole_vars | combine({'deployment': {'imageName': supported_ossmconsole_images[ossmconsole_vars.version].imageName}}, recursive=True) }}" + when: + - ossmconsole_vars.deployment.imageName == "" +- name: Default the image version to a known supported image. + set_fact: + ossmconsole_vars: "{{ ossmconsole_vars | combine({'deployment': {'imageVersion': ('latest' if operator_version == 'master' else operator_version) if supported_ossmconsole_images[ossmconsole_vars.version].imageVersion == 'operator_version' else supported_ossmconsole_images[ossmconsole_vars.version].imageVersion}}, recursive=True) }}" + when: + - ossmconsole_vars.deployment.imageVersion == "" + +- name: If image version is latest then we will want to always pull + set_fact: + ossmconsole_vars: "{{ ossmconsole_vars | combine({'deployment': {'imagePullPolicy': 'Always'}}, recursive=True) }}" + when: + - ossmconsole_vars.deployment.imageVersion == "latest" + +- name: Confirm the cluster can access github.com when it needs to determine the last release of Kiali + uri: + url: https://api.github.com/repos/kiali/openshift-servicemesh-plugin/releases + when: + - ossmconsole_vars.deployment.imageVersion == "lastrelease" +- name: Determine image version when last release is to be installed + shell: echo -n $(curl -s https://api.github.com/repos/kiali/openshift-servicemesh-plugin/releases 2> /dev/null | grep "tag_name" | sed -e 's/.*://' -e 's/ *"//' -e 's/",//' | grep -v "snapshot" | sort -t "." -k 1.2g,1 -k 2g,2 -k 3g | tail -n 1) + register: github_lastrelease + when: + - ossmconsole_vars.deployment.imageVersion == "lastrelease" +- set_fact: + ossmconsole_vars: "{{ ossmconsole_vars | combine({'deployment': {'imageVersion': github_lastrelease.stdout}}, recursive=True) }}" + when: + - ossmconsole_vars.deployment.imageVersion == "lastrelease" + +- name: Determine image version when it explicitly was configured as the operator_version + set_fact: + ossmconsole_vars: "{{ ossmconsole_vars | combine({'deployment': {'imageVersion': 'latest' if operator_version == 'master' else operator_version}}, recursive=True) }}" + when: + - ossmconsole_vars.deployment.imageVersion == "operator_version" + +- fail: + msg: "Could not determine what the image version should be. Set deployment.imageVersion to a valid value" + when: + - ossmconsole_vars.deployment.imageVersion == "" or ossmconsole_vars.deployment.imageVersion == "unknown" + +# Indicate which image we are going to use. +- debug: + msg: "IMAGE_NAME={{ ossmconsole_vars.deployment.imageName }}; IMAGE VERSION={{ ossmconsole_vars.deployment.imageVersion }}" + +- name: Determine what metadata labels to apply to all created resources + set_fact: + ossmconsole_resource_metadata_labels: + app: ossmconsole + version: "{{ ossmconsole_vars.deployment.imageVersion }}" + app.kubernetes.io/name: ossmconsole + app.kubernetes.io/version: "{{ ossmconsole_vars.deployment.imageVersion }}" + app.kubernetes.io/instance: ossmconsole + app.kubernetes.io/part-of: ossmconsole + +- name: Delete OSSM Console deployment if image is changing - this uninstalls any old version of OSSM Console that might be running + k8s: + state: absent + api_version: apps/v1 + kind: Deployment + namespace: "{{ ossmconsole_vars.deployment.namespace }}" + name: ossmconsole + when: + - current_image_name is defined and current_image_version is defined + - (current_image_name != ossmconsole_vars.deployment.imageName) or (current_image_version != ossmconsole_vars.deployment.imageVersion) + +# Get the deployment's custom annotation we set that tells us when we last updated the Deployment. +# We need this to ensure the Deployment we update retains this same timestamp unless changes are made +# that requires a pod restart - in which case we update this timestamp. +- name: Find current deployment, if it exists + set_fact: + current_deployment: "{{ lookup(k8s_plugin, resource_name='ossmconsole', namespace=ossmconsole_vars.deployment.namespace, api_version='apps/v1', kind='Deployment') }}" + +- name: Get current deployment last-updated annotation timestamp from existing deployment + set_fact: + current_deployment_last_updated: "{{ current_deployment.spec.template.metadata.annotations['ossmconsole.kiali.io/last-updated'] if current_deployment.spec.template.metadata.annotations['ossmconsole.kiali.io/last-updated'] is defined else lookup('pipe','date') }}" + deployment_is_new: false + when: + - current_deployment is defined + - current_deployment.spec is defined + - current_deployment.spec.template is defined + - current_deployment.spec.template.metadata is defined + - current_deployment.spec.template.metadata.annotations is defined + +- name: Set current deployment last-updated annotation timestamp for new deployments + set_fact: + current_deployment_last_updated: "{{ lookup('pipe','date') }}" + deployment_is_new: true + when: + - current_deployment_last_updated is not defined + +# Now deploy all resources for the specific cluster environment + +- name: Execute for OpenShift environment + include: openshift/os-main.yml + vars: + deployment_last_updated: "{{ current_deployment_last_updated }}" + +# If something changed that can only be picked up when the OSSM Console pod starts up, then restart the pod using a rolling restart +# We do this by checking the processed_resources_dict created by process-resources.yml task. If there is a map key +# with the kind (ConfigMap) with the name of our config map appended to it ("-plugin-conf") see if that config map changed. +# If it did, we need to restart the pod so it can re-read the new config. +- name: Force the OSSM Console pod to restart if necessary + vars: + keyname: "{{ 'ConfigMap-plugin-conf' }}" + updated_deployment: "{{ lookup(k8s_plugin, resource_name='ossmconsole', namespace=ossmconsole_vars.deployment.namespace, api_version='apps/v1', kind='Deployment') | combine({'spec': {'template': {'metadata': {'annotations': {'ossmconsole.kiali.io/last-updated': lookup('pipe','date') }}}}}, recursive=True) }}" + k8s: + state: "present" + definition: "{{ updated_deployment }}" + when: + - deployment_is_new == False + - processed_resources_dict is defined + - processed_resources_dict[keyname] is defined + - processed_resources_dict[keyname].changed == True + - processed_resources_dict[keyname].method == "patch" + +- include_tasks: update-status-progress.yml + vars: + status_progress_message: "Enabling plugin" + status_vars: {} + +- name: Enable plugin by ensuring the OSSM Console is in the Console list of plugins + vars: + existing_plugins: "{{ lookup(k8s_plugin, resource_name='cluster', api_version='operator.openshift.io/v1', kind='Console').spec.plugins | default([]) }}" + k8s: + state: patched + api_version: operator.openshift.io/v1 + kind: Console + name: cluster + definition: + spec: + plugins: "{{ (existing_plugins | difference(['ossmconsole'])) + ['ossmconsole'] }}" + +- include_tasks: update-status-progress.yml + vars: + status_progress_message: "Finished" + status_vars: {} diff --git a/roles/default/ossmconsole-deploy/tasks/openshift/os-main.yml b/roles/default/ossmconsole-deploy/tasks/openshift/os-main.yml new file mode 100644 index 00000000..98aebb69 --- /dev/null +++ b/roles/default/ossmconsole-deploy/tasks/openshift/os-main.yml @@ -0,0 +1,13 @@ +- include_tasks: update-status-progress.yml + vars: + status_progress_message: "Creating core resources" + +- name: Create OSSM Console objects on OpenShift + include_tasks: process-resource.yml + vars: + process_resource_templates: + - "templates/openshift/configmap-nginx.yaml" + - "templates/openshift/configmap-plugin.yaml" + - "templates/openshift/deployment.yaml" + - "templates/openshift/service.yaml" + - "templates/openshift/consoleplugin.yaml" \ No newline at end of file diff --git a/roles/default/ossmconsole-deploy/tasks/process-resource.yml b/roles/default/ossmconsole-deploy/tasks/process-resource.yml new file mode 100644 index 00000000..9b165d44 --- /dev/null +++ b/roles/default/ossmconsole-deploy/tasks/process-resource.yml @@ -0,0 +1,31 @@ +# process all template names found in process_resource_templates - any empty strings in the list are ignored. +# This will keep a running tally of all processed resources in "processed_resources_dict". +- name: "Create Kiali resources from templates" + k8s: + state: "present" + continue_on_error: false + template: "{{ process_resource_templates | select() | list }}" + register: process_resource_templates_result + retries: 6 + delay: 10 + +# Store the results of the processed resource so they can be examined later (e.g. to know if something changed or stayed the same) +- vars: + kinds: "{{ process_resource_templates_result.result.results | map(attribute='result.kind') | list }}" + names: "{{ process_resource_templates_result.result.results | map(attribute='result.metadata.name') | list }}" + changed: "{{ process_resource_templates_result.result.results | map(attribute='changed') | list }}" + method: "{{ process_resource_templates_result.result.results | map(attribute='method') | list }}" + thedict: "{{ processed_resources_dict | default({}) }}" + set_fact: + processed_resources_dict: | + {% for kind in kinds %} + {% set _ = thedict.update({ (kind + '-' + names[loop.index0]): {'name': names[loop.index0], 'changed': changed[loop.index0], 'method': method[loop.index0]}}) %} + {% endfor %} + {{ thedict }} + when: + - process_resource_templates_result is defined + - process_resource_templates_result | length > 0 + +- name: "Resource creation results" + debug: + msg: "{{ processed_resources_dict }}" \ No newline at end of file diff --git a/roles/default/ossmconsole-deploy/tasks/update-status-progress.yml b/roles/default/ossmconsole-deploy/tasks/update-status-progress.yml new file mode 100644 index 00000000..58570bce --- /dev/null +++ b/roles/default/ossmconsole-deploy/tasks/update-status-progress.yml @@ -0,0 +1,16 @@ +- name: Prepare status progress facts + ignore_errors: yes + set_fact: + status_progress_step: "{{ 1 if status_progress_step is not defined else (status_progress_step|int + 1) }}" + status_progress_start: "{{ ('%Y-%m-%d %H:%M:%S' | strftime) if status_progress_start is not defined else (status_progress_start) }}" + +- name: Update CR status progress field with any additional status fields + ignore_errors: yes + vars: + duration: "{{ ('%Y-%m-%d %H:%M:%S' | strftime | to_datetime) - (status_progress_start | to_datetime) }}" + operator_sdk.util.k8s_status: + api_version: "{{ current_cr.apiVersion }}" + kind: "{{ current_cr.kind }}" + name: "{{ current_cr.metadata.name }}" + namespace: "{{ current_cr.metadata.namespace }}" + status: "{{ status_vars | default({}) | combine({'progress':{'message': status_progress_step + '. ' + status_progress_message, 'duration': duration }}, recursive=True) }}" diff --git a/roles/default/ossmconsole-deploy/tasks/update-status.yml b/roles/default/ossmconsole-deploy/tasks/update-status.yml new file mode 100644 index 00000000..fa779308 --- /dev/null +++ b/roles/default/ossmconsole-deploy/tasks/update-status.yml @@ -0,0 +1,8 @@ +- name: Update CR status field + ignore_errors: yes + operator_sdk.util.k8s_status: + api_version: "{{ current_cr.apiVersion }}" + kind: "{{ current_cr.kind }}" + name: "{{ current_cr.metadata.name }}" + namespace: "{{ current_cr.metadata.namespace }}" + status: "{{ status_vars }}" diff --git a/roles/default/ossmconsole-deploy/templates/openshift/configmap-nginx.yaml b/roles/default/ossmconsole-deploy/templates/openshift/configmap-nginx.yaml new file mode 100644 index 00000000..ba0e660c --- /dev/null +++ b/roles/default/ossmconsole-deploy/templates/openshift/configmap-nginx.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: nginx-conf + namespace: {{ ossmconsole_vars.deployment.namespace }} + labels: {{ ossmconsole_resource_metadata_labels }} +data: + nginx.conf: | + error_log /dev/stdout; + events {} + http { + access_log /dev/stdout; + include /etc/nginx/mime.types; + default_type application/octet-stream; + keepalive_timeout 65; + server { + listen 9443 ssl; + ssl_certificate /var/serving-cert/tls.crt; + ssl_certificate_key /var/serving-cert/tls.key; + + add_header oauth_token "$http_Authorization"; + + location / { + root /usr/share/nginx/html; + } + } + } diff --git a/roles/default/ossmconsole-deploy/templates/openshift/configmap-plugin.yaml b/roles/default/ossmconsole-deploy/templates/openshift/configmap-plugin.yaml new file mode 100644 index 00000000..a198dcd9 --- /dev/null +++ b/roles/default/ossmconsole-deploy/templates/openshift/configmap-plugin.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: plugin-conf + namespace: {{ ossmconsole_vars.deployment.namespace }} + labels: {{ ossmconsole_resource_metadata_labels }} +data: + plugin-config.json: | + { + "graph": { + "impl": "{{ ossmconsole_vars.kiali.graph.impl }}" + } + } diff --git a/roles/default/ossmconsole-deploy/templates/openshift/consoleplugin.yaml b/roles/default/ossmconsole-deploy/templates/openshift/consoleplugin.yaml new file mode 100644 index 00000000..5aa65869 --- /dev/null +++ b/roles/default/ossmconsole-deploy/templates/openshift/consoleplugin.yaml @@ -0,0 +1,20 @@ +apiVersion: console.openshift.io/v1alpha1 +kind: ConsolePlugin +metadata: + name: ossmconsole + labels: {{ ossmconsole_resource_metadata_labels }} +spec: + displayName: "OpenShift Service Mesh Console" + service: + name: ossmconsole + namespace: {{ ossmconsole_vars.deployment.namespace }} + port: 9443 + basePath: "/" + proxy: + - type: Service + alias: kiali + authorize: true + service: + name: {{ ossmconsole_vars.kiali.serviceName }} + namespace: {{ ossmconsole_vars.kiali.serviceNamespace }} + port: {{ ossmconsole_vars.kiali.servicePort }} \ No newline at end of file diff --git a/roles/default/ossmconsole-deploy/templates/openshift/deployment.yaml b/roles/default/ossmconsole-deploy/templates/openshift/deployment.yaml new file mode 100644 index 00000000..f0d5fb4e --- /dev/null +++ b/roles/default/ossmconsole-deploy/templates/openshift/deployment.yaml @@ -0,0 +1,71 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ossmconsole + namespace: {{ ossmconsole_vars.deployment.namespace }} + labels: {{ ossmconsole_resource_metadata_labels }} +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: ossmconsole + app.kubernetes.io/instance: ossmconsole + template: + metadata: + name: ossmconsole + labels: {{ ossmconsole_resource_metadata_labels }} + annotations: + ossmconsole.kiali.io/last-updated: "{{ deployment_last_updated }}" + spec: +{% if ossmconsole_vars.deployment.imagePullSecrets | default([]) | length > 0 %} + imagePullSecrets: +{% for n in ossmconsole_vars.deployment.imagePullSecrets %} + - name: {{ n }} +{% endfor %} +{% endif %} + containers: + - name: ossmconsole + image: {{ ossmconsole_vars.deployment.imageName }}{{ '@' + ossmconsole_vars.deployment.imageDigest if ossmconsole_vars.deployment.imageDigest != '' else '' }}:{{ ossmconsole_vars.deployment.imageVersion }} + imagePullPolicy: {{ ossmconsole_vars.deployment.imagePullPolicy }} + ports: + - containerPort: 9443 + protocol: TCP + securityContext: + allowPrivilegeEscalation: false + privileged: false + runAsNonRoot: true + capabilities: + drop: + - ALL + volumeMounts: + - name: ossmconsole-cert-secret + readOnly: true + mountPath: /var/serving-cert + - name: nginx-conf + readOnly: true + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + - name: plugin-conf + readOnly: true + mountPath: /usr/share/nginx/html/plugin-config.json + subPath: plugin-config.json + volumes: + - name: ossmconsole-cert-secret + secret: + secretName: ossmconsole-cert-secret + defaultMode: 420 + - name: nginx-conf + configMap: + name: nginx-conf + defaultMode: 420 + - name: plugin-conf + configMap: + name: plugin-conf + defaultMode: 420 + restartPolicy: Always + dnsPolicy: ClusterFirst + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: "25%" + maxSurge: "25%" diff --git a/roles/default/ossmconsole-deploy/templates/openshift/service.yaml b/roles/default/ossmconsole-deploy/templates/openshift/service.yaml new file mode 100644 index 00000000..190a24dd --- /dev/null +++ b/roles/default/ossmconsole-deploy/templates/openshift/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: ossmconsole + namespace: {{ ossmconsole_vars.deployment.namespace }} + labels: {{ ossmconsole_resource_metadata_labels }} + annotations: + service.beta.openshift.io/serving-cert-secret-name: ossmconsole-cert-secret +spec: + ports: + - name: 9443-tcp + protocol: TCP + port: 9443 + targetPort: 9443 + selector: + app.kubernetes.io/name: ossmconsole + app.kubernetes.io/instance: ossmconsole + type: ClusterIP + sessionAffinity: None diff --git a/roles/default/ossmconsole-deploy/vars/main.yml b/roles/default/ossmconsole-deploy/vars/main.yml new file mode 100644 index 00000000..c67b8805 --- /dev/null +++ b/roles/default/ossmconsole-deploy/vars/main.yml @@ -0,0 +1,30 @@ +# These are the actual variables used by the role. You will notice it is +# one big dictionary (key="ossmconsole_vars") whose child dictionaries mimic those +# as defined in defaults/main.yml. +# The child dictionaries below will have values that are a combination of the default values +# (as found in defaults/main.yaml) and user-supplied values. +# Without this magic, a user supplying only one key/value pair in a child dictionary will +# clear out (make undefined) all the rest of the key/value pairs in that child dictionary. +# This is not what we want. We want the rest of the dictionary to keep the defaults, +# thus allowing the user to override only a subset of key/values in a dictionary. +# +# I found this trick at https://groups.google.com/forum/#!topic/Ansible-project/pGbRYZyqxZ4 +# I tweeked that solution a little bit because I did not want to require the user to supply +# everything under a main "ossmconsole_vars" dictionary. + +ossmconsole_vars: + version: "{{ version | default(ossmconsole_defaults.version) }}" + + deployment: | + {%- if deployment is defined and deployment is iterable -%} + {{ ossmconsole_defaults.deployment | combine((deployment | stripnone), recursive=True) }} + {%- else -%} + {{ ossmconsole_defaults.deployment }} + {%- endif -%} + + kiali: | + {%- if kiali is defined and kiali is iterable -%} + {{ ossmconsole_defaults.kiali | combine((kiali | stripnone), recursive=True) }} + {%- else -%} + {{ ossmconsole_defaults.kiali }} + {%- endif -%} diff --git a/roles/default/ossmconsole-remove/defaults/main.yml b/roles/default/ossmconsole-remove/defaults/main.yml new file mode 100644 index 00000000..71bbb33a --- /dev/null +++ b/roles/default/ossmconsole-remove/defaults/main.yml @@ -0,0 +1,3 @@ +ossmconsole_defaults: + deployment: + namespace: "" diff --git a/roles/default/ossmconsole-remove/filter_plugins/stripnone.py b/roles/default/ossmconsole-remove/filter_plugins/stripnone.py new file mode 100644 index 00000000..4dbd5303 --- /dev/null +++ b/roles/default/ossmconsole-remove/filter_plugins/stripnone.py @@ -0,0 +1,28 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} + +# Process recursively the given value if it is a dict and remove all keys that have a None value +def strip_none(value): + if isinstance(value, dict): + dicts = {} + for k,v in value.items(): + if isinstance(v, dict): + dicts[k] = strip_none(v) + elif v is not None: + dicts[k] = v + return dicts + else: + return value + +# ---- Ansible filters ---- +class FilterModule(object): + def filters(self): + return { + 'stripnone': strip_none + } diff --git a/roles/default/ossmconsole-remove/meta/main.yml b/roles/default/ossmconsole-remove/meta/main.yml new file mode 100644 index 00000000..e9334e3c --- /dev/null +++ b/roles/default/ossmconsole-remove/meta/main.yml @@ -0,0 +1,2 @@ +collections: +- kubernetes.core diff --git a/roles/default/ossmconsole-remove/tasks/main.yml b/roles/default/ossmconsole-remove/tasks/main.yml new file mode 100644 index 00000000..9fc3d6df --- /dev/null +++ b/roles/default/ossmconsole-remove/tasks/main.yml @@ -0,0 +1,56 @@ +# These tasks remove all resources such that no remnants of OSSM Console will remain. +# +# Note that we ignore_errors everywhere - we do not want these tasks to ever abort with a failure. +# This is because these are run within a finalizer and if a failure aborts any task here +# the user will never be able to delete the OSSMConsole CR - in fact, the delete will hang indefinitely +# and the user will need to do an ugly hack to fix it. + +- ignore_errors: yes + set_fact: + k8s_plugin: kubernetes.core.k8s + +- name: Get the original CR that was deleted + ignore_errors: yes + set_fact: + current_cr: "{{ _kiali_io_ossmconsole }}" + +- name: Print some debug information + ignore_errors: yes + vars: + msg: | + OSSM Console Variables: + -------------------------------- + {{ ossmconsole_vars_remove | to_nice_yaml }} + debug: + msg: "{{ msg.split('\n') }}" + +- name: Set default deployment namespace to the same namespace where the CR lives + ignore_errors: yes + set_fact: + ossmconsole_vars_remove: "{{ ossmconsole_vars_remove | combine({'deployment': {'namespace': current_cr.metadata.namespace}}, recursive=True) }}" + when: + - ossmconsole_vars_remove.deployment.namespace is not defined or ossmconsole_vars_remove.deployment.namespace == "" + +- name: Disable plugin by ensuring the OSSM Console is removed from the Console list of plugins + ignore_errors: yes + vars: + existing_plugins: "{{ lookup('kubernetes.core.k8s', resource_name='cluster', api_version='operator.openshift.io/v1', kind='Console').spec.plugins | default([]) }}" + k8s: + state: patched + api_version: operator.openshift.io/v1 + kind: Console + name: cluster + definition: + spec: + plugins: "{{ existing_plugins | difference(['ossmconsole']) }}" + +- name: Delete OSSM Console resources + ignore_errors: yes + k8s: + state: absent + namespace: "{{ ossmconsole_vars_remove.deployment.namespace }}" + continue_on_error: false + template: + - resources-to-remove.yml + retries: 6 + delay: 10 diff --git a/roles/default/ossmconsole-remove/tasks/resources-to-remove.yml b/roles/default/ossmconsole-remove/tasks/resources-to-remove.yml new file mode 100644 index 00000000..bbe89a75 --- /dev/null +++ b/roles/default/ossmconsole-remove/tasks/resources-to-remove.yml @@ -0,0 +1,29 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ ossmconsole_vars_remove.deployment.namespace }} + name: nginx-config +--- +apiVersion: v1 +kind: ConfigMap +metadata: + namespace: {{ ossmconsole_vars_remove.deployment.namespace }} + name: plugin-config +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: {{ ossmconsole_vars_remove.deployment.namespace }} + name: ossmconsole +--- +apiVersion: v1 +kind: Service +metadata: + namespace: {{ ossmconsole_vars_remove.deployment.namespace }} + name: ossmconsole +--- +apiVersion: console.openshift.io/v1alpha1 +kind: ConsolePlugin +metadata: + name: ossmconsole diff --git a/roles/default/ossmconsole-remove/vars/main.yml b/roles/default/ossmconsole-remove/vars/main.yml new file mode 100644 index 00000000..f2bbfbc2 --- /dev/null +++ b/roles/default/ossmconsole-remove/vars/main.yml @@ -0,0 +1,7 @@ +ossmconsole_vars_remove: + deployment: | + {%- if deployment is defined and deployment is iterable -%} + {{ ossmconsole_defaults.deployment | combine((deployment | stripnone), recursive=True) }} + {%- else -%} + {{ ossmconsole_defaults.deployment }} + {%- endif -%} diff --git a/watches.yaml b/watches.yaml index e02abdf9..e30a68a7 100644 --- a/watches.yaml +++ b/watches.yaml @@ -20,4 +20,16 @@ manageStatus: False watchDependentResources: False watchClusterScopedResources: False - watchAnnotationsChanges: False \ No newline at end of file + watchAnnotationsChanges: False +# The normal processing for the OpenShift ServiceMesh Console plugin playbook +- version: v1alpha1 + group: kiali.io + kind: OSSMConsole + playbook: playbooks/ossmconsole-deploy.yml + reconcilePeriod: "0s" + watchDependentResources: False + watchClusterScopedResources: False + snakeCaseParameters: False + finalizer: + name: kiali.io/finalizer + playbook: playbooks/ossmconsole-remove.yml