github.com/john-lin/cni@v0.6.0-rc1.0.20170712150331-b69e640cc0e2/libcni/api.go (about) 1 // Copyright 2015 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 package libcni 16 17 import ( 18 "os" 19 "strings" 20 21 "github.com/containernetworking/cni/pkg/invoke" 22 "github.com/containernetworking/cni/pkg/types" 23 "github.com/containernetworking/cni/pkg/version" 24 ) 25 26 type RuntimeConf struct { 27 ContainerID string 28 NetNS string 29 IfName string 30 Args [][2]string 31 // A dictionary of capability-specific data passed by the runtime 32 // to plugins as top-level keys in the 'runtimeConfig' dictionary 33 // of the plugin's stdin data. libcni will ensure that only keys 34 // in this map which match the capabilities of the plugin are passed 35 // to the plugin 36 CapabilityArgs map[string]interface{} 37 } 38 39 type NetworkConfig struct { 40 Network *types.NetConf 41 Bytes []byte 42 } 43 44 type NetworkConfigList struct { 45 Name string 46 CNIVersion string 47 Plugins []*NetworkConfig 48 Bytes []byte 49 } 50 51 type CNI interface { 52 AddNetworkList(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error) 53 DelNetworkList(net *NetworkConfigList, rt *RuntimeConf) error 54 55 AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) 56 DelNetwork(net *NetworkConfig, rt *RuntimeConf) error 57 } 58 59 type CNIConfig struct { 60 Path []string 61 } 62 63 // CNIConfig implements the CNI interface 64 var _ CNI = &CNIConfig{} 65 66 func buildOneConfig(list *NetworkConfigList, orig *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (*NetworkConfig, error) { 67 var err error 68 69 inject := map[string]interface{}{ 70 "name": list.Name, 71 "cniVersion": list.CNIVersion, 72 } 73 // Add previous plugin result 74 if prevResult != nil { 75 inject["prevResult"] = prevResult 76 } 77 78 // Ensure every config uses the same name and version 79 orig, err = InjectConf(orig, inject) 80 if err != nil { 81 return nil, err 82 } 83 84 return injectRuntimeConfig(orig, rt) 85 } 86 87 // This function takes a libcni RuntimeConf structure and injects values into 88 // a "runtimeConfig" dictionary in the CNI network configuration JSON that 89 // will be passed to the plugin on stdin. 90 // 91 // Only "capabilities arguments" passed by the runtime are currently injected. 92 // These capabilities arguments are filtered through the plugin's advertised 93 // capabilities from its config JSON, and any keys in the CapabilityArgs 94 // matching plugin capabilities are added to the "runtimeConfig" dictionary 95 // sent to the plugin via JSON on stdin. For exmaple, if the plugin's 96 // capabilities include "portMappings", and the CapabilityArgs map includes a 97 // "portMappings" key, that key and its value are added to the "runtimeConfig" 98 // dictionary to be passed to the plugin's stdin. 99 func injectRuntimeConfig(orig *NetworkConfig, rt *RuntimeConf) (*NetworkConfig, error) { 100 var err error 101 102 rc := make(map[string]interface{}) 103 for capability, supported := range orig.Network.Capabilities { 104 if !supported { 105 continue 106 } 107 if data, ok := rt.CapabilityArgs[capability]; ok { 108 rc[capability] = data 109 } 110 } 111 112 if len(rc) > 0 { 113 orig, err = InjectConf(orig, map[string]interface{}{"runtimeConfig": rc}) 114 if err != nil { 115 return nil, err 116 } 117 } 118 119 return orig, nil 120 } 121 122 // AddNetworkList executes a sequence of plugins with the ADD command 123 func (c *CNIConfig) AddNetworkList(list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) { 124 var prevResult types.Result 125 for _, net := range list.Plugins { 126 pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path) 127 if err != nil { 128 return nil, err 129 } 130 131 newConf, err := buildOneConfig(list, net, prevResult, rt) 132 if err != nil { 133 return nil, err 134 } 135 136 prevResult, err = invoke.ExecPluginWithResult(pluginPath, newConf.Bytes, c.args("ADD", rt)) 137 if err != nil { 138 return nil, err 139 } 140 } 141 142 return prevResult, nil 143 } 144 145 // DelNetworkList executes a sequence of plugins with the DEL command 146 func (c *CNIConfig) DelNetworkList(list *NetworkConfigList, rt *RuntimeConf) error { 147 for i := len(list.Plugins) - 1; i >= 0; i-- { 148 net := list.Plugins[i] 149 150 pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path) 151 if err != nil { 152 return err 153 } 154 155 newConf, err := buildOneConfig(list, net, nil, rt) 156 if err != nil { 157 return err 158 } 159 160 if err := invoke.ExecPluginWithoutResult(pluginPath, newConf.Bytes, c.args("DEL", rt)); err != nil { 161 return err 162 } 163 } 164 165 return nil 166 } 167 168 // AddNetwork executes the plugin with the ADD command 169 func (c *CNIConfig) AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) { 170 pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path) 171 if err != nil { 172 return nil, err 173 } 174 175 net, err = injectRuntimeConfig(net, rt) 176 if err != nil { 177 return nil, err 178 } 179 180 return invoke.ExecPluginWithResult(pluginPath, net.Bytes, c.args("ADD", rt)) 181 } 182 183 // DelNetwork executes the plugin with the DEL command 184 func (c *CNIConfig) DelNetwork(net *NetworkConfig, rt *RuntimeConf) error { 185 pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path) 186 if err != nil { 187 return err 188 } 189 190 net, err = injectRuntimeConfig(net, rt) 191 if err != nil { 192 return err 193 } 194 195 return invoke.ExecPluginWithoutResult(pluginPath, net.Bytes, c.args("DEL", rt)) 196 } 197 198 // GetVersionInfo reports which versions of the CNI spec are supported by 199 // the given plugin. 200 func (c *CNIConfig) GetVersionInfo(pluginType string) (version.PluginInfo, error) { 201 pluginPath, err := invoke.FindInPath(pluginType, c.Path) 202 if err != nil { 203 return nil, err 204 } 205 206 return invoke.GetVersionInfo(pluginPath) 207 } 208 209 // ===== 210 func (c *CNIConfig) args(action string, rt *RuntimeConf) *invoke.Args { 211 return &invoke.Args{ 212 Command: action, 213 ContainerID: rt.ContainerID, 214 NetNS: rt.NetNS, 215 PluginArgs: rt.Args, 216 IfName: rt.IfName, 217 Path: strings.Join(c.Path, string(os.PathListSeparator)), 218 } 219 }