Skip to content

Commit

Permalink
refactor(stapel-to-buildah): docker instructions stage
Browse files Browse the repository at this point in the history
Signed-off-by: Ilya Lesikov <ilya@lesikov.com>
  • Loading branch information
ilya-lesikov authored and distorhead committed Apr 5, 2022
1 parent cbacb54 commit c3059ac
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 15 deletions.
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -47,6 +47,7 @@ require (
github.com/helm/helm-2to3 v0.8.1
github.com/jinzhu/gorm v1.9.12 // indirect
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/minio/minio v0.0.0-20210311070216-f92b7a562103
github.com/mitchellh/copystructure v1.2.0
github.com/moby/buildkit v0.8.2
Expand Down
17 changes: 13 additions & 4 deletions pkg/build/stage/docker_instructions.go
Expand Up @@ -76,10 +76,19 @@ func (s *DockerInstructionsStage) PrepareImage(ctx context.Context, c Conveyor,
imageCommitChangeOptions.AddUser(s.instructions.User)
imageCommitChangeOptions.AddWorkdir(s.instructions.Workdir)
imageCommitChangeOptions.AddHealthCheck(s.instructions.HealthCheck)

return nil
} else {
// TODO(stapel-to-buildah)
panic("not implemented")
stageImage.Builder.StapelStageBuilder().SetStageType(container_backend.DockerInstructionsStage)
stageImage.Builder.StapelStageBuilder().
AddVolumes(s.instructions.Volume).
AddExpose(s.instructions.Expose).
AddEnvs(s.instructions.Env).
AddLabels(s.instructions.Label).
SetCmd([]string{s.instructions.Cmd}).
SetEntrypoint([]string{s.instructions.Entrypoint}).
SetUser(s.instructions.User).
SetWorkdir(s.instructions.Workdir).
SetHealthcheck(s.instructions.HealthCheck)
}

return nil
}
17 changes: 9 additions & 8 deletions pkg/buildah/common.go
Expand Up @@ -70,14 +70,15 @@ type CommitOpts struct {

type ConfigOpts struct {
CommonOpts
Labels []string
// TODO:
// Cmd []string
// Entrypoint []string
// Env []string
// Shell string
// User string
// WorkDir string
Labels []string
Volumes []string
Expose []string
Envs map[string]string
Cmd []string
Entrypoint []string
User string
Workdir string
Healthcheck string
}

type (
Expand Down
94 changes: 94 additions & 0 deletions pkg/buildah/native_linux.go
Expand Up @@ -15,6 +15,7 @@ import (

"github.com/containers/buildah"
"github.com/containers/buildah/define"
"github.com/containers/buildah/docker"
"github.com/containers/buildah/imagebuildah"
"github.com/containers/common/libimage"
"github.com/containers/image/v5/manifest"
Expand All @@ -27,7 +28,9 @@ import (
"github.com/containers/storage/pkg/reexec"
"github.com/containers/storage/pkg/unshare"
"github.com/hashicorp/go-multierror"
"github.com/mattn/go-shellwords"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"gopkg.in/errgo.v2/fmt/errors"

"github.com/werf/logboek"
Expand Down Expand Up @@ -359,6 +362,42 @@ func (b *NativeBuildah) Config(ctx context.Context, container string, opts Confi
}
}

for name, value := range opts.Envs {
builder.SetEnv(name, value)
}

for _, volume := range opts.Volumes {
builder.AddVolume(volume)
}

for _, expose := range opts.Expose {
builder.SetPort(expose)
}

if len(opts.Cmd) > 0 {
builder.SetCmd(opts.Cmd)
}

if len(opts.Entrypoint) > 0 {
builder.SetEntrypoint(opts.Entrypoint)
}

if opts.User != "" {
builder.SetUser(opts.User)
}

if opts.Workdir != "" {
builder.SetWorkDir(opts.Workdir)
}

if opts.Healthcheck != "" {
if healthcheck, err := newHealthConfigFromString(opts.Healthcheck); err != nil {
return fmt.Errorf("error creating HEALTHCHECK: %w", err)
} else if healthcheck != nil {
builder.SetHealthcheck(healthcheck)
}
}

return builder.Save()
}

Expand Down Expand Up @@ -485,3 +524,58 @@ func NewNativeStoreOptions(rootlessUID int, driver StorageDriver) (*thirdparty.S
GraphDriverOptions: graphDriverOptions,
}, nil
}

// Can return nil pointer to HealthConfig.
func newHealthConfigFromString(healthcheck string) (*docker.HealthConfig, error) {
if healthcheck == "" {
return nil, nil
}

healthConfig := &docker.HealthConfig{}

cmd := &cobra.Command{
SilenceErrors: true,
SilenceUsage: true,
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return nil
}

switch args[0] {
case "NONE":
healthConfig = &docker.HealthConfig{
Test: []string{"NONE"},
}
return nil
case "CMD", "CMD-SHELL":
if len(args) == 1 {
return fmt.Errorf("HEALTHCHECK %s should have command specified", args[0])
}
healthConfig.Test = args
return nil
}

healthConfig = nil
return nil
},
}

flags := cmd.Flags()
flags.DurationVar(&healthConfig.Interval, "interval", 30*time.Second, "")
flags.DurationVar(&healthConfig.Timeout, "timeout", 30*time.Second, "")
flags.DurationVar(&healthConfig.StartPeriod, "start-period", 0, "")
flags.IntVar(&healthConfig.Retries, "retries", 3, "")

healthcheckSlice, err := shellwords.Parse(healthcheck)
if err != nil {
return nil, fmt.Errorf("error parsing HEALTHCHECK: %w", err)
}
cmd.SetArgs(healthcheckSlice)

if err := cmd.Execute(); err != nil {
return nil, fmt.Errorf("error parsing HEALTHCHECK: %w", err)
}

return healthConfig, nil
}
14 changes: 11 additions & 3 deletions pkg/container_backend/buildah_backend.go
Expand Up @@ -120,10 +120,18 @@ func (runtime *BuildahBackend) BuildStapelStage(ctx context.Context, stageType S
return "", fmt.Errorf("unsupported stage type %q", stageType.String())
}

logboek.Context(ctx).Debug().LogF("Setting labels %v for build container %q\n", opts.Labels, containerID)
logboek.Context(ctx).Debug().LogF("Setting config for build container %q\n", containerID)
if err := runtime.buildah.Config(ctx, containerID, buildah.ConfigOpts{
CommonOpts: runtime.getBuildahCommonOpts(ctx, true),
Labels: opts.Labels,
CommonOpts: runtime.getBuildahCommonOpts(ctx, true),
Labels: opts.Labels,
Volumes: opts.Volumes,
Expose: opts.Expose,
Envs: opts.Envs,
Cmd: opts.Cmd,
Entrypoint: opts.Entrypoint,
User: opts.User,
Workdir: opts.Workdir,
Healthcheck: opts.Healthcheck,
}); err != nil {
return "", fmt.Errorf("unable to set container %q config: %w", containerID, err)
}
Expand Down
63 changes: 63 additions & 0 deletions pkg/container_backend/stapelstagetype.go
Expand Up @@ -14,7 +14,15 @@ const (
type BuildStapelStageOptionsInterface interface {
SetBaseImage(baseImage string) BuildStapelStageOptionsInterface
AddLabels(labels map[string]string) BuildStapelStageOptionsInterface
AddVolumes(volumes []string) BuildStapelStageOptionsInterface
AddExpose(expose []string) BuildStapelStageOptionsInterface
AddEnvs(envs map[string]string) BuildStapelStageOptionsInterface
AddBuildVolumes(volumes ...string) BuildStapelStageOptionsInterface
SetCmd(cmd []string) BuildStapelStageOptionsInterface
SetEntrypoint(entrypoint []string) BuildStapelStageOptionsInterface
SetUser(user string) BuildStapelStageOptionsInterface
SetWorkdir(workdir string) BuildStapelStageOptionsInterface
SetHealthcheck(healthcheck string) BuildStapelStageOptionsInterface

UserCommandsStage() UserCommandsStageOptionsInterface
}
Expand All @@ -27,6 +35,14 @@ type BuildStapelStageOptions struct {
BaseImage string
Labels []string
BuildVolumes []string
Volumes []string
Expose []string
Envs map[string]string
Cmd []string
Entrypoint []string
User string
Workdir string
Healthcheck string

UserCommandsStageOptions
}
Expand All @@ -43,6 +59,53 @@ func (opts *BuildStapelStageOptions) AddLabels(labels map[string]string) BuildSt
return opts
}

func (opts *BuildStapelStageOptions) AddVolumes(volumes []string) BuildStapelStageOptionsInterface {
opts.Volumes = append(opts.Volumes, volumes...)
return opts
}

func (opts *BuildStapelStageOptions) AddExpose(expose []string) BuildStapelStageOptionsInterface {
opts.Expose = append(opts.Expose, expose...)
return opts
}

func (opts *BuildStapelStageOptions) AddEnvs(envs map[string]string) BuildStapelStageOptionsInterface {
if opts.Envs == nil {
opts.Envs = map[string]string{}
}

for k, v := range envs {
opts.Envs[k] = v
}

return opts
}

func (opts *BuildStapelStageOptions) SetCmd(cmd []string) BuildStapelStageOptionsInterface {
opts.Cmd = cmd
return opts
}

func (opts *BuildStapelStageOptions) SetEntrypoint(entrypoint []string) BuildStapelStageOptionsInterface {
opts.Entrypoint = entrypoint
return opts
}

func (opts *BuildStapelStageOptions) SetUser(user string) BuildStapelStageOptionsInterface {
opts.User = user
return opts
}

func (opts *BuildStapelStageOptions) SetWorkdir(workdir string) BuildStapelStageOptionsInterface {
opts.Workdir = workdir
return opts
}

func (opts *BuildStapelStageOptions) SetHealthcheck(healthcheck string) BuildStapelStageOptionsInterface {
opts.Healthcheck = healthcheck
return opts
}

func (opts *BuildStapelStageOptions) AddBuildVolumes(volumes ...string) BuildStapelStageOptionsInterface {
opts.BuildVolumes = append(opts.BuildVolumes, volumes...)
return opts
Expand Down

0 comments on commit c3059ac

Please sign in to comment.