[lxc-devel] [distrobuilder/master] Add cloud-init generator
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Tue Jul 9 21:06:54 UTC 2019
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 310 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190709/bbdc99c8/attachment.bin>
-------------- next part --------------
From 306b851623bbc31e3843b348854b9d4dc298e944 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Tue, 9 Jul 2019 22:25:49 +0200
Subject: [PATCH 1/2] generators: Add cloud-init generator
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
generators/cloud-init.go | 108 ++++++++++++++++++++++++++++++++++
generators/cloud-init_test.go | 97 ++++++++++++++++++++++++++++++
generators/generators.go | 2 +
shared/definition.go | 1 +
4 files changed, 208 insertions(+)
create mode 100644 generators/cloud-init.go
create mode 100644 generators/cloud-init_test.go
diff --git a/generators/cloud-init.go b/generators/cloud-init.go
new file mode 100644
index 0000000..2078afc
--- /dev/null
+++ b/generators/cloud-init.go
@@ -0,0 +1,108 @@
+package generators
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/lxc/lxd/shared/api"
+
+ "github.com/lxc/distrobuilder/image"
+ "github.com/lxc/distrobuilder/shared"
+)
+
+// CloudInitGenerator represents the cloud-init generator.
+type CloudInitGenerator struct{}
+
+// RunLXC does nothing.
+func (g CloudInitGenerator) RunLXC(cacheDir, sourceDir string, img *image.LXCImage,
+ defFile shared.DefinitionFile) error {
+ // no cloud-init support for LXC, ignoring generator
+ return nil
+}
+
+// RunLXD creates cloud-init template files.
+func (g CloudInitGenerator) RunLXD(cacheDir, sourceDir string, img *image.LXDImage,
+ defFile shared.DefinitionFile) error {
+ templateDir := filepath.Join(cacheDir, "templates")
+
+ err := os.MkdirAll(templateDir, 0755)
+ if err != nil {
+ return err
+ }
+
+ var content string
+ properties := make(map[string]string)
+
+ switch defFile.Name {
+ case "user-data":
+ content = `{{ config_get("user.user-data", properties.default) }}
+`
+ properties["default"] = `#cloud-config
+{}`
+ case "meta-data":
+ content = `instance-id: {{ container.name }}
+local-hostname: {{ container.name }}
+{{ config_get("user.meta-data", "") }}
+`
+ case "vendor-data":
+ content = `{{ config_get("user.vendor-data", properties.default) }}
+`
+ properties["default"] = `#cloud-config
+{}`
+ case "network-config":
+ content = `{% if config_get("user.network-config", "") == "" %}version: 1
+config:
+ - type: physical
+ name: eth0
+ subnets:
+ - type: {% if config_get("user.network_mode", "") == "link-local" %}manual{% else %}dhcp{% endif %}
+ control: auto{% else %}{{ config_get("user.network-config", "") }}{% endif %}
+`
+ default:
+ return fmt.Errorf("Unknown cloud-init configuration: %s", defFile.Name)
+ }
+
+ template := fmt.Sprintf("cloud-init-%s.tpl", defFile.Name)
+
+ file, err := os.Create(filepath.Join(templateDir, template))
+ if err != nil {
+ return err
+ }
+
+ defer file.Close()
+
+ if defFile.Content != "" {
+ content = defFile.Content
+ }
+
+ // Append final new line if missing
+ if !strings.HasSuffix(content, "\n") {
+ content += "\n"
+ }
+
+ _, err = file.WriteString(content)
+ if err != nil {
+ return fmt.Errorf("Failed to write to content to %s template: %s", defFile.Name, err)
+ }
+
+ if len(defFile.Template.Properties) > 0 {
+ properties = defFile.Template.Properties
+ }
+
+ // Add to LXD templates
+ img.Metadata.Templates[filepath.Join("/var/lib/cloud/seed/nocloud-net", defFile.Name)] = &api.ImageMetadataTemplate{
+ Template: template,
+ Properties: properties,
+ When: []string{"create", "copy"},
+ }
+
+ return err
+}
+
+// Run does nothing.
+func (g CloudInitGenerator) Run(cacheDir, sourceDir string,
+ defFile shared.DefinitionFile) error {
+ return nil
+}
diff --git a/generators/cloud-init_test.go b/generators/cloud-init_test.go
new file mode 100644
index 0000000..c6b341f
--- /dev/null
+++ b/generators/cloud-init_test.go
@@ -0,0 +1,97 @@
+package generators
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/lxc/distrobuilder/image"
+ "github.com/lxc/distrobuilder/shared"
+ "github.com/stretchr/testify/require"
+)
+
+func TestCloudInitGeneratorRunLXD(t *testing.T) {
+
+ cacheDir := filepath.Join(os.TempDir(), "distrobuilder-test")
+ rootfsDir := filepath.Join(cacheDir, "rootfs")
+
+ setup(t, cacheDir)
+ defer teardown(cacheDir)
+
+ generator := Get("cloud-init")
+ require.Equal(t, CloudInitGenerator{}, generator)
+
+ definition := shared.Definition{
+ Image: shared.DefinitionImage{
+ Distribution: "ubuntu",
+ Release: "artful",
+ },
+ }
+
+ image := image.NewLXDImage(cacheDir, "", cacheDir, definition)
+
+ tests := []struct {
+ name string
+ expected string
+ shouldFail bool
+ }{
+ {
+ "user-data",
+ `{{ config_get("user.user-data", properties.default) }}
+`,
+ false,
+ },
+ {
+ "meta-data",
+ `instance-id: {{ container.name }}
+local-hostname: {{ container.name }}
+{{ config_get("user.meta-data", "") }}
+`,
+ false,
+ },
+ {
+ "vendor-data",
+ `{{ config_get("user.vendor-data", properties.default) }}
+`,
+ false,
+ },
+ {
+ "network-config",
+ `{% if config_get("user.network-config", "") == "" %}version: 1
+config:
+ - type: physical
+ name: eth0
+ subnets:
+ - type: {% if config_get("user.network_mode", "") == "link-local" %}manual{% else %}dhcp{% endif %}
+ control: auto{% else %}{{ config_get("user.network-config", "") }}{% endif %}
+`,
+ false,
+ },
+ {
+ "foo",
+ "Unknown cloud-init configuration: foo",
+ true,
+ },
+ }
+
+ for i, tt := range tests {
+ log.Printf("Running test #%d: %s", i, tt.name)
+
+ err := generator.RunLXD(cacheDir, rootfsDir, image, shared.DefinitionFile{
+ Generator: "cloud-init",
+ Name: tt.name,
+ })
+
+ if !tt.shouldFail {
+ require.NoError(t, err)
+ } else {
+ require.Regexp(t, tt.expected, err)
+ continue
+ }
+
+ validateTestFile(t, filepath.Join(cacheDir, "templates", fmt.Sprintf("cloud-init-%s.tpl", tt.name)), tt.expected)
+ }
+
+}
diff --git a/generators/generators.go b/generators/generators.go
index 12b6dd3..f4f1ef6 100644
--- a/generators/generators.go
+++ b/generators/generators.go
@@ -33,6 +33,8 @@ func Get(generator string) Generator {
return TemplateGenerator{}
case "upstart-tty":
return UpstartTTYGenerator{}
+ case "cloud-init":
+ return CloudInitGenerator{}
}
return nil
diff --git a/shared/definition.go b/shared/definition.go
index 9f666ca..21463d0 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -319,6 +319,7 @@ func (d *Definition) Validate() error {
"hosts",
"remove",
"upstart-tty",
+ "cloud-init",
}
for _, file := range d.Files {
From 1628a20d66b1edac70774063ffb971a974853111 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Tue, 9 Jul 2019 22:26:41 +0200
Subject: [PATCH 2/2] doc: Use cloud-init generator in Debian example
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
doc/examples/debian-cloud-init | 65 ++++++----------------------------
1 file changed, 11 insertions(+), 54 deletions(-)
diff --git a/doc/examples/debian-cloud-init b/doc/examples/debian-cloud-init
index 1fc56e6..15f3431 100644
--- a/doc/examples/debian-cloud-init
+++ b/doc/examples/debian-cloud-init
@@ -72,60 +72,17 @@ files:
auto eth0
iface eth0 inet dhcp
- - name: cloud-init-meta
- path: /var/lib/cloud/seed/nocloud-net/meta-data
- generator: template
- template:
- when:
- - create
- - copy
- content: |
- #cloud-config
- instance-id: {{ container.name }}
- local-hostname: {{ container.name }}
- {{ config_get("user.meta-data", "") }}
-
- - name: cloud-init-network
- path: /var/lib/cloud/seed/nocloud-net/network-config
- generator: template
- template:
- when:
- - create
- - copy
- content: |
- {% if config_get("user.network-config", "") == "" %}version: 1
- config:
- - type: physical
- name: eth0
- subnets:
- - type: {% if config_get("user.network_mode", "") == "link-local" %}manual{% else %}dhcp{% endif %}
- control: auto{% else %}{{ config_get("user.network-config", "") }}{% endif %}
-
- - name: cloud-init-user-data
- path: /var/lib/cloud/seed/nocloud-net/user-data
- generator: template
- content: '{{ config_get("user.user-data", properties.default) }}'
- template:
- properties:
- default: |
- #cloud-config
- {}
- when:
- - create
- - copy
-
- - name: cloud-init-vedor-data
- path: /var/lib/cloud/seed/nocloud-net/vendor-data
- generator: template
- content: '{{ config_get("user.vendor-data", properties.default) }}'
- template:
- properties:
- default: |
- #cloud-config
- {}
- when:
- - create
- - copy
+ - name: meta-data
+ generator: cloud-init
+
+ - name: network-config
+ generator: cloud-init
+
+ - name: user-data
+ generator: cloud-init
+
+ - name: vendor-data
+ generator: cloud-init
packages:
manager: apt
More information about the lxc-devel
mailing list