Skip to content

Commit 6d5bd3d

Browse files
authored
Merge pull request #292 from asteurer/redis-sample
adding redis-sample
2 parents c777f08 + e5ba077 commit 6d5bd3d

File tree

6 files changed

+205
-1
lines changed

6 files changed

+205
-1
lines changed

.github/workflows/sample-apps.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515
strategy:
1616
matrix:
17-
app: [cpu-load-gen, hello-world, outbound-http, variabletester]
17+
app: [cpu-load-gen, hello-world, outbound-http, variabletester, redis-sample]
1818
env:
1919
IMAGE_NAME: ${{ github.repository }}
2020

apps/redis-sample/README.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Overview
2+
3+
This is an OCI-compliant package that can be used to demonstrate how a Spin app interacts with Redis in a Kubernetes cluster.
4+
5+
# Usage
6+
7+
## Deploying the Spin app
8+
9+
Create a Kubernetes manifest file named `redis_client.yaml` with the following code:
10+
11+
```yaml
12+
apiVersion: core.spinoperator.dev/v1alpha1
13+
kind: SpinApp
14+
metadata:
15+
name: redis-spinapp
16+
spec:
17+
image: "ghcr.io/spinkube/redis-sample"
18+
replicas: 1
19+
executor: containerd-shim-spin
20+
variables:
21+
- name: redis_endpoint
22+
value: redis://redis.default.svc.cluster.local:6379
23+
```
24+
25+
Once created, run `kubectl apply -f redis_client.yaml`.
26+
27+
## Deploying Redis
28+
29+
Create a Kubernetes manifest file named `redis_db.yaml` with the following code:
30+
31+
```yaml
32+
apiVersion: apps/v1
33+
kind: Deployment
34+
metadata:
35+
name: redis
36+
labels:
37+
app: redis
38+
spec:
39+
replicas: 1
40+
selector:
41+
matchLabels:
42+
app: redis
43+
template:
44+
metadata:
45+
labels:
46+
app: redis
47+
spec:
48+
containers:
49+
- name: redis
50+
image: redis
51+
ports:
52+
- containerPort: 6379
53+
54+
---
55+
apiVersion: v1
56+
kind: Service
57+
metadata:
58+
name: redis
59+
spec:
60+
selector:
61+
app: redis
62+
ports:
63+
- protocol: TCP
64+
port: 6379
65+
targetPort: 6379
66+
```
67+
68+
Once created, run `kubectl apply -f redis_db.yaml`.
69+
70+
## Interacting with the Spin app
71+
72+
In your terminal run `kubectl port-forward svc/redis-spinapp 3000:80`, then in a different terminal window, try the below commands:
73+
74+
### Place a key-value pair in Redis
75+
76+
```bash
77+
curl --request PUT --data-binary "Hello, world\!" -H 'x-key: helloKey' localhost:3000
78+
```
79+
80+
### Retrieve a value from Redis
81+
82+
```bash
83+
curl -H 'x-key: helloKey' localhost:3000
84+
```
85+
86+
### Delete a value from Redis
87+
88+
```bash
89+
curl --request DELETE -H 'x-key: helloKey' localhost:3000
90+
```

apps/redis-sample/go.mod

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module github.com/spin_redis_sample
2+
3+
go 1.20
4+
5+
require github.com/fermyon/spin/sdk/go/v2 v2.2.0
6+
7+
require github.com/julienschmidt/httprouter v1.3.0 // indirect

apps/redis-sample/go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
github.com/fermyon/spin/sdk/go/v2 v2.2.0 h1:zHZdIqjbUwyxiwdygHItnM+vUUNSZ3CX43jbIUemBI4=
2+
github.com/fermyon/spin/sdk/go/v2 v2.2.0/go.mod h1:kfJ+gdf/xIaKrsC6JHCUDYMv2Bzib1ohFIYUzvP+SCw=
3+
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
4+
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=

apps/redis-sample/main.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
8+
spinhttp "github.com/fermyon/spin/sdk/go/v2/http"
9+
"github.com/fermyon/spin/sdk/go/v2/redis"
10+
"github.com/fermyon/spin/sdk/go/v2/variables"
11+
)
12+
13+
var rdb *redis.Client
14+
15+
func init() {
16+
spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) {
17+
redisEndpoint, err := variables.Get("redis_endpoint")
18+
if err != nil {
19+
http.Error(w, "unable to parse variable 'redis_endpoint'", http.StatusInternalServerError)
20+
return
21+
}
22+
23+
if redisEndpoint == "" {
24+
http.Error(w, "cannot find 'redis_endpoint' environment variable", http.StatusInternalServerError)
25+
return
26+
}
27+
28+
rdb = redis.NewClient(redisEndpoint)
29+
30+
reqKey := r.Header.Get("x-key")
31+
if reqKey == "" {
32+
http.Error(w, "you must include the 'x-key' header in your request", http.StatusBadRequest)
33+
return
34+
}
35+
36+
if r.Method == "GET" {
37+
value, err := rdb.Get(reqKey)
38+
if err != nil {
39+
http.Error(w, fmt.Sprintf("no value found for key '%s'", reqKey), http.StatusNotFound)
40+
return
41+
}
42+
43+
w.WriteHeader(http.StatusOK)
44+
w.Write(value)
45+
return
46+
47+
} else if r.Method == "PUT" {
48+
bodyBytes, err := io.ReadAll(r.Body)
49+
if err != nil {
50+
http.Error(w, fmt.Sprintf("error reading request body: %w", err), http.StatusInternalServerError)
51+
}
52+
defer r.Body.Close()
53+
54+
if err := rdb.Set(reqKey, bodyBytes); err != nil {
55+
http.Error(w, fmt.Sprintf("unable to add value for key '%s' to database: %w", reqKey, err), http.StatusInternalServerError)
56+
return
57+
}
58+
59+
w.WriteHeader(http.StatusCreated)
60+
return
61+
62+
} else if r.Method == "DELETE" {
63+
_, err := rdb.Del(reqKey)
64+
if err != nil {
65+
http.Error(w, fmt.Sprintf("error deleting value for key '%w'", err), http.StatusInternalServerError)
66+
return
67+
}
68+
69+
w.WriteHeader(http.StatusOK)
70+
return
71+
72+
} else {
73+
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)
74+
return
75+
}
76+
})
77+
}
78+
79+
func main() {}

apps/redis-sample/spin.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
spin_manifest_version = 2
2+
3+
[application]
4+
name = "spin-redis-sample"
5+
version = "0.1.0"
6+
authors = ["Fermyon Engineering Team <[email protected]>"]
7+
8+
[variables]
9+
redis_endpoint = {required = true}
10+
11+
[[trigger.http]]
12+
route = "/..."
13+
component = "spin-redis-sample"
14+
15+
[component.spin-redis-sample]
16+
source = "main.wasm"
17+
allowed_outbound_hosts = ["redis://*"]
18+
19+
[component.spin-redis-sample.build]
20+
command = "tinygo build -target=wasi -gc=leaking -no-debug -o main.wasm main.go"
21+
watch = ["**/*.go", "go.mod"]
22+
23+
[component.spin-redis-sample.variables]
24+
redis_endpoint = "{{ redis_endpoint }}"

0 commit comments

Comments
 (0)