From 0c826f50b78e4bc8dcba4ac431d848d1185047e6 Mon Sep 17 00:00:00 2001 From: Fabian Mueller Date: Fri, 8 Sep 2023 15:58:37 +0200 Subject: [PATCH] updates to Makefile to enable image digests Use Digest for Grafana Instance Image Add grafana image to CSV; update release guidelines --- Makefile | 40 +- PREPARE_RELEASE.md | 27 +- ...rafana-operator.clusterserviceversion.yaml | 472 +++++++++--------- controllers/config/operator_constants.go | 6 +- .../grafana/deployment_reconciler.go | 2 +- 5 files changed, 291 insertions(+), 256 deletions(-) diff --git a/Makefile b/Makefile index e9750b36a..64dd5eccd 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,20 @@ # Current Operator version VERSION ?= 5.4.1 +# BUNDLE_GEN_FLAGS are the flags passed to the operator-sdk generate bundle command +BUNDLE_GEN_FLAGS ?= -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) + +# USE_IMAGE_DIGESTS defines if images are resolved via tags or digests +# You can enable this value if you would like to use SHA Based Digests +# To enable set flag to true +USE_IMAGE_DIGESTS ?= true +ifeq ($(USE_IMAGE_DIGESTS), true) + BUNDLE_GEN_FLAGS += --use-image-digests +endif + +# Set the Operator SDK version to use. By default, what is installed on the system is used. +# This is useful for CI or a project to utilize a specific version of the operator-sdk toolkit. +OPERATOR_SDK_VERSION ?= v1.31.0 # Image URL to use all building/pushing image targets REGISTRY ?= ghcr.io REPO ?= grafana-operator @@ -155,6 +169,23 @@ envtest: $(ENVTEST) ## Download envtest-setup locally if necessary. $(ENVTEST): $(LOCALBIN) test -s $(LOCALBIN)/setup-envtest || GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest +.PHONY: operator-sdk +OPERATOR_SDK ?= $(LOCALBIN)/operator-sdk +operator-sdk: ## Download operator-sdk locally if necessary. +ifeq (,$(wildcard $(OPERATOR_SDK))) +ifeq (, $(shell which operator-sdk 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPERATOR_SDK)) ;\ + OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(OPERATOR_SDK) https://github.com/operator-framework/operator-sdk/releases/download/$(OPERATOR_SDK_VERSION)/operator-sdk_$${OS}_$${ARCH} ;\ + chmod +x $(OPERATOR_SDK) ;\ + } +else +OPERATOR_SDK = $(shell which operator-sdk) +endif +endif + ### # END OF kubebuilder SECTION ### @@ -179,12 +210,11 @@ endif BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) .PHONY: bundle -bundle: manifests kustomize ## Generate bundle manifests and metadata, then validate generated files. - operator-sdk generate kustomize manifests -q +bundle: manifests kustomize operator-sdk ## Generate bundle manifests and metadata, then validate generated files. + $(OPERATOR_SDK) generate kustomize manifests -q cd config/manager && $(KUSTOMIZE) edit set image controller=$(IMG) - $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) - operator-sdk bundle validate ./bundle - + $(KUSTOMIZE) build config/manifests | $(OPERATOR_SDK) generate bundle $(BUNDLE_GEN_FLAGS) + $(OPERATOR_SDK) bundle validate ./bundle # e2e .PHONY: e2e diff --git a/PREPARE_RELEASE.md b/PREPARE_RELEASE.md index 4e368bbd5..17b4d60ac 100644 --- a/PREPARE_RELEASE.md +++ b/PREPARE_RELEASE.md @@ -15,19 +15,22 @@ After that you need to run `make helm/docs` which will generate the changes to b There is a lot of information on what is needed to manage OLM [compatible operators](https://redhat-connect.gitbook.io/certified-operator-guide/ocp-deployment/operator-metadata/creating-the-csv). - Update the `Makefile` version -- `make generate`, `make manifests` & `make bundle` -- Update `containerImage` field in `config/manifests/bases/grafana-operator.clusterserviceversion.yaml` -- Update `replaces` field in `config/manifests/bases/grafana-operator.clusterserviceversion.yaml` -- Update `CreatedAt` field in `config/manifests/bases/grafana-operator.clusterserviceversion.yaml` - You will have to asses when it's going to get merged and you will be able to do a release. - You should make sure it's the same date. If not you will have to change it - manually when creating PR:s to OLM. - - # This is how the time syntax should look. - $ docker inspect ghcr.io/grafana-operator/grafana-operator:v5.0.0 |jq '.[0].Created' - "2023-11-22T10:34:12.173861869Z" - # 2023-11-22T10:34:12Z is enough +- Run `make generate` & `make manifests` +- Update the following fields under `metadata.annotations` in `config/manifests/bases/grafana-operator.clusterserviceversion.yaml`: + - `containerImage` + - `replaces` + - `createdAt`: You will have to asses when it's going to get merged and you will be able to do a release. You should make sure it's the same date. If not you will have to change it manually when creating PR:s to OLM. + ``` + # This is how the time syntax should look. + $ docker inspect ghcr.io/grafana-operator/grafana-operator:v5.0.0 |jq '.[0].Created' + "2023-11-22T10:34:12.173861869Z" + # 2023-11-22T10:34:12Z is enough + ``` - Run `make bundle` +- Add the grafana image specified by digest to `spec.relatedImages` to `bundle/manifests/grafana-operator.clusterserviceversion.yaml` by running + ``` + GRAFANA_IMAGE="$(grep 'GrafanaImage =' controllers/config/operator_constants.go| awk -F '"' '{print $2}')@$(grep 'GrafanaDigest =' controllers/config/operator_constants.go| awk -F '"' '{print $2}')" yq -i '.spec.relatedImages += {"image": strenv(GRAFANA_IMAGE), "name": "grafana"}' bundle/manifests/grafana-operator.clusterserviceversion.yaml + ``` - `Helm` look if any rbac rules have been changed in the last release, if so verify that the rbac rules for the helm chart is correct. This should be done in those PRs but it don't hurt take an extra look. - Create a PR and get it merged - Create a new release with the new tag, make sure to compile release notes (github has an option to do this for you) diff --git a/bundle/manifests/grafana-operator.clusterserviceversion.yaml b/bundle/manifests/grafana-operator.clusterserviceversion.yaml index 713ddaf0d..79a443d8b 100644 --- a/bundle/manifests/grafana-operator.clusterserviceversion.yaml +++ b/bundle/manifests/grafana-operator.clusterserviceversion.yaml @@ -106,202 +106,202 @@ spec: apiservicedefinitions: {} customresourcedefinitions: owned: - - description: GrafanaDashboard is the Schema for the grafanadashboards API - displayName: Grafana Dashboard - kind: GrafanaDashboard - name: grafanadashboards.grafana.integreatly.org - version: v1beta1 - - description: GrafanaDatasource is the Schema for the grafanadatasources API - displayName: Grafana Datasource - kind: GrafanaDatasource - name: grafanadatasources.grafana.integreatly.org - version: v1beta1 - - description: GrafanaFolder is the Schema for the grafanafolders API - displayName: Grafana Folder - kind: GrafanaFolder - name: grafanafolders.grafana.integreatly.org - version: v1beta1 - - description: Grafana is the Schema for the grafanas API - displayName: Grafana - kind: Grafana - name: grafanas.grafana.integreatly.org - version: v1beta1 + - description: GrafanaDashboard is the Schema for the grafanadashboards API + displayName: Grafana Dashboard + kind: GrafanaDashboard + name: grafanadashboards.grafana.integreatly.org + version: v1beta1 + - description: GrafanaDatasource is the Schema for the grafanadatasources API + displayName: Grafana Datasource + kind: GrafanaDatasource + name: grafanadatasources.grafana.integreatly.org + version: v1beta1 + - description: GrafanaFolder is the Schema for the grafanafolders API + displayName: Grafana Folder + kind: GrafanaFolder + name: grafanafolders.grafana.integreatly.org + version: v1beta1 + - description: Grafana is the Schema for the grafanas API + displayName: Grafana + kind: Grafana + name: grafanas.grafana.integreatly.org + version: v1beta1 description: Deploys and manages Grafana instances, dashboards and data sources displayName: Grafana Operator icon: - - base64data: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMC4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4KCjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0iTGF5ZXJfMSIKICAgeD0iMHB4IgogICB5PSIwcHgiCiAgIHdpZHRoPSI1Ny43OTk5OTkiCiAgIGhlaWdodD0iNTcuNzk5OTk5IgogICB2aWV3Qm94PSIwIDAgNTcuNzk5OTk5IDU3LjgiCiAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImxvZ29fc21hbGwuc3ZnIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkyLjQgKDVkYTY4OWMzMTMsIDIwMTktMDEtMTQpIj48bWV0YWRhdGEKICAgaWQ9Im1ldGFkYXRhMzc4NSI+PHJkZjpSREY+PGNjOldvcmsKICAgICAgIHJkZjphYm91dD0iIj48ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD48ZGM6dHlwZQogICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPjxkYzp0aXRsZT48L2RjOnRpdGxlPjwvY2M6V29yaz48L3JkZjpSREY+PC9tZXRhZGF0YT48ZGVmcwogICBpZD0iZGVmczM3ODMiIC8+PHNvZGlwb2RpOm5hbWVkdmlldwogICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICBib3JkZXJvcGFjaXR5PSIxIgogICBvYmplY3R0b2xlcmFuY2U9IjEwIgogICBncmlkdG9sZXJhbmNlPSIxMCIKICAgZ3VpZGV0b2xlcmFuY2U9IjEwIgogICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIKICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzg2IgogICBpZD0ibmFtZWR2aWV3Mzc4MSIKICAgc2hvd2dyaWQ9ImZhbHNlIgogICBpbmtzY2FwZTp6b29tPSIxMy44NTg3MTQiCiAgIGlua3NjYXBlOmN4PSI3NS40MTI5MDQiCiAgIGlua3NjYXBlOmN5PSIyMy4wNzc2MDYiCiAgIGlua3NjYXBlOndpbmRvdy14PSIwIgogICBpbmtzY2FwZTp3aW5kb3cteT0iMCIKICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iTGF5ZXJfMSIgLz4KPHN0eWxlCiAgIHR5cGU9InRleHQvY3NzIgogICBpZD0ic3R5bGUzNzY5Ij4KCS5zdDB7ZmlsbDojRTZFN0U4O30KCS5zdDF7ZmlsbDp1cmwoI1NWR0lEXzFfKTt9Cjwvc3R5bGU+Cgo8bGluZWFyR3JhZGllbnQKICAgaWQ9IlNWR0lEXzFfIgogICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgeDE9IjI2LjcwMDAwMSIKICAgeTE9Ii05Ljg1MDE5OTciCiAgIHgyPSIyNi43MDAwMDEiCiAgIHkyPSI0My4xNjYiCiAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsLTEsMiw2MC4wMDAwMDIpIj4KCTxzdG9wCiAgIG9mZnNldD0iMCIKICAgc3R5bGU9InN0b3AtY29sb3I6I0ZGRjEwMCIKICAgaWQ9InN0b3AzNzczIiAvPgoJPHN0b3AKICAgb2Zmc2V0PSIxIgogICBzdHlsZT0ic3RvcC1jb2xvcjojRjA1QTI4IgogICBpZD0ic3RvcDM3NzUiIC8+CjwvbGluZWFyR3JhZGllbnQ+CjxwYXRoCiAgIGNsYXNzPSJzdDEiCiAgIGQ9Im0gNTUuMSwyNS41MDAwMDIgYyAtMC4xLC0xIC0wLjMsLTIuMSAtMC42LC0zLjMgLTAuMywtMS4yIC0wLjgsLTIuNiAtMS41LC00IC0wLjcsLTEuNCAtMS42LC0yLjkgLTIuOCwtNC4zIC0wLjUsLTAuNiAtMSwtMS4xIC0xLjUsLTEuNiAwLjgsLTMuMjAwMDAwNCAtMSwtNi4wMDAwMDA0IC0xLC02LjAwMDAwMDQgLTMuMSwtMC4yIC01LjEsMSAtNS44LDEuNSAtMC4xLC0wLjEgLTAuMiwtMC4xIC0wLjQsLTAuMiAtMC41LC0wLjIgLTEsLTAuNCAtMS42LC0wLjYgLTAuNiwtMC4yIC0xLjEsLTAuMyAtMS43LC0wLjUgLTAuNiwtMC4xIC0xLjIsLTAuMyAtMS44LC0wLjMgLTAuMSwwIC0wLjIsMCAtMC4zLDAgQyAzNC44LDEuODAwMDAxNiAzMC45LDEuNTI1ODc4OWUtNiAzMC45LDEuNTI1ODc4OWUtNiAyNi42LDIuODAwMDAxNiAyNS43LDYuNjAwMDAxNiAyNS43LDYuNjAwMDAxNiBjIDAsMCAwLDAuMSAwLDAuMiAtMC4yLDAuMSAtMC41LDAuMSAtMC43LDAuMiAtMC4zLDAuMSAtMC43LDAuMiAtMSwwLjMgLTAuMywwLjEgLTAuNywwLjMgLTEsMC40IC0wLjcsMC4zIC0xLjMsMC42IC0xLjksMSAtMC42LDAuMyAtMS4yLDAuNyAtMS44LDEuMSAtMC4xLDAgLTAuMiwtMC4xIC0wLjIsLTAuMSAtNiwtMi4zIC0xMS40LDAuNTAwMDAwNCAtMTEuNCwwLjUwMDAwMDQgLTAuNSw2LjQgMi40LDEwLjQgMywxMS4yIC0wLjEsMC40IC0wLjMsMC44IC0wLjQsMS4yIC0wLjQsMS40IC0wLjgsMi45IC0xLDQuNSAwLDAuMiAtMC4xLDAuNCAtMC4xLDAuNyAtNS42LDIuNyAtNy4yLDguNCAtNy4yLDguNCA0LjYsNS4zIDEwLDUuNyAxMCw1LjcgdiAwIGMgMC43LDEuMiAxLjUsMi40IDIuNCwzLjUgMC40LDAuNSAwLjgsMC45IDEuMiwxLjMgLTEuNyw0LjggMC4yLDguOSAwLjIsOC45IDUuMiwwLjIgOC42LC0yLjMgOS4zLC0yLjggMC41LDAuMiAxLDAuMyAxLjYsMC41IDEuNiwwLjQgMy4yLDAuNiA0LjgsMC43IDAuNCwwIDAuOCwwIDEuMiwwIGggMC4yIDAuMSAwLjMgMC4zIHYgMCBjIDIuNCwzLjUgNi43LDQgNi43LDQgMy40LC0zLjYgMy4yLC03LjIgMy4yLC03LjIgbCAtMC4xLC0wLjEgYyAwLjcsLTAuNSAxLjMsLTEgMS45LC0xLjUgMS4yLC0xLjEgMi4zLC0yLjQgMy4yLC0zLjcgMC4xLC0wLjEgMC4yLC0wLjMgMC4yLC0wLjQgMy40LDAuMiA1LjksLTIuMSA1LjksLTIuMSAtMC42LC00IC0zLjEsLTUuNyAtMy4xLC01LjcgaCAtMC4xIGMgMCwtMC4yIDAsLTAuNSAwLjEsLTAuNyAwLC0wLjQgMCwtMC44IDAsLTEuMiB2IC0wLjMgLTAuMSAtMC4xIGMgMCwtMC4xIDAsLTAuMSAwLC0wLjEgdiAtMC4yIC0wLjMgYyAwLC0wLjEgMCwtMC4yIDAsLTAuMyAwLC0wLjEgMCwtMC4yIDAsLTAuMyB2IC0wLjMgLTAuMyBjIC0wLjEsLTAuNCAtMC4xLC0wLjggLTAuMiwtMS4yIC0wLjQsLTEuNSAtMSwtMyAtMS44LC00LjMgLTAuOCwtMS4zIC0xLjgsLTIuNSAtMi45LC0zLjUgLTEuMSwtMSAtMi40LC0xLjggLTMuNywtMi40IC0xLjMsLTAuNiAtMi43LC0xIC00LjEsLTEuMSAtMC43LC0wLjEgLTEuNCwtMC4xIC0yLC0wLjEgaCAtMC4zIC0wLjEgLTAuMSAtMC4xIC0wLjMgYyAtMC4xLDAgLTAuMiwwIC0wLjMsMCAtMC4zLDAgLTAuNywwLjEgLTEsMC4xIC0xLjQsMC4zIC0yLjcsMC43IC0zLjgsMS40IC0xLjEsMC43IC0yLjEsMS41IC0yLjksMi41IC0wLjgsMSAtMS40LDIgLTEuOSwzLjEgLTAuNCwxLjEgLTAuNywyLjIgLTAuNywzLjMgMCwwLjMgMCwwLjYgMCwwLjggMCwwLjEgMCwwLjEgMCwwLjIgdiAwLjIgYyAwLDAuMSAwLDAuMyAwLDAuNCAwLjEsMC42IDAuMiwxLjEgMC4zLDEuNiAwLjMsMSAwLjgsMiAxLjQsMi44IDAuNiwwLjggMS4zLDEuNSAyLjEsMiAwLjgsMC41IDEuNiwwLjkgMi40LDEuMSAwLjgsMC4yIDEuNiwwLjMgMi4zLDAuMyAwLjEsMCAwLjIsMCAwLjMsMCBoIDAuMSAwLjEgYyAwLjEsMCAwLjIsMCAwLjIsMCAwLDAgMCwwIDAuMSwwIGggMC4xIDAuMSBjIDAuMSwwIDAuMiwwIDAuMywwIDAuMSwwIDAuMiwwIDAuMywtMC4xIDAuMiwwIDAuMywtMC4xIDAuNSwtMC4xIDAuMywtMC4xIDAuNiwtMC4yIDAuOSwtMC40IDAuMywtMC4xIDAuNSwtMC4zIDAuOCwtMC41IDAuMSwtMC4xIDAuMSwtMC4xIDAuMiwtMC4yIDAuMywtMC4yIDAuMywtMC42IDAuMSwtMC44IC0wLjIsLTAuMiAtMC41LC0wLjMgLTAuNywtMC4xIC0wLjIsLTAuMiAtMC4yLC0wLjEgLTAuMywtMC4xIC0wLjIsMC4xIC0wLjQsMC4yIC0wLjcsMC4zIC0wLjIsMC4xIC0wLjUsMC4xIC0wLjgsMC4yIC0wLjEsMCAtMC4zLDAgLTAuNCwwIC0wLjEsMCAtMC4xLDAgLTAuMiwwIC0wLjEsMCAtMC4xLDAgLTAuMiwwIC0wLjEsMCAtMC4xLDAgLTAuMiwwIC0wLjEsMCAtMC4yLDAgLTAuMiwwIHYgMCAwIEggMzQuMSAzNCBjIC0wLjEsMCAtMC4xLDAgLTAuMiwwIC0wLjYsLTAuMSAtMS4yLC0wLjMgLTEuNywtMC41IC0wLjYsLTAuMyAtMS4xLC0wLjYgLTEuNiwtMS4xIC0wLjUsLTAuNCAtMC45LC0xIC0xLjMsLTEuNiAtMC4zLC0wLjYgLTAuNiwtMS4zIC0wLjcsLTIgLTAuMSwtMC4zIC0wLjEsLTAuNyAtMC4xLC0xLjEgMCwtMC4xIDAsLTAuMiAwLC0wLjMgdiAwIDAgLTAuMSAtMC4xIGMgMCwtMC4yIDAsLTAuNCAwLjEsLTAuNiAwLjMsLTEuNSAxLC0zIDIuMiwtNC4yIDAuMywtMC4zIDAuNiwtMC41IDEsLTAuOCAwLjMsLTAuMiAwLjcsLTAuNCAxLjEsLTAuNiAwLjQsLTAuMiAwLjgsLTAuMyAxLjIsLTAuNCAwLjQsLTAuMSAwLjgsLTAuMiAxLjIsLTAuMiAwLjIsMCAwLjQsMCAwLjYsMCAwLjEsMCAwLjEsMCAwLjEsMCBoIDAuMiAwLjEgdiAwIDAgaCAwLjIgYyAwLjUsMCAwLjksMC4xIDEuNCwwLjIgMC45LDAuMiAxLjgsMC41IDIuNiwxIDEuNiwwLjkgMywyLjMgMy45LDQgMC40LDAuOCAwLjcsMS44IDAuOSwyLjcgMCwwLjIgMC4xLDAuNSAwLjEsMC43IHYgMC4yIDAuMiBjIDAsMC4xIDAsMC4xIDAsMC4yIDAsMC4xIDAsMC4xIDAsMC4yIHYgMC4yIDAuMiBjIDAsMC4xIDAsMC4zIDAsMC40IDAsMC4zIDAsMC41IC0wLjEsMC44IDAsMC4zIC0wLjEsMC41IC0wLjEsMC44IC0wLjEsMC4xIC0wLjEsMC4zIC0wLjIsMC42IC0wLjEsMC41IC0wLjMsMSAtMC41LDEuNSAtMC40LDEgLTAuOSwxLjkgLTEuNSwyLjcgLTEuMiwxLjcgLTIuOSwzLjEgLTQuOCwzLjkgLTEsMC40IC0yLDAuNyAtMywwLjkgLTAuNSwwLjEgLTEsMC4xIC0xLjYsMC4yIGggLTAuMSAtMC4xIC0wLjIgLTAuMyAtMC4xIGMgMC4xLDAgMCwwIDAsMCBoIC0wLjEgYyAtMC4zLDAgLTAuNiwwIC0wLjgsMCAtMS4xLC0wLjEgLTIuMiwtMC4zIC0zLjMsLTAuNiAtMS4xLC0wLjMgLTIuMSwtMC43IC0zLjEsLTEuMiAtMiwtMSAtMy43LC0yLjUgLTUuMSwtNC4yIC0wLjcsLTAuOSAtMS4zLC0xLjggLTEuOCwtMi44IC0wLjUsLTEgLTAuOSwtMiAtMS4yLC0zIC0wLjMsLTEgLTAuNSwtMi4xIC0wLjUsLTMuMiB2IC0wLjIgLTAuMSAwIC0wLjEgLTAuMiAwIC0wLjEgLTAuMSAtMC4zIDAgMCAtMC4xIGMgMCwtMC4xIDAsLTAuMyAwLC0wLjQgMCwtMC41IDAuMSwtMS4xIDAuMSwtMS42IDAuMSwtMC41IDAuMiwtMS4xIDAuMywtMS42IDAuMSwtMC41IDAuMiwtMS4xIDAuNCwtMS42IDAuMywtMS4xIDAuNywtMi4xIDEuMSwtMy4xIDAuOSwtMiAyLjEsLTMuNyAzLjUsLTUuMSAwLjQsLTAuMyAwLjcsLTAuNyAxLjEsLTEgMC40LC0wLjMgMC44LC0wLjYgMS4yLC0wLjkgMC40LC0wLjMgMC44LC0wLjUgMS4zLC0wLjcgMC4yLC0wLjEgMC40LC0wLjIgMC43LC0wLjMgMC4xLDAgMC4yLC0wLjEgMC4zLC0wLjEgMC4xLC0wLjEgMC4yLC0wLjEgMC4zLC0wLjEgMC40LC0wLjIgMC45LC0wLjQgMS40LC0wLjUgMC4xLDAgMC4yLC0wLjEgMC40LC0wLjEgMC4xLDAgMC4yLC0wLjEgMC40LC0wLjEgMC4yLC0wLjEgMC41LC0wLjEgMC43LC0wLjIgMC4xLDAgMC4yLC0wLjEgMC40LC0wLjEgMC4xLDAgMC4yLC0wLjEgMC40LC0wLjEgMC4xLDAgMC4yLDAgMC40LC0wLjEgaCAwLjIgMC4yIGMgMC4xLDAgMC4yLDAgMC40LC0wLjEgMC4xLDAgMC4zLDAgMC40LC0wLjEgMC4xLDAgMC4zLDAgMC40LDAgMC4xLDAgMC4yLDAgMC4zLDAgaCAwLjIgMC4xIDAuMSBjIDAuMSwwIDAuMywwIDAuNCwwIGggMC4yIGMgMCwwIDAuMSwwIDAsMCB2IDAgaCAwLjEgYyAwLjEsMCAwLjIsMCAwLjQsMCAwLjUsMCAwLjksMCAxLjQsMCAwLjksMCAxLjgsMC4xIDIuNywwLjMgMS44LDAuMyAzLjQsMC45IDQuOSwxLjYgMS41LDAuNyAyLjksMS42IDQsMi42IDAuMSwwLjEgMC4xLDAuMSAwLjIsMC4yIDAuMSwwLjEgMC4xLDAuMSAwLjIsMC4yIDAuMSwwLjEgMC4zLDAuMyAwLjQsMC40IDAuMSwwLjEgMC4zLDAuMyAwLjQsMC40IDAuMSwwLjEgMC4zLDAuMyAwLjQsMC40IDAuNSwwLjUgMSwxLjEgMS40LDEuNiAwLjgsMS4xIDEuNSwyLjEgMiwzLjIgMCwwLjEgMC4xLDAuMSAwLjEsMC4yIDAsMC4xIDAuMSwwLjEgMC4xLDAuMiAwLjEsMC4xIDAuMSwwLjMgMC4yLDAuNCAwLjEsMC4xIDAuMSwwLjIgMC4yLDAuNCAwLjEsMC4xIDAuMSwwLjIgMC4yLDAuNCAwLjIsMC41IDAuNCwwLjkgMC41LDEuNCAwLjIsMC43IDAuNCwxLjMgMC42LDEuOSAwLjEsMC4yIDAuMywwLjQgMC41LDAuMyAwLjIsMCAwLjQsLTAuMiAwLjQsLTAuNCAtMC4yLC0xLjEgLTAuMiwtMS44IC0wLjMsLTIuNiB6IgogICBpZD0icGF0aDM3NzgiCiAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgIHN0eWxlPSJmaWxsOnVybCgjU1ZHSURfMV8pIiAvPgo8L3N2Zz4= - mediatype: image/svg+xml + - base64data: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMC4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4KCjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0iTGF5ZXJfMSIKICAgeD0iMHB4IgogICB5PSIwcHgiCiAgIHdpZHRoPSI1Ny43OTk5OTkiCiAgIGhlaWdodD0iNTcuNzk5OTk5IgogICB2aWV3Qm94PSIwIDAgNTcuNzk5OTk5IDU3LjgiCiAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImxvZ29fc21hbGwuc3ZnIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkyLjQgKDVkYTY4OWMzMTMsIDIwMTktMDEtMTQpIj48bWV0YWRhdGEKICAgaWQ9Im1ldGFkYXRhMzc4NSI+PHJkZjpSREY+PGNjOldvcmsKICAgICAgIHJkZjphYm91dD0iIj48ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD48ZGM6dHlwZQogICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPjxkYzp0aXRsZT48L2RjOnRpdGxlPjwvY2M6V29yaz48L3JkZjpSREY+PC9tZXRhZGF0YT48ZGVmcwogICBpZD0iZGVmczM3ODMiIC8+PHNvZGlwb2RpOm5hbWVkdmlldwogICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICBib3JkZXJvcGFjaXR5PSIxIgogICBvYmplY3R0b2xlcmFuY2U9IjEwIgogICBncmlkdG9sZXJhbmNlPSIxMCIKICAgZ3VpZGV0b2xlcmFuY2U9IjEwIgogICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIKICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzg2IgogICBpZD0ibmFtZWR2aWV3Mzc4MSIKICAgc2hvd2dyaWQ9ImZhbHNlIgogICBpbmtzY2FwZTp6b29tPSIxMy44NTg3MTQiCiAgIGlua3NjYXBlOmN4PSI3NS40MTI5MDQiCiAgIGlua3NjYXBlOmN5PSIyMy4wNzc2MDYiCiAgIGlua3NjYXBlOndpbmRvdy14PSIwIgogICBpbmtzY2FwZTp3aW5kb3cteT0iMCIKICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iTGF5ZXJfMSIgLz4KPHN0eWxlCiAgIHR5cGU9InRleHQvY3NzIgogICBpZD0ic3R5bGUzNzY5Ij4KCS5zdDB7ZmlsbDojRTZFN0U4O30KCS5zdDF7ZmlsbDp1cmwoI1NWR0lEXzFfKTt9Cjwvc3R5bGU+Cgo8bGluZWFyR3JhZGllbnQKICAgaWQ9IlNWR0lEXzFfIgogICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgeDE9IjI2LjcwMDAwMSIKICAgeTE9Ii05Ljg1MDE5OTciCiAgIHgyPSIyNi43MDAwMDEiCiAgIHkyPSI0My4xNjYiCiAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsLTEsMiw2MC4wMDAwMDIpIj4KCTxzdG9wCiAgIG9mZnNldD0iMCIKICAgc3R5bGU9InN0b3AtY29sb3I6I0ZGRjEwMCIKICAgaWQ9InN0b3AzNzczIiAvPgoJPHN0b3AKICAgb2Zmc2V0PSIxIgogICBzdHlsZT0ic3RvcC1jb2xvcjojRjA1QTI4IgogICBpZD0ic3RvcDM3NzUiIC8+CjwvbGluZWFyR3JhZGllbnQ+CjxwYXRoCiAgIGNsYXNzPSJzdDEiCiAgIGQ9Im0gNTUuMSwyNS41MDAwMDIgYyAtMC4xLC0xIC0wLjMsLTIuMSAtMC42LC0zLjMgLTAuMywtMS4yIC0wLjgsLTIuNiAtMS41LC00IC0wLjcsLTEuNCAtMS42LC0yLjkgLTIuOCwtNC4zIC0wLjUsLTAuNiAtMSwtMS4xIC0xLjUsLTEuNiAwLjgsLTMuMjAwMDAwNCAtMSwtNi4wMDAwMDA0IC0xLC02LjAwMDAwMDQgLTMuMSwtMC4yIC01LjEsMSAtNS44LDEuNSAtMC4xLC0wLjEgLTAuMiwtMC4xIC0wLjQsLTAuMiAtMC41LC0wLjIgLTEsLTAuNCAtMS42LC0wLjYgLTAuNiwtMC4yIC0xLjEsLTAuMyAtMS43LC0wLjUgLTAuNiwtMC4xIC0xLjIsLTAuMyAtMS44LC0wLjMgLTAuMSwwIC0wLjIsMCAtMC4zLDAgQyAzNC44LDEuODAwMDAxNiAzMC45LDEuNTI1ODc4OWUtNiAzMC45LDEuNTI1ODc4OWUtNiAyNi42LDIuODAwMDAxNiAyNS43LDYuNjAwMDAxNiAyNS43LDYuNjAwMDAxNiBjIDAsMCAwLDAuMSAwLDAuMiAtMC4yLDAuMSAtMC41LDAuMSAtMC43LDAuMiAtMC4zLDAuMSAtMC43LDAuMiAtMSwwLjMgLTAuMywwLjEgLTAuNywwLjMgLTEsMC40IC0wLjcsMC4zIC0xLjMsMC42IC0xLjksMSAtMC42LDAuMyAtMS4yLDAuNyAtMS44LDEuMSAtMC4xLDAgLTAuMiwtMC4xIC0wLjIsLTAuMSAtNiwtMi4zIC0xMS40LDAuNTAwMDAwNCAtMTEuNCwwLjUwMDAwMDQgLTAuNSw2LjQgMi40LDEwLjQgMywxMS4yIC0wLjEsMC40IC0wLjMsMC44IC0wLjQsMS4yIC0wLjQsMS40IC0wLjgsMi45IC0xLDQuNSAwLDAuMiAtMC4xLDAuNCAtMC4xLDAuNyAtNS42LDIuNyAtNy4yLDguNCAtNy4yLDguNCA0LjYsNS4zIDEwLDUuNyAxMCw1LjcgdiAwIGMgMC43LDEuMiAxLjUsMi40IDIuNCwzLjUgMC40LDAuNSAwLjgsMC45IDEuMiwxLjMgLTEuNyw0LjggMC4yLDguOSAwLjIsOC45IDUuMiwwLjIgOC42LC0yLjMgOS4zLC0yLjggMC41LDAuMiAxLDAuMyAxLjYsMC41IDEuNiwwLjQgMy4yLDAuNiA0LjgsMC43IDAuNCwwIDAuOCwwIDEuMiwwIGggMC4yIDAuMSAwLjMgMC4zIHYgMCBjIDIuNCwzLjUgNi43LDQgNi43LDQgMy40LC0zLjYgMy4yLC03LjIgMy4yLC03LjIgbCAtMC4xLC0wLjEgYyAwLjcsLTAuNSAxLjMsLTEgMS45LC0xLjUgMS4yLC0xLjEgMi4zLC0yLjQgMy4yLC0zLjcgMC4xLC0wLjEgMC4yLC0wLjMgMC4yLC0wLjQgMy40LDAuMiA1LjksLTIuMSA1LjksLTIuMSAtMC42LC00IC0zLjEsLTUuNyAtMy4xLC01LjcgaCAtMC4xIGMgMCwtMC4yIDAsLTAuNSAwLjEsLTAuNyAwLC0wLjQgMCwtMC44IDAsLTEuMiB2IC0wLjMgLTAuMSAtMC4xIGMgMCwtMC4xIDAsLTAuMSAwLC0wLjEgdiAtMC4yIC0wLjMgYyAwLC0wLjEgMCwtMC4yIDAsLTAuMyAwLC0wLjEgMCwtMC4yIDAsLTAuMyB2IC0wLjMgLTAuMyBjIC0wLjEsLTAuNCAtMC4xLC0wLjggLTAuMiwtMS4yIC0wLjQsLTEuNSAtMSwtMyAtMS44LC00LjMgLTAuOCwtMS4zIC0xLjgsLTIuNSAtMi45LC0zLjUgLTEuMSwtMSAtMi40LC0xLjggLTMuNywtMi40IC0xLjMsLTAuNiAtMi43LC0xIC00LjEsLTEuMSAtMC43LC0wLjEgLTEuNCwtMC4xIC0yLC0wLjEgaCAtMC4zIC0wLjEgLTAuMSAtMC4xIC0wLjMgYyAtMC4xLDAgLTAuMiwwIC0wLjMsMCAtMC4zLDAgLTAuNywwLjEgLTEsMC4xIC0xLjQsMC4zIC0yLjcsMC43IC0zLjgsMS40IC0xLjEsMC43IC0yLjEsMS41IC0yLjksMi41IC0wLjgsMSAtMS40LDIgLTEuOSwzLjEgLTAuNCwxLjEgLTAuNywyLjIgLTAuNywzLjMgMCwwLjMgMCwwLjYgMCwwLjggMCwwLjEgMCwwLjEgMCwwLjIgdiAwLjIgYyAwLDAuMSAwLDAuMyAwLDAuNCAwLjEsMC42IDAuMiwxLjEgMC4zLDEuNiAwLjMsMSAwLjgsMiAxLjQsMi44IDAuNiwwLjggMS4zLDEuNSAyLjEsMiAwLjgsMC41IDEuNiwwLjkgMi40LDEuMSAwLjgsMC4yIDEuNiwwLjMgMi4zLDAuMyAwLjEsMCAwLjIsMCAwLjMsMCBoIDAuMSAwLjEgYyAwLjEsMCAwLjIsMCAwLjIsMCAwLDAgMCwwIDAuMSwwIGggMC4xIDAuMSBjIDAuMSwwIDAuMiwwIDAuMywwIDAuMSwwIDAuMiwwIDAuMywtMC4xIDAuMiwwIDAuMywtMC4xIDAuNSwtMC4xIDAuMywtMC4xIDAuNiwtMC4yIDAuOSwtMC40IDAuMywtMC4xIDAuNSwtMC4zIDAuOCwtMC41IDAuMSwtMC4xIDAuMSwtMC4xIDAuMiwtMC4yIDAuMywtMC4yIDAuMywtMC42IDAuMSwtMC44IC0wLjIsLTAuMiAtMC41LC0wLjMgLTAuNywtMC4xIC0wLjIsLTAuMiAtMC4yLC0wLjEgLTAuMywtMC4xIC0wLjIsMC4xIC0wLjQsMC4yIC0wLjcsMC4zIC0wLjIsMC4xIC0wLjUsMC4xIC0wLjgsMC4yIC0wLjEsMCAtMC4zLDAgLTAuNCwwIC0wLjEsMCAtMC4xLDAgLTAuMiwwIC0wLjEsMCAtMC4xLDAgLTAuMiwwIC0wLjEsMCAtMC4xLDAgLTAuMiwwIC0wLjEsMCAtMC4yLDAgLTAuMiwwIHYgMCAwIEggMzQuMSAzNCBjIC0wLjEsMCAtMC4xLDAgLTAuMiwwIC0wLjYsLTAuMSAtMS4yLC0wLjMgLTEuNywtMC41IC0wLjYsLTAuMyAtMS4xLC0wLjYgLTEuNiwtMS4xIC0wLjUsLTAuNCAtMC45LC0xIC0xLjMsLTEuNiAtMC4zLC0wLjYgLTAuNiwtMS4zIC0wLjcsLTIgLTAuMSwtMC4zIC0wLjEsLTAuNyAtMC4xLC0xLjEgMCwtMC4xIDAsLTAuMiAwLC0wLjMgdiAwIDAgLTAuMSAtMC4xIGMgMCwtMC4yIDAsLTAuNCAwLjEsLTAuNiAwLjMsLTEuNSAxLC0zIDIuMiwtNC4yIDAuMywtMC4zIDAuNiwtMC41IDEsLTAuOCAwLjMsLTAuMiAwLjcsLTAuNCAxLjEsLTAuNiAwLjQsLTAuMiAwLjgsLTAuMyAxLjIsLTAuNCAwLjQsLTAuMSAwLjgsLTAuMiAxLjIsLTAuMiAwLjIsMCAwLjQsMCAwLjYsMCAwLjEsMCAwLjEsMCAwLjEsMCBoIDAuMiAwLjEgdiAwIDAgaCAwLjIgYyAwLjUsMCAwLjksMC4xIDEuNCwwLjIgMC45LDAuMiAxLjgsMC41IDIuNiwxIDEuNiwwLjkgMywyLjMgMy45LDQgMC40LDAuOCAwLjcsMS44IDAuOSwyLjcgMCwwLjIgMC4xLDAuNSAwLjEsMC43IHYgMC4yIDAuMiBjIDAsMC4xIDAsMC4xIDAsMC4yIDAsMC4xIDAsMC4xIDAsMC4yIHYgMC4yIDAuMiBjIDAsMC4xIDAsMC4zIDAsMC40IDAsMC4zIDAsMC41IC0wLjEsMC44IDAsMC4zIC0wLjEsMC41IC0wLjEsMC44IC0wLjEsMC4xIC0wLjEsMC4zIC0wLjIsMC42IC0wLjEsMC41IC0wLjMsMSAtMC41LDEuNSAtMC40LDEgLTAuOSwxLjkgLTEuNSwyLjcgLTEuMiwxLjcgLTIuOSwzLjEgLTQuOCwzLjkgLTEsMC40IC0yLDAuNyAtMywwLjkgLTAuNSwwLjEgLTEsMC4xIC0xLjYsMC4yIGggLTAuMSAtMC4xIC0wLjIgLTAuMyAtMC4xIGMgMC4xLDAgMCwwIDAsMCBoIC0wLjEgYyAtMC4zLDAgLTAuNiwwIC0wLjgsMCAtMS4xLC0wLjEgLTIuMiwtMC4zIC0zLjMsLTAuNiAtMS4xLC0wLjMgLTIuMSwtMC43IC0zLjEsLTEuMiAtMiwtMSAtMy43LC0yLjUgLTUuMSwtNC4yIC0wLjcsLTAuOSAtMS4zLC0xLjggLTEuOCwtMi44IC0wLjUsLTEgLTAuOSwtMiAtMS4yLC0zIC0wLjMsLTEgLTAuNSwtMi4xIC0wLjUsLTMuMiB2IC0wLjIgLTAuMSAwIC0wLjEgLTAuMiAwIC0wLjEgLTAuMSAtMC4zIDAgMCAtMC4xIGMgMCwtMC4xIDAsLTAuMyAwLC0wLjQgMCwtMC41IDAuMSwtMS4xIDAuMSwtMS42IDAuMSwtMC41IDAuMiwtMS4xIDAuMywtMS42IDAuMSwtMC41IDAuMiwtMS4xIDAuNCwtMS42IDAuMywtMS4xIDAuNywtMi4xIDEuMSwtMy4xIDAuOSwtMiAyLjEsLTMuNyAzLjUsLTUuMSAwLjQsLTAuMyAwLjcsLTAuNyAxLjEsLTEgMC40LC0wLjMgMC44LC0wLjYgMS4yLC0wLjkgMC40LC0wLjMgMC44LC0wLjUgMS4zLC0wLjcgMC4yLC0wLjEgMC40LC0wLjIgMC43LC0wLjMgMC4xLDAgMC4yLC0wLjEgMC4zLC0wLjEgMC4xLC0wLjEgMC4yLC0wLjEgMC4zLC0wLjEgMC40LC0wLjIgMC45LC0wLjQgMS40LC0wLjUgMC4xLDAgMC4yLC0wLjEgMC40LC0wLjEgMC4xLDAgMC4yLC0wLjEgMC40LC0wLjEgMC4yLC0wLjEgMC41LC0wLjEgMC43LC0wLjIgMC4xLDAgMC4yLC0wLjEgMC40LC0wLjEgMC4xLDAgMC4yLC0wLjEgMC40LC0wLjEgMC4xLDAgMC4yLDAgMC40LC0wLjEgaCAwLjIgMC4yIGMgMC4xLDAgMC4yLDAgMC40LC0wLjEgMC4xLDAgMC4zLDAgMC40LC0wLjEgMC4xLDAgMC4zLDAgMC40LDAgMC4xLDAgMC4yLDAgMC4zLDAgaCAwLjIgMC4xIDAuMSBjIDAuMSwwIDAuMywwIDAuNCwwIGggMC4yIGMgMCwwIDAuMSwwIDAsMCB2IDAgaCAwLjEgYyAwLjEsMCAwLjIsMCAwLjQsMCAwLjUsMCAwLjksMCAxLjQsMCAwLjksMCAxLjgsMC4xIDIuNywwLjMgMS44LDAuMyAzLjQsMC45IDQuOSwxLjYgMS41LDAuNyAyLjksMS42IDQsMi42IDAuMSwwLjEgMC4xLDAuMSAwLjIsMC4yIDAuMSwwLjEgMC4xLDAuMSAwLjIsMC4yIDAuMSwwLjEgMC4zLDAuMyAwLjQsMC40IDAuMSwwLjEgMC4zLDAuMyAwLjQsMC40IDAuMSwwLjEgMC4zLDAuMyAwLjQsMC40IDAuNSwwLjUgMSwxLjEgMS40LDEuNiAwLjgsMS4xIDEuNSwyLjEgMiwzLjIgMCwwLjEgMC4xLDAuMSAwLjEsMC4yIDAsMC4xIDAuMSwwLjEgMC4xLDAuMiAwLjEsMC4xIDAuMSwwLjMgMC4yLDAuNCAwLjEsMC4xIDAuMSwwLjIgMC4yLDAuNCAwLjEsMC4xIDAuMSwwLjIgMC4yLDAuNCAwLjIsMC41IDAuNCwwLjkgMC41LDEuNCAwLjIsMC43IDAuNCwxLjMgMC42LDEuOSAwLjEsMC4yIDAuMywwLjQgMC41LDAuMyAwLjIsMCAwLjQsLTAuMiAwLjQsLTAuNCAtMC4yLC0xLjEgLTAuMiwtMS44IC0wLjMsLTIuNiB6IgogICBpZD0icGF0aDM3NzgiCiAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgIHN0eWxlPSJmaWxsOnVybCgjU1ZHSURfMV8pIiAvPgo8L3N2Zz4= + mediatype: image/svg+xml install: spec: clusterPermissions: - - rules: - - apiGroups: - - "" - resources: - - configmaps - - persistentvolumeclaims - - secrets - - serviceaccounts - - services - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - get - - list - - patch - - watch - - apiGroups: - - apps - resources: - - deployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - grafana.integreatly.org - resources: - - grafanadashboards - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - grafana.integreatly.org - resources: - - grafanadashboards/finalizers - verbs: - - update - - apiGroups: - - grafana.integreatly.org - resources: - - grafanadashboards/status - verbs: - - get - - patch - - update - - apiGroups: - - grafana.integreatly.org - resources: - - grafanadatasources - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - grafana.integreatly.org - resources: - - grafanadatasources/finalizers - verbs: - - update - - apiGroups: - - grafana.integreatly.org - resources: - - grafanadatasources/status - verbs: - - get - - patch - - update - - apiGroups: - - grafana.integreatly.org - resources: - - grafanafolders - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - grafana.integreatly.org - resources: - - grafanafolders/finalizers - verbs: - - update - - apiGroups: - - grafana.integreatly.org - resources: - - grafanafolders/status - verbs: - - get - - patch - - update - - apiGroups: - - grafana.integreatly.org - resources: - - grafanas - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - grafana.integreatly.org - resources: - - grafanas/finalizers - verbs: - - update - - apiGroups: - - grafana.integreatly.org - resources: - - grafanas/status - verbs: - - get - - patch - - update - - apiGroups: - - networking.k8s.io - resources: - - ingresses - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - route.openshift.io - resources: - - routes - - routes/custom-host - verbs: - - create - - delete - - get - - list - - update - - watch - serviceAccountName: grafana-operator-controller-manager + - rules: + - apiGroups: + - "" + resources: + - configmaps + - persistentvolumeclaims + - secrets + - serviceaccounts + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - create + - get + - list + - patch + - watch + - apiGroups: + - apps + resources: + - deployments + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - grafana.integreatly.org + resources: + - grafanadashboards + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - grafana.integreatly.org + resources: + - grafanadashboards/finalizers + verbs: + - update + - apiGroups: + - grafana.integreatly.org + resources: + - grafanadashboards/status + verbs: + - get + - patch + - update + - apiGroups: + - grafana.integreatly.org + resources: + - grafanadatasources + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - grafana.integreatly.org + resources: + - grafanadatasources/finalizers + verbs: + - update + - apiGroups: + - grafana.integreatly.org + resources: + - grafanadatasources/status + verbs: + - get + - patch + - update + - apiGroups: + - grafana.integreatly.org + resources: + - grafanafolders + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - grafana.integreatly.org + resources: + - grafanafolders/finalizers + verbs: + - update + - apiGroups: + - grafana.integreatly.org + resources: + - grafanafolders/status + verbs: + - get + - patch + - update + - apiGroups: + - grafana.integreatly.org + resources: + - grafanas + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - grafana.integreatly.org + resources: + - grafanas/finalizers + verbs: + - update + - apiGroups: + - grafana.integreatly.org + resources: + - grafanas/status + verbs: + - get + - patch + - update + - apiGroups: + - networking.k8s.io + resources: + - ingresses + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: + - create + - delete + - get + - list + - update + - watch + serviceAccountName: grafana-operator-controller-manager deployments: - label: control-plane: controller-manager @@ -360,56 +360,56 @@ spec: serviceAccountName: grafana-operator-controller-manager terminationGracePeriodSeconds: 10 permissions: - - rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - serviceAccountName: grafana-operator-controller-manager + - rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + serviceAccountName: grafana-operator-controller-manager strategy: deployment installModes: - - supported: true - type: OwnNamespace - - supported: true - type: SingleNamespace - - supported: true - type: MultiNamespace - - supported: true - type: AllNamespaces + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces keywords: - - Grafana - - Metrics - - Observability + - Grafana + - Metrics + - Observability links: - - name: Grafana Operator - url: https://grafana-operator.github.io/grafana-operator + - name: Grafana Operator + url: https://grafana-operator.github.io/grafana-operator maturity: alpha minKubeVersion: 1.23.0 provider: diff --git a/controllers/config/operator_constants.go b/controllers/config/operator_constants.go index 73c6289d1..e666f42ce 100644 --- a/controllers/config/operator_constants.go +++ b/controllers/config/operator_constants.go @@ -2,8 +2,10 @@ package config const ( // Grafana - GrafanaImage = "docker.io/grafana/grafana" - GrafanaVersion = "9.1.6" + GrafanaImage = "docker.io/grafana/grafana" + // Get Image Digest by executing, e.g.: + // skopeo inspect --raw docker://docker.io/grafana/grafana:9.1.6 | jq '.manifests | map(select(.platform.architecture == "amd64" and .platform.os == "linux") )' | jq -r '.[0].digest' + GrafanaDigest = "sha256:f5518c6c6392bb767813b78d474ed3a228ca0673f1867770d8fd312067abc558" // Paths GrafanaDataPath = "/var/lib/grafana" diff --git a/controllers/reconcilers/grafana/deployment_reconciler.go b/controllers/reconcilers/grafana/deployment_reconciler.go index ea7b97856..d05ee486e 100644 --- a/controllers/reconcilers/grafana/deployment_reconciler.go +++ b/controllers/reconcilers/grafana/deployment_reconciler.go @@ -135,7 +135,7 @@ func getVolumeMounts(cr *v1beta1.Grafana, scheme *runtime.Scheme) []v1.VolumeMou func getContainers(cr *v1beta1.Grafana, scheme *runtime.Scheme, vars *v1beta1.OperatorReconcileVars, openshiftPlatform bool) []v1.Container { var containers []v1.Container - image := fmt.Sprintf("%s:%s", config2.GrafanaImage, config2.GrafanaVersion) + image := fmt.Sprintf("%s@%s", config2.GrafanaImage, config2.GrafanaDigest) plugins := model.GetPluginsConfigMap(cr, scheme) // env var to restart containers if plugins change