Skip to content

Commit

Permalink
add default app to root
Browse files Browse the repository at this point in the history
Signed-off-by: Doug Davis <[email protected]>
  • Loading branch information
Doug Davis committed Feb 23, 2021
1 parent 433e2b8 commit b37a036
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 96 deletions.
8 changes: 8 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM golang:alpine
COPY codeengine.go /
RUN go build -o /codeengine /codeengine.go

# Copy the exe into a smaller base image
FROM alpine
COPY --from=0 /codeengine /codeengine
CMD /codeengine
4 changes: 2 additions & 2 deletions bin/build-all
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

# This will build and run all demos.
# This will build and all demos.
#
# NOTE: to run this you MUST set the REGISTRY environment variable to
# your own image registry/namespace otherwise the `docker push` commands
Expand All @@ -10,7 +10,7 @@
cd $(dirname $0)/..

set -e
for file in `find . -name run | sort` ; do (
for file in `find . -name build | sort` ; do (

echo -e "\n### `dirname $file`\n"
cd `dirname $file`
Expand Down
14 changes: 14 additions & 0 deletions bin/prep
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

set +x
set -e

# Make sure we're pointing to a Code Engine project
ic ce project current > out 2>&1 || (cat out && rm out && exit 1)
rm out

# If $REGISTRY_SECRET is defined, then define $REG_SEC so we can use it later
# on, and prepend it with the `--rs` flag
if [[ -n "$REGISTRY_SECRET" ]]; then
export REG_SEC="--rs $REGISTRY_SECRET"
fi
28 changes: 13 additions & 15 deletions bin/run-all-parallel
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ cd $(dirname $0)/..
echo "Cleaning..."
bin/clean > /dev/null 2>&1

rm -f run-all.out run-fail.out

set -e
(time (
for file in `find . -name run | sort` ; do
Expand Down Expand Up @@ -60,34 +62,30 @@ set -e
echo
)) 2>&1 | tee run-all.out

res="0"
for file in `find . -name run | sort` ; do
dir=`dirname $file`
dir=${dir:2} # remove leading ./

if [[ -e ${dir}.fail ]]; then
rm ${dir}.fail
res=1
echo -e "\n### $dir\n" >> run-all.out
tail ${dir}.out >> run-all.out
echo >> run-all.out
echo -e "\n### $dir\n" >> run-fail.out
tail ${dir}.out >> run-fail.out
fi

if [[ -e ${dir}.out ]]; then
echo -e "\n### $dir\n"
cat ${dir}.out
echo -e "\n### $dir\n" >> run-all.out
cat ${dir}.out >> run-all.out
echo >> run-all.out
rm ${dir}.out
fi
done

echo
cat run-all.out
rm run-all.out
echo

if [[ "$res" == "0" ]]; then
echo "PASSED"
if [[ ! -e run-fail.out ]]; then
echo -e "\nPASSED"
else
echo "FAILED!"
echo -e "\n### Failing tests:"
cat run-fail.out
rm run-fail.out
echo -e "\nFAILED!"
exit 1
fi
1 change: 1 addition & 0 deletions codeengine.go
3 changes: 3 additions & 0 deletions helloworld/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ Check the source code for all of the things you can make it do either via
environment variables or query parameters. This is good for testing the
system to see how it reacts - for example, when the app crashes.

Note: we added some extra logic to this so I can also be used as a batch job
but you can ignore that if all you care about is the App side of things.

- - -

As noted in [the main README](../README.md), this sample has two pieces:
Expand Down
4 changes: 4 additions & 0 deletions helloworld/build
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ docker build -t ${REGISTRY}/helloworld .

# And push it
docker push ${REGISTRY}/helloworld

# Copy the image so it's also called ${REGISTRY}/codeengine, and push it
docker tag ${REGISTRY}/helloworld ${REGISTRY}/codeengine
docker push ${REGISTRY}/codeengine
199 changes: 120 additions & 79 deletions helloworld/helloworld.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
package main

// If you're just starting out please see the "hello" sample instead. While
// this one is relatively simple, if has quite a few extra flags that can
// be set to control how the code behaves at runtime. So, this is great
// for debugging and exploring those options - but not great if you want
// to see the bare minimum needed to start an app.

// The main purpose of this is to run an App (http server), however, it
// can also be used as a Batch Job if the JOB_INDEX env var is set - which
// is set by the Code Engine batch processor. This can be useful if you want
// the same code to be used for both Apps and Jobs. In this respect it's
// very similar to the app-n-job sample, but this has all of the interesting
// debug/configuration flags that can be tweaked.

import (
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
Expand All @@ -19,6 +33,8 @@ func Curl(url string) (string, error) {
}

var GlobalDebug = (os.Getenv("DEBUG") != "")
var envs = []string{}
var msg = ""

func Debug(doit bool, format string, args ...interface{}) {
// If either is 'true' then print it
Expand All @@ -30,6 +46,83 @@ func Debug(doit bool, format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, format, args...)
}

// Just print an cool essage to the Writer that's passed in
func PrintMessage(w io.Writer) {
fmt.Fprintf(w, `%s:
___ __ ____ ____
/ __)/ \( \( __)
( (__( O )) D ( ) _)
\___)\__/(____/(____)
____ __ _ ___ __ __ _ ____
( __)( ( \ / __)( )( ( \( __)
) _) / /( (_ \ )( / / ) _)
(____)\_)__) \___/(__)\_)__)(____)
`, msg)

fmt.Fprintf(w, "Some Env Vars:\n")
fmt.Fprintf(w, "--------------\n")
for _, env := range envs {
fmt.Fprintf(w, "%s\n", env)
}
}

// This func will handle all incoming HTTP requests
func HandleHTTP(w http.ResponseWriter, r *http.Request) {
body := []byte{}
debug := false

// If there's a body then read it in for later use
if r.Body != nil {
body, _ = ioutil.ReadAll(r.Body)
}

// Turn on debugging if the 'debug' query param is there. Just for
// this request tho - unless global debug is set.
if _, ok := r.URL.Query()["debug"]; ok {
debug = true
}

Debug(debug, "%s:\n%s %s\nHeaders:\n%s\n\nBody:\n%s\n",
time.Now().String(), r.Method, r.URL, r.Header, string(body))

// If the 'sleep' query parameter is passed in then sleep for
// that many seconds
if t := r.URL.Query().Get("sleep"); t != "" {
len, _ := strconv.Atoi(t)
Debug(debug, "Sleeping %d", len)
time.Sleep(time.Duration(len) * time.Second)
}

// If the 'crash' query parameter is passed in then crash!
if r.URL.Query().Get("crash") != "" {
Debug(debug, "Crashing...")
os.Exit(1)
}

// If 'fail' query parameter is there then return its value
// as the HTTP return code, defaults to '500'
if t, ok := r.URL.Query()["fail"]; ok {
status := 500

if t != nil && t[0] != "" {
status, _ = strconv.Atoi(t[0])
}
Debug(debug, "Failing with: %d", status)
w.WriteHeader(status)
}

// If there's no 'body' then just print something neat.
// But if there is a body, echo it back to the client.
if len(body) == 0 {
w.Header().Add("Content-Type", "text/plain")
// http://patorjk.com/software/taag/#p=display&f=Graceful&t=Code%0AEngine
PrintMessage(w)
} else {
fmt.Fprintf(w, string(body)+"\n")
}
}

func main() {
// If env var CRASH is set then crash immediately.
// If its value is of the form HH:MM then crash at the specified time
Expand Down Expand Up @@ -59,7 +152,10 @@ func main() {
}
}

msg := os.Getenv("MSG")
// Figure out what message we want to print. You can override this
// via the "MSG" environment variable. Or, you can just change who
// it says hello to via the "TARGET" environment variable
msg = os.Getenv("MSG")
if msg == "" {
target := os.Getenv("TARGET")
if target == "" {
Expand All @@ -69,89 +165,34 @@ func main() {
}

// Get the list of env vars, and sort them for easy reading
envs := os.Environ()
envs = os.Environ()
sort.StringSlice(envs).Sort()
Debug(false, "Envs:\n%s", strings.Join(envs, "\n"))

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
body := []byte{}
debug := false

// If there's a body then read it in for later use
if r.Body != nil {
body, _ = ioutil.ReadAll(r.Body)
}

// Turn on debugging if the 'debug' query param is there. Just for
// this request tho - unless global debug is set.
if _, ok := r.URL.Query()["debug"]; ok {
debug = true
}

Debug(debug, "%s:\n%s %s\nHeaders:\n%s\n\nBody:\n%s\n",
time.Now().String(), r.Method, r.URL, r.Header, string(body))

// If the 'sleep' query parameter is passed in then sleep for
// that many seconds
if t := r.URL.Query().Get("sleep"); t != "" {
len, _ := strconv.Atoi(t)
Debug(debug, "Sleeping %d", len)
time.Sleep(time.Duration(len) * time.Second)
}

// If the 'crash' query parameter is passed in then crash!
if r.URL.Query().Get("crash") != "" {
Debug(debug, "Crashing...")
os.Exit(1)
}

// If 'fail' query parameter is there then return its value
// as the HTTP return code, defaults to '500'
if t, ok := r.URL.Query()["fail"]; ok {
status := 500

if t != nil && t[0] != "" {
status, _ = strconv.Atoi(t[0])
// Real work.
// If we're being run as a Batch Jobthen the JOB_INDEX env var
// will be set. In which case, just print the message to stdout.
// Otherwise we're an App and we need to start the HTTP server
// to processing incoming requests
if jobIndex := os.Getenv("JOB_INDEX"); jobIndex != "" {
fmt.Printf("Hello from helloworld! I'm a batch job! Index: %s\n\n",
jobIndex)
PrintMessage(os.Stdout)

} else {
// Debug the http handler for all requests
http.HandleFunc("/", HandleHTTP)

// HTTP_DELAY will pause for 'delay' seconds before starting the
// HTTP server. This is useful for simulating a long readiness probe
if delay := os.Getenv("HTTP_DELAY"); delay != "" {
if sec, _ := strconv.Atoi(delay); sec != 0 {
Debug(false, "Sleeping %d seconds", sec)
time.Sleep(time.Duration(sec) * time.Second)
}
Debug(debug, "Failing with: %d", status)
w.WriteHeader(status)
}

// If there's no 'body' then just print something neat.
// But if there is a body, echo it back to the client.
if len(body) == 0 {
w.Header().Add("Content-Type", "text/plain")
// http://patorjk.com/software/taag/#p=display&f=Graceful&t=Code%0AEngine
fmt.Fprintf(w, `%s:
___ __ ____ ____
/ __)/ \( \( __)
( (__( O )) D ( ) _)
\___)\__/(____/(____)
____ __ _ ___ __ __ _ ____
( __)( ( \ / __)( )( ( \( __)
) _) / /( (_ \ )( / / ) _)
(____)\_)__) \___/(__)\_)__)(____)
`, msg)
fmt.Fprintf(w, "Some Env Vars:\n")
fmt.Fprintf(w, "--------------\n")
for _, env := range envs {
fmt.Fprintf(w, "%s\n", env)
}
} else {
fmt.Fprintf(w, string(body)+"\n")
}
})

// HTTP_DELAY will pause for 'delay' seconds before starting the
// HTTP server. This is useful for simulating a long readiness probe
if delay := os.Getenv("HTTP_DELAY"); delay != "" {
if sec, _ := strconv.Atoi(delay); sec != 0 {
Debug(false, "Sleeping %d seconds", sec)
time.Sleep(time.Duration(sec) * time.Second)
}
Debug(true, "Listening on port 8080")
http.ListenAndServe(":8080", nil)
}

Debug(true, "Listening on port 8080")
http.ListenAndServe(":8080", nil)
}
7 changes: 7 additions & 0 deletions helloworld/run
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ function clean() {
echo Cleaning...
(
ibmcloud ce app delete -n helloworld -f --wto=0
ibmcloud ce jobrun delete -n hi-job -f
rm -f out
) > /dev/null 2>&1
}

Expand All @@ -32,5 +34,10 @@ if ! [[ "$(curl -Ls ${URL} --post301 -d "Hi")" == "Hi" ]]; then
exit 1
fi

# Since the image can be used as a job too, test it
ibmcloud ce jobrun submit --name hi-job --ai=1 --image ${REGISTRY}/helloworld \
--wait --wait-timeout=500
ibmcloud ce jobrun logs -n hi-job | tee out | grep "Hello from.*job" || exit 1

# Clean up
clean

0 comments on commit b37a036

Please sign in to comment.