Skip to content

Commit 3c5b7df

Browse files
authored
Delete List Value(s) on Game Server Allocation (#4054)
* Adds DeleteValues as a ListAction during allocation * Generated Files * Adds tests * Adds DeleteValues documentation * Updates tabs to spaces per protobuf style guide * Generate Rust file * Adds unit test for DeleteListValues
1 parent ccca32a commit 3c5b7df

File tree

18 files changed

+269
-78
lines changed

18 files changed

+269
-78
lines changed

examples/gameserverallocation.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,6 @@ spec:
116116
- x7un
117117
- 8inz
118118
capacity: 40 # Updates the maximum capacity of the Counter to this number. Min 0, Max 1000.
119+
deleteValues: # removes values from a List's Valules array. Any nonexistant values are ignored.
120+
- alice
121+
- bob

pkg/allocation/converters/converter.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,12 @@ func convertAllocationListsToGSAListActions(in map[string]*pb.ListAction) map[st
615615
copy(copyValues, addValues)
616616
la.AddValues = copyValues
617617
}
618+
if v.DeleteValues != nil {
619+
deleteValues := v.GetDeleteValues()
620+
copyValues := make([]string, len(deleteValues))
621+
copy(copyValues, deleteValues)
622+
la.DeleteValues = copyValues
623+
}
618624
if v.Capacity != nil {
619625
capacity := v.Capacity.GetValue()
620626
la.Capacity = &capacity
@@ -639,6 +645,11 @@ func convertGSAListActionsToAllocationLists(in map[string]allocationv1.ListActio
639645
copy(copyValues, v.AddValues)
640646
la.AddValues = copyValues
641647
}
648+
if v.DeleteValues != nil {
649+
copyValues := make([]string, len(v.DeleteValues))
650+
copy(copyValues, v.DeleteValues)
651+
la.DeleteValues = copyValues
652+
}
642653
if v.Capacity != nil {
643654
la.Capacity = wrapperspb.Int64(*v.Capacity)
644655
}

pkg/allocation/converters/converter_test.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,9 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) {
135135
},
136136
Lists: map[string]*pb.ListAction{
137137
"p": {
138-
AddValues: []string{"foo", "bar", "baz"},
139-
Capacity: wrapperspb.Int64(10),
138+
AddValues: []string{"foo", "bar", "baz"},
139+
Capacity: wrapperspb.Int64(10),
140+
DeleteValues: []string{"alice", "bob", "cat"},
140141
},
141142
},
142143
Scheduling: pb.AllocationRequest_Packed,
@@ -217,8 +218,9 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) {
217218
},
218219
Lists: map[string]allocationv1.ListAction{
219220
"p": {
220-
AddValues: []string{"foo", "bar", "baz"},
221-
Capacity: &ten,
221+
AddValues: []string{"foo", "bar", "baz"},
222+
Capacity: &ten,
223+
DeleteValues: []string{"alice", "bob", "cat"},
222224
},
223225
},
224226
Selectors: []allocationv1.GameServerSelector{
@@ -742,6 +744,9 @@ func TestConvertGSAToAllocationRequest(t *testing.T) {
742744
"d": {
743745
Capacity: &two,
744746
},
747+
"c": {
748+
DeleteValues: []string{"good", "bye"},
749+
},
745750
},
746751
Scheduling: apis.Distributed,
747752
},
@@ -821,6 +826,9 @@ func TestConvertGSAToAllocationRequest(t *testing.T) {
821826
"d": {
822827
Capacity: wrapperspb.Int64(two),
823828
},
829+
"c": {
830+
DeleteValues: []string{"good", "bye"},
831+
},
824832
},
825833
},
826834
},

pkg/allocation/go/allocation.pb.go

Lines changed: 36 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/allocation/go/allocation.swagger.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,9 +351,15 @@
351351
"capacity": {
352352
"type": "string",
353353
"format": "int64"
354+
},
355+
"deleteValues": {
356+
"type": "array",
357+
"items": {
358+
"type": "string"
359+
}
354360
}
355361
},
356-
"description": "ListAction is an optional action that can be performed on a List at allocation.\nAddValues: Append values to a List's Values array (optional). Any duplicate values will be ignored.\nCapacity: Update the maximum capacity of the Counter to this number (optional). Min 0, Max 1000."
362+
"description": "ListAction is an optional action that can be performed on a List at allocation.\nAddValues: Append values to a List's Values array (optional). Any duplicate values will be ignored.\nCapacity: Update the maximum capacity of the Counter to this number (optional). Min 0, Max 1000.\nDeleteValues: Remove values from a List's Values array (optional). Any nonexistant values will be ignored."
357363
},
358364
"allocationListSelector": {
359365
"type": "object",

pkg/apis/agones/v1/gameserver.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,6 +1026,37 @@ func (gs *GameServer) AppendListValues(name string, values []string) error {
10261026
return errors.Errorf("unable to AppendListValues: Name %s, Values %s. List not found in GameServer %s", name, values, gs.ObjectMeta.GetName())
10271027
}
10281028

1029+
// DeleteListValues removes values from the ListStatus Values list. Values in the DeleteListValues
1030+
// list that are not in the ListStatus Values list are ignored.
1031+
func (gs *GameServer) DeleteListValues(name string, values []string) error {
1032+
if values == nil {
1033+
return errors.Errorf("unable to DeleteListValues: Name %s, Values %s. Values must not be nil", name, values)
1034+
}
1035+
if list, ok := gs.Status.Lists[name]; ok {
1036+
deleteValuesMap := make(map[string]bool)
1037+
for _, value := range values {
1038+
deleteValuesMap[value] = true
1039+
}
1040+
newList := deleteValues(list.Values, deleteValuesMap)
1041+
list.Values = newList
1042+
gs.Status.Lists[name] = list
1043+
return nil
1044+
}
1045+
return errors.Errorf("unable to DeleteListValues: Name %s, Values %s. List not found in GameServer %s", name, values, gs.ObjectMeta.GetName())
1046+
}
1047+
1048+
// deleteValues returns a new list with all the values in valuesList that are not keys in deleteValuesMap.
1049+
func deleteValues(valuesList []string, deleteValuesMap map[string]bool) []string {
1050+
newValuesList := []string{}
1051+
for _, value := range valuesList {
1052+
if _, ok := deleteValuesMap[value]; ok {
1053+
continue
1054+
}
1055+
newValuesList = append(newValuesList, value)
1056+
}
1057+
return newValuesList
1058+
}
1059+
10291060
// truncateList truncates the list to the given capacity
10301061
func truncateList(capacity int64, list []string) []string {
10311062
if list == nil || len(list) <= int(capacity) {

pkg/apis/agones/v1/gameserver_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,6 +2223,63 @@ func TestGameServerAppendListValues(t *testing.T) {
22232223
}
22242224
}
22252225

2226+
func TestGameServerDeleteListValues(t *testing.T) {
2227+
t.Parallel()
2228+
2229+
testCases := map[string]struct {
2230+
gs GameServer
2231+
name string
2232+
want ListStatus
2233+
values []string
2234+
wantErr bool
2235+
}{
2236+
"list not in game server no-op and error": {
2237+
gs: GameServer{Status: GameServerStatus{
2238+
Lists: map[string]ListStatus{
2239+
"foos": {
2240+
Values: []string{"foo", "bar", "bax"},
2241+
Capacity: 100,
2242+
},
2243+
},
2244+
}},
2245+
name: "foo",
2246+
values: []string{"bar", "baz"},
2247+
wantErr: true,
2248+
},
2249+
"delete list value - one value not present": {
2250+
gs: GameServer{Status: GameServerStatus{
2251+
Lists: map[string]ListStatus{
2252+
"foo": {
2253+
Values: []string{"foo", "bar", "bax"},
2254+
Capacity: 100,
2255+
},
2256+
},
2257+
}},
2258+
name: "foo",
2259+
values: []string{"bar", "baz"},
2260+
wantErr: false,
2261+
want: ListStatus{
2262+
Values: []string{"foo", "bax"},
2263+
Capacity: 100,
2264+
},
2265+
},
2266+
}
2267+
2268+
for test, testCase := range testCases {
2269+
t.Run(test, func(t *testing.T) {
2270+
err := testCase.gs.DeleteListValues(testCase.name, testCase.values)
2271+
if err != nil {
2272+
assert.True(t, testCase.wantErr)
2273+
} else {
2274+
assert.False(t, testCase.wantErr)
2275+
}
2276+
if list, ok := testCase.gs.Status.Lists[testCase.name]; ok {
2277+
assert.Equal(t, testCase.want, list)
2278+
}
2279+
})
2280+
}
2281+
}
2282+
22262283
func TestMergeRemoveDuplicates(t *testing.T) {
22272284
t.Parallel()
22282285

pkg/apis/allocation/v1/gameserverallocation.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ type ListAction struct {
209209
// AddValues appends values to a List's Values array. Any duplicate values will be ignored.
210210
// +optional
211211
AddValues []string `json:"addValues,omitempty"`
212+
// DeleteValues removes values from a List's Values array. Any nonexistant values will be ignored.
213+
// +optional
214+
DeleteValues []string `json:"deleteValues,omitempty"`
212215
// Capacity updates the maximum capacity of the Counter to this number. Min 0, Max 1000.
213216
// +optional
214217
Capacity *int64 `json:"capacity,omitempty"`
@@ -349,6 +352,12 @@ func (la *ListAction) ListActions(list string, gs *agonesv1.GameServer) error {
349352
errs = errors.Join(errs, cntErr)
350353
}
351354
}
355+
if len(la.DeleteValues) > 0 {
356+
cntErr := gs.DeleteListValues(list, la.DeleteValues)
357+
if cntErr != nil {
358+
errs = errors.Join(errs, cntErr)
359+
}
360+
}
352361
return errs
353362
}
354363

pkg/apis/allocation/v1/gameserverallocation_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,20 +1019,21 @@ func TestGameServerListActions(t *testing.T) {
10191019
},
10201020
"update list values and capacity": {
10211021
la: ListAction{
1022-
AddValues: []string{"magician1", "magician3"},
1023-
Capacity: int64Pointer(42),
1022+
AddValues: []string{"magician1", "magician3"},
1023+
Capacity: int64Pointer(42),
1024+
DeleteValues: []string{"magician2", "magician5", "magician6"},
10241025
},
10251026
list: "magicians",
10261027
gs: &agonesv1.GameServer{Status: agonesv1.GameServerStatus{
10271028
Lists: map[string]agonesv1.ListStatus{
10281029
"magicians": {
1029-
Values: []string{"magician1", "magician2"},
1030+
Values: []string{"magician1", "magician2", "magician4", "magician5"},
10301031
Capacity: 100,
10311032
}}}},
10321033
want: &agonesv1.GameServer{Status: agonesv1.GameServerStatus{
10331034
Lists: map[string]agonesv1.ListStatus{
10341035
"magicians": {
1035-
Values: []string{"magician1", "magician2", "magician3"},
1036+
Values: []string{"magician1", "magician4", "magician3"},
10361037
Capacity: 42,
10371038
}}}},
10381039
wantErr: false,
@@ -1263,7 +1264,8 @@ func TestValidateListActions(t *testing.T) {
12631264
Capacity: int64Pointer(0),
12641265
},
12651266
"baz": {
1266-
AddValues: []string{},
1267+
AddValues: []string{},
1268+
DeleteValues: []string{"good", "bye"},
12671269
},
12681270
},
12691271
wantErr: false,

pkg/apis/allocation/v1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)