github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/e2e/scalingpolicies/scalingpolicies.go (about) 1 package scalingpolicies 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/uuid" 10 "github.com/stretchr/testify/require" 11 ) 12 13 type ScalingPolicyE2ETest struct { 14 framework.TC 15 namespaceIDs []string 16 namespacedJobIDs [][2]string 17 } 18 19 func init() { 20 framework.AddSuites(&framework.TestSuite{ 21 Component: "ScalingPolicies", 22 CanRunLocal: true, 23 Cases: []framework.TestCase{ 24 new(ScalingPolicyE2ETest), 25 }, 26 }) 27 28 } 29 30 func (tc *ScalingPolicyE2ETest) BeforeAll(f *framework.F) { 31 e2eutil.WaitForLeader(f.T(), tc.Nomad()) 32 e2eutil.WaitForNodesReady(f.T(), tc.Nomad(), 1) 33 } 34 35 func (tc *ScalingPolicyE2ETest) 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.Assert().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.Assert().NoError(err) 50 } 51 tc.namespaceIDs = []string{} 52 53 _, err := e2eutil.Command("nomad", "system", "gc") 54 f.Assert().NoError(err) 55 } 56 57 // TestScalingPolicies multi-namespace scaling policy test which performs reads 58 // and job manipulations to ensure Nomad behaves as expected. 59 func (tc *ScalingPolicyE2ETest) TestScalingPolicies(f *framework.F) { 60 t := f.T() 61 62 // Create our non-default namespace. 63 _, err := e2eutil.Command("nomad", "namespace", "apply", "NamespaceA") 64 f.NoError(err, "could not create namespace") 65 tc.namespaceIDs = append(tc.namespaceIDs, "NamespaceA") 66 67 // Register the jobs, capturing their IDs. 68 jobDefault1 := tc.run(f, "scalingpolicies/input/namespace_default_1.nomad", "default", []string{"running"}) 69 jobDefault2 := tc.run(f, "scalingpolicies/input/namespace_default_1.nomad", "default", []string{"running"}) 70 jobA := tc.run(f, "scalingpolicies/input/namespace_a_1.nomad", "NamespaceA", []string{"running"}) 71 72 // Setup some reused query options. 73 defaultQueryOpts := api.QueryOptions{Namespace: "default"} 74 aQueryOpts := api.QueryOptions{Namespace: "NamespaceA"} 75 76 // Perform initial listings to check each namespace has the correct number 77 // of policies. 78 defaultPolicyList, _, err := tc.Nomad().Scaling().ListPolicies(&defaultQueryOpts) 79 require.NoError(t, err) 80 require.Len(t, defaultPolicyList, 2) 81 82 policyListA, _, err := tc.Nomad().Scaling().ListPolicies(&aQueryOpts) 83 require.NoError(t, err) 84 require.Len(t, policyListA, 1) 85 86 // Deregister a job from the default namespace and then check all the 87 // response objects. 88 _, _, err = tc.Nomad().Jobs().Deregister(jobDefault1, true, &api.WriteOptions{Namespace: "default"}) 89 require.NoError(t, err) 90 91 for i, namespacedJob := range tc.namespacedJobIDs { 92 if namespacedJob[1] == jobDefault1 && namespacedJob[0] == "default" { 93 tc.namespacedJobIDs = append(tc.namespacedJobIDs[:i], tc.namespacedJobIDs[i+1:]...) 94 break 95 } 96 } 97 98 defaultPolicyList, _, err = tc.Nomad().Scaling().ListPolicies(&defaultQueryOpts) 99 require.NoError(t, err) 100 require.Len(t, defaultPolicyList, 1) 101 102 defaultPolicy := defaultPolicyList[0] 103 require.True(t, defaultPolicy.Enabled) 104 require.Equal(t, "horizontal", defaultPolicy.Type) 105 require.Equal(t, defaultPolicy.Target["Namespace"], "default") 106 require.Equal(t, defaultPolicy.Target["Job"], jobDefault2) 107 require.Equal(t, defaultPolicy.Target["Group"], "horizontally_scalable") 108 109 defaultPolicyInfo, _, err := tc.Nomad().Scaling().GetPolicy(defaultPolicy.ID, &defaultQueryOpts) 110 require.NoError(t, err) 111 require.Equal(t, *defaultPolicyInfo.Min, int64(1)) 112 require.Equal(t, *defaultPolicyInfo.Max, int64(10)) 113 require.Equal(t, defaultPolicyInfo.Policy["cooldown"], "13m") 114 require.Equal(t, defaultPolicyInfo.Target["Namespace"], "default") 115 require.Equal(t, defaultPolicyInfo.Target["Job"], jobDefault2) 116 require.Equal(t, defaultPolicyInfo.Target["Group"], "horizontally_scalable") 117 118 // Check response objects from the namespace with name "NamespaceA". 119 aPolicyList, _, err := tc.Nomad().Scaling().ListPolicies(&aQueryOpts) 120 require.NoError(t, err) 121 require.Len(t, aPolicyList, 1) 122 123 aPolicy := aPolicyList[0] 124 require.True(t, aPolicy.Enabled) 125 require.Equal(t, "horizontal", aPolicy.Type) 126 require.Equal(t, aPolicy.Target["Namespace"], "NamespaceA") 127 require.Equal(t, aPolicy.Target["Job"], jobA) 128 require.Equal(t, aPolicy.Target["Group"], "horizontally_scalable") 129 130 aPolicyInfo, _, err := tc.Nomad().Scaling().GetPolicy(aPolicy.ID, &aQueryOpts) 131 require.NoError(t, err) 132 require.Equal(t, *aPolicyInfo.Min, int64(1)) 133 require.Equal(t, *aPolicyInfo.Max, int64(10)) 134 require.Equal(t, aPolicyInfo.Policy["cooldown"], "13m") 135 require.Equal(t, aPolicyInfo.Target["Namespace"], "NamespaceA") 136 require.Equal(t, aPolicyInfo.Target["Job"], jobA) 137 require.Equal(t, aPolicyInfo.Target["Group"], "horizontally_scalable") 138 139 // List policies using the splat namespace operator. 140 splatPolicyList, _, err := tc.Nomad().Scaling().ListPolicies(&api.QueryOptions{Namespace: "*"}) 141 require.NoError(t, err) 142 require.Len(t, splatPolicyList, 2) 143 144 // Deregister the job from the "NamespaceA" namespace and then check the 145 // response objects. 146 _, _, err = tc.Nomad().Jobs().Deregister(jobA, true, &api.WriteOptions{Namespace: "NamespaceA"}) 147 require.NoError(t, err) 148 149 for i, namespacedJob := range tc.namespacedJobIDs { 150 if namespacedJob[1] == jobA && namespacedJob[0] == "NamespaceA" { 151 tc.namespacedJobIDs = append(tc.namespacedJobIDs[:i], tc.namespacedJobIDs[i+1:]...) 152 break 153 } 154 } 155 156 aPolicyList, _, err = tc.Nomad().Scaling().ListPolicies(&aQueryOpts) 157 require.NoError(t, err) 158 require.Len(t, aPolicyList, 0) 159 160 // Update the running job scaling policy and ensure the changes are 161 // reflected. 162 err = e2eutil.Register(jobDefault2, "scalingpolicies/input/namespace_default_2.nomad") 163 require.NoError(t, err) 164 165 defaultPolicyList, _, err = tc.Nomad().Scaling().ListPolicies(&defaultQueryOpts) 166 require.NoError(t, err) 167 require.Len(t, defaultPolicyList, 1) 168 169 defaultPolicyInfo, _, err = tc.Nomad().Scaling().GetPolicy(defaultPolicyList[0].ID, &defaultQueryOpts) 170 require.NoError(t, err) 171 require.Equal(t, *defaultPolicyInfo.Min, int64(1)) 172 require.Equal(t, *defaultPolicyInfo.Max, int64(11)) 173 require.Equal(t, defaultPolicyInfo.Policy["cooldown"], "14m") 174 require.Equal(t, defaultPolicyInfo.Target["Namespace"], "default") 175 require.Equal(t, defaultPolicyInfo.Target["Job"], jobDefault2) 176 require.Equal(t, defaultPolicyInfo.Target["Group"], "horizontally_scalable") 177 178 } 179 180 // run is a helper which runs a job within a namespace, providing the caller 181 // with the generated jobID. 182 func (tc *ScalingPolicyE2ETest) run(f *framework.F, jobSpec, ns string, expected []string) string { 183 jobID := "test-scaling-policy-" + uuid.Generate()[0:8] 184 f.NoError(e2eutil.Register(jobID, jobSpec)) 185 tc.namespacedJobIDs = append(tc.namespacedJobIDs, [2]string{ns, jobID}) 186 f.NoError(e2eutil.WaitForAllocStatusExpected(jobID, ns, expected), "job should be running") 187 return jobID 188 }