diff --git a/examples/gameserverallocation-deprecated.yaml b/examples/gameserverallocation-deprecated.yaml new file mode 100644 index 0000000000..530b650b1a --- /dev/null +++ b/examples/gameserverallocation-deprecated.yaml @@ -0,0 +1,76 @@ +# Copyright 2018 Google LLC All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# Full example of a GameServerAllocation. This is used to allocate +# A GameServer out of a set of GameServers. This could be a Fleet, +# multiple Fleets, or a self managed group of GameServers. +# + +# +# For a full reference and details: https://agones.dev/site/docs/reference/gameserverallocation/ +# + +apiVersion: "allocation.agones.dev/v1" +kind: GameServerAllocation +spec: + # Deprecated, use selectors instead. + # GameServer selector from which to choose GameServers from. + # GameServers still have the hard requirement to be `Ready` to be allocated from + # however we can also make available `matchExpressions` for even greater + # flexibility. + # Below is an example of a GameServer allocated against a given fleet. + # See: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more details + required: + matchLabels: + game: my-game + matchExpressions: + - {key: tier, operator: In, values: [cache]} + # [Stage:Alpha] + # [FeatureFlag:StateAllocationFilter] + # Specifies which State is the filter to be used when attempting to retrieve a GameServer + # via Allocation. Defaults to "Ready". The only other option is "Allocated", which can be used in conjunction with + # label/annotation/player selectors to retrieve an already Allocated GameServer. + gameServerState: Ready + # [Stage:Alpha] + # [FeatureFlag:PlayerAllocationFilter] + # Provides a filter on minimum and maximum values for player capacity when retrieving a GameServer + # through Allocation. Defaults to no limits. + players: + minAvailable: 0 + maxAvailable: 99 + # Deprecated, use selectors instead. + # ordered list of preferred allocations out of the `required` set. + # If the first selector is not matched, the selection attempts the second selector, and so on. + # This is useful for things like smoke testing of new game servers. + # This also support `matchExpressions` + preferred: + - matchLabels: + agones.dev/fleet: green-fleet + - matchLabels: + agones.dev/fleet: blue-fleet + # defines how GameServers are organised across the cluster. + # Options include: + # "Packed" (default) is aimed at dynamic Kubernetes clusters, such as cloud providers, wherein we want to bin pack + # resources + # "Distributed" is aimed at static Kubernetes clusters, wherein we want to distribute resources across the entire + # cluster + scheduling: Packed + # Optional custom metadata that is added to the game server at allocation + # You can use this to tell the server necessary session data + metadata: + labels: + mode: deathmatch + annotations: + map: garden22 \ No newline at end of file diff --git a/examples/gameserverallocation.yaml b/examples/gameserverallocation.yaml index 8008acf43f..1861da7b8a 100644 --- a/examples/gameserverallocation.yaml +++ b/examples/gameserverallocation.yaml @@ -31,33 +31,32 @@ spec: # flexibility. # Below is an example of a GameServer allocated against a given fleet. # See: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more details - required: - matchLabels: - game: my-game - matchExpressions: - - {key: tier, operator: In, values: [cache]} - # [Stage:Alpha] - # [FeatureFlag:StateAllocationFilter] - # Specifies which State is the filter to be used when attempting to retrieve a GameServer - # via Allocation. Defaults to "Ready". The only other option is "Allocated", which can be used in conjunction with - # label/annotation/player selectors to retrieve an already Allocated GameServer. - gameServerState: Ready - # [Stage:Alpha] - # [FeatureFlag:PlayerAllocationFilter] - # Provides a filter on minimum and maximum values for player capacity when retrieving a GameServer - # through Allocation. Defaults to no limits. - players: - minAvailable: 0 - maxAvailable: 99 - # ordered list of preferred allocations out of the `required` set. + # The selectors is an ordered list of allocations set. # If the first selector is not matched, the selection attempts the second selector, and so on. # This is useful for things like smoke testing of new game servers. # This also support `matchExpressions` - preferred: + selectors: - matchLabels: agones.dev/fleet: green-fleet - matchLabels: agones.dev/fleet: blue-fleet + - matchLabels: + game: my-game + matchExpressions: + - {key: tier, operator: In, values: [cache]} + # [Stage:Alpha] + # [FeatureFlag:StateAllocationFilter] + # Specifies which State is the filter to be used when attempting to retrieve a GameServer + # via Allocation. Defaults to "Ready". The only other option is "Allocated", which can be used in conjunction with + # label/annotation/player selectors to retrieve an already Allocated GameServer. + gameServerState: Ready + # [Stage:Alpha] + # [FeatureFlag:PlayerAllocationFilter] + # Provides a filter on minimum and maximum values for player capacity when retrieving a GameServer + # through Allocation. Defaults to no limits. + players: + minAvailable: 0 + maxAvailable: 99 # defines how GameServers are organised across the cluster. # Options include: # "Packed" (default) is aimed at dynamic Kubernetes clusters, such as cloud providers, wherein we want to bin pack diff --git a/pkg/allocation/converters/converter.go b/pkg/allocation/converters/converter.go index 411c58720e..170770f0fe 100644 --- a/pkg/allocation/converters/converter.go +++ b/pkg/allocation/converters/converter.go @@ -37,7 +37,9 @@ func ConvertAllocationRequestToGSA(in *pb.AllocationRequest) *allocationv1.GameS Namespace: in.GetNamespace(), }, Spec: allocationv1.GameServerAllocationSpec{ + // nolint:staticcheck Preferred: convertGameServerSelectorsToInternalGameServerSelectors(in.GetPreferredGameServerSelectors()), + Selectors: convertGameServerSelectorsToInternalGameServerSelectors(in.GetGameServerSelectors()), Scheduling: convertAllocationSchedulingToGSASchedulingStrategy(in.GetScheduling()), }, } @@ -64,7 +66,9 @@ func ConvertAllocationRequestToGSA(in *pb.AllocationRequest) *allocationv1.GameS } } + // nolint:staticcheck if selector := convertGameServerSelectorToInternalGameServerSelector(in.GetRequiredGameServerSelector()); selector != nil { + // nolint:staticcheck gsa.Spec.Required = *selector } return gsa @@ -77,13 +81,12 @@ func ConvertGSAToAllocationRequest(in *allocationv1.GameServerAllocation) *pb.Al } out := &pb.AllocationRequest{ - Namespace: in.GetNamespace(), - PreferredGameServerSelectors: convertInternalLabelSelectorsToLabelSelectors(in.Spec.Preferred), - Scheduling: convertGSASchedulingStrategyToAllocationScheduling(in.Spec.Scheduling), + Namespace: in.GetNamespace(), + Scheduling: convertGSASchedulingStrategyToAllocationScheduling(in.Spec.Scheduling), + GameServerSelectors: convertInternalLabelSelectorsToLabelSelectors(in.Spec.Selectors), MultiClusterSetting: &pb.MultiClusterSetting{ Enabled: in.Spec.MultiClusterSetting.Enabled, }, - RequiredGameServerSelector: convertInternalGameServerSelectorToGameServer(&in.Spec.Required), Metadata: &pb.MetaPatch{ Labels: in.Spec.MetaPatch.Labels, Annotations: in.Spec.MetaPatch.Annotations, @@ -97,6 +100,14 @@ func ConvertGSAToAllocationRequest(in *allocationv1.GameServerAllocation) *pb.Al }, } + l := len(out.GameServerSelectors) + if l > 0 { + // nolint:staticcheck + out.PreferredGameServerSelectors = out.GameServerSelectors[:l-1] + // nolint:staticcheck + out.RequiredGameServerSelector = out.GameServerSelectors[l-1] + } + if in.Spec.MultiClusterSetting.Enabled { out.MultiClusterSetting.PolicySelector = convertInternalLabelSelectorToLabelSelector(&in.Spec.MultiClusterSetting.PolicySelector) } diff --git a/pkg/allocation/converters/converter_test.go b/pkg/allocation/converters/converter_test.go index fff812c64f..136bb2076d 100644 --- a/pkg/allocation/converters/converter_test.go +++ b/pkg/allocation/converters/converter_test.go @@ -35,11 +35,10 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) { ready := agonesv1.GameServerStateReady tests := []struct { - name string - features string - in *pb.AllocationRequest - want *allocationv1.GameServerAllocation - skipConvertFromGSA bool + name string + features string + in *pb.AllocationRequest + want *allocationv1.GameServerAllocation }{ { name: "all fields are set (StateAllocationFilter, PlayerAllocationFilter)", @@ -172,6 +171,13 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) { }, }, }, + GameServerSelectors: []*pb.GameServerSelector{ + { + MatchLabels: map[string]string{ + "m": "n", + }, + }, + }, Scheduling: pb.AllocationRequest_Packed, Metadata: &pb.MetaPatch{ Labels: map[string]string{ @@ -218,6 +224,15 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) { }, }, }, + Selectors: []allocationv1.GameServerSelector{ + { + LabelSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{ + "m": "n", + }, + }, + }, + }, Scheduling: apis.Packed, MetaPatch: allocationv1.MetaPatch{ Labels: map[string]string{ @@ -248,7 +263,6 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) { Scheduling: apis.Distributed, }, }, - skipConvertFromGSA: true, }, { name: "empty fields to GSA (StateAllocationFilter, PlayerAllocationFilter)", @@ -275,7 +289,31 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) { Scheduling: apis.Distributed, }, }, - skipConvertFromGSA: true, + }, + { + name: "empty fields to GSA (StateAllocationFilter, PlayerAllocationFilter) with selectors fields", + features: fmt.Sprintf("%s=true&%s=true", runtime.FeaturePlayerAllocationFilter, runtime.FeatureStateAllocationFilter), + in: &pb.AllocationRequest{ + Namespace: "", + MultiClusterSetting: &pb.MultiClusterSetting{}, + GameServerSelectors: []*pb.GameServerSelector{{}}, + Scheduling: pb.AllocationRequest_Distributed, + Metadata: &pb.MetaPatch{}, + }, + want: &allocationv1.GameServerAllocation{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "", + }, + Spec: allocationv1.GameServerAllocationSpec{ + MultiClusterSetting: allocationv1.MultiClusterSetting{ + Enabled: false, + }, + Selectors: []allocationv1.GameServerSelector{ + {GameServerState: &ready}, + }, + Scheduling: apis.Distributed, + }, + }, }, { name: "empty object to GSA", @@ -285,7 +323,6 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) { Scheduling: apis.Packed, }, }, - skipConvertFromGSA: true, }, { name: "nil object", @@ -322,7 +359,6 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) { }, }, }, - skipConvertFromGSA: true, }, { name: "Prefers metadata over metapatch field", @@ -359,7 +395,6 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) { }, }, }, - skipConvertFromGSA: true, }, } for _, tc := range tests { @@ -373,11 +408,6 @@ func TestConvertAllocationRequestToGameServerAllocation(t *testing.T) { out := ConvertAllocationRequestToGSA(tc.in) assert.Equal(t, tc.want, out, "mismatch with want after conversion: \"%s\"", tc.name) - - if !tc.skipConvertFromGSA { - gsa := ConvertGSAToAllocationRequest(tc.want) - assert.Equal(t, tc.in, gsa, "mismatch with input after double conversion \"%s\"", tc.name) - } }) } } @@ -402,12 +432,11 @@ func TestConvertGSAToAllocationRequestEmpty(t *testing.T) { }, }, want: &pb.AllocationRequest{ - Namespace: "", - MultiClusterSetting: &pb.MultiClusterSetting{}, - RequiredGameServerSelector: &pb.GameServerSelector{}, - Scheduling: pb.AllocationRequest_Distributed, - Metadata: &pb.MetaPatch{}, - MetaPatch: &pb.MetaPatch{}, + Namespace: "", + MultiClusterSetting: &pb.MultiClusterSetting{}, + Scheduling: pb.AllocationRequest_Distributed, + Metadata: &pb.MetaPatch{}, + MetaPatch: &pb.MetaPatch{}, }, }, { name: "empty object", @@ -417,10 +446,9 @@ func TestConvertGSAToAllocationRequestEmpty(t *testing.T) { }, }, want: &pb.AllocationRequest{ - MultiClusterSetting: &pb.MultiClusterSetting{}, - RequiredGameServerSelector: &pb.GameServerSelector{}, - Metadata: &pb.MetaPatch{}, - MetaPatch: &pb.MetaPatch{}, + MultiClusterSetting: &pb.MultiClusterSetting{}, + Metadata: &pb.MetaPatch{}, + MetaPatch: &pb.MetaPatch{}, }, }, } diff --git a/pkg/allocation/go/allocation.pb.go b/pkg/allocation/go/allocation.pb.go index 7ff7a0c9d6..fc702e612b 100644 --- a/pkg/allocation/go/allocation.pb.go +++ b/pkg/allocation/go/allocation.pb.go @@ -63,7 +63,7 @@ func (x AllocationRequest_SchedulingStrategy) String() string { return proto.EnumName(AllocationRequest_SchedulingStrategy_name, int32(x)) } func (AllocationRequest_SchedulingStrategy) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{0, 0} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{0, 0} } type GameServerSelector_GameServerState int32 @@ -86,7 +86,7 @@ func (x GameServerSelector_GameServerState) String() string { return proto.EnumName(GameServerSelector_GameServerState_name, int32(x)) } func (GameServerSelector_GameServerState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{5, 0} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{5, 0} } type AllocationRequest struct { @@ -94,11 +94,15 @@ type AllocationRequest struct { Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"` // If specified, multi-cluster policies are applied. Otherwise, allocation will happen locally. MultiClusterSetting *MultiClusterSetting `protobuf:"bytes,2,opt,name=multiClusterSetting,proto3" json:"multiClusterSetting,omitempty"` + // Deprecated: Please use gameServerSelectors instead. This field is ignored if the + // gameServerSelectors field is set // The required allocation. Defaults to all GameServers. - RequiredGameServerSelector *GameServerSelector `protobuf:"bytes,3,opt,name=requiredGameServerSelector,proto3" json:"requiredGameServerSelector,omitempty"` + RequiredGameServerSelector *GameServerSelector `protobuf:"bytes,3,opt,name=requiredGameServerSelector,proto3" json:"requiredGameServerSelector,omitempty"` // Deprecated: Do not use. + // Deprecated: Please use gameServerSelectors instead. This field is ignored if the + // gameServerSelectors field is set // The ordered list of preferred allocations out of the `required` set. // If the first selector is not matched, the selection attempts the second selector, and so on. - PreferredGameServerSelectors []*GameServerSelector `protobuf:"bytes,4,rep,name=preferredGameServerSelectors,proto3" json:"preferredGameServerSelectors,omitempty"` + PreferredGameServerSelectors []*GameServerSelector `protobuf:"bytes,4,rep,name=preferredGameServerSelectors,proto3" json:"preferredGameServerSelectors,omitempty"` // Deprecated: Do not use. // Scheduling strategy. Defaults to "Packed". Scheduling AllocationRequest_SchedulingStrategy `protobuf:"varint,5,opt,name=scheduling,proto3,enum=allocation.AllocationRequest_SchedulingStrategy" json:"scheduling,omitempty"` // Deprecated: Please use metadata instead. This field is ignored if the @@ -106,17 +110,22 @@ type AllocationRequest struct { MetaPatch *MetaPatch `protobuf:"bytes,6,opt,name=metaPatch,proto3" json:"metaPatch,omitempty"` // Metadata is optional custom metadata that is added to the game server at // allocation. You can use this to tell the server necessary session data - Metadata *MetaPatch `protobuf:"bytes,7,opt,name=metadata,proto3" json:"metadata,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Metadata *MetaPatch `protobuf:"bytes,7,opt,name=metadata,proto3" json:"metadata,omitempty"` + // Ordered list of GameServer label selectors. + // If the first selector is not matched, the selection attempts the second selector, and so on. + // This is useful for things like smoke testing of new game servers. + // Note: This field can only be set if neither Required or Preferred is set. + GameServerSelectors []*GameServerSelector `protobuf:"bytes,8,rep,name=gameServerSelectors,proto3" json:"gameServerSelectors,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *AllocationRequest) Reset() { *m = AllocationRequest{} } func (m *AllocationRequest) String() string { return proto.CompactTextString(m) } func (*AllocationRequest) ProtoMessage() {} func (*AllocationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{0} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{0} } func (m *AllocationRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AllocationRequest.Unmarshal(m, b) @@ -150,6 +159,7 @@ func (m *AllocationRequest) GetMultiClusterSetting() *MultiClusterSetting { return nil } +// Deprecated: Do not use. func (m *AllocationRequest) GetRequiredGameServerSelector() *GameServerSelector { if m != nil { return m.RequiredGameServerSelector @@ -157,6 +167,7 @@ func (m *AllocationRequest) GetRequiredGameServerSelector() *GameServerSelector return nil } +// Deprecated: Do not use. func (m *AllocationRequest) GetPreferredGameServerSelectors() []*GameServerSelector { if m != nil { return m.PreferredGameServerSelectors @@ -185,6 +196,13 @@ func (m *AllocationRequest) GetMetadata() *MetaPatch { return nil } +func (m *AllocationRequest) GetGameServerSelectors() []*GameServerSelector { + if m != nil { + return m.GameServerSelectors + } + return nil +} + type AllocationResponse struct { GameServerName string `protobuf:"bytes,2,opt,name=gameServerName,proto3" json:"gameServerName,omitempty"` Ports []*AllocationResponse_GameServerStatusPort `protobuf:"bytes,3,rep,name=ports,proto3" json:"ports,omitempty"` @@ -199,7 +217,7 @@ func (m *AllocationResponse) Reset() { *m = AllocationResponse{} } func (m *AllocationResponse) String() string { return proto.CompactTextString(m) } func (*AllocationResponse) ProtoMessage() {} func (*AllocationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{1} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{1} } func (m *AllocationResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AllocationResponse.Unmarshal(m, b) @@ -262,7 +280,7 @@ func (m *AllocationResponse_GameServerStatusPort) Reset() { func (m *AllocationResponse_GameServerStatusPort) String() string { return proto.CompactTextString(m) } func (*AllocationResponse_GameServerStatusPort) ProtoMessage() {} func (*AllocationResponse_GameServerStatusPort) Descriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{1, 0} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{1, 0} } func (m *AllocationResponse_GameServerStatusPort) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AllocationResponse_GameServerStatusPort.Unmarshal(m, b) @@ -311,7 +329,7 @@ func (m *MultiClusterSetting) Reset() { *m = MultiClusterSetting{} } func (m *MultiClusterSetting) String() string { return proto.CompactTextString(m) } func (*MultiClusterSetting) ProtoMessage() {} func (*MultiClusterSetting) Descriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{2} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{2} } func (m *MultiClusterSetting) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MultiClusterSetting.Unmarshal(m, b) @@ -358,7 +376,7 @@ func (m *MetaPatch) Reset() { *m = MetaPatch{} } func (m *MetaPatch) String() string { return proto.CompactTextString(m) } func (*MetaPatch) ProtoMessage() {} func (*MetaPatch) Descriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{3} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{3} } func (m *MetaPatch) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MetaPatch.Unmarshal(m, b) @@ -405,7 +423,7 @@ func (m *LabelSelector) Reset() { *m = LabelSelector{} } func (m *LabelSelector) String() string { return proto.CompactTextString(m) } func (*LabelSelector) ProtoMessage() {} func (*LabelSelector) Descriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{4} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{4} } func (m *LabelSelector) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LabelSelector.Unmarshal(m, b) @@ -447,7 +465,7 @@ func (m *GameServerSelector) Reset() { *m = GameServerSelector{} } func (m *GameServerSelector) String() string { return proto.CompactTextString(m) } func (*GameServerSelector) ProtoMessage() {} func (*GameServerSelector) Descriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{5} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{5} } func (m *GameServerSelector) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GameServerSelector.Unmarshal(m, b) @@ -502,7 +520,7 @@ func (m *PlayerSelector) Reset() { *m = PlayerSelector{} } func (m *PlayerSelector) String() string { return proto.CompactTextString(m) } func (*PlayerSelector) ProtoMessage() {} func (*PlayerSelector) Descriptor() ([]byte, []int) { - return fileDescriptor_allocation_bb4a9ec25bdc6979, []int{6} + return fileDescriptor_allocation_ffd63343a38c3b54, []int{6} } func (m *PlayerSelector) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PlayerSelector.Unmarshal(m, b) @@ -626,57 +644,58 @@ var _AllocationService_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("proto/allocation/allocation.proto", fileDescriptor_allocation_bb4a9ec25bdc6979) -} - -var fileDescriptor_allocation_bb4a9ec25bdc6979 = []byte{ - // 760 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xcd, 0x6e, 0xf3, 0x44, - 0x14, 0xfd, 0x9c, 0xbf, 0x26, 0x37, 0x7c, 0x69, 0xb8, 0x6d, 0x25, 0x63, 0x95, 0x92, 0x7a, 0x51, - 0x55, 0x45, 0x4a, 0x68, 0xca, 0x82, 0x76, 0x51, 0x29, 0x6a, 0x2b, 0x40, 0x4a, 0x21, 0x75, 0x58, - 0x94, 0x0d, 0xd2, 0xc4, 0x1e, 0x52, 0xab, 0x8e, 0xed, 0xce, 0x8c, 0x2b, 0xb2, 0x43, 0x6c, 0x59, - 0xb2, 0xe6, 0x31, 0x78, 0x12, 0x5e, 0xa1, 0xaf, 0x81, 0x84, 0x66, 0x9c, 0x38, 0x93, 0xc4, 0x0d, - 0x54, 0xdf, 0x6e, 0xe6, 0xde, 0x73, 0xcf, 0x9c, 0x39, 0x73, 0x7d, 0x0d, 0x87, 0x31, 0x8b, 0x44, - 0xd4, 0x21, 0x41, 0x10, 0xb9, 0x44, 0xf8, 0x51, 0xa8, 0x2d, 0xdb, 0x2a, 0x87, 0xb0, 0x88, 0x58, - 0xfb, 0xe3, 0x28, 0x1a, 0x07, 0xb4, 0x43, 0x62, 0xbf, 0x43, 0xc2, 0x30, 0x12, 0x2a, 0xcc, 0x53, - 0xa4, 0xfd, 0x57, 0x09, 0x3e, 0xee, 0x65, 0x60, 0x87, 0x3e, 0x25, 0x94, 0x0b, 0xdc, 0x87, 0x5a, - 0x48, 0x26, 0x94, 0xc7, 0xc4, 0xa5, 0xa6, 0xd1, 0x32, 0x8e, 0x6b, 0xce, 0x22, 0x80, 0x77, 0xb0, - 0x33, 0x49, 0x02, 0xe1, 0x5f, 0x05, 0x09, 0x17, 0x94, 0x0d, 0xa9, 0x10, 0x7e, 0x38, 0x36, 0x0b, - 0x2d, 0xe3, 0xb8, 0xde, 0xfd, 0xac, 0xad, 0xa9, 0xb9, 0x5d, 0x87, 0x39, 0x79, 0xb5, 0xf8, 0x13, - 0x58, 0x8c, 0x3e, 0x25, 0x3e, 0xa3, 0xde, 0xd7, 0x64, 0x42, 0x87, 0x94, 0x3d, 0xcb, 0x64, 0x40, - 0x5d, 0x11, 0x31, 0xb3, 0xa8, 0x98, 0x0f, 0x74, 0xe6, 0x75, 0x94, 0xb3, 0x81, 0x01, 0x47, 0xb0, - 0x1f, 0x33, 0xfa, 0x33, 0x65, 0xb9, 0x69, 0x6e, 0x96, 0x5a, 0xc5, 0xff, 0x71, 0xc2, 0x46, 0x0e, - 0x1c, 0x00, 0x70, 0xf7, 0x81, 0x7a, 0x49, 0x20, 0xdd, 0x28, 0xb7, 0x8c, 0xe3, 0x46, 0xf7, 0x0b, - 0x9d, 0x71, 0xcd, 0xe7, 0xf6, 0x30, 0xc3, 0x0f, 0x05, 0x23, 0x82, 0x8e, 0xa7, 0x8e, 0xc6, 0x81, - 0x67, 0x50, 0x9b, 0x50, 0x41, 0x06, 0x44, 0xb8, 0x0f, 0x66, 0x45, 0x99, 0xb0, 0xb7, 0x64, 0xef, - 0x3c, 0xe9, 0x2c, 0x70, 0x78, 0x0a, 0x55, 0xb9, 0xf1, 0x88, 0x20, 0xe6, 0xd6, 0xa6, 0x9a, 0x0c, - 0x66, 0x9f, 0x02, 0xae, 0x2b, 0x41, 0x80, 0xca, 0x80, 0xb8, 0x8f, 0xd4, 0x6b, 0xbe, 0xc3, 0x6d, - 0xa8, 0x5f, 0xfb, 0x5c, 0x30, 0x7f, 0x94, 0x08, 0xea, 0x35, 0x0d, 0xfb, 0x1f, 0x03, 0x50, 0xbf, - 0x0f, 0x8f, 0xa3, 0x90, 0x53, 0x3c, 0x82, 0xc6, 0x38, 0xb3, 0xe6, 0x3b, 0x32, 0xa1, 0xaa, 0x2b, - 0x6a, 0xce, 0x4a, 0x14, 0xbf, 0x85, 0x72, 0x1c, 0x31, 0xc1, 0xcd, 0xa2, 0x32, 0xfe, 0xec, 0x35, - 0x9b, 0x52, 0x5a, 0xfd, 0x2d, 0x04, 0x11, 0x09, 0x1f, 0x44, 0x4c, 0x38, 0x29, 0x03, 0x9a, 0xb0, - 0x45, 0x3c, 0x8f, 0x51, 0x2e, 0x5f, 0x51, 0x9e, 0x35, 0xdf, 0xa2, 0x05, 0xd5, 0x30, 0xf2, 0xa8, - 0x92, 0x51, 0x56, 0xa9, 0x6c, 0x6f, 0x5d, 0xc2, 0x6e, 0x1e, 0x29, 0x22, 0x94, 0x64, 0xa3, 0xcf, - 0x9a, 0x5e, 0xad, 0x65, 0x4c, 0x1e, 0xa5, 0xae, 0x52, 0x76, 0xd4, 0xda, 0x66, 0xb0, 0x93, 0xd3, - 0xdc, 0x52, 0x0c, 0x0d, 0xc9, 0x28, 0xa0, 0x9e, 0x62, 0xa8, 0x3a, 0xf3, 0x2d, 0xf6, 0xa0, 0x11, - 0x47, 0x81, 0xef, 0x4e, 0xb3, 0xae, 0x4e, 0xbf, 0x97, 0x4f, 0xf4, 0xab, 0xf7, 0xc9, 0x88, 0x06, - 0x59, 0xbb, 0xad, 0x14, 0xd8, 0xbf, 0x17, 0xa0, 0x96, 0x3d, 0x1f, 0x9e, 0x43, 0x25, 0x90, 0x70, - 0x6e, 0x1a, 0xca, 0xc3, 0xc3, 0xdc, 0x57, 0x4e, 0x29, 0xf9, 0x4d, 0x28, 0xd8, 0xd4, 0x99, 0x15, - 0xe0, 0x37, 0x50, 0xd7, 0x26, 0x81, 0x59, 0x50, 0xf5, 0x47, 0xf9, 0xf5, 0xbd, 0x05, 0x30, 0x25, - 0xd1, 0x4b, 0xad, 0x73, 0xa8, 0x6b, 0x07, 0x60, 0x13, 0x8a, 0x8f, 0x74, 0x3a, 0x33, 0x4f, 0x2e, - 0x71, 0x17, 0xca, 0xcf, 0x24, 0x48, 0xe6, 0x7d, 0x90, 0x6e, 0x2e, 0x0a, 0x5f, 0x19, 0xd6, 0x25, - 0x34, 0x57, 0xb9, 0xdf, 0x52, 0x6f, 0xff, 0x69, 0xc0, 0xfb, 0x25, 0xbf, 0xb0, 0x0f, 0xf5, 0x89, - 0xd4, 0xdc, 0xd7, 0x6d, 0x39, 0x79, 0xd5, 0xdf, 0xf6, 0xed, 0x02, 0x3c, 0xbb, 0x9a, 0x56, 0x2e, - 0xf5, 0xad, 0x02, 0xde, 0xa4, 0xef, 0xa5, 0x00, 0x98, 0x33, 0x89, 0xee, 0xf2, 0x44, 0x76, 0x36, - 0x0f, 0x9e, 0xcd, 0x4a, 0xf1, 0x1e, 0xb6, 0xc7, 0x4b, 0xbd, 0x9c, 0xaa, 0x69, 0x74, 0xdb, 0xff, - 0x41, 0xbb, 0xfc, 0x05, 0x50, 0x67, 0x95, 0x06, 0xbf, 0x84, 0xad, 0x38, 0x20, 0x53, 0xca, 0xf8, - 0x6c, 0x06, 0x5b, 0x3a, 0xe3, 0x40, 0xa5, 0xb2, 0x76, 0x9d, 0x43, 0x3f, 0xd8, 0xb9, 0xcf, 0x61, - 0x7b, 0x45, 0x19, 0xd6, 0xa0, 0xec, 0xdc, 0xf4, 0xae, 0x7f, 0x6c, 0xbe, 0xc3, 0xf7, 0x50, 0xeb, - 0xf5, 0xfb, 0xdf, 0x5f, 0xf5, 0x7e, 0xb8, 0xb9, 0x6e, 0x1a, 0xf6, 0x3d, 0x34, 0x96, 0x75, 0xa0, - 0x0d, 0x1f, 0x4d, 0xfc, 0xb0, 0xf7, 0x4c, 0xfc, 0x40, 0x7e, 0x7a, 0xea, 0xcc, 0x92, 0xb3, 0x14, - 0x53, 0x18, 0xf2, 0xcb, 0x02, 0x53, 0x98, 0x61, 0xb4, 0x58, 0xf7, 0x57, 0x43, 0xff, 0x35, 0x4a, - 0x35, 0xbe, 0x4b, 0xf1, 0x11, 0xaa, 0xb3, 0x20, 0xc5, 0x4f, 0x37, 0x4e, 0x77, 0xeb, 0x60, 0xf3, - 0x54, 0xb3, 0x5b, 0xbf, 0xfd, 0xfd, 0xf2, 0x47, 0xc1, 0xb2, 0xf7, 0x3a, 0xd2, 0x77, 0xae, 0xae, - 0xbb, 0xa8, 0xb8, 0x30, 0x4e, 0x46, 0x15, 0xf5, 0x93, 0x3e, 0xfb, 0x37, 0x00, 0x00, 0xff, 0xff, - 0x0d, 0x34, 0x24, 0x46, 0xf3, 0x07, 0x00, 0x00, + proto.RegisterFile("proto/allocation/allocation.proto", fileDescriptor_allocation_ffd63343a38c3b54) +} + +var fileDescriptor_allocation_ffd63343a38c3b54 = []byte{ + // 776 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0x41, 0x6f, 0xe3, 0x44, + 0x14, 0x5e, 0x3b, 0x4d, 0x9a, 0xbc, 0xb0, 0x69, 0x78, 0xdd, 0x95, 0x8c, 0x55, 0x96, 0xac, 0x0f, + 0xab, 0x6a, 0x91, 0x12, 0x36, 0xe5, 0xc0, 0xee, 0xa1, 0x52, 0x68, 0x2b, 0x40, 0x4a, 0x21, 0x75, + 0x38, 0x94, 0xe3, 0xc4, 0x9e, 0xa6, 0x56, 0x1d, 0xdb, 0x9d, 0x19, 0x57, 0xe4, 0x86, 0xb8, 0x72, + 0xe0, 0xc0, 0x99, 0x5f, 0xc5, 0x5f, 0xe8, 0xdf, 0x40, 0x42, 0x33, 0x4e, 0xec, 0x49, 0xe2, 0x86, + 0x56, 0x7b, 0x9b, 0x79, 0xf3, 0xbd, 0x6f, 0xbe, 0xf7, 0xf9, 0xbd, 0x31, 0xbc, 0x4e, 0x58, 0x2c, + 0xe2, 0x1e, 0x09, 0xc3, 0xd8, 0x23, 0x22, 0x88, 0x23, 0x6d, 0xd9, 0x55, 0x67, 0x08, 0x45, 0xc4, + 0x3e, 0x98, 0xc6, 0xf1, 0x34, 0xa4, 0x3d, 0x92, 0x04, 0x3d, 0x12, 0x45, 0xb1, 0x50, 0x61, 0x9e, + 0x21, 0x9d, 0x3f, 0xab, 0xf0, 0xe9, 0x20, 0x07, 0xbb, 0xf4, 0x36, 0xa5, 0x5c, 0xe0, 0x01, 0x34, + 0x22, 0x32, 0xa3, 0x3c, 0x21, 0x1e, 0xb5, 0x8c, 0x8e, 0x71, 0xd8, 0x70, 0x8b, 0x00, 0x5e, 0xc0, + 0xfe, 0x2c, 0x0d, 0x45, 0x70, 0x12, 0xa6, 0x5c, 0x50, 0x36, 0xa6, 0x42, 0x04, 0xd1, 0xd4, 0x32, + 0x3b, 0xc6, 0x61, 0xb3, 0xff, 0x45, 0x57, 0x53, 0x73, 0xbe, 0x09, 0x73, 0xcb, 0x72, 0x71, 0x02, + 0x36, 0xa3, 0xb7, 0x69, 0xc0, 0xa8, 0xff, 0x1d, 0x99, 0xd1, 0x31, 0x65, 0x77, 0xf2, 0x30, 0xa4, + 0x9e, 0x88, 0x99, 0x55, 0x51, 0xcc, 0xaf, 0x74, 0xe6, 0x4d, 0xd4, 0xb7, 0xa6, 0x65, 0xb8, 0x5b, + 0x58, 0xf0, 0x0a, 0x0e, 0x12, 0x46, 0xaf, 0x28, 0x2b, 0x3d, 0xe6, 0xd6, 0x4e, 0xa7, 0xf2, 0xc8, + 0x5b, 0xb6, 0xf2, 0xe0, 0x08, 0x80, 0x7b, 0xd7, 0xd4, 0x4f, 0x43, 0xe9, 0x4a, 0xb5, 0x63, 0x1c, + 0xb6, 0xfa, 0x5f, 0xe9, 0xac, 0x1b, 0x7e, 0x77, 0xc7, 0x39, 0x7e, 0x2c, 0x18, 0x11, 0x74, 0x3a, + 0x77, 0x35, 0x0e, 0x3c, 0x82, 0xc6, 0x8c, 0x0a, 0x32, 0x22, 0xc2, 0xbb, 0xb6, 0x6a, 0xca, 0x8c, + 0x97, 0x2b, 0x36, 0x2f, 0x0f, 0xdd, 0x02, 0x87, 0xef, 0xa0, 0x2e, 0x37, 0x3e, 0x11, 0xc4, 0xda, + 0xdd, 0x96, 0x93, 0xc3, 0x70, 0x04, 0xfb, 0xd3, 0x12, 0x63, 0xea, 0x8f, 0x31, 0xc6, 0x2d, 0x4b, + 0x75, 0xde, 0x01, 0x6e, 0xd6, 0x86, 0x00, 0xb5, 0x11, 0xf1, 0x6e, 0xa8, 0xdf, 0x7e, 0x86, 0x7b, + 0xd0, 0x3c, 0x0d, 0xb8, 0x60, 0xc1, 0x24, 0x15, 0xd4, 0x6f, 0x1b, 0xce, 0xbf, 0x06, 0xa0, 0xee, + 0x10, 0x4f, 0xe2, 0x88, 0x53, 0x7c, 0x03, 0xad, 0xe2, 0x82, 0x1f, 0xc9, 0x8c, 0xaa, 0x7e, 0x6b, + 0xb8, 0x6b, 0x51, 0xfc, 0x01, 0xaa, 0x49, 0xcc, 0x04, 0xb7, 0x2a, 0x4a, 0xf5, 0xd1, 0x43, 0xc6, + 0x67, 0xb4, 0x7a, 0x21, 0x82, 0x88, 0x94, 0x8f, 0x62, 0x26, 0xdc, 0x8c, 0x01, 0x2d, 0xd8, 0x25, + 0xbe, 0xcf, 0x28, 0x97, 0xbd, 0x21, 0xef, 0x5a, 0x6e, 0xd1, 0x86, 0x7a, 0x14, 0xfb, 0x54, 0xc9, + 0xa8, 0xaa, 0xa3, 0x7c, 0x6f, 0x1f, 0xc3, 0x8b, 0x32, 0x52, 0x44, 0xd8, 0x91, 0x23, 0xb4, 0x18, + 0x27, 0xb5, 0x96, 0x31, 0x79, 0x95, 0x2a, 0xa5, 0xea, 0xaa, 0xb5, 0xc3, 0x60, 0xbf, 0x64, 0x6c, + 0xa4, 0x18, 0x1a, 0x91, 0x49, 0x48, 0x7d, 0xc5, 0x50, 0x77, 0x97, 0x5b, 0x1c, 0x40, 0x2b, 0x89, + 0xc3, 0xc0, 0x9b, 0xe7, 0xf3, 0x92, 0x4d, 0xe2, 0x67, 0x7a, 0xe9, 0x43, 0x32, 0xa1, 0x61, 0xfe, + 0xad, 0xd6, 0x12, 0x9c, 0x3f, 0x4c, 0x68, 0xe4, 0x0d, 0x81, 0xef, 0xa1, 0x16, 0x4a, 0x38, 0xb7, + 0x0c, 0xe5, 0xe1, 0xeb, 0xd2, 0xbe, 0xc9, 0x28, 0xf9, 0x59, 0x24, 0xd8, 0xdc, 0x5d, 0x24, 0xe0, + 0xf7, 0xd0, 0xd4, 0xde, 0x18, 0xcb, 0x54, 0xf9, 0x6f, 0xca, 0xf3, 0x07, 0x05, 0x30, 0x23, 0xd1, + 0x53, 0xed, 0xf7, 0xd0, 0xd4, 0x2e, 0xc0, 0x36, 0x54, 0x6e, 0xe8, 0x7c, 0x61, 0x9e, 0x5c, 0xe2, + 0x0b, 0xa8, 0xde, 0x91, 0x30, 0x5d, 0xf6, 0x41, 0xb6, 0xf9, 0x60, 0x7e, 0x63, 0xd8, 0xc7, 0xd0, + 0x5e, 0xe7, 0x7e, 0x4a, 0xbe, 0xf3, 0xb7, 0x01, 0xcf, 0x57, 0xfc, 0xc2, 0x21, 0x34, 0x67, 0x52, + 0xf3, 0x50, 0xb7, 0xe5, 0xed, 0x83, 0xfe, 0x76, 0xcf, 0x0b, 0xf0, 0xa2, 0x34, 0x2d, 0x5d, 0xea, + 0x5b, 0x07, 0x3c, 0x49, 0xdf, 0xbd, 0x09, 0x58, 0xf2, 0xbe, 0x5d, 0x94, 0x89, 0xec, 0x6d, 0x9f, + 0xda, 0xed, 0x4a, 0xf1, 0x12, 0xf6, 0xa6, 0x2b, 0xbd, 0x9c, 0xa9, 0x69, 0xf5, 0xbb, 0xff, 0x43, + 0xbb, 0x3a, 0x01, 0xd4, 0x5d, 0xa7, 0xc1, 0xaf, 0x61, 0x37, 0x09, 0xc9, 0x9c, 0x32, 0xbe, 0x78, + 0xdd, 0x6d, 0x9d, 0x71, 0xa4, 0x8e, 0xf2, 0x76, 0x5d, 0x42, 0x3f, 0xda, 0xb9, 0x2f, 0x61, 0x6f, + 0x4d, 0x19, 0x36, 0xa0, 0xea, 0x9e, 0x0d, 0x4e, 0x7f, 0x69, 0x3f, 0xc3, 0xe7, 0xd0, 0x18, 0x0c, + 0x87, 0x3f, 0x9d, 0x0c, 0x7e, 0x3e, 0x3b, 0x6d, 0x1b, 0xce, 0x25, 0xb4, 0x56, 0x75, 0xa0, 0x03, + 0x9f, 0xcc, 0x82, 0x68, 0x70, 0x47, 0x82, 0x50, 0x8e, 0x9e, 0xba, 0x73, 0xc7, 0x5d, 0x89, 0x29, + 0x0c, 0xf9, 0xb5, 0xc0, 0x98, 0x0b, 0x8c, 0x16, 0xeb, 0xff, 0x66, 0xe8, 0x3f, 0x5d, 0xa9, 0x26, + 0xf0, 0x28, 0xde, 0x40, 0x7d, 0x11, 0xa4, 0xf8, 0xf9, 0xd6, 0xff, 0x85, 0xfd, 0x6a, 0xfb, 0xab, + 0xe6, 0x74, 0x7e, 0xff, 0xe7, 0xfe, 0x2f, 0xd3, 0x76, 0x5e, 0xf6, 0xa4, 0xef, 0x5c, 0x95, 0x5b, + 0x64, 0x7c, 0x30, 0xde, 0x4e, 0x6a, 0xea, 0xf7, 0x7f, 0xf4, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x44, 0x23, 0x5c, 0x13, 0x4d, 0x08, 0x00, 0x00, } diff --git a/pkg/allocation/go/allocation.swagger.json b/pkg/allocation/go/allocation.swagger.json index 806b8ba73a..dc2e2d88ff 100644 --- a/pkg/allocation/go/allocation.swagger.json +++ b/pkg/allocation/go/allocation.swagger.json @@ -84,14 +84,14 @@ }, "requiredGameServerSelector": { "$ref": "#/definitions/allocationGameServerSelector", - "description": "The required allocation. Defaults to all GameServers." + "description": "Deprecated: Please use gameServerSelectors instead. This field is ignored if the\ngameServerSelectors field is set\nThe required allocation. Defaults to all GameServers." }, "preferredGameServerSelectors": { "type": "array", "items": { "$ref": "#/definitions/allocationGameServerSelector" }, - "description": "The ordered list of preferred allocations out of the `required` set.\nIf the first selector is not matched, the selection attempts the second selector, and so on." + "description": "Deprecated: Please use gameServerSelectors instead. This field is ignored if the\ngameServerSelectors field is set\nThe ordered list of preferred allocations out of the `required` set.\nIf the first selector is not matched, the selection attempts the second selector, and so on." }, "scheduling": { "$ref": "#/definitions/AllocationRequestSchedulingStrategy", @@ -104,6 +104,13 @@ "metadata": { "$ref": "#/definitions/allocationMetaPatch", "title": "Metadata is optional custom metadata that is added to the game server at\nallocation. You can use this to tell the server necessary session data" + }, + "gameServerSelectors": { + "type": "array", + "items": { + "$ref": "#/definitions/allocationGameServerSelector" + }, + "description": "Ordered list of GameServer label selectors.\nIf the first selector is not matched, the selection attempts the second selector, and so on.\nThis is useful for things like smoke testing of new game servers.\nNote: This field can only be set if neither Required or Preferred is set." } } }, diff --git a/pkg/apis/allocation/v1/gameserverallocation.go b/pkg/apis/allocation/v1/gameserverallocation.go index f4b754ee47..aa3eb55e03 100644 --- a/pkg/apis/allocation/v1/gameserverallocation.go +++ b/pkg/apis/allocation/v1/gameserverallocation.go @@ -42,7 +42,7 @@ type GameServerAllocationState string // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // GameServerAllocation is the data structure for allocating against a set of -// GameServers, defined `required` and `preferred` selectors +// GameServers, defined `selectors` selectors type GameServerAllocation struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` @@ -66,10 +66,12 @@ type GameServerAllocationSpec struct { // Otherwise, allocation will happen locally. MultiClusterSetting MultiClusterSetting `json:"multiClusterSetting,omitempty"` + // Deprecated: use field Selectors instead. If Selectors is set, this field is ignored. // Required is the GameServer selector from which to choose GameServers from. // Defaults to all GameServers. Required GameServerSelector `json:"required,omitempty"` + // Deprecated: use field Selectors instead. If Selectors is set, this field is ignored. // Preferred is an ordered list of preferred GameServer selectors // that are optional to be fulfilled, but will be searched before the `required` selector. // If the first selector is not matched, the selection attempts the second selector, and so on. @@ -77,6 +79,12 @@ type GameServerAllocationSpec struct { // This is useful for things like smoke testing of new game servers. Preferred []GameServerSelector `json:"preferred,omitempty"` + // Ordered list of GameServer label selectors. + // If the first selector is not matched, the selection attempts the second selector, and so on. + // This is useful for things like smoke testing of new game servers. + // Note: This field can only be set if neither Required or Preferred is set. + Selectors []GameServerSelector `json:"selectors,omitempty"` + // Scheduling strategy. Defaults to "Packed". Scheduling apis.SchedulingStrategy `json:"scheduling"` @@ -246,10 +254,16 @@ func (gsa *GameServerAllocation) ApplyDefaults() { gsa.Spec.Scheduling = apis.Packed } - gsa.Spec.Required.ApplyDefaults() + if len(gsa.Spec.Selectors) == 0 { + gsa.Spec.Required.ApplyDefaults() - for i := range gsa.Spec.Preferred { - gsa.Spec.Preferred[i].ApplyDefaults() + for i := range gsa.Spec.Preferred { + gsa.Spec.Preferred[i].ApplyDefaults() + } + } else { + for i := range gsa.Spec.Selectors { + gsa.Spec.Selectors[i].ApplyDefaults() + } } } @@ -278,6 +292,21 @@ func (gsa *GameServerAllocation) Validate() ([]metav1.StatusCause, bool) { causes = append(causes, c...) } } + for i := range gsa.Spec.Selectors { + if c, ok := gsa.Spec.Selectors[i].Validate(fmt.Sprintf("spec.selectors[%d]", i)); !ok { + causes = append(causes, c...) + } + } return causes, len(causes) == 0 } + +// Converter converts game server allocation required and preferred fields to selectors field. +func (gsa *GameServerAllocation) Converter() { + if len(gsa.Spec.Selectors) == 0 { + var selectors []GameServerSelector + selectors = append(selectors, gsa.Spec.Preferred...) + selectors = append(selectors, gsa.Spec.Required) + gsa.Spec.Selectors = selectors + } +} diff --git a/pkg/apis/allocation/v1/gameserverallocation_test.go b/pkg/apis/allocation/v1/gameserverallocation_test.go index 007b5347e1..143d7a11e0 100644 --- a/pkg/apis/allocation/v1/gameserverallocation_test.go +++ b/pkg/apis/allocation/v1/gameserverallocation_test.go @@ -50,6 +50,7 @@ func TestGameServerAllocationApplyDefaults(t *testing.T) { assert.Equal(t, int64(0), gsa.Spec.Required.Players.MinAvailable) } +//nolint // Current lint duplicate threshold will consider this function is a duplication of the function TestGameServerAllocationSpecSelectors func TestGameServerAllocationSpecPreferredSelectors(t *testing.T) { t.Parallel() @@ -77,6 +78,34 @@ func TestGameServerAllocationSpecPreferredSelectors(t *testing.T) { assert.True(t, gsas.Preferred[1].Matches(gs)) } +//nolint // Current lint duplicate threshold will consider this function is a duplication of the function TestGameServerAllocationSpecPreferredSelectors +func TestGameServerAllocationSpecSelectors(t *testing.T) { + t.Parallel() + + gsas := &GameServerAllocationSpec{ + Selectors: []GameServerSelector{ + {LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"check": "blue"}}}, + {LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"check": "red"}}}, + }, + } + + require.Len(t, gsas.Selectors, 2) + + gs := &agonesv1.GameServer{ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{}}} + + for _, s := range gsas.Selectors { + assert.False(t, s.Matches(gs)) + } + + gs.ObjectMeta.Labels["check"] = "blue" + assert.True(t, gsas.Selectors[0].Matches(gs)) + assert.False(t, gsas.Selectors[1].Matches(gs)) + + gs.ObjectMeta.Labels["check"] = "red" + assert.False(t, gsas.Selectors[0].Matches(gs)) + assert.True(t, gsas.Selectors[1].Matches(gs)) +} + func TestGameServerSelectorApplyDefaults(t *testing.T) { t.Parallel() runtime.FeatureTestMutex.Lock() @@ -435,3 +464,48 @@ func TestGameServerAllocationValidate(t *testing.T) { assert.Equal(t, "spec.preferred[0]", causes[1].Field) assert.Equal(t, "spec.preferred[0]", causes[2].Field) } + +func TestGameServerAllocationConverter(t *testing.T) { + t.Parallel() + + gsa := &GameServerAllocation{ + Spec: GameServerAllocationSpec{ + Scheduling: "Packed", + Required: GameServerSelector{ + Players: &PlayerSelector{ + MinAvailable: 5, + MaxAvailable: 10, + }, + }, + Preferred: []GameServerSelector{ + {Players: &PlayerSelector{MinAvailable: 10, + MaxAvailable: 20}}, + }, + }, + } + gsaExpected := &GameServerAllocation{ + Spec: GameServerAllocationSpec{ + Scheduling: "Packed", + Required: GameServerSelector{ + Players: &PlayerSelector{ + MinAvailable: 5, + MaxAvailable: 10, + }, + }, + Preferred: []GameServerSelector{ + {Players: &PlayerSelector{MinAvailable: 10, + MaxAvailable: 20}}, + }, + Selectors: []GameServerSelector{ + {Players: &PlayerSelector{MinAvailable: 10, + MaxAvailable: 20}}, + {Players: &PlayerSelector{ + MinAvailable: 5, + MaxAvailable: 10}}, + }, + }, + } + + gsa.Converter() + assert.Equal(t, gsaExpected, gsa) +} diff --git a/pkg/apis/allocation/v1/zz_generated.deepcopy.go b/pkg/apis/allocation/v1/zz_generated.deepcopy.go index a6393f7f66..037f3261ae 100644 --- a/pkg/apis/allocation/v1/zz_generated.deepcopy.go +++ b/pkg/apis/allocation/v1/zz_generated.deepcopy.go @@ -98,6 +98,13 @@ func (in *GameServerAllocationSpec) DeepCopyInto(out *GameServerAllocationSpec) (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Selectors != nil { + in, out := &in.Selectors, &out.Selectors + *out = make([]GameServerSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } in.MetaPatch.DeepCopyInto(&out.MetaPatch) return } diff --git a/pkg/gameserverallocations/allocator.go b/pkg/gameserverallocations/allocator.go index 20c762027f..eae9142a55 100644 --- a/pkg/gameserverallocations/allocator.go +++ b/pkg/gameserverallocations/allocator.go @@ -217,6 +217,9 @@ func (c *Allocator) Allocate(ctx context.Context, gsa *allocationv1.GameServerAl return s, nil } + // Convert gsa required and preferred fields to selectors field + gsa.Converter() + // If multi-cluster setting is enabled, allocate base on the multicluster allocation policy. if gsa.Spec.MultiClusterSetting.Enabled { out, err = c.applyMultiClusterAllocation(ctx, gsa) diff --git a/pkg/gameserverallocations/controller_test.go b/pkg/gameserverallocations/controller_test.go index c3b2e1a163..14f58f44e7 100644 --- a/pkg/gameserverallocations/controller_test.go +++ b/pkg/gameserverallocations/controller_test.go @@ -67,9 +67,13 @@ func TestControllerAllocator(t *testing.T) { require.NoError(t, runtime.ParseFeatures(string(runtime.FeatureStateAllocationFilter)+"=false")) t.Run("successful allocation", func(t *testing.T) { - f, gsList := defaultFixtures(3) + f, gsList := defaultFixtures(4) - gsa := &allocationv1.GameServerAllocation{ + gsaSelectors := &allocationv1.GameServerAllocation{ + Spec: allocationv1.GameServerAllocationSpec{ + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}}}}, + }} + gsaRequired := &allocationv1.GameServerAllocation{ Spec: allocationv1.GameServerAllocationSpec{ Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}}}, }} @@ -114,14 +118,22 @@ func TestControllerAllocator(t *testing.T) { err = json.Unmarshal(rec.Body.Bytes(), ret) assert.NoError(t, err) - assert.Equal(t, gsa.Spec.Required.LabelSelector, ret.Spec.Required.LabelSelector) + if len(gsa.Spec.Selectors) != 0 { + assert.Equal(t, gsa.Spec.Selectors[0].LabelSelector, ret.Spec.Selectors[0].LabelSelector) + } else { + // nolint:staticcheck + assert.Equal(t, gsa.Spec.Required.LabelSelector, ret.Spec.Selectors[0].LabelSelector) + } + assert.True(t, expectedState == ret.Status.State, "Failed: %s vs %s", expectedState, ret.Status.State) } - test(gsa.DeepCopy(), allocationv1.GameServerAllocationAllocated) - test(gsa.DeepCopy(), allocationv1.GameServerAllocationAllocated) - test(gsa.DeepCopy(), allocationv1.GameServerAllocationAllocated) - test(gsa.DeepCopy(), allocationv1.GameServerAllocationUnAllocated) + test(gsaSelectors.DeepCopy(), allocationv1.GameServerAllocationAllocated) + test(gsaRequired.DeepCopy(), allocationv1.GameServerAllocationAllocated) + test(gsaSelectors.DeepCopy(), allocationv1.GameServerAllocationAllocated) + test(gsaRequired.DeepCopy(), allocationv1.GameServerAllocationAllocated) + test(gsaSelectors.DeepCopy(), allocationv1.GameServerAllocationUnAllocated) + test(gsaRequired.DeepCopy(), allocationv1.GameServerAllocationUnAllocated) }) t.Run("method not allowed", func(t *testing.T) { @@ -211,7 +223,7 @@ func TestControllerAllocate(t *testing.T) { gsa := allocationv1.GameServerAllocation{ObjectMeta: metav1.ObjectMeta{Name: "gsa-1", Namespace: defaultNs}, Spec: allocationv1.GameServerAllocationSpec{ - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}}}}, MetaPatch: fam, }} gsa.ApplyDefaults() @@ -297,7 +309,7 @@ func TestControllerAllocatePriority(t *testing.T) { gsa := &allocationv1.GameServerAllocation{ObjectMeta: metav1.ObjectMeta{Name: "fa-1", Namespace: defaultNs}, Spec: allocationv1.GameServerAllocationSpec{ - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}}}}, }} gsa.ApplyDefaults() _, ok := gsa.Validate() @@ -400,7 +412,7 @@ func TestControllerRunLocalAllocations(t *testing.T) { Namespace: defaultNs, }, Spec: allocationv1.GameServerAllocationSpec{ - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}}}}, }} gsa.ApplyDefaults() _, ok := gsa.Validate() @@ -457,7 +469,7 @@ func TestControllerRunLocalAllocations(t *testing.T) { Namespace: defaultNs, }, Spec: allocationv1.GameServerAllocationSpec{ - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: "thereisnofleet"}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: "thereisnofleet"}}}}, }} gsa.ApplyDefaults() _, ok := gsa.Validate() @@ -677,13 +689,13 @@ func TestMultiClusterAllocationFromLocal(t *testing.T) { }, }, }, - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}}, }, } ret, err := executeAllocation(gsa, c) assert.NoError(t, err) - assert.Equal(t, gsa.Spec.Required.LabelSelector, ret.Spec.Required.LabelSelector) + assert.Equal(t, gsa.Spec.Selectors[0].LabelSelector, ret.Spec.Selectors[0].LabelSelector) assert.Equal(t, gsa.Namespace, ret.Namespace) expectedState := allocationv1.GameServerAllocationAllocated assert.True(t, expectedState == ret.Status.State, "Failed: %s vs %s", expectedState, ret.Status.State) @@ -726,7 +738,7 @@ func TestMultiClusterAllocationFromLocal(t *testing.T) { }, }, }, - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}}, }, } @@ -787,13 +799,13 @@ func TestMultiClusterAllocationFromLocal(t *testing.T) { }, }, }, - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: "empty-fleet"}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: "empty-fleet"}}}}, }, } ret, err := executeAllocation(gsa, c) assert.NoError(t, err) - assert.Equal(t, gsa.Spec.Required.LabelSelector, ret.Spec.Required.LabelSelector) + assert.Equal(t, gsa.Spec.Selectors[0].LabelSelector, ret.Spec.Selectors[0].LabelSelector) assert.Equal(t, gsa.Namespace, ret.Namespace) expectedState := allocationv1.GameServerAllocationUnAllocated assert.True(t, expectedState == ret.Status.State, "Failed: %s vs %s", expectedState, ret.Status.State) @@ -860,7 +872,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) { MultiClusterSetting: allocationv1.MultiClusterSetting{ Enabled: true, }, - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}}, }, } @@ -964,7 +976,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) { MultiClusterSetting: allocationv1.MultiClusterSetting{ Enabled: true, }, - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}}, }, } @@ -1043,7 +1055,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) { MultiClusterSetting: allocationv1.MultiClusterSetting{ Enabled: true, }, - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}}, }, } @@ -1111,7 +1123,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) { MultiClusterSetting: allocationv1.MultiClusterSetting{ Enabled: true, }, - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}}, }, } @@ -1185,7 +1197,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) { MultiClusterSetting: allocationv1.MultiClusterSetting{ Enabled: true, }, - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}}}, }, } diff --git a/pkg/gameserverallocations/find.go b/pkg/gameserverallocations/find.go index ed76a65a7e..d0c68aeb05 100644 --- a/pkg/gameserverallocations/find.go +++ b/pkg/gameserverallocations/find.go @@ -35,8 +35,7 @@ func findGameServerForAllocation(gsa *allocationv1.GameServerAllocation, list [] index int } - var required *result - preferred := make([]*result, len(gsa.Spec.Preferred)) + selectors := make([]*result, len(gsa.Spec.Selectors)) var loop func(list []*agonesv1.GameServer, f func(i int, gs *agonesv1.GameServer)) @@ -75,28 +74,18 @@ func findGameServerForAllocation(gsa *allocationv1.GameServerAllocation, list [] return } - // first look at preferred - for j, sel := range gsa.Spec.Preferred { - if preferred[j] == nil && sel.Matches(gs) { - preferred[j] = &result{gs: gs, index: i} + for j, sel := range gsa.Spec.Selectors { + if selectors[j] == nil && sel.Matches(gs) { + selectors[j] = &result{gs: gs, index: i} } } - - // then look at required - if required == nil && gsa.Spec.Required.Matches(gs) { - required = &result{gs: gs, index: i} - } }) - for _, r := range preferred { + for _, r := range selectors { if r != nil { return r.gs, r.index, nil } } - if required == nil { - return nil, 0, ErrNoGameServer - } - - return required.gs, required.index, nil + return nil, 0, ErrNoGameServer } diff --git a/pkg/gameserverallocations/find_test.go b/pkg/gameserverallocations/find_test.go index ab824f9db5..c3e83ccf75 100644 --- a/pkg/gameserverallocations/find_test.go +++ b/pkg/gameserverallocations/find_test.go @@ -33,41 +33,41 @@ import ( func TestFindGameServerForAllocationPacked(t *testing.T) { t.Parallel() - labels := map[string]string{"role": "gameserver"} - prefLabels := map[string]string{"role": "gameserver", "preferred": "true"} + oneLabel := map[string]string{"role": "gameserver"} + twoLabels := map[string]string{"role": "gameserver", "preferred": "true"} gsa := &allocationv1.GameServerAllocation{ ObjectMeta: metav1.ObjectMeta{Namespace: defaultNs}, Spec: allocationv1.GameServerAllocationSpec{ - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{ - MatchLabels: labels, - }}, + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{ + MatchLabels: oneLabel, + }}}, Scheduling: apis.Packed, }, } n := metav1.Now() - prefGsa := gsa.DeepCopy() - prefGsa.Spec.Preferred = append(prefGsa.Spec.Preferred, - allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{ + twoLabelsGsa := gsa.DeepCopy() + twoLabelsGsa.Spec.Selectors = append( + []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{ MatchLabels: map[string]string{"preferred": "true"}, - }}) + }}}, twoLabelsGsa.Spec.Selectors...) fixtures := map[string]struct { list []agonesv1.GameServer test func(*testing.T, []*agonesv1.GameServer) features string }{ - "required": { + "one label": { // nolint: dupl list: []agonesv1.GameServer{ - {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: defaultNs, Labels: labels, DeletionTimestamp: &n}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs5", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateError}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: "does-not-apply", Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: defaultNs, Labels: oneLabel, DeletionTimestamp: &n}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs5", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateError}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: "does-not-apply", Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, }, test: func(t *testing.T, list []*agonesv1.GameServer) { assert.Len(t, list, 3) @@ -105,20 +105,20 @@ func TestFindGameServerForAllocationPacked(t *testing.T) { }, features: fmt.Sprintf("%s=false&%s=false", runtime.FeaturePlayerAllocationFilter, runtime.FeatureStateAllocationFilter), }, - "required with player state (StateAllocationFilter)": { + "one label with player state (StateAllocationFilter)": { // nolint: dupl list: []agonesv1.GameServer{ - {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: defaultNs, Labels: labels, DeletionTimestamp: &n}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs5", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateError}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: "does-not-apply", Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: defaultNs, Labels: oneLabel, DeletionTimestamp: &n}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs5", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateError}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: "does-not-apply", Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, }, test: func(t *testing.T, list []*agonesv1.GameServer) { require.Len(t, list, 5) - require.Equal(t, agonesv1.GameServerStateReady, *gsa.Spec.Required.GameServerState) + require.Equal(t, agonesv1.GameServerStateReady, *gsa.Spec.Selectors[0].GameServerState) gs, index, err := findGameServerForAllocation(gsa, list) assert.NoError(t, err) @@ -144,7 +144,7 @@ func TestFindGameServerForAllocationPacked(t *testing.T) { // now try an allocated state gsa := gsa.DeepCopy() allocated := agonesv1.GameServerStateAllocated - gsa.Spec.Required.GameServerState = &allocated + gsa.Spec.Selectors[0].GameServerState = &allocated gs, index, err = findGameServerForAllocation(gsa, list) assert.NoError(t, err) @@ -164,54 +164,14 @@ func TestFindGameServerForAllocationPacked(t *testing.T) { }, features: fmt.Sprintf("%s=true&%s=true", runtime.FeaturePlayerAllocationFilter, runtime.FeatureStateAllocationFilter), }, - "preferred allocated over required (StateAllocationFilter)": { - list: []agonesv1.GameServer{ - {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, - }, - test: func(t *testing.T, list []*agonesv1.GameServer) { - require.Len(t, list, 3) - - allocated := agonesv1.GameServerStateAllocated - gsa := &allocationv1.GameServerAllocation{ - ObjectMeta: metav1.ObjectMeta{Namespace: defaultNs}, - Spec: allocationv1.GameServerAllocationSpec{ - Preferred: []allocationv1.GameServerSelector{ - { - LabelSelector: metav1.LabelSelector{MatchLabels: labels}, - GameServerState: &allocated, - }, - }, - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{ - MatchLabels: labels, - }}, - }, - } - gsa.ApplyDefaults() - _, ok := gsa.Validate() - require.True(t, ok) - assert.Equal(t, agonesv1.GameServerStateReady, *gsa.Spec.Required.GameServerState) - assert.Equal(t, allocated, *gsa.Spec.Preferred[0].GameServerState) - - gs, index, err := findGameServerForAllocation(gsa, list) - assert.NoError(t, err) - require.NotNil(t, gs) - assert.Equal(t, "node1", gs.Status.NodeName) - assert.Equal(t, "gs3", gs.ObjectMeta.Name) - assert.Equal(t, gs, list[index]) - assert.Equal(t, agonesv1.GameServerStateAllocated, gs.Status.State) - }, - features: fmt.Sprintf("%s=true&%s=true", runtime.FeaturePlayerAllocationFilter, runtime.FeatureStateAllocationFilter), - }, - "required with player counts and state (PlayerAllocationFilter)": { + "one label with player counts and state (PlayerAllocationFilter)": { list: []agonesv1.GameServer{ - {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, Labels: labels}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated, Players: &agonesv1.PlayerStatus{Count: 10, Capacity: 15}}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, Labels: labels}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated, Players: &agonesv1.PlayerStatus{ Count: 3, Capacity: 15, @@ -220,8 +180,8 @@ func TestFindGameServerForAllocationPacked(t *testing.T) { test: func(t *testing.T, list []*agonesv1.GameServer) { gsa := gsa.DeepCopy() allocated := agonesv1.GameServerStateAllocated - gsa.Spec.Required.GameServerState = &allocated - gsa.Spec.Required.Players = &allocationv1.PlayerSelector{ + gsa.Spec.Selectors[0].GameServerState = &allocated + gsa.Spec.Selectors[0].Players = &allocationv1.PlayerSelector{ MinAvailable: 1, MaxAvailable: 10, } @@ -239,17 +199,17 @@ func TestFindGameServerForAllocationPacked(t *testing.T) { }, "preferred": { list: []agonesv1.GameServer{ - {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, Labels: prefLabels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, Labels: prefLabels}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs5", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: defaultNs, Labels: labels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Namespace: defaultNs, Labels: twoLabels}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Namespace: defaultNs, Labels: twoLabels}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs5", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Namespace: defaultNs, Labels: oneLabel}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateReady}}, }, test: func(t *testing.T, list []*agonesv1.GameServer) { assert.Len(t, list, 6) - gs, index, err := findGameServerForAllocation(prefGsa, list) + gs, index, err := findGameServerForAllocation(twoLabelsGsa, list) assert.NoError(t, err) assert.Equal(t, "node1", gs.Status.NodeName) assert.Equal(t, "gs1", gs.ObjectMeta.Name) @@ -257,7 +217,7 @@ func TestFindGameServerForAllocationPacked(t *testing.T) { assert.Equal(t, agonesv1.GameServerStateReady, gs.Status.State) list = append(list[:index], list[index+1:]...) - gs, index, err = findGameServerForAllocation(prefGsa, list) + gs, index, err = findGameServerForAllocation(twoLabelsGsa, list) assert.NoError(t, err) assert.Equal(t, "node2", gs.Status.NodeName) assert.Equal(t, "gs4", gs.ObjectMeta.Name) @@ -265,7 +225,7 @@ func TestFindGameServerForAllocationPacked(t *testing.T) { assert.Equal(t, agonesv1.GameServerStateReady, gs.Status.State) list = append(list[:index], list[index+1:]...) - gs, index, err = findGameServerForAllocation(prefGsa, list) + gs, index, err = findGameServerForAllocation(twoLabelsGsa, list) assert.NoError(t, err) assert.Equal(t, "node1", gs.Status.NodeName) assert.Contains(t, []string{"gs3", "gs5", "gs6"}, gs.ObjectMeta.Name) @@ -276,14 +236,14 @@ func TestFindGameServerForAllocationPacked(t *testing.T) { }, "allocation trap": { list: []agonesv1.GameServer{ - {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Labels: labels, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Labels: labels, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Labels: labels, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Labels: labels, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs5", Labels: labels, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Labels: labels, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs7", Labels: labels, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, - {ObjectMeta: metav1.ObjectMeta{Name: "gs8", Labels: labels, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs1", Labels: oneLabel, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs2", Labels: oneLabel, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs3", Labels: oneLabel, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs4", Labels: oneLabel, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node1", State: agonesv1.GameServerStateAllocated}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs5", Labels: oneLabel, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs6", Labels: oneLabel, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs7", Labels: oneLabel, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, + {ObjectMeta: metav1.ObjectMeta{Name: "gs8", Labels: oneLabel, Namespace: defaultNs}, Status: agonesv1.GameServerStatus{NodeName: "node2", State: agonesv1.GameServerStateReady}}, }, test: func(t *testing.T, list []*agonesv1.GameServer) { assert.Len(t, list, 4) @@ -309,8 +269,8 @@ func TestFindGameServerForAllocationPacked(t *testing.T) { _, ok := gsa.Validate() require.True(t, ok) - prefGsa.ApplyDefaults() - _, ok = prefGsa.Validate() + twoLabelsGsa.ApplyDefaults() + _, ok = twoLabelsGsa.Validate() require.True(t, ok) controller, m := newFakeController() @@ -346,9 +306,9 @@ func TestFindGameServerForAllocationDistributed(t *testing.T) { gsa := &allocationv1.GameServerAllocation{ ObjectMeta: metav1.ObjectMeta{Namespace: defaultNs}, Spec: allocationv1.GameServerAllocationSpec{ - Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{ + Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{ MatchLabels: labels, - }}, + }}}, Scheduling: apis.Distributed, }, } diff --git a/proto/allocation/allocation.proto b/proto/allocation/allocation.proto index 963936ee72..9f4eff4c06 100644 --- a/proto/allocation/allocation.proto +++ b/proto/allocation/allocation.proto @@ -34,12 +34,16 @@ message AllocationRequest { // If specified, multi-cluster policies are applied. Otherwise, allocation will happen locally. MultiClusterSetting multiClusterSetting = 2; + // Deprecated: Please use gameServerSelectors instead. This field is ignored if the + // gameServerSelectors field is set // The required allocation. Defaults to all GameServers. - GameServerSelector requiredGameServerSelector = 3; + GameServerSelector requiredGameServerSelector = 3 [deprecated = true]; + // Deprecated: Please use gameServerSelectors instead. This field is ignored if the + // gameServerSelectors field is set // The ordered list of preferred allocations out of the `required` set. // If the first selector is not matched, the selection attempts the second selector, and so on. - repeated GameServerSelector preferredGameServerSelectors = 4; + repeated GameServerSelector preferredGameServerSelectors = 4 [deprecated = true]; // Scheduling strategy. Defaults to "Packed". SchedulingStrategy scheduling = 5; @@ -55,6 +59,12 @@ message AllocationRequest { // Metadata is optional custom metadata that is added to the game server at // allocation. You can use this to tell the server necessary session data MetaPatch metadata = 7; + + // Ordered list of GameServer label selectors. + // If the first selector is not matched, the selection attempts the second selector, and so on. + // This is useful for things like smoke testing of new game servers. + // Note: This field can only be set if neither Required or Preferred is set. + repeated GameServerSelector gameServerSelectors = 8; } message AllocationResponse { diff --git a/site/content/en/docs/Guides/fleet-updates.md b/site/content/en/docs/Guides/fleet-updates.md index 25f998228d..00aecc15e6 100644 --- a/site/content/en/docs/Guides/fleet-updates.md +++ b/site/content/en/docs/Guides/fleet-updates.md @@ -93,6 +93,7 @@ In a scenario where a new `v2` version of a `Fleet` is being slowly scaled up in Fleet, we can specify that we `prefer` allocation to occur from the `v2` Fleet, and if none are available, fallback to the `v1` Fleet, like so: +{{% feature expiryVersion="1.17.0" %}} ```yaml apiVersion: "allocation.agones.dev/v1" kind: GameServerAllocation @@ -104,10 +105,46 @@ spec: - matchLabels: agones.dev/fleet: v2 ``` +{{% /feature %}} +{{% feature publishVersion="1.17.0" %}} +{{< tabpane >}} + {{< tab header="selectors" lang="yaml" >}} +apiVersion: "allocation.agones.dev/v1" +kind: GameServerAllocation +spec: + selectors: + - matchLabels: + agones.dev/fleet: v2 + - matchLabels: + game: my-awesome-game + {{< /tab >}} + {{< tab header="required & preferred (deprecated)" lang="yaml" >}} +apiVersion: "allocation.agones.dev/v1" +kind: GameServerAllocation +spec: + # Deprecated, use field selectors instead. + required: + matchLabels: + game: my-awesome-game + # Deprecated, use field selectors instead. + preferred: + - matchLabels: + agones.dev/fleet: v2 + {{< /tab >}} +{{< /tabpane >}} +{{% /feature %}} + +{{% feature expiryVersion="1.17.0" %}} In this example, all `GameServers` have the label `game: my-awesome-game`, so the Allocation will search across both Fleets through that mechanism. The `preferred` label matching selector tells the allocation system to first search all `GameServers` with the `v2` `Fleet` label, and if not found, search through the rest of the set. +{{% /feature %}} +{{% feature publishVersion="1.17.0" %}} +In this example, all `GameServers` have the label `game: my-awesome-game`, so the Allocation will search across both +Fleets through that mechanism. The `selectors` label matching selector tells the allocation system to first search +all `GameServers` with the `v2` `Fleet` label, and if not found, search through the rest of the set. +{{% /feature %}} The above `GameServerAllocation` can then be used while you scale up the `v2` Fleet and scale down the original Fleet at the rate that you deem fit for your specific rollout. diff --git a/site/content/en/docs/Reference/agones_crd_api_reference.html b/site/content/en/docs/Reference/agones_crd_api_reference.html index b253a73e4a..6a6ef28648 100644 --- a/site/content/en/docs/Reference/agones_crd_api_reference.html +++ b/site/content/en/docs/Reference/agones_crd_api_reference.html @@ -1474,7 +1474,7 @@
GameServerAllocation is the data structure for allocating against a set of
-GameServers, defined required
and preferred
selectors
selectors
selectors
-required
-
-
-GameServerSelector
-
-
- |
-
- Required The required allocation. Defaults to all GameServers. - |
-||||||||||
-preferred
+selectors
[]GameServerSelector
@@ -1565,7 +1552,7 @@ GameServerAllocation |
- Preferred ordered list of preferred allocations out of the An ordered list of allocations set. If the first selector is not matched, the selection attempts the second selector, and so on. |
@@ -1645,20 +1632,7 @@ ||||||||||
-required
-
-
-GameServerSelector
-
-
- |
-
- Required The required allocation. Defaults to all GameServers. - |
-||||||||||
-preferred
+selectors
[]GameServerSelector
@@ -1666,7 +1640,7 @@ GameServerAllocationS |
- Preferred ordered list of preferred allocations out of the An ordered list of allocations set. If the first selector is not matched, the selection attempts the second selector, and so on. |
@@ -5341,7 +5315,7 @@
- Required is the GameServer selector from which to choose GameServers from. + Deprecated: use field Selectors instead. If Selectors is set, this field is ignored. +Required is the GameServer selector from which to choose GameServers from. Defaults to all GameServers. |
@@ -5433,7 +5408,8 @@
- Preferred is an ordered list of preferred GameServer selectors + Deprecated: use field Selectors instead. If Selectors is set, this field is ignored.
+Preferred is an ordered list of preferred GameServer selectors
that are optional to be fulfilled, but will be searched before the GameServerAllocation
+ |
+selectors
+
+
+[]GameServerSelector
+
+
+
+ |
+Ordered list of GameServer label selectors. +If the first selector is not matched, the selection attempts the second selector, and so on. +This is useful for things like smoke testing of new game servers. +Note: This field can only be set if neither Required or Preferred is set. + |
- Preferred is an ordered list of preferred GameServer selectors + Deprecated: use field Selectors instead. If Selectors is set, this field is ignored.
+Preferred is an ordered list of preferred GameServer selectors
that are optional to be fulfilled, but will be searched before the GameServerAllocationS
+ |
+selectors
+
+
+[]GameServerSelector
+
+
+
+ |
+Ordered list of GameServer label selectors. +If the first selector is not matched, the selection attempts the second selector, and so on. +This is useful for things like smoke testing of new game servers. +Note: This field can only be set if neither Required or Preferred is set. + |
scheduling
agones.dev/agones/pkg/apis.SchedulingStrategy
@@ -5523,7 +5515,8 @@ Required is the GameServer selector from which to choose GameServers from. +
Deprecated: use field Selectors instead. If Selectors is set, this field is ignored. +Required is the GameServer selector from which to choose GameServers from. Defaults to all GameServers.
scheduling
agones.dev/agones/pkg/apis.SchedulingStrategy
diff --git a/site/content/en/docs/Reference/gameserverallocation.md b/site/content/en/docs/Reference/gameserverallocation.md
index 3daa837460..fe71bdb927 100644
--- a/site/content/en/docs/Reference/gameserverallocation.md
+++ b/site/content/en/docs/Reference/gameserverallocation.md
@@ -81,7 +81,8 @@ The `spec` field is the actual `GameServerAllocation` specification, and it is c
{{% feature publishVersion="1.17.0" %}}
-```yaml
+{{< tabpane >}}
+ {{< tab header="selectors" lang="yaml" >}}
apiVersion: "allocation.agones.dev/v1"
kind: GameServerAllocation
spec:
@@ -89,6 +90,61 @@ spec:
# Defaults to all GameServers.
# matchLabels, matchExpressions, gameServerState and player filters can be used for filtering.
# See: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more details on label selectors.
+ # An ordered list of GameServer label selectors.
+ # If the first selector is not matched, the selection attempts the second selector, and so on.
+ # This is useful for things like smoke testing of new game servers.
+ selectors:
+ - matchLabels:
+ agones.dev/fleet: green-fleet
+ # [Stage:Alpha]
+ # [FeatureFlag:PlayerAllocationFilter]
+ players:
+ minAvailable: 0
+ maxAvailable: 99
+ - matchLabels:
+ agones.dev/fleet: blue-fleet
+ - matchLabels:
+ game: my-game
+ matchExpressions:
+ - {key: tier, operator: In, values: [cache]}
+ # [Stage:Alpha]
+ # [FeatureFlag:StateAllocationFilter]
+ # Specifies which State is the filter to be used when attempting to retrieve a GameServer
+ # via Allocation. Defaults to "Ready". The only other option is "Allocated", which can be used in conjunction with
+ # label/annotation/player selectors to retrieve an already Allocated GameServer.
+ gameServerState: Ready
+ # [Stage:Alpha]
+ # [FeatureFlag:PlayerAllocationFilter]
+ # Provides a filter on minimum and maximum values for player capacity when retrieving a GameServer
+ # through Allocation. Defaults to no limits.
+ players:
+ minAvailable: 0
+ maxAvailable: 99
+ # defines how GameServers are organised across the cluster.
+ # Options include:
+ # "Packed" (default) is aimed at dynamic Kubernetes clusters, such as cloud providers, wherein we want to bin pack
+ # resources
+ # "Distributed" is aimed at static Kubernetes clusters, wherein we want to distribute resources across the entire
+ # cluster
+ scheduling: Packed
+ # Optional custom metadata that is added to the game server at allocation
+ # You can use this to tell the server necessary session data
+ metadata:
+ labels:
+ mode: deathmatch
+ annotations:
+ map: garden22
+ {{< /tab >}}
+ {{< tab header="required & preferred (deprecated)" lang="yaml" >}}
+apiVersion: "allocation.agones.dev/v1"
+kind: GameServerAllocation
+spec:
+ # Deprecated, use field selectors instead.
+ # GameServer selector from which to choose GameServers from.
+ # Defaults to all GameServers.
+ # matchLabels, matchExpressions, gameServerState and player filters can be used for filtering.
+ # See: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ for more details on label selectors.
+ # Deprecated, use field selectors instead.
required:
matchLabels:
game: my-game
@@ -107,6 +163,7 @@ spec:
players:
minAvailable: 0
maxAvailable: 99
+ # Deprecated, use field selectors instead.
# An ordered list of preferred GameServer label selectors
# that are optional to be fulfilled, but will be searched before the `required` selector.
# If the first selector is not matched, the selection attempts the second selector, and so on.
@@ -137,18 +194,23 @@ spec:
mode: deathmatch
annotations:
map: garden22
-```
+ {{< /tab >}}
+{{< /tabpane >}}
The `spec` field is the actual `GameServerAllocation` specification, and it is composed as follows:
-- `required` is a [GameServerSelector][gameserverselector]
+- Deprecated, use `selectors` instead. If `selectors` is set, this field will be ignored.
+ `required` is a [GameServerSelector][gameserverselector]
(matchLabels. matchExpressions, gameServerState and player filters) from which to choose GameServers from.
-- `preferred` is an ordered list of preferred
- [GameServerSelector][gameserverselector]
+- Deprecated, use `selectors` instead. If `selectors` is set, this field will be ignored.
+ `preferred` is an ordered list of preferred [GameServerSelector][gameserverselector]
that are _optional_ to be fulfilled, but will be searched before the `required` selector.
If the first selector is not matched, the selection attempts the second selector, and so on.
If any of the `preferred` selectors are matched, the `required` selector is not considered.
This is useful for things like smoke testing of new game servers.
+- `selectors` is an ordered list of [GameServerSelector][gameserverselector].
+ If the first selector is not matched, the selection attempts the second selector, and so on.
+ This is useful for things like smoke testing of new game servers.
- `scheduling` defines how GameServers are organised across the cluster, in this case specifically when allocating
`GameServers` for usage.
"Packed" (default) is aimed at dynamic Kubernetes clusters, such as cloud providers, wherein we want to bin pack
diff --git a/test/e2e/allocator_test.go b/test/e2e/allocator_test.go
index 983f3b137c..7c7378fe14 100644
--- a/test/e2e/allocator_test.go
+++ b/test/e2e/allocator_test.go
@@ -61,7 +61,7 @@ const (
allocatorClientSecretNamespace = "default"
)
-func TestAllocator(t *testing.T) {
+func TestAllocatorWithDeprecatedRequired(t *testing.T) {
ctx := context.Background()
ip, port := getAllocatorEndpoint(ctx, t)
@@ -117,6 +117,7 @@ func TestAllocator(t *testing.T) {
// let's do a re-allocation
if runtime.FeatureEnabled(runtime.FeatureStateAllocationFilter) && runtime.FeatureEnabled(runtime.FeaturePlayerAllocationFilter) {
logrus.Info("testing state allocation filter")
+ // nolint:staticcheck
request.PreferredGameServerSelectors[0].GameServerState = pb.GameServerSelector_ALLOCATED
allocatedResponse, err := grpcClient.Allocate(context.Background(), request)
require.NoError(t, err)
@@ -125,6 +126,7 @@ func TestAllocator(t *testing.T) {
// do a capacity based allocation
logrus.Info("testing capacity allocation filter")
+ // nolint:staticcheck
request.PreferredGameServerSelectors[0].Players = &pb.PlayerSelector{
MinAvailable: 5,
MaxAvailable: 10,
@@ -135,8 +137,11 @@ func TestAllocator(t *testing.T) {
validateAllocatorResponse(t, allocatedResponse)
// do a capacity based allocation that should fail
+ // nolint:staticcheck
request.PreferredGameServerSelectors = nil
+ // nolint:staticcheck
request.RequiredGameServerSelector.GameServerState = pb.GameServerSelector_ALLOCATED
+ // nolint:staticcheck
request.RequiredGameServerSelector.Players = &pb.PlayerSelector{MinAvailable: 99, MaxAvailable: 200}
allocatedResponse, err = grpcClient.Allocate(context.Background(), request)
@@ -152,7 +157,96 @@ func TestAllocator(t *testing.T) {
assert.NoError(t, err)
}
-func TestRestAllocator(t *testing.T) {
+func TestAllocatorWithSelectors(t *testing.T) {
+ ctx := context.Background()
+
+ ip, port := getAllocatorEndpoint(ctx, t)
+ requestURL := fmt.Sprintf(allocatorReqURLFmt, ip, port)
+ tlsCA := refreshAllocatorTLSCerts(ctx, t, ip)
+
+ var flt *agonesv1.Fleet
+ var err error
+ if runtime.FeatureEnabled(runtime.FeaturePlayerAllocationFilter) {
+ flt, err = createFleetWithOpts(ctx, framework.Namespace, func(f *agonesv1.Fleet) {
+ f.Spec.Template.Spec.Players = &agonesv1.PlayersSpec{
+ InitialCapacity: 10,
+ }
+ })
+ } else {
+ flt, err = createFleet(ctx, framework.Namespace)
+ }
+ assert.NoError(t, err)
+
+ framework.AssertFleetCondition(t, flt, e2e.FleetReadyCount(flt.Spec.Replicas))
+ request := &pb.AllocationRequest{
+ Namespace: framework.Namespace,
+ GameServerSelectors: []*pb.GameServerSelector{{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}},
+ Scheduling: pb.AllocationRequest_Packed,
+ Metadata: &pb.MetaPatch{Labels: map[string]string{"gslabel": "allocatedbytest"}},
+ }
+
+ var response *pb.AllocationResponse
+ // wait for the allocation system to come online
+ err = wait.PollImmediate(2*time.Second, 5*time.Minute, func() (bool, error) {
+ // create the grpc client each time, as we may end up looking at an old cert
+ dialOpts, err := createRemoteClusterDialOption(ctx, allocatorClientSecretNamespace, allocatorClientSecretName, tlsCA)
+ if err != nil {
+ return false, err
+ }
+
+ conn, err := grpc.Dial(requestURL, dialOpts)
+ if err != nil {
+ logrus.WithError(err).Info("failing grpc.Dial")
+ return false, nil
+ }
+ defer conn.Close() // nolint: errcheck
+
+ grpcClient := pb.NewAllocationServiceClient(conn)
+ response, err = grpcClient.Allocate(context.Background(), request)
+ if err != nil {
+ logrus.WithError(err).Info("failing Allocate request")
+ return false, nil
+ }
+ validateAllocatorResponse(t, response)
+
+ // let's do a re-allocation
+ if runtime.FeatureEnabled(runtime.FeatureStateAllocationFilter) && runtime.FeatureEnabled(runtime.FeaturePlayerAllocationFilter) {
+ logrus.Info("testing state allocation filter")
+ request.GameServerSelectors[0].GameServerState = pb.GameServerSelector_ALLOCATED
+ allocatedResponse, err := grpcClient.Allocate(context.Background(), request)
+ require.NoError(t, err)
+ require.Equal(t, response.GameServerName, allocatedResponse.GameServerName)
+ validateAllocatorResponse(t, allocatedResponse)
+
+ // do a capacity based allocation
+ logrus.Info("testing capacity allocation filter")
+ request.GameServerSelectors[0].Players = &pb.PlayerSelector{
+ MinAvailable: 5,
+ MaxAvailable: 10,
+ }
+ allocatedResponse, err = grpcClient.Allocate(context.Background(), request)
+ require.NoError(t, err)
+ require.Equal(t, response.GameServerName, allocatedResponse.GameServerName)
+ validateAllocatorResponse(t, allocatedResponse)
+
+ // do a capacity based allocation that should fail
+ request.GameServerSelectors[0].GameServerState = pb.GameServerSelector_ALLOCATED
+ request.GameServerSelectors[0].Players = &pb.PlayerSelector{MinAvailable: 99, MaxAvailable: 200}
+
+ allocatedResponse, err = grpcClient.Allocate(context.Background(), request)
+ assert.Nil(t, allocatedResponse)
+ status, ok := status.FromError(err)
+ require.True(t, ok)
+ assert.Equal(t, codes.ResourceExhausted, status.Code())
+ }
+
+ return true, nil
+ })
+
+ assert.NoError(t, err)
+}
+
+func TestRestAllocatorWithDeprecatedRequired(t *testing.T) {
ctx := context.Background()
ip, port := getAllocatorEndpoint(ctx, t)
@@ -216,6 +310,69 @@ func TestRestAllocator(t *testing.T) {
assert.NoError(t, err)
}
+func TestRestAllocatorWithSelectors(t *testing.T) {
+ ctx := context.Background()
+
+ ip, port := getAllocatorEndpoint(ctx, t)
+ requestURL := fmt.Sprintf(allocatorReqURLFmt, ip, port)
+ tlsCA := refreshAllocatorTLSCerts(ctx, t, ip)
+
+ flt, err := createFleet(ctx, framework.Namespace)
+ if !assert.Nil(t, err) {
+ return
+ }
+ framework.AssertFleetCondition(t, flt, e2e.FleetReadyCount(flt.Spec.Replicas))
+ request := &pb.AllocationRequest{
+ Namespace: framework.Namespace,
+ GameServerSelectors: []*pb.GameServerSelector{{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}},
+ Scheduling: pb.AllocationRequest_Packed,
+ Metadata: &pb.MetaPatch{Labels: map[string]string{"gslabel": "allocatedbytest"}},
+ }
+ tlsCfg, err := getTLSConfig(ctx, allocatorClientSecretNamespace, allocatorClientSecretName, tlsCA)
+ if !assert.Nil(t, err) {
+ return
+ }
+ client := &http.Client{
+ Transport: &http.Transport{
+ TLSClientConfig: tlsCfg,
+ },
+ }
+ jsonRes, err := json.Marshal(request)
+ if !assert.Nil(t, err) {
+ return
+ }
+ req, err := http.NewRequest("POST", "https://"+requestURL+"/gameserverallocation", bytes.NewBuffer(jsonRes))
+ if !assert.Nil(t, err) {
+ logrus.WithError(err).Info("failed to create rest request")
+ return
+ }
+
+ // wait for the allocation system to come online
+ err = wait.PollImmediate(2*time.Second, 5*time.Minute, func() (bool, error) {
+ resp, err := client.Do(req)
+ if err != nil {
+ logrus.WithError(err).Info("failed Allocate rest request")
+ return false, nil
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ logrus.WithError(err).Info("failed to read Allocate response body")
+ return false, nil
+ }
+ defer resp.Body.Close() // nolint: errcheck
+ var response pb.AllocationResponse
+ err = json.Unmarshal(body, &response)
+ if err != nil {
+ logrus.WithError(err).Info("failed to unmarshal Allocate response")
+ return false, nil
+ }
+ validateAllocatorResponse(t, &response)
+ return true, nil
+ })
+
+ assert.NoError(t, err)
+}
+
// Tests multi-cluster allocation by reusing the same cluster but across namespace.
// Multi-cluster is represented as two namespaces A and B in the same cluster.
// Namespace A received the allocation request, but because namespace B has the highest priority, A will forward the request to B.
@@ -269,8 +426,8 @@ func TestAllocatorCrossNamespace(t *testing.T) {
request := &pb.AllocationRequest{
Namespace: namespaceA,
// Enable multi-cluster setting
- MultiClusterSetting: &pb.MultiClusterSetting{Enabled: true},
- RequiredGameServerSelector: &pb.GameServerSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}},
+ MultiClusterSetting: &pb.MultiClusterSetting{Enabled: true},
+ GameServerSelectors: []*pb.GameServerSelector{{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}},
}
// wait for the allocation system to come online
@@ -347,6 +504,7 @@ func getAllocatorEndpoint(ctx context.Context, t *testing.T) (string, int32) {
}
// createRemoteClusterDialOption creates a grpc client dial option with proper certs to make a remote call.
+//nolint:unparam
func createRemoteClusterDialOption(ctx context.Context, namespace, clientSecretName string, tlsCA []byte) (grpc.DialOption, error) {
tlsConfig, err := getTLSConfig(ctx, namespace, clientSecretName, tlsCA)
if err != nil {
diff --git a/test/e2e/fleet_test.go b/test/e2e/fleet_test.go
index b8095d8011..bb70a5c489 100644
--- a/test/e2e/fleet_test.go
+++ b/test/e2e/fleet_test.go
@@ -435,7 +435,7 @@ func TestScaleFleetUpAndDownWithGameServerAllocation(t *testing.T) {
// get an allocation
gsa := &allocationv1.GameServerAllocation{ObjectMeta: metav1.ObjectMeta{GenerateName: "allocation-"},
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}},
+ Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}}},
}}
gsa, err = framework.AgonesClient.AllocationV1().GameServerAllocations(framework.Namespace).Create(ctx, gsa, metav1.CreateOptions{})
@@ -556,7 +556,7 @@ func TestUpdateGameServerConfigurationInFleet(t *testing.T) {
// get an allocation
gsa := &allocationv1.GameServerAllocation{ObjectMeta: metav1.ObjectMeta{GenerateName: "allocation-"},
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}},
+ Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}}},
}}
gsa, err = framework.AgonesClient.AllocationV1().GameServerAllocations(framework.Namespace).Create(ctx, gsa, metav1.CreateOptions{})
@@ -774,7 +774,7 @@ func TestGameServerAllocationDuringGameServerDeletion(t *testing.T) {
time.Sleep(100 * time.Millisecond)
gsa := &allocationv1.GameServerAllocation{ObjectMeta: metav1.ObjectMeta{GenerateName: "allocation-"},
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}},
+ Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}}},
}}
gsa, err = framework.AgonesClient.AllocationV1().GameServerAllocations(framework.Namespace).Create(ctx, gsa, metav1.CreateOptions{})
if err != nil || gsa.Status.State == allocationv1.GameServerAllocationUnAllocated {
diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go
index d9d02428de..dfff8ed844 100644
--- a/test/e2e/framework/framework.go
+++ b/test/e2e/framework/framework.go
@@ -576,8 +576,8 @@ func GetAllocation(f *agonesv1.Fleet) *allocationv1.GameServerAllocation {
// get an allocation
return &allocationv1.GameServerAllocation{
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{
- LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}},
+ Selectors: []allocationv1.GameServerSelector{
+ {LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: f.ObjectMeta.Name}}},
},
}}
}
diff --git a/test/e2e/gameserverallocation_test.go b/test/e2e/gameserverallocation_test.go
index 2a061dbed7..d4ac3d11ee 100644
--- a/test/e2e/gameserverallocation_test.go
+++ b/test/e2e/gameserverallocation_test.go
@@ -57,15 +57,22 @@ func TestCreateFleetAndGameServerAllocate(t *testing.T) {
framework.AssertFleetCondition(t, flt, e2e.FleetReadyCount(flt.Spec.Replicas))
- gsa := &allocationv1.GameServerAllocation{
- Spec: allocationv1.GameServerAllocationSpec{
+ gsaList := []*allocationv1.GameServerAllocation{
+ {Spec: allocationv1.GameServerAllocationSpec{
Scheduling: strategy,
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}},
- }}
+ Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}}}},
+ },
+ {Spec: allocationv1.GameServerAllocationSpec{
+ Scheduling: strategy,
+ Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}}},
+ },
+ }
- gsa, err = framework.AgonesClient.AllocationV1().GameServerAllocations(fleet.ObjectMeta.Namespace).Create(ctx, gsa, metav1.CreateOptions{})
- if assert.NoError(t, err) {
- assert.Equal(t, string(allocationv1.GameServerAllocationAllocated), string(gsa.Status.State))
+ for _, gsa := range gsaList {
+ gsa, err = framework.AgonesClient.AllocationV1().GameServerAllocations(fleet.ObjectMeta.Namespace).Create(ctx, gsa, metav1.CreateOptions{})
+ if assert.NoError(t, err) {
+ assert.Equal(t, string(allocationv1.GameServerAllocationAllocated), string(gsa.Status.State))
+ }
}
})
}
@@ -90,7 +97,7 @@ func TestCreateFleetAndGameServerStateFilterAllocation(t *testing.T) {
fleetSelector := metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}
gsa := &allocationv1.GameServerAllocation{
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: fleetSelector},
+ Selectors: []allocationv1.GameServerSelector{{LabelSelector: fleetSelector}},
}}
// standard allocation
@@ -103,10 +110,10 @@ func TestCreateFleetAndGameServerStateFilterAllocation(t *testing.T) {
assert.Equal(t, agonesv1.GameServerStateAllocated, gs1.Status.State)
assert.NotNil(t, gs1.ObjectMeta.Annotations["agones.dev/last-allocated"])
- // now let's get it back again as required
+ // now let's get it back again
gsa = gsa.DeepCopy()
allocated := agonesv1.GameServerStateAllocated
- gsa.Spec.Required.GameServerState = &allocated
+ gsa.Spec.Selectors[0].GameServerState = &allocated
gsa, err = framework.AgonesClient.AllocationV1().GameServerAllocations(fleet.ObjectMeta.Namespace).Create(ctx, gsa, metav1.CreateOptions{})
require.NoError(t, err)
@@ -120,23 +127,6 @@ func TestCreateFleetAndGameServerStateFilterAllocation(t *testing.T) {
require.Equal(t, gs1.ObjectMeta.Name, gs2.ObjectMeta.Name)
require.NotEqual(t, gs1.ObjectMeta.ResourceVersion, gs2.ObjectMeta.ResourceVersion)
require.NotEqual(t, gs1.ObjectMeta.Annotations["agones.dev/last-allocated"], gs2.ObjectMeta.Annotations["agones.dev/last-allocated"])
-
- // and again as preferred
- gsa = &allocationv1.GameServerAllocation{
- Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: fleetSelector},
- Preferred: []allocationv1.GameServerSelector{
- {
- LabelSelector: fleetSelector,
- GameServerState: &allocated,
- },
- },
- }}
-
- gsa, err = framework.AgonesClient.AllocationV1().GameServerAllocations(fleet.ObjectMeta.Namespace).Create(ctx, gsa, metav1.CreateOptions{})
- require.NoError(t, err)
- assert.Equal(t, string(allocationv1.GameServerAllocationAllocated), string(gsa.Status.State))
- assert.Equal(t, gs1.ObjectMeta.Name, gsa.Status.GameServerName)
}
func TestCreateFleetAndGameServerPlayerCapacityAllocation(t *testing.T) {
@@ -160,8 +150,7 @@ func TestCreateFleetAndGameServerPlayerCapacityAllocation(t *testing.T) {
allocated := agonesv1.GameServerStateAllocated
gsa := &allocationv1.GameServerAllocation{
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: fleetSelector, Players: &allocationv1.PlayerSelector{MinAvailable: 5, MaxAvailable: 10}},
- Preferred: []allocationv1.GameServerSelector{
+ Selectors: []allocationv1.GameServerSelector{
{
LabelSelector: fleetSelector,
GameServerState: &allocated,
@@ -170,6 +159,7 @@ func TestCreateFleetAndGameServerPlayerCapacityAllocation(t *testing.T) {
MaxAvailable: 99,
},
},
+ {LabelSelector: fleetSelector, Players: &allocationv1.PlayerSelector{MinAvailable: 5, MaxAvailable: 10}},
},
}}
@@ -299,7 +289,7 @@ func TestMultiClusterAllocationOnLocalCluster(t *testing.T) {
gsa := &allocationv1.GameServerAllocation{
Spec: allocationv1.GameServerAllocationSpec{
Scheduling: strategy,
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}},
+ Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}}},
MultiClusterSetting: allocationv1.MultiClusterSetting{
Enabled: true,
PolicySelector: metav1.LabelSelector{
@@ -359,7 +349,7 @@ func TestCreateFullFleetAndCantGameServerAllocate(t *testing.T) {
gsa := &allocationv1.GameServerAllocation{
Spec: allocationv1.GameServerAllocationSpec{
Scheduling: strategy,
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}},
+ Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: flt.ObjectMeta.Name}}}},
}}
for i := 0; i < replicasCount; i++ {
@@ -397,7 +387,7 @@ func TestGameServerAllocationMetaDataPatch(t *testing.T) {
gsa := &allocationv1.GameServerAllocation{ObjectMeta: metav1.ObjectMeta{GenerateName: "allocation-"},
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"test": t.Name()}}},
+ Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"test": t.Name()}}}},
MetaPatch: allocationv1.MetaPatch{
Labels: map[string]string{"red": "blue"},
Annotations: map[string]string{"dog": "good"},
@@ -459,9 +449,9 @@ func TestGameServerAllocationPreferredSelection(t *testing.T) {
gsa := &allocationv1.GameServerAllocation{ObjectMeta: metav1.ObjectMeta{GenerateName: "allocation-"},
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: label}},
- Preferred: []allocationv1.GameServerSelector{
+ Selectors: []allocationv1.GameServerSelector{
{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: preferred.ObjectMeta.Name}}},
+ {LabelSelector: metav1.LabelSelector{MatchLabels: label}},
},
}}
@@ -524,7 +514,7 @@ func TestGameServerAllocationDeletionOnUnAllocate(t *testing.T) {
gsa := &allocationv1.GameServerAllocation{ObjectMeta: metav1.ObjectMeta{GenerateName: "allocation-"},
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"never": "goingtohappen"}}},
+ Selectors: []allocationv1.GameServerSelector{{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{"never": "goingtohappen"}}}},
}}
gsa, err := allocations.Create(ctx, gsa.DeepCopy(), metav1.CreateOptions{})
@@ -558,9 +548,9 @@ func TestGameServerAllocationDuringMultipleAllocationClients(t *testing.T) {
gsa := &allocationv1.GameServerAllocation{ObjectMeta: metav1.ObjectMeta{GenerateName: "allocation-"},
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: label}},
- Preferred: []allocationv1.GameServerSelector{
+ Selectors: []allocationv1.GameServerSelector{
{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: "preferred"}}},
+ {LabelSelector: metav1.LabelSelector{MatchLabels: label}},
},
}}
diff --git a/test/load/allocation/allocationload.go b/test/load/allocation/allocationload.go
index 1615eef8ac..7f030a0bb5 100644
--- a/test/load/allocation/allocationload.go
+++ b/test/load/allocation/allocationload.go
@@ -68,8 +68,7 @@ func allocate(framework *e2eframework.Framework, numOfClients int, fleetName str
gsa := &allocationv1.GameServerAllocation{
ObjectMeta: metav1.ObjectMeta{GenerateName: "allocation-"},
Spec: allocationv1.GameServerAllocationSpec{
- Required: allocationv1.GameServerSelector{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}},
- Preferred: []allocationv1.GameServerSelector{
+ Selectors: []allocationv1.GameServerSelector{
{LabelSelector: metav1.LabelSelector{MatchLabels: map[string]string{agonesv1.FleetNameLabel: fleetName}}},
},
},