Repository: lxc/distrobuilder (go)

Issue:
Using variables/definitions under files section
Hi,
I am trying to use `image.variant` in the file generators, i don't know what the expected behavior is for this usecase.
I have some examples, with the results that I expect to happen and what actually happens

Variant is the explanations is `Test`  by  adding `-o image.variant=Test` to the distorbuilder command

### Example 1:
Set content of `dump` generator
**Config:**
```
- path: /CurrentVariant
  generator: dump
  content: |-
    MyVariant: {{ image.variant }}
```
**Expected result:**
Filename:  /CurrentVariant
Content: `MyVariant: Test`

**Actual result:**
Filename:  /CurrentVariant
Content: `MyVariant: {{ image.variant }}`

### Example 2:
Set File path for all generators (tested on `dump` and `copy`)
**Config:**
```
- path: /{{ image.variant }}
  generator: dump
  content: |-
    Hello
```
**Expected result:**
Filename:  /Test
Content: `Hello` 

**Actual result:**
Filename:  /{{ image.variant }}
Content: `Hello` 

### Example 3:
Set source of `copy` generator
**Config:** 
```
- path: /root/readme
  generator: copy
  source: CT-files/{{ image.variant }}/Readme
```
**Expected result:** 
Filename:  /root/readme
Content:  Those the file stored in CT-Files/Test/Readme (On the build host)

**Actual result:**
A error when building the image
```
Error: Failed to run generator "copy": Failed to read directory "CT-files/{{ image.variant }}": open CT-files/{{ image.variant }}: no such file or directory
```

Pull request:
Extend templating support
This extends templating support to all generators. Source, Path,
and Content can be templated.

This resolves #550.

Note: This breaks backward compatability as some yaml keys are
renamed. That is because pongo2 doesn't support hyphens in key
names.


Patch:
diff --git a/distrobuilder/main_build-dir.go b/distrobuilder/main_build-dir.go
index 3dac286..459b225 100644
--- a/distrobuilder/main_build-dir.go
+++ b/distrobuilder/main_build-dir.go
@@ -27,7 +27,7 @@ func (c *cmdBuildDir) command() *cobra.Command {
 					continue
 				}
 
-				generator, err := generators.Load(file.Generator, c.global.logger, c.global.flagCacheDir, c.global.targetDir, file)
+				generator, err := generators.Load(file.Generator, c.global.logger, c.global.flagCacheDir, c.global.targetDir, file, *c.global.definition)
 				if err != nil {
 					return fmt.Errorf("Failed to load generator %q: %w", file.Generator, err)
 				}
diff --git a/distrobuilder/main_lxc.go b/distrobuilder/main_lxc.go
index 2a9d934..ef16977 100644
--- a/distrobuilder/main_lxc.go
+++ b/distrobuilder/main_lxc.go
@@ -156,7 +156,7 @@ func (c *cmdLXC) run(cmd *cobra.Command, args []string, overlayDir string) error
 			continue
 		}
 
-		generator, err := generators.Load(file.Generator, c.global.logger, c.global.flagCacheDir, overlayDir, file)
+		generator, err := generators.Load(file.Generator, c.global.logger, c.global.flagCacheDir, overlayDir, file, *c.global.definition)
 		if err != nil {
 			return fmt.Errorf("Failed to load generator %q: %w", file.Generator, err)
 		}
diff --git a/distrobuilder/main_lxd.go b/distrobuilder/main_lxd.go
index 274c696..ca341c7 100644
--- a/distrobuilder/main_lxd.go
+++ b/distrobuilder/main_lxd.go
@@ -225,7 +225,7 @@ func (c *cmdLXD) run(cmd *cobra.Command, args []string, overlayDir string) error
 			continue
 		}
 
-		generator, err := generators.Load(file.Generator, c.global.logger, c.global.flagCacheDir, overlayDir, file)
+		generator, err := generators.Load(file.Generator, c.global.logger, c.global.flagCacheDir, overlayDir, file, *c.global.definition)
 		if err != nil {
 			return fmt.Errorf("Failed to load generator %q: %w", file.Generator, err)
 		}
diff --git a/doc/packages.md b/doc/packages.md
index 679c0a1..91e83c1 100644
--- a/doc/packages.md
+++ b/doc/packages.md
@@ -50,7 +50,7 @@ This is useful if the desired package manager is not supported by distrobuilder.
 
 ```yaml
 packages:
-    custom-manager: # required
+    custom_manager: # required
         clean: # required
             cmd: <string>
             flags: <array>
diff --git a/doc/targets.md b/doc/targets.md
index 722ef84..fc6be94 100644
--- a/doc/targets.md
+++ b/doc/targets.md
@@ -5,7 +5,7 @@ The target section is for target dependent files.
 ```yaml
 targets:
     lxc:
-        create-message: <string>
+        create_message: <string>
         config:
             - type: <string>
               before: <uint>
@@ -20,7 +20,7 @@ targets:
 
 ## LXC
 
-The `create-message` field is a string which is displayed after new LXC container has been created.
+The `create_message` field is a string which is displayed after new LXC container has been created.
 This string is rendered using pongo2 and can include various fields from the definition file, e.g. `{{ image.description }}`.
 
 `config` is a list of container config options.
diff --git a/generators/cloud-init.go b/generators/cloud-init.go
index 44bc1f9..7a25786 100644
--- a/generators/cloud-init.go
+++ b/generators/cloud-init.go
@@ -7,7 +7,6 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/flosch/pongo2"
 	lxd "github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/api"
 
@@ -154,18 +153,6 @@ config:
 		content += "\n"
 	}
 
-	if g.defFile.Pongo {
-		tpl, err := pongo2.FromString(content)
-		if err != nil {
-			return fmt.Errorf("Failed to parse template: %w", err)
-		}
-
-		content, err = tpl.Execute(pongo2.Context{"lxd": target})
-		if err != nil {
-			return fmt.Errorf("Failed to execute template: %w", err)
-		}
-	}
-
 	_, err = file.WriteString(content)
 	if err != nil {
 		return fmt.Errorf("Failed to write to content to %s template: %w", g.defFile.Name, err)
diff --git a/generators/common.go b/generators/common.go
index e39868c..a108db9 100644
--- a/generators/common.go
+++ b/generators/common.go
@@ -13,9 +13,29 @@ type common struct {
 	defFile   shared.DefinitionFile
 }
 
-func (g *common) init(logger *zap.SugaredLogger, cacheDir string, sourceDir string, defFile shared.DefinitionFile) {
+func (g *common) init(logger *zap.SugaredLogger, cacheDir string, sourceDir string, defFile shared.DefinitionFile, def shared.Definition) {
 	g.logger = logger
 	g.cacheDir = cacheDir
 	g.sourceDir = sourceDir
 	g.defFile = defFile
+
+	render := func(val string) string {
+		if !defFile.Pongo {
+			return val
+		}
+
+		out, err := shared.RenderTemplate(val, def)
+		if err != nil {
+			logger.Warnw("Failed to render template", "err", err)
+			return val
+		}
+
+		return out
+	}
+
+	if defFile.Pongo {
+		g.defFile.Content = render(g.defFile.Content)
+		g.defFile.Path = render(g.defFile.Path)
+		g.defFile.Source = render(g.defFile.Source)
+	}
 }
diff --git a/generators/dump.go b/generators/dump.go
index 937fd1a..c54a1e4 100644
--- a/generators/dump.go
+++ b/generators/dump.go
@@ -6,8 +6,6 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/flosch/pongo2"
-
 	"github.com/lxc/distrobuilder/image"
 	"github.com/lxc/distrobuilder/shared"
 )
@@ -20,18 +18,6 @@ type dump struct {
 func (g *dump) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLXC) error {
 	content := g.defFile.Content
 
-	if g.defFile.Pongo {
-		tpl, err := pongo2.FromString(g.defFile.Content)
-		if err != nil {
-			return fmt.Errorf("Failed to parse template: %w", err)
-		}
-
-		content, err = tpl.Execute(pongo2.Context{"lxc": target})
-		if err != nil {
-			return fmt.Errorf("Failed to execute template: %w", err)
-		}
-	}
-
 	err := g.run(content)
 	if err != nil {
 		return fmt.Errorf("Failed to dump content: %w", err)
@@ -51,18 +37,6 @@ func (g *dump) RunLXC(img *image.LXCImage, target shared.DefinitionTargetLXC) er
 func (g *dump) RunLXD(img *image.LXDImage, target shared.DefinitionTargetLXD) error {
 	content := g.defFile.Content
 
-	if g.defFile.Pongo {
-		tpl, err := pongo2.FromString(g.defFile.Content)
-		if err != nil {
-			return fmt.Errorf("Failed to parse template: %w", err)
-		}
-
-		content, err = tpl.Execute(pongo2.Context{"lxd": target})
-		if err != nil {
-			return fmt.Errorf("Failed to execute template: %w", err)
-		}
-	}
-
 	return g.run(content)
 }
 
diff --git a/generators/generators.go b/generators/generators.go
index 0e71481..66f0ebb 100644
--- a/generators/generators.go
+++ b/generators/generators.go
@@ -15,7 +15,7 @@ var ErrNotSupported = errors.New("Not supported")
 var ErrUnknownGenerator = errors.New("Unknown generator")
 
 type generator interface {
-	init(logger *zap.SugaredLogger, cacheDir string, sourceDir string, defFile shared.DefinitionFile)
+	init(logger *zap.SugaredLogger, cacheDir string, sourceDir string, defFile shared.DefinitionFile, def shared.Definition)
 
 	Generator
 }
@@ -40,7 +40,7 @@ var generators = map[string]func() generator{
 }
 
 // Load loads and initializes a generator.
-func Load(generatorName string, logger *zap.SugaredLogger, cacheDir string, sourceDir string, defFile shared.DefinitionFile) (Generator, error) {
+func Load(generatorName string, logger *zap.SugaredLogger, cacheDir string, sourceDir string, defFile shared.DefinitionFile, def shared.Definition) (Generator, error) {
 	df, ok := generators[generatorName]
 	if !ok {
 		return nil, ErrUnknownGenerator
@@ -48,7 +48,7 @@ func Load(generatorName string, logger *zap.SugaredLogger, cacheDir string, sour
 
 	d := df()
 
-	d.init(logger, cacheDir, sourceDir, defFile)
+	d.init(logger, cacheDir, sourceDir, defFile, def)
 
 	return d, nil
 }
diff --git a/shared/definition.go b/shared/definition.go
index fab7b52..210e26d 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -103,7 +103,7 @@ type DefinitionPackagesCustomManager struct {
 // A DefinitionPackages represents a package handler.
 type DefinitionPackages struct {
 	Manager       string                           `yaml:"manager,omitempty"`
-	CustomManager *DefinitionPackagesCustomManager `yaml:"custom-manager,omitempty"`
+	CustomManager *DefinitionPackagesCustomManager `yaml:"custom_manager,omitempty"`
 	Update        bool                             `yaml:"update,omitempty"`
 	Cleanup       bool                             `yaml:"cleanup,omitempty"`
 	Sets          []DefinitionPackagesSet          `yaml:"sets,omitempty"`
@@ -149,7 +149,7 @@ type DefinitionTargetLXCConfig struct {
 
 // A DefinitionTargetLXC represents LXC specific files as part of the metadata.
 type DefinitionTargetLXC struct {
-	CreateMessage string                      `yaml:"create-message,omitempty"`
+	CreateMessage string                      `yaml:"create_message,omitempty"`
 	Config        []DefinitionTargetLXCConfig `yaml:"config,omitempty"`
 }
 
@@ -367,31 +367,31 @@ func (d *Definition) Validate() error {
 		}
 
 		if d.Packages.CustomManager != nil {
-			return errors.New("cannot have both packages.manager and packages.custom-manager set")
+			return errors.New("cannot have both packages.manager and packages.custom_manager set")
 		}
 	} else {
 		if d.Packages.CustomManager == nil {
-			return errors.New("packages.manager or packages.custom-manager needs to be set")
+			return errors.New("packages.manager or packages.custom_manager needs to be set")
 		}
 
 		if d.Packages.CustomManager.Clean.Command == "" {
-			return errors.New("packages.custom-manager requires a clean command")
+			return errors.New("packages.custom_manager requires a clean command")
 		}
 
 		if d.Packages.CustomManager.Install.Command == "" {
-			return errors.New("packages.custom-manager requires an install command")
+			return errors.New("packages.custom_manager requires an install command")
 		}
 
 		if d.Packages.CustomManager.Remove.Command == "" {
-			return errors.New("packages.custom-manager requires a remove command")
+			return errors.New("packages.custom_manager requires a remove command")
 		}
 
 		if d.Packages.CustomManager.Refresh.Command == "" {
-			return errors.New("packages.custom-manager requires a refresh command")
+			return errors.New("packages.custom_manager requires a refresh command")
 		}
 
 		if d.Packages.CustomManager.Update.Command == "" {
-			return errors.New("packages.custom-manager requires an update command")
+			return errors.New("packages.custom_manager requires an update command")
 		}
 	}
 


Test patch:
diff --git a/generators/cloud-init_test.go b/generators/cloud-init_test.go
index cf92766..88e2d6a 100644
--- a/generators/cloud-init_test.go
+++ b/generators/cloud-init_test.go
@@ -21,7 +21,7 @@ func TestCloudInitGeneratorRunLXC(t *testing.T) {
 	setup(t, cacheDir)
 	defer teardown(cacheDir)
 
-	generator, err := Load("cloud-init", nil, cacheDir, rootfsDir, shared.DefinitionFile{})
+	generator, err := Load("cloud-init", nil, cacheDir, rootfsDir, shared.DefinitionFile{}, shared.Definition{})
 	require.IsType(t, &cloudInit{}, generator)
 	require.NoError(t, err)
 
@@ -140,7 +140,7 @@ config:
 		generator, err := Load("cloud-init", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 			Generator: "cloud-init",
 			Name:      tt.name,
-		})
+		}, shared.Definition{})
 		require.IsType(t, &cloudInit{}, generator)
 		require.NoError(t, err)
 
diff --git a/generators/copy_test.go b/generators/copy_test.go
index 90c4b3f..aa4fc7d 100644
--- a/generators/copy_test.go
+++ b/generators/copy_test.go
@@ -22,7 +22,7 @@ func TestCopyGeneratorRun(t *testing.T) {
 	generator, err := Load("copy", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Source: "copy_test",
 		Path:   "copy_test_dir",
-	})
+	}, shared.Definition{})
 	require.IsType(t, &copy{}, generator)
 	require.NoError(t, err)
 
@@ -85,7 +85,7 @@ func TestCopyGeneratorRun(t *testing.T) {
 	generator, err = Load("copy", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Source: "copy_test/src*",
 		Path:   "copy_test_wildcard",
-	})
+	}, shared.Definition{})
 	require.IsType(t, &copy{}, generator)
 	require.NoError(t, err)
 
@@ -126,7 +126,7 @@ func TestCopyGeneratorRun(t *testing.T) {
 	_, err = src1.Seek(0, 0)
 	generator, err = Load("copy", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Source: "copy_test/src1",
-	})
+	}, shared.Definition{})
 	require.IsType(t, &copy{}, generator)
 	require.NoError(t, err)
 
@@ -154,7 +154,7 @@ func TestCopyGeneratorRun(t *testing.T) {
 	generator, err = Load("copy", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Source: "copy_test/src1",
 		Path:   "/hello/world/",
-	})
+	}, shared.Definition{})
 	require.IsType(t, &copy{}, generator)
 	require.NoError(t, err)
 
diff --git a/generators/dump_test.go b/generators/dump_test.go
index b1cf805..946de79 100644
--- a/generators/dump_test.go
+++ b/generators/dump_test.go
@@ -19,11 +19,19 @@ func TestDumpGeneratorRunLXC(t *testing.T) {
 	setup(t, cacheDir)
 	defer teardown(cacheDir)
 
+	def := shared.Definition{
+		Targets: shared.DefinitionTarget{
+			LXC: shared.DefinitionTargetLXC{
+				CreateMessage: "message",
+			},
+		},
+	}
+
 	generator, err := Load("dump", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Path:    "/hello/world",
-		Content: "hello {{ lxc.CreateMessage }}",
+		Content: "hello {{ targets.lxc.create_message }}",
 		Pongo:   true,
-	})
+	}, def)
 	require.IsType(t, &dump{}, generator)
 	require.NoError(t, err)
 
@@ -45,8 +53,8 @@ func TestDumpGeneratorRunLXC(t *testing.T) {
 
 	generator, err = Load("dump", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Path:    "/hello/world",
-		Content: "hello {{ lxc.CreateMessage }}",
-	})
+		Content: "hello {{ targets.lxc.create_message }}",
+	}, def)
 	require.IsType(t, &dump{}, generator)
 	require.NoError(t, err)
 
@@ -64,7 +72,7 @@ func TestDumpGeneratorRunLXC(t *testing.T) {
 	buffer.Reset()
 	io.Copy(&buffer, file)
 
-	require.Equal(t, "hello {{ lxc.CreateMessage }}\n", buffer.String())
+	require.Equal(t, "hello {{ targets.lxc.create_message }}\n", buffer.String())
 }
 
 func TestDumpGeneratorRunLXD(t *testing.T) {
@@ -74,11 +82,21 @@ func TestDumpGeneratorRunLXD(t *testing.T) {
 	setup(t, cacheDir)
 	defer teardown(cacheDir)
 
+	def := shared.Definition{
+		Targets: shared.DefinitionTarget{
+			LXD: shared.DefinitionTargetLXD{
+				VM: shared.DefinitionTargetLXDVM{
+					Filesystem: "ext4",
+				},
+			},
+		},
+	}
+
 	generator, err := Load("dump", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Path:    "/hello/world",
-		Content: "hello {{ lxd.VM.Filesystem }}",
+		Content: "hello {{ targets.lxd.vm.filesystem }}",
 		Pongo:   true,
-	})
+	}, def)
 	require.IsType(t, &dump{}, generator)
 	require.NoError(t, err)
 
@@ -103,8 +121,8 @@ func TestDumpGeneratorRunLXD(t *testing.T) {
 
 	generator, err = Load("dump", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Path:    "/hello/world",
-		Content: "hello {{ lxd.VM.Filesystem }}",
-	})
+		Content: "hello {{ targets.lxd.vm.filesystem }}",
+	}, def)
 	require.IsType(t, &dump{}, generator)
 	require.NoError(t, err)
 
@@ -123,5 +141,5 @@ func TestDumpGeneratorRunLXD(t *testing.T) {
 	buffer.Reset()
 	io.Copy(&buffer, file)
 
-	require.Equal(t, "hello {{ lxd.VM.Filesystem }}\n", buffer.String())
+	require.Equal(t, "hello {{ targets.lxd.vm.filesystem }}\n", buffer.String())
 }
diff --git a/generators/generators_test.go b/generators/generators_test.go
index 3c4419a..3167692 100644
--- a/generators/generators_test.go
+++ b/generators/generators_test.go
@@ -22,11 +22,11 @@ func teardown(cacheDir string) {
 }
 
 func TestGet(t *testing.T) {
-	generator, err := Load("hostname", nil, "", "", shared.DefinitionFile{})
+	generator, err := Load("hostname", nil, "", "", shared.DefinitionFile{}, shared.Definition{})
 	require.IsType(t, &hostname{}, generator)
 	require.NoError(t, err)
 
-	generator, err = Load("", nil, "", "", shared.DefinitionFile{})
+	generator, err = Load("", nil, "", "", shared.DefinitionFile{}, shared.Definition{})
 	require.Nil(t, generator)
 	require.Error(t, err)
 }
diff --git a/generators/hostname_test.go b/generators/hostname_test.go
index cf10ed3..94cbba3 100644
--- a/generators/hostname_test.go
+++ b/generators/hostname_test.go
@@ -18,7 +18,7 @@ func TestHostnameGeneratorRunLXC(t *testing.T) {
 	setup(t, cacheDir)
 	defer teardown(cacheDir)
 
-	generator, err := Load("hostname", nil, cacheDir, rootfsDir, shared.DefinitionFile{Path: "/etc/hostname"})
+	generator, err := Load("hostname", nil, cacheDir, rootfsDir, shared.DefinitionFile{Path: "/etc/hostname"}, shared.Definition{})
 	require.IsType(t, &hostname{}, generator)
 	require.NoError(t, err)
 
@@ -49,7 +49,7 @@ func TestHostnameGeneratorRunLXD(t *testing.T) {
 	setup(t, cacheDir)
 	defer teardown(cacheDir)
 
-	generator, err := Load("hostname", nil, cacheDir, rootfsDir, shared.DefinitionFile{Path: "/etc/hostname"})
+	generator, err := Load("hostname", nil, cacheDir, rootfsDir, shared.DefinitionFile{Path: "/etc/hostname"}, shared.Definition{})
 	require.IsType(t, &hostname{}, generator)
 	require.NoError(t, err)
 
diff --git a/generators/hosts_test.go b/generators/hosts_test.go
index 4ff5c2f..a2a968c 100644
--- a/generators/hosts_test.go
+++ b/generators/hosts_test.go
@@ -18,7 +18,7 @@ func TestHostsGeneratorRunLXC(t *testing.T) {
 	setup(t, cacheDir)
 	defer teardown(cacheDir)
 
-	generator, err := Load("hosts", nil, cacheDir, rootfsDir, shared.DefinitionFile{Path: "/etc/hosts"})
+	generator, err := Load("hosts", nil, cacheDir, rootfsDir, shared.DefinitionFile{Path: "/etc/hosts"}, shared.Definition{})
 	require.IsType(t, &hosts{}, generator)
 	require.NoError(t, err)
 
@@ -51,7 +51,7 @@ func TestHostsGeneratorRunLXD(t *testing.T) {
 	setup(t, cacheDir)
 	defer teardown(cacheDir)
 
-	generator, err := Load("hosts", nil, cacheDir, rootfsDir, shared.DefinitionFile{Path: "/etc/hosts"})
+	generator, err := Load("hosts", nil, cacheDir, rootfsDir, shared.DefinitionFile{Path: "/etc/hosts"}, shared.Definition{})
 	require.IsType(t, &hosts{}, generator)
 	require.NoError(t, err)
 
diff --git a/generators/template_test.go b/generators/template_test.go
index 34c0fed..09ffd34 100644
--- a/generators/template_test.go
+++ b/generators/template_test.go
@@ -18,22 +18,22 @@ func TestTemplateGeneratorRunLXD(t *testing.T) {
 	setup(t, cacheDir)
 	defer teardown(cacheDir)
 
+	definition := shared.Definition{
+		Image: shared.DefinitionImage{
+			Distribution: "ubuntu",
+			Release:      "artful",
+		},
+	}
+
 	generator, err := Load("template", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Generator: "template",
 		Name:      "template",
 		Content:   "==test==",
 		Path:      "/root/template",
-	})
+	}, definition)
 	require.IsType(t, &template{}, generator)
 	require.NoError(t, err)
 
-	definition := shared.Definition{
-		Image: shared.DefinitionImage{
-			Distribution: "ubuntu",
-			Release:      "artful",
-		},
-	}
-
 	image := image.NewLXDImage(cacheDir, "", cacheDir, definition)
 
 	err = os.MkdirAll(filepath.Join(cacheDir, "rootfs", "root"), 0755)
@@ -55,22 +55,22 @@ func TestTemplateGeneratorRunLXDDefaultWhen(t *testing.T) {
 	setup(t, cacheDir)
 	defer teardown(cacheDir)
 
+	definition := shared.Definition{
+		Image: shared.DefinitionImage{
+			Distribution: "ubuntu",
+			Release:      "artful",
+		},
+	}
+
 	generator, err := Load("template", nil, cacheDir, rootfsDir, shared.DefinitionFile{
 		Generator: "template",
 		Name:      "test-default-when",
 		Content:   "==test==",
 		Path:      "test-default-when",
-	})
+	}, definition)
 	require.IsType(t, &template{}, generator)
 	require.NoError(t, err)
 
-	definition := shared.Definition{
-		Image: shared.DefinitionImage{
-			Distribution: "ubuntu",
-			Release:      "artful",
-		},
-	}
-
 	image := image.NewLXDImage(cacheDir, "", cacheDir, definition)
 
 	err = generator.RunLXD(image, shared.DefinitionTargetLXD{})
@@ -84,7 +84,7 @@ func TestTemplateGeneratorRunLXDDefaultWhen(t *testing.T) {
 		Template: shared.DefinitionFileTemplate{
 			When: []string{"create"},
 		},
-	})
+	}, definition)
 	require.IsType(t, &template{}, generator)
 	require.NoError(t, err)
 
diff --git a/shared/definition_test.go b/shared/definition_test.go
index fabfebf..549d4c1 100644
--- a/shared/definition_test.go
+++ b/shared/definition_test.go
@@ -90,7 +90,7 @@ func TestValidateDefinition(t *testing.T) {
 			false,
 		},
 		{
-			"valid Defintion with packages.custom-manager",
+			"valid Defintion with packages.custom_manager",
 			Definition{
 				Image: DefinitionImage{
 					Distribution: "ubuntu",
@@ -213,7 +213,7 @@ func TestValidateDefinition(t *testing.T) {
 			true,
 		},
 		{
-			"missing clean command in packages.custom-manager",
+			"missing clean command in packages.custom_manager",
 			Definition{
 				Image: DefinitionImage{
 					Distribution: "ubuntu",
@@ -228,11 +228,11 @@ func TestValidateDefinition(t *testing.T) {
 					CustomManager: &DefinitionPackagesCustomManager{},
 				},
 			},
-			"packages.custom-manager requires a clean command",
+			"packages.custom_manager requires a clean command",
 			true,
 		},
 		{
-			"missing install command in packages.custom-manager",
+			"missing install command in packages.custom_manager",
 			Definition{
 				Image: DefinitionImage{
 					Distribution: "ubuntu",
@@ -251,11 +251,11 @@ func TestValidateDefinition(t *testing.T) {
 					},
 				},
 			},
-			"packages.custom-manager requires an install command",
+			"packages.custom_manager requires an install command",
 			true,
 		},
 		{
-			"missing remove command in packages.custom-manager",
+			"missing remove command in packages.custom_manager",
 			Definition{
 				Image: DefinitionImage{
 					Distribution: "ubuntu",
@@ -277,11 +277,11 @@ func TestValidateDefinition(t *testing.T) {
 					},
 				},
 			},
-			"packages.custom-manager requires a remove command",
+			"packages.custom_manager requires a remove command",
 			true,
 		},
 		{
-			"missing refresh command in packages.custom-manager",
+			"missing refresh command in packages.custom_manager",
 			Definition{
 				Image: DefinitionImage{
 					Distribution: "ubuntu",
@@ -306,11 +306,11 @@ func TestValidateDefinition(t *testing.T) {
 					},
 				},
 			},
-			"packages.custom-manager requires a refresh command",
+			"packages.custom_manager requires a refresh command",
 			true,
 		},
 		{
-			"missing update command in packages.custom-manager",
+			"missing update command in packages.custom_manager",
 			Definition{
 				Image: DefinitionImage{
 					Distribution: "ubuntu",
@@ -338,11 +338,11 @@ func TestValidateDefinition(t *testing.T) {
 					},
 				},
 			},
-			"packages.custom-manager requires an update command",
+			"packages.custom_manager requires an update command",
 			true,
 		},
 		{
-			"package.manager and package.custom-manager set",
+			"package.manager and package.custom_manager set",
 			Definition{
 				Image: DefinitionImage{
 					Distribution: "ubuntu",
@@ -358,11 +358,11 @@ func TestValidateDefinition(t *testing.T) {
 					CustomManager: &DefinitionPackagesCustomManager{},
 				},
 			},
-			"cannot have both packages.manager and packages.custom-manager set",
+			"cannot have both packages.manager and packages.custom_manager set",
 			true,
 		},
 		{
-			"package.manager and package.custom-manager unset",
+			"package.manager and package.custom_manager unset",
 			Definition{
 				Image: DefinitionImage{
 					Distribution: "ubuntu",
@@ -375,7 +375,7 @@ func TestValidateDefinition(t *testing.T) {
 				},
 				Packages: DefinitionPackages{},
 			},
-			"packages.manager or packages.custom-manager needs to be set",
+			"packages.manager or packages.custom_manager needs to be set",
 			true,
 		},
 		{