[lxc-devel] [distrobuilder/master] Fix file templating

stgraber on Github lxc-bot at linuxcontainers.org
Tue Mar 13 19:40:59 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/20180313/31277830/attachment.bin>
-------------- next part --------------
From 32dc1ab397a8f25c8f6d6f146aeb9adfb3aad7ed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 13 Mar 2018 13:00:22 -0400
Subject: [PATCH 1/8] Rename Arch to Architecture
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 README.md                 | 2 +-
 distrobuilder/main.go     | 8 ++++----
 image/lxc_test.go         | 4 ++--
 image/lxd.go              | 8 ++++----
 image/lxd_test.go         | 4 ++--
 shared/definition.go      | 6 +++---
 shared/definition_test.go | 4 ++--
 7 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/README.md b/README.md
index 7b75d22..3ad4925 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ image:
   variant: default # optional
   description: Ubuntu Artful # optional
   expiry: 30d # optional: defaults to 30d
-  arch: x86_64 # optional: defaults to local architecture
+  architecture: x86_64 # optional: defaults to local architecture
 
 source:
   downloader: ubuntu-http
diff --git a/distrobuilder/main.go b/distrobuilder/main.go
index cae2fa8..8cc5fd8 100644
--- a/distrobuilder/main.go
+++ b/distrobuilder/main.go
@@ -294,21 +294,21 @@ func getMappedArchitecture(def *shared.Definition) (string, error) {
 	if def.Mappings.ArchitectureMap != "" {
 		// Translate the architecture using the requested map
 		var err error
-		arch, err = shared.GetArch(def.Mappings.ArchitectureMap, def.Image.Arch)
+		arch, err = shared.GetArch(def.Mappings.ArchitectureMap, def.Image.Architecture)
 		if err != nil {
 			return "", fmt.Errorf("Failed to translate the architecture name: %s", err)
 		}
 	} else if len(def.Mappings.Architectures) > 0 {
 		// Translate the architecture using a user specified mapping
 		var ok bool
-		arch, ok = def.Mappings.Architectures[def.Image.Arch]
+		arch, ok = def.Mappings.Architectures[def.Image.Architecture]
 		if !ok {
 			// If no mapping exists, it means it doesn't need translating
-			arch = def.Image.Arch
+			arch = def.Image.Architecture
 		}
 	} else {
 		// No map or mappings provided, just go with it as it is
-		arch = def.Image.Arch
+		arch = def.Image.Architecture
 	}
 
 	return arch, nil
diff --git a/image/lxc_test.go b/image/lxc_test.go
index 93de24f..41180d6 100644
--- a/image/lxc_test.go
+++ b/image/lxc_test.go
@@ -18,9 +18,9 @@ var lxcImageDef = shared.DefinitionImage{
 	Description:  "{{ image. Distribution|capfirst }} {{ image.Release }}",
 	Distribution: "ubuntu",
 	Release:      "17.10",
-	Arch:         "amd64",
+	Architecture: "amd64",
 	Expiry:       "30d",
-	Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ image.Arch }}-{{ creation_date }}",
+	Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ image.Architecture }}-{{ creation_date }}",
 }
 
 var lxcTarget = shared.DefinitionTargetLXC{
diff --git a/image/lxd.go b/image/lxd.go
index 56b5054..31d5a72 100644
--- a/image/lxd.go
+++ b/image/lxd.go
@@ -123,7 +123,7 @@ func (l *LXDImage) createMetadata() error {
 	var err error
 
 	// Get the arch ID of the provided architecture.
-	ID, err := osarch.ArchitectureId(l.definition.Arch)
+	ID, err := osarch.ArchitectureId(l.definition.Architecture)
 	if err != nil {
 		return err
 	}
@@ -135,11 +135,11 @@ func (l *LXDImage) createMetadata() error {
 	}
 
 	// Use proper architecture name from now on.
-	l.definition.Arch = arch
+	l.definition.Architecture = arch
 
-	l.Metadata.Architecture = l.definition.Arch
+	l.Metadata.Architecture = l.definition.Architecture
 	l.Metadata.CreationDate = l.creationDate.Unix()
-	l.Metadata.Properties["architecture"] = l.definition.Arch
+	l.Metadata.Properties["architecture"] = l.definition.Architecture
 	l.Metadata.Properties["os"] = l.definition.Distribution
 	l.Metadata.Properties["release"] = l.definition.Release
 
diff --git a/image/lxd_test.go b/image/lxd_test.go
index 04f6caa..9789a06 100644
--- a/image/lxd_test.go
+++ b/image/lxd_test.go
@@ -19,9 +19,9 @@ var lxdImageDef = shared.DefinitionImage{
 	Description:  "{{ image. Distribution|capfirst }} {{ image.Release }}",
 	Distribution: "ubuntu",
 	Release:      "17.10",
-	Arch:         "amd64",
+	Architecture: "amd64",
 	Expiry:       "30d",
-	Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ image.Arch }}-{{ creation_date }}",
+	Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ image.Architecture }}-{{ creation_date }}",
 }
 
 func setupLXD(t *testing.T) *LXDImage {
diff --git a/shared/definition.go b/shared/definition.go
index 00e1a1b..c555e12 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -23,7 +23,7 @@ type DefinitionImage struct {
 	Description  string `yaml:"description"`
 	Distribution string `yaml:"distribution"`
 	Release      string `yaml:"release,omitempty"`
-	Arch         string `yaml:"arch,omitempty"`
+	Architecture string `yaml:"arch,omitempty"`
 	Expiry       string `yaml:"expiry,omitempty"`
 	Variant      string `yaml:"variant,omitempty"`
 	Name         string `yaml:"name,omitempty"`
@@ -95,8 +95,8 @@ type Definition struct {
 // SetDefinitionDefaults sets some default values for the given Definition.
 func SetDefinitionDefaults(def *Definition) {
 	// default to local arch
-	if def.Image.Arch == "" {
-		def.Image.Arch = runtime.GOARCH
+	if def.Image.Architecture == "" {
+		def.Image.Architecture = runtime.GOARCH
 	}
 
 	// set default expiry of 30 days
diff --git a/shared/definition_test.go b/shared/definition_test.go
index 1686aed..dfbd93d 100644
--- a/shared/definition_test.go
+++ b/shared/definition_test.go
@@ -12,8 +12,8 @@ func TestSetDefinitionDefaults(t *testing.T) {
 
 	SetDefinitionDefaults(&def)
 
-	if def.Image.Arch != runtime.GOARCH {
-		t.Fatalf("Expected image.arch to be '%s', got '%s'", runtime.GOARCH, def.Image.Arch)
+	if def.Image.Architecture != runtime.GOARCH {
+		t.Fatalf("Expected image.arch to be '%s', got '%s'", runtime.GOARCH, def.Image.Architecture)
 	}
 
 	if def.Image.Expiry != "30d" {

From e20b1fbe198d9dc5856a1fc8c82956db8230d532 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 13 Mar 2018 13:23:55 -0400
Subject: [PATCH 2/8] Set variant as LXD image property
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 image/lxd.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/image/lxd.go b/image/lxd.go
index 31d5a72..7ec2bc9 100644
--- a/image/lxd.go
+++ b/image/lxd.go
@@ -99,7 +99,6 @@ func (l *LXDImage) Build(unified bool, compression string) error {
 		if err != nil {
 			return err
 		}
-
 	} else {
 		// Create rootfs as squashfs.
 		err = shared.RunCommand("mksquashfs", l.sourceDir,
@@ -142,6 +141,7 @@ func (l *LXDImage) createMetadata() error {
 	l.Metadata.Properties["architecture"] = l.definition.Architecture
 	l.Metadata.Properties["os"] = l.definition.Distribution
 	l.Metadata.Properties["release"] = l.definition.Release
+	l.Metadata.Properties["variant"] = l.definition.Variant
 
 	ctx := pongo2.Context{
 		"image":         l.definition,

From 6da67fa5749bd5a938c8b68e31372e56c38f209e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 13 Mar 2018 14:03:35 -0400
Subject: [PATCH 3/8] Add serial to LXD metadata
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 image/lxd.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/image/lxd.go b/image/lxd.go
index 7ec2bc9..4ebdbb9 100644
--- a/image/lxd.go
+++ b/image/lxd.go
@@ -142,6 +142,7 @@ func (l *LXDImage) createMetadata() error {
 	l.Metadata.Properties["os"] = l.definition.Distribution
 	l.Metadata.Properties["release"] = l.definition.Release
 	l.Metadata.Properties["variant"] = l.definition.Variant
+	l.Metadata.Properties["serial"] = l.creationDate.Format("20060201_1504")
 
 	ctx := pongo2.Context{
 		"image":         l.definition,

From 617f4d4e5f87f357cb61e4251a7a9f779a3f3ab3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 13 Mar 2018 14:04:13 -0400
Subject: [PATCH 4/8] definition: Add missing comment
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/definition.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/shared/definition.go b/shared/definition.go
index c555e12..16d5b95 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -109,6 +109,7 @@ func SetDefinitionDefaults(def *Definition) {
 		def.Image.Variant = "default"
 	}
 
+	// Set default keyserver
 	if def.Source.Keyserver == "" {
 		def.Source.Keyserver = "hkps.pool.sks-keyservers.net"
 	}

From 5a7b54d18827b8175dae6591c16eb328abb3e69c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 13 Mar 2018 14:06:18 -0400
Subject: [PATCH 5/8] definition: Set default templates
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/definition.go | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/shared/definition.go b/shared/definition.go
index 16d5b95..6756df1 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -113,6 +113,15 @@ func SetDefinitionDefaults(def *Definition) {
 	if def.Source.Keyserver == "" {
 		def.Source.Keyserver = "hkps.pool.sks-keyservers.net"
 	}
+
+	// Set default name and description templates
+	if def.Image.Name == "" {
+		def.Image.Name = "{{ image.Distribution }}-{{ image.Release }}-{{ image.Architecture }}-{{ image.Variant }}-{{ creation_date }}"
+	}
+
+	if def.Image.Description == "" {
+		def.Image.Description = "{{ image.Distribution|capfirst }} {{ image.Release }} {{ image.Architecture }}{% if image.Variant != \"default\" %} ({{ image.Variant }}){% endif %} ({{ creation_date }})"
+	}
 }
 
 // ValidateDefinition validates the given Definition.

From 5f5f48a40f283ceae2e38dd5571cb82f1324145a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 13 Mar 2018 14:25:53 -0400
Subject: [PATCH 6/8] definition: Make the serial a first class variable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 image/lxc_test.go    |  4 ++--
 image/lxd.go         | 24 ++++++++++--------------
 image/lxd_test.go    | 25 ++++++-------------------
 shared/definition.go | 11 +++++++++--
 4 files changed, 27 insertions(+), 37 deletions(-)

diff --git a/image/lxc_test.go b/image/lxc_test.go
index 41180d6..b2fe043 100644
--- a/image/lxc_test.go
+++ b/image/lxc_test.go
@@ -20,7 +20,7 @@ var lxcImageDef = shared.DefinitionImage{
 	Release:      "17.10",
 	Architecture: "amd64",
 	Expiry:       "30d",
-	Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ image.Architecture }}-{{ creation_date }}",
+	Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ image.Architecture }}-{{ image.Serial }}",
 }
 
 var lxcTarget = shared.DefinitionTargetLXC{
@@ -231,7 +231,7 @@ func TestLXCCreateMetadataBasic(t *testing.T) {
 		err := image.createMetadata()
 		if tt.shouldFail {
 			if err == nil {
-				t.Fatal("Expected to fail, but didn't")
+				t.Fatalf("Expected to fail, but didn't: %s", tt.name)
 			}
 
 			match, _ := regexp.MatchString(tt.expectedError, err.Error())
diff --git a/image/lxd.go b/image/lxd.go
index 4ebdbb9..151d607 100644
--- a/image/lxd.go
+++ b/image/lxd.go
@@ -16,12 +16,11 @@ import (
 
 // A LXDImage represents a LXD image.
 type LXDImage struct {
-	sourceDir    string
-	targetDir    string
-	cacheDir     string
-	creationDate time.Time
-	Metadata     api.ImageMetadata
-	definition   shared.DefinitionImage
+	sourceDir  string
+	targetDir  string
+	cacheDir   string
+	Metadata   api.ImageMetadata
+	definition shared.DefinitionImage
 }
 
 // NewLXDImage returns a LXDImage.
@@ -31,7 +30,6 @@ func NewLXDImage(sourceDir, targetDir, cacheDir string,
 		sourceDir,
 		targetDir,
 		cacheDir,
-		time.Now(),
 		api.ImageMetadata{
 			Properties: make(map[string]string),
 			Templates:  make(map[string]*api.ImageMetadataTemplate),
@@ -73,8 +71,7 @@ func (l *LXDImage) Build(unified bool, compression string) error {
 
 	if unified {
 		ctx := pongo2.Context{
-			"image":         l.definition,
-			"creation_date": l.creationDate.Format("20060201_1504"),
+			"image": l.definition,
 		}
 
 		var fname string
@@ -137,16 +134,15 @@ func (l *LXDImage) createMetadata() error {
 	l.definition.Architecture = arch
 
 	l.Metadata.Architecture = l.definition.Architecture
-	l.Metadata.CreationDate = l.creationDate.Unix()
+	l.Metadata.CreationDate = time.Now().UTC().Unix()
 	l.Metadata.Properties["architecture"] = l.definition.Architecture
 	l.Metadata.Properties["os"] = l.definition.Distribution
 	l.Metadata.Properties["release"] = l.definition.Release
 	l.Metadata.Properties["variant"] = l.definition.Variant
-	l.Metadata.Properties["serial"] = l.creationDate.Format("20060201_1504")
+	l.Metadata.Properties["serial"] = l.definition.Serial
 
 	ctx := pongo2.Context{
-		"image":         l.definition,
-		"creation_date": l.creationDate.Format("20060201_1504"),
+		"image": l.definition,
 	}
 
 	l.Metadata.Properties["description"], err = shared.RenderTemplate(l.definition.Description, ctx)
@@ -159,7 +155,7 @@ func (l *LXDImage) createMetadata() error {
 		return err
 	}
 
-	l.Metadata.ExpiryDate = shared.GetExpiryDate(l.creationDate, l.definition.Expiry).Unix()
+	l.Metadata.ExpiryDate = shared.GetExpiryDate(time.Now(), l.definition.Expiry).Unix()
 
 	return err
 }
diff --git a/image/lxd_test.go b/image/lxd_test.go
index 9789a06..1aef997 100644
--- a/image/lxd_test.go
+++ b/image/lxd_test.go
@@ -8,7 +8,6 @@ import (
 	"reflect"
 	"strings"
 	"testing"
-	"time"
 
 	lxd "github.com/lxc/lxd/shared"
 
@@ -21,7 +20,8 @@ var lxdImageDef = shared.DefinitionImage{
 	Release:      "17.10",
 	Architecture: "amd64",
 	Expiry:       "30d",
-	Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ image.Architecture }}-{{ creation_date }}",
+	Name:         "{{ image.Distribution|lower }}-{{ image.Release }}-{{ image.Architecture }}-{{ image.Serial }}",
+	Serial:       "testing",
 }
 
 func setupLXD(t *testing.T) *LXDImage {
@@ -39,9 +39,6 @@ func setupLXD(t *testing.T) *LXDImage {
 
 	image := NewLXDImage(cacheDir, "", cacheDir, lxdImageDef)
 
-	// Override creation date
-	image.creationDate = time.Date(2006, 1, 2, 3, 4, 5, 0, time.UTC)
-
 	// Check cache directory
 	if image.cacheDir != cacheDir {
 		teardownLXD(t)
@@ -94,10 +91,10 @@ func testLXDBuildUnifiedImage(t *testing.T, image *LXDImage) {
 	if err != nil {
 		t.Fatalf("Unexpected error: %s", err)
 	}
-	defer os.Remove("ubuntu-17.10-x86_64-20060201_0304.tar.xz")
+	defer os.Remove("ubuntu-17.10-x86_64-testing.tar.xz")
 
-	if !lxd.PathExists("ubuntu-17.10-x86_64-20060201_0304.tar.xz") {
-		t.Fatalf("File '%s' does not exist", "ubuntu-17.10-x86_64-20060201_0304.tar.xz")
+	if !lxd.PathExists("ubuntu-17.10-x86_64-testing.tar.xz") {
+		t.Fatalf("File '%s' does not exist", "ubuntu-17.10-x86_64-testing.tar.xz")
 	}
 
 	// Create unified tarball with default name.
@@ -132,11 +129,6 @@ func TestLXDCreateMetadata(t *testing.T) {
 			image.Metadata.Architecture,
 			"x86_64",
 		},
-		{
-			"CreationDate",
-			fmt.Sprint(image.Metadata.CreationDate),
-			fmt.Sprint(image.creationDate.Unix()),
-		},
 		{
 			"Properties[architecture]",
 			image.Metadata.Properties["architecture"],
@@ -162,12 +154,7 @@ func TestLXDCreateMetadata(t *testing.T) {
 			"Properties[name]",
 			image.Metadata.Properties["name"],
 			fmt.Sprintf("%s-%s-%s-%s", strings.ToLower(lxdImageDef.Distribution),
-				lxdImageDef.Release, "x86_64", image.creationDate.Format("20060201_1504")),
-		},
-		{
-			"ExpiryDate",
-			fmt.Sprintf("%d", image.Metadata.ExpiryDate),
-			"1138763045",
+				lxdImageDef.Release, "x86_64", lxdImageDef.Serial),
 		},
 	}
 
diff --git a/shared/definition.go b/shared/definition.go
index 6756df1..8db06fe 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"runtime"
 	"strings"
+	"time"
 
 	"github.com/lxc/lxd/shared"
 )
@@ -27,6 +28,7 @@ type DefinitionImage struct {
 	Expiry       string `yaml:"expiry,omitempty"`
 	Variant      string `yaml:"variant,omitempty"`
 	Name         string `yaml:"name,omitempty"`
+	Serial       string `yaml:"serial,omitempty"`
 }
 
 // A DefinitionSource specifies the download type and location
@@ -104,6 +106,11 @@ func SetDefinitionDefaults(def *Definition) {
 		def.Image.Expiry = "30d"
 	}
 
+	// Set default serial number
+	if def.Image.Serial == "" {
+		def.Image.Serial = time.Now().UTC().Format("20060201_1504")
+	}
+
 	// Set default variant
 	if def.Image.Variant == "" {
 		def.Image.Variant = "default"
@@ -116,11 +123,11 @@ func SetDefinitionDefaults(def *Definition) {
 
 	// Set default name and description templates
 	if def.Image.Name == "" {
-		def.Image.Name = "{{ image.Distribution }}-{{ image.Release }}-{{ image.Architecture }}-{{ image.Variant }}-{{ creation_date }}"
+		def.Image.Name = "{{ image.Distribution }}-{{ image.Release }}-{{ image.Architecture }}-{{ image.Variant }}-{{ image.Serial }}"
 	}
 
 	if def.Image.Description == "" {
-		def.Image.Description = "{{ image.Distribution|capfirst }} {{ image.Release }} {{ image.Architecture }}{% if image.Variant != \"default\" %} ({{ image.Variant }}){% endif %} ({{ creation_date }})"
+		def.Image.Description = "{{ image.Distribution|capfirst }} {{ image.Release }} {{ image.Architecture }}{% if image.Variant != \"default\" %} ({{ image.Variant }}){% endif %} ({{ image.Serial }})"
 	}
 }
 

From 163eb1a61aa5f90d9e845d94ff550a282623ccef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 13 Mar 2018 14:38:46 -0400
Subject: [PATCH 7/8] definition: Fix date format
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/definition.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/shared/definition.go b/shared/definition.go
index 8db06fe..1cecf79 100644
--- a/shared/definition.go
+++ b/shared/definition.go
@@ -108,7 +108,7 @@ func SetDefinitionDefaults(def *Definition) {
 
 	// Set default serial number
 	if def.Image.Serial == "" {
-		def.Image.Serial = time.Now().UTC().Format("20060201_1504")
+		def.Image.Serial = time.Now().UTC().Format("20060102_1504")
 	}
 
 	// Set default variant

From 1a277a93ee57739e27f0ce0310bd107b8ced1067 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 13 Mar 2018 15:05:45 -0400
Subject: [PATCH 8/8] shared: Allow chaining templates
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/util.go | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/shared/util.go b/shared/util.go
index 874d6e0..4b1d057 100644
--- a/shared/util.go
+++ b/shared/util.go
@@ -11,6 +11,7 @@ import (
 	"path/filepath"
 	"regexp"
 	"strconv"
+	"strings"
 	"time"
 
 	lxd "github.com/lxc/lxd/shared"
@@ -214,7 +215,7 @@ func RenderTemplate(template string, ctx pongo2.Context) (string, error) {
 	)
 
 	// Load template from string
-	tpl, err := pongo2.FromString(template)
+	tpl, err := pongo2.FromString("{% autoescape off %}" + template + "{% endautoescape %}")
 	if err != nil {
 		return ret, err
 	}
@@ -225,6 +226,11 @@ func RenderTemplate(template string, ctx pongo2.Context) (string, error) {
 		return ret, err
 	}
 
+	// Looks like we're nesting templates so run pongo again
+	if strings.Contains(ret, "{{") || strings.Contains(ret, "{%") {
+		return RenderTemplate(ret, ctx)
+	}
+
 	return ret, err
 }
 


More information about the lxc-devel mailing list