[lxc-devel] [lxd/master] Backup: Splitting up backup package into smaller files and common struct

tomponline on Github lxc-bot at linuxcontainers.org
Thu Sep 24 14:50:09 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 333 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200924/f60543c2/attachment-0001.bin>
-------------- next part --------------
From fdea618103eb2c9b00e8dd358871bf52ef683963 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:13:27 +0100
Subject: [PATCH 01/14] lxd/backup/instance/config: Renames InstanceConfig to
 Config

As a precursor to including custom volume support in this struct.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 ...backup_instance_config.go => backup_config.go} | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)
 rename lxd/backup/{backup_instance_config.go => backup_config.go} (84%)

diff --git a/lxd/backup/backup_instance_config.go b/lxd/backup/backup_config.go
similarity index 84%
rename from lxd/backup/backup_instance_config.go
rename to lxd/backup/backup_config.go
index 5120087bb5..c0e6d3357d 100644
--- a/lxd/backup/backup_instance_config.go
+++ b/lxd/backup/backup_config.go
@@ -13,22 +13,22 @@ import (
 	"github.com/lxc/lxd/shared/api"
 )
 
-// InstanceConfig represents the config of an instance that can be stored in a backup.yaml file.
-type InstanceConfig struct {
+// Config represents the config of a backup that can be stored in a backup.yaml file (or embedded in index.yaml).
+type Config struct {
 	Container *api.Instance           `yaml:"container"`
 	Snapshots []*api.InstanceSnapshot `yaml:"snapshots"`
 	Pool      *api.StoragePool        `yaml:"pool"`
 	Volume    *api.StorageVolume      `yaml:"volume"`
 }
 
-// ParseInstanceConfigYamlFile decodes the YAML file at path specified into an InstanceConfig.
-func ParseInstanceConfigYamlFile(path string) (*InstanceConfig, error) {
+// ParseConfigYamlFile decodes the YAML file at path specified into a Config.
+func ParseConfigYamlFile(path string) (*Config, error) {
 	data, err := ioutil.ReadFile(path)
 	if err != nil {
 		return nil, err
 	}
 
-	backup := InstanceConfig{}
+	backup := Config{}
 	if err := yaml.Unmarshal(data, &backup); err != nil {
 		return nil, err
 	}
@@ -50,8 +50,7 @@ func updateRootDevicePool(devices map[string]map[string]string, poolName string)
 	return false
 }
 
-// UpdateInstanceConfigStoragePool changes the pool information in the backup.yaml to the pool
-// specified in b.Pool.
+// UpdateInstanceConfigStoragePool changes the pool information in the backup.yaml to the pool specified in b.Pool.
 func UpdateInstanceConfigStoragePool(c *db.Cluster, b Info, mountPath string) error {
 	// Load the storage pool.
 	_, pool, err := c.GetStoragePool(b.Pool)
@@ -61,7 +60,7 @@ func UpdateInstanceConfigStoragePool(c *db.Cluster, b Info, mountPath string) er
 
 	f := func(path string) error {
 		// Read in the backup.yaml file.
-		backup, err := ParseInstanceConfigYamlFile(path)
+		backup, err := ParseConfigYamlFile(path)
 		if err != nil {
 			return err
 		}

From acb0551aad7b544be9055c0a1b2ccce4fbf08f59 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:18:26 +0100
Subject: [PATCH 02/14] lxd/backup/config: Makes Config fields omitempty so
 custom volume's encoded yaml doesn't contain instance fields

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

diff --git a/lxd/backup/backup_config.go b/lxd/backup/backup_config.go
index c0e6d3357d..ddfd8078a0 100644
--- a/lxd/backup/backup_config.go
+++ b/lxd/backup/backup_config.go
@@ -15,10 +15,10 @@ import (
 
 // Config represents the config of a backup that can be stored in a backup.yaml file (or embedded in index.yaml).
 type Config struct {
-	Container *api.Instance           `yaml:"container"`
-	Snapshots []*api.InstanceSnapshot `yaml:"snapshots"`
-	Pool      *api.StoragePool        `yaml:"pool"`
-	Volume    *api.StorageVolume      `yaml:"volume"`
+	Container *api.Instance           `yaml:"container,omitempty"`
+	Snapshots []*api.InstanceSnapshot `yaml:"snapshots,omitempty"`
+	Pool      *api.StoragePool        `yaml:"pool,omitempty"`
+	Volume    *api.StorageVolume      `yaml:"volume,omitempty"`
 }
 
 // ParseConfigYamlFile decodes the YAML file at path specified into a Config.

From 52d6705ac9f6189a4a0e6c8f5cde9c84595bf14a Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:19:13 +0100
Subject: [PATCH 03/14] lxd/storage/pool/interface: backup.Config usage

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

diff --git a/lxd/storage/pool_interface.go b/lxd/storage/pool_interface.go
index 82a424f07f..a4de84cc73 100644
--- a/lxd/storage/pool_interface.go
+++ b/lxd/storage/pool_interface.go
@@ -39,7 +39,7 @@ type Pool interface {
 	DeleteInstance(inst instance.Instance, op *operations.Operation) error
 	UpdateInstance(inst instance.Instance, newDesc string, newConfig map[string]string, op *operations.Operation) error
 	UpdateInstanceBackupFile(inst instance.Instance, op *operations.Operation) error
-	CheckInstanceBackupFileSnapshots(backupConf *backup.InstanceConfig, projectName string, deleteMissing bool, op *operations.Operation) ([]*api.InstanceSnapshot, error)
+	CheckInstanceBackupFileSnapshots(backupConf *backup.Config, projectName string, deleteMissing bool, op *operations.Operation) ([]*api.InstanceSnapshot, error)
 
 	MigrateInstance(inst instance.Instance, conn io.ReadWriteCloser, args *migration.VolumeSourceArgs, op *operations.Operation) error
 	RefreshInstance(inst instance.Instance, src instance.Instance, srcSnapshots []instance.Instance, op *operations.Operation) error

From fe5dd1852003af29bed60a9d54d01e72d15801ee Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:19:38 +0100
Subject: [PATCH 04/14] lxd/api/internal: backup.ParseConfigYamlFile usage

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

diff --git a/lxd/api_internal.go b/lxd/api_internal.go
index 8df0ac82bc..320f09a955 100644
--- a/lxd/api_internal.go
+++ b/lxd/api_internal.go
@@ -495,7 +495,7 @@ func internalImport(d *Daemon, r *http.Request) response.Response {
 
 	// Read in the backup.yaml file.
 	backupYamlPath := filepath.Join(instanceMountPoint, "backup.yaml")
-	backupConf, err := backup.ParseInstanceConfigYamlFile(backupYamlPath)
+	backupConf, err := backup.ParseConfigYamlFile(backupYamlPath)
 	if err != nil {
 		return response.SmartError(err)
 	}

From e26ca50d0f058a14be21312f7019f531e08bf47c Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:20:06 +0100
Subject: [PATCH 05/14] lxd/storage/backend: backup.Config usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/storage/backend_lxd.go  | 4 ++--
 lxd/storage/backend_mock.go | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
index c4f34c08d6..d5b523f437 100644
--- a/lxd/storage/backend_lxd.go
+++ b/lxd/storage/backend_lxd.go
@@ -3254,7 +3254,7 @@ func (b *lxdBackend) UpdateInstanceBackupFile(inst instance.Instance, op *operat
 		return err
 	}
 
-	data, err := yaml.Marshal(&backup.InstanceConfig{
+	data, err := yaml.Marshal(&backup.Config{
 		Container: ci.(*api.Instance),
 		Snapshots: sis,
 		Pool:      &b.db,
@@ -3302,7 +3302,7 @@ func (b *lxdBackend) UpdateInstanceBackupFile(inst instance.Instance, op *operat
 // config are removed from the storage device, and any snapshots that exist in the backup config but do not exist
 // on the storage device are ignored. The remaining set of snapshots that exist on both the storage device and the
 // backup config are returned. They set can be used to re-create the snapshot database entries when importing.
-func (b *lxdBackend) CheckInstanceBackupFileSnapshots(backupConf *backup.InstanceConfig, projectName string, deleteMissing bool, op *operations.Operation) ([]*api.InstanceSnapshot, error) {
+func (b *lxdBackend) CheckInstanceBackupFileSnapshots(backupConf *backup.Config, projectName string, deleteMissing bool, op *operations.Operation) ([]*api.InstanceSnapshot, error) {
 	logger := logging.AddContext(b.logger, log.Ctx{"project": projectName, "instance": backupConf.Container.Name, "deleteMissing": deleteMissing})
 	logger.Debug("CheckInstanceBackupFileSnapshots started")
 	defer logger.Debug("CheckInstanceBackupFileSnapshots finished")
diff --git a/lxd/storage/backend_mock.go b/lxd/storage/backend_mock.go
index 48d8be7ecd..becf5391bb 100644
--- a/lxd/storage/backend_mock.go
+++ b/lxd/storage/backend_mock.go
@@ -103,7 +103,7 @@ func (b *mockBackend) UpdateInstanceBackupFile(inst instance.Instance, op *opera
 	return nil
 }
 
-func (b *mockBackend) CheckInstanceBackupFileSnapshots(backupConf *backup.InstanceConfig, projectName string, deleteMissing bool, op *operations.Operation) ([]*api.InstanceSnapshot, error) {
+func (b *mockBackend) CheckInstanceBackupFileSnapshots(backupConf *backup.Config, projectName string, deleteMissing bool, op *operations.Operation) ([]*api.InstanceSnapshot, error) {
 	return nil, nil
 }
 

From 90a3ec2f66d06cacef316bca93ffe4d5e4fabc65 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:21:53 +0100
Subject: [PATCH 06/14] lxd/backup: Moves Instance interface into own file

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/backup/backup.go          | 7 -------
 lxd/backup/backup_instance.go | 8 ++++++++
 2 files changed, 8 insertions(+), 7 deletions(-)
 create mode 100644 lxd/backup/backup_instance.go

diff --git a/lxd/backup/backup.go b/lxd/backup/backup.go
index c7226b32d3..6f6867bb05 100644
--- a/lxd/backup/backup.go
+++ b/lxd/backup/backup.go
@@ -20,13 +20,6 @@ import (
 // WorkingDirPrefix is used when temporary working directories are needed.
 const WorkingDirPrefix = "lxd_backup"
 
-// Instance represents the backup relevant subset of a LXD instance.
-// This is used rather than instance.Instance to avoid import loops.
-type Instance interface {
-	Name() string
-	Project() string
-}
-
 // Info represents exported backup information.
 type Info struct {
 	Project          string           `json:"-" yaml:"-"` // Project is set during import based on current project.
diff --git a/lxd/backup/backup_instance.go b/lxd/backup/backup_instance.go
new file mode 100644
index 0000000000..d2d63c7074
--- /dev/null
+++ b/lxd/backup/backup_instance.go
@@ -0,0 +1,8 @@
+package backup
+
+// Instance represents the backup relevant subset of a LXD instance.
+// This is used rather than instance.Instance to avoid import loops.
+type Instance interface {
+	Name() string
+	Project() string
+}

From 9d6ee4b8d012a04391fad2ac8509cb50d4b82a00 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:24:49 +0100
Subject: [PATCH 07/14] lxd/backup: Moves Info struct and GetInfo function into
 own file

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/backup/backup.go      | 103 -----------------------------------
 lxd/backup/backup_info.go | 110 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 110 insertions(+), 103 deletions(-)
 create mode 100644 lxd/backup/backup_info.go

diff --git a/lxd/backup/backup.go b/lxd/backup/backup.go
index 6f6867bb05..e586906feb 100644
--- a/lxd/backup/backup.go
+++ b/lxd/backup/backup.go
@@ -1,16 +1,10 @@
 package backup
 
 import (
-	"context"
-	"fmt"
-	"io"
 	"os"
 	"strings"
 	"time"
 
-	"github.com/pkg/errors"
-	"gopkg.in/yaml.v2"
-
 	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/state"
 	"github.com/lxc/lxd/shared"
@@ -20,103 +14,6 @@ import (
 // WorkingDirPrefix is used when temporary working directories are needed.
 const WorkingDirPrefix = "lxd_backup"
 
-// Info represents exported backup information.
-type Info struct {
-	Project          string           `json:"-" yaml:"-"` // Project is set during import based on current project.
-	Name             string           `json:"name" yaml:"name"`
-	Backend          string           `json:"backend" yaml:"backend"`
-	Pool             string           `json:"pool" yaml:"pool"`
-	Snapshots        []string         `json:"snapshots,omitempty" yaml:"snapshots,omitempty"`
-	OptimizedStorage *bool            `json:"optimized,omitempty" yaml:"optimized,omitempty"`               // Optional field to handle older optimized backups that don't have this field.
-	OptimizedHeader  *bool            `json:"optimized_header,omitempty" yaml:"optimized_header,omitempty"` // Optional field to handle older optimized backups that don't have this field.
-	Type             api.InstanceType `json:"type" yaml:"type"`
-}
-
-// GetInfo extracts backup information from a given ReadSeeker.
-func GetInfo(r io.ReadSeeker) (*Info, error) {
-	result := Info{}
-	hasIndexFile := false
-
-	// Define some bools used to create points for OptimizedStorage field.
-	optimizedStorageFalse := false
-	optimizedHeaderFalse := false
-
-	// Extract
-	r.Seek(0, 0)
-	_, _, unpacker, err := shared.DetectCompressionFile(r)
-	if err != nil {
-		return nil, err
-	}
-
-	if unpacker == nil {
-		return nil, fmt.Errorf("Unsupported backup compression")
-	}
-
-	tr, cancelFunc, err := shared.CompressedTarReader(context.Background(), r, unpacker)
-	if err != nil {
-		return nil, err
-	}
-	defer cancelFunc()
-
-	for {
-		hdr, err := tr.Next()
-		if err == io.EOF {
-			break // End of archive
-		}
-		if err != nil {
-			return nil, errors.Wrapf(err, "Error reading backup file info")
-		}
-
-		if hdr.Name == "backup/index.yaml" {
-			err = yaml.NewDecoder(tr).Decode(&result)
-			if err != nil {
-				return nil, err
-			}
-
-			hasIndexFile = true
-
-			// Default to container if index doesn't specify instance type.
-			if result.Type == api.InstanceTypeAny {
-				result.Type = api.InstanceTypeContainer
-			}
-
-			// Default to no optimized header if not specified.
-			if result.OptimizedHeader == nil {
-				result.OptimizedHeader = &optimizedHeaderFalse
-			}
-
-			if result.OptimizedStorage != nil {
-				// No need to continue looking for optimized storage hint using the presence of the
-				// container.bin file below, as the index.yaml file tells us directly.
-				cancelFunc()
-				break
-			} else {
-				// Default to non-optimized if not specified and continue reading to see if
-				// optimized container.bin file present.
-				result.OptimizedStorage = &optimizedStorageFalse
-			}
-		}
-
-		// If the tarball contains a binary dump of the container, then this is an optimized backup.
-		if hdr.Name == "backup/container.bin" {
-			optimizedStorageTrue := true
-			result.OptimizedStorage = &optimizedStorageTrue
-
-			// Stop read loop if index.yaml already parsed.
-			if hasIndexFile {
-				cancelFunc()
-				break
-			}
-		}
-	}
-
-	if !hasIndexFile {
-		return nil, fmt.Errorf("Backup is missing index.yaml")
-	}
-
-	return &result, nil
-}
-
 // Backup represents a container backup
 type Backup struct {
 	state    *state.State
diff --git a/lxd/backup/backup_info.go b/lxd/backup/backup_info.go
new file mode 100644
index 0000000000..1c8e47083e
--- /dev/null
+++ b/lxd/backup/backup_info.go
@@ -0,0 +1,110 @@
+package backup
+
+import (
+	"context"
+	"fmt"
+	"io"
+
+	"github.com/pkg/errors"
+	"gopkg.in/yaml.v2"
+
+	"github.com/lxc/lxd/shared"
+	"github.com/lxc/lxd/shared/api"
+)
+
+// Info represents exported backup information.
+type Info struct {
+	Project          string           `json:"-" yaml:"-"` // Project is set during import based on current project.
+	Name             string           `json:"name" yaml:"name"`
+	Backend          string           `json:"backend" yaml:"backend"`
+	Pool             string           `json:"pool" yaml:"pool"`
+	Snapshots        []string         `json:"snapshots,omitempty" yaml:"snapshots,omitempty"`
+	OptimizedStorage *bool            `json:"optimized,omitempty" yaml:"optimized,omitempty"`               // Optional field to handle older optimized backups that don't have this field.
+	OptimizedHeader  *bool            `json:"optimized_header,omitempty" yaml:"optimized_header,omitempty"` // Optional field to handle older optimized backups that don't have this field.
+	Type             api.InstanceType `json:"type" yaml:"type"`
+}
+
+// GetInfo extracts backup information from a given ReadSeeker.
+func GetInfo(r io.ReadSeeker) (*Info, error) {
+	result := Info{}
+	hasIndexFile := false
+
+	// Define some bools used to create points for OptimizedStorage field.
+	optimizedStorageFalse := false
+	optimizedHeaderFalse := false
+
+	// Extract
+	r.Seek(0, 0)
+	_, _, unpacker, err := shared.DetectCompressionFile(r)
+	if err != nil {
+		return nil, err
+	}
+
+	if unpacker == nil {
+		return nil, fmt.Errorf("Unsupported backup compression")
+	}
+
+	tr, cancelFunc, err := shared.CompressedTarReader(context.Background(), r, unpacker)
+	if err != nil {
+		return nil, err
+	}
+	defer cancelFunc()
+
+	for {
+		hdr, err := tr.Next()
+		if err == io.EOF {
+			break // End of archive
+		}
+		if err != nil {
+			return nil, errors.Wrapf(err, "Error reading backup file info")
+		}
+
+		if hdr.Name == "backup/index.yaml" {
+			err = yaml.NewDecoder(tr).Decode(&result)
+			if err != nil {
+				return nil, err
+			}
+
+			hasIndexFile = true
+
+			// Default to container if index doesn't specify instance type.
+			if result.Type == api.InstanceTypeAny {
+				result.Type = api.InstanceTypeContainer
+			}
+
+			// Default to no optimized header if not specified.
+			if result.OptimizedHeader == nil {
+				result.OptimizedHeader = &optimizedHeaderFalse
+			}
+
+			if result.OptimizedStorage != nil {
+				// No need to continue looking for optimized storage hint using the presence of the
+				// container.bin file below, as the index.yaml file tells us directly.
+				cancelFunc()
+				break
+			} else {
+				// Default to non-optimized if not specified and continue reading to see if
+				// optimized container.bin file present.
+				result.OptimizedStorage = &optimizedStorageFalse
+			}
+		}
+
+		// If the tarball contains a binary dump of the container, then this is an optimized backup.
+		if hdr.Name == "backup/container.bin" {
+			optimizedStorageTrue := true
+			result.OptimizedStorage = &optimizedStorageTrue
+
+			// Stop read loop if index.yaml already parsed.
+			if hasIndexFile {
+				cancelFunc()
+				break
+			}
+		}
+	}
+
+	if !hasIndexFile {
+		return nil, fmt.Errorf("Backup is missing index.yaml")
+	}
+
+	return &result, nil
+}

From f87c451c0718223ed57511c3e909fe786bbee05e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:27:31 +0100
Subject: [PATCH 08/14] lxd/backup: Renames backup to backup_common

To accomodate more specific implementation types.

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/backup/{backup.go => backup_common.go} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename lxd/backup/{backup.go => backup_common.go} (100%)

diff --git a/lxd/backup/backup.go b/lxd/backup/backup_common.go
similarity index 100%
rename from lxd/backup/backup.go
rename to lxd/backup/backup_common.go

From 00d0039cbb715cb2125187a8476cc41048c0e4dc Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:44:30 +0100
Subject: [PATCH 09/14] lxd/backup/backup/common: Renames Backup to
 BackupCommon

Removes any-non common backup functionality.

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

diff --git a/lxd/backup/backup_common.go b/lxd/backup/backup_common.go
index e586906feb..6b298bcdd2 100644
--- a/lxd/backup/backup_common.go
+++ b/lxd/backup/backup_common.go
@@ -1,156 +1,42 @@
 package backup
 
 import (
-	"os"
-	"strings"
 	"time"
 
-	"github.com/lxc/lxd/lxd/project"
 	"github.com/lxc/lxd/lxd/state"
-	"github.com/lxc/lxd/shared"
-	"github.com/lxc/lxd/shared/api"
 )
 
 // WorkingDirPrefix is used when temporary working directories are needed.
 const WorkingDirPrefix = "lxd_backup"
 
-// Backup represents a container backup
-type Backup struct {
-	state    *state.State
-	instance Instance
-
-	// Properties
+// CommonBackup represents a common backup.
+type CommonBackup struct {
+	state                *state.State
 	id                   int
 	name                 string
 	creationDate         time.Time
 	expiryDate           time.Time
-	instanceOnly         bool
 	optimizedStorage     bool
 	compressionAlgorithm string
 }
 
-// New instantiates a new Backup struct.
-func New(state *state.State, inst Instance, ID int, name string, creationDate, expiryDate time.Time, instanceOnly, optimizedStorage bool) *Backup {
-	return &Backup{
-		state:            state,
-		instance:         inst,
-		id:               ID,
-		name:             name,
-		creationDate:     creationDate,
-		expiryDate:       expiryDate,
-		instanceOnly:     instanceOnly,
-		optimizedStorage: optimizedStorage,
-	}
+// Name returns the name of the backup.
+func (b *CommonBackup) Name() string {
+	return b.name
 }
 
 // CompressionAlgorithm returns the compression used for the tarball.
-func (b *Backup) CompressionAlgorithm() string {
+func (b *CommonBackup) CompressionAlgorithm() string {
 	return b.compressionAlgorithm
 }
 
 // SetCompressionAlgorithm sets the tarball compression.
-func (b *Backup) SetCompressionAlgorithm(compression string) {
+func (b *CommonBackup) SetCompressionAlgorithm(compression string) {
 	b.compressionAlgorithm = compression
 }
 
-// InstanceOnly returns whether only the instance itself is to be backed up.
-func (b *Backup) InstanceOnly() bool {
-	return b.instanceOnly
-}
-
-// Name returns the name of the backup.
-func (b *Backup) Name() string {
-	return b.name
-}
-
 // OptimizedStorage returns whether the backup is to be performed using
 // optimization supported by the storage driver.
-func (b *Backup) OptimizedStorage() bool {
+func (b *CommonBackup) OptimizedStorage() bool {
 	return b.optimizedStorage
 }
-
-// Rename renames an instance backup.
-func (b *Backup) Rename(newName string) error {
-	oldBackupPath := shared.VarPath("backups", "instances", project.Instance(b.instance.Project(), b.name))
-	newBackupPath := shared.VarPath("backups", "instances", project.Instance(b.instance.Project(), newName))
-
-	// Create the new backup path.
-	backupsPath := shared.VarPath("backups", "instances", project.Instance(b.instance.Project(), b.instance.Name()))
-	if !shared.PathExists(backupsPath) {
-		err := os.MkdirAll(backupsPath, 0700)
-		if err != nil {
-			return err
-		}
-	}
-
-	// Rename the backup directory.
-	err := os.Rename(oldBackupPath, newBackupPath)
-	if err != nil {
-		return err
-	}
-
-	// Check if we can remove the instance directory.
-	empty, _ := shared.PathIsEmpty(backupsPath)
-	if empty {
-		err := os.Remove(backupsPath)
-		if err != nil {
-			return err
-		}
-	}
-
-	// Rename the database record.
-	err = b.state.Cluster.RenameInstanceBackup(b.name, newName)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// Delete removes an instance backup
-func (b *Backup) Delete() error {
-	return DoBackupDelete(b.state, b.instance.Project(), b.name, b.instance.Name())
-}
-
-// Render returns an InstanceBackup struct of the backup.
-func (b *Backup) Render() *api.InstanceBackup {
-	return &api.InstanceBackup{
-		Name:             strings.SplitN(b.name, "/", 2)[1],
-		CreatedAt:        b.creationDate,
-		ExpiresAt:        b.expiryDate,
-		InstanceOnly:     b.instanceOnly,
-		ContainerOnly:    b.instanceOnly,
-		OptimizedStorage: b.optimizedStorage,
-	}
-}
-
-// DoBackupDelete deletes a backup.
-func DoBackupDelete(s *state.State, projectName, backupName, instanceName string) error {
-	backupPath := shared.VarPath("backups", "instances", project.Instance(projectName, backupName))
-
-	// Delete the on-disk data.
-	if shared.PathExists(backupPath) {
-		err := os.RemoveAll(backupPath)
-		if err != nil {
-			return err
-		}
-	}
-
-	// Check if we can remove the instance directory.
-	backupsPath := shared.VarPath("backups", "instances", project.Instance(projectName, instanceName))
-	empty, _ := shared.PathIsEmpty(backupsPath)
-	if empty {
-		err := os.Remove(backupsPath)
-		if err != nil {
-			return err
-		}
-	}
-
-	// Remove the database record.
-	err := s.Cluster.DeleteInstanceBackup(backupName)
-	if err != nil {
-		return err
-	}
-
-	return nil
-}

From 36a3f9d76401c11c0f5dfca0dfc943487c3965f2 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:45:20 +0100
Subject: [PATCH 10/14] lxd/backup/backup/instance: Adds InstanceBackup using
 CommonBackup as basis

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

diff --git a/lxd/backup/backup_instance.go b/lxd/backup/backup_instance.go
index d2d63c7074..9d6554bd60 100644
--- a/lxd/backup/backup_instance.go
+++ b/lxd/backup/backup_instance.go
@@ -1,8 +1,129 @@
 package backup
 
+import (
+	"os"
+	"strings"
+	"time"
+
+	"github.com/lxc/lxd/lxd/project"
+	"github.com/lxc/lxd/lxd/state"
+	"github.com/lxc/lxd/shared"
+	"github.com/lxc/lxd/shared/api"
+)
+
 // Instance represents the backup relevant subset of a LXD instance.
 // This is used rather than instance.Instance to avoid import loops.
 type Instance interface {
 	Name() string
 	Project() string
 }
+
+// InstanceBackup represents an instance backup.
+type InstanceBackup struct {
+	CommonBackup
+
+	instance     Instance
+	instanceOnly bool
+}
+
+// NewInstanceBackup instantiates a new InstanceBackup struct.
+func NewInstanceBackup(state *state.State, inst Instance, ID int, name string, creationDate time.Time, expiryDate time.Time, instanceOnly bool, optimizedStorage bool) *InstanceBackup {
+	return &InstanceBackup{
+		CommonBackup: CommonBackup{
+			state:            state,
+			id:               ID,
+			name:             name,
+			creationDate:     creationDate,
+			expiryDate:       expiryDate,
+			optimizedStorage: optimizedStorage,
+		},
+		instance:     inst,
+		instanceOnly: instanceOnly,
+	}
+}
+
+// InstanceOnly returns whether only the instance itself is to be backed up.
+func (b *InstanceBackup) InstanceOnly() bool {
+	return b.instanceOnly
+}
+
+// Rename renames an instance backup.
+func (b *InstanceBackup) Rename(newName string) error {
+	oldBackupPath := shared.VarPath("backups", "instances", project.Instance(b.instance.Project(), b.name))
+	newBackupPath := shared.VarPath("backups", "instances", project.Instance(b.instance.Project(), newName))
+
+	// Create the new backup path.
+	backupsPath := shared.VarPath("backups", "instances", project.Instance(b.instance.Project(), b.instance.Name()))
+	if !shared.PathExists(backupsPath) {
+		err := os.MkdirAll(backupsPath, 0700)
+		if err != nil {
+			return err
+		}
+	}
+
+	// Rename the backup directory.
+	err := os.Rename(oldBackupPath, newBackupPath)
+	if err != nil {
+		return err
+	}
+
+	// Check if we can remove the instance directory.
+	empty, _ := shared.PathIsEmpty(backupsPath)
+	if empty {
+		err := os.Remove(backupsPath)
+		if err != nil {
+			return err
+		}
+	}
+
+	// Rename the database record.
+	err = b.state.Cluster.RenameInstanceBackup(b.name, newName)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Delete removes an instance backup.
+func (b *InstanceBackup) Delete() error {
+	backupPath := shared.VarPath("backups", "instances", project.Instance(b.instance.Project(), b.name))
+
+	// Delete the on-disk data.
+	if shared.PathExists(backupPath) {
+		err := os.RemoveAll(backupPath)
+		if err != nil {
+			return err
+		}
+	}
+
+	// Check if we can remove the instance directory.
+	backupsPath := shared.VarPath("backups", "instances", project.Instance(b.instance.Project(), b.instance.Name()))
+	empty, _ := shared.PathIsEmpty(backupsPath)
+	if empty {
+		err := os.Remove(backupsPath)
+		if err != nil {
+			return err
+		}
+	}
+
+	// Remove the database record.
+	err := b.state.Cluster.DeleteInstanceBackup(b.name)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Render returns an InstanceBackup struct of the backup.
+func (b *InstanceBackup) Render() *api.InstanceBackup {
+	return &api.InstanceBackup{
+		Name:             strings.SplitN(b.name, "/", 2)[1],
+		CreatedAt:        b.creationDate,
+		ExpiresAt:        b.expiryDate,
+		InstanceOnly:     b.instanceOnly,
+		ContainerOnly:    b.instanceOnly,
+		OptimizedStorage: b.optimizedStorage,
+	}
+}

From 68e2ecb85f4523449cf25911f6e4a3a47b4bb161 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:46:24 +0100
Subject: [PATCH 11/14] lxd/backup: Changes pruneExpiredContainerBackups to use
 InstanceBackup.Delete() function

Avoids having to expose a separate standalone function.

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

diff --git a/lxd/backup.go b/lxd/backup.go
index 3014912073..c7c352e7c2 100644
--- a/lxd/backup.go
+++ b/lxd/backup.go
@@ -279,12 +279,13 @@ func pruneExpiredContainerBackups(ctx context.Context, d *Daemon) error {
 	for _, b := range backups {
 		inst, err := instance.LoadByID(d.State(), b.InstanceID)
 		if err != nil {
-			return errors.Wrapf(err, "Error deleting instance backup %s", b.Name)
+			return errors.Wrapf(err, "Error loading instance for deleting backup %q", b.Name)
 		}
 
-		err = backup.DoBackupDelete(d.State(), inst.Project(), b.Name, inst.Name())
+		instBackup := backup.NewInstanceBackup(d.State(), inst, b.ID, b.Name, b.CreationDate, b.ExpiryDate, b.InstanceOnly, b.OptimizedStorage)
+		err = instBackup.Delete()
 		if err != nil {
-			return errors.Wrapf(err, "Error deleting instance backup %s", b.Name)
+			return errors.Wrapf(err, "Error deleting instance backup %q", b.Name)
 		}
 	}
 

From 17336382dca08e0f80782edb1fe3f2139b42ac98 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:48:23 +0100
Subject: [PATCH 12/14] lxd/instance/instance/utils: backup.InstanceBackup
 usage

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

diff --git a/lxd/instance/instance_utils.go b/lxd/instance/instance_utils.go
index 7af24f7ee8..589ab7b567 100644
--- a/lxd/instance/instance_utils.go
+++ b/lxd/instance/instance_utils.go
@@ -661,7 +661,7 @@ func DeviceNextInterfaceHWAddr() (string, error) {
 }
 
 // BackupLoadByName load an instance backup from the database.
-func BackupLoadByName(s *state.State, project, name string) (*backup.Backup, error) {
+func BackupLoadByName(s *state.State, project, name string) (*backup.InstanceBackup, error) {
 	// Get the backup database record
 	args, err := s.Cluster.GetInstanceBackup(project, name)
 	if err != nil {
@@ -674,7 +674,7 @@ func BackupLoadByName(s *state.State, project, name string) (*backup.Backup, err
 		return nil, errors.Wrap(err, "Load instance from database")
 	}
 
-	return backup.New(s, instance, args.ID, name, args.CreationDate, args.ExpiryDate, args.InstanceOnly, args.OptimizedStorage), nil
+	return backup.NewInstanceBackup(s, instance, args.ID, name, args.CreationDate, args.ExpiryDate, args.InstanceOnly, args.OptimizedStorage), nil
 }
 
 // ResolveImage takes an instance source and returns a hash suitable for instance creation or download.

From 84e4129c9e9e043db4906afcb837fa58f1751c9e Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:48:37 +0100
Subject: [PATCH 13/14] lxd/instance/instance/interface: backup.InstanceBackup
 usage

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

diff --git a/lxd/instance/instance_interface.go b/lxd/instance/instance_interface.go
index bfe9054a70..e49458bd86 100644
--- a/lxd/instance/instance_interface.go
+++ b/lxd/instance/instance_interface.go
@@ -59,7 +59,7 @@ type Instance interface {
 	// Snapshots & migration & backups.
 	Restore(source Instance, stateful bool) error
 	Snapshots() ([]Instance, error)
-	Backups() ([]backup.Backup, error)
+	Backups() ([]backup.InstanceBackup, error)
 	UpdateBackupFile() error
 
 	// Config handling.

From 76ba76ba0a976994b6e58a2dbc7b66028cb2e964 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 24 Sep 2020 15:49:04 +0100
Subject: [PATCH 14/14] lxd/instance/drivers: backup.InstanceBackup usage

Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
 lxd/instance/drivers/driver_lxc.go  | 4 ++--
 lxd/instance/drivers/driver_qemu.go | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lxd/instance/drivers/driver_lxc.go b/lxd/instance/drivers/driver_lxc.go
index 70fe25c4e7..49c68c9469 100644
--- a/lxd/instance/drivers/driver_lxc.go
+++ b/lxd/instance/drivers/driver_lxc.go
@@ -3274,7 +3274,7 @@ func (c *lxc) Snapshots() ([]instance.Instance, error) {
 }
 
 // Backups returns the backups of the instance.
-func (c *lxc) Backups() ([]backup.Backup, error) {
+func (c *lxc) Backups() ([]backup.InstanceBackup, error) {
 	// Get all the backups
 	backupNames, err := c.state.Cluster.GetInstanceBackups(c.project, c.name)
 	if err != nil {
@@ -3282,7 +3282,7 @@ func (c *lxc) Backups() ([]backup.Backup, error) {
 	}
 
 	// Build the backup list
-	backups := []backup.Backup{}
+	backups := []backup.InstanceBackup{}
 	for _, backupName := range backupNames {
 		backup, err := instance.BackupLoadByName(c.state, c.project, backupName)
 		if err != nil {
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index c0ad24b982..8572365fb2 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -2505,8 +2505,8 @@ func (vm *qemu) Snapshots() ([]instance.Instance, error) {
 }
 
 // Backups returns a list of backups.
-func (vm *qemu) Backups() ([]backup.Backup, error) {
-	return []backup.Backup{}, nil
+func (vm *qemu) Backups() ([]backup.InstanceBackup, error) {
+	return []backup.InstanceBackup{}, nil
 }
 
 // Rename the instance.


More information about the lxc-devel mailing list