ocp Posts

Injecting Openshift Secret and Reading it as an Environment Variables in Spring Boot

In this writing, im planning to create a simple Spring Boot application but with a dynamic configuration that is going to be fetched from environment variables. Usually we are using this for securing some sensitive values such as Database credentials or endpoints.

For this scenario, im trying to make password variables as parameterized inside Spring Boot’s application.properties. Binds it with environment variables with the name of OPENSHIFT_APP_PASSWORD.

server.port=8080
server.password=${OPENSHIFT_APP_PASSWORD}

And call it from our controller,

package com.edw.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class IndexController {

    @Value("${server.password}")
    private String serverPassword;

    @GetMapping("/")
    public Map helloWorld() {
        return new HashMap() {{
            put("hello", "world");
            put("password", serverPassword);
        }};
    }
}

Dont forget setting up maven’s configuration,

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edw</groupId>
    <artifactId>ocpsecret</artifactId>
    <version>1.0-SNAPSHOT</version>

    <repositories>
        <repository>
            <id>redhat-early-access</id>
            <name>Red Hat Early Access Repository</name>
            <url>https://maven.repository.redhat.com/earlyaccess/all/</url>
        </repository>
        <repository>
            <id>redhat-ga</id>
            <name>Red Hat GA Repository</name>
            <url>https://maven.repository.redhat.com/ga/</url>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>redhat-early-access</id>
            <name>Red Hat Early Access Repository</name>
            <url>https://maven.repository.redhat.com/earlyaccess/all/</url>
        </pluginRepository>
        <pluginRepository>
            <id>redhat-ga</id>
            <name>Red Hat GA Repository</name>
            <url>https://maven.repository.redhat.com/ga/</url>
        </pluginRepository>
    </pluginRepositories>

    <properties>
        <snowdrop-bom.version>2.3.6.Final-redhat-00001</snowdrop-bom.version>
        <spring-boot.version>2.1.4.RELEASE-redhat-00001</spring-boot.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <start-class>com.edw.Main</start-class>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>dev.snowdrop</groupId>
                <artifactId>snowdrop-dependencies</artifactId>
                <version>${snowdrop-bom.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

After we commit all the code into github, we can pull them from Openshift with a simple oc command.

$ oc new-app registry.access.redhat.com/ubi8/openjdk-11~https://github.com/edwin/spring-boot-and-ocp-secret

We can create a variable as a Secret by using below oc command

$ oc create secret generic mypassword --from-literal=OPENSHIFT_APP_PASSWORD=whatever

And inject it into our application,

$ oc set env --from=secret/mypassword dc/spring-boot-and-ocp-secret

Expose our app’s endpoint,

$ oc expose service spring-boot-and-ocp-secret

And do a curl to see that variable “password” has been filled with “whatever” which comes from our OCP Secret.

$ curl -kv http://ocp-endpoint/

* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: application/json
<
{"password":"whatever","hello":"world"}

Code for this can be found on below link

https://github.com/edwin/spring-boot-and-ocp-secret

How to Solve Openshift “Failed to pull image, unauthorized: authentication required”

Just recently got an unique error, this happens when my application is pulling an image within a different Openshift namespace. In this example, im creating my application in “xyz-project” and try to pull image from “abc-project”. Here’s the complete error detail,

Failed to pull image "image-registry.openshift-image-registry.svc:5000/abc-project/image01@sha256:xxxxxxxxxxxx": 
rpc error: code = Unknown desc = Error reading manifest sha256:xxxxxxxxxxxx in 
image-registry.openshift-image-registry.svc:5000/abc-project/image01: unauthorized: authentication required

Solution for this is quite easy, actually we need to give a specific access right in order for “xyz-project” to be able to pull image from “abc-project”.

oc policy add-role-to-user system:image-puller system:serviceaccount:xyz-project:default -n abc-project

Hope it helps.

Get ImageStream Name and SHA from All DeploymentConfig within a Namespace on Openshift 4

There are times where we want to display list of DC within one Namespace, and want to see what are the images involved within it. We can do that easily by using a simple OC command like below,

oc get dc -n  <namespace> --no-headers -o template \
     --template='{{range.items}}{{.metadata.namespace}}{{"/"}}{{.metadata.name}}{{" - "}}
     {{(index .spec.template.spec.containers 0).image}}{{"\n"}}{{end}}'

Delete All Pods Within a Specific Project or Namespace in Openshift 4

Sometimes we got some pods stuck in our namespace and unable to be deleted within a specific timeframe so we need to delete them forcefully, but sometimes it becomes problematic when we have like hundreds of them. Well deleting all of them is actually quite easy, all i have to do is run below command.

oc delete pod  -n youropenshiftprojectname --grace-period=0 --force --all

How to Handle CORS in Red Hat Process Automation Manager

One feature on Red Hat Process Automation Manager (RHPAM) is the ability to provide an API endpoint which can be accessed from multiple applications. But when we call them directly from javascript within a browser, sometimes it would shows a CORS error.

Workaround is quite easy, either we add a CORS header on RHPAM API response or change call method from a browser call into server-to-server call. For this article i would go with the first approach, and that is adding a CORS header on API that RHPAM provides.

Luckily our RHPAM deployment is on top of Openshift, and by adding below key-value parameters to RHPAM kie-server’s Deployment Config is good enough to solve CORS issue.

         - name: FILTERS
           value: "AC_ALLOW_ORIGIN,AC_ALLOW_METHODS,AC_ALLOW_HEADERS,AC_ALLOW_CREDENTIALS,AC_MAX_AGE"
         - name: AC_ALLOW_ORIGIN_FILTER_RESPONSE_HEADER_NAME
           value: "Access-Control-Allow-Origin"
         - name: AC_ALLOW_ORIGIN_FILTER_RESPONSE_HEADER_VALUE
           value: "*"
         - name: AC_ALLOW_METHODS_FILTER_RESPONSE_HEADER_NAME
           value: "Access-Control-Allow-Methods"
         - name: AC_ALLOW_METHODS_FILTER_RESPONSE_HEADER_VALUE
           value: "POST,GET,OPTIONS,PUT"
         - name: AC_ALLOW_HEADERS_FILTER_RESPONSE_HEADER_NAME
           value: "Access-Control-Allow-Headers"
         - name: AC_ALLOW_HEADERS_FILTER_RESPONSE_HEADER_VALUE
           value: "*"
         - name: AC_ALLOW_CREDENTIALS_FILTER_RESPONSE_HEADER_NAME
           value: "Access-Control-Allow-Credentials"
         - name: AC_ALLOW_CREDENTIALS_FILTER_RESPONSE_HEADER_VALUE
           value: "true"
         - name: AC_MAX_AGE_FILTER_RESPONSE_HEADER_NAME
           value: "Access-Control-Max-Age"
         - name: AC_MAX_AGE_FILTER_RESPONSE_HEADER_VALUE
           value: "86400"