github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/networking/net_plugin.go (about) 1 // Copyright 2015 The rkt 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 package networking 16 17 import ( 18 "bytes" 19 "encoding/json" 20 "fmt" 21 "net" 22 "os" 23 "os/exec" 24 "path/filepath" 25 "strings" 26 27 cnitypes "github.com/appc/cni/pkg/types" 28 "github.com/hashicorp/errwrap" 29 30 "github.com/coreos/rkt/common" 31 ) 32 33 // TODO(eyakubovich): make this configurable in rkt.conf 34 const UserNetPluginsPath = "/usr/lib/rkt/plugins/net" 35 const BuiltinNetPluginsPath = "usr/lib/rkt/plugins/net" 36 37 func pluginErr(err error, output []byte) error { 38 if _, ok := err.(*exec.ExitError); ok { 39 emsg := cnitypes.Error{} 40 if perr := json.Unmarshal(output, &emsg); perr != nil { 41 return errwrap.Wrap(fmt.Errorf("netplugin failed but error parsing its diagnostic message %q", string(output)), perr) 42 } 43 details := "" 44 if emsg.Details != "" { 45 details = fmt.Sprintf("; %v", emsg.Details) 46 } 47 return fmt.Errorf("%v%v", emsg.Msg, details) 48 } 49 50 return err 51 } 52 53 func (e *podEnv) netPluginAdd(n *activeNet, netns string) (ip, hostIP net.IP, err error) { 54 output, err := e.execNetPlugin("ADD", n, netns) 55 if err != nil { 56 return nil, nil, pluginErr(err, output) 57 } 58 59 pr := cnitypes.Result{} 60 if err = json.Unmarshal(output, &pr); err != nil { 61 return nil, nil, errwrap.Wrap(fmt.Errorf("error parsing %q result", n.conf.Name), err) 62 } 63 64 if pr.IP4 == nil { 65 return nil, nil, fmt.Errorf("net-plugin returned no IPv4 configuration") 66 } 67 68 return pr.IP4.IP.IP, pr.IP4.Gateway, nil 69 } 70 71 func (e *podEnv) netPluginDel(n *activeNet, netns string) error { 72 output, err := e.execNetPlugin("DEL", n, netns) 73 if err != nil { 74 return pluginErr(err, output) 75 } 76 return nil 77 } 78 79 func (e *podEnv) pluginPaths() []string { 80 // try 3rd-party path first 81 return []string{ 82 filepath.Join(e.localConfig, UserNetPathSuffix), 83 UserNetPluginsPath, 84 filepath.Join(common.Stage1RootfsPath(e.podRoot), BuiltinNetPluginsPath), 85 } 86 } 87 88 func (e *podEnv) findNetPlugin(plugin string) string { 89 for _, p := range e.pluginPaths() { 90 fullname := filepath.Join(p, plugin) 91 if fi, err := os.Stat(fullname); err == nil && fi.Mode().IsRegular() { 92 return fullname 93 } 94 } 95 96 return "" 97 } 98 99 func envVars(vars [][2]string) []string { 100 env := os.Environ() 101 102 for _, kv := range vars { 103 env = append(env, strings.Join(kv[:], "=")) 104 } 105 106 return env 107 } 108 109 func (e *podEnv) execNetPlugin(cmd string, n *activeNet, netns string) ([]byte, error) { 110 pluginPath := e.findNetPlugin(n.conf.Type) 111 if pluginPath == "" { 112 return nil, fmt.Errorf("Could not find plugin %q", n.conf.Type) 113 } 114 115 vars := [][2]string{ 116 {"CNI_COMMAND", cmd}, 117 {"CNI_CONTAINERID", e.podID.String()}, 118 {"CNI_NETNS", netns}, 119 {"CNI_ARGS", n.runtime.Args}, 120 {"CNI_IFNAME", n.runtime.IfName}, 121 {"CNI_PATH", strings.Join(e.pluginPaths(), ":")}, 122 } 123 124 stdin := bytes.NewBuffer(n.confBytes) 125 stdout := &bytes.Buffer{} 126 127 c := exec.Cmd{ 128 Path: pluginPath, 129 Args: []string{pluginPath}, 130 Env: envVars(vars), 131 Stdin: stdin, 132 Stdout: stdout, 133 Stderr: os.Stderr, 134 } 135 136 err := c.Run() 137 return stdout.Bytes(), err 138 }