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

libcni, skel: implement STATUS #1030

Merged
merged 1 commit into from
Dec 4, 2023
Merged
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
36 changes: 36 additions & 0 deletions libcni/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ type CNI interface {
ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error)

GCNetworkList(ctx context.Context, net *NetworkConfigList, args *GCArgs) error
GetStatusNetworkList(ctx context.Context, net *NetworkConfigList) error

GetCachedAttachments(containerID string) ([]*NetworkAttachment, error)
}
Expand Down Expand Up @@ -829,6 +830,41 @@ func (c *CNIConfig) gcNetwork(ctx context.Context, net *NetworkConfig) error {
return invoke.ExecPluginWithoutResult(ctx, pluginPath, net.Bytes, args, c.exec)
}

func (c *CNIConfig) GetStatusNetworkList(ctx context.Context, list *NetworkConfigList) error {
// If the version doesn't support status, abort.
if gt, _ := version.GreaterThanOrEqualTo(list.CNIVersion, "1.1.0"); !gt {
return nil
}

inject := map[string]interface{}{
"name": list.Name,
"cniVersion": list.CNIVersion,
}

for _, plugin := range list.Plugins {
// build config here
pluginConfig, err := InjectConf(plugin, inject)
if err != nil {
return fmt.Errorf("failed to generate configuration to get plugin STATUS %s: %w", plugin.Network.Type, err)
}
if err := c.getStatusNetwork(ctx, pluginConfig); err != nil {
return err // Don't collect errors here, so we return a clean error code.
}
}
return nil
}

func (c *CNIConfig) getStatusNetwork(ctx context.Context, net *NetworkConfig) error {
c.ensureExec()
pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
if err != nil {
return err
}
args := c.args("STATUS", &RuntimeConf{})

return invoke.ExecPluginWithoutResult(ctx, pluginPath, net.Bytes, args, c.exec)
}

// =====
func (c *CNIConfig) args(action string, rt *RuntimeConf) *invoke.Args {
return &invoke.Args{
Expand Down
38 changes: 38 additions & 0 deletions libcni/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1580,6 +1580,44 @@ var _ = Describe("Invoking plugins", func() {
}
})
})
Describe("GetStatusNetworkList", func() {
It("issues a STATUS request", func() {
netConfigList, plugins = makePluginList("1.1.0", ipResult, rcMap)

err := cniConfig.GetStatusNetworkList(ctx, netConfigList)
Expect(err).NotTo(HaveOccurred())

debug, err := noop_debug.ReadDebug(plugins[0].debugFilePath)
Expect(err).NotTo(HaveOccurred())
Expect(debug.Command).To(Equal("STATUS"))
})

It("correctly reports an error", func() {
netConfigList, plugins = makePluginList("1.1.0", ipResult, rcMap)

plugins[1].debug.ReportError = "plugin error: banana"
plugins[1].debug.ReportErrorCode = 50
Expect(plugins[1].debug.WriteDebug(plugins[1].debugFilePath)).To(Succeed())

err := cniConfig.GetStatusNetworkList(ctx, netConfigList)
Expect(err).To(HaveOccurred())
var eerr *types.Error
Expect(errors.As(err, &eerr)).To(BeTrue())
Expect(eerr.Code).To(Equal(uint(50)))

debug, err := noop_debug.ReadDebug(plugins[0].debugFilePath)
Expect(err).NotTo(HaveOccurred())
Expect(debug.Command).To(Equal("STATUS"))

debug, err = noop_debug.ReadDebug(plugins[1].debugFilePath)
Expect(err).NotTo(HaveOccurred())
Expect(debug.Command).To(Equal("STATUS"))

debug, err = noop_debug.ReadDebug(plugins[2].debugFilePath)
Expect(err).NotTo(HaveOccurred())
Expect(debug.Command).To(Equal(""))
})
})
})

Describe("Invoking a sleep plugin", func() {
Expand Down
49 changes: 37 additions & 12 deletions pkg/skel/skel.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ func (t *dispatcher) getCmdArgsFromEnv() (string, *CmdArgs, *types.Error) {
"CNI_COMMAND",
&cmd,
reqForCmdEntry{
"ADD": true,
"CHECK": true,
"DEL": true,
"GC": true,
"ADD": true,
"CHECK": true,
"DEL": true,
"GC": true,
"STATUS": true,
},
nil,
},
Expand Down Expand Up @@ -120,10 +121,11 @@ func (t *dispatcher) getCmdArgsFromEnv() (string, *CmdArgs, *types.Error) {
"CNI_PATH",
&path,
reqForCmdEntry{
"ADD": true,
"CHECK": true,
"DEL": true,
"GC": true,
"ADD": true,
"CHECK": true,
"DEL": true,
"GC": true,
"STATUS": true,
},
nil,
},
Expand Down Expand Up @@ -310,6 +312,28 @@ func (t *dispatcher) pluginMain(funcs CNIFuncs, versionInfo version.PluginInfo,
}
}
return types.NewError(types.ErrIncompatibleCNIVersion, "plugin version does not allow GC", "")
case "STATUS":
configVersion, err := t.ConfVersionDecoder.Decode(cmdArgs.StdinData)
if err != nil {
return types.NewError(types.ErrDecodingFailure, err.Error(), "")
}
if gtet, err := version.GreaterThanOrEqualTo(configVersion, "1.1.0"); err != nil {
return types.NewError(types.ErrDecodingFailure, err.Error(), "")
} else if !gtet {
return types.NewError(types.ErrIncompatibleCNIVersion, "config version does not allow STATUS", "")
}
for _, pluginVersion := range versionInfo.SupportedVersions() {
gtet, err := version.GreaterThanOrEqualTo(pluginVersion, configVersion)
if err != nil {
return types.NewError(types.ErrDecodingFailure, err.Error(), "")
} else if gtet {
if err := t.checkVersionAndCall(cmdArgs, versionInfo, funcs.Status); err != nil {
return err
}
return nil
}
}
return types.NewError(types.ErrIncompatibleCNIVersion, "plugin version does not allow STATUS", "")
case "VERSION":
if err := versionInfo.Encode(t.Stdout); err != nil {
return types.NewError(types.ErrIOFailure, err.Error(), "")
Expand Down Expand Up @@ -342,10 +366,11 @@ func PluginMainWithError(cmdAdd, cmdCheck, cmdDel func(_ *CmdArgs) error, versio
// CNIFuncs contains a group of callback command funcs to be passed in as
// parameters to the core "main" for a plugin.
type CNIFuncs struct {
Add func(_ *CmdArgs) error
Del func(_ *CmdArgs) error
Check func(_ *CmdArgs) error
GC func(_ *CmdArgs) error
Add func(_ *CmdArgs) error
Del func(_ *CmdArgs) error
Check func(_ *CmdArgs) error
GC func(_ *CmdArgs) error
Status func(_ *CmdArgs) error
}

// PluginMainFuncsWithError is the core "main" for a plugin. It accepts
Expand Down
1 change: 1 addition & 0 deletions plugins/test/noop/debug/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type Debug struct {
// Report* fields allow the test to control the behavior of the no-op plugin
ReportResult string
ReportError string
ReportErrorCode uint
ReportStderr string
ReportVersionSupport []string
ExitWithCode int
Expand Down
23 changes: 17 additions & 6 deletions plugins/test/noop/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ package main

import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -136,7 +135,14 @@ func debugBehavior(args *skel.CmdArgs, command string) error {
}
switch {
case debug.ReportError != "":
return errors.New(debug.ReportError)
ec := debug.ReportErrorCode
if ec == 0 {
ec = types.ErrInternal
}
return &types.Error{
Msg: debug.ReportError,
Code: ec,
}
case debug.ReportResult == "PASSTHROUGH" || debug.ReportResult == "INJECT-DNS":
prevResult := netConf.PrevResult
if debug.ReportResult == "INJECT-DNS" {
Expand Down Expand Up @@ -212,6 +218,10 @@ func cmdGC(args *skel.CmdArgs) error {
return debugBehavior(args, "GC")
}

func cmdStatus(args *skel.CmdArgs) error {
return debugBehavior(args, "STATUS")
}

func saveStdin() ([]byte, error) {
// Read original stdin
stdinData, err := io.ReadAll(os.Stdin)
Expand Down Expand Up @@ -244,9 +254,10 @@ func main() {

supportedVersions := debugGetSupportedVersions(stdinData)
skel.PluginMainFuncs(skel.CNIFuncs{
Add: cmdAdd,
Check: cmdCheck,
Del: cmdDel,
GC: cmdGC,
Add: cmdAdd,
Check: cmdCheck,
Del: cmdDel,
GC: cmdGC,
Status: cmdStatus,
}, version.PluginSupports(supportedVersions...), "CNI noop plugin v0.7.0")
}
Loading