diff --git a/charts/backstage/Chart.yaml b/charts/backstage/Chart.yaml index 4d58584f..50f1140a 100644 --- a/charts/backstage/Chart.yaml +++ b/charts/backstage/Chart.yaml @@ -41,4 +41,4 @@ sources: # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 2.8.1 +version: 2.9.0 diff --git a/charts/backstage/README.md b/charts/backstage/README.md index 8a6ea6c6..ae4c8d14 100644 --- a/charts/backstage/README.md +++ b/charts/backstage/README.md @@ -2,7 +2,7 @@ # Janus-IDP Backstage Helm Chart [![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/janus-idp&style=flat-square)](https://artifacthub.io/packages/search?repo=janus-idp) -![Version: 2.8.1](https://img.shields.io/badge/Version-2.8.1-informational?style=flat-square) +![Version: 2.9.0](https://img.shields.io/badge/Version-2.9.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) A Helm chart for deploying a Backstage application @@ -129,6 +129,9 @@ Kubernetes: `>= 1.19.0-0` | Key | Description | Type | Default | |-----|-------------|------|---------| | global.clusterRouterBase | Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled. | string | `"apps.example.com"` | +| global.dynamic.includes | Array of YAML files listing dynamic plugins to include with those listed in the `plugins` field. Relative paths are resolved from the working directory of the initContainer that will install the plugins (`/opt/app-root/src`). | list | `["dynamic-plugins.default.yaml"]` | +| global.dynamic.includes[0] | List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. This file ONLY works with the `janus-idp/backstage-showcase` container image. | string | `"dynamic-plugins.default.yaml"` | +| global.dynamic.plugins | List of dynamic plugins, possibly overriding the plugins listed in `includes` files. Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin listed in `includes` files. | list | `[]` | | global.host | Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig` | string | `""` | | route | OpenShift Route parameters | object | `{"annotations":{},"enabled":true,"host":"{{ .Values.global.host }}","path":"/","tls":{"caCertificate":"","certificate":"","destinationCACertificate":"","enabled":true,"insecureEdgeTerminationPolicy":"Redirect","key":"","termination":"edge"},"wildcardPolicy":"None"}` | | route.annotations | Route specific annotations | object | `{}` | @@ -145,6 +148,8 @@ Kubernetes: `>= 1.19.0-0` | route.tls.termination | Specify TLS termination. | string | `"edge"` | | route.wildcardPolicy | Wildcard policy if any for the route. Currently only 'Subdomain' or 'None' is allowed. | string | `"None"` | | upstream | Upstream Backstage [chart configuration](https://github.com/backstage/charts/blob/main/charts/backstage/values.yaml) | object | Use Openshift compatible settings | +| upstream.backstage.extraVolumes[0] | Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. To have more control on underlying storage, the [emptyDir](https://docs.openshift.com/container-platform/4.13/storage/understanding-ephemeral-storage.html) could be changed to a [generic ephemeral volume](https://docs.openshift.com/container-platform/4.13/storage/generic-ephemeral-vols.html#generic-ephemeral-vols-procedure_generic-ephemeral-volumes). | object | `{"emptyDir":{},"name":"dynamic-plugins-root"}` | +| upstream.backstage.initContainers[0].image | Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. It could be replaced by a custom image based on this one. | string | `quay.io/janus-idp/backstage-showcase:latest` | ## Opinionated Backstage deployment diff --git a/charts/backstage/ci/default-values.yaml b/charts/backstage/ci/default-values.yaml index da4457ad..65f133b8 100644 --- a/charts/backstage/ci/default-values.yaml +++ b/charts/backstage/ci/default-values.yaml @@ -6,3 +6,9 @@ upstream: primary: persistence: enabled: false + backstage: + appConfig: + backend: + auth: + keys: + - secret: sEKIT4CwJ4MwVLzen5SFL6fJmwOPB2sl diff --git a/charts/backstage/templates/dynamic-plugins-configmap.yaml b/charts/backstage/templates/dynamic-plugins-configmap.yaml new file mode 100644 index 00000000..25cf919f --- /dev/null +++ b/charts/backstage/templates/dynamic-plugins-configmap.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: dynamic-plugins +data: + dynamic-plugins.yaml: | + {{- include "common.tplvalues.render" ( dict "value" + .Values.global.dynamic "context" $) | nindent 4 }} diff --git a/charts/backstage/templates/tests/test-connection.yaml b/charts/backstage/templates/tests/test-connection.yaml index 855b1c34..a382602e 100644 --- a/charts/backstage/templates/tests/test-connection.yaml +++ b/charts/backstage/templates/tests/test-connection.yaml @@ -16,5 +16,5 @@ spec: command: ["/bin/sh", "-c"] args: - | - curl --connect-timeout 5 --max-time 10 --retry 10 --retry-delay 10 --retry-max-time 30 --retry-all-errors {{ include "common.names.fullname" . }}:{{ .Values.upstream.service.ports.backend }} + curl --connect-timeout 5 --max-time 20 --retry 20 --retry-delay 10 --retry-max-time 60 --retry-all-errors {{ include "common.names.fullname" . }}:{{ .Values.upstream.service.ports.backend }} restartPolicy: Never diff --git a/charts/backstage/values.schema.json b/charts/backstage/values.schema.json index d2d786ab..25ccc474 100644 --- a/charts/backstage/values.schema.json +++ b/charts/backstage/values.schema.json @@ -8,6 +8,46 @@ "title": "Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled.", "type": "string" }, + "dynamic": { + "additionalProperties": false, + "properties": { + "includes": { + "default": [], + "items": { + "type": "string" + }, + "title": "List of YAML files to include, each of which should contain a `plugins` array.", + "type": "array" + }, + "plugins": { + "items": { + "properties": { + "disabled": { + "default": false, + "title": "Disable the plugin.", + "type": "boolean" + }, + "package": { + "title": "Package specification of the dynamic plugin to install. It should be usable by the `npm pack` command.", + "type": "string" + }, + "pluginConfig": { + "title": "Optional plugin-specific app-config YAML fragment.", + "type": "object" + } + }, + "required": [ + "package" + ], + "type": "object" + }, + "title": "List of dynamic plugins that should be installed in the backstage application.", + "type": "array" + } + }, + "title": "Dynamic plugins configuration.", + "type": "object" + }, "host": { "default": "", "title": "Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`", diff --git a/charts/backstage/values.schema.tmpl.json b/charts/backstage/values.schema.tmpl.json index d5d2a34c..b9ad0561 100644 --- a/charts/backstage/values.schema.tmpl.json +++ b/charts/backstage/values.schema.tmpl.json @@ -29,6 +29,44 @@ "title": "Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`", "type": "string", "default": "" + }, + "dynamic": { + "title": "Dynamic plugins configuration.", + "type": "object", + "additionalProperties": false, + "properties": { + "plugins": { + "title": "List of dynamic plugins that should be installed in the backstage application.", + "type": "array", + "items": { + "type": "object", + "properties": { + "package": { + "title": "Package specification of the dynamic plugin to install. It should be usable by the `npm pack` command.", + "type": "string" + }, + "pluginConfig": { + "title": "Optional plugin-specific app-config YAML fragment.", + "type": "object" + }, + "disabled": { + "title": "Disable the plugin.", + "type": "boolean", + "default": false + } + }, + "required": ["package"] + } + }, + "includes": { + "title": "List of YAML files to include, each of which should contain a `plugins` array.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + } + } } } }, diff --git a/charts/backstage/values.yaml b/charts/backstage/values.yaml index 7a9e84c9..692ae44e 100644 --- a/charts/backstage/values.yaml +++ b/charts/backstage/values.yaml @@ -1,4 +1,18 @@ global: + dynamic: + # -- Array of YAML files listing dynamic plugins to include with those listed in the `plugins` field. + # Relative paths are resolved from the working directory of the initContainer that will install the plugins (`/opt/app-root/src`). + includes: + # -- List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default. + # This file ONLY works with the `janus-idp/backstage-showcase` container image. + - 'dynamic-plugins.default.yaml' + + # -- List of dynamic plugins, possibly overriding the plugins listed in `includes` files. + # Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec), + # an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin + # listed in `includes` files. + plugins: [] + # -- Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled. clusterRouterBase: apps.example.com # -- Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig` @@ -60,6 +74,66 @@ upstream: key: postgres-password name: "{{ .Release.Name }}-postgresql" + args: + # This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins. + - '--config' + - dynamic-plugins-root/app-config.dynamic-plugins.yaml + extraVolumeMounts: + # The initContainer below will install dynamic plugins in this volume mount. + - name: dynamic-plugins-root + mountPath: /opt/app-root/src/dynamic-plugins-root + extraVolumes: + # -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start. + # To have more control on underlying storage, the [emptyDir](https://docs.openshift.com/container-platform/4.13/storage/understanding-ephemeral-storage.html) + # could be changed to a [generic ephemeral volume](https://docs.openshift.com/container-platform/4.13/storage/generic-ephemeral-vols.html#generic-ephemeral-vols-procedure_generic-ephemeral-volumes). + - name: dynamic-plugins-root + emptyDir: {} + + # Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map. + # The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field. + - name: dynamic-plugins + configMap: + defaultMode: 420 + name: dynamic-plugins + optional: true + # Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret) + # to be used when running `npm pack` during the dynamic plugins installation by the initContainer. + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: dynamic-plugins-npmrc + initContainers: + - name: install-dynamic-plugins + # -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount. + # It could be replaced by a custom image based on this one. + # @default -- `quay.io/janus-idp/backstage-showcase:latest` + image: '{{ include "backstage.image" . }}' + command: + - python + - install-dynamic-plugins.py + - /dynamic-plugins-root + env: + - name: NPM_CONFIG_USERCONFIG + value: /opt/app-root/src/.npmrc.dynamic-plugins + imagePullPolicy: Always + volumeMounts: + - mountPath: /dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /opt/app-root/src/dynamic-plugins.yaml + name: dynamic-plugins + readOnly: true + subPath: dynamic-plugins.yaml + - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins + name: dynamic-plugins-npmrc + readOnly: true + subPath: .npmrc + workingDir: /opt/app-root/src + installDir: /opt/app-root/src + podAnnotations: + checksum/dynamic-plugins: >- + {{- include "common.tplvalues.render" ( dict "value" + .Values.global.dynamic "context" $) | sha256sum }} postgresql: enabled: true postgresqlDataDir: /var/lib/pgsql/data/userdata