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  }