Skip to content

Commit

Permalink
Tf deploy custom container (#287)
Browse files Browse the repository at this point in the history
* Fixing ui apollo ref

* Rebuild UI

* Automate embed.go creation

* Switch to catch-all for requests without a file
  • Loading branch information
hulto authored Oct 3, 2023
1 parent 38c1d60 commit 7ffe6ba
Show file tree
Hide file tree
Showing 15 changed files with 180 additions and 11 deletions.
23 changes: 23 additions & 0 deletions docs/_docs/dev-guide/tavern.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,29 @@ Tavern hosts two endpoints to support OAuth:

Tavern supports a Trust on First Use (TOFU) authentication model, meaning the first user to successfully authenticate will be granted admin permissions. Subsequent users that login will have accounts created, but will require activation before they can interact with any Tavern APIs. Only admin users may activate other users.

## Build and publish tavern container
If you want to deploy tavern without using the published version you'll have to build and publish your own container.

**Build your container**
```bash
cd ./realm
docker build --tag tavern:dev --file ./docker/tavern.Dockerfile .
```

**Publish your container to docker hub**
If you haven't before [sign-up for a docker hub account](https://hub.docker.com/signup) and login with the CLI `docker login`

```bash
docker tag tavern:dev <YOUR_DOCKER_HUB_USERNAME>/tavern:dev
docker push <YOUR_DOCKER_HUB_USERNAME>/tavern:dev
```

**Specify your container during terraform deploy**
```bash
terraform apply -var="gcp_project=<PROJECT_ID>" -var="oauth_client_id=<OAUTH_CLIENT_ID>" -var="oauth_client_secret=<OAUTH_CLIENT_SECRET>" -var="oauth_domain=<OAUTH_DOMAIN>" -var="tavern_container_image=<YOUR_DOCKER_HUB_USERNAME>/tavern:dev"
```


## User Interface

## CDN API
Expand Down
3 changes: 2 additions & 1 deletion tavern/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ func NewServer(ctx context.Context, options ...func(*Config)) (*Server, error) {
router.Handle("/graphql", newGraphQLHandler(client))
router.Handle("/cdn/", cdn.NewDownloadHandler(client))
router.Handle("/cdn/upload", cdn.NewUploadHandler(client))
router.Handle("/", auth.WithLoginRedirect("/oauth/login", www.NewAppHandler()))
fallbackhandler := www.FallbackAppHandler{}
router.Handle("/", auth.WithLoginRedirect("/oauth/login", &fallbackhandler))
router.Handle("/playground", auth.WithLoginRedirect("/oauth/login", playground.Handler("Tavern", "/graphql")))

// Log Middleware
Expand Down
3 changes: 0 additions & 3 deletions tavern/internal/www/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
Expand Down
2 changes: 1 addition & 1 deletion tavern/internal/www/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ _If this is your first time contributing WWW changes in this dev environment, re

## Building the Application

When you're ready to include changes to the UI in the tavern binary, you'll need to run `npm build` to update files in the `build/` directory. These files will automatically be bundled into new compliations of the tavern binary.
When you're ready to include changes to the UI in the tavern binary, you'll need to run `npm run build` to update files in the `build/` directory. These files will automatically be bundled into new compliations of the tavern binary.
4 changes: 4 additions & 0 deletions tavern/internal/www/build/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package build

import "embed"

// This file is a template that is copied into the npm build dir by the npm build script after a successful build.
// The template exists at: `/realm/tavern/internal/www/embed-template.go`
// The template destination is: `/realm/tavern/internal/www/build/embed.go`

// Content embedded from the application's build directory, includes the latest build of the UI.
//
//go:embed *.png *.html *.json *.txt *.ico
Expand Down
2 changes: 1 addition & 1 deletion tavern/internal/www/build/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.589fc4d1.js"></script><link href="/static/css/main.35a119f9.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.589fc4d1.js"></script><link href="/static/css/main.35a119f9.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
4 changes: 4 additions & 0 deletions tavern/internal/www/build/static/css/main.f256fd21.css

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tavern/internal/www/build/static/css/main.f256fd21.css.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tavern/internal/www/build/static/js/main.0fb7e2ca.js

Large diffs are not rendered by default.

83 changes: 83 additions & 0 deletions tavern/internal/www/build/static/js/main.0fb7e2ca.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */

/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* @remix-run/router v1.4.0
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/

/**
* React Router DOM v6.9.0
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/

/**
* React Router v6.9.0
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/

/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
1 change: 1 addition & 0 deletions tavern/internal/www/build/static/js/main.0fb7e2ca.js.map

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions tavern/internal/www/embed-template.go.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package build

import "embed"

// This file is a template that is copied into the npm build dir by the npm build script after a successful build.
// The template exists at: `/realm/tavern/internal/www/embed-template.go`
// The template destination is: `/realm/tavern/internal/www/build/embed.go`

// Content embedded from the application's build directory, includes the latest build of the UI.
//
//go:embed *.png *.html *.json *.txt *.ico
//go:embed static/*
var Content embed.FS
39 changes: 36 additions & 3 deletions tavern/internal/www/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,44 @@ package www

import (
"net/http"
"strings"

"github.com/kcarretto/realm/tavern/internal/www/build"
)

// NewAppHandler returns a new handler to serve embedded UI files.
func NewAppHandler() http.Handler {
return http.FileServer(http.FS(build.Content))
// FallbackAppHandler is a custom handler for the single page react app - if the path doesn't exist the react app is returned.
type FallbackAppHandler struct{}

func (h *FallbackAppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Extract the path from the http request
path := r.URL.Path[1:]
// Try to read the file requested
resp, err := build.Content.ReadFile(path)
if err != nil {
// If the file doesn't exist
if strings.Contains(err.Error(), "file does not exist") {
// Return our react apps main page and let it handle the route using react router.
resp, err := build.Content.ReadFile("index.html")
if err != nil {
println("Read error")
}
// Our index page will always be html
w.Header().Add("Content-Type", "text/html")
w.Write(resp)
} else {
println("Real error") // Should probably use the logging system.
}
} else {
// If the file does exist then it's a real embeded file and we'll write it's contents back.
// Since `w.Write` isn't aware of the file type we need to manually add the MIME types for files we'll serve.
// These MIME types only need to account for the files we'll be embedding through the `./build/` directory.
if strings.HasSuffix(path, ".css") {
w.Header().Add("Content-Type", "text/css")
} else if strings.HasSuffix(path, ".js") {
w.Header().Add("Content-Type", "text/javascript")
} else if strings.HasSuffix(path, ".html") {
w.Header().Add("Content-Type", "text/html")
}
w.Write(resp)
}
}
2 changes: 1 addition & 1 deletion tavern/internal/www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"build": "react-scripts build && cp ./embed-template.go.tmpl ./build/embed.go",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Expand Down
8 changes: 7 additions & 1 deletion terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ resource "random_password" "defaultmysql" {
override_special = "!#$%&*()-_=+[]{}<>:?"
}

variable "tavern_container_image" {
type = string
description = "Docker container to deploy"
default = "kcarretto/tavern:latest"
}

variable "gcp_project" {
type = string
description = "GCP Project ID for deployment"
Expand Down Expand Up @@ -139,7 +145,7 @@ resource "google_cloud_run_service" "tavern" {
template {
spec {
containers {
image = "kcarretto/tavern:latest"
image = var.tavern_container_image
ports {
container_port = 80
}
Expand Down

0 comments on commit 7ffe6ba

Please sign in to comment.