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