various partition related todos (#11822)

This commit is contained in:
R.B. Boyer 2021-12-13 11:43:33 -06:00 committed by GitHub
parent 11ab84f840
commit 631c649291
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 115 additions and 96 deletions

View File

@ -43,19 +43,20 @@ func (a *Agent) vetServiceRegister(token string, service *structs.NodeService) e
func (a *Agent) vetServiceRegisterWithAuthorizer(authz acl.Authorizer, service *structs.NodeService) error { func (a *Agent) vetServiceRegisterWithAuthorizer(authz acl.Authorizer, service *structs.NodeService) error {
var authzContext acl.AuthorizerContext var authzContext acl.AuthorizerContext
service.FillAuthzContext(&authzContext)
// Vet the service itself. // Vet the service itself.
service.FillAuthzContext(&authzContext)
if authz.ServiceWrite(service.Service, &authzContext) != acl.Allow { if authz.ServiceWrite(service.Service, &authzContext) != acl.Allow {
serviceName := service.CompoundServiceName() return acl.PermissionDenied("Missing service:write on %s",
return acl.PermissionDenied("Missing service:write on %s", serviceName.String()) structs.ServiceIDString(service.Service, &service.EnterpriseMeta))
} }
// Vet any service that might be getting overwritten. // Vet any service that might be getting overwritten.
if existing := a.State.Service(service.CompoundServiceID()); existing != nil { if existing := a.State.Service(service.CompoundServiceID()); existing != nil {
existing.FillAuthzContext(&authzContext) existing.FillAuthzContext(&authzContext)
if authz.ServiceWrite(existing.Service, &authzContext) != acl.Allow { if authz.ServiceWrite(existing.Service, &authzContext) != acl.Allow {
serviceName := service.CompoundServiceName() return acl.PermissionDenied("Missing service:write on %s",
return acl.PermissionDenied("Missing service:write on %s", serviceName.String()) structs.ServiceIDString(service.Service, &service.EnterpriseMeta))
} }
} }
@ -64,8 +65,8 @@ func (a *Agent) vetServiceRegisterWithAuthorizer(authz acl.Authorizer, service *
if service.Kind == structs.ServiceKindConnectProxy { if service.Kind == structs.ServiceKindConnectProxy {
service.FillAuthzContext(&authzContext) service.FillAuthzContext(&authzContext)
if authz.ServiceWrite(service.Proxy.DestinationServiceName, &authzContext) != acl.Allow { if authz.ServiceWrite(service.Proxy.DestinationServiceName, &authzContext) != acl.Allow {
// TODO(partitions) fix this to include namespace and partition return acl.PermissionDenied("Missing service:write on %s",
return acl.PermissionDenied("Missing service:write on %s", service.Proxy.DestinationServiceName) structs.ServiceIDString(service.Proxy.DestinationServiceName, &service.EnterpriseMeta))
} }
} }
@ -79,8 +80,8 @@ func (a *Agent) vetServiceUpdateWithAuthorizer(authz acl.Authorizer, serviceID s
if existing := a.State.Service(serviceID); existing != nil { if existing := a.State.Service(serviceID); existing != nil {
existing.FillAuthzContext(&authzContext) existing.FillAuthzContext(&authzContext)
if authz.ServiceWrite(existing.Service, &authzContext) != acl.Allow { if authz.ServiceWrite(existing.Service, &authzContext) != acl.Allow {
serviceName := existing.CompoundServiceName() return acl.PermissionDenied("Missing service:write on %s",
return acl.PermissionDenied("Missing service:write on %s", serviceName.String()) structs.ServiceIDString(existing.Service, &existing.EnterpriseMeta))
} }
} else { } else {
return NotFoundError{Reason: fmt.Sprintf("Unknown service %q", serviceID)} return NotFoundError{Reason: fmt.Sprintf("Unknown service %q", serviceID)}
@ -90,18 +91,19 @@ func (a *Agent) vetServiceUpdateWithAuthorizer(authz acl.Authorizer, serviceID s
} }
func (a *Agent) vetCheckRegisterWithAuthorizer(authz acl.Authorizer, check *structs.HealthCheck) error { func (a *Agent) vetCheckRegisterWithAuthorizer(authz acl.Authorizer, check *structs.HealthCheck) error {
// TODO(partitions)
var authzContext acl.AuthorizerContext var authzContext acl.AuthorizerContext
check.FillAuthzContext(&authzContext) check.FillAuthzContext(&authzContext)
// Vet the check itself. // Vet the check itself.
if len(check.ServiceName) > 0 { if len(check.ServiceName) > 0 {
if authz.ServiceWrite(check.ServiceName, &authzContext) != acl.Allow { if authz.ServiceWrite(check.ServiceName, &authzContext) != acl.Allow {
return acl.PermissionDenied("Missing service:write on %v", structs.ServiceIDString(check.ServiceName, &check.EnterpriseMeta)) return acl.PermissionDenied("Missing service:write on %s",
structs.ServiceIDString(check.ServiceName, &check.EnterpriseMeta))
} }
} else { } else {
if authz.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow { if authz.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow {
return acl.PermissionDenied("Missing node:write on %s", structs.NodeNameString(a.config.NodeName, a.AgentEnterpriseMeta())) return acl.PermissionDenied("Missing node:write on %s",
structs.NodeNameString(a.config.NodeName, a.AgentEnterpriseMeta()))
} }
} }
@ -109,11 +111,13 @@ func (a *Agent) vetCheckRegisterWithAuthorizer(authz acl.Authorizer, check *stru
if existing := a.State.Check(check.CompoundCheckID()); existing != nil { if existing := a.State.Check(check.CompoundCheckID()); existing != nil {
if len(existing.ServiceName) > 0 { if len(existing.ServiceName) > 0 {
if authz.ServiceWrite(existing.ServiceName, &authzContext) != acl.Allow { if authz.ServiceWrite(existing.ServiceName, &authzContext) != acl.Allow {
return acl.PermissionDenied("Missing service:write on %s", structs.ServiceIDString(existing.ServiceName, &existing.EnterpriseMeta)) return acl.PermissionDenied("Missing service:write on %s",
structs.ServiceIDString(existing.ServiceName, &existing.EnterpriseMeta))
} }
} else { } else {
if authz.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow { if authz.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow {
return acl.PermissionDenied("Missing node:write on %s", structs.NodeNameString(a.config.NodeName, a.AgentEnterpriseMeta())) return acl.PermissionDenied("Missing node:write on %s",
structs.NodeNameString(a.config.NodeName, a.AgentEnterpriseMeta()))
} }
} }
} }
@ -129,11 +133,13 @@ func (a *Agent) vetCheckUpdateWithAuthorizer(authz acl.Authorizer, checkID struc
if existing := a.State.Check(checkID); existing != nil { if existing := a.State.Check(checkID); existing != nil {
if len(existing.ServiceName) > 0 { if len(existing.ServiceName) > 0 {
if authz.ServiceWrite(existing.ServiceName, &authzContext) != acl.Allow { if authz.ServiceWrite(existing.ServiceName, &authzContext) != acl.Allow {
return acl.PermissionDenied("Missing service:write on %s", structs.ServiceIDString(existing.ServiceName, &existing.EnterpriseMeta)) return acl.PermissionDenied("Missing service:write on %s",
structs.ServiceIDString(existing.ServiceName, &existing.EnterpriseMeta))
} }
} else { } else {
if authz.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow { if authz.NodeWrite(a.config.NodeName, &authzContext) != acl.Allow {
return acl.PermissionDenied("Missing node:write on %s", structs.NodeNameString(a.config.NodeName, a.AgentEnterpriseMeta())) return acl.PermissionDenied("Missing node:write on %s",
structs.NodeNameString(a.config.NodeName, a.AgentEnterpriseMeta()))
} }
} }
} else { } else {

View File

@ -306,7 +306,6 @@ func (s *HTTPHandlers) AgentServices(resp http.ResponseWriter, req *http.Request
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
// TODO(partitions): should this default to the agent's partition?
var entMeta structs.EnterpriseMeta var entMeta structs.EnterpriseMeta
if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil {
return nil, err return nil, err
@ -393,7 +392,6 @@ func (s *HTTPHandlers) AgentService(resp http.ResponseWriter, req *http.Request)
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
// TODO(partitions): should this default to the agent's partition?
var entMeta structs.EnterpriseMeta var entMeta structs.EnterpriseMeta
if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil {
return nil, err return nil, err
@ -470,7 +468,6 @@ func (s *HTTPHandlers) AgentChecks(resp http.ResponseWriter, req *http.Request)
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
// TODO(partitions): should this default to the agent's partition?
var entMeta structs.EnterpriseMeta var entMeta structs.EnterpriseMeta
if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil {
return nil, err return nil, err
@ -637,7 +634,6 @@ func (s *HTTPHandlers) AgentJoin(resp http.ResponseWriter, req *http.Request) (i
wan := false wan := false
if other := req.URL.Query().Get("wan"); other != "" { if other := req.URL.Query().Get("wan"); other != "" {
wan = true wan = true
// TODO(partitions) : block wan join
} }
// Get the address // Get the address
@ -722,7 +718,6 @@ func (s *HTTPHandlers) AgentRegisterCheck(resp http.ResponseWriter, req *http.Re
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
// TODO(partitions): should this default to the agent's partition?
var args structs.CheckDefinition var args structs.CheckDefinition
if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil {
return nil, err return nil, err
@ -794,7 +789,6 @@ func (s *HTTPHandlers) AgentDeregisterCheck(resp http.ResponseWriter, req *http.
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
// TODO(partitions): should this default to the agent's partition?
if err := s.parseEntMetaNoWildcard(req, &checkID.EnterpriseMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &checkID.EnterpriseMeta); err != nil {
return nil, err return nil, err
} }
@ -887,7 +881,6 @@ func (s *HTTPHandlers) agentCheckUpdate(resp http.ResponseWriter, req *http.Requ
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
// TODO(partitions): should this default to the agent's partition?
if err := s.parseEntMetaNoWildcard(req, &cid.EnterpriseMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &cid.EnterpriseMeta); err != nil {
return nil, err return nil, err
} }
@ -963,7 +956,6 @@ func (s *HTTPHandlers) AgentHealthServiceByID(resp http.ResponseWriter, req *htt
return nil, &BadRequestError{Reason: "Missing serviceID"} return nil, &BadRequestError{Reason: "Missing serviceID"}
} }
// TODO(partitions): should this default to the agent's partition?
var entMeta structs.EnterpriseMeta var entMeta structs.EnterpriseMeta
if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil {
return nil, err return nil, err
@ -1022,7 +1014,6 @@ func (s *HTTPHandlers) AgentHealthServiceByName(resp http.ResponseWriter, req *h
return nil, &BadRequestError{Reason: "Missing service Name"} return nil, &BadRequestError{Reason: "Missing service Name"}
} }
// TODO(partitions): should this default to the agent's partition?
var entMeta structs.EnterpriseMeta var entMeta structs.EnterpriseMeta
if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil {
return nil, err return nil, err
@ -1086,7 +1077,6 @@ func (s *HTTPHandlers) AgentRegisterService(resp http.ResponseWriter, req *http.
var args structs.ServiceDefinition var args structs.ServiceDefinition
// Fixup the type decode of TTL or Interval if a check if provided. // Fixup the type decode of TTL or Interval if a check if provided.
// TODO(partitions): should this default to the agent's partition?
if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil {
return nil, err return nil, err
} }
@ -1253,7 +1243,6 @@ func (s *HTTPHandlers) AgentDeregisterService(resp http.ResponseWriter, req *htt
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
// TODO(partitions): should this default to the agent's partition?
if err := s.parseEntMetaNoWildcard(req, &sid.EnterpriseMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &sid.EnterpriseMeta); err != nil {
return nil, err return nil, err
} }
@ -1311,7 +1300,6 @@ func (s *HTTPHandlers) AgentServiceMaintenance(resp http.ResponseWriter, req *ht
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
// TODO(partitions): should this default to the agent's partition?
if err := s.parseEntMetaNoWildcard(req, &sid.EnterpriseMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &sid.EnterpriseMeta); err != nil {
return nil, err return nil, err
} }
@ -1369,6 +1357,7 @@ func (s *HTTPHandlers) AgentNodeMaintenance(resp http.ResponseWriter, req *http.
// Get the provided token, if any, and vet against any ACL policies. // Get the provided token, if any, and vet against any ACL policies.
var token string var token string
s.parseToken(req, &token) s.parseToken(req, &token)
authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil) authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -1576,7 +1565,6 @@ func (s *HTTPHandlers) AgentConnectCALeafCert(resp http.ResponseWriter, req *htt
} }
var qOpts structs.QueryOptions var qOpts structs.QueryOptions
// TODO(partitions): should this default to the agent's partition?
if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil {
return nil, err return nil, err
} }
@ -1632,7 +1620,6 @@ func (s *HTTPHandlers) AgentConnectAuthorize(resp http.ResponseWriter, req *http
var authReq structs.ConnectAuthorizeRequest var authReq structs.ConnectAuthorizeRequest
// TODO(partitions): should this default to the agent's partition?
if err := s.parseEntMetaNoWildcard(req, &authReq.EnterpriseMeta); err != nil { if err := s.parseEntMetaNoWildcard(req, &authReq.EnterpriseMeta); err != nil {
return nil, err return nil, err
} }

View File

@ -637,7 +637,6 @@ func (r *ACLResolver) resolvePoliciesForIdentity(identity structs.ACLIdentity) (
policies = append(policies, syntheticPolicies...) policies = append(policies, syntheticPolicies...)
filtered := r.filterPoliciesByScope(policies) filtered := r.filterPoliciesByScope(policies)
// TODO(partitions,acls): filter these by the partition/namespace of the token trying to use them?
return filtered, nil return filtered, nil
} }

View File

@ -4,9 +4,10 @@
package consul package consul
import ( import (
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/go-hclog"
) )
// EnterpriseACLResolverDelegate stub // EnterpriseACLResolverDelegate stub

View File

@ -387,8 +387,6 @@ func (s *Server) initializeACLs(ctx context.Context) error {
if s.InPrimaryDatacenter() { if s.InPrimaryDatacenter() {
s.logger.Info("initializing acls") s.logger.Info("initializing acls")
// TODO(partitions): initialize acls in all of the partitions?
// Create/Upgrade the builtin global-management policy // Create/Upgrade the builtin global-management policy
_, policy, err := s.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, structs.DefaultEnterpriseMetaInDefaultPartition()) _, policy, err := s.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, structs.DefaultEnterpriseMetaInDefaultPartition())
if err != nil { if err != nil {
@ -965,8 +963,10 @@ func (s *Server) reconcileReaped(known map[string]struct{}, nodeEntMeta *structs
func (s *Server) reconcileMember(member serf.Member) error { func (s *Server) reconcileMember(member serf.Member) error {
// Check if this is a member we should handle // Check if this is a member we should handle
if !s.shouldHandleMember(member) { if !s.shouldHandleMember(member) {
// TODO(partition): log the partition name s.logger.Warn("skipping reconcile of node",
s.logger.Warn("skipping reconcile of node", "member", member) "member", member,
"partition", getSerfMemberEnterpriseMeta(member).PartitionOrDefault(),
)
return nil return nil
} }
defer metrics.MeasureSince([]string{"leader", "reconcileMember"}, time.Now()) defer metrics.MeasureSince([]string{"leader", "reconcileMember"}, time.Now())
@ -986,8 +986,8 @@ func (s *Server) reconcileMember(member serf.Member) error {
} }
if err != nil { if err != nil {
s.logger.Error("failed to reconcile member", s.logger.Error("failed to reconcile member",
// TODO(partition): log the partition name
"member", member, "member", member,
"partition", getSerfMemberEnterpriseMeta(member).PartitionOrDefault(),
"error", err, "error", err,
) )
@ -1089,7 +1089,10 @@ func (s *Server) handleAliveMember(member serf.Member, nodeEntMeta *structs.Ente
} }
} }
AFTER_CHECK: AFTER_CHECK:
s.logger.Info("member joined, marking health alive", "member", member.Name) s.logger.Info("member joined, marking health alive",
"member", member.Name,
"partition", getSerfMemberEnterpriseMeta(member).PartitionOrDefault(),
)
// Register with the catalog. // Register with the catalog.
req := structs.RegisterRequest{ req := structs.RegisterRequest{
@ -1131,12 +1134,13 @@ func (s *Server) handleFailedMember(member serf.Member, nodeEntMeta *structs.Ent
} }
if node == nil { if node == nil {
s.logger.Info("ignoring failed event for member because it does not exist in the catalog", "member", member.Name) s.logger.Info("ignoring failed event for member because it does not exist in the catalog",
"member", member.Name,
"partition", getSerfMemberEnterpriseMeta(member).PartitionOrDefault(),
)
return nil return nil
} }
// TODO(partitions): get the ent meta by parsing serf tags
if node.Address == member.Addr.String() { if node.Address == member.Addr.String() {
// Check if the serfCheck is in the critical state // Check if the serfCheck is in the critical state
_, checks, err := state.NodeChecks(nil, member.Name, nodeEntMeta) _, checks, err := state.NodeChecks(nil, member.Name, nodeEntMeta)
@ -1149,7 +1153,10 @@ func (s *Server) handleFailedMember(member serf.Member, nodeEntMeta *structs.Ent
} }
} }
} }
s.logger.Info("member failed, marking health critical", "member", member.Name) s.logger.Info("member failed, marking health critical",
"member", member.Name,
"partition", getSerfMemberEnterpriseMeta(member).PartitionOrDefault(),
)
// Register with the catalog // Register with the catalog
req := structs.RegisterRequest{ req := structs.RegisterRequest{
@ -1195,8 +1202,13 @@ func (s *Server) handleDeregisterMember(reason string, member serf.Member, nodeE
// Do not deregister ourself. This can only happen if the current leader // Do not deregister ourself. This can only happen if the current leader
// is leaving. Instead, we should allow a follower to take-over and // is leaving. Instead, we should allow a follower to take-over and
// deregister us later. // deregister us later.
//
// TODO(partitions): check partitions here too? server names should be unique in general though
if member.Name == s.config.NodeName { if member.Name == s.config.NodeName {
s.logger.Warn("deregistering self should be done by follower", "name", s.config.NodeName) s.logger.Warn("deregistering self should be done by follower",
"name", s.config.NodeName,
"partition", getSerfMemberEnterpriseMeta(member).PartitionOrDefault(),
)
return nil return nil
} }
@ -1218,7 +1230,11 @@ func (s *Server) handleDeregisterMember(reason string, member serf.Member, nodeE
} }
// Deregister the node // Deregister the node
s.logger.Info("deregistering member", "member", member.Name, "reason", reason) s.logger.Info("deregistering member",
"member", member.Name,
"partition", getSerfMemberEnterpriseMeta(member).PartitionOrDefault(),
"reason", reason,
)
req := structs.DeregisterRequest{ req := structs.DeregisterRequest{
Datacenter: s.config.Datacenter, Datacenter: s.config.Datacenter,
Node: member.Name, Node: member.Name,

View File

@ -90,7 +90,6 @@ func Compile(query *structs.PreparedQuery) (*CompiledTemplate, error) {
// prefix it will be expected to run with. The results might not make // prefix it will be expected to run with. The results might not make
// sense and create a valid service to lookup, but it should render // sense and create a valid service to lookup, but it should render
// without any errors. // without any errors.
// TODO(partitions) should this have a partition on it?
if _, err = ct.Render(ct.query.Name, structs.QuerySource{}); err != nil { if _, err = ct.Render(ct.query.Name, structs.QuerySource{}); err != nil {
return nil, err return nil, err
} }
@ -158,7 +157,6 @@ func (ct *CompiledTemplate) Render(name string, source structs.QuerySource) (*st
Type: ast.TypeString, Type: ast.TypeString,
Value: source.Segment, Value: source.Segment,
}, },
// TODO(partitions): should NodePartition be projected here?
}, },
FuncMap: map[string]ast.Function{ FuncMap: map[string]ast.Function{
"match": match, "match": match,

View File

@ -128,18 +128,33 @@ func (s *Store) EnsureRegistration(idx uint64, req *structs.RegisterRequest) err
return tx.Commit() return tx.Commit()
} }
func (s *Store) ensureCheckIfNodeMatches(tx WriteTxn, idx uint64, preserveIndexes bool, node string, check *structs.HealthCheck) error { func (s *Store) ensureCheckIfNodeMatches(
// TODO(partitions): do we have to check partition here? probably not tx WriteTxn,
if check.Node != node { idx uint64,
preserveIndexes bool,
node string,
nodePartition string,
check *structs.HealthCheck,
) error {
if check.Node != node || !structs.EqualPartitions(nodePartition, check.PartitionOrDefault()) {
return fmt.Errorf("check node %q does not match node %q", return fmt.Errorf("check node %q does not match node %q",
check.Node, node) printNodeName(check.Node, check.PartitionOrDefault()),
printNodeName(node, nodePartition),
)
} }
if err := s.ensureCheckTxn(tx, idx, preserveIndexes, check); err != nil { if err := s.ensureCheckTxn(tx, idx, preserveIndexes, check); err != nil {
return fmt.Errorf("failed inserting check: %s on node %q", err, check.Node) return fmt.Errorf("failed inserting check on node %q: %v", printNodeName(check.Node, check.PartitionOrDefault()), err)
} }
return nil return nil
} }
func printNodeName(nodeName, partition string) string {
if structs.IsDefaultPartition(partition) {
return nodeName
}
return partition + "/" + nodeName
}
// ensureRegistrationTxn is used to make sure a node, service, and check // ensureRegistrationTxn is used to make sure a node, service, and check
// registration is performed within a single transaction to avoid race // registration is performed within a single transaction to avoid race
// conditions on state updates. // conditions on state updates.
@ -205,12 +220,12 @@ func (s *Store) ensureRegistrationTxn(tx WriteTxn, idx uint64, preserveIndexes b
// Add the checks, if any. // Add the checks, if any.
if req.Check != nil { if req.Check != nil {
if err := s.ensureCheckIfNodeMatches(tx, idx, preserveIndexes, req.Node, req.Check); err != nil { if err := s.ensureCheckIfNodeMatches(tx, idx, preserveIndexes, req.Node, req.PartitionOrDefault(), req.Check); err != nil {
return err return err
} }
} }
for _, check := range req.Checks { for _, check := range req.Checks {
if err := s.ensureCheckIfNodeMatches(tx, idx, preserveIndexes, req.Node, check); err != nil { if err := s.ensureCheckIfNodeMatches(tx, idx, preserveIndexes, req.Node, req.PartitionOrDefault(), check); err != nil {
return err return err
} }
} }
@ -526,9 +541,6 @@ func (s *Store) DeleteNode(idx uint64, nodeName string, entMeta *structs.Enterpr
tx := s.db.WriteTxn(idx) tx := s.db.WriteTxn(idx)
defer tx.Abort() defer tx.Abort()
// TODO(partition): double check all freshly modified state store functions
// that take an ent meta do this trick
// TODO: accept non-pointer value // TODO: accept non-pointer value
if entMeta == nil { if entMeta == nil {
entMeta = structs.NodeEnterpriseMetaInDefaultPartition() entMeta = structs.NodeEnterpriseMetaInDefaultPartition()

View File

@ -78,9 +78,6 @@ func (s *handlerConnectProxy) initialize(ctx context.Context) (ConfigSnapshot, e
return snap, err return snap, err
} }
// default the namespace to the namespace of this proxy service
currentNamespace := s.proxyID.NamespaceOrDefault()
if s.proxyCfg.Mode == structs.ProxyModeTransparent { if s.proxyCfg.Mode == structs.ProxyModeTransparent {
// When in transparent proxy we will infer upstreams from intentions with this source // When in transparent proxy we will infer upstreams from intentions with this source
err := s.cache.Notify(ctx, cachetype.IntentionUpstreamsName, &structs.ServiceSpecificRequest{ err := s.cache.Notify(ctx, cachetype.IntentionUpstreamsName, &structs.ServiceSpecificRequest{
@ -131,15 +128,15 @@ func (s *handlerConnectProxy) initialize(ctx context.Context) (ConfigSnapshot, e
continue continue
} }
ns := currentNamespace // Default the partition and namespace to the namespace of this proxy service.
if u.DestinationNamespace != "" {
ns = u.DestinationNamespace
}
partition := s.proxyID.PartitionOrDefault() partition := s.proxyID.PartitionOrDefault()
if u.DestinationPartition != "" { if u.DestinationPartition != "" {
partition = u.DestinationPartition partition = u.DestinationPartition
} }
ns := s.proxyID.NamespaceOrDefault()
if u.DestinationNamespace != "" {
ns = u.DestinationNamespace
}
cfg, err := parseReducedUpstreamConfig(u.Config) cfg, err := parseReducedUpstreamConfig(u.Config)
if err != nil { if err != nil {

View File

@ -18,6 +18,7 @@ import (
"github.com/hashicorp/consul/agent/rpcclient/health" "github.com/hashicorp/consul/agent/rpcclient/health"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/agent/token" "github.com/hashicorp/consul/agent/token"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil"
) )
@ -103,6 +104,7 @@ func TestManager_BasicLifecycle(t *testing.T) {
upstreams := structs.TestUpstreams(t) upstreams := structs.TestUpstreams(t)
for i := range upstreams { for i := range upstreams {
upstreams[i].DestinationNamespace = structs.IntentionDefaultNamespace upstreams[i].DestinationNamespace = structs.IntentionDefaultNamespace
upstreams[i].DestinationPartition = api.PartitionDefaultName
} }
webProxy := &structs.NodeService{ webProxy := &structs.NodeService{
Kind: structs.ServiceKindConnectProxy, Kind: structs.ServiceKindConnectProxy,

View File

@ -113,14 +113,18 @@ func copyProxyConfig(ns *structs.NodeService) (structs.ConnectProxyConfig, error
// we can safely modify these since we just copied them // we can safely modify these since we just copied them
for idx := range proxyCfg.Upstreams { for idx := range proxyCfg.Upstreams {
us := &proxyCfg.Upstreams[idx] us := &proxyCfg.Upstreams[idx]
if us.DestinationType != structs.UpstreamDestTypePreparedQuery && us.DestinationNamespace == "" { if us.DestinationType != structs.UpstreamDestTypePreparedQuery {
// default the upstreams target namespace and partition to those of the proxy // default the upstreams target namespace and partition to those of the proxy
// doing this here prevents needing much more complex logic a bunch of other // doing this here prevents needing much more complex logic a bunch of other
// places and makes tracking these upstreams simpler as we can dedup them // places and makes tracking these upstreams simpler as we can dedup them
// with the maps tracking upstream ids being watched. // with the maps tracking upstream ids being watched.
proxyCfg.Upstreams[idx].DestinationNamespace = ns.EnterpriseMeta.NamespaceOrDefault() if us.DestinationPartition == "" {
proxyCfg.Upstreams[idx].DestinationPartition = ns.EnterpriseMeta.PartitionOrDefault() proxyCfg.Upstreams[idx].DestinationPartition = ns.EnterpriseMeta.PartitionOrDefault()
} }
if us.DestinationNamespace == "" {
proxyCfg.Upstreams[idx].DestinationNamespace = ns.EnterpriseMeta.NamespaceOrDefault()
}
}
} }
return proxyCfg, nil return proxyCfg, nil

View File

@ -547,6 +547,25 @@ func (u *Upstream) String() string {
return u.Identifier() return u.Identifier()
} }
// Identifier returns a string representation that uniquely identifies the
// upstream in a canonical but human readable way.
func (us *Upstream) Identifier() string {
name := us.enterpriseIdentifierPrefix() + us.DestinationName
typ := us.DestinationType
if us.Datacenter != "" {
name += "?dc=" + us.Datacenter
}
// Service is default type so never prefix it. This is more readable and long
// term it is the only type that matters so we can drop the prefix and have
// nicer naming in metrics etc.
if typ == "" || typ == UpstreamDestTypeService {
return name
}
return typ + ":" + name
}
// UpstreamFromAPI is a helper for converting api.Upstream to Upstream. // UpstreamFromAPI is a helper for converting api.Upstream to Upstream.
func UpstreamFromAPI(u api.Upstream) Upstream { func UpstreamFromAPI(u api.Upstream) Upstream {
return Upstream{ return Upstream{

View File

@ -13,24 +13,6 @@ func (us *Upstream) DestinationID() ServiceID {
} }
} }
// Identifier returns a string representation that uniquely identifies the func (us *Upstream) enterpriseIdentifierPrefix() string {
// upstream in a canonical but human readable way. return ""
func (us *Upstream) Identifier() string {
name := us.DestinationName
typ := us.DestinationType
if typ != UpstreamDestTypePreparedQuery && us.DestinationNamespace != "" && us.DestinationNamespace != IntentionDefaultNamespace {
name = us.DestinationNamespace + "/" + us.DestinationName
}
if us.Datacenter != "" {
name += "?dc=" + us.Datacenter
}
// Service is default type so never prefix it. This is more readable and long
// term it is the only type that matters so we can drop the prefix and have
// nicer naming in metrics etc.
if typ == "" || typ == UpstreamDestTypeService {
return name
}
return typ + ":" + name
} }

View File

@ -422,7 +422,6 @@ type RegisterRequest struct {
// node portion of this update will not apply. // node portion of this update will not apply.
SkipNodeUpdate bool SkipNodeUpdate bool
// TODO(partitions): ensure the partition part is used for node reg
// EnterpriseMeta is the embedded enterprise metadata // EnterpriseMeta is the embedded enterprise metadata
EnterpriseMeta `hcl:",squash" mapstructure:",squash"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
@ -473,7 +472,6 @@ type DeregisterRequest struct {
Node string Node string
ServiceID string ServiceID string
CheckID types.CheckID CheckID types.CheckID
// TODO(partitions): ensure the partition part is used for node reg
EnterpriseMeta `hcl:",squash" mapstructure:",squash"` EnterpriseMeta `hcl:",squash" mapstructure:",squash"`
WriteRequest WriteRequest
} }
@ -916,7 +914,6 @@ type ServiceNode struct {
ServiceProxy ConnectProxyConfig ServiceProxy ConnectProxyConfig
ServiceConnect ServiceConnect ServiceConnect ServiceConnect
// TODO(partitions): ensure that Node+Service are both in the same Partition
EnterpriseMeta `hcl:",squash" mapstructure:",squash" bexpr:"-"` EnterpriseMeta `hcl:",squash" mapstructure:",squash" bexpr:"-"`
RaftIndex `bexpr:"-"` RaftIndex `bexpr:"-"`
@ -1125,7 +1122,6 @@ type NodeService struct {
// somewhere this is used in API output. // somewhere this is used in API output.
LocallyRegisteredAsSidecar bool `json:"-" bexpr:"-"` LocallyRegisteredAsSidecar bool `json:"-" bexpr:"-"`
// TODO(partitions): ensure that Node+Service are both in the same Partition
EnterpriseMeta `hcl:",squash" mapstructure:",squash" bexpr:"-"` EnterpriseMeta `hcl:",squash" mapstructure:",squash" bexpr:"-"`
RaftIndex `bexpr:"-"` RaftIndex `bexpr:"-"`