From 8eb1091d788c18281ec837ff7818eb829cd99cef Mon Sep 17 00:00:00 2001 From: Casey Callendrello Date: Thu, 11 Jan 2024 19:17:45 +0100 Subject: [PATCH 1/2] pkg/invoke: add DelegateStatus, DelegateGC methods Signed-off-by: Casey Callendrello --- pkg/invoke/delegate.go | 25 ++++++++++++++------- pkg/invoke/delegate_test.go | 44 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/pkg/invoke/delegate.go b/pkg/invoke/delegate.go index 8defe4dd..c8b548e7 100644 --- a/pkg/invoke/delegate.go +++ b/pkg/invoke/delegate.go @@ -51,25 +51,34 @@ func DelegateAdd(ctx context.Context, delegatePlugin string, netconf []byte, exe // DelegateCheck calls the given delegate plugin with the CNI CHECK action and // JSON configuration func DelegateCheck(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { + return delegateNoResult(ctx, delegatePlugin, netconf, exec, "CHECK") +} + +func delegateNoResult(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec, verb string) error { pluginPath, realExec, err := delegateCommon(delegatePlugin, exec) if err != nil { return err } - // DelegateCheck will override the original CNI_COMMAND env from process with CHECK - return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs("CHECK"), realExec) + return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs(verb), realExec) } // DelegateDel calls the given delegate plugin with the CNI DEL action and // JSON configuration func DelegateDel(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { - pluginPath, realExec, err := delegateCommon(delegatePlugin, exec) - if err != nil { - return err - } + return delegateNoResult(ctx, delegatePlugin, netconf, exec, "DEL") +} - // DelegateDel will override the original CNI_COMMAND env from process with DEL - return ExecPluginWithoutResult(ctx, pluginPath, netconf, delegateArgs("DEL"), realExec) +// DelegateStatus calls the given delegate plugin with the CNI STATUS action and +// JSON configuration +func DelegateStatus(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { + return delegateNoResult(ctx, delegatePlugin, netconf, exec, "STATUS") +} + +// DelegateGC calls the given delegate plugin with the CNI GC action and +// JSON configuration +func DelegateGC(ctx context.Context, delegatePlugin string, netconf []byte, exec Exec) error { + return delegateNoResult(ctx, delegatePlugin, netconf, exec, "GC") } // return CNIArgs used by delegation diff --git a/pkg/invoke/delegate_test.go b/pkg/invoke/delegate_test.go index d7869bc8..023fa8e8 100644 --- a/pkg/invoke/delegate_test.go +++ b/pkg/invoke/delegate_test.go @@ -223,4 +223,48 @@ var _ = Describe("Delegate", func() { }) }) }) + + Describe("DelegateStatus", func() { + BeforeEach(func() { + os.Setenv("CNI_COMMAND", "STATUS") + }) + + It("finds and execs the named plugin", func() { + err := invoke.DelegateStatus(ctx, pluginName, netConf, nil) + Expect(err).NotTo(HaveOccurred()) + + pluginInvocation, err := debug.ReadDebug(debugFileName) + Expect(err).NotTo(HaveOccurred()) + Expect(pluginInvocation.Command).To(Equal("STATUS")) + }) + + Context("if the STATUS delegation runs on an existing non-STATUS command", func() { + BeforeEach(func() { + os.Setenv("CNI_COMMAND", "NOPE") + }) + + It("aborts and returns a useful error", func() { + err := invoke.DelegateStatus(ctx, pluginName, netConf, nil) + Expect(err).NotTo(HaveOccurred()) + + pluginInvocation, err := debug.ReadDebug(debugFileName) + Expect(err).NotTo(HaveOccurred()) + Expect(pluginInvocation.Command).To(Equal("STATUS")) + + // check the original env + Expect(os.Getenv("CNI_COMMAND")).To(Equal("NOPE")) + }) + }) + + Context("when the plugin cannot be found", func() { + BeforeEach(func() { + pluginName = "non-existent-plugin" + }) + + It("returns a useful error", func() { + err := invoke.DelegateStatus(ctx, pluginName, netConf, nil) + Expect(err).To(MatchError(HavePrefix("failed to find plugin"))) + }) + }) + }) }) From 56f11c6c0cc043e4d24a321c102f6a329a87a193 Mon Sep 17 00:00:00 2001 From: Casey Callendrello Date: Fri, 12 Jan 2024 21:07:53 +0100 Subject: [PATCH 2/2] types: add ValidAttachments to "base" NetConf struct Since every plugin needs to deserialize this, it should be in the standard network configuration struct. Signed-off-by: Casey Callendrello --- libcni/api.go | 10 +++------- libcni/api_test.go | 2 +- pkg/types/types.go | 11 +++++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libcni/api.go b/libcni/api.go index d32c0f60..5c7f3b02 100644 --- a/libcni/api.go +++ b/libcni/api.go @@ -89,12 +89,8 @@ type NetworkAttachment struct { CapabilityArgs map[string]interface{} } -type GCAttachment struct { - ContainerID string `json:"containerID"` - IfName string `json:"ifname"` -} type GCArgs struct { - ValidAttachments []GCAttachment + ValidAttachments []types.GCAttachment } type CNI interface { @@ -768,7 +764,7 @@ func (c *CNIConfig) GCNetworkList(ctx context.Context, list *NetworkConfigList, return nil } - validAttachments := make(map[GCAttachment]interface{}, len(args.ValidAttachments)) + validAttachments := make(map[types.GCAttachment]interface{}, len(args.ValidAttachments)) for _, a := range args.ValidAttachments { validAttachments[a] = nil } @@ -780,7 +776,7 @@ func (c *CNIConfig) GCNetworkList(ctx context.Context, list *NetworkConfigList, continue } // we found this attachment - gca := GCAttachment{ + gca := types.GCAttachment{ ContainerID: cachedAttachment.ContainerID, IfName: cachedAttachment.IfName, } diff --git a/libcni/api_test.go b/libcni/api_test.go index c00424da..33254633 100644 --- a/libcni/api_test.go +++ b/libcni/api_test.go @@ -1513,7 +1513,7 @@ var _ = Describe("Invoking plugins", func() { By("Issuing a GC with valid networks") gcargs := &libcni.GCArgs{ - ValidAttachments: []libcni.GCAttachment{{ + ValidAttachments: []types.GCAttachment{{ ContainerID: runtimeConfig.ContainerID, IfName: runtimeConfig.IfName, }}, diff --git a/pkg/types/types.go b/pkg/types/types.go index ed7a1bd9..193ac46e 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -68,6 +68,17 @@ type NetConf struct { RawPrevResult map[string]interface{} `json:"prevResult,omitempty"` PrevResult Result `json:"-"` + + // ValidAttachments is only supplied when executing a GC operation + ValidAttachments []GCAttachment `json:"cni.dev/valid-attachments,omitempty"` +} + +// GCAttachment is the parameters to a GC call -- namely, +// the container ID and ifname pair that represents a +// still-valid attachment. +type GCAttachment struct { + ContainerID string `json:"containerID"` + IfName string `json:"ifname"` } // Note: DNS should be omit if DNS is empty but default Marshal function