File: backup_bucket.go

package info (click to toggle)
incus 6.0.5-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 24,428 kB
  • sloc: sh: 16,313; ansic: 3,121; python: 457; makefile: 337; ruby: 51; sql: 50; lisp: 6
file content (134 lines) | stat: -rw-r--r-- 4,011 bytes parent folder | download | duplicates (5)
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package backup

import (
	"context"
	"os"
	"time"

	"github.com/lxc/incus/v6/internal/server/db"
	"github.com/lxc/incus/v6/internal/server/project"
	"github.com/lxc/incus/v6/internal/server/state"
	internalUtil "github.com/lxc/incus/v6/internal/util"
	"github.com/lxc/incus/v6/shared/api"
	"github.com/lxc/incus/v6/shared/revert"
	"github.com/lxc/incus/v6/shared/util"
)

// BucketBackup represents a bucket backup.
type BucketBackup struct {
	CommonBackup

	projectName string
	poolName    string
	bucketName  string
}

// NewBucketBackup instantiates a new BucketBackup struct.
func NewBucketBackup(s *state.State, projectName, poolName, bucketName string, ID int, name string, creationDate, expiryDate time.Time) *BucketBackup {
	return &BucketBackup{
		CommonBackup: CommonBackup{
			state:        s,
			id:           ID,
			name:         name,
			creationDate: creationDate,
			expiryDate:   expiryDate,
		},
		projectName: projectName,
		poolName:    poolName,
		bucketName:  bucketName,
	}
}

// Delete removes a bucket backup.
func (b *BucketBackup) Delete() error {
	backupPath := internalUtil.VarPath("backups", "buckets", b.poolName, project.StorageBucket(b.projectName, b.name))
	// Delete the on-disk data.
	if util.PathExists(backupPath) {
		err := os.RemoveAll(backupPath)
		if err != nil {
			return err
		}
	}

	// Check if we can remove the bucket directory.
	backupsPath := internalUtil.VarPath("backups", "buckets", b.poolName, project.StorageBucket(b.projectName, b.bucketName))
	empty, _ := internalUtil.PathIsEmpty(backupsPath)
	if empty {
		err := os.Remove(backupsPath)
		if err != nil {
			return err
		}
	}

	// Remove the database record.
	err := b.state.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
		return tx.DeleteStoragePoolBucketBackup(ctx, b.name)
	})
	if err != nil {
		return err
	}

	return nil
}

// Rename renames a bucket backup.
func (b *BucketBackup) Rename(newName string) error {
	oldBackupPath := internalUtil.VarPath("backups", "buckets", b.poolName, project.StorageBucket(b.projectName, b.name))
	newBackupPath := internalUtil.VarPath("backups", "buckets", b.poolName, project.StorageBucket(b.projectName, newName))

	// Extract the old and new parent backup paths from the old and new backup names rather than use
	// bucket.Name() as this may be in flux if the bucket itself is being renamed, whereas the relevant
	// bucket name is encoded into the backup names.
	oldParentName, _, _ := api.GetParentAndSnapshotName(b.name)
	oldParentBackupsPath := internalUtil.VarPath("backups", "buckets", b.poolName, project.StorageBucket(b.projectName, oldParentName))
	newParentName, _, _ := api.GetParentAndSnapshotName(newName)
	newParentBackupsPath := internalUtil.VarPath("backups", "buckets", b.poolName, project.StorageBucket(b.projectName, newParentName))

	reverter := revert.New()
	defer reverter.Fail()

	// Create the new backup path if doesn't exist.
	if !util.PathExists(newParentBackupsPath) {
		err := os.MkdirAll(newParentBackupsPath, 0o700)
		if err != nil {
			return err
		}
	}

	// Rename the backup directory.
	err := os.Rename(oldBackupPath, newBackupPath)
	if err != nil {
		return err
	}

	reverter.Add(func() { _ = os.Rename(newBackupPath, oldBackupPath) })

	// Check if we can remove the old parent directory.
	empty, _ := internalUtil.PathIsEmpty(oldParentBackupsPath)
	if empty {
		err := os.Remove(oldParentBackupsPath)
		if err != nil {
			return err
		}
	}

	// Rename the database record.
	err = b.state.DB.Cluster.Transaction(context.TODO(), func(ctx context.Context, tx *db.ClusterTx) error {
		return tx.RenameBucketBackup(ctx, b.name, newName)
	})
	if err != nil {
		return err
	}

	reverter.Success()
	return nil
}

// Render returns a BucketBackup struct of the backup.
func (b *BucketBackup) Render() *api.StorageBucketBackup {
	return &api.StorageBucketBackup{
		Name:                 b.name,
		ExpiresAt:            b.expiryDate,
		CompressionAlgorithm: b.compressionAlgorithm,
	}
}