Skip to content

Commit b404f28

Browse files
authored
Get the datastore accessible topology from the snapshot (#3424)
1 parent 09db543 commit b404f28

File tree

1 file changed

+98
-0
lines changed

1 file changed

+98
-0
lines changed

pkg/csi/service/wcp/controller.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,30 @@ func (c *controller) createBlockVolume(ctx context.Context, req *csi.CreateVolum
545545
}
546546
// Initiate TKGs HA workflow when the topology requirement contains zone labels only.
547547
log.Infof("Topology aware environment detected with requirement: %+v", topologyRequirement)
548+
549+
// if volume is created from snapshot, get the datastore accessible topology from the snapshot
550+
if req.GetVolumeContentSource() != nil {
551+
snapshotID := ""
552+
if req.GetVolumeContentSource().GetSnapshot() != nil {
553+
snapshotID = req.GetVolumeContentSource().GetSnapshot().GetSnapshotId()
554+
}
555+
log.Infof("Volume %s is created from snapshot %s, get the datastore accessible topology from the snapshot",
556+
req.Name, snapshotID)
557+
datastoreAccessibleTopology, err := c.getDatastoreAccessibleTopologyForSnapshot(ctx,
558+
req.GetVolumeContentSource().GetSnapshot().GetSnapshotId(), storageTopologyType,
559+
topologyRequirement, topoSegToDatastoresMap)
560+
if err != nil {
561+
return nil, csifault.CSIInternalFault, logger.LogNewErrorCodef(log, codes.Internal,
562+
"failed to get datastore accessible topology. Error: %v", err)
563+
}
564+
topologyRequirement = &csi.TopologyRequirement{
565+
Preferred: datastoreAccessibleTopology,
566+
Requisite: datastoreAccessibleTopology,
567+
}
568+
log.Infof("Replaced with topologyRequirement %+v for creating volume %s from snapshot %s",
569+
topologyRequirement, req.Name, snapshotID)
570+
}
571+
548572
sharedDatastores, err = c.topologyMgr.GetSharedDatastoresInTopology(ctx,
549573
commoncotypes.WCPTopologyFetchDSParams{
550574
TopologyRequirement: topologyRequirement,
@@ -953,6 +977,80 @@ func (c *controller) createBlockVolume(ctx context.Context, req *csi.CreateVolum
953977
return resp, "", nil
954978
}
955979

980+
func (c *controller) getDatastoreAccessibleTopologyForSnapshot(ctx context.Context, contentSourceSnapshotID string,
981+
storageTopologyType string, topologyRequirement *csi.TopologyRequirement,
982+
topoSegToDatastoresMap map[string][]*cnsvsphere.DatastoreInfo) ([]*csi.Topology, error) {
983+
log := logger.GetLogger(ctx)
984+
985+
log.Debugf("getDatastoreAccessibleTopologyForSnapshot: contentSourceSnapshotID: %s, storageTopologyType: %s, "+
986+
"topologyRequirement %+v, topoSegToDatastoresMap %+v",
987+
contentSourceSnapshotID, storageTopologyType, topologyRequirement, topoSegToDatastoresMap)
988+
989+
vc, err := c.manager.VcenterManager.GetVirtualCenter(ctx, c.manager.VcenterConfig.Host)
990+
if err != nil {
991+
return nil, logger.LogNewErrorCodef(log, codes.Internal,
992+
"failed to get vCenter. Error: %+v", err)
993+
}
994+
995+
if c.topologyMgr == nil {
996+
return nil, logger.LogNewErrorCode(log, codes.Internal,
997+
"topology manager not initialized.")
998+
}
999+
1000+
// Query the datastore of snapshot. By design, snapshot is always located at the same datastore
1001+
// as the source volume
1002+
querySelection := cnstypes.CnsQuerySelection{
1003+
Names: []string{string(cnstypes.QuerySelectionNameTypeDataStoreUrl)},
1004+
}
1005+
1006+
// Parse contentSourceSnapshotID into CNS VolumeID and CNS SnapshotID using "+" as the delimiter
1007+
cnsVolumeID, _, err := common.ParseCSISnapshotID(contentSourceSnapshotID)
1008+
if err != nil {
1009+
return nil, logger.LogNewErrorCodef(log, codes.Internal,
1010+
"failed to parse snapshot id. Error: %+v", err)
1011+
}
1012+
cnsVolumeInfo, err := common.QueryVolumeByID(ctx, c.manager.VolumeManager, cnsVolumeID, &querySelection)
1013+
if err != nil {
1014+
return nil, logger.LogNewErrorf(log,
1015+
"failed to query datastore for the volume %s with error %+v",
1016+
cnsVolumeID, err)
1017+
}
1018+
1019+
selectedDatastore := cnsVolumeInfo.DatastoreUrl
1020+
log.Debugf("getDatastoreAccessibleTopologyForSnapshot: selectedDatastore: %s", selectedDatastore)
1021+
1022+
if selectedDatastore == "" {
1023+
return nil, logger.LogNewErrorCodef(log, codes.Internal,
1024+
"failed to get datastore for volume %q. Error: %+v",
1025+
cnsVolumeID, err)
1026+
}
1027+
1028+
// Calculate accessible topology for the provisioned volume.
1029+
datastoreAccessibleTopologySegments, err := c.topologyMgr.GetTopologyInfoFromNodes(ctx,
1030+
commoncotypes.WCPRetrieveTopologyInfoParams{
1031+
DatastoreURL: selectedDatastore,
1032+
StorageTopologyType: storageTopologyType,
1033+
TopologyRequirement: topologyRequirement,
1034+
Vc: vc,
1035+
TopoSegToDatastoresMap: topoSegToDatastoresMap})
1036+
if err != nil {
1037+
return nil, logger.LogNewErrorCodef(log, codes.Internal,
1038+
"failed to find accessible topologies for volume %q. Error: %+v",
1039+
cnsVolumeID, err)
1040+
}
1041+
1042+
// Convert []map[string]string to []*csi.Topology
1043+
var datastoreAccessibleTopology []*csi.Topology
1044+
for _, topoSegments := range datastoreAccessibleTopologySegments {
1045+
volumeTopology := &csi.Topology{
1046+
Segments: topoSegments,
1047+
}
1048+
datastoreAccessibleTopology = append(datastoreAccessibleTopology, volumeTopology)
1049+
}
1050+
log.Infof("getDatastoreAccessibleTopologyForSnapshot: returning topology %+v", datastoreAccessibleTopology)
1051+
return datastoreAccessibleTopology, nil
1052+
}
1053+
9561054
// createFileVolume creates a file volume based on the CreateVolumeRequest.
9571055
func (c *controller) createFileVolume(ctx context.Context, req *csi.CreateVolumeRequest,
9581056
isWorkloadDomainIsolationEnabled bool) (

0 commit comments

Comments
 (0)