From 289e0831075e6326ef2aaba63e53e56c90b6a49b Mon Sep 17 00:00:00 2001 From: Enrico Regge Date: Thu, 10 Oct 2024 22:33:14 +0200 Subject: [PATCH 1/3] Converted the hello sample to use distroless nodejs --- hello/Dockerfile | 9 +++++++-- hello/server.js | 34 ++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/hello/Dockerfile b/hello/Dockerfile index 84e8b899b..62c65b7b9 100644 --- a/hello/Dockerfile +++ b/hello/Dockerfile @@ -1,7 +1,12 @@ -FROM icr.io/codeengine/node:22-alpine -RUN apk -U upgrade +FROM registry.access.redhat.com/ubi9/nodejs-20-minimal:latest AS build-env WORKDIR /app RUN npm init -f && npm install COPY server.js . EXPOSE 8080 CMD [ "node", "server.js" ] + +FROM gcr.io/distroless/nodejs20-debian12 +COPY --from=build-env /app /app +WORKDIR /app +EXPOSE 8080 +CMD ["server.js"] \ No newline at end of file diff --git a/hello/server.js b/hello/server.js index c2365388c..c06144a88 100644 --- a/hello/server.js +++ b/hello/server.js @@ -1,10 +1,28 @@ -const http = require('http'); +const http = require("http"); -http.createServer(function (request, response) { - target = process.env.TARGET ? process.env.TARGET : 'World' ; - msg = process.env.MSG ? process.env.MSG : 'Hello ' + target + '\n'; - response.writeHead(200, {'Content-Type': 'text/plain'}); - response.end(msg); -}).listen(8080); +http + .createServer(function (request, response) { + // + // debug endpoint, which prints all incoming headers and environment variables + if (request.url == "/debug") { + const respData = { + headers: request.headers, + url: request.url, + method: request.method, + env: process.env, + }; + response.writeHead(200, { "Content-Type": "application/json" }); + response.end(JSON.stringify(respData)); + return; + } -console.log('Server running at http://0.0.0.0:8080/'); + // + // default http endpoint, which prints a simple hello world + target = process.env.TARGET ? process.env.TARGET : "World"; + msg = process.env.MSG ? process.env.MSG : "Hello " + target + "\n"; + response.writeHead(200, { "Content-Type": "text/plain" }); + response.end(msg); + }) + .listen(8080); + +console.log("Server running at http://0.0.0.0:8080/"); From c7378e19b1a8c33ab62590032309362b3721a3b5 Mon Sep 17 00:00:00 2001 From: Enrico Regge Date: Thu, 10 Oct 2024 23:15:56 +0200 Subject: [PATCH 2/3] adjust helloworld dockerfile --- helloworld/Dockerfile | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/helloworld/Dockerfile b/helloworld/Dockerfile index 13f37e647..e5c7b0d92 100644 --- a/helloworld/Dockerfile +++ b/helloworld/Dockerfile @@ -1,10 +1,8 @@ -FROM icr.io/codeengine/golang:alpine -RUN apk -U upgrade -COPY helloworld.go / -RUN go build -ldflags '-s -w -extldflags "-static"' -o /helloworld /helloworld.go +FROM quay.io/app-sre/ubi8-go-toolset AS build-env +COPY helloworld.go . +RUN CGO_ENABLED=0 go build -o /opt/app-root/src/app helloworld.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -RUN apk -U upgrade -COPY --from=0 /helloworld /helloworld -CMD /helloworld +FROM registry.access.redhat.com/ubi9-minimal:latest +COPY --from=build-env /opt/app-root/src/app / +CMD ["/app"] From 8be9901b3f64d7543cbb6f30bd0b047e919bbc0b Mon Sep 17 00:00:00 2001 From: Enrico Regge Date: Fri, 25 Oct 2024 16:51:41 +0200 Subject: [PATCH 3/3] re-worked and tested quite some samples --- app-n-job/Dockerfile | 8 - app-n-job/README.md | 16 - app-n-job/app-n-job.go | 25 -- app-n-job/build | 19 -- app-n-job/run | 52 ---- app2job/Dockerfile.app | 14 +- app2job/Dockerfile.job | 14 +- app2job/run | 4 +- bash/Dockerfile | 25 -- bash/README.md | 39 --- bash/app | 6 - bash/build | 19 -- bash/init | 16 - bash/run | 58 ---- bash/server.go | 101 ------- bind-job/run | 2 +- cecli/Dockerfile | 21 +- cecli/cecli.go | 4 +- cecli/run | 14 +- cloudant-change-listener/Dockerfile | 15 +- cloudant-change-listener/run | 55 +++- configmaps-env/Dockerfile | 14 +- configmaps-env/run | 6 +- configmaps-vol/Dockerfile | 14 +- configmaps-vol/run | 6 +- cos-event-job/run | 8 +- cos-event/Dockerfile | 14 +- cos-event/run | 9 +- cos2cos/.DEPS | 1 - cos2cos/.SEQ | 0 cos2cos/.gitignore | 4 - cos2cos/Dockerfile | 12 - cos2cos/README.md | 72 ----- cos2cos/__init__.py | 0 cos2cos/build | 19 -- cos2cos/cos.py | 85 ------ cos2cos/cos_2_cos.py | 279 ------------------ cos2cos/run | 150 ---------- cos2cos/setup.py | 17 -- cos2cos/templates/files.html | 49 --- cos2cos/templates/history.html | 49 --- cron/Dockerfile | 14 +- cron/run | 2 +- cronjob/Dockerfile | 13 +- cronjob/run | 2 +- daemonjob/Dockerfile | 15 +- daemonjob/run | 18 +- function2job/Dockerfile | 13 +- function2job/run | 2 +- gallery/README.md | 2 +- gallery/app/Dockerfile | 13 +- gallery/job/Dockerfile | 11 +- github/Dockerfile | 14 +- github/run | 2 +- hello/Dockerfile | 5 +- .../function-codebundle-nodejs/README.md | 2 +- helloworld/Dockerfile | 12 +- helloworld/helloworld.go | 8 +- job/Dockerfile | 8 - job/README.md | 21 -- job/build | 17 -- job/job.go | 10 - job/run | 49 --- job2app/Dockerfile | 14 +- job2app/Dockerfile.app | 14 +- job2app/job.go | 10 +- job2app/run | 4 +- metrics-collector/Dockerfile | 18 +- metrics-collector/go.mod | 1 - metrics-collector/go.sum | 109 +------ private/Dockerfile.backend | 8 - private/Dockerfile.frontend | 8 - private/README.md | 20 -- private/backend.go | 19 -- private/build | 21 -- private/frontend.go | 45 --- private/run | 43 --- s2i-buildpacks/README.md | 17 -- s2i-buildpacks/package.json | 14 - s2i-buildpacks/run | 62 ---- s2i-buildpacks/server.js | 18 -- s2i-dockerfile/Dockerfile | 8 - s2i-dockerfile/README.md | 18 -- s2i-dockerfile/app.go | 16 - s2i-dockerfile/run | 61 ---- testjob/Dockerfile | 8 - testjob/README.md | 31 -- testjob/build | 17 -- testjob/run | 58 ---- testjob/testjob.go | 42 --- 90 files changed, 262 insertions(+), 2030 deletions(-) delete mode 100644 app-n-job/Dockerfile delete mode 100644 app-n-job/README.md delete mode 100644 app-n-job/app-n-job.go delete mode 100755 app-n-job/build delete mode 100755 app-n-job/run delete mode 100644 bash/Dockerfile delete mode 100644 bash/README.md delete mode 100755 bash/app delete mode 100755 bash/build delete mode 100755 bash/init delete mode 100755 bash/run delete mode 100644 bash/server.go delete mode 100644 cos2cos/.DEPS delete mode 100644 cos2cos/.SEQ delete mode 100644 cos2cos/.gitignore delete mode 100644 cos2cos/Dockerfile delete mode 100644 cos2cos/README.md delete mode 100644 cos2cos/__init__.py delete mode 100755 cos2cos/build delete mode 100644 cos2cos/cos.py delete mode 100644 cos2cos/cos_2_cos.py delete mode 100755 cos2cos/run delete mode 100644 cos2cos/setup.py delete mode 100644 cos2cos/templates/files.html delete mode 100644 cos2cos/templates/history.html delete mode 100644 job/Dockerfile delete mode 100644 job/README.md delete mode 100755 job/build delete mode 100644 job/job.go delete mode 100755 job/run delete mode 100644 private/Dockerfile.backend delete mode 100644 private/Dockerfile.frontend delete mode 100644 private/README.md delete mode 100644 private/backend.go delete mode 100755 private/build delete mode 100644 private/frontend.go delete mode 100755 private/run delete mode 100644 s2i-buildpacks/README.md delete mode 100644 s2i-buildpacks/package.json delete mode 100755 s2i-buildpacks/run delete mode 100644 s2i-buildpacks/server.js delete mode 100644 s2i-dockerfile/Dockerfile delete mode 100644 s2i-dockerfile/README.md delete mode 100644 s2i-dockerfile/app.go delete mode 100755 s2i-dockerfile/run delete mode 100644 testjob/Dockerfile delete mode 100644 testjob/README.md delete mode 100755 testjob/build delete mode 100755 testjob/run delete mode 100644 testjob/testjob.go diff --git a/app-n-job/Dockerfile b/app-n-job/Dockerfile deleted file mode 100644 index f598dc336..000000000 --- a/app-n-job/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM icr.io/codeengine/golang:alpine -COPY app-n-job.go / -RUN go build -o /app-n-job /app-n-job.go - -# Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /app-n-job /app-n-job -CMD /app-n-job diff --git a/app-n-job/README.md b/app-n-job/README.md deleted file mode 100644 index 26bcae28f..000000000 --- a/app-n-job/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# App-n-Job - -This will build an image that can be used for both Applications and Batch Jobs. -By checking for the presence of the `JOB_INDEX` environment variable, the code -will know whether to start a web service (Application) or just do its task -and exit (Batch Job). - -- - - - -As noted in [the main README](../README.md), this sample has two pieces: - -- a `build` script which will build the container image(s) used -- a `run` script which deploys resources that use those images - -The main purpose of this example is the `run` script, but the `build` -script is included for complete educational (and reuse) purposes. diff --git a/app-n-job/app-n-job.go b/app-n-job/app-n-job.go deleted file mode 100644 index 8b74b0743..000000000 --- a/app-n-job/app-n-job.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/http" - "os" -) - -func main() { - jobIndex := os.Getenv("JOB_INDEX") - - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - log.Printf("log: app-n-job got an incoming request\n") - fmt.Fprintf(w, "Hello from app-n-job! I'm a web app!\n") - }) - - if jobIndex == "" { - log.Printf("Listening on port 8080\n") - http.ListenAndServe(":8080", nil) - } else { - log.Printf("Hello from app-n-job! I'm a batch job! Index: %s\n", - jobIndex) - } -} diff --git a/app-n-job/build b/app-n-job/build deleted file mode 100755 index 5e00353c5..000000000 --- a/app-n-job/build +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Env Vars: -# REGISTRY: name of the image registry/namespace to store the images -# NOCACHE: set this to "--no-cache" to turn off the Docker build cache -# -# NOTE: to run this you MUST set the REGISTRY environment variable to -# your own image registry/namespace otherwise the `docker push` commands -# will fail due to an auth failure. Which means, you also need to be logged -# into that registry before you run it. - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} - -# Build the image -docker build ${NOCACHE} -t ${REGISTRY}/app-n-job . --platform linux/amd64 - -# And push it -docker push ${REGISTRY}/app-n-job diff --git a/app-n-job/run b/app-n-job/run deleted file mode 100755 index 79b4ab01c..000000000 --- a/app-n-job/run +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -# Env Vars: -# NUM: number of instances of the job to run -# REGISTRY: name of the image registry/namespace to get the images - -# Clean up previous run -function clean() { - set +ex - echo Cleaning... - ( - ibmcloud ce app delete -n anj-app -f - ibmcloud ce jobrun delete -n anj-job -f - rm -f out - ) > /dev/null 2>&1 -} - -clean -[[ "$1" == "clean" ]] && exit 0 - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} -export NUM=${NUM:-10} - -# First create an app based on our image -ibmcloud ce app create -n anj-app --image ${REGISTRY}/app-n-job - -# Get the URL of the app -URL=$(ibmcloud ce app get -n anj-app -o url) - -# And call it -curl -fs $URL | tee out -[[ "${PIPESTATUS[0]}" == "0" ]] - -if ! grep "Hello from.*app" out > /dev/null ; then - echo "Unexpected output" - exit 1 -fi - -# And now use the same image as a batch job - and wait to finish -ibmcloud ce jobrun submit --name anj-job --ai=1-$NUM \ - --image ${REGISTRY}/app-n-job --wait - -ibmcloud ce jobrun logs --instance anj-job-1-0 | tee out - -if ! grep "Hello from.*job" out > /dev/null ; then - echo "Missing expected outout" - exit 1 -fi - -# Clean up -clean diff --git a/app2job/Dockerfile.app b/app2job/Dockerfile.app index 64724a2f1..d849c7d51 100644 --- a/app2job/Dockerfile.app +++ b/app2job/Dockerfile.app @@ -1,8 +1,10 @@ -FROM icr.io/codeengine/golang:alpine -COPY app.go / -RUN go build -o /app /app.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY app.go . + +RUN CGO_ENABLED=0 go build -o /go/bin/app app.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /app /app -CMD /app +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / +CMD ["/app"] diff --git a/app2job/Dockerfile.job b/app2job/Dockerfile.job index 2a71dc87a..43c82d5b6 100644 --- a/app2job/Dockerfile.job +++ b/app2job/Dockerfile.job @@ -1,8 +1,10 @@ -FROM icr.io/codeengine/golang:alpine -COPY job.go / -RUN go build -o /job /job.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY job.go . + +RUN CGO_ENABLED=0 go build -o /go/bin/job job.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /job /job -CMD /job +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/job / +CMD ["/job"] diff --git a/app2job/run b/app2job/run index 7eef453af..eb894758a 100755 --- a/app2job/run +++ b/app2job/run @@ -23,13 +23,13 @@ export REGISTRY=${REGISTRY:-icr.io/codeengine} export COUNT=${COUNT:-50} # Create the app -ibmcloud ce app create -n a2j-app --image ${REGISTRY}/a2j-app +ibmcloud ce app create -n a2j-app --cpu .125 --memory 0.25G --image ${REGISTRY}/a2j-app # Get metadata about the app for later use URL=$(ibmcloud ce app get -n a2j-app -o url) # Create the job definition -ibmcloud ce job create -n a2j-job --ai=1-${COUNT} --image ${REGISTRY}/a2j-job +ibmcloud ce job create -n a2j-job --ai=1-${COUNT} --cpu .125 --memory 0.25G --image ${REGISTRY}/a2j-job # Now, curl the app and see if it creates the job curl -fs ${URL}/a2j-job -X PUT | tee out diff --git a/bash/Dockerfile b/bash/Dockerfile deleted file mode 100644 index 2003e8b00..000000000 --- a/bash/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -FROM icr.io/codeengine/golang:alpine - -COPY server.go / -RUN GO111MODULE=off go build -o /server /server.go - -FROM icr.io/codeengine/alpine - -# Upgrade the OS, install some common tools -# Install the IBM Cloud CLI and Code Engine plugin - -RUN apk update && apk upgrade && apk add bash curl jq git ncurses && \ - curl -fsSL https://clis.cloud.ibm.com/install/linux | bash && \ - ln -s /usr/local/bin/ibmcloud /usr/local/bin/ic && \ - ibmcloud plugin install cloud-object-storage && \ - ibmcloud plugin install container-registry && \ - ibmcloud plugin install code-engine - -ENV TERM=vt100 -COPY --from=0 server / - -WORKDIR /app -COPY init /app/ -COPY app /app/ - -CMD /server diff --git a/bash/README.md b/bash/README.md deleted file mode 100644 index 00ba38611..000000000 --- a/bash/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# BASH - -This sample will show how to create an application that is nothing more than -a bash script. While there is still an HTTP server as part of the solution, -you should be able to reuse the `bash` container image in other projects -without needing to do more than just provide a custom bash script. - -In this setup the follow will happen: -- during the startup of each instance of your applciation, if present, - a file named `/app/init` will be invoked. You can also set an environment - variable called `INIT` to the path of an additional program that you - want executed. The environment variable program will be called after - `/app/init`. This allows for you to execute code that you want only - run once per instance - and not on each incoming HTTP request. -- upon receiving an HTTP request, a file named `/app/app` will be invoked. - The following environment variables will be set: - - `METHOD` - the HTTP method (GET, POST,...) values - - `URL` - the URL from the HTTP request - - `HEADER_xxx` - where `xxx` is an HTTP header name, and the environment - variable's value is the HTTP headers value. All HTTP headers will appear - as environment variables. -- if `/app/app` exits with a zero exit code then an HTTP `200 OK` will be - returned. Otherwise an HTTP `503 Internal Server Error` will be returned. -- if you define an environment variable called `DEBUG` then the application - will print useful debugging information in the logs - -The `/app/init` program in this sample will log into the IBM Cloud using -an API Key provided in a secret. The `/app/app` program will invoke the -`ibmcloud ce app list` command and return the result to the client. - -- - - - -As noted in [the main README](../README.md), this sample has two pieces: - -- a `build` script which will build the container image(s) used -- a `run` script which deploys resources that use those images - -The main purpose of this example is the `run` script, but the `build` -script is included for complete educational (and reuse) purposes. diff --git a/bash/app b/bash/app deleted file mode 100755 index cbf887107..000000000 --- a/bash/app +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -# Fail is any command fails -set -e - -ibmcloud ce app list diff --git a/bash/build b/bash/build deleted file mode 100755 index a3adb7aba..000000000 --- a/bash/build +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Env Vars: -# REGISTRY: name of the image registry/namespace to store the images -# NOCACHE: set this to "--no-cache" to turn off the Docker build cache -# -# NOTE: to run this you MUST set the REGISTRY environment variable to -# your own image registry/namespace otherwise the `docker push` commands -# will fail due to an auth failure. Which means, you also need to be logged -# into that registry before you run it. - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} - -# Build the image -docker build ${NOCACHE} -t ${REGISTRY}/ce-bash . --platform linux/amd64 - -# And push it -docker push ${REGISTRY}/ce-bash diff --git a/bash/init b/bash/init deleted file mode 100755 index 412950f20..000000000 --- a/bash/init +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -# Wait until we have connectivity -while ! curl -fs ibm.com ; do true ; done - -set -ex - -REGION=$(cat /keys/REGION) -GROUP=$(cat /keys/GROUP) -PROJECT=$(cat /keys/PROJECT) - -# Login during the "init" so that we don't do it on each HTTP request -ibmcloud login -r $REGION --apikey @/keys/APIKEY -g $GROUP - -# And select our Code Engine project -ibmcloud ce project select -n $PROJECT diff --git a/bash/run b/bash/run deleted file mode 100755 index 4f0ebfce6..000000000 --- a/bash/run +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -# Env Vars: -# REGISTRY: name of the image registry/namespace to get the images - -# Clean up previous run -function clean() { - set +ex - echo Cleaning... - ( - ibmcloud ce app delete -n ce-bash -f - ibmcloud ce secret delete -n bash-keys -f - ibmcloud iam api-keys | grep bash | sed "s/.*\(ApiKey\)/\1/" | while read a - do ibmcloud iam api-key-delete -f $a - done - - rm -f out .apikey - ) > /dev/null 2>&1 -} - -clean -[[ "$1" == "clean" ]] && exit 0 - -export REGISTRY=${REGISTRY:-icr.io/codeengine} - -set -ex - -# Create an API Key so that our App can use it to talk to Code Engine -ibmcloud iam api-key-create -q bash | awk '/API Key/{ print $3 }' > .apikey - -# Create a 'secret' to hold our API Key, Project, Resource Group and Region -ibmcloud ce secret create -n bash-keys \ - --from-file APIKEY=.apikey \ - --from-literal PROJECT=$(ibmcloud ce proj current|awk '/^Name:/{print $2}') \ - --from-literal GROUP=$(ibmcloud target | awk '/Resource group:/{print $3}') \ - --from-literal REGION=$(ibmcloud target | awk '/Region:/{print $2}') - -rm .apikey # erase it since we don't need it any more - -# Create our application that will invoke: -# - "init" script upon each instance's startup -# - "app" script when an incoming request is received -# Notice we mount our "bash-keys" secret into the app at the "/keys" directory. -# Each name/value pair in the secret appears as a separate file in the dir. -ibmcloud ce app create -n ce-bash --image $REGISTRY/ce-bash \ - --mount-secret /keys=bash-keys - -# Save App's URL for later -APP=$(ibmcloud ce app get -n ce-bash -o url) - -# Call the app - if it works it should return the output of the 'app list' cmd -curl -w "\n%{http_code}\n" -fs $APP/ | tee out -[[ "${PIPESTATUS[0]}" == "0" ]] - -# Verify we see our App in the output -grep "^ce-bash.*Ready" out - -clean diff --git a/bash/server.go b/bash/server.go deleted file mode 100644 index f2ee5d53b..000000000 --- a/bash/server.go +++ /dev/null @@ -1,101 +0,0 @@ -package main - -// This program is a simple HTTP server that will do 2 things: -// 1 - invoke an "init" app (/app/init) at start-up -// 2 - invoke an "app" app (/app/app) upon each HTTP request -// See the README for more info - -import ( - "bytes" - "fmt" - "io/ioutil" - "log" - "net/http" - "os" - "os/exec" - "strings" -) - -var verbose = 1 - -func Debug(level int, msg string, args ...interface{}) { - // Note: 0 == always print - if level > verbose { - return - } - log.Printf(msg, args...) -} - -func Run(envs []string, input []byte, cmdStr string, args ...interface{}) (int, string) { - Debug(1, "Running: %s", fmt.Sprint(cmdStr)) - cmd := exec.Command("/bin/sh", "-c", fmt.Sprintf(cmdStr, args...)) - if len(envs) != 0 { - cmd.Env = os.Environ() - cmd.Env = append(cmd.Env, envs...) - } - - if input != nil { - cmd.Stdin = bytes.NewReader(input) - } else { - cmd.Stdin = nil - } - - buf, err := cmd.CombinedOutput() - if err != nil { - if len(buf) > 0 { - buf = append(buf, []byte("\n")...) - } - buf = append(buf, []byte(err.Error()+"\n")...) - Debug(2, " Error: %s", err) - } - - Debug(2, "Output:\n%s", string(buf)) - Debug(2, "Exit Code: %d", cmd.ProcessState.ExitCode()) - - return cmd.ProcessState.ExitCode(), string(buf) -} - -func main() { - if os.Getenv("DEBUG") != "" { - verbose = 2 - } - - if _, err := os.Stat("/app/init"); err == nil { - Run(nil, nil, "/app/init") - } - - if tmp := os.Getenv("INIT"); tmp != "" { - Run(nil, nil, tmp) - } - - Command := "/app/app" - if tmp := os.Getenv("APP"); tmp != "" { - Command = tmp - } - - // Our HTTP handler func - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - Debug(1, "Request: %s -> %s", r.Method, r.URL) - envs := []string{ - "METHOD=" + r.Method, - "URL=" + r.URL.Path, - } - - for k, v := range r.Header { - k = strings.ReplaceAll(k, "-", "_") - k = strings.ToUpper(k) - envs = append(envs, fmt.Sprintf("HEADER_%s=%s", k, v)) - } - - body, _ := ioutil.ReadAll(r.Body) - code, result := Run(envs, body, Command) - - if code != 0 { - w.WriteHeader(http.StatusInternalServerError) - } - fmt.Fprintf(w, result) - }) - - Debug(1, "Listening on port 8080") - http.ListenAndServe(":8080", nil) -} diff --git a/bind-job/run b/bind-job/run index 257f8dbe1..81051f877 100755 --- a/bind-job/run +++ b/bind-job/run @@ -55,7 +55,7 @@ ibmcloud ce jobrun submit --name myrun --job bj-job --wait ibmcloud ce jobrun logs --instance myrun-1-0 | tee out if ! grep CE_SERVICES out > /dev/null ; then - echo "Missing CE_SERVICES in App's env vars" + echo "Missing CE_SERVICES in Job's env vars" exit 1 fi diff --git a/cecli/Dockerfile b/cecli/Dockerfile index b69a142f7..0dfc11ebc 100644 --- a/cecli/Dockerfile +++ b/cecli/Dockerfile @@ -1,13 +1,16 @@ -FROM icr.io/codeengine/golang -COPY cecli.go / -RUN go build -o /cecli /cecli.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY . . + +RUN CGO_ENABLED=0 go build -o /go/bin/app cecli.go # Copy the exe into a non-golang image -FROM icr.io/codeengine/ubuntu -RUN apt-get update -y && apt-get install -y curl -WORKDIR /root +FROM quay.io/centos/centos:stream9 + # Install the IBM Cloud CLI and Code Engine plugin -RUN curl -sL https://raw.githubusercontent.com/IBM-Cloud/ibm-cloud-developer-tools/master/linux-installer/idt-installer | bash +RUN dnf install yum && yum update -y && yum install which -y +RUN curl -fsSL https://clis.cloud.ibm.com/install/linux | sh RUN ibmcloud plugin install code-engine -COPY --from=0 /cecli /cecli -CMD /cecli + +COPY --from=0 /go/bin/app / +CMD ["/app"] diff --git a/cecli/cecli.go b/cecli/cecli.go index bf1bcf235..73775c58a 100644 --- a/cecli/cecli.go +++ b/cecli/cecli.go @@ -33,10 +33,10 @@ func Run(out *string, cmdStr string, args ...interface{}) string { func main() { // These are run during the start-up of the container so that // we don't have the pay the cost of this on each HTTP request - Run(nil, "ibmcloud login -r "+os.Getenv("REGION")+" --apikey %s -g %s", + Run(nil, "ibmcloud login -r "+os.Getenv("CE_REGION")+" --apikey %s -g %s", strings.TrimSpace(os.Getenv("APIKEY")), strings.TrimSpace(os.Getenv("GROUP"))) - Run(nil, "ibmcloud ce project select -n %s", os.Getenv("PROJECT")) + Run(nil, "ibmcloud ce project select --id %s", os.Getenv("CE_PROJECT_ID")) // Our HTTP handler func http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { diff --git a/cecli/run b/cecli/run index 8215ef5fc..fca527d5c 100755 --- a/cecli/run +++ b/cecli/run @@ -13,8 +13,6 @@ function clean() { ibmcloud iam api-keys | grep cecli | sed "s/.*\(ApiKey\)/\1/" | while read a do ibmcloud iam api-key-delete -f $a done - - rm -f out .apikey ) > /dev/null 2>&1 } @@ -26,24 +24,20 @@ export REGISTRY=${REGISTRY:-icr.io/codeengine} set -ex # Create an API Key so that our App can use it to talk to Code Engine -ibmcloud iam api-key-create -q cecli | awk '/API Key/{ print $3 }' > .apikey +apikey="$(ibmcloud iam api-key-create cecli -q -o json|jq -r '.apikey')" # Create a 'secret' to hold our API Key, Project name, Resource Group and # Region ibmcloud ce secret create -n cecli-keys \ - --from-file APIKEY=.apikey \ - --from-literal PROJECT=$(ibmcloud ce project current|awk '/^Name/{ print $2 }') \ - --from-literal GROUP=$(ibmcloud target | awk '/group:/{ print $3 }') \ - --from-literal REGION=$(ibmcloud target | awk '/Region:/{ print $2 }') + --from-literal "APIKEY=$apikey" \ + --from-literal "GROUP=$(ibmcloud target -o json|jq -r '.resource_group.name')" -rm .apikey # erase it since we don't need it any more # Create our application that will kick off the "ibmcloud ce app list". # Note that the App will take a little longer than normal to start-up because we # setup the cloud CLI environment (eg. login) before starting the HTTP server. # Need to give it a little more CPU than the default. -ibmcloud ce app create -n lister --image $REGISTRY/cecli \ - --env-sec cecli-keys --cpu .5 +ibmcloud ce app create -n lister --image $REGISTRY/cecli --env-sec cecli-keys --cpu .125 --memory 0.25G # Save App's URL for later APP=$(ibmcloud ce app get -n lister -o url) diff --git a/cloudant-change-listener/Dockerfile b/cloudant-change-listener/Dockerfile index 9f5b17908..e75ee8b9d 100644 --- a/cloudant-change-listener/Dockerfile +++ b/cloudant-change-listener/Dockerfile @@ -1,7 +1,10 @@ -FROM icr.io/codeengine/node:20-alpine -WORKDIR /usr/job -COPY . /usr/job/ -RUN pwd -WORKDIR /usr/job/job +FROM registry.access.redhat.com/ubi9/nodejs-20:latest AS build-env +WORKDIR /opt/app-root/src +COPY --chown=default:root job/* . RUN npm install -CMD [ "node", "./job.mjs" ] + +# Use a small distroless image for as runtime image +FROM gcr.io/distroless/nodejs20-debian12 +COPY --from=build-env /opt/app-root/src /app +WORKDIR /app +CMD ["job.mjs"] \ No newline at end of file diff --git a/cloudant-change-listener/run b/cloudant-change-listener/run index 8f8d8fc98..2185dec21 100755 --- a/cloudant-change-listener/run +++ b/cloudant-change-listener/run @@ -1,18 +1,24 @@ #!/bin/bash +echo "" +echo "Installing cloudant-change-listener example ..." +echo "" + # Ensure that jq tool is installed if ! command -v jq &>/dev/null; then echo "FAILED - 'jq' tool is not installed" exit 1 fi +echo "" +echo "Install necessary IBM Cloud CLI plugins ..." + # Ensure that latest versions of used IBM Cloud ClI is installed -ibmcloud update --force +ibmcloud update -f --quiet # Ensure that latest versions of used IBM Cloud CLI plugins are installed -echo "Install necessary ibmcloud cli plugins ..." -ibmcloud plugin install cloudant -f -ibmcloud plugin install code-engine -f +ibmcloud plugin install cloudant -f --quiet +ibmcloud plugin install code-engine -f --quiet function delete_serviceids() { service_ids=$(ibmcloud resource search "type:serviceid AND $1" --output JSON | jq -r '.items') @@ -26,8 +32,8 @@ function delete_serviceids() { # Clean up previous run function clean() { - echo "==================================================================================" - echo "Cleaning... (FAILED results are expected for NON-existing elements while cleaning)" + echo "" + echo "Cleaning up resources from previous runs ..." ( ## first select the project with the name like is was created in last session # if project does not exist, then there is no need to delete the artifacts @@ -52,9 +58,8 @@ function clean() { ibmcloud resource service-key-delete cloudant-creds-ce-project --force - ) - echo Cleaning DONE ... - echo "==================================================================================" + ) > /dev/null 2>&1 + echo "Cleaning up resources from previous runs [DONE]" } clean @@ -62,6 +67,12 @@ clean # In case this script has been executed with `./run clean`, we stop right after the cleanup [[ "$1" == "clean" ]] && exit 0 +echo "" +echo "==================================================================================" +echo "Starting to setup the cloudant-change-listener ..." +echo "" + +echo "" echo "Check if a Cloudant instance 'CE-Cloudant-SampleDB' is properly initialized ..." COUNTER=0 @@ -85,6 +96,7 @@ if [ -z "$cloudant_instances" ]; then exit 1 fi +echo "" echo "Obtain the service URL of the newly created Cloudant instance '$cloudant_instance_name' (id: $cloudant_instance_guid) ..." cloudant_url=$(ibmcloud cloudant url --resource-id $cloudant_instance_guid --output JSON) echo "$cloudant_url" @@ -105,6 +117,7 @@ echo "" echo "Try to delete the sample-db Cloudant database if exists from a previous run " curl -H "Authorization: $iam_access_token" -X DELETE "$cloudant_url/sample-db" +echo "" echo "Creating a new database 'sample-db' within Cloudant instance '$cloudant_instance_name' ..." echo "using cloudant API https://cloud.ibm.com/apidocs/cloudant#putdatabase" curl -H "Authorization: $iam_access_token" -X PUT "$cloudant_url/sample-db" @@ -113,6 +126,7 @@ if [ $? != 0 ]; then exit 1 fi +echo "" echo "Creating Code Engine project 'ce-sample-cloudant-change-listener-project' ..." ibmcloud ce proj create --name ce-sample-cloudant-change-listener-project if [ $? != 0 ]; then @@ -131,12 +145,14 @@ if [ -z "$ce_project_region" ]; then exit 1 fi +echo "" echo "Creating the Code Engine function 'cloudant-change-listener-function' ..." ibmcloud ce fn create \ --name cloudant-change-listener-function \ - --runtime nodejs-18 \ + --runtime nodejs-20 \ --inline-code ./function/function.js +echo "" echo "Waiting for the function to get properly initialized ..." ce_fn_endpoint="null" ce_fn_endpoint_internal="null" @@ -155,6 +171,7 @@ while [ "$ce_fn_endpoint" == "null" ]; do done echo "Function public endpoint: '$ce_fn_endpoint', internal endpoint: '$ce_fn_endpoint_internal'" +echo "" echo "Creating a config map to store the event state" ibmcloud ce configmap create \ --name cloudant-change-listener-job-config \ @@ -165,6 +182,7 @@ if [ $? != 0 ]; then fi # See Code Engine docs: Managing user access (https://cloud.ibm.com/docs/codeengine?topic=codeengine-iam#service) +echo "" echo "Creating an IAM ServiceID that contains a policy to access the Code Engine project '${ce_project_guid}' ..." ibmcloud iam service-id-create ce-sample-cloudant-change-listener-api-credentials --description "Service ID to operate towards the Code Engine project ${ce_project_guid}" if [ $? != 0 ]; then @@ -182,6 +200,7 @@ if [ -z "$ce_api_key" ]; then exit 1 fi +echo "" echo "Creating a secret that stores a serviceID APIKey to enable the job storing state in a Configmap within the project '$ce_project_guid' ..." ibmcloud ce secret create \ --name cloudant-change-listener-credentials \ @@ -191,6 +210,7 @@ if [ $? != 0 ]; then exit 1 fi +echo "" echo "Creating the Code Engine daemon job 'cloudant-change-listener-job' ..." ibmcloud ce job create \ --name cloudant-change-listener-job \ @@ -207,6 +227,7 @@ if [ $? != 0 ]; then exit 1 fi +echo "" echo "Creating the service credential on the Cloudant database to be able to bind the job and the function ..." ibmcloud resource service-key-create cloudant-creds-ce-project Reader --instance-id $cloudant_instance_guid if [ $? != 0 ]; then @@ -214,6 +235,7 @@ if [ $? != 0 ]; then exit 1 fi +echo "" echo "Binding the Cloudant credentials to the Code Engine function to enable that the function code can access the DB via Env vars ..." ibmcloud ce fn bind \ --name cloudant-change-listener-function \ @@ -224,6 +246,7 @@ if [ $? != 0 ]; then exit 1 fi +echo "" echo "Binding the Cloudant credentials to the Code Engine job ..." ibmcloud ce job bind \ --name cloudant-change-listener-job \ @@ -234,6 +257,7 @@ if [ $? != 0 ]; then exit 1 fi +echo "" echo "Starting the daemon job ..." job_run_name=$(ibmcloud ce jobrun submit --job cloudant-change-listener-job --output json | jq -r '.metadata|.name') echo "with job id = $job_run_name" @@ -242,6 +266,7 @@ if [ -z "$job_run_name" ]; then exit 1 fi +echo "" echo "Check whether the job started properly ..." COUNTER=0 while ! ibmcloud ce jobrun get -n ${job_run_name} | grep "1/1" | grep "Running"; do @@ -256,6 +281,7 @@ while ! ibmcloud ce jobrun get -n ${job_run_name} | grep "1/1" | grep "Running"; done sleep 2 +echo "" echo "Upload a file to the Cloudant database ..." curl -H "Authorization: $iam_access_token" -X POST "$cloudant_url/sample-db" -H "Content-Type: application/json" --data '{ "_id": "small-appliances:1000043", @@ -265,18 +291,19 @@ curl -H "Authorization: $iam_access_token" -X POST "$cloudant_url/sample-db" -H "name": "Digital Kitchen Scales" }' +echo "" echo "Verify job receives the Cloudant event by fetching the job run logs ..." COUNTER=0 while true; do - echo "Waiting on job to detect change" + echo " Waiting on job to detect change" sleep 5 foundDetectedChange=$(ibmcloud ce jobrun logs -n ${job_run_name} | grep "Detected 1 change(s) in the DB") foundCalledFunction=$(ibmcloud ce jobrun logs -n ${job_run_name} | grep "Successfully called CE") if [[ $foundDetectedChange && $foundCalledFunction ]]; then echo "" - echo "That was a success :)" + echo " That was a success :)" break fi COUNTER=$((COUNTER + 1)) @@ -293,5 +320,9 @@ while true; do fi done +echo "" +echo "Completed successfully :)" +echo "" + # Clean up clean diff --git a/configmaps-env/Dockerfile b/configmaps-env/Dockerfile index 4e4a9ed82..8d3b0303e 100644 --- a/configmaps-env/Dockerfile +++ b/configmaps-env/Dockerfile @@ -1,8 +1,10 @@ -FROM icr.io/codeengine/golang:alpine -COPY config.go / -RUN go build -o /config /config.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY config.go . + +RUN CGO_ENABLED=0 go build -o /go/bin/app config.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /config /config -CMD /config +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / +CMD ["/app"] diff --git a/configmaps-env/run b/configmaps-env/run index 7fcbe6715..64ac1ea6d 100755 --- a/configmaps-env/run +++ b/configmaps-env/run @@ -33,6 +33,8 @@ ibmcloud ce configmap create --name cm-config-env \ # Create the app ibmcloud ce app create -n cm-app-env --image ${REGISTRY}/ce-config-env \ + --cpu 0.125 \ + --memory 0.25G \ --env-from-configmap cm-config-env # Get the URL of the app for later use @@ -45,13 +47,13 @@ curl -fs $URL ibmcloud ce app logs -n cm-app-env | tee out [[ "${PIPESTATUS[0]}" == "0" ]] grep MY_ out -if ! [[ $(grep MY_ out | wc -l) == "4" ]]; then +if (( $(grep MY_ out | wc -l) != 4 )); then echo "Unexpected output" exit 1 fi # Check to see if the context of "file" are assign to the "file" env var. -if ! [[ $(grep '^file=In Congress' out | wc -l) == "1" ]]; then +if (( $(grep '^file=In Congress' out | wc -l) != 1 )); then echo "Unexpected output" exit 1 fi diff --git a/configmaps-vol/Dockerfile b/configmaps-vol/Dockerfile index 4e4a9ed82..8d3b0303e 100644 --- a/configmaps-vol/Dockerfile +++ b/configmaps-vol/Dockerfile @@ -1,8 +1,10 @@ -FROM icr.io/codeengine/golang:alpine -COPY config.go / -RUN go build -o /config /config.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY config.go . + +RUN CGO_ENABLED=0 go build -o /go/bin/app config.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /config /config -CMD /config +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / +CMD ["/app"] diff --git a/configmaps-vol/run b/configmaps-vol/run index da80787f8..81afc16e4 100755 --- a/configmaps-vol/run +++ b/configmaps-vol/run @@ -33,6 +33,8 @@ ibmcloud ce configmap create --name cm-config-vol \ # Create the app ibmcloud ce app create -n cm-app-vol --image ${REGISTRY}/ce-config-vol \ + --cpu 0.125 \ + --memory 0.25G \ --mount-configmap /myconfig=cm-config-vol # Get the URL of the app for later use @@ -45,13 +47,13 @@ curl -fs $URL ibmcloud ce app logs -n cm-app-vol | tee out [[ "${PIPESTATUS[0]}" == "0" ]] grep MY_ out -if ! [[ $(grep MY_ out | wc -l) == "4" ]]; then +if (( $(grep MY_ out | wc -l) != 4 )); then echo "Unexpected output" exit 1 fi # Check to see if the context of "file" are assign to the "file" env var. -if ! [[ $(grep '^file: In Congress' out | wc -l) == "1" ]]; then +if (( $(grep '^file: In Congress' out | wc -l) != 1 )); then echo "Unexpected output" exit 1 fi diff --git a/cos-event-job/run b/cos-event-job/run index 2ed3eec79..156cdd737 100755 --- a/cos-event-job/run +++ b/cos-event-job/run @@ -7,8 +7,9 @@ export PROJECT_NAME=$(ibmcloud ce project current | awk '/^Name/{ print $2 }') export PROJECT_ID=$(ibmcloud ce project get --name ${PROJECT_NAME} | \ awk '/^ID/{ print $2 }') +export REGION=$(ibmcloud ce project current --output json|jq -r '.region_id') export POLICY_ID="" -export BUCKET=${PROJECT_NAME}-${PROJECT_ID} +export BUCKET="${PROJECT_ID}-ce-samples-test" # Clean up previous run function clean() { @@ -46,8 +47,9 @@ if [[ $CID == "" ]]; then fi # Set the COS config to use this instance -ibmcloud cos config crn --crn $CID --force ibmcloud cos config auth --method IAM +ibmcloud cos config crn --crn $CID --force +ibmcloud cos config region --region $REGION # Create IAM authorization policy so we can receive notifications from COS POLICY_ID=$(ibmcloud iam authorization-policy-create codeengine \ @@ -60,6 +62,8 @@ ibmcloud cos bucket-create --bucket ${BUCKET} --ibm-service-instance-id $CID # Create a simple job which prints the CE_DATA ibmcloud ce job create -n cos-job \ + --cpu 0.125 \ + --memory 0.25G \ --image registry.access.redhat.com/ubi8/ubi-minimal:latest \ --arg "/bin/sh" \ --arg "-c" \ diff --git a/cos-event/Dockerfile b/cos-event/Dockerfile index 0dcaa4168..c70aa206b 100644 --- a/cos-event/Dockerfile +++ b/cos-event/Dockerfile @@ -1,8 +1,10 @@ -FROM icr.io/codeengine/golang:alpine -COPY cos-listen.go / -RUN go build -o /cos-listen /cos-listen.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY cos-listen.go . + +RUN CGO_ENABLED=0 go build -o /go/bin/app cos-listen.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /cos-listen /cos-listen -CMD /cos-listen +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / +CMD ["/app"] diff --git a/cos-event/run b/cos-event/run index 2e0cfc90c..1b173528f 100755 --- a/cos-event/run +++ b/cos-event/run @@ -9,8 +9,9 @@ export REGISTRY=${REGISTRY:-icr.io/codeengine} export PROJECT_NAME=$(ibmcloud ce project current | awk '/^Name/{ print $2 }') export PROJECT_ID=$(ibmcloud ce project get --name ${PROJECT_NAME} | \ awk '/^ID/{ print $2 }') +export REGION=$(ibmcloud ce project current --output json|jq -r '.region_id') export POLICY_ID="" -export BUCKET=${PROJECT_NAME}-${PROJECT_ID} +export BUCKET="${PROJECT_ID}-ce-samples-test" # Clean up previous run function clean() { @@ -50,6 +51,7 @@ fi # Set the COS config to use this instance ibmcloud cos config crn --crn $CID --force ibmcloud cos config auth --method IAM +ibmcloud cos config region --region $REGION # Create IAM authorization policy so we can receive notifications from COS POLICY_ID=$(ibmcloud iam authorization-policy-create codeengine \ @@ -62,7 +64,10 @@ ibmcloud cos bucket-create --bucket ${BUCKET} --ibm-service-instance-id $CID # Create the app && save its URL for later ibmcloud ce app create -n cos-app --image ${REGISTRY}/cos-listen \ - --min-scale=1 --max-scale=1 + --cpu 0.125 \ + --memory 0.25G \ + --min-scale=1 \ + --max-scale=1 URL=$(ibmcloud ce app get --output url --name cos-app) # Setup the COS Event Source diff --git a/cos2cos/.DEPS b/cos2cos/.DEPS deleted file mode 100644 index ea2c599dd..000000000 --- a/cos2cos/.DEPS +++ /dev/null @@ -1 +0,0 @@ -cos diff --git a/cos2cos/.SEQ b/cos2cos/.SEQ deleted file mode 100644 index e69de29bb..000000000 diff --git a/cos2cos/.gitignore b/cos2cos/.gitignore deleted file mode 100644 index 67da64db7..000000000 --- a/cos2cos/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# .gitignore file for cos2cos -venv/ -__pycache__/ -*.egg-info diff --git a/cos2cos/Dockerfile b/cos2cos/Dockerfile deleted file mode 100644 index ab5df4555..000000000 --- a/cos2cos/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM icr.io/codeengine/python:latest - - -WORKDIR cos2cos -ADD templates ./templates/ -ADD *.py ./ -RUN ls -lR . -RUN /usr/local/bin/python -m pip install --upgrade pip -RUN /usr/local/bin/python -m pip install -e . -RUN which c2c - -CMD ["/usr/local/bin/c2c","-i","https://iam.cloud.ibm.com/identity/token"] diff --git a/cos2cos/README.md b/cos2cos/README.md deleted file mode 100644 index cef78ec5c..000000000 --- a/cos2cos/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# COS-to-COS - -This sample shows a somewhat more complex example than some of the others - it -demonstrates a simple event-driven application pattern wherein the uploading of -an object to a Cloud Object Storage (COS) bucket generates an event. When the -app receives the event, it parses out the bucket and object key from the event, -downloads the object (file), "processes" it, and then uploads the resulting -file to a separate (pre-configured) destination bucket. The app then deletes -the file from the original source bucket. - -The app also includes a listener for cron events. Upon receipt of a cron event, -it will inventory the source bucket for files. Any file found is assumed not to -have been processed successfully, so the app then -processes the file as per normal (including deleting it from the source bucket). - -This app also includes some informational endpoints which can be used to inspect -what it is doing/has done: - -- `/events/stats`: A GET request against this endpoint returns statistics about events -in JSON. This includes counters of COS events processed successfully, COS events -which resulted in errors (of any type, for any reason), cron events processed -successfully, and cron events which resulted in errors. -- `/events/history`: This displays an HTML page showing a list of all events -received since the application started. The list includes, for each event, -information such as the event type, time of receipt, and a list of files -processed as a result of the event, as well as a status and timestamp for the -processing of each file. -- `/files`: This displays a table showing each file known to the app and its -presence (or lack thereof) in each bucket. - -All of this information is maintained in memory, so the `run` script creates the -app with minimum and maximum scale values of 1. This ensures that there is always -exactly one instance of the app running, regardless of load. In a real application, -you would want to externalize the storage of statistics and history information, -using e.g. a redis instance, which would then let you share the information across -instances and allow you to take advantage of Code Engine's scale-to-zero -capabilities. - -The app is written/packaged as a [Flask](https://flask.palletsprojects.com/en/1.1.x/) -application and deployed using the built-in development server (which is not - meant for general production usage). - -## How to use the sample - -The `run` script will create the app and an event subscription connecting the -app to the specified COS bucket. The script will then upload a file to the -bucket, resulting in the generation of an event. Upon receiving the event, -the application will take the names of the bucket and object listed in the event, -retrieve the object, process it, and then upload the result to a different bucket. -The application then deletes the object from the original source bucket. - -If you already have a COS instance that you want to use, you can set the -`COS_ID` environment variable to the CRN of that instance. You can find -existing instances by running -``` -ibmcloud resource service-instances --service-name cloud-object-storage --long -``` -If you want to use one of the listed instances, set `COS_ID` to the instance -CRN/ID (the value in the first column of each row). If you leave this -variable unset, the `run` script will attempt to create a `lite` (free of -charge) COS instance for you, which it will then delete upon completion. It -will not delete any existing instance you specify via the `COS_ID` variable. - -- - - - -As noted in [the main README](../README.md), this sample has two pieces: - -- a `build` script which will build the container image(s) used -- a `run` script which deploys resources that use those images - -The main purpose of this example is the `run` script, but the `build` -script is included for complete educational (and reuse) purposes. diff --git a/cos2cos/__init__.py b/cos2cos/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/cos2cos/build b/cos2cos/build deleted file mode 100755 index adeaa7e19..000000000 --- a/cos2cos/build +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Env Vars: -# REPOSITORY: name of the image registry/namespace to store the images -# NOCACHE: set this to "--no-cache" to turn off the Docker build cache -# -# NOTE: to run this you MUST set the REPOSITORY environment variable to -# your own image registry/namespace otherwise the `docker push` commands -# will fail due to an auth failure. Which means, you also need to be logged -# into that registry before you run it. - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} - -# Build the image -docker build ${NOCACHE} -t ${REGISTRY}/cos2cos . --platform linux/amd64 - -# And push it -docker push ${REGISTRY}/cos2cos diff --git a/cos2cos/cos.py b/cos2cos/cos.py deleted file mode 100644 index 0ace51bdf..000000000 --- a/cos2cos/cos.py +++ /dev/null @@ -1,85 +0,0 @@ -from ibm_boto3.session import Session -from ibm_botocore.client import Config -from pathlib import PurePath - - -class CloudObjectStorage(): - def __init__(self, api_key=None, instance_id=None, iam_endpoint=None, - cos_endpoint=None): - self.cos_endpoint = cos_endpoint - self.session = Session( - ibm_api_key_id=api_key, - ibm_service_instance_id=instance_id, - ibm_auth_endpoint=iam_endpoint) - - # The COS sdk call download_file() downloads to a local file. - # If you have an object which implements file-like behavior - # (e.g. it supports write() and can store bytes) - # you can pass that into a call to - # download_fileobj() instead of download_file(). - # You would then need to change the implemention of put_file() - # to call upload_fileobj() and pass in your object instead of - # the file name. - - def get_file(self, bucket_name=None, file=None): - cos = self.session.resource( - service_name='s3', - endpoint_url=self.cos_endpoint, - config=Config(signature_version='oauth') - ) - response = cos.Bucket(bucket_name).download_file( - Key=PurePath(file).name, - Filename=file - ) - return response - - def put_file(self, bucket_name=None, file=None): - cos = self.session.resource( - service_name='s3', - endpoint_url=self.cos_endpoint, - config=Config(signature_version='oauth') - ) - cos.Bucket(bucket_name).upload_file(file, PurePath(file).name) - - def delete_file(self, bucket_name=None, file=None): - cos = self.session.resource( - service_name='s3', - endpoint_url=self.cos_endpoint, - config=Config(signature_version='oauth') - ) - response = cos.Bucket(bucket_name).delete_objects( - Delete={ - 'Objects': [ - {'Key': file} - ], - 'Quiet': True - }, - MFA='string', - RequestPayer='requester' - ) - if 'Errors' in response.keys(): - raise COSError - - # get_files returns a dict. The key is the object key, - # the value is a dict containing core object metadata. - # See https://ibm.github.io/ibm-cos-sdk-python/reference/services/s3.html#S3.ObjectVersion - - def get_files_info(self, bucket_name=None): - cos = self.session.resource( - service_name='s3', - endpoint_url=self.cos_endpoint, - config=Config(signature_version='oauth') - ) - files = {} - object_summaries = cos.Bucket(bucket_name).objects.all() - for s in object_summaries: - object = s.Object() - files[object.key] = {'last_modified': object.last_modified, - 'size': object.content_length, - 'version': object.version_id} - return files - - -class COSError(Exception): - """Exception class for errors when interacting with COS.""" - pass diff --git a/cos2cos/cos_2_cos.py b/cos2cos/cos_2_cos.py deleted file mode 100644 index 5162bac26..000000000 --- a/cos2cos/cos_2_cos.py +++ /dev/null @@ -1,279 +0,0 @@ -import click -from datetime import datetime -import logging -from os import environ -from flask import Flask, request, abort, render_template -from cos import CloudObjectStorage, COSError - - -# FileHandler contains all of the file download/upload/delete logic. -# If you want to add some actual file processing, hook it in here. -class FileHandler(): - def __init__(self, cos_client, source_bucket, destination_bucket, file): - self.cos_client = cos_client - self.source_bucket = source_bucket - self.destination_bucket = destination_bucket - self.file = file - - def do(self): - object = self.cos_client.get_file( - bucket_name=self.source_bucket, - file=self.file) - - logging.info('File downloaded') - logging.info('Processing file') - # Since the COS object has been stored as a local file, you'd - # need to read that in and process it, then write the results back - # out to another file (or store them in a file-like object). - # This demo program does no actual processing of the file contents. - logging.info('Processing complete') - logging.info('Uploading file %s to COS bucket %s', - self.file, self.destination_bucket) - - self.cos_client.put_file( - bucket_name=self.destination_bucket, - file=self.file) - - logging.info('Upload complete') - - try: - logging.info('Deleting file %s from bucket %s', - self.file, self.source_bucket) - self.cos_client.delete_file( - bucket_name=self.source_bucket, file=self.file) - except COSError as e: - logging.warning('Error when trying to delete file %s from bucket %s', - self.file, self.source_bucket) - raise e - - -def create_server(cos_client=None, destination_bucket=None, source_bucket=None): - event_stats = {'cron': 0, 'cron_error': 0, 'cos': 0, 'cos_error': 0} - event_history = [] - buckets = [source_bucket, destination_bucket] - - app = Flask(__name__) - - # Retrieve a table showing each file known to us, along with its state - # (present, not present, if present version/size/timestamp) within each - # known bucket. We'll use this to build the reconciliation hook for cron - # events later. - @app.route('/files', methods=['GET']) - def get_files(): - file_inventory = {} - # Check each bucket, get the ObjectSummary listing for that bucket, - # store in nested dicts filename -> bucket -> file version info for - # that bucket - for b in buckets: - bucket_files = cos_client.get_files_info(bucket_name=b) - for f, f_info in bucket_files.items(): - if f not in file_inventory.keys(): - file_inventory[f] = {} - file_inventory[f][b] = f_info - return render_template('files.html', - file_names=sorted(file_inventory.keys()), - files=file_inventory, - buckets=buckets) - - @app.route('/events/stats', methods=['GET']) - def get_event_stats(): - return event_stats - - @app.route('/events/history', methods=['GET']) - def get_event_history(): - return render_template('history.html', events=event_history) - - @app.route('/events/cos', methods=['POST']) - def handle_cos_event(): - event_timestamp = datetime.now() - # Setting silent to True causes parsing errors to return None, - # the errors are themselves swallowed. See Flask API docs for details. - event = request.get_json(silent=True) - if event: - # We discard events not generated by our configured source bucket - if event['bucket'] != source_bucket: - event_stats['cos_error'] = event_stats['cos_error'] + 1 - abort(400) - event_status = 'OK' - event_stats['cos'] = event_stats['cos'] + 1 - source_object = event['key'] - - logging.info('Event received for file %s in bucket %s', - source_object, source_bucket) - - handler = FileHandler(cos_client=cos_client, - source_bucket=source_bucket, - destination_bucket=destination_bucket, - file=source_object) - - try: - handler.do() - except COSError: - event_status = 'Deletion Error' - # We could return a 500 due to the failure to delete. - # If you're customizing this code, you'd need to do a little - # bit of refactoring to maintain the event history, etc. if - # you decide you want to abort(500) here. - history_event = { - 'id': 'cos-' + str(event_stats['cos']), - 'timestamp': event_timestamp, - 'objects': [ - { - 'key': source_object, - 'timestamp': datetime.now(), - 'source_bucket': source_bucket, - 'destination_bucket': destination_bucket, - 'status': event_status - } - ] - } - - # Update our event history and make sure we store the source - # bucket name - event_history.append(history_event) - if source_bucket not in buckets: - buckets.append(source_bucket) - - return 'OK' - else: - event_stats['cos_error'] = event_stats['cos_error'] + 1 - abort(400) - - # Any cron event will trigger reconciliation - any file which is present - # in the source bucket will be assumed not to have been processed, - # so we'll process it and transfer it. - - @app.route('/events/cron', methods=['POST']) - def handle_cron_event(): - # All we check is that the body is valid JSON, nothing beyond that. - # It would be trivial to check for specific message body elements - # and probably advisable in a real world application. - event = request.get_json(silent=True) - if event: - event_stats['cron'] = event_stats['cron'] + 1 - event_timestamp = datetime.now() - history_event = { - 'id': 'cron-' + str(event_stats['cron']), - 'timestamp': event_timestamp, - 'objects': [] - } - source_inventory = cos_client.get_files_info( - bucket_name=source_bucket) - for file in source_inventory.keys(): - object_status = 'OK' - logging.info('RECONCILE: Processing and transferring %s to %s', - file, destination_bucket) - handler = FileHandler(cos_client=cos_client, - source_bucket=source_bucket, - destination_bucket=destination_bucket, - file=file) - - try: - handler.do() - except COSError: - object_status = 'Deletion Error' - logging.info( - 'RECONCILE: Processing complete for %s', file) - - history_event['objects'].append({ - 'key': file, - 'timestamp': datetime.now(), - 'source_bucket': source_bucket, - 'destination_bucket': destination_bucket, - 'status': object_status - }) - event_history.append(history_event) - return 'OK' - else: - event_stats['cron_error'] = event_stats['cron_error'] + 1 - abort(400) - - return app - - -@click.command() -@click.option('-d', '--destination-bucket', help='Destination bucket for processing output') -@click.option('-s', '--source-bucket', help='Source bucket for input') -@click.option('-x', '--cos-instance-id', help='COS instance ID') -@click.option('-e', '--cos-endpoint', help='COS endpoint URL') -@click.option('-i', '--iam-endpoint', help='IAM token endpoint') -@click.option('-k', '--api-key', help='IAM API key') -@click.option('-p', '--port', default=8080, - help='HTTP listener port (defaults to 8080)') -@click.option('-h', '--host', default='0.0.0.0', - help='Host IP address (set to 127.0.0.1 to disable remote connections, default is 0.0.0.0)') -@click.option('-l', '--log-level', default='info', - help='Log level (debug|info|warning|error|critical). The default is info.') -def start_server(destination_bucket, - source_bucket, - cos_instance_id, - cos_endpoint, - iam_endpoint, - api_key, - port, - host, - log_level): - """Demo app for processing files and moving between buckets.""" - - log_levels = { - 'debug': logging.DEBUG, - 'info': logging.INFO, - 'warning': logging.WARNING, - 'error': logging.ERROR, - 'critical': logging.CRITICAL - } - logging.basicConfig(level=log_levels[log_level]) - # Get our config/arguments - - # TODO: Move to click-based environment var handling - cos_endpoint = cos_endpoint if cos_endpoint else environ.get( - 'COS_ENDPOINT') - if not cos_endpoint: - logging.error('No valid COS endpoint specified') - return -1 - - api_key = api_key if api_key else environ.get('APIKEY') - if not api_key: - logging.error('No IAM API key found') - return -1 - - destination_bucket = destination_bucket if destination_bucket else environ.get( - 'DESTINATION_BUCKET') - if not destination_bucket: - logging.error('Must specify a destination bucket') - return -1 - - source_bucket = source_bucket if source_bucket else environ.get( - 'SOURCE_BUCKET') - if not source_bucket: - logging.error('Must specify a source bucket') - return -1 - - cos_instance_id = cos_instance_id if cos_instance_id else environ.get( - 'COS_INSTANCE_ID') - if not cos_instance_id: - logging.error('No COS instance ID found') - return -1 - - iam_endpoint = iam_endpoint if iam_endpoint else environ.get( - 'IAM_ENDPOINT') - if not iam_endpoint: - logging.error('No IAM endpoint specified') - return -1 - - cos_client = CloudObjectStorage( - api_key=api_key, - instance_id=cos_instance_id, - iam_endpoint=iam_endpoint, - cos_endpoint=cos_endpoint) - - logging.info('Starting cos-2-cos server') - - server = create_server(cos_client=cos_client, - destination_bucket=destination_bucket, - source_bucket=source_bucket) - server.run(port=port) - - -if __name__ == "__main__": - exit(start_server()) diff --git a/cos2cos/run b/cos2cos/run deleted file mode 100755 index cd29aaaa9..000000000 --- a/cos2cos/run +++ /dev/null @@ -1,150 +0,0 @@ -#!/bin/bash - -# Env Vars: -# REGISTRY: name of the image registry/namespace to get the images -# COS_ID: If set, specifies the full CRN of a Cloud Object Storage instance to -# use - -REGISTRY=${REGISTRY:-icr.io/codeengine} -PROJECT_NAME=$(ibmcloud ce project current | awk '/^Name/{ print $2 }') -PROJECT_REGION=$(ibmcloud ce project current | \ - awk -F: '/^Region/{ print $2 }' | sed -e 's/^[[:space:]]*//' -e "s/[[:space:]]*$//") -POLICY_ID="" -PROJECT_ID=$(ibmcloud ce project get --name ${PROJECT_NAME} | \ - awk '/^ID/{ print $2 }') -BUCKET=${PROJECT_NAME}-${PROJECT_ID} -SOURCE_BUCKET="${BUCKET}-source" -DESTINATION_BUCKET="${BUCKET}-destination" - -function delete_serviceids() { - service_ids=$(ibmcloud resource search "type:serviceid AND $1" --output JSON | jq -r '.items') - for service_id in $(echo "${service_ids}" | jq -r '.[] | @base64'); do - _jqServiceID() { - echo "${service_id}" | base64 --decode | jq -r "${1}" - } - ibmcloud iam service-id-delete "$(_jqServiceID '.resource_id')" --force - done -} - -# Clean up previous run -function clean() { - set +ex - echo "Cleaning..." - ( - # Delete the event subscription - ibmcloud ce sub cos delete -n cos2cos-sub -f --wait=true - - # Delete the IAM auth policy - if [[ -n "$POLICY_ID" ]]; then - ibmcloud iam authorization-policy-delete $POLICY_ID --force - fi - - # Delete the app, config map, secret - ibmcloud ce app delete --name cos2cos --force - ibmcloud ce cm delete --name cos2cos-config --force - ibmcloud ce secret delete --name cos2cos-key --force - - # Delete the COS service ID - delete_serviceids cos2cos-service-id - - # Empty the COS buckets - ibmcloud cos object-delete --bucket ${SOURCE_BUCKET} --key "README.md" --force - ibmcloud cos object-delete --bucket ${DESTINATION_BUCKET} --key "README.md" --force - - # Delete the COS buckets - ibmcloud cos bucket-delete --bucket ${SOURCE_BUCKET} --force - ibmcloud cos bucket-delete --bucket ${DESTINATION_BUCKET} --force - - # Delete the COS instance unless the instance was given to us - if [[ -z "$COS_ID" ]]; then - ibmcloud resource service-instance-delete ce-cos2cos -f -q - fi - - rm -f out .tmpkey - ) > /dev/null 2>&1 -} - -clean -[[ "$1" == "clean" ]] && exit 0 - -set -ex - -CID=${COS_ID} - -# Create a COS instance unless one has been specified for use -if [[ -z "$CID" ]]; then - ibmcloud resource service-instance-create ce-cos2cos \ - cloud-object-storage lite global - CID=$(ibmcloud resource service-instance ce-cos2cos | awk '/^ID/{ print $2 }') -fi - -# Set the COS config to use this instance -ibmcloud cos config crn --crn $CID --force -ibmcloud cos config auth --method IAM - -# Create IAM authorization policy so we can receive notifications from COS -POLICY_ID=$(ibmcloud iam authorization-policy-create codeengine \ - cloud-object-storage "Notifications Manager" \ - --source-service-instance-name ${PROJECT_NAME} \ - --target-service-instance-id ${CID} | awk '/^Authorization/{ print $3 }') - -# Create our buckets -ibmcloud cos bucket-create --bucket ${SOURCE_BUCKET} \ - --ibm-service-instance-id $CID \ - --region $PROJECT_REGION -ibmcloud cos bucket-create --bucket ${DESTINATION_BUCKET} \ - --ibm-service-instance-id $CID \ - --region $PROJECT_REGION - -# Create a configmap -COS_REGION=$(ibmcloud cos config list | awk '/Default Region/{ print $3 }') -ibmcloud ce cm create -n cos2cos-config \ - --from-literal DESTINATION_BUCKET=${DESTINATION_BUCKET} \ - --from-literal SOURCE_BUCKET=${SOURCE_BUCKET} \ - --from-literal COS_ENDPOINT=https://s3.${COS_REGION}.cloud-object-storage.appdomain.cloud \ - --from-literal COS_INSTANCE_ID=${CID} \ - --from-literal IAM_ENDPOINT=https://iam.cloud.ibm.com/identity/token - -# Create a service ID to use when accessing COS and an API key for that ID -ibmcloud iam service-id-create cos2cos-service-id -ibmcloud iam service-policy-create cos2cos-service-id \ - --service-name cloud-object-storage \ - --service-instance ${CID} --roles Writer - -# Store the API key in a secret -ibmcloud iam service-api-key-create cos2cos-apikey cos2cos-service-id \ - | awk '/API Key/{ print $3 }' > .tmpkey -ibmcloud ce secret create -n cos2cos-key --from-file APIKEY=.tmpkey -rm -f .tmpkey - -# Create the app -ibmcloud ce app create -n cos2cos --image ${REGISTRY}/cos2cos \ - --env-from-configmap cos2cos-config \ - --env-from-secret cos2cos-key \ - --min-scale 1 \ - --max-scale 1 - -# Setup the COS Event Source -ibmcloud ce sub cos create -n cos2cos-sub -d cos2cos -b ${SOURCE_BUCKET} \ - --path "/events/cos" - -# Now wait until we get the event - shouldn't take more than a minute -while true ; do - sleep 10 - - # Upload a file to the source bucket (this will generate an event) - ibmcloud cos object-put --bucket ${SOURCE_BUCKET} --key "README.md" \ - --body README.md - - # Check for the file in the destination bucket (presence there is - # triggered by the upload event) - declare -i FOUND=$(ibmcloud cos objects --bucket ${DESTINATION_BUCKET} | \ - grep -c "README.md") - if [[ $FOUND -ge 1 ]]; then - echo "File found in destination bucket" - break - fi -done - -# Clean up -clean diff --git a/cos2cos/setup.py b/cos2cos/setup.py deleted file mode 100644 index d1108eb0e..000000000 --- a/cos2cos/setup.py +++ /dev/null @@ -1,17 +0,0 @@ -from setuptools import setup, find_packages - -setup( - name='cos2cos', - version='0.1', - packages=find_packages(), - install_requires=[ - 'click', - 'flask', - 'requests', - 'ibm-cos-sdk' - ], - entry_points=''' - [console_scripts] - c2c=cos_2_cos:start_server - ''', -) diff --git a/cos2cos/templates/files.html b/cos2cos/templates/files.html deleted file mode 100644 index d8def42e9..000000000 --- a/cos2cos/templates/files.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - C2C File Inventory - - - -

File Inventory

- {% if file_names %} - {% if buckets %} - {% if files %} - - - - {% for bucket in buckets %} - - {% endfor %} - - - - {% for bucket in buckets %} - - - - {% endfor %} - - {% for f_name in file_names %} - - - {% for bucket in buckets %} - {% if files[f_name][bucket] %} - - - - {% else %} - - {% endif %} - {% endfor %} - - {% endfor %} -
Bucket Name{{ bucket }}
File NameLast ModifiedSizeVersion ID
{{ f_name }}{{ files[f_name][bucket]['last_modified'] }}{{ files[f_name][bucket]['size'] }}{{ files[f_name][bucket]['version'] }}Not Found
- {% endif %} - {% endif %} - {% endif %} - diff --git a/cos2cos/templates/history.html b/cos2cos/templates/history.html deleted file mode 100644 index d68878761..000000000 --- a/cos2cos/templates/history.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - C2C Event History - - - -

Event History

- - - - - - - - - - - {% if events %} - {% for event in events %} - {% if event.objects|length is gt(0) %} - {% for object in event.objects %} - - {% if loop.index0 is eq(0) %} - - - {% endif %} - - - - - - - {% endfor %} - {% else %} - - - - - - {% endif %} - {% endfor %} - {% endif %} -
Triggering EventEvent ReceivedObjectTimestampSource BucketDestination BucketStatus
{{ event.id }}{{ event.timestamp }}{{ object.key }}{{ object.timestamp }}{{ object.source_bucket }}{{ object.destination_bucket }}{{ object.status }}
{{ event.id }}{{ event.timestamp }}No objects found
- diff --git a/cron/Dockerfile b/cron/Dockerfile index f7220487a..f27a1074a 100644 --- a/cron/Dockerfile +++ b/cron/Dockerfile @@ -1,8 +1,10 @@ -FROM icr.io/codeengine/golang:alpine -COPY cron.go / -RUN go build -o /cron /cron.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY cron.go . + +RUN CGO_ENABLED=0 go build -o /go/bin/app cron.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /cron /cron -CMD /cron +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / +CMD ["/app"] diff --git a/cron/run b/cron/run index 308314fcb..9557faaee 100755 --- a/cron/run +++ b/cron/run @@ -21,7 +21,7 @@ set -ex export REGISTRY=${REGISTRY:-icr.io/codeengine} # Create the app -ibmcloud ce app create -n cron-app --image ${REGISTRY}/cron --min-scale=1 +ibmcloud ce app create --name cron-app --cpu 0.125 --memory 0.25G --min-scale=1 --image ${REGISTRY}/cron # Setup the cron Event Source, send event every minute ibmcloud ce sub cron create -n cron-sub -d cron-app \ diff --git a/cronjob/Dockerfile b/cronjob/Dockerfile index d4abfb09b..bca300a5f 100644 --- a/cronjob/Dockerfile +++ b/cronjob/Dockerfile @@ -1,8 +1,9 @@ -FROM icr.io/codeengine/golang:alpine -COPY cronjob.go / -RUN go build -o /cronjob /cronjob.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY cronjob.go . +RUN CGO_ENABLED=0 go build -o /go/bin/job cronjob.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /cronjob /cronjob -CMD /cronjob +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/job / +CMD ["/job"] \ No newline at end of file diff --git a/cronjob/run b/cronjob/run index ee415d814..e231cba4b 100755 --- a/cronjob/run +++ b/cronjob/run @@ -22,7 +22,7 @@ export REGISTRY=${REGISTRY:-icr.io/codeengine} # Create a Job - just it's definition. The "running" instance of it # will be created when the event is sent to it. -ibmcloud ce job create -n cron-job --image ${REGISTRY}/cronjob +ibmcloud ce job create --name cron-job --cpu 0.125 --memory 0.25G --image ${REGISTRY}/cronjob # Setup the cron Event Source, send event every minute ibmcloud ce sub cron create -n cron-job-sub -d cron-job \ diff --git a/daemonjob/Dockerfile b/daemonjob/Dockerfile index f39d686e3..99bf0844d 100644 --- a/daemonjob/Dockerfile +++ b/daemonjob/Dockerfile @@ -1,8 +1,9 @@ -FROM icr.io/codeengine/golang:alpine -COPY daemonjob.go / -RUN go build -o /daemonjob /daemonjob.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY daemonjob.go . +RUN CGO_ENABLED=0 go build -o /go/bin/daemonjob daemonjob.go -# Copy exe into a smaller image -FROM icr.io/codeengine/alpine -COPY --from=0 /daemonjob /daemonjob -CMD /daemonjob +# Copy the exe into a smaller base image +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/daemonjob / +CMD ["/daemonjob"] \ No newline at end of file diff --git a/daemonjob/run b/daemonjob/run index 7714ee415..9327e7127 100755 --- a/daemonjob/run +++ b/daemonjob/run @@ -24,29 +24,35 @@ export REGISTRY=${REGISTRY:-icr.io/codeengine} export NUM=${NUM:-10} # Create a Job definition that will run 10 instances -ibmcloud ce job create --name tester-daemonjob --array-indices=1-${NUM} \ +ibmcloud ce job create --name tester-daemonjob --cpu 0.125 --memory 0.25G --array-indices=1-${NUM} \ --image ${REGISTRY}/daemonjob --mode daemon # Now submit the job using that definition - and wait for it to finish -ibmcloud ce jobrun submit --name tester-daemonjob-doit --job tester-daemonjob --wait +ibmcloud ce jobrun submit --name tester-daemonjob-doit --job tester-daemonjob + +# Wait for 30 seconds +sleep 30 # Now look at a view of the logs to make sure it worked ibmcloud ce jobrun logs --instance tester-daemonjob-doit-1-0 | tee out -# Verify it ran ok +# Verify it runs ok if ! grep "Hello World" out > /dev/null ; then echo "Missing expected outout" exit 1 fi # Now submit a job w/o creating a job definition first - and wait to finish -ibmcloud ce jobrun submit --name tester-daemonjob-doit2 --array-indices=1-${NUM} \ - --image ${REGISTRY}/daemonjob --mode daemon --env MSG="Hi there" --wait +ibmcloud ce jobrun submit --name tester-daemonjob-doit2 --cpu 0.125 --memory 0.25G --array-indices=1-${NUM} \ + --image ${REGISTRY}/daemonjob --mode daemon --env MSG="Hi there" + +# Wait for 30 seconds +sleep 30 # Show the stats about the job ibmcloud ce jobrun get --name tester-daemonjob-doit2 -# Now look at a view of the logs to make sure it worked +# Now look at a view of the logs to make sure it works ibmcloud ce jobrun logs --instance tester-daemonjob-doit2-1-0 | tee out if ! grep "Hi there" out > /dev/null ; then diff --git a/function2job/Dockerfile b/function2job/Dockerfile index 2a71dc87a..7c77eb67b 100644 --- a/function2job/Dockerfile +++ b/function2job/Dockerfile @@ -1,8 +1,9 @@ -FROM icr.io/codeengine/golang:alpine -COPY job.go / -RUN go build -o /job /job.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY . . +RUN CGO_ENABLED=0 go build -o /go/bin/job job.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /job /job -CMD /job +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/job / +CMD ["/job"] \ No newline at end of file diff --git a/function2job/run b/function2job/run index 74e40c6ee..b92d47307 100755 --- a/function2job/run +++ b/function2job/run @@ -72,7 +72,7 @@ ibmcloud ce secret create --name f2j-secret --from-literal CE_API_KEY=${ce_api_k # Create the function ibmcloud ce fn create \ --name f2j-function \ - --runtime nodejs-18 \ + --runtime nodejs-20 \ --inline-code fn.js \ --env-from-secret f2j-secret \ --env CE_REGION=$(echo $project|jq -r '.region_id') \ diff --git a/gallery/README.md b/gallery/README.md index 87aaf86e0..e25eb7288 100644 --- a/gallery/README.md +++ b/gallery/README.md @@ -217,7 +217,7 @@ Utilize local build capabilities, which is able to take your local source code a ``` $ ibmcloud ce fn create --name change-color \ --build-source . \ - --runtime nodejs-18 \ + --runtime nodejs-20 \ --memory 4G \ --cpu 1 \ --env BUCKET=$BUCKET diff --git a/gallery/app/Dockerfile b/gallery/app/Dockerfile index 566546e38..bf5eb0a76 100644 --- a/gallery/app/Dockerfile +++ b/gallery/app/Dockerfile @@ -1,15 +1,18 @@ -FROM icr.io/codeengine/node:22-alpine -RUN apk -U upgrade +FROM registry.access.redhat.com/ubi9/nodejs-20:latest AS build-env +WORKDIR /app # Define which files should be copied into the container image COPY *.js . COPY page.* . -COPY pictures/* /pictures/ +COPY pictures/* pictures/ COPY package.json . # Load all dependencies RUN npm install -# Define how the app is being started +# Use a small distroless image for as runtime image +FROM gcr.io/distroless/nodejs20-debian12 +COPY --from=build-env /app /app +WORKDIR /app EXPOSE 8080 -CMD [ "node", "app.js" ] +CMD ["app.js"] \ No newline at end of file diff --git a/gallery/job/Dockerfile b/gallery/job/Dockerfile index a5f36e1ba..8e3eba4d8 100644 --- a/gallery/job/Dockerfile +++ b/gallery/job/Dockerfile @@ -1,5 +1,5 @@ -FROM icr.io/codeengine/node:22-alpine -RUN apk -U upgrade +FROM registry.access.redhat.com/ubi9/nodejs-20:latest AS build-env +WORKDIR /app # Define which files should be copied into the container image COPY *.js . @@ -8,5 +8,8 @@ COPY package.json . # Load all dependencies RUN npm install -# Define how the job is being started -CMD [ "node", "job.js" ] +# Use a small distroless image for as runtime image +FROM gcr.io/distroless/nodejs20-debian12 +COPY --from=build-env /app /app +WORKDIR /app +CMD ["job.js"] diff --git a/github/Dockerfile b/github/Dockerfile index 26a2d5445..b350be34d 100644 --- a/github/Dockerfile +++ b/github/Dockerfile @@ -1,8 +1,10 @@ -FROM icr.io/codeengine/golang:alpine -COPY github.go / -RUN go build -o /github /github.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY github.go . + +RUN CGO_ENABLED=0 go build -o /go/bin/app github.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /github /github -CMD /github +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / +CMD ["/app"] diff --git a/github/run b/github/run index 5b9255be4..acefb1877 100755 --- a/github/run +++ b/github/run @@ -24,7 +24,7 @@ clean export REGISTRY=${REGISTRY:-icr.io/codeengine} # Create our github webhook processor Application, use secret in a env vars -ibmcloud ce app create -n github --image $REGISTRY/github +ibmcloud ce app create -n github --cpu 0.125 --memory 0.25G --image $REGISTRY/github # Save App's URL for later APP=$(ibmcloud ce app get -n github -o url) diff --git a/hello/Dockerfile b/hello/Dockerfile index 62c65b7b9..71207c024 100644 --- a/hello/Dockerfile +++ b/hello/Dockerfile @@ -1,10 +1,9 @@ -FROM registry.access.redhat.com/ubi9/nodejs-20-minimal:latest AS build-env +FROM registry.access.redhat.com/ubi9/nodejs-20:latest AS build-env WORKDIR /app RUN npm init -f && npm install COPY server.js . -EXPOSE 8080 -CMD [ "node", "server.js" ] +# Use a small distroless image for as runtime image FROM gcr.io/distroless/nodejs20-debian12 COPY --from=build-env /app /app WORKDIR /app diff --git a/helloworld-samples/function-codebundle-nodejs/README.md b/helloworld-samples/function-codebundle-nodejs/README.md index 18ecdd793..c7247db6d 100644 --- a/helloworld-samples/function-codebundle-nodejs/README.md +++ b/helloworld-samples/function-codebundle-nodejs/README.md @@ -5,7 +5,7 @@ A sample nodejs function (main.js) that uses an external npm module referenced b Deploy the function straight to Code Engine by running the following command from the source directory ```bash -ibmcloud ce fn create -n lorem-node -runtime nodejs-18 --build-source . +ibmcloud ce fn create -n lorem-node -runtime nodejs-20 --build-source . ``` For more information follow the official docs -> [Including modules for a Node.js Function](https://cloud.ibm.com/docs/codeengine?topic=codeengine-fun-create-repo#function-nodejs-dep-repo) diff --git a/helloworld/Dockerfile b/helloworld/Dockerfile index e5c7b0d92..a4855f08b 100644 --- a/helloworld/Dockerfile +++ b/helloworld/Dockerfile @@ -1,8 +1,10 @@ -FROM quay.io/app-sre/ubi8-go-toolset AS build-env -COPY helloworld.go . -RUN CGO_ENABLED=0 go build -o /opt/app-root/src/app helloworld.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY . . + +RUN CGO_ENABLED=0 go build -o /go/bin/app helloworld.go # Copy the exe into a smaller base image -FROM registry.access.redhat.com/ubi9-minimal:latest -COPY --from=build-env /opt/app-root/src/app / +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / CMD ["/app"] diff --git a/helloworld/helloworld.go b/helloworld/helloworld.go index 55c814fcf..2c994f0f5 100644 --- a/helloworld/helloworld.go +++ b/helloworld/helloworld.go @@ -234,9 +234,15 @@ func main() { time.Sleep(time.Duration(sleepDuration) * time.Second) } - fmt.Printf("Hello from helloworld! I'm a %s job! Index: %s\n\n", jobMode, jobIndex) + fmt.Printf("Hello from helloworld! I'm a %s job! Index: %s of %s\n\n", jobMode, jobIndex, os.Getenv("JOB_ARRAY_SIZE")) PrintMessage(os.Stdout, os.Getenv("SHOW") == "") + // If the 'CRASH' or 'FAIL' env vars are set then crash! + if os.Getenv("CRASH") != "" || os.Getenv("FAIL") != "" { + fmt.Printf("Crashing...") + os.Exit(1) + } + if jobMode == "task" { // If this job is of type task (aka run-to-completion), let it exit the loop break diff --git a/job/Dockerfile b/job/Dockerfile deleted file mode 100644 index 36f8d1c2e..000000000 --- a/job/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM icr.io/codeengine/golang:alpine -COPY job.go / -RUN go build -o /job /job.go - -# Copy exe into a smaller image -FROM icr.io/codeengine/alpine -COPY --from=0 /job /job -CMD /job diff --git a/job/README.md b/job/README.md deleted file mode 100644 index 32e4de0f2..000000000 --- a/job/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Job - -This sample shows up to run a batch job. It will create the batch job two ways: -1 - first, it'll create a Job definition (the config information about a job) - and then it submits that Job to actually do the work. -2 - second, it'll submit the Job directly without creating the definition - first. Both will generate the same results though. - -Each instance of each Job submitted will print, to its logs, its "index", -which is defined by its `JOB_INDEX` environment variable. The `run` script -will print some of the log files to show this. - -- - - - -As noted in [the main README](../README.md), this sample has two pieces: - -- a `build` script which will build the container image(s) used -- a `run` script which deploys resources that use those images - -The main purpose of this example is the `run` script, but the `build` -script is included for complete educational (and reuse) purposes. diff --git a/job/build b/job/build deleted file mode 100755 index 959a69256..000000000 --- a/job/build +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# Env Vars: -# REGISTRY: name of the image registry/namespace to store the images -# NOCACHE: set this to "--no-cache" to turn off the Docker build cache -# -# NOTE: to run this you MUST set the REGISTRY environment variable to -# your own image registry/namespace otherwise the `docker push` commands -# will fail due to an auth failure. Which means, you also need to be logged -# into that registry before you run it. - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} - -# Build the job image and push it -docker build ${NOCACHE} -t ${REGISTRY}/firstjob -f Dockerfile . --platform linux/amd64 -docker push ${REGISTRY}/firstjob diff --git a/job/job.go b/job/job.go deleted file mode 100644 index a9816d413..000000000 --- a/job/job.go +++ /dev/null @@ -1,10 +0,0 @@ -package main - -import ( - "fmt" - "os" -) - -func main() { - fmt.Printf("Hi from a batch job! My index within the array of %s instance(s) is %s\n", os.Getenv("JOB_ARRAY_SIZE"), os.Getenv("JOB_INDEX")) -} diff --git a/job/run b/job/run deleted file mode 100755 index 103d368c8..000000000 --- a/job/run +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -# Env Vars: -# NUM: number of instances of the job to run -# REGISTRY: name of the image registry/namespace to get the images - -# Clean up previous run -function clean() { - set +ex - echo Cleaning... - ( - ibmcloud ce job delete -n job-job -f - ibmcloud ce jobrun delete -n job-doit -f - ibmcloud ce jobrun delete -n job-doit2 -f - rm -f out - ) > /dev/null 2>&1 -} - -clean -[[ "$1" == "clean" ]] && exit 0 - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} -export NUM=${NUM:-10} - -# Create a Job definition -ibmcloud ce job create --name job-job --array-indices=1-${NUM} \ - --image ${REGISTRY}/firstjob - -# Now submit the job using that definition - and wait for it to finish -ibmcloud ce jobrun submit --name job-doit --job job-job --wait - -# Now submit a job w/o creating a job definition first - and wait to finish -ibmcloud ce jobrun submit --name job-doit2 --array-indices=1-${NUM} \ - --image ${REGISTRY}/firstjob --wait - -# Show the stats about the job -ibmcloud ce jobrun get --name job-doit2 - -# Now look at a view of the logs to make sure it worked -ibmcloud ce jobrun logs --instance job-doit2-1-0 | tee out - -if ! grep "Hi from" out > /dev/null ; then - echo "Missing expected outout" - exit 1 -fi - -# Clean up -clean diff --git a/job2app/Dockerfile b/job2app/Dockerfile index 2a71dc87a..2c67dc615 100644 --- a/job2app/Dockerfile +++ b/job2app/Dockerfile @@ -1,8 +1,10 @@ -FROM icr.io/codeengine/golang:alpine -COPY job.go / -RUN go build -o /job /job.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY job.go . + +RUN CGO_ENABLED=0 go build -o /go/bin/app job.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /job /job -CMD /job +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / +CMD ["/app"] diff --git a/job2app/Dockerfile.app b/job2app/Dockerfile.app index 64724a2f1..d849c7d51 100644 --- a/job2app/Dockerfile.app +++ b/job2app/Dockerfile.app @@ -1,8 +1,10 @@ -FROM icr.io/codeengine/golang:alpine -COPY app.go / -RUN go build -o /app /app.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY app.go . + +RUN CGO_ENABLED=0 go build -o /go/bin/app app.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /app /app -CMD /app +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / +CMD ["/app"] diff --git a/job2app/job.go b/job2app/job.go index 60a80f1bf..1e9869801 100644 --- a/job2app/job.go +++ b/job2app/job.go @@ -10,20 +10,12 @@ import ( ) func main() { - // Get the namespace we're in so we know how to talk to the App - file := "/var/run/secrets/kubernetes.io/serviceaccount/namespace" - namespace, err := ioutil.ReadFile(file) - if err != nil || len(namespace) == 0 { - fmt.Fprintf(os.Stderr, "Missing namespace: %s\n%s\n", err, namespace) - os.Exit(1) - } - count := 10 fmt.Printf("Sending %d requests...\n", count) wg := sync.WaitGroup{} // URL to the App - url := "http://j2a-app." + string(namespace) + ".svc.cluster.local" + url := "http://j2a-app." + os.Getenv("CE_SUBDOMAIN") + ".svc.cluster.local" // Do all requests to the App in parallel - why not? for i := 0; i < count; i++ { diff --git a/job2app/run b/job2app/run index 3e866c097..cc0c1d693 100755 --- a/job2app/run +++ b/job2app/run @@ -22,13 +22,13 @@ export REGISTRY=${REGISTRY:-icr.io/codeengine} export COUNT=${COUNT:-50} # Create the app -ibmcloud ce app create -n j2a-app --min=1 --max=1 --image ${REGISTRY}/j2a-app +ibmcloud ce app create -n j2a-app --min=1 --max=1 --cpu 0.125 --memory 0.25G --image ${REGISTRY}/j2a-app # Get metadata about the app for later use URL=$(ibmcloud ce app get -n j2a-app -o url) # Create/run the job, passing in the project/namespace - and wait to finish -ibmcloud ce jobrun submit -n j2a-job --ai=1-${COUNT} \ +ibmcloud ce jobrun submit -n j2a-job --ai=1-${COUNT} --cpu 0.125 --memory 0.25G \ --image ${REGISTRY}/j2a-job --wait # Check the app to see how many times it was hit diff --git a/metrics-collector/Dockerfile b/metrics-collector/Dockerfile index b717c3c48..f1cd5bc1f 100644 --- a/metrics-collector/Dockerfile +++ b/metrics-collector/Dockerfile @@ -1,11 +1,11 @@ -FROM icr.io/codeengine/golang:alpine -RUN apk -U upgrade -ENV GOTOOLCHAIN auto -COPY . / -RUN go build -o /main /main.go +FROM quay.io/projectquay/golang:1.22 AS build-env +WORKDIR /go/src/app +COPY . . + +RUN go mod download +RUN CGO_ENABLED=0 go build -o /go/bin/app main.go # Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -RUN apk -U upgrade -COPY --from=0 /main /main -CMD /main +FROM gcr.io/distroless/static-debian12 +COPY --from=build-env /go/bin/app / +CMD ["/app"] diff --git a/metrics-collector/go.mod b/metrics-collector/go.mod index 76a841fff..e8244ff03 100644 --- a/metrics-collector/go.mod +++ b/metrics-collector/go.mod @@ -37,7 +37,6 @@ require ( golang.org/x/term v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect golang.org/x/time v0.5.0 // indirect - google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/metrics-collector/go.sum b/metrics-collector/go.sum index 1c78d1e69..4960d47b7 100644 --- a/metrics-collector/go.sum +++ b/metrics-collector/go.sum @@ -1,58 +1,38 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -61,11 +41,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= @@ -81,104 +58,61 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= -github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= -github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= +github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -189,39 +123,22 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.29.2 h1:hBC7B9+MU+ptchxEqTNW2DkUosJpp1P+Wn6YncZ474A= -k8s.io/api v0.29.2/go.mod h1:sdIaaKuU7P44aoyyLlikSLayT6Vb7bvJNCX105xZXY0= k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY= k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM= -k8s.io/apimachinery v0.29.2 h1:EWGpfJ856oj11C52NRCHuU7rFDwxev48z+6DSlGNsV8= -k8s.io/apimachinery v0.29.2/go.mod h1:6HVkd1FwxIagpYrHSwJlQqZI3G9LfYWRPAkUvLnXTKU= k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U= k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/client-go v0.29.2 h1:FEg85el1TeZp+/vYJM7hkDlSTFZ+c5nnK44DJ4FyoRg= -k8s.io/client-go v0.29.2/go.mod h1:knlvFZE58VpqbQpJNbCbctTVXcd35mMyAAwBdpt4jrA= k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q= k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGcXawNMouPECM1+F9BVxEaM= k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro= -k8s.io/kubectl v0.29.2 h1:uaDYaBhumvkwz0S2XHt36fK0v5IdNgL7HyUniwb2IUo= -k8s.io/kubectl v0.29.2/go.mod h1:BhizuYBGcKaHWyq+G7txGw2fXg576QbPrrnQdQDZgqI= k8s.io/kubectl v0.30.1 h1:sHFIRI3oP0FFZmBAVEE8ErjnTyXDPkBcvO88mH9RjuY= k8s.io/kubectl v0.30.1/go.mod h1:7j+L0Cc38RYEcx+WH3y44jRBe1Q1jxdGPKkX0h4iDq0= -k8s.io/metrics v0.29.2 h1:oLSTHEr40V7c7C8wDRRhiAefjGRHROK5zeV8NT0tpzc= -k8s.io/metrics v0.29.2/go.mod h1:cWzACDpKElWhm0CElwfK+7I39wDNbmDDCX7hywjvgR4= k8s.io/metrics v0.30.1 h1:PeA9cP0kxVtaC8Wkzp4sTkr7YSkd9R0UYP6cCHOOY1M= k8s.io/metrics v0.30.1/go.mod h1:gVAhTTgfNKsn9D1kB7Nmb1T31relBuXzzGUE7klyOkM= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak= k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/private/Dockerfile.backend b/private/Dockerfile.backend deleted file mode 100644 index 7b1783b48..000000000 --- a/private/Dockerfile.backend +++ /dev/null @@ -1,8 +0,0 @@ -FROM icr.io/codeengine/golang:alpine -COPY backend.go / -RUN go build -o /backend /backend.go - -# Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /backend /backend -CMD /backend diff --git a/private/Dockerfile.frontend b/private/Dockerfile.frontend deleted file mode 100644 index a472f341d..000000000 --- a/private/Dockerfile.frontend +++ /dev/null @@ -1,8 +0,0 @@ -FROM icr.io/codeengine/golang -COPY frontend.go / -RUN go build -o /frontend /frontend.go - -# Copy the exe into a smaller base image -FROM icr.io/codeengine/ubuntu -COPY --from=0 /frontend /frontend -CMD /frontend diff --git a/private/README.md b/private/README.md deleted file mode 100644 index 098f1dc39..000000000 --- a/private/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Private - -Demo that shows how to create a "private" application that is only accessible -from within the Code Engine product. Meaning, it does not have an external -endpoint/URL that is reachable from the internal. - -In this example we'll create 2 apps, `frontend` and `backend`. `frontend` -will be a normal app, accessible from the internet. `backend` is private and -is only accessible to `frontend`. Calling `frontend` will `curl` the `backend` -app and then include its response in the output back to the user. - -- - - - -As noted in [the main README](../README.md), this sample has two pieces: - -- a `build` script which will build the container image(s) used -- a `run` script which deploys resources that use those images - -The main purpose of this example is the `run` script, but the `build` -script is included for complete educational (and reuse) purposes. diff --git a/private/backend.go b/private/backend.go deleted file mode 100644 index 4ce6f3173..000000000 --- a/private/backend.go +++ /dev/null @@ -1,19 +0,0 @@ -package main - -import ( - "fmt" - "net/http" - "time" -) - -func main() { - // Process incoming http request - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - // Just say HI along with the time - fmt.Fprintf(w, "Hello from the backend. The time is now: %s\n", - time.Now().Format(time.Kitchen)) - }) - - fmt.Printf("Listening on port 8080\n") - http.ListenAndServe(":8080", nil) -} diff --git a/private/build b/private/build deleted file mode 100755 index a2e4c2bdf..000000000 --- a/private/build +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -# Env Vars: -# REGISTRY: name of the image registry/namespace to store the images -# NOCACHE: set this to "--no-cache" to turn off the Docker build cache -# -# NOTE: to run this you MUST set the REGISTRY environment variable to -# your own image registry/namespace otherwise the `docker push` commands -# will fail due to an auth failure. Which means, you also need to be logged -# into that registry before you run it. - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} - -# Build the image -docker build ${NOCACHE} -t ${REGISTRY}/priv-front -f Dockerfile.frontend . --platform linux/amd64 -docker build ${NOCACHE} -t ${REGISTRY}/priv-back -f Dockerfile.backend . --platform linux/amd64 - -# And push it -docker push ${REGISTRY}/priv-front -docker push ${REGISTRY}/priv-back diff --git a/private/frontend.go b/private/frontend.go deleted file mode 100644 index ccf4dc3a7..000000000 --- a/private/frontend.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "fmt" - "io/ioutil" - "net/http" -) - -func main() { - // Get our namespace (aka Code Engine project) - ns := "" - dir := "/var/run/secrets/kubernetes.io/serviceaccount" - - if buf, err := ioutil.ReadFile(dir + "/namespace"); err != nil { - panic(fmt.Sprintf("Can't read namespace: %s\n", err)) - } else { - ns = string(buf) - } - - // Process incoming http request - http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { - // Calc backend URL and GET it - backend := fmt.Sprintf("http://backend.%s.svc.cluster.local", ns) - - res, err := http.Get(backend) - if err != nil || res.StatusCode/100 != 2 { - w.WriteHeader(http.StatusInternalServerError) - if err != nil { - fmt.Fprintf(w, "Error reaching backend: %s\n", err) - } else { - fmt.Fprintf(w, "Error reaching backend: %s\n", res.Status) - } - return - } - - body, _ := ioutil.ReadAll(res.Body) - - // Return nice response - fmt.Fprint(w, "Hello from the front-end\n") - fmt.Fprintf(w, "The backend says: %s\n", string(body)) - }) - - fmt.Printf("Listening on port 8080\n") - http.ListenAndServe(":8080", nil) -} diff --git a/private/run b/private/run deleted file mode 100755 index c68e6735c..000000000 --- a/private/run +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -# Env Vars: -# REGISTRY: name of the image registry/namespace to get the images - -# Clean up previous run -function clean() { - set +ex - echo Cleaning... - ( - ibmcloud ce app delete -n frontend -f - ibmcloud ce app delete -n backend -f - rm -f out - ) > /dev/null 2>&1 -} - -clean -[[ "$1" == "clean" ]] && exit 0 - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} - -# Create our frontend and backend apps. -# Note that the "backend" app is "cluster local", meaning that it does -# not get assign a public facing URL. Only the "frontend" app can access it -ibmcloud ce app create -n backend --image ${REGISTRY}/priv-back --cluster-local -ibmcloud ce app create -n frontend --image ${REGISTRY}/priv-front - -# Get the URL of the app for later use -URL=$(ibmcloud ce app get -n frontend -o url) - -# Now call it (stop if curl fails) -curl -fsw "%{http_code}\n" $URL | tee out -[[ "${PIPESTATUS[0]}" == "0" ]] - -# Verify the frontend got the right output from the backend -if ! grep "The time is now" out > /dev/null ; then - echo "Missing expected output" - exit 1 -fi - -# Clean up -clean diff --git a/s2i-buildpacks/README.md b/s2i-buildpacks/README.md deleted file mode 100644 index c8fd47e40..000000000 --- a/s2i-buildpacks/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Source-to-Image with Buildpacks - -This sample shows how to use the Code Engine source-to-image feature using -Buildpacks to build your application from a git repo, push the image into a -registry, and then deploy it as a Code Engine application. It doesn't require -a Dockerfile in the git repo. - -More details and supported runtimes and versions can be found in [Code Engine -Docs](https://cloud.ibm.com/docs/codeengine?topic=codeengine-plan-build). - -The exact steps taken in [`run`](./run) are: -- Create an ICR (IBM Container Registry) namespace to store the resulting image -- Create an IBM API Key that will be used by the build process to push the - image to ICR -- Define a build that points to a git repo for the source, and then defines - where in ICR to store the image -- Creates a Code Engine app from that image diff --git a/s2i-buildpacks/package.json b/s2i-buildpacks/package.json deleted file mode 100644 index 2c77d9323..000000000 --- a/s2i-buildpacks/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "author": "Code Engine", - "dependencies": { - "express": "^4.17.0" - }, - "description": "Sample Node.js Application using NPM", - "license": "Apache-2.0", - "name": "sample", - "repository": { - "type": "git", - "url": "https://github.com/IBM/CodeEngine" - }, - "version": "0.0.0" -} diff --git a/s2i-buildpacks/run b/s2i-buildpacks/run deleted file mode 100755 index 5d330f24d..000000000 --- a/s2i-buildpacks/run +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash - -# Define our ICR Namespace env var for later use -ID=$(ibmcloud ce project current | sed -n "s/^Subdomain: *\([^ ]*\).*$/\1/p") -ICR_NS=s2i-b-${ID:1:12} - -# Clean up previous run -function clean() { - set +ex - echo Cleaning... - ( - ibmcloud cr namespace-rm "${ICR_NS}" -f - ibmcloud ce app delete -n s2i-bapp -f - ibmcloud ce registry delete -n s2i-bicr -f - ibmcloud ce buildrun delete -n s2i-brun -f - ibmcloud ce build delete -n s2i-bbuild -f - ibmcloud iam api-keys | grep s2i-bapi | sed "s/.*\(ApiKey\)/\1/" | while read a - do - ibmcloud iam api-key-delete -f $a - done - rm -f out .ce-reg-secret || true - ) > /dev/null 2>&1 -} - -clean -[[ "$1" == "clean" ]] && exit 0 - -# Grab the ICR server location based no our region -export ICR=$(ibmcloud cr info | sed -n 's/.*Registry *\(.*icr.io\).*/\1/p') - -set -ex - -# Create an ICR namespace to hold our new image -ibmcloud cr namespace-add $ICR_NS - -# Create an apikey, put it in a registry secret. Used to push/pull image to ICR -ibmcloud iam api-key-create s2i-bapi | \ - grep "API Key" | sed 's/^.*Key *//' | sed "s/ *$//" > .ce-reg-secret -ibmcloud ce registry create -n s2i-bicr -s $ICR -u iamapikey \ - --password-from-file .ce-reg-secret - -# Define the build of this dir in this github repo -ibmcloud ce build create -n s2i-bbuild -i "$ICR/${ICR_NS}/app" --rs s2i-bicr \ - --source https://github.com/IBM/CodeEngine --context-dir s2i-buildpacks \ - --strategy buildpacks - -# Now kick off the build itself -ibmcloud ce buildrun submit -n s2i-brun --build s2i-bbuild --wait - -# Test the image we just built - deploy an app and 'curl' it -ibmcloud ce app create -n s2i-bapp --image "$ICR/${ICR_NS}/app" --rs s2i-bicr -URL=$(ibmcloud ce app get -n s2i-bapp -o url) -curl -fs "${URL}" | tee out -[[ "${PIPESTATUS[0]}" == "0" ]] - -if ! grep "I was built" out > /dev/null ; then - echo "Missing expected outout" - exit 1 -fi - -# Clean -clean diff --git a/s2i-buildpacks/server.js b/s2i-buildpacks/server.js deleted file mode 100644 index 8a5dd8c09..000000000 --- a/s2i-buildpacks/server.js +++ /dev/null @@ -1,18 +0,0 @@ -const express = require('express'); -const port = process.env.PORT || 8080; - -const app = express(); - -app.get('/', (request, response) => { - response.send(` - - - Powered By Code Engine - - - I was built by Buildpacks with Code Engine! - -`); -}); - -app.listen(port); diff --git a/s2i-dockerfile/Dockerfile b/s2i-dockerfile/Dockerfile deleted file mode 100644 index 2ced8ca0a..000000000 --- a/s2i-dockerfile/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM icr.io/codeengine/golang:alpine -COPY app.go / -RUN go build -o /app /app.go - -# Copy the exe into a smaller base image -FROM icr.io/codeengine/alpine -COPY --from=0 /app /app -CMD /app diff --git a/s2i-dockerfile/README.md b/s2i-dockerfile/README.md deleted file mode 100644 index 87197397a..000000000 --- a/s2i-dockerfile/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Source-to-Image with a Dockerfile - -This sample shows how to use the Code Engine source-to-image feature using -a Dockerfile to build your application from a git repo, push the image into a -registry, and then deploy it as a Code Engine application. This will assume -that there's a Dockerfile in the root of the build context that will be used -to build the image. - -More details can be found in [Code Engine -Docs](https://cloud.ibm.com/docs/codeengine?topic=codeengine-plan-build). - -The exact steps taken in [`run`](./run) are: -- Create an ICR (IBM Container Registry) namespace to store the resulting image -- Create an IBM API Key that will be used by the build process to push the - image to ICR -- Define a build that points to a git repo for the source, and then define - where in ICR to store the image -- Creates a Code Engine app from that image diff --git a/s2i-dockerfile/app.go b/s2i-dockerfile/app.go deleted file mode 100644 index 46e7ed02b..000000000 --- a/s2i-dockerfile/app.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "fmt" - "net/http" -) - -func Handler(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "\n\nI was built with a Dockerfile by Code Engine!\n\n\n") -} - -func main() { - http.HandleFunc("/", Handler) - fmt.Printf("Listening on port 8080") - http.ListenAndServe(":8080", nil) -} diff --git a/s2i-dockerfile/run b/s2i-dockerfile/run deleted file mode 100755 index 7442ed1e9..000000000 --- a/s2i-dockerfile/run +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -# Define our ICR Namespace env var for later use -ID=$(ibmcloud ce project current | sed -n "s/^Subdomain: *\([^ ]*\).*$/\1/p") -ICR_NS=s2i-d-${ID:0:12} - -# Clean up previous run -function clean() { - set +ex - echo Cleaning... - ( - ibmcloud cr namespace-rm "${ICR_NS}" -f - ibmcloud ce app delete -n s2i-dockerfile -f - ibmcloud ce registry delete -n s2i-dicr -f - ibmcloud ce buildrun delete -n s2i-drun -f - ibmcloud ce build delete -n s2i-dbuild -f - ibmcloud iam api-keys | grep s2i-dapi | sed "s/.*\(ApiKey\)/\1/" | while read a - do - ibmcloud iam api-key-delete -f $a - done - rm -f out .ce-reg-secret || true - ) > /dev/null 2>&1 -} - -clean -[[ "$1" == "clean" ]] && exit 0 - -# Grab the ICR server location based no our region -export ICR=$(ibmcloud cr info | sed -n 's/.*Registry *\(.*icr.io\).*/\1/p') - -set -ex - -# Create an ICR namespace to hold our new image -ibmcloud cr namespace-add $ICR_NS - -# Create an apikey, put it in a registry secret. Used to push/pull image to ICR -ibmcloud iam api-key-create s2i-dapi | \ - grep "API Key" | sed 's/^.*Key *//' | sed "s/ *$//" > .ce-reg-secret -ibmcloud ce registry create -n s2i-dicr -s $ICR -u iamapikey \ - --password-from-file .ce-reg-secret - -# Define the build of this dir in this github repo -ibmcloud ce build create -n s2i-dbuild -i "$ICR/${ICR_NS}/app" --rs s2i-dicr \ - --source https://github.com/IBM/CodeEngine --context-dir s2i-dockerfile - -# Now kick off the build itself -ibmcloud ce buildrun submit -n s2i-drun --build s2i-dbuild --wait - -# Test the image we just built - deploy an app and 'curl' it -ibmcloud ce app create -n s2i-dockerfile --image "$ICR/${ICR_NS}/app" --rs s2i-dicr -URL=$(ibmcloud ce app get -n s2i-dockerfile -o url) -curl -fs "${URL}" | tee out -[[ "${PIPESTATUS[0]}" == "0" ]] - -if ! grep "I was built" out > /dev/null ; then - echo "Missing expected outout" - exit 1 -fi - -# Clean -clean diff --git a/testjob/Dockerfile b/testjob/Dockerfile deleted file mode 100644 index f5ff87e15..000000000 --- a/testjob/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM icr.io/codeengine/golang:alpine -COPY testjob.go / -RUN go build -o /testjob /testjob.go - -# Copy exe into a smaller image -FROM icr.io/codeengine/alpine -COPY --from=0 /testjob /testjob -CMD /testjob diff --git a/testjob/README.md b/testjob/README.md deleted file mode 100644 index c261ed898..000000000 --- a/testjob/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Test JOb - -This sample shows up to run a batch job. This is very similar to the -[job](../job) sample but this code will allow you to modify the behavior -of the code through the following environment variables: - - `MSG` : specifies the message printed to the logs. By default it will be - a simple "Hello World" type of message - - `TARGET` : When the default message is printed, you can change the word - "World" to something else by setting the `TARGET` environment variable. - - `SLEEP` : will tell the code to sleep for the specified number of seconds - before exiting. - - `CRASH` : will tell the code to exit with a non-zero exit code. This is - useful if you want to test the job "retry" logic. - -The code will also print the list of environment variables to the log file -for debugging purposes. - -The sample script will also submit the job twice. First by creating a -job definition, followed by submitting it, and then it will submit a new -job directly without first creating a job definition. In the second case -it will also change the message printed via the `MSG` environment variable. - -- - - - -As noted in [the main README](../README.md), this sample has two pieces: - -- a `build` script which will build the container image(s) used -- a `run` script which deploys resources that use those images - -The main purpose of this example is the `run` script, but the `build` -script is included for complete educational (and reuse) purposes. diff --git a/testjob/build b/testjob/build deleted file mode 100755 index df3636975..000000000 --- a/testjob/build +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -# Env Vars: -# REGISTRY: name of the image registry/namespace to store the images -# NOCACHE: set this to "--no-cache" to turn off the Docker build cache -# -# NOTE: to run this you MUST set the REGISTRY environment variable to -# your own image registry/namespace otherwise the `docker push` commands -# will fail due to an auth failure. Which means, you also need to be logged -# into that registry before you run it. - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} - -# Build the job image and push it -docker build ${NOCACHE} -t ${REGISTRY}/testjob -f Dockerfile . --platform linux/amd64 -docker push ${REGISTRY}/testjob diff --git a/testjob/run b/testjob/run deleted file mode 100755 index ab6ec73db..000000000 --- a/testjob/run +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -# Env Vars: -# NUM: number of instances of the job to run -# REGISTRY: name of the image registry/namespace to get the images - -# Clean up previous run -function clean() { - set +ex - echo Cleaning... - ( - ibmcloud ce job delete -n tester-j -f - ibmcloud ce jobrun delete -n tester-doit -f - ibmcloud ce jobrun delete -n tester-doit2 -f - rm -f out - ) > /dev/null 2>&1 -} - -clean -[[ "$1" == "clean" ]] && exit 0 - -set -ex -export REGISTRY=${REGISTRY:-icr.io/codeengine} -export NUM=${NUM:-10} - -# Create a Job definition that will run 10 instances -ibmcloud ce job create --name tester-j --array-indices=1-${NUM} \ - --image ${REGISTRY}/testjob - -# Now submit the job using that definition - and wait for it to finish -ibmcloud ce jobrun submit --name tester-doit --job tester-j --wait - -# Now look at a view of the logs to make sure it worked -ibmcloud ce jobrun logs --instance tester-doit-1-0 | tee out - -# Verify it ran ok -if ! grep "Hello World" out > /dev/null ; then - echo "Missing expected outout" - exit 1 -fi - -# Now submit a job w/o creating a job definition first - and wait to finish -ibmcloud ce jobrun submit --name tester-doit2 --array-indices=1-${NUM} \ - --image ${REGISTRY}/testjob --env MSG="Hi there" --wait - -# Show the stats about the job -ibmcloud ce jobrun get --name tester-doit2 - -# Now look at a view of the logs to make sure it worked -ibmcloud ce jobrun logs --instance tester-doit2-1-0 | tee out - -if ! grep "Hi there" out > /dev/null ; then - echo "Missing expected outout" - exit 1 -fi - -# Clean up -clean diff --git a/testjob/testjob.go b/testjob/testjob.go deleted file mode 100644 index 3dc8597a5..000000000 --- a/testjob/testjob.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - "fmt" - "os" - "sort" - "strconv" - "strings" - "time" -) - -func main() { - // MSG env var allows you to edit our message - msg := os.Getenv("MSG") - if msg == "" { - target := os.Getenv("TARGET") - if target == "" { - target = "World" - } - msg = "Hello " + target + "!" - } - - // Just for debugging... show the env vars if DEBUG is set - envs := os.Environ() - sort.StringSlice(envs).Sort() - fmt.Printf("Envs:\n%s\n", strings.Join(envs, "\n")) - - // If the 'SLEEP' env var is set then sleep for that many seconds - if t := os.Getenv("SLEEP"); t != "" { - len, _ := strconv.Atoi(t) - fmt.Printf("Sleeping %d", len) - time.Sleep(time.Duration(len) * time.Second) - } - - // If the 'CRASH' or 'FAIL' env vars are set then crash! - if os.Getenv("CRASH") != "" || os.Getenv("FAIL") != "" { - fmt.Printf("Crashing...") - os.Exit(1) - } - - fmt.Printf("%s\n", msg) -}