Skip to content

Commit

Permalink
Setting up sandwich-shop for running on a server
Browse files Browse the repository at this point in the history
  • Loading branch information
suhay committed Jan 4, 2020
1 parent cae0a7c commit 50b7dbb
Show file tree
Hide file tree
Showing 9 changed files with 268 additions and 30 deletions.
11 changes: 7 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ GOCMD=go
GOINSTALL=$(GOCMD) install
GOCLEAN=$(GOCMD) clean
GORUN=$(GOCMD) run
GOWICH=$(GOINSTALL) $(shell pwd)/gowich/gowich.go
NODEWICH=cd $(shell pwd)/nodewich && yarn install --production && cd $(shell pwd)
GOWICH=$(GOINSTALL) ${GOPATH}/src/github.com/suhay/sandwich-shop/gowich/gowich.go
NODEWICH=cd ${GOPATH}/src/github.com/suhay/sandwich-shop/nodewich && yarn install --production && cd $(shell pwd)

install:
$(GOINSTALL) $(shell pwd)/shop/sandwich-shop.go
$(GOINSTALL) ${GOPATH}/src/github.com/suhay/sandwich-shop/shop/sandwich-shop.go

sandwiches:
$(GOWICH)
Expand All @@ -27,4 +27,7 @@ gqlgen:
$(GORUN) github.com/99designs/gqlgen -v

generate:
go generate .
go generate .

dev:
CompileDaemon -directory=./shop -color=true -command="./shop/shop"
240 changes: 225 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,250 @@ The purpose of this experiment is to explore other alternatives to the container
The current version of Sandwich Shop has a prepackaged Go and Node based sandwich it can make. To install the main shop, from the project root, type:

```bash
make install
$ make install
```

To add the Go and Node sandwiches to the menu, from the project root, type:

```bash
make sandwiches
$ make sandwiches
```

You will need to provide your own version of Node and Go in order to run these modules.

### Run

```bash
$ sandwich-shop [--env=<path>] [--port=<port>]
```

|||
|-|-|
|`--env`|Path to a local, or remote `.env` this process should use for default configurations.|
|`--port`|The port number to run on.|

## Setting up shop

Once you have the shop installed, and any of the sandwiches added that you need, the next task is to set up your `.env` files. These can live anywhere and are included as arguments when launching the shop or sandwiches.
Once you have Sandwich Shop installed, and any of the sandwiches added that you need, the next task is to set up your `.env` files. These can live anywhere and are included as arguments when launching the shop or sandwiches.

- `MONGODB_URL`: URL to the mongo database that stores tenant information including the `Bearer` token.
- `MONGODB_USER`: User for logging into the tenant info database.
- `MONGODB_PASSWD`: Password for the user above.
- `JWT_SECRET`: Used for signing a JWT payload while passing it through the shop as an order. This is used to verify the order came through a shop directly and that it was unchanged while in transit. This secret must be identical across all shops and sandwich makers.
- `TIMEOUT`: Seconds to wait on the order to complete.
```
MONGODB_URL=cluster0.mongodb.net
MONGODB_USER=mango
MONGODB_PASSWD=1234password
JWT_SECRET=1234567890jwtsecretcode
TIMEOUT=60
```

|||
|---|---|
|`MONGODB_URL`|URL to the mongo database that stores tenant information including the `Bearer` token.|
|`MONGODB_USER`|User for logging into the tenant info database.|
|`MONGODB_PASSWD`|Password for the user above.|
|`JWT_SECRET`|Used for signing a JWT payload while passing it through the shop as an order. This is used to verify the order came through a shop directly and that it was unchanged while in transit. This secret must be identical across all shops and sandwich makers.|
|`TIMEOUT`|Seconds to wait on the order to complete.|

shops.json
### Registering a shop

### Tenant
A shop is what is handling the heavy lifting. Each shop is specialized in running one type of application (Node.js, Golang, Python, etc.). There are two ways you can register your shops. The first way is through a local `shops.json` file. This is the more clunky way to maintain your shop registry, but it cuts out a round trip to a MongoDB.

```json
[
{
"_id": "rye",
"name": "Rye",
"host": "http://localhost:4006",
"runtimes": [
"node12_7"
]
},
{
"_id": "ciabatta",
"name": "Ciabatta",
"host": "http://localhost:4007",
"runtimes": [
"go1_13"
]
}
]
```

More soon!
|||
|---|---|
|`_id`|Shop's id|
|`name`|Human readable name, used more for easily identifying when there is an error (and the shop ids are uuids).|
|`host`|URL and port the shop will be reached from by the main Sandwich Shop process (how it will receive orders).|
|`runtimes`|Array of runtime identifiers that show what this shop is set up to run.|

.key files
orders.yml
At the time of writing this README, the current available `runtimes` are `node9_10`,
`node10_6`, `node12_7`, and `go1_13`. These are within a GraphQL `enum` so adding to this list will require a pull request.

The above schema can also be stored within a MongoDB collection called `shops` on the `sandwich-shop` database you are using to run this application.

### Gowich

More soon!
A `Gowich` is a shop designed to run Golang applications. You may have as many of these running as needed as long as they are all running on separate ports. Each `Gowich` should have a `.env` file, or one supplied to it as a CLI argument.

```
PORT=3001
TIMEOUT=60
JWT_SECRET=1234567890jwtsecretcode
GO1_13=/path/to/go1.13
TENANTS=/path/to/tenants
```

|||
|-|-|
|`PORT`|Port to run this shop on. This will be overridden if `--port` is supplied as a command argument.|
|`TIMEOUT`|Timeout, in seconds, to wait for an order to finish.|
|`JWT_SECRET`|Must be the same `JWT_SECRET` as specified in the main Sandwich Shop's `.env` variables. This is used to ensure the request was generated and not changed between Sandwich Shop and the Gowich.|
|`GO1_13`|Absolute path to the runtime's binary executable.|
|`TENANTS`|Absolute path to tenants directory.|

#### Running

```bash
$ gowich [--env=<path>] [--port=<port>]
```

|||
|-|-|
|`--env`|Path to a local, or remote `.env` this process should use for default configurations.|
|`--port`|The port number to run on.|

### Nodewich

More soon!
A `Nodewich` is a shop designed to run Node applications. You may have as many of these running as needed as long as they are all running on separate ports. Each `Nodewich` should have a `.env` file, or one supplied to it as a CLI argument.

```
PORT=4001
TIMEOUT=60
JWT_SECRET=1234567890jwtsecretcode
NODE9_10=/path/to/node9
NODE12_7=/path/to/node12
TENANTS=/path/to/tenants
```

|||
|-|-|
|`PORT`|Port to run this shop on. This will be overridden if `--port` is supplied as a command argument.|
|`TIMEOUT`|Timeout, in seconds, to wait for an order to finish.|
|`JWT_SECRET`|Must be the same `JWT_SECRET` as specified in the main Sandwich Shop's `.env` variables. This is used to ensure the request was generated and not changed between Sandwich Shop and the Gowich.|
|`NODE9_10`, `NODE12_7`|Absolute path to the runtime's binary executable.|
|`TENANTS`|Absolute path to tenants directory.|

#### Running

CLI arguments are still in development.

```bash
$ nodewich
```
<!--[--env=<path>] [--port=<port>]-->
<!--|||
|-|-|
|`--env`|Path to a local, or remote `.env` this process should use for default configurations.|
|`--port`|The port number to run on.|-->

### Tenants

Tenants are the buckets where your functional code is placed. At the writing of this README, the `tenant` directory must be relative to the application root.

Within the `tenant` directory, you will place the different tenant directories. These will eventually be locked down to the individual tenants to prevent directory level access to the shops so tenants will not be able to execute each other's code. Along with the functions a tenant wishes to run, there also must be an `orders.yml` file to hold the function configurations. There should also either be an optional `.key` file to hold the API key for this particular tenant, or their API key must be stored within the `tenants` collection on your `sandwich-shop` MongoDB database.

```
tenants
└── b78682b3-36c8-4759-b8d1-5e62f029a1bc
├── .key (optional)
├── getSandwich.js
├── make_sandwich.go
└── orders.yml
```

```yaml
# order.yml
---
getSandwich: # order name, will be called via https://shop.example/{tenantid}/getSandwich
runtime: node9_10 # shop to run in
path: getSandwich.js # path where function lives relative to this tenant's root
env: [] # any variables to include
makeSandwich:
runtime: go1_13
path: make_sandwich.go
env: []
```
*.key* file
```
this-is-my-api-key
```
**OR**

`sandwich-shop.tenants` in your MongoDB cluster
```
{
"_id": "tenant id",
"key": "this-is-my-api-key"
}
```

## TL;DR - `sudo make me a gowich`

```bash
$ mkdir sandwich-shop

$ cd sandwich-shop

$ go mod init sandwiches.example.com

$ go get github.com/suhay/sandwich-shop

$ make -C $GOPATH/src/github.com/suhay/sandwich-shop/ install

$ make -C $GOPATH/src/github.com/suhay/sandwich-shop/ gowich

$ touch .env
```

### `.env`

```
MONGODB_URL=cluster0.mongodb.net
MONGODB_USER=mongo
MONGODB_PASSWD=123password
JWT_SECRET=123jwtsecret
TIMEOUT=60
GO1_13=/path/to/go1.13
TENANTS=/path/to/tenants
```

### Run

```bash
$ sandwich-shop &

$ gowich &
```

## Current Development

- [ ] Nodewich CLI

- [x] Move tenant path into an environment variable

- [ ] Dockerize `Gowich` and `Nodewich` shops for ease of adding or removing them as needed

- [ ] `Shop Manager` script for adding and editing `tenants` more easily

- [ ] Allowing `Shop Manager` to also have the ability to stand up and tear down shops based upon a CLI argument

- [ ] A+B testing against a Serverless pattern (to see if this is even a thing, or just something for fun)

- [ ] Security audit on tenants

- [ ] Pywich

### Developing for Sandwich Shop

```bash
$ make dev
```
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ go 1.13
require (
github.com/99designs/gqlgen v0.10.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fatih/color v1.8.0 // indirect
github.com/githubnemo/CompileDaemon v1.0.0 // indirect
github.com/go-chi/chi v4.0.2+incompatible
github.com/go-stack/stack v1.8.0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/google/go-cmp v0.3.1 // indirect
github.com/howeyc/fsnotify v0.9.0 // indirect
github.com/joho/godotenv v1.3.0
github.com/tidwall/pretty v1.0.0 // indirect
github.com/vektah/gqlparser v1.1.2
Expand Down
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ 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/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/fatih/color v1.8.0 h1:5bzFgL+oy7JITMTxUPJ00n7VxmYd/PdMp5mHFX40/RY=
github.com/fatih/color v1.8.0/go.mod h1:3l45GVGkyrnYNl9HoIjnp2NnNWvh6hLAqD8yTfGjnw8=
github.com/githubnemo/CompileDaemon v1.0.0 h1:F4nrVyPOxva6gJIw320fwfaFaPl8ZuEk95RZOy9Q4eM=
github.com/githubnemo/CompileDaemon v1.0.0/go.mod h1:lE3EXX1td33uhlkFLp+ImWY9qBaoRcDeA3neh4m8ic0=
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
Expand All @@ -25,13 +29,19 @@ github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTM
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/howeyc/fsnotify v0.9.0 h1:0gtV5JmOKH4A8SsFxG2BczSeXWWPvcMT0euZt5gDAxY=
github.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5nrJJVjbXiDZcVhOBSzKn3o9LgRLLMRNuru8=
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
Expand Down Expand Up @@ -69,6 +79,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJV
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180202135801-37707fdb30a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
9 changes: 4 additions & 5 deletions gowich/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
MONGODB_URL=cluster0.mongodb.net
MONGODB_USER=mango
MONGODB_PASSWD=1234password
JWT_SECRET=1234567890jwtsecretcode
PORT=3001
TIMEOUT=60
GO1_13=/path/to/go1.13
JWT_SECRET=1234567890jwtsecretcode
GO1_13=/path/to/go1.13
TENANTS=/path/to/tenants
9 changes: 8 additions & 1 deletion gowich/gowich.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,14 @@ func main() {
if claims, ok := token.Claims.(*shopOrder); ok && token.Valid {
if chi.URLParam(r, "tenantID") == claims.Tenant && claims.Authorized {
cmd := exec.Command(os.Getenv(strings.ToUpper(claims.Runtime)), "run", chi.URLParam(r, "order"))
cmd.Dir = "../tenants/" + claims.Tenant

tenants := "../tenants"
if envTenants := os.Getenv("TENANTS"); envTenants != "" {
tenants = envTenants
}

cmd.Dir = tenants+"/"+claims.Tenant

out, err := cmd.Output()
if err != nil {
log.Println(err.Error())
Expand Down
5 changes: 2 additions & 3 deletions nodewich/.env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
MONGODB_URL=cluster0.mongodb.net
MONGODB_USER=mango
MONGODB_PASSWD=1234password
PORT=4001
JWT_SECRET=1234567890jwtsecretcode
TIMEOUT=60
TENANTS=/path/to/tenants
NODE9_10=/path/to/node9
NODE12_7=/path/to/node12
2 changes: 1 addition & 1 deletion nodewich/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ app.post('/:tenantID/:order',
if (req.user.tenant === req.params.tenantID && req.user.authorized) {
const child = cp.exec(`${process.env[req.user.runtime.toUpperCase()]} ${req.params.order} '${JSON.stringify(req.body)}'`,
{
cwd: path.resolve(`../tenants/${req.params.tenantID}`),
cwd: path.resolve(`${process.env.TENANTS || `../tenants`}/${req.params.tenantID}`),
timeout: process.env.TIMEOUT * 1000
},
(err, stdout, stderr) => {
Expand Down
Loading

0 comments on commit 50b7dbb

Please sign in to comment.