/
search_endpoint_oss.go
137 lines (119 loc) · 4.22 KB
/
search_endpoint_oss.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//go:build !ent
// +build !ent
package nomad
import (
"fmt"
memdb "github.com/hashicorp/go-memdb"
"github.com/hashicorp/nomad/acl"
"github.com/hashicorp/nomad/nomad/state"
"github.com/hashicorp/nomad/nomad/structs"
)
var (
// allContexts are the available contexts which are searched to find matches
// for a given prefix
allContexts = ossContexts
)
// contextToIndex returns the index name to lookup in the state store.
func contextToIndex(ctx structs.Context) string {
return string(ctx)
}
// 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.
func getEnterpriseResourceIter(context structs.Context, _ *acl.ACL, namespace, prefix string, ws memdb.WatchSet, state *state.StateStore) (memdb.ResultIterator, error) {
// If we have made it here then it is an error since we have exhausted all
// open source contexts.
return nil, fmt.Errorf("context must be one of %v or 'all' for all contexts; got %q", allContexts, context)
}
// getEnterpriseFuzzyResourceIter is used to retrieve an iterator over an enterprise
// only table.
func getEnterpriseFuzzyResourceIter(context structs.Context, _ *acl.ACL, _ string, _ memdb.WatchSet, _ *state.StateStore) (memdb.ResultIterator, error) {
return nil, fmt.Errorf("context must be one of %v or 'all' for all contexts; got %q", allContexts, context)
}
// sufficientSearchPerms returns true if the provided ACL has access to each
// capability required for prefix searching for the given context.
//
// Returns true if aclObj is nil.
func sufficientSearchPerms(aclObj *acl.ACL, namespace string, context structs.Context) bool {
if aclObj == nil {
return true
}
nodeRead := aclObj.AllowNodeRead()
allowNS := aclObj.AllowNamespace(namespace)
jobRead := aclObj.AllowNsOp(namespace, acl.NamespaceCapabilityReadJob)
allowVolume := acl.NamespaceValidator(acl.NamespaceCapabilityCSIListVolume,
acl.NamespaceCapabilityCSIReadVolume,
acl.NamespaceCapabilityListJobs,
acl.NamespaceCapabilityReadJob)
volRead := allowVolume(aclObj, namespace)
if !nodeRead && !jobRead && !volRead && !allowNS {
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 !allowNS && context == structs.Namespaces {
return false
}
if !jobRead {
switch context {
case structs.Allocs, structs.Deployments, structs.Evals, structs.Jobs:
return false
}
}
if !volRead && context == structs.Volumes {
return false
}
return true
}
// filteredSearchContexts returns the expanded set of contexts, filtered down
// to the subset of contexts the aclObj is valid for.
//
// If aclObj is nil, no contexts are filtered out.
func filteredSearchContexts(aclObj *acl.ACL, namespace string, context structs.Context) []structs.Context {
desired := expandContext(context)
// If ACLs aren't enabled return all contexts
if aclObj == nil {
return desired
}
jobRead := aclObj.AllowNsOp(namespace, acl.NamespaceCapabilityReadJob)
allowVolume := acl.NamespaceValidator(acl.NamespaceCapabilityCSIListVolume,
acl.NamespaceCapabilityCSIReadVolume,
acl.NamespaceCapabilityListJobs,
acl.NamespaceCapabilityReadJob)
volRead := allowVolume(aclObj, namespace)
policyRead := aclObj.AllowNsOp(namespace, acl.NamespaceCapabilityListScalingPolicies)
// Filter contexts down to those the ACL grants access to
available := make([]structs.Context, 0, len(desired))
for _, c := range desired {
switch c {
case structs.Allocs, structs.Jobs, structs.Evals, structs.Deployments:
if jobRead {
available = append(available, c)
}
case structs.ScalingPolicies:
if policyRead || jobRead {
available = append(available, c)
}
case structs.Namespaces:
if aclObj.AllowNamespace(namespace) {
available = append(available, c)
}
case structs.Nodes:
if aclObj.AllowNodeRead() {
available = append(available, c)
}
case structs.Volumes:
if volRead {
available = append(available, c)
}
}
}
return available
}