2017-09-07 23:56:15 +00:00
|
|
|
// +build !pro,!ent
|
|
|
|
|
|
|
|
package nomad
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
memdb "github.com/hashicorp/go-memdb"
|
2017-10-12 01:05:27 +00:00
|
|
|
"github.com/hashicorp/nomad/acl"
|
2017-09-07 23:56:15 +00:00
|
|
|
"github.com/hashicorp/nomad/nomad/state"
|
|
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
|
|
)
|
|
|
|
|
2017-09-08 00:13:18 +00:00
|
|
|
var (
|
|
|
|
// allContexts are the available contexts which are searched to find matches
|
|
|
|
// for a given prefix
|
|
|
|
allContexts = ossContexts
|
|
|
|
)
|
|
|
|
|
2017-10-13 21:36:02 +00:00
|
|
|
// contextToIndex returns the index name to lookup in the state store.
|
|
|
|
func contextToIndex(ctx structs.Context) string {
|
|
|
|
return string(ctx)
|
|
|
|
}
|
|
|
|
|
2017-09-07 23:56:15 +00:00
|
|
|
// getEnterpriseMatch is a no-op in oss since there are no enterprise objects.
|
|
|
|
func getEnterpriseMatch(match interface{}) (id string, ok bool) {
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
|
|
|
// getEnterpriseResourceIter is used to retrieve an iterator over an enterprise
|
|
|
|
// only table.
|
2017-10-13 21:36:02 +00:00
|
|
|
func getEnterpriseResourceIter(context structs.Context, _ *acl.ACL, namespace, prefix string, ws memdb.WatchSet, state *state.StateStore) (memdb.ResultIterator, error) {
|
2017-09-07 23:56:15 +00:00
|
|
|
// If we have made it here then it is an error since we have exhausted all
|
|
|
|
// open source contexts.
|
2017-09-08 00:13:18 +00:00
|
|
|
return nil, fmt.Errorf("context must be one of %v or 'all' for all contexts; got %q", allContexts, context)
|
2017-09-07 23:56:15 +00:00
|
|
|
}
|
2017-10-12 01:05:27 +00:00
|
|
|
|
|
|
|
// anySearchPerms returns true if the provided ACL has access to any
|
|
|
|
// capabilities required for prefix searching. Returns true if aclObj is nil.
|
|
|
|
func anySearchPerms(aclObj *acl.ACL, namespace string, context structs.Context) bool {
|
|
|
|
if aclObj == nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
nodeRead := aclObj.AllowNodeRead()
|
|
|
|
jobRead := aclObj.AllowNsOp(namespace, acl.NamespaceCapabilityReadJob)
|
|
|
|
if !nodeRead && !jobRead {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reject requests that explicitly specify a disallowed context. This
|
|
|
|
// should give the user better feedback then simply filtering out all
|
|
|
|
// results and returning an empty list.
|
|
|
|
if !nodeRead && context == structs.Nodes {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if !jobRead {
|
|
|
|
switch context {
|
|
|
|
case structs.Allocs, structs.Deployments, structs.Evals, structs.Jobs:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// searchContexts returns the contexts the aclObj is valid for. If aclObj is
|
|
|
|
// nil all contexts are returned.
|
|
|
|
func searchContexts(aclObj *acl.ACL, namespace string, context structs.Context) []structs.Context {
|
|
|
|
var all []structs.Context
|
|
|
|
|
|
|
|
switch context {
|
|
|
|
case structs.All:
|
|
|
|
all = make([]structs.Context, len(allContexts))
|
|
|
|
copy(all, allContexts)
|
|
|
|
default:
|
|
|
|
all = []structs.Context{context}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If ACLs aren't enabled return all contexts
|
|
|
|
if aclObj == nil {
|
|
|
|
return all
|
|
|
|
}
|
|
|
|
|
|
|
|
jobRead := aclObj.AllowNsOp(namespace, acl.NamespaceCapabilityReadJob)
|
|
|
|
|
|
|
|
// Filter contexts down to those the ACL grants access to
|
|
|
|
available := make([]structs.Context, 0, len(all))
|
|
|
|
for _, c := range all {
|
|
|
|
switch c {
|
|
|
|
case structs.Allocs, structs.Jobs, structs.Evals, structs.Deployments:
|
|
|
|
if jobRead {
|
|
|
|
available = append(available, c)
|
|
|
|
}
|
|
|
|
case structs.Nodes:
|
|
|
|
if aclObj.AllowNodeRead() {
|
|
|
|
available = append(available, c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return available
|
|
|
|
}
|