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  }