Skip to content

Commit

Permalink
test rebindVSC pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
majodev committed Oct 30, 2024
1 parent 1845952 commit 7fa7fb9
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 72 deletions.
75 changes: 4 additions & 71 deletions cmd/rebindVsc.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cmd

import (
"fmt"
"log"

"github.com/allaboutapps/backup-ns/internal/lib"
Expand All @@ -18,7 +17,10 @@ from the VolumeSnapshotContent.`,
Args: cobra.ExactArgs(1),
Run: func(_ *cobra.Command, args []string) {
vscName := args[0]
if err := rebindVsc(vscName); err != nil {

config := lib.LoadConfig()

if err := lib.RebindVsc(vscName, config.VSRand, config.VSWaitUntilReady, config.VSWaitUntilReadyTimeout); err != nil {
log.Fatalf("Error rebinding VSC: %v", err)
}
},
Expand All @@ -27,72 +29,3 @@ from the VolumeSnapshotContent.`,
func init() {
rootCmd.AddCommand(rebindVscCmd)
}

func rebindVsc(oldVSCName string) error {
config := lib.LoadConfig()

// Get the VolumeSnapshotContent object
oldVSCObject, err := lib.GetVolumeSnapshotContentObject(oldVSCName)
if err != nil {
return fmt.Errorf("failed to get VolumeSnapshotContent object: %w", err)
}

// Create a restored VSC from the existing VSC
restoredVSC, err := lib.CreatePreProvisionedVSC(oldVSCObject, config.VSRand)
if err != nil {
return fmt.Errorf("failed to create restored VolumeSnapshotContent: %w", err)
}

// Generate the VolumeSnapshot object from the restored VolumeSnapshotContent
vsObject, err := lib.GenerateVSObjectFromVSC(restoredVSC["metadata"].(map[string]interface{})["name"].(string), restoredVSC)
if err != nil {
return fmt.Errorf("failed to generate VolumeSnapshot object: %w", err)
}

// Extract necessary information from the generated VS object
metadata, ok := vsObject["metadata"].(map[string]interface{})
if !ok {
return fmt.Errorf("invalid metadata in generated VolumeSnapshot object")
}

namespace, ok := metadata["namespace"].(string)
if !ok {
return fmt.Errorf("invalid namespace in generated VolumeSnapshot object")
}

vsName, ok := metadata["name"].(string)
if !ok {
return fmt.Errorf("invalid name in generated VolumeSnapshot object")
}

// Create the VolumeSnapshot
err = lib.CreateVolumeSnapshot(namespace, false, vsName, vsObject, config.VSWaitUntilReady, config.VSWaitUntilReadyTimeout)
if err != nil {
return fmt.Errorf("failed to create VolumeSnapshot: %w", err)
}

fmt.Printf("Successfully rebound old VolumeSnapshotContent '%s' to new VolumeSnapshot '%s' in namespace '%s'\n", oldVSCName, vsName, namespace)

// Delete the old VolumeSnapshotContent after making sure its deletionPolicy is 'Retain'
fmt.Printf("Attempting to delete old VolumeSnapshotContent '%s'...\n", oldVSCName)

deletionPolicy, ok := oldVSCObject["spec"].(map[string]interface{})["deletionPolicy"].(string)
if !ok {
return fmt.Errorf("deletionPolicy not found in old VolumeSnapshotContent")
}

if deletionPolicy != "Retain" {
return fmt.Errorf("deletionPolicy is not 'Retain' in old VolumeSnapshotContent, refusing to delete")
}

fmt.Printf("Old VolumeSnapshotContent '%s' has deletionPolicy 'Retain' set and is thus safe to delete! Deleting...\n", oldVSCName)

err = lib.DeleteVolumeSnapshotContent(oldVSCName)
if err != nil {
return fmt.Errorf("failed to delete old VolumeSnapshotContent: %w", err)
}

fmt.Printf("Successfully deleted old VolumeSnapshotContent '%s'\n", oldVSCName)

return nil
}
68 changes: 68 additions & 0 deletions internal/lib/vsc.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,74 @@ func DeleteVolumeSnapshotContent(volumeSnapshotContentName string) error {
return nil
}

func RebindVsc(oldVSCName, vsRand string, wait bool, waitTimeout string) error {

// Get the VolumeSnapshotContent object
oldVSCObject, err := GetVolumeSnapshotContentObject(oldVSCName)
if err != nil {
return fmt.Errorf("failed to get VolumeSnapshotContent object: %w", err)
}

// Create a restored VSC from the existing VSC
restoredVSC, err := CreatePreProvisionedVSC(oldVSCObject, vsRand)
if err != nil {
return fmt.Errorf("failed to create restored VolumeSnapshotContent: %w", err)
}

// Generate the VolumeSnapshot object from the restored VolumeSnapshotContent
vsObject, err := GenerateVSObjectFromVSC(restoredVSC["metadata"].(map[string]interface{})["name"].(string), restoredVSC)
if err != nil {
return fmt.Errorf("failed to generate VolumeSnapshot object: %w", err)
}

// Extract necessary information from the generated VS object
metadata, ok := vsObject["metadata"].(map[string]interface{})
if !ok {
return fmt.Errorf("invalid metadata in generated VolumeSnapshot object")
}

namespace, ok := metadata["namespace"].(string)
if !ok {
return fmt.Errorf("invalid namespace in generated VolumeSnapshot object")
}

vsName, ok := metadata["name"].(string)
if !ok {
return fmt.Errorf("invalid name in generated VolumeSnapshot object")
}

// Create the VolumeSnapshot
err = CreateVolumeSnapshot(namespace, false, vsName, vsObject, wait, waitTimeout)
if err != nil {
return fmt.Errorf("failed to create VolumeSnapshot: %w", err)
}

fmt.Printf("Successfully rebound old VolumeSnapshotContent '%s' to new VolumeSnapshot '%s' in namespace '%s'\n", oldVSCName, vsName, namespace)

// Delete the old VolumeSnapshotContent after making sure its deletionPolicy is 'Retain'
fmt.Printf("Attempting to delete old VolumeSnapshotContent '%s'...\n", oldVSCName)

deletionPolicy, ok := oldVSCObject["spec"].(map[string]interface{})["deletionPolicy"].(string)
if !ok {
return fmt.Errorf("deletionPolicy not found in old VolumeSnapshotContent")
}

if deletionPolicy != "Retain" {
return fmt.Errorf("deletionPolicy is not 'Retain' in old VolumeSnapshotContent, refusing to delete")
}

fmt.Printf("Old VolumeSnapshotContent '%s' has deletionPolicy 'Retain' set and is thus safe to delete! Deleting...\n", oldVSCName)

err = DeleteVolumeSnapshotContent(oldVSCName)
if err != nil {
return fmt.Errorf("failed to delete old VolumeSnapshotContent: %w", err)
}

fmt.Printf("Successfully deleted old VolumeSnapshotContent '%s'\n", oldVSCName)

return nil
}

// func deepCopy(src, dst map[string]interface{}) {
// for k, v := range src {
// switch v := v.(type) {
Expand Down
37 changes: 36 additions & 1 deletion internal/lib/vsc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestSyncVSLabelsToVsc(t *testing.T) {
test.Snapshoter.Redact("backup-ns.sh/delete-after").SaveJSON(t, postSyncLabelMap)
}

func TestRebindVSC(t *testing.T) {
func TestPreProvisionedVSC(t *testing.T) {

namespace, vsName := createTestVS(t)

Expand Down Expand Up @@ -112,6 +112,41 @@ func TestRebindVSC(t *testing.T) {
test.Snapshoter.Redact("backup-ns.sh/delete-after").SaveJSON(t, postSyncLabelMap)
}

func TestRebindVSC(t *testing.T) {

rndStr := lib.GenerateRandomStringOrPanic(6)

namespace, vsName := createTestVS(t)

// sync labels
require.NoError(t, lib.SyncVSLabelsToVsc(namespace, vsName))

// grab the created VSC name
vscName, err := lib.GetVolumeSnapshotContentName(namespace, vsName)
require.NoError(t, err)

// now delete the vs without affecting the VSC (like what would happen if the ns was deleted)
cmd := exec.Command("kubectl", "-n", namespace, "delete", "volumesnapshot", vsName)
require.NoError(t, cmd.Run())

// Rebind the VSC to a new VS
require.NoError(t, lib.RebindVsc(vscName, rndStr, true, "25s"))

// old vsc should now be gone -> error!
_, err = lib.GetVolumeSnapshotContentObject(vscName)
require.Error(t, err)

// new vs should be created with the name "test-backup-generic-random"
newVsName := fmt.Sprintf("test-backup-generic-%s", rndStr)

// grab the created VSC name
newVscName, err := lib.GetVolumeSnapshotContentName(namespace, newVsName)
require.NoError(t, err)

// new vsc name should start with "restoredvsc-"
require.Contains(t, newVscName, "restoredvsc-")
}

func TestSyncVSLabelsToVscFail(t *testing.T) {
vsName := "test-backup-generic-not-available"
namespace := "generic-test"
Expand Down

0 comments on commit 7fa7fb9

Please sign in to comment.