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