Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
feat: add docker support and support a workdir CLI option in case you…
Browse files Browse the repository at this point in the history
…r running in a kube pod with the config directory readonly (due to it being mounted from a ConfigMap).
  • Loading branch information
chirino committed Jul 23, 2020
1 parent 2f76a97 commit 9e0c60c
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 22 deletions.
2 changes: 2 additions & 0 deletions docker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin
etc
17 changes: 17 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM golang:alpine as build
RUN apk --no-cache add ca-certificates

# In case we want to build the gateway in docker....
#WORKDIR /go/src/app
#COPY . .
#RUN CGO_ENABLED=0 go-wrapper install -ldflags '-extldflags "-static"'

FROM scratch
# FROM alpine
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

ADD bin /bin
ADD etc /etc
WORKDIR /etc/graphql-gw
EXPOSE 8080/tcp
ENTRYPOINT ["/bin/graphql-gw", "serve"]
15 changes: 15 additions & 0 deletions docker/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -e
cd -P $(dirname "${BASH_SOURCE[0]}")

mkdir -p bin || true 2> /dev/null
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ./bin/graphql-gw ../main.go

mkdir -p etc/graphql-gw 2> /dev/null || true
cd etc/graphql-gw
rm graphql-gw.yaml 2> /dev/null || true
go run ../../../main.go config init
cd -

docker build -t "chirino/graphql-gw" .
# docker push chirino/graphql-gw
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module github.com/chirino/graphql-gw

require (
github.com/chirino/graphql v0.0.0-20200620205252-3aa1055298c1
github.com/chirino/graphql v0.0.0-20200723150749-b1992f46a318
github.com/chirino/graphql-4-apis v0.0.0-20200622132210-66059999b694
github.com/chirino/hawtgo v0.0.1
github.com/fsnotify/fsnotify v1.4.9
Expand All @@ -10,10 +10,13 @@ require (
github.com/go-chi/chi v4.1.2+incompatible
github.com/go-chi/render v1.0.1
github.com/golang/protobuf v1.3.1
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pkg/errors v0.9.1
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749
github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd
github.com/spf13/cobra v1.0.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.4.0
github.com/stretchr/testify v1.5.1
golang.org/x/sys v0.0.0-20200620081246-981b61492c35 // indirect
google.golang.org/grpc v1.21.0
Expand All @@ -23,4 +26,6 @@ require (
go 1.13

//replace github.com/chirino/graphql => ../graphql
// replace github.com/chirino/graphql => ../graphql

//replace github.com/chirino/graphql-4-apis => ../graphql-4-apis
5 changes: 4 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chirino/graphql v0.0.0-20200620205252-3aa1055298c1 h1:9R1VO7zZ/jDc2uqFp7FjvwwruVGfR6TO3TaeVyDCU5I=
github.com/chirino/graphql v0.0.0-20200620205252-3aa1055298c1/go.mod h1:QJryzmxY+8v+nP7+HjPsMxT4q+tfZZq387ZdG0md+kU=
github.com/chirino/graphql v0.0.0-20200723150749-b1992f46a318 h1:3BfsEyOx1rmoL9W23etW8sJ2oQV+hMa0TAFUO6ewReM=
github.com/chirino/graphql v0.0.0-20200723150749-b1992f46a318/go.mod h1:QJryzmxY+8v+nP7+HjPsMxT4q+tfZZq387ZdG0md+kU=
github.com/chirino/graphql-4-apis v0.0.0-20200622132210-66059999b694 h1:WmZ0Y9xkgCft6P4DdIZ5qBwQWlMkQH2wiUy4JcsXPfE=
github.com/chirino/graphql-4-apis v0.0.0-20200622132210-66059999b694/go.mod h1:JUqXBL6BnmaECzXkZnSAunwgAccI1MY0SYVEGuxSX3A=
github.com/chirino/hawtgo v0.0.1 h1:BwUkArpv32ZDK5QFnG1RysagrKe82TsagXxi2Ys2flA=
Expand Down Expand Up @@ -100,6 +101,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
Expand Down
6 changes: 5 additions & 1 deletion graphql-gw.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Configure the host and port the service will listen on
listen: 0.0.0.0:8080

#policy-agent:
# insecure-client: true
# address: 127.0.0.1:10000

#
# Configure the GraphQL upstream servers you will be accessing
upstreams:
Expand All @@ -17,7 +21,6 @@ upstreams:
url: https://weather.com/swagger-docs/sun/v1/sunV1DailyForecast.json
api:
api-key: please configure me

types:
- name: Query
actions:
Expand All @@ -38,6 +41,7 @@ types:
upstream: weather
query: query {}


- name: AniCharacter
actions:
# mounts the root anilist query to the anime field
Expand Down
4 changes: 2 additions & 2 deletions internal/cmd/config/add/upstream/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ func run(cmd *cobra.Command, args []string) {
}

// Store it's schema
os.MkdirAll(filepath.Join(c.ConfigDirectory, "upstreams"), 0755)
upstreamSchemaFile := filepath.Join(c.ConfigDirectory, "upstreams", upstreamName+".graphql")
os.MkdirAll(filepath.Join(c.WorkDirectory, "upstreams"), 0755)
upstreamSchemaFile := filepath.Join(c.WorkDirectory, "upstreams", upstreamName+".graphql")
err = ioutil.WriteFile(upstreamSchemaFile, []byte(upstreamSchema.String()), 0644)
if err != nil {
log.Fatalf(root.Verbosity, err)
Expand Down
13 changes: 10 additions & 3 deletions internal/cmd/config/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ var (
Short: "Modifies the gateway configuration",
PersistentPreRunE: PreRunLoad,
}
File string
Value *Config
File string
WorkDir string
Value *Config
)

func init() {
Command.PersistentFlags().StringVar(&File, "config", "graphql-gw.yaml", "path to the config file to modify")
Command.PersistentFlags().StringVar(&WorkDir, "workdir", "", "working to write files to in dev mode. (default to the directory the config file is in)")
root.Command.AddCommand(Command)
}

Expand All @@ -51,7 +53,12 @@ func Load(config *Config) error {
return errors.Wrapf(err, "parsing yaml of: %s.", File)
}

config.ConfigDirectory = filepath.Dir(File)
if WorkDir == "" {
config.WorkDirectory = filepath.Dir(File)
} else {
config.WorkDirectory = WorkDir
}

config.Log = gateway.SimpleLog

if config.Upstreams == nil {
Expand Down
33 changes: 33 additions & 0 deletions internal/cmd/root/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package root
import (
"fmt"
"os"
"strings"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)

var (
Expand All @@ -23,6 +26,9 @@ var (

func init() {
Command.PersistentFlags().BoolVar(&Verbose, "verbose", false, "enables increased verbosity")
viper.SetEnvPrefix("GRAPHQL_GW")
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.AutomaticEnv()
}

func Main() {
Expand All @@ -31,3 +37,30 @@ func Main() {
os.Exit(1)
}
}

func IntBind(f *pflag.FlagSet, name string, defaultValue int, usage string) func() int {
f.Int(name, defaultValue, usage)
viper.SetDefault(name, defaultValue)
viper.BindPFlag(name, f.Lookup(name))
return func() int {
return viper.GetInt(name)
}
}

func StringBind(f *pflag.FlagSet, name string, defaultValue string, usage string) func() string {
f.String(name, defaultValue, usage)
viper.SetDefault(name, defaultValue)
viper.BindPFlag(name, f.Lookup(name))
return func() string {
return viper.GetString(name)
}
}

func BoolBind(f *pflag.FlagSet, name string, defaultValue bool, usage string) func() bool {
f.Bool(name, defaultValue, usage)
viper.SetDefault(name, defaultValue)
viper.BindPFlag(name, f.Lookup(name))
return func() bool {
return viper.GetBool(name)
}
}
68 changes: 61 additions & 7 deletions internal/cmd/serve/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package serve

import (
"fmt"
"io"
"net/http"
"os"
"os/signal"
Expand Down Expand Up @@ -30,12 +31,13 @@ var (
Run: run,
PersistentPreRunE: config.PreRunLoad,
}
Production = false
Production func() bool
)

func init() {
Command.Flags().StringVar(&config.File, "config", "graphql-gw.yaml", "path to the config file to load")
Command.Flags().BoolVar(&Production, "production", false, "when true, the server will not download and store schemas from remote graphql endpoints.")
Command.Flags().StringVar(&config.WorkDir, "workdir", "", "working to write files to in dev mode. (default to the directory the config file is in)")
Production = root.BoolBind(Command.Flags(), "production", false, "when true, the server will not download and store schemas from remote graphql endpoints.")
root.Command.AddCommand(Command)
}

Expand All @@ -44,6 +46,37 @@ func run(_ *cobra.Command, _ []string) {
lastConfig.Log = gateway.TimestampedLog
log := lastConfig.Log

if Production() {
if config.WorkDir != filepath.Dir(config.File) {
log.Fatalf("work directory cannot be configured in production mode")
}
} else {

if config.WorkDir != filepath.Dir(config.File) {
os.MkdirAll(config.WorkDir, 0755)

source := config.File
target := filepath.Join(config.WorkDir, "graphql-gw.yaml")
if _, err := os.Stat(target); err != nil && os.IsNotExist(err) {
err := copy(source, target)
if err != nil {
log.Fatal(err)
}
}

// so we update and watch the config file in the work dir.
config.File = target

// but watch the original for changes...
watchFile(source, func(in fsnotify.Event) {
err := copy(source, target)
if err != nil {
log.Printf("Could not copy the config file to the work directory: %s", err)
}
})
}
}

err := startServer(&lastConfig)
if err != nil {
log.Fatalf("could not start the sever: "+root.Verbosity, err)
Expand Down Expand Up @@ -82,7 +115,7 @@ func run(_ *cobra.Command, _ []string) {
lastConfig = nextConfig
}

if !Production {
if !Production() {
watchFile(config.File, func(in fsnotify.Event) {
log.Println("restarting due to configuration change:", in.Name)
restart()
Expand Down Expand Up @@ -165,28 +198,49 @@ func startServer(config *config.Config) error {
return mountGatewayOnHttpServer(config)
}

func copy(src, dst string) error {
in, err := os.Open(src)
if err != nil {
return err
}
defer in.Close()

out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()

_, err = io.Copy(out, in)
if err != nil {
return err
}
return out.Close()
}

func mountGatewayOnHttpServer(c *config.Config) (err error) {

c.Gateway, err = gateway.New(c.Config)
if err != nil {
return err
}
gatewayHandler := gateway.CreateHttpHandler(c.Gateway.ServeGraphQLStream).(*httpgql.Handler)
// Enable pretty printed json results when in dev mode.
if !Production {
if !Production() {
gatewayHandler.Indent = " "
}
graphqlURL := fmt.Sprintf("%s/graphql", c.Server.URL)
r := chi.NewRouter()
r.Use(middleware.Logger)
if !Production {
if !Production() {
r.Mount("/", http.FileServer(assets.FileSystem))
r.Mount("/admin", admin.CreateHttpHandler())
}
r.Handle("/graphql", gatewayHandler)
r.Handle("/graphiql", graphiql.New(graphqlURL, true))
c.Server.Config.Handler = r
c.Config.Log.Printf("GraphQL endpoint is running at %s", graphqlURL)
if Production {
if Production() {
c.Config.Log.Printf("Gateway GraphQL IDE is running at %s/graphiql", c.Server.URL)
} else {
c.Config.Log.Printf("Gateway Admin UI and GraphQL IDE is running at %s", c.Server.URL)
Expand All @@ -209,7 +263,7 @@ func postProcess(config *config.Config) {
config.Listen = "0.0.0.0:8080"
}

if Production {
if Production() {
config.DisableSchemaDownloads = true
config.EnabledSchemaStorage = false
} else {
Expand Down
10 changes: 5 additions & 5 deletions internal/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type PolicyAgentConfig struct {
}

type Config struct {
ConfigDirectory string `yaml:"-"`
WorkDirectory string `yaml:"-"`
Log *log.Logger `yaml:"-"`
DisableSchemaDownloads bool `yaml:"disable-schema-downloads,omitempty"`
EnabledSchemaStorage bool `yaml:"enable-schema-storage,omitempty"`
Expand Down Expand Up @@ -68,11 +68,11 @@ func New(config Config) (*Gateway, error) {
if config.Log == nil {
config.Log = NoLog
}
if config.ConfigDirectory == "" {
config.ConfigDirectory = "."
if config.WorkDirectory == "" {
config.WorkDirectory = "."
}
if config.EnabledSchemaStorage {
os.MkdirAll(filepath.Join(config.ConfigDirectory, "upstreams"), 0755)
os.MkdirAll(filepath.Join(config.WorkDirectory, "upstreams"), 0755)
}

fieldResolver := resolvers.TypeAndFieldResolver{}
Expand Down Expand Up @@ -309,7 +309,7 @@ func HaveUpstreamSchemaChanged(config Config) (bool, error) {
for eid, upstream := range upstreams {

// Load the old stored schema.
upstreamSchemaFile := filepath.Join(config.ConfigDirectory, "upstreams", eid+".graphql")
upstreamSchemaFile := filepath.Join(config.WorkDirectory, "upstreams", eid+".graphql")
data, err := ioutil.ReadFile(upstreamSchemaFile)
if err != nil {
return false, err
Expand Down
4 changes: 2 additions & 2 deletions internal/gateway/schema_load.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func loadEndpointSchema(config Config, upstream *upstreamServer) (*schema.Schema
return Parse(schemaText)
}

upstreamSchemaFile := filepath.Join(config.ConfigDirectory, "upstreams", upstream.id+".graphql")
upstreamSchemaFile := filepath.Join(config.WorkDirectory, "upstreams", upstream.id+".graphql")
upstreamSchemaFileExists := false
if stat, err := os.Stat(upstreamSchemaFile); err == nil && !stat.IsDir() {
upstreamSchemaFileExists = true
Expand Down Expand Up @@ -69,7 +69,7 @@ func downloadSchema(config Config, upstream *upstreamServer) (*schema.Schema, er

// We may need to store it if it succeeded.
if err == nil && config.EnabledSchemaStorage {
upstreamSchemaFile := filepath.Join(config.ConfigDirectory, "upstreams", upstream.id+".graphql")
upstreamSchemaFile := filepath.Join(config.WorkDirectory, "upstreams", upstream.id+".graphql")
err := ioutil.WriteFile(upstreamSchemaFile, []byte(s.String()), 0644)
if err != nil {
return nil, errors.Wrap(err, "could not update schema")
Expand Down

0 comments on commit 9e0c60c

Please sign in to comment.