From 3db6ba7667e64b763e97822a07871cdf6e20fd37 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 5 Sep 2017 15:06:26 -0500 Subject: [PATCH] vendor: add github.com/cri-o/ocicni Signed-off-by: Dan Williams --- vendor/github.com/cri-o/ocicni/LICENSE | 191 ++++++++ vendor/github.com/cri-o/ocicni/README.md | 3 + .../cri-o/ocicni/pkg/ocicni/noop.go | 24 + .../cri-o/ocicni/pkg/ocicni/ocicni.go | 421 ++++++++++++++++++ .../cri-o/ocicni/pkg/ocicni/types.go | 62 +++ .../cri-o/ocicni/pkg/ocicni/util.go | 32 ++ 6 files changed, 733 insertions(+) create mode 100644 vendor/github.com/cri-o/ocicni/LICENSE create mode 100644 vendor/github.com/cri-o/ocicni/README.md create mode 100644 vendor/github.com/cri-o/ocicni/pkg/ocicni/noop.go create mode 100644 vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go create mode 100644 vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go create mode 100644 vendor/github.com/cri-o/ocicni/pkg/ocicni/util.go diff --git a/vendor/github.com/cri-o/ocicni/LICENSE b/vendor/github.com/cri-o/ocicni/LICENSE new file mode 100644 index 00000000..3fd70307 --- /dev/null +++ b/vendor/github.com/cri-o/ocicni/LICENSE @@ -0,0 +1,191 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2016 Red Hat, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/cri-o/ocicni/README.md b/vendor/github.com/cri-o/ocicni/README.md new file mode 100644 index 00000000..99c103c8 --- /dev/null +++ b/vendor/github.com/cri-o/ocicni/README.md @@ -0,0 +1,3 @@ +# ocicni + +API layer to call the CNI plugins from an OCI lifecycle daemon diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/noop.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/noop.go new file mode 100644 index 00000000..9f315a7c --- /dev/null +++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/noop.go @@ -0,0 +1,24 @@ +package ocicni + +type cniNoOp struct { +} + +func (noop *cniNoOp) Name() string { + return "CNINoOp" +} + +func (noop *cniNoOp) SetUpPod(network PodNetwork) error { + return nil +} + +func (noop *cniNoOp) TearDownPod(network PodNetwork) error { + return nil +} + +func (noop *cniNoOp) GetPodNetworkStatus(network PodNetwork) (string, error) { + return "", nil +} + +func (noop *cniNoOp) Status() error { + return nil +} diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go new file mode 100644 index 00000000..03918bfa --- /dev/null +++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/ocicni.go @@ -0,0 +1,421 @@ +package ocicni + +import ( + "errors" + "fmt" + "os/exec" + "sort" + "strings" + "sync" + + "github.com/containernetworking/cni/libcni" + cnitypes "github.com/containernetworking/cni/pkg/types" + "github.com/fsnotify/fsnotify" + "github.com/sirupsen/logrus" +) + +type cniNetworkPlugin struct { + loNetwork *cniNetwork + + sync.RWMutex + defaultNetwork *cniNetwork + + nsenterPath string + pluginDir string + cniDirs []string + vendorCNIDirPrefix string + + monitorNetDirChan chan struct{} + + // The pod map provides synchronization for a given pod's network + // operations. Each pod's setup/teardown/status operations + // are synchronized against each other, but network operations of other + // pods can proceed in parallel. + podsLock sync.Mutex + pods map[string]*podLock +} + +type cniNetwork struct { + name string + NetworkConfig *libcni.NetworkConfigList + CNIConfig libcni.CNI +} + +var errMissingDefaultNetwork = errors.New("Missing CNI default network") + +type podLock struct { + // Count of in-flight operations for this pod; when this reaches zero + // the lock can be removed from the pod map + refcount uint + + // Lock to synchronize operations for this specific pod + mu sync.Mutex +} + +func buildFullPodName(podNetwork PodNetwork) string { + return podNetwork.Namespace + "_" + podNetwork.Name +} + +// Lock network operations for a specific pod. If that pod is not yet in +// the pod map, it will be added. The reference count for the pod will +// be increased. +func (plugin *cniNetworkPlugin) podLock(podNetwork PodNetwork) *sync.Mutex { + plugin.podsLock.Lock() + defer plugin.podsLock.Unlock() + + fullPodName := buildFullPodName(podNetwork) + lock, ok := plugin.pods[fullPodName] + if !ok { + lock = &podLock{} + plugin.pods[fullPodName] = lock + } + lock.refcount++ + return &lock.mu +} + +// Unlock network operations for a specific pod. The reference count for the +// pod will be decreased. If the reference count reaches zero, the pod will be +// removed from the pod map. +func (plugin *cniNetworkPlugin) podUnlock(podNetwork PodNetwork) { + plugin.podsLock.Lock() + defer plugin.podsLock.Unlock() + + fullPodName := buildFullPodName(podNetwork) + lock, ok := plugin.pods[fullPodName] + if !ok { + logrus.Warningf("Unbalanced pod lock unref for %s", fullPodName) + return + } else if lock.refcount == 0 { + // This should never ever happen, but handle it anyway + delete(plugin.pods, fullPodName) + logrus.Errorf("Pod lock for %s still in map with zero refcount", fullPodName) + return + } + lock.refcount-- + lock.mu.Unlock() + if lock.refcount == 0 { + delete(plugin.pods, fullPodName) + } +} + +func (plugin *cniNetworkPlugin) monitorNetDir() { + watcher, err := fsnotify.NewWatcher() + if err != nil { + logrus.Errorf("could not create new watcher %v", err) + return + } + defer watcher.Close() + + go func() { + for { + select { + case event := <-watcher.Events: + logrus.Debugf("CNI monitoring event %v", event) + if event.Op&fsnotify.Create != fsnotify.Create && + event.Op&fsnotify.Write != fsnotify.Write { + continue + } + + if err = plugin.syncNetworkConfig(); err == nil { + logrus.Infof("CNI asynchronous setting succeeded") + continue + } + + logrus.Errorf("CNI setting failed, continue monitoring: %v", err) + + case err := <-watcher.Errors: + logrus.Errorf("CNI monitoring error %v", err) + close(plugin.monitorNetDirChan) + return + } + } + }() + + if err = watcher.Add(plugin.pluginDir); err != nil { + logrus.Error(err) + return + } + + <-plugin.monitorNetDirChan +} + +// InitCNI takes the plugin directory and cni directories where the cni files should be searched for +// Returns a valid plugin object and any error +func InitCNI(pluginDir string, cniDirs ...string) (CNIPlugin, error) { + plugin := probeNetworkPluginsWithVendorCNIDirPrefix(pluginDir, cniDirs, "") + var err error + plugin.nsenterPath, err = exec.LookPath("nsenter") + if err != nil { + return nil, err + } + + // check if a default network exists, otherwise dump the CNI search and return a noop plugin + _, err = getDefaultCNINetwork(plugin.pluginDir, plugin.cniDirs, plugin.vendorCNIDirPrefix) + if err != nil { + if err != errMissingDefaultNetwork { + logrus.Warningf("Error in finding usable CNI plugin - %v", err) + // create a noop plugin instead + return &cniNoOp{}, nil + } + + // We do not have a default network, we start the monitoring thread. + go plugin.monitorNetDir() + } + + return plugin, nil +} + +func probeNetworkPluginsWithVendorCNIDirPrefix(pluginDir string, cniDirs []string, vendorCNIDirPrefix string) *cniNetworkPlugin { + plugin := &cniNetworkPlugin{ + defaultNetwork: nil, + loNetwork: getLoNetwork(cniDirs, vendorCNIDirPrefix), + pluginDir: pluginDir, + cniDirs: cniDirs, + vendorCNIDirPrefix: vendorCNIDirPrefix, + monitorNetDirChan: make(chan struct{}), + pods: make(map[string]*podLock), + } + + // sync NetworkConfig in best effort during probing. + if err := plugin.syncNetworkConfig(); err != nil { + logrus.Error(err) + } + return plugin +} + +func getDefaultCNINetwork(pluginDir string, cniDirs []string, vendorCNIDirPrefix string) (*cniNetwork, error) { + if pluginDir == "" { + pluginDir = DefaultNetDir + } + if len(cniDirs) == 0 { + cniDirs = []string{DefaultCNIDir} + } + + files, err := libcni.ConfFiles(pluginDir, []string{".conf", ".conflist", ".json"}) + switch { + case err != nil: + return nil, err + case len(files) == 0: + return nil, errMissingDefaultNetwork + } + + sort.Strings(files) + for _, confFile := range files { + var confList *libcni.NetworkConfigList + if strings.HasSuffix(confFile, ".conflist") { + confList, err = libcni.ConfListFromFile(confFile) + if err != nil { + logrus.Warningf("Error loading CNI config list file %s: %v", confFile, err) + continue + } + } else { + conf, err := libcni.ConfFromFile(confFile) + if err != nil { + logrus.Warningf("Error loading CNI config file %s: %v", confFile, err) + continue + } + if conf.Network.Type == "" { + logrus.Warningf("Error loading CNI config file %s: no 'type'; perhaps this is a .conflist?", confFile) + continue + } + confList, err = libcni.ConfListFromConf(conf) + if err != nil { + logrus.Warningf("Error converting CNI config file %s to list: %v", confFile, err) + continue + } + } + if len(confList.Plugins) == 0 { + logrus.Warningf("CNI config list %s has no networks, skipping", confFile) + continue + } + logrus.Infof("CNI network %s (type=%v) is used from %s", confList.Name, confList.Plugins[0].Network.Type, confFile) + // Search for vendor-specific plugins as well as default plugins in the CNI codebase. + vendorDir := vendorCNIDir(vendorCNIDirPrefix, confList.Plugins[0].Network.Type) + cninet := &libcni.CNIConfig{ + Path: append(cniDirs, vendorDir), + } + network := &cniNetwork{name: confList.Name, NetworkConfig: confList, CNIConfig: cninet} + return network, nil + } + return nil, fmt.Errorf("No valid networks found in %s", pluginDir) +} + +func vendorCNIDir(prefix, pluginType string) string { + return fmt.Sprintf(VendorCNIDirTemplate, prefix, pluginType) +} + +func getLoNetwork(cniDirs []string, vendorDirPrefix string) *cniNetwork { + if len(cniDirs) == 0 { + cniDirs = []string{DefaultCNIDir} + } + + loConfig, err := libcni.ConfListFromBytes([]byte(`{ + "cniVersion": "0.2.0", + "name": "cni-loopback", + "plugins": [{ + "type": "loopback" + }] +}`)) + if err != nil { + // The hardcoded config above should always be valid and unit tests will + // catch this + panic(err) + } + vendorDir := vendorCNIDir(vendorDirPrefix, loConfig.Plugins[0].Network.Type) + cninet := &libcni.CNIConfig{ + Path: append(cniDirs, vendorDir), + } + loNetwork := &cniNetwork{ + name: "lo", + NetworkConfig: loConfig, + CNIConfig: cninet, + } + + return loNetwork +} + +func (plugin *cniNetworkPlugin) syncNetworkConfig() error { + network, err := getDefaultCNINetwork(plugin.pluginDir, plugin.cniDirs, plugin.vendorCNIDirPrefix) + if err != nil { + logrus.Errorf("error updating cni config: %s", err) + return err + } + plugin.setDefaultNetwork(network) + + return nil +} + +func (plugin *cniNetworkPlugin) getDefaultNetwork() *cniNetwork { + plugin.RLock() + defer plugin.RUnlock() + return plugin.defaultNetwork +} + +func (plugin *cniNetworkPlugin) setDefaultNetwork(n *cniNetwork) { + plugin.Lock() + defer plugin.Unlock() + plugin.defaultNetwork = n +} + +func (plugin *cniNetworkPlugin) checkInitialized() error { + if plugin.getDefaultNetwork() == nil { + return errors.New("cni config uninitialized") + } + return nil +} + +func (plugin *cniNetworkPlugin) Name() string { + return CNIPluginName +} + +func (plugin *cniNetworkPlugin) SetUpPod(podNetwork PodNetwork) error { + if err := plugin.checkInitialized(); err != nil { + return err + } + + plugin.podLock(podNetwork).Lock() + defer plugin.podUnlock(podNetwork) + + _, err := plugin.loNetwork.addToNetwork(podNetwork) + if err != nil { + logrus.Errorf("Error while adding to cni lo network: %s", err) + return err + } + + _, err = plugin.getDefaultNetwork().addToNetwork(podNetwork) + if err != nil { + logrus.Errorf("Error while adding to cni network: %s", err) + return err + } + + return err +} + +func (plugin *cniNetworkPlugin) TearDownPod(podNetwork PodNetwork) error { + if err := plugin.checkInitialized(); err != nil { + return err + } + + plugin.podLock(podNetwork).Lock() + defer plugin.podUnlock(podNetwork) + + return plugin.getDefaultNetwork().deleteFromNetwork(podNetwork) +} + +// TODO: Use the addToNetwork function to obtain the IP of the Pod. That will assume idempotent ADD call to the plugin. +// Also fix the runtime's call to Status function to be done only in the case that the IP is lost, no need to do periodic calls +func (plugin *cniNetworkPlugin) GetPodNetworkStatus(podNetwork PodNetwork) (string, error) { + plugin.podLock(podNetwork).Lock() + defer plugin.podUnlock(podNetwork) + + ip, err := getContainerIP(plugin.nsenterPath, podNetwork.NetNS, DefaultInterfaceName, "-4") + if err != nil { + return "", err + } + + return ip.String(), nil +} + +func (network *cniNetwork) addToNetwork(podNetwork PodNetwork) (cnitypes.Result, error) { + rt, err := buildCNIRuntimeConf(podNetwork) + if err != nil { + logrus.Errorf("Error adding network: %v", err) + return nil, err + } + + netconf, cninet := network.NetworkConfig, network.CNIConfig + logrus.Infof("About to add CNI network %s (type=%v)", netconf.Name, netconf.Plugins[0].Network.Type) + res, err := cninet.AddNetworkList(netconf, rt) + if err != nil { + logrus.Errorf("Error adding network: %v", err) + return nil, err + } + + return res, nil +} + +func (network *cniNetwork) deleteFromNetwork(podNetwork PodNetwork) error { + rt, err := buildCNIRuntimeConf(podNetwork) + if err != nil { + logrus.Errorf("Error deleting network: %v", err) + return err + } + + netconf, cninet := network.NetworkConfig, network.CNIConfig + logrus.Infof("About to del CNI network %s (type=%v)", netconf.Name, netconf.Plugins[0].Network.Type) + err = cninet.DelNetworkList(netconf, rt) + if err != nil { + logrus.Errorf("Error deleting network: %v", err) + return err + } + return nil +} + +func buildCNIRuntimeConf(podNetwork PodNetwork) (*libcni.RuntimeConf, error) { + logrus.Infof("Got pod network %+v", podNetwork) + + rt := &libcni.RuntimeConf{ + ContainerID: podNetwork.ID, + NetNS: podNetwork.NetNS, + IfName: DefaultInterfaceName, + Args: [][2]string{ + {"IgnoreUnknown", "1"}, + {"K8S_POD_NAMESPACE", podNetwork.Namespace}, + {"K8S_POD_NAME", podNetwork.Name}, + {"K8S_POD_INFRA_CONTAINER_ID", podNetwork.ID}, + }, + } + + if len(podNetwork.PortMappings) == 0 { + return rt, nil + } + + rt.CapabilityArgs = map[string]interface{}{ + "portMappings": podNetwork.PortMappings, + } + return rt, nil +} + +func (plugin *cniNetworkPlugin) Status() error { + return plugin.checkInitialized() +} diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go new file mode 100644 index 00000000..a272e92e --- /dev/null +++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/types.go @@ -0,0 +1,62 @@ +package ocicni + +const ( + // DefaultInterfaceName is the string to be used for the interface name inside the net namespace + DefaultInterfaceName = "eth0" + // CNIPluginName is the default name of the plugin + CNIPluginName = "cni" + // DefaultNetDir is the place to look for CNI Network + DefaultNetDir = "/etc/cni/net.d" + // DefaultCNIDir is the place to look for cni config files + DefaultCNIDir = "/opt/cni/bin" + // VendorCNIDirTemplate is the template for looking up vendor specific cni config/executable files + VendorCNIDirTemplate = "%s/opt/%s/bin" +) + +// PortMapping maps to the standard CNI portmapping Capability +// see: https://github.com/containernetworking/cni/blob/master/CONVENTIONS.md +type PortMapping struct { + // HostPort is the port number on the host. + HostPort int32 `json:"hostPort"` + // ContainerPort is the port number inside the sandbox. + ContainerPort int32 `json:"containerPort"` + // Protocol is the protocol of the port mapping. + Protocol string `json:"protocol"` + // HostIP is the host ip to use. + HostIP string `json:"hostIP"` +} + +// PodNetwork configures the network of a pod sandbox. +type PodNetwork struct { + // Name is the name of the sandbox. + Name string + // Namespace is the namespace of the sandbox. + Namespace string + // ID is the id of the sandbox container. + ID string + // NetNS is the network namespace path of the sandbox. + NetNS string + // PortMappings is the port mapping of the sandbox. + PortMappings []PortMapping +} + +// CNIPlugin is the interface that needs to be implemented by a plugin +type CNIPlugin interface { + // Name returns the plugin's name. This will be used when searching + // for a plugin by name, e.g. + Name() string + + // SetUpPod is the method called after the sandbox container of + // the pod has been created but before the other containers of the + // pod are launched. + SetUpPod(network PodNetwork) error + + // TearDownPod is the method called before a pod's sandbox container will be deleted + TearDownPod(network PodNetwork) error + + // Status is the method called to obtain the ipv4 or ipv6 addresses of the pod sandbox + GetPodNetworkStatus(network PodNetwork) (string, error) + + // NetworkStatus returns error if the network plugin is in error state + Status() error +} diff --git a/vendor/github.com/cri-o/ocicni/pkg/ocicni/util.go b/vendor/github.com/cri-o/ocicni/pkg/ocicni/util.go new file mode 100644 index 00000000..547e9597 --- /dev/null +++ b/vendor/github.com/cri-o/ocicni/pkg/ocicni/util.go @@ -0,0 +1,32 @@ +package ocicni + +import ( + "fmt" + "net" + "os/exec" + "strings" +) + +func getContainerIP(nsenterPath, netnsPath, interfaceName, addrType string) (net.IP, error) { + // Try to retrieve ip inside container network namespace + output, err := exec.Command(nsenterPath, fmt.Sprintf("--net=%s", netnsPath), "-F", "--", + "ip", "-o", addrType, "addr", "show", "dev", interfaceName, "scope", "global").CombinedOutput() + if err != nil { + return nil, fmt.Errorf("Unexpected command output %s with error: %v", output, err) + } + + lines := strings.Split(string(output), "\n") + if len(lines) < 1 { + return nil, fmt.Errorf("Unexpected command output %s", output) + } + fields := strings.Fields(lines[0]) + if len(fields) < 4 { + return nil, fmt.Errorf("Unexpected address output %s ", lines[0]) + } + ip, _, err := net.ParseCIDR(fields[3]) + if err != nil { + return nil, fmt.Errorf("CNI failed to parse ip from output %s due to %v", output, err) + } + + return ip, nil +}