mirror of https://github.com/containers/podman.git
				
				
				
			
		
			
				
	
	
		
			111 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
// 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
 | 
						|
//
 | 
						|
//     https://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"
 | 
						|
	"github.com/containers/podman/v3/pkg/rootless"
 | 
						|
)
 | 
						|
 | 
						|
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
 | 
						|
 | 
						|
	// The dnsname plugin tries to use XDG_RUNTIME_DIR to store files.
 | 
						|
	// podman run will have XDG_RUNTIME_DIR set and thus the cni plugin can use
 | 
						|
	// it. The problem is that XDG_RUNTIME_DIR is unset for the conmon process
 | 
						|
	// for rootful users. This causes issues since the cleanup process is spawned
 | 
						|
	// by conmon and thus not have XDG_RUNTIME_DIR set to same value as podman run.
 | 
						|
	// Because of it dnsname will not find the config files and cannot correctly cleanup.
 | 
						|
	// To fix this we should also unset XDG_RUNTIME_DIR for the cni plugins as rootful.
 | 
						|
	if !rootless.IsRootless() {
 | 
						|
		c.Env = append(c.Env, "XDG_RUNTIME_DIR=")
 | 
						|
	}
 | 
						|
 | 
						|
	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)
 | 
						|
}
 |