github.com/defensepoint-snyk-test/helm-new@v0.0.0-20211130153739-c57ea64d6603/cmd/helm/load_plugins.go (about) 1 /* 2 Copyright The Helm Authors. 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 16 package main 17 18 import ( 19 "fmt" 20 "io" 21 "os" 22 "os/exec" 23 "path/filepath" 24 "strings" 25 "syscall" 26 27 "github.com/spf13/cobra" 28 29 "k8s.io/helm/pkg/plugin" 30 ) 31 32 type pluginError struct { 33 error 34 code int 35 } 36 37 // loadPlugins loads plugins into the command list. 38 // 39 // This follows a different pattern than the other commands because it has 40 // to inspect its environment and then add commands to the base command 41 // as it finds them. 42 func loadPlugins(baseCmd *cobra.Command, out io.Writer) { 43 44 // If HELM_NO_PLUGINS is set to 1, do not load plugins. 45 if os.Getenv("HELM_NO_PLUGINS") == "1" { 46 return 47 } 48 49 // debug("HELM_PLUGIN_DIRS=%s", settings.PluginDirs()) 50 found, err := findPlugins(settings.PluginDirs()) 51 if err != nil { 52 fmt.Fprintf(os.Stderr, "failed to load plugins: %s", err) 53 return 54 } 55 56 processParent := func(cmd *cobra.Command, args []string) ([]string, error) { 57 k, u := manuallyProcessArgs(args) 58 if err := cmd.Parent().ParseFlags(k); err != nil { 59 return nil, err 60 } 61 return u, nil 62 } 63 64 // Now we create commands for all of these. 65 for _, plug := range found { 66 plug := plug 67 md := plug.Metadata 68 if md.Usage == "" { 69 md.Usage = fmt.Sprintf("the %q plugin", md.Name) 70 } 71 72 c := &cobra.Command{ 73 Use: md.Name, 74 Short: md.Usage, 75 Long: md.Description, 76 RunE: func(cmd *cobra.Command, args []string) error { 77 u, err := processParent(cmd, args) 78 if err != nil { 79 return err 80 } 81 82 // Call setupEnv before PrepareCommand because 83 // PrepareCommand uses os.ExpandEnv and expects the 84 // setupEnv vars. 85 plugin.SetupPluginEnv(settings, md.Name, plug.Dir) 86 main, argv := plug.PrepareCommand(u) 87 88 prog := exec.Command(main, argv...) 89 prog.Env = os.Environ() 90 prog.Stdin = os.Stdin 91 prog.Stdout = out 92 prog.Stderr = os.Stderr 93 if err := prog.Run(); err != nil { 94 if eerr, ok := err.(*exec.ExitError); ok { 95 os.Stderr.Write(eerr.Stderr) 96 status := eerr.Sys().(syscall.WaitStatus) 97 return pluginError{ 98 error: fmt.Errorf("plugin %q exited with error", md.Name), 99 code: status.ExitStatus(), 100 } 101 } 102 return err 103 } 104 return nil 105 }, 106 // This passes all the flags to the subcommand. 107 DisableFlagParsing: true, 108 } 109 110 if md.UseTunnel { 111 c.PreRunE = func(cmd *cobra.Command, args []string) error { 112 // Parse the parent flag, but not the local flags. 113 if _, err := processParent(cmd, args); err != nil { 114 return err 115 } 116 return setupConnection() 117 } 118 } 119 120 // TODO: Make sure a command with this name does not already exist. 121 baseCmd.AddCommand(c) 122 } 123 } 124 125 // manuallyProcessArgs processes an arg array, removing special args. 126 // 127 // Returns two sets of args: known and unknown (in that order) 128 func manuallyProcessArgs(args []string) ([]string, []string) { 129 known := []string{} 130 unknown := []string{} 131 kvargs := []string{"--host", "--kube-context", "--home", "--tiller-namespace"} 132 knownArg := func(a string) bool { 133 for _, pre := range kvargs { 134 if strings.HasPrefix(a, pre+"=") { 135 return true 136 } 137 } 138 return false 139 } 140 for i := 0; i < len(args); i++ { 141 switch a := args[i]; a { 142 case "--debug": 143 known = append(known, a) 144 case "--host", "--kube-context", "--home", "--tiller-namespace": 145 known = append(known, a, args[i+1]) 146 i++ 147 default: 148 if knownArg(a) { 149 known = append(known, a) 150 continue 151 } 152 unknown = append(unknown, a) 153 } 154 } 155 return known, unknown 156 } 157 158 // findPlugins returns a list of YAML files that describe plugins. 159 func findPlugins(plugdirs string) ([]*plugin.Plugin, error) { 160 found := []*plugin.Plugin{} 161 // Let's get all UNIXy and allow path separators 162 for _, p := range filepath.SplitList(plugdirs) { 163 matches, err := plugin.LoadAll(p) 164 if err != nil { 165 return matches, err 166 } 167 found = append(found, matches...) 168 } 169 return found, nil 170 }