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