Skip to content

Commit 815a916

Browse files
committed
feat(code-as-config): Add support for golang
1 parent 78d1f1c commit 815a916

File tree

13 files changed

+198
-32
lines changed

13 files changed

+198
-32
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ require (
2020
github.com/hashicorp/go-getter v1.5.11
2121
github.com/imdario/mergo v0.3.12
2222
github.com/jedib0t/go-pretty v4.3.0+incompatible
23-
github.com/jhoonb/archivex v0.0.0-20201016144719-6a343cdae81d
2423
github.com/mitchellh/mapstructure v1.4.2
2524
github.com/moby/buildkit v0.9.3 // indirect
25+
github.com/moby/moby v20.10.12+incompatible
2626
github.com/nitrictech/boxygen v0.0.1-rc.7.0.20211212231606-62c668408f91
2727
github.com/nitrictech/nitric v0.13.0-rc.11
2828
github.com/pkg/errors v0.9.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,8 +1011,6 @@ github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0
10111011
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
10121012
github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM=
10131013
github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
1014-
github.com/jhoonb/archivex v0.0.0-20201016144719-6a343cdae81d h1:q7n+5taxmM+9T2Q7Ydo7YN90FkoDuR5bbzByZwkQqPo=
1015-
github.com/jhoonb/archivex v0.0.0-20201016144719-6a343cdae81d/go.mod h1:GN1Mg/uXQ6qwXA0HypnUO3xlcQJS9/y68EsHNeuuRa4=
10161014
github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4=
10171015
github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s=
10181016
github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
@@ -1219,6 +1217,8 @@ github.com/moby/buildkit v0.8.1/go.mod h1:/kyU1hKy/aYCuP39GZA9MaKioovHku57N6cqlK
12191217
github.com/moby/buildkit v0.9.3 h1:0JmMLY45KIKFogJXv4LyWo+KmIMuvhit5TDrwBlxDp0=
12201218
github.com/moby/buildkit v0.9.3/go.mod h1:5dZQUHg9STw/Fhl4zZiusDJKn8uje/0x952Nce4a8cg=
12211219
github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
1220+
github.com/moby/moby v20.10.12+incompatible h1:MJVrdG0tIQqVJQBTdtooPuZQFIgski5pYTXlcW8ToE0=
1221+
github.com/moby/moby v20.10.12+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
12221222
github.com/moby/sys/mount v0.1.0/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
12231223
github.com/moby/sys/mount v0.1.1/go.mod h1:FVQFLDRWwyBjDTBNQXDlWnSFREqOo3OKX9aqhmeoo74=
12241224
github.com/moby/sys/mount v0.2.0/go.mod h1:aAivFE2LB3W4bACsUXChRHQ0qKWsetY4Y9V7sxOougM=

mocks/mock_containerengine/mock_containerengine.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/codeconfig/codeconfig.go

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,26 @@ package codeconfig
1919
import (
2020
"fmt"
2121
"net"
22+
"os"
2223
"path"
2324
"runtime"
2425
"strings"
2526
"sync"
2627

28+
"github.com/docker/docker/api/types"
2729
"github.com/docker/docker/api/types/container"
2830
"github.com/docker/docker/api/types/mount"
2931
"github.com/docker/docker/api/types/strslice"
3032
"github.com/getkin/kin-openapi/openapi3"
3133
"github.com/imdario/mergo"
34+
"github.com/moby/moby/pkg/stdcopy"
3235
"github.com/pkg/errors"
3336
"google.golang.org/grpc"
3437

3538
"github.com/nitrictech/newcli/pkg/build"
3639
"github.com/nitrictech/newcli/pkg/containerengine"
3740
"github.com/nitrictech/newcli/pkg/cron"
41+
"github.com/nitrictech/newcli/pkg/run"
3842
"github.com/nitrictech/newcli/pkg/stack"
3943
"github.com/nitrictech/newcli/pkg/utils"
4044
v1 "github.com/nitrictech/nitric/pkg/api/nitric/v1"
@@ -209,6 +213,35 @@ func (c *codeConfig) apiSpec(api string) (*openapi3.T, error) {
209213
return doc, nil
210214
}
211215

216+
func launchOptsForFunctionCollect(runCtx, handler string) (run.LaunchOpts, error) {
217+
rt, err := utils.NewRunTimeFromFilename(handler)
218+
if err != nil {
219+
return run.LaunchOpts{}, err
220+
}
221+
222+
switch rt {
223+
case utils.RuntimeJavascript, utils.RuntimeTypescript:
224+
return run.LaunchOpts{
225+
Image: rt.DevImageName(),
226+
Entrypoint: strslice.StrSlice{"ts-node"},
227+
Cmd: strslice.StrSlice{"-T " + "/app/" + handler},
228+
}, nil
229+
case utils.RuntimeGolang:
230+
module, err := utils.GoModule(runCtx)
231+
if err != nil {
232+
return run.LaunchOpts{}, err
233+
}
234+
return run.LaunchOpts{
235+
Image: rt.DevImageName(),
236+
TargetWD: path.Join("/go/src", module),
237+
Entrypoint: strslice.StrSlice{"go", "run"},
238+
Cmd: strslice.StrSlice{"./" + handler},
239+
}, nil
240+
default:
241+
return run.LaunchOpts{}, errors.New("could not get launchOpts from " + handler + ", runtime not supported")
242+
}
243+
}
244+
212245
// collectOne - Collects information about a function for a nitric stack
213246
// handler - the specific handler for the application
214247
func (c *codeConfig) collectOne(handler string) error {
@@ -240,13 +273,19 @@ func (c *codeConfig) collectOne(handler string) error {
240273
return errors.WithMessage(err, "error running the handler")
241274
}
242275

276+
opts, err := launchOptsForFunctionCollect(c.initialStack.Dir, handler)
277+
if err != nil {
278+
return err
279+
}
280+
fmt.Println(opts.String())
281+
243282
hostConfig := &container.HostConfig{
244283
AutoRemove: true,
245284
Mounts: []mount.Mount{
246285
{
247286
Type: "bind",
248287
Source: c.initialStack.Dir,
249-
Target: "/app",
288+
Target: opts.TargetWD,
250289
},
251290
},
252291
}
@@ -256,15 +295,18 @@ func (c *codeConfig) collectOne(handler string) error {
256295
hostConfig.ExtraHosts = []string{"host.docker.internal:172.17.0.1"}
257296
}
258297

259-
rt, err := utils.NewRunTimeFromFilename(handler)
260-
if err != nil {
261-
return err
262-
}
263298
cID, err := ce.ContainerCreate(&container.Config{
264-
Image: rt.DevImageName(), // Select an image to use based on the handler
265-
// Set the address to the bound port
266-
Env: []string{fmt.Sprintf("SERVICE_ADDRESS=host.docker.internal:%d", port)},
267-
Cmd: strslice.StrSlice{"-T", handler},
299+
AttachStdout: true,
300+
AttachStderr: true,
301+
Image: opts.Image,
302+
Env: []string{
303+
fmt.Sprintf("SERVICE_ADDRESS=host.docker.internal:%d", port),
304+
fmt.Sprintf("NITRIC_SERVICE_PORT=%d", port),
305+
fmt.Sprintf("NITRIC_SERVICE_HOST=%s", "host.docker.internal"),
306+
},
307+
Cmd: opts.Cmd,
308+
Entrypoint: opts.Entrypoint,
309+
WorkingDir: opts.TargetWD,
268310
}, hostConfig, nil, containerNameFromHandler(handler))
269311
if err != nil {
270312
return err
@@ -275,6 +317,18 @@ func (c *codeConfig) collectOne(handler string) error {
275317
return err
276318
}
277319

320+
logreader, err := ce.ContainerLogs(cID, types.ContainerLogsOptions{
321+
ShowStdout: true,
322+
ShowStderr: true,
323+
Follow: true,
324+
})
325+
if err != nil {
326+
return err
327+
}
328+
go func() {
329+
_, _ = stdcopy.StdCopy(os.Stdout, os.Stderr, logreader)
330+
}()
331+
278332
errs := utils.NewErrorList()
279333
waitChan, cErrChan := ce.ContainerWait(cID, container.WaitConditionNextExit)
280334
select {
@@ -300,7 +354,8 @@ func (c *codeConfig) collectOne(handler string) error {
300354
}
301355

302356
func containerNameFromHandler(handler string) string {
303-
return strings.Replace(path.Base(handler), path.Ext(handler), "", 1)
357+
rt, _ := utils.NewRunTimeFromFilename(handler)
358+
return rt.ContainerName(handler)
304359
}
305360

306361
func (c *codeConfig) addFunction(fun *FunctionDependencies, handler string) {

pkg/containerengine/docker.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@ func (d *docker) ContainerWait(containerID string, condition container.WaitCondi
257257
return d.cli.ContainerWait(context.Background(), containerID, condition)
258258
}
259259

260+
func (d *docker) ContainerLogs(containerID string, opts types.ContainerLogsOptions) (io.ReadCloser, error) {
261+
return d.cli.ContainerLogs(context.Background(), containerID, opts)
262+
}
263+
260264
func (d *docker) ContainerExec(containerName string, cmd []string, workingDir string) error {
261265
ctx := context.Background()
262266
rst, err := d.cli.ContainerExecCreate(ctx, containerName, types.ExecConfig{

pkg/containerengine/podman.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ func (p *podman) ContainerExec(containerName string, cmd []string, workingDir st
129129
return p.docker.ContainerExec(containerName, cmd, workingDir)
130130
}
131131

132+
func (p *podman) ContainerLogs(containerID string, opts types.ContainerLogsOptions) (io.ReadCloser, error) {
133+
return p.docker.ContainerLogs(containerID, opts)
134+
}
135+
132136
func (p *podman) Logger(stackPath string) ContainerLogger {
133137
logPath, _ := utils.NewNitricLogFile(stackPath)
134138
return &jsonfile{logPath: logPath}

pkg/containerengine/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ type ContainerEngine interface {
5656
ContainersListByLabel(match map[string]string) ([]types.Container, error)
5757
RemoveByLabel(name, value string) error
5858
ContainerExec(containerName string, cmd []string, workingDir string) error
59+
ContainerLogs(containerID string, opts types.ContainerLogsOptions) (io.ReadCloser, error)
5960
Logger(stackPath string) ContainerLogger
6061
}
6162

pkg/functiondockerfile/generator.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ func GenerateForCodeAsConfig(handler string, fwriter io.Writer) error {
7373
switch rt {
7474
case utils.RuntimeJavascript, utils.RuntimeTypescript:
7575
return typescriptDevBaseGenerator(fwriter)
76+
case utils.RuntimeGolang:
77+
return golangDevBaseGenerator(fwriter)
7678
}
7779

7880
return errors.New("could not build dockerfile from " + handler + ", extension not supported")

pkg/functiondockerfile/golang.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,17 @@ func golangGenerator(f *stack.Function, version, provider string, w io.Writer) e
7474
_, err = w.Write([]byte(strings.Join(append(buildCon.Lines(), con.Lines()...), "\n")))
7575
return err
7676
}
77+
78+
// golangDevBaseGenerator generates a base image for code-as-config
79+
func golangDevBaseGenerator(w io.Writer) error {
80+
con, err := dockerfile.NewContainer(dockerfile.NewContainerOpts{
81+
From: "golang:alpine",
82+
Ignore: []string{},
83+
})
84+
if err != nil {
85+
return err
86+
}
87+
88+
_, err = w.Write([]byte(strings.Join(con.Lines(), "\n")))
89+
return err
90+
}

pkg/run/function.go

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ package run
1818
import (
1919
"errors"
2020
"fmt"
21-
"path/filepath"
21+
"path"
2222
"runtime"
2323
"strings"
2424

@@ -41,37 +41,56 @@ type Function struct {
4141
}
4242

4343
type LaunchOpts struct {
44+
Image string
45+
TargetWD string
4446
Entrypoint []string
4547
Cmd []string
4648
}
4749

50+
func (o *LaunchOpts) String() string {
51+
return fmt.Sprintf("docker run -v <stackDir>:%s -w %s %s %v %v", o.TargetWD, o.TargetWD, o.Image, strings.Join(o.Entrypoint, " "), strings.Join(o.Cmd, " "))
52+
}
53+
4854
func launchOptsForFunction(f *Function) (LaunchOpts, error) {
49-
opts := LaunchOpts{Entrypoint: strslice.StrSlice{"nodemon"}}
50-
rt, err := utils.NewRunTimeFromFilename(f.handler)
51-
if err != nil {
52-
return opts, err
53-
}
54-
switch rt {
55+
switch f.runtime {
5556
case utils.RuntimeJavascript, utils.RuntimeTypescript:
56-
opts.Cmd = strslice.StrSlice{"--watch", "/app/**", "--ext", "ts,js,json", "--exec", "ts-node -T " + "/app/" + f.handler}
57+
return LaunchOpts{
58+
TargetWD: "/app",
59+
Entrypoint: strslice.StrSlice{"nodemon"},
60+
Cmd: strslice.StrSlice{"--watch", "/app/**", "--ext", "ts,js,json", "--exec", "ts-node -T " + "/app/" + f.handler},
61+
}, nil
62+
case utils.RuntimeGolang:
63+
module, err := utils.GoModule(f.runCtx)
64+
if err != nil {
65+
return LaunchOpts{}, err
66+
}
67+
return LaunchOpts{
68+
TargetWD: path.Join("/go/src", module),
69+
Entrypoint: strslice.StrSlice{"go", "run"},
70+
Cmd: strslice.StrSlice{"./" + f.handler},
71+
}, nil
5772
default:
58-
return opts, errors.New("could not get launchOpts from " + f.handler + ", runtime not supported")
73+
return LaunchOpts{}, errors.New("could not get launchOpts from " + f.handler + ", runtime not supported")
5974
}
60-
return opts, nil
6175
}
6276

6377
func (f *Function) Name() string {
64-
return strings.Replace(filepath.Base(f.handler), filepath.Ext(f.handler), "", 1)
78+
return f.runtime.ContainerName(f.handler)
6579
}
6680

6781
func (f *Function) Start() error {
82+
launchOpts, err := launchOptsForFunction(f)
83+
if err != nil {
84+
return err
85+
}
86+
6887
hostConfig := &container.HostConfig{
6988
AutoRemove: true,
7089
Mounts: []mount.Mount{
7190
{
7291
Type: "bind",
7392
Source: f.runCtx,
74-
Target: "/app",
93+
Target: launchOpts.TargetWD,
7594
},
7695
},
7796
LogConfig: *f.ce.Logger(f.runCtx).Config(),
@@ -82,17 +101,13 @@ func (f *Function) Start() error {
82101
hostConfig.ExtraHosts = []string{"host.docker.internal:172.17.0.1"}
83102
}
84103

85-
launchOpts, err := launchOptsForFunction(f)
86-
if err != nil {
87-
return err
88-
}
89-
90104
cID, err := f.ce.ContainerCreate(&container.Config{
91105
Image: f.runtime.DevImageName(), // Select an image to use based on the handler
92106
// Set the address to the bound port
93107
Env: []string{fmt.Sprintf("SERVICE_ADDRESS=host.docker.internal:%d", 50051)},
94108
Entrypoint: launchOpts.Entrypoint,
95109
Cmd: launchOpts.Cmd,
110+
WorkingDir: launchOpts.TargetWD,
96111
}, hostConfig, nil, f.Name())
97112
if err != nil {
98113
return err

pkg/stack/options.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"os"
2121
"path"
2222
"path/filepath"
23-
"strings"
2423

2524
"github.com/pkg/errors"
2625
"github.com/spf13/cobra"
@@ -61,7 +60,8 @@ func FromOptions() (*Stack, error) {
6160
}
6261

6362
func FunctionFromHandler(h, stackDir string) Function {
64-
name := strings.Replace(path.Base(h), path.Ext(h), "", 1)
63+
rt, _ := utils.NewRunTimeFromFilename(h)
64+
name := rt.ContainerName(h)
6565
fn := Function{
6666
ComputeUnit: ComputeUnit{Name: name},
6767
Handler: h,

0 commit comments

Comments
 (0)