agones.dev/agones@v1.53.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 }