Skip to content

Commit

Permalink
Merge pull request #292 from asteurer/redis-sample
Browse files Browse the repository at this point in the history
adding redis-sample
  • Loading branch information
calebschoepp authored Aug 13, 2024
2 parents c777f08 + e5ba077 commit 6d5bd3d
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/sample-apps.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
app: [cpu-load-gen, hello-world, outbound-http, variabletester]
app: [cpu-load-gen, hello-world, outbound-http, variabletester, redis-sample]
env:
IMAGE_NAME: ${{ github.repository }}

Expand Down
90 changes: 90 additions & 0 deletions apps/redis-sample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Overview

This is an OCI-compliant package that can be used to demonstrate how a Spin app interacts with Redis in a Kubernetes cluster.

# Usage

## Deploying the Spin app

Create a Kubernetes manifest file named `redis_client.yaml` with the following code:

```yaml
apiVersion: core.spinoperator.dev/v1alpha1
kind: SpinApp
metadata:
name: redis-spinapp
spec:
image: "ghcr.io/spinkube/redis-sample"
replicas: 1
executor: containerd-shim-spin
variables:
- name: redis_endpoint
value: redis://redis.default.svc.cluster.local:6379
```
Once created, run `kubectl apply -f redis_client.yaml`.

## Deploying Redis

Create a Kubernetes manifest file named `redis_db.yaml` with the following code:

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
labels:
app: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis
ports:
- containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
selector:
app: redis
ports:
- protocol: TCP
port: 6379
targetPort: 6379
```

Once created, run `kubectl apply -f redis_db.yaml`.

## Interacting with the Spin app

In your terminal run `kubectl port-forward svc/redis-spinapp 3000:80`, then in a different terminal window, try the below commands:

### Place a key-value pair in Redis

```bash
curl --request PUT --data-binary "Hello, world\!" -H 'x-key: helloKey' localhost:3000
```

### Retrieve a value from Redis

```bash
curl -H 'x-key: helloKey' localhost:3000
```

### Delete a value from Redis

```bash
curl --request DELETE -H 'x-key: helloKey' localhost:3000
```
7 changes: 7 additions & 0 deletions apps/redis-sample/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/spin_redis_sample

go 1.20

require github.com/fermyon/spin/sdk/go/v2 v2.2.0

require github.com/julienschmidt/httprouter v1.3.0 // indirect
4 changes: 4 additions & 0 deletions apps/redis-sample/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/fermyon/spin/sdk/go/v2 v2.2.0 h1:zHZdIqjbUwyxiwdygHItnM+vUUNSZ3CX43jbIUemBI4=
github.com/fermyon/spin/sdk/go/v2 v2.2.0/go.mod h1:kfJ+gdf/xIaKrsC6JHCUDYMv2Bzib1ohFIYUzvP+SCw=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
79 changes: 79 additions & 0 deletions apps/redis-sample/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package main

import (
"fmt"
"io"
"net/http"

spinhttp "github.com/fermyon/spin/sdk/go/v2/http"
"github.com/fermyon/spin/sdk/go/v2/redis"
"github.com/fermyon/spin/sdk/go/v2/variables"
)

var rdb *redis.Client

func init() {
spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) {
redisEndpoint, err := variables.Get("redis_endpoint")
if err != nil {
http.Error(w, "unable to parse variable 'redis_endpoint'", http.StatusInternalServerError)
return
}

if redisEndpoint == "" {
http.Error(w, "cannot find 'redis_endpoint' environment variable", http.StatusInternalServerError)
return
}

rdb = redis.NewClient(redisEndpoint)

reqKey := r.Header.Get("x-key")
if reqKey == "" {
http.Error(w, "you must include the 'x-key' header in your request", http.StatusBadRequest)
return
}

if r.Method == "GET" {
value, err := rdb.Get(reqKey)
if err != nil {
http.Error(w, fmt.Sprintf("no value found for key '%s'", reqKey), http.StatusNotFound)
return
}

w.WriteHeader(http.StatusOK)
w.Write(value)
return

} else if r.Method == "PUT" {
bodyBytes, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("error reading request body: %w", err), http.StatusInternalServerError)
}
defer r.Body.Close()

if err := rdb.Set(reqKey, bodyBytes); err != nil {
http.Error(w, fmt.Sprintf("unable to add value for key '%s' to database: %w", reqKey, err), http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusCreated)
return

} else if r.Method == "DELETE" {
_, err := rdb.Del(reqKey)
if err != nil {
http.Error(w, fmt.Sprintf("error deleting value for key '%w'", err), http.StatusInternalServerError)
return
}

w.WriteHeader(http.StatusOK)
return

} else {
http.Error(w, fmt.Sprintf("method %q is not supported, so please try again using 'GET' or 'PUT' for the HTTP method", r.Method), http.StatusBadRequest)
return
}
})
}

func main() {}
24 changes: 24 additions & 0 deletions apps/redis-sample/spin.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
spin_manifest_version = 2

[application]
name = "spin-redis-sample"
version = "0.1.0"
authors = ["Fermyon Engineering Team <engineering@fermyon.com>"]

[variables]
redis_endpoint = {required = true}

[[trigger.http]]
route = "/..."
component = "spin-redis-sample"

[component.spin-redis-sample]
source = "main.wasm"
allowed_outbound_hosts = ["redis://*"]

[component.spin-redis-sample.build]
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
watch = ["**/*.go", "go.mod"]

[component.spin-redis-sample.variables]
redis_endpoint = "{{ redis_endpoint }}"

0 comments on commit 6d5bd3d

Please sign in to comment.