Skip to content

Commit

Permalink
feat: Support legacy 'import' directive and use 'imports' for future
Browse files Browse the repository at this point in the history
This changes the behavior of the 'import' target to behave as it did
before the breaking change that moved imports into /stacker/imports/

So now, if the stacker file uses 'import', then imports will
be placed in /stacker.  If the stacker file uses 'imports' (plural)
then they will be placed in /stacker/imports.

What we actually get in both cases is all the binds being done into
either /.stacker (legacy) or /stacker (new).  In the legacy case, the
imports are also bind-mounted into /stacker

Legacy (for those that used 'import:')
    stacker: /.stacker/bin/stacker
    imports: /.stacker/imports -> /stacker
    runscript: /.stacker/imports/.stacker-run.sh
    artifacts: /.stacker/artifacts

new (for those that use 'imports:')
    stacker: /stacker/bin/stacker
    imports: /stacker/imports
    runscript: /stacker/imports/.stacker-run.sh
    artifacts: /stacker/artifacts

TODO:
 * update tests
 * update docs
 * ideally get runscript into /stacker/bin
  • Loading branch information
smoser committed Nov 11, 2023
1 parent dcc1eca commit de6ea75
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 68 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ STACKER_OPTS=--oci-dir=$(BUILD_D)/oci --roots-dir=$(BUILD_D)/roots --stacker-dir
build_stacker = go build -tags "$(BUILD_TAGS) $1" -ldflags "-X main.version=$(VERSION_FULL) -X main.lxc_version=$(LXC_VERSION) $2" -o $3 ./cmd/stacker

# See doc/hacking.md for how to use a local oci or docker repository.
STACKER_DOCKER_BASE?=docker://
STACKER_DOCKER_BASE ?= oci:$(CLONE_D):
# They default to their image name in STACKER_DOCKER_BASE
STACKER_BUILD_BASE_IMAGE?=$(STACKER_DOCKER_BASE)alpine:edge
STACKER_BUILD_CENTOS_IMAGE?=$(STACKER_DOCKER_BASE)centos:latest
Expand All @@ -44,7 +44,7 @@ STAGE1_STACKER ?= ./stacker-dynamic

STACKER_DEPS = $(GO_SRC) go.mod go.sum

stacker: $(STAGE1_STACKER) $(STACKER_DEPS) cmd/stacker/lxc-wrapper/lxc-wrapper.c
stacker: $(STAGE1_STACKER) $(STACKER_DEPS)
$(STAGE1_STACKER) --debug $(STACKER_OPTS) build \
-f build.yaml \
--substitute BUILD_D=$(BUILD_D) \
Expand Down
15 changes: 9 additions & 6 deletions cmd/stacker/bom.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"stackerbuild.io/stacker-bom/pkg/bom"
"stackerbuild.io/stacker-bom/pkg/distro"
"stackerbuild.io/stacker-bom/pkg/fs"
"stackerbuild.io/stacker/pkg/types"
)

var bomCmd = cli.Command{
Expand Down Expand Up @@ -39,7 +40,7 @@ func doBomDiscover(ctx *cli.Context) error {
author := "stacker-internal"
org := "stacker-internal"

if err := fs.Discover(author, org, "/stacker/artifacts/installed-packages.json"); err != nil {
if err := fs.Discover(author, org, types.InternalStackerDir+"/artifacts/installed-packages.json"); err != nil {
return nil
}

Expand All @@ -57,7 +58,8 @@ func doBomGenerate(ctx *cli.Context) error {
org := "stacker-internal"
lic := "unknown"

if err := distro.ParsePackage(input, author, org, lic, fmt.Sprintf("/stacker/artifacts/%s.json", filepath.Base(input))); err != nil {
if err := distro.ParsePackage(input, author, org, lic, fmt.Sprintf("%s/artifacts/%s.json",
types.InternalStackerDir, filepath.Base(input))); err != nil {
return nil
}

Expand Down Expand Up @@ -98,16 +100,17 @@ func doBomVerify(ctx *cli.Context) error {
org := ctx.Args().Get(3)

// first merge all individual sbom artifacts that may have been generated
if err := bom.MergeDocuments("/stacker/artifacts", name, author, org, dest); err != nil {
iDir := types.InternalStackerDir
if err := bom.MergeDocuments(iDir+"/artifacts", name, author, org, dest); err != nil {
return err
}

// check against inventory
if err := fs.GenerateInventory("/",
[]string{"/proc", "/sys", "/dev", "/etc/resolv.conf", "/stacker"},
"/stacker/artifacts/inventory.json"); err != nil {
[]string{"/proc", "/sys", "/dev", "/etc/resolv.conf", iDir},
iDir+"/artifacts/inventory.json"); err != nil {
return err
}

return fs.Verify(dest, "/stacker/artifacts/inventory.json", "")
return fs.Verify(dest, iDir+"/artifacts/inventory.json", "")
}
4 changes: 2 additions & 2 deletions cmd/stacker/chroot.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ func doChroot(ctx *cli.Context) error {
}
defer c.Close()

err = stacker.SetupBuildContainerConfig(config, s, c, name)
err = stacker.SetupBuildContainerConfig(config, s, c, types.InternalStackerDir, name)
if err != nil {
return err
}
err = stacker.SetupLayerConfig(config, c, layer, name)
err = stacker.SetupLayerConfig(config, c, layer, types.InternalStackerDir, name)
if err != nil {
return err
}
Expand Down
19 changes: 11 additions & 8 deletions pkg/stacker/bom.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io"
"os"
"path"
"path/filepath"

"stackerbuild.io/stacker/pkg/container"
"stackerbuild.io/stacker/pkg/log"
Expand All @@ -27,24 +28,25 @@ func BuildLayerArtifacts(sc types.StackerConfig, storage types.Storage, l types.
}
defer c.Close()

err = SetupBuildContainerConfig(sc, storage, c, tag)
inDir := types.InternalStackerDir
err = SetupBuildContainerConfig(sc, storage, c, inDir, tag)
if err != nil {
log.Errorf("build container %v", err)
return err
}

err = SetupLayerConfig(sc, c, l, tag)
err = SetupLayerConfig(sc, c, l, inDir, tag)
if err != nil {
return err
}

cmd := []string{insideStaticStacker}
cmd := []string{filepath.Join(inDir, types.BinStacker)}

if sc.Debug {
cmd = append(cmd, "--debug")
}

cmd = append(cmd, "bom", "build", "/stacker/artifacts",
cmd = append(cmd, "bom", "build", filepath.Join(inDir, "artifacts"),
l.Annotations[types.AuthorAnnotation],
l.Annotations[types.OrgAnnotation],
l.Annotations[types.LicenseAnnotation],
Expand All @@ -71,25 +73,26 @@ func VerifyLayerArtifacts(sc types.StackerConfig, storage types.Storage, l types
}
defer c.Close()

err = SetupBuildContainerConfig(sc, storage, c, tag)
inDir := types.InternalStackerDir
err = SetupBuildContainerConfig(sc, storage, c, inDir, tag)
if err != nil {
log.Errorf("build container %v", err)
return err
}

err = SetupLayerConfig(sc, c, l, tag)
err = SetupLayerConfig(sc, c, l, inDir, tag)
if err != nil {
return err
}

cmd := []string{insideStaticStacker}
cmd := []string{filepath.Join(inDir, types.BinStacker)}

if sc.Debug {
cmd = append(cmd, "--debug")
}

cmd = append(cmd, "bom", "verify",
fmt.Sprintf("/stacker/artifacts/%s.json", tag),
fmt.Sprintf(types.InternalStackerDir+"/artifacts/%s.json", tag),
tag, l.Annotations[types.AuthorAnnotation], l.Annotations[types.OrgAnnotation])

err = c.Execute(cmd, os.Stdin)
Expand Down
64 changes: 42 additions & 22 deletions pkg/stacker/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os/exec"
"os/user"
"path"
"path/filepath"
"strings"
"time"

Expand All @@ -22,8 +23,7 @@ import (
)

const (
DefaultShell = "/bin/sh"
insideStaticStacker = "/stacker/tools/static-stacker"
DefaultShell = "/bin/sh"
)

type BuildArgs struct {
Expand Down Expand Up @@ -114,6 +114,11 @@ func (b *Builder) updateOCIConfigForOutput(sf *types.Stackerfile, s types.Storag
imageConfig.Labels = map[string]string{}
}

inDir := types.InternalStackerDir
if l.WasLegacyImport {
inDir = types.LegacyInternalStackerDir
}

if len(l.GenerateLabels) > 0 {
writable, cleanup, err := s.TemporaryWritableSnapshot(name)
if err != nil {
Expand All @@ -133,24 +138,26 @@ func (b *Builder) updateOCIConfigForOutput(sf *types.Stackerfile, s types.Storag
}
defer c.Close()

err = SetupBuildContainerConfig(opts.Config, s, c, writable)
err = SetupBuildContainerConfig(opts.Config, s, c, inDir, writable)
if err != nil {
return err
}

err = c.BindMount(dir, "/stacker/oci-labels", "")
// /stacker/oci-labels
labelInDir := filepath.Join(inDir, "oci-labels")
const script = ".stacker-run.sh"
err = c.BindMount(dir, labelInDir, "")
if err != nil {
return err
}

rootfs := path.Join(opts.Config.RootFSDir, writable, "rootfs")
runPath := path.Join(dir, ".stacker-run.sh")
err = generateShellForRunning(rootfs, l.GenerateLabels, runPath)
rootfs := filepath.Join(opts.Config.RootFSDir, writable, "rootfs")
err = generateShellForRunning(rootfs, l.GenerateLabels, filepath.Join(dir, script))
if err != nil {
return err
}

err = c.Execute([]string{"/stacker/oci-labels/.stacker-run.sh"}, nil)
err = c.Execute([]string{filepath.Join(labelInDir, script)}, nil)
if err != nil {
return err
}
Expand All @@ -165,7 +172,7 @@ func (b *Builder) updateOCIConfigForOutput(sf *types.Stackerfile, s types.Storag
continue
}

content, err := os.ReadFile(path.Join(dir, ent.Name()))
content, err := os.ReadFile(filepath.Join(dir, ent.Name()))
if err != nil {
return errors.Wrapf(err, "couldn't read label %s", ent.Name())
}
Expand Down Expand Up @@ -361,6 +368,10 @@ func (b *Builder) build(s types.Storage, file string) error {
}

log.Infof("preparing image %s...", name)
inDir := types.InternalStackerDir
if l.WasLegacyImport {
inDir = types.LegacyInternalStackerDir
}

// We need to run the imports first since we now compare
// against imports for caching layers. Since we don't do
Expand Down Expand Up @@ -450,18 +461,18 @@ func (b *Builder) build(s types.Storage, file string) error {
}
defer c.Close()

err = SetupBuildContainerConfig(opts.Config, s, c, name)
err = SetupBuildContainerConfig(opts.Config, s, c, inDir, name)
if err != nil {
return err
}

err = SetupLayerConfig(opts.Config, c, l, name)
err = SetupLayerConfig(opts.Config, c, l, inDir, name)
if err != nil {
return err
}

if opts.SetupOnly {
err = c.SaveConfigFile(path.Join(opts.Config.RootFSDir, name, "lxc.conf"))
err = c.SaveConfigFile(filepath.Join(opts.Config.RootFSDir, name, "lxc.conf"))
if err != nil {
return errors.Wrapf(err, "error saving config file for %s", name)
}
Expand All @@ -471,15 +482,15 @@ func (b *Builder) build(s types.Storage, file string) error {
}

if len(l.Run) != 0 {
rootfs := path.Join(opts.Config.RootFSDir, name, "rootfs")
shellScript := path.Join(opts.Config.StackerDir, "imports", name, ".stacker-run.sh")
rootfs := filepath.Join(opts.Config.RootFSDir, name, "rootfs")
shellScript := filepath.Join(opts.Config.StackerDir, "imports", name, ".stacker-run.sh")
err = generateShellForRunning(rootfs, l.Run, shellScript)
if err != nil {
return err
}

// These should all be non-interactive; let's ensure that.
err = c.Execute([]string{"/stacker/imports/.stacker-run.sh"}, nil)
err = c.Execute([]string{filepath.Join(inDir, "imports", ".stacker-run.sh")}, nil)
if err != nil {
if opts.OnRunFailure != "" {
err2 := c.Execute([]string{opts.OnRunFailure}, os.Stdin)
Expand Down Expand Up @@ -654,7 +665,7 @@ func runInternalGoSubcommand(config types.StackerConfig, args []string) error {
return errors.WithStack(c.Run())
}

func SetupBuildContainerConfig(config types.StackerConfig, storage types.Storage, c *container.Container, name string) error {
func SetupBuildContainerConfig(config types.StackerConfig, storage types.Storage, c *container.Container, inDir string, name string) error {
rootfsPivot := path.Join(config.StackerDir, "rootfsPivot")
if err := os.MkdirAll(rootfsPivot, 0755); err != nil {
return err
Expand Down Expand Up @@ -695,7 +706,7 @@ func SetupBuildContainerConfig(config types.StackerConfig, storage types.Storage
}

// make stacker binary available inside container
if err := c.BindMount(binary, insideStaticStacker, ""); err != nil {
if err := c.BindMount(binary, filepath.Join(inDir, "bin/stacker"), ""); err != nil {
return err
}

Expand Down Expand Up @@ -732,19 +743,27 @@ func SetupBuildContainerConfig(config types.StackerConfig, storage types.Storage
return nil
}

func SetupLayerConfig(config types.StackerConfig, c *container.Container, l types.Layer, name string) error {
func SetupLayerConfig(config types.StackerConfig, c *container.Container, l types.Layer, inDir, name string) error {
env, err := l.BuildEnvironment(name)
if err != nil {
return err
}

importsDir := path.Join(config.StackerDir, "imports", name)
if _, err := os.Stat(importsDir); err == nil {
log.Debugf("bind mounting %s into container", importsDir)
err = c.BindMount(importsDir, "/stacker/imports", "ro")
d := filepath.Join(inDir, "imports")
log.Debugf("bind mounting %s into container at %s", importsDir, d)
err = c.BindMount(importsDir, d, "ro")
if err != nil {
return err
}
// legacy expect imports in /stacker
if inDir == types.LegacyInternalStackerDir {
err = c.BindMount(importsDir, types.InternalStackerDir, "ro")
if err != nil {
return err
}
}
} else {
log.Debugf("not bind mounting %s into container", importsDir)
}
Expand All @@ -753,8 +772,9 @@ func SetupLayerConfig(config types.StackerConfig, c *container.Container, l type
if l.Bom != nil {
artifactsDir := path.Join(config.StackerDir, "artifacts", name)
if _, err := os.Stat(artifactsDir); err == nil {
log.Debugf("bind mounting %s into container", artifactsDir)
err = c.BindMount(artifactsDir, "/stacker/artifacts", "rw")
d := filepath.Join(inDir, "artifacts")
log.Debugf("bind mounting %s dir into container at %s", artifactsDir, d)
err = c.BindMount(artifactsDir, d, "rw")
if err != nil {
return err
}
Expand Down
16 changes: 9 additions & 7 deletions pkg/stacker/grab.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/fs"
"os"
"path"
"path/filepath"

"stackerbuild.io/stacker/pkg/container"
"stackerbuild.io/stacker/pkg/types"
Expand All @@ -19,30 +20,31 @@ func Grab(sc types.StackerConfig, storage types.Storage, name string, source str
}
defer c.Close()

err = c.BindMount(targetDir, "/stacker", "")
err = c.BindMount(targetDir, types.InternalStackerDir, "")
if err != nil {
return err
}
defer os.Remove(path.Join(sc.RootFSDir, name, "rootfs", "stacker"))

err = SetupBuildContainerConfig(sc, storage, c, name)
err = SetupBuildContainerConfig(sc, storage, c, types.InternalStackerDir, name)
if err != nil {
return err
}

bcmd := []string{insideStaticStacker, "internal-go"}
bcmd := []string{filepath.Join(types.InternalStackerDir, types.BinStacker), "internal-go"}

iDestName := filepath.Join(types.InternalStackerDir, path.Base(source))
if idest == "" || source[len(source)-1:] != "/" {
err = c.Execute(append(bcmd, "cp", source, "/stacker/"+path.Base(source)), nil)
err = c.Execute(append(bcmd, "cp", source, iDestName), nil)
} else {
err = c.Execute(append(bcmd, "cp", source, "/stacker/"), nil)
err = c.Execute(append(bcmd, "cp", source, types.InternalStackerDir+"/"), nil)
}
if err != nil {
return err
}

if mode != nil {
err = c.Execute(append(bcmd, "chmod", fmt.Sprintf("%o", *mode), "/stacker/"+path.Base(source)), nil)
err = c.Execute(append(bcmd, "chmod", fmt.Sprintf("%o", *mode), iDestName), nil)
if err != nil {
return err
}
Expand All @@ -54,7 +56,7 @@ func Grab(sc types.StackerConfig, storage types.Storage, name string, source str
owns += fmt.Sprintf(":%d", gid)
}

err = c.Execute(append(bcmd, "chown", owns, "/stacker/"+path.Base(source)), nil)
err = c.Execute(append(bcmd, "chown", owns, iDestName), nil)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit de6ea75

Please sign in to comment.