Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions java/autonomousdb-wallet-secret-sample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Java Sample Using an Oracle Wallet as a Kubernetes Secret

In this minimalistic Java sample we show you how to use a wallet downloaded by the [Oracle Database Operator for Kubernetes](https://github.com/oracle/oracle-database-operator).

An example is also provided to use a wallet downloaded from the Cloud Console.

This microservice can also be used to validate connectivity with the database by looking at its log or issuing http requests.

## Configuration

To configure the database wallet you only need to update [src/main/k8s/app.yaml](src/main/k8s/app.yaml) to use the same secret name that you used to download the wallet with the Operator.

The key part to understand its simplicity is that the deployment file uses the same mount path that the container configures in the oracle.net.wallet_location VM parameter [src/main/docker/Dockerfile](src/main/docker/Dockerfile). You don't need to change this file if you are going to use the example's mount path.

If you want to configure a previously downloaded wallet you can just create the secret (and use the same secret name for the Pod's spec) pointing to the directory where you unzipped the wallet:

```sh
kubectl create secret generic instance-wallet --from-file=<path-to-wallets-unzipped-folder>
```
The Java microservice retrieves username, password and url also from a secret. To create it you can use the following script as an example:

```sh
kubectl create secret generic user-jdbc \
--from-literal=user='<username>' \
--from-literal=password='<password>' \
--from-literal=url='jdbc:oracle:thin:@<alias-in-tnsnames.ora>'
```
## Install, build and deploy

It is as simple as to build the maven project, create the docker image and deploy the Pod:

```sh
mvn clean install
docker build -t adb-health-check target
kubectl apply -f target/app.yaml
```

## Usage

After successsful installation you can validate first connectivity through the Pod's log:

```sh
kubectl logs pods/adb-health-check
'Database version: Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production'
'Version 19.13.0.1.0'
'Retrieveing connections: true'
```

And you can use the Pod's http listener to validate connectivity (for local tests you can just port forward a local port):

```sh
kubectl port-forward adb-health-check 8080:8080 &
curl -X GET http://localhost:8080
'{"database-version": "19.0", "database-sysdate": "2021-10-06 15:38:43"}'
```
162 changes: 162 additions & 0 deletions java/autonomousdb-wallet-secret-sample/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>adb-health-check</groupId>
<artifactId>adb-health-check</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demok8s</name>

<properties>
<package>adb-health-check</package>
<mainClass>com.oracle.healthcheck.Client</mainClass>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>${maven.compiler.source}</maven.compiler.target>
<libs.classpath.prefix>libs</libs.classpath.prefix>
<copied.libs.dir>${project.build.directory}/${libs.classpath.prefix}</copied.libs.dir>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<argLine>-Dfile.encoding=UTF-8</argLine>
<checkstyle.config.location>etc/checkstyle.xml</checkstyle.config.location>
</properties>


<build>
<finalName>${project.artifactId}</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<dependencies>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-surefire-provider</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>${libs.classpath.prefix}</classpathPrefix>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</pluginManagement>

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${copied.libs.dir}</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
<excludeScope>test</excludeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-dockerfile</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}</outputDirectory>
<resources>
<resource>
<directory>src/main/docker</directory>
<filtering>true</filtering>
<includes>
<include>Dockerfile</include>
</includes>
</resource>
<resource>
<filtering>true</filtering>
<directory>src/main/k8s</directory>
<includes>
<include>app.yaml</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<dependencies>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<version>21.3.0.0</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ucp</artifactId>
<version>21.3.0.0</version>
</dependency>
<dependency>
<groupId>com.oracle.database.ha</groupId>
<artifactId>ons</artifactId>
<version>21.3.0.0</version>
</dependency>
<dependency>
<groupId>com.oracle.database.security</groupId>
<artifactId>oraclepki</artifactId>
<version>21.3.0.0</version>
</dependency>
<dependency>
<groupId>com.oracle.database.security</groupId>
<artifactId>osdt_core</artifactId>
<version>21.3.0.0</version>
</dependency>
<dependency>
<groupId>com.oracle.database.security</groupId>
<artifactId>osdt_cert</artifactId>
<version>21.3.0.0</version>
</dependency>
</dependencies>
</project>
16 changes: 16 additions & 0 deletions java/autonomousdb-wallet-secret-sample/src/main/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM openjdk:11

RUN mkdir /app
COPY libs /app/libs
COPY ${project.artifactId}.jar /app

# The driver will look for the wallet in folder /app/wallet
# This value must match the one in the mountPath of the container
# Reference in src/main/k8s/app.yaml

CMD ["java", \
"-Doracle.net.tns_admin=/app/wallet", \
"-Doracle.net.wallet_location=/app/wallet", \
"-Doracle.jdbc.fanEnabled=false", \
"-jar", \
"/app/${project.artifactId}.jar"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
** Copyright (c) 2021 Oracle and/or its affiliates.
**
** The Universal Permissive License (UPL), Version 1.0
**
** Subject to the condition set forth below, permission is hereby granted to any
** person obtaining a copy of this software, associated documentation and/or data
** (collectively the "Software"), free of charge and under any and all copyright
** rights in the Software, and any and all patent rights owned or freely
** licensable by each licensor hereunder covering either (i) the unmodified
** Software as contributed to or provided by such licensor, or (ii) the Larger
** Works (as defined below), to deal in both
**
** (a) the Software, and
** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
** one is included with the Software (each a "Larger Work" to which the Software
** is contributed by such licensors),
**
** without restriction, including without limitation the rights to copy, create
** derivative works of, display, perform, and distribute the Software and make,
** use, sell, offer for sale, import, export, have made, and have sold the
** Software and the Larger Work(s), and to sublicense the foregoing rights on
** either these or other terms.
**
** This license is subject to the following condition:
** The above copyright notice and either this complete permission notice or at
** a minimum a reference to the UPL must be included in all copies or
** substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
** SOFTWARE.
*/

package com.oracle.healthcheck;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.net.ssl.HttpsURLConnection;

import com.sun.net.httpserver.HttpServer;

import oracle.jdbc.internal.OracleConnection;
import oracle.jdbc.pool.OracleDataSource;

public class Client {

public static void main(String[] args)
throws SQLException, IOException {

// Retrieve user credentials from environment variables.
// They are set in the Pod from a Secret in src/main/k8s/app.yaml
OracleDataSource ds = new OracleDataSource();
ds.setURL(System.getenv("url"));
ds.setUser(System.getenv("user"));
ds.setPassword(System.getenv("password"));

// Validate and log connection
OracleConnection connection = (OracleConnection) ds.getConnection();
System.out.println("Retrieving connections: " + connection.isValid(0));
System.out
.println("Database version: "
+ connection.getMetaData().getDatabaseMajorVersion() + "."
+ connection.getMetaData().getDatabaseMinorVersion());

// Start an HttpServer listening on port 8080 to send database status.
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
server.createContext("/", (httpExchange) -> {

try (OracleConnection conn = (OracleConnection) ds.getConnection();
Statement stmt = conn.createStatement()) {

// Database message: version and sysdate
ResultSet rs = stmt.executeQuery("select SYSDATE from dual");
rs.next();

String message = "{\"database-version\": \""
+ conn.getMetaData().getDatabaseMajorVersion() + "."
+ conn.getMetaData().getDatabaseMinorVersion()
+ "\", \"database-sysdate\": \"" + rs.getString(1) + "\"}";
System.out.println(message);

// Send message, status and flush
httpExchange
.sendResponseHeaders(HttpsURLConnection.HTTP_OK, message.length());
OutputStream os = httpExchange.getResponseBody();
os.write(message.getBytes());
os.close();

} catch (SQLException e) {
e.printStackTrace();
}
});

server.setExecutor(null);
server.start();
}
}
38 changes: 38 additions & 0 deletions java/autonomousdb-wallet-secret-sample/src/main/k8s/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
kind: Pod
apiVersion: v1
metadata:
name: adb-health-check
spec:
volumes:
- name: wallet
secret:
# Either the secret name of the downloaded wallet with the kubernetes operator
# TODO add link to operator
# Or the secret name holding the wallet created ad-hoc:
# kubectl create secret generic instance-wallet --from-file=<path to wallet dir>
secretName: instance-wallet
containers:
- name: adb-health-check
image: adb-health-check
imagePullPolicy: IfNotPresent
volumeMounts:
- name: wallet
# mountPath must coincide with the one selected for oracle.net.wallet_location
mountPath: "/app/wallet"
readOnly: true
env:
- name: user
valueFrom:
secretKeyRef:
name: user-jdbc
key: user
- name: password
valueFrom:
secretKeyRef:
name: user-jdbc
key: password
- name: url
valueFrom:
secretKeyRef:
name: user-jdbc
key: url