@@ -306,13 +306,37 @@ func (h *helper) getSnapshotCloneSourceInfo(
306306 if sourceSnapshotName == "" {
307307 return "" , "" , fmt .Errorf ("annotation 'cloneFromSnapshot' is empty" )
308308 }
309+ namespace := clonePVC .Namespace
310+ cloneFromNamespace := getAnnotation (annotations , AnnVolumeCloneFromNS )
311+ if cloneFromNamespace != "" {
312+ // Source snapshot is in a different namespace
313+ namespace = cloneFromNamespace
314+ }
309315
310316 // Get the VolumeSnapshot
311- snapshot , err := h .getVolumeSnapshot (ctx , sourceSnapshotName , clonePVC . Namespace )
317+ snapshot , err := h .getVolumeSnapshot (ctx , sourceSnapshotName , namespace )
312318 if err != nil {
313319 return "" , "" , err
314320 }
315321
322+ // If cloning from another namespace, ensure the source PVC has the required annotation
323+ if cloneFromNamespace != "" {
324+ snapSourcePVC , err := h .waitForCachedPVCByName (ctx , * snapshot .Spec .Source .PersistentVolumeClaimName , namespace , PreSyncCacheWaitPeriod )
325+ if err != nil {
326+ Logc (ctx ).WithFields (LogFields {
327+ "sourcePVCName" : snapSourcePVC .Name ,
328+ "namespace" : namespace ,
329+ }).Errorf ("Clone source PVC not found in local cache: %v" , err )
330+ return "" , "" , err
331+ }
332+ sourceAnnotations := processPVCAnnotations (snapSourcePVC , "" )
333+ sourceCloneToNamespaces := getAnnotation (sourceAnnotations , AnnVolumeCloneToNS )
334+ // Ensure the source PVC has been explicitly allowed to clone to the subordinate PVC namespace
335+ if ! h .matchNamespaceToAnnotation (clonePVC .Namespace , sourceCloneToNamespaces ) {
336+ return "" , "" , fmt .Errorf ("cloning to namespace %s is not allowed, it is not listed in cloneToNamespace annotation" , clonePVC .Namespace )
337+ }
338+
339+ }
316340 // If the clone from PVC annotation is also set, ensure it matches the snapshot
317341 sourcePVCName := getAnnotation (annotations , AnnCloneFromPVC )
318342 if sourcePVCName != "" {
@@ -371,16 +395,33 @@ func (h *helper) getCloneSourceInfo(ctx context.Context, clonePVC *v1.Persistent
371395 if sourcePVCName == "" {
372396 return "" , fmt .Errorf ("annotation 'cloneFromPVC' is empty" )
373397 }
398+ namespace := clonePVC .Namespace
399+ cloneFromNamespace := getAnnotation (annotations , AnnVolumeCloneFromNS )
374400
375- // Check that the source PVC is in the same namespace.
376- // NOTE: For VolumeContentSource this check is performed by CSI
377- sourcePVC , err := h .waitForCachedPVCByName (ctx , sourcePVCName , clonePVC .Namespace , PreSyncCacheWaitPeriod )
401+ // Determine what namespace to look for the source PVC in
402+ if cloneFromNamespace != "" {
403+ // Source PVC is in a different namespace
404+ namespace = cloneFromNamespace
405+ }
406+
407+ // Retrieve the source PVC from the cache
408+ sourcePVC , err := h .waitForCachedPVCByName (ctx , sourcePVCName , namespace , PreSyncCacheWaitPeriod )
378409 if err != nil {
379410 Logc (ctx ).WithFields (LogFields {
380411 "sourcePVCName" : sourcePVCName ,
381- "namespace" : clonePVC . Namespace ,
412+ "namespace" : namespace ,
382413 }).Errorf ("Clone source PVC not found in local cache: %v" , err )
383- return "" , fmt .Errorf ("cloning from a PVC requires both PVCs be in the same namespace: %v" , err )
414+ return "" , fmt .Errorf ("source PVC not found in namespace: %v" , err )
415+ }
416+
417+ // If cloning from another namespace, ensure the source PVC has the required annotation
418+ if cloneFromNamespace != "" {
419+ sourceAnnotations := processPVCAnnotations (sourcePVC , "" )
420+ sourceCloneToNamespaces := getAnnotation (sourceAnnotations , AnnVolumeCloneToNS )
421+ // Ensure the source PVC has been explicitly allowed to clone to the subordinate PVC namespace
422+ if ! h .matchNamespaceToAnnotation (clonePVC .Namespace , sourceCloneToNamespaces ) {
423+ return "" , fmt .Errorf ("cloning to namespace %s is not allowed, it is not listed in cloneToNamespace annotation" , clonePVC .Namespace )
424+ }
384425 }
385426
386427 // Check that both source and clone PVCs have the same storage class
@@ -481,10 +522,10 @@ func (h *helper) validateSubordinateVolumeConfig(
481522 return nil
482523}
483524
484- func (h * helper ) matchNamespaceToAnnotation (namespace , shareToAnnotation string ) bool {
485- shareToNamespaces := strings .Split (shareToAnnotation , "," )
486- for _ , shareToNamespace := range shareToNamespaces {
487- if shareToNamespace == namespace || shareToNamespace == "*" {
525+ func (h * helper ) matchNamespaceToAnnotation (namespace , annotation string ) bool {
526+ availableToNamespaces := strings .Split (annotation , "," )
527+ for _ , availableToNamespace := range availableToNamespaces {
528+ if availableToNamespace == namespace || availableToNamespace == "*" {
488529 return true
489530 }
490531 }
0 commit comments