Skip to content

Commit ce177f6

Browse files
Rewrite executor for standalone restic
Signed-off-by: Anisur Rahman <anisur@appscode.com>
1 parent 05fc8da commit ce177f6

1,178 files changed

Lines changed: 93423 additions & 41049 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build topolvm
2-
FROM --platform=$BUILDPLATFORM golang:1.24-bookworm AS build-topolvm
2+
FROM --platform=$BUILDPLATFORM golang:1.25-bookworm AS build-topolvm
33

44
# Get argument
55
ARG TOPOLVM_VERSION

api/legacy/v1/logicalvolume_types.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ type SnapshotStatus struct {
7272
// Error contains details if the operation encountered an error.
7373
// +optional
7474
Error *SnapshotError `json:"error,omitempty"`
75-
// Paths are the paths that were backed up or restored
75+
// Path represents the directory inside the SnapshotStorage where this backup was stored.
7676
// +optional
77-
Paths []string `json:"paths,omitempty"`
78-
// Repository is the Restic repository path where the snapshot is stored
77+
Path string `json:"path,omitempty"`
78+
// Repository is the Restic repository path/url where the snapshot is stored
7979
// +optional
8080
Repository string `json:"repository,omitempty"`
8181
// SnapshotID is the identifier of the Restic snapshot involved in the operation.

api/legacy/v1/zz_generated.deepcopy.go

Lines changed: 0 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/v1/logicalvolume_types.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ type SnapshotStatus struct {
7272
// Error contains details if the operation encountered an error.
7373
// +optional
7474
Error *SnapshotError `json:"error,omitempty"`
75-
// Paths are the paths that were backed up or restored
75+
// Path represents the directory inside the SnapshotStorage where this backup was stored.
7676
// +optional
77-
Paths []string `json:"paths,omitempty"`
78-
// Repository is the Restic repository path where the snapshot is stored
77+
Path string `json:"path,omitempty"`
78+
// Repository is the Restic repository path/url where the snapshot is stored
7979
// +optional
8080
Repository string `json:"repository,omitempty"`
8181
// SnapshotID is the identifier of the Restic snapshot involved in the operation.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package v1
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
core "k8s.io/api/core/v1"
8+
"kubestash.dev/apimachinery/pkg/restic"
9+
"sigs.k8s.io/controller-runtime/pkg/client"
10+
)
11+
12+
// NewSnapshotStorageResolver creates a StorageConfigResolver that resolves storage configuration
13+
func NewSnapshotStorageResolver(kbClient client.Client, bs *SnapshotBackupStorage) restic.StorageConfigResolver {
14+
return func(backend *restic.Backend) error {
15+
var storageSecretName string
16+
switch {
17+
case bs.Spec.Storage.S3 != nil:
18+
s3 := bs.Spec.Storage.S3
19+
storageSecretName = s3.SecretName
20+
backend.StorageConfig = &restic.StorageConfig{
21+
Provider: string(ProviderS3),
22+
Bucket: s3.Bucket,
23+
Endpoint: s3.Endpoint,
24+
Region: s3.Region,
25+
Prefix: s3.Prefix,
26+
InsecureTLS: s3.InsecureTLS,
27+
MaxConnections: s3.MaxConnections,
28+
}
29+
case bs.Spec.Storage.GCS != nil:
30+
gcs := bs.Spec.Storage.GCS
31+
storageSecretName = gcs.SecretName
32+
backend.StorageConfig = &restic.StorageConfig{
33+
Provider: string(ProviderGCS),
34+
Bucket: gcs.Bucket,
35+
Prefix: gcs.Prefix,
36+
MaxConnections: gcs.MaxConnections,
37+
}
38+
case bs.Spec.Storage.Azure != nil:
39+
azure := bs.Spec.Storage.Azure
40+
storageSecretName = azure.SecretName
41+
backend.StorageConfig = &restic.StorageConfig{
42+
Provider: string(ProviderAzure),
43+
Bucket: azure.Container,
44+
Prefix: azure.Prefix,
45+
AzureStorageAccount: azure.StorageAccount,
46+
MaxConnections: azure.MaxConnections,
47+
}
48+
default:
49+
return fmt.Errorf("no storage backend configured in BackupStorage %s/%s", bs.Namespace, bs.Name)
50+
}
51+
52+
if storageSecretName != "" {
53+
secret := &core.Secret{}
54+
if err := kbClient.Get(context.Background(), client.ObjectKey{Name: storageSecretName, Namespace: bs.Namespace}, secret); err != nil {
55+
return fmt.Errorf("failed to get storage Secret %s/%s: %w", bs.Namespace, storageSecretName, err)
56+
}
57+
backend.StorageSecret = secret
58+
backend.EncryptionSecret = secret
59+
}
60+
return nil
61+
}
62+
}

api/v1/zz_generated.deepcopy.go

Lines changed: 0 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

charts/topolvm-15.7.1.tgz

-160 KB
Binary file not shown.

charts/topolvm/templates/crds/topolvm.cybozu.com_logicalvolumes.yaml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,10 @@ spec:
177177
description: Operation indicates whether this status is for a
178178
backup or a restore.
179179
type: string
180-
paths:
181-
description: Paths are the paths that were backed up or restored
182-
items:
183-
type: string
184-
type: array
180+
path:
181+
description: Path represents the directory inside the SnapshotStorage
182+
where this backup was stored.
183+
type: string
185184
phase:
186185
description: Phase represents the current phase of the backup
187186
or restore operation.
@@ -202,8 +201,8 @@ spec:
202201
type: integer
203202
type: object
204203
repository:
205-
description: Repository is the Restic repository path where the
206-
snapshot is stored
204+
description: Repository is the Restic repository path/url where
205+
the snapshot is stored
207206
type: string
208207
snapshotID:
209208
description: SnapshotID is the identifier of the Restic snapshot

charts/topolvm/templates/crds/topolvm.io_logicalvolumes.yaml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,10 @@ spec:
177177
description: Operation indicates whether this status is for a
178178
backup or a restore.
179179
type: string
180-
paths:
181-
description: Paths are the paths that were backed up or restored
182-
items:
183-
type: string
184-
type: array
180+
path:
181+
description: Path represents the directory inside the SnapshotStorage
182+
where this backup was stored.
183+
type: string
185184
phase:
186185
description: Phase represents the current phase of the backup
187186
or restore operation.
@@ -202,8 +201,8 @@ spec:
202201
type: integer
203202
type: object
204203
repository:
205-
description: Repository is the Restic repository path where the
206-
snapshot is stored
204+
description: Repository is the Restic repository path/url where
205+
the snapshot is stored
207206
type: string
208207
snapshotID:
209208
description: SnapshotID is the identifier of the Restic snapshot

cmd/topolvm-snapshotter/app/backup.go

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func newBackupCommand() *cobra.Command {
4545
Use: "backup",
4646
Short: "Take an online snapshot of a logical volume",
4747
Long: `The backup command performs an online snapshot of a logical volume.
48-
It backs up the mounted filesystem to a remote repository using Restic or Kopia.`,
48+
It backs up the mounted filesystem to a remote repoPath using Restic or Kopia.`,
4949
RunE: func(cmd *cobra.Command, args []string) error {
5050
ctx := context.Background()
5151
bOpt.log = ctrl.Log.WithName("backup")
@@ -152,13 +152,7 @@ func (opt *BackupOptions) performBackup(ctx context.Context) error {
152152
"nodeName", opt.nodeName,
153153
"mountPath", opt.mountPath)
154154

155-
pvider, err := opt.getBackupProvider()
156-
if err != nil {
157-
opt.handleBackupError(ctx, "failed to initialize backup provider", err)
158-
return err
159-
}
160-
161-
result, err := opt.executeBackup(ctx, pvider)
155+
result, err := opt.executeBackup(ctx)
162156
if err != nil {
163157
opt.handleBackupError(ctx, "backup execution failed", err)
164158
return err
@@ -170,24 +164,16 @@ func (opt *BackupOptions) performBackup(ctx context.Context) error {
170164
return nil
171165
}
172166

173-
func (opt *BackupOptions) getBackupProvider() (provider.Provider, error) {
174-
pvider, err := provider.GetProvider(opt.client, opt.snapshotStorage)
175-
if err != nil {
176-
return nil, fmt.Errorf("failed to get snapshot provider: %w", err)
177-
}
178-
opt.log.Info("backup provider initialized", "engine", opt.snapshotStorage.Spec.Engine)
179-
return pvider, nil
180-
}
181-
182-
func (opt *BackupOptions) executeBackup(ctx context.Context, pvider provider.Provider) (*provider.BackupResult, error) {
167+
func (opt *BackupOptions) executeBackup(ctx context.Context) (*provider.BackupResult, error) {
183168
params := opt.buildBackupParams()
184169
opt.log.Info("executing backup with params",
185-
"repository", params.Suffix,
186-
"paths", params.BackupPaths,
187-
"exclude", params.Exclude,
188-
"args", params.Args,
170+
"repo-name", params.Repo.Name, "repo-path", params.Repo.Path,
171+
"backup-paths", params.BackupPaths, "exclude", params.Exclude, "args", params.Args,
189172
)
190-
173+
pvider, err := getProvider(opt.client, opt.log, opt.snapshotStorage, params.Repo)
174+
if err != nil {
175+
return nil, fmt.Errorf("failed to initialize backup provider: %w", err)
176+
}
191177
result, err := pvider.Backup(ctx, params)
192178
if err != nil {
193179
return nil, fmt.Errorf("backup operation failed: %w", err)
@@ -204,7 +190,7 @@ func (opt *BackupOptions) handleBackupError(ctx context.Context, message string,
204190
opt.log.Error(err, message, "lvName", opt.lvName)
205191

206192
errorMsg := err.Error()
207-
if updateErr := setStatusFailed(ctx, opt.client, opt.logicalVol, errorMsg); updateErr != nil {
193+
if updateErr := setStatusFailed(ctx, opt.client, opt.logicalVol, backupErrorCode, errorMsg); updateErr != nil {
208194
opt.log.Error(updateErr, "failed to update error status", "originalError", errorMsg)
209195
}
210196

@@ -228,12 +214,15 @@ func (opt *BackupOptions) handleBackupSuccess(ctx context.Context, result *provi
228214
return nil
229215
}
230216

231-
func (opt *BackupOptions) buildBackupParams() provider.BackupParam {
232-
return provider.BackupParam{
233-
RepoRef: provider.RepoRef{
234-
Suffix: filepath.Join(opt.targetedPVCRef.Namespace, opt.targetedPVCRef.Name),
217+
func (opt *BackupOptions) buildBackupParams() *provider.BackupParam {
218+
return &provider.BackupParam{
219+
Client: opt.client,
220+
Namespace: getNamespace(),
221+
Repo: &provider.RepoInf{
222+
Name: filepath.Join(opt.targetedPVCRef.Namespace, opt.targetedPVCRef.Name),
223+
Path: filepath.Join(opt.targetedPVCRef.Namespace, opt.targetedPVCRef.Name),
235224
},
236-
BackupPaths: []string{opt.mountPath},
225+
BackupPaths: []string{filepath.Join("/", opt.mountPath)},
237226
}
238227
}
239228

@@ -272,6 +261,7 @@ func (opt *BackupOptions) setStatusSuccess(ctx context.Context, result *provider
272261
lv.Status.Snapshot.Duration = result.Duration
273262
lv.Status.Snapshot.Version = result.Provider
274263
lv.Status.Snapshot.Error = nil
264+
lv.Status.Snapshot.Path = result.Path
275265
lv.Status.Snapshot.Repository = result.Repository
276266
if err := opt.client.Status().Update(ctx, lv); err != nil {
277267
return fmt.Errorf("failed to update status: %w", err)

0 commit comments

Comments
 (0)