Con­fig­ure Nexus with Pulumi: A Step-by-Step Guide



In this blog post, we’ll explore how to use Pulumi and the Ter­ra­form Nexus Pro­vider to con­fig­ure and man­age Son­a­type Nexus, a power­ful tool for man­aging and gov­ern­ing the flow of soft­ware com­pon­ents through­out the devel­op­ment life­cycle. We’ll take a step-by-step approach, cov­er­ing everything from installing and con­fig­ur­ing Pulumi to defin­ing and deploy­ing Nexus resources. By the end of this post, you’ll have a solid under­stand­ing of how to lever­age Infra­struc­ture as Code (IaC) to auto­mate your Nexus configuration.

Tools

Ter­ra­form Nexus Provider:

The first com­mit of the Synvert Datadrivers Nexus Pro­vider for Ter­ra­form was pushed on Janu­ary, 10th 2020. What was meant to be a purely internal pro­ject is now used by many indi­vidu­als glob­ally, expect­ing to reach two mil­lion down­loads in 2025. The pro­vider is a plu­gin which enables us to describe the desired con­fig­ur­a­tion of our Nexus in Terraform’s nat­ive lan­guage called Hashicorp Con­fig­ur­a­tion Lan­guage (HCL). Without it, Ter­ra­form would not know how to map Cre­ate, Read, Update and Delete oper­a­tions (CRUD) to the Nexus API.

Ter­ra­form / OpenTofu:

For quite some time, Ter­ra­form was seen as the de facto industry stand­ard for declar­at­ive con­fig­ur­a­tion and infra­struc­ture man­age­ment.
OpenTofu is a com­munity pro­ject based on the ori­ginal Ter­ra­form code­base that was forked prior to Hashicorps announce­ment to adopt the BSL license.

Pulumi:

Like Ter­ra­form, Pulumi is a Soft­ware to describe and man­age IaC. What’s unique to Pulumi, is that you can choose the pro­gram­ming lan­guage of your choice for this task and not have to bother with HCL.

Pulumi’s Any Ter­ra­form Provider:

In August 2024 Pulumi announced a new fea­ture which enables it’s users to use any Ter­ra­form or OpenTofu Pro­vider without the neces­sity to bridge a Ter­ra­form Pro­vider to Pulumi in order to make use of it.

How To

Setup Nexus

If you don’t have a run­ning Nexus install­a­tion at hand, which you can use to go through the next steps, you can use our devel­op­ment setup from this link.
This will setup Nexus in your Docker envir­on­ment, thus you need to have Docker and Docker Com­pose run­ning and configured.

git clone https://github.com/datadrivers/terraform-provider-nexus.git
cd terraform-provider-nexus/scripts
source .env
./start-services.sh
# It might take a minute or two to setup Nexus
# Use curl to check if the setup is completed
curl localhost:8081
Execute start-services.sh and wait for Nexus to be up and running
Fig­ure 1: Execute start-services.sh and wait for Nexus to be up and running

Install Pulumi

Pulumi is avail­able for Linux, macOS and Win­dows and can be installed by down­load­ing the respect­ive bin­ary from the Pulumi web­site or by using your favor­ite pack­age man­ager. If you are on macOS and have brew installed, installing Pulumi is as simple as:

brew install pulumi

Cre­ate a work­ing dir­ect­ory and setup a Pulumi project

Once you have Pulumi installed, open a ter­minal and execute the fol­low­ing com­mands to setup the basic scaffold:

mkdir nexus-pulumi
cd nexus-pulumi
pulumi new python -g
  • mkdir cre­ates a new dir­ect­ory and cd switches into it,
  • The new sub­com­mand instructs Pulumi to setup a new pro­ject in the cur­rent work­ing dir­ect­ory sup­port­ing the Python pro­gram­ming lan­guage and the -g flag tells Pulumi to only gen­er­ate the scaf­fold, without a Pulumi stack or the install­a­tion of any depend­en­cies, as this will be done in the fol­low­ing steps. The com­mand prompts for three inputs:
    - Pro­ject name,
    - Pro­ject descrip­tion and
    - Tool­chain for the depend­ency man­age­ment. (Select pip in case you are unsure)
Example output of the pulumi new command
Fig­ure 2: Example out­put of the pulumi new command

Con­fig­ure Pulumi to use the Any Ter­ra­form Pro­vider with the Nexus Provider

pulumi package add terraform-provider datadrivers/nexus
pulumi install
pulumi login --local
pulumi stack init
pulumi config set nexus:url "http://127.0.0.1:8081"

This is where the magic hap­pens. The first com­mand does a couple things: First it instructs Pulumi to set up a new vir­tualenv for Python and then it down­loads the Any Ter­ra­form Pro­vider from the Pulumi Registry. This Pro­vider is then con­figured to be used with the Ter­ra­form Nexus Pro­vider. This Con­fig­ur­a­tion res­ults in a Nexus SDK which is loc­ated under­neath the “sdks” folder in the cur­rent work­ing dir­ect­ory.
In order to cre­ate Resources in your Nexus install­a­tion you need to point the Nexus Pro­vider to cor­rect URL, this can be achieved using the con­fig sub­com­mand as shown in the last com­mand above.

Cre­ate Nexus Resources using Pulumi

Depend­ing on the lan­guage that has been selec­ted with the pulumi new com­mand, Pulumi also cre­ates a main source file on your behalf. In case of Python it is called __main__.py. This file can be fur­ther mod­i­fied to cre­ate a Nexus Blob­store and a Yum Repos­it­ory like so:

"""A Python Pulumi program"""

import pulumi
import pulumi_nexus as nexus

yum_blob_store = nexus.BlobstoreFile(
"yum_blob_store",
path="/yum_blob_store",
)

yum_repo = nexus.RepositoryYumHosted(
"yum_repo",
name="YumRepository",
storage={
"blob_store_name": yum_blob_store.name,
"strict_content_type_validation": True
},
)

We can break this file up into two parts.

  1. Depend­ency Management:
import pulumi
import pulumi_nexus as nexus

The first line imports gen­eral Pulumi depend­en­cies and the second line cre­ates a new Python object named nexus that holds all the meth­ods that we pro­grammed into the Nexus Ter­ra­form Provider.

2. Nexus Configuration:

yum_blob_store = nexus.BlobstoreFile(
"yum_blob_store",
path="/yum_blob_store",
)

yum_repo = nexus.RepositoryYumHosted(
"yum_repo",
name="YumRepository",
storage={
"blob_store_name": yum_blob_store.name,
"strict_content_type_validation": True
},
)

Among oth­ers the nexus object con­tains two methods:

  • Blob­store­File and
  • Repos­it­oryY­um­Hos­ted

Using this meth­ods, we first define a Blob­store named “yum_blob_store” and then a Yum Repos­it­ory named “Yum­Re­pos­it­ory”.
You can now save this file and execute the command:

pulumi up

You should get an out­put sim­ilar to the following:

Output of pulumi up command
Fig­ure 3: Out­put of pulumi up command

If you select yes, Pulumi checks your code and cre­ates the described Resources respect­ing the con­figured order. What that means, is that the blob­store is cre­ated before the Yum Repos­it­ory. You should see some­thing sim­ilar to this:

Final Output of pulumi up command
Fig­ure 4: Final Out­put of pulumi up command

Finally, look­ing at the Nexus Web-UI (http://127.0.0.1:8081), we can see that a new Repos­it­ory has been created.

New Nexus Yum Repository has been created by Pulumi
Fig­ure 5: New Nexus Yum Repos­it­ory has been cre­ated by Pulumi

Final words of caution

At the time of writ­ing (Feb­ru­ary, 21st 2025) the Any Ter­ra­form Pro­vider is still in pub­lic beta.

A com­plete life­cycle man­age­ment of resources should also include the destruc­tion of such resources. This is what the pulumi des­troy com­mand is for. But for unknown reas­ons the destruc­tion of the resources fails:

Pulumi fails to destroy the Resources.
Fig­ure 6: Pulumi fails to des­troy the Resources.

This excep­tion does not occur when using the Nexus Ter­ra­form Pro­vider with Ter­ra­form, thus I sus­pect it to be some­how related to the Any Ter­ra­form Pro­vider by Pulumi and the way it is bridging the CRUD oper­a­tions from Python to Golang. This is a known issue, which should have been resolved with v0.7.0. But I still run in to this behavior.

Nev­er­the­less, this looks like a very prom­ising fea­ture as it enables devel­op­ment teams to setup their own infra­struc­ture using the pro­gram­ming lan­guages they are most famil­iar with.