forked from canonical/lxd
/
backup_config.go
116 lines (93 loc) · 2.79 KB
/
backup_config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package backup
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"gopkg.in/yaml.v2"
"github.com/lxc/lxd/lxd/db"
"github.com/lxc/lxd/shared"
"github.com/lxc/lxd/shared/api"
)
// 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,omitempty"` // Used by VM backups too.
Snapshots []*api.InstanceSnapshot `yaml:"snapshots,omitempty"`
Pool *api.StoragePool `yaml:"pool,omitempty"`
Volume *api.StorageVolume `yaml:"volume,omitempty"`
VolumeSnapshots []*api.StorageVolumeSnapshot `yaml:"volume_snapshots,omitempty"`
}
// 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 := Config{}
if err := yaml.Unmarshal(data, &backup); err != nil {
return nil, err
}
return &backup, nil
}
// updateRootDevicePool updates the root disk device in the supplied list of devices to the pool
// specified. Returns true if a root disk device has been found and updated otherwise false.
func updateRootDevicePool(devices map[string]map[string]string, poolName string) bool {
if devices != nil {
devName, _, err := shared.GetRootDiskDevice(devices)
if err == nil {
devices[devName]["pool"] = poolName
return true
}
}
return false
}
// 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)
if err != nil {
return err
}
f := func(path string) error {
// Read in the backup.yaml file.
backup, err := ParseConfigYamlFile(path)
if err != nil {
return err
}
rootDiskDeviceFound := false
// Change the pool in the backup.yaml.
backup.Pool = pool
if updateRootDevicePool(backup.Container.Devices, pool.Name) {
rootDiskDeviceFound = true
}
if updateRootDevicePool(backup.Container.ExpandedDevices, pool.Name) {
rootDiskDeviceFound = true
}
for _, snapshot := range backup.Snapshots {
updateRootDevicePool(snapshot.Devices, pool.Name)
updateRootDevicePool(snapshot.ExpandedDevices, pool.Name)
}
if !rootDiskDeviceFound {
return fmt.Errorf("No root device could be found")
}
file, err := os.Create(path)
if err != nil {
return err
}
defer file.Close()
data, err := yaml.Marshal(&backup)
if err != nil {
return err
}
_, err = file.Write(data)
if err != nil {
return err
}
return nil
}
err = f(filepath.Join(mountPath, "backup.yaml"))
if err != nil {
return err
}
return nil
}