github.com/hernad/nomad@v1.6.112/e2e/scaling/scaling.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package scaling 5 6 import ( 7 "os" 8 9 "github.com/hernad/nomad/api" 10 "github.com/hernad/nomad/e2e/e2eutil" 11 "github.com/hernad/nomad/e2e/framework" 12 "github.com/hernad/nomad/helper/pointer" 13 "github.com/hernad/nomad/helper/uuid" 14 ) 15 16 type ScalingE2ETest struct { 17 framework.TC 18 namespaceIDs []string 19 namespacedJobIDs [][2]string 20 } 21 22 func init() { 23 framework.AddSuites(&framework.TestSuite{ 24 Component: "Scaling", 25 CanRunLocal: true, 26 Cases: []framework.TestCase{ 27 new(ScalingE2ETest), 28 }, 29 }) 30 31 } 32 33 func (tc *ScalingE2ETest) BeforeAll(f *framework.F) { 34 e2eutil.WaitForLeader(f.T(), tc.Nomad()) 35 e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1) 36 } 37 38 func (tc *ScalingE2ETest) AfterEach(f *framework.F) { 39 if os.Getenv("NOMAD_TEST_SKIPCLEANUP") == "1" { 40 return 41 } 42 43 for _, namespacedJob := range tc.namespacedJobIDs { 44 err := e2eutil.StopJob(namespacedJob[1], "-purge", "-namespace", 45 namespacedJob[0]) 46 f.NoError(err) 47 } 48 tc.namespacedJobIDs = [][2]string{} 49 50 for _, ns := range tc.namespaceIDs { 51 _, err := e2eutil.Command("nomad", "namespace", "delete", ns) 52 f.NoError(err) 53 } 54 tc.namespaceIDs = []string{} 55 56 _, err := e2eutil.Command("nomad", "system", "gc") 57 f.NoError(err) 58 } 59 60 // TestScalingBasic performs basic scaling e2e tests within a single namespace. 61 func (tc *ScalingE2ETest) TestScalingBasic(f *framework.F) { 62 defaultNS := "default" 63 64 // Register a job with a scaling policy. The group doesn't include the 65 // count parameter, therefore Nomad should dynamically set this value to 66 // the policy min. 67 jobID := "test-scaling-" + uuid.Generate()[0:8] 68 f.NoError(e2eutil.Register(jobID, "scaling/input/namespace_default_1.nomad")) 69 tc.namespacedJobIDs = append(tc.namespacedJobIDs, [2]string{defaultNS, jobID}) 70 f.NoError(e2eutil.WaitForAllocStatusExpected(jobID, defaultNS, []string{"running", "running"}), 71 "job should be running with 2 allocs") 72 73 // Ensure we wait for the deployment to finish, otherwise scaling will 74 // fail. 75 f.NoError(e2eutil.WaitForLastDeploymentStatus(jobID, defaultNS, "successful", nil)) 76 77 // Simple scaling action. 78 testMeta := map[string]interface{}{"scaling-e2e-test": "value"} 79 scaleResp, _, err := tc.Nomad().Jobs().Scale( 80 jobID, "horizontally_scalable", pointer.Of(3), 81 "Nomad e2e testing", false, testMeta, nil) 82 f.NoError(err) 83 f.NotEmpty(scaleResp.EvalID) 84 f.NoError(e2eutil.WaitForAllocStatusExpected(jobID, defaultNS, []string{"running", "running", "running"}), 85 "job should be running with 3 allocs") 86 87 // Ensure we wait for the deployment to finish, otherwise scaling will 88 // fail for this reason. 89 f.NoError(e2eutil.WaitForLastDeploymentStatus(jobID, defaultNS, "successful", nil)) 90 91 // Attempt break break the policy min/max parameters. 92 _, _, err = tc.Nomad().Jobs().Scale( 93 jobID, "horizontally_scalable", pointer.Of(4), 94 "Nomad e2e testing", false, nil, nil) 95 f.Error(err) 96 _, _, err = tc.Nomad().Jobs().Scale( 97 jobID, "horizontally_scalable", pointer.Of(1), 98 "Nomad e2e testing", false, nil, nil) 99 f.Error(err) 100 101 // Check the scaling events. 102 statusResp, _, err := tc.Nomad().Jobs().ScaleStatus(jobID, nil) 103 f.NoError(err) 104 f.Len(statusResp.TaskGroups["horizontally_scalable"].Events, 1) 105 f.Equal(testMeta, statusResp.TaskGroups["horizontally_scalable"].Events[0].Meta) 106 107 // Remove the job. 108 _, _, err = tc.Nomad().Jobs().Deregister(jobID, true, nil) 109 f.NoError(err) 110 f.NoError(tc.Nomad().System().GarbageCollect()) 111 tc.namespacedJobIDs = [][2]string{} 112 113 // Attempt job registrations where the group count violates the policy 114 // min/max parameters. 115 f.Error(e2eutil.Register(jobID, "scaling/input/namespace_default_2.nomad")) 116 f.Error(e2eutil.Register(jobID, "scaling/input/namespace_default_3.nomad")) 117 } 118 119 // TestScalingNamespaces runs tests to ensure the job scaling endpoint adheres 120 // to Nomad's basic namespace principles. 121 func (tc *ScalingE2ETest) TestScalingNamespaces(f *framework.F) { 122 123 defaultNS := "default" 124 ANS := "NamespaceA" 125 126 // Create our non-default namespace. 127 _, err := e2eutil.Command("nomad", "namespace", "apply", ANS) 128 f.NoError(err, "could not create namespace") 129 tc.namespaceIDs = append(tc.namespaceIDs, ANS) 130 131 defaultJobID := "test-scaling-default-" + uuid.Generate()[0:8] 132 aJobID := "test-scaling-a-" + uuid.Generate()[0:8] 133 134 // Register and wait for the job deployments to succeed. 135 f.NoError(e2eutil.Register(defaultJobID, "scaling/input/namespace_default_1.nomad")) 136 f.NoError(e2eutil.Register(aJobID, "scaling/input/namespace_a_1.nomad")) 137 f.NoError(e2eutil.WaitForLastDeploymentStatus(defaultJobID, defaultNS, "successful", nil)) 138 f.NoError(e2eutil.WaitForLastDeploymentStatus(aJobID, ANS, "successful", nil)) 139 140 tc.namespacedJobIDs = append(tc.namespacedJobIDs, [2]string{defaultNS, defaultJobID}) 141 tc.namespacedJobIDs = append(tc.namespacedJobIDs, [2]string{ANS, aJobID}) 142 143 // Setup the WriteOptions for each namespace. 144 defaultWriteOpts := api.WriteOptions{Namespace: defaultNS} 145 aWriteOpts := api.WriteOptions{Namespace: ANS} 146 147 // We shouldn't be able to trigger scaling across the namespace boundary. 148 _, _, err = tc.Nomad().Jobs().Scale( 149 defaultJobID, "horizontally_scalable", pointer.Of(3), 150 "Nomad e2e testing", false, nil, &aWriteOpts) 151 f.Error(err) 152 _, _, err = tc.Nomad().Jobs().Scale( 153 aJobID, "horizontally_scalable", pointer.Of(3), 154 "Nomad e2e testing", false, nil, &defaultWriteOpts) 155 f.Error(err) 156 157 // We should be able to trigger scaling when using the correct namespace, 158 // duh. 159 _, _, err = tc.Nomad().Jobs().Scale( 160 defaultJobID, "horizontally_scalable", pointer.Of(3), 161 "Nomad e2e testing", false, nil, &defaultWriteOpts) 162 f.NoError(err) 163 _, _, err = tc.Nomad().Jobs().Scale( 164 aJobID, "horizontally_scalable", pointer.Of(3), 165 "Nomad e2e testing", false, nil, &aWriteOpts) 166 f.NoError(err) 167 }