From fd3ba834960279cff58141cbf24b7387ac821b49 Mon Sep 17 00:00:00 2001 From: Baha Aiman Date: Wed, 25 Dec 2024 23:07:41 +0000 Subject: [PATCH] include expire time in options --- bigtable/admin.go | 74 +++++++++++++++++++++--------------- bigtable/admin_test.go | 10 +++++ bigtable/integration_test.go | 6 +-- 3 files changed, 56 insertions(+), 34 deletions(-) diff --git a/bigtable/admin.go b/bigtable/admin.go index 3018597020d8..794f27aaa2bc 100644 --- a/bigtable/admin.go +++ b/bigtable/admin.go @@ -47,6 +47,8 @@ import ( const adminAddr = "bigtableadmin.googleapis.com:443" const mtlsAdminAddr = "bigtableadmin.mtls.googleapis.com:443" +var errExpiryMissing = errors.New("WithExpiry is a required option") + // ErrPartiallyUnavailable is returned when some locations (clusters) are // unavailable. Both partial results (retrieved from available locations) // and the error are returned when this exception occurred. @@ -2153,54 +2155,69 @@ func (ac *AdminClient) RestoreTableFrom(ctx context.Context, sourceInstance, tab type backupOptions struct { backupType *BackupType hotToStandardTime *time.Time + expireTime *time.Time } // BackupOption can be used to specify parameters for backup operations. -type BackupOption interface { - apply(o *backupOptions) -} - -type hotBackupOption struct { - htsTime *time.Time -} - -func (hbo hotBackupOption) apply(o *backupOptions) { - o.hotToStandardTime = hbo.htsTime - btHot := BackupTypeHot - o.backupType = &btHot -} +type BackupOption func(*backupOptions) -// HotToStandardBackup option can be used to create backup with +// WithHotToStandardBackup option can be used to create backup with // type [BackupTypeHot] and specify time at which the hot backup will be -// converted to a standard backup. Once the `hot_to_standard_time` has passed, +// converted to a standard backup. Once the 'hotToStandardTime' has passed, // Cloud Bigtable will convert the hot backup to a standard backup. // This value must be greater than the backup creation time by at least 24 hours -func HotToStandardBackup(hotToStandardTime time.Time) BackupOption { - return hotBackupOption{htsTime: &hotToStandardTime} +func WithHotToStandardBackup(hotToStandardTime time.Time) BackupOption { + return func(bo *backupOptions) { + btHot := BackupTypeHot + bo.backupType = &btHot + bo.hotToStandardTime = &hotToStandardTime + } +} + +// WithExpiry option can be used to create backup +// that expires after time 'expireTime'. +// Once the 'expireTime' has passed, Cloud Bigtable will delete the backup. +func WithExpiry(expireTime time.Time) BackupOption { + return func(bo *backupOptions) { + bo.expireTime = &expireTime + } } -// HotBackup option can be used to create backup +// WithHotBackup option can be used to create backup // with type [BackupTypeHot] -func HotBackup() BackupOption { - return hotBackupOption{} +func WithHotBackup() BackupOption { + return func(bo *backupOptions) { + btHot := BackupTypeHot + bo.backupType = &btHot + } } // CreateBackup creates a new backup in the specified cluster from the // specified source table with the user-provided expire time. func (ac *AdminClient) CreateBackup(ctx context.Context, table, cluster, backup string, expireTime time.Time) error { - return ac.createBackup(ctx, table, cluster, backup, expireTime, nil) + return ac.createBackup(ctx, table, cluster, backup, WithExpiry(expireTime)) } // CreateBackupWithOptions is similar to CreateBackup but lets the user specify additional options. -func (ac *AdminClient) CreateBackupWithOptions(ctx context.Context, table, cluster, backup string, expireTime time.Time, opts ...BackupOption) error { - return ac.createBackup(ctx, table, cluster, backup, expireTime, opts...) +func (ac *AdminClient) CreateBackupWithOptions(ctx context.Context, table, cluster, backup string, opts ...BackupOption) error { + return ac.createBackup(ctx, table, cluster, backup, opts...) } -func (ac *AdminClient) createBackup(ctx context.Context, table, cluster, backup string, expireTime time.Time, opts ...BackupOption) error { +func (ac *AdminClient) createBackup(ctx context.Context, table, cluster, backup string, opts ...BackupOption) error { ctx = mergeOutgoingMetadata(ctx, ac.md) prefix := ac.instancePrefix() - parsedExpireTime := timestamppb.New(expireTime) + o := backupOptions{} + for _, opt := range opts { + if opt != nil { + opt(&o) + } + } + + if o.expireTime == nil { + return errExpiryMissing + } + parsedExpireTime := timestamppb.New(*o.expireTime) req := &btapb.CreateBackupRequest{ Parent: prefix + "/clusters/" + cluster, @@ -2210,12 +2227,7 @@ func (ac *AdminClient) createBackup(ctx context.Context, table, cluster, backup SourceTable: prefix + "/tables/" + table, }, } - o := backupOptions{} - for _, opt := range opts { - if opt != nil { - opt.apply(&o) - } - } + if o.backupType != nil { req.Backup.BackupType = btapb.Backup_BackupType(*o.backupType) } diff --git a/bigtable/admin_test.go b/bigtable/admin_test.go index 445aa447fbed..ed5ecc53f518 100644 --- a/bigtable/admin_test.go +++ b/bigtable/admin_test.go @@ -205,6 +205,16 @@ func TestTableAdmin_CreateTableFromConf_AutomatedBackupPolicy_Valid(t *testing.T } } +func TestTableAdmin_CreateBackupWithOptions_NoExpiryTime(t *testing.T) { + mock := &mockTableAdminClock{} + c := setupTableClient(t, mock) + + err := c.CreateBackupWithOptions(context.Background(), "table", "cluster", "backup-01") + if err == nil || !errors.Is(err, errExpiryMissing) { + t.Errorf("CreateBackupWithOptions got: %v, want: %v error", err, errExpiryMissing) + } +} + func TestTableAdmin_CopyBackup_ErrorFromClient(t *testing.T) { mock := &mockTableAdminClock{} c := setupTableClient(t, mock) diff --git a/bigtable/integration_test.go b/bigtable/integration_test.go index 0b69cb7940a2..67a4f0cd9bf8 100644 --- a/bigtable/integration_test.go +++ b/bigtable/integration_test.go @@ -3757,7 +3757,7 @@ func TestIntegration_AdminBackup(t *testing.T) { defer adminClient.DeleteBackup(ctx, sourceCluster, hotBkpName1) wantHtsTime := time.Now().Truncate(time.Second).Add(48 * time.Hour) if err = adminClient.CreateBackupWithOptions(ctx, tblConf.TableID, sourceCluster, hotBkpName1, - time.Now().Add(8*time.Hour), HotToStandardBackup(wantHtsTime)); err != nil { + WithExpiry(time.Now().Add(8*time.Hour)), WithHotToStandardBackup(wantHtsTime)); err != nil { t.Fatalf("Creating backup: %v", err) } @@ -3765,7 +3765,7 @@ func TestIntegration_AdminBackup(t *testing.T) { hotBkpName2 := backupUID.New() defer adminClient.DeleteBackup(ctx, sourceCluster, hotBkpName2) if err = adminClient.CreateBackupWithOptions(ctx, tblConf.TableID, sourceCluster, hotBkpName2, - time.Now().Add(8*time.Hour), HotBackup()); err != nil { + WithExpiry(time.Now().Add(8*time.Hour)), WithHotBackup()); err != nil { t.Fatalf("Creating backup: %v", err) } @@ -3946,7 +3946,7 @@ func TestIntegration_AdminUpdateBackupHotToStandardTime(t *testing.T) { bkpName := backupUID.New() defer adminClient.DeleteBackup(ctx, testEnv.Config().Cluster, bkpName) if err = adminClient.CreateBackupWithOptions(ctx, tblConf.TableID, testEnv.Config().Cluster, bkpName, - time.Now().Add(8*time.Hour), HotToStandardBackup(time.Now().Truncate(time.Second).Add(2*24*time.Hour))); err != nil { + WithExpiry(time.Now().Add(8*time.Hour)), WithHotToStandardBackup(time.Now().Truncate(time.Second).Add(2*24*time.Hour))); err != nil { t.Fatalf("Creating backup: %v", err) }