agones.dev/agones@v1.53.0/pkg/apis/agones/v1/gameserverset.go (about) 1 // Copyright 2018 Google LLC All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package v1 16 17 import ( 18 "agones.dev/agones/pkg/apis" 19 "agones.dev/agones/pkg/apis/agones" 20 "agones.dev/agones/pkg/util/runtime" 21 apiequality "k8s.io/apimachinery/pkg/api/equality" 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 "k8s.io/apimachinery/pkg/util/validation/field" 24 ) 25 26 const ( 27 // GameServerSetGameServerLabel is the label that the name of the GameServerSet 28 // is set on the GameServer the GameServerSet controls 29 GameServerSetGameServerLabel = agones.GroupName + "/gameserverset" 30 ) 31 32 // +genclient 33 // +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/api/autoscaling/v1.Scale 34 // +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/api/autoscaling/v1.Scale,result=k8s.io/api/autoscaling/v1.Scale 35 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 36 37 // GameServerSet is the data structure for a set of GameServers. 38 // This matches philosophically with the relationship between 39 // Deployments and ReplicaSets 40 type GameServerSet struct { 41 metav1.TypeMeta `json:",inline"` 42 metav1.ObjectMeta `json:"metadata,omitempty"` 43 44 Spec GameServerSetSpec `json:"spec"` 45 Status GameServerSetStatus `json:"status"` 46 } 47 48 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 49 50 // GameServerSetList is a list of GameServerSet resources 51 type GameServerSetList struct { 52 metav1.TypeMeta `json:",inline"` 53 metav1.ListMeta `json:"metadata,omitempty"` 54 55 Items []GameServerSet `json:"items"` 56 } 57 58 // GameServerSetSpec the specification for GameServerSet 59 type GameServerSetSpec struct { 60 // Replicas are the number of GameServers that should be in this set 61 Replicas int32 `json:"replicas"` 62 // Labels and Annotations to apply to GameServers when the number of Allocated GameServers drops below 63 // the desired replicas on the underlying `GameServerSet` 64 // +optional 65 AllocationOverflow *AllocationOverflow `json:"allocationOverflow,omitempty"` 66 // Scheduling strategy. Defaults to "Packed". 67 Scheduling apis.SchedulingStrategy `json:"scheduling,omitempty"` 68 // [Stage: Beta] 69 // [FeatureFlag:CountsAndLists] 70 // `Priorities` configuration alters scale down logic in Fleets based on the configured available capacity order under that key. 71 // 72 // Priority of sorting is in descending importance. I.e. The position 0 `priority` entry is checked first. 73 // 74 // For `Packed` strategy scale down, this priority list will be the tie-breaker within the node, to ensure optimal 75 // infrastructure usage while also allowing some custom prioritisation of `GameServers`. 76 // 77 // For `Distributed` strategy scale down, the entire `Fleet` will be sorted by this priority list to provide the 78 // order of `GameServers` to delete on scale down. 79 // +optional 80 Priorities []Priority `json:"priorities,omitempty"` 81 // Template the GameServer template to apply for this GameServerSet 82 Template GameServerTemplateSpec `json:"template"` 83 } 84 85 // GameServerSetStatus is the status of a GameServerSet 86 type GameServerSetStatus struct { 87 // Replicas is the total number of current GameServer replicas 88 Replicas int32 `json:"replicas"` 89 // ReadyReplicas is the number of Ready GameServer replicas 90 ReadyReplicas int32 `json:"readyReplicas"` 91 // ReservedReplicas is the number of Reserved GameServer replicas 92 ReservedReplicas int32 `json:"reservedReplicas"` 93 // AllocatedReplicas is the number of Allocated GameServer replicas 94 AllocatedReplicas int32 `json:"allocatedReplicas"` 95 // ShutdownReplicas is the number of Shutdown GameServers replicas 96 ShutdownReplicas int32 `json:"shutdownReplicas"` 97 // [Stage:Alpha] 98 // [FeatureFlag:PlayerTracking] 99 // Players is the current total player capacity and count for this GameServerSet 100 // +optional 101 Players *AggregatedPlayerStatus `json:"players,omitempty"` 102 // (Beta, CountsAndLists feature flag) Counters provides aggregated Counter capacity and Counter 103 // count for this GameServerSet. 104 // +optional 105 Counters map[string]AggregatedCounterStatus `json:"counters,omitempty"` 106 // (Beta, CountsAndLists feature flag) Lists provides aggregated List capacity and List values 107 // for this GameServerSet. 108 // +optional 109 Lists map[string]AggregatedListStatus `json:"lists,omitempty"` 110 } 111 112 // ValidateUpdate validates when updates occur. The argument 113 // is the new GameServerSet, being passed into the old GameServerSet 114 func (gsSet *GameServerSet) ValidateUpdate(newGSS *GameServerSet) field.ErrorList { 115 allErrs := validateName(newGSS, field.NewPath("metadata")) 116 if !apiequality.Semantic.DeepEqual(gsSet.Spec.Template, newGSS.Spec.Template) { 117 allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "template"), gsSet.Spec.Template, "GameServerSet template cannot be updated")) 118 } 119 120 return allErrs 121 } 122 123 // Validate validates when Create occurs. Check the name size 124 func (gsSet *GameServerSet) Validate(apiHooks APIHooks) field.ErrorList { 125 allErrs := validateName(gsSet, field.NewPath("metadata")) 126 127 // check GameServer specification in a GameServerSet 128 allErrs = append(allErrs, validateGSSpec(apiHooks, gsSet, field.NewPath("spec", "template", "spec"))...) 129 allErrs = append(allErrs, apiHooks.ValidateScheduling(gsSet.Spec.Scheduling, field.NewPath("spec", "scheduling"))...) 130 131 if gsSet.Spec.Priorities != nil && !runtime.FeatureEnabled(runtime.FeatureCountsAndLists) { 132 allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "priorities"), "FeatureCountsAndLists is not enabled")) 133 } 134 135 allErrs = append(allErrs, validateObjectMeta(&gsSet.Spec.Template.ObjectMeta, field.NewPath("spec", "template", "metadata"))...) 136 return allErrs 137 } 138 139 // GetGameServerSpec get underlying GameServer specification 140 func (gsSet *GameServerSet) GetGameServerSpec() *GameServerSpec { 141 return &gsSet.Spec.Template.Spec 142 } 143 144 // GameServer returns a single GameServer derived 145 // from the GameServer template 146 func (gsSet *GameServerSet) GameServer() *GameServer { 147 gs := &GameServer{ 148 ObjectMeta: *gsSet.Spec.Template.ObjectMeta.DeepCopy(), 149 Spec: *gsSet.Spec.Template.Spec.DeepCopy(), 150 } 151 152 gs.Spec.Scheduling = gsSet.Spec.Scheduling 153 154 // Switch to GenerateName, so that we always get a Unique name for the GameServer, and there 155 // can be no collisions 156 gs.ObjectMeta.GenerateName = gsSet.ObjectMeta.Name + "-" 157 gs.ObjectMeta.Name = "" 158 gs.ObjectMeta.Namespace = gsSet.ObjectMeta.Namespace 159 gs.ObjectMeta.ResourceVersion = "" 160 gs.ObjectMeta.UID = "" 161 162 ref := metav1.NewControllerRef(gsSet, SchemeGroupVersion.WithKind("GameServerSet")) 163 gs.ObjectMeta.OwnerReferences = append(gs.ObjectMeta.OwnerReferences, *ref) 164 165 if gs.ObjectMeta.Labels == nil { 166 gs.ObjectMeta.Labels = make(map[string]string, 2) 167 } 168 169 gs.ObjectMeta.Labels[GameServerSetGameServerLabel] = gsSet.ObjectMeta.Name 170 gs.ObjectMeta.Labels[FleetNameLabel] = gsSet.ObjectMeta.Labels[FleetNameLabel] 171 return gs 172 }