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

feat: add docker support and support a workdir CLI option in case your running in a kube pod with the config directory readonly (due to it being mounted from a ConfigMap). #36

Merged
merged 1 commit into from
Jul 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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