The "Nexus3 as Code" project provides assets to manage Sonatype Nexus 3 as code using Terraform.
This code is based on the Nexus Provider: https://registry.terraform.io/providers/datadrivers/nexus/latest/docs
- Nexus3 as Code
- Getting Started
- Quick Make Guide
- Adding a New Project
- Configuring Maven Repositories
- Setting up Maven Staging Repositories
- Configuring Other Repository Types
- Configuring Proxies
- Advanced Configuration
- Terraform Best Practices
- Bot Management
- Troubleshooting
- Terraform: Install from HashiCorp's website
- kubectl: For Kubernetes backend state management
- jsonnet (optional): For using template-based configurations
- Access credentials: Nexus admin credentials and secretsmanager token
-
Set your environment variables in
.env.sh:export NEXUS_ENV="prod" # or "dev", "staging"
-
Source the environment:
source .env.sh -
Initialize Terraform and create workspace:
make setup
-
Plan and apply:
make plan make apply
This project uses a Makefile to simplify Terraform operations. Always use make commands instead of running terraform directly to ensure proper variable file handling, validation, and compilation.
| Command | Description | What it does |
|---|---|---|
make help |
Show all available commands | Lists all make targets with descriptions |
make setup |
Quick setup | Initializes backend and creates/selects workspace (one command) |
make init |
Initialize Terraform | Runs terraform init with correct backend config |
make select |
Select/create workspace | Selects workspace or creates if doesn't exist |
make validate |
Validate configuration | Checks Terraform syntax and configuration |
make fmt |
Format Terraform files | Auto-formats all .tf files |
make compile-jsonnet |
Compile Jsonnet to JSON | Converts .jsonnet template to .tfvars.json |
make plan |
Plan changes | Shows what will be changed (dry-run) |
make apply |
Apply changes | Applies the configuration to Nexus |
make destroy |
Destroy all resources | DANGEROUS: Destroys all managed resources |
make refresh |
Refresh state | Updates state from actual infrastructure |
make outputs |
Show outputs | Displays Terraform outputs |
make outputs-json |
Show outputs as JSON | Displays outputs in JSON format |
make status |
Show current state | Displays current Terraform state |
make clean |
Clean local files | Removes .terraform/ and lock files |
# Edit Jsonnet template
vim env/terraform.prod.tfvars.jsonnet
# Compile and plan (compile happens automatically)
make plan
# Or compile manually
make compile-jsonnetThe Makefile uses these environment variables:
| Variable | Description | Example |
|---|---|---|
NEXUS_ENV |
Target environment | prod, staging, dev |
TF_PARALLELISM |
Terraform parallelism level | 30 (default) |
JSONNET_FILE |
Source Jsonnet file | Auto-detected from $NEXUS_ENV |
TF_VAR_FILE |
Target tfvars JSON file | Auto-detected from $NEXUS_ENV |
Important: Always set NEXUS_ENV before running any make commands!
There are two approaches to adding a project: using templates (recommended) or custom configuration.
IMPORTANT: Before creating a project in Terraform, you must first configure the Helm deployment to create the necessary Persistent Volume Claim (PVC) for the project's blob store.
-
Add the project to the Nexus Helm chart repository:
- Repository: https://github.com/eclipse-cbi/sonatype-nexus
-
Update the
values.yamlfile:- File: https://github.com/eclipse-cbi/sonatype-nexus/blob/master/charts/nexus3/values.yaml
- Add your project's blob store configuration and quotas if needed to create the PVC
-
Apply the Helm changes:
# Update the Nexus deployment with the new PVC configuration ./helm-deploy-nexus3.sh <env>
-
Verify PVC creation:
# Check that the PVC was created successfully kubectl get pvc -n repo3-eclipse-org | grep <your-project>
Once the PVC is created on the cluster, you can proceed with the Terraform configuration below.
Templates provide pre-configured repository sets for common use cases. Available templates:
maven2Standard: Creates releases + snapshots repositories with auto-groupmaven2StandardWithStaging: Adds staging repository to maven2Standardmaven2StagingOnly: Only staging repositorymaven2StandardNoStrictValidation: Maven2 with permissive layout policyhelmStandard: Helm releases + stagingaptStandard: APT stable + unstable distributions
Edit env/<env>.json and add to the projects array:
{
"id": "technology.myproject",
"template": "maven2StandardWithStaging"
}This will automatically create:
myproject-maven2-releasesrepositorymyproject-maven2-snapshotsrepositorymyproject-maven2-stagingrepositorymyproject-maven2group (containing all three)- Bot user:
eclipse-myproject-bot - Roles and permissions for the project
{
"id": "technology.myproject",
"template": "maven2Standard",
"archived": true, // archived do not create bot
"shortNameOverride": "custom-name", // Override default short name
"blobstore_soft_quota_limit": 95 // specific soft quota when set above default size 50G
}{
"id": "technology.simple",
"template": "maven2Standard"
}Created Resources:
Repositories:
simple-maven2-releases- URL:
https://repo.eclipse.org/repository/simple-maven2-releases/ - Type: Maven2 (RELEASE)
- URL:
simple-maven2-snapshots- URL:
https://repo.eclipse.org/repository/simple-maven2-snapshots/ - Type: Maven2 (SNAPSHOT)
- URL:
Groups:
simple-maven2- URL:
https://repo.eclipse.org/repository/simple-maven2/ - Members: simple-maven2-releases, simple-maven2-snapshots
- URL:
Users:
eclipse-simple-bot(with credentials in the secretsmanager)
Roles & Permissions:
simple-repository-admin- View and admin permissions for all repositories
{
"id": "technology.complex",
"template": "maven2StandardWithStaging",
"blobstore_soft_quota_limit": 100
}Created Resources:
Repositories:
complex-maven2-releases- URL:
https://repo.eclipse.org/repository/complex-maven2-releases/ - Type: Maven2 (RELEASE)
- URL:
complex-maven2-snapshots- URL:
https://repo.eclipse.org/repository/complex-maven2-snapshots/ - Type: Maven2 (SNAPSHOT)
- URL:
complex-maven2-staging- URL:
https://repo.eclipse.org/repository/complex-maven2-staging/ - Type: Maven2 (MIXED)
- URL:
Groups:
complex-maven2- URL:
https://repo.eclipse.org/repository/complex-maven2/ - Members: complex-maven2-releases, complex-maven2-snapshots, complex-maven2-staging
- URL:
Blob Store:
technology-complex(with 100GB soft quota limit)
Users:
eclipse-complex-bot(with credentials in the secretsmanager)
Roles & Permissions:
complex-repository-admin- View and admin permissions for all repositories
{
"id": "automotive.tractusx",
"template": "helmStandard"
}Created Resources:
Repositories:
tractusx-helm-releases- URL:
https://repo.eclipse.org/repository/tractusx-helm-releases/ - Type: Helm
- URL:
tractusx-helm-staging- URL:
https://repo.eclipse.org/repository/tractusx-helm-staging/ - Type: Helm
- URL:
Groups:
tractusx-helm- URL:
https://repo.eclipse.org/repository/tractusx-helm/ - Members: tractusx-helm-releases, tractusx-helm-staging
- URL:
Users:
eclipse-tractusx-bot(with credentials in secretsmanager)
Roles & Permissions:
tractusx-repository-admin- View and admin permissions for all repositories
For projects with specific requirements, use the custom template:
{
"id": "technology.myproject",
"template": "custom",
"config": {
"project_id": "technology.myproject",
"repositories": [
{
"type": "maven2",
"env": "releases",
"maven": {
"version_policy": "RELEASE",
"layout_policy": "STRICT"
}
},
{
"type": "docker",
"env": "releases",
"docker": {
"http_port": 8082,
"https_port": 8443,
"force_basic_auth": true
}
}
],
"create_group_auto": true
}
}{
"id": "technology.multi",
"template": "custom",
"config": {
"project_id": "technology.multi",
"repositories": [
{ "type": "maven2", "env": "releases" },
{ "type": "maven2", "env": "snapshots" },
{ "type": "docker", "env": "releases" },
{ "type": "npm", "env": "releases" }
],
"create_group_auto": true
}
}Created Resources:
Repositories:
multi-maven2-releases- URL:
https://repo.eclipse.org/repository/multi-maven2-releases/ - Type: Maven2 (RELEASE)
- URL:
multi-maven2-snapshots- URL:
https://repo.eclipse.org/repository/multi-maven2-snapshots/ - Type: Maven2 (SNAPSHOT)
- URL:
multi-docker-releases- URL:
https://repo.eclipse.org/repository/multi-docker-releases/ - Type: Docker (requires docker login)
- URL:
multi-npm-releases- URL:
https://repo.eclipse.org/repository/multi-npm-releases/ - Type: NPM
- URL:
Groups (auto-created per type):
multi-maven2- URL:
https://repo.eclipse.org/repository/multi-maven2/ - Members: multi-maven2-releases, multi-maven2-snapshots
- URL:
multi-docker- URL:
https://repo.eclipse.org/repository/multi-docker/ - Members: multi-docker-releases
- URL:
multi-npm- URL:
https://repo.eclipse.org/repository/multi-npm/ - Members: multi-npm-releases
- URL:
Users:
eclipse-multi-bot(with credentials in secretsmanager)
Roles & Permissions:
multi-repository-admin- View and admin permissions for all repositories and types
{
"id": "technology.custom",
"template": "custom",
"config": {
"project_id": "technology.custom",
"repositories": [
{ "type": "maven2", "env": "releases" },
{ "type": "maven2", "env": "snapshots" }
],
"proxies": [
{
"type": "maven2",
"custom_name": "custom-proxy",
"remote_url": "https://custom.maven.repo/maven2/",
"proxy": {
"metadata_max_age": 60
},
"negative_cache": {
"enabled": true,
"ttl": 10
}
}
],
"create_group_auto": true
}
}Created Resources:
Repositories:
custom-maven2-releases- URL:
https://repo.eclipse.org/repository/custom-maven2-releases/ - Type: Maven2 (RELEASE)
- URL:
custom-maven2-snapshots- URL:
https://repo.eclipse.org/repository/custom-maven2-snapshots/ - Type: Maven2 (SNAPSHOT)
- URL:
Proxies:
custom-proxy-maven2-proxy- URL:
https://repo.eclipse.org/repository/custom-proxy-maven2-proxy/ - Remote:
https://custom.maven.repo/maven2/ - Cache: Metadata TTL 60min, Negative cache 10min
- URL:
Groups:
custom-maven2- URL:
https://repo.eclipse.org/repository/custom-maven2/ - Members: custom-maven2-releases, custom-maven2-snapshots
- URL:
Users:
eclipse-custom-bot(with credentials in the secretsmanager)
Roles & Permissions:
custom-repository-admin(for repositories)custom-proxy-admin(for proxies)- View and admin permissions for all repositories and proxies
Usage Example:
<!-- pom.xml -->
<repositories>
<repository>
<id>custom-maven2</id>
<url>https://repo.eclipse.org/repository/custom-maven2/</url>
</repository>
</repositories>- Default repository name:
<short-name>-<type>-<env>- Example:
myproject-maven2-releases
- Example:
- Short name extraction: Last segment of project ID
technology.nebula.nattable→nattable
- Custom names: Use
custom_nameattributes to override
Terraform Documentation: Maven Hosted | Maven Proxy | Maven Group
{
"project_id": "technology.myproject",
"repositories": [
{
"type": "maven2",
"env": "releases"
},
{
"type": "maven2",
"env": "snapshots"
}
],
"create_group_auto": true
}This creates:
myproject-maven2-releasesmyproject-maven2-snapshotsmyproject-maven2(group containing both)
{
"type": "maven2",
"env": "releases",
"maven": {
"version_policy": "RELEASE", // RELEASE, SNAPSHOT, MIXED
"layout_policy": "STRICT", // STRICT, PERMISSIVE
"content_disposition": "INLINE" // INLINE, ATTACHMENT
},
"storage": {
"blob_store_name": "custom-blob",
"strict_content_type_validation": true,
"write_policy": "ALLOW" // ALLOW, ALLOW_ONCE, DENY
}
}{
"type": "maven2",
"env": "releases",
"name": "custom-repo-name" // Overrides default naming
}Groups aggregate multiple repositories for simplified access.
Set create_group_auto: true to automatically create a group containing all project repositories:
{
"project_id": "technology.myproject",
"repositories": [
{ "type": "maven2", "env": "releases" },
{ "type": "maven2", "env": "snapshots" }
],
"create_group_auto": true
}Creates: myproject-maven2 group with both repositories.
{
"project_id": "technology.myproject",
"repositories": [
{ "type": "maven2", "env": "releases" },
{ "type": "maven2", "env": "snapshots" }
],
"groups": [
{
"type": "maven2",
"custom_name": "myproject-public",
"include_type_in_name": false,
"members": [
"myproject-maven2-releases",
"myproject-maven2-snapshots",
"maven-central-releases-proxy"
]
}
]
}Staging repositories are used for release candidate validation before promoting to production.
Use the maven2StandardWithStaging template:
{
"id": "technology.myproject",
"template": "maven2StandardWithStaging"
}Creates:
myproject-maven2-releasesmyproject-maven2-snapshotsmyproject-maven2-stagingmyproject-maven2group (containing all three)
For projects that only need staging (common for Jakarta EE projects):
{
"id": "ee4j.myproject",
"template": "maven2StagingOnly"
}Creates only:
myproject-maven2-staging
{
"project_id": "technology.myproject",
"repositories": [
{ "type": "maven2", "env": "releases" },
{ "type": "maven2", "env": "snapshots" },
{
"type": "maven2",
"env": "staging",
"maven": {
"version_policy": "MIXED", // Allows both releases and snapshots
"layout_policy": "STRICT"
}
}
],
"create_group_auto": true
}For aggregating multiple staging repositories:
{
"project_id": "ee4j",
"groups": [
{
"type": "maven2",
"custom_name": "ee4j-staging",
"include_type_in_name": false,
"members": [
"angus-maven2-staging",
"batch-maven2-staging",
"cdi-maven2-staging",
"faces-maven2-staging"
]
}
]
}In addition to Maven repositories, Nexus supports multiple repository formats for different package ecosystems.
Terraform Documentation: NPM Hosted | NPM Proxy | NPM Group
NPM repositories store Node.js packages and dependencies.
{
"project_id": "technology.myproject",
"repositories": [
{
"type": "npm",
"env": "releases"
},
{
"type": "npm",
"env": "snapshots"
}
]
}Creates:
myproject-npm-releasesmyproject-npm-snapshots
{
"type": "npm",
"env": "releases",
"storage": {
"blob_store_name": "npm-blob",
"strict_content_type_validation": true,
"write_policy": "ALLOW_ONCE"
},
"component": {
"proprietary_components": true
}
}NPM-specific options:
component.proprietary_components: Mark packages as proprietary (default: false)
Terraform Documentation: PyPI Hosted | PyPI Proxy | PyPI Group
PyPI repositories store Python packages.
{
"project_id": "technology.myproject",
"repositories": [
{
"type": "pypi",
"env": "releases"
}
]
}Creates:
myproject-pypi-releases
{
"type": "pypi",
"env": "releases",
"storage": {
"blob_store_name": "pypi-blob",
"strict_content_type_validation": true,
"write_policy": "ALLOW"
},
"component": {
"proprietary_components": false
}
}Terraform Documentation: Docker Hosted | Docker Proxy | Docker Group
Docker repositories store container images.
IMPORTANT: we won't support Docker repositories for projects, alternative options: dockerhub, GitLab container registry, ghcr.io, quay.io and later harbor.
{
"project_id": "technology.myproject",
"repositories": [
{
"type": "docker",
"env": "releases"
}
]
}Creates: myproject-docker-releases
{
"type": "docker",
"env": "releases",
"docker": {
"http_port": 8082,
"https_port": 8443,
"force_basic_auth": true,
"v1_enabled": false
},
"storage": {
"blob_store_name": "docker-blob",
"write_policy": "ALLOW"
}
}Terraform Documentation: Helm Hosted | Helm Proxy
Helm repositories store Kubernetes Helm charts.
{
"project_id": "technology.myproject",
"repositories": [
{
"type": "helm",
"env": "releases"
},
{
"type": "helm",
"env": "staging"
}
]
}Creates:
myproject-helm-releasesmyproject-helm-staging
{
"type": "helm",
"env": "releases",
"storage": {
"blob_store_name": "helm-blob",
"strict_content_type_validation": true,
"write_policy": "ALLOW_ONCE"
}
}# Add repository
helm repo add myproject https://repo.eclipse.org/repository/myproject-helm-releases/
# Update repos
helm repo update
# Install chart
helm install my-release myproject/my-chartTerraform Documentation: APT Hosted | APT Proxy
APT repositories store Debian/Ubuntu packages.
{
"project_id": "technology.myproject",
"repositories": [
{
"type": "apt",
"distribution": "stable"
},
{
"type": "apt",
"env": "dev",
"distribution": "unstable"
}
]
}Creates:
myproject-apt(for stable)myproject-apt-dev(for unstable)
{
"type": "apt",
"distribution": "stable",
"storage": {
"blob_store_name": "apt-blob",
"strict_content_type_validation": true,
"write_policy": "ALLOW"
},
"apt_signing": {
"keypair": "-----BEGIN PGP PRIVATE KEY BLOCK-----...",
"passphrase": "secret-passphrase"
},
"component": {
"proprietary_components": false
}
}APT-specific options:
| Option | Description | Required |
|---|---|---|
distribution |
Debian distribution name (e.g., stable, testing, unstable) | Yes |
apt_signing.keypair |
GPG private key for signing packages | Yes* |
apt_signing.passphrase |
Passphrase for GPG key | Yes* |
*Signing credentials are typically stored in the secretsmanager and auto-retrieved.
Important Notes:
- APT repositories require GPG signing for package integrity
- The system automatically retrieves GPG keys from the secretsmanager at path:
cbi/<project_id>/gpg
Terraform Documentation: RAW Hosted | RAW Proxy | RAW Group
RAW repositories store arbitrary files (binaries, archives, etc.).
{
"project_id": "technology.myproject",
"repositories": [
{
"type": "raw",
"env": "releases"
}
]
}Creates: myproject-raw-releases
{
"type": "raw",
"env": "releases",
"storage": {
"blob_store_name": "raw-blob",
"strict_content_type_validation": false,
"write_policy": "ALLOW"
}
}A complete project with multiple repository types:
{
"id": "technology.multiformat",
"template": "custom",
"config": {
"project_id": "technology.multiformat",
"repositories": [
{
"type": "maven2",
"env": "releases",
"maven": {
"version_policy": "RELEASE",
"layout_policy": "STRICT"
}
},
{
"type": "docker",
"env": "releases",
"docker": {
"http_port": 8090,
"force_basic_auth": true
}
},
{
"type": "npm",
"env": "releases"
},
{
"type": "pypi",
"env": "releases"
},
{
"type": "helm",
"env": "releases"
},
{
"type": "raw",
"env": "releases"
}
],
"create_group_auto": true
}
}This creates:
multiformat-maven2-releasesmultiformat-docker-releasesmultiformat-npm-releasesmultiformat-pypi-releasesmultiformat-helm-releasesmultiformat-raw-releases- Auto-generated groups per type
Terraform Documentation: Proxy resources are type-specific - see Maven Proxy, Docker Proxy, NPM Proxy, etc.
Proxies cache artifacts from external repositories.
Global proxies are shared across all projects. Configure in the global_proxies section:
{
"config": {
"global_proxies": [
{
"type": "maven2",
"custom_name": "maven-central-releases",
"include_type_in_name": false,
"remote_url": "https://repo1.maven.org/maven2/",
"maven": {
"version_policy": "RELEASE",
"layout_policy": "STRICT"
},
"storage": {
"blob_store_name": "blobs-proxy-maven2"
},
"negative_cache": {
"enabled": true,
"ttl": 10
},
"proxy": {
"content_max_age": 1440,
"metadata_max_age": 60
}
}
]
}
}Add proxies to individual projects:
{
"project_id": "technology.myproject",
"proxies": [
{
"type": "maven2",
"remote_url": "https://custom-maven-repo.com/maven2/",
"proxy": {
"content_max_age": 1440,
"metadata_max_age": 1440
},
"storage": {
"blob_store_name": "custom-blob"
}
}
]
}{
"negative_cache": {
"enabled": true,
"ttl": 10 // Minutes to cache 404 responses
},
"proxy": {
"content_max_age": 1440, // Minutes to cache content
"metadata_max_age": 60 // Minutes to cache metadata
}
}{
"type": "docker",
"custom_name": "docker-hub",
"include_type_in_name": false,
"remote_url": "https://registry-1.docker.io",
"docker": {
"force_basic_auth": true,
"v1_enabled": false
},
"docker_proxy": {
"index_type": "HUB" // HUB, REGISTRY, CUSTOM
},
"storage": {
"blob_store_name": "blobs-proxy-docker"
}
}For complex, repetitive configurations, use Jsonnet templates.
- Edit the Jsonnet file:
env/terraform.<env>.tfvars.jsonnet - Compile to JSON:
Or manually:
make compile-jsonnet
jsonnet env/terraform.prod.tfvars.jsonnet > terraform.prod.tfvars.json
Set defaults for all repositories/proxies of a specific type:
{
"config": {
"defaults": {
"repositories": {
"maven2": {
"storage": {
"blob_store_name": "default-maven-blob"
},
"maven": {
"layout_policy": "STRICT"
}
}
},
"proxies": {
"docker": {
"docker": {
"force_basic_auth": true
},
"storage": {
"blob_store_name": "default-docker-blob"
}
}
}
}
}
}Automatically collect repositories across projects:
{
"global_groups": [
{
"type": "maven2",
"custom_name": "maven2-releases",
"include_type_in_name": false,
"auto_collect": {
"env": "releases",
"type": "maven2"
},
"additional_members": ["maven-central-releases-proxy"]
}
]
}This automatically adds all maven2 repositories with env: "releases" to the group.
{
"project_id": "technology.myproject",
"repositories": [
{ "type": "maven2", "env": "releases" },
{ "type": "docker", "env": "releases" },
{ "type": "npm", "env": "releases" },
{ "type": "pypi", "env": "releases" }
]
}When renaming a project, Terraform will destroy and recreate all resources unless you manage the state.
If changing the project ID from old.project to new.project:
# List current state
make status | grep old-project
# Or directly with terraform
terraform state list | grep old-project
# Move each resource (requires direct terraform command)
terraform state mv \
'nexus_repository_maven_hosted.maven-repositories["old-project-maven2-releases"]' \
'nexus_repository_maven_hosted.maven-repositories["new-project-maven2-releases"]'
# Verify changes
make planIf resources already exist in Nexus:
# Import repository (requires direct terraform command)
terraform import \
'nexus_repository_maven_hosted.maven-repositories["project-maven2-releases"]' \
project-maven2-releases
# Verify changes
make planFor projects with many resources:
# Increase parallelism (default: 30)
TF_PARALLELISM=50 make applyTo apply changes to specific resources only:
# Target specific resources (requires direct terraform command)
# Note: Make doesn't support -target flag, use terraform directly
terraform apply -var-file=terraform.${NEXUS_ENV}.tfvars.json \
-target=module.blobstores
# Or target specific resources
terraform apply -var-file=terraform.${NEXUS_ENV}.tfvars.json \
-target='nexus_repository_maven_hosted.maven-repositories["myproject-maven2-releases"]'Always work in the correct workspace:
# List workspaces (requires direct terraform command)
terraform workspace list
# Select workspace (use make instead)
make select # Uses $NEXUS_ENV variable
# Or select manually
terraform workspace select prod
# Verify current workspace
terraform workspace showTo mark a project as archived without deleting:
{
"id": "old.project",
"template": "maven2Standard",
"archived": true
}The archived flag is metadata only and doesn't affect Terraform resources.
When changing blob stores, data must be manually migrated:
- Create new blob store (https://github.com/eclipse-cbi/sonatype-nexus)
- Update repository configuration
- Apply changes (creates new repo or updates existing)
- Manually migrate data in Nexus UI
- Delete old blob store when empty
When encountering lock issues:
# Force unlock (use with caution!) - requires direct terraform command
terraform force-unlock <lock-id>
# Verify workspace is clean
make status
# Or list resources
terraform state listWhen you have multiple related projects that need access to the same repositories but require separate bot accounts, use the shared_perms_from feature. This allows projects to share repository resources and permissions without duplicating Nexus resources.
Projects eclipse.platform and eclipse.platform.releng both need access to the same Maven repositories, but each requires its own bot account with similar permissions.
In the environment configuration file (e.g., env/<env>.json):
{
"projects": [
{
"id": "eclipse.platform.releng",
"template": "maven2StandardWithStaging",
"config": {
"project_id": "eclipse.platform.releng"
}
},
{
"id": "eclipse.platform",
"template": "custom",
"config": {
"project_id": "eclipse.platform",
"shared_perms_from": "eclipse.platform.releng"
}
}
]
}For eclipse.platform.releng (main project):
- Blobstore:
eclipse-platform-releng - Repositories:
eclipse-releng-maven2-releaseseclipse-releng-maven2-snapshotseclipse-releng-maven2-staging
- Repository group:
eclipse-releng-maven2 - Bot:
eclipse-releng-bot - Role:
releng-repository-bot-role(with permissions to all repositories)
For eclipse.platform (shared permissions project):
- Bot:
eclipse-platform-bot - Role:
platform-repository-bot-role(with same permissions as releng role) - No duplicate resources: Uses existing repositories from
eclipse.platform.releng
NOTE:
- The referenced project (specified in
shared_perms_from) must be defined before the sharing project in the configuration - Bot credentials are stored separately in Vault:
repo.eclipse.org/bot/<bot-userid> - Both bots can publish to the same repositories simultaneously
When you need to regenerate bot credentials (e.g., for security rotation or when credentials are compromised), use the force_token_update flag.
The bot password for eclipse.platform.releng needs to be regenerated and updated in Vault.
- Add force_token_update flag to your project configuration:
{
"id": "eclipse.platform.releng",
"template": "maven2StandardWithStaging",
"config": {
"project_id": "eclipse.platform.releng",
"force_token_update": true
}
}- Apply the configuration:
make applyThis will:
- Generate a new random password for the bot
- Update the bot's password in Nexus
- Store the new credentials in Vault at:
cbi/eclipse.platform.releng/repo.eclipse.org
- Remove the flag after successful update:
{
"id": "eclipse.platform.releng",
"template": "maven2StandardWithStaging",
"config": {
"project_id": "eclipse.platform.releng"
}
}- Apply again to persist the clean configuration:
make apply- Temporary Flag: The
force_token_updateflag should only be present during the credential renewal operation - Automatic Cleanup: Always remove the flag after credentials are successfully updated
- Vault Integration: New credentials are automatically stored in Vault
- Secret Protection: The
ignore_changeslifecycle rule prevents accidental credential updates - Required for Username Changes: Also use this flag when bot usernames change (e.g., after refactoring project structure)
Scenario 1: Renew Bot Password
// Step 1: Add flag
{ "id": "myproject", "template": "maven2Standard", "force_token_update": true }
// Step 2: Apply → password regenerated
// Step 3: Remove flag
{ "id": "myproject", "template": "maven2Standard" }
// Step 4: Apply → configuration cleanedScenario 2: Update Bot Username After Refactoring
If bot userid changes (e.g., from eclipse-platform-bot to eclipse-releng-bot), the Vault secret must be updated:
// Before: eclipse.platform with bot eclipse-platform-bot
// After: Renamed to eclipse.platform.releng, bot should be eclipse-releng-bot
// Step 1: Add force_token_update to trigger Vault secret update
{
"id": "eclipse.platform.releng",
"template": "maven2StandardWithStaging",
"force_token_update": true
}
// Step 2: Apply → Vault secret updated with new username
// Step 3: Remove flag and apply againThe force_token_update flag bypasses Terraform's ignore_changes protection on the Vault secret, allowing the username and other fields to be updated.
After renewal, retrieve credentials from Vault:
# Using Vault CLI
vault kv get -mount="cbi" "<project_id>/repo.eclipse.org"Cause: Terraform workspace not initialized.
Solution:
# Set environment and use make setup (recommended)
export NEXUS_ENV="prod"
source .env.sh
make setup
# Or manually with terraform
terraform workspace new prod
# or
terraform workspace select prodCause: Invalid Nexus or credentials.
Solution:
# Check environment variables
echo $VAULT_TOKEN
echo $NEXUS_URL
vaultctl status
# Re-source environment
. ./.env.shCause: Previous operation didn't complete properly.
Solution:
# Force unlock (last resort)
terraform force-unlock <lock-id>Cause: Syntax errors in .jsonnet file.
Solution:
# Test jsonnet compilation
jsonnet env/terraform.prod.tfvars.jsonnet
# Check for syntax errors
jsonnetfmt --test env/terraform.prod.tfvars.jsonnetterraform init -backend-config=./backend/backend.staging.hcl
Initializing the backend...
Initializing modules...
╷
│ Error: Backend configuration changed
│
│ A change in the backend configuration has been detected, which may require migrating existing state.
│
│ If you wish to attempt automatic migration of the state, use "terraform init -migrate-state".
│ If you wish to store the current configuration with no changes to the state, use "terraform init
│ -reconfigure".Solution: Use make setup which handles this automatically:
export NEXUS_ENV="staging"
source .env.sh
make setupOr run manually:
terraform init -reconfigure -backend-config=./backend/backend.staging.hcl# Enable debug logging
export TF_LOG=DEBUG
make apply# Show specific resource (requires direct terraform command)
terraform state show 'nexus_repository_maven_hosted.maven-repositories["myproject-maven2-releases"]'
# List all resources
terraform state list
# Get outputs
make outputs
# Or in JSON format
make outputs-json