Easily run your java microservice locally with go-c8y-cli

Introduction

A recurrent question I get is how the hell can we easily run a microservice locally.
Regardless of the technology, one needs to provide the following environment variables to the microservice (given it is multitenant):

  • C8Y_BASEURL
  • C8Y_BOOTSTRAP_USER
  • C8Y_BOOTSTRAP_PASSWORD
  • C8Y_BOOTSTRAP_TENANT
  • C8Y_MICROSERVICE_ISOLATION=MULTI_TENANT
  • APPLICATION_NAME
  • APPLICATION_KEY

C8Y_URL is rather straightforward: this is your tenant URL.
C8Y_BOOTSTRAP_TENANT is also rather straightforward as getting one’s tenant Id is easy.
Now the tricky part is getting the other parameters. If you create an application or a microservice in Cumulocity UI, you will immediately see the application name and the application key.
But how the hell do you get the bootstrap user and the bootstrap password? Let’s dig into that.

Creating your application

The first thing to do is to create the application.
Basically, you will need to do that through the API… Or using go-c8y-cli!
If you’re not familiar with this wonderful tool, I urge you to get a look at its website: Cumulocity IoT CLI | Cumulocity IoT CLI (goc8ycli.netlify.app)
Now, let’s first detail the steps to create an application:

  • First, you need to create the application object itself in Cumulocity
  • While creating this application object you need to indicate this is a microservice
  • Last but not least, you need to give at least the required roles of your microservice, otherwise, your nice little microservice won’t be able to do a thing in Cumulocity
    The go-c8y-cli command to create such an app with the minimum required stuff looks like this:
        c8y applications create --name my-new-ms --type MICROSERVICE --key my-new-ms-key --data 'requiredRoles=[
                "ROLE_INVENTORY_READ",
                "ROLE_INVENTORY_ADMIN",
                "ROLE_INVENTORY_CREATE",
                "ROLE_EVENT_READ",
                "ROLE_EVENT_ADMIN",
                "ROLE_ALARM_READ",
                "ROLE_ALARM_ADMIN",
                "ROLE_IDENTITY_READ",
                "ROLE_IDENTITY_ADMIN",
                "ROLE_DEVICE_CONTROL_READ",
                "ROLE_DEVICE_CONTROL_ADMIN",
                "ROLE_MEASUREMENT_READ",
                "ROLE_MEASUREMENT_ADMIN"
        ]'

This will create a new empty microservice called my-new-ms

Enable your microservice

Next, since this is a multi-tenant microservice, you’ll need to ensure that your tenant subscribes to this microservice.
With go-c8y-cli this can be done with a simple command:

c8y microservices enable --id my-new-ms

Getting your microservice bootstrap user

Again, with go-c8y-cli this is insanely simple:

c8y microservices getBootstrapUser --id my-new-ms

Now you’ve got all you need to run any microservice locally.
But let’s focus on Java.

Running your Java microservice with one line

I will assume that you are using the Microservice SDK which is based on Spring Boot.
There are plenty of environment variables that are supported by Spring Boot, but only one that is of special interest to us here: SPRING_APPLICATION_JSON
This variable allows you to pass the whole application configuration as a JSON string to Spring Boot.
Why do we need that? Because go-c8y-cli outputs are in JSON :slight_smile:
With that we can start our microservice with just one line:

SPRING_APPLICATION_JSON=$(c8y microservices get --id my-new-ms | c8y microservices getBootstrapUser --outputTemplate="{application:{name:'my-new-ms'}, C8Y:{baseUrl:'$C8Y_HOST', bootstrap:{tenant:output.tenant, user:output.name, password:output.password}, microservice: {isolation: 'MULTI_TENANT'}}}") java -jar my-new-ms/target/my-new-ms-1.0-SNAPSHOT.jar

That’s it!
If you’re wondering, the C8Y_HOST env variable is set for you by go-c8y-cli when you set a session.

Putting everything together

Finally here is a script (for Debian/Ubuntu) that takes your application name as a parameter and will do everything for you:

  • Installs go-c8y-cli if it’s not there
  • Creates a session if none exists
  • Sets a session
  • Creates and enables the application
  • Starts the microservice
#!/usr/bin/bash
echo "Checking that go-c8y-cli is installed"
if ! c8y version 2> /dev/null ; then
	echo "go-c8y-cli will be installed"
	sudo apt-get install -y curl gnupg2 apt-transport-https
	curl https://reubenmiller.github.io/go-c8y-cli-repo/debian/PUBLIC.KEY | gpg --dearmor | sudo tee /usr/share/keyrings/go-c8y-cli-archive-keyring.gpg >/dev/null
	sudo sh -c "echo 'deb [signed-by=/usr/share/keyrings/go-c8y-cli-archive-keyring.gpg] http://reubenmiller.github.io/go-c8y-cli-repo/debian stable main' >> /etc/apt/sources.list"
	sudo apt-get update
	sudo apt-get install go-c8y-cli
fi
echo "Checking that at least a Cumulocity session exists"
if ! c8y sessions list 2> /dev/null ; then
	echo "A Cumulocity session needs to be created"
	c8y sessions create
fi
c8y sessions set
if c8y microservices get --id $1 2> /dev/null ; then
        echo "Microservice $1 exists"
else
        echo "Microservice $1 does not exist and will be created"
        c8y applications create --name $1 --type MICROSERVICE --key $1-key --data 'requiredRoles=[
                "ROLE_INVENTORY_READ",
                "ROLE_INVENTORY_ADMIN",
                "ROLE_INVENTORY_CREATE",
                "ROLE_EVENT_READ",
                "ROLE_EVENT_ADMIN",
                "ROLE_ALARM_READ",
                "ROLE_ALARM_ADMIN",
                "ROLE_IDENTITY_READ",
                "ROLE_IDENTITY_ADMIN",
                "ROLE_DEVICE_CONTROL_READ",
                "ROLE_DEVICE_CONTROL_ADMIN",
                "ROLE_MEASUREMENT_READ",
                "ROLE_MEASUREMENT_ADMIN"
        ]'
        c8y microservices enable --id $1
fi
SPRING_APPLICATION_JSON=$(c8y microservices get --id $1 | c8y microservices getBootstrapUser --outputTemplate="{application:{name:'$1'}, C8Y:{baseUrl:'$C8Y_HOST', bootstrap:{tenant:output.tenant, user:output.name, password:output.password}, microservice: {isolation: 'MULTI_TENANT'}}}") java -jar $1/target/$1-1.0-SNAPSHOT.jar

Useful links | Relevant resources

https://cumulocity.com/docs/microservice-sdk/general-aspects/#environment-variables
https://cumulocity.com/docs/microservice-sdk/java/#general-properties
Cumulocity IoT CLI (goc8ycli.netlify.app)

8 Likes

@Cyril_Poder thank you! Do you know how to do this without first building a JAR? When I try to run the project with

mvn spring-boot:run 

the mechanism you are using to provide the tenant parameters to java does not work. I get an “Illegal characters used in URL.” error.

Weird, for me it’s working perfectly fine…
I just replace the last line by:
SPRING_APPLICATION_JSON=$(c8y microservices get --id $1 | c8y microservices getBootstrapUser --outputTemplate="{server: {port: 8090}, application:{name:'$1'}, C8Y:{baseUrl:'$C8Y_HOST', bootstrap:{tenant:output.tenant, user:output.name, password:output.password}, microservice: {isolation: 'MULTI_TENANT'}}}") mvn spring-boot:run
and run the script from within the java project obviously and it works.

Thank you! Yes, I confirm that it is working now as well. The problem was caused by additional parameters I provided.