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  }