agones.dev/agones@v1.53.0/test/e2e/extensions/high_availability_test.go (about) 1 // Copyright 2023 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 extensions 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 e2eframework "agones.dev/agones/test/e2e/framework" 23 "github.com/stretchr/testify/assert" 24 "github.com/stretchr/testify/require" 25 corev1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/labels" 28 "k8s.io/apimachinery/pkg/util/wait" 29 ) 30 31 // Test creating a gameserver when one of the extensions pods is down/deleted 32 func TestGameServerCreationAfterDeletingOneExtensionsPod(t *testing.T) { 33 logger := e2eframework.TestLogger(t) 34 ctx := context.Background() 35 36 assert.NoError(t, waitForAgonesExtensionsRunning(ctx)) 37 38 list, err := getAgonesExtensionsPods(ctx) 39 logger.Infof("Length of pod list is %v", len(list.Items)) 40 if len(list.Items) > 2 { 41 logger.WithField("podCount", len(list.Items)).Info("Logging events for the Deployment due to pod count > 2 before deleting extensions pod") 42 for i := range list.Items { 43 logger.Infof("Name of extensions pod %v: %v", i, list.Items[i].ObjectMeta.Name) 44 logger.Infof("Status of extensions pod %v", list.Items[i].Status) 45 framework.LogEvents(t, logger, "agones-system", &list.Items[i]) 46 } 47 } else { 48 for i := range list.Items { 49 logger.Infof("Name of extensions pod %v: %v", i, list.Items[i].ObjectMeta.Name) 50 logger.Infof("Host IP %v", list.Items[i].Status.HostIP) 51 logger.Infof("Pod IPs %v", list.Items[i].Status.PodIPs) 52 } 53 } 54 require.NoError(t, err, "Could not get list of Extension pods") 55 require.Greater(t, len(list.Items), 1, "Cluster has no Extensions pod or has only 1 extensions pod") 56 57 logger.Infof("Removing one of the Extensions Pods: %v", list.Items[1].ObjectMeta.Name) 58 deleteAgonesExtensionsPod(ctx, t, true) 59 60 require.NoError(t, waitForAgonesExtensionsRunning(ctx)) 61 62 gs := framework.DefaultGameServer(defaultNs) 63 logger.Infof("Creating game-server %s...", gs.Name) 64 readyGs, err := framework.CreateGameServerAndWaitUntilReady(t, defaultNs, gs) 65 require.NoError(t, err, "Could not get a GameServer ready") 66 logger.WithField("gsKey", readyGs.ObjectMeta.Name).Info("GameServer Ready") 67 68 require.NoError(t, framework.AgonesClient.AgonesV1().GameServers(defaultNs).Delete(ctx, readyGs.ObjectMeta.Name, metav1.DeleteOptions{})) 69 } 70 71 func TestGameServerCreationRightAfterDeletingOneExtensionsPod(t *testing.T) { 72 logger := e2eframework.TestLogger(t) 73 ctx := context.Background() 74 75 assert.NoError(t, waitForAgonesExtensionsRunning(ctx)) 76 77 list, err := getAgonesExtensionsPods(ctx) 78 logger.Infof("Length of pod list is %v", len(list.Items)) 79 for i := range list.Items { 80 logger.Infof("Name of extensions pod %v: %v", i, list.Items[i].ObjectMeta.Name) 81 } 82 require.NoError(t, err, "Could not get list of Extension pods") 83 84 logger.Infof("Removing one of the Extensions Pods: %v", list.Items[1].ObjectMeta.Name) 85 deleteAgonesExtensionsPod(ctx, t, false) 86 87 endTime := time.Now().Add(30 * time.Second) 88 for time.Now().Before(endTime) { 89 gs := framework.DefaultGameServer(defaultNs) 90 logger.Infof("Creating game-server %s...", gs.Name) 91 newGs, err := framework.AgonesClient.AgonesV1().GameServers(defaultNs).Create(context.Background(), gs, metav1.CreateOptions{}) 92 assert.NoError(t, err) 93 assert.NoError(t, framework.AgonesClient.AgonesV1().GameServers(defaultNs).Delete(ctx, newGs.ObjectMeta.Name, metav1.DeleteOptions{})) // nolint: errcheck 94 } 95 } 96 97 // deleteAgonesExtensionsPod deletes one of the extensions pod for the Agones extensions, 98 // faking a extensions pod crash. 99 func deleteAgonesExtensionsPod(ctx context.Context, t *testing.T, waitForExtensions bool) { 100 list, err := getAgonesExtensionsPods(ctx) 101 require.NoError(t, err, "Could not get list of Extension pods") 102 103 policy := metav1.DeletePropagationBackground 104 podToDelete := list.Items[1] 105 err = framework.KubeClient.CoreV1().Pods("agones-system").Delete(ctx, podToDelete.ObjectMeta.Name, 106 metav1.DeleteOptions{PropagationPolicy: &policy}) 107 require.NoError(t, err, "Could not delete the Extension pods") 108 if waitForExtensions { 109 require.Eventually(t, func() bool { 110 _, err := framework.KubeClient.CoreV1().Pods("agones-system").Get(ctx, podToDelete.ObjectMeta.Name, metav1.GetOptions{}) 111 return err != nil 112 }, 5*time.Minute, time.Second) 113 } 114 } 115 116 func waitForAgonesExtensionsRunning(ctx context.Context) error { 117 return wait.PollUntilContextTimeout(ctx, time.Second, 5*time.Minute, true, func(ctx context.Context) (bool, error) { 118 list, err := getAgonesExtensionsPods(ctx) 119 if err != nil { 120 return true, err 121 } 122 123 // count the number of Running instances 124 count := 0 125 for i := range list.Items { 126 if list.Items[i].Status.Phase == corev1.PodRunning { 127 count++ 128 } 129 } 130 131 return count == 2, nil 132 }) 133 } 134 135 // getAgonesExtensionsPods returns all the Agones extensions pods 136 func getAgonesExtensionsPods(ctx context.Context) (*corev1.PodList, error) { 137 opts := metav1.ListOptions{LabelSelector: labels.Set{"agones.dev/role": "extensions"}.String()} 138 pods, err := framework.KubeClient.CoreV1().Pods("agones-system").List(ctx, opts) 139 if err != nil { 140 return nil, err 141 } 142 143 // Filter Running pods 144 var runningPods []corev1.Pod 145 for i := range pods.Items { 146 if pods.Items[i].ObjectMeta.DeletionTimestamp.IsZero() { 147 runningPods = append(runningPods, pods.Items[i]) 148 } 149 } 150 151 return &corev1.PodList{Items: runningPods}, nil 152 }