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 }