enhance: ServiceQuality supports multiple results returned by a single probe (#117)
Signed-off-by: ChrisLiu <chrisliu1995@163.com>
This commit is contained in:
parent
1181b22e4e
commit
4013d3e597
|
|
@ -77,15 +77,20 @@ type ServiceQuality struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceQualityCondition struct {
|
type ServiceQualityCondition struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Status string `json:"status,omitempty"`
|
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"`
|
LastProbeTime metav1.Time `json:"lastProbeTime,omitempty"`
|
||||||
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
|
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
|
||||||
LastActionTransitionTime metav1.Time `json:"lastActionTransitionTime,omitempty"`
|
LastActionTransitionTime metav1.Time `json:"lastActionTransitionTime,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceQualityAction struct {
|
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"`
|
GameServerSpec `json:",inline"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -855,6 +855,10 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
|
result:
|
||||||
|
description: Result indicate the probe message returned by the
|
||||||
|
script
|
||||||
|
type: string
|
||||||
status:
|
status:
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
|
|
|
||||||
|
|
@ -544,6 +544,11 @@ spec:
|
||||||
type: boolean
|
type: boolean
|
||||||
opsState:
|
opsState:
|
||||||
type: string
|
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:
|
state:
|
||||||
type: boolean
|
type: boolean
|
||||||
updatePriority:
|
updatePriority:
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -316,25 +317,29 @@ func syncServiceQualities(serviceQualities []gameKruiseV1alpha1.ServiceQuality,
|
||||||
for _, sqc := range sqConditions {
|
for _, sqc := range sqConditions {
|
||||||
sqConditionsMap[sqc.Name] = sqc
|
sqConditionsMap[sqc.Name] = sqc
|
||||||
}
|
}
|
||||||
|
timeNow := metav1.Now()
|
||||||
for _, sq := range serviceQualities {
|
for _, sq := range serviceQualities {
|
||||||
var newSqCondition gameKruiseV1alpha1.ServiceQualityCondition
|
var newSqCondition gameKruiseV1alpha1.ServiceQualityCondition
|
||||||
newSqCondition.Name = sq.Name
|
newSqCondition.Name = sq.Name
|
||||||
index, podCondition := util.GetPodConditionFromList(podConditions, corev1.PodConditionType(util.AddPrefixGameKruise(sq.Name)))
|
index, podCondition := util.GetPodConditionFromList(podConditions, corev1.PodConditionType(util.AddPrefixGameKruise(sq.Name)))
|
||||||
if index != -1 {
|
if index != -1 {
|
||||||
|
podConditionMessage := strings.ReplaceAll(podCondition.Message, "|", "")
|
||||||
|
podConditionMessage = strings.ReplaceAll(podConditionMessage, "\n", "")
|
||||||
newSqCondition.Status = string(podCondition.Status)
|
newSqCondition.Status = string(podCondition.Status)
|
||||||
|
newSqCondition.Result = podConditionMessage
|
||||||
newSqCondition.LastProbeTime = podCondition.LastProbeTime
|
newSqCondition.LastProbeTime = podCondition.LastProbeTime
|
||||||
var lastActionTransitionTime metav1.Time
|
var lastActionTransitionTime metav1.Time
|
||||||
sqCondition, exist := sqConditionsMap[sq.Name]
|
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
|
// exec action
|
||||||
for _, action := range sq.ServiceQualityAction {
|
for _, action := range sq.ServiceQualityAction {
|
||||||
state, err := strconv.ParseBool(string(podCondition.Status))
|
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.DeletionPriority = action.DeletionPriority
|
||||||
spec.UpdatePriority = action.UpdatePriority
|
spec.UpdatePriority = action.UpdatePriority
|
||||||
spec.OpsState = action.OpsState
|
spec.OpsState = action.OpsState
|
||||||
spec.NetworkDisabled = action.NetworkDisabled
|
spec.NetworkDisabled = action.NetworkDisabled
|
||||||
lastActionTransitionTime = metav1.Now()
|
lastActionTransitionTime = timeNow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -342,7 +347,13 @@ func syncServiceQualities(serviceQualities []gameKruiseV1alpha1.ServiceQuality,
|
||||||
}
|
}
|
||||||
newSqCondition.LastActionTransitionTime = 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)
|
newGsConditions = append(newGsConditions, newSqCondition)
|
||||||
}
|
}
|
||||||
return spec, newGsConditions
|
return spec, newGsConditions
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ func TestSyncServiceQualities(t *testing.T) {
|
||||||
spec gameKruiseV1alpha1.GameServerSpec
|
spec gameKruiseV1alpha1.GameServerSpec
|
||||||
newSqConditions []gameKruiseV1alpha1.ServiceQualityCondition
|
newSqConditions []gameKruiseV1alpha1.ServiceQualityCondition
|
||||||
}{
|
}{
|
||||||
|
//case 0
|
||||||
{
|
{
|
||||||
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
||||||
{
|
{
|
||||||
|
|
@ -88,6 +89,7 @@ func TestSyncServiceQualities(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// case 1
|
||||||
{
|
{
|
||||||
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
||||||
{
|
{
|
||||||
|
|
@ -139,6 +141,7 @@ func TestSyncServiceQualities(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// case 2
|
||||||
{
|
{
|
||||||
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
||||||
{
|
{
|
||||||
|
|
@ -175,6 +178,7 @@ func TestSyncServiceQualities(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// case 3
|
||||||
{
|
{
|
||||||
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
||||||
{
|
{
|
||||||
|
|
@ -212,6 +216,7 @@ func TestSyncServiceQualities(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// case 4
|
||||||
{
|
{
|
||||||
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
serviceQualities: []gameKruiseV1alpha1.ServiceQuality{
|
||||||
{
|
{
|
||||||
|
|
@ -265,17 +270,131 @@ 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)
|
actualSpec, actualNewSqConditions := syncServiceQualities(test.serviceQualities, test.podConditions, test.sqConditions)
|
||||||
expectSpec := test.spec
|
expectSpec := test.spec
|
||||||
expectNewSqConditions := test.newSqConditions
|
expectNewSqConditions := test.newSqConditions
|
||||||
if !reflect.DeepEqual(actualSpec, expectSpec) {
|
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) {
|
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 {
|
for _, expectNewSqCondition := range expectNewSqConditions {
|
||||||
exist := false
|
exist := false
|
||||||
|
|
@ -283,19 +402,19 @@ func TestSyncServiceQualities(t *testing.T) {
|
||||||
if actualNewSqCondition.Name == expectNewSqCondition.Name {
|
if actualNewSqCondition.Name == expectNewSqCondition.Name {
|
||||||
exist = true
|
exist = true
|
||||||
if actualNewSqCondition.Status != expectNewSqCondition.Status {
|
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 {
|
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() {
|
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
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !exist {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue