mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
Add support for erasure coded pools
This commit adds support to mention dataPool parameter for the topology constrained pools in the StorageClass, that can be leveraged to mention erasure coded pool names to use for RBD data instead of the replica pools. Signed-off-by: ShyamsundarR <srangana@redhat.com>
This commit is contained in:
committed by
mergify[bot]
parent
3f06fedf61
commit
1a8f8e3c24
@ -125,6 +125,7 @@ type topologySegment struct {
|
||||
// TopologyConstrainedPool stores the pool name and a list of its associated topology domain values
|
||||
type TopologyConstrainedPool struct {
|
||||
PoolName string `json:"poolName"`
|
||||
DataPoolName string `json:"dataPool"`
|
||||
DomainSegments []topologySegment `json:"domainSegments"`
|
||||
}
|
||||
|
||||
@ -178,7 +179,7 @@ func MatchTopologyForPool(topologyPools *[]TopologyConstrainedPool,
|
||||
topologyPools, poolName)
|
||||
}
|
||||
|
||||
_, topology, err := FindPoolAndTopology(&topologyPool, accessibilityRequirements)
|
||||
_, _, topology, err := FindPoolAndTopology(&topologyPool, accessibilityRequirements)
|
||||
|
||||
return topology, err
|
||||
}
|
||||
@ -188,28 +189,28 @@ func MatchTopologyForPool(topologyPools *[]TopologyConstrainedPool,
|
||||
// The return variables are, image poolname, data poolname, and topology map of
|
||||
// matched requirement
|
||||
func FindPoolAndTopology(topologyPools *[]TopologyConstrainedPool,
|
||||
accessibilityRequirements *csi.TopologyRequirement) (string, map[string]string, error) {
|
||||
accessibilityRequirements *csi.TopologyRequirement) (string, string, map[string]string, error) {
|
||||
if topologyPools == nil || accessibilityRequirements == nil {
|
||||
return "", nil, nil
|
||||
return "", "", nil, nil
|
||||
}
|
||||
|
||||
// select pool that fits first topology constraint preferred requirements
|
||||
for _, topology := range accessibilityRequirements.GetPreferred() {
|
||||
poolName := matchPoolToTopology(topologyPools, topology)
|
||||
if poolName != "" {
|
||||
return poolName, topology.GetSegments(), nil
|
||||
topologyPool := matchPoolToTopology(topologyPools, topology)
|
||||
if topologyPool.PoolName != "" {
|
||||
return topologyPool.PoolName, topologyPool.DataPoolName, topology.GetSegments(), nil
|
||||
}
|
||||
}
|
||||
|
||||
// If preferred mismatches, check requisite for a fit
|
||||
for _, topology := range accessibilityRequirements.GetRequisite() {
|
||||
poolName := matchPoolToTopology(topologyPools, topology)
|
||||
if poolName != "" {
|
||||
return poolName, topology.GetSegments(), nil
|
||||
topologyPool := matchPoolToTopology(topologyPools, topology)
|
||||
if topologyPool.PoolName != "" {
|
||||
return topologyPool.PoolName, topologyPool.DataPoolName, topology.GetSegments(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", nil, fmt.Errorf("none of the topology constrained pools matched requested "+
|
||||
return "", "", nil, fmt.Errorf("none of the topology constrained pools matched requested "+
|
||||
"topology constraints : pools (%+v) requested topology (%+v)",
|
||||
*topologyPools, *accessibilityRequirements)
|
||||
}
|
||||
@ -217,7 +218,7 @@ func FindPoolAndTopology(topologyPools *[]TopologyConstrainedPool,
|
||||
// matchPoolToTopology loops through passed in pools, and for each pool checks if all
|
||||
// requested topology segments are present and match the request, returning the first pool
|
||||
// that hence matches (or an empty string if none match)
|
||||
func matchPoolToTopology(topologyPools *[]TopologyConstrainedPool, topology *csi.Topology) string {
|
||||
func matchPoolToTopology(topologyPools *[]TopologyConstrainedPool, topology *csi.Topology) TopologyConstrainedPool {
|
||||
domainMap := extractDomainsFromlabels(topology)
|
||||
|
||||
// check if any pool matches all the domain keys and values
|
||||
@ -235,10 +236,10 @@ func matchPoolToTopology(topologyPools *[]TopologyConstrainedPool, topology *csi
|
||||
continue
|
||||
}
|
||||
|
||||
return topologyPool.PoolName
|
||||
return topologyPool
|
||||
}
|
||||
|
||||
return ""
|
||||
return TopologyConstrainedPool{}
|
||||
}
|
||||
|
||||
// extractDomainsFromlabels returns the domain name map, from passed in domain segments,
|
||||
|
@ -224,91 +224,91 @@ func TestFindPoolAndTopology(t *testing.T) {
|
||||
return nil
|
||||
}
|
||||
// Test nil values
|
||||
_, _, err = FindPoolAndTopology(nil, nil)
|
||||
_, _, _, err = FindPoolAndTopology(nil, nil)
|
||||
if err != nil {
|
||||
t.Errorf("expected success due to nil in-args (%v)", err)
|
||||
}
|
||||
|
||||
poolName, _, err := FindPoolAndTopology(&validMultipleTopoPools, nil)
|
||||
poolName, _, _, err := FindPoolAndTopology(&validMultipleTopoPools, nil)
|
||||
if err != nil || poolName != "" {
|
||||
t.Errorf("expected success due to nil accessibility requirements (err - %v) (poolName - %s)", err, poolName)
|
||||
}
|
||||
|
||||
poolName, _, err = FindPoolAndTopology(nil, &validAccReq)
|
||||
poolName, _, _, err = FindPoolAndTopology(nil, &validAccReq)
|
||||
if err != nil || poolName != "" {
|
||||
t.Errorf("expected success due to nil topology pools (err - %v) (poolName - %s)", err, poolName)
|
||||
}
|
||||
|
||||
// Test valid accessibility requirement, with invalid topology pools values
|
||||
_, _, err = FindPoolAndTopology(&emptyTopoPools, &validAccReq)
|
||||
_, _, _, err = FindPoolAndTopology(&emptyTopoPools, &validAccReq)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure due to empty topology pools")
|
||||
}
|
||||
|
||||
_, _, err = FindPoolAndTopology(&emptyPoolNameTopoPools, &validAccReq)
|
||||
_, _, _, err = FindPoolAndTopology(&emptyPoolNameTopoPools, &validAccReq)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure due to missing pool name in topology pools")
|
||||
}
|
||||
|
||||
_, _, err = FindPoolAndTopology(&differentDomainsInTopoPools, &validAccReq)
|
||||
_, _, _, err = FindPoolAndTopology(&differentDomainsInTopoPools, &validAccReq)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure due to mismatching domains in topology pools")
|
||||
}
|
||||
|
||||
// Test valid topology pools, with invalid accessibility requirements
|
||||
_, _, err = FindPoolAndTopology(&validMultipleTopoPools, &emptyAccReq)
|
||||
_, _, _, err = FindPoolAndTopology(&validMultipleTopoPools, &emptyAccReq)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure due to empty accessibility requirements")
|
||||
}
|
||||
|
||||
_, _, err = FindPoolAndTopology(&validSingletonTopoPools, &emptySegmentAccReq)
|
||||
_, _, _, err = FindPoolAndTopology(&validSingletonTopoPools, &emptySegmentAccReq)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure due to empty segments in accessibility requirements")
|
||||
}
|
||||
|
||||
_, _, err = FindPoolAndTopology(&validMultipleTopoPools, &partialHigherSegmentAccReq)
|
||||
_, _, _, err = FindPoolAndTopology(&validMultipleTopoPools, &partialHigherSegmentAccReq)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure due to partial segments in accessibility requirements")
|
||||
}
|
||||
|
||||
_, _, err = FindPoolAndTopology(&validSingletonTopoPools, &partialLowerSegmentAccReq)
|
||||
_, _, _, err = FindPoolAndTopology(&validSingletonTopoPools, &partialLowerSegmentAccReq)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure due to partial segments in accessibility requirements")
|
||||
}
|
||||
|
||||
_, _, err = FindPoolAndTopology(&validMultipleTopoPools, &partialLowerSegmentAccReq)
|
||||
_, _, _, err = FindPoolAndTopology(&validMultipleTopoPools, &partialLowerSegmentAccReq)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure due to partial segments in accessibility requirements")
|
||||
}
|
||||
|
||||
_, _, err = FindPoolAndTopology(&validMultipleTopoPools, &differentSegmentAccReq)
|
||||
_, _, _, err = FindPoolAndTopology(&validMultipleTopoPools, &differentSegmentAccReq)
|
||||
if err == nil {
|
||||
t.Errorf("expected failure due to mismatching segments in accessibility requirements")
|
||||
}
|
||||
|
||||
// Test success cases
|
||||
// If a pool is a superset of domains (either empty domain labels or partial), it can be selected
|
||||
poolName, topoSegment, err := FindPoolAndTopology(&emptyDomainsInTopoPools, &validAccReq)
|
||||
poolName, _, topoSegment, err := FindPoolAndTopology(&emptyDomainsInTopoPools, &validAccReq)
|
||||
err = checkOutput(err, poolName, topoSegment)
|
||||
if err != nil {
|
||||
t.Errorf("expected success got: (%v)", err)
|
||||
}
|
||||
|
||||
poolName, topoSegment, err = FindPoolAndTopology(&partialDomainsInTopoPools, &validAccReq)
|
||||
poolName, _, topoSegment, err = FindPoolAndTopology(&partialDomainsInTopoPools, &validAccReq)
|
||||
err = checkOutput(err, poolName, topoSegment)
|
||||
if err != nil {
|
||||
t.Errorf("expected success got: (%v)", err)
|
||||
}
|
||||
|
||||
// match in a singleton topology pools
|
||||
poolName, topoSegment, err = FindPoolAndTopology(&validSingletonTopoPools, &validAccReq)
|
||||
poolName, _, topoSegment, err = FindPoolAndTopology(&validSingletonTopoPools, &validAccReq)
|
||||
err = checkOutput(err, poolName, topoSegment)
|
||||
if err != nil {
|
||||
t.Errorf("expected success got: (%v)", err)
|
||||
}
|
||||
|
||||
// match first in multiple topology pools
|
||||
poolName, topoSegment, err = FindPoolAndTopology(&validMultipleTopoPools, &validAccReq)
|
||||
poolName, _, topoSegment, err = FindPoolAndTopology(&validMultipleTopoPools, &validAccReq)
|
||||
err = checkOutput(err, poolName, topoSegment)
|
||||
if err != nil {
|
||||
t.Errorf("expected success got: (%v)", err)
|
||||
@ -317,12 +317,25 @@ func TestFindPoolAndTopology(t *testing.T) {
|
||||
// match non-first in multiple topology pools
|
||||
switchPoolOrder := []TopologyConstrainedPool{}
|
||||
switchPoolOrder = append(switchPoolOrder, validMultipleTopoPools[1], validMultipleTopoPools[0])
|
||||
poolName, topoSegment, err = FindPoolAndTopology(&switchPoolOrder, &validAccReq)
|
||||
poolName, _, topoSegment, err = FindPoolAndTopology(&switchPoolOrder, &validAccReq)
|
||||
err = checkOutput(err, poolName, topoSegment)
|
||||
if err != nil {
|
||||
t.Errorf("expected success got: (%v)", err)
|
||||
}
|
||||
|
||||
// test valid dataPool return
|
||||
for i := range switchPoolOrder {
|
||||
switchPoolOrder[i].DataPoolName = "ec-" + switchPoolOrder[i].PoolName
|
||||
}
|
||||
poolName, dataPoolName, topoSegment, err := FindPoolAndTopology(&switchPoolOrder, &validAccReq)
|
||||
err = checkOutput(err, poolName, topoSegment)
|
||||
if err != nil {
|
||||
t.Errorf("expected success got: (%v)", err)
|
||||
}
|
||||
if dataPoolName != "ec-"+poolName {
|
||||
t.Errorf("expected data pool to be named ec-%s, got %s", poolName, dataPoolName)
|
||||
}
|
||||
|
||||
// TEST: MatchTopologyForPool
|
||||
// check for non-existent pool
|
||||
_, err = MatchTopologyForPool(&validMultipleTopoPools, &validAccReq, pool1+"fuzz")
|
||||
|
Reference in New Issue
Block a user