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

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) ===

From f412fc349d543b65122575fc8861b68891f05adc Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Wed, 7 Mar 2018 13:38:55 +0100
Subject: [PATCH 1/2] *: Add support for compat level overrides

Resolves #30

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 image/lxc.go         | 99 +++++++++++++++++++++++++++++++++++++++++++---------
 shared/definition.go | 13 +++++--
 2 files changed, 93 insertions(+), 19 deletions(-)

diff --git a/image/lxc.go b/image/lxc.go
index d8467f1..3c5a9fb 100644
--- a/image/lxc.go
+++ b/image/lxc.go
@@ -13,6 +13,8 @@ import (
        "github.com/lxc/distrobuilder/shared"
 )
 
+const maxLXCCompatLevel = 5
+
 // LXCImage represents a LXC image.
 type LXCImage struct {
        sourceDir  string
@@ -85,23 +87,58 @@ func (l *LXCImage) Build() error {
 func (l *LXCImage) createMetadata() error {
        metaDir := filepath.Join(l.cacheDir, "metadata")
 
-       err := l.writeMetadata(filepath.Join(metaDir, "config"), 
l.target.Config)
-       if err != nil {
-               return fmt.Errorf("Error writing 'config': %s", err)
-       }
+       for _, c := range l.target.Config {
+               // If not specified, create files up to ${maxLXCCompatLevel}
+               if c.Before == 0 {
+                       c.Before = maxLXCCompatLevel + 1
+               }
+               for i := uint(1); i < maxLXCCompatLevel+1; i++ {
+                       // Bound checking
+                       if c.After < c.Before {
+                               if i <= c.After || i >= c.Before {
+                                       continue
+                               }
 
-       err = l.writeMetadata(filepath.Join(metaDir, "config-user"), 
l.target.ConfigUser)
-       if err != nil {
-               return fmt.Errorf("Error writing 'config-user': %s", err)
+                       } else if c.After >= c.Before {
+                               if i <= c.After && i >= c.Before {
+                                       continue
+                               }
+                       }
+
+                       switch c.Type {
+                       case "all":
+                               err := l.writeConfig(i, filepath.Join(metaDir, 
"config"), c.Content)
+                               if err != nil {
+                                       return err
+                               }
+
+                               err = l.writeConfig(i, filepath.Join(metaDir, 
"config.user"), c.Content)
+                               if err != nil {
+                                       return err
+                               }
+                       case "system":
+                               err := l.writeConfig(i, filepath.Join(metaDir, 
"config"), c.Content)
+                               if err != nil {
+                                       return err
+                               }
+                       case "user":
+                               err := l.writeConfig(i, filepath.Join(metaDir, 
"config.user"), c.Content)
+                               if err != nil {
+                                       return err
+                               }
+                       }
+               }
        }
 
-       err = l.writeMetadata(filepath.Join(metaDir, "create-message"), 
l.target.CreateMessage)
+       err := l.writeMetadata(filepath.Join(metaDir, "create-message"),
+               l.target.CreateMessage, false)
        if err != nil {
                return fmt.Errorf("Error writing 'create-message': %s", err)
        }
 
        err = l.writeMetadata(filepath.Join(metaDir, "expiry"),
-               fmt.Sprint(shared.GetExpiryDate(time.Now(), 
l.definition.Expiry).Unix()))
+               fmt.Sprint(shared.GetExpiryDate(time.Now(), 
l.definition.Expiry).Unix()),
+               false)
        if err != nil {
                return fmt.Errorf("Error writing 'expiry': %s", err)
        }
@@ -127,7 +164,8 @@ func (l *LXCImage) createMetadata() error {
                }
        }
 
-       err = l.writeMetadata(filepath.Join(metaDir, "excludes-user"), 
excludesUser)
+       err = l.writeMetadata(filepath.Join(metaDir, "excludes-user"), 
excludesUser,
+               false)
        if err != nil {
                return fmt.Errorf("Error writing 'excludes-user': %s", err)
        }
@@ -136,14 +174,23 @@ func (l *LXCImage) createMetadata() error {
 }
 
 func (l *LXCImage) packMetadata() error {
-       files := []string{"config", "config-user", "create-message", "expiry",
-               "excludes-user"}
+       files := []string{"create-message", "expiry", "excludes-user"}
+
+       // Get all config and config.user files
+       configs, err := filepath.Glob(filepath.Join(l.cacheDir, "metadata", 
"config*"))
+       if err != nil {
+               return err
+       }
+
+       for _, c := range configs {
+               files = append(files, filepath.Base(c))
+       }
 
        if lxd.PathExists(filepath.Join(l.cacheDir, "metadata", "templates")) {
                files = append(files, "templates")
        }
 
-       err := shared.Pack(filepath.Join(l.targetDir, "meta.tar"), "xz",
+       err = shared.Pack(filepath.Join(l.targetDir, "meta.tar"), "xz",
                filepath.Join(l.cacheDir, "metadata"), files...)
        if err != nil {
                return fmt.Errorf("Failed to create metadata: %s", err)
@@ -151,8 +198,15 @@ func (l *LXCImage) packMetadata() error {
 
        return nil
 }
-func (l *LXCImage) writeMetadata(filename, content string) error {
-       file, err := os.Create(filename)
+func (l *LXCImage) writeMetadata(filename, content string, append bool) error {
+       var file *os.File
+       var err error
+
+       if append {
+               file, err = os.OpenFile(filename, 
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+       } else {
+               file, err = os.Create(filename)
+       }
        if err != nil {
                return err
        }
@@ -167,10 +221,23 @@ func (l *LXCImage) writeMetadata(filename, content 
string) error {
                return err
        }
 
-       _, err = file.WriteString(out)
+       _, err = file.WriteString(out + "\n")
        if err != nil {
                return err
        }
 
        return nil
 }
+
+func (l *LXCImage) writeConfig(compatLevel uint, filename, content string) 
error {
+       // Only add suffix if it's not the latest compatLevel
+       if compatLevel != maxLXCCompatLevel {
+               filename = fmt.Sprintf("%s.%d", filename, compatLevel)
+       }
+       err := l.writeMetadata(filename, content, true)
+       if err != nil {
+               return fmt.Errorf("Error writing '%s': %s", 
filepath.Base(filename), err)
+       }
+
+       return nil
+}
diff --git a/shared/definition.go b/shared/definition.go
index 63cba8c..93950bc 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -40,11 +40,18 @@ type DefinitionSource struct {
        AptSources string   `yaml:"apt_sources,omitempty"`
 }
 
+// A DefinitionTargetLXCConfig represents the config part of the metadata.
+type DefinitionTargetLXCConfig struct {
+       Type    string `yaml:"type"`
+       Before  uint   `yaml:"before,omitempty"`
+       After   uint   `yaml:"after,omitempty"`
+       Content string `yaml:"content"`
+}
+
 // A DefinitionTargetLXC represents LXC specific files as part of the metadata.
 type DefinitionTargetLXC struct {
-       CreateMessage string `yaml:"create-message,omitempty"`
-       Config        string `yaml:"config,omitempty"`
-       ConfigUser    string `yaml:"config-user,omitempty"`
+       CreateMessage string                      
`yaml:"create-message,omitempty"`
+       Config        []DefinitionTargetLXCConfig `yaml:"config,omitempty"`
 }
 
 // A DefinitionTarget specifies target dependent files.

From 0c7e50de7c5c114cdb91d165a5ae47365de3a33c Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.h...@canonical.com>
Date: Wed, 7 Mar 2018 15:50:48 +0100
Subject: [PATCH 2/2] tests: Update lxc config tests

Signed-off-by: Thomas Hipp <thomas.h...@canonical.com>
---
 image/lxc_test.go | 152 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 134 insertions(+), 18 deletions(-)

diff --git a/image/lxc_test.go b/image/lxc_test.go
index 9271176..93de24f 100644
--- a/image/lxc_test.go
+++ b/image/lxc_test.go
@@ -25,11 +25,55 @@ var lxcImageDef = shared.DefinitionImage{
 
 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`,
+       Config: []shared.DefinitionTargetLXCConfig{
+               {
+                       Type:    "all",
+                       Before:  5,
+                       Content: "all_before_5",
+               },
+               {
+                       Type:    "user",
+                       Before:  5,
+                       Content: "user_before_5",
+               },
+               {
+                       Type:    "all",
+                       After:   4,
+                       Content: "all_after_4",
+               },
+               {
+                       Type:    "user",
+                       After:   4,
+                       Content: "user_after_4",
+               },
+               {
+                       Type:    "all",
+                       Content: "all",
+               },
+               {
+                       Type:    "system",
+                       Before:  2,
+                       Content: "system_before_2",
+               },
+               {
+                       Type:    "system",
+                       Before:  2,
+                       After:   4,
+                       Content: "system_before_2_after_4",
+               },
+               {
+                       Type:    "user",
+                       Before:  3,
+                       After:   3,
+                       Content: "user_before_3_after_3",
+               },
+               {
+                       Type:    "system",
+                       Before:  4,
+                       After:   2,
+                       Content: "system_before_4_after_2",
+               },
+       },
 }
 
 func lxcCacheDir() string {
@@ -127,7 +171,7 @@ func TestLXCBuild(t *testing.T) {
        }()
 }
 
-func TestLXCCreateMetadata(t *testing.T) {
+func TestLXCCreateMetadataBasic(t *testing.T) {
        defaultImage := setupLXC()
        defer teardownLXC()
 
@@ -148,16 +192,13 @@ func TestLXCCreateMetadata(t *testing.T) {
                        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 }"
+                               l.target.Config = 
[]shared.DefinitionTargetLXCConfig{
+                                       {
+                                               Type:    "all",
+                                               After:   4,
+                                               Content: "{{ invalid }",
+                                       },
+                               }
                                return &l
                        },
                },
@@ -205,6 +246,81 @@ func TestLXCCreateMetadata(t *testing.T) {
        }
 }
 
+func TestLXCCreateMetadataConfig(t *testing.T) {
+       image := setupLXC()
+       defer teardownLXC()
+
+       tests := []struct {
+               configFile string
+               expected   string
+       }{
+               {
+                       "config",
+                       "all_after_4\nall\nsystem_before_2_after_4\n",
+               },
+               {
+                       "config.1",
+                       
"all_before_5\nall\nsystem_before_2\nsystem_before_2_after_4\n",
+               },
+               {
+                       "config.2",
+                       "all_before_5\nall\n",
+               },
+               {
+                       "config.3",
+                       "all_before_5\nall\nsystem_before_4_after_2\n",
+               },
+               {
+                       "config.4",
+                       "all_before_5\nall\n",
+               },
+               {
+                       "config.user",
+                       
"all_after_4\nuser_after_4\nall\nuser_before_3_after_3\n",
+               },
+               {
+                       "config.user.1",
+                       
"all_before_5\nuser_before_5\nall\nuser_before_3_after_3\n",
+               },
+               {
+                       "config.user.2",
+                       
"all_before_5\nuser_before_5\nall\nuser_before_3_after_3\n",
+               },
+               {
+                       "config.user.3",
+                       "all_before_5\nuser_before_5\nall\n",
+               },
+               {
+                       "config.user.4",
+                       
"all_before_5\nuser_before_5\nall\nuser_before_3_after_3\n",
+               },
+       }
+
+       err := image.createMetadata()
+       if err != nil {
+               t.Fatalf("Unexpected error: %s", err)
+       }
+
+       for _, tt := range tests {
+               log.Printf("Checking '%s'", tt.configFile)
+               file, err := os.Open(filepath.Join(lxcCacheDir(), "metadata", 
tt.configFile))
+               if err != nil {
+                       t.Fatalf("Unexpected error: %s", err)
+               }
+
+               var buffer bytes.Buffer
+               _, err = io.Copy(&buffer, file)
+               file.Close()
+               if err != nil {
+                       t.Fatalf("Unexpected error: %s", err)
+               }
+
+               if buffer.String() != tt.expected {
+                       t.Fatalf("Expected '%s', got '%s'", tt.expected, 
buffer.String())
+               }
+       }
+}
+
 func TestLXCPackMetadata(t *testing.T) {
        image := setupLXC()
        defer func() {
@@ -243,13 +359,13 @@ func TestLXCWriteMetadata(t *testing.T) {
        defer teardownLXC()
 
        // Should fail due to invalid path
-       err := image.writeMetadata("/path/file", "")
+       err := image.writeMetadata("/path/file", "", false)
        if err == nil {
                t.Fatal("Expected failure")
        }
 
        // Should succeed
-       err = image.writeMetadata("test", "metadata")
+       err = image.writeMetadata("test", "metadata", false)
        if err != nil {
                t.Fatalf("Unexpected failure: %s", err)
        }
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to