Skip to content

Commit f6fbb36

Browse files
committed
sync
1 parent f4e93d9 commit f6fbb36

File tree

104 files changed

+3718
-435
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+3718
-435
lines changed

acl/acl.go

+52
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type ACL struct {
4747
agent string
4848
node string
4949
operator string
50+
quota string
5051
}
5152

5253
// maxPrivilege returns the policy which grants the most privilege
@@ -115,6 +116,9 @@ func NewACL(management bool, policies []*Policy) (*ACL, error) {
115116
if policy.Operator != nil {
116117
acl.operator = maxPrivilege(acl.operator, policy.Operator.Policy)
117118
}
119+
if policy.Quota != nil {
120+
acl.quota = maxPrivilege(acl.quota, policy.Quota.Policy)
121+
}
118122
}
119123

120124
// Finalize the namespaces
@@ -145,6 +149,28 @@ func (a *ACL) AllowNamespaceOperation(ns string, op string) bool {
145149
return capabilities.Check(op)
146150
}
147151

152+
// AllowNamespace checks if any operations are allowed for a namespace
153+
func (a *ACL) AllowNamespace(ns string) bool {
154+
// Hot path management tokens
155+
if a.management {
156+
return true
157+
}
158+
159+
// Check for a matching capability set
160+
raw, ok := a.namespaces.Get([]byte(ns))
161+
if !ok {
162+
return false
163+
}
164+
165+
// Check if the capability has been granted
166+
capabilities := raw.(capabilitySet)
167+
if len(capabilities) == 0 {
168+
return false
169+
}
170+
171+
return !capabilities.Check(PolicyDeny)
172+
}
173+
148174
// AllowAgentRead checks if read operations are allowed for an agent
149175
func (a *ACL) AllowAgentRead() bool {
150176
switch {
@@ -223,6 +249,32 @@ func (a *ACL) AllowOperatorWrite() bool {
223249
}
224250
}
225251

252+
// AllowQuotaRead checks if read operations are allowed for all quotas
253+
func (a *ACL) AllowQuotaRead() bool {
254+
switch {
255+
case a.management:
256+
return true
257+
case a.quota == PolicyWrite:
258+
return true
259+
case a.quota == PolicyRead:
260+
return true
261+
default:
262+
return false
263+
}
264+
}
265+
266+
// AllowQuotaWrite checks if write operations are allowed for quotas
267+
func (a *ACL) AllowQuotaWrite() bool {
268+
switch {
269+
case a.management:
270+
return true
271+
case a.quota == PolicyWrite:
272+
return true
273+
default:
274+
return false
275+
}
276+
}
277+
226278
// IsManagement checks if this represents a management token
227279
func (a *ACL) IsManagement() bool {
228280
return a.management

acl/acl_test.go

+115-48
Original file line numberDiff line numberDiff line change
@@ -60,95 +60,111 @@ func TestMaxPrivilege(t *testing.T) {
6060
}
6161

6262
func TestACLManagement(t *testing.T) {
63+
assert := assert.New(t)
64+
6365
// Create management ACL
6466
acl, err := NewACL(true, nil)
65-
assert.Nil(t, err)
67+
assert.Nil(err)
6668

6769
// Check default namespace rights
68-
assert.Equal(t, true, acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
69-
assert.Equal(t, true, acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
70+
assert.True(acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
71+
assert.True(acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
72+
assert.True(acl.AllowNamespace("default"))
7073

7174
// Check non-specified namespace
72-
assert.Equal(t, true, acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
75+
assert.True(acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
76+
assert.True(acl.AllowNamespace("foo"))
7377

7478
// Check the other simpler operations
75-
assert.Equal(t, true, acl.IsManagement())
76-
assert.Equal(t, true, acl.AllowAgentRead())
77-
assert.Equal(t, true, acl.AllowAgentWrite())
78-
assert.Equal(t, true, acl.AllowNodeRead())
79-
assert.Equal(t, true, acl.AllowNodeWrite())
80-
assert.Equal(t, true, acl.AllowOperatorRead())
81-
assert.Equal(t, true, acl.AllowOperatorWrite())
79+
assert.True(acl.IsManagement())
80+
assert.True(acl.AllowAgentRead())
81+
assert.True(acl.AllowAgentWrite())
82+
assert.True(acl.AllowNodeRead())
83+
assert.True(acl.AllowNodeWrite())
84+
assert.True(acl.AllowOperatorRead())
85+
assert.True(acl.AllowOperatorWrite())
86+
assert.True(acl.AllowQuotaRead())
87+
assert.True(acl.AllowQuotaWrite())
8288
}
8389

8490
func TestACLMerge(t *testing.T) {
91+
assert := assert.New(t)
92+
8593
// Merge read + write policy
8694
p1, err := Parse(readAll)
87-
assert.Nil(t, err)
95+
assert.Nil(err)
8896
p2, err := Parse(writeAll)
89-
assert.Nil(t, err)
97+
assert.Nil(err)
9098
acl, err := NewACL(false, []*Policy{p1, p2})
91-
assert.Nil(t, err)
99+
assert.Nil(err)
92100

93101
// Check default namespace rights
94-
assert.Equal(t, true, acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
95-
assert.Equal(t, true, acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
102+
assert.True(acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
103+
assert.True(acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
104+
assert.True(acl.AllowNamespace("default"))
96105

97106
// Check non-specified namespace
98-
assert.Equal(t, false, acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
107+
assert.False(acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
108+
assert.False(acl.AllowNamespace("foo"))
99109

100110
// Check the other simpler operations
101-
assert.Equal(t, false, acl.IsManagement())
102-
assert.Equal(t, true, acl.AllowAgentRead())
103-
assert.Equal(t, true, acl.AllowAgentWrite())
104-
assert.Equal(t, true, acl.AllowNodeRead())
105-
assert.Equal(t, true, acl.AllowNodeWrite())
106-
assert.Equal(t, true, acl.AllowOperatorRead())
107-
assert.Equal(t, true, acl.AllowOperatorWrite())
111+
assert.False(acl.IsManagement())
112+
assert.True(acl.AllowAgentRead())
113+
assert.True(acl.AllowAgentWrite())
114+
assert.True(acl.AllowNodeRead())
115+
assert.True(acl.AllowNodeWrite())
116+
assert.True(acl.AllowOperatorRead())
117+
assert.True(acl.AllowOperatorWrite())
118+
assert.True(acl.AllowQuotaRead())
119+
assert.True(acl.AllowQuotaWrite())
108120

109121
// Merge read + blank
110122
p3, err := Parse("")
111-
assert.Nil(t, err)
123+
assert.Nil(err)
112124
acl, err = NewACL(false, []*Policy{p1, p3})
113-
assert.Nil(t, err)
125+
assert.Nil(err)
114126

115127
// Check default namespace rights
116-
assert.Equal(t, true, acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
117-
assert.Equal(t, false, acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
128+
assert.True(acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
129+
assert.False(acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
118130

119131
// Check non-specified namespace
120-
assert.Equal(t, false, acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
132+
assert.False(acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
121133

122134
// Check the other simpler operations
123-
assert.Equal(t, false, acl.IsManagement())
124-
assert.Equal(t, true, acl.AllowAgentRead())
125-
assert.Equal(t, false, acl.AllowAgentWrite())
126-
assert.Equal(t, true, acl.AllowNodeRead())
127-
assert.Equal(t, false, acl.AllowNodeWrite())
128-
assert.Equal(t, true, acl.AllowOperatorRead())
129-
assert.Equal(t, false, acl.AllowOperatorWrite())
135+
assert.False(acl.IsManagement())
136+
assert.True(acl.AllowAgentRead())
137+
assert.False(acl.AllowAgentWrite())
138+
assert.True(acl.AllowNodeRead())
139+
assert.False(acl.AllowNodeWrite())
140+
assert.True(acl.AllowOperatorRead())
141+
assert.False(acl.AllowOperatorWrite())
142+
assert.True(acl.AllowQuotaRead())
143+
assert.False(acl.AllowQuotaWrite())
130144

131145
// Merge read + deny
132146
p4, err := Parse(denyAll)
133-
assert.Nil(t, err)
147+
assert.Nil(err)
134148
acl, err = NewACL(false, []*Policy{p1, p4})
135-
assert.Nil(t, err)
149+
assert.Nil(err)
136150

137151
// Check default namespace rights
138-
assert.Equal(t, false, acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
139-
assert.Equal(t, false, acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
152+
assert.False(acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
153+
assert.False(acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
140154

141155
// Check non-specified namespace
142-
assert.Equal(t, false, acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
156+
assert.False(acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
143157

144158
// Check the other simpler operations
145-
assert.Equal(t, false, acl.IsManagement())
146-
assert.Equal(t, false, acl.AllowAgentRead())
147-
assert.Equal(t, false, acl.AllowAgentWrite())
148-
assert.Equal(t, false, acl.AllowNodeRead())
149-
assert.Equal(t, false, acl.AllowNodeWrite())
150-
assert.Equal(t, false, acl.AllowOperatorRead())
151-
assert.Equal(t, false, acl.AllowOperatorWrite())
159+
assert.False(acl.IsManagement())
160+
assert.False(acl.AllowAgentRead())
161+
assert.False(acl.AllowAgentWrite())
162+
assert.False(acl.AllowNodeRead())
163+
assert.False(acl.AllowNodeWrite())
164+
assert.False(acl.AllowOperatorRead())
165+
assert.False(acl.AllowOperatorWrite())
166+
assert.False(acl.AllowQuotaRead())
167+
assert.False(acl.AllowQuotaWrite())
152168
}
153169

154170
var readAll = `
@@ -164,6 +180,9 @@ node {
164180
operator {
165181
policy = "read"
166182
}
183+
quota {
184+
policy = "read"
185+
}
167186
`
168187

169188
var writeAll = `
@@ -179,6 +198,9 @@ node {
179198
operator {
180199
policy = "write"
181200
}
201+
quota {
202+
policy = "write"
203+
}
182204
`
183205

184206
var denyAll = `
@@ -194,4 +216,49 @@ node {
194216
operator {
195217
policy = "deny"
196218
}
219+
quota {
220+
policy = "deny"
221+
}
197222
`
223+
224+
func TestAllowNamespace(t *testing.T) {
225+
tests := []struct {
226+
Policy string
227+
Allow bool
228+
}{
229+
{
230+
Policy: `namespace "foo" {}`,
231+
Allow: false,
232+
},
233+
{
234+
Policy: `namespace "foo" { policy = "deny" }`,
235+
Allow: false,
236+
},
237+
{
238+
Policy: `namespace "foo" { capabilities = ["deny"] }`,
239+
Allow: false,
240+
},
241+
{
242+
Policy: `namespace "foo" { capabilities = ["list-jobs"] }`,
243+
Allow: true,
244+
},
245+
{
246+
Policy: `namespace "foo" { policy = "read" }`,
247+
Allow: true,
248+
},
249+
}
250+
251+
for _, tc := range tests {
252+
t.Run(tc.Policy, func(t *testing.T) {
253+
assert := assert.New(t)
254+
255+
policy, err := Parse(tc.Policy)
256+
assert.Nil(err)
257+
258+
acl, err := NewACL(false, []*Policy{policy})
259+
assert.Nil(err)
260+
261+
assert.Equal(tc.Allow, acl.AllowNamespace("foo"))
262+
})
263+
}
264+
}

acl/policy.go

+9
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type Policy struct {
4141
Agent *AgentPolicy `hcl:"agent"`
4242
Node *NodePolicy `hcl:"node"`
4343
Operator *OperatorPolicy `hcl:"operator"`
44+
Quota *QuotaPolicy `hcl:"quota"`
4445
Raw string `hcl:"-"`
4546
}
4647

@@ -63,6 +64,10 @@ type OperatorPolicy struct {
6364
Policy string
6465
}
6566

67+
type QuotaPolicy struct {
68+
Policy string
69+
}
70+
6671
// isPolicyValid makes sure the given string matches one of the valid policies.
6772
func isPolicyValid(policy string) bool {
6873
switch policy {
@@ -162,5 +167,9 @@ func Parse(rules string) (*Policy, error) {
162167
if p.Operator != nil && !isPolicyValid(p.Operator.Policy) {
163168
return nil, fmt.Errorf("Invalid operator policy: %#v", p.Operator)
164169
}
170+
171+
if p.Quota != nil && !isPolicyValid(p.Quota.Policy) {
172+
return nil, fmt.Errorf("Invalid quota policy: %#v", p.Quota)
173+
}
165174
return p, nil
166175
}

acl/policy_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ func TestParse(t *testing.T) {
5555
operator {
5656
policy = "deny"
5757
}
58+
quota {
59+
policy = "read"
60+
}
5861
`,
5962
"",
6063
&Policy{
@@ -96,6 +99,9 @@ func TestParse(t *testing.T) {
9699
Operator: &OperatorPolicy{
97100
Policy: PolicyDeny,
98101
},
102+
Quota: &QuotaPolicy{
103+
Policy: PolicyRead,
104+
},
99105
},
100106
},
101107
{
@@ -143,6 +149,15 @@ func TestParse(t *testing.T) {
143149
"Invalid operator policy",
144150
nil,
145151
},
152+
{
153+
`
154+
quota {
155+
policy = "foo"
156+
}
157+
`,
158+
"Invalid quota policy",
159+
nil,
160+
},
146161
{
147162
`
148163
namespace "has a space"{

api/allocations.go

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ type AllocationMetric struct {
107107
NodesExhausted int
108108
ClassExhausted map[string]int
109109
DimensionExhausted map[string]int
110+
QuotaExhausted []string
110111
Scores map[string]float64
111112
AllocationTime time.Duration
112113
CoalescedFailures int

api/contexts/contexts.go

+1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ const (
1010
Jobs Context = "jobs"
1111
Nodes Context = "nodes"
1212
Namespaces Context = "namespaces"
13+
Quotas Context = "quotas"
1314
All Context = "all"
1415
)

api/evaluations.go

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ type Evaluation struct {
7373
FailedTGAllocs map[string]*AllocationMetric
7474
ClassEligibility map[string]bool
7575
EscapedComputedClass bool
76+
QuotaLimitReached string
7677
AnnotatePlan bool
7778
QueuedAllocations map[string]int
7879
SnapshotIndex uint64

0 commit comments

Comments
 (0)