diff --git a/acl/acl_oss.go b/acl/acl_oss.go index 667b300d38..3da5d7b29c 100644 --- a/acl/acl_oss.go +++ b/acl/acl_oss.go @@ -4,3 +4,5 @@ package acl // EnterpriseACLConfig stub type EnterpriseACLConfig struct{} + +func (_ *EnterpriseACLConfig) Close() {} diff --git a/agent/acl_test.go b/agent/acl_test.go index ae46d8e905..5e60d4d5cc 100644 --- a/agent/acl_test.go +++ b/agent/acl_test.go @@ -4,7 +4,6 @@ import ( "fmt" "io" "log" - "os" "testing" "time" @@ -16,6 +15,7 @@ import ( "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/logger" + "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/types" "github.com/hashicorp/serf/serf" @@ -55,28 +55,27 @@ type TestACLAgent struct { // NewTestACLAGent does just enough so that all the code within agent/acl.go can work // Basically it needs a local state for some of the vet* functions, a logger and a delegate. // The key is that we are the delegate so we can control the ResolveToken responses -func NewTestACLAgent(name string, hcl string, resolveFn func(string) (acl.Authorizer, error)) *TestACLAgent { +func NewTestACLAgent(t *testing.T, name string, hcl string, resolveFn func(string) (acl.Authorizer, error)) *TestACLAgent { a := &TestACLAgent{Name: name, HCL: hcl, resolveTokenFn: resolveFn} hclDataDir := `data_dir = "acl-agent"` - a.Config = TestConfig( + logOutput := testutil.TestWriter(t) + logger := log.New(logOutput, a.Name+" - ", log.LstdFlags|log.Lmicroseconds) + + a.Config = TestConfig(logger, config.Source{Name: a.Name, Format: "hcl", Data: a.HCL}, config.Source{Name: a.Name + ".data_dir", Format: "hcl", Data: hclDataDir}, ) - agent, err := New(a.Config, nil) + agent, err := New(a.Config, logger) if err != nil { panic(fmt.Sprintf("Error creating agent: %v", err)) } a.Agent = agent - logOutput := a.LogOutput - if logOutput == nil { - logOutput = os.Stderr - } agent.LogOutput = logOutput agent.LogWriter = a.LogWriter - agent.logger = log.New(logOutput, a.Name+" - ", log.LstdFlags|log.Lmicroseconds) + agent.logger = logger agent.MemSink = metrics.NewInmemSink(1*time.Second, time.Minute) a.Agent.delegate = a @@ -156,7 +155,7 @@ func TestACL_Version8(t *testing.T) { return nil, fmt.Errorf("should not have called delegate.ResolveToken") } - a := NewTestACLAgent(t.Name(), TestACLConfig()+` + a := NewTestACLAgent(t, t.Name(), TestACLConfig()+` acl_enforce_version_8 = false `, resolveFn) @@ -171,7 +170,7 @@ func TestACL_Version8(t *testing.T) { called = true return nil, acl.ErrNotFound } - a := NewTestACLAgent(t.Name(), TestACLConfig()+` + a := NewTestACLAgent(t, t.Name(), TestACLConfig()+` acl_enforce_version_8 = true `, resolveFn) @@ -189,7 +188,7 @@ func TestACL_AgentMasterToken(t *testing.T) { return nil, fmt.Errorf("should not have called delegate.ResolveToken") } - a := NewTestACLAgent(t.Name(), TestACLConfig(), resolveFn) + a := NewTestACLAgent(t, t.Name(), TestACLConfig(), resolveFn) a.loadTokens(a.config) authz, err := a.resolveToken("towel") require.NotNil(t, authz) @@ -209,7 +208,7 @@ func TestACL_RootAuthorizersDenied(t *testing.T) { return nil, fmt.Errorf("should not have called delegate.ResolveToken") } - a := NewTestACLAgent(t.Name(), TestACLConfig(), resolveFn) + a := NewTestACLAgent(t, t.Name(), TestACLConfig(), resolveFn) authz, err := a.resolveToken("deny") require.Nil(t, authz) require.Error(t, err) @@ -224,8 +223,8 @@ func TestACL_RootAuthorizersDenied(t *testing.T) { require.True(t, acl.IsErrRootDenied(err)) } -func authzFromPolicy(policy *acl.Policy) (acl.Authorizer, error) { - return acl.NewPolicyAuthorizerWithDefaults(acl.DenyAll(), []*acl.Policy{policy}, nil) +func authzFromPolicy(policy *acl.Policy, cfg *acl.EnterpriseACLConfig) (acl.Authorizer, error) { + return acl.NewPolicyAuthorizerWithDefaults(acl.DenyAll(), []*acl.Policy{policy}, cfg) } // catalogPolicy supplies some standard policies to help with testing the @@ -240,7 +239,7 @@ func catalogPolicy(token string) (acl.Authorizer, error) { &acl.NodeRule{Name: "Node", Policy: "read"}, }, }, - }) + }, nil) case "node-rw": return authzFromPolicy(&acl.Policy{ PolicyRules: acl.PolicyRules{ @@ -248,7 +247,7 @@ func catalogPolicy(token string) (acl.Authorizer, error) { &acl.NodeRule{Name: "Node", Policy: "write"}, }, }, - }) + }, nil) case "service-ro": return authzFromPolicy(&acl.Policy{ PolicyRules: acl.PolicyRules{ @@ -256,7 +255,7 @@ func catalogPolicy(token string) (acl.Authorizer, error) { &acl.ServiceRule{Name: "service", Policy: "read"}, }, }, - }) + }, nil) case "service-rw": return authzFromPolicy(&acl.Policy{ PolicyRules: acl.PolicyRules{ @@ -264,7 +263,7 @@ func catalogPolicy(token string) (acl.Authorizer, error) { &acl.ServiceRule{Name: "service", Policy: "write"}, }, }, - }) + }, nil) case "other-rw": return authzFromPolicy(&acl.Policy{ PolicyRules: acl.PolicyRules{ @@ -272,7 +271,7 @@ func catalogPolicy(token string) (acl.Authorizer, error) { &acl.ServiceRule{Name: "other", Policy: "write"}, }, }, - }) + }, nil) default: return nil, fmt.Errorf("unknown token %q", token) } @@ -280,7 +279,7 @@ func catalogPolicy(token string) (acl.Authorizer, error) { func TestACL_vetServiceRegister(t *testing.T) { t.Parallel() - a := NewTestACLAgent(t.Name(), TestACLConfig(), catalogPolicy) + a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) // Register a new service, with permission. err := a.vetServiceRegister("service-rw", &structs.NodeService{ @@ -311,7 +310,7 @@ func TestACL_vetServiceRegister(t *testing.T) { func TestACL_vetServiceUpdate(t *testing.T) { t.Parallel() - a := NewTestACLAgent(t.Name(), TestACLConfig(), catalogPolicy) + a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) // Update a service that doesn't exist. err := a.vetServiceUpdate("service-rw", "my-service") @@ -334,7 +333,7 @@ func TestACL_vetServiceUpdate(t *testing.T) { func TestACL_vetCheckRegister(t *testing.T) { t.Parallel() - a := NewTestACLAgent(t.Name(), TestACLConfig(), catalogPolicy) + a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) // Register a new service check with write privs. err := a.vetCheckRegister("service-rw", &structs.HealthCheck{ @@ -400,7 +399,7 @@ func TestACL_vetCheckRegister(t *testing.T) { func TestACL_vetCheckUpdate(t *testing.T) { t.Parallel() - a := NewTestACLAgent(t.Name(), TestACLConfig(), catalogPolicy) + a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) // Update a check that doesn't exist. err := a.vetCheckUpdate("node-rw", "my-check") @@ -440,7 +439,7 @@ func TestACL_vetCheckUpdate(t *testing.T) { func TestACL_filterMembers(t *testing.T) { t.Parallel() - a := NewTestACLAgent(t.Name(), TestACLConfig(), catalogPolicy) + a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) var members []serf.Member require.NoError(t, a.filterMembers("node-ro", &members)) @@ -459,7 +458,7 @@ func TestACL_filterMembers(t *testing.T) { func TestACL_filterServices(t *testing.T) { t.Parallel() - a := NewTestACLAgent(t.Name(), TestACLConfig(), catalogPolicy) + a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) services := make(map[string]*structs.NodeService) require.NoError(t, a.filterServices("node-ro", &services)) @@ -473,7 +472,7 @@ func TestACL_filterServices(t *testing.T) { func TestACL_filterChecks(t *testing.T) { t.Parallel() - a := NewTestACLAgent(t.Name(), TestACLConfig(), catalogPolicy) + a := NewTestACLAgent(t, t.Name(), TestACLConfig(), catalogPolicy) checks := make(map[types.CheckID]*structs.HealthCheck) require.NoError(t, a.filterChecks("node-ro", &checks)) diff --git a/agent/agent_endpoint_test.go b/agent/agent_endpoint_test.go index ef19f0970e..a38efbe309 100644 --- a/agent/agent_endpoint_test.go +++ b/agent/agent_endpoint_test.go @@ -30,6 +30,7 @@ import ( "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/logger" + "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/consul/testrpc" "github.com/hashicorp/consul/types" @@ -1245,7 +1246,7 @@ func TestAgent_Reload(t *testing.T) { t.Fatal("missing redis service") } - cfg2 := TestConfig(config.Source{ + cfg2 := TestConfig(testutil.TestLogger(t), config.Source{ Name: "reload", Format: "hcl", Data: ` diff --git a/agent/agent_test.go b/agent/agent_test.go index 1f7e2626ba..04893c4530 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -3456,7 +3456,7 @@ func TestAgent_ReloadConfigOutgoingRPCConfig(t *testing.T) { key_file = "../test/key/ourdomain.key" verify_server_hostname = true ` - c := TestConfig(config.Source{Name: t.Name(), Format: "hcl", Data: hcl}) + c := TestConfig(testutil.TestLogger(t), config.Source{Name: t.Name(), Format: "hcl", Data: hcl}) require.NoError(t, a.ReloadConfig(c)) tlsConf = a.tlsConfigurator.OutgoingRPCConfig() require.False(t, tlsConf.InsecureSkipVerify) @@ -3495,7 +3495,7 @@ func TestAgent_ReloadConfigIncomingRPCConfig(t *testing.T) { key_file = "../test/key/ourdomain.key" verify_server_hostname = true ` - c := TestConfig(config.Source{Name: t.Name(), Format: "hcl", Data: hcl}) + c := TestConfig(testutil.TestLogger(t), config.Source{Name: t.Name(), Format: "hcl", Data: hcl}) require.NoError(t, a.ReloadConfig(c)) tlsConf, err = tlsConf.GetConfigForClient(nil) require.NoError(t, err) @@ -3524,7 +3524,7 @@ func TestAgent_ReloadConfigTLSConfigFailure(t *testing.T) { data_dir = "` + dataDir + `" verify_incoming = true ` - c := TestConfig(config.Source{Name: t.Name(), Format: "hcl", Data: hcl}) + c := TestConfig(testutil.TestLogger(t), config.Source{Name: t.Name(), Format: "hcl", Data: hcl}) require.Error(t, a.ReloadConfig(c)) tlsConf, err := tlsConf.GetConfigForClient(nil) require.NoError(t, err) diff --git a/agent/consul/acl.go b/agent/consul/acl.go index a9b52981c6..43ae8524b1 100644 --- a/agent/consul/acl.go +++ b/agent/consul/acl.go @@ -223,6 +223,10 @@ func NewACLResolver(config *ACLResolverConfig) (*ACLResolver, error) { }, nil } +func (r *ACLResolver) Close() { + r.entConf.Close() +} + func (r *ACLResolver) fetchAndCacheTokenLegacy(token string, cached *structs.AuthorizerCacheEntry) (acl.Authorizer, error) { req := structs.ACLPolicyResolveLegacyRequest{ Datacenter: r.delegate.ACLDatacenter(true), @@ -1205,8 +1209,11 @@ func (f *aclFilter) filterSessions(sessions *structs.Sessions) { s := *sessions for i := 0; i < len(s); i++ { session := s[i] - // TODO (namespaces) update to call with an actual ent authz context once sessions supports ns - if f.allowSession(session.Node, nil) { + + var entCtx acl.EnterpriseAuthorizerContext + session.FillAuthzContext(&entCtx) + + if f.allowSession(session.Node, &entCtx) { continue } f.logger.Printf("[DEBUG] consul: dropping session %q from result due to ACLs", session.ID) diff --git a/agent/consul/acl_endpoint.go b/agent/consul/acl_endpoint.go index 1ca6cf7282..77c76ee9b7 100644 --- a/agent/consul/acl_endpoint.go +++ b/agent/consul/acl_endpoint.go @@ -161,13 +161,12 @@ func (a *ACL) BootstrapTokens(args *structs.DCSpecificRequest, reply *structs.AC CreateTime: time.Now(), Local: false, // DEPRECATED (ACL-Legacy-Compat) - This is used so that the bootstrap token is still visible via the v1 acl APIs - Type: structs.ACLTokenTypeManagement, + Type: structs.ACLTokenTypeManagement, + EnterpriseMeta: *structs.DefaultEnterpriseMeta(), }, ResetIndex: specifiedIndex, } - req.Token.EnterpriseMeta.InitDefault() - req.Token.SetHash(true) resp, err := a.srv.raftApply(structs.ACLBootstrapRequestType, &req) diff --git a/agent/consul/acl_replication_test.go b/agent/consul/acl_replication_test.go index f2b8ed91c0..6ff55b8f83 100644 --- a/agent/consul/acl_replication_test.go +++ b/agent/consul/acl_replication_test.go @@ -758,7 +758,7 @@ func TestACLReplication_AllTypes(t *testing.T) { c.ACLsEnabled = true c.ACLTokenReplication = true c.ACLReplicationRate = 100 - c.ACLReplicationBurst = 100 + c.ACLReplicationBurst = 25 c.ACLReplicationApplyLimit = 1000000 }) s2.tokens.UpdateReplicationToken("root", tokenStore.TokenSourceConfig) diff --git a/agent/consul/client.go b/agent/consul/client.go index 3e84be9cca..3b90acce8c 100644 --- a/agent/consul/client.go +++ b/agent/consul/client.go @@ -214,6 +214,9 @@ func (c *Client) Shutdown() error { // Close the connection pool c.connPool.Shutdown() + + c.acls.Close() + return nil } diff --git a/agent/consul/leader.go b/agent/consul/leader.go index 5a30a49474..23c91d78e9 100644 --- a/agent/consul/leader.go +++ b/agent/consul/leader.go @@ -505,18 +505,18 @@ func (s *Server) initializeACLs(upgrade bool) error { } if policy == nil || policy.Rules != structs.ACLPolicyGlobalManagement { newPolicy := structs.ACLPolicy{ - ID: structs.ACLPolicyGlobalManagementID, - Name: "global-management", - Description: "Builtin Policy that grants unlimited access", - Rules: structs.ACLPolicyGlobalManagement, - Syntax: acl.SyntaxCurrent, + ID: structs.ACLPolicyGlobalManagementID, + Name: "global-management", + Description: "Builtin Policy that grants unlimited access", + Rules: structs.ACLPolicyGlobalManagement, + Syntax: acl.SyntaxCurrent, + EnterpriseMeta: *structs.DefaultEnterpriseMeta(), } if policy != nil { newPolicy.Name = policy.Name newPolicy.Description = policy.Description } - newPolicy.EnterpriseMeta.InitDefault() newPolicy.SetHash(true) req := structs.ACLPolicyBatchSetRequest{ @@ -560,10 +560,10 @@ func (s *Server) initializeACLs(upgrade bool) error { Local: false, // DEPRECATED (ACL-Legacy-Compat) - only needed for compatibility - Type: structs.ACLTokenTypeManagement, + Type: structs.ACLTokenTypeManagement, + EnterpriseMeta: *structs.DefaultEnterpriseMeta(), } - token.EnterpriseMeta.InitDefault() token.SetHash(true) done := false @@ -616,13 +616,13 @@ func (s *Server) initializeACLs(upgrade bool) error { // the token upgrade routine will take care of upgrading the token if a legacy version exists if legacyToken == nil { token = &structs.ACLToken{ - AccessorID: structs.ACLTokenAnonymousID, - SecretID: anonymousToken, - Description: "Anonymous Token", - CreateTime: time.Now(), + AccessorID: structs.ACLTokenAnonymousID, + SecretID: anonymousToken, + Description: "Anonymous Token", + CreateTime: time.Now(), + EnterpriseMeta: *structs.DefaultEnterpriseMeta(), } token.SetHash(true) - token.EnterpriseMeta.InitDefault() req := structs.ACLTokenBatchSetRequest{ Tokens: structs.ACLTokens{token}, diff --git a/agent/consul/server.go b/agent/consul/server.go index 1b6f1087c0..659fe9117c 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -847,6 +847,8 @@ func (s *Server) Shutdown() error { // Close the connection pool s.connPool.Shutdown() + s.acls.Close() + if s.config.NotifyShutdown != nil { s.config.NotifyShutdown() } diff --git a/agent/consul/state/acl.go b/agent/consul/state/acl.go index a452b9975c..fdef4d7634 100644 --- a/agent/consul/state/acl.go +++ b/agent/consul/state/acl.go @@ -230,7 +230,7 @@ func (s *Snapshot) ACLTokens() (memdb.ResultIterator, error) { // ACLToken is used when restoring from a snapshot. For general inserts, use ACL. func (s *Restore) ACLToken(token *structs.ACLToken) error { - return s.store.aclTokenInsert(s.tx, token, false) + return s.store.aclTokenInsert(s.tx, token) } // ACLPolicies is used when saving a snapshot @@ -243,7 +243,7 @@ func (s *Snapshot) ACLPolicies() (memdb.ResultIterator, error) { } func (s *Restore) ACLPolicy(policy *structs.ACLPolicy) error { - return s.store.aclPolicyInsert(s.tx, policy, false) + return s.store.aclPolicyInsert(s.tx, policy) } // ACLRoles is used when saving a snapshot @@ -256,7 +256,7 @@ func (s *Snapshot) ACLRoles() (memdb.ResultIterator, error) { } func (s *Restore) ACLRole(role *structs.ACLRole) error { - return s.store.aclRoleInsert(s.tx, role, false) + return s.store.aclRoleInsert(s.tx, role) } // ACLBindingRules is used when saving a snapshot @@ -269,7 +269,7 @@ func (s *Snapshot) ACLBindingRules() (memdb.ResultIterator, error) { } func (s *Restore) ACLBindingRule(rule *structs.ACLBindingRule) error { - return s.store.aclBindingRuleInsert(s.tx, rule, false) + return s.store.aclBindingRuleInsert(s.tx, rule) } // ACLAuthMethods is used when saving a snapshot @@ -282,7 +282,7 @@ func (s *Snapshot) ACLAuthMethods() (memdb.ResultIterator, error) { } func (s *Restore) ACLAuthMethod(method *structs.ACLAuthMethod) error { - return s.store.aclAuthMethodInsert(s.tx, method, false) + return s.store.aclAuthMethodInsert(s.tx, method) } // ACLBootstrap is used to perform a one-time ACL bootstrap operation on a @@ -765,7 +765,7 @@ func (s *Store) aclTokenSetTxn(tx *memdb.Txn, idx uint64, token *structs.ACLToke token.ModifyIndex = idx } - return s.aclTokenInsert(tx, token, true) + return s.aclTokenInsert(tx, token) } // ACLTokenGetBySecret is used to look up an existing ACL token by its SecretID. @@ -1163,7 +1163,7 @@ func (s *Store) aclPolicySetTxn(tx *memdb.Txn, idx uint64, policy *structs.ACLPo } // Insert the ACL - return s.aclPolicyInsert(tx, policy, true) + return s.aclPolicyInsert(tx, policy) } func (s *Store) ACLPolicyGetByID(ws memdb.WatchSet, id string, entMeta *structs.EnterpriseMeta) (uint64, *structs.ACLPolicy, error) { @@ -1379,7 +1379,7 @@ func (s *Store) aclRoleSetTxn(tx *memdb.Txn, idx uint64, role *structs.ACLRole, role.ModifyIndex = idx } - return s.aclRoleInsert(tx, role, true) + return s.aclRoleInsert(tx, role) } type aclRoleGetFn func(*memdb.Txn, string, *structs.EnterpriseMeta) (<-chan struct{}, interface{}, error) @@ -1588,7 +1588,7 @@ func (s *Store) aclBindingRuleSetTxn(tx *memdb.Txn, idx uint64, rule *structs.AC return fmt.Errorf("failed inserting acl binding rule: auth method not found") } - return s.aclBindingRuleInsert(tx, rule, true) + return s.aclBindingRuleInsert(tx, rule) } func (s *Store) ACLBindingRuleGetByID(ws memdb.WatchSet, id string, entMeta *structs.EnterpriseMeta) (uint64, *structs.ACLBindingRule, error) { @@ -1771,7 +1771,7 @@ func (s *Store) aclAuthMethodSetTxn(tx *memdb.Txn, idx uint64, method *structs.A method.ModifyIndex = idx } - return s.aclAuthMethodInsert(tx, method, true) + return s.aclAuthMethodInsert(tx, method) } func (s *Store) ACLAuthMethodGetByName(ws memdb.WatchSet, name string, entMeta *structs.EnterpriseMeta) (uint64, *structs.ACLAuthMethod, error) { diff --git a/agent/consul/state/acl_oss.go b/agent/consul/state/acl_oss.go index fef5ba6edc..bbf9ed6a85 100644 --- a/agent/consul/state/acl_oss.go +++ b/agent/consul/state/acl_oss.go @@ -206,15 +206,13 @@ func authMethodsTableSchema() *memdb.TableSchema { ///// ACL Policy Functions ///// /////////////////////////////////////////////////////////////////////////////// -func (s *Store) aclPolicyInsert(tx *memdb.Txn, policy *structs.ACLPolicy, updateIndexes bool) error { +func (s *Store) aclPolicyInsert(tx *memdb.Txn, policy *structs.ACLPolicy) error { if err := tx.Insert("acl-policies", policy); err != nil { return fmt.Errorf("failed inserting acl policy: %v", err) } - if updateIndexes { - if err := tx.Insert("index", &IndexEntry{"acl-policies", policy.ModifyIndex}); err != nil { - return fmt.Errorf("failed updating acl policies index: %v", err) - } + if err := indexUpdateMaxTxn(tx, policy.ModifyIndex, "acl-policies"); err != nil { + return fmt.Errorf("failed updating acl policies index: %v", err) } return nil @@ -239,7 +237,7 @@ func (s *Store) aclPolicyDeleteWithPolicy(tx *memdb.Txn, policy *structs.ACLPoli } // update the overall acl-policies index - if err := tx.Insert("index", &IndexEntry{"acl-policies", idx}); err != nil { + if err := indexUpdateMaxTxn(tx, idx, "acl-policies"); err != nil { return fmt.Errorf("failed updating acl policies index: %v", err) } return nil @@ -261,17 +259,15 @@ func (s *Store) ACLPolicyUpsertValidateEnterprise(*structs.ACLPolicy, *structs.A ///// ACL Token Functions ///// /////////////////////////////////////////////////////////////////////////////// -func (s *Store) aclTokenInsert(tx *memdb.Txn, token *structs.ACLToken, updateIndexes bool) error { +func (s *Store) aclTokenInsert(tx *memdb.Txn, token *structs.ACLToken) error { // insert the token into memdb if err := tx.Insert("acl-tokens", token); err != nil { return fmt.Errorf("failed inserting acl token: %v", err) } - if updateIndexes { - // update the overall acl-tokens index - if err := tx.Insert("index", &IndexEntry{"acl-tokens", token.ModifyIndex}); err != nil { - return fmt.Errorf("failed updating acl tokens index: %v", err) - } + // update the overall acl-tokens index + if err := indexUpdateMaxTxn(tx, token.ModifyIndex, "acl-tokens"); err != nil { + return fmt.Errorf("failed updating acl tokens index: %v", err) } return nil @@ -312,7 +308,7 @@ func (s *Store) aclTokenDeleteWithToken(tx *memdb.Txn, token *structs.ACLToken, } // update the overall acl-tokens index - if err := tx.Insert("index", &IndexEntry{"acl-tokens", idx}); err != nil { + if err := indexUpdateMaxTxn(tx, idx, "acl-tokens"); err != nil { return fmt.Errorf("failed updating acl tokens index: %v", err) } return nil @@ -334,17 +330,15 @@ func (s *Store) ACLTokenUpsertValidateEnterprise(token *structs.ACLToken, existi ///// ACL Role Functions ///// /////////////////////////////////////////////////////////////////////////////// -func (s *Store) aclRoleInsert(tx *memdb.Txn, role *structs.ACLRole, updateIndexes bool) error { +func (s *Store) aclRoleInsert(tx *memdb.Txn, role *structs.ACLRole) error { // insert the role into memdb if err := tx.Insert("acl-roles", role); err != nil { return fmt.Errorf("failed inserting acl role: %v", err) } - if updateIndexes { - // update the overall acl-roles index - if err := tx.Insert("index", &IndexEntry{"acl-roles", role.ModifyIndex}); err != nil { - return fmt.Errorf("failed updating acl roles index: %v", err) - } + // update the overall acl-roles index + if err := indexUpdateMaxTxn(tx, role.ModifyIndex, "acl-roles"); err != nil { + return fmt.Errorf("failed updating acl roles index: %v", err) } return nil } @@ -372,7 +366,7 @@ func (s *Store) aclRoleDeleteWithRole(tx *memdb.Txn, role *structs.ACLRole, idx } // update the overall acl-roles index - if err := tx.Insert("index", &IndexEntry{"acl-roles", idx}); err != nil { + if err := indexUpdateMaxTxn(tx, idx, "acl-roles"); err != nil { return fmt.Errorf("failed updating acl policies index: %v", err) } return nil @@ -394,17 +388,15 @@ func (s *Store) ACLRoleUpsertValidateEnterprise(role *structs.ACLRole, existing ///// ACL Binding Rule Functions ///// /////////////////////////////////////////////////////////////////////////////// -func (s *Store) aclBindingRuleInsert(tx *memdb.Txn, rule *structs.ACLBindingRule, updateIndexes bool) error { +func (s *Store) aclBindingRuleInsert(tx *memdb.Txn, rule *structs.ACLBindingRule) error { // insert the role into memdb if err := tx.Insert("acl-binding-rules", rule); err != nil { return fmt.Errorf("failed inserting acl role: %v", err) } - if updateIndexes { - // update the overall acl-binding-rules index - if err := tx.Insert("index", &IndexEntry{"acl-binding-rules", rule.ModifyIndex}); err != nil { - return fmt.Errorf("failed updating acl binding-rules index: %v", err) - } + // update the overall acl-binding-rules index + if err := indexUpdateMaxTxn(tx, rule.ModifyIndex, "acl-binding-rules"); err != nil { + return fmt.Errorf("failed updating acl binding-rules index: %v", err) } return nil @@ -429,7 +421,7 @@ func (s *Store) aclBindingRuleDeleteWithRule(tx *memdb.Txn, rule *structs.ACLBin } // update the overall acl-binding-rules index - if err := tx.Insert("index", &IndexEntry{"acl-binding-rules", idx}); err != nil { + if err := indexUpdateMaxTxn(tx, idx, "acl-binding-rules"); err != nil { return fmt.Errorf("failed updating acl binding rules index: %v", err) } return nil @@ -451,17 +443,15 @@ func (s *Store) ACLBindingRuleUpsertValidateEnterprise(rule *structs.ACLBindingR ///// ACL Auth Method Functions ///// /////////////////////////////////////////////////////////////////////////////// -func (s *Store) aclAuthMethodInsert(tx *memdb.Txn, method *structs.ACLAuthMethod, updateIndexes bool) error { +func (s *Store) aclAuthMethodInsert(tx *memdb.Txn, method *structs.ACLAuthMethod) error { // insert the role into memdb if err := tx.Insert("acl-auth-methods", method); err != nil { return fmt.Errorf("failed inserting acl role: %v", err) } - if updateIndexes { - // update the overall acl-auth-methods index - if err := tx.Insert("index", &IndexEntry{"acl-auth-methods", method.ModifyIndex}); err != nil { - return fmt.Errorf("failed updating acl auth methods index: %v", err) - } + // update the overall acl-auth-methods index + if err := indexUpdateMaxTxn(tx, method.ModifyIndex, "acl-auth-methods"); err != nil { + return fmt.Errorf("failed updating acl auth methods index: %v", err) } return nil @@ -482,7 +472,7 @@ func (s *Store) aclAuthMethodDeleteWithMethod(tx *memdb.Txn, method *structs.ACL } // update the overall acl-auth-methods index - if err := tx.Insert("index", &IndexEntry{"acl-auth-methods", idx}); err != nil { + if err := indexUpdateMaxTxn(tx, idx, "acl-auth-methods"); err != nil { return fmt.Errorf("failed updating acl auth methods index: %v", err) } return nil diff --git a/agent/http_oss.go b/agent/http_oss.go index cf1fc63226..40c637726d 100644 --- a/agent/http_oss.go +++ b/agent/http_oss.go @@ -20,6 +20,10 @@ func (s *HTTPServer) parseEntMeta(req *http.Request, entMeta *structs.Enterprise return nil } +func (s *HTTPServer) parseEntMetaNoWildcard(req *http.Request, _ *structs.EnterpriseMeta) error { + return s.parseEntMeta(req, nil) +} + func (s *HTTPServer) rewordUnknownEnterpriseFieldError(err error) error { if err == nil { return nil diff --git a/agent/structs/acl.go b/agent/structs/acl.go index 0d007d1494..fe8cb5c147 100644 --- a/agent/structs/acl.go +++ b/agent/structs/acl.go @@ -452,7 +452,7 @@ func (t *ACLToken) SetHash(force bool) []byte { srvid.AddToHash(hash) } - t.EnterpriseMeta.addToHash(hash) + t.EnterpriseMeta.addToHash(hash, false) // Finalize the hash hashVal := hash.Sum(nil) @@ -645,7 +645,7 @@ func (p *ACLPolicy) SetHash(force bool) []byte { hash.Write([]byte(dc)) } - p.EnterpriseMeta.addToHash(hash) + p.EnterpriseMeta.addToHash(hash, false) // Finalize the hash hashVal := hash.Sum(nil) @@ -879,7 +879,7 @@ func (r *ACLRole) SetHash(force bool) []byte { srvid.AddToHash(hash) } - r.EnterpriseMeta.addToHash(hash) + r.EnterpriseMeta.addToHash(hash, false) // Finalize the hash hashVal := hash.Sum(nil) diff --git a/agent/structs/structs_oss.go b/agent/structs/structs_oss.go index 1d146be24a..d2c99717e1 100644 --- a/agent/structs/structs_oss.go +++ b/agent/structs/structs_oss.go @@ -8,6 +8,8 @@ import ( "github.com/hashicorp/consul/acl" ) +var emptyEnterpriseMeta = EnterpriseMeta{} + // EnterpriseMeta stub type EnterpriseMeta struct{} @@ -15,30 +17,27 @@ func (m *EnterpriseMeta) estimateSize() int { return 0 } -func (m *EnterpriseMeta) addToHash(hasher hash.Hash) { +func (m *EnterpriseMeta) addToHash(_ hash.Hash, _ bool) { // do nothing } -// WildcardEnterpriseMeta stub -func WildcardEnterpriseMeta() *EnterpriseMeta { - return nil -} - // ReplicationEnterpriseMeta stub func ReplicationEnterpriseMeta() *EnterpriseMeta { - return nil + return &emptyEnterpriseMeta } // DefaultEnterpriseMeta stub func DefaultEnterpriseMeta() *EnterpriseMeta { - return nil + return &emptyEnterpriseMeta } -// InitDefault stub -func (m *EnterpriseMeta) InitDefault() {} +// WildcardEnterpriseMeta stub +func WildcardEnterpriseMeta() *EnterpriseMeta { + return &emptyEnterpriseMeta +} // FillAuthzContext stub -func (m *EnterpriseMeta) FillAuthzContext(*acl.EnterpriseAuthorizerContext) {} +func (_ *EnterpriseMeta) FillAuthzContext(_ *acl.EnterpriseAuthorizerContext) {} // FillAuthzContext stub func (d *DirEntry) FillAuthzContext(*acl.EnterpriseAuthorizerContext) {} diff --git a/agent/testagent.go b/agent/testagent.go index a67ffa29c2..cf810ee320 100644 --- a/agent/testagent.go +++ b/agent/testagent.go @@ -156,9 +156,15 @@ func (a *TestAgent) Start() (err error) { hclDataDir = `data_dir = "` + d + `"` } + logOutput := a.LogOutput + if logOutput == nil { + logOutput = os.Stderr + } + agentLogger := log.New(logOutput, a.Name+" - ", log.LstdFlags|log.Lmicroseconds) + portsConfig, returnPortsFn := randomPortsSource(a.UseTLS) a.returnPortsFn = returnPortsFn - a.Config = TestConfig( + a.Config = TestConfig(agentLogger, portsConfig, config.Source{Name: a.Name, Format: "hcl", Data: a.HCL}, config.Source{Name: a.Name + ".data_dir", Format: "hcl", Data: hclDataDir}, @@ -191,12 +197,6 @@ func (a *TestAgent) Start() (err error) { } } - logOutput := a.LogOutput - if logOutput == nil { - logOutput = os.Stderr - } - agentLogger := log.New(logOutput, a.Name+" - ", log.LstdFlags|log.Lmicroseconds) - agent, err := New(a.Config, agentLogger) if err != nil { cleanupTmpDir() @@ -411,7 +411,7 @@ func NodeID() string { // TestConfig returns a unique default configuration for testing an // agent. -func TestConfig(sources ...config.Source) *config.RuntimeConfig { +func TestConfig(logger *log.Logger, sources ...config.Source) *config.RuntimeConfig { nodeID := NodeID() testsrc := config.Source{ Name: "test", @@ -450,7 +450,7 @@ func TestConfig(sources ...config.Source) *config.RuntimeConfig { } for _, w := range b.Warnings { - fmt.Println("WARNING:", w) + logger.Printf("[WARN] %s", w) } // Effectively disables the delay after root rotation before requesting CSRs diff --git a/sentinel/evaluator.go b/sentinel/evaluator.go index 607e22cc74..0c83eae7df 100644 --- a/sentinel/evaluator.go +++ b/sentinel/evaluator.go @@ -5,4 +5,5 @@ package sentinel type Evaluator interface { Compile(policy string) error Execute(policy string, enforcementLevel string, data map[string]interface{}) bool + Close() } diff --git a/testrpc/wait.go b/testrpc/wait.go index 503b84f027..49811ba166 100644 --- a/testrpc/wait.go +++ b/testrpc/wait.go @@ -12,6 +12,8 @@ type rpcFn func(string, interface{}, interface{}) error // WaitForLeader ensures we have a leader and a node registration. func WaitForLeader(t *testing.T, rpc rpcFn, dc string) { + t.Helper() + var out structs.IndexedNodes retry.Run(t, func(r *retry.R) { args := &structs.DCSpecificRequest{Datacenter: dc} @@ -29,6 +31,8 @@ func WaitForLeader(t *testing.T, rpc rpcFn, dc string) { // WaitUntilNoLeader ensures no leader is present, useful for testing lost leadership. func WaitUntilNoLeader(t *testing.T, rpc rpcFn, dc string) { + t.Helper() + var out structs.IndexedNodes retry.Run(t, func(r *retry.R) { args := &structs.DCSpecificRequest{Datacenter: dc} @@ -56,6 +60,8 @@ func WaitForAntiEntropySync() waitOption { // WaitForTestAgent ensures we have a node with serfHealth check registered func WaitForTestAgent(t *testing.T, rpc rpcFn, dc string, options ...waitOption) { + t.Helper() + var nodes structs.IndexedNodes var checks structs.IndexedHealthChecks