Repository: dragonflyoss/Dragonfly2
Pull request #917 (2021-12-10 09:30:47)

feat: dfdaemon list scheduler cluster with multi idc
Signed-off-by: Gaius <gaius.qi@gmail.com>

<!--- Provide a general summary of your changes in the Title above -->

## Description
- Dfdaemon list scheduler cluster with multi idc
<!--- Describe your changes in detail -->

## Related Issue

<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->

## Screenshots (if appropriate):

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation Update (if none of the other choices apply)

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [x] Code compiles correctly.
- [x] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [x] I have read the **CONTRIBUTING** document.
- [x] I have added tests to cover my changes.
- [x] All new and existing tests passed.



Patch:
diff --git a/deploy/helm-charts b/deploy/helm-charts
index 110c286f..324e3512 160000
--- a/deploy/helm-charts
+++ b/deploy/helm-charts
@@ -1,1 +1,1 @@
-Subproject commit 110c286f416c1c88070861ad9d07f942a69881e6
+Subproject commit 324e351222bb3098722ab4d0a35beece7bfefeaf
diff --git a/go.sum b/go.sum
index 9afe1e59..c03975ee 100644
--- a/go.sum
+++ b/go.sum
@@ -110,7 +110,6 @@ github.com/casbin/gorm-adapter/v3 v3.3.2/go.mod h1:z0J/CpAznL6MyXMPnzltbLBI6lykp
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
diff --git a/manager/console b/manager/console
index bbd994b3..cd8a0e49 160000
--- a/manager/console
+++ b/manager/console
@@ -1,1 +1,1 @@
-Subproject commit bbd994b32d6f445d73d7104aaf21888d42f3801d
+Subproject commit cd8a0e49a2f598b741163a0c05dd0c816d8e3333
diff --git a/manager/searcher/searcher.go b/manager/searcher/searcher.go
index c7b59dab..a4e0cd2c 100644
--- a/manager/searcher/searcher.go
+++ b/manager/searcher/searcher.go
@@ -139,6 +139,7 @@ func (s *searcher) FindSchedulerCluster(ctx context.Context, schedulerClusters [
 		for _, cluster := range clusters {
 			var scopes Scopes
 			if err := mapstructure.Decode(cluster.Scopes, &scopes); err != nil {
+				logger.Infof("cluster %s decode scopes failed: %v", cluster.Name, err)
 				// Scopes parse failed to skip this evaluation
 				continue
 			}
@@ -162,10 +163,24 @@ func Evaluate(conditions map[string]string, scopes Scopes) float64 {
 
 // calculateIDCAffinityScore 0.0~1.0 larger and better
 func calculateIDCAffinityScore(dst, src string) float64 {
-	if dst != "" && src != "" && strings.Compare(dst, src) == 0 {
+	if dst == "" || src == "" {
+		return minScore
+	}
+
+	if strings.Compare(dst, src) == 0 {
 		return maxScore
 	}
 
+	// Dst has only one element, src has multiple elements separated by "|".
+	// When dst element matches one of the multiple elements of src,
+	// it gets the max score of idc.
+	srcElements := strings.Split(src, "|")
+	for _, srcElement := range srcElements {
+		if strings.Compare(dst, srcElement) == 0 {
+			return maxScore
+		}
+	}
+
 	return minScore
 }
 


Test patch:
diff --git a/manager/searcher/searcher_test.go b/manager/searcher/searcher_test.go
index 2e02b2f0..34af2c37 100644
--- a/manager/searcher/searcher_test.go
+++ b/manager/searcher/searcher_test.go
@@ -117,7 +117,7 @@ func TestSchedulerCluster(t *testing.T) {
 				{
 					Name: "foo",
 					Scopes: map[string]interface{}{
-						"location": []string{"location-1"},
+						"location": "location-1",
 					},
 					Schedulers: []model.Scheduler{
 						{
@@ -149,7 +149,7 @@ func TestSchedulerCluster(t *testing.T) {
 				{
 					Name: "foo",
 					Scopes: map[string]interface{}{
-						"idc": []string{"idc-1"},
+						"idc": "idc|idc-1",
 					},
 					Schedulers: []model.Scheduler{
 						{
@@ -160,6 +160,9 @@ func TestSchedulerCluster(t *testing.T) {
 				},
 				{
 					Name: "bar",
+					Scopes: map[string]interface{}{
+						"idc": "idc-2|idc-3",
+					},
 					Schedulers: []model.Scheduler{
 						{
 							HostName: "bar",
@@ -168,10 +171,10 @@ func TestSchedulerCluster(t *testing.T) {
 					},
 				},
 			},
-			conditions: map[string]string{"idc": "idc-1"},
+			conditions: map[string]string{"idc": "idc-2"},
 			expect: func(t *testing.T, data model.SchedulerCluster, err error) {
 				assert := assert.New(t)
-				assert.Equal(data.Name, "foo")
+				assert.Equal(data.Name, "bar")
 				assert.NoError(err)
 			},
 		},
@@ -181,7 +184,7 @@ func TestSchedulerCluster(t *testing.T) {
 				{
 					Name: "foo",
 					Scopes: map[string]interface{}{
-						"net_topology": []string{"net-topology-1"},
+						"net_topology": "net-topology-1",
 					},
 					Schedulers: []model.Scheduler{
 						{
@@ -213,8 +216,8 @@ func TestSchedulerCluster(t *testing.T) {
 				{
 					Name: "foo",
 					Scopes: map[string]interface{}{
-						"location": []string{"location-1"},
-						"idc":      []string{"idc-1"},
+						"location": "location-1|location-2",
+						"idc":      "idc-1|idc-2",
 					},
 					Schedulers: []model.Scheduler{
 						{
@@ -249,7 +252,7 @@ func TestSchedulerCluster(t *testing.T) {
 				{
 					Name: "foo",
 					Scopes: map[string]interface{}{
-						"location": []string{"location-1"},
+						"location": "location-1",
 					},
 					SecurityGroup: model.SecurityGroup{
 						SecurityRules: []model.SecurityRule{
@@ -291,7 +294,7 @@ func TestSchedulerCluster(t *testing.T) {
 				{
 					Name: "foo",
 					Scopes: map[string]interface{}{
-						"idc": []string{"idc-1"},
+						"idc": "idc-1",
 					},
 					SecurityGroup: model.SecurityGroup{
 						SecurityRules: []model.SecurityRule{
@@ -328,13 +331,13 @@ func TestSchedulerCluster(t *testing.T) {
 			},
 		},
 		{
-			name: "match according to all conditions",
+			name: "match according to security_domain, idc and location conditions",
 			schedulerClusters: []model.SchedulerCluster{
 				{
 					Name: "foo",
 					Scopes: map[string]interface{}{
-						"idc":      []string{"idc-1"},
-						"location": []string{"location-1"},
+						"idc":      "idc-1",
+						"location": "location-1",
 					},
 					SecurityGroup: model.SecurityGroup{
 						SecurityRules: []model.SecurityRule{
@@ -352,6 +355,17 @@ func TestSchedulerCluster(t *testing.T) {
 				},
 				{
 					Name: "bar",
+					Scopes: map[string]interface{}{
+						"idc":      "idc-2",
+						"location": "location-1",
+					},
+					SecurityGroup: model.SecurityGroup{
+						SecurityRules: []model.SecurityRule{
+							{
+								Domain: "domain-1",
+							},
+						},
+					},
 					Schedulers: []model.Scheduler{
 						{
 							HostName: "bar",
@@ -362,8 +376,8 @@ func TestSchedulerCluster(t *testing.T) {
 			},
 			conditions: map[string]string{
 				"security_domain": "domain-1",
-				"idc":             "idc-1",
-				"location":        "location-1",
+				"idc":             "idc-1|idc-2",
+				"location":        "location-1|location-2",
 			},
 			expect: func(t *testing.T, data model.SchedulerCluster, err error) {
 				assert := assert.New(t)
@@ -371,6 +385,61 @@ func TestSchedulerCluster(t *testing.T) {
 				assert.NoError(err)
 			},
 		},
+		{
+			name: "match according to all conditions",
+			schedulerClusters: []model.SchedulerCluster{
+				{
+					Name: "foo",
+					Scopes: map[string]interface{}{
+						"idc":      "idc-1",
+						"location": "location-2",
+					},
+					SecurityGroup: model.SecurityGroup{
+						SecurityRules: []model.SecurityRule{
+							{
+								Domain: "domain-1",
+							},
+						},
+					},
+					Schedulers: []model.Scheduler{
+						{
+							HostName: "foo",
+							State:    "active",
+						},
+					},
+				},
+				{
+					Name: "bar",
+					Scopes: map[string]interface{}{
+						"idc":      "idc-1",
+						"location": "location-1",
+					},
+					SecurityGroup: model.SecurityGroup{
+						SecurityRules: []model.SecurityRule{
+							{
+								Domain: "domain-1",
+							},
+						},
+					},
+					Schedulers: []model.Scheduler{
+						{
+							HostName: "bar",
+							State:    "active",
+						},
+					},
+				},
+			},
+			conditions: map[string]string{
+				"security_domain": "domain-1",
+				"idc":             "idc-1|idc-2",
+				"location":        "location-1|location-2",
+			},
+			expect: func(t *testing.T, data model.SchedulerCluster, err error) {
+				assert := assert.New(t)
+				assert.Equal(data.Name, "bar")
+				assert.NoError(err)
+			},
+		},
 	}
 
 	for _, tc := range tests {