Skip to content

CICD integration🔗

All relevant steps for creating and releasing new versions of SFH apps are accessible via the platforms API.

That makes it possible to control the lifecycle of an app version via CICD pipelines in gitlab, azure devops, etc.

There are multiple examples of successful integrations into cicd pipelines. To get working templates fitting your existing CICD infrastructre contact the SFH dev team.

Obtaining tokens from keyloak🔗

Currently no long lasting API tokens are available. Tokens must be obtained from keycloak via the token route before using the API.

Only users which authenticate via password, can obtain a token via the token route. Users authenticating via OIDC (e.g. TRUMPF IDM) can't be used. Therefore either create a user via the Register form or request one the SFH dev team.

The user must of course have the relevant roles for the apps it has to access.

curl --location 'https://keycloak.smartfactoryhost.com/realms/SFH/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=commandline-client' \
--data-urlencode 'username=exampleuser' \
--data-urlencode 'password=examplepassword' \
--data-urlencode 'grant_type=password'
{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJtQWVkdFMyazVtMFpXblExYm4wbGR5a2dacHlLRkt6QWRpZ1M3V1VDelk4In0.eyJleHAiOjE3MDQyODc4MTMsImlhdCI6MTcwNDI4NjAxMywianRpIjoiNzM2OWZkNzEtYTEzMi00MjU4LWJhM2UtNjY2Yjg2ZDlkNzMxIiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5zZmgtZGV2LmF2YWFwZ2guZGUvcmVhbG1zL1NGSC1EZW1vIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6ImE2YmFjMjE2LTFiZDQtNDQ2Ni05NzJjLTllMGQ2NTdjODZlYiIsInR5cCI6IkJlYXJlciIsImF6cCI6InBvc3RtYW4tY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjdlYTkyZWNlLWNkMGItNGZmNS1iNmYzLTE5MzVjOWY5MDBlYyIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIiwiZGVmYXVsdC1yb2xlcy1zZmgtZGVtbyJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJzaWQiOiI3ZWE5MmVjZS1jZDBiLTRmZjUtYjZmMy0xOTM1YzlmOTAwZWMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZ3JvdXBzIjpbXSwicHJlZmVycmVkX3VzZXJuYW1lIjoidGVzdEB0ZXN0LmRlIiwiZ2l2ZW5fbmFtZSI6IiIsImZhbWlseV9uYW1lIjoiIiwiZW1haWwiOiJ0ZXN0QHRlc3QuZGUifQ.PmyYmSb1yJzkG3wr9K6Hb5s3ef8YSLksvNP0APtKf1yotdxCwAD7rR-AmpB9ONLpEac5YXApWIoRCyhXyO0K85q1eaUVEI--3vQwfN0TNFEnE0wSP1bzuBPAOvJGxooPoXi9M8OqQsufbjJn3LyCc4PtU8bqnhrY8JcD7mVvptEZqSjidr2hsP7Dpvwd0p8S7K5u-uAc6Ny5RfN1YGbsB3wXhOQF0r0jJLVRN6u3f7UtQBy1WdIDEjPs1fADdAgwP2xJwva7hKRM6-SxHLZ2Twi4xuWTz6cxtZLzch9Omu0gxle5yhyl1h9rSlMncOm-DAMo9Y5z2Vy83AWxpUx_BA",
    "expires_in": 1799,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI5OGJjMDc4Zi0zMTc2LTRlOWMtYTdkMi0wMGE1MjM3NWFlMGMifQ.eyJleHAiOjE3MDQyODc4MTQsImlhdCI6MTcwNDI4NjAxNCwianRpIjoiMmZmMjJjNDktYmNmOC00YTAwLTk5NWMtMzZlZmQyNGYyMDMwIiwiaXNzIjoiaHR0cHM6Ly9rZXljbG9hay5zZmgtZGV2LmF2YWFwZ2guZGUvcmVhbG1zL1NGSC1EZW1vIiwiYXVkIjoiaHR0cHM6Ly9rZXljbG9hay5zZmgtZGV2LmF2YWFwZ2guZGUvcmVhbG1zL1NGSC1EZW1vIiwic3ViIjoiYTZiYWMyMTYtMWJkNC00NDY2LTk3MmMtOWUwZDY1N2M4NmViIiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InBvc3RtYW4tY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6IjdlYTkyZWNlLWNkMGItNGZmNS1iNmYzLTE5MzVjOWY5MDBlYyIsInNjb3BlIjoiZW1haWwgcHJvZmlsZSIsInNpZCI6IjdlYTkyZWNlLWNkMGItNGZmNS1iNmYzLTE5MzVjOWY5MDBlYyJ9.pwKjitW1KCn0qpo-AAN90NrVZO9JAdQWIsaJZhVo8Mg",
    "token_type": "Bearer",
    "not-before-policy": 0,
    "session_state": "7ea92ece-cd0b-4ff5-b6f3-1935c9f900ec",
    "scope": "email profile"
}

Then just use the access_token prefixed by Bearer in the Authentication header, when accessing the platforms API.

Creating new AppVersions🔗

A typical job is to create new AppVersions for SFH Apps, whenever new versions of the underlying container are created.

These steps have to be done:

  1. Generate an AppDefinition
  2. Create a new AppVersion based on the AppDefinition from before
  3. Push the images to harbor
  4. Optionally: release the AppVersion to testing
  5. Optionally: deploy the AppVersion to specific SFH for dev testing purposes

Generate AppDefinition🔗

Best practice is to have a template for the appdefinition in your project's repository and let the pipeline apply the versions for the containers and the appversion on the template. For this, the tools jq or sed can be used.

Example:

{
    "semver": "",
    "changelog": "",
    "definition": {
        "definitionVersion": "1.0.0",
        "containers": [
            {
                "image": "test",
                "tag": "left-empty",
                "name": "test",
                "resources": {
                    "requests": {
                        "memory": "500Mi",
                        "cpu": "100m"
                    },
                    "limits": {
                        "memory": "500Mi"
                    }
                },

            }
        ],
    }
}
cat template.json | jq --arg semVer "$versionFromPipeline" --arg changeLogText "$CHANGELOGCONTENT" -c '.semver = $semVer | .changelog = $changeLogText | .definition.containers[0].tag = $semVer' > generatedappdefinition.json

Create AppVersion🔗

# get token
response=$(curl -s --location --request POST 'https://keycloak.smartfactoryhost.com/realms/SFH/protocol/openid-connect/token' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'client_id=commandline-client' \
    --data-urlencode "username=exampleuser" \
    --data-urlencode "password=examplepassword" \
    --data-urlencode 'grant_type=password')
token=$(echo $response | jq -r .access_token)


content=$(cat generatedappdefinition.json)
response=$(curl -s --location --request $request "https://api.smartfactoryhost.com/api/v1/apps/$APP_ID/versions" \
    --header "Authorization: Bearer $token" \
    --header 'Content-Type: application/json' \
    --data-raw "$content")

Push image🔗

For pushing the image to harbor, you will need to get the registry secret by logging into harbor. Details here: Upload Container images

# get information about app by its App ID with token from before
response=$(curl -s --location --request GET "https://api.smartfactoryhost.com/api/v1/apps/$APP_ID" \
    --header "Authorization: Bearer $token" \
    --header 'Content-Type: application/json')
title=$(echo $response | jq -r .title)
registry=$(echo $response | jq -r .registry)
project=$(echo $response | jq -r .project)

docker login -u $exampleuser -p $registrysecret $registry
docker tag mytestimage:$versionFromPipeline $registry/$project/test:$versionFromPipeline
docker push $registry/$project/test:$versionFromPipeline

Futher Automation🔗

Next steps in the automation are highly dependent on your processes.

All of the API functionality can be found here: API Specification

Testing🔗

Depending on your current stage of development, testing environments may look totally different.

Three options are detailed here.

Docker Compose🔗

The most basic way for testing is a docker compose environment. It gives the highest flexibility but acts mostly equivalent to the SFH's environment.

There are of course differences in syntax and functionality:

  • Be aware of not configuring containers by mounting config files from the host's filesystem. There is no way of replicating this on the SFH
  • The AppDefinition for SFH apps is based on the Kubernetes Syntax for defining Pods. There are important naming differences for defining the containers entrypoint and arguments:

docker-compose.yaml

services:
    web:
        image: nginx
        entrypoint: ["sh", "-c"]
        command: ["nginx", "-g", "daemon off;"]

SFH AppDefinition

{
    "definitionVersion": "1.0.0",
    "containers": {
        "image": "nginx",
        "tag": "latest",
        "name": "web",
        "resources": {
            "requests": {
                "memory": "100Mi",
                "cpu": "100m"
            },
            "limits": {
                "memory": "100Mi"
            }
        },
        "command": [
            "sh",
            "-c"
        ],
        "args": [
            "nginx",
            "-g",
            "daemon off;"
        ]
    }
}

Don't mix up command, args and entrypoint. 😉

Testing on SFHs🔗

When testing on the target environment is necessary, tests before releasing the software to (test)customers can be done in state "Testing". The appversion states are further described here: AppVersions

The appversion can be deployed manually to single SFHs via the platforms UI, on which the acting user has "SFHOwner" role.

Use ReleaseVersion with "action": "development-release" to get the AppVersion to state Testing.

Use DeployVersion to deploy this version to a single SFH.

Testing on Kubernetes🔗

The SFH is build on top of kubernetes. For really advanced users with profound kubernetes knowhow, it is possible to build their own testing environment with kuberenetes to directly SFH apps run on it.

Inside the SFH management platform there is a component called Appgenerator that takes the AppDefinition and generates a helm chart from it. This is done automatically on transition from state development to testing.

The Appgenerator can also be used via the API for authenticated users to use the helm charts outside from SFHs. This can be done with a POST call to https://api.smartfactoryhost.com/appgenerator. The body is a slightly modified AppDefinition:

{
    "definitionVersion": "1.0.0",
    "appId": 1,
    "name": "test",
    "semver": "0.0.1",
    "containers": {
        "image": "nginx",
        "tag": "latest",
        "name": "web",
        "resources": {
            "requests": {
                "memory": "100Mi",
                "cpu": "100m"
            },
            "limits": {
                "memory": "100Mi"
            }
        },
        "command": [
            "sh",
            "-c"
        ],
        "args": [
            "echo Hello, world!"
        ]
    }
}

For details about the requirements on the kubernetes environment and some undocumented special configurations in the ApPDefinition, contact the SFH dev team.