diff --git a/src/csi/backend/backend.go b/src/csi/backend/backend.go index 314f0b58..83996f90 100644 --- a/src/csi/backend/backend.go +++ b/src/csi/backend/backend.go @@ -9,6 +9,7 @@ import ( "sync" "utils" "utils/log" + "utils/k8sutils" ) const ( @@ -122,26 +123,10 @@ func newBackend(backendName string, config map[string]interface{}) (*Backend, er return nil, errors.New("parameters must be configured for backend") } - supportedTopologies := make([]map[string]string, 0) - if topologies, exist := config[SupportedTopologies]; exist { - topologyArray, ok := topologies.([]interface{}) - if !ok { - return nil, errors.New("invalid supported topologies configuration") - } - for _, topologyArrElem := range topologyArray { - topologyMap, ok := topologyArrElem.(map[string]interface{}) - if !ok { - return nil, errors.New("invalid supported topologies configuration") - } - tempMap := make(map[string]string, 0) - for topologyKey, value := range topologyMap { - if topologyValue, ok := value.(string); ok { - tempMap[topologyKey] = topologyValue - } - } - - supportedTopologies = append(supportedTopologies, tempMap) - } + // Get supported topologies for backend + supportedTopologies, err := getSupportedTopologies(config) + if err != nil { + return nil, err } plugin := plugin.GetPlugin(storage) @@ -174,6 +159,47 @@ func newBackend(backendName string, config map[string]interface{}) (*Backend, er }, nil } +func getSupportedTopologies(config map[string]interface{}) ([]map[string]string, error) { + supportedTopologies := make([]map[string]string, 0) + if topologies, exist := config[SupportedTopologies]; exist { + // populate configured topologies + topologyArray, ok := topologies.([]interface{}) + if !ok { + return nil, errors.New("invalid supported topologies configuration") + } + for _, topologyArrElem := range topologyArray { + topologyMap, ok := topologyArrElem.(map[string]interface{}) + if !ok { + return nil, errors.New("invalid supported topologies configuration") + } + tempMap := make(map[string]string, 0) + for topologyKey, value := range topologyMap { + if topologyValue, ok := value.(string); ok { + tempMap[topologyKey] = topologyValue + } + } + + supportedTopologies = append(supportedTopologies, tempMap) + } + } + + return supportedTopologies, nil +} + +// addProtocolTopology add up protocol specific topological support +func addProtocolTopology(backend *Backend, driverName string){ + proto, protocolAvailable := backend.Parameters["protocol"] + if protocol, isString := proto.(string); protocolAvailable && isString { + backend.SupportedTopologies = append(backend.SupportedTopologies, map[string]string{ + k8sutils.TopologyPrefix + "/protocol." + protocol: driverName, + }) + return + } + + log.Warningf("supported topology for protocol may not work as protocol is miss configured " + + "in backend configuration") +} + func analyzeBackend(config map[string]interface{}) (*Backend, error) { backendName, exist := config["name"].(string) if !exist { @@ -245,7 +271,7 @@ func updateReplicaBackends() { } } -func RegisterBackend(backendConfigs []map[string]interface{}, keepLogin bool) error { +func RegisterBackend(backendConfigs []map[string]interface{}, keepLogin bool, driverName string) error { for _, i := range backendConfigs { backend, err := analyzeBackend(i) if err != nil { @@ -259,6 +285,18 @@ func RegisterBackend(backendConfigs []map[string]interface{}, keepLogin bool) er return err } + // Note: Protocol is considered as special topological parameter. The protocol topology + // is populated internally by plugin using protocol name. + // If configured protocol for backend is "iscsi", CSI plugin internally add + // topology.kubernetes.io/protocol.iscsi = csi.huawei.com in supportedTopologies. + // + // Now users can opt to provision volumes based on protocol by + // 1. Labeling kubernetes nodes with protocol specific label (ie topology.kubernetes.io/protocol.iscsi = csi.huawei.com) + // 2. Configure topology support in plugin + // 3. Configure protocol topology in allowedTopologies fo Storage class + // addProtocolTopology is called after backend plugin init as init takes care of protocol validation + addProtocolTopology(backend, driverName) + csiBackends[backend.Name] = backend } diff --git a/src/csi/main.go b/src/csi/main.go index 5f781d14..8f819f65 100644 --- a/src/csi/main.go +++ b/src/csi/main.go @@ -182,14 +182,14 @@ func main() { }() if *controller || *controllerFlagFile != "" { - err := backend.RegisterBackend(config.Backends, true) + err := backend.RegisterBackend(config.Backends, true, *driverName) if err != nil { log.Fatalf("Register backends error: %v", err) } go updateBackendCapabilities() } else { - err := backend.RegisterBackend(config.Backends, false) + err := backend.RegisterBackend(config.Backends, false, *driverName) if err != nil { log.Fatalf("Register backends error: %v", err) } diff --git a/src/utils/k8sutils/k8sutils.go b/src/utils/k8sutils/k8sutils.go index dff1deac..08c2b6fc 100644 --- a/src/utils/k8sutils/k8sutils.go +++ b/src/utils/k8sutils/k8sutils.go @@ -13,7 +13,8 @@ import ( ) const ( - topologyRegx = "topology.kubernetes.io/*" + TopologyPrefix = "topology.kubernetes.io" + topologyRegx = TopologyPrefix + "/.*" ) type Interface interface {