package main
import (
+ "encoding/json"
"errors"
"fmt"
+ "io/ioutil"
"os"
"strings"
"github.com/containernetworking/cni/pkg/skel"
+ "github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/cni/pkg/version"
noop_debug "github.com/containernetworking/cni/plugins/test/noop/debug"
)
+type NetConf struct {
+ types.NetConf
+ DebugFile string `json:"debugFile"`
+}
+
+func loadConf(bytes []byte) (*NetConf, error) {
+ n := &NetConf{}
+ if err := json.Unmarshal(bytes, n); err != nil {
+ return nil, fmt.Errorf("failed to load netconf: %v", err)
+ }
+ return n, nil
+}
+
// parse extra args i.e. FOO=BAR;ABC=123
func parseExtraArgs(args string) (map[string]string, error) {
m := make(map[string]string)
+ if len(args) == 0 {
+ return m, nil
+ }
items := strings.Split(args, ";")
for _, item := range items {
return m, nil
}
-func debugBehavior(args *skel.CmdArgs, command string) error {
- extraArgs, err := parseExtraArgs(args.Args)
+func getDebugFilePath(stdinData []byte, args string) (string, error) {
+ netConf, err := loadConf(stdinData)
if err != nil {
- return err
+ return "", err
+ }
+
+ extraArgs, err := parseExtraArgs(args)
+ if err != nil {
+ return "", err
}
debugFilePath, ok := extraArgs["DEBUG"]
if !ok {
+ debugFilePath = netConf.DebugFile
+ }
+
+ return debugFilePath, nil
+}
+
+func debugBehavior(args *skel.CmdArgs, command string) error {
+ debugFilePath, err := getDebugFilePath(args.StdinData, args.Args)
+ if err != nil {
+ return err
+ }
+
+ if debugFilePath == "" {
fmt.Printf(`{}`)
- os.Stderr.WriteString("CNI_ARGS empty, no debug behavior\n")
+ os.Stderr.WriteString("CNI_ARGS or config empty, no debug behavior\n")
return nil
}
return nil
}
-func debugGetSupportedVersions() []string {
+func debugGetSupportedVersions(stdinData []byte) []string {
vers := []string{"0.-42.0", "0.1.0", "0.2.0"}
cniArgs := os.Getenv("CNI_ARGS")
if cniArgs == "" {
return vers
}
- extraArgs, err := parseExtraArgs(cniArgs)
+ debugFilePath, err := getDebugFilePath(stdinData, cniArgs)
if err != nil {
- panic("test setup error: invalid CNI_ARGS format")
- }
-
- debugFilePath, ok := extraArgs["DEBUG"]
- if !ok {
- panic("test setup error: missing DEBUG in CNI_ARGS")
+ panic("test setup error: unable to get debug file path: " + err.Error())
}
debug, err := noop_debug.ReadDebug(debugFilePath)
return debugBehavior(args, "DEL")
}
+func saveStdin() ([]byte, error) {
+ // Read original stdin
+ stdinData, err := ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ return nil, err
+ }
+
+ // Make a new pipe for stdin, and write original stdin data to it
+ r, w, err := os.Pipe()
+ if err != nil {
+ return nil, err
+ }
+ if _, err := w.Write(stdinData); err != nil {
+ return nil, err
+ }
+ if err := w.Close(); err != nil {
+ return nil, err
+ }
+
+ os.Stdin = r
+ return stdinData, nil
+}
+
func main() {
- supportedVersions := debugGetSupportedVersions()
+ // Grab and read stdin before pkg/skel gets it
+ stdinData, err := saveStdin()
+ if err != nil {
+ panic("test setup error: unable to read stdin: " + err.Error())
+ }
+
+ supportedVersions := debugGetSupportedVersions(stdinData)
skel.PluginMain(cmdAdd, cmdDel, version.PluginSupports(supportedVersions...))
}
cmd.Env = []string{
"CNI_COMMAND=ADD",
"CNI_CONTAINERID=some-container-id",
- "CNI_ARGS=" + args,
"CNI_NETNS=/some/netns/path",
"CNI_IFNAME=some-eth0",
"CNI_PATH=/some/bin/path",
+ // Keep this last
+ "CNI_ARGS=" + args,
}
cmd.Stdin = strings.NewReader(`{"some":"stdin-json", "cniVersion": "0.2.0"}`)
expectedCmdArgs = skel.CmdArgs{
Expect(session.Out.Contents()).To(MatchJSON(reportResult))
})
+ It("panics when no debug file is given", func() {
+ // Remove the DEBUG option from CNI_ARGS and regular args
+ cmd.Env[len(cmd.Env)-1] = "CNI_ARGS=FOO=BAR"
+ expectedCmdArgs.Args = "FOO=BAR"
+
+ session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
+ Expect(err).NotTo(HaveOccurred())
+ Eventually(session).Should(gexec.Exit(2))
+ })
+
+ It("allows passing debug file in config JSON", func() {
+ // Remove the DEBUG option from CNI_ARGS and regular args
+ newArgs := "FOO=BAR"
+ cmd.Env[len(cmd.Env)-1] = "CNI_ARGS=" + newArgs
+ newStdin := fmt.Sprintf(`{"some":"stdin-json", "cniVersion": "0.2.0", "debugFile": "%s"}`, debugFileName)
+ cmd.Stdin = strings.NewReader(newStdin)
+ expectedCmdArgs.Args = newArgs
+ expectedCmdArgs.StdinData = []byte(newStdin)
+
+ session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
+ Expect(err).NotTo(HaveOccurred())
+ Eventually(session).Should(gexec.Exit(0))
+ Expect(session.Out.Contents()).To(MatchJSON(reportResult))
+
+ debug, err := noop_debug.ReadDebug(debugFileName)
+ Expect(err).NotTo(HaveOccurred())
+ Expect(debug.Command).To(Equal("ADD"))
+ Expect(debug.CmdArgs).To(Equal(expectedCmdArgs))
+ })
+
It("records all the args provided by skel.PluginMain", func() {
session, err := gexec.Start(cmd, GinkgoWriter, GinkgoWriter)
Expect(err).NotTo(HaveOccurred())