summaryrefslogtreecommitdiff
path: root/libpod/network/cni/cni_exec.go
diff options
context:
space:
mode:
authorPaul Holzinger <pholzing@redhat.com>2021-07-15 10:29:19 +0200
committerPaul Holzinger <pholzing@redhat.com>2021-08-24 12:28:03 +0200
commitc0b1edd6a4dcad2b89a01975988d186b21b3158e (patch)
treeea500d48f28682ad36f6eb4954717c6629fb68b4 /libpod/network/cni/cni_exec.go
parente20ec47a59b4ac65d42f3fee7b8b7ec5760ea35d (diff)
downloadpodman-c0b1edd6a4dcad2b89a01975988d186b21b3158e.tar.gz
podman-c0b1edd6a4dcad2b89a01975988d186b21b3158e.tar.bz2
podman-c0b1edd6a4dcad2b89a01975988d186b21b3158e.zip
Network interface
Implement a new network interface to abstract CNI from libpod. The interface is implemented for the CNI backend but in the future we can add more backends. The code is structured in three new packages: - `libpod/network/types`: contains the interface definition and the necessary types for it. - `libpod/network/cni` contains the interface implementation for the CNI backend. - `libpod/network/util` a set of utility functions related to networking. The CNI package uses ginkgo style unit tests. To test Setup/Teardown the test must be run as root. Each test will run in their own namespace to make the test independent from the host environment. New features with the CNI backend: - The default network will be created in memory if it does not exists on disk. - It can set more than one static IP per container network. - Networks are loaded once from disk and only if this interface is used, e.g. for commands such as `podman info` networks are not loaded. This reduces unnecessary disk IO. This commit only adds the interface it is not wired into libpod. This requires a lot of breaking changes which will be done in a followup commit. Once this is integrated into libpod the current network code under `libpod/network` should be removed. Also the dependency on OCICNI should be dropped. Signed-off-by: Paul Holzinger <pholzing@redhat.com>
Diffstat (limited to 'libpod/network/cni/cni_exec.go')
-rw-r--r--libpod/network/cni/cni_exec.go98
1 files changed, 98 insertions, 0 deletions
diff --git a/libpod/network/cni/cni_exec.go b/libpod/network/cni/cni_exec.go
new file mode 100644
index 000000000..0aec3d4f1
--- /dev/null
+++ b/libpod/network/cni/cni_exec.go
@@ -0,0 +1,98 @@
+// Copyright 2016 CNI authors
+// Copyright 2021 Podman authors
+//
+// This code has been originally copied from github.com/containernetworking/cni
+// but has been changed to better fit the Podman use case.
+//
+// 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.
+
+// +build linux
+
+package cni
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "os/exec"
+ "path/filepath"
+
+ "github.com/containernetworking/cni/pkg/invoke"
+ "github.com/containernetworking/cni/pkg/version"
+)
+
+type cniExec struct {
+ version.PluginDecoder
+}
+
+type cniPluginError struct {
+ plugin string
+ Code uint `json:"code"`
+ Msg string `json:"msg"`
+ Details string `json:"details,omitempty"`
+}
+
+// Error returns a nicely formatted error message for the cni plugin errors.
+func (e *cniPluginError) Error() string {
+ err := fmt.Sprintf("cni plugin %s failed", e.plugin)
+ if e.Msg != "" {
+ err = fmt.Sprintf("%s: %s", err, e.Msg)
+ } else if e.Code > 0 {
+ err = fmt.Sprintf("%s with error code %d", err, e.Code)
+ }
+ if e.Details != "" {
+ err = fmt.Sprintf("%s: %s", err, e.Details)
+ }
+ return err
+}
+
+// ExecPlugin execute the cni plugin. Returns the stdout of the plugin or an error.
+func (e *cniExec) ExecPlugin(ctx context.Context, pluginPath string, stdinData []byte, environ []string) ([]byte, error) {
+ stdout := &bytes.Buffer{}
+ stderr := &bytes.Buffer{}
+ c := exec.CommandContext(ctx, pluginPath)
+ c.Env = environ
+ c.Stdin = bytes.NewBuffer(stdinData)
+ c.Stdout = stdout
+ c.Stderr = stderr
+
+ err := c.Run()
+ if err != nil {
+ return nil, annotatePluginError(err, pluginPath, stdout.Bytes(), stderr.Bytes())
+ }
+ return stdout.Bytes(), nil
+}
+
+// annotatePluginError parses the common cni plugin error json.
+func annotatePluginError(err error, plugin string, stdout []byte, stderr []byte) error {
+ pluginName := filepath.Base(plugin)
+ emsg := cniPluginError{
+ plugin: pluginName,
+ }
+ if len(stdout) == 0 {
+ if len(stderr) == 0 {
+ emsg.Msg = err.Error()
+ } else {
+ emsg.Msg = string(stderr)
+ }
+ } else if perr := json.Unmarshal(stdout, &emsg); perr != nil {
+ emsg.Msg = fmt.Sprintf("failed to unmarshal error message %q: %v", string(stdout), perr)
+ }
+ return &emsg
+}
+
+// FindInPath finds the plugin in the given paths.
+func (e *cniExec) FindInPath(plugin string, paths []string) (string, error) {
+ return invoke.FindInPath(plugin, paths)
+}