github.com/jk-he/cni@v0.8.1/pkg/invoke/args.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 invoke
    16  
    17  import (
    18  	"fmt"
    19  	"os"
    20  	"strings"
    21  )
    22  
    23  type CNIArgs interface {
    24  	// For use with os/exec; i.e., return nil to inherit the
    25  	// environment from this process
    26  	// For use in delegation; inherit the environment from this
    27  	// process and allow overrides
    28  	AsEnv() []string
    29  }
    30  
    31  type inherited struct{}
    32  
    33  var inheritArgsFromEnv inherited
    34  
    35  func (*inherited) AsEnv() []string {
    36  	return nil
    37  }
    38  
    39  func ArgsFromEnv() CNIArgs {
    40  	return &inheritArgsFromEnv
    41  }
    42  
    43  type Args struct {
    44  	Command       string
    45  	ContainerID   string
    46  	NetNS         string
    47  	PluginArgs    [][2]string
    48  	PluginArgsStr string
    49  	IfName        string
    50  	Path          string
    51  }
    52  
    53  // Args implements the CNIArgs interface
    54  var _ CNIArgs = &Args{}
    55  
    56  func (args *Args) AsEnv() []string {
    57  	env := os.Environ()
    58  	pluginArgsStr := args.PluginArgsStr
    59  	if pluginArgsStr == "" {
    60  		pluginArgsStr = stringify(args.PluginArgs)
    61  	}
    62  
    63  	// Duplicated values which come first will be overridden, so we must put the
    64  	// custom values in the end to avoid being overridden by the process environments.
    65  	env = append(env,
    66  		"CNI_COMMAND="+args.Command,
    67  		"CNI_CONTAINERID="+args.ContainerID,
    68  		"CNI_NETNS="+args.NetNS,
    69  		"CNI_ARGS="+pluginArgsStr,
    70  		"CNI_IFNAME="+args.IfName,
    71  		"CNI_PATH="+args.Path,
    72  	)
    73  	return dedupEnv(env)
    74  }
    75  
    76  // taken from rkt/networking/net_plugin.go
    77  func stringify(pluginArgs [][2]string) string {
    78  	entries := make([]string, len(pluginArgs))
    79  
    80  	for i, kv := range pluginArgs {
    81  		entries[i] = strings.Join(kv[:], "=")
    82  	}
    83  
    84  	return strings.Join(entries, ";")
    85  }
    86  
    87  // DelegateArgs implements the CNIArgs interface
    88  // used for delegation to inherit from environments
    89  // and allow some overrides like CNI_COMMAND
    90  var _ CNIArgs = &DelegateArgs{}
    91  
    92  type DelegateArgs struct {
    93  	Command string
    94  }
    95  
    96  func (d *DelegateArgs) AsEnv() []string {
    97  	env := os.Environ()
    98  
    99  	// The custom values should come in the end to override the existing
   100  	// process environment of the same key.
   101  	env = append(env,
   102  		"CNI_COMMAND="+d.Command,
   103  	)
   104  	return dedupEnv(env)
   105  }
   106  
   107  // dedupEnv returns a copy of env with any duplicates removed, in favor of later values.
   108  // Items not of the normal environment "key=value" form are preserved unchanged.
   109  func dedupEnv(env []string) []string {
   110  	out := make([]string, 0, len(env))
   111  	envMap := map[string]string{}
   112  
   113  	for _, kv := range env {
   114  		// find the first "=" in environment, if not, just keep it
   115  		eq := strings.Index(kv, "=")
   116  		if eq < 0 {
   117  			out = append(out, kv)
   118  			continue
   119  		}
   120  		envMap[kv[:eq]] = kv[eq+1:]
   121  	}
   122  
   123  	for k, v := range envMap {
   124  		out = append(out, fmt.Sprintf("%s=%s", k, v))
   125  	}
   126  
   127  	return out
   128  }