From fcb83fbc43afe9579c781b4a9ccd8c08f329b838 Mon Sep 17 00:00:00 2001 From: Patrick Knight Date: Sat, 31 Jan 2026 04:28:58 -0500 Subject: [PATCH 1/8] Add support for building scripts as an image externally Signed-off-by: Patrick Knight --- README.md | 142 +++++++++++++++------ deploy/configmap.yaml | 12 +- deploy/job-internal-registry.yaml | 4 +- deploy/secret-template.yaml | 20 +-- deploy/teardown-job-internal-registry.yaml | 4 +- deploy/teardown-job.yaml | 4 +- 6 files changed, 123 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index a13d60f..797f0cb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # rhdh-testbed -A collection of resources and scripts to quickly deploy an RHDH instance in Kubernetes, preloaded with useful plugins, example entities, and third-party integrations for rapid testing and development. +A collection of resources and scripts to quickly deploy an RHDH instance in Kubernetes, preloaded +with useful plugins, example entities, and third-party integrations for rapid testing and +development. ## Table of Contents @@ -15,32 +17,47 @@ A collection of resources and scripts to quickly deploy an RHDH instance in Kube ## Background and Purpose -These scripts were created out of a need to quickly spin up an RHDH instance preconfigured for testing. The goal is to streamline the process of deploying Red Hat Developer Hub with preconfigured plugins and supporting resources, making it easy for team members, especially those working on plugins, to verify changes, report bugs, and explore features in a real environment. It also serves as a practical example of how RHDH and its plugins can be integrated and showcased. +These scripts were created out of a need to quickly spin up an RHDH instance preconfigured for +testing. The goal is to streamline the process of deploying Red Hat Developer Hub with preconfigured +plugins and supporting resources, making it easy for team members, especially those working on +plugins, to verify changes, report bugs, and explore features in a real environment. It also serves +as a practical example of how RHDH and its plugins can be integrated and showcased. ### What the Script Does -The RHDH Start-Up Script is designed to launch an RHDH instance with a selected set of plugins and supporting resources. Its goals are: +The RHDH Start-Up Script is designed to launch an RHDH instance with a selected set of plugins and +supporting resources. Its goals are: - To reduce the manual work of configuring plugins and their integration points - To create an environment well-suited for various testing scenarios - To demonstrate the capabilities of RHDH and its bundled plugins -It also deploys companion resources that are registered into the catalog, making it useful as a standalone demo environment. +It also deploys companion resources that are registered into the catalog, making it useful as a +standalone demo environment. ### Intended Usage and Environment -These scripts are tailored for OpenShift clusters, ideally short-lived or non-production environments like: +These scripts are tailored for OpenShift clusters, ideally short-lived or non-production +environments like: - OpenShift Local (CRC) - Cluster Bot clusters -They may work on other Kubernetes platforms, but this hasn't been tested or verified. At the time of writing, most of my testing has been performed using Cluster bot. +They may work on other Kubernetes platforms, but this hasn't been tested or verified. At the time of +writing, most of my testing has been performed using Cluster bot. -**Important** Running this script will install several components and operators, included Red Hat SSO, Advance Cluster Management, OpenShift GitOps, and more. It will also create service accounts and other cluster-level resources. For this reason, it is strongly recommended to use a disposable or non-critical cluster. Before running the scripts, you should review the resources being deployed. Additional documentation is provided to walk through the steps taken for setting up specific plugin configurations. +**Important** Running this script will install several components and operators, included Red Hat +SSO, Advance Cluster Management, OpenShift GitOps, and more. It will also create service accounts +and other cluster-level resources. For this reason, it is strongly recommended to use a disposable +or non-critical cluster. Before running the scripts, you should review the resources being deployed. +Additional documentation is provided to walk through the steps taken for setting up specific plugin +configurations. ## Outline of this project -This project includes a collection of scripts and Kubernetes resources designed to streamline the deployment and testing of an RHDH instance. The structure and tooling are intended to offer both an out-of-the-box experience and the flexibility to customize plugin configurations. +This project includes a collection of scripts and Kubernetes resources designed to streamline the +deployment and testing of an RHDH instance. The structure and tooling are intended to offer both an +out-of-the-box experience and the flexibility to customize plugin configurations. ### `start.sh`: RHDH Setup Script @@ -50,7 +67,11 @@ The main setup script (`start.sh`) is used to: - Deploy a variety of preconfigured Kubernetes resources that integrate with RHDH - Optionally configure additional plugins and integrations -By default, the script is designed to work "out of the box" on first run, creating a working RHDH environment with minimal effort. Follow-up runs can be used to customize the setup further or to selectively configure only specific components. For users who prefer full control from the beginning, it's also possible to bypass the initial setup and tailor the configuration to specific needs. This versatility is intentional and core to the project's design. +By default, the script is designed to work "out of the box" on first run, creating a working RHDH +environment with minimal effort. Follow-up runs can be used to customize the setup further or to +selectively configure only specific components. For users who prefer full control from the +beginning, it's also possible to bypass the initial setup and tailor the configuration to specific +needs. This versatility is intentional and core to the project's design. ### `teardown.sh`: RHDH Cleanup Script @@ -59,29 +80,36 @@ The teardown script (`teardown.sh`) is used to: - Clean up the RHDH instance and all associated resources - Free up compute resources for redeploying a different plugin set or environment configuration -This script removes nearly everything created by the setup process, except for the namespace itself, allowing for quick redeployment into the same logical space. +This script removes nearly everything created by the setup process, except for the namespace itself, +allowing for quick redeployment into the same logical space. ### Plugin Demo Resources -A set of Kubernetes resources are included to support demoing various RHDH plugins. These resources are: +A set of Kubernetes resources are included to support demoing various RHDH plugins. These resources +are: - Preconfigured for ease of use - Intended to simplify setup for plugin features like GitOps, SSO, etc. -Some additional configuration may be required for smooth deployment, which is detailed in the plugin specific documentation +Some additional configuration may be required for smooth deployment, which is detailed in the plugin +specific documentation ### `/auth`: Auth and Integration Credentials -The `/auth` directory is intended to store sensitive configuration files used by various plugins, an example being the GitHub App credentials used for authentication and catalog ingestion. While these values could be set via environment variables, storing them in a centralized directory: +The `/auth` directory is intended to store sensitive configuration files used by various plugins, an +example being the GitHub App credentials used for authentication and catalog ingestion. While these +values could be set via environment variables, storing them in a centralized directory: - Keeps credential files easy to reference and manage - Supports manual plugin configuration outside of the automated script flow -More details about this directory and how to populate it are provided in the plugin specific documentation. +More details about this directory and how to populate it are provided in the plugin specific +documentation. ## Plugin Configuration -This project uses the upstream RHDH `dynamic-plugins.default.yaml` directly, keeping configuration in sync with official releases. +This project uses the upstream RHDH `dynamic-plugins.default.yaml` directly, keeping configuration +in sync with official releases. ### Automatic Sync from Upstream @@ -120,7 +148,9 @@ There are three ways to run the testbed scripts, depending on your environment a ### Option 1: Local Installation -These scripts are designed to work out-of-the-box with minimal setup. In fact, it's recommended that you start with the default setup to better understand how everything fits together. You can always customize and extend things later. +These scripts are designed to work out-of-the-box with minimal setup. In fact, it's recommended that +you start with the default setup to better understand how everything fits together. You can always +customize and extend things later. ### Requirements @@ -136,7 +166,8 @@ cd rhdh-testbed Step 2. Ensure access to an OpenShift Cluster: -- These scripts rely on `oc` and `helm` to manage the resources for you, so an OpenShift cluster is a must. +- These scripts rely on `oc` and `helm` to manage the resources for you, so an OpenShift cluster is + a must. **Important**: Most testing has been done using Cluster Bot @@ -164,7 +195,8 @@ Step 5. Run the script: Step 6. Access your RHDH instance: -- Once deployment is complete, navigate to the exposed route for RHDH in your OpenShift cluster (this is typically displayed in the script output). +- Once deployment is complete, navigate to the exposed route for RHDH in your OpenShift cluster + (this is typically displayed in the script output). You'll now have a clean, working instance of RHDH that's ready to be enhanced in the next steps @@ -188,7 +220,8 @@ docker compose up rhdh-teardown ## Option 3: Deploy as Kubernetes Job -For fully automated, hands-off deployment directly on your cluster without any local tooling requirements, you can deploy the testbed as a Kubernetes Job. +For fully automated, hands-off deployment directly on your cluster without any local tooling +requirements, you can deploy the testbed as a Kubernetes Job. ### Prerequisites @@ -214,7 +247,8 @@ Key ConfigMap values: | K8S_CLUSTER_NAME | Name for you cluster in RHDH | my-cluster | | SIGN_IN_PAGE | Authentication method (guest or oidc) | guest | -> **Note:** Plugin enablement is configured via the dynamic plugins ConfigMap (see Step 2c below), not through environment variables +> **Note:** Plugin enablement is configured via the dynamic plugins ConfigMap (see Step 2c below), +> not through environment variables **Step 2b.** Create your secret file using `deploy/secret-template.yaml` as an example: @@ -228,7 +262,8 @@ oc apply -f deploy/secret.local.yaml -n rhdh-testbed **Step 2c.** Configure dynamic plugins: -The testbed detects which plugins you've enabled in your `dynamic-plugins-configmap.yaml` and automatically deploys any required cluster resources (operators, CRDs, etc.). +The testbed detects which plugins you've enabled in your `dynamic-plugins-configmap.yaml` and +automatically deploys any required cluster resources (operators, CRDs, etc.). **Option A**: Use the default configuration (simplest) @@ -270,7 +305,10 @@ Plugins that trigger cluster resource deployment: | plugin-3scale-backend | 3scale Operator + API Manager | | plugin-kubernetes / plugin-topology | ServiceAccount token configuration | -> **Work in Progress:** Not all plugins require cluster resources, and not all plugins that do require resources have been integrated into the automation scripts yet. If you enable a plugin that needs additional setup (like an operator), check the `docs/` folder for manual configuration steps or open an issue if support is missing. +> **Work in Progress:** Not all plugins require cluster resources, and not all plugins that do +> require resources have been integrated into the automation scripts yet. If you enable a plugin +> that needs additional setup (like an operator), check the `docs/` folder for manual configuration +> steps or open an issue if support is missing. **Step 3.** Apply the deployment resources: @@ -285,7 +323,9 @@ oc get configmap rhdh-dynamic-plugins -n rhdh-testbed oc apply -f deploy/job.yaml ``` -> **Note:** The Job mounts the `rhdh-dynamic-plugins` ConfigMap to `/app/resources/user-resources/dynamic-plugins-configmap.local.yaml`. The setup script reads this to determine which cluster resources to deploy. +> **Note:** The Job mounts the `rhdh-dynamic-plugins` ConfigMap to +> `/app/resources/user-resources/dynamic-plugins-configmap.local.yaml`. The setup script reads this +> to determine which cluster resources to deploy. **Optional Step** Monitor the deployment: @@ -348,7 +388,8 @@ oc apply -k . ### Building the Image In-Cluster (Optional) -If you prefer to build the image directly in OpenShift instead of using the pre-built image from ghcr.io: +If you prefer to build the image directly in OpenShift instead of using the pre-built image from +ghcr.io: **Step 1.** Create the namespace and apply the BuildConfig: @@ -411,34 +452,43 @@ The Kubernetes Job requires elevated permissions to: - Create ClusterRoles and ClusterRoleBindings - Deploy various workloads and CRDs -**This tool is designed for disposable, non-production clusters.** The included ClusterRole grants broad permissions necessary for the automation. Always review `deploy/cluster-role.yaml` before applying. -The Job uses a dedicated ServiceAccount (`rhdh-testbed-runner`) that is scoped to only what's necessary for the deployment automation. +**This tool is designed for disposable, non-production clusters.** The included ClusterRole grants +broad permissions necessary for the automation. Always review `deploy/cluster-role.yaml` before +applying. The Job uses a dedicated ServiceAccount (`rhdh-testbed-runner`) that is scoped to only +what's necessary for the deployment automation. ## Next Steps -So, you now have a running RHDH (Red Hat Developer Hub) instance, great! But this base setup is just the foundation. To transform it into a useful demo or testing environment, here are some next steps to take: +So, you now have a running RHDH (Red Hat Developer Hub) instance, great! But this base setup is just +the foundation. To transform it into a useful demo or testing environment, here are some next steps +to take: ### Understanding the Generated Resources -During setup, a number of editable resources are created under `resources/user-resources/`. These are designed for customization and extension. +During setup, a number of editable resources are created under `resources/user-resources/`. These +are designed for customization and extension. - `resources/user-resources/app-config` - Stores application configuration -- `resources/user-resources/rbac-policy` - Contains RBAC policy definitions used to manage user permissions. +- `resources/user-resources/rbac-policy` - Contains RBAC policy definitions used to manage user + permissions. - `resources/user-resources/rhdh-secrets` - Holds required secrets like credentials and tokens - **Note:** This file is auto-generated, avoid editing manually unless necessary. Changes could be overwritten. -- `resources/user-resources/dynamic-plugins` - Controls which dynamic plugins are enabled and their configurations. + **Note:** This file is auto-generated, avoid editing manually unless necessary. Changes could be + overwritten. +- `resources/user-resources/dynamic-plugins` - Controls which dynamic plugins are enabled and their + configurations. ### Enabling Additional Plugins -The testbed uses the standard RHDH `dynamic-plugins.default.yaml format for plugin configuration. To enable a plugin: +The testbed uses the standard RHDH `dynamic-plugins.default.yaml format for plugin configuration. To +enable a plugin: 1. **Edit the dynamic plugins config file:** - Local runs: `resources/user-resources/dynamic-plugins-configmap.local.yaml` - Kubernetes Job: Create a ConfigMap (see [Option 3](#option-3-deploy-as-kubernetes-job)) 2. **Set `disabled: false`** on the plugin(s) you want: - - package: ./dynamic-plugins/dist/backstage-community-plugin-tekton - disabled: false # Change from true to false + - package: ./dynamic-plugins/dist/backstage-community-plugin-tekton disabled: false # Change from + true to false 3. Re-run the setup to apply changes: - Local: `./start.sh` @@ -447,15 +497,25 @@ The testbed uses the standard RHDH `dynamic-plugins.default.yaml format for plug ### Using the Instance as a Demo Environment -Each plugin includes demo guidance and sample scenarios to help showcase its features in a meaningful way. +Each plugin includes demo guidance and sample scenarios to help showcase its features in a +meaningful way. - Plugin documentation within this project includes a Demo section -- Many plugins and integrations include sample data, configurations, or actions that simulate real-world usage. -- These examples are designed to create a richer, interactive experience for testing and presentation. +- Many plugins and integrations include sample data, configurations, or actions that simulate + real-world usage. +- These examples are designed to create a richer, interactive experience for testing and + presentation. ## General notes -- There are a number of resources included in this project, I was aiming to make it require as little configuration as possible, as such it isn't recommended to make changes to k8s resources themselves. Ideally, just the `user-resources` should be updated (minus the `rhdh-secrets`). -- A number of credentials are meant to be stored to make access easier, included is a `.gitIgnore` that will ignore any yaml files containing `.local.yaml` to hopefully prevent accidental leaks, still be mindful of anything that you add to this project. - - This also doubles in that if you wish to contribute any changes / enhancements to the project, you do not have to worry about reverting / removing credentials and secrets -- Following up from that, contributions are welcome. This was definitely a learning experience for me which translates to there are more than likely much better (and probably simpler) ways to accomplish what I did. +- There are a number of resources included in this project, I was aiming to make it require as + little configuration as possible, as such it isn't recommended to make changes to k8s resources + themselves. Ideally, just the `user-resources` should be updated (minus the `rhdh-secrets`). +- A number of credentials are meant to be stored to make access easier, included is a `.gitIgnore` + that will ignore any yaml files containing `.local.yaml` to hopefully prevent accidental leaks, + still be mindful of anything that you add to this project. + - This also doubles in that if you wish to contribute any changes / enhancements to the project, + you do not have to worry about reverting / removing credentials and secrets +- Following up from that, contributions are welcome. This was definitely a learning experience for + me which translates to there are more than likely much better (and probably simpler) ways to + accomplish what I did. diff --git a/deploy/configmap.yaml b/deploy/configmap.yaml index b547c62..415e17a 100644 --- a/deploy/configmap.yaml +++ b/deploy/configmap.yaml @@ -8,9 +8,9 @@ metadata: app.kubernetes.io/component: config data: # Core settings - NAMESPACE: 'rhdh' - RELEASE_NAME: 'backstage' - K8S_CLUSTER_NAME: 'my-cluster' + NAMESPACE: "rhdh" + RELEASE_NAME: "backstage" + K8S_CLUSTER_NAME: "my-cluster" # Use this for the RHDH chart from the Red Hat Developer GitHub repository HELM_REPO_NAME: rhdh-chart @@ -25,11 +25,11 @@ data: # HELM_CHART_VERSION: 1.9.0 # Authentication - SIGN_IN_PAGE: 'guest' + SIGN_IN_PAGE: "guest" # Timeouts - TIMEOUT: '600' - INTERVAL: '10' + TIMEOUT: "600" + INTERVAL: "10" # Note: Plugin enablement is configured via the rhdh-dynamic-plugins ConfigMap # See README.md for details on creating this ConfigMap diff --git a/deploy/job-internal-registry.yaml b/deploy/job-internal-registry.yaml index bec9c1a..1433267 100644 --- a/deploy/job-internal-registry.yaml +++ b/deploy/job-internal-registry.yaml @@ -23,7 +23,7 @@ spec: - name: setup # Use image from internal OpenShift registry image: image-registry.openshift-image-registry.svc:5000/rhdh-testbed/rhdh-testbed:latest - args: ['/app/start.sh'] + args: ["/app/start.sh"] envFrom: - configMapRef: name: rhdh-testbed-config @@ -31,7 +31,7 @@ spec: name: rhdh-testbed-secrets env: - name: IN_CLUSTER - value: 'true' + value: "true" volumeMounts: - name: dynamic-plugins-config mountPath: /app/resources/user-resources/dynamic-plugins-configmap.local.yaml diff --git a/deploy/secret-template.yaml b/deploy/secret-template.yaml index 6542768..11c6a45 100644 --- a/deploy/secret-template.yaml +++ b/deploy/secret-template.yaml @@ -18,19 +18,19 @@ type: Opaque stringData: # Only needed if configuring a DIFFERENT cluster than where Job runs # Leave empty to use in-cluster ServiceAccount authentication - K8S_CLUSTER_TOKEN: '' - K8S_CLUSTER_URL: '' + K8S_CLUSTER_TOKEN: "" + K8S_CLUSTER_URL: "" # Optional: GitHub integration - GITHUB_TOKEN: '' - GITHUB_APP_ID: '' - GITHUB_APP_CLIENT_ID: '' - GITHUB_APP_CLIENT_SECRET: '' + GITHUB_TOKEN: "" + GITHUB_APP_ID: "" + GITHUB_APP_CLIENT_ID: "" + GITHUB_APP_CLIENT_SECRET: "" # Optional: GitLab integration - GITLAB_TOKEN: '' + GITLAB_TOKEN: "" # Optional: OCM settings - OCM_HUB_NAME: '' - OCM_HUB_URL: '' - OCM_SA_TOKEN: '' + OCM_HUB_NAME: "" + OCM_HUB_URL: "" + OCM_SA_TOKEN: "" diff --git a/deploy/teardown-job-internal-registry.yaml b/deploy/teardown-job-internal-registry.yaml index 070654a..b05d375 100644 --- a/deploy/teardown-job-internal-registry.yaml +++ b/deploy/teardown-job-internal-registry.yaml @@ -23,7 +23,7 @@ spec: - name: teardown # Use image from internal OpenShift registry image: image-registry.openshift-image-registry.svc:5000/rhdh-testbed/rhdh-testbed:latest - args: ['/app/teardown.sh'] + args: ["/app/teardown.sh"] envFrom: - configMapRef: name: rhdh-testbed-config @@ -31,7 +31,7 @@ spec: name: rhdh-testbed-secrets env: - name: IN_CLUSTER - value: 'true' + value: "true" volumeMounts: - name: dynamic-plugins-config mountPath: /app/resources/user-resources/dynamic-plugins-configmap.local.yaml diff --git a/deploy/teardown-job.yaml b/deploy/teardown-job.yaml index c9c0a9a..661090d 100644 --- a/deploy/teardown-job.yaml +++ b/deploy/teardown-job.yaml @@ -20,7 +20,7 @@ spec: containers: - name: teardown image: ghcr.io/pataknight/rhdh-testbed:latest - args: ['/app/teardown.sh'] + args: ["/app/teardown.sh"] envFrom: - configMapRef: name: rhdh-testbed-config @@ -28,7 +28,7 @@ spec: name: rhdh-testbed-secrets env: - name: IN_CLUSTER - value: 'true' + value: "true" volumeMounts: - name: dynamic-plugins-config mountPath: /app/resources/user-resources/dynamic-plugins-configmap.local.yaml From 08585f16019a1e28a85fc4b03195909f36e1d02f Mon Sep 17 00:00:00 2001 From: Patrick Knight Date: Mon, 9 Feb 2026 05:12:58 -0500 Subject: [PATCH 2/8] Update scaffolder rule to ensure we create demo data Signed-off-by: Patrick Knight --- .cursor/rules/plugin-scaffolding.mdc | 403 +++++++++++++++++++++++++-- 1 file changed, 385 insertions(+), 18 deletions(-) diff --git a/.cursor/rules/plugin-scaffolding.mdc b/.cursor/rules/plugin-scaffolding.mdc index ebeb302..24c886d 100644 --- a/.cursor/rules/plugin-scaffolding.mdc +++ b/.cursor/rules/plugin-scaffolding.mdc @@ -28,14 +28,14 @@ Examples of what NOT to generate: ```yaml # BAD - actual values -GITHUB_TOKEN: 'ghp_xxxxxxxxxxxxxxxxxxxx' -API_KEY: 'sk-1234567890abcdef' +GITHUB_TOKEN: "ghp_xxxxxxxxxxxxxxxxxxxx" +API_KEY: "sk-1234567890abcdef" ``` ```yaml # GOOD - placeholders only -GITHUB_TOKEN: '' -API_KEY: '' +GITHUB_TOKEN: "" +API_KEY: "" ``` --- @@ -225,6 +225,355 @@ spec: - Are suitable for demo/testing environments - Don't require external dependencies beyond the cluster +### Demo Data and Test Resources (`resources//demo-data/`) + +**REQUIREMENT**: When adding a new plugin that deploys a service (repository manager, API gateway, etc.), you MUST include demo/test resources to populate the service with realistic data. + +#### Why Demo Data is Required + +- **Robust Demo Environment**: Users can immediately see the plugin working with real data +- **Validation**: Ensures the integration is functional and properly configured +- **Documentation**: Provides examples of what the plugin can display/manage +- **User Experience**: Demonstrates the full capabilities of the plugin + +#### Guidelines for Demo Data + +1. **Self-Contained**: Demo data should not create hard dependencies on other plugins +2. **Lightweight**: Keep test artifacts small and focused (a few examples, not comprehensive datasets) +3. **Realistic**: Use examples that demonstrate typical use cases +4. **Automated**: Demo data population should be automated via Jobs or init scripts +5. **Catalog Entities Required**: MUST create catalog entities for demo artifacts so they appear in RHDH catalog with proper plugin annotations + +#### Implementation Approaches + +Choose the approach that best fits the plugin: + +**Option 1: Kubernetes Job with Init Script** (Recommended) + +Create a Job that runs after the service is ready and populates it with test data: + +```yaml +# resources//populate-demo-data-job.yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: -populate-demo-data +spec: + template: + spec: + containers: + - name: populate + image: curlimages/curl:latest + command: + - /bin/sh + - -c + - | + # Wait for service to be ready + until curl -f http://:/health; do + echo "Waiting for to be ready..." + sleep 5 + done + + # Upload/create test data via API + curl -X POST http://:/api/... + restartPolicy: OnFailure +``` + +**Option 2: ConfigMap with Test Data** + +For small text-based artifacts (scripts, configs, sample files): + +```yaml +# resources//demo-data-configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: -demo-data +data: + sample-script.sh: | + #!/bin/bash + echo "Sample script" + sample-config.yaml: | + key: value +``` + +**Option 3: Pre-built Artifacts in Repository** + +For binary files or larger artifacts: + +``` +resources// + demo-data/ + README.md # Describes the demo data + sample-artifact-1.0.0.jar # Example: Maven artifact + Dockerfile.demo # Example: Docker image source + upload-artifacts.sh # Script to upload to the service +``` + +**Option 4: Fetch from External Sources** + +Download demo data from public repositories during setup: + +```bash +# In deploy__resources() function +echo "Downloading demo artifacts..." +curl -L -o /tmp/demo-artifact.jar https://repo1.maven.org/maven2/... +# Upload to service +``` + +#### Configuration Script Integration + +Update the configuration script to include demo data population and catalog entity registration: + +```bash +populate__demo_data() { + # Check if demo data population is enabled + if [[ "${POPULATE_DEMO_DATA:-true}" == "false" ]]; then + echo "Demo data population disabled, skipping..." + return 0 + fi + + echo "Populating with demo data..." + + # Deploy the demo data job + oc apply -f $PWD/resources//populate-demo-data-job.yaml --namespace=${NAMESPACE} + + # Wait for job to complete + oc wait --for=condition=complete --timeout=300s \ + job/-populate-demo-data -n ${NAMESPACE} +} + +register__demo_catalog_entities() { + # Check if demo data population is enabled + if [[ "${POPULATE_DEMO_DATA:-true}" == "false" ]]; then + echo "Demo data disabled, skipping catalog entity registration..." + return 0 + fi + + echo "Registering demo catalog entities..." + + # Create ConfigMap for demo catalog entities + oc create configmap -demo-entities-config-map \ + --from-file=demo--artifacts.yaml=$PWD/resources//demo-catalog-entities.yaml \ + --namespace=${NAMESPACE} \ + --dry-run=client -o yaml | oc apply -f - --namespace=${NAMESPACE} + + # Add label for Backstage to discover + oc label configmap -demo-entities-config-map \ + backstage.io/kubernetes-id=developer-hub \ + --overwrite -n ${NAMESPACE} + + echo "Demo catalog entities registered!" +} + +# Add to CATEGORY_SETUP_FUNCTIONS +[]="deploy_ deploy__resources config_secrets_for__plugins apply__labels populate__demo_data register__demo_catalog_entities" +``` + +#### Environment Variable Control + +Add to `.env.sample`: + +```bash +# Demo Data Configuration +POPULATE_DEMO_DATA=true # Set to false to skip demo data population +``` + +#### Examples by Plugin Type + +**Nexus Repository Manager:** + +- Maven artifacts (JARs with POM files) +- npm packages +- Catalog entities with proper annotations (`nexus-repository-manager/repository`, `maven.group-id`, `maven.artifact-id`, etc.) +- Approach: Job using Nexus REST API + ConfigMap for catalog entities + +**3scale API Manager:** + +- Sample API definitions +- Mock backends +- API keys and rate limits +- Catalog entities with 3scale annotations +- Approach: 3scale CLI in Job + +**Quay Registry:** + +- Sample container images +- Tags and labels +- Catalog entities with image annotations +- Approach: Podman push from Job + +**Tekton:** + +- Sample Pipelines +- PipelineRuns with history +- Catalog entities for pipeline resources +- Approach: Apply sample YAML manifests + +**ArgoCD:** + +- Sample Application definitions +- Git repositories (public examples) +- Catalog entities for applications +- Approach: ArgoCD CLI in Job + +#### Documentation Requirements + +In `docs/.md`, add a "Demo Data" section that includes **both artifacts and catalog entities**: + +```markdown +## Demo Data + +This plugin includes test resources to demonstrate functionality: + +### Demo Artifacts + +- **Sample Artifact 1**: Description and purpose +- **Sample Artifact 2**: Description and purpose + +### Demo Catalog Entities + +The setup automatically registers demo components in the RHDH catalog: + +- **component-name-1** (Component) - Description + - Annotations: List the plugin-specific annotations used + - Purpose: Explain what this demonstrates +- **component-name-2** (Component) - Description + - Annotations: List the plugin-specific annotations used + - Purpose: Explain what this demonstrates + +These catalog entities showcase how to use the plugin annotations in your own components. + +### Configuration + +Demo data is automatically populated during setup. To disable: + +\`\`\`bash +export POPULATE_DEMO_DATA=false +./scripts/config--plugin.sh +\`\`\` + +To manually populate demo data after deployment: + +\`\`\`bash +oc apply -f resources//populate-demo-data-job.yaml -n rhdh +\`\`\` + +To manually register catalog entities: + +\`\`\`bash +oc create configmap -demo-entities-config-map \ + --from-file=demo--artifacts.yaml=resources//demo-catalog-entities.yaml \ + -n rhdh + +oc label configmap -demo-entities-config-map \ + backstage.io/kubernetes-id=developer-hub -n rhdh +\`\`\` +``` + +#### Demo Catalog Entities File + +Create `resources//demo-catalog-entities.yaml` with proper plugin annotations: + +```yaml +--- +# Demo Component for +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: demo-component-name + title: Demo Component Display Name + description: Description of what this demonstrates + annotations: + # Plugin-specific annotations - CHECK PLUGIN DOCUMENTATION + # Example for Nexus Repository Manager: + nexus-repository-manager/repository: maven-releases + nexus-repository-manager/maven.group-id: com.example.demo + nexus-repository-manager/maven.artifact-id: demo-artifact + nexus-repository-manager/maven.base-version: 1.0.0 + + # Backstage Kubernetes integration + backstage.io/kubernetes-id: -demo + tags: + - demo + - + links: + - url: https://link-to-plugin-docs + title: Plugin Documentation + icon: docs +spec: + type: library # or service, website, etc. + lifecycle: experimental + owner: group:default/guardians-of-the-galaxy # Use existing Keycloak team + dependencyOf: + - resource:default/-resource +--- +# Additional demo components can be owned by different teams +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: demo-component-name-2 + title: Another Demo Component + description: Another example demonstrating different team ownership + annotations: + # Plugin-specific annotations... +spec: + type: service + lifecycle: experimental + owner: group:default/x-men # Different team for RBAC testing + dependencyOf: + - resource:default/-resource +``` + +**CRITICAL NOTES**: + +1. **Always check the plugin's official documentation** for correct annotation names and formats. Annotations vary by plugin and wrong annotations will prevent the plugin from displaying data. + +2. **Use Existing Keycloak Teams for Ownership**: Instead of creating new Group entities, use the teams already defined in Keycloak. This enables proper RBAC testing where different users see different components. + + **Available Keycloak Teams** (when Keycloak plugin is enabled): + - `group:default/avengers` + - `group:default/defenders` + - `group:default/fantastic-four` + - `group:default/guardians-of-the-galaxy` + - `group:default/x-men` + - `group:default/x-force` + - `group:default/cluster-admins` + +3. **Vary Team Ownership**: Assign different demo components to different teams. This allows users to test RBAC by logging in as different users and seeing only the components their team owns. + + **Example Strategy**: + - First demo artifact → `group:default/guardians-of-the-galaxy` + - Second demo artifact → `group:default/x-men` + - Third demo artifact → `group:default/avengers` + + This way, users from different teams will see different subsets of demo data when RBAC is enabled! + +4. **Random Assignment Suggestion**: When creating multiple demo components, vary team assignments to demonstrate RBAC capabilities. + +5. **DO NOT create custom Group/System entities** unless absolutely necessary for the plugin's functionality. Reuse existing Keycloak groups. + +#### Checklist for Demo Data + +When adding demo data for a plugin: + +- [ ] Determine appropriate demo data for the service type +- [ ] Choose implementation approach (Job, ConfigMap, pre-built artifacts, or external fetch) +- [ ] Create demo data resources in `resources//demo-data/` or `populate-demo-data-job.yaml` +- [ ] **Create catalog entities file** `resources//demo-catalog-entities.yaml` with proper plugin annotations +- [ ] **Use existing Keycloak teams** for component ownership (e.g., `group:default/guardians-of-the-galaxy`) +- [ ] **Vary team ownership** across demo components to enable RBAC testing +- [ ] Add `populate__demo_data()` function to config script +- [ ] **Add `register__demo_catalog_entities()` function** to config script +- [ ] Update `CATEGORY_SETUP_FUNCTIONS` to include demo data population AND catalog entity registration +- [ ] Add `POPULATE_DEMO_DATA` environment variable support +- [ ] Document demo data in `docs/.md` +- [ ] **Document catalog entities** in `docs/.md` with annotation examples +- [ ] Ensure demo data is self-contained (no cross-plugin dependencies) +- [ ] Test demo data population in clean environment +- [ ] **Verify catalog entities appear in RHDH catalog** +- [ ] Verify plugin displays demo data correctly in RHDH UI with proper annotations + ## 4. Update `config-plugins.sh` Add entries to three associative arrays: @@ -247,7 +596,7 @@ declare -A PACKAGE_TO_CATEGORY=( declare -A CATEGORY_SETUP_FUNCTIONS=( # ... existing entries ... - []="deploy_ deploy__resources config_secrets_for__plugins apply__labels" + []="deploy_ deploy__resources config_secrets_for__plugins apply__labels populate__demo_data register__demo_catalog_entities" ) ``` @@ -270,9 +619,9 @@ stringData: # ... existing entries ... # - _URL: '' - _TOKEN: '' - _SECRET: '' + _URL: "" + _TOKEN: "" + _SECRET: "" ``` Also update `deploy/secret-template.yaml` with the same entries. @@ -368,29 +717,47 @@ When scaffolding a new plugin, create/update these files: - [ ] `scripts/config--plugin.sh` - Configuration script - [ ] `resources//` - Resource manifests (if needed) - [ ] `resources/operators/-subscription.yaml` - Operator subscription (if needed) +- [ ] `resources//populate-demo-data-job.yaml` - Demo data population (REQUIRED for services) +- [ ] **`resources//demo-catalog-entities.yaml`** - **Catalog entities for demo artifacts (REQUIRED)** +- [ ] `resources//demo-data/` - Test artifacts/scripts (if applicable) - [ ] `config-plugins.sh` - Add to PACKAGE_TO_CATEGORY, CATEGORY_SETUP_FUNCTIONS, CATEGORY_TEARDOWN_FUNCTIONS - [ ] `resources/rhdh/rhdh-secrets.yaml` - Add secret placeholders - [ ] `deploy/secret-template.yaml` - Add secret placeholders -- [ ] `.env.sample` - Add user-provided variables (if any) +- [ ] `.env.sample` - Add user-provided variables and `POPULATE_DEMO_DATA` flag - [ ] Add operator entity to `operators.yaml` - [ ] Add CR entities to `operators.yaml` or `resources.yaml` - [ ] Ensure `backstage.io/kubernetes-id` matches labels in the config script - [ ] Define proper `dependsOn`/`dependencyOf` relationships +- [ ] **Include demo catalog entities documentation in `docs/.md`** +- [ ] **Verify plugin annotations are correct** (check plugin's official documentation) +- [ ] Add `populate__demo_data()` function to config script +- [ ] **Add `register__demo_catalog_entities()` function** to config script +- [ ] **Update CATEGORY_SETUP_FUNCTIONS to include both populate AND register functions** +- [ ] Test demo data population in clean environment +- [ ] **Test that catalog entities appear in RHDH catalog** +- [ ] **Test that plugin UI displays data with correct annotations** ## Example: Adding Support for "Ansible" Plugin If asked to add Ansible plugin support: -1. Create docs/ansible.md using template -2. Create scripts/config-ansible-plugin.sh with deploy/config/teardown functions -3. Create resources/ansible/ with AWX or AAP manifests (if available without license) -4. Create resources/operators/ansible-subscription.yaml for the operator -5. Update config-plugins.sh: +1. Create `docs/ansible.md` using template +2. Create `scripts/config-ansible-plugin.sh` with deploy/config/teardown functions +3. Create `resources/ansible/` with AWX or AAP manifests (if available without license) +4. Create `resources/operators/ansible-subscription.yaml` for the operator +5. **Create demo data resources:** + - `resources/ansible/populate-demo-data-job.yaml` - Job to create sample playbooks/inventories + - **`resources/ansible/demo-catalog-entities.yaml` - Catalog entities with Ansible plugin annotations** + - Add `populate_ansible_demo_data()` function to script + - **Add `register_ansible_demo_catalog_entities()` function to script** +6. Update `config-plugins.sh`: ```bash - ["plugin-ansible"]="ANSIBLE" - [ANSIBLE]="deploy_ansible deploy_ansible_resources config_secrets_for_ansible_plugins" - [ANSIBLE]="uninstall_ansible" + ["plugin-ansible"]="ANSIBLE" + [ANSIBLE]="deploy_ansible deploy_ansible_resources config_secrets_for_ansible_plugins apply_ansible_labels populate_ansible_demo_data register_ansible_demo_catalog_entities" + [ANSIBLE]="uninstall_ansible" ``` -6. Update secrets template with `ANSIBLE_URL`, `ANSIBLE_TOKEN`, etc. +7. Update secrets template with `ANSIBLE_URL`, `ANSIBLE_TOKEN`, etc. +8. **Document demo catalog entities in `docs/ansible.md` with correct annotations** +9. **Verify annotations match Ansible plugin documentation** From ad1c46766fdf97fa7f33e70177cb5275614c82e6 Mon Sep 17 00:00:00 2001 From: Patrick Knight Date: Mon, 9 Feb 2026 05:26:41 -0500 Subject: [PATCH 3/8] Add clarifier on the different config options for plugins to scaffolder rule Signed-off-by: Patrick Knight --- .cursor/rules/plugin-scaffolding.mdc | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/.cursor/rules/plugin-scaffolding.mdc b/.cursor/rules/plugin-scaffolding.mdc index 24c886d..878a5ad 100644 --- a/.cursor/rules/plugin-scaffolding.mdc +++ b/.cursor/rules/plugin-scaffolding.mdc @@ -40,6 +40,68 @@ API_KEY: "" --- +## IMPORTANT: Frontend vs Backend Plugins + +When scaffolding plugins, understand whether the plugin is frontend or backend, as this affects configuration: + +### Backend Plugins + +- Run on the RHDH backend server +- Configured via `app-config.yaml` or environment variables +- Example: `@backstage-community/plugin-3scale-backend` + +**Configuration Pattern:** + +```yaml +# In app-config.yaml +threeScaleApiEntity: + baseUrl: ${THREESCALE_BASE_URL} + accessToken: ${THREESCALE_ACCESS_TOKEN} +``` + +### Frontend Plugins + +- Run in the user's browser +- Require **proxy configuration** in `dynamic-plugins-configmap.yaml` +- Example: `@janus-idp/backstage-plugin-nexus-repository-manager` + +**Configuration Pattern:** + +```yaml +# In dynamic-plugins-configmap.yaml +- package: "@janus-idp/plugin-name" + pluginConfig: + dynamicPlugins: + frontend: + plugin.name: + mountPoints: [...] + proxy: + endpoints: + "/plugin-api-path": + target: "${SERVICE_URL}" + headers: + Authorization: "Basic ${AUTH_HEADER}" + changeOrigin: true + secure: true +``` + +**Why Frontend Plugins Need Proxies:** + +1. Browsers block cross-origin requests (CORS) +2. Credentials should not be exposed to browser +3. SSL certificate handling is centralized +4. Backend can cache responses + +**When Scaffolding Frontend Plugins:** + +- ✅ Generate proxy configuration in plugin config section +- ✅ Use `NEXUS_AUTH_HEADER` format (Base64 `username:password`) +- ✅ Document the proxy requirement clearly +- ✅ Note that secrets go in the proxy config, not app-config +- ❌ Don't generate backend `app-config.yaml` sections + +--- + ## 1. Documentation (`docs/.md`) Create documentation following the template at `docs/plugin-template.md`. Include: From c12e3217161a40a8927fbaca5a464892b41c6fc7 Mon Sep 17 00:00:00 2001 From: Patrick Knight Date: Thu, 12 Feb 2026 20:38:12 -0500 Subject: [PATCH 4/8] Update ACM operator subscription Signed-off-by: Patrick Knight --- resources/operators/acm-subscription.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/operators/acm-subscription.yaml b/resources/operators/acm-subscription.yaml index df19e83..dae0aff 100644 --- a/resources/operators/acm-subscription.yaml +++ b/resources/operators/acm-subscription.yaml @@ -5,6 +5,6 @@ metadata: spec: sourceNamespace: openshift-marketplace source: redhat-operators - channel: release-2.12 + channel: release-2.15 installPlanApproval: Automatic name: advanced-cluster-management From 0e0f01de308c04df31a32d64776efc6a53717013 Mon Sep 17 00:00:00 2001 From: Patrick Knight Date: Thu, 12 Feb 2026 20:39:53 -0500 Subject: [PATCH 5/8] Update 3Scale operator subscription Signed-off-by: Patrick Knight --- resources/3scale/api-manager.yaml | 21 ++++++++++++++++++++ resources/operators/3scale-subscription.yaml | 3 +-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/resources/3scale/api-manager.yaml b/resources/3scale/api-manager.yaml index 6dac31d..513ae7e 100644 --- a/resources/3scale/api-manager.yaml +++ b/resources/3scale/api-manager.yaml @@ -4,8 +4,29 @@ metadata: name: 3scale spec: system: + appSpec: + replicas: 1 + sidekiqSpec: + replicas: 1 fileStorage: simpleStorageService: configurationSecretRef: name: 3scale wildcardDomain: $ROUTER_BASE + + # Reduce replicas to 1 for demo purposes + apicast: + productionSpec: + replicas: 1 + stagingSpec: + replicas: 1 + backend: + listenerSpec: + replicas: 1 + workerSpec: + replicas: 1 + zync: + appSpec: + replicas: 1 + queSpec: + replicas: 1 diff --git a/resources/operators/3scale-subscription.yaml b/resources/operators/3scale-subscription.yaml index 821ae60..6a04bb9 100644 --- a/resources/operators/3scale-subscription.yaml +++ b/resources/operators/3scale-subscription.yaml @@ -3,9 +3,8 @@ kind: Subscription metadata: name: 3scale-operator spec: - channel: threescale-2.15 + channel: threescale-2.13 installPlanApproval: Automatic name: 3scale-operator source: redhat-operators sourceNamespace: openshift-marketplace - startingCSV: 3scale-operator.v0.12.3 From 9a9147a1a0db47619748c8aa40481c72b8934ed3 Mon Sep 17 00:00:00 2001 From: Patrick Knight Date: Thu, 12 Feb 2026 20:49:38 -0500 Subject: [PATCH 6/8] Add nexus repository manager plugin Signed-off-by: Patrick Knight --- .env.sample | 3 + config-plugins.sh | 5 + deploy/secret-template.yaml | 4 + docs/nexus.md | 363 +++++++++ guides/README.md | 122 +++ guides/nexus-advanced-config.md | 813 ++++++++++++++++++++ guides/nexus-troubleshooting.md | 678 ++++++++++++++++ resources/catalog-entities/operators.yaml | 38 + resources/nexus/demo-catalog-entities.yaml | 71 ++ resources/nexus/nexus-repo.yaml | 34 + resources/nexus/populate-demo-data-job.yaml | 172 +++++ resources/operators/nexus-subscription.yaml | 11 + resources/rhdh/rhdh-secrets.yaml | 29 +- scripts/config-nexus-plugin.sh | 251 ++++++ 14 files changed, 2581 insertions(+), 13 deletions(-) create mode 100644 docs/nexus.md create mode 100644 guides/README.md create mode 100644 guides/nexus-advanced-config.md create mode 100644 guides/nexus-troubleshooting.md create mode 100644 resources/nexus/demo-catalog-entities.yaml create mode 100644 resources/nexus/nexus-repo.yaml create mode 100644 resources/nexus/populate-demo-data-job.yaml create mode 100644 resources/operators/nexus-subscription.yaml create mode 100755 scripts/config-nexus-plugin.sh diff --git a/.env.sample b/.env.sample index 4054e0b..7535c52 100644 --- a/.env.sample +++ b/.env.sample @@ -5,3 +5,6 @@ K8S_CLUSTER_NAME="" SIGN_IN_PAGE="" OCM_HUB_NAME="" + +# Demo Data Configuration +POPULATE_DEMO_DATA=true # Set to false to skip demo data population diff --git a/config-plugins.sh b/config-plugins.sh index 66ac0df..85a67c0 100755 --- a/config-plugins.sh +++ b/config-plugins.sh @@ -28,6 +28,9 @@ declare -A PACKAGE_TO_CATEGORY=( # 3scale - requires 3scale operator deployment ["plugin-3scale-backend"]="3SCALE" + # Nexus Repository Manager - requires Nexus operator deployment + ["plugin-nexus-repository-manager"]="NEXUS" + #Kubernetes - needs ServiceAccount token setup ["plugin-kubernetes-backend"]="KUBERNETES" ["plugin-kubernetes"]="KUBERNETES" @@ -43,6 +46,7 @@ declare -A CATEGORY_SETUP_FUNCTIONS=( [TEKTON]="deploy_tekon deploy_pipelines apply_tekton_labels" [OCM]="deploy_acm config_secrets_for_ocm_plugins deploy_multicluster_hub apply_ocm_labels" [3SCALE]="copy_3scale_files deploy_3scale deploy_minio deploy_3scale_resources" + [NEXUS]="deploy_nexus deploy_nexus_resources config_secrets_for_nexus_plugins apply_nexus_labels populate_nexus_demo_data register_nexus_demo_catalog_entities" [KUBERNETES]="config_secrets_for_kubernetes_plugins" ) @@ -51,6 +55,7 @@ declare -A CATEGORY_TEARDOWN_FUNCTIONS=( [TEKTON]="uninstall_tekton" [OCM]="uninstall_acm" [3SCALE]="uninstall_3scale" + [NEXUS]="uninstall_nexus" [KUBERNETES]=":" ) diff --git a/deploy/secret-template.yaml b/deploy/secret-template.yaml index 11c6a45..7c6dd32 100644 --- a/deploy/secret-template.yaml +++ b/deploy/secret-template.yaml @@ -34,3 +34,7 @@ stringData: OCM_HUB_NAME: "" OCM_HUB_URL: "" OCM_SA_TOKEN: "" + + # Optional: Nexus Repository Manager (Frontend Proxy) + NEXUS_URL: "" + NEXUS_AUTH_HEADER: "" diff --git a/docs/nexus.md b/docs/nexus.md new file mode 100644 index 0000000..1bb7b24 --- /dev/null +++ b/docs/nexus.md @@ -0,0 +1,363 @@ +# Plugin: @janus-idp/backstage-plugin-nexus-repository-manager + +## Description + +The Nexus Repository Manager plugin integrates Sonatype Nexus Repository Manager with Red Hat +Developer Hub (RHDH), allowing you to view and manage artifacts stored in Nexus directly from the +Backstage catalog. This plugin provides visibility into Maven, npm, Docker, and other artifact +repositories, making it easier for developers to discover and use published artifacts. + +Key features: + +- View artifact information and metadata +- Browse repository contents +- Display artifact versions and download statistics +- Link artifacts to their corresponding components in the catalog + +--- + +## How to Configure + +You can configure this plugin either manually or automatically using the provided scripts. + +### Manual Setup + +1. Deploy required infrastructure: + - Install the Nexus Repository Manager Operator (community operator). + - Deploy a `NexusRepo` custom resource to create a Nexus instance. + - Wait for the Nexus instance to be ready and obtain the URL and credentials. + +2. Configure RHDH integration: + - Enable the Nexus Repository Manager plugin in your dynamic plugins configuration with proper + proxy settings. + - The plugin uses a **frontend proxy** to communicate with Nexus (not backend environment + variables). + - Add this configuration to your `dynamic-plugins-configmap.yaml`: + + ```yaml + - package: "@janus-idp/backstage-plugin-nexus-repository-manager" + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + janus-idp.backstage-plugin-nexus-repository-manager: + mountPoints: + - mountPoint: entity.page.image-registry/cards + importName: NexusRepositoryManagerPage + config: + layout: + gridColumn: 1 / -1 + if: + anyOf: + - isNexusRepositoryManagerAvailable + proxy: + endpoints: + "/nexus-repository-manager": + target: "https://${NEXUS_URL}" + headers: + X-Requested-With: "XMLHttpRequest" + # For authenticated access (recommended): + Authorization: "Basic ${NEXUS_AUTH_HEADER}" + changeOrigin: true + # Set to false if using self-signed certificates + secure: true + ``` + + - **Important**: The plugin requires a proxy configuration because it's a frontend plugin that + calls Nexus from the browser. + - The `target` should be your Nexus URL (without `/api` or other paths) + - For authentication, use a Base64-encoded `username:password` in the Authorization header + +3. Configure authentication: + - Generate the auth header value: `echo -n "admin:" | base64` + - Add to your secrets: + + ```yaml + NEXUS_URL: "https://nexus-repo-route.example.com" + NEXUS_AUTH_HEADER: "" + ``` + +4. Add annotations to catalog entities: + - Add the following annotations to your component's `catalog-info.yaml`: + + ```yaml + metadata: + annotations: + # For Maven artifacts + nexus-repository-manager/repository: maven-releases + nexus-repository-manager/maven.group-id: com.example + nexus-repository-manager/maven.artifact-id: my-app + nexus-repository-manager/maven.base-version: 1.0.0 + ``` + + - See the + [full list of available annotations](https://github.com/backstage/community-plugins/blob/main/workspaces/nexus-repository-manager/plugins/nexus-repository-manager/ANNOTATIONS.md). + +--- + +### Automatic Setup + +Automated setup is available in two levels depending on how much you want configured for you. + +#### Everything + +Runs the root-level script to deploy the complete infrastructure including Nexus Repository Manager. +Requires the Nexus plugin to be enabled by setting `disabled: false` in your dynamic plugins +configuration. + +**Run:** + +```bash +./start.sh +``` + +#### Just the Integration + +Only configures the integration resources for this plugin. Use this if you already have a Backstage +instance running and just need this plugin. + +**Run:** + +```bash +./scripts/config-nexus-plugin.sh +``` + +This script will: + +- Install the Nexus Repository Manager Operator +- Deploy a Nexus Repository Manager instance +- Configure secrets for RHDH authentication (`NEXUS_URL` and `NEXUS_AUTH_HEADER`) +- Apply Kubernetes labels for topology view +- Populate demo data (Maven and npm artifacts) +- Register demo catalog entities + +**Important - Manual Step Required:** + +After running the script, you must **add the proxy configuration** to your +`dynamic-plugins-configmap.yaml`: + +```yaml +- package: "@janus-idp/backstage-plugin-nexus-repository-manager" + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + janus-idp.backstage-plugin-nexus-repository-manager: + mountPoints: + - mountPoint: entity.page.image-registry/cards + importName: NexusRepositoryManagerPage + config: + layout: + gridColumn: 1 / -1 + if: + anyOf: + - isNexusRepositoryManagerAvailable + proxy: + endpoints: + "/nexus-repository-manager": + target: "${NEXUS_URL}" + headers: + X-Requested-With: "XMLHttpRequest" + Authorization: "Basic ${NEXUS_AUTH_HEADER}" + changeOrigin: true + secure: true # Set to false if using self-signed certificates +``` + +The setup script automatically generates the `NEXUS_URL` and `NEXUS_AUTH_HEADER` environment +variables and stores them in the `rhdh-secrets` secret. The proxy configuration above references +these variables. + +**Why proxy configuration?** + +- The Nexus plugin is a **frontend plugin** (runs in the browser) +- RHDH's backend acts as a proxy to avoid CORS issues and handle authentication +- The proxy forwards requests from `/api/nexus-repository-manager/*` to your Nexus instance + +--- + +## Demo + +1. Go to your RHDH instance. +2. Navigate to the Catalog. +3. Open a component that has Nexus annotations. +4. Look for the "Nexus Repository Manager" tab or card. +5. View the artifact information, versions, and repository details. + +Alternatively: + +1. Access the Nexus web UI directly at the route created in your namespace. +2. Login with admin credentials (check the `nexus-admin-credentials` secret). +3. Browse the repositories and verify demo artifacts are present. + +--- + +## Demo Data + +This plugin includes test resources to demonstrate functionality: + +### Demo Artifacts + +- **Sample Maven Artifact**: `com.example.demo:hello-world-lib:1.0.0` - A simple Java library JAR + with POM file +- **Sample npm Package**: `@demo/hello-world@1.0.0` - A basic Node.js package demonstrating npm + repository + +### Demo Catalog Entities + +The setup automatically registers demo components in the RHDH catalog: + +- **hello-world-lib** (Component) - Maven library with Nexus annotations + - Repository: `maven-releases` + - Maven Group ID: `com.example.demo` + - Maven Artifact ID: `hello-world-lib` + - Maven Base Version: `1.0.0` + - Owner: `group:default/guardians-of-the-galaxy` + +- **hello-world-npm** (Component) - npm package with Nexus annotations + - Repository: `npm-internal` + - Name: `@demo/hello-world` + - npm Scope: `@demo` + - Owner: `group:default/x-men` + +These catalog entities use existing Keycloak teams for ownership, enabling RBAC testing. Different +users will see different components based on their team membership: + +- Users in the Guardians of the Galaxy team will see the Maven library +- Users in the X-Men team will see the npm package +- Cluster admins will see all components + +These catalog entities showcase how to use the Nexus Repository Manager plugin annotations in your +own components. + +### Configuration + +Demo data is automatically populated during setup. To disable: + +```bash +export POPULATE_DEMO_DATA=false +./scripts/config-nexus-plugin.sh +``` + +To manually populate demo data after deployment: + +```bash +oc apply -f resources/nexus/populate-demo-data-job.yaml -n rhdh +``` + +To manually register catalog entities: + +```bash +oc create configmap nexus-demo-entities-config-map \ + --from-file=demo-nexus-artifacts.yaml=resources/nexus/demo-catalog-entities.yaml \ + -n rhdh + +oc label configmap nexus-demo-entities-config-map \ + backstage.io/kubernetes-id=developer-hub -n rhdh +``` + +--- + +## Accessing Nexus + +### Web UI + +Get the Nexus URL and login: + +```bash +# Get the URL +echo "https://$(oc get route nexus-repo -n rhdh -o jsonpath='{.spec.host}')" + +# Get admin password +oc get secret nexus-admin-credentials -n rhdh -o jsonpath='{.data.password}' | base64 -d +echo "" +``` + +Default username: `admin` + +### REST API + +You can interact with Nexus programmatically: + +```bash +NEXUS_URL=$(oc get route nexus-repo -n rhdh -o jsonpath='{.spec.host}') +NEXUS_PASS=$(oc get secret nexus-admin-credentials -n rhdh -o jsonpath='{.data.password}' | base64 -d) + +# Check status +curl -u admin:${NEXUS_PASS} https://${NEXUS_URL}/service/rest/v1/status + +# List components in a repository +curl -u admin:${NEXUS_PASS} https://${NEXUS_URL}/service/rest/v1/components?repository=maven-releases +``` + +--- + +## Available Repositories + +After deployment, Nexus comes pre-configured with: + +| Repository | Type | Purpose | +| --------------- | ------ | ------------------------------------------- | +| maven-releases | hosted | Release artifacts for Maven (includes demo) | +| maven-snapshots | hosted | Snapshot artifacts for Maven | +| maven-central | proxy | Proxy to Maven Central | +| npm-internal | hosted | Private npm packages (includes demo) | +| npm-proxy | proxy | Proxy to npmjs.org | +| docker-hosted | hosted | Private Docker images | +| docker-proxy | proxy | Proxy to Docker Hub | + +--- + +## Quick Verification + +After deployment, verify everything is working: + +```bash +# 1. Check operator is installed +oc get csv -n rhdh | grep nxrm-operator + +# 2. Check Nexus instance is running +oc get nexusrepo nexus-repo -n rhdh + +# 3. Check demo data job completed +oc get job nexus-populate-demo-data -n rhdh + +# 4. Check catalog entities are registered +oc get configmap nexus-demo-entities-config-map -n rhdh + +# 5. Verify demo artifacts in Nexus +NEXUS_URL=$(oc get route nexus-repo -n rhdh -o jsonpath='{.spec.host}') +NEXUS_PASS=$(oc get secret nexus-admin-credentials -n rhdh -o jsonpath='{.data.password}' | base64 -d) +curl -u admin:${NEXUS_PASS} https://${NEXUS_URL}/service/rest/v1/components?repository=maven-releases +``` + +--- + +## Related Files + +- `/scripts/config-nexus-plugin.sh` - Automates plugin setup +- `/resources/nexus/` - Nexus CRs and supporting manifests +- `/resources/nexus/nexus-repo.yaml` - Nexus Repository Manager instance definition +- `/resources/nexus/populate-demo-data-job.yaml` - Demo data population job +- `/resources/nexus/demo-catalog-entities.yaml` - Demo catalog entities with Nexus annotations +- `/resources/operators/nexus-subscription.yaml` - Nexus operator subscription + +--- + +## Additional Resources + +For more detailed information: + +- [Nexus Troubleshooting Guide](../guides/nexus-troubleshooting.md) - Common issues and solutions +- [Nexus Advanced Configuration](../guides/nexus-advanced-config.md) - Production setup, + persistence, performance tuning + +--- + +## Notes + +- The Nexus Repository Manager Operator is a community operator and is available in the OperatorHub. +- The default installation uses ephemeral storage. For production use, configure persistent volume + claims. +- Initial admin password can be retrieved from the `nexus-admin-credentials` secret. +- The plugin supports multiple repository formats: Maven, npm, Docker, PyPI, RubyGems, and more. +- Initial Nexus startup may take 2-3 minutes. diff --git a/guides/README.md b/guides/README.md new file mode 100644 index 0000000..3b29bae --- /dev/null +++ b/guides/README.md @@ -0,0 +1,122 @@ +# RHDH Testbed Guides + +This directory contains in-depth technical guides for RHDH plugin configurations, troubleshooting, +and advanced setups. + +## Purpose + +While the `docs/` directory provides **reference documentation** for each plugin (overview, setup, +basic usage), the `guides/` directory offers **how-to guides** and **deep-dive technical content** +for developers and operators. + +## Directory Structure + +``` +guides/ +├── README.md # This file +├── nexus-troubleshooting.md # Nexus plugin troubleshooting +├── nexus-advanced-config.md # Nexus production setup +└── [future guides] +``` + +## Available Guides + +### Nexus Repository Manager + +- **[Troubleshooting Guide](nexus-troubleshooting.md)** - Diagnose and fix common issues + - Operator installation problems + - Nexus instance startup issues + - Demo data failures + - Plugin integration problems + - Network connectivity + - Performance issues +- **[Advanced Configuration](nexus-advanced-config.md)** - Production-ready setups + - Persistent storage configuration + - Resource tuning and JVM optimization + - High availability strategies + - Custom repository creation + - Security configuration (LDAP, RBAC, SSL/TLS) + - Backup and restore procedures + - Monitoring and metrics + - Performance optimization + +## When to Use Docs vs Guides + +### Use `docs/.md` for: + +- Plugin overview and description +- Quick start and basic setup +- Demo instructions +- File references +- Standard usage patterns + +### Use `guides/-*.md` for: + +- Detailed troubleshooting procedures +- Production configuration examples +- Performance tuning +- Security hardening +- Advanced integrations +- Operational procedures +- Deep technical details + +## Guide Template + +When creating new guides, follow this structure: + +```markdown +# [Plugin Name] - [Guide Type] + +Brief introduction explaining what this guide covers. + +--- + +## Table of Contents + +- [Section 1](#section-1) +- [Section 2](#section-2) + +--- + +## Section 1 + +### Subsection + +**Problem/Scenario:** Description + +**Diagnosis:** \`\`\`bash commands to diagnose \`\`\` + +**Solution:** \`\`\`bash commands to fix \`\`\` + +--- + +## Additional Resources + +- Links to official docs +- Related guides +``` + +## Contributing Guides + +When adding new plugin support, consider creating: + +1. **Troubleshooting Guide** if the plugin: + - Has complex installation steps + - Commonly encounters issues + - Requires operator/CRD management + - Has network/connectivity requirements + +2. **Advanced Configuration Guide** if the plugin: + - Supports production deployments + - Has performance tuning options + - Requires security configuration + - Supports high availability + - Has complex integration scenarios + +Not every plugin needs these guides - simple plugins with straightforward setup can rely solely on +`docs/` documentation. + +## Feedback + +These guides are living documents. If you encounter issues not covered here or have suggestions for +additional topics, please contribute! diff --git a/guides/nexus-advanced-config.md b/guides/nexus-advanced-config.md new file mode 100644 index 0000000..dc64bb4 --- /dev/null +++ b/guides/nexus-advanced-config.md @@ -0,0 +1,813 @@ +# Nexus Repository Manager - Advanced Configuration + +This guide covers production-ready configurations, performance tuning, and advanced features for the +Nexus Repository Manager plugin in RHDH. + +--- + +## Table of Contents + +- [Persistent Storage](#persistent-storage) +- [Resource Tuning](#resource-tuning) +- [High Availability](#high-availability) +- [Custom Repositories](#custom-repositories) +- [Security Configuration](#security-configuration) +- [Backup and Restore](#backup-and-restore) +- [Monitoring and Metrics](#monitoring-and-metrics) +- [Custom Plugin Configuration](#custom-plugin-configuration) + +--- + +## Persistent Storage + +The default demo configuration uses **ephemeral storage** which is lost when the pod restarts. For +production use, configure persistent storage. + +### Enable Persistent Volume Claim + +Edit `resources/nexus/nexus-repo.yaml`: + +```yaml +apiVersion: sonatype.com/v1alpha1 +kind: NexusRepo +metadata: + name: nexus-repo +spec: + useRedHatImage: true + + networking: + expose: true + exposeAs: Route + + nexus: + # Enable PVC + volumeClaimTemplate: + enabled: true + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Gi # Adjust size as needed + # Optional: specify storage class + # storageClassName: gp2 + + resources: + requests: + cpu: 1000m + memory: 4Gi + limits: + cpu: 4000m + memory: 8Gi +``` + +### Storage Sizing Guidelines + +| Environment | Recommended Size | Notes | +| ----------- | ---------------- | ----------------------------------- | +| Demo/Test | 10-20Gi | Ephemeral OK | +| Development | 50-100Gi | Persistent recommended | +| Staging | 100-250Gi | Persistent required | +| Production | 250Gi-1Ti+ | Persistent required, monitor growth | + +### Storage Class Selection + +**For AWS:** + +```yaml +storageClassName: gp3 # Recommended: AWS EBS gp3 +``` + +**For Azure:** + +```yaml +storageClassName: managed-premium # Azure Premium SSD +``` + +**For GCP:** + +```yaml +storageClassName: standard-rwo # GCP Persistent Disk +``` + +**For OpenShift Container Storage:** + +```yaml +storageClassName: ocs-storagecluster-ceph-rbd +``` + +### Migrate from Ephemeral to Persistent + +If you already have a running Nexus instance with data you want to preserve: + +1. **Export current data:** + + ```bash + # Create backup of Nexus data + NEXUS_POD=$(oc get pods -n rhdh -l app=nexus-repo -o jsonpath='{.items[0].metadata.name}') + oc exec ${NEXUS_POD} -n rhdh -- tar czf /tmp/nexus-backup.tar.gz /nexus-data + oc cp rhdh/${NEXUS_POD}:/tmp/nexus-backup.tar.gz ./nexus-backup.tar.gz + ``` + +2. **Update nexus-repo.yaml** with PVC configuration + +3. **Delete and recreate:** + + ```bash + oc delete nexusrepo nexus-repo -n rhdh + oc apply -f resources/nexus/nexus-repo.yaml -n rhdh + ``` + +4. **Restore data:** + ```bash + # Wait for new pod to be ready + NEXUS_POD=$(oc get pods -n rhdh -l app=nexus-repo -o jsonpath='{.items[0].metadata.name}') + oc cp ./nexus-backup.tar.gz rhdh/${NEXUS_POD}:/tmp/ + oc exec ${NEXUS_POD} -n rhdh -- tar xzf /tmp/nexus-backup.tar.gz -C / + oc delete pod ${NEXUS_POD} -n rhdh # Restart to apply + ``` + +--- + +## Resource Tuning + +### Memory Configuration + +Nexus is a Java application and benefits from proper JVM tuning. + +**Minimum Requirements:** + +- Development: 2Gi RAM +- Production: 4Gi RAM (8Gi+ recommended) + +**Optimal Configuration:** + +```yaml +resources: + requests: + memory: 4Gi + cpu: 1000m + limits: + memory: 8Gi + cpu: 4000m +``` + +### JVM Tuning + +For advanced JVM configuration, create a ConfigMap: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: nexus-jvm-config + namespace: rhdh +data: + jvm.properties: | + -Xms4g + -Xmx4g + -XX:MaxDirectMemorySize=2g + -XX:+UseG1GC + -XX:MaxGCPauseMillis=200 + -Djava.util.prefs.userRoot=/nexus-data/javaprefs +``` + +Then reference in NexusRepo: + +```yaml +spec: + nexus: + env: + - name: INSTALL4J_ADD_VM_PARAMS + valueFrom: + configMapKeyRef: + name: nexus-jvm-config + key: jvm.properties +``` + +### CPU Considerations + +**Recommendations:** + +- **Minimum**: 500m (0.5 cores) +- **Recommended**: 1000m-2000m (1-2 cores) +- **High load**: 4000m+ (4+ cores) + +### Vertical Pod Autoscaling + +Enable VPA for automatic resource adjustment: + +```yaml +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: nexus-vpa + namespace: rhdh +spec: + targetRef: + apiVersion: "apps/v1" + kind: StatefulSet + name: nexus-repo + updatePolicy: + updateMode: "Auto" + resourcePolicy: + containerPolicies: + - containerName: nexus + minAllowed: + memory: 2Gi + cpu: 500m + maxAllowed: + memory: 16Gi + cpu: 8000m +``` + +--- + +## High Availability + +**Note:** The Nexus Operator currently deploys single-instance Nexus. For HA, you need Nexus +Repository Pro (commercial license). + +### HA Options + +1. **PostgreSQL Backend** (Pro feature) +2. **Clustered Deployment** (Pro feature) +3. **Active-Passive Failover** (OSS - manual setup) + +### Active-Passive Failover (OSS) + +For improved availability without Pro license: + +1. **Use ReadWriteMany PVC** (if your storage supports it): + + ```yaml + volumeClaimTemplate: + enabled: true + spec: + accessModes: + - ReadWriteMany # Requires NFS or similar + ``` + +2. **Set up regular backups** (see Backup section) + +3. **Use PodDisruptionBudget**: + ```yaml + apiVersion: policy/v1 + kind: PodDisruptionBudget + metadata: + name: nexus-pdb + namespace: rhdh + spec: + maxUnavailable: 0 + selector: + matchLabels: + app: nexus-repo + ``` + +--- + +## Custom Repositories + +### Create Additional Repositories via API + +After Nexus is running, you can create custom repositories: + +```bash +NEXUS_URL=$(oc get route nexus-repo -n rhdh -o jsonpath='{.spec.host}') +NEXUS_PASS=$(oc get secret nexus-admin-credentials -n rhdh -o jsonpath='{.data.password}' | base64 -d) + +# Create a hosted Maven repository +curl -u admin:${NEXUS_PASS} -X POST "https://${NEXUS_URL}/service/rest/v1/repositories/maven/hosted" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "my-maven-repo", + "online": true, + "storage": { + "blobStoreName": "default", + "strictContentTypeValidation": true, + "writePolicy": "ALLOW" + }, + "maven": { + "versionPolicy": "RELEASE", + "layoutPolicy": "STRICT" + } + }' + +# Create a hosted npm repository +curl -u admin:${NEXUS_PASS} -X POST "https://${NEXUS_URL}/service/rest/v1/repositories/npm/hosted" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "my-npm-repo", + "online": true, + "storage": { + "blobStoreName": "default", + "strictContentTypeValidation": true, + "writePolicy": "ALLOW_ONCE" + } + }' +``` + +### Create Repository Groups + +Group repositories for unified access: + +```bash +curl -u admin:${NEXUS_PASS} -X POST "https://${NEXUS_URL}/service/rest/v1/repositories/maven/group" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "maven-all", + "online": true, + "storage": { + "blobStoreName": "default", + "strictContentTypeValidation": true + }, + "group": { + "memberNames": [ + "maven-releases", + "maven-snapshots", + "maven-central" + ] + }, + "maven": { + "versionPolicy": "MIXED" + } + }' +``` + +### Automate Repository Creation + +Create a Job to initialize custom repositories: + +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: nexus-setup-repositories + namespace: rhdh +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: setup + image: curlimages/curl:latest + command: + - /bin/sh + - -c + - | + # Wait for Nexus + until curl -sf http://nexus-repo-service:8081/service/rest/v1/status; do + sleep 5 + done + + # Create repositories + curl -u admin:${NEXUS_PASS} -X POST \ + "http://nexus-repo-service:8081/service/rest/v1/repositories/maven/hosted" \ + -H "Content-Type: application/json" \ + -d '{"name":"custom-releases",...}' + env: + - name: NEXUS_PASS + valueFrom: + secretKeyRef: + name: nexus-admin-credentials + key: password +``` + +--- + +## Security Configuration + +### Change Default Admin Password + +**Important:** Change the default admin password immediately in production. + +```bash +NEXUS_URL=$(oc get route nexus-repo -n rhdh -o jsonpath='{.spec.host}') +OLD_PASS=$(oc get secret nexus-admin-credentials -n rhdh -o jsonpath='{.data.password}' | base64 -d) +NEW_PASS="" + +# Change password via API +curl -u admin:${OLD_PASS} -X PUT "https://${NEXUS_URL}/service/rest/v1/security/users/admin/change-password" \ + -H "Content-Type: text/plain" \ + -d "${NEW_PASS}" + +# Update secret +oc create secret generic nexus-admin-credentials \ + --from-literal=password=${NEW_PASS} \ + --dry-run=client -o yaml | oc apply -n rhdh -f - + +# Update RHDH secrets +oc patch secret rhdh-secrets -n rhdh --type merge -p "{\"data\":{\"NEXUS_PASSWORD\":\"$(echo -n ${NEW_PASS} | base64 -w 0)\"}}" +``` + +### Enable LDAP Authentication + +Integrate with external LDAP/Active Directory: + +```bash +curl -u admin:${NEXUS_PASS} -X POST "https://${NEXUS_URL}/service/rest/v1/security/ldap" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "corporate-ldap", + "protocol": "ldaps", + "host": "ldap.example.com", + "port": 636, + "searchBase": "dc=example,dc=com", + "authScheme": "simple", + "authUsername": "cn=nexus,ou=service-accounts,dc=example,dc=com", + "authPassword": "", + "userBaseDn": "ou=users", + "userSubtree": true, + "userObjectClass": "inetOrgPerson", + "userIdAttribute": "uid", + "userRealNameAttribute": "cn", + "userEmailAddressAttribute": "mail" + }' +``` + +### Configure Role-Based Access Control (RBAC) + +Create custom roles: + +```bash +# Create developer role with read-only access +curl -u admin:${NEXUS_PASS} -X POST "https://${NEXUS_URL}/service/rest/v1/security/roles" \ + -H "Content-Type: application/json" \ + -d '{ + "id": "developer", + "name": "Developer", + "description": "Read-only access to artifacts", + "privileges": [ + "nx-repository-view-*-*-read", + "nx-repository-view-*-*-browse" + ] + }' +``` + +### Enable SSL/TLS + +The operator creates a route with OpenShift's default TLS. For custom certificates: + +```bash +# Create TLS secret +oc create secret tls nexus-tls \ + --cert=nexus.crt \ + --key=nexus.key \ + -n rhdh + +# Patch route to use custom cert +oc patch route nexus-repo -n rhdh -p '{ + "spec": { + "tls": { + "certificate": "", + "key": "" + } + } +}' +``` + +--- + +## Backup and Restore + +### Backup Strategy + +**Recommended approach:** + +1. **Backup blob stores** (contains actual artifacts) +2. **Backup database** (metadata and configuration) +3. **Backup configuration** (admin password, repositories) + +### Manual Backup + +```bash +NEXUS_POD=$(oc get pods -n rhdh -l app=nexus-repo -o jsonpath='{.items[0].metadata.name}') + +# Full backup +oc exec ${NEXUS_POD} -n rhdh -- tar czf /tmp/nexus-full-backup.tar.gz /nexus-data + +# Download backup +oc cp rhdh/${NEXUS_POD}:/tmp/nexus-full-backup.tar.gz ./nexus-backup-$(date +%Y%m%d).tar.gz +``` + +### Automated Backups with CronJob + +```yaml +apiVersion: batch/v1 +kind: CronJob +metadata: + name: nexus-backup + namespace: rhdh +spec: + schedule: "0 2 * * *" # Daily at 2 AM + jobTemplate: + spec: + template: + spec: + containers: + - name: backup + image: registry.access.redhat.com/ubi9/ubi:latest + command: + - /bin/bash + - -c + - | + # Install dependencies + dnf install -y tar gzip aws-cli + + # Create backup + tar czf /tmp/nexus-backup-$(date +%Y%m%d).tar.gz /nexus-data + + # Upload to S3 (or your backup storage) + aws s3 cp /tmp/nexus-backup-*.tar.gz s3://my-backups/nexus/ + volumeMounts: + - name: nexus-data + mountPath: /nexus-data + readOnly: true + env: + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: aws-credentials + key: access-key-id + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: aws-credentials + key: secret-access-key + volumes: + - name: nexus-data + persistentVolumeClaim: + claimName: nexus-pvc + restartPolicy: OnFailure +``` + +### Restore from Backup + +```bash +# Stop Nexus +oc scale statefulset nexus-repo --replicas=0 -n rhdh + +# Upload and extract backup +oc cp nexus-backup-20241201.tar.gz rhdh/ < pod-name > :/tmp/ +oc exec rhdh -- tar xzf /tmp/nexus-backup-20241201.tar.gz -C / < pod-name > -n + +# Restart Nexus +oc scale statefulset nexus-repo --replicas=1 -n rhdh +``` + +--- + +## Monitoring and Metrics + +### Enable Prometheus Metrics + +Nexus exposes metrics for Prometheus: + +```yaml +# ServiceMonitor for Prometheus Operator +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: nexus-metrics + namespace: rhdh + labels: + app: nexus-repo +spec: + selector: + matchLabels: + app: nexus-repo + endpoints: + - port: http + path: /service/metrics/prometheus + interval: 30s +``` + +### Key Metrics to Monitor + +| Metric | Description | Alert Threshold | +| ---------------------------------------- | --------------------- | --------------- | +| `nexus_blobstore_total_size_bytes` | Total blob store size | > 80% capacity | +| `nexus_jvm_memory_used_bytes` | JVM memory usage | > 90% limit | +| `nexus_repository_component_total_count` | Number of components | Growth rate | +| `nexus_http_requests_total` | HTTP request rate | Sudden drops | + +### Grafana Dashboard + +Import the Nexus dashboard: + +```bash +# Dashboard ID: 13463 (from grafana.com) +# Or create custom dashboard with above metrics +``` + +### Health Checks + +Configure liveness and readiness probes: + +```yaml +spec: + nexus: + livenessProbe: + httpGet: + path: /service/rest/v1/status + port: 8081 + initialDelaySeconds: 180 + periodSeconds: 30 + timeoutSeconds: 10 + failureThreshold: 6 + + readinessProbe: + httpGet: + path: /service/rest/v1/status + port: 8081 + initialDelaySeconds: 60 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 +``` + +--- + +## Custom Plugin Configuration + +### Required Proxy Configuration + +The Nexus Repository Manager plugin is a **frontend plugin** that requires proxy configuration in +the dynamic plugins configmap. This is different from backend plugins that use app-config.yaml. + +**Complete plugin configuration:** + +```yaml +- package: "@janus-idp/backstage-plugin-nexus-repository-manager" + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + janus-idp.backstage-plugin-nexus-repository-manager: + mountPoints: + - mountPoint: entity.page.image-registry/cards + importName: NexusRepositoryManagerPage + config: + layout: + gridColumn: 1 / -1 + if: + anyOf: + - isNexusRepositoryManagerAvailable + proxy: + endpoints: + "/nexus-repository-manager": + target: "${NEXUS_URL}" + headers: + X-Requested-With: "XMLHttpRequest" + Authorization: "Basic ${NEXUS_AUTH_HEADER}" + changeOrigin: true + secure: true +``` + +**Environment Variables Required:** + +- `NEXUS_URL` - Full Nexus URL (e.g., `https://nexus.example.com`) +- `NEXUS_AUTH_HEADER` - Base64-encoded `username:password` for HTTP Basic auth + +### Generating Auth Header + +The setup script automatically generates this, but for manual configuration: + +```bash +# Generate auth header +USERNAME="admin" +PASSWORD="" +AUTH_HEADER=$(echo -n "${USERNAME}:${PASSWORD}" | base64 -w 0) + +# Add to secrets +oc patch secret rhdh-secrets -n rhdh --type merge -p "{\"data\":{\"NEXUS_AUTH_HEADER\":\"$(echo -n ${AUTH_HEADER} | base64 -w 0)\"}}" +``` + +### Why Proxy Configuration? + +Frontend plugins make API calls from the user's browser. The proxy: + +1. **Avoids CORS** - Browsers block cross-origin requests +2. **Handles Authentication** - Keeps credentials server-side +3. **Simplifies SSL** - Handles certificate validation centrally +4. **Provides Caching** - Can cache responses for performance + +### Advanced Annotation Usage + +Use multiple annotations for richer queries: + +```yaml +metadata: + annotations: + # Query by multiple criteria + nexus-repository-manager/repository: maven-releases + nexus-repository-manager/maven.group-id: com.example + nexus-repository-manager/maven.artifact-id: myapp + nexus-repository-manager/maven.base-version: 1.0.0 + + # Add custom title + nexus-repository-manager/config.title: "Production Artifacts" +``` + +### Configure Plugin Polling Interval + +In RHDH app-config: + +```yaml +nexusRepositoryManager: + baseUrl: ${NEXUS_URL} + username: ${NEXUS_USERNAME} + password: ${NEXUS_PASSWORD} + cache: + ttl: 300000 # 5 minutes in milliseconds +``` + +### Custom Component Card Layout + +```yaml +- package: "@janus-idp/backstage-plugin-nexus-repository-manager" + disabled: false + pluginConfig: + dynamicPlugins: + frontend: + janus-idp.backstage-plugin-nexus-repository-manager: + mountPoints: + - mountPoint: entity.page.overview/cards + importName: EntityNexusRepositoryManagerCard + config: + layout: + gridColumn: 1 / -1 # Full width + gridRow: auto + if: + allOf: + - isNexusAvailable # Only show if annotations present +``` + +--- + +## Performance Optimization + +### Connection Pooling + +Configure connection pools for high-traffic scenarios: + +```yaml +env: + - name: NEXUS_DATASTORE_NEXUS_JDBC_URL + value: "jdbc:h2:file:/nexus-data/db/nexus" + - name: NEXUS_DATASTORE_NEXUS_POOL_MAXPOOLSIZE + value: "50" + - name: NEXUS_DATASTORE_NEXUS_POOL_MINPOOLSIZE + value: "10" +``` + +### Cleanup Policies + +Automate cleanup of old artifacts: + +```bash +curl -u admin:${NEXUS_PASS} -X POST "https://${NEXUS_URL}/service/rest/v1/cleanup-policies" \ + -H "Content-Type: application/json" \ + -d '{ + "name": "cleanup-old-snapshots", + "format": "maven2", + "notes": "Remove snapshots older than 30 days", + "criteriaLastBlobUpdated": 30, + "criteriaReleaseType": "SNAPSHOTS" + }' +``` + +### Enable Request Caching + +Add a caching proxy (Varnish, nginx) in front of Nexus for static assets. + +--- + +## Production Checklist + +Before going to production: + +- [ ] Enable persistent storage with adequate sizing +- [ ] Configure resource limits based on expected load +- [ ] Change default admin password +- [ ] Set up LDAP/SSO authentication +- [ ] Configure RBAC for different user roles +- [ ] Enable SSL/TLS with valid certificates +- [ ] Set up automated backups +- [ ] Configure monitoring and alerting +- [ ] Test disaster recovery procedures +- [ ] Document repository structure and policies +- [ ] Configure cleanup policies for old artifacts +- [ ] Review and adjust JVM settings +- [ ] Set up log aggregation +- [ ] Configure network policies +- [ ] Test failover procedures + +--- + +## Additional Resources + +- [Nexus Repository Manager Documentation](https://help.sonatype.com/repomanager3) +- [Nexus Operator GitHub](https://github.com/sonatype/operator-nxrm3) +- [Nexus REST API Reference](https://help.sonatype.com/repomanager3/rest-and-integration-api) +- [Performance and Scaling Guide](https://help.sonatype.com/repomanager3/planning-your-implementation/performance-and-scaling) diff --git a/guides/nexus-troubleshooting.md b/guides/nexus-troubleshooting.md new file mode 100644 index 0000000..ba01ca2 --- /dev/null +++ b/guides/nexus-troubleshooting.md @@ -0,0 +1,678 @@ +# Nexus Repository Manager - Troubleshooting Guide + +This guide helps you diagnose and fix common issues with the Nexus Repository Manager plugin for +RHDH. + +--- + +## Table of Contents + +- [Operator Issues](#operator-issues) +- [Nexus Instance Issues](#nexus-instance-issues) +- [Demo Data Issues](#demo-data-issues) +- [Plugin Integration Issues](#plugin-integration-issues) +- [Network and Connectivity](#network-and-connectivity) +- [Performance Issues](#performance-issues) +- [Common Error Messages](#common-error-messages) + +--- + +## Operator Issues + +### Operator Not Installing + +**Symptoms:** + +- Subscription exists but CSV never appears +- Install plan is stuck in "Installing" state + +**Diagnosis:** + +```bash +# Check subscription status +oc get subscription nexus-operator-subscription -n rhdh -o yaml + +# Check install plan +oc get installplan -n rhdh + +# Check for operator pod issues +oc get pods -n openshift-marketplace | grep certified-operators +``` + +**Solutions:** + +1. **Verify operator catalog is healthy:** + + ```bash + oc get catalogsource -n openshift-marketplace + oc get pods -n openshift-marketplace + ``` + +2. **Check for approval requirements:** + + ```bash + # If manual approval is needed + INSTALL_PLAN=$(oc get installplan -n rhdh -o jsonpath='{.items[0].metadata.name}') + oc patch installplan ${INSTALL_PLAN} -n rhdh --type merge -p '{"spec":{"approved":true}}' + ``` + +3. **Restart marketplace operators:** + + ```bash + oc delete pod -n openshift-marketplace -l marketplace.redhat.com/name=certified-operators + ``` + +4. **Check for resource conflicts:** + + ```bash + # Look for existing Nexus CRDs + oc get crd | grep nexus + + # If old CRDs exist, they may conflict + # Only delete if you're sure they're not in use + ``` + +### Operator CSV Fails + +**Symptoms:** + +- CSV shows "Failed" status +- Operator pod is CrashLooping + +**Diagnosis:** + +```bash +# Check CSV status +oc get csv -n rhdh | grep nxrm-operator + +# Check operator pod logs +OPERATOR_POD=$(oc get pods -n rhdh -l app=nxrm-operator -o name) +oc logs ${OPERATOR_POD} -n rhdh +``` + +**Solutions:** + +1. **Check RBAC permissions:** + + ```bash + # Operator needs proper ClusterRole permissions + oc get clusterrole | grep nxrm + oc describe clusterrole nxrm-operator + ``` + +2. **Reinstall operator:** + + ```bash + # Delete CSV (subscription will recreate it) + CSV_NAME=$(oc get csv -n rhdh | grep nxrm-operator | awk '{print $1}') + oc delete csv ${CSV_NAME} -n rhdh + + # Wait for automatic recreation + oc get csv -n rhdh -w + ``` + +--- + +## Nexus Instance Issues + +### Nexus Instance Won't Start + +**Symptoms:** + +- NexusRepo CR exists but no pods are created +- Pods are created but crash immediately + +**Diagnosis:** + +```bash +# Check NexusRepo resource status +oc get nexusrepo nexus-repo -n rhdh -o yaml + +# Check for pods +oc get pods -n rhdh | grep nexus + +# If pods exist, check logs +oc logs -n rhdh -l app=nexus-repo --tail=100 +``` + +**Solutions:** + +1. **Check resource limits:** + + ```bash + # Nexus needs at least 2Gi memory + oc describe nexusrepo nexus-repo -n rhdh | grep -A 10 resources + ``` + + If insufficient, update `resources/nexus/nexus-repo.yaml`: + + ```yaml + resources: + requests: + memory: 2Gi + cpu: 500m + limits: + memory: 4Gi + cpu: 2000m + ``` + +2. **Check namespace quotas:** + + ```bash + oc get resourcequota -n rhdh + oc describe resourcequota -n rhdh + ``` + +3. **Check storage:** + + ```bash + # If using PVC (not ephemeral) + oc get pvc -n rhdh + oc describe pvc nexus-pvc -n rhdh + ``` + +4. **Check operator logs:** + ```bash + oc logs -n rhdh -l app=nxrm-operator --tail=200 + ``` + +### Nexus Pod is CrashLooping + +**Symptoms:** + +- Pod restarts repeatedly +- Status shows `CrashLoopBackOff` + +**Diagnosis:** + +```bash +# Get pod name +NEXUS_POD=$(oc get pods -n rhdh -l app=nexus-repo -o name) + +# Check recent logs +oc logs ${NEXUS_POD} -n rhdh --tail=100 + +# Check previous container logs +oc logs ${NEXUS_POD} -n rhdh --previous --tail=100 + +# Check events +oc get events -n rhdh --sort-by='.lastTimestamp' | grep nexus +``` + +**Common Causes & Solutions:** + +1. **Out of Memory:** + + ``` + Error: java.lang.OutOfMemoryError: Java heap space + ``` + + **Solution:** Increase memory in nexus-repo.yaml + +2. **Permissions Issue:** + + ``` + Error: Permission denied + ``` + + **Solution:** Check securityContext settings + + ```yaml + securityContext: + fsGroup: 200 + runAsUser: 200 + ``` + +3. **Port Conflict:** + ``` + Error: Address already in use + ``` + **Solution:** Check for service conflicts + ```bash + oc get svc -n rhdh | grep 8081 + ``` + +### Nexus is Slow to Start + +**Symptoms:** + +- Pod is running but Nexus UI not accessible +- Takes > 5 minutes to become ready + +**This is Normal:** + +- Nexus typically takes 2-3 minutes for initial startup +- First-time initialization can take up to 5 minutes + +**Check Progress:** + +```bash +# Watch pod logs for startup messages +oc logs -n rhdh -l app=nexus-repo -f | grep "Started Sonatype Nexus" + +# Check readiness probes +oc describe pod -n rhdh -l app=nexus-repo | grep -A 5 Readiness +``` + +**If Taking > 10 Minutes:** + +```bash +# Check for Java errors +oc logs -n rhdh -l app=nexus-repo | grep -i error + +# Check resource constraints +oc top pod -n rhdh -l app=nexus-repo +``` + +--- + +## Demo Data Issues + +### Demo Data Job Fails + +**Symptoms:** + +- Job shows "Error" or "Failed" status +- Job never completes + +**Diagnosis:** + +```bash +# Check job status +oc get job nexus-populate-demo-data -n rhdh + +# Check pod status +oc get pods -n rhdh | grep nexus-populate-demo-data + +# View logs +oc logs -n rhdh job/nexus-populate-demo-data --tail=200 +``` + +**Common Issues:** + +1. **Nexus Not Ready:** + + ``` + Error: Connection refused + ``` + + **Solution:** Job runs too early. Wait for Nexus to be fully ready: + + ```bash + oc delete job nexus-populate-demo-data -n rhdh + # Wait 2-3 minutes after Nexus pod is running + oc apply -f resources/nexus/populate-demo-data-job.yaml -n rhdh + ``` + +2. **Authentication Failed:** + + ``` + Error: 401 Unauthorized + ``` + + **Solution:** Check admin credentials: + + ```bash + oc get secret nexus-admin-credentials -n rhdh + ``` + +3. **Repository Doesn't Exist:** + + ``` + Error: 404 Not Found + ``` + + **Solution:** Repositories not initialized. Wait longer or check Nexus UI. + +4. **Network Policy Blocking:** + ``` + Error: timeout + ``` + **Solution:** Check network policies: + ```bash + oc get networkpolicy -n rhdh + ``` + +### Re-running Demo Data Job + +If job fails and you want to retry: + +```bash +# Delete failed job +oc delete job nexus-populate-demo-data -n rhdh + +# Ensure Nexus is ready +oc get nexusrepo nexus-repo -n rhdh +# Should show status: Running or Ready + +# Re-apply job +oc apply -f resources/nexus/populate-demo-data-job.yaml -n rhdh + +# Watch progress +oc logs -n rhdh job/nexus-populate-demo-data -f +``` + +### Artifacts Not Showing in Nexus UI + +**Check if artifacts were uploaded:** + +```bash +NEXUS_URL=$(oc get route nexus-repo -n rhdh -o jsonpath='{.spec.host}') +NEXUS_PASS=$(oc get secret nexus-admin-credentials -n rhdh -o jsonpath='{.data.password}' | base64 -d) + +# Check Maven artifacts +curl -u admin:${NEXUS_PASS} "https://${NEXUS_URL}/service/rest/v1/components?repository=maven-releases" | jq + +# Check npm artifacts +curl -u admin:${NEXUS_PASS} "https://${NEXUS_URL}/service/rest/v1/components?repository=npm-internal" | jq +``` + +--- + +## Plugin Integration Issues + +### Plugin Not Showing in RHDH + +**Diagnosis:** + +```bash +# Check if plugin is enabled +oc get configmap dynamic-plugins-configmap -n rhdh -o yaml | grep nexus-repository-manager + +# Check RHDH logs +RHDH_POD=$(oc get pods -n rhdh -l app=backstage -o name) +oc logs ${RHDH_POD} -n rhdh | grep -i nexus +``` + +**Solutions:** + +1. **Plugin not enabled:** Edit dynamic-plugins-configmap.yaml: + + ```yaml + - package: "@janus-idp/backstage-plugin-nexus-repository-manager" + disabled: false # Make sure this is false + ``` + +2. **Restart RHDH:** + ```bash + oc rollout restart deployment/backstage -n rhdh + oc rollout status deployment/backstage -n rhdh + ``` + +### Catalog Entities Not Appearing + +**Diagnosis:** + +```bash +# Check if ConfigMap exists +oc get configmap nexus-demo-entities-config-map -n rhdh + +# Check if it has the correct label +oc get configmap nexus-demo-entities-config-map -n rhdh -o yaml | grep backstage.io/kubernetes-id + +# Check RHDH catalog processing +RHDH_POD=$(oc get pods -n rhdh -l app=backstage -o name) +oc logs ${RHDH_POD} -n rhdh | grep -i "catalog.*entity" +``` + +**Solutions:** + +1. **Missing or incorrect label:** + + ```bash + oc label configmap nexus-demo-entities-config-map \ + backstage.io/kubernetes-id=developer-hub \ + --overwrite -n rhdh + ``` + +2. **Refresh catalog:** + - In RHDH UI: Settings → Catalog → Refresh + +3. **Check entity processing errors:** + - Navigate to RHDH UI → Settings → Catalog → Unprocessed Entities + +### Plugin Shows "No Data" or "Connection Error" + +**Check Nexus connection from RHDH:** + +1. **Verify secrets are configured:** + + ```bash + oc get secret rhdh-secrets -n rhdh -o yaml | grep NEXUS + ``` + +2. **Check app-config:** + + ```bash + oc get configmap app-config-rhdh -n rhdh -o yaml | grep -A 5 nexusRepositoryManager + ``` + +3. **Test connectivity from RHDH pod:** + ```bash + RHDH_POD=$(oc get pods -n rhdh -l app=backstage -o jsonpath='{.items[0].metadata.name}') + oc exec ${RHDH_POD} -n rhdh -- curl -v http://nexus-repo-service:8081/service/rest/v1/status + ``` + +### Annotations Not Working + +**Verify annotation format:** + +Correct format: + +```yaml +annotations: + nexus-repository-manager/repository: maven-releases + nexus-repository-manager/maven.group-id: com.example.demo + nexus-repository-manager/maven.artifact-id: hello-world-lib + nexus-repository-manager/maven.base-version: 1.0.0 +``` + +See +[official annotations documentation](https://github.com/backstage/community-plugins/blob/main/workspaces/nexus-repository-manager/plugins/nexus-repository-manager/ANNOTATIONS.md). + +--- + +## Network and Connectivity + +### Cannot Access Nexus UI + +**Diagnosis:** + +```bash +# Check route exists +oc get route nexus-repo -n rhdh + +# Check route status +oc describe route nexus-repo -n rhdh + +# Test from outside cluster +NEXUS_URL=$(oc get route nexus-repo -n rhdh -o jsonpath='{.spec.host}') +curl -v https://${NEXUS_URL} +``` + +**Solutions:** + +1. **Route not created:** Check nexus-repo.yaml has: + + ```yaml + networking: + expose: true + exposeAs: Route + ``` + +2. **TLS certificate issues:** + + ```bash + # Check certificate + echo | openssl s_client -servername ${NEXUS_URL} -connect ${NEXUS_URL}:443 2> /dev/null | openssl x509 -noout -dates + ``` + +3. **Firewall/Network policy:** + ```bash + oc get networkpolicy -n rhdh + ``` + +### Service-to-Service Communication Fails + +**Test internal connectivity:** + +```bash +# From demo data job perspective +oc run test-curl --image=curlimages/curl -n rhdh --rm -it -- curl -v http://nexus-repo-service:8081/service/rest/v1/status +``` + +**Check service:** + +```bash +oc get svc nexus-repo-service -n rhdh +oc describe svc nexus-repo-service -n rhdh +``` + +--- + +## Performance Issues + +### Nexus is Slow + +**Check resource usage:** + +```bash +# Check current usage +oc top pod -n rhdh -l app=nexus-repo + +# Check limits +oc get nexusrepo nexus-repo -n rhdh -o yaml | grep -A 10 resources +``` + +**Increase resources:** Edit nexus-repo.yaml: + +```yaml +resources: + requests: + cpu: 1000m + memory: 4Gi + limits: + cpu: 4000m + memory: 8Gi +``` + +Apply changes: + +```bash +oc apply -f resources/nexus/nexus-repo.yaml -n rhdh +# Pod will be recreated with new limits +``` + +### Storage Running Out + +**Check storage usage:** + +```bash +# If using PVC +oc get pvc -n rhdh +oc exec -n rhdh -l app=nexus-repo -- df -h /nexus-data + +# Check for ephemeral storage warnings +oc describe pod -n rhdh -l app=nexus-repo | grep -i ephemeral +``` + +**Switch to persistent storage:** See +[Nexus Advanced Configuration](nexus-advanced-config.md#persistent-storage). + +--- + +## Common Error Messages + +### "Failed to pull image" + +**Full Error:** + +``` +Failed to pull image "registry.connect.redhat.com/sonatype/nexus-repository-manager:..." +``` + +**Solution:** Ensure proper image pull secrets or use useRedHatImage: + +```yaml +spec: + useRedHatImage: true +``` + +### "NexusRepo CRD not found" + +**Error:** + +``` +no matches for kind "NexusRepo" in version "sonatype.com/v1alpha1" +``` + +**Solution:** Operator not installed or CRD not registered: + +```bash +# Check CRD +oc get crd nexusrepos.sonatype.com + +# If missing, reinstall operator +oc delete subscription nexus-operator-subscription -n rhdh +oc apply -f resources/operators/nexus-subscription.yaml -n rhdh +``` + +### "Address already in use" + +**Error:** + +``` +java.net.BindException: Address already in use +``` + +**Solution:** Port 8081 is occupied. Check for conflicts: + +```bash +oc get svc -n rhdh +oc get pods -n rhdh -o wide +``` + +### "Insufficient CPU/Memory" + +**Error:** + +``` +Insufficient cpu/memory +``` + +**Solution:** Namespace has resource quotas. Check and adjust: + +```bash +oc get resourcequota -n rhdh -o yaml +# Contact cluster admin to increase quota if needed +``` + +--- + +## Getting Help + +If issues persist: + +1. **Collect diagnostic information:** + + ```bash + # Save all relevant resources + oc get all,configmap,secret,nexusrepo -n rhdh -o yaml > nexus-diagnostics.yaml + + # Get operator logs + oc logs -n rhdh -l app=nxrm-operator --tail=500 > operator-logs.txt + + # Get Nexus logs + oc logs -n rhdh -l app=nexus-repo --tail=500 > nexus-logs.txt + + # Get demo job logs + oc logs -n rhdh job/nexus-populate-demo-data > demo-job-logs.txt + ``` + +2. **Check official documentation:** + - [Nexus Operator Docs](https://github.com/sonatype/operator-nxrm3) + - [Backstage Plugin Docs](https://github.com/backstage/community-plugins/tree/main/workspaces/nexus-repository-manager) + +3. **Search for similar issues:** + - [Nexus Operator Issues](https://github.com/sonatype/operator-nxrm3/issues) + - [Plugin Issues](https://github.com/backstage/community-plugins/issues) diff --git a/resources/catalog-entities/operators.yaml b/resources/catalog-entities/operators.yaml index 9d663d9..8b0dfd4 100644 --- a/resources/catalog-entities/operators.yaml +++ b/resources/catalog-entities/operators.yaml @@ -108,3 +108,41 @@ data: dependencyOf: component:default/backstage-plugin-tekton-workspace dependsOn: - resource:default/test-cluster + --- + # Nexus Repository Manager Operator + apiVersion: backstage.io/v1alpha1 + kind: Resource + metadata: + name: nxrm-operator + title: Nexus Repository Manager Operator + description: Operator that is used to deploy and manage Sonatype Nexus Repository Manager instances + annotations: + backstage.io/kubernetes-id: nxrm-operator + backstage.io/kubernetes-namespace: rhdh + spec: + type: operator + owner: cluster-admins + dependencyOf: component:default/janus-idp-nexus-repository-manager + dependsOn: + - resource:default/test-cluster + --- + apiVersion: backstage.io/v1alpha1 + kind: Resource + metadata: + name: nexus-repo + title: Nexus Repository Manager + description: Nexus Repository Manager instance for artifact management + annotations: + backstage.io/kubernetes-id: nexus-repo + backstage.io/kubernetes-namespace: rhdh + links: + - url: https://help.sonatype.com/repomanager3 + title: Documentation + icon: web + spec: + type: artifact-repository + lifecycle: production + owner: cluster-admins + dependencyOf: component:default/janus-idp-nexus-repository-manager + dependsOn: + - resource:default/nxrm-operator diff --git a/resources/nexus/demo-catalog-entities.yaml b/resources/nexus/demo-catalog-entities.yaml new file mode 100644 index 0000000..bb2c6ef --- /dev/null +++ b/resources/nexus/demo-catalog-entities.yaml @@ -0,0 +1,71 @@ +--- +# Demo Maven Component for Nexus Repository Manager Plugin +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: hello-world-lib + title: Hello World Library (Maven) + description: Demo Maven library showcasing Nexus Repository Manager integration with RHDH + annotations: + # Nexus Repository Manager plugin annotations + # See: https://github.com/backstage/community-plugins/blob/main/workspaces/nexus-repository-manager/plugins/nexus-repository-manager/ANNOTATIONS.md + nexus-repository-manager/repository: maven-releases + nexus-repository-manager/maven.group-id: com.example.demo + nexus-repository-manager/maven.artifact-id: hello-world-lib + nexus-repository-manager/maven.base-version: 1.0.0 + + # Backstage Kubernetes integration + backstage.io/kubernetes-id: nexus-demo-maven + + # Source code location (example) + backstage.io/source-location: url:https://github.com/example/hello-world-lib + tags: + - java + - maven + - demo + - nexus + links: + - url: https://help.sonatype.com/repomanager3/formats/maven-repositories + title: Maven Repositories Documentation + icon: docs +spec: + type: library + lifecycle: experimental + owner: group:default/guardians-of-the-galaxy + dependencyOf: + - resource:default/nexus-repo +--- +# Demo npm Component for Nexus Repository Manager Plugin +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: hello-world-npm + title: Hello World Package (npm) + description: Demo npm package showcasing Nexus Repository Manager integration with RHDH + annotations: + # Nexus Repository Manager plugin annotations + # See: https://github.com/backstage/community-plugins/blob/main/workspaces/nexus-repository-manager/plugins/nexus-repository-manager/ANNOTATIONS.md + nexus-repository-manager/repository: npm-internal + nexus-repository-manager/name: "@demo/hello-world" + nexus-repository-manager/npm.scope: "@demo" + + # Backstage Kubernetes integration + backstage.io/kubernetes-id: nexus-demo-npm + + # Source code location (example) + backstage.io/source-location: url:https://github.com/example/hello-world-npm + tags: + - nodejs + - npm + - demo + - nexus + links: + - url: https://help.sonatype.com/repomanager3/formats/npm-registry + title: npm Registry Documentation + icon: docs +spec: + type: library + lifecycle: experimental + owner: group:default/x-men + dependencyOf: + - resource:default/nexus-repo diff --git a/resources/nexus/nexus-repo.yaml b/resources/nexus/nexus-repo.yaml new file mode 100644 index 0000000..9e90ffc --- /dev/null +++ b/resources/nexus/nexus-repo.yaml @@ -0,0 +1,34 @@ +apiVersion: sonatype.com/v1alpha1 +kind: NexusRepo +metadata: + name: nexus-repo + labels: + backstage.io/kubernetes-id: nexus-repo +spec: + # Use OpenShift route for external access + useRedHatImage: true + + # Expose via OpenShift route + networking: + expose: true + exposeAs: Route + + # Nexus configuration + nexus: + # Use ephemeral storage for demo/test environments + # For production, configure persistent storage + volumeClaimTemplate: + enabled: false + + resources: + requests: + cpu: 500m + memory: 2Gi + limits: + cpu: 2000m + memory: 4Gi + + # Default admin credentials will be generated + # Retrieve from nexus-admin-credentials secret + securityContext: + runAsUser: null diff --git a/resources/nexus/populate-demo-data-job.yaml b/resources/nexus/populate-demo-data-job.yaml new file mode 100644 index 0000000..a33682b --- /dev/null +++ b/resources/nexus/populate-demo-data-job.yaml @@ -0,0 +1,172 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: nexus-populate-demo-data + labels: + backstage.io/kubernetes-id: nexus-repo +spec: + template: + spec: + serviceAccountName: rhdh-testbed-job-sa + restartPolicy: OnFailure + containers: + - name: populate-nexus + image: registry.access.redhat.com/ubi9/ubi:latest + command: + - /bin/bash + - -c + - | + set -e + + echo "Installing required tools..." + dnf install -y curl jq java-11-openjdk-devel maven nodejs npm + + # Get Nexus URL and credentials + echo "Retrieving Nexus connection details..." + NEXUS_URL="http://nexus-repo-service:8081" + NEXUS_USER="admin" + NEXUS_PASS=$(cat /var/run/secrets/nexus-credentials/password 2>/dev/null) + + if [ -z "$NEXUS_PASS" ]; then + echo "Error: Nexus admin credentials not found" + echo "The nexus-admin-credentials secret must exist" + exit 1 + fi + + # Wait for Nexus to be ready + echo "Waiting for Nexus to be ready..." + MAX_RETRIES=60 + RETRY_COUNT=0 + + until curl -sf "${NEXUS_URL}/service/rest/v1/status" >/dev/null 2>&1; do + RETRY_COUNT=$((RETRY_COUNT + 1)) + if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then + echo "Timeout waiting for Nexus to be ready" + exit 1 + fi + echo "Nexus not ready yet. Retrying in 5 seconds... (${RETRY_COUNT}/${MAX_RETRIES})" + sleep 5 + done + + echo "Nexus is ready!" + + # Wait a bit more for repositories to be initialized + sleep 10 + + # Create demo Maven artifact + echo "Creating demo Maven artifact..." + mkdir -p /tmp/demo-maven + cd /tmp/demo-maven + + cat > pom.xml << 'EOF' + + 4.0.0 + com.example.demo + hello-world-lib + 1.0.0 + jar + Hello World Demo Library + A demo library for RHDH Nexus integration + + EOF + + mkdir -p src/main/java/com/example/demo + cat > src/main/java/com/example/demo/HelloWorld.java << 'EOF' + package com.example.demo; + + public class HelloWorld { + public static String getGreeting() { + return "Hello from Nexus Repository Manager!"; + } + } + EOF + + # Build the Maven artifact + mvn clean package -DskipTests + + # Upload to Nexus using REST API (maven-releases repository) + echo "Uploading Maven artifact to Nexus..." + JAR_FILE="target/hello-world-lib-1.0.0.jar" + POM_FILE="pom.xml" + + curl -v -u "${NEXUS_USER}:${NEXUS_PASS}" \ + --upload-file "${JAR_FILE}" \ + "${NEXUS_URL}/repository/maven-releases/com/example/demo/hello-world-lib/1.0.0/hello-world-lib-1.0.0.jar" + + curl -v -u "${NEXUS_USER}:${NEXUS_PASS}" \ + --upload-file "${POM_FILE}" \ + "${NEXUS_URL}/repository/maven-releases/com/example/demo/hello-world-lib/1.0.0/hello-world-lib-1.0.0.pom" + + # Create demo npm package + echo "Creating demo npm package..." + mkdir -p /tmp/demo-npm + cd /tmp/demo-npm + + cat > package.json << 'EOF' + { + "name": "@demo/hello-world", + "version": "1.0.0", + "description": "A demo npm package for RHDH Nexus integration", + "main": "index.js", + "scripts": { + "test": "echo \"No tests\" && exit 0" + }, + "keywords": ["demo", "nexus", "rhdh"], + "author": "RHDH Demo", + "license": "Apache-2.0" + } + EOF + + cat > index.js << 'EOF' + module.exports = { + greeting: function() { + return "Hello from Nexus npm registry!"; + } + }; + EOF + + cat > README.md << 'EOF' + # Demo npm Package + + This is a demo package showcasing Nexus Repository Manager integration with RHDH. + + ## Usage + + ```javascript + const demo = require('@demo/hello-world'); + console.log(demo.greeting()); + ``` + EOF + + # Create tarball + npm pack + + # Upload to Nexus npm repository + echo "Uploading npm package to Nexus..." + TARBALL=$(ls demo-hello-world-1.0.0.tgz) + + curl -v -u "${NEXUS_USER}:${NEXUS_PASS}" \ + --upload-file "${TARBALL}" \ + "${NEXUS_URL}/repository/npm-internal/" + + echo "Demo data population completed successfully!" + echo "" + echo "Artifacts uploaded:" + echo " - Maven: com.example.demo:hello-world-lib:1.0.0" + echo " - npm: @demo/hello-world@1.0.0" + echo "" + echo "Access Nexus UI at: ${NEXUS_URL}" + echo "Username: ${NEXUS_USER}" + + volumeMounts: + - name: nexus-credentials + mountPath: /var/run/secrets/nexus-credentials + readOnly: true + volumes: + - name: nexus-credentials + secret: + secretName: nexus-admin-credentials + optional: true diff --git a/resources/operators/nexus-subscription.yaml b/resources/operators/nexus-subscription.yaml new file mode 100644 index 0000000..fd9a1ce --- /dev/null +++ b/resources/operators/nexus-subscription.yaml @@ -0,0 +1,11 @@ +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: nexus-operator-subscription + namespace: rhdh +spec: + channel: alpha + installPlanApproval: Automatic + name: nxrm-operator-certified + source: certified-operators + sourceNamespace: openshift-marketplace diff --git a/resources/rhdh/rhdh-secrets.yaml b/resources/rhdh/rhdh-secrets.yaml index 2e750b7..fe66d1e 100644 --- a/resources/rhdh/rhdh-secrets.yaml +++ b/resources/rhdh/rhdh-secrets.yaml @@ -5,17 +5,20 @@ metadata: labels: backstage.io/kubernetes-id: developer-hub data: - SIGN_IN_PAGE: '' - AUTH_SESSION_SECRET: '' - KEYCLOAK_CLIENT_ID: '' - KEYCLOAK_REALM: '' - KEYCLOAK_LOGIN_REALM: '' - KEYCLOAK_CLIENT_SECRET: '' - KEYCLOAK_BASE_URL: '' - K8S_CLUSTER_NAME: '' - K8S_CLUSTER_TOKEN: '' - K8S_CLUSTER_URL: '' - OCM_HUB_NAME: '' - OCM_HUB_URL: '' - OCM_SA_TOKEN: '' + SIGN_IN_PAGE: "" + AUTH_SESSION_SECRET: "" + KEYCLOAK_CLIENT_ID: "" + KEYCLOAK_REALM: "" + KEYCLOAK_LOGIN_REALM: "" + KEYCLOAK_CLIENT_SECRET: "" + KEYCLOAK_BASE_URL: "" + K8S_CLUSTER_NAME: "" + K8S_CLUSTER_TOKEN: "" + K8S_CLUSTER_URL: "" + OCM_HUB_NAME: "" + OCM_HUB_URL: "" + OCM_SA_TOKEN: "" + # Nexus Repository Manager (Proxy Configuration) + NEXUS_URL: "" + NEXUS_AUTH_HEADER: "" type: Opaque diff --git a/scripts/config-nexus-plugin.sh b/scripts/config-nexus-plugin.sh new file mode 100755 index 0000000..2e44cd0 --- /dev/null +++ b/scripts/config-nexus-plugin.sh @@ -0,0 +1,251 @@ +#!/bin/bash + +# ============================================================================= +# Nexus Repository Manager Plugin Configuration +# ============================================================================= +# This script deploys and configures resources required for the Nexus +# Repository Manager plugin integration with RHDH. +# ============================================================================= + +deploy_nexus() { + echo "Deploying Nexus Repository Manager Operator..." + oc apply -f $PWD/resources/operators/nexus-subscription.yaml --namespace=${NAMESPACE} +} + +deploy_nexus_resources() { + # Wait for operator to be ready + echo "Waiting for Nexus operator to become ready..." + SECONDS=0 + while true; do + STATUS=$(oc get csv --namespace=${NAMESPACE} 2>/dev/null | grep nxrm-operator | awk '{print $NF}') + + if [[ "$STATUS" == "Succeeded" ]]; then + echo "Nexus operator is ready!" + break + fi + + if [[ $SECONDS -ge $TIMEOUT ]]; then + echo "Timeout waiting for Nexus operator to become ready." + exit 1 + fi + + echo "Nexus operator not ready yet. Retrying in $INTERVAL seconds..." + sleep "$INTERVAL" + done + + # Deploy Nexus Repository Manager instance + echo "Deploying Nexus Repository Manager instance..." + oc apply -f $PWD/resources/nexus/nexus-repo.yaml --namespace=${NAMESPACE} + + # Wait for Nexus instance to be ready + echo "Waiting for Nexus instance to be ready..." + SECONDS=0 + while true; do + NEXUS_STATUS=$(oc get nexusrepo nexus-repo --namespace=${NAMESPACE} -o jsonpath='{.status.nexusStatus}' 2>/dev/null) + + if [[ "$NEXUS_STATUS" == "Running" ]] || [[ "$NEXUS_STATUS" == "Ready" ]]; then + echo "Nexus instance is ready!" + break + fi + + if [[ $SECONDS -ge $TIMEOUT ]]; then + echo "Timeout waiting for Nexus instance to become ready." + echo "Current status: ${NEXUS_STATUS}" + exit 1 + fi + + echo "Nexus instance not ready yet (status: ${NEXUS_STATUS}). Retrying in $INTERVAL seconds..." + sleep "$INTERVAL" + done +} + +config_secrets_for_nexus_plugins() { + echo "Configuring secrets for Nexus plugin..." + + # Get Nexus URL from the route + NEXUS_URL=$(oc get route nexus-repo --namespace=${NAMESPACE} -o jsonpath='{.spec.host}' 2>/dev/null) + + if [[ -z "$NEXUS_URL" ]]; then + echo "Warning: Could not retrieve Nexus URL from route. Checking service..." + NEXUS_URL="nexus-repo-service.${NAMESPACE}.svc.cluster.local:8081" + fi + + # Get admin credentials from secret (generated by operator) + NEXUS_PASSWORD=$(oc get secret nexus-admin-credentials --namespace=${NAMESPACE} -o jsonpath='{.data.password}' 2>/dev/null | base64 -d) + + if [ -z "$NEXUS_PASSWORD" ]; then + echo "Error: Nexus admin credentials not found" + echo "The nexus-admin-credentials secret must exist before running this job" + echo "This is typically created by the Nexus operator during installation" + exit 1 + fi + + NEXUS_USERNAME="admin" + + # Generate Base64-encoded auth header for proxy (frontend plugin requirement) + NEXUS_AUTH_HEADER=$(echo -n "${NEXUS_USERNAME}:${NEXUS_PASSWORD}" | base64 -w 0) + + # Ensure local secrets file exists + if [ ! -f "$PWD/resources/user-resources/rhdh-secrets.local.yaml" ]; then + echo "Creating local secrets file..." + cp $PWD/resources/rhdh/rhdh-secrets.yaml $PWD/resources/user-resources/rhdh-secrets.local.yaml + fi + + # Update secrets file with Nexus configuration + echo "Updating RHDH secrets with Nexus configuration..." + + # Add or update NEXUS_URL (include https://) + if grep -q "NEXUS_URL:" $PWD/resources/user-resources/rhdh-secrets.local.yaml; then + sed -i "s|NEXUS_URL:.*|NEXUS_URL: $(echo -n "https://$NEXUS_URL" | base64 -w 0)|g" \ + $PWD/resources/user-resources/rhdh-secrets.local.yaml + else + sed -i "/^data:/a\\ NEXUS_URL: $(echo -n "https://$NEXUS_URL" | base64 -w 0)" \ + $PWD/resources/user-resources/rhdh-secrets.local.yaml + fi + + # Add or update NEXUS_AUTH_HEADER (for proxy authentication) + if grep -q "NEXUS_AUTH_HEADER:" $PWD/resources/user-resources/rhdh-secrets.local.yaml; then + sed -i "s|NEXUS_AUTH_HEADER:.*|NEXUS_AUTH_HEADER: $(echo -n "$NEXUS_AUTH_HEADER" | base64 -w 0)|g" \ + $PWD/resources/user-resources/rhdh-secrets.local.yaml + else + sed -i "/^data:/a\\ NEXUS_AUTH_HEADER: $(echo -n "$NEXUS_AUTH_HEADER" | base64 -w 0)" \ + $PWD/resources/user-resources/rhdh-secrets.local.yaml + fi + + echo "Nexus configuration completed:" + echo " URL: https://$NEXUS_URL" + echo " Username: $NEXUS_USERNAME" + echo " Auth Header: [configured in secrets]" + echo "" + echo "NOTE: This plugin uses a frontend proxy configuration." + echo "You must add the proxy configuration to your dynamic-plugins-configmap.yaml." + echo "See docs/nexus.md for the required proxy configuration." +} + +apply_nexus_labels() { + echo "Applying Kubernetes labels for Nexus resources..." + + # Define label patterns for Nexus resources + declare -A patterns=( + ["nexus"]="backstage.io/kubernetes-id=nexus-repo" + ["nxrm-operator"]="backstage.io/kubernetes-id=nxrm-operator" + ) + + resource_types=("pods" "deployments" "replicasets" "services" "routes" "statefulsets") + + for resource in "${resource_types[@]}"; do + for pattern in "${!patterns[@]}"; do + label="${patterns[$pattern]}" + oc get "$resource" -n $NAMESPACE --no-headers -o custom-columns=":metadata.name" 2>/dev/null \ + | grep "$pattern" \ + | xargs -I {} oc label "$resource" {} "$label" --overwrite -n $NAMESPACE 2>/dev/null || true + done + done + + echo "Labels applied successfully!" +} + +populate_nexus_demo_data() { + # Check if demo data population is enabled + if [[ "${POPULATE_DEMO_DATA:-true}" == "false" ]]; then + echo "Demo data population disabled, skipping..." + return 0 + fi + + echo "Populating Nexus with demo data..." + + # Deploy the demo data job + oc apply -f $PWD/resources/nexus/populate-demo-data-job.yaml --namespace=${NAMESPACE} + + # Wait for job to complete + echo "Waiting for demo data population job to complete..." + oc wait --for=condition=complete --timeout=600s \ + job/nexus-populate-demo-data -n ${NAMESPACE} 2>/dev/null || { + echo "Warning: Demo data population job did not complete successfully." + echo "Check job logs with: oc logs -n ${NAMESPACE} job/nexus-populate-demo-data" + # Don't fail the entire setup if demo data fails + return 0 + } + + echo "Demo data population completed!" +} + +register_nexus_demo_catalog_entities() { + # Check if demo data population is enabled + if [[ "${POPULATE_DEMO_DATA:-true}" == "false" ]]; then + echo "Demo data disabled, skipping catalog entity registration..." + return 0 + fi + + echo "Registering Nexus demo catalog entities..." + + # Create ConfigMap for demo catalog entities + oc create configmap nexus-demo-entities-config-map \ + --from-file=demo-nexus-artifacts.yaml=$PWD/resources/nexus/demo-catalog-entities.yaml \ + --namespace=${NAMESPACE} \ + --dry-run=client -o yaml | oc apply -f - --namespace=${NAMESPACE} + + # Add label for Backstage to discover + oc label configmap nexus-demo-entities-config-map \ + backstage.io/kubernetes-id=developer-hub \ + --overwrite -n ${NAMESPACE} + + echo "Demo catalog entities registered!" + echo "Entities will be available in RHDH catalog:" + echo " - Component: hello-world-lib (Maven)" + echo " - Component: hello-world-npm (npm)" + echo " - System: demo-system" + echo " - Group: platform-team" +} + +uninstall_nexus() { + echo "Uninstalling Nexus Repository Manager..." + + # Delete demo catalog entities ConfigMap + oc delete configmap nexus-demo-entities-config-map --namespace=${NAMESPACE} 2>/dev/null || true + + # Delete demo data job + oc delete job nexus-populate-demo-data --namespace=${NAMESPACE} 2>/dev/null || true + + # Delete Nexus instance + oc delete nexusrepo nexus-repo --namespace=${NAMESPACE} 2>/dev/null || true + + # Wait for resources to be cleaned up + sleep 10 + + # Uninstall the operator + OPERATOR=$(oc get csv --namespace=${NAMESPACE} 2>/dev/null | grep nxrm-operator | awk '{print $1}') + if [[ -n "$OPERATOR" ]]; then + oc delete clusterserviceversion $OPERATOR --namespace=${NAMESPACE} + fi + oc delete subscription nexus-operator-subscription --namespace=${NAMESPACE} 2>/dev/null || true + + echo "Nexus Repository Manager uninstalled!" +} + +main() { + source "${PWD}/env_variables.sh" + source "${PWD}/.env" + + echo "==============================================" + echo "Configuring Nexus Repository Manager Plugin" + echo "==============================================" + + deploy_nexus + deploy_nexus_resources + config_secrets_for_nexus_plugins + apply_nexus_labels + populate_nexus_demo_data + register_nexus_demo_catalog_entities + + echo "" + echo "==============================================" + echo "Nexus Repository Manager configuration complete!" + echo "==============================================" + + exit "${OVERALL_RESULT}" +} + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main +fi From 66cd4cebb127f4a0eaadc07688da7e077e737256 Mon Sep 17 00:00:00 2001 From: Patrick Knight Date: Thu, 12 Feb 2026 21:27:30 -0500 Subject: [PATCH 7/8] Better utilize the round robin deployment patterns Signed-off-by: Patrick Knight --- config-plugins.sh | 2 +- scripts/config-nexus-plugin.sh | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/config-plugins.sh b/config-plugins.sh index 85a67c0..e027e89 100755 --- a/config-plugins.sh +++ b/config-plugins.sh @@ -46,7 +46,7 @@ declare -A CATEGORY_SETUP_FUNCTIONS=( [TEKTON]="deploy_tekon deploy_pipelines apply_tekton_labels" [OCM]="deploy_acm config_secrets_for_ocm_plugins deploy_multicluster_hub apply_ocm_labels" [3SCALE]="copy_3scale_files deploy_3scale deploy_minio deploy_3scale_resources" - [NEXUS]="deploy_nexus deploy_nexus_resources config_secrets_for_nexus_plugins apply_nexus_labels populate_nexus_demo_data register_nexus_demo_catalog_entities" + [NEXUS]="deploy_nexus wait_for_nexus_operator_and_deploy_instance wait_for_nexus_instance config_secrets_for_nexus_plugins apply_nexus_labels populate_nexus_demo_data register_nexus_demo_catalog_entities" [KUBERNETES]="config_secrets_for_kubernetes_plugins" ) diff --git a/scripts/config-nexus-plugin.sh b/scripts/config-nexus-plugin.sh index 2e44cd0..36af286 100755 --- a/scripts/config-nexus-plugin.sh +++ b/scripts/config-nexus-plugin.sh @@ -12,7 +12,7 @@ deploy_nexus() { oc apply -f $PWD/resources/operators/nexus-subscription.yaml --namespace=${NAMESPACE} } -deploy_nexus_resources() { +wait_for_nexus_operator_and_deploy_instance() { # Wait for operator to be ready echo "Waiting for Nexus operator to become ready..." SECONDS=0 @@ -33,10 +33,12 @@ deploy_nexus_resources() { sleep "$INTERVAL" done - # Deploy Nexus Repository Manager instance + # Deploy Nexus Repository Manager instance (immediately after operator is ready) echo "Deploying Nexus Repository Manager instance..." oc apply -f $PWD/resources/nexus/nexus-repo.yaml --namespace=${NAMESPACE} +} +wait_for_nexus_instance() { # Wait for Nexus instance to be ready echo "Waiting for Nexus instance to be ready..." SECONDS=0 @@ -232,7 +234,8 @@ main() { echo "==============================================" deploy_nexus - deploy_nexus_resources + wait_for_nexus_operator_and_deploy_instance + wait_for_nexus_instance config_secrets_for_nexus_plugins apply_nexus_labels populate_nexus_demo_data From e7ef377bdf45f9ff92f9c2ba1c3856546d690ce5 Mon Sep 17 00:00:00 2001 From: Patrick Knight Date: Mon, 16 Feb 2026 08:53:42 -0500 Subject: [PATCH 8/8] Ignore shellcheck warnings for variables set within yaml files Signed-off-by: Patrick Knight --- scripts/config-3scale-plugin.sh | 1 + scripts/config-keycloak-plugin.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/config-3scale-plugin.sh b/scripts/config-3scale-plugin.sh index a2f8dfa..2eecb3b 100644 --- a/scripts/config-3scale-plugin.sh +++ b/scripts/config-3scale-plugin.sh @@ -46,6 +46,7 @@ deploy_minio() { deploy_3scale_resources() { set -a + # shellcheck disable=SC2034 ROUTER_BASE=$(oc get ingress.config.openshift.io/cluster -o=jsonpath='{.spec.domain}') set +a diff --git a/scripts/config-keycloak-plugin.sh b/scripts/config-keycloak-plugin.sh index 490c6fb..93a19b2 100644 --- a/scripts/config-keycloak-plugin.sh +++ b/scripts/config-keycloak-plugin.sh @@ -153,6 +153,7 @@ create_users_and_groups_keycloak() { fi set -a + # shellcheck disable=SC2034 USER_CREDENTIALS=$(tr -cd '[:alnum:]'