[lxc-devel] [distrobuilder/master] Add support for Alpine edge

stgraber on Github lxc-bot at linuxcontainers.org
Wed Jun 27 23:29:10 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 363 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180627/8de2aa1d/attachment.bin>
-------------- next part --------------
From 2e3d2075ed8340bcfb1cc57b1e136796b505589e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Wed, 27 Jun 2018 19:25:51 -0400
Subject: [PATCH] Add support for Alpine edge
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 distrobuilder/chroot.go   | 273 ---------------------------------------------
 distrobuilder/main.go     |   2 +-
 distrobuilder/main_lxc.go |   2 +-
 distrobuilder/main_lxd.go |   2 +-
 shared/chroot.go          | 279 ++++++++++++++++++++++++++++++++++++++++++++++
 sources/alpine-http.go    |  50 ++++++++-
 6 files changed, 328 insertions(+), 280 deletions(-)
 create mode 100644 shared/chroot.go

diff --git a/distrobuilder/chroot.go b/distrobuilder/chroot.go
index 8fae569..de3e0fd 100644
--- a/distrobuilder/chroot.go
+++ b/distrobuilder/chroot.go
@@ -2,284 +2,11 @@ package main
 
 import (
 	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"regexp"
-	"strconv"
-	"syscall"
-
-	lxd "github.com/lxc/lxd/shared"
 
 	"github.com/lxc/distrobuilder/managers"
 	"github.com/lxc/distrobuilder/shared"
 )
 
-type chrootMount struct {
-	source string
-	target string
-	fstype string
-	flags  uintptr
-	data   string
-	isDir  bool
-}
-
-func setupMounts(rootfs string, mounts []chrootMount) error {
-	// Create a temporary mount path
-	err := os.MkdirAll(filepath.Join(rootfs, ".distrobuilder"), 0700)
-	if err != nil {
-		return err
-	}
-
-	for i, mount := range mounts {
-		// Target path
-		tmpTarget := filepath.Join(rootfs, ".distrobuilder", fmt.Sprintf("%d", i))
-
-		// Create the target mountpoint
-		if mount.isDir {
-			err := os.Mkdir(tmpTarget, 0755)
-			if err != nil {
-				return err
-			}
-		} else {
-			_, err = os.Create(tmpTarget)
-			if err != nil {
-				return err
-			}
-		}
-
-		// Mount to the temporary path
-		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 nil
-}
-
-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
-		for {
-			// Get information on current target
-			fi, err := os.Lstat(target)
-			if err != nil {
-				break
-			}
-
-			// If not a symlink, we're done
-			if fi.Mode()&os.ModeSymlink == 0 {
-				break
-			}
-
-			// If a symlink, resolve it
-			newTarget, err := os.Readlink(target)
-			if err != nil {
-				break
-			}
-
-			target = newTarget
-		}
-
-		// Create parent paths if missing
-		err := os.MkdirAll(filepath.Dir(target), 0755)
-		if err != nil {
-			return err
-		}
-
-		// Create target path
-		if mount.isDir {
-			err = os.MkdirAll(target, 0755)
-			if err != nil {
-				return err
-			}
-		} else {
-			_, err = os.Create(target)
-			if err != nil {
-				return err
-			}
-		}
-
-		// 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)
-		}
-	}
-
-	// Cleanup our temporary path
-	err := os.RemoveAll(filepath.Join("/", ".distrobuilder"))
-	if err != nil {
-		return err
-	}
-
-	return nil
-
-}
-
-func killChrootProcesses(rootfs string) error {
-	// List all files under /proc
-	proc, err := os.Open(filepath.Join(rootfs, "proc"))
-	if err != nil {
-		return err
-	}
-
-	dirs, err := proc.Readdirnames(0)
-	if err != nil {
-		return err
-	}
-
-	// Get all processes and kill them
-	for _, dir := range dirs {
-		match, _ := regexp.MatchString(`\d+`, dir)
-		if match {
-			link, _ := os.Readlink(filepath.Join(rootfs, "proc", dir, "root"))
-			if link == rootfs {
-				pid, _ := strconv.Atoi(dir)
-				syscall.Kill(pid, syscall.SIGKILL)
-			}
-		}
-	}
-
-	return nil
-}
-
-func setupChroot(rootfs string) (func() error, error) {
-	// Mount the rootfs
-	err := syscall.Mount(rootfs, rootfs, "", syscall.MS_BIND, "")
-	if err != nil {
-		return nil, fmt.Errorf("Failed to mount '%s': %s", rootfs, err)
-	}
-
-	// Setup all other needed mounts
-	mounts := []chrootMount{
-		{"none", "/proc", "proc", 0, "", true},
-		{"none", "/sys", "sysfs", 0, "", true},
-		{"/dev", "/dev", "", syscall.MS_BIND, "", true},
-		{"none", "/run", "tmpfs", 0, "", true},
-		{"none", "/tmp", "tmpfs", 0, "", true},
-		{"/etc/resolv.conf", "/etc/resolv.conf", "", syscall.MS_BIND, "", false},
-	}
-
-	// Keep a reference to the host rootfs and cwd
-	root, err := os.Open("/")
-	if err != nil {
-		return nil, err
-	}
-
-	cwd, err := os.Getwd()
-	if err != nil {
-		return nil, err
-	}
-
-	// Setup all needed mounts in a temporary location
-	err = setupMounts(rootfs, mounts)
-	if err != nil {
-		return nil, fmt.Errorf("Failed to mount filesystems: %v", err)
-	}
-
-	// Chroot into the container's rootfs
-	err = syscall.Chroot(rootfs)
-	if err != nil {
-		root.Close()
-		return nil, err
-	}
-
-	err = syscall.Chdir("/")
-	if err != nil {
-		return nil, err
-	}
-
-	// Move all the mounts into place
-	err = moveMounts(mounts)
-	if err != nil {
-		return nil, err
-	}
-
-	// Set environment variables
-	oldEnvVariables := shared.SetEnvVariables(
-		[]shared.EnvVariable{
-			{
-				Key:   "PATH",
-				Value: "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
-				Set:   true,
-			},
-			{
-				Key:   "SHELL",
-				Value: "/bin/sh",
-				Set:   true,
-			},
-			{
-				Key:   "TERM",
-				Value: "xterm",
-				Set:   true,
-			},
-			{
-				Key:   "DEBIAN_FRONTEND",
-				Value: "noninteractive",
-				Set:   true,
-			},
-		})
-
-	// Setup policy-rc.d override
-	policyCleanup := false
-	if lxd.PathExists("/usr/sbin/") && !lxd.PathExists("/usr/sbin/policy-rc.d") {
-		err = ioutil.WriteFile("/usr/sbin/policy-rc.d", []byte(`#!/bin/sh
-exit 101
-`), 0755)
-		if err != nil {
-			return nil, err
-		}
-
-		policyCleanup = true
-	}
-
-	return func() error {
-		defer root.Close()
-
-		// Cleanup policy-rc.d
-		if policyCleanup {
-			err = os.Remove("/usr/sbin/policy-rc.d")
-			if err != nil {
-				return err
-			}
-		}
-
-		// Reset old environment variables
-		shared.SetEnvVariables(oldEnvVariables)
-
-		// Switch back to the host rootfs
-		err = root.Chdir()
-		if err != nil {
-			return err
-		}
-
-		err = syscall.Chroot(".")
-		if err != nil {
-			return err
-		}
-
-		err = syscall.Chdir(cwd)
-		if err != nil {
-			return err
-		}
-
-		// This will kill all processes in the chroot and allow to cleanly
-		// unmount everything.
-		killChrootProcesses(rootfs)
-
-		// And now unmount the entire tree
-		syscall.Unmount(rootfs, syscall.MNT_DETACH)
-
-		return nil
-	}, nil
-}
-
 func managePackages(def shared.DefinitionPackages, actions []shared.DefinitionAction) error {
 	var err error
 
diff --git a/distrobuilder/main.go b/distrobuilder/main.go
index d376447..ed14548 100644
--- a/distrobuilder/main.go
+++ b/distrobuilder/main.go
@@ -197,7 +197,7 @@ func (c *cmdGlobal) preRunBuild(cmd *cobra.Command, args []string) error {
 	}
 
 	// Setup the mounts and chroot into the rootfs
-	exitChroot, err := setupChroot(c.sourceDir)
+	exitChroot, err := shared.SetupChroot(c.sourceDir)
 	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 3885390..86cb4d2 100644
--- a/distrobuilder/main_lxc.go
+++ b/distrobuilder/main_lxc.go
@@ -66,7 +66,7 @@ func (c *cmdLXC) run(cmd *cobra.Command, args []string) error {
 		}
 	}
 
-	exitChroot, err := setupChroot(c.global.sourceDir)
+	exitChroot, err := shared.SetupChroot(c.global.sourceDir)
 	if err != nil {
 		return err
 	}
diff --git a/distrobuilder/main_lxd.go b/distrobuilder/main_lxd.go
index e9d3d7d..3a33696 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 := setupChroot(c.global.sourceDir)
+	exitChroot, err := shared.SetupChroot(c.global.sourceDir)
 	if err != nil {
 		return err
 	}
diff --git a/shared/chroot.go b/shared/chroot.go
new file mode 100644
index 0000000..0b28201
--- /dev/null
+++ b/shared/chroot.go
@@ -0,0 +1,279 @@
+package shared
+
+import (
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"regexp"
+	"strconv"
+	"syscall"
+
+	lxd "github.com/lxc/lxd/shared"
+)
+
+type chrootMount struct {
+	source string
+	target string
+	fstype string
+	flags  uintptr
+	data   string
+	isDir  bool
+}
+
+func setupMounts(rootfs string, mounts []chrootMount) error {
+	// Create a temporary mount path
+	err := os.MkdirAll(filepath.Join(rootfs, ".distrobuilder"), 0700)
+	if err != nil {
+		return err
+	}
+
+	for i, mount := range mounts {
+		// Target path
+		tmpTarget := filepath.Join(rootfs, ".distrobuilder", fmt.Sprintf("%d", i))
+
+		// Create the target mountpoint
+		if mount.isDir {
+			err := os.Mkdir(tmpTarget, 0755)
+			if err != nil {
+				return err
+			}
+		} else {
+			_, err = os.Create(tmpTarget)
+			if err != nil {
+				return err
+			}
+		}
+
+		// Mount to the temporary path
+		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 nil
+}
+
+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
+		for {
+			// Get information on current target
+			fi, err := os.Lstat(target)
+			if err != nil {
+				break
+			}
+
+			// If not a symlink, we're done
+			if fi.Mode()&os.ModeSymlink == 0 {
+				break
+			}
+
+			// If a symlink, resolve it
+			newTarget, err := os.Readlink(target)
+			if err != nil {
+				break
+			}
+
+			target = newTarget
+		}
+
+		// Create parent paths if missing
+		err := os.MkdirAll(filepath.Dir(target), 0755)
+		if err != nil {
+			return err
+		}
+
+		// Create target path
+		if mount.isDir {
+			err = os.MkdirAll(target, 0755)
+			if err != nil {
+				return err
+			}
+		} else {
+			_, err = os.Create(target)
+			if err != nil {
+				return err
+			}
+		}
+
+		// 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)
+		}
+	}
+
+	// Cleanup our temporary path
+	err := os.RemoveAll(filepath.Join("/", ".distrobuilder"))
+	if err != nil {
+		return err
+	}
+
+	return nil
+
+}
+
+func killChrootProcesses(rootfs string) error {
+	// List all files under /proc
+	proc, err := os.Open(filepath.Join(rootfs, "proc"))
+	if err != nil {
+		return err
+	}
+
+	dirs, err := proc.Readdirnames(0)
+	if err != nil {
+		return err
+	}
+
+	// Get all processes and kill them
+	for _, dir := range dirs {
+		match, _ := regexp.MatchString(`\d+`, dir)
+		if match {
+			link, _ := os.Readlink(filepath.Join(rootfs, "proc", dir, "root"))
+			if link == rootfs {
+				pid, _ := strconv.Atoi(dir)
+				syscall.Kill(pid, syscall.SIGKILL)
+			}
+		}
+	}
+
+	return nil
+}
+
+// SetupChroot sets up mount and files, a reverter and then chroots for you
+func SetupChroot(rootfs string) (func() error, error) {
+	// Mount the rootfs
+	err := syscall.Mount(rootfs, rootfs, "", syscall.MS_BIND, "")
+	if err != nil {
+		return nil, fmt.Errorf("Failed to mount '%s': %s", rootfs, err)
+	}
+
+	// Setup all other needed mounts
+	mounts := []chrootMount{
+		{"none", "/proc", "proc", 0, "", true},
+		{"none", "/sys", "sysfs", 0, "", true},
+		{"/dev", "/dev", "", syscall.MS_BIND, "", true},
+		{"none", "/run", "tmpfs", 0, "", true},
+		{"none", "/tmp", "tmpfs", 0, "", true},
+		{"/etc/resolv.conf", "/etc/resolv.conf", "", syscall.MS_BIND, "", false},
+	}
+
+	// Keep a reference to the host rootfs and cwd
+	root, err := os.Open("/")
+	if err != nil {
+		return nil, err
+	}
+
+	cwd, err := os.Getwd()
+	if err != nil {
+		return nil, err
+	}
+
+	// Setup all needed mounts in a temporary location
+	err = setupMounts(rootfs, mounts)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to mount filesystems: %v", err)
+	}
+
+	// Chroot into the container's rootfs
+	err = syscall.Chroot(rootfs)
+	if err != nil {
+		root.Close()
+		return nil, err
+	}
+
+	err = syscall.Chdir("/")
+	if err != nil {
+		return nil, err
+	}
+
+	// Move all the mounts into place
+	err = moveMounts(mounts)
+	if err != nil {
+		return nil, err
+	}
+
+	// Set environment variables
+	oldEnvVariables := SetEnvVariables(
+		[]EnvVariable{
+			{
+				Key:   "PATH",
+				Value: "/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin",
+				Set:   true,
+			},
+			{
+				Key:   "SHELL",
+				Value: "/bin/sh",
+				Set:   true,
+			},
+			{
+				Key:   "TERM",
+				Value: "xterm",
+				Set:   true,
+			},
+			{
+				Key:   "DEBIAN_FRONTEND",
+				Value: "noninteractive",
+				Set:   true,
+			},
+		})
+
+	// Setup policy-rc.d override
+	policyCleanup := false
+	if lxd.PathExists("/usr/sbin/") && !lxd.PathExists("/usr/sbin/policy-rc.d") {
+		err = ioutil.WriteFile("/usr/sbin/policy-rc.d", []byte(`#!/bin/sh
+exit 101
+`), 0755)
+		if err != nil {
+			return nil, err
+		}
+
+		policyCleanup = true
+	}
+
+	return func() error {
+		defer root.Close()
+
+		// Cleanup policy-rc.d
+		if policyCleanup {
+			err = os.Remove("/usr/sbin/policy-rc.d")
+			if err != nil {
+				return err
+			}
+		}
+
+		// Reset old environment variables
+		SetEnvVariables(oldEnvVariables)
+
+		// Switch back to the host rootfs
+		err = root.Chdir()
+		if err != nil {
+			return err
+		}
+
+		err = syscall.Chroot(".")
+		if err != nil {
+			return err
+		}
+
+		err = syscall.Chdir(cwd)
+		if err != nil {
+			return err
+		}
+
+		// This will kill all processes in the chroot and allow to cleanly
+		// unmount everything.
+		killChrootProcesses(rootfs)
+
+		// And now unmount the entire tree
+		syscall.Unmount(rootfs, syscall.MNT_DETACH)
+
+		return nil
+	}, nil
+}
diff --git a/sources/alpine-http.go b/sources/alpine-http.go
index 6435bdc..7fe1736 100644
--- a/sources/alpine-http.go
+++ b/sources/alpine-http.go
@@ -23,11 +23,33 @@ func NewAlpineLinuxHTTP() *AlpineLinuxHTTP {
 
 // Run downloads an Alpine Linux mini root filesystem.
 func (s *AlpineLinuxHTTP) Run(definition shared.Definition, rootfsDir string) error {
-	fname := fmt.Sprintf("alpine-minirootfs-%s-%s.tar.gz", definition.Image.Release,
+	releaseFull := definition.Image.Release
+	releaseShort := releaseFull
+
+	if definition.Image.Release == "edge" {
+		if definition.Source.SameAs == "" {
+			return fmt.Errorf("You can't use Alpine edge without setting same_as")
+		}
+
+		releaseFull = definition.Source.SameAs
+		releaseShort = releaseFull
+	}
+
+	releaseField := strings.Split(releaseFull, ".")
+	if len(releaseField) == 2 {
+		releaseShort = fmt.Sprintf("v%s", releaseFull)
+		releaseFull = fmt.Sprintf("%s.0", releaseFull)
+	} else if len(releaseField) == 3 {
+		releaseShort = fmt.Sprintf("v%s.%s", releaseField[0], releaseField[1])
+	} else {
+		return fmt.Errorf("Bad Alpine release: %s", releaseFull)
+	}
+
+	fname := fmt.Sprintf("alpine-minirootfs-%s-%s.tar.gz", releaseFull,
 		definition.Image.ArchitectureMapped)
-	tarball := fmt.Sprintf("%s/v%s/releases/%s/%s", definition.Source.URL,
-		strings.Join(strings.Split(definition.Image.Release, ".")[0:2], "."),
-		definition.Image.ArchitectureMapped, fname)
+
+	tarball := fmt.Sprintf("%s/%s/releases/%s/%s", definition.Source.URL,
+		releaseShort, definition.Image.ArchitectureMapped, fname)
 
 	url, err := url.Parse(tarball)
 	if err != nil {
@@ -65,5 +87,25 @@ func (s *AlpineLinuxHTTP) Run(definition shared.Definition, rootfsDir string) er
 		return err
 	}
 
+	if definition.Image.Release == "edge" {
+		// Upgrade to edge
+		exitChroot, err := shared.SetupChroot(rootfsDir)
+		if err != nil {
+			return err
+		}
+
+		err = shared.RunCommand("sed", "-i", "-e", "s/v[[:digit:]]\\.[[:digit:]]/edge/g", "/etc/apk/repositories")
+		if err != nil {
+			return err
+		}
+
+		err = shared.RunCommand("apk", "upgrade", "--update-cache", "--available")
+		if err != nil {
+			return err
+		}
+
+		exitChroot()
+	}
+
 	return nil
 }


More information about the lxc-devel mailing list