github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/state/state_store_acl_binding_rule_test.go (about) 1 package state 2 3 import ( 4 "testing" 5 6 "github.com/hashicorp/go-memdb" 7 "github.com/hashicorp/nomad/ci" 8 "github.com/hashicorp/nomad/helper/uuid" 9 "github.com/hashicorp/nomad/nomad/mock" 10 "github.com/hashicorp/nomad/nomad/structs" 11 "github.com/shoenig/test/must" 12 ) 13 14 func TestStateStore_UpsertACLBindingRules(t *testing.T) { 15 ci.Parallel(t) 16 testState := testStateStore(t) 17 18 // Generate a mocked ACL binding rule for testing and attempt to upsert 19 // this straight into state. It should fail because the auth method does 20 // not exist. 21 mockedACLBindingRules := []*structs.ACLBindingRule{mock.ACLBindingRule()} 22 err := testState.UpsertACLBindingRules(10, mockedACLBindingRules, false) 23 must.EqError(t, err, "ACL binding rule insert failed: ACL auth method not found") 24 25 // Create an auth method and ensure the binding rule is updated, so it is 26 // related to it. 27 authMethod := mock.ACLAuthMethod() 28 mockedACLBindingRules[0].AuthMethod = authMethod.Name 29 30 must.NoError(t, testState.UpsertACLAuthMethods(10, []*structs.ACLAuthMethod{authMethod})) 31 must.NoError(t, testState.UpsertACLBindingRules(20, mockedACLBindingRules, false)) 32 33 // Check that the index for the table was modified as expected. 34 initialIndex, err := testState.Index(TableACLBindingRules) 35 must.NoError(t, err) 36 must.Eq(t, 20, initialIndex) 37 38 // List all the ACL binding rules in the table, so we can perform a number 39 // of tests on the return array. 40 ws := memdb.NewWatchSet() 41 iter, err := testState.GetACLBindingRules(ws) 42 must.NoError(t, err) 43 44 // Count how many table entries we have, to ensure it is the expected 45 // number. 46 var count int 47 48 for raw := iter.Next(); raw != nil; raw = iter.Next() { 49 count++ 50 51 // Ensure the create and modify indexes are populated correctly. 52 aclRole := raw.(*structs.ACLBindingRule) 53 must.Eq(t, 20, aclRole.CreateIndex) 54 must.Eq(t, 20, aclRole.ModifyIndex) 55 } 56 must.Eq(t, 1, count) 57 58 // Try writing the same ACL binding rule to state which should not result 59 // in an update to the table index. 60 must.NoError(t, testState.UpsertACLBindingRules(20, mockedACLBindingRules, false)) 61 reInsertActualIndex, err := testState.Index(TableACLBindingRules) 62 must.NoError(t, err) 63 must.Eq(t, 20, reInsertActualIndex) 64 65 // Make a change to the binding rule and ensure this update is accepted and 66 // the table index is updated. 67 updatedMockedACLBindingRule := mockedACLBindingRules[0].Copy() 68 updatedMockedACLBindingRule.BindType = "role-name" 69 updatedMockedACLBindingRule.SetHash() 70 must.NoError(t, testState.UpsertACLBindingRules( 71 30, []*structs.ACLBindingRule{updatedMockedACLBindingRule}, false)) 72 73 // Check that the index for the table was modified as expected. 74 updatedIndex, err := testState.Index(TableACLBindingRules) 75 must.NoError(t, err) 76 must.Eq(t, 30, updatedIndex) 77 78 // List the ACL roles in state. 79 iter, err = testState.GetACLBindingRules(ws) 80 must.NoError(t, err) 81 82 // Count how many table entries we have, to ensure it is the expected 83 // number. 84 count = 0 85 86 for raw := iter.Next(); raw != nil; raw = iter.Next() { 87 count++ 88 89 // Ensure the create and modify indexes are populated correctly. 90 aclRole := raw.(*structs.ACLBindingRule) 91 must.Eq(t, 20, aclRole.CreateIndex) 92 must.Eq(t, 30, aclRole.ModifyIndex) 93 } 94 must.Eq(t, 1, count) 95 96 // Now try inserting an ACL binding rule using the missing auth methods 97 // argument to simulate replication. 98 replicatedACLBindingRule := []*structs.ACLBindingRule{mock.ACLBindingRule()} 99 must.NoError(t, testState.UpsertACLBindingRules(40, replicatedACLBindingRule, true)) 100 101 replicatedACLBindingRuleResp, err := testState.GetACLBindingRule(ws, replicatedACLBindingRule[0].ID) 102 must.NoError(t, err) 103 must.Eq(t, replicatedACLBindingRule[0].Hash, replicatedACLBindingRuleResp.Hash) 104 } 105 106 func TestStateStore_DeleteACLBindingRules(t *testing.T) { 107 ci.Parallel(t) 108 testState := testStateStore(t) 109 110 // Generate a some mocked ACL binding rules for testing and upsert these 111 // straight into state. 112 mockedACLBindingRoles := []*structs.ACLBindingRule{mock.ACLBindingRule(), mock.ACLBindingRule()} 113 must.NoError(t, testState.UpsertACLBindingRules(10, mockedACLBindingRoles, true)) 114 115 // Try and delete a binding rule using an ID that doesn't exist. This 116 // should return an error and not change the index for the table. 117 err := testState.DeleteACLBindingRules(20, []string{uuid.Generate()}) 118 must.EqError(t, err, "ACL binding rule not found") 119 120 tableIndex, err := testState.Index(TableACLBindingRules) 121 must.NoError(t, err) 122 must.Eq(t, 10, tableIndex) 123 124 // Delete one of the previously upserted ACL binding rules. This should 125 // succeed and modify the table index. 126 must.NoError(t, testState.DeleteACLBindingRules(20, []string{mockedACLBindingRoles[0].ID})) 127 128 tableIndex, err = testState.Index(TableACLBindingRules) 129 must.NoError(t, err) 130 must.Eq(t, 20, tableIndex) 131 132 // List the ACL binding rules and ensure we now only have one present and 133 // that it is the one we expect. 134 ws := memdb.NewWatchSet() 135 iter, err := testState.GetACLBindingRules(ws) 136 must.NoError(t, err) 137 138 var aclBindingRules []*structs.ACLBindingRule 139 140 for raw := iter.Next(); raw != nil; raw = iter.Next() { 141 aclBindingRules = append(aclBindingRules, raw.(*structs.ACLBindingRule)) 142 } 143 144 must.Len(t, 1, aclBindingRules) 145 must.True(t, aclBindingRules[0].Equal(mockedACLBindingRoles[1])) 146 147 // Delete the final remaining ACL binding rule. This should succeed and 148 // modify the table index. 149 must.NoError(t, testState.DeleteACLBindingRules(30, []string{mockedACLBindingRoles[1].ID})) 150 151 tableIndex, err = testState.Index(TableACLBindingRules) 152 must.NoError(t, err) 153 must.Eq(t, 30, tableIndex) 154 155 // List the ACL binding rules and ensure we have zero entries. 156 iter, err = testState.GetACLBindingRules(ws) 157 must.NoError(t, err) 158 159 aclBindingRules = make([]*structs.ACLBindingRule, 0) 160 161 for raw := iter.Next(); raw != nil; raw = iter.Next() { 162 aclBindingRules = append(aclBindingRules, raw.(*structs.ACLBindingRule)) 163 } 164 must.Len(t, 0, aclBindingRules) 165 } 166 167 func TestStateStore_GetACLBindingRules(t *testing.T) { 168 ci.Parallel(t) 169 testState := testStateStore(t) 170 171 // Generate a some mocked ACL binding rules for testing and upsert these 172 // straight into state. 173 mockedACLBindingRoles := []*structs.ACLBindingRule{mock.ACLBindingRule(), mock.ACLBindingRule()} 174 must.NoError(t, testState.UpsertACLBindingRules(10, mockedACLBindingRoles, true)) 175 176 // List the ACL binding rules and ensure they are exactly as we expect. 177 ws := memdb.NewWatchSet() 178 iter, err := testState.GetACLBindingRules(ws) 179 must.NoError(t, err) 180 181 var aclBindingRules []*structs.ACLBindingRule 182 183 for raw := iter.Next(); raw != nil; raw = iter.Next() { 184 aclBindingRules = append(aclBindingRules, raw.(*structs.ACLBindingRule)) 185 } 186 187 expected := mockedACLBindingRoles 188 for i := range expected { 189 expected[i].CreateIndex = 10 190 expected[i].ModifyIndex = 10 191 } 192 193 must.Eq(t, aclBindingRules, expected) 194 } 195 196 func TestStateStore_GetACLBindingRule(t *testing.T) { 197 ci.Parallel(t) 198 testState := testStateStore(t) 199 200 // Generate a some mocked ACL binding rules for testing and upsert these 201 // straight into state. 202 mockedACLBindingRoles := []*structs.ACLBindingRule{mock.ACLBindingRule(), mock.ACLBindingRule()} 203 must.NoError(t, testState.UpsertACLBindingRules(10, mockedACLBindingRoles, true)) 204 205 ws := memdb.NewWatchSet() 206 207 // Try reading an ACL binding rule that does not exist. 208 aclBindingRule, err := testState.GetACLBindingRule(ws, uuid.Generate()) 209 must.NoError(t, err) 210 must.Nil(t, aclBindingRule) 211 212 // Read the two ACL binding rules that we should find. 213 aclBindingRule, err = testState.GetACLBindingRule(ws, mockedACLBindingRoles[0].ID) 214 must.NoError(t, err) 215 must.Eq(t, mockedACLBindingRoles[0], aclBindingRule) 216 217 aclBindingRule, err = testState.GetACLBindingRule(ws, mockedACLBindingRoles[1].ID) 218 must.NoError(t, err) 219 must.Eq(t, mockedACLBindingRoles[1], aclBindingRule) 220 } 221 222 func TestStateStore_GetACLBindingRulesByAuthMethod(t *testing.T) { 223 ci.Parallel(t) 224 testState := testStateStore(t) 225 226 // Generate a some mocked ACL binding rules for testing and upsert these 227 // straight into state. 228 mockedACLBindingRoles := []*structs.ACLBindingRule{mock.ACLBindingRule(), mock.ACLBindingRule()} 229 must.NoError(t, testState.UpsertACLBindingRules(10, mockedACLBindingRoles, true)) 230 231 ws := memdb.NewWatchSet() 232 233 // Lookup ACL binding rules using an auth method that is not referenced. We 234 // should not get any results within the iterator. 235 iter, err := testState.GetACLBindingRulesByAuthMethod(ws, "not-an-auth-method") 236 must.NoError(t, err) 237 238 var aclBindingRules []*structs.ACLBindingRule 239 240 for raw := iter.Next(); raw != nil; raw = iter.Next() { 241 aclBindingRules = append(aclBindingRules, raw.(*structs.ACLBindingRule)) 242 } 243 must.Len(t, 0, aclBindingRules) 244 245 // Lookup ACL binding rules using an auth method that is referenced by both 246 // mocked rules. Ensure the results are as expected. 247 iter, err = testState.GetACLBindingRulesByAuthMethod(ws, mockedACLBindingRoles[0].AuthMethod) 248 must.NoError(t, err) 249 250 aclBindingRules = make([]*structs.ACLBindingRule, 0) 251 252 for raw := iter.Next(); raw != nil; raw = iter.Next() { 253 aclBindingRules = append(aclBindingRules, raw.(*structs.ACLBindingRule)) 254 } 255 must.Len(t, 2, aclBindingRules) 256 }