[lxc-devel] [lxd/master] Backup: Allow import of instances and custom volume under different names

tomponline on Github lxc-bot at linuxcontainers.org
Tue Sep 29 13:46:05 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 469 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200929/dbc9aacd/attachment.bin>
-------------- next part --------------
From dff5ed87fc1ec382d3c04bef8df1df5fa295141d Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 11:55:36 +0100
Subject: [PATCH 01/18] client/interfaces: Adds Name field to
 InstanceBackupArgs

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 client/interfaces.go | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/client/interfaces.go b/client/interfaces.go
index e676a12cdc..0067ac826b 100644
--- a/client/interfaces.go
+++ b/client/interfaces.go
@@ -446,6 +446,9 @@ type InstanceBackupArgs struct {
 
 	// Storage pool to use
 	PoolName string
+
+	// Name to import backup as
+	Name string
 }
 
 // The InstanceCopyArgs struct is used to pass additional options during instance copy.

From b93ee8f20e4123486480e08aa65e1b076f440961 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 11:56:07 +0100
Subject: [PATCH 02/18] client/lxd/instances: Adds custom name restore support
 to CreateInstanceFromBackup

Utilising a new `X-LXD-name` header.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 client/lxd_instances.go | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/client/lxd_instances.go b/client/lxd_instances.go
index eba694e410..0195d7504d 100644
--- a/client/lxd_instances.go
+++ b/client/lxd_instances.go
@@ -145,7 +145,7 @@ func (r *ProtocolLXD) CreateInstanceFromBackup(args InstanceBackupArgs) (Operati
 		return nil, err
 	}
 
-	if args.PoolName == "" {
+	if args.PoolName == "" && args.Name == "" {
 		// Send the request
 		op, _, err := r.queryOperation("POST", path, args.BackupFile, "")
 		if err != nil {
@@ -155,8 +155,12 @@ func (r *ProtocolLXD) CreateInstanceFromBackup(args InstanceBackupArgs) (Operati
 		return op, nil
 	}
 
-	if !r.HasExtension("container_backup_override_pool") {
-		return nil, fmt.Errorf("The server is missing the required \"container_backup_override_pool\" API extension")
+	if args.PoolName != "" && !r.HasExtension("container_backup_override_pool") {
+		return nil, fmt.Errorf(`The server is missing the required "container_backup_override_pool" API extension`)
+	}
+
+	if args.Name != "" && !r.HasExtension("backup_override_name") {
+		return nil, fmt.Errorf(`The server is missing the required "backup_override_name" API extension`)
 	}
 
 	// Prepare the HTTP request
@@ -171,7 +175,14 @@ func (r *ProtocolLXD) CreateInstanceFromBackup(args InstanceBackupArgs) (Operati
 	}
 
 	req.Header.Set("Content-Type", "application/octet-stream")
-	req.Header.Set("X-LXD-pool", args.PoolName)
+
+	if args.PoolName != "" {
+		req.Header.Set("X-LXD-pool", args.PoolName)
+	}
+
+	if args.Name != "" {
+		req.Header.Set("X-LXD-name", args.Name)
+	}
 
 	// Set the user agent
 	if r.httpUserAgent != "" {

From ae9b5d5fc19cd58b89f14bab37a838e3097ec6e7 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 11:56:42 +0100
Subject: [PATCH 03/18] lxc/import: Adds --name and -n flags to lxc import
 command

Allows importing an instance backup as a different instance name.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxc/import.go | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lxc/import.go b/lxc/import.go
index edbb137428..0fa0437995 100644
--- a/lxc/import.go
+++ b/lxc/import.go
@@ -19,6 +19,7 @@ type cmdImport struct {
 	global *cmdGlobal
 
 	flagStorage string
+	flagName    string
 }
 
 func (c *cmdImport) Command() *cobra.Command {
@@ -33,6 +34,7 @@ func (c *cmdImport) Command() *cobra.Command {
 
 	cmd.RunE = c.Run
 	cmd.Flags().StringVarP(&c.flagStorage, "storage", "s", "", i18n.G("Storage pool name")+"``")
+	cmd.Flags().StringVarP(&c.flagName, "name", "n", "", i18n.G("Instance name")+"``")
 
 	return cmd
 }
@@ -84,6 +86,7 @@ func (c *cmdImport) Run(cmd *cobra.Command, args []string) error {
 			},
 		},
 		PoolName: c.flagStorage,
+		Name:     c.flagName,
 	}
 
 	op, err := resource.server.CreateInstanceFromBackup(createArgs)

From fea3c86a6aab864bb1e1a827ac2f7845ca4668fe Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 11:57:43 +0100
Subject: [PATCH 04/18] lxd/instances/post: Adds custom name support for backup
 import to createFromBackup

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/instances_post.go | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/lxd/instances_post.go b/lxd/instances_post.go
index cbe58a1bba..bdbac617b8 100644
--- a/lxd/instances_post.go
+++ b/lxd/instances_post.go
@@ -545,7 +545,7 @@ func createFromCopy(d *Daemon, project string, req *api.InstancesPost) response.
 	return operations.OperationResponse(op)
 }
 
-func createFromBackup(d *Daemon, project string, data io.Reader, pool string) response.Response {
+func createFromBackup(d *Daemon, project string, data io.Reader, pool string, instanceName string) response.Response {
 	revert := revert.New()
 	defer revert.Fail()
 
@@ -609,6 +609,11 @@ func createFromBackup(d *Daemon, project string, data io.Reader, pool string) re
 		bInfo.Pool = pool
 	}
 
+	// Override instance name.
+	if instanceName != "" {
+		bInfo.Name = instanceName
+	}
+
 	logger.Debug("Backup file info loaded", log.Ctx{
 		"type":      bInfo.Type,
 		"name":      bInfo.Name,
@@ -675,8 +680,9 @@ func createFromBackup(d *Daemon, project string, data io.Reader, pool string) re
 		runRevert.Add(revertHook)
 
 		body, err := json.Marshal(&internalImportPost{
-			Name:  bInfo.Name,
-			Force: true,
+			Name:              bInfo.Name,
+			Force:             true,
+			AllowNameOverride: instanceName != "",
 		})
 		if err != nil {
 			return errors.Wrap(err, "Marshal internal import request")

From 210833514474bfe3bf81ba67e9b7889598cf00c5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 11:58:05 +0100
Subject: [PATCH 05/18] lxd/instances/post: createFromBackup usage in
 containersPost for custom backup name restore

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/instances_post.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/instances_post.go b/lxd/instances_post.go
index bdbac617b8..ebbff5c700 100644
--- a/lxd/instances_post.go
+++ b/lxd/instances_post.go
@@ -742,7 +742,7 @@ func containersPost(d *Daemon, r *http.Request) response.Response {
 
 	// If we're getting binary content, process separately
 	if r.Header.Get("Content-Type") == "application/octet-stream" {
-		return createFromBackup(d, project, r.Body, r.Header.Get("X-LXD-pool"))
+		return createFromBackup(d, project, r.Body, r.Header.Get("X-LXD-pool"), r.Header.Get("X-LXD-name"))
 	}
 
 	// Parse the request

From bcb7a54dd022aa2ed8a21b791cfedac3fe6e3d83 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 11:58:38 +0100
Subject: [PATCH 06/18] lxd/api/internal: Adds AllowNameOverride to
 internalImportPost

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_internal.go | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 320f09a955..b912f6cc3b 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -415,8 +415,9 @@ func internalSQLExec(tx *sql.Tx, query string, result *internalSQLResult) error
 }
 
 type internalImportPost struct {
-	Name  string `json:"name" yaml:"name"`
-	Force bool   `json:"force" yaml:"force"`
+	Name              string `json:"name" yaml:"name"`
+	Force             bool   `json:"force" yaml:"force"`
+	AllowNameOverride bool   `json:"allow_name_override" yaml:"allow_name_override"`
 }
 
 func internalImport(d *Daemon, r *http.Request) response.Response {

From 691bc053e4fed9843074440b18edaa3ec593af1c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 11:59:10 +0100
Subject: [PATCH 07/18] lxd/api/internal: Override instance name in
 internalImport when AllowNameOverride is set

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/api_internal.go | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index b912f6cc3b..e10e3404c0 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -501,6 +501,10 @@ func internalImport(d *Daemon, r *http.Request) response.Response {
 		return response.SmartError(err)
 	}
 
+	if req.AllowNameOverride && req.Name != "" {
+		backupConf.Container.Name = req.Name
+	}
+
 	if req.Name != backupConf.Container.Name {
 		return response.InternalError(fmt.Errorf("Instance name in request %q doesn't match instance name in backup config %q", req.Name, backupConf.Container.Name))
 	}

From c1c7c8003ab1467cb9bf3cc7c8445c23f1b76737 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:03:37 +0100
Subject: [PATCH 08/18] client/interfaces: Changes
 CreateStoragePoolVolumeFromBackup args to bring in to line with
 CreateInstanceFromBackup

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 client/interfaces.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/client/interfaces.go b/client/interfaces.go
index 0067ac826b..726be7712e 100644
--- a/client/interfaces.go
+++ b/client/interfaces.go
@@ -291,7 +291,7 @@ type InstanceServer interface {
 	RenameStoragePoolVolumeBackup(pool string, volName string, name string, backup api.StoragePoolVolumeBackupPost) (op Operation, err error)
 	DeleteStoragePoolVolumeBackup(pool string, volName string, name string) (op Operation, err error)
 	GetStoragePoolVolumeBackupFile(pool string, volName string, name string, req *BackupFileRequest) (resp *BackupFileResponse, err error)
-	CreateStoragePoolVolumeFromBackup(pool string, args StoragePoolVolumeBackupArgs) (op Operation, err error)
+	CreateStoragePoolVolumeFromBackup(args StoragePoolVolumeBackupArgs) (op Operation, err error)
 
 	// Cluster functions ("cluster" API extensions)
 	GetCluster() (cluster *api.Cluster, ETag string, err error)

From df6e9fbbc76ff394defe82b954f76ecbbee3fffb Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:04:31 +0100
Subject: [PATCH 09/18] client/interfaces: Adds PoolName and Name fields to
 StoragePoolVolumeBackupArgs to bring in line with InstanceBackupArgs

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 client/interfaces.go | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/client/interfaces.go b/client/interfaces.go
index 726be7712e..9b0bffcf18 100644
--- a/client/interfaces.go
+++ b/client/interfaces.go
@@ -437,6 +437,12 @@ type StoragePoolVolumeMoveArgs struct {
 type StoragePoolVolumeBackupArgs struct {
 	// The backup file
 	BackupFile io.Reader
+
+	// Storage pool to use
+	PoolName string
+
+	// Name to import backup as
+	Name string
 }
 
 // The InstanceBackupArgs struct is used when creating a instance from a backup.

From cfeffbd7c6460225b62bece2b94b810500e8f1e2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:07:32 +0100
Subject: [PATCH 10/18] client/lxd/storage/volumes: Updates
 CreateStoragePoolVolumeFromBackup usage to accept only
 StoragePoolVolumeBackupArgs

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 client/lxd_storage_volumes.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/client/lxd_storage_volumes.go b/client/lxd_storage_volumes.go
index 3a3725c398..e7966ed68a 100644
--- a/client/lxd_storage_volumes.go
+++ b/client/lxd_storage_volumes.go
@@ -779,13 +779,13 @@ func (r *ProtocolLXD) GetStoragePoolVolumeBackupFile(pool string, volName string
 }
 
 // CreateStoragePoolVolumeFromBackup creates a custom volume from a backup file.
-func (r *ProtocolLXD) CreateStoragePoolVolumeFromBackup(pool string, args StoragePoolVolumeBackupArgs) (Operation, error) {
+func (r *ProtocolLXD) CreateStoragePoolVolumeFromBackup(args StoragePoolVolumeBackupArgs) (Operation, error) {
 	if !r.HasExtension("custom_volume_backup") {
 		return nil, fmt.Errorf("The server is missing the required \"custom_volume_backup\" API extension")
 	}
 
 	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/storage-pools/%s/volumes/custom", url.PathEscape(pool)), args.BackupFile, "")
+	op, _, err := r.queryOperation("POST", fmt.Sprintf("/storage-pools/%s/volumes/custom", url.PathEscape(args.PoolName)), args.BackupFile, "")
 	if err != nil {
 		return nil, err
 	}

From f422b6258f09628bfcf17020d3f3873158885554 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:08:25 +0100
Subject: [PATCH 11/18] client/lxd/storage/volumes: Updates
 CreateStoragePoolVolumeFromBackup to accept volume name override via
 X-LXD-name header

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 client/lxd_storage_volumes.go | 56 ++++++++++++++++++++++++++++++++---
 1 file changed, 52 insertions(+), 4 deletions(-)

diff --git a/client/lxd_storage_volumes.go b/client/lxd_storage_volumes.go
index e7966ed68a..882e3a723c 100644
--- a/client/lxd_storage_volumes.go
+++ b/client/lxd_storage_volumes.go
@@ -781,14 +781,62 @@ func (r *ProtocolLXD) GetStoragePoolVolumeBackupFile(pool string, volName string
 // CreateStoragePoolVolumeFromBackup creates a custom volume from a backup file.
 func (r *ProtocolLXD) CreateStoragePoolVolumeFromBackup(args StoragePoolVolumeBackupArgs) (Operation, error) {
 	if !r.HasExtension("custom_volume_backup") {
-		return nil, fmt.Errorf("The server is missing the required \"custom_volume_backup\" API extension")
+		return nil, fmt.Errorf(`The server is missing the required "custom_volume_backup" API extension`)
 	}
 
-	// Send the request
-	op, _, err := r.queryOperation("POST", fmt.Sprintf("/storage-pools/%s/volumes/custom", url.PathEscape(args.PoolName)), args.BackupFile, "")
+	if args.Name != "" && !r.HasExtension("backup_override_name") {
+		return nil, fmt.Errorf(`The server is missing the required "backup_override_name" API extension`)
+	}
+
+	path := fmt.Sprintf("/storage-pools/%s/volumes/custom", url.PathEscape(args.PoolName))
+
+	// Prepare the HTTP request.
+	reqURL, err := r.setQueryAttributes(fmt.Sprintf("%s/1.0%s", r.httpHost, path))
 	if err != nil {
 		return nil, err
 	}
 
-	return op, nil
+	req, err := http.NewRequest("POST", reqURL, args.BackupFile)
+	if err != nil {
+		return nil, err
+	}
+
+	req.Header.Set("Content-Type", "application/octet-stream")
+
+	if args.Name != "" {
+		req.Header.Set("X-LXD-name", args.Name)
+	}
+
+	// Set the user agent.
+	if r.httpUserAgent != "" {
+		req.Header.Set("User-Agent", r.httpUserAgent)
+	}
+
+	// Send the request.
+	resp, err := r.do(req)
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+
+	// Handle errors.
+	response, _, err := lxdParseResponse(resp)
+	if err != nil {
+		return nil, err
+	}
+
+	// Get to the operation.
+	respOperation, err := response.MetadataAsOperation()
+	if err != nil {
+		return nil, err
+	}
+
+	// Setup an Operation wrapper.
+	op := operation{
+		Operation: *respOperation,
+		r:         r,
+		chActive:  make(chan bool),
+	}
+
+	return &op, nil
 }

From 4485133f5c97ff0c8d6be057cfa44b66e0ce9f23 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:09:36 +0100
Subject: [PATCH 12/18] lxc/storage/volume: Adds --name flag to lxc storage
 volume import

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxc/storage_volume.go | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/lxc/storage_volume.go b/lxc/storage_volume.go
index 7bb6229d06..07103cd9d5 100644
--- a/lxc/storage_volume.go
+++ b/lxc/storage_volume.go
@@ -1788,6 +1788,7 @@ type cmdStorageVolumeImport struct {
 	global        *cmdGlobal
 	storage       *cmdStorage
 	storageVolume *cmdStorageVolume
+	flagName      string
 }
 
 func (c *cmdStorageVolumeImport) Command() *cobra.Command {
@@ -1800,6 +1801,7 @@ func (c *cmdStorageVolumeImport) Command() *cobra.Command {
 		`lxc storage volume import default backup0.tar.gz
 		Create a new custom volume using backup0.tar.gz as the source.`))
 	cmd.RunE = c.Run
+	cmd.Flags().StringVarP(&c.flagName, "name", "n", "", i18n.G("Volume name")+"``")
 
 	return cmd
 }
@@ -1814,7 +1816,7 @@ func (c *cmdStorageVolumeImport) Run(cmd *cobra.Command, args []string) error {
 	}
 
 	// Connect to LXD
-	remote, name, err := conf.ParseRemote(args[0])
+	remote, pool, err := conf.ParseRemote(args[0])
 	if err != nil {
 		return err
 	}
@@ -1850,9 +1852,11 @@ func (c *cmdStorageVolumeImport) Run(cmd *cobra.Command, args []string) error {
 				},
 			},
 		},
+		PoolName: pool,
+		Name:     c.flagName,
 	}
 
-	op, err := d.CreateStoragePoolVolumeFromBackup(name, createArgs)
+	op, err := d.CreateStoragePoolVolumeFromBackup(createArgs)
 	if err != nil {
 		return err
 	}

From 724d1e6d4dc5a7efa41e08fc1cbffa61cce91526 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:10:33 +0100
Subject: [PATCH 13/18] lxd/storage/volumes: Adds volName arg to
 createStoragePoolVolumeFromBackup

And re-orders arguments to resemble createFromBackup.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_volumes.go | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index 0e6e6a5827..713abc8fda 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -1232,7 +1232,7 @@ func storagePoolVolumeTypeImageDelete(d *Daemon, r *http.Request) response.Respo
 	return storagePoolVolumeTypeDelete(d, r, "image")
 }
 
-func createStoragePoolVolumeFromBackup(d *Daemon, project string, pool string, data io.Reader) response.Response {
+func createStoragePoolVolumeFromBackup(d *Daemon, project string, data io.Reader, pool string, volName string) response.Response {
 	revert := revert.New()
 	defer revert.Fail()
 
@@ -1296,6 +1296,11 @@ func createStoragePoolVolumeFromBackup(d *Daemon, project string, pool string, d
 		bInfo.Pool = pool
 	}
 
+	// Override volume name.
+	if volName != "" {
+		bInfo.Name = volName
+	}
+
 	logger.Debug("Backup file info loaded", log.Ctx{
 		"type":      bInfo.Type,
 		"name":      bInfo.Name,

From 09970e9cbfef61ee70009472fc9727a02446cb7f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:11:53 +0100
Subject: [PATCH 14/18] lxd/storage/volumes: createStoragePoolVolumeFromBackup
 usage in storagePoolVolumesTypePost

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage_volumes.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/storage_volumes.go b/lxd/storage_volumes.go
index 713abc8fda..a7c0f6c4ca 100644
--- a/lxd/storage_volumes.go
+++ b/lxd/storage_volumes.go
@@ -294,7 +294,7 @@ func storagePoolVolumesTypePost(d *Daemon, r *http.Request) response.Response {
 
 	// If we're getting binary content, process separately.
 	if r.Header.Get("Content-Type") == "application/octet-stream" {
-		return createStoragePoolVolumeFromBackup(d, projectName, poolName, r.Body)
+		return createStoragePoolVolumeFromBackup(d, projectName, r.Body, poolName, r.Header.Get("X-LXD-name"))
 	}
 
 	req := api.StorageVolumesPost{}

From eaf66ca2e5d3ee5d33b031d223c4117a9b98c90b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:16:27 +0100
Subject: [PATCH 15/18] lxd/storage/backend/lxd: Updates
 CreateCustomVolumeFromBackup to support custom volume import name

Ensure only uses srcBackup.Name as volume name and snapshot prefix, and not the names in the encoded index.yaml Config field.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/backend_lxd.go | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index a1b8b99ab2..379c644874 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -3469,7 +3469,7 @@ func (b *lxdBackend) CreateCustomVolumeFromBackup(srcBackup backup.Info, srcData
 		StorageVolumePut: api.StorageVolumePut{
 			Config: srcBackup.Config.Volume.Config,
 		},
-		Name: srcBackup.Config.Volume.Name,
+		Name: srcBackup.Name,
 	}
 	err := b.state.Cluster.Transaction(func(tx *db.ClusterTx) error {
 		return project.AllowVolumeCreation(tx, srcBackup.Project, req)
@@ -3494,7 +3494,7 @@ func (b *lxdBackend) CreateCustomVolumeFromBackup(srcBackup backup.Info, srcData
 	}
 
 	// Create database entry for new storage volume using the validated config.
-	err = VolumeDBCreate(b.state, srcBackup.Project, b.name, srcBackup.Config.Volume.Name, srcBackup.Config.Volume.Description, db.StoragePoolVolumeTypeNameCustom, false, vol.Config(), time.Time{}, string(vol.ContentType()))
+	err = VolumeDBCreate(b.state, srcBackup.Project, b.name, srcBackup.Name, srcBackup.Config.Volume.Description, db.StoragePoolVolumeTypeNameCustom, false, vol.Config(), time.Time{}, string(vol.ContentType()))
 	if err != nil {
 		return err
 	}
@@ -3506,7 +3506,9 @@ func (b *lxdBackend) CreateCustomVolumeFromBackup(srcBackup backup.Info, srcData
 	// Create database entries fro new storage volume snapshots.
 	for _, s := range srcBackup.Config.VolumeSnapshots {
 		snapshot := s // Local var for revert.
-		snapVolStorageName := project.StorageVolume(srcBackup.Project, snapshot.Name)
+		_, snapName, _ := shared.InstanceGetParentAndSnapshotName(snapshot.Name)
+		fullSnapName := drivers.GetSnapshotVolumeName(srcBackup.Name, snapName)
+		snapVolStorageName := project.StorageVolume(srcBackup.Project, fullSnapName)
 		snapVol := b.newVolume(drivers.VolumeTypeCustom, drivers.ContentType(srcBackup.Config.Volume.ContentType), snapVolStorageName, srcBackup.Config.Volume.Config)
 
 		// Strip any unsupported config keys (in case the export was made from a different type of storage pool).
@@ -3515,13 +3517,13 @@ func (b *lxdBackend) CreateCustomVolumeFromBackup(srcBackup backup.Info, srcData
 			return err
 		}
 
-		err = VolumeDBCreate(b.state, srcBackup.Project, b.name, snapshot.Name, snapshot.Description, db.StoragePoolVolumeTypeNameCustom, true, snapVol.Config(), *snapshot.ExpiresAt, string(snapVol.ContentType()))
+		err = VolumeDBCreate(b.state, srcBackup.Project, b.name, fullSnapName, snapshot.Description, db.StoragePoolVolumeTypeNameCustom, true, snapVol.Config(), *snapshot.ExpiresAt, string(snapVol.ContentType()))
 		if err != nil {
 			return err
 		}
 
 		revert.Add(func() {
-			b.state.Cluster.RemoveStoragePoolVolume(srcBackup.Project, snapshot.Name, db.StoragePoolVolumeTypeCustom, b.ID())
+			b.state.Cluster.RemoveStoragePoolVolume(srcBackup.Project, fullSnapName, db.StoragePoolVolumeTypeCustom, b.ID())
 		})
 	}
 

From aa873809f7b3dd5cb868bc89c0fc9bdaa6c664ed Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:19:21 +0100
Subject: [PATCH 16/18] api: Adds backup_override_name extension

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 doc/api-extensions.md | 6 ++++++
 shared/version/api.go | 1 +
 2 files changed, 7 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 52be415f36..a0cd6ec30c 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -1176,3 +1176,9 @@ This includes the following new endpoints (see [RESTful API](rest-api.md) for de
 The following existing endpoint has been modified:
 
  * `POST /1.0/storage-pools/<pool>/<type>/<volume>` accepts the new source type `backup`
+
+## backup\_override\_name
+Adds `Name` field to `InstanceBackupArgs` to allow specifying a different instance name when restoring a backup.
+
+Adds `Name` and `PoolName` fields to `StoragePoolVolumeBackupArgs` to allow specifying a different volume name
+when restoring a custom volume backup.
diff --git a/shared/version/api.go b/shared/version/api.go
index dfe5156e54..41a64fac67 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -227,6 +227,7 @@ var APIExtensions = []string{
 	"projects_networks",
 	"projects_networks_restricted_uplinks",
 	"custom_volume_backup",
+	"backup_override_name",
 }
 
 // APIExtensionsCount returns the number of available API extensions.

From e15e949b2ef7494b6bb38745fd2a939ccbbeacc9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:30:12 +0100
Subject: [PATCH 17/18] test/suites/backup: Adds tests for custom volume import
 name override

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 test/suites/backup.sh | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/test/suites/backup.sh b/test/suites/backup.sh
index f8781d58f7..65de390338 100644
--- a/test/suites/backup.sh
+++ b/test/suites/backup.sh
@@ -551,38 +551,52 @@ test_backup_volume_export_with_project() {
   lxc storage volume detach "${pool}" testvol c1
   lxc storage volume delete "${pool}" testvol
   lxc storage volume import "${pool}" "${LXD_DIR}/testvol.tar.gz"
+  lxc storage volume import "${pool}" "${LXD_DIR}/testvol.tar.gz" --name testvol2
   lxc storage volume attach "${pool}" testvol c1 /mnt
+  lxc storage volume attach "${pool}" testvol2 c1 /mnt2
   lxc start c1
   lxc exec c1 --project "$project" -- stat /mnt/test
+  lxc exec c1 --project "$project" -- stat /mnt2/test
   lxc stop -f c1
 
   if [ "$#" -ne 0 ]; then
     # Import into different project (before deleting earlier import).
     lxc storage volume import "${pool}" "${LXD_DIR}/testvol.tar.gz" --project "$project-b"
+    lxc storage volume import "${pool}" "${LXD_DIR}/testvol.tar.gz" --project "$project-b" --name testvol2
     lxc storage volume delete "${pool}" testvol --project "$project-b"
+    lxc storage volume delete "${pool}" testvol2 --project "$project-b"
   fi
 
   # Test optimized import.
   if [ "$lxd_backend" = "btrfs" ] || [ "$lxd_backend" = "zfs" ]; then
     lxc storage volume detach "${pool}" testvol c1
+    lxc storage volume detach "${pool}" testvol2 c1
     lxc storage volume delete "${pool}" testvol
+    lxc storage volume delete "${pool}" testvol2
     lxc storage volume import "${pool}" "${LXD_DIR}/testvol-optimized.tar.gz"
+    lxc storage volume import "${pool}" "${LXD_DIR}/testvol-optimized.tar.gz" --name testvol2
     lxc storage volume attach "${pool}" testvol c1 /mnt
+    lxc storage volume attach "${pool}" testvol2 c1 /mnt2
     lxc start c1
     lxc exec c1 --project "$project" -- stat /mnt/test
+    lxc exec c1 --project "$project" -- stat /mnt2/test
     lxc stop -f c1
 
     if [ "$#" -ne 0 ]; then
       # Import into different project (before deleting earlier import).
       lxc storage volume import "${pool}" "${LXD_DIR}/testvol-optimized.tar.gz" --project "$project-b"
+      lxc storage volume import "${pool}" "${LXD_DIR}/testvol-optimized.tar.gz" --project "$project-b" --name testvol2
       lxc storage volume delete "${pool}" testvol --project "$project-b"
+      lxc storage volume delete "${pool}" testvol2 --project "$project-b"
     fi
   fi
 
   # Clean up.
   rm -rf "${LXD_DIR}/non-optimized/"* "${LXD_DIR}/optimized/"*
   lxc storage volume detach "${pool}" testvol c1
+  lxc storage volume detach "${pool}" testvol2 c1
   lxc storage volume rm "${pool}" testvol
+  lxc storage volume rm "${pool}" testvol2
   lxc rm -f c1
   rmdir "${LXD_DIR}/optimized"
   rmdir "${LXD_DIR}/non-optimized"

From ffe8afdf3e1d8bfca3926c150f31b1a9f7b20d7b Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Tue, 29 Sep 2020 14:39:12 +0100
Subject: [PATCH 18/18] test/suites/backup: Adds instance import name override
 tests

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 test/suites/backup.sh | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/test/suites/backup.sh b/test/suites/backup.sh
index 65de390338..2d9095b01d 100644
--- a/test/suites/backup.sh
+++ b/test/suites/backup.sh
@@ -221,33 +221,53 @@ test_backup_import_with_project() {
   lxc delete --force c2
 
   lxc import "${LXD_DIR}/c2.tar.gz"
+  lxc import "${LXD_DIR}/c2.tar.gz" --name c3
   lxc info c2 | grep snap0
+  lxc info c3 | grep snap0
   lxc start c2
+  lxc start c3
   lxc stop c2 --force
+  lxc stop c3 --force
 
   if [ "$#" -ne 0 ]; then
     # Import into different project (before deleting earlier import).
     lxc import "${LXD_DIR}/c2.tar.gz" --project "$project-b"
+    lxc import "${LXD_DIR}/c2.tar.gz" --project "$project-b" --name c3
     lxc info c2 --project "$project-b" | grep snap0
+    lxc info c3 --project "$project-b" | grep snap0
     lxc start c2 --project "$project-b"
+    lxc start c3 --project "$project-b"
     lxc stop c2 --project "$project-b" --force
+    lxc stop c3 --project "$project-b" --force
     lxc restore c2 snap0 --project "$project-b"
+    lxc restore c3 snap0 --project "$project-b"
     lxc delete --force c2 --project "$project-b"
+    lxc delete --force c3 --project "$project-b"
   fi
 
   lxc restore c2 snap0
+  lxc restore c3 snap0
   lxc start c2
+  lxc start c3
   lxc delete --force c2
+  lxc delete --force c3
+
 
   if [ "$lxd_backend" = "btrfs" ] || [ "$lxd_backend" = "zfs" ]; then
     lxc import "${LXD_DIR}/c2-optimized.tar.gz"
+    lxc import "${LXD_DIR}/c2-optimized.tar.gz" --name c3
     lxc info c2 | grep snap0
+    lxc info c3 | grep snap0
     lxc start c2
+    lxc start c3
     lxc stop c2 --force
-
+    lxc stop c3 --force
     lxc restore c2 snap0
+    lxc restore c3 snap0
     lxc start c2
+    lxc start c3
     lxc delete --force c2
+    lxc delete --force c3
   fi
 
   # Test hyphenated container and snapshot names


More information about the lxc-devel mailing list