[lxc-devel] [distrobuilder/master] Add support form compat level overrides
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Wed Mar 7 14:53:44 UTC 2018
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 309 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180307/96ad67a3/attachment.bin>
-------------- next part --------------
From f412fc349d543b65122575fc8861b68891f05adc Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at 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.hipp at 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.hipp at 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.hipp at 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)
}
More information about the lxc-devel
mailing list