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