github.com/devcamcar/cli@v0.0.0-20181107134215-706a05759d18/commands/build_server.go (about) 1 package commands 2 3 import ( 4 "errors" 5 "fmt" 6 "html/template" 7 "io/ioutil" 8 "os" 9 10 "github.com/fnproject/cli/common" 11 "github.com/urfave/cli" 12 yaml "gopkg.in/yaml.v2" 13 ) 14 15 type BuildServerCmd struct { 16 verbose bool 17 noCache bool 18 } 19 20 // BuildServerCommand returns build server cli.command 21 func BuildServerCommand() cli.Command { 22 cmd := BuildServerCmd{} 23 flags := append([]cli.Flag{}, cmd.flags()...) 24 return cli.Command{ 25 Name: "build-server", 26 Usage: "Build custom Fn server", 27 Category: "SERVER COMMANDS", 28 Description: "This command builds a custom Fn server.", 29 Flags: flags, 30 Action: cmd.buildServer, 31 } 32 } 33 34 func (b *BuildServerCmd) flags() []cli.Flag { 35 return []cli.Flag{ 36 cli.BoolFlag{ 37 Name: "v", 38 Usage: "verbose mode", 39 Destination: &b.verbose, 40 }, 41 cli.BoolFlag{ 42 Name: "no-cache", 43 Usage: "Don't use docker cache", 44 Destination: &b.noCache, 45 }, 46 cli.StringFlag{ 47 Name: "tag,t", 48 Usage: "Image name and optional tag", 49 }, 50 } 51 } 52 53 // steps: 54 // • Yaml file with extensions listed 55 // • NOTE: All extensions should use env vars for config 56 // • Generating main.go with extensions 57 // * Generate a Dockerfile that gets all the extensions (using dep) 58 // • then generate a main.go with extensions 59 // • compile, throw in another container like main dockerfile 60 func (b *BuildServerCmd) buildServer(c *cli.Context) error { 61 62 if c.String("tag") == "" { 63 return errors.New("Docker tag required") 64 } 65 66 // path, err := os.Getwd() 67 // if err != nil { 68 // return err 69 // } 70 fpath := "ext.yaml" 71 bb, err := ioutil.ReadFile(fpath) 72 if err != nil { 73 return fmt.Errorf("Could not open %s for parsing. Error: %v", fpath, err) 74 } 75 ef := &extFile{} 76 err = yaml.Unmarshal(bb, ef) 77 if err != nil { 78 return err 79 } 80 81 err = os.MkdirAll("tmp", 0777) 82 if err != nil { 83 return err 84 } 85 err = os.Chdir("tmp") 86 if err != nil { 87 return err 88 } 89 err = generateMain(ef) 90 if err != nil { 91 return err 92 } 93 err = generateDockerfile() 94 if err != nil { 95 return err 96 } 97 dir, err := os.Getwd() 98 if err != nil { 99 return err 100 } 101 err = common.RunBuild(c.GlobalBool("verbose"), dir, c.String("tag"), "Dockerfile", nil, b.noCache) 102 if err != nil { 103 return err 104 } 105 fmt.Printf("Custom Fn server built successfully.\n") 106 return nil 107 } 108 109 func generateMain(ef *extFile) error { 110 tmpl, err := template.New("main").Parse(mainTmpl) 111 if err != nil { 112 return err 113 } 114 f, err := os.Create("main.go") 115 if err != nil { 116 return err 117 } 118 defer f.Close() 119 err = tmpl.Execute(f, ef) 120 if err != nil { 121 return err 122 } 123 return nil 124 } 125 126 func generateDockerfile() error { 127 return ioutil.WriteFile("Dockerfile", []byte(dockerFileTmpl), os.FileMode(0644)) 128 } 129 130 type extFile struct { 131 Extensions []*extInfo `yaml:"extensions"` 132 } 133 134 type extInfo struct { 135 Name string `yaml:"name"` 136 // will have version and other things down the road 137 } 138 139 var mainTmpl = `package main 140 141 import ( 142 "context" 143 144 "github.com/fnproject/fn/api/server" 145 146 {{- range .Extensions }} 147 _ "{{ .Name }}" 148 {{- end}} 149 ) 150 151 func main() { 152 ctx := context.Background() 153 funcServer := server.NewFromEnv(ctx) 154 {{- range .Extensions }} 155 funcServer.AddExtensionByName("{{ .Name }}") 156 {{- end}} 157 funcServer.Start(ctx) 158 } 159 ` 160 161 // NOTE: Getting build errors with dep, probably because our vendor dir is wack. Might work again once we switch to dep. 162 // vendor/github.com/fnproject/fn/api/agent/drivers/docker/registry.go:93: too many arguments in call to client.NewRepository 163 // have ("context".Context, reference.Named, string, http.RoundTripper) want (reference.Named, string, http.RoundTripper) 164 // go build github.com/x/y/vendor/github.com/rdallman/migrate/database/mysql: no buildable Go source files in /go/src/github.com/x/y/vendor/github.com/rdallman/migrate/database/mysql 165 // # github.com/x/y/vendor/github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/scribe 166 // vendor/github.com/openzipkin/zipkin-go-opentracing/thrift/gen-go/scribe/scribe.go:210: undefined: thrift.TClient 167 var dockerFileTmpl = `# build stage 168 FROM golang:1.10-alpine AS build-env 169 RUN apk --no-cache add build-base git bzr mercurial gcc 170 # RUN go get -u github.com/golang/dep/cmd/dep 171 ENV D=/go/src/github.com/x/y 172 ADD main.go $D/ 173 RUN cd $D && go get 174 # RUN cd $D && dep init && dep ensure 175 RUN cd $D && go build -o fnserver && cp fnserver /tmp/ 176 177 # final stage 178 FROM fnproject/dind 179 RUN apk add --no-cache ca-certificates 180 WORKDIR /app 181 COPY --from=build-env /tmp/fnserver /app/fnserver 182 CMD ["./fnserver"] 183 `