You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(pre-sync-mode): copy RWX PVCs without actually swapping them
permits to reduce the downtime for the actual migration
can typically be used with RWX PVCs to create all destination
PVCs and already rsync the data, without having to scale down
the pods/deployments/statefulsets.
at a later stage, the actual swap of the PVC can be done, with
a lesser time duration, as most of the data will already have
been rsync'ed
Signed-off-by: Clément Nussbaumer <[email protected]>
fix(pre-sync-mode): skip volumes not supporting RWX access mode
Signed-off-by: Clément Nussbaumer <[email protected]>
fix: proper matching PVCs count
Signed-off-by: Clément Nussbaumer <[email protected]>
feat: add max-pvs=n flags
Signed-off-by: Clément Nussbaumer <[email protected]>
feat(pre-sync-mode): run a "prefetch" copy before actually migrating
Signed-off-by: Clément Nussbaumer <[email protected]>
Copy file name to clipboardExpand all lines: cmd/main.go
+2Lines changed: 2 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -39,7 +39,9 @@ func main() {
39
39
flag.StringVar(&options.Namespace, "namespace", "", "only migrate PVCs within this namespace")
40
40
flag.BoolVar(&options.SetDefaults, "set-defaults", false, "change default storage class from source to dest")
41
41
flag.BoolVar(&options.VerboseCopy, "verbose-copy", false, "show output from the rsync command used to copy data between PVCs")
42
+
flag.BoolVar(&options.PreSyncMode, "pre-sync-mode", false, "create the new PVC and copy the data, then scale down, run another copy and finally swap the PVCs")
42
43
flag.BoolVar(&options.SkipSourceValidation, "skip-source-validation", false, "migrate from PVCs using a particular StorageClass name, even if that StorageClass does not exist")
44
+
flag.IntVar(&options.MaxPVs, "max-pvs", 0, "maximum number of PVs to process. default to 0 (unlimited)")
43
45
flag.IntVar(&podReadyTimeout, "pod-ready-timeout", 60, "length of time to wait (in seconds) for validation pod(s) to go into Ready phase")
44
46
flag.IntVar(&deletePVTimeout, "delete-pv-timeout", 300, "length of time to wait (in seconds) for backing PV to be removed when temporary PVC is deleted")
45
47
flag.BoolVar(&skipPreflightValidation, "skip-preflight-validation", false, "skip preflight migration validation on the destination storage provider")
w.Println("\nRunning in pre-sync-mode: we first copy the PVC live, without scaling down pods. Once that pre-sync is completed, we scale down, do another copy/sync and finally swap the PVCs.")
returnnil, fmt.Errorf("migration pod %s in %s leftover from a previous run failed to delete, please delete it before retrying: %w", nsPod.Name, ns, err)
798
+
returnfmt.Errorf("migration pod %s in %s leftover from a previous run failed to delete, please delete it before retrying: %w", nsPod.Name, ns, err)
775
799
}
776
800
} else {
777
801
// TODO: handle properly
778
-
returnnil, fmt.Errorf("pod %s in %s did not have any owners!\nPlease delete it before retrying", nsPod.Name, ns)
802
+
returnfmt.Errorf("pod %s in %s did not have any owners!\nPlease delete it before retrying", nsPod.Name, ns)
returnnil, fmt.Errorf("failed to get replicaset %s in %s: %w", ownerName, ns, err)
844
+
returnfmt.Errorf("failed to get replicaset %s in %s: %w", ownerName, ns, err)
821
845
}
822
846
823
847
iflen(rs.OwnerReferences) !=1 {
824
-
returnnil, fmt.Errorf("expected 1 owner for replicaset %s in %s, found %d instead", ownerName, ns, len(rs.OwnerReferences))
848
+
returnfmt.Errorf("expected 1 owner for replicaset %s in %s, found %d instead", ownerName, ns, len(rs.OwnerReferences))
825
849
}
826
850
ifrs.OwnerReferences[0].Kind!="Deployment" {
827
-
returnnil, fmt.Errorf("expected owner for replicaset %s in %s to be a deployment, found %s of kind %s instead", ownerName, ns, rs.OwnerReferences[0].Name, rs.OwnerReferences[0].Kind)
851
+
returnfmt.Errorf("expected owner for replicaset %s in %s to be a deployment, found %s of kind %s instead", ownerName, ns, rs.OwnerReferences[0].Name, rs.OwnerReferences[0].Kind)
returnnil, fmt.Errorf("failed to scale statefulset %s to zero in %s: %w", ownerName, ns, err)
877
+
returnfmt.Errorf("failed to scale statefulset %s to zero in %s: %w", ownerName, ns, err)
854
878
}
855
879
default:
856
-
returnnil, fmt.Errorf("scaling pods controlled by a %s is not supported, please delete the pods controlled by %s in %s before retrying", ownerKind, ownerKind, ns)
880
+
returnfmt.Errorf("scaling pods controlled by a %s is not supported, please delete the pods controlled by %s in %s before retrying", ownerKind, ownerKind, ns)
returnnil, fmt.Errorf("pod %s in %s mounting %s was created at %s, after scale-down started at %s. It is likely that there is some other operator scaling this back up", nsPod.Name, ns, nsClaim.Name, nsPod.CreationTimestamp.Format(time.RFC3339), migrationStartTime.Format(time.RFC3339))
902
+
returnfmt.Errorf("pod %s in %s mounting %s was created at %s, after scale-down started at %s. It is likely that there is some other operator scaling this back up", nsPod.Name, ns, nsClaim.Name, nsPod.CreationTimestamp.Format(time.RFC3339), migrationStartTime.Format(time.RFC3339))
879
903
}
880
904
881
905
w.Printf("Found pod %s in %s mounting to-be-migrated PVC %s, waiting\n", nsPod.Name, ns, nsClaim.Name)
0 commit comments