Skip to content

Commit

Permalink
enhance: ServiceQuality supports multiple results returned by a singl…
Browse files Browse the repository at this point in the history
…e probe

Signed-off-by: ChrisLiu <[email protected]>
  • Loading branch information
chrisliu1995 committed Dec 18, 2023
1 parent 250bd86 commit af700f0
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 14 deletions.
11 changes: 8 additions & 3 deletions apis/v1alpha1/gameserver_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,20 @@ type ServiceQuality struct {
}

type ServiceQualityCondition struct {
Name string `json:"name"`
Status string `json:"status,omitempty"`
Name string `json:"name"`
Status string `json:"status,omitempty"`
// Result indicate the probe message returned by the script
Result string `json:"result,omitempty"`
LastProbeTime metav1.Time `json:"lastProbeTime,omitempty"`
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
LastActionTransitionTime metav1.Time `json:"lastActionTransitionTime,omitempty"`
}

type ServiceQualityAction struct {
State bool `json:"state"`
State bool `json:"state"`
// Result indicate the probe message returned by the script.
// When Result is defined, it would exec action only when the according Result is actually returns.
Result string `json:"result,omitempty"`
GameServerSpec `json:",inline"`
}

Expand Down
4 changes: 4 additions & 0 deletions config/crd/bases/game.kruise.io_gameservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,10 @@ spec:
type: string
name:
type: string
result:
description: Result indicate the probe message returned by the
script
type: string
status:
type: string
required:
Expand Down
5 changes: 5 additions & 0 deletions config/crd/bases/game.kruise.io_gameserversets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,11 @@ spec:
type: boolean
opsState:
type: string
result:
description: Result indicate the probe message returned
by the script. When Result is defined, it would exec
action only when the according Result is actually returns.
type: string
state:
type: boolean
updatePriority:
Expand Down
19 changes: 15 additions & 4 deletions pkg/controllers/gameserver/gameserver_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"reflect"
"sigs.k8s.io/controller-runtime/pkg/client"
"strconv"
"strings"
"time"
)

Expand Down Expand Up @@ -316,33 +317,43 @@ func syncServiceQualities(serviceQualities []gameKruiseV1alpha1.ServiceQuality,
for _, sqc := range sqConditions {
sqConditionsMap[sqc.Name] = sqc
}
timeNow := metav1.Now()
for _, sq := range serviceQualities {
var newSqCondition gameKruiseV1alpha1.ServiceQualityCondition
newSqCondition.Name = sq.Name
index, podCondition := util.GetPodConditionFromList(podConditions, corev1.PodConditionType(util.AddPrefixGameKruise(sq.Name)))
if index != -1 {
podConditionMessage := strings.ReplaceAll(podCondition.Message, "|", "")
podConditionMessage = strings.ReplaceAll(podConditionMessage, "\n", "")
newSqCondition.Status = string(podCondition.Status)
newSqCondition.Result = podConditionMessage
newSqCondition.LastProbeTime = podCondition.LastProbeTime
var lastActionTransitionTime metav1.Time
sqCondition, exist := sqConditionsMap[sq.Name]
if !exist || (sqCondition.Status != string(podCondition.Status) && (sqCondition.LastActionTransitionTime.IsZero() || !sq.Permanent)) {
if !exist || ((sqCondition.Status != string(podCondition.Status) || (sqCondition.Result != podConditionMessage)) && (sqCondition.LastActionTransitionTime.IsZero() || !sq.Permanent)) {
// exec action
for _, action := range sq.ServiceQualityAction {
state, err := strconv.ParseBool(string(podCondition.Status))
if err == nil && state == action.State {
if err == nil && state == action.State && (action.Result == "" || podConditionMessage == action.Result) {
spec.DeletionPriority = action.DeletionPriority
spec.UpdatePriority = action.UpdatePriority
spec.OpsState = action.OpsState
spec.NetworkDisabled = action.NetworkDisabled
lastActionTransitionTime = metav1.Now()
lastActionTransitionTime = timeNow
}
}
} else {
lastActionTransitionTime = sqCondition.LastActionTransitionTime
}
newSqCondition.LastActionTransitionTime = lastActionTransitionTime
}
newSqCondition.LastTransitionTime = metav1.Now()

// Set LastTransitionTime, which depends on which value, the LastActionTransitionTime or LastProbeTime, is closer to the current time.
if timeNow.Sub(newSqCondition.LastActionTransitionTime.Time) < timeNow.Sub(newSqCondition.LastProbeTime.Time) {
newSqCondition.LastTransitionTime = newSqCondition.LastActionTransitionTime
} else {
newSqCondition.LastTransitionTime = newSqCondition.LastProbeTime
}
newGsConditions = append(newGsConditions, newSqCondition)
}
return spec, newGsConditions
Expand Down
133 changes: 126 additions & 7 deletions pkg/controllers/gameserver/gameserver_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func TestSyncServiceQualities(t *testing.T) {
spec gameKruiseV1alpha1.GameServerSpec
newSqConditions []gameKruiseV1alpha1.ServiceQualityCondition
}{
//case 0
{
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
{
Expand Down Expand Up @@ -88,6 +89,7 @@ func TestSyncServiceQualities(t *testing.T) {
},
},
},
// case 1
{
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
{
Expand Down Expand Up @@ -139,6 +141,7 @@ func TestSyncServiceQualities(t *testing.T) {
},
},
},
// case 2
{
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
{
Expand Down Expand Up @@ -175,6 +178,7 @@ func TestSyncServiceQualities(t *testing.T) {
},
},
},
// case 3
{
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
{
Expand Down Expand Up @@ -212,6 +216,7 @@ func TestSyncServiceQualities(t *testing.T) {
},
},
},
// case 4
{
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
{
Expand Down Expand Up @@ -265,37 +270,151 @@ func TestSyncServiceQualities(t *testing.T) {
},
},
},
// case 5
{
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
{
Name: "multi-return",
Permanent: false,
ServiceQualityAction: []gameKruiseV1alpha1.ServiceQualityAction{
{
State: true,
Result: "A",
GameServerSpec: gameKruiseV1alpha1.GameServerSpec{
OpsState: "A",
},
},
{
State: true,
Result: "B",
GameServerSpec: gameKruiseV1alpha1.GameServerSpec{
OpsState: "B",
},
},
{
State: true,
Result: "C",
GameServerSpec: gameKruiseV1alpha1.GameServerSpec{
OpsState: "C",
},
},
},
},
},
podConditions: []corev1.PodCondition{
{
Type: "game.kruise.io/multi-return",
Status: corev1.ConditionTrue,
Message: "B",
LastProbeTime: fakeProbeTime,
},
},
sqConditions: nil,
spec: gameKruiseV1alpha1.GameServerSpec{
OpsState: "B",
},
newSqConditions: []gameKruiseV1alpha1.ServiceQualityCondition{
{
Name: "multi-return",
Result: "B",
Status: string(corev1.ConditionTrue),
LastProbeTime: fakeProbeTime,
LastActionTransitionTime: fakeActionTime,
},
},
},
// case 6
{
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
{
Name: "multi-return",
Permanent: false,
ServiceQualityAction: []gameKruiseV1alpha1.ServiceQualityAction{
{
State: true,
Result: "A",
GameServerSpec: gameKruiseV1alpha1.GameServerSpec{
OpsState: "A",
},
},
{
State: true,
Result: "B",
GameServerSpec: gameKruiseV1alpha1.GameServerSpec{
OpsState: "B",
},
},
{
State: true,
Result: "C",
GameServerSpec: gameKruiseV1alpha1.GameServerSpec{
OpsState: "C",
},
},
},
},
},
podConditions: []corev1.PodCondition{
{
Type: "game.kruise.io/multi-return",
Status: corev1.ConditionTrue,
Message: "A",
LastProbeTime: fakeProbeTime,
},
},
sqConditions: []gameKruiseV1alpha1.ServiceQualityCondition{
{
Name: "multi-return",
Result: "B",
Status: string(corev1.ConditionTrue),
LastProbeTime: fakeProbeTime,
LastActionTransitionTime: fakeActionTime,
},
},
spec: gameKruiseV1alpha1.GameServerSpec{
OpsState: "A",
},
newSqConditions: []gameKruiseV1alpha1.ServiceQualityCondition{
{
Name: "multi-return",
Result: "A",
Status: string(corev1.ConditionTrue),
LastProbeTime: fakeProbeTime,
LastActionTransitionTime: fakeActionTime,
},
},
},
}

for _, test := range tests {
for i, test := range tests {
actualSpec, actualNewSqConditions := syncServiceQualities(test.serviceQualities, test.podConditions, test.sqConditions)
expectSpec := test.spec
expectNewSqConditions := test.newSqConditions
if !reflect.DeepEqual(actualSpec, expectSpec) {
t.Errorf("expect spec %v but got %v", expectSpec, actualSpec)
t.Errorf("case %d: expect spec %v but got %v", i, expectSpec, actualSpec)
}
if len(actualNewSqConditions) != len(expectNewSqConditions) {
t.Errorf("expect sq conditions len %v but got %v", len(expectNewSqConditions), len(actualNewSqConditions))
t.Errorf("case %d: expect sq conditions len %v but got %v", i, len(expectNewSqConditions), len(actualNewSqConditions))
}
for _, expectNewSqCondition := range expectNewSqConditions {
exist := false
for _, actualNewSqCondition := range actualNewSqConditions {
if actualNewSqCondition.Name == expectNewSqCondition.Name {
exist = true
if actualNewSqCondition.Status != expectNewSqCondition.Status {
t.Errorf("expect sq condition status %v but got %v", expectNewSqCondition.Status, actualNewSqCondition.Status)
t.Errorf("case %d: expect sq condition status %v but got %v", i, expectNewSqCondition.Status, actualNewSqCondition.Status)
}
if actualNewSqCondition.LastProbeTime != expectNewSqCondition.LastProbeTime {
t.Errorf("expect sq condition LastProbeTime %v but got %v", expectNewSqCondition.LastProbeTime, actualNewSqCondition.LastProbeTime)
t.Errorf("case %d: expect sq condition LastProbeTime %v but got %v", i, expectNewSqCondition.LastProbeTime, actualNewSqCondition.LastProbeTime)
}
if actualNewSqCondition.LastActionTransitionTime.IsZero() != expectNewSqCondition.LastActionTransitionTime.IsZero() {
t.Errorf("expect sq condition LastActionTransitionTime IsZero %v but got %v", expectNewSqCondition.LastActionTransitionTime.IsZero(), actualNewSqCondition.LastActionTransitionTime.IsZero())
t.Errorf("case %d: expect sq condition LastActionTransitionTime IsZero %v but got %v", i, expectNewSqCondition.LastActionTransitionTime.IsZero(), actualNewSqCondition.LastActionTransitionTime.IsZero())
}
break
}
}
if !exist {
t.Errorf("expect sq condition %s exist, but actually not", expectNewSqCondition.Name)
t.Errorf("case %d: expect sq condition %s exist, but actually not", i, expectNewSqCondition.Name)
}
}
}
Expand Down

0 comments on commit af700f0

Please sign in to comment.