Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions pkg/multus/multus.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ func conflistStatus(rt *libcni.RuntimeConf, rawnetconflist []byte, multusNetconf
}
if gt, _ := cniversion.GreaterThanOrEqualTo(confList.CNIVersion, "1.1.0"); !gt {
logging.Debugf("conflistStatus: skipping STATUS for network list %q cniVersion %q (< 1.1.0)", confList.Name, confList.CNIVersion)
return nil
}

err = cniNet.GetStatusNetworkList(context.Background(), confList)
Expand Down
39 changes: 22 additions & 17 deletions pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,9 +434,14 @@ func (s *Server) handleCNIRequest(r *http.Request) ([]byte, error) {
return nil, fmt.Errorf("could not extract the CNI command args: %w", err)
}

k8sArgs, err := kubernetesRuntimeArgs(cr.Env, s.kubeclient)
if err != nil {
return nil, fmt.Errorf("could not extract the kubernetes runtime args: %w", err)
// STATUS and GC are plugin-level commands with no pod context,
// so they don't have K8S_POD_NAME/K8S_POD_NAMESPACE in CNI_ARGS.
var k8sArgs *types.K8sArgs
if cmdType != "STATUS" && cmdType != "GC" {
k8sArgs, err = kubernetesRuntimeArgs(cr.Env, s.kubeclient)
if err != nil {
return nil, fmt.Errorf("could not extract the kubernetes runtime args: %w", err)
}
}

result, err := s.HandleCNIRequest(cmdType, k8sArgs, cniCmdArgs)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider documenting that k8sArgs may be nil for STATUS/GC in the HandleCNIRequest() signature, or adding a nil guard in it.

Expand Down Expand Up @@ -514,6 +519,18 @@ func (s *Server) extractCniData(cniRequest *api.Request, overrideConf []byte) (s
}

cniCmdArgs := &skel.CmdArgs{}

// STATUS and GC are plugin-level commands with no pod context;
// they don't require CNI_CONTAINERID, CNI_NETNS, or CNI_ARGS.
if cmd == "STATUS" || cmd == "GC" {
var err error
cniCmdArgs.StdinData, err = overrideCNIConfigWithServerConfig(cniRequest.Config, overrideConf, s.ignoreReadinessIndicator)
if err != nil {
return "", nil, err
}
return cmd, cniCmdArgs, nil
}

cniCmdArgs.ContainerID, ok = cniRequest.Env["CNI_CONTAINERID"]
if !ok {
return "", nil, fmt.Errorf("missing CNI_CONTAINERID")
Expand Down Expand Up @@ -648,24 +665,12 @@ func (s *Server) cmdCheck(cmdArgs *skel.CmdArgs, k8sArgs *types.K8sArgs) error {
}

func (s *Server) cmdGC(cmdArgs *skel.CmdArgs, k8sArgs *types.K8sArgs) error {
namespace := string(k8sArgs.K8S_POD_NAMESPACE)
podName := string(k8sArgs.K8S_POD_NAME)
if namespace == "" || podName == "" {
return fmt.Errorf("required CNI variable missing. pod name: %s; pod namespace: %s", podName, namespace)
}

logging.Debugf("CmdGC for [%s/%s]. CNI conf: %+v", namespace, podName, *cmdArgs)
logging.Debugf("CmdGC. CNI conf: %+v", *cmdArgs)
return multus.CmdGC(cmdArgs, s.exec, s.kubeclient)
}

func (s *Server) cmdStatus(cmdArgs *skel.CmdArgs, k8sArgs *types.K8sArgs) error {
namespace := string(k8sArgs.K8S_POD_NAMESPACE)
podName := string(k8sArgs.K8S_POD_NAME)
if namespace == "" || podName == "" {
return fmt.Errorf("required CNI variable missing. pod name: %s; pod namespace: %s", podName, namespace)
}

logging.Debugf("CmdStatus for [%s/%s]. CNI conf: %+v", namespace, podName, *cmdArgs)
logging.Debugf("CmdStatus. CNI conf: %+v", *cmdArgs)
return multus.CmdStatus(cmdArgs, s.exec, s.kubeclient)
}

Expand Down
63 changes: 63 additions & 0 deletions pkg/server/thick_cni_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,69 @@ var _ = Describe(suiteName, func() {
})
})

Context("STATUS and GC commands without pod context", func() {
const configPath = "/tmp/foo.multus.conf"

var (
cniServer *Server
K8sClient *k8s.ClientInfo
ctx context.Context
cancel context.CancelFunc
)

BeforeEach(func() {
var err error
K8sClient = fakeK8sClient()
// Touch the default network file.
os.OpenFile(configPath, os.O_RDONLY|os.O_CREATE, 0755)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return values are ignored. We shall ensure no error returned by this call.


Expect(FilesystemPreRequirements(thickPluginRunDir)).To(Succeed())

ctx, cancel = context.WithCancel(context.TODO())
cniServer, err = startCNIServer(ctx, thickPluginRunDir, K8sClient, nil)
Expect(err).NotTo(HaveOccurred())

// Only set CNI_COMMAND — no CNI_CONTAINERID, CNI_NETNS, or CNI_ARGS
// to simulate how kubelet invokes STATUS/GC (plugin-level, no pod context).
os.Unsetenv("CNI_CONTAINERID")
os.Unsetenv("CNI_NETNS")
os.Unsetenv("CNI_ARGS")
})

AfterEach(func() {
cancel()
if _, errStat := os.Stat(configPath); errStat == nil {
Expect(os.Remove(configPath)).To(Succeed())
}
unregisterMetrics(cniServer)
Expect(cniServer.Close()).To(Succeed())
os.Unsetenv("CNI_COMMAND")
os.Unsetenv("CNI_ARGS")
})

It("STATUS succeeds with CNI_ARGS unset", func() {
Expect(os.Setenv("CNI_COMMAND", "STATUS")).NotTo(HaveOccurred())
Expect(api.CmdStatus(cniCmdArgs("", "", "", referenceConfig(thickPluginRunDir)))).To(Succeed())
})

It("GC succeeds with CNI_ARGS unset", func() {
Expect(os.Setenv("CNI_COMMAND", "GC")).NotTo(HaveOccurred())
Expect(api.CmdGC(cniCmdArgs("", "", "", referenceConfig(thickPluginRunDir)))).To(Succeed())
})

It("STATUS succeeds with CNI_ARGS empty", func() {
Expect(os.Setenv("CNI_COMMAND", "STATUS")).NotTo(HaveOccurred())
Expect(os.Setenv("CNI_ARGS", "")).NotTo(HaveOccurred())
Expect(api.CmdStatus(cniCmdArgs("", "", "", referenceConfig(thickPluginRunDir)))).To(Succeed())
})

It("GC succeeds with CNI_ARGS empty", func() {
Expect(os.Setenv("CNI_COMMAND", "GC")).NotTo(HaveOccurred())
Expect(os.Setenv("CNI_ARGS", "")).NotTo(HaveOccurred())
Expect(api.CmdGC(cniCmdArgs("", "", "", referenceConfig(thickPluginRunDir)))).To(Succeed())
})
})

Context("CNI operations started from the shim", func() {
const (
containerID = "123456789"
Expand Down