Skip to content

Commit

Permalink
fix: rework services
Browse files Browse the repository at this point in the history
  • Loading branch information
hackercat committed Dec 20, 2021
1 parent ada1375 commit cd0cfc9
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 68 deletions.
44 changes: 40 additions & 4 deletions pkg/container/docker_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@ import (
"github.com/nektos/act/pkg/common"
)

func NewDockerNetworkCreateExecutor(name string) common.Executor {
func NewDockerNetworkCreateExecutor(name string, config types.NetworkCreate) common.Executor {
return func(ctx context.Context) error {
if common.Dryrun(ctx) {
return nil
}

cli, err := GetDockerClient(ctx)
if err != nil {
return err
}

_, err = cli.NetworkCreate(ctx, name, types.NetworkCreate{})
if err != nil {
if exists := DockerNetworkExists(ctx, name); exists {
return nil
}

if _, err = cli.NetworkCreate(ctx, name, config); err != nil {
return err
}

Expand All @@ -25,12 +32,41 @@ func NewDockerNetworkCreateExecutor(name string) common.Executor {

func NewDockerNetworkRemoveExecutor(name string) common.Executor {
return func(ctx context.Context) error {
if common.Dryrun(ctx) {
return nil
}

cli, err := GetDockerClient(ctx)
if err != nil {
return err
}

cli.NetworkRemove(ctx, name)
err = cli.NetworkRemove(ctx, name)
if err != nil {
return err
}

return nil
}
}

func DockerNetworkExists(ctx context.Context, name string) bool {
if _, exists, _ := GetDockerNetwork(ctx, name); !exists {
return false
}
return true
}

func GetDockerNetwork(ctx context.Context, name string) (types.NetworkResource, bool, error) {
cli, err := GetDockerClient(ctx)
if err != nil {
return types.NetworkResource{}, false, err
}

res, err := cli.NetworkInspect(ctx, name, types.NetworkInspectOptions{})
if err != nil {
return types.NetworkResource{}, false, err
}

return res, true, nil
}
80 changes: 56 additions & 24 deletions pkg/container/docker_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type Container interface {
UpdateFromPath(env *map[string]string) common.Executor
Remove() common.Executor
Close() common.Executor
SetContainerNetworkMode(mode string) common.Executor
}

// NewContainer creates a reference to a container
Expand Down Expand Up @@ -106,12 +107,26 @@ func supportsContainerImagePlatform(cli *client.Client) bool {
return constraint.Check(sv)
}

func (cr *containerReference) SetContainerNetworkMode(mode string) common.Executor {
return common.
NewDebugExecutor("Changed network mode for container '%s' from '%s' to '%s'", cr.input.Name, cr.input.NetworkMode, mode).
Then(
common.NewPipelineExecutor(
func(ctx context.Context) error {
cr.input.NetworkMode = mode
return nil
},
).IfNot(common.Dryrun),
)
}

func (cr *containerReference) ConnectToNetwork(name string) common.Executor {
return common.
NewDebugExecutor("%sdocker network connect %s %s", logPrefix, name, cr.input.Name).
NewInfoExecutor("%sdocker network connect %s %s", logPrefix, name, cr.input.Name).
Then(
common.NewPipelineExecutor(
cr.connect(),
cr.find(),
cr.connectToNetwork(name),
).IfNot(common.Dryrun),
)
Expand Down Expand Up @@ -158,19 +173,26 @@ func (cr *containerReference) Pull(forcePull bool) common.Executor {
}

func (cr *containerReference) Copy(destPath string, files ...*FileEntry) common.Executor {
return common.NewPipelineExecutor(
cr.connect(),
cr.find(),
cr.copyContent(destPath, files...),
).IfNot(common.Dryrun)
return common.
NewInfoExecutor("%sdocker cp %+v destPath=%s", logPrefix, files, destPath).
Then(
common.NewPipelineExecutor(
cr.connect(),
cr.find(),
cr.copyContent(destPath, files...),
).IfNot(common.Dryrun),
)
}

func (cr *containerReference) CopyDir(destPath string, srcPath string, useGitIgnore bool) common.Executor {
return common.NewPipelineExecutor(
common.NewInfoExecutor("%sdocker cp src=%s dst=%s", logPrefix, srcPath, destPath),
cr.Exec([]string{"mkdir", "-p", destPath}, nil, "", ""),
cr.copyDir(destPath, srcPath, useGitIgnore),
).IfNot(common.Dryrun)
return common.
NewInfoExecutor("%sdocker cp src=%s dst=%s", logPrefix, srcPath, destPath).
Then(
common.NewPipelineExecutor(
cr.Exec([]string{"mkdir", "-p", destPath}, nil, "", ""),
cr.copyDir(destPath, srcPath, useGitIgnore),
).IfNot(common.Dryrun),
)
}

func (cr *containerReference) GetContainerArchive(ctx context.Context, srcPath string) (io.ReadCloser, error) {
Expand All @@ -191,21 +213,28 @@ func (cr *containerReference) UpdateFromPath(env *map[string]string) common.Exec
}

func (cr *containerReference) Exec(command []string, env map[string]string, user, workdir string) common.Executor {
return common.NewPipelineExecutor(
common.NewInfoExecutor("%sdocker exec cmd=[%s] user=%s workdir=%s", logPrefix, strings.Join(command, " "), user, workdir),
cr.connect(),
cr.find(),
cr.exec(command, env, user, workdir),
).IfNot(common.Dryrun)
return common.
NewInfoExecutor("%sdocker exec cmd=%v user=%s workdir=%s", logPrefix, command, user, workdir).
Then(
common.NewPipelineExecutor(
cr.connect(),
cr.find(),
cr.exec(command, env, user, workdir),
).IfNot(common.Dryrun),
)
}

func (cr *containerReference) Remove() common.Executor {
return common.NewPipelineExecutor(
cr.connect(),
cr.find(),
).Finally(
cr.remove(),
).IfNot(common.Dryrun)
return common.
NewInfoExecutor("%sdocker rm %s", logPrefix, cr.id).
Then(
common.NewPipelineExecutor(
cr.connect(),
cr.find(),
).Finally(
cr.remove(),
).IfNot(common.Dryrun),
)
}

type containerReference struct {
Expand Down Expand Up @@ -247,7 +276,7 @@ func GetDockerClient(ctx context.Context) (*client.Client, error) {

func (cr *containerReference) connectToNetwork(name string) common.Executor {
return func(ctx context.Context) error {
return cr.cli.NetworkConnect(ctx, name, cr.input.Name, nil)
return cr.cli.NetworkConnect(ctx, name, cr.id, nil)
}
}

Expand Down Expand Up @@ -338,9 +367,11 @@ func (cr *containerReference) create(capAdd []string, capDrop []string) common.E
Tty: isTerminal,
Hostname: input.Hostname,
}

if len(input.Cmd) > 0 {
config.Cmd = input.Cmd
}

if len(input.Entrypoint) > 0 {
config.Entrypoint = input.Entrypoint
}
Expand Down Expand Up @@ -379,6 +410,7 @@ func (cr *containerReference) create(capAdd []string, capDrop []string) common.E
if err != nil {
return errors.WithStack(err)
}

logger.Debugf("Created container name=%s id=%v from image %v (platform: %s)", input.Name, resp.ID, input.Image, input.Platform)
logger.Debugf("ENV ==> %v", input.Env)

Expand Down
95 changes: 58 additions & 37 deletions pkg/runner/run_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"runtime"
"strings"

"github.com/docker/docker/api/types"
"github.com/google/shlex"
"github.com/spf13/pflag"

Expand Down Expand Up @@ -138,6 +139,11 @@ func (rc *RunContext) GetBindsAndMounts() ([]string, map[string]string) {
return binds, mounts
}

// JobNetworkName returns formatted network name used in main container and its services
func (rc *RunContext) JobNetworkName() string {
return createNetworkName("act", rc.Run.Workflow.Name, rc.Run.JobID, rc.Name)
}

func (rc *RunContext) startJobContainer() common.Executor {
image := rc.platformImage()
hostname := rc.hostname()
Expand All @@ -160,6 +166,7 @@ func (rc *RunContext) startJobContainer() common.Executor {

common.Logger(ctx).Infof("\U0001f680 Start image=%s", image)
name := rc.jobContainerName()
networkName := rc.JobNetworkName()

envList := make([]string, 0)

Expand All @@ -169,33 +176,35 @@ func (rc *RunContext) startJobContainer() common.Executor {

binds, mounts := rc.GetBindsAndMounts()

// add service containers
for name, spec := range rc.Run.Job().Services {
mergedEnv := envList
for k, v := range spec.Env {
mergedEnv = append(mergedEnv, fmt.Sprintf("%s=%s", k, v))
}
if rc.Run.Job().Services != nil {
// add service containers
for name, spec := range rc.Run.Job().Services {
mergedEnv := envList
for k, v := range spec.Env {
mergedEnv = append(mergedEnv, fmt.Sprintf("%s=%s", k, v))
}

mnt := mounts
mnt[name] = filepath.Dir(rc.Config.ContainerWorkdir())

c := container.NewContainer(&container.NewContainerInput{
Name: name,
WorkingDir: rc.Config.ContainerWorkdir(),
Image: spec.Image,
Username: rc.Config.Secrets["DOCKER_USERNAME"],
Password: rc.Config.Secrets["DOCKER_PASSWORD"],
Env: mergedEnv,
Mounts: mnt,
// NetworkMode: "host",
Binds: binds,
Stdout: logWriter,
Stderr: logWriter,
Privileged: rc.Config.Privileged,
UsernsMode: rc.Config.UsernsMode,
Platform: rc.Config.ContainerArchitecture,
})
rc.ServiceContainers = append(rc.ServiceContainers, c)
mnt := mounts
mnt[name] = filepath.Dir(rc.Config.ContainerWorkdir())

c := container.NewContainer(&container.NewContainerInput{
Name: name,
Hostname: name,
WorkingDir: rc.Config.ContainerWorkdir(),
Image: spec.Image,
Username: rc.Config.Secrets["DOCKER_USERNAME"],
Password: rc.Config.Secrets["DOCKER_PASSWORD"],
Env: mergedEnv,
Mounts: mnt,
Binds: binds,
Stdout: logWriter,
Stderr: logWriter,
Privileged: rc.Config.Privileged,
UsernsMode: rc.Config.UsernsMode,
Platform: rc.Config.ContainerArchitecture,
})
rc.ServiceContainers = append(rc.ServiceContainers, c)
}
}

rc.JobContainer = container.NewContainer(&container.NewContainerInput{
Expand All @@ -208,7 +217,6 @@ func (rc *RunContext) startJobContainer() common.Executor {
Name: name,
Env: envList,
Mounts: mounts,
// NetworkMode: "host",
Binds: binds,
Stdout: logWriter,
Stderr: logWriter,
Expand All @@ -218,25 +226,31 @@ func (rc *RunContext) startJobContainer() common.Executor {
Hostname: hostname,
})

if rc.Run.Job().Services == nil {
rc.JobContainer.SetContainerNetworkMode("host")
}

var copyWorkspace bool
var copyToPath string
if !rc.Config.BindWorkdir {
copyToPath, copyWorkspace = rc.localCheckoutPath()
copyToPath = filepath.Join(rc.Config.ContainerWorkdir(), copyToPath)
}

networkName := fmt.Sprintf("act-%s-network", rc.Run.JobID)
return common.NewPipelineExecutor(
rc.JobContainer.Pull(rc.Config.ForcePull),
rc.stopServiceContainers(),
rc.stopJobContainer(),
rc.removeNetwork(networkName),
rc.createNetwork(networkName),
rc.startServiceContainers(networkName),
common.NewPipelineExecutor(
rc.createNetwork(networkName, types.NetworkCreate{CheckDuplicate: true}).IfBool(!container.DockerNetworkExists(ctx, networkName)),
rc.startServiceContainers(networkName),
).IfBool(rc.Run.Job().Services != nil || rc.Run.Job().Container() != nil),
rc.JobContainer.Create(rc.Config.ContainerCapAdd, rc.Config.ContainerCapDrop),
rc.JobContainer.Start(false),
rc.JobContainer.UpdateFromImageEnv(&rc.Env),
rc.JobContainer.ConnectToNetwork(networkName),
common.NewPipelineExecutor(
rc.JobContainer.ConnectToNetwork(networkName),
).IfBool(rc.Run.Job().Services != nil || rc.Run.Job().Container() != nil),
rc.JobContainer.UpdateFromEnv("/etc/environment", &rc.Env),
rc.JobContainer.Exec([]string{"mkdir", "-m", "0777", "-p", ActPath}, rc.Env, "root", ""),
rc.JobContainer.CopyDir(copyToPath, rc.Config.Workdir+string(filepath.Separator)+".", rc.Config.UseGitIgnore).IfBool(copyWorkspace),
Expand All @@ -257,9 +271,9 @@ func (rc *RunContext) startJobContainer() common.Executor {
}
}

func (rc *RunContext) createNetwork(name string) common.Executor {
func (rc *RunContext) createNetwork(name string, config types.NetworkCreate) common.Executor {
return func(ctx context.Context) error {
return container.NewDockerNetworkCreateExecutor(name)(ctx)
return container.NewDockerNetworkCreateExecutor(name, config)(ctx)
}
}

Expand All @@ -279,8 +293,11 @@ func (rc *RunContext) execJobContainer(cmd []string, env map[string]string, user
func (rc *RunContext) stopJobContainer() common.Executor {
return func(ctx context.Context) error {
if rc.JobContainer != nil && !rc.Config.ReuseContainers {
return rc.JobContainer.Remove().
Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName(), false))(ctx)
return common.NewPipelineExecutor(
rc.stopServiceContainers(),
rc.JobContainer.Remove().Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName(), false)),
rc.removeNetwork(rc.JobNetworkName()).IfBool((rc.Run.Job().Services != nil || rc.Run.Job().Container() != nil) && !rc.Config.ReuseContainers && container.DockerNetworkExists(ctx, rc.JobNetworkName())),
)(ctx)
}
return nil
}
Expand All @@ -293,8 +310,8 @@ func (rc *RunContext) startServiceContainers(networkName string) common.Executor
execs = append(execs, common.NewPipelineExecutor(
c.Pull(false),
c.Create([]string{}, []string{}),
c.Start(false),
c.ConnectToNetwork(networkName),
c.Start(false),
))
}
return common.NewParallelExecutor(execs...)(ctx)
Expand Down Expand Up @@ -551,6 +568,10 @@ func createContainerName(parts ...string) string {
return strings.ReplaceAll(strings.Trim(strings.Join(name, "-"), "-"), "--", "-")
}

func createNetworkName(parts ...string) string {
return strings.ReplaceAll(strings.Trim(strings.Join(parts, "_"), "-"), "--", "-")
}

func trimToLen(s string, l int) string {
if l < 0 {
l = 0
Expand Down
Loading

0 comments on commit cd0cfc9

Please sign in to comment.