From 5b328d9adc98cb317f39d7006179ed84308efb04 Mon Sep 17 00:00:00 2001 From: Tim Gross Date: Mon, 13 May 2024 15:42:35 -0400 Subject: [PATCH] CSI: add support for wildcard namespaces on `plugin status` (#20551) The `nomad plugin status :plugin_id` command lists allocations that implement the plugin being queried. This list is filtered by the `-namespace` flag as usual. Cluster admins will likely deploy plugins to a single namespace, but for convenience they may want to have the wildcard namespace set in their command environment. Add support for handling the wildcard namespace to the CSI plugin RPC handler. Fixes: https://github.com/hashicorp/nomad/issues/20537 --- .changelog/20551.txt | 3 +++ nomad/csi_endpoint.go | 15 ++++++++++----- nomad/csi_endpoint_test.go | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 .changelog/20551.txt diff --git a/.changelog/20551.txt b/.changelog/20551.txt new file mode 100644 index 000000000..a6f922fe6 --- /dev/null +++ b/.changelog/20551.txt @@ -0,0 +1,3 @@ +```release-note:improvement +csi: Added support for wildcard namespace to `plugin status` command +``` diff --git a/nomad/csi_endpoint.go b/nomad/csi_endpoint.go index afa7aaa0c..006b8c912 100644 --- a/nomad/csi_endpoint.go +++ b/nomad/csi_endpoint.go @@ -1797,7 +1797,8 @@ func (v *CSIPlugin) Get(args *structs.CSIPluginGetRequest, reply *structs.CSIPlu return structs.ErrPermissionDenied } - withAllocs := aclObj.AllowNsOp(args.RequestNamespace(), acl.NamespaceCapabilityReadJob) + ns := args.RequestNamespace() + withAllocs := aclObj.AllowNsOp(ns, acl.NamespaceCapabilityReadJob) if args.ID == "" { return fmt.Errorf("missing plugin ID") @@ -1821,18 +1822,22 @@ func (v *CSIPlugin) Get(args *structs.CSIPluginGetRequest, reply *structs.CSIPlu return nil } + // if we're not allowed access to the namespace at all, we skip this + // copy as an optimization. withAllocs will be true for the wildcard + // namespace if withAllocs { plug, err = snap.CSIPluginDenormalize(ws, plug.Copy()) if err != nil { return err } - // Filter the allocation stubs by our namespace. withAllocs - // means we're allowed + // Filter the allocation stubs by allowed namespace var as []*structs.AllocListStub for _, a := range plug.Allocations { - if a.Namespace == args.RequestNamespace() { - as = append(as, a) + if ns == structs.AllNamespacesSentinel || a.Namespace == ns { + if aclObj.AllowNsOp(a.Namespace, acl.NamespaceCapabilityReadJob) { + as = append(as, a) + } } } plug.Allocations = as diff --git a/nomad/csi_endpoint_test.go b/nomad/csi_endpoint_test.go index c1d1e9959..d22cce25e 100644 --- a/nomad/csi_endpoint_test.go +++ b/nomad/csi_endpoint_test.go @@ -2478,10 +2478,24 @@ func TestCSIPluginEndpoint_ACLNamespaceFilterAlloc(t *testing.T) { must.Eq(t, structs.DefaultNamespace, a.Namespace) } + // filter out all allocs p2 := mock.PluginPolicy("read") t2 := mock.CreatePolicyAndToken(t, s, 1004, "plugin-read2", p2) req.AuthToken = t2.SecretID err = msgpackrpc.CallWithCodec(codec, "CSIPlugin.Get", req, resp) must.NoError(t, err) must.Eq(t, 0, len(resp.Plugin.Allocations)) + + // wildcard namespace filter + p3 := mock.PluginPolicy("read") + + mock.NamespacePolicy(ns1.Name, "", []string{acl.NamespaceCapabilityReadJob}) + t3 := mock.CreatePolicyAndToken(t, s, 1005, "plugin-read", p3) + + req.Namespace = structs.AllNamespacesSentinel + req.AuthToken = t3.SecretID + resp = &structs.CSIPluginGetResponse{} + err = msgpackrpc.CallWithCodec(codec, "CSIPlugin.Get", req, resp) + must.NoError(t, err) + must.Eq(t, 1, len(resp.Plugin.Allocations)) + must.Eq(t, ns1.Name, resp.Plugin.Allocations[0].Namespace) }