Sunday, September 4, 2022

OCI function in golang connecting to autonomous database over TLS

 In this post we will discuss how to connect oracle cloud infrastructure function implemented in golang connect to the autonomous database. We will configure the adb on TLS, so that we don't need the client credential wallet for connection. If we need to connect over mtls still this post will give some idea but we need to stage the client credential in the function runtime container, this I may discuss in a different post. 

1. Configure ADB for TLS

We need to enable TLS connection in the autonomous database detail page. (More details).  

a) In adb detail page under the Network section enable the access control list, here I configured the allow-only ip addresses of a particular vcn should able to connect the adb.

 b) Set Mutual TLS authentication to not required, so that TLS connection will be allowed. 

2. Create a oracle function appliaction in the same VCN, which we configured  in above step (1. a), if we wish to run the function in private subnet then few more things we need to take care, details can be found here

3. Go lang function which will connect to ADB. 

we will use godror library to connect to ADB. A standalone golang program connecting ADB will be found here, the same concept we will use to write our function code. 

/**
* @Author Pallab (pallab.rath@gmail.com)
*/

package main

import (
"context"
"database/sql"
"encoding/json"
"fmt"
"io"

fdk "github.com/fnproject/fdk-go"
_ "github.com/godror/godror"
)

func main() {
fdk.Handle(fdk.HandlerFunc(myHandler))
}

func myHandler(ctx context.Context, in io.Reader, out io.Writer) {
db_user := "<db-user>"
db_pwd := "<db-pwd>"
db_host := "<db-host>"
db_port := "<db-port>>"
db_srvc := "<db-service>"

db_details := fmt.Sprintf(`user="%s" password="%s" connectString="tcps://%s:%s/%s"`, db_user, db_pwd,
db_host, db_port, db_srvc)
db, err := sql.Open("godror", db_details)
if err != nil {
fmt.Println(err)
return
}
defer db.Close()
rows, err := db.Query("select sysdate from dual")
if err != nil {
fmt.Println("Error running query")
fmt.Println(err)
return
}
defer rows.Close()
var resData string
for rows.Next() {
rows.Scan(&resData)
}
json.NewEncoder(out).Encode(&resData)
}

In this program, we need to provide db user, pwd, host, port, and service name. we can find the host port and service name from tls connect string. The tls connection string can be found on the Database Connection page.

4. Building and publishing the above function.

To build this function we need godror dependency, and this requires gcc compile to be present in build time env. So I created my custom build environment where gcc is installed, instead of the default fnproject/go:1.15-dev build image.

a) Create the build image docker definition (gofn_build.Dockerfile)

FROM oraclelinux:8
RUN yum -y install golang && yum -y clean all && rm -rf /var/cache

Then build this image using the below command

$ docker build -f gofn_build.Dockerfile -t gofn_build .

b) Create the runtime image docker definition (gofn_runtime.Dockerfile), in the runtime container godror need oracle instant client.

FROM oraclelinux:8
WORKDIR /function
RUN curl https://download.oracle.com/otn_software/linux/instantclient/217000/oracle-instantclient-basiclite-21.7.0.0.0-1.el8.x86_64.rpm --output oracle-instantclient-basiclite-21.7.0.0.0-1.el8.x86_64.rpm
RUN yum -y install oracle-instantclient-basiclite-21.7.0.0.0-1.el8.x86_64.rpm && yum -y clean all && rm -rf /var/cache
RUN rm -f oracle-instantclient-basiclite-21.7.0.0.0-1.el8.x86_64.rpm

Then build this image using the below comman

docker build -f gofn_build.Dockerfile -t gofn_runtime

c) Create the custom Dockerfile with below content, where we use build go function in the build conatiner we just created in above steps and create a image of our runtime image and the executable function.

FROM gofn_build as build-stage
WORKDIR /function
WORKDIR /go/src/func/
ENV GO111MODULE=on
COPY . .
RUN cd /go/src/func/ && go build -o func
FROM gofn_runtime
WORKDIR /function
COPY --from=build-stage /go/src/func/func /function/
ENTRYPOINT ["./func"]

d) Finally change the func.yaml with below content

schema_version: 20180708
name: function-adb
version: 0.0.26
runtime: docker

$ fn deploy -verbose <ap-name>

Then fn deploy should do the job for us.

$ fn invoke <ap-name>
"2022-09-04T17:56:09Z"


No comments:

Post a Comment

Thanks.