diff --git a/.github/workflows/nightly-upgrade-test.yaml b/.github/workflows/nightly-upgrade-test.yaml index c933edd73..6b7a16dad 100644 --- a/.github/workflows/nightly-upgrade-test.yaml +++ b/.github/workflows/nightly-upgrade-test.yaml @@ -15,8 +15,10 @@ jobs: from_version: - 1.3 - 1.4 + - 1.5 to_branch: - main + - release-1.5 - release-1.4 - release-1.3 exclude: @@ -28,6 +30,13 @@ jobs: - from_version: 1.4 to_branch: release-1.4 + - from_version: 1.5 + to_branch: release-1.3 + - from_version: 1.5 + to_branch: release-1.4 + - from_version: 1.5 + to_branch: release-1.5 + name: 'E2E Upgrade: ${{ matrix.from_version }} => ${{ matrix.to_branch }}' concurrency: group: '${{ github.workflow }}-${{ matrix.to_branch }}-${{ matrix.from_version }}' diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index 4f33e71fd..886f3dedc 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -14,6 +14,7 @@ jobs: matrix: branch: - main + - release-1.5 - release-1.4 - release-1.3 name: 'E2E Tests on ${{ matrix.branch }}' diff --git a/.github/workflows/pr-bundle-diff-checks.yaml b/.github/workflows/pr-bundle-diff-checks.yaml index 8a9e0b8b6..b12daaef5 100644 --- a/.github/workflows/pr-bundle-diff-checks.yaml +++ b/.github/workflows/pr-bundle-diff-checks.yaml @@ -50,12 +50,12 @@ jobs: - name: Check for outdated bundle or manifests id: manifests-diff-checker run: | - make bundles + make bundles build-installers git status --porcelain # Since operator-sdk 1.26.0, `make bundle` changes the `createdAt` field from the bundle every time we run it. # The `git diff` below checks if only the createdAt field has changed. If is the only change, it is ignored. # Inspired from https://github.com/operator-framework/operator-sdk/issues/6285#issuecomment-1415350333 - echo "MANIFESTS_CHANGED=$(if git diff --quiet -I'^ createdAt: ' bundle config; then echo "false"; else echo "true"; fi)" >> $GITHUB_OUTPUT + echo "MANIFESTS_CHANGED=$(if git diff --quiet -I'^ createdAt: ' bundle config dist; then echo "false"; else echo "true"; fi)" >> $GITHUB_OUTPUT - name: Commit any manifest changes if: ${{ steps.manifests-diff-checker.outputs.MANIFESTS_CHANGED == 'true' }} @@ -66,11 +66,11 @@ jobs: git pull --rebase --autostash git add -A . git commit \ - -m "Regenerate bundle manifests" \ + -m "Regenerate bundle/installer manifests" \ -m "Co-authored-by: $GITHUB_ACTOR <$GITHUB_ACTOR@users.noreply.github.com>" git push - - name: Comment on PR if bundle manifests were updated + - name: Comment on PR if manifests were updated uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 if: ${{ !cancelled() && steps.manifests-diff-checker.outputs.MANIFESTS_CHANGED == 'true' }} continue-on-error: true @@ -82,5 +82,5 @@ jobs: issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: '⚠️ Files changed in bundle generation!

Those changes to the operator bundle manifests should have been pushed automatically to your PR branch.' + body: '⚠️ Files changed in bundle and installer generation!

Those changes to the operator bundle/installer manifests should have been pushed automatically to your PR branch.' }) diff --git a/Makefile b/Makefile index a18b099f1..11bda04b7 100644 --- a/Makefile +++ b/Makefile @@ -256,6 +256,12 @@ docker-buildx: ## Build and push docker image for the manager for cross-platform - $(CONTAINER_TOOL) buildx rm project-v3-builder rm -f Dockerfile.cross +.PHONY: build-installers +build-installers: ## Generate a consolidated YAML with CRDs and deployment for all available profiles. + @for profile in $(PROFILES); do \ + $(MAKE) build-installer PROFILE=$$profile; \ + done + .PHONY: build-installer build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment. mkdir -p dist/$(PROFILE) @@ -265,8 +271,8 @@ build-installer: manifests generate kustomize ## Generate a consolidated YAML wi .PHONY: deployment-manifest deployment-manifest: build-installer ## Generate manifest to deploy operator. Deprecated. Use 'make build-installer' instead. - cp -f dist/$(PROFILE)/install.yaml rhdh-operator-${VERSION}.yaml - @echo "Generated operator script rhdh-operator-${VERSION}.yaml" + cp -f dist/$(PROFILE)/install.yaml $(PROFILE)-operator-${VERSION}.yaml + @echo "Generated operator script $(PROFILE)-operator-${VERSION}.yaml" # A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ca4d7a346..9b7acdd38 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -5,7 +5,7 @@ package v1alpha1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/api/v1alpha2/zz_generated.deepcopy.go b/api/v1alpha2/zz_generated.deepcopy.go index 1357c08bd..c3ecd6b25 100644 --- a/api/v1alpha2/zz_generated.deepcopy.go +++ b/api/v1alpha2/zz_generated.deepcopy.go @@ -5,7 +5,7 @@ package v1alpha2 import ( - v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/api/v1alpha3/zz_generated.deepcopy.go b/api/v1alpha3/zz_generated.deepcopy.go index 6613a8896..b315b789e 100644 --- a/api/v1alpha3/zz_generated.deepcopy.go +++ b/api/v1alpha3/zz_generated.deepcopy.go @@ -5,7 +5,7 @@ package v1alpha3 import ( - v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/bundle/backstage.io/manifests/backstage-operator.clusterserviceversion.yaml b/bundle/backstage.io/manifests/backstage-operator.clusterserviceversion.yaml index 18f1933fd..e91d32ecb 100644 --- a/bundle/backstage.io/manifests/backstage-operator.clusterserviceversion.yaml +++ b/bundle/backstage.io/manifests/backstage-operator.clusterserviceversion.yaml @@ -35,7 +35,7 @@ metadata: } } ] - createdAt: "2025-02-11T17:40:38Z" + createdAt: "2025-02-17T10:12:56Z" description: Backstage Operator operators.operatorframework.io/builder: operator-sdk-v1.37.0 operators.operatorframework.io/project_layout: go.kubebuilder.io/v4 diff --git a/bundle/rhdh/manifests/backstage-operator.clusterserviceversion.yaml b/bundle/rhdh/manifests/backstage-operator.clusterserviceversion.yaml index 7c51476c3..c2fc4bd87 100644 --- a/bundle/rhdh/manifests/backstage-operator.clusterserviceversion.yaml +++ b/bundle/rhdh/manifests/backstage-operator.clusterserviceversion.yaml @@ -39,7 +39,7 @@ metadata: categories: Developer Tools certified: "true" containerImage: registry.redhat.io/rhdh/rhdh-rhel9-operator:1.5 - createdAt: "2025-02-11T17:40:40Z" + createdAt: "2025-02-17T10:12:59Z" description: Red Hat Developer Hub is a Red Hat supported version of Backstage. It comes with pre-built plug-ins and configuration settings, supports use of an external database, and can help streamline the process of setting up a self-managed diff --git a/dist/backstage.io/install.yaml b/dist/backstage.io/install.yaml new file mode 100644 index 000000000..379759fed --- /dev/null +++ b/dist/backstage.io/install.yaml @@ -0,0 +1,1826 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: system + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: namespace + app.kubernetes.io/part-of: backstage-operator + control-plane: controller-manager + name: backstage-system +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: backstages.rhdh.redhat.com +spec: + group: rhdh.redhat.com + names: + kind: Backstage + listKind: BackstageList + plural: backstages + singular: backstage + scope: Namespaced + versions: + - deprecated: true + deprecationWarning: Since 1.3.0 spec.application.image, spec.application.replicas, + spec.application.imagePullSecrets are deprecated in favor of corresponding spec.deployment + fields + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + Backstage is the Schema for the Red Hat Developer Hub backstages API. + It comes with pre-built plug-ins, configuration settings, and deployment mechanisms, + which can help streamline the process of setting up a self-managed internal + developer portal for adopters who are just starting out. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BackstageSpec defines the desired state of Backstage + properties: + application: + description: Configuration for Backstage. Optional. + properties: + appConfig: + description: |- + References to existing app-configs ConfigMap objects, that will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret, + and will be mounted inside the main application container under a specified mount directory. + Additionally, each file will be passed as a `--config /mount/path/to/configmap/key` to the + main container args in the order of the entries defined in the AppConfigs list. + But bear in mind that for a single ConfigMap element containing several filenames, + the order in which those files will be appended to the main container args cannot be guaranteed. + So if you want to pass multiple app-config files, it is recommended to pass one ConfigMap per app-config file. + properties: + configMaps: + description: |- + List of ConfigMaps storing the app-config files. Will be mounted as files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + Bear in mind not to put sensitive data in those ConfigMaps. Instead, your app-config content can reference + environment variables (which you can set with the ExtraEnvs field) and/or include extra files (see the ExtraFiles field). + More details on https://backstage.io/docs/conf/writing/. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all app-config files listed in + the ConfigMapRefs field + type: string + type: object + dynamicPluginsConfigMapName: + description: |- + Reference to an existing ConfigMap for Dynamic Plugins. + A new one will be generated with the default config if not set. + The ConfigMap object must have an existing key named: 'dynamic-plugins.yaml'. + type: string + extraEnvs: + description: Extra environment variables + properties: + configMaps: + description: |- + List of references to ConfigMaps objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be injected as additional environment variables. + Otherwise, only the specified key will be injected as an additional environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + envs: + description: List of name and value pairs to add as environment + variables. + items: + properties: + name: + description: Name of the environment variable + type: string + value: + description: Value of the environment variable + type: string + required: + - name + - value + type: object + type: array + secrets: + description: |- + List of references to Secrets objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the Secret will be injected as additional environment variables. + Otherwise, only the specified key will be injected as environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + extraFiles: + description: |- + References to existing Config objects to use as extra config files. + They will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret. + properties: + configMaps: + description: |- + List of references to ConfigMaps objects mounted as extra files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all extra configuration files + listed in the Items field + type: string + secrets: + description: |- + List of references to Secrets objects mounted as extra files under the MountPath specified. + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + image: + description: |- + Custom image to use in all containers (including Init Containers). + It is your responsibility to make sure the image is from trusted sources and has been validated for security compliance + type: string + imagePullSecrets: + description: Image Pull Secrets to use in all containers (including + Init Containers) + items: + type: string + type: array + replicas: + default: 1 + description: |- + Number of desired replicas to set in the Backstage Deployment. + Defaults to 1. + format: int32 + type: integer + route: + description: Route configuration. Used for OpenShift only. + properties: + enabled: + default: true + description: Control the creation of a Route on OpenShift. + type: boolean + host: + description: |- + Host is an alias/DNS that points to the service. Optional. + Ignored if Enabled is false. + If not specified a route name will typically be automatically + chosen. Must follow DNS952 subdomain conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + subdomain: + description: |- + Subdomain is a DNS subdomain that is requested within the ingress controller's + domain (as a subdomain). + Ignored if Enabled is false. + Example: subdomain `frontend` automatically receives the router subdomain + `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: |- + The tls field provides the ability to configure certificates for the route. + Ignored if Enabled is false. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: |- + certificate provides certificate contents. This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. + type: string + externalCertificateSecretName: + description: |- + ExternalCertificateSecretName provides certificate contents as a secret reference. + This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. The secret referenced should + be present in the same namespace as that of the Route. + Forbidden when `certificate` is set. + Note that securing Routes with external certificates in TLS secrets is a Technology Preview feature in OpenShift, + and requires enabling the `RouteExternalCertificate` OpenShift Feature Gate and might not be functionally complete. + type: string + key: + description: key provides key file contents + type: string + type: object + type: object + type: object + database: + description: Configuration for database access. Optional. + properties: + authSecretName: + description: |- + Name of the secret for database authentication. Optional. + For a local database deployment (EnableLocalDb=true), a secret will be auto generated if it does not exist. + The secret shall include information used for the database access. + An example for PostgreSQL DB access: + "POSTGRES_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_PORT": "5432" + "POSTGRES_USER": "postgres" + "POSTGRESQL_ADMIN_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_HOST": "backstage-psql-bs1" # For local database, set to "backstage-psql-". + type: string + enableLocalDb: + default: true + description: Control the creation of a local PostgreSQL DB. Set + to false if using for example an external Database for Backstage. + type: boolean + type: object + rawRuntimeConfig: + description: Raw Runtime RuntimeObjects configuration. For Advanced + scenarios. + properties: + backstageConfig: + description: Name of ConfigMap containing Backstage runtime objects + configuration + type: string + localDbConfig: + description: Name of ConfigMap containing LocalDb (PostgreSQL) + runtime objects configuration + type: string + type: object + type: object + status: + description: BackstageStatus defines the observed state of Backstage + properties: + conditions: + description: Conditions is the list of conditions describing the state + of the runtime + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + Backstage is the Schema for the Red Hat Developer Hub backstages API. + It comes with pre-built plug-ins, configuration settings, and deployment mechanisms, + which can help streamline the process of setting up a self-managed internal + developer portal for adopters who are just starting out. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BackstageSpec defines the desired state of Backstage + properties: + application: + description: Configuration for Backstage. Optional. + properties: + appConfig: + description: |- + References to existing app-configs ConfigMap objects, that will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret, + and will be mounted inside the main application container under a specified mount directory. + Additionally, each file will be passed as a `--config /mount/path/to/configmap/key` to the + main container args in the order of the entries defined in the AppConfigs list. + But bear in mind that for a single ConfigMap element containing several filenames, + the order in which those files will be appended to the main container args cannot be guaranteed. + So if you want to pass multiple app-config files, it is recommended to pass one ConfigMap per app-config file. + properties: + configMaps: + description: |- + List of ConfigMaps storing the app-config files. Will be mounted as files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + Bear in mind not to put sensitive data in those ConfigMaps. Instead, your app-config content can reference + environment variables (which you can set with the ExtraEnvs field) and/or include extra files (see the ExtraFiles field). + More details on https://backstage.io/docs/conf/writing/. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all app-config files listed in + the ConfigMapRefs field + type: string + type: object + dynamicPluginsConfigMapName: + description: |- + Reference to an existing ConfigMap for Dynamic Plugins. + A new one will be generated with the default config if not set. + The ConfigMap object must have an existing key named: 'dynamic-plugins.yaml'. + type: string + extraEnvs: + description: Extra environment variables + properties: + configMaps: + description: |- + List of references to ConfigMaps objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be injected as additional environment variables. + Otherwise, only the specified key will be injected as an additional environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + envs: + description: List of name and value pairs to add as environment + variables. + items: + properties: + name: + description: Name of the environment variable + type: string + value: + description: Value of the environment variable + type: string + required: + - name + - value + type: object + type: array + secrets: + description: |- + List of references to Secrets objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the Secret will be injected as additional environment variables. + Otherwise, only the specified key will be injected as environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + extraFiles: + description: |- + References to existing Config objects to use as extra config files. + They will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret. + properties: + configMaps: + description: |- + List of references to ConfigMaps objects mounted as extra files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all extra configuration files + listed in the Items field + type: string + secrets: + description: |- + List of references to Secrets objects mounted as extra files under the MountPath specified. + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + image: + description: |- + Custom image to use in all containers (including Init Containers). + It is your responsibility to make sure the image is from trusted sources and has been validated for security compliance + type: string + imagePullSecrets: + description: Image Pull Secrets to use in all containers (including + Init Containers) + items: + type: string + type: array + replicas: + default: 1 + description: |- + Number of desired replicas to set in the Backstage Deployment. + Defaults to 1. + format: int32 + type: integer + route: + description: Route configuration. Used for OpenShift only. + properties: + enabled: + default: true + description: Control the creation of a Route on OpenShift. + type: boolean + host: + description: |- + Host is an alias/DNS that points to the service. Optional. + Ignored if Enabled is false. + If not specified a route name will typically be automatically + chosen. Must follow DNS952 subdomain conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + subdomain: + description: |- + Subdomain is a DNS subdomain that is requested within the ingress controller's + domain (as a subdomain). + Ignored if Enabled is false. + Example: subdomain `frontend` automatically receives the router subdomain + `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: |- + The tls field provides the ability to configure certificates for the route. + Ignored if Enabled is false. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: |- + certificate provides certificate contents. This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. + type: string + externalCertificateSecretName: + description: |- + ExternalCertificateSecretName provides certificate contents as a secret reference. + This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. The secret referenced should + be present in the same namespace as that of the Route. + Forbidden when `certificate` is set. + Note that securing Routes with external certificates in TLS secrets is a Technology Preview feature in OpenShift, + and requires enabling the `RouteExternalCertificate` OpenShift Feature Gate and might not be functionally complete. + type: string + key: + description: key provides key file contents + type: string + type: object + type: object + type: object + database: + description: Configuration for database access. Optional. + properties: + authSecretName: + description: |- + Name of the secret for database authentication. Optional. + For a local database deployment (EnableLocalDb=true), a secret will be auto generated if it does not exist. + The secret shall include information used for the database access. + An example for PostgreSQL DB access: + "POSTGRES_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_PORT": "5432" + "POSTGRES_USER": "postgres" + "POSTGRESQL_ADMIN_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_HOST": "backstage-psql-bs1" # For local database, set to "backstage-psql-". + type: string + enableLocalDb: + default: true + description: Control the creation of a local PostgreSQL DB. Set + to false if using for example an external Database for Backstage. + type: boolean + type: object + deployment: + description: |- + Configuration for Backstage Deployment resource. + Optional. + properties: + patch: + description: |- + Valid fragment of Deployment to be merged with default/raw configuration. + Set the Deployment's metadata and|or spec fields you want to override or add. + Optional. + x-kubernetes-preserve-unknown-fields: true + type: object + rawRuntimeConfig: + description: Raw Runtime RuntimeObjects configuration. For Advanced + scenarios. + properties: + backstageConfig: + description: Name of ConfigMap containing Backstage runtime objects + configuration + type: string + localDbConfig: + description: Name of ConfigMap containing LocalDb (PostgreSQL) + runtime objects configuration + type: string + type: object + type: object + status: + description: BackstageStatus defines the observed state of Backstage + properties: + conditions: + description: Conditions is the list of conditions describing the state + of the runtime + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha3 + schema: + openAPIV3Schema: + description: |- + Backstage is the Schema for the Red Hat Developer Hub backstages API. + It comes with pre-built plug-ins, configuration settings, and deployment mechanisms, + which can help streamline the process of setting up a self-managed internal + developer portal for adopters who are just starting out. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BackstageSpec defines the desired state of Backstage + properties: + application: + description: Configuration for Backstage. Optional. + properties: + appConfig: + description: |- + References to existing app-configs ConfigMap objects, that will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret, + and will be mounted inside the main application container under a specified mount directory. + Additionally, each file will be passed as a `--config /mount/path/to/configmap/key` to the + main container args in the order of the entries defined in the AppConfigs list. + But bear in mind that for a single ConfigMap element containing several filenames, + the order in which those files will be appended to the main container args cannot be guaranteed. + So if you want to pass multiple app-config files, it is recommended to pass one ConfigMap per app-config file. + properties: + configMaps: + description: |- + List of ConfigMaps storing the app-config files. Will be mounted as files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + Bear in mind not to put sensitive data in those ConfigMaps. Instead, your app-config content can reference + environment variables (which you can set with the ExtraEnvs field) and/or include extra files (see the ExtraFiles field). + More details on https://backstage.io/docs/conf/writing/. + items: + properties: + key: + description: Key in the object + type: string + mountPath: + description: Path to mount the Object. If not specified + default-path/Name will be used + type: string + name: + description: |- + Name of the object + Supported ConfigMaps and Secrets + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all app-config files listed in + the ConfigMapRefs field + type: string + type: object + dynamicPluginsConfigMapName: + description: |- + Reference to an existing ConfigMap for Dynamic Plugins. + A new one will be generated with the default config if not set. + The ConfigMap object must have an existing key named: 'dynamic-plugins.yaml'. + type: string + extraEnvs: + description: Extra environment variables + properties: + configMaps: + description: |- + List of references to ConfigMaps objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be injected as additional environment variables. + Otherwise, only the specified key will be injected as an additional environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + envs: + description: List of name and value pairs to add as environment + variables. + items: + properties: + name: + description: Name of the environment variable + type: string + value: + description: Value of the environment variable + type: string + required: + - name + - value + type: object + type: array + secrets: + description: |- + List of references to Secrets objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the Secret will be injected as additional environment variables. + Otherwise, only the specified key will be injected as environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + extraFiles: + description: |- + References to existing Config objects to use as extra config files. + They will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret. + properties: + configMaps: + description: |- + List of references to ConfigMaps objects mounted as extra files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + mountPath: + description: Path to mount the Object. If not specified + default-path/Name will be used + type: string + name: + description: |- + Name of the object + Supported ConfigMaps and Secrets + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all extra configuration files + listed in the Items field + type: string + pvcs: + description: |- + List of references to Persistent Volume Claim objects mounted as extra files + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + mountPath: + description: Path to mount PVC. If not specified default-path/Name + will be used + type: string + name: + description: Name of the object + type: string + required: + - name + type: object + type: array + secrets: + description: |- + List of references to Secrets objects mounted as extra files under the MountPath specified. + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + mountPath: + description: Path to mount the Object. If not specified + default-path/Name will be used + type: string + name: + description: |- + Name of the object + Supported ConfigMaps and Secrets + type: string + required: + - name + type: object + type: array + type: object + image: + description: |- + Custom image to use in all containers (including Init Containers). + It is your responsibility to make sure the image is from trusted sources and has been validated for security compliance + type: string + imagePullSecrets: + description: Image Pull Secrets to use in all containers (including + Init Containers) + items: + type: string + type: array + replicas: + default: 1 + description: |- + Number of desired replicas to set in the Backstage Deployment. + Defaults to 1. + format: int32 + type: integer + route: + description: Route configuration. Used for OpenShift only. + properties: + enabled: + default: true + description: Control the creation of a Route on OpenShift. + type: boolean + host: + description: |- + Host is an alias/DNS that points to the service. Optional. + Ignored if Enabled is false. + If not specified a route name will typically be automatically + chosen. Must follow DNS952 subdomain conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + subdomain: + description: |- + Subdomain is a DNS subdomain that is requested within the ingress controller's + domain (as a subdomain). + Ignored if Enabled is false. + Example: subdomain `frontend` automatically receives the router subdomain + `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: |- + The tls field provides the ability to configure certificates for the route. + Ignored if Enabled is false. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: |- + certificate provides certificate contents. This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. + type: string + externalCertificateSecretName: + description: |- + ExternalCertificateSecretName provides certificate contents as a secret reference. + This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. The secret referenced should + be present in the same namespace as that of the Route. + Forbidden when `certificate` is set. + Note that securing Routes with external certificates in TLS secrets is a Technology Preview feature in OpenShift, + and requires enabling the `RouteExternalCertificate` OpenShift Feature Gate and might not be functionally complete. + type: string + key: + description: key provides key file contents + type: string + type: object + type: object + type: object + database: + description: Configuration for database access. Optional. + properties: + authSecretName: + description: |- + Name of the secret for database authentication. Optional. + For a local database deployment (EnableLocalDb=true), a secret will be auto generated if it does not exist. + The secret shall include information used for the database access. + An example for PostgreSQL DB access: + "POSTGRES_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_PORT": "5432" + "POSTGRES_USER": "postgres" + "POSTGRESQL_ADMIN_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_HOST": "backstage-psql-bs1" # For local database, set to "backstage-psql-". + type: string + enableLocalDb: + default: true + description: Control the creation of a local PostgreSQL DB. Set + to false if using for example an external Database for Backstage. + type: boolean + type: object + deployment: + description: |- + Valid fragment of Deployment to be merged with default/raw configuration. + Set the Deployment's metadata and|or spec fields you want to override or add. + Optional. + properties: + patch: + description: |- + Valid fragment of Deployment to be merged with default/raw configuration. + Set the Deployment's metadata and|or spec fields you want to override or add. + Optional. + x-kubernetes-preserve-unknown-fields: true + type: object + rawRuntimeConfig: + description: Raw Runtime RuntimeObjects configuration. For Advanced + scenarios. + properties: + backstageConfig: + description: Name of ConfigMap containing Backstage runtime objects + configuration + type: string + localDbConfig: + description: Name of ConfigMap containing LocalDb (PostgreSQL) + runtime objects configuration + type: string + type: object + type: object + status: + description: BackstageStatus defines the observed state of Backstage + properties: + conditions: + description: Conditions is the list of conditions describing the state + of the runtime + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: serviceaccount + app.kubernetes.io/part-of: backstage-operator + name: backstage-controller-manager + namespace: backstage-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: leader-election-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: role + app.kubernetes.io/part-of: backstage-operator + name: backstage-leader-election-role + namespace: backstage-system +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 +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: backstage-editor-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: backstage-operator + name: backstage-backstage-editor-role +rules: +- apiGroups: + - rhdh.redhat.com + resources: + - backstages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: backstage-viewer-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: backstage-operator + name: backstage-backstage-viewer-role +rules: +- apiGroups: + - rhdh.redhat.com + resources: + - backstages + verbs: + - get + - list + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: backstage-manager-role +rules: +- apiGroups: + - "" + resources: + - configmaps + - persistentvolumeclaims + - secrets + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - persistentvolumes + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: + - deployments + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/finalizers + verbs: + - update +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/status + verbs: + - get + - patch + - update +- apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: metrics-auth-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: metrics-auth-role + app.kubernetes.io/part-of: backstage-operator + name: backstage-metrics-auth-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: metrics-rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: metrics-reader + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: backstage-operator + name: backstage-metrics-reader +rules: +- nonResourceURLs: + - /metrics + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: leader-election-rolebinding + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: rolebinding + app.kubernetes.io/part-of: backstage-operator + name: backstage-leader-election-rolebinding + namespace: backstage-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: backstage-leader-election-role +subjects: +- kind: ServiceAccount + name: backstage-controller-manager + namespace: backstage-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: manager-rolebinding + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/part-of: backstage-operator + name: backstage-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: backstage-manager-role +subjects: +- kind: ServiceAccount + name: backstage-controller-manager + namespace: backstage-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: metrics-auth-rolebinding + app.kubernetes.io/name: metrics-auth-rolebinding + app.kubernetes.io/part-of: backstage-operator + name: backstage-metrics-auth-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: backstage-metrics-auth-role +subjects: +- kind: ServiceAccount + name: backstage-controller-manager + namespace: backstage-system +--- +apiVersion: v1 +data: + app-config.yaml: | + apiVersion: v1 + kind: ConfigMap + metadata: + name: my-backstage-config-cm1 # placeholder for -default-appconfig + data: + default.app-config.yaml: | + backend: + auth: + externalAccess: + - type: legacy + options: + subject: legacy-default-config + # This is a default value, which you should change by providing your own app-config + secret: "pl4s3Ch4ng3M3" + db-secret.yaml: |- + apiVersion: v1 + kind: Secret + metadata: + name: postgres-secrets # will be replaced + type: Opaque + #stringData: + # POSTGRES_PASSWORD: + # POSTGRES_PORT: "5432" + # POSTGRES_USER: postgres + # POSTGRESQL_ADMIN_PASSWORD: admin123 + # POSTGRES_HOST: bs1-db-service #placeholder -db-service + db-service.yaml: | + apiVersion: v1 + kind: Service + metadata: + name: backstage-psql # placeholder for 'backstage-psql-' .NOTE: For the time it is static and linked to Secret-> postgres-secrets -> OSTGRES_HOST + spec: + selector: + rhdh.redhat.com/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + clusterIP: None + ports: + - port: 5432 + db-statefulset.yaml: |- + apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: backstage-psql-cr1 # placeholder for 'backstage-psql-' + spec: + podManagementPolicy: OrderedReady + replicas: 1 + selector: + matchLabels: + rhdh.redhat.com/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + serviceName: backstage-psql-cr1-hl # placeholder for 'backstage-psql--hl' + template: + metadata: + labels: + rhdh.redhat.com/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + spec: + # fsGroup does not work for Openshift + # AKS/EKS does not work w/o it + #securityContext: + # fsGroup: 26 + automountServiceAccountToken: false + ## https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ + ## The optional .spec.persistentVolumeClaimRetentionPolicy field controls if and how PVCs are deleted during the lifecycle of a StatefulSet. + ## You must enable the StatefulSetAutoDeletePVC feature gate on the API server and the controller manager to use this field. + # persistentVolumeClaimRetentionPolicy: + # whenDeleted: Retain + # whenScaled: Retain + containers: + - env: + - name: POSTGRESQL_PORT_NUMBER + value: "5432" + - name: POSTGRESQL_VOLUME_DIR + value: /var/lib/pgsql/data + - name: PGDATA + value: /var/lib/pgsql/data/userdata + image: quay.io/fedora/postgresql-15:latest # will be replaced with the actual image + imagePullPolicy: IfNotPresent + securityContext: + # runAsUser:26 does not work for Openshift but looks work for AKS/EKS + # runAsUser: 26 + runAsGroup: 0 + runAsNonRoot: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL + livenessProbe: + exec: + command: + - /bin/sh + - -c + - exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 + failureThreshold: 6 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: postgresql + ports: + - containerPort: 5432 + name: tcp-postgresql + protocol: TCP + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + - | + exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 + failureThreshold: 6 + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 250m + memory: 1024Mi + ephemeral-storage: 20Mi + volumeMounts: + - mountPath: /dev/shm + name: dshm + - mountPath: /var/lib/pgsql/data + name: data + restartPolicy: Always + serviceAccountName: default + volumes: + - emptyDir: + medium: Memory + name: dshm + updateStrategy: + rollingUpdate: + partition: 0 + type: RollingUpdate + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + deployment.yaml: |- + # kubernetes/backstage.yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: backstage + spec: + selector: + matchLabels: + app: backstage + template: + metadata: + labels: + app: backstage + spec: + containers: + - name: backstage-backend + image: ghcr.io/backstage/backstage:1.28.4 + imagePullPolicy: IfNotPresent + command: + - "node" + - "packages/backend" + - "--no-node-snapshot" + args: + - "--config" + - "app-config.yaml" + - "--config" + - "app-config.production.yaml" + ports: + - name: http + containerPort: 7007 + # envFrom: + # - secretRef: + # name: postgres-secrets + # - secretRef: + # name: backstage-secrets + service.yaml: |- + apiVersion: v1 + kind: Service + metadata: + name: backstage # placeholder for 'backstage-' + spec: + type: ClusterIP + selector: + rhdh.redhat.com/app: # placeholder for 'backstage-' + ports: + - name: http-backend + port: 80 + targetPort: backend + - name: http-metrics + protocol: TCP + port: 9464 + targetPort: 9464 +kind: ConfigMap +metadata: + name: backstage-default-config + namespace: backstage-system +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: metrics + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: controller-manager-metrics-service + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: service + app.kubernetes.io/part-of: backstage-operator + control-plane: controller-manager + name: backstage-controller-manager-metrics-service + namespace: backstage-system +spec: + ports: + - name: metrics + port: 8443 + protocol: TCP + targetPort: metrics + selector: + control-plane: controller-manager +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: operator + control-plane: controller-manager + name: backstage-operator + namespace: backstage-system +spec: + replicas: 1 + selector: + matchLabels: + app: operator + strategy: + type: RollingUpdate + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + app: operator + control-plane: controller-manager + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - key: kubernetes.io/os + operator: In + values: + - linux + automountServiceAccountToken: true + containers: + - args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=:8443 + - --metrics-secure=true + - --leader-elect + command: + - /manager + image: quay.io/rhdh-community/operator:0.6.0 + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + ports: + - containerPort: 8081 + name: health + - containerPort: 8443 + name: metrics + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + ephemeral-storage: 20Mi + memory: 1Gi + requests: + cpu: 10m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /default-config + name: default-config + securityContext: + runAsNonRoot: true + serviceAccountName: backstage-controller-manager + terminationGracePeriodSeconds: 10 + volumes: + - configMap: + name: backstage-default-config + name: default-config diff --git a/dist/rhdh/install.yaml b/dist/rhdh/install.yaml new file mode 100644 index 000000000..da0a5c79c --- /dev/null +++ b/dist/rhdh/install.yaml @@ -0,0 +1,2025 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: system + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: namespace + app.kubernetes.io/part-of: backstage-operator + control-plane: controller-manager + name: rhdh-operator +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: backstages.rhdh.redhat.com +spec: + group: rhdh.redhat.com + names: + kind: Backstage + listKind: BackstageList + plural: backstages + singular: backstage + scope: Namespaced + versions: + - deprecated: true + deprecationWarning: Since 1.3.0 spec.application.image, spec.application.replicas, + spec.application.imagePullSecrets are deprecated in favor of corresponding spec.deployment + fields + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + Backstage is the Schema for the Red Hat Developer Hub backstages API. + It comes with pre-built plug-ins, configuration settings, and deployment mechanisms, + which can help streamline the process of setting up a self-managed internal + developer portal for adopters who are just starting out. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BackstageSpec defines the desired state of Backstage + properties: + application: + description: Configuration for Backstage. Optional. + properties: + appConfig: + description: |- + References to existing app-configs ConfigMap objects, that will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret, + and will be mounted inside the main application container under a specified mount directory. + Additionally, each file will be passed as a `--config /mount/path/to/configmap/key` to the + main container args in the order of the entries defined in the AppConfigs list. + But bear in mind that for a single ConfigMap element containing several filenames, + the order in which those files will be appended to the main container args cannot be guaranteed. + So if you want to pass multiple app-config files, it is recommended to pass one ConfigMap per app-config file. + properties: + configMaps: + description: |- + List of ConfigMaps storing the app-config files. Will be mounted as files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + Bear in mind not to put sensitive data in those ConfigMaps. Instead, your app-config content can reference + environment variables (which you can set with the ExtraEnvs field) and/or include extra files (see the ExtraFiles field). + More details on https://backstage.io/docs/conf/writing/. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all app-config files listed in + the ConfigMapRefs field + type: string + type: object + dynamicPluginsConfigMapName: + description: |- + Reference to an existing ConfigMap for Dynamic Plugins. + A new one will be generated with the default config if not set. + The ConfigMap object must have an existing key named: 'dynamic-plugins.yaml'. + type: string + extraEnvs: + description: Extra environment variables + properties: + configMaps: + description: |- + List of references to ConfigMaps objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be injected as additional environment variables. + Otherwise, only the specified key will be injected as an additional environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + envs: + description: List of name and value pairs to add as environment + variables. + items: + properties: + name: + description: Name of the environment variable + type: string + value: + description: Value of the environment variable + type: string + required: + - name + - value + type: object + type: array + secrets: + description: |- + List of references to Secrets objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the Secret will be injected as additional environment variables. + Otherwise, only the specified key will be injected as environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + extraFiles: + description: |- + References to existing Config objects to use as extra config files. + They will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret. + properties: + configMaps: + description: |- + List of references to ConfigMaps objects mounted as extra files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all extra configuration files + listed in the Items field + type: string + secrets: + description: |- + List of references to Secrets objects mounted as extra files under the MountPath specified. + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + image: + description: |- + Custom image to use in all containers (including Init Containers). + It is your responsibility to make sure the image is from trusted sources and has been validated for security compliance + type: string + imagePullSecrets: + description: Image Pull Secrets to use in all containers (including + Init Containers) + items: + type: string + type: array + replicas: + default: 1 + description: |- + Number of desired replicas to set in the Backstage Deployment. + Defaults to 1. + format: int32 + type: integer + route: + description: Route configuration. Used for OpenShift only. + properties: + enabled: + default: true + description: Control the creation of a Route on OpenShift. + type: boolean + host: + description: |- + Host is an alias/DNS that points to the service. Optional. + Ignored if Enabled is false. + If not specified a route name will typically be automatically + chosen. Must follow DNS952 subdomain conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + subdomain: + description: |- + Subdomain is a DNS subdomain that is requested within the ingress controller's + domain (as a subdomain). + Ignored if Enabled is false. + Example: subdomain `frontend` automatically receives the router subdomain + `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: |- + The tls field provides the ability to configure certificates for the route. + Ignored if Enabled is false. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: |- + certificate provides certificate contents. This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. + type: string + externalCertificateSecretName: + description: |- + ExternalCertificateSecretName provides certificate contents as a secret reference. + This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. The secret referenced should + be present in the same namespace as that of the Route. + Forbidden when `certificate` is set. + Note that securing Routes with external certificates in TLS secrets is a Technology Preview feature in OpenShift, + and requires enabling the `RouteExternalCertificate` OpenShift Feature Gate and might not be functionally complete. + type: string + key: + description: key provides key file contents + type: string + type: object + type: object + type: object + database: + description: Configuration for database access. Optional. + properties: + authSecretName: + description: |- + Name of the secret for database authentication. Optional. + For a local database deployment (EnableLocalDb=true), a secret will be auto generated if it does not exist. + The secret shall include information used for the database access. + An example for PostgreSQL DB access: + "POSTGRES_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_PORT": "5432" + "POSTGRES_USER": "postgres" + "POSTGRESQL_ADMIN_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_HOST": "backstage-psql-bs1" # For local database, set to "backstage-psql-". + type: string + enableLocalDb: + default: true + description: Control the creation of a local PostgreSQL DB. Set + to false if using for example an external Database for Backstage. + type: boolean + type: object + rawRuntimeConfig: + description: Raw Runtime RuntimeObjects configuration. For Advanced + scenarios. + properties: + backstageConfig: + description: Name of ConfigMap containing Backstage runtime objects + configuration + type: string + localDbConfig: + description: Name of ConfigMap containing LocalDb (PostgreSQL) + runtime objects configuration + type: string + type: object + type: object + status: + description: BackstageStatus defines the observed state of Backstage + properties: + conditions: + description: Conditions is the list of conditions describing the state + of the runtime + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + Backstage is the Schema for the Red Hat Developer Hub backstages API. + It comes with pre-built plug-ins, configuration settings, and deployment mechanisms, + which can help streamline the process of setting up a self-managed internal + developer portal for adopters who are just starting out. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BackstageSpec defines the desired state of Backstage + properties: + application: + description: Configuration for Backstage. Optional. + properties: + appConfig: + description: |- + References to existing app-configs ConfigMap objects, that will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret, + and will be mounted inside the main application container under a specified mount directory. + Additionally, each file will be passed as a `--config /mount/path/to/configmap/key` to the + main container args in the order of the entries defined in the AppConfigs list. + But bear in mind that for a single ConfigMap element containing several filenames, + the order in which those files will be appended to the main container args cannot be guaranteed. + So if you want to pass multiple app-config files, it is recommended to pass one ConfigMap per app-config file. + properties: + configMaps: + description: |- + List of ConfigMaps storing the app-config files. Will be mounted as files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + Bear in mind not to put sensitive data in those ConfigMaps. Instead, your app-config content can reference + environment variables (which you can set with the ExtraEnvs field) and/or include extra files (see the ExtraFiles field). + More details on https://backstage.io/docs/conf/writing/. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all app-config files listed in + the ConfigMapRefs field + type: string + type: object + dynamicPluginsConfigMapName: + description: |- + Reference to an existing ConfigMap for Dynamic Plugins. + A new one will be generated with the default config if not set. + The ConfigMap object must have an existing key named: 'dynamic-plugins.yaml'. + type: string + extraEnvs: + description: Extra environment variables + properties: + configMaps: + description: |- + List of references to ConfigMaps objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be injected as additional environment variables. + Otherwise, only the specified key will be injected as an additional environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + envs: + description: List of name and value pairs to add as environment + variables. + items: + properties: + name: + description: Name of the environment variable + type: string + value: + description: Value of the environment variable + type: string + required: + - name + - value + type: object + type: array + secrets: + description: |- + List of references to Secrets objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the Secret will be injected as additional environment variables. + Otherwise, only the specified key will be injected as environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + extraFiles: + description: |- + References to existing Config objects to use as extra config files. + They will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret. + properties: + configMaps: + description: |- + List of references to ConfigMaps objects mounted as extra files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all extra configuration files + listed in the Items field + type: string + secrets: + description: |- + List of references to Secrets objects mounted as extra files under the MountPath specified. + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + image: + description: |- + Custom image to use in all containers (including Init Containers). + It is your responsibility to make sure the image is from trusted sources and has been validated for security compliance + type: string + imagePullSecrets: + description: Image Pull Secrets to use in all containers (including + Init Containers) + items: + type: string + type: array + replicas: + default: 1 + description: |- + Number of desired replicas to set in the Backstage Deployment. + Defaults to 1. + format: int32 + type: integer + route: + description: Route configuration. Used for OpenShift only. + properties: + enabled: + default: true + description: Control the creation of a Route on OpenShift. + type: boolean + host: + description: |- + Host is an alias/DNS that points to the service. Optional. + Ignored if Enabled is false. + If not specified a route name will typically be automatically + chosen. Must follow DNS952 subdomain conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + subdomain: + description: |- + Subdomain is a DNS subdomain that is requested within the ingress controller's + domain (as a subdomain). + Ignored if Enabled is false. + Example: subdomain `frontend` automatically receives the router subdomain + `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: |- + The tls field provides the ability to configure certificates for the route. + Ignored if Enabled is false. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: |- + certificate provides certificate contents. This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. + type: string + externalCertificateSecretName: + description: |- + ExternalCertificateSecretName provides certificate contents as a secret reference. + This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. The secret referenced should + be present in the same namespace as that of the Route. + Forbidden when `certificate` is set. + Note that securing Routes with external certificates in TLS secrets is a Technology Preview feature in OpenShift, + and requires enabling the `RouteExternalCertificate` OpenShift Feature Gate and might not be functionally complete. + type: string + key: + description: key provides key file contents + type: string + type: object + type: object + type: object + database: + description: Configuration for database access. Optional. + properties: + authSecretName: + description: |- + Name of the secret for database authentication. Optional. + For a local database deployment (EnableLocalDb=true), a secret will be auto generated if it does not exist. + The secret shall include information used for the database access. + An example for PostgreSQL DB access: + "POSTGRES_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_PORT": "5432" + "POSTGRES_USER": "postgres" + "POSTGRESQL_ADMIN_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_HOST": "backstage-psql-bs1" # For local database, set to "backstage-psql-". + type: string + enableLocalDb: + default: true + description: Control the creation of a local PostgreSQL DB. Set + to false if using for example an external Database for Backstage. + type: boolean + type: object + deployment: + description: |- + Configuration for Backstage Deployment resource. + Optional. + properties: + patch: + description: |- + Valid fragment of Deployment to be merged with default/raw configuration. + Set the Deployment's metadata and|or spec fields you want to override or add. + Optional. + x-kubernetes-preserve-unknown-fields: true + type: object + rawRuntimeConfig: + description: Raw Runtime RuntimeObjects configuration. For Advanced + scenarios. + properties: + backstageConfig: + description: Name of ConfigMap containing Backstage runtime objects + configuration + type: string + localDbConfig: + description: Name of ConfigMap containing LocalDb (PostgreSQL) + runtime objects configuration + type: string + type: object + type: object + status: + description: BackstageStatus defines the observed state of Backstage + properties: + conditions: + description: Conditions is the list of conditions describing the state + of the runtime + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha3 + schema: + openAPIV3Schema: + description: |- + Backstage is the Schema for the Red Hat Developer Hub backstages API. + It comes with pre-built plug-ins, configuration settings, and deployment mechanisms, + which can help streamline the process of setting up a self-managed internal + developer portal for adopters who are just starting out. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BackstageSpec defines the desired state of Backstage + properties: + application: + description: Configuration for Backstage. Optional. + properties: + appConfig: + description: |- + References to existing app-configs ConfigMap objects, that will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret, + and will be mounted inside the main application container under a specified mount directory. + Additionally, each file will be passed as a `--config /mount/path/to/configmap/key` to the + main container args in the order of the entries defined in the AppConfigs list. + But bear in mind that for a single ConfigMap element containing several filenames, + the order in which those files will be appended to the main container args cannot be guaranteed. + So if you want to pass multiple app-config files, it is recommended to pass one ConfigMap per app-config file. + properties: + configMaps: + description: |- + List of ConfigMaps storing the app-config files. Will be mounted as files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + Bear in mind not to put sensitive data in those ConfigMaps. Instead, your app-config content can reference + environment variables (which you can set with the ExtraEnvs field) and/or include extra files (see the ExtraFiles field). + More details on https://backstage.io/docs/conf/writing/. + items: + properties: + key: + description: Key in the object + type: string + mountPath: + description: Path to mount the Object. If not specified + default-path/Name will be used + type: string + name: + description: |- + Name of the object + Supported ConfigMaps and Secrets + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all app-config files listed in + the ConfigMapRefs field + type: string + type: object + dynamicPluginsConfigMapName: + description: |- + Reference to an existing ConfigMap for Dynamic Plugins. + A new one will be generated with the default config if not set. + The ConfigMap object must have an existing key named: 'dynamic-plugins.yaml'. + type: string + extraEnvs: + description: Extra environment variables + properties: + configMaps: + description: |- + List of references to ConfigMaps objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be injected as additional environment variables. + Otherwise, only the specified key will be injected as an additional environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + envs: + description: List of name and value pairs to add as environment + variables. + items: + properties: + name: + description: Name of the environment variable + type: string + value: + description: Value of the environment variable + type: string + required: + - name + - value + type: object + type: array + secrets: + description: |- + List of references to Secrets objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the Secret will be injected as additional environment variables. + Otherwise, only the specified key will be injected as environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + extraFiles: + description: |- + References to existing Config objects to use as extra config files. + They will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret. + properties: + configMaps: + description: |- + List of references to ConfigMaps objects mounted as extra files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + mountPath: + description: Path to mount the Object. If not specified + default-path/Name will be used + type: string + name: + description: |- + Name of the object + Supported ConfigMaps and Secrets + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all extra configuration files + listed in the Items field + type: string + pvcs: + description: |- + List of references to Persistent Volume Claim objects mounted as extra files + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + mountPath: + description: Path to mount PVC. If not specified default-path/Name + will be used + type: string + name: + description: Name of the object + type: string + required: + - name + type: object + type: array + secrets: + description: |- + List of references to Secrets objects mounted as extra files under the MountPath specified. + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + mountPath: + description: Path to mount the Object. If not specified + default-path/Name will be used + type: string + name: + description: |- + Name of the object + Supported ConfigMaps and Secrets + type: string + required: + - name + type: object + type: array + type: object + image: + description: |- + Custom image to use in all containers (including Init Containers). + It is your responsibility to make sure the image is from trusted sources and has been validated for security compliance + type: string + imagePullSecrets: + description: Image Pull Secrets to use in all containers (including + Init Containers) + items: + type: string + type: array + replicas: + default: 1 + description: |- + Number of desired replicas to set in the Backstage Deployment. + Defaults to 1. + format: int32 + type: integer + route: + description: Route configuration. Used for OpenShift only. + properties: + enabled: + default: true + description: Control the creation of a Route on OpenShift. + type: boolean + host: + description: |- + Host is an alias/DNS that points to the service. Optional. + Ignored if Enabled is false. + If not specified a route name will typically be automatically + chosen. Must follow DNS952 subdomain conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + subdomain: + description: |- + Subdomain is a DNS subdomain that is requested within the ingress controller's + domain (as a subdomain). + Ignored if Enabled is false. + Example: subdomain `frontend` automatically receives the router subdomain + `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: |- + The tls field provides the ability to configure certificates for the route. + Ignored if Enabled is false. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: |- + certificate provides certificate contents. This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. + type: string + externalCertificateSecretName: + description: |- + ExternalCertificateSecretName provides certificate contents as a secret reference. + This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. The secret referenced should + be present in the same namespace as that of the Route. + Forbidden when `certificate` is set. + Note that securing Routes with external certificates in TLS secrets is a Technology Preview feature in OpenShift, + and requires enabling the `RouteExternalCertificate` OpenShift Feature Gate and might not be functionally complete. + type: string + key: + description: key provides key file contents + type: string + type: object + type: object + type: object + database: + description: Configuration for database access. Optional. + properties: + authSecretName: + description: |- + Name of the secret for database authentication. Optional. + For a local database deployment (EnableLocalDb=true), a secret will be auto generated if it does not exist. + The secret shall include information used for the database access. + An example for PostgreSQL DB access: + "POSTGRES_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_PORT": "5432" + "POSTGRES_USER": "postgres" + "POSTGRESQL_ADMIN_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_HOST": "backstage-psql-bs1" # For local database, set to "backstage-psql-". + type: string + enableLocalDb: + default: true + description: Control the creation of a local PostgreSQL DB. Set + to false if using for example an external Database for Backstage. + type: boolean + type: object + deployment: + description: |- + Valid fragment of Deployment to be merged with default/raw configuration. + Set the Deployment's metadata and|or spec fields you want to override or add. + Optional. + properties: + patch: + description: |- + Valid fragment of Deployment to be merged with default/raw configuration. + Set the Deployment's metadata and|or spec fields you want to override or add. + Optional. + x-kubernetes-preserve-unknown-fields: true + type: object + rawRuntimeConfig: + description: Raw Runtime RuntimeObjects configuration. For Advanced + scenarios. + properties: + backstageConfig: + description: Name of ConfigMap containing Backstage runtime objects + configuration + type: string + localDbConfig: + description: Name of ConfigMap containing LocalDb (PostgreSQL) + runtime objects configuration + type: string + type: object + type: object + status: + description: BackstageStatus defines the observed state of Backstage + properties: + conditions: + description: Conditions is the list of conditions describing the state + of the runtime + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: serviceaccount + app.kubernetes.io/part-of: backstage-operator + name: rhdh-controller-manager + namespace: rhdh-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: leader-election-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: role + app.kubernetes.io/part-of: backstage-operator + name: rhdh-leader-election-role + namespace: rhdh-operator +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 +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: backstage-editor-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: backstage-operator + name: rhdh-backstage-editor-role +rules: +- apiGroups: + - rhdh.redhat.com + resources: + - backstages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: backstage-viewer-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: backstage-operator + name: rhdh-backstage-viewer-role +rules: +- apiGroups: + - rhdh.redhat.com + resources: + - backstages + verbs: + - get + - list + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: rhdh-manager-role +rules: +- apiGroups: + - "" + resources: + - configmaps + - persistentvolumeclaims + - secrets + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - persistentvolumes + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: + - deployments + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/finalizers + verbs: + - update +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/status + verbs: + - get + - patch + - update +- apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: metrics-auth-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: metrics-auth-role + app.kubernetes.io/part-of: backstage-operator + name: rhdh-metrics-auth-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: metrics-rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: metrics-reader + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: backstage-operator + name: rhdh-metrics-reader +rules: +- nonResourceURLs: + - /metrics + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: leader-election-rolebinding + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: rolebinding + app.kubernetes.io/part-of: backstage-operator + name: rhdh-leader-election-rolebinding + namespace: rhdh-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rhdh-leader-election-role +subjects: +- kind: ServiceAccount + name: rhdh-controller-manager + namespace: rhdh-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: manager-rolebinding + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/part-of: backstage-operator + name: rhdh-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: rhdh-manager-role +subjects: +- kind: ServiceAccount + name: rhdh-controller-manager + namespace: rhdh-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: metrics-auth-rolebinding + app.kubernetes.io/name: metrics-auth-rolebinding + app.kubernetes.io/part-of: backstage-operator + name: rhdh-metrics-auth-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: rhdh-metrics-auth-role +subjects: +- kind: ServiceAccount + name: rhdh-controller-manager + namespace: rhdh-operator +--- +apiVersion: v1 +data: + app-config.yaml: | + apiVersion: v1 + kind: ConfigMap + metadata: + name: my-backstage-config-cm1 # placeholder for -default-appconfig + data: + default.app-config.yaml: | + backend: + auth: + externalAccess: + - type: legacy + options: + subject: legacy-default-config + # This is a default value, which you should change by providing your own app-config + secret: "pl4s3Ch4ng3M3" + auth: + providers: {} + db-secret.yaml: |- + apiVersion: v1 + kind: Secret + metadata: + name: postgres-secrets # will be replaced + type: Opaque + #stringData: + # POSTGRES_PASSWORD: + # POSTGRES_PORT: "5432" + # POSTGRES_USER: postgres + # POSTGRESQL_ADMIN_PASSWORD: admin123 + # POSTGRES_HOST: bs1-db-service #placeholder -db-service + db-service.yaml: | + apiVersion: v1 + kind: Service + metadata: + name: backstage-psql # placeholder for 'backstage-psql-' .NOTE: For the time it is static and linked to Secret-> postgres-secrets -> OSTGRES_HOST + spec: + selector: + rhdh.redhat.com/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + clusterIP: None + ports: + - port: 5432 + db-statefulset.yaml: |- + apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: backstage-psql-cr1 # placeholder for 'backstage-psql-' + spec: + podManagementPolicy: OrderedReady + replicas: 1 + selector: + matchLabels: + rhdh.redhat.com/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + serviceName: backstage-psql-cr1-hl # placeholder for 'backstage-psql--hl' + template: + metadata: + labels: + rhdh.redhat.com/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + spec: + # fsGroup does not work for Openshift + # AKS/EKS does not work w/o it + #securityContext: + # fsGroup: 26 + automountServiceAccountToken: false + ## https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ + ## The optional .spec.persistentVolumeClaimRetentionPolicy field controls if and how PVCs are deleted during the lifecycle of a StatefulSet. + ## You must enable the StatefulSetAutoDeletePVC feature gate on the API server and the controller manager to use this field. + # persistentVolumeClaimRetentionPolicy: + # whenDeleted: Retain + # whenScaled: Retain + containers: + - env: + - name: POSTGRESQL_PORT_NUMBER + value: "5432" + - name: POSTGRESQL_VOLUME_DIR + value: /var/lib/pgsql/data + - name: PGDATA + value: /var/lib/pgsql/data/userdata + image: quay.io/fedora/postgresql-15:latest # will be replaced with the actual image + imagePullPolicy: IfNotPresent + securityContext: + # runAsUser:26 does not work for Openshift but looks work for AKS/EKS + # runAsUser: 26 + runAsGroup: 0 + runAsNonRoot: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL + livenessProbe: + exec: + command: + - /bin/sh + - -c + - exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 + failureThreshold: 6 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: postgresql + ports: + - containerPort: 5432 + name: tcp-postgresql + protocol: TCP + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + - | + exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 + failureThreshold: 6 + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 250m + memory: 1024Mi + ephemeral-storage: 20Mi + volumeMounts: + - mountPath: /dev/shm + name: dshm + - mountPath: /var/lib/pgsql/data + name: data + restartPolicy: Always + serviceAccountName: default + volumes: + - emptyDir: + medium: Memory + name: dshm + updateStrategy: + rollingUpdate: + partition: 0 + type: RollingUpdate + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + db-statefulset.yaml.k8s: |- + # if securityContext not present in AKS/EKS, the error is like this: + # Error: EACCES: permission denied, open '/dynamic-plugins-root/backstage-plugin-scaffolder-backend-module-github-dynamic-0.2.2.tgz' + # fsGroup doesn not work for Openshift + spec: + template: + spec: + securityContext: + # any group id + fsGroup: 1001 + deployment.yaml: | + apiVersion: apps/v1 + kind: Deployment + metadata: + name: backstage # placeholder for 'backstage-' + spec: + replicas: 1 + selector: + matchLabels: + rhdh.redhat.com/app: # placeholder for 'backstage-' + template: + metadata: + labels: + rhdh.redhat.com/app: # placeholder for 'backstage-' + spec: + automountServiceAccountToken: false + # if securityContext not present in AKS/EKS, the error is like this: + #Error: EACCES: permission denied, open '/dynamic-plugins-root/backstage-plugin-scaffolder-backend-module-github-dynamic-0.2.2.tgz' + # fsGroup doesn not work for Openshift + #securityContext: + # fsGroup: 1001 + volumes: + - ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + name: dynamic-plugins-root + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: dynamic-plugins-npmrc + - name: dynamic-plugins-registry-auth + secret: + defaultMode: 416 + optional: true + secretName: dynamic-plugins-registry-auth + - emptyDir: {} + name: npmcacache + - name: temp + emptyDir: {} + initContainers: + - name: install-dynamic-plugins + command: + - ./install-dynamic-plugins.sh + - /dynamic-plugins-root + # image will be replaced by the value of the `RELATED_IMAGE_backstage` env var, if set + image: quay.io/rhdh/rhdh-hub-rhel9:next + imagePullPolicy: IfNotPresent + securityContext: + readOnlyRootFilesystem: true + runAsNonRoot: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL + env: + - name: NPM_CONFIG_USERCONFIG + value: /opt/app-root/src/.npmrc.dynamic-plugins + volumeMounts: + - mountPath: /dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins + name: dynamic-plugins-npmrc + readOnly: true + subPath: .npmrc + - mountPath: /opt/app-root/src/.config/containers + name: dynamic-plugins-registry-auth + readOnly: true + - mountPath: /opt/app-root/src/.npm/_cacache + name: npmcacache + - mountPath: /tmp + name: temp + workingDir: /opt/app-root/src + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 1000m + memory: 2.5Gi + ephemeral-storage: 5Gi + containers: + - name: backstage-backend + # image will be replaced by the value of the `RELATED_IMAGE_backstage` env var, if set + image: quay.io/rhdh/rhdh-hub-rhel9:next + imagePullPolicy: IfNotPresent + args: + - "--config" + - "dynamic-plugins-root/app-config.dynamic-plugins.yaml" + securityContext: + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + allowPrivilegeEscalation: false + startupProbe: + # This gives enough time upon container startup before the liveness and readiness probes are triggered. + # Giving (120s = initialDelaySeconds + failureThreshold * periodSeconds) to account for the worst case scenario. + httpGet: + path: /.backstage/health/v1/liveness + port: backend + scheme: HTTP + initialDelaySeconds: 30 + timeoutSeconds: 4 + periodSeconds: 20 + successThreshold: 1 + failureThreshold: 3 + readinessProbe: + failureThreshold: 3 + httpGet: + path: /.backstage/health/v1/readiness + port: backend + scheme: HTTP + # Both liveness and readiness probes won't be triggered until the startup probe is successful. + # The startup probe is already configured to give enough time for the application to be started. + # So removing the additional delay here allows the readiness probe to be checked right away after the startup probe, + # which helps make the application available faster to the end-user. + #initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 2 + timeoutSeconds: 4 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /.backstage/health/v1/liveness + port: backend + scheme: HTTP + # Both liveness and readiness probes won't be triggered until the startup probe is successful. + # The startup probe is already configured to give enough time for the application to be started. + # So removing the additional delay here allows the readiness probe to be checked right away after the startup probe, + # which helps make the application available faster to the end-user. + #initialDelaySeconds: 60 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 4 + ports: + - name: backend + containerPort: 7007 + env: + - name: APP_CONFIG_backend_listen_port + value: "7007" + volumeMounts: + - mountPath: /opt/app-root/src/dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /tmp + name: temp + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 1000m + memory: 2.5Gi + ephemeral-storage: 5Gi + workingDir: /opt/app-root/src + deployment.yaml.k8s: |- + # if securityContext not present in AKS/EKS, the error is like this: + # Error: EACCES: permission denied, open '/dynamic-plugins-root/backstage-plugin-scaffolder-backend-module-github-dynamic-0.2.2.tgz' + # fsGroup doesn not work for Openshift + spec: + template: + spec: + securityContext: + # any group id + fsGroup: 1001 + dynamic-plugins.yaml: |- + apiVersion: v1 + kind: ConfigMap + metadata: + name: default-dynamic-plugins # must be the same as (deployment.yaml).spec.template.spec.volumes.name.dynamic-plugins-conf.configMap.name + data: + "dynamic-plugins.yaml": | + includes: + - dynamic-plugins.default.yaml + plugins: [] + route.yaml: |- + apiVersion: route.openshift.io/v1 + kind: Route + metadata: + name: route # placeholder for 'backstage-' + spec: + port: + targetPort: http-backend + path: / + tls: + insecureEdgeTerminationPolicy: Redirect + termination: edge + to: + kind: Service + name: # placeholder for 'backstage-' + secret-envs.yaml: | + apiVersion: v1 + kind: Secret + metadata: + name: backend-auth-secret + stringData: + # generated with the command below (from https://janus-idp.io/docs/auth/service-to-service-auth/#setup): + # node -p 'require("crypto").randomBytes(24).toString("base64")' + BACKEND_SECRET: "R2FxRVNrcmwzYzhhN3l0V1VRcnQ3L1pLT09WaVhDNUEK" # notsecret + service.yaml: |- + apiVersion: v1 + kind: Service + metadata: + name: backstage # placeholder for 'backstage-' + spec: + type: ClusterIP + selector: + rhdh.redhat.com/app: # placeholder for 'backstage-' + ports: + - name: http-backend + port: 80 + targetPort: backend + - name: http-metrics + protocol: TCP + port: 9464 + targetPort: 9464 + service.yaml.k8s: | + spec: + type: NodePort +kind: ConfigMap +metadata: + name: rhdh-default-config + namespace: rhdh-operator +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: metrics + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: controller-manager-metrics-service + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: service + app.kubernetes.io/part-of: backstage-operator + control-plane: controller-manager + name: rhdh-controller-manager-metrics-service + namespace: rhdh-operator +spec: + ports: + - name: metrics + port: 8443 + protocol: TCP + targetPort: metrics + selector: + control-plane: controller-manager +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: rhdh-operator + control-plane: controller-manager + name: rhdh-operator + namespace: rhdh-operator +spec: + replicas: 1 + selector: + matchLabels: + app: rhdh-operator + strategy: + type: RollingUpdate + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + app: rhdh-operator + app.kubernetes.io/component: rhdh-operator + control-plane: controller-manager + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - key: kubernetes.io/os + operator: In + values: + - linux + automountServiceAccountToken: true + containers: + - args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=:8443 + - --metrics-secure=true + - --leader-elect + command: + - /manager + env: + - name: OPERATOR_NAME + value: rhdh-operator + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: RELATED_IMAGE_postgresql + value: quay.io/fedora/postgresql-15:latest + - name: RELATED_IMAGE_backstage + value: quay.io/rhdh/rhdh-hub-rhel9:next + image: quay.io/rhdh/rhdh-rhel9-operator:1.6 + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + ports: + - containerPort: 8081 + name: health + - containerPort: 8443 + name: metrics + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + ephemeral-storage: 20Mi + memory: 1Gi + requests: + cpu: 10m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /default-config + name: default-config + securityContext: + runAsNonRoot: true + serviceAccountName: rhdh-controller-manager + terminationGracePeriodSeconds: 10 + volumes: + - configMap: + name: rhdh-default-config + name: default-config diff --git a/tests/e2e/testdata/rhdh-operator-1.3.yaml b/tests/e2e/testdata/rhdh-operator-1.3.yaml index 6afb9ed9f..6ed1315cc 100644 --- a/tests/e2e/testdata/rhdh-operator-1.3.yaml +++ b/tests/e2e/testdata/rhdh-operator-1.3.yaml @@ -1478,7 +1478,7 @@ spec: value: quay.io/fedora/postgresql-15:latest - name: RELATED_IMAGE_backstage value: quay.io/rhdh/rhdh-hub-rhel9:1.3 - image: quay.io/rhdh-community/operator:0.3.4 + image: quay.io/rhdh-community/operator:0.3.6 livenessProbe: httpGet: path: /healthz diff --git a/tests/e2e/testdata/rhdh-operator-1.4.yaml b/tests/e2e/testdata/rhdh-operator-1.4.yaml index 67d567d76..4ba75ef2c 100644 --- a/tests/e2e/testdata/rhdh-operator-1.4.yaml +++ b/tests/e2e/testdata/rhdh-operator-1.4.yaml @@ -1952,7 +1952,7 @@ spec: value: quay.io/fedora/postgresql-15:latest - name: RELATED_IMAGE_backstage value: quay.io/rhdh/rhdh-hub-rhel9:1.4 - image: quay.io/rhdh-community/operator:0.4.1 + image: quay.io/rhdh-community/operator:0.4.2 livenessProbe: httpGet: path: /healthz diff --git a/tests/e2e/testdata/rhdh-operator-1.5.yaml b/tests/e2e/testdata/rhdh-operator-1.5.yaml new file mode 100644 index 000000000..2c4e268e0 --- /dev/null +++ b/tests/e2e/testdata/rhdh-operator-1.5.yaml @@ -0,0 +1,2025 @@ +apiVersion: v1 +kind: Namespace +metadata: + labels: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: system + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: namespace + app.kubernetes.io/part-of: backstage-operator + control-plane: controller-manager + name: rhdh-operator +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: backstages.rhdh.redhat.com +spec: + group: rhdh.redhat.com + names: + kind: Backstage + listKind: BackstageList + plural: backstages + singular: backstage + scope: Namespaced + versions: + - deprecated: true + deprecationWarning: Since 1.3.0 spec.application.image, spec.application.replicas, + spec.application.imagePullSecrets are deprecated in favor of corresponding spec.deployment + fields + name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + Backstage is the Schema for the Red Hat Developer Hub backstages API. + It comes with pre-built plug-ins, configuration settings, and deployment mechanisms, + which can help streamline the process of setting up a self-managed internal + developer portal for adopters who are just starting out. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BackstageSpec defines the desired state of Backstage + properties: + application: + description: Configuration for Backstage. Optional. + properties: + appConfig: + description: |- + References to existing app-configs ConfigMap objects, that will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret, + and will be mounted inside the main application container under a specified mount directory. + Additionally, each file will be passed as a `--config /mount/path/to/configmap/key` to the + main container args in the order of the entries defined in the AppConfigs list. + But bear in mind that for a single ConfigMap element containing several filenames, + the order in which those files will be appended to the main container args cannot be guaranteed. + So if you want to pass multiple app-config files, it is recommended to pass one ConfigMap per app-config file. + properties: + configMaps: + description: |- + List of ConfigMaps storing the app-config files. Will be mounted as files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + Bear in mind not to put sensitive data in those ConfigMaps. Instead, your app-config content can reference + environment variables (which you can set with the ExtraEnvs field) and/or include extra files (see the ExtraFiles field). + More details on https://backstage.io/docs/conf/writing/. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all app-config files listed in + the ConfigMapRefs field + type: string + type: object + dynamicPluginsConfigMapName: + description: |- + Reference to an existing ConfigMap for Dynamic Plugins. + A new one will be generated with the default config if not set. + The ConfigMap object must have an existing key named: 'dynamic-plugins.yaml'. + type: string + extraEnvs: + description: Extra environment variables + properties: + configMaps: + description: |- + List of references to ConfigMaps objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be injected as additional environment variables. + Otherwise, only the specified key will be injected as an additional environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + envs: + description: List of name and value pairs to add as environment + variables. + items: + properties: + name: + description: Name of the environment variable + type: string + value: + description: Value of the environment variable + type: string + required: + - name + - value + type: object + type: array + secrets: + description: |- + List of references to Secrets objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the Secret will be injected as additional environment variables. + Otherwise, only the specified key will be injected as environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + extraFiles: + description: |- + References to existing Config objects to use as extra config files. + They will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret. + properties: + configMaps: + description: |- + List of references to ConfigMaps objects mounted as extra files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all extra configuration files + listed in the Items field + type: string + secrets: + description: |- + List of references to Secrets objects mounted as extra files under the MountPath specified. + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + image: + description: |- + Custom image to use in all containers (including Init Containers). + It is your responsibility to make sure the image is from trusted sources and has been validated for security compliance + type: string + imagePullSecrets: + description: Image Pull Secrets to use in all containers (including + Init Containers) + items: + type: string + type: array + replicas: + default: 1 + description: |- + Number of desired replicas to set in the Backstage Deployment. + Defaults to 1. + format: int32 + type: integer + route: + description: Route configuration. Used for OpenShift only. + properties: + enabled: + default: true + description: Control the creation of a Route on OpenShift. + type: boolean + host: + description: |- + Host is an alias/DNS that points to the service. Optional. + Ignored if Enabled is false. + If not specified a route name will typically be automatically + chosen. Must follow DNS952 subdomain conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + subdomain: + description: |- + Subdomain is a DNS subdomain that is requested within the ingress controller's + domain (as a subdomain). + Ignored if Enabled is false. + Example: subdomain `frontend` automatically receives the router subdomain + `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: |- + The tls field provides the ability to configure certificates for the route. + Ignored if Enabled is false. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: |- + certificate provides certificate contents. This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. + type: string + externalCertificateSecretName: + description: |- + ExternalCertificateSecretName provides certificate contents as a secret reference. + This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. The secret referenced should + be present in the same namespace as that of the Route. + Forbidden when `certificate` is set. + Note that securing Routes with external certificates in TLS secrets is a Technology Preview feature in OpenShift, + and requires enabling the `RouteExternalCertificate` OpenShift Feature Gate and might not be functionally complete. + type: string + key: + description: key provides key file contents + type: string + type: object + type: object + type: object + database: + description: Configuration for database access. Optional. + properties: + authSecretName: + description: |- + Name of the secret for database authentication. Optional. + For a local database deployment (EnableLocalDb=true), a secret will be auto generated if it does not exist. + The secret shall include information used for the database access. + An example for PostgreSQL DB access: + "POSTGRES_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_PORT": "5432" + "POSTGRES_USER": "postgres" + "POSTGRESQL_ADMIN_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_HOST": "backstage-psql-bs1" # For local database, set to "backstage-psql-". + type: string + enableLocalDb: + default: true + description: Control the creation of a local PostgreSQL DB. Set + to false if using for example an external Database for Backstage. + type: boolean + type: object + rawRuntimeConfig: + description: Raw Runtime RuntimeObjects configuration. For Advanced + scenarios. + properties: + backstageConfig: + description: Name of ConfigMap containing Backstage runtime objects + configuration + type: string + localDbConfig: + description: Name of ConfigMap containing LocalDb (PostgreSQL) + runtime objects configuration + type: string + type: object + type: object + status: + description: BackstageStatus defines the observed state of Backstage + properties: + conditions: + description: Conditions is the list of conditions describing the state + of the runtime + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha2 + schema: + openAPIV3Schema: + description: |- + Backstage is the Schema for the Red Hat Developer Hub backstages API. + It comes with pre-built plug-ins, configuration settings, and deployment mechanisms, + which can help streamline the process of setting up a self-managed internal + developer portal for adopters who are just starting out. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BackstageSpec defines the desired state of Backstage + properties: + application: + description: Configuration for Backstage. Optional. + properties: + appConfig: + description: |- + References to existing app-configs ConfigMap objects, that will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret, + and will be mounted inside the main application container under a specified mount directory. + Additionally, each file will be passed as a `--config /mount/path/to/configmap/key` to the + main container args in the order of the entries defined in the AppConfigs list. + But bear in mind that for a single ConfigMap element containing several filenames, + the order in which those files will be appended to the main container args cannot be guaranteed. + So if you want to pass multiple app-config files, it is recommended to pass one ConfigMap per app-config file. + properties: + configMaps: + description: |- + List of ConfigMaps storing the app-config files. Will be mounted as files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + Bear in mind not to put sensitive data in those ConfigMaps. Instead, your app-config content can reference + environment variables (which you can set with the ExtraEnvs field) and/or include extra files (see the ExtraFiles field). + More details on https://backstage.io/docs/conf/writing/. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all app-config files listed in + the ConfigMapRefs field + type: string + type: object + dynamicPluginsConfigMapName: + description: |- + Reference to an existing ConfigMap for Dynamic Plugins. + A new one will be generated with the default config if not set. + The ConfigMap object must have an existing key named: 'dynamic-plugins.yaml'. + type: string + extraEnvs: + description: Extra environment variables + properties: + configMaps: + description: |- + List of references to ConfigMaps objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be injected as additional environment variables. + Otherwise, only the specified key will be injected as an additional environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + envs: + description: List of name and value pairs to add as environment + variables. + items: + properties: + name: + description: Name of the environment variable + type: string + value: + description: Value of the environment variable + type: string + required: + - name + - value + type: object + type: array + secrets: + description: |- + List of references to Secrets objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the Secret will be injected as additional environment variables. + Otherwise, only the specified key will be injected as environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + extraFiles: + description: |- + References to existing Config objects to use as extra config files. + They will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret. + properties: + configMaps: + description: |- + List of references to ConfigMaps objects mounted as extra files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all extra configuration files + listed in the Items field + type: string + secrets: + description: |- + List of references to Secrets objects mounted as extra files under the MountPath specified. + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + image: + description: |- + Custom image to use in all containers (including Init Containers). + It is your responsibility to make sure the image is from trusted sources and has been validated for security compliance + type: string + imagePullSecrets: + description: Image Pull Secrets to use in all containers (including + Init Containers) + items: + type: string + type: array + replicas: + default: 1 + description: |- + Number of desired replicas to set in the Backstage Deployment. + Defaults to 1. + format: int32 + type: integer + route: + description: Route configuration. Used for OpenShift only. + properties: + enabled: + default: true + description: Control the creation of a Route on OpenShift. + type: boolean + host: + description: |- + Host is an alias/DNS that points to the service. Optional. + Ignored if Enabled is false. + If not specified a route name will typically be automatically + chosen. Must follow DNS952 subdomain conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + subdomain: + description: |- + Subdomain is a DNS subdomain that is requested within the ingress controller's + domain (as a subdomain). + Ignored if Enabled is false. + Example: subdomain `frontend` automatically receives the router subdomain + `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: |- + The tls field provides the ability to configure certificates for the route. + Ignored if Enabled is false. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: |- + certificate provides certificate contents. This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. + type: string + externalCertificateSecretName: + description: |- + ExternalCertificateSecretName provides certificate contents as a secret reference. + This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. The secret referenced should + be present in the same namespace as that of the Route. + Forbidden when `certificate` is set. + Note that securing Routes with external certificates in TLS secrets is a Technology Preview feature in OpenShift, + and requires enabling the `RouteExternalCertificate` OpenShift Feature Gate and might not be functionally complete. + type: string + key: + description: key provides key file contents + type: string + type: object + type: object + type: object + database: + description: Configuration for database access. Optional. + properties: + authSecretName: + description: |- + Name of the secret for database authentication. Optional. + For a local database deployment (EnableLocalDb=true), a secret will be auto generated if it does not exist. + The secret shall include information used for the database access. + An example for PostgreSQL DB access: + "POSTGRES_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_PORT": "5432" + "POSTGRES_USER": "postgres" + "POSTGRESQL_ADMIN_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_HOST": "backstage-psql-bs1" # For local database, set to "backstage-psql-". + type: string + enableLocalDb: + default: true + description: Control the creation of a local PostgreSQL DB. Set + to false if using for example an external Database for Backstage. + type: boolean + type: object + deployment: + description: |- + Configuration for Backstage Deployment resource. + Optional. + properties: + patch: + description: |- + Valid fragment of Deployment to be merged with default/raw configuration. + Set the Deployment's metadata and|or spec fields you want to override or add. + Optional. + x-kubernetes-preserve-unknown-fields: true + type: object + rawRuntimeConfig: + description: Raw Runtime RuntimeObjects configuration. For Advanced + scenarios. + properties: + backstageConfig: + description: Name of ConfigMap containing Backstage runtime objects + configuration + type: string + localDbConfig: + description: Name of ConfigMap containing LocalDb (PostgreSQL) + runtime objects configuration + type: string + type: object + type: object + status: + description: BackstageStatus defines the observed state of Backstage + properties: + conditions: + description: Conditions is the list of conditions describing the state + of the runtime + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: false + subresources: + status: {} + - name: v1alpha3 + schema: + openAPIV3Schema: + description: |- + Backstage is the Schema for the Red Hat Developer Hub backstages API. + It comes with pre-built plug-ins, configuration settings, and deployment mechanisms, + which can help streamline the process of setting up a self-managed internal + developer portal for adopters who are just starting out. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: BackstageSpec defines the desired state of Backstage + properties: + application: + description: Configuration for Backstage. Optional. + properties: + appConfig: + description: |- + References to existing app-configs ConfigMap objects, that will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret, + and will be mounted inside the main application container under a specified mount directory. + Additionally, each file will be passed as a `--config /mount/path/to/configmap/key` to the + main container args in the order of the entries defined in the AppConfigs list. + But bear in mind that for a single ConfigMap element containing several filenames, + the order in which those files will be appended to the main container args cannot be guaranteed. + So if you want to pass multiple app-config files, it is recommended to pass one ConfigMap per app-config file. + properties: + configMaps: + description: |- + List of ConfigMaps storing the app-config files. Will be mounted as files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + Bear in mind not to put sensitive data in those ConfigMaps. Instead, your app-config content can reference + environment variables (which you can set with the ExtraEnvs field) and/or include extra files (see the ExtraFiles field). + More details on https://backstage.io/docs/conf/writing/. + items: + properties: + key: + description: Key in the object + type: string + mountPath: + description: Path to mount the Object. If not specified + default-path/Name will be used + type: string + name: + description: |- + Name of the object + Supported ConfigMaps and Secrets + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all app-config files listed in + the ConfigMapRefs field + type: string + type: object + dynamicPluginsConfigMapName: + description: |- + Reference to an existing ConfigMap for Dynamic Plugins. + A new one will be generated with the default config if not set. + The ConfigMap object must have an existing key named: 'dynamic-plugins.yaml'. + type: string + extraEnvs: + description: Extra environment variables + properties: + configMaps: + description: |- + List of references to ConfigMaps objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be injected as additional environment variables. + Otherwise, only the specified key will be injected as an additional environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + envs: + description: List of name and value pairs to add as environment + variables. + items: + properties: + name: + description: Name of the environment variable + type: string + value: + description: Value of the environment variable + type: string + required: + - name + - value + type: object + type: array + secrets: + description: |- + List of references to Secrets objects to inject as additional environment variables. + For each item in this array, if a key is not specified, it means that all keys in the Secret will be injected as additional environment variables. + Otherwise, only the specified key will be injected as environment variable. + items: + properties: + key: + description: Key in the object + type: string + name: + description: |- + Name of the object + We support only ConfigMaps and Secrets. + type: string + required: + - name + type: object + type: array + type: object + extraFiles: + description: |- + References to existing Config objects to use as extra config files. + They will be mounted as files in the specified mount path. + Each element can be a reference to any ConfigMap or Secret. + properties: + configMaps: + description: |- + List of references to ConfigMaps objects mounted as extra files under the MountPath specified. + For each item in this array, if a key is not specified, it means that all keys in the ConfigMap will be mounted as files. + Otherwise, only the specified key will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + mountPath: + description: Path to mount the Object. If not specified + default-path/Name will be used + type: string + name: + description: |- + Name of the object + Supported ConfigMaps and Secrets + type: string + required: + - name + type: object + type: array + mountPath: + default: /opt/app-root/src + description: Mount path for all extra configuration files + listed in the Items field + type: string + pvcs: + description: |- + List of references to Persistent Volume Claim objects mounted as extra files + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + mountPath: + description: Path to mount PVC. If not specified default-path/Name + will be used + type: string + name: + description: Name of the object + type: string + required: + - name + type: object + type: array + secrets: + description: |- + List of references to Secrets objects mounted as extra files under the MountPath specified. + For each item in this array, a key must be specified that will be mounted as a file. + items: + properties: + key: + description: Key in the object + type: string + mountPath: + description: Path to mount the Object. If not specified + default-path/Name will be used + type: string + name: + description: |- + Name of the object + Supported ConfigMaps and Secrets + type: string + required: + - name + type: object + type: array + type: object + image: + description: |- + Custom image to use in all containers (including Init Containers). + It is your responsibility to make sure the image is from trusted sources and has been validated for security compliance + type: string + imagePullSecrets: + description: Image Pull Secrets to use in all containers (including + Init Containers) + items: + type: string + type: array + replicas: + default: 1 + description: |- + Number of desired replicas to set in the Backstage Deployment. + Defaults to 1. + format: int32 + type: integer + route: + description: Route configuration. Used for OpenShift only. + properties: + enabled: + default: true + description: Control the creation of a Route on OpenShift. + type: boolean + host: + description: |- + Host is an alias/DNS that points to the service. Optional. + Ignored if Enabled is false. + If not specified a route name will typically be automatically + chosen. Must follow DNS952 subdomain conventions. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + subdomain: + description: |- + Subdomain is a DNS subdomain that is requested within the ingress controller's + domain (as a subdomain). + Ignored if Enabled is false. + Example: subdomain `frontend` automatically receives the router subdomain + `apps.mycluster.com` to have a full hostname `frontend.apps.mycluster.com`. + maxLength: 253 + pattern: ^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])(\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]{0,61}[a-zA-Z0-9]))*$ + type: string + tls: + description: |- + The tls field provides the ability to configure certificates for the route. + Ignored if Enabled is false. + properties: + caCertificate: + description: caCertificate provides the cert authority + certificate contents + type: string + certificate: + description: |- + certificate provides certificate contents. This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. + type: string + externalCertificateSecretName: + description: |- + ExternalCertificateSecretName provides certificate contents as a secret reference. + This should be a single serving certificate, not a certificate + chain. Do not include a CA certificate. The secret referenced should + be present in the same namespace as that of the Route. + Forbidden when `certificate` is set. + Note that securing Routes with external certificates in TLS secrets is a Technology Preview feature in OpenShift, + and requires enabling the `RouteExternalCertificate` OpenShift Feature Gate and might not be functionally complete. + type: string + key: + description: key provides key file contents + type: string + type: object + type: object + type: object + database: + description: Configuration for database access. Optional. + properties: + authSecretName: + description: |- + Name of the secret for database authentication. Optional. + For a local database deployment (EnableLocalDb=true), a secret will be auto generated if it does not exist. + The secret shall include information used for the database access. + An example for PostgreSQL DB access: + "POSTGRES_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_PORT": "5432" + "POSTGRES_USER": "postgres" + "POSTGRESQL_ADMIN_PASSWORD": "rl4s3Fh4ng3M4" + "POSTGRES_HOST": "backstage-psql-bs1" # For local database, set to "backstage-psql-". + type: string + enableLocalDb: + default: true + description: Control the creation of a local PostgreSQL DB. Set + to false if using for example an external Database for Backstage. + type: boolean + type: object + deployment: + description: |- + Valid fragment of Deployment to be merged with default/raw configuration. + Set the Deployment's metadata and|or spec fields you want to override or add. + Optional. + properties: + patch: + description: |- + Valid fragment of Deployment to be merged with default/raw configuration. + Set the Deployment's metadata and|or spec fields you want to override or add. + Optional. + x-kubernetes-preserve-unknown-fields: true + type: object + rawRuntimeConfig: + description: Raw Runtime RuntimeObjects configuration. For Advanced + scenarios. + properties: + backstageConfig: + description: Name of ConfigMap containing Backstage runtime objects + configuration + type: string + localDbConfig: + description: Name of ConfigMap containing LocalDb (PostgreSQL) + runtime objects configuration + type: string + type: object + type: object + status: + description: BackstageStatus defines the observed state of Backstage + properties: + conditions: + description: Conditions is the list of conditions describing the state + of the runtime + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: controller-manager + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: serviceaccount + app.kubernetes.io/part-of: backstage-operator + name: rhdh-controller-manager + namespace: rhdh-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: leader-election-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: role + app.kubernetes.io/part-of: backstage-operator + name: rhdh-leader-election-role + namespace: rhdh-operator +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 +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: backstage-editor-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: backstage-operator + name: rhdh-backstage-editor-role +rules: +- apiGroups: + - rhdh.redhat.com + resources: + - backstages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: backstage-viewer-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: backstage-operator + name: rhdh-backstage-viewer-role +rules: +- apiGroups: + - rhdh.redhat.com + resources: + - backstages + verbs: + - get + - list + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/status + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: rhdh-manager-role +rules: +- apiGroups: + - "" + resources: + - configmaps + - persistentvolumeclaims + - secrets + - services + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - persistentvolumes + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: + - deployments + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/finalizers + verbs: + - update +- apiGroups: + - rhdh.redhat.com + resources: + - backstages/status + verbs: + - get + - patch + - update +- apiGroups: + - route.openshift.io + resources: + - routes + - routes/custom-host + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: metrics-auth-role + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: metrics-auth-role + app.kubernetes.io/part-of: backstage-operator + name: rhdh-metrics-auth-role +rules: +- apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create +- apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: metrics-rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: metrics-reader + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrole + app.kubernetes.io/part-of: backstage-operator + name: rhdh-metrics-reader +rules: +- nonResourceURLs: + - /metrics + verbs: + - get +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: leader-election-rolebinding + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: rolebinding + app.kubernetes.io/part-of: backstage-operator + name: rhdh-leader-election-rolebinding + namespace: rhdh-operator +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: rhdh-leader-election-role +subjects: +- kind: ServiceAccount + name: rhdh-controller-manager + namespace: rhdh-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: manager-rolebinding + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: clusterrolebinding + app.kubernetes.io/part-of: backstage-operator + name: rhdh-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: rhdh-manager-role +subjects: +- kind: ServiceAccount + name: rhdh-controller-manager + namespace: rhdh-operator +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: metrics-auth-rolebinding + app.kubernetes.io/name: metrics-auth-rolebinding + app.kubernetes.io/part-of: backstage-operator + name: rhdh-metrics-auth-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: rhdh-metrics-auth-role +subjects: +- kind: ServiceAccount + name: rhdh-controller-manager + namespace: rhdh-operator +--- +apiVersion: v1 +data: + app-config.yaml: | + apiVersion: v1 + kind: ConfigMap + metadata: + name: my-backstage-config-cm1 # placeholder for -default-appconfig + data: + default.app-config.yaml: | + backend: + auth: + externalAccess: + - type: legacy + options: + subject: legacy-default-config + # This is a default value, which you should change by providing your own app-config + secret: "pl4s3Ch4ng3M3" + auth: + providers: {} + db-secret.yaml: |- + apiVersion: v1 + kind: Secret + metadata: + name: postgres-secrets # will be replaced + type: Opaque + #stringData: + # POSTGRES_PASSWORD: + # POSTGRES_PORT: "5432" + # POSTGRES_USER: postgres + # POSTGRESQL_ADMIN_PASSWORD: admin123 + # POSTGRES_HOST: bs1-db-service #placeholder -db-service + db-service.yaml: | + apiVersion: v1 + kind: Service + metadata: + name: backstage-psql # placeholder for 'backstage-psql-' .NOTE: For the time it is static and linked to Secret-> postgres-secrets -> OSTGRES_HOST + spec: + selector: + rhdh.redhat.com/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + clusterIP: None + ports: + - port: 5432 + db-statefulset.yaml: |- + apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: backstage-psql-cr1 # placeholder for 'backstage-psql-' + spec: + podManagementPolicy: OrderedReady + replicas: 1 + selector: + matchLabels: + rhdh.redhat.com/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + serviceName: backstage-psql-cr1-hl # placeholder for 'backstage-psql--hl' + template: + metadata: + labels: + rhdh.redhat.com/app: backstage-psql-cr1 # placeholder for 'backstage-psql-' + spec: + # fsGroup does not work for Openshift + # AKS/EKS does not work w/o it + #securityContext: + # fsGroup: 26 + automountServiceAccountToken: false + ## https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/ + ## The optional .spec.persistentVolumeClaimRetentionPolicy field controls if and how PVCs are deleted during the lifecycle of a StatefulSet. + ## You must enable the StatefulSetAutoDeletePVC feature gate on the API server and the controller manager to use this field. + # persistentVolumeClaimRetentionPolicy: + # whenDeleted: Retain + # whenScaled: Retain + containers: + - env: + - name: POSTGRESQL_PORT_NUMBER + value: "5432" + - name: POSTGRESQL_VOLUME_DIR + value: /var/lib/pgsql/data + - name: PGDATA + value: /var/lib/pgsql/data/userdata + image: quay.io/fedora/postgresql-15:latest # will be replaced with the actual image + imagePullPolicy: IfNotPresent + securityContext: + # runAsUser:26 does not work for Openshift but looks work for AKS/EKS + # runAsUser: 26 + runAsGroup: 0 + runAsNonRoot: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL + livenessProbe: + exec: + command: + - /bin/sh + - -c + - exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 + failureThreshold: 6 + initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: postgresql + ports: + - containerPort: 5432 + name: tcp-postgresql + protocol: TCP + readinessProbe: + exec: + command: + - /bin/sh + - -c + - -e + - | + exec pg_isready -U ${POSTGRES_USER} -h 127.0.0.1 -p 5432 + failureThreshold: 6 + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 250m + memory: 1024Mi + ephemeral-storage: 20Mi + volumeMounts: + - mountPath: /dev/shm + name: dshm + - mountPath: /var/lib/pgsql/data + name: data + restartPolicy: Always + serviceAccountName: default + volumes: + - emptyDir: + medium: Memory + name: dshm + updateStrategy: + rollingUpdate: + partition: 0 + type: RollingUpdate + volumeClaimTemplates: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: + name: data + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + db-statefulset.yaml.k8s: |- + # if securityContext not present in AKS/EKS, the error is like this: + # Error: EACCES: permission denied, open '/dynamic-plugins-root/backstage-plugin-scaffolder-backend-module-github-dynamic-0.2.2.tgz' + # fsGroup doesn not work for Openshift + spec: + template: + spec: + securityContext: + # any group id + fsGroup: 1001 + deployment.yaml: | + apiVersion: apps/v1 + kind: Deployment + metadata: + name: backstage # placeholder for 'backstage-' + spec: + replicas: 1 + selector: + matchLabels: + rhdh.redhat.com/app: # placeholder for 'backstage-' + template: + metadata: + labels: + rhdh.redhat.com/app: # placeholder for 'backstage-' + spec: + automountServiceAccountToken: false + # if securityContext not present in AKS/EKS, the error is like this: + #Error: EACCES: permission denied, open '/dynamic-plugins-root/backstage-plugin-scaffolder-backend-module-github-dynamic-0.2.2.tgz' + # fsGroup doesn not work for Openshift + #securityContext: + # fsGroup: 1001 + volumes: + - ephemeral: + volumeClaimTemplate: + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + name: dynamic-plugins-root + - name: dynamic-plugins-npmrc + secret: + defaultMode: 420 + optional: true + secretName: dynamic-plugins-npmrc + - name: dynamic-plugins-registry-auth + secret: + defaultMode: 416 + optional: true + secretName: dynamic-plugins-registry-auth + - emptyDir: {} + name: npmcacache + - name: temp + emptyDir: {} + initContainers: + - name: install-dynamic-plugins + command: + - ./install-dynamic-plugins.sh + - /dynamic-plugins-root + # image will be replaced by the value of the `RELATED_IMAGE_backstage` env var, if set + image: quay.io/rhdh/rhdh-hub-rhel9:next + imagePullPolicy: IfNotPresent + securityContext: + readOnlyRootFilesystem: true + runAsNonRoot: true + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + capabilities: + drop: + - ALL + env: + - name: NPM_CONFIG_USERCONFIG + value: /opt/app-root/src/.npmrc.dynamic-plugins + volumeMounts: + - mountPath: /dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /opt/app-root/src/.npmrc.dynamic-plugins + name: dynamic-plugins-npmrc + readOnly: true + subPath: .npmrc + - mountPath: /opt/app-root/src/.config/containers + name: dynamic-plugins-registry-auth + readOnly: true + - mountPath: /opt/app-root/src/.npm/_cacache + name: npmcacache + - mountPath: /tmp + name: temp + workingDir: /opt/app-root/src + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 1000m + memory: 2.5Gi + ephemeral-storage: 5Gi + containers: + - name: backstage-backend + # image will be replaced by the value of the `RELATED_IMAGE_backstage` env var, if set + image: quay.io/rhdh/rhdh-hub-rhel9:next + imagePullPolicy: IfNotPresent + args: + - "--config" + - "dynamic-plugins-root/app-config.dynamic-plugins.yaml" + securityContext: + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + allowPrivilegeEscalation: false + startupProbe: + # This gives enough time upon container startup before the liveness and readiness probes are triggered. + # Giving (120s = initialDelaySeconds + failureThreshold * periodSeconds) to account for the worst case scenario. + httpGet: + path: /.backstage/health/v1/liveness + port: backend + scheme: HTTP + initialDelaySeconds: 30 + timeoutSeconds: 4 + periodSeconds: 20 + successThreshold: 1 + failureThreshold: 3 + readinessProbe: + failureThreshold: 3 + httpGet: + path: /.backstage/health/v1/readiness + port: backend + scheme: HTTP + # Both liveness and readiness probes won't be triggered until the startup probe is successful. + # The startup probe is already configured to give enough time for the application to be started. + # So removing the additional delay here allows the readiness probe to be checked right away after the startup probe, + # which helps make the application available faster to the end-user. + #initialDelaySeconds: 30 + periodSeconds: 10 + successThreshold: 2 + timeoutSeconds: 4 + livenessProbe: + failureThreshold: 3 + httpGet: + path: /.backstage/health/v1/liveness + port: backend + scheme: HTTP + # Both liveness and readiness probes won't be triggered until the startup probe is successful. + # The startup probe is already configured to give enough time for the application to be started. + # So removing the additional delay here allows the readiness probe to be checked right away after the startup probe, + # which helps make the application available faster to the end-user. + #initialDelaySeconds: 60 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 4 + ports: + - name: backend + containerPort: 7007 + env: + - name: APP_CONFIG_backend_listen_port + value: "7007" + volumeMounts: + - mountPath: /opt/app-root/src/dynamic-plugins-root + name: dynamic-plugins-root + - mountPath: /tmp + name: temp + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 1000m + memory: 2.5Gi + ephemeral-storage: 5Gi + workingDir: /opt/app-root/src + deployment.yaml.k8s: |- + # if securityContext not present in AKS/EKS, the error is like this: + # Error: EACCES: permission denied, open '/dynamic-plugins-root/backstage-plugin-scaffolder-backend-module-github-dynamic-0.2.2.tgz' + # fsGroup doesn not work for Openshift + spec: + template: + spec: + securityContext: + # any group id + fsGroup: 1001 + dynamic-plugins.yaml: |- + apiVersion: v1 + kind: ConfigMap + metadata: + name: default-dynamic-plugins # must be the same as (deployment.yaml).spec.template.spec.volumes.name.dynamic-plugins-conf.configMap.name + data: + "dynamic-plugins.yaml": | + includes: + - dynamic-plugins.default.yaml + plugins: [] + route.yaml: |- + apiVersion: route.openshift.io/v1 + kind: Route + metadata: + name: route # placeholder for 'backstage-' + spec: + port: + targetPort: http-backend + path: / + tls: + insecureEdgeTerminationPolicy: Redirect + termination: edge + to: + kind: Service + name: # placeholder for 'backstage-' + secret-envs.yaml: | + apiVersion: v1 + kind: Secret + metadata: + name: backend-auth-secret + stringData: + # generated with the command below (from https://janus-idp.io/docs/auth/service-to-service-auth/#setup): + # node -p 'require("crypto").randomBytes(24).toString("base64")' + BACKEND_SECRET: "R2FxRVNrcmwzYzhhN3l0V1VRcnQ3L1pLT09WaVhDNUEK" # notsecret + service.yaml: |- + apiVersion: v1 + kind: Service + metadata: + name: backstage # placeholder for 'backstage-' + spec: + type: ClusterIP + selector: + rhdh.redhat.com/app: # placeholder for 'backstage-' + ports: + - name: http-backend + port: 80 + targetPort: backend + - name: http-metrics + protocol: TCP + port: 9464 + targetPort: 9464 + service.yaml.k8s: | + spec: + type: NodePort +kind: ConfigMap +metadata: + name: rhdh-default-config + namespace: rhdh-operator +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: metrics + app.kubernetes.io/created-by: backstage-operator + app.kubernetes.io/instance: controller-manager-metrics-service + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/name: service + app.kubernetes.io/part-of: backstage-operator + control-plane: controller-manager + name: rhdh-controller-manager-metrics-service + namespace: rhdh-operator +spec: + ports: + - name: metrics + port: 8443 + protocol: TCP + targetPort: metrics + selector: + control-plane: controller-manager +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: rhdh-operator + control-plane: controller-manager + name: rhdh-operator + namespace: rhdh-operator +spec: + replicas: 1 + selector: + matchLabels: + app: rhdh-operator + strategy: + type: RollingUpdate + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + app: rhdh-operator + app.kubernetes.io/component: rhdh-operator + control-plane: controller-manager + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/arch + operator: In + values: + - amd64 + - key: kubernetes.io/os + operator: In + values: + - linux + automountServiceAccountToken: true + containers: + - args: + - --health-probe-bind-address=:8081 + - --metrics-bind-address=:8443 + - --metrics-secure=true + - --leader-elect + command: + - /manager + env: + - name: OPERATOR_NAME + value: rhdh-operator + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: RELATED_IMAGE_postgresql + value: quay.io/fedora/postgresql-15:latest + - name: RELATED_IMAGE_backstage + value: quay.io/rhdh/rhdh-hub-rhel9:1.5 + image: quay.io/rhdh-community/operator:0.5.0 + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + ports: + - containerPort: 8081 + name: health + - containerPort: 8443 + name: metrics + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + ephemeral-storage: 20Mi + memory: 1Gi + requests: + cpu: 10m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + volumeMounts: + - mountPath: /default-config + name: default-config + securityContext: + runAsNonRoot: true + serviceAccountName: rhdh-controller-manager + terminationGracePeriodSeconds: 10 + volumes: + - configMap: + name: rhdh-default-config + name: default-config