Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic Host Volumes #24479

Merged
merged 35 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
d8c9015
dynamic host volumes: ACL policies (#24356)
tgross Nov 5, 2024
75c142f
dynamic host volumes: initial state store implementation (#24353)
tgross Nov 7, 2024
6a3803c
dynamic host volumes: RPC handlers (#24373)
tgross Nov 8, 2024
a65358d
dynamic host volumes: HTTP API endpoint (#24380)
tgross Nov 11, 2024
7c85176
dynamic host volumes: basic CLI CRUD operations (#24382)
tgross Nov 11, 2024
c373512
allow FlattenMultierror to accept standard error
tgross Nov 19, 2024
0f92134
dynamic host volumes: fix unblocking bug in state store
tgross Nov 19, 2024
10a5f48
dynamic host volumes: create/register RPC validation
tgross Nov 18, 2024
c2dd97d
HostVolumePlugin interface and two implementations (#24497)
gulducat Nov 20, 2024
bbf49a9
dynamic host volumes: node selection via constraints (#24518)
tgross Nov 21, 2024
0a08ddb
dynamic host volumes: update volume from node fingerprint (#24521)
tgross Nov 21, 2024
2b04d47
dynamic host volumes: test client RPC and plugins (#24535)
gulducat Nov 22, 2024
298460d
dynamic host volumes: monitor readiness from CLI (#24528)
tgross Nov 22, 2024
926925b
dynamic host volumes: search endpoint (#24531)
tgross Nov 22, 2024
d1352b2
dynamic host volumes: Enterprise stubs and refactor API (#24545)
tgross Dec 2, 2024
e3864a5
dynamic host volumes: autocomplete for CLI (#24533)
tgross Dec 2, 2024
f0b89fc
dynamic host volumes: make example-host-volume plugin run on macOS (#…
pkazmierczak Dec 2, 2024
df258ac
dynamic host volumes: set namespace from volume spec when monitoring …
tgross Dec 2, 2024
46a3956
dynamic host volumes: fingerprint client plugins (#24589)
gulducat Dec 2, 2024
d700538
dynamic host volumes: Sentinel improvements for CLI (#24592)
tgross Dec 3, 2024
787fbbe
sentinel: remove default scope for Sentinel apply command (#24601)
tgross Dec 3, 2024
05f1cda
dynamic host volumes: client state (#24595)
gulducat Dec 3, 2024
67ed31d
dynamic host volumes: add implicit constraints on plugin fingerprint …
tgross Dec 4, 2024
5826e92
dynamic host volumes: delete by single volume ID (#24606)
gulducat Dec 4, 2024
76641c8
dynamic host volumes: refactor HTTP routes for volumes list dispatch …
tgross Dec 6, 2024
e76f5e0
dynamic host volumes: volume fingerprinting (#24613)
gulducat Dec 9, 2024
3143019
dynamic host volumes: capabilities check during scheduling (#24617)
tgross Dec 10, 2024
258b159
stateful deployments: add Sticky property to task group volumes (#24641)
pkazmierczak Dec 11, 2024
fd05e46
dynamic host volumes: add -type flag to volume init (#24667)
tgross Dec 16, 2024
967adde
stateful deployments: add corrections to API structs and methods (#24…
pkazmierczak Dec 17, 2024
2adf6d5
dynamic host volumes: remove multi-node access modes (#24705)
tgross Dec 18, 2024
8cbb747
stateful deployments: find feasible node for sticky host volumes (#24…
pkazmierczak Dec 18, 2024
af96718
dynamic host volumes: tweak plugin fingerprint (#24711)
gulducat Dec 18, 2024
fea8461
dynamic host volumes: account for other claims in capability check (#…
tgross Dec 19, 2024
ad1e597
stateful deployments: validate there are no sticky per_alloc volume r…
pkazmierczak Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/24601.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:breaking-change
sentinel: The sentinel apply command now requires the -scope option
```
4 changes: 4 additions & 0 deletions acl/acl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ func TestACLManagement(t *testing.T) {
// Check default namespace rights
must.True(t, acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
must.True(t, acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
must.True(t, acl.AllowNamespaceOperation("default", NamespaceCapabilityHostVolumeCreate))
must.True(t, acl.AllowNamespace("default"))

// Check non-specified namespace
must.True(t, acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
must.True(t, acl.AllowNamespaceOperation("foo", NamespaceCapabilityHostVolumeCreate))
must.True(t, acl.AllowNamespace("foo"))

// Check node pool rights.
Expand Down Expand Up @@ -155,9 +157,11 @@ func TestACLMerge(t *testing.T) {
// Check default namespace rights
must.True(t, acl.AllowNamespaceOperation("default", NamespaceCapabilityListJobs))
must.False(t, acl.AllowNamespaceOperation("default", NamespaceCapabilitySubmitJob))
must.False(t, acl.AllowNamespaceOperation("default", NamespaceCapabilityHostVolumeRegister))

// Check non-specified namespace
must.False(t, acl.AllowNamespaceOperation("foo", NamespaceCapabilityListJobs))
must.False(t, acl.AllowNamespaceOperation("foo", NamespaceCapabilityHostVolumeCreate))

// Check rights in the node pool specified in policies.
must.True(t, acl.AllowNodePoolOperation("my-pool", NodePoolCapabilityRead))
Expand Down
38 changes: 37 additions & 1 deletion acl/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ const (
NamespaceCapabilityCSIReadVolume = "csi-read-volume"
NamespaceCapabilityCSIListVolume = "csi-list-volume"
NamespaceCapabilityCSIMountVolume = "csi-mount-volume"
NamespaceCapabilityHostVolumeCreate = "host-volume-create"
NamespaceCapabilityHostVolumeRegister = "host-volume-register"
NamespaceCapabilityHostVolumeRead = "host-volume-read"
NamespaceCapabilityHostVolumeWrite = "host-volume-write"
NamespaceCapabilityHostVolumeDelete = "host-volume-delete"
NamespaceCapabilityListScalingPolicies = "list-scaling-policies"
NamespaceCapabilityReadScalingPolicy = "read-scaling-policy"
NamespaceCapabilityReadJobScaling = "read-job-scaling"
Expand Down Expand Up @@ -207,7 +212,7 @@ func isNamespaceCapabilityValid(cap string) bool {
NamespaceCapabilityReadFS, NamespaceCapabilityAllocLifecycle,
NamespaceCapabilityAllocExec, NamespaceCapabilityAllocNodeExec,
NamespaceCapabilityCSIReadVolume, NamespaceCapabilityCSIWriteVolume, NamespaceCapabilityCSIListVolume, NamespaceCapabilityCSIMountVolume, NamespaceCapabilityCSIRegisterPlugin,
NamespaceCapabilityListScalingPolicies, NamespaceCapabilityReadScalingPolicy, NamespaceCapabilityReadJobScaling, NamespaceCapabilityScaleJob:
NamespaceCapabilityListScalingPolicies, NamespaceCapabilityReadScalingPolicy, NamespaceCapabilityReadJobScaling, NamespaceCapabilityScaleJob, NamespaceCapabilityHostVolumeCreate, NamespaceCapabilityHostVolumeRegister, NamespaceCapabilityHostVolumeWrite, NamespaceCapabilityHostVolumeRead:
return true
// Separate the enterprise-only capabilities
case NamespaceCapabilitySentinelOverride, NamespaceCapabilitySubmitRecommendation:
Expand Down Expand Up @@ -241,6 +246,7 @@ func expandNamespacePolicy(policy string) []string {
NamespaceCapabilityReadJobScaling,
NamespaceCapabilityListScalingPolicies,
NamespaceCapabilityReadScalingPolicy,
NamespaceCapabilityHostVolumeRead,
}

write := make([]string, len(read))
Expand All @@ -257,6 +263,7 @@ func expandNamespacePolicy(policy string) []string {
NamespaceCapabilityCSIMountVolume,
NamespaceCapabilityCSIWriteVolume,
NamespaceCapabilitySubmitRecommendation,
NamespaceCapabilityHostVolumeCreate,
}...)

switch policy {
Expand All @@ -278,6 +285,32 @@ func expandNamespacePolicy(policy string) []string {
}
}

// expandNamespaceCapabilities adds extra capabilities implied by fine-grained
// capabilities.
func expandNamespaceCapabilities(ns *NamespacePolicy) {
extraCaps := []string{}
for _, cap := range ns.Capabilities {
switch cap {
case NamespaceCapabilityHostVolumeWrite:
extraCaps = append(extraCaps,
NamespaceCapabilityHostVolumeRegister,
NamespaceCapabilityHostVolumeCreate,
NamespaceCapabilityHostVolumeDelete,
NamespaceCapabilityHostVolumeRead)
case NamespaceCapabilityHostVolumeRegister:
extraCaps = append(extraCaps,
NamespaceCapabilityHostVolumeCreate,
NamespaceCapabilityHostVolumeRead)
case NamespaceCapabilityHostVolumeCreate:
extraCaps = append(extraCaps, NamespaceCapabilityHostVolumeRead)
}
}

// These may end up being duplicated, but they'll get deduplicated in NewACL
// when inserted into the radix tree.
ns.Capabilities = append(ns.Capabilities, extraCaps...)
}

func isNodePoolCapabilityValid(cap string) bool {
switch cap {
case NodePoolCapabilityDelete, NodePoolCapabilityRead, NodePoolCapabilityWrite,
Expand Down Expand Up @@ -388,6 +421,9 @@ func Parse(rules string) (*Policy, error) {
ns.Capabilities = append(ns.Capabilities, extraCap...)
}

// Expand implicit capabilities
expandNamespaceCapabilities(ns)

if ns.Variables != nil {
if len(ns.Variables.Paths) == 0 {
return nil, fmt.Errorf("Invalid variable policy: no variable paths in namespace %s", ns.Name)
Expand Down
86 changes: 69 additions & 17 deletions acl/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package acl

import (
"fmt"
"strings"
"testing"

"github.com/hashicorp/nomad/ci"
Expand All @@ -17,9 +16,9 @@ func TestParse(t *testing.T) {
ci.Parallel(t)

type tcase struct {
Raw string
ErrStr string
Expect *Policy
Raw string
ExpectErr string
Expect *Policy
}
tcases := []tcase{
{
Expand All @@ -43,6 +42,7 @@ func TestParse(t *testing.T) {
NamespaceCapabilityReadJobScaling,
NamespaceCapabilityListScalingPolicies,
NamespaceCapabilityReadScalingPolicy,
NamespaceCapabilityHostVolumeRead,
},
},
},
Expand Down Expand Up @@ -118,6 +118,7 @@ func TestParse(t *testing.T) {
NamespaceCapabilityReadJobScaling,
NamespaceCapabilityListScalingPolicies,
NamespaceCapabilityReadScalingPolicy,
NamespaceCapabilityHostVolumeRead,
},
},
{
Expand All @@ -132,6 +133,7 @@ func TestParse(t *testing.T) {
NamespaceCapabilityReadJobScaling,
NamespaceCapabilityListScalingPolicies,
NamespaceCapabilityReadScalingPolicy,
NamespaceCapabilityHostVolumeRead,
NamespaceCapabilityScaleJob,
NamespaceCapabilitySubmitJob,
NamespaceCapabilityDispatchJob,
Expand All @@ -142,6 +144,8 @@ func TestParse(t *testing.T) {
NamespaceCapabilityCSIMountVolume,
NamespaceCapabilityCSIWriteVolume,
NamespaceCapabilitySubmitRecommendation,
NamespaceCapabilityHostVolumeCreate,
NamespaceCapabilityHostVolumeRead,
},
},
{
Expand Down Expand Up @@ -338,6 +342,7 @@ func TestParse(t *testing.T) {
NamespaceCapabilityReadJobScaling,
NamespaceCapabilityListScalingPolicies,
NamespaceCapabilityReadScalingPolicy,
NamespaceCapabilityHostVolumeRead,
},
},
{
Expand All @@ -352,6 +357,7 @@ func TestParse(t *testing.T) {
NamespaceCapabilityReadJobScaling,
NamespaceCapabilityListScalingPolicies,
NamespaceCapabilityReadScalingPolicy,
NamespaceCapabilityHostVolumeRead,
NamespaceCapabilityScaleJob,
NamespaceCapabilitySubmitJob,
NamespaceCapabilityDispatchJob,
Expand All @@ -362,6 +368,8 @@ func TestParse(t *testing.T) {
NamespaceCapabilityCSIMountVolume,
NamespaceCapabilityCSIWriteVolume,
NamespaceCapabilitySubmitRecommendation,
NamespaceCapabilityHostVolumeCreate,
NamespaceCapabilityHostVolumeRead,
},
},
{
Expand Down Expand Up @@ -638,6 +646,54 @@ func TestParse(t *testing.T) {
},
},
},
{
`
namespace "default" {
capabilities = ["host-volume-register"]
}

namespace "other" {
capabilities = ["host-volume-create"]
}

namespace "foo" {
capabilities = ["host-volume-write"]
}
`,
"",
&Policy{
Namespaces: []*NamespacePolicy{
{
Name: "default",
Policy: "",
Capabilities: []string{
NamespaceCapabilityHostVolumeRegister,
NamespaceCapabilityHostVolumeCreate,
NamespaceCapabilityHostVolumeRead,
},
},
{
Name: "other",
Policy: "",
Capabilities: []string{
NamespaceCapabilityHostVolumeCreate,
NamespaceCapabilityHostVolumeRead,
},
},
{
Name: "foo",
Policy: "",
Capabilities: []string{
NamespaceCapabilityHostVolumeWrite,
NamespaceCapabilityHostVolumeRegister,
NamespaceCapabilityHostVolumeCreate,
NamespaceCapabilityHostVolumeDelete,
NamespaceCapabilityHostVolumeRead,
},
},
},
},
},
{
`
node_pool "pool-read-only" {
Expand Down Expand Up @@ -878,22 +934,18 @@ func TestParse(t *testing.T) {
}

for idx, tc := range tcases {
t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
t.Run(fmt.Sprintf("%02d", idx), func(t *testing.T) {
p, err := Parse(tc.Raw)
if err != nil {
if tc.ErrStr == "" {
t.Fatalf("Unexpected err: %v", err)
}
if !strings.Contains(err.Error(), tc.ErrStr) {
t.Fatalf("Unexpected err: %v", err)
}
return
if tc.ExpectErr == "" {
must.NoError(t, err)
} else {
must.ErrorContains(t, err, tc.ExpectErr)
}
if err == nil && tc.ErrStr != "" {
t.Fatalf("Missing expected err")

if tc.Expect != nil {
tc.Expect.Raw = tc.Raw
must.Eq(t, tc.Expect, p)
}
tc.Expect.Raw = tc.Raw
assert.EqualValues(t, tc.Expect, p)
})
}
}
Expand Down
2 changes: 2 additions & 0 deletions api/allocations.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,8 @@ type Allocation struct {
Resources *Resources
TaskResources map[string]*Resources
AllocatedResources *AllocatedResources
HostVolumeIDs []string
CSIVolumeIDs []string
Services map[string]string
Metrics *AllocationMetric
DesiredStatus string
Expand Down
1 change: 1 addition & 0 deletions api/contexts/contexts.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
Plugins Context = "plugins"
Variables Context = "vars"
Volumes Context = "volumes"
HostVolumes Context = "host_volumes"

// These Context types are used to associate a search result from a lower
// level Nomad object with one of the higher level Context types above.
Expand Down
Loading
Loading