The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/distrobuilder/pull/21

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Resolves #19 
From d1946033d0481a8de624f8c7621c5c34e29a82ec Mon Sep 17 00:00:00 2001
From: Thomas Hipp <[email protected]>
Date: Mon, 26 Feb 2018 17:04:29 +0100
Subject: [PATCH 1/2] image: Add LXD tests

Signed-off-by: Thomas Hipp <[email protected]>
---
 image/lxd.go      |  26 ++++++--
 image/lxd_test.go | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 199 insertions(+), 6 deletions(-)
 create mode 100644 image/lxd_test.go

diff --git a/image/lxd.go b/image/lxd.go
index ae3607c..f04b6c6 100644
--- a/image/lxd.go
+++ b/image/lxd.go
@@ -57,33 +57,44 @@ func (l *LXDImage) Build(unified bool) error {
                return fmt.Errorf("Failed to write metadata: %s", err)
        }
 
-       if unified {
-               var fname string
-               paths := []string{"rootfs", "templates", "metadata.yaml"}
+       paths := []string{"metadata.yaml"}
+
+       // Only include templates directory in the tarball if it's present.
+       info, err := os.Stat(filepath.Join(l.cacheDir, "templates"))
+       if err == nil && info.IsDir() {
+               paths = append(paths, "templates")
+       }
 
+       if unified {
                ctx := pongo2.Context{
                        "image":         l.definition,
                        "creation_date": l.creationDate.Format("20060201_1504"),
                }
 
+               var fname string
                if l.definition.Name != "" {
+                       // Use a custom name for the unified tarball.
                        fname, _ = renderTemplate(l.definition.Name, ctx)
                } else {
+                       // Default name for the unified tarball.
                        fname = "lxd"
                }
 
+               paths = append(paths, "rootfs")
                err = shared.Pack(fmt.Sprintf("%s.tar.xz", fname), l.cacheDir, 
paths...)
                if err != nil {
                        return err
                }
        } else {
+               // Create rootfs as squashfs.
                err = shared.RunCommand("mksquashfs", filepath.Join(l.cacheDir, 
"rootfs"),
                        "rootfs.squashfs", "-noappend")
                if err != nil {
                        return err
                }
 
-               err = shared.Pack("lxd.tar.xz", l.cacheDir, "templates", 
"metadata.yaml")
+               // Create metadata tarball.
+               err = shared.Pack("lxd.tar.xz", l.cacheDir, paths...)
                if err != nil {
                        return err
                }
@@ -107,9 +118,12 @@ func (l *LXDImage) createMetadata() error {
                return err
        }
 
-       l.Metadata.Architecture = arch
+       // Use proper architecture name from now on.
+       l.definition.Arch = arch
+
+       l.Metadata.Architecture = l.definition.Arch
        l.Metadata.CreationDate = l.creationDate.Unix()
-       l.Metadata.Properties["architecture"] = arch
+       l.Metadata.Properties["architecture"] = l.definition.Arch
        l.Metadata.Properties["os"] = l.definition.Distribution
        l.Metadata.Properties["release"] = l.definition.Release
 
diff --git a/image/lxd_test.go b/image/lxd_test.go
new file mode 100644
index 0000000..48b2fad
--- /dev/null
+++ b/image/lxd_test.go
@@ -0,0 +1,179 @@
+package image
+
+import (
+       "fmt"
+       "log"
+       "os"
+       "path/filepath"
+       "reflect"
+       "strings"
+       "testing"
+       "time"
+
+       "github.com/lxc/distrobuilder/shared"
+       lxd "github.com/lxc/lxd/shared"
+)
+
+var lxdImageDef = shared.DefinitionImage{
+       Description:  "{{ image. Distribution|capfirst }} {{ image.Release }}",
+       Distribution: "ubuntu",
+       Release:      "17.10",
+       Arch:         "amd64",
+       Expiry:       "30d",
+       Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ 
image.Arch }}-{{ creation_date }}",
+}
+
+func setupLXD(t *testing.T) *LXDImage {
+       cacheDir := filepath.Join(os.TempDir(), "distrobuilder-test")
+
+       err := os.MkdirAll(filepath.Join(cacheDir, "rootfs"), 0755)
+       if err != nil {
+               t.Fatalf("Failed to create rootfs directory: %s", err)
+       }
+
+       err = os.MkdirAll(filepath.Join(cacheDir, "templates"), 0755)
+       if err != nil {
+               t.Fatalf("Failed to create templates directory: %s", err)
+       }
+
+       image := NewLXDImage(cacheDir, lxdImageDef)
+
+       // Override creation date
+       image.creationDate = time.Date(2006, 1, 2, 3, 4, 5, 0, time.UTC)
+
+       // Check cache directory
+       if image.cacheDir != cacheDir {
+               teardownLXD(t)
+               t.Fatalf("Expected cacheDir to be '%s', is '%s'", cacheDir, 
image.cacheDir)
+       }
+
+       if !reflect.DeepEqual(lxdImageDef, image.definition) {
+               teardownLXD(t)
+               t.Fatal("lxdImageDef and image.definition are not equal")
+       }
+
+       return image
+}
+
+func teardownLXD(t *testing.T) {
+       os.RemoveAll(filepath.Join(os.TempDir(), "distrobuilder-test"))
+}
+
+func TestLXDBuild(t *testing.T) {
+       image := setupLXD(t)
+       defer teardownLXD(t)
+
+       testLXDBuildSplitImage(t, image)
+       testLXDBuildUnifiedImage(t, image)
+}
+
+func testLXDBuildSplitImage(t *testing.T, image *LXDImage) {
+       // Create split tarball and squashfs.
+       err := image.Build(false)
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+       defer func() {
+               os.Remove("lxd.tar.xz")
+               os.Remove("rootfs.squashfs")
+       }()
+
+       if !lxd.PathExists("lxd.tar.xz") {
+               t.Fatalf("File '%s' does not exist", "lxd.tar.xz")
+       }
+
+       if !lxd.PathExists("rootfs.squashfs") {
+               t.Fatalf("File '%s' does not exist", "rootfs.squashfs")
+       }
+}
+
+func testLXDBuildUnifiedImage(t *testing.T, image *LXDImage) {
+       // Create unified tarball with custom name.
+       err := image.Build(true)
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+       defer os.Remove("ubuntu-17.10-x86_64-20060201_0304.tar.xz")
+
+       if !lxd.PathExists("ubuntu-17.10-x86_64-20060201_0304.tar.xz") {
+               t.Fatalf("File '%s' does not exist", 
"ubuntu-17.10-x86_64-20060201_0304.tar.xz")
+       }
+
+       // Create unified tarball with default name.
+       image.definition.Name = ""
+       err = image.Build(true)
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+       defer os.Remove("lxd.tar.xz")
+
+       if !lxd.PathExists("lxd.tar.xz") {
+               t.Fatalf("File '%s' does not exist", "lxd.tar.xz")
+       }
+}
+
+func TestLXDCreateMetadata(t *testing.T) {
+       image := setupLXD(t)
+       defer teardownLXD(t)
+
+       err := image.createMetadata()
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+
+       tests := []struct {
+               name     string
+               have     string
+               expected string
+       }{
+               {
+                       "Architecture",
+                       image.Metadata.Architecture,
+                       "x86_64",
+               },
+               {
+                       "CreationDate",
+                       string(image.Metadata.CreationDate),
+                       string(image.creationDate.Unix()),
+               },
+               {
+                       "Properties[architecture]",
+                       image.Metadata.Properties["architecture"],
+                       "x86_64",
+               },
+               {
+                       "Properties[os]",
+                       image.Metadata.Properties["os"],
+                       lxdImageDef.Distribution,
+               },
+               {
+                       "Properties[release]",
+                       image.Metadata.Properties["release"],
+                       lxdImageDef.Release,
+               },
+               {
+                       "Properties[description]",
+                       image.Metadata.Properties["description"],
+                       fmt.Sprintf("%s %s", 
strings.Title(lxdImageDef.Distribution),
+                               lxdImageDef.Release),
+               },
+               {
+                       "Properties[name]",
+                       image.Metadata.Properties["name"],
+                       fmt.Sprintf("%s-%s-%s-%s", 
strings.ToLower(lxdImageDef.Distribution),
+                               lxdImageDef.Release, "x86_64", 
image.creationDate.Format("20060201_1504")),
+               },
+               {
+                       "ExpiryDate",
+                       fmt.Sprintf("%d", image.Metadata.ExpiryDate),
+                       "1138763045",
+               },
+       }
+
+       for i, tt := range tests {
+               log.Printf("Running test #%d: %s", i, tt.name)
+               if tt.have != tt.expected {
+                       t.Fatalf("Expected '%s', got '%s'", tt.expected, 
tt.have)
+               }
+       }
+}

From 92bb3540a70a4875bb99555c0fd05246ce35b34d Mon Sep 17 00:00:00 2001
From: Thomas Hipp <[email protected]>
Date: Tue, 27 Feb 2018 18:23:05 +0100
Subject: [PATCH 2/2] image: Add LXC tests

Signed-off-by: Thomas Hipp <[email protected]>
---
 image/lxc.go      |  36 +++++---
 image/lxc_test.go | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 283 insertions(+), 10 deletions(-)
 create mode 100644 image/lxc_test.go

diff --git a/image/lxc.go b/image/lxc.go
index 449eba4..10b90f3 100644
--- a/image/lxc.go
+++ b/image/lxc.go
@@ -7,6 +7,7 @@ import (
        "strings"
        "time"
 
+       lxd "github.com/lxc/lxd/shared"
        pongo2 "gopkg.in/flosch/pongo2.v3"
 
        "github.com/lxc/distrobuilder/shared"
@@ -102,15 +103,24 @@ func (l *LXCImage) createMetadata() error {
 
        var excludesUser string
 
-       filepath.Walk(filepath.Join(l.cacheDir, "rootfs", "dev"),
-               func(path string, info os.FileInfo, err error) error {
-                       if info.Mode()&os.ModeDevice != 0 {
-                               excludesUser += fmt.Sprintf("%s\n",
-                                       strings.TrimPrefix(path, 
filepath.Join(l.cacheDir, "rootfs")))
-                       }
+       if lxd.PathExists(filepath.Join(l.cacheDir, "rootfs", "dev")) {
+               err := filepath.Walk(filepath.Join(l.cacheDir, "rootfs", "dev"),
+                       func(path string, info os.FileInfo, err error) error {
+                               if err != nil {
+                                       return err
+                               }
 
-                       return nil
-               })
+                               if info.Mode()&os.ModeDevice != 0 {
+                                       excludesUser += fmt.Sprintf("%s\n",
+                                               strings.TrimPrefix(path, 
filepath.Join(l.cacheDir, "rootfs")))
+                               }
+
+                               return nil
+                       })
+               if err != nil {
+                       return fmt.Errorf("Error while walking /dev: %s", err)
+               }
+       }
 
        err = l.writeMetadata(filepath.Join(metaDir, "excludes-user"), 
excludesUser)
        if err != nil {
@@ -121,8 +131,14 @@ func (l *LXCImage) createMetadata() error {
 }
 
 func (l *LXCImage) packMetadata() error {
-       err := shared.Pack("meta.tar.xz", filepath.Join(l.cacheDir, 
"metadata"), "config",
-               "config-user", "create-message", "expiry", "templates", 
"excludes-user")
+       files := []string{"config", "config-user", "create-message", "expiry",
+               "excludes-user"}
+
+       if lxd.PathExists(filepath.Join(l.cacheDir, "metadata", "templates")) {
+               files = append(files, "templates")
+       }
+
+       err := shared.Pack("meta.tar.xz", filepath.Join(l.cacheDir, 
"metadata"), files...)
        if err != nil {
                return fmt.Errorf("Failed to create metadata: %s", err)
        }
diff --git a/image/lxc_test.go b/image/lxc_test.go
new file mode 100644
index 0000000..803d73b
--- /dev/null
+++ b/image/lxc_test.go
@@ -0,0 +1,257 @@
+package image
+
+import (
+       "bytes"
+       "io"
+       "log"
+       "os"
+       "path/filepath"
+       "reflect"
+       "regexp"
+       "syscall"
+       "testing"
+
+       "github.com/lxc/distrobuilder/shared"
+)
+
+var lxcImageDef = shared.DefinitionImage{
+       Description:  "{{ image. Distribution|capfirst }} {{ image.Release }}",
+       Distribution: "ubuntu",
+       Release:      "17.10",
+       Arch:         "amd64",
+       Expiry:       "30d",
+       Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ 
image.Arch }}-{{ creation_date }}",
+}
+
+var lxcTarget = shared.DefinitionTargetLXC{
+       CreateMessage: "Welcome to {{ image.Distribution|capfirst}} {{ 
image.Release }}",
+       Config: `lxc.include = LXC_TEMPLATE_CONFIG/ubuntu.common.conf
+lxc.arch = x86_64`,
+       ConfigUser: `lxc.include = LXC_TEMPLATE_CONFIG/ubuntu.common.conf
+lxc.include = LXC_TEMPLATE_CONFIG/ubuntu.userns.conf
+lxc.arch = x86_64`,
+}
+
+func lxcCacheDir() string {
+       wd, _ := os.Getwd()
+       return filepath.Join(wd, "distrobuilder-test")
+}
+
+func setupLXC() *LXCImage {
+       return NewLXCImage(lxcCacheDir(), lxcImageDef, lxcTarget)
+}
+
+func teardownLXC() {
+       os.RemoveAll(lxcCacheDir())
+}
+
+func TestNewLXCImage(t *testing.T) {
+       image := NewLXCImage(lxcCacheDir(), lxcImageDef, lxcTarget)
+       defer teardownLXC()
+
+       if image.cacheDir != lxcCacheDir() {
+               t.Fatalf("Expected image.cacheDir to be '%s', got '%s'", 
lxcCacheDir(),
+                       image.cacheDir)
+       }
+
+       if !reflect.DeepEqual(image.definition, lxcImageDef) {
+               t.Fatalf("lxcImageDef and image.definition are not equal")
+       }
+
+       if !reflect.DeepEqual(image.target, lxcTarget) {
+               t.Fatalf("lxcTarget and image.target are not equal")
+       }
+}
+
+func TestLXCAddTemplate(t *testing.T) {
+       image := setupLXC()
+       defer teardownLXC()
+
+       // Make sure templates file is empty.
+       info, err := os.Stat(filepath.Join(lxcCacheDir(), "metadata", 
"templates"))
+       if err == nil && info.Size() > 0 {
+               t.Fatalf("Expected file size to be 0, got %d", info.Size())
+       }
+
+       // Add first template entry.
+       image.AddTemplate("/path/file1")
+       file, err := os.Open(filepath.Join(lxcCacheDir(), "metadata", 
"templates"))
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+
+       // Copy file content to buffer.
+       var buffer bytes.Buffer
+       io.Copy(&buffer, file)
+       file.Close()
+
+       if buffer.String() != "/path/file1\n" {
+               t.Fatalf("Expected templates content to be '%s', got '%s'",
+                       "/path/file", buffer.String())
+       }
+
+       // Add second template entry.
+       image.AddTemplate("/path/file2")
+       file, err = os.Open(filepath.Join(lxcCacheDir(), "metadata", 
"templates"))
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+
+       // Copy file content to buffer.
+       buffer.Reset()
+       io.Copy(&buffer, file)
+       file.Close()
+
+       if buffer.String() != "/path/file1\n/path/file2\n" {
+               t.Fatalf("Expected templates content to be '%s', got '%s'",
+                       "/path/file1\n/path/file2", buffer.String())
+       }
+}
+
+func TestLXCBuild(t *testing.T) {
+       image := setupLXC()
+       defer teardownLXC()
+
+       err := os.MkdirAll(filepath.Join(lxcCacheDir(), "rootfs"), 0755)
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+
+       err = image.Build()
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+       defer func() {
+               os.Remove("meta.tar.xz")
+               os.Remove("rootfs.tar.xz")
+       }()
+}
+
+func TestLXCCreateMetadata(t *testing.T) {
+       defaultImage := setupLXC()
+       defer teardownLXC()
+
+       tests := []struct {
+               name          string
+               shouldFail    bool
+               expectedError string
+               prepareImage  func(LXCImage) *LXCImage
+       }{
+               {
+                       "valid metadata",
+                       false,
+                       "",
+                       func(l LXCImage) *LXCImage { return &l },
+               },
+               {
+                       "invalid config template",
+                       true,
+                       "Error writing 'config': .+",
+                       func(l LXCImage) *LXCImage {
+                               l.target.Config = "{{ invalid }"
+                               return &l
+                       },
+               },
+               {
+                       "invalid config-user template",
+                       true,
+                       "Error writing 'config-user': .+",
+                       func(l LXCImage) *LXCImage {
+                               l.target.ConfigUser = "{{ invalid }"
+                               return &l
+                       },
+               },
+               {
+                       "invalid create-message template",
+                       true,
+                       "Error writing 'create-message': .+",
+                       func(l LXCImage) *LXCImage {
+                               l.target.CreateMessage = "{{ invalid }"
+                               return &l
+                       },
+               },
+               {
+                       "existing dev directory",
+                       false,
+                       "",
+                       func(l LXCImage) *LXCImage {
+                               // Create /dev and device file.
+                               os.MkdirAll(filepath.Join(lxcCacheDir(), 
"rootfs", "dev"), 0755)
+                               syscall.Mknod(filepath.Join(lxcCacheDir(), 
"rootfs", "dev", "null"),
+                                       syscall.S_IFCHR, 0)
+                               return &l
+                       },
+               },
+       }
+
+       for i, tt := range tests {
+               log.Printf("Running test #%d: %s", i, tt.name)
+               image := tt.prepareImage(*defaultImage)
+               err := image.createMetadata()
+               if tt.shouldFail {
+                       if err == nil {
+                               t.Fatal("Expected to fail, but didn't")
+                       }
+
+                       match, _ := regexp.MatchString(tt.expectedError, 
err.Error())
+                       if !match {
+                               t.Fatalf("Expected to fail with '%s', got 
'%s'", tt.expectedError,
+                                       err.Error())
+                       }
+               }
+               if !tt.shouldFail && err != nil {
+                       t.Fatalf("Unexpected error: %s", err)
+               }
+       }
+}
+
+func TestLXCPackMetadata(t *testing.T) {
+       image := setupLXC()
+       defer func() {
+               teardownLXC()
+               os.Remove("meta.tar.xz")
+       }()
+
+       err := image.createMetadata()
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+
+       err = image.packMetadata()
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+
+       // Include templates directory.
+       image.AddTemplate("/path/file")
+       err = image.packMetadata()
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+
+       // Provoke error by removing the metadata directory
+       os.RemoveAll(filepath.Join(lxcCacheDir(), "metadata"))
+       err = image.packMetadata()
+       if err == nil {
+               t.Fatal("Expected failure")
+       }
+
+}
+
+func TestLXCWriteMetadata(t *testing.T) {
+       image := setupLXC()
+       defer teardownLXC()
+
+       // Should fail due to invalid path
+       err := image.writeMetadata("/path/file", "")
+       if err == nil {
+               t.Fatal("Expected failure")
+       }
+
+       // Should succeed
+       err = image.writeMetadata("test", "metadata")
+       if err != nil {
+               t.Fatalf("Unexpected failure: %s", err)
+       }
+       os.Remove("test")
+}
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to