github.com/jk-he/cni@v0.8.1/plugins/test/noop/main.go (about) 1 // Copyright 2016 CNI authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 /* 16 Noop plugin is a CNI plugin designed for use as a test-double. 17 18 When calling, set the CNI_ARGS env var equal to the path of a file containing 19 the JSON encoding of a Debug. 20 */ 21 22 package main 23 24 import ( 25 "encoding/json" 26 "errors" 27 "fmt" 28 "io/ioutil" 29 "os" 30 "strings" 31 32 "github.com/containernetworking/cni/pkg/skel" 33 "github.com/containernetworking/cni/pkg/types" 34 "github.com/containernetworking/cni/pkg/types/current" 35 "github.com/containernetworking/cni/pkg/version" 36 noop_debug "github.com/containernetworking/cni/plugins/test/noop/debug" 37 ) 38 39 type NetConf struct { 40 types.NetConf 41 DebugFile string `json:"debugFile"` 42 PrevResult *current.Result `json:"prevResult,omitempty"` 43 } 44 45 func loadConf(bytes []byte) (*NetConf, error) { 46 n := &NetConf{} 47 if err := json.Unmarshal(bytes, n); err != nil { 48 return nil, fmt.Errorf("failed to load netconf: %v %q", err, string(bytes)) 49 } 50 return n, nil 51 } 52 53 // parse extra args i.e. FOO=BAR;ABC=123 54 func parseExtraArgs(args string) (map[string]string, error) { 55 m := make(map[string]string) 56 if len(args) == 0 { 57 return m, nil 58 } 59 60 items := strings.Split(args, ";") 61 for _, item := range items { 62 kv := strings.Split(item, "=") 63 if len(kv) != 2 { 64 return nil, fmt.Errorf("CNI_ARGS invalid key/value pair: %s", kv) 65 } 66 m[kv[0]] = kv[1] 67 } 68 return m, nil 69 } 70 71 func getConfig(stdinData []byte, args string) (string, *NetConf, error) { 72 netConf, err := loadConf(stdinData) 73 if err != nil { 74 return "", nil, err 75 } 76 77 extraArgs, err := parseExtraArgs(args) 78 if err != nil { 79 return "", nil, err 80 } 81 82 debugFilePath, ok := extraArgs["DEBUG"] 83 if !ok { 84 debugFilePath = netConf.DebugFile 85 } 86 87 return debugFilePath, netConf, nil 88 } 89 90 func debugBehavior(args *skel.CmdArgs, command string) error { 91 debugFilePath, netConf, err := getConfig(args.StdinData, args.Args) 92 if err != nil { 93 return err 94 } 95 96 if debugFilePath == "" { 97 fmt.Printf(`{}`) 98 _, err = os.Stderr.WriteString("CNI_ARGS or config empty, no debug behavior\n") 99 if err != nil { 100 return err 101 } 102 return nil 103 } 104 105 debug, err := noop_debug.ReadDebug(debugFilePath) 106 if err != nil { 107 return err 108 } 109 110 debug.CmdArgs = *args 111 debug.Command = command 112 113 err = debug.WriteDebug(debugFilePath) 114 if err != nil { 115 return err 116 } 117 118 if debug.ReportStderr != "" { 119 if _, err = os.Stderr.WriteString(debug.ReportStderr); err != nil { 120 return err 121 } 122 } 123 124 if debug.ReportError != "" { 125 return errors.New(debug.ReportError) 126 } else if debug.ReportResult == "PASSTHROUGH" || debug.ReportResult == "INJECT-DNS" { 127 prevResult := netConf.PrevResult 128 if debug.ReportResult == "INJECT-DNS" { 129 prevResult, err = current.NewResultFromResult(netConf.PrevResult) 130 if err != nil { 131 return err 132 } 133 prevResult.DNS.Nameservers = []string{"1.2.3.4"} 134 } 135 136 // Must print the prevResult as the CNIVersion of the config 137 newResult, err := prevResult.GetAsVersion(netConf.CNIVersion) 138 if err != nil { 139 return fmt.Errorf("failed to convert result to config %q: %v", netConf.CNIVersion, err) 140 } 141 resultBytes, err := json.Marshal(newResult) 142 if err != nil { 143 return fmt.Errorf("failed to marshal new result: %v", err) 144 } 145 _, err = os.Stdout.WriteString(string(resultBytes)) 146 if err != nil { 147 return err 148 } 149 } else if debug.ReportResult != "" { 150 _, err = os.Stdout.WriteString(debug.ReportResult) 151 if err != nil { 152 return err 153 } 154 } 155 156 if debug.ExitWithCode > 0 { 157 os.Exit(debug.ExitWithCode) 158 } 159 return nil 160 } 161 162 func debugGetSupportedVersions(stdinData []byte) []string { 163 vers := []string{"0.-42.0", "0.1.0", "0.2.0", "0.3.0", "0.3.1", "0.4.0"} 164 cniArgs := os.Getenv("CNI_ARGS") 165 if cniArgs == "" { 166 return vers 167 } 168 169 debugFilePath, _, err := getConfig(stdinData, cniArgs) 170 if err != nil { 171 panic("test setup error: unable to get debug file path: " + err.Error()) 172 } 173 174 debug, err := noop_debug.ReadDebug(debugFilePath) 175 if err != nil { 176 panic("test setup error: unable to read debug file: " + err.Error()) 177 } 178 if debug.ReportVersionSupport == nil { 179 return vers 180 } 181 return debug.ReportVersionSupport 182 } 183 184 func cmdAdd(args *skel.CmdArgs) error { 185 return debugBehavior(args, "ADD") 186 } 187 188 func cmdCheck(args *skel.CmdArgs) error { 189 return debugBehavior(args, "CHECK") 190 } 191 192 func cmdDel(args *skel.CmdArgs) error { 193 return debugBehavior(args, "DEL") 194 } 195 196 func saveStdin() ([]byte, error) { 197 // Read original stdin 198 stdinData, err := ioutil.ReadAll(os.Stdin) 199 if err != nil { 200 return nil, err 201 } 202 203 // Make a new pipe for stdin, and write original stdin data to it 204 r, w, err := os.Pipe() 205 if err != nil { 206 return nil, err 207 } 208 if _, err := w.Write(stdinData); err != nil { 209 return nil, err 210 } 211 if err := w.Close(); err != nil { 212 return nil, err 213 } 214 215 os.Stdin = r 216 return stdinData, nil 217 } 218 219 func main() { 220 // Grab and read stdin before pkg/skel gets it 221 stdinData, err := saveStdin() 222 if err != nil { 223 panic("test setup error: unable to read stdin: " + err.Error()) 224 } 225 226 supportedVersions := debugGetSupportedVersions(stdinData) 227 skel.PluginMain(cmdAdd, cmdCheck, cmdDel, version.PluginSupports(supportedVersions...), "CNI noop plugin v0.7.0") 228 }