[lxc-devel] [distrobuilder/master] VM preparations

monstermunchkin on Github lxc-bot at linuxcontainers.org
Fri Feb 14 11:03:57 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 365 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200214/9a5db6b2/attachment.bin>
-------------- next part --------------
From 65112ce0b9a49cb33fbec289e38135ff9577be25 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 12 Feb 2020 17:29:44 +0100
Subject: [PATCH 1/7] shared/definition: Add LXD target

Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
 shared/definition.go | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/shared/definition.go b/shared/definition.go
index 7b586d5..62262a7 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -129,9 +129,21 @@ type DefinitionTargetLXC struct {
 	Config        []DefinitionTargetLXCConfig `yaml:"config,omitempty"`
 }
 
+// DefinitionTargetLXDVM represents LXD VM specific options.
+type DefinitionTargetLXDVM struct {
+	Size       uint   `yaml:"size,omitempty"`
+	Filesystem string `yaml:"filesystem,omitempty"`
+}
+
+// DefinitionTargetLXD represents LXD specific options.
+type DefinitionTargetLXD struct {
+	VM DefinitionTargetLXDVM `yaml:"vm,omitempty"`
+}
+
 // A DefinitionTarget specifies target dependent files.
 type DefinitionTarget struct {
 	LXC DefinitionTargetLXC `yaml:"lxc,omitempty"`
+	LXD DefinitionTargetLXD `yaml:"lxd,omitempty"`
 }
 
 // A DefinitionFile represents a file which is to be created inside to chroot.

From 39d263ae2a10b14070485c9dd6fdd66ab0282779 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 12 Feb 2020 17:32:20 +0100
Subject: [PATCH 2/7] shared/definition: Add VM field to target

This add a VM field to target which is for internal use only. It makes
it simpler to deal with VMs as it removes the necessity of passing the
value of the --vm flag.

Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
 shared/definition.go | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/shared/definition.go b/shared/definition.go
index 62262a7..ff0c30d 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -142,8 +142,9 @@ type DefinitionTargetLXD struct {
 
 // A DefinitionTarget specifies target dependent files.
 type DefinitionTarget struct {
-	LXC DefinitionTargetLXC `yaml:"lxc,omitempty"`
-	LXD DefinitionTargetLXD `yaml:"lxd,omitempty"`
+	LXC  DefinitionTargetLXC `yaml:"lxc,omitempty"`
+	LXD  DefinitionTargetLXD `yaml:"lxd,omitempty"`
+	Type string              // This field is internal only and used only for simplicity.
 }
 
 // A DefinitionFile represents a file which is to be created inside to chroot.
@@ -278,6 +279,9 @@ func (d *Definition) SetDefaults() {
 	if d.Image.Description == "" {
 		d.Image.Description = "{{ image.distribution|capfirst }} {{ image.release }} {{ image.architecture_mapped }}{% if image.variant != \"default\" %} ({{ image.variant }}){% endif %} ({{ image.serial }})"
 	}
+
+	// Set default target type. This will only be overriden if building VMs for LXD.
+	d.Targets.Type = "container"
 }
 
 // Validate validates the Definition.

From e41a1a15767bead9333b30c78f2f8188892bf927 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 12 Feb 2020 17:34:08 +0100
Subject: [PATCH 3/7] shared/definition: Add GetTypes to filter

This adds a new `types` filter which is used for differentiating between
containers and VMs.

Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
 shared/definition.go | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/shared/definition.go b/shared/definition.go
index ff0c30d..23a4006 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -17,6 +17,7 @@ type Filter interface {
 	GetReleases() []string
 	GetArchitectures() []string
 	GetVariants() []string
+	GetTypes() []string
 }
 
 // A DefinitionFilter defines filters for various actions.
@@ -24,6 +25,7 @@ type DefinitionFilter struct {
 	Releases      []string `yaml:"releases,omitempty"`
 	Architectures []string `yaml:"architectures,omitempty"`
 	Variants      []string `yaml:"variants,omitempty"`
+	Types         []string `yaml:"types,omitempty"`
 }
 
 // GetReleases returns a list of releases.
@@ -41,6 +43,11 @@ func (d *DefinitionFilter) GetVariants() []string {
 	return d.Variants
 }
 
+// GetTypes returns a list of types.
+func (d *DefinitionFilter) GetTypes() []string {
+	return d.Types
+}
+
 // A DefinitionPackagesSet is a set of packages which are to be installed
 // or removed.
 type DefinitionPackagesSet struct {

From 907bf785d2a15b1094c7e9a145971de65924d7ae Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Tue, 29 Oct 2019 13:38:12 +0100
Subject: [PATCH 4/7] shared: Export ChrootMount struct

This exports the ChrootMount struct.

Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
 shared/chroot.go | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/shared/chroot.go b/shared/chroot.go
index eefdeab..a6ad591 100644
--- a/shared/chroot.go
+++ b/shared/chroot.go
@@ -12,19 +12,20 @@ import (
 	lxd "github.com/lxc/lxd/shared"
 )
 
-type chrootMount struct {
-	source string
-	target string
-	fstype string
-	flags  uintptr
-	data   string
-	isDir  bool
+// ChrootMount defines mount args.
+type ChrootMount struct {
+	Source string
+	Target string
+	FSType string
+	Flags  uintptr
+	Data   string
+	IsDir  bool
 }
 
 // ActiveChroots is a map of all active chroots and their exit functions
 var ActiveChroots = make(map[string]func() error)
 
-func setupMounts(rootfs string, mounts []chrootMount) error {
+func setupMounts(rootfs string, mounts []ChrootMount) error {
 	// Create a temporary mount path
 	err := os.MkdirAll(filepath.Join(rootfs, ".distrobuilder"), 0700)
 	if err != nil {
@@ -36,7 +37,7 @@ func setupMounts(rootfs string, mounts []chrootMount) error {
 		tmpTarget := filepath.Join(rootfs, ".distrobuilder", fmt.Sprintf("%d", i))
 
 		// Create the target mountpoint
-		if mount.isDir {
+		if mount.IsDir {
 			err := os.MkdirAll(tmpTarget, 0755)
 			if err != nil {
 				return err
@@ -49,22 +50,22 @@ func setupMounts(rootfs string, mounts []chrootMount) error {
 		}
 
 		// Mount to the temporary path
-		err := syscall.Mount(mount.source, tmpTarget, mount.fstype, mount.flags, mount.data)
+		err := syscall.Mount(mount.Source, tmpTarget, mount.FSType, mount.Flags, mount.Data)
 		if err != nil {
-			return fmt.Errorf("Failed to mount '%s': %s", mount.source, err)
+			return fmt.Errorf("Failed to mount '%s': %s", mount.Source, err)
 		}
 	}
 
 	return nil
 }
 
-func moveMounts(mounts []chrootMount) error {
+func moveMounts(mounts []ChrootMount) error {
 	for i, mount := range mounts {
 		// Source path
 		tmpSource := filepath.Join("/", ".distrobuilder", fmt.Sprintf("%d", i))
 
 		// Resolve symlinks
-		target := mount.target
+		target := mount.Target
 		for {
 			// Get information on current target
 			fi, err := os.Lstat(target)
@@ -93,7 +94,7 @@ func moveMounts(mounts []chrootMount) error {
 		}
 
 		// Create target path
-		if mount.isDir {
+		if mount.IsDir {
 			err = os.MkdirAll(target, 0755)
 			if err != nil {
 				return err
@@ -108,7 +109,7 @@ func moveMounts(mounts []chrootMount) error {
 		// Move the mount to its destination
 		err = syscall.Mount(tmpSource, target, "", syscall.MS_MOVE, "")
 		if err != nil {
-			return fmt.Errorf("Failed to mount '%s': %s", mount.source, err)
+			return fmt.Errorf("Failed to mount '%s': %s", mount.Source, err)
 		}
 	}
 
@@ -159,7 +160,7 @@ func SetupChroot(rootfs string, envs DefinitionEnv) (func() error, error) {
 	}
 
 	// Setup all other needed mounts
-	mounts := []chrootMount{
+	mounts := []ChrootMount{
 		{"none", "/proc", "proc", 0, "", true},
 		{"none", "/sys", "sysfs", 0, "", true},
 		{"/dev", "/dev", "", syscall.MS_BIND, "", true},

From 2e5d184154a038f6d7ed252cac21b91a7de2f505 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Tue, 29 Oct 2019 15:07:57 +0100
Subject: [PATCH 5/7] *: Pass custom mounts to SetupChroot()

This allows additional mounts to be passed to SetupChroot()

Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
 distrobuilder/main.go       |  2 +-
 distrobuilder/main_lxc.go   |  2 +-
 distrobuilder/main_lxd.go   |  2 +-
 shared/chroot.go            | 10 +++++++---
 sources/alpine-http.go      |  2 +-
 sources/centos-http.go      |  4 ++--
 sources/oraclelinux-http.go |  2 +-
 sources/ubuntu-http.go      |  2 +-
 8 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/distrobuilder/main.go b/distrobuilder/main.go
index 043d656..e820357 100644
--- a/distrobuilder/main.go
+++ b/distrobuilder/main.go
@@ -251,7 +251,7 @@ func (c *cmdGlobal) preRunBuild(cmd *cobra.Command, args []string) error {
 	}
 
 	// Setup the mounts and chroot into the rootfs
-	exitChroot, err := shared.SetupChroot(c.sourceDir, c.definition.Environment)
+	exitChroot, err := shared.SetupChroot(c.sourceDir, c.definition.Environment, nil)
 	if err != nil {
 		return fmt.Errorf("Failed to setup chroot: %s", err)
 	}
diff --git a/distrobuilder/main_lxc.go b/distrobuilder/main_lxc.go
index 0b8fb77..9ce050e 100644
--- a/distrobuilder/main_lxc.go
+++ b/distrobuilder/main_lxc.go
@@ -60,7 +60,7 @@ func (c *cmdLXC) run(cmd *cobra.Command, args []string) error {
 	}
 
 	exitChroot, err := shared.SetupChroot(c.global.sourceDir,
-		c.global.definition.Environment)
+		c.global.definition.Environment, nil)
 	if err != nil {
 		return err
 	}
diff --git a/distrobuilder/main_lxd.go b/distrobuilder/main_lxd.go
index 9aea6dc..73596bb 100644
--- a/distrobuilder/main_lxd.go
+++ b/distrobuilder/main_lxd.go
@@ -85,7 +85,7 @@ func (c *cmdLXD) run(cmd *cobra.Command, args []string) error {
 	}
 
 	exitChroot, err := shared.SetupChroot(c.global.sourceDir,
-		c.global.definition.Environment)
+		c.global.definition.Environment, nil)
 	if err != nil {
 		return err
 	}
diff --git a/shared/chroot.go b/shared/chroot.go
index a6ad591..1c652b3 100644
--- a/shared/chroot.go
+++ b/shared/chroot.go
@@ -152,7 +152,7 @@ func killChrootProcesses(rootfs string) error {
 }
 
 // SetupChroot sets up mount and files, a reverter and then chroots for you
-func SetupChroot(rootfs string, envs DefinitionEnv) (func() error, error) {
+func SetupChroot(rootfs string, envs DefinitionEnv, m []ChrootMount) (func() error, error) {
 	// Mount the rootfs
 	err := syscall.Mount(rootfs, rootfs, "", syscall.MS_BIND, "")
 	if err != nil {
@@ -181,7 +181,11 @@ func SetupChroot(rootfs string, envs DefinitionEnv) (func() error, error) {
 	}
 
 	// Setup all needed mounts in a temporary location
-	err = setupMounts(rootfs, mounts)
+	if m != nil && len(m) > 0 {
+		err = setupMounts(rootfs, append(mounts, m...))
+	} else {
+		err = setupMounts(rootfs, mounts)
+	}
 	if err != nil {
 		return nil, fmt.Errorf("Failed to mount filesystems: %v", err)
 	}
@@ -199,7 +203,7 @@ func SetupChroot(rootfs string, envs DefinitionEnv) (func() error, error) {
 	}
 
 	// Move all the mounts into place
-	err = moveMounts(mounts)
+	err = moveMounts(append(mounts, m...))
 	if err != nil {
 		return nil, err
 	}
diff --git a/sources/alpine-http.go b/sources/alpine-http.go
index ecb95a6..4edd5d7 100644
--- a/sources/alpine-http.go
+++ b/sources/alpine-http.go
@@ -98,7 +98,7 @@ func (s *AlpineLinuxHTTP) Run(definition shared.Definition, rootfsDir string) er
 	// Handle edge builds
 	if definition.Image.Release == "edge" {
 		// Upgrade to edge
-		exitChroot, err := shared.SetupChroot(rootfsDir, definition.Environment)
+		exitChroot, err := shared.SetupChroot(rootfsDir, definition.Environment, nil)
 		if err != nil {
 			return err
 		}
diff --git a/sources/centos-http.go b/sources/centos-http.go
index d23bf1c..9888217 100644
--- a/sources/centos-http.go
+++ b/sources/centos-http.go
@@ -169,7 +169,7 @@ func (s CentOSHTTP) unpackRaw(filePath, rootfsDir string) error {
 	}
 
 	// Setup the mounts and chroot into the rootfs
-	exitChroot, err := shared.SetupChroot(tempRootDir, shared.DefinitionEnv{})
+	exitChroot, err := shared.SetupChroot(tempRootDir, shared.DefinitionEnv{}, nil)
 	if err != nil {
 		return fmt.Errorf("Failed to setup chroot: %s", err)
 	}
@@ -296,7 +296,7 @@ func (s CentOSHTTP) unpackISO(filePath, rootfsDir string) error {
 	}
 
 	// Setup the mounts and chroot into the rootfs
-	exitChroot, err := shared.SetupChroot(tempRootDir, shared.DefinitionEnv{})
+	exitChroot, err := shared.SetupChroot(tempRootDir, shared.DefinitionEnv{}, nil)
 	if err != nil {
 		return fmt.Errorf("Failed to setup chroot: %s", err)
 	}
diff --git a/sources/oraclelinux-http.go b/sources/oraclelinux-http.go
index 4906455..6d21904 100644
--- a/sources/oraclelinux-http.go
+++ b/sources/oraclelinux-http.go
@@ -169,7 +169,7 @@ func (s *OracleLinuxHTTP) unpackISO(latestUpdate, filePath, rootfsDir string) er
 	}
 
 	// Setup the mounts and chroot into the rootfs
-	exitChroot, err := shared.SetupChroot(tempRootDir, shared.DefinitionEnv{})
+	exitChroot, err := shared.SetupChroot(tempRootDir, shared.DefinitionEnv{}, nil)
 	if err != nil {
 		return fmt.Errorf("Failed to setup chroot: %s", err)
 	}
diff --git a/sources/ubuntu-http.go b/sources/ubuntu-http.go
index b82042a..c7ca68c 100644
--- a/sources/ubuntu-http.go
+++ b/sources/ubuntu-http.go
@@ -150,7 +150,7 @@ func (s *UbuntuHTTP) runCoreVariant(definition shared.Definition, rootfsDir stri
 		return err
 	}
 
-	exitChroot, err := shared.SetupChroot(baseImageDir, shared.DefinitionEnv{})
+	exitChroot, err := shared.SetupChroot(baseImageDir, shared.DefinitionEnv{}, nil)
 	if err != nil {
 		return err
 	}

From 7528172e2c76791abae1dfd958ce3b99b3b2e4df Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Wed, 12 Feb 2020 17:37:30 +0100
Subject: [PATCH 6/7] *: Support VM filtering

Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
 distrobuilder/chroot.go         | 10 +++++-----
 distrobuilder/main.go           |  8 ++++----
 distrobuilder/main_build-dir.go |  2 +-
 distrobuilder/main_lxc.go       |  4 ++--
 distrobuilder/main_lxd.go       |  4 ++--
 shared/definition.go            | 22 ++++++++++++++++++----
 shared/definition_test.go       | 26 ++++++++++++++++++++++++--
 7 files changed, 56 insertions(+), 20 deletions(-)

diff --git a/distrobuilder/chroot.go b/distrobuilder/chroot.go
index 0602469..a723d54 100644
--- a/distrobuilder/chroot.go
+++ b/distrobuilder/chroot.go
@@ -8,7 +8,7 @@ import (
 	"github.com/lxc/distrobuilder/shared"
 )
 
-func manageRepositories(def *shared.Definition, manager *managers.Manager) error {
+func manageRepositories(def *shared.Definition, manager *managers.Manager, vmOnly bool) error {
 	var err error
 
 	if def.Packages.Repositories == nil || len(def.Packages.Repositories) == 0 {
@@ -21,7 +21,7 @@ func manageRepositories(def *shared.Definition, manager *managers.Manager) error
 	}
 
 	for _, repo := range def.Packages.Repositories {
-		if !shared.ApplyFilter(&repo, def.Image.Release, def.Image.ArchitectureMapped, def.Image.Variant) {
+		if !shared.ApplyFilter(&repo, def.Image.Release, def.Image.ArchitectureMapped, def.Image.Variant, def.Targets.Type, vmOnly) {
 			continue
 		}
 
@@ -46,7 +46,7 @@ func manageRepositories(def *shared.Definition, manager *managers.Manager) error
 	return nil
 }
 
-func managePackages(def *shared.Definition, manager *managers.Manager) error {
+func managePackages(def *shared.Definition, manager *managers.Manager, vmOnly bool) error {
 	var err error
 
 	err = manager.Refresh()
@@ -61,7 +61,7 @@ func managePackages(def *shared.Definition, manager *managers.Manager) error {
 		}
 
 		// Run post update hook
-		for _, action := range def.GetRunnableActions("post-update") {
+		for _, action := range def.GetRunnableActions("post-update", vmOnly) {
 			err = shared.RunScript(action.Action)
 			if err != nil {
 				return fmt.Errorf("Failed to run post-update: %s", err)
@@ -72,7 +72,7 @@ func managePackages(def *shared.Definition, manager *managers.Manager) error {
 	var validSets []shared.DefinitionPackagesSet
 
 	for _, set := range def.Packages.Sets {
-		if !shared.ApplyFilter(&set, def.Image.Release, def.Image.ArchitectureMapped, def.Image.Variant) {
+		if !shared.ApplyFilter(&set, def.Image.Release, def.Image.ArchitectureMapped, def.Image.Variant, def.Targets.Type, vmOnly) {
 			continue
 		}
 
diff --git a/distrobuilder/main.go b/distrobuilder/main.go
index e820357..a963e1e 100644
--- a/distrobuilder/main.go
+++ b/distrobuilder/main.go
@@ -269,13 +269,13 @@ func (c *cmdGlobal) preRunBuild(cmd *cobra.Command, args []string) error {
 		manager = managers.GetCustom(*c.definition.Packages.CustomManager)
 	}
 
-	err = manageRepositories(c.definition, manager)
+	err = manageRepositories(c.definition, manager, false)
 	if err != nil {
 		return fmt.Errorf("Failed to manage repositories: %s", err)
 	}
 
 	// Run post unpack hook
-	for _, hook := range c.definition.GetRunnableActions("post-unpack") {
+	for _, hook := range c.definition.GetRunnableActions("post-unpack", false) {
 		err := shared.RunScript(hook.Action)
 		if err != nil {
 			return fmt.Errorf("Failed to run post-unpack: %s", err)
@@ -283,13 +283,13 @@ func (c *cmdGlobal) preRunBuild(cmd *cobra.Command, args []string) error {
 	}
 
 	// Install/remove/update packages
-	err = managePackages(c.definition, manager)
+	err = managePackages(c.definition, manager, false)
 	if err != nil {
 		return fmt.Errorf("Failed to manage packages: %s", err)
 	}
 
 	// Run post packages hook
-	for _, hook := range c.definition.GetRunnableActions("post-packages") {
+	for _, hook := range c.definition.GetRunnableActions("post-packages", false) {
 		err := shared.RunScript(hook.Action)
 		if err != nil {
 			return fmt.Errorf("Failed to run post-packages: %s", err)
diff --git a/distrobuilder/main_build-dir.go b/distrobuilder/main_build-dir.go
index 3f8a3a0..e7ab644 100644
--- a/distrobuilder/main_build-dir.go
+++ b/distrobuilder/main_build-dir.go
@@ -28,7 +28,7 @@ func (c *cmdBuildDir) command() *cobra.Command {
 					return fmt.Errorf("Unknown generator '%s'", file.Generator)
 				}
 
-				if !shared.ApplyFilter(&file, c.global.definition.Image.Release, c.global.definition.Image.ArchitectureMapped, c.global.definition.Image.Variant) {
+				if !shared.ApplyFilter(&file, c.global.definition.Image.Release, c.global.definition.Image.ArchitectureMapped, c.global.definition.Image.Variant, c.global.definition.Targets.Type, false) {
 					continue
 				}
 
diff --git a/distrobuilder/main_lxc.go b/distrobuilder/main_lxc.go
index 9ce050e..0990d32 100644
--- a/distrobuilder/main_lxc.go
+++ b/distrobuilder/main_lxc.go
@@ -48,7 +48,7 @@ func (c *cmdLXC) run(cmd *cobra.Command, args []string) error {
 			return fmt.Errorf("Unknown generator '%s'", file.Generator)
 		}
 
-		if !shared.ApplyFilter(&file, c.global.definition.Image.Release, c.global.definition.Image.ArchitectureMapped, c.global.definition.Image.Variant) {
+		if !shared.ApplyFilter(&file, c.global.definition.Image.Release, c.global.definition.Image.ArchitectureMapped, c.global.definition.Image.Variant, c.global.definition.Targets.Type, false) {
 			continue
 		}
 
@@ -66,7 +66,7 @@ func (c *cmdLXC) run(cmd *cobra.Command, args []string) error {
 	}
 
 	// Run post files hook
-	for _, action := range c.global.definition.GetRunnableActions("post-files") {
+	for _, action := range c.global.definition.GetRunnableActions("post-files", false) {
 		err := shared.RunScript(action.Action)
 		if err != nil {
 			exitChroot()
diff --git a/distrobuilder/main_lxd.go b/distrobuilder/main_lxd.go
index 73596bb..2d2ec5c 100644
--- a/distrobuilder/main_lxd.go
+++ b/distrobuilder/main_lxd.go
@@ -68,7 +68,7 @@ func (c *cmdLXD) run(cmd *cobra.Command, args []string) error {
 		c.global.flagCacheDir, *c.global.definition)
 
 	for _, file := range c.global.definition.Files {
-		if !shared.ApplyFilter(&file, c.global.definition.Image.Release, c.global.definition.Image.ArchitectureMapped, c.global.definition.Image.Variant) {
+		if !shared.ApplyFilter(&file, c.global.definition.Image.Release, c.global.definition.Image.ArchitectureMapped, c.global.definition.Image.Variant, c.global.definition.Targets.Type, false) {
 			continue
 		}
 
@@ -91,7 +91,7 @@ func (c *cmdLXD) run(cmd *cobra.Command, args []string) error {
 	}
 
 	// Run post files hook
-	for _, action := range c.global.definition.GetRunnableActions("post-files") {
+	for _, action := range c.global.definition.GetRunnableActions("post-files", false) {
 		err := shared.RunScript(action.Action)
 		if err != nil {
 			exitChroot()
diff --git a/shared/definition.go b/shared/definition.go
index 23a4006..d3abca7 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -459,7 +459,7 @@ func (d *Definition) Validate() error {
 
 // GetRunnableActions returns a list of actions depending on the trigger
 // and releases.
-func (d *Definition) GetRunnableActions(trigger string) []DefinitionAction {
+func (d *Definition) GetRunnableActions(trigger string, vmOnly bool) []DefinitionAction {
 	out := []DefinitionAction{}
 
 	for _, action := range d.Actions {
@@ -467,7 +467,7 @@ func (d *Definition) GetRunnableActions(trigger string) []DefinitionAction {
 			continue
 		}
 
-		if !ApplyFilter(&action, d.Image.Release, d.Image.ArchitectureMapped, d.Image.Variant) {
+		if !ApplyFilter(&action, d.Image.Release, d.Image.ArchitectureMapped, d.Image.Variant, d.Targets.Type, vmOnly) {
 			continue
 		}
 
@@ -485,7 +485,7 @@ func (d *Definition) GetEarlyPackages(action string) []string {
 	normal := []DefinitionPackagesSet{}
 
 	for _, set := range d.Packages.Sets {
-		if set.Early && set.Action == action && ApplyFilter(&set, d.Image.Release, d.Image.ArchitectureMapped, d.Image.Variant) {
+		if set.Early && set.Action == action && ApplyFilter(&set, d.Image.Release, d.Image.ArchitectureMapped, d.Image.Variant, d.Targets.Type, false) {
 			early = append(early, set.Packages...)
 		} else {
 			normal = append(normal, set)
@@ -563,7 +563,7 @@ func getFieldByTag(v reflect.Value, t reflect.Type, tag string) (reflect.Value,
 }
 
 // ApplyFilter returns true if the filter matches.
-func ApplyFilter(filter Filter, release string, architecture string, variant string) bool {
+func ApplyFilter(filter Filter, release string, architecture string, variant string, targetType string, vmOnly bool) bool {
 	if len(filter.GetReleases()) > 0 && !shared.StringInSlice(release, filter.GetReleases()) {
 		return false
 	}
@@ -576,5 +576,19 @@ func ApplyFilter(filter Filter, release string, architecture string, variant str
 		return false
 	}
 
+	types := filter.GetTypes()
+
+	if vmOnly {
+		if len(types) == 1 && types[0] == "vm" && targetType == "vm" {
+			return true
+		}
+
+		return false
+	}
+
+	if len(types) > 0 && !shared.StringInSlice(targetType, types) {
+		return false
+	}
+
 	return true
 }
diff --git a/shared/definition_test.go b/shared/definition_test.go
index 6186501..6238620 100644
--- a/shared/definition_test.go
+++ b/shared/definition_test.go
@@ -510,7 +510,29 @@ func TestApplyFilter(t *testing.T) {
 	repo.Variants = []string{"default"}
 	repo.Architectures = []string{"amd64", "i386"}
 	repo.Releases = []string{"foo"}
+	repo.Types = []string{"vm"}
 
-	require.True(t, ApplyFilter(&repo, "foo", "amd64", "default"))
-	require.False(t, ApplyFilter(&repo, "", "arm64", "default"))
+	require.True(t, ApplyFilter(&repo, "foo", "amd64", "default", "vm", true))
+	require.True(t, ApplyFilter(&repo, "foo", "amd64", "default", "vm", false))
+	require.False(t, ApplyFilter(&repo, "foo", "amd64", "default", "container", false))
+	require.False(t, ApplyFilter(&repo, "foo", "amd64", "default", "container", true))
+	require.False(t, ApplyFilter(&repo, "", "arm64", "default", "vm", false))
+
+	repo.Types = []string{"container"}
+	require.False(t, ApplyFilter(&repo, "foo", "amd64", "default", "vm", true))
+	require.False(t, ApplyFilter(&repo, "foo", "amd64", "default", "vm", false))
+	require.True(t, ApplyFilter(&repo, "foo", "amd64", "default", "container", false))
+	require.False(t, ApplyFilter(&repo, "foo", "amd64", "default", "container", true))
+
+	repo.Types = []string{"container", "vm"}
+	require.True(t, ApplyFilter(&repo, "foo", "amd64", "default", "vm", false))
+	require.True(t, ApplyFilter(&repo, "foo", "amd64", "default", "container", false))
+	require.False(t, ApplyFilter(&repo, "foo", "amd64", "default", "container", true))
+	require.False(t, ApplyFilter(&repo, "foo", "amd64", "default", "vm", true))
+
+	repo.Types = []string{}
+	require.True(t, ApplyFilter(&repo, "foo", "amd64", "default", "vm", false))
+	require.True(t, ApplyFilter(&repo, "foo", "amd64", "default", "container", false))
+	require.False(t, ApplyFilter(&repo, "foo", "amd64", "default", "container", true))
+	require.False(t, ApplyFilter(&repo, "foo", "amd64", "default", "vm", true))
 }

From e5d467b3c1333c5ea028ece42e8adece2e8d0c5c Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Fri, 14 Feb 2020 11:54:41 +0100
Subject: [PATCH 7/7] distrobuilder: Use overlayfs

Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
 distrobuilder/chroot.go   | 57 +++++++++++++++++++++++++++++++++++++++
 distrobuilder/main_lxc.go | 15 ++++++++---
 distrobuilder/main_lxd.go | 14 +++++++---
 3 files changed, 78 insertions(+), 8 deletions(-)

diff --git a/distrobuilder/chroot.go b/distrobuilder/chroot.go
index a723d54..1e37dba 100644
--- a/distrobuilder/chroot.go
+++ b/distrobuilder/chroot.go
@@ -2,8 +2,13 @@ package main
 
 import (
 	"fmt"
+	"os"
+	"path/filepath"
 	"strings"
 
+	"github.com/pkg/errors"
+	"golang.org/x/sys/unix"
+
 	"github.com/lxc/distrobuilder/managers"
 	"github.com/lxc/distrobuilder/shared"
 )
@@ -138,3 +143,55 @@ func optimizePackageSets(sets []shared.DefinitionPackagesSet) []shared.Definitio
 
 	return newSets
 }
+
+func getOverlay(cacheDir, sourceDir string) (func(), string, error) {
+	upperDir := filepath.Join(cacheDir, "upper")
+	overlayDir := filepath.Join(cacheDir, "overlay")
+	workDir := filepath.Join(cacheDir, "work")
+
+	err := os.Mkdir(upperDir, 0755)
+	if err != nil {
+		return nil, "", err
+	}
+
+	err = os.Mkdir(overlayDir, 0755)
+	if err != nil {
+		return nil, "", err
+	}
+
+	err = os.Mkdir(workDir, 0755)
+	if err != nil {
+		return nil, "", err
+	}
+
+	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", sourceDir, upperDir, workDir)
+
+	err = unix.Mount("overlay", overlayDir, "overlay", 0, opts)
+	if err != nil {
+		return nil, "", err
+	}
+
+	cleanup := func() {
+		err := unix.Unmount(overlayDir, 0)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, errors.Wrap(err, "Failed to unmount overlay"))
+		}
+
+		err = os.RemoveAll(upperDir)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, errors.Wrap(err, "Failed to remove upper directory"))
+		}
+
+		err = os.RemoveAll(workDir)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, errors.Wrap(err, "Failed to remove work directory"))
+		}
+
+		err = os.Remove(overlayDir)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, errors.Wrap(err, "Failed to remove overlay directory"))
+		}
+	}
+
+	return cleanup, overlayDir, nil
+}
diff --git a/distrobuilder/main_lxc.go b/distrobuilder/main_lxc.go
index 0990d32..00731b8 100644
--- a/distrobuilder/main_lxc.go
+++ b/distrobuilder/main_lxc.go
@@ -3,6 +3,7 @@ package main
 import (
 	"fmt"
 
+	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 
 	"github.com/lxc/distrobuilder/generators"
@@ -39,7 +40,13 @@ func (c *cmdLXC) commandPack() *cobra.Command {
 }
 
 func (c *cmdLXC) run(cmd *cobra.Command, args []string) error {
-	img := image.NewLXCImage(c.global.sourceDir, c.global.targetDir,
+	cleanup, overlayDir, err := getOverlay(c.global.flagCacheDir, c.global.sourceDir)
+	if err != nil {
+		return errors.Wrap(err, "Failed to create overlay")
+	}
+	defer cleanup()
+
+	img := image.NewLXCImage(overlayDir, c.global.targetDir,
 		c.global.flagCacheDir, *c.global.definition)
 
 	for _, file := range c.global.definition.Files {
@@ -52,14 +59,14 @@ func (c *cmdLXC) run(cmd *cobra.Command, args []string) error {
 			continue
 		}
 
-		err := generator.RunLXC(c.global.flagCacheDir, c.global.sourceDir, img,
+		err := generator.RunLXC(c.global.flagCacheDir, overlayDir, img,
 			file)
 		if err != nil {
 			return err
 		}
 	}
 
-	exitChroot, err := shared.SetupChroot(c.global.sourceDir,
+	exitChroot, err := shared.SetupChroot(overlayDir,
 		c.global.definition.Environment, nil)
 	if err != nil {
 		return err
@@ -82,7 +89,7 @@ func (c *cmdLXC) run(cmd *cobra.Command, args []string) error {
 	}
 
 	// Clean up the chroot by restoring the orginal files.
-	err = generators.RestoreFiles(c.global.flagCacheDir, c.global.sourceDir)
+	err = generators.RestoreFiles(c.global.flagCacheDir, overlayDir)
 	if err != nil {
 		return fmt.Errorf("Failed to restore cached files: %s", err)
 	}
diff --git a/distrobuilder/main_lxd.go b/distrobuilder/main_lxd.go
index 2d2ec5c..8823f39 100644
--- a/distrobuilder/main_lxd.go
+++ b/distrobuilder/main_lxd.go
@@ -1,10 +1,10 @@
 package main
 
 import (
-	"errors"
 	"fmt"
 
 	lxd "github.com/lxc/lxd/shared"
+	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 
 	"github.com/lxc/distrobuilder/generators"
@@ -64,7 +64,13 @@ func (c *cmdLXD) commandPack() *cobra.Command {
 }
 
 func (c *cmdLXD) run(cmd *cobra.Command, args []string) error {
-	img := image.NewLXDImage(c.global.sourceDir, c.global.targetDir,
+	cleanup, overlayDir, err := getOverlay(c.global.flagCacheDir, c.global.sourceDir)
+	if err != nil {
+		return errors.Wrap(err, "Failed to create overlay")
+	}
+	defer cleanup()
+
+	img := image.NewLXDImage(overlayDir, c.global.targetDir,
 		c.global.flagCacheDir, *c.global.definition)
 
 	for _, file := range c.global.definition.Files {
@@ -77,14 +83,14 @@ func (c *cmdLXD) run(cmd *cobra.Command, args []string) error {
 			return fmt.Errorf("Unknown generator '%s'", file.Generator)
 		}
 
-		err := generator.RunLXD(c.global.flagCacheDir, c.global.sourceDir,
+		err := generator.RunLXD(c.global.flagCacheDir, overlayDir,
 			img, file)
 		if err != nil {
 			return fmt.Errorf("Failed to create LXD data: %s", err)
 		}
 	}
 
-	exitChroot, err := shared.SetupChroot(c.global.sourceDir,
+	exitChroot, err := shared.SetupChroot(overlayDir,
 		c.global.definition.Environment, nil)
 	if err != nil {
 		return err


More information about the lxc-devel mailing list