[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