api.go 6.1 KB

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