agones.dev/agones@v1.54.0/pkg/gameservers/gameservers.go (about)

     1  // Copyright 2020 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 gameservers
    16  
    17  import (
    18  	"net"
    19  
    20  	agonesv1 "agones.dev/agones/pkg/apis/agones/v1"
    21  	"github.com/pkg/errors"
    22  	corev1 "k8s.io/api/core/v1"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/labels"
    25  )
    26  
    27  // isGameServerPod returns if this Pod is a Pod that comes from a GameServer
    28  func isGameServerPod(pod *corev1.Pod) bool {
    29  	// add some defense in case this happens
    30  	if pod == nil {
    31  		return false
    32  	}
    33  
    34  	if agonesv1.GameServerRolePodSelector.Matches(labels.Set(pod.ObjectMeta.Labels)) {
    35  		owner := metav1.GetControllerOf(pod)
    36  		return owner != nil && owner.Kind == "GameServer"
    37  	}
    38  
    39  	return false
    40  }
    41  
    42  // address returns the "primary" network address that the given Pod is run on,
    43  // and a slice of all network addresses.
    44  //
    45  // The primary address will default to the ExternalDNS, but if the ExternalDNS is
    46  // not set, it will fall back to the ExternalIP then InternalDNS then InternalIP,
    47  // If externalDNS is false, skip ExternalDNS and InternalDNS.
    48  // since we can have clusters that are private, and/or tools like minikube
    49  // that only report an InternalIP.
    50  func address(node *corev1.Node) (string, []corev1.NodeAddress, error) {
    51  	addresses := make([]corev1.NodeAddress, 0, len(node.Status.Addresses))
    52  	for _, a := range node.Status.Addresses {
    53  		addresses = append(addresses, *a.DeepCopy())
    54  	}
    55  
    56  	for _, a := range addresses {
    57  		if a.Type == corev1.NodeExternalDNS {
    58  			return a.Address, addresses, nil
    59  		}
    60  	}
    61  
    62  	for _, a := range addresses {
    63  		if a.Type == corev1.NodeExternalIP && net.ParseIP(a.Address) != nil {
    64  			return a.Address, addresses, nil
    65  		}
    66  	}
    67  
    68  	// There might not be a public DNS/IP, so fall back to the private DNS/IP
    69  	for _, a := range addresses {
    70  		if a.Type == corev1.NodeInternalDNS {
    71  			return a.Address, addresses, nil
    72  		}
    73  	}
    74  
    75  	for _, a := range addresses {
    76  		if a.Type == corev1.NodeInternalIP && net.ParseIP(a.Address) != nil {
    77  			return a.Address, addresses, nil
    78  		}
    79  	}
    80  
    81  	return "", nil, errors.Errorf("Could not find an address for Node: %s", node.ObjectMeta.Name)
    82  }
    83  
    84  // applyGameServerAddressAndPort gathers the address and port details from the node and pod
    85  // and applies them to the GameServer that is passed in, and returns it.
    86  func applyGameServerAddressAndPort(gs *agonesv1.GameServer, node *corev1.Node, pod *corev1.Pod, syncPodPortsToGameServer func(*agonesv1.GameServer, *corev1.Pod) error) (*agonesv1.GameServer, error) {
    87  	addr, addrs, err := address(node)
    88  	if err != nil {
    89  		return gs, errors.Wrapf(err, "error getting external address for GameServer %s", gs.ObjectMeta.Name)
    90  	}
    91  
    92  	gs.Status.Address = addr
    93  	gs.Status.Addresses = addrs
    94  	gs.Status.NodeName = pod.Spec.NodeName
    95  
    96  	for _, ip := range pod.Status.PodIPs {
    97  		gs.Status.Addresses = append(gs.Status.Addresses, corev1.NodeAddress{
    98  			Type:    agonesv1.NodePodIP,
    99  			Address: ip.IP,
   100  		})
   101  	}
   102  
   103  	if err := syncPodPortsToGameServer(gs, pod); err != nil {
   104  		return gs, errors.Wrapf(err, "cloud product error syncing ports on GameServer %s", gs.ObjectMeta.Name)
   105  	}
   106  
   107  	// HostPort is always going to be populated, even when dynamic
   108  	// This will be a double up of information, but it will be easier to read
   109  	gs.Status.Ports = make([]agonesv1.GameServerStatusPort, len(gs.Spec.Ports))
   110  	for i, p := range gs.Spec.Ports {
   111  		gs.Status.Ports[i] = p.Status()
   112  	}
   113  
   114  	return gs, nil
   115  }
   116  
   117  // isBeforePodCreated checks to see if the GameServer is in a state in which the pod could not have been
   118  // created yet. This includes "Starting" in which a pod MAY exist, but may not yet be available, depending on when the
   119  // informer cache updates
   120  func isBeforePodCreated(gs *agonesv1.GameServer) bool {
   121  	state := gs.Status.State
   122  	return state == agonesv1.GameServerStatePortAllocation || state == agonesv1.GameServerStateCreating || state == agonesv1.GameServerStateStarting
   123  }