From e98cd621f0c16cf1ee3a53e8324e18bb0f0cc297 Mon Sep 17 00:00:00 2001 From: raffaelespazzoli Date: Mon, 4 Nov 2019 15:24:52 -0500 Subject: [PATCH] added rest client passed with action configuration Signed-off-by: raffaelespazzoli --- pkg/action/install.go | 7 +++- pkg/engine/engine.go | 15 +++++++ pkg/engine/funcs.go | 1 - pkg/engine/lookup_func.go | 86 +++++++++++++++------------------------ 4 files changed, 54 insertions(+), 55 deletions(-) diff --git a/pkg/action/install.go b/pkg/action/install.go index dc5941810..8f865ddf9 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -436,7 +436,12 @@ func (c *Configuration) renderResources(ch *chart.Chart, values chartutil.Values } } - files, err := engine.Render(ch, values) + rest, err := c.RESTClientGetter.ToRESTConfig() + if err != nil { + return hs, b, "", err + } + + files, err := engine.RenderWithClient(ch, values, rest) if err != nil { return hs, b, "", err } diff --git a/pkg/engine/engine.go b/pkg/engine/engine.go index 5a7d54993..c4d5ee5a7 100644 --- a/pkg/engine/engine.go +++ b/pkg/engine/engine.go @@ -27,6 +27,7 @@ import ( "text/template" "github.com/pkg/errors" + "k8s.io/client-go/rest" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/chartutil" @@ -39,6 +40,8 @@ type Engine struct { Strict bool // In LintMode, some 'required' template values may be missing, so don't fail LintMode bool + // the rest config to connect to te kubernetes api + config *rest.Config } // Render takes a chart, optional values, and value overrides, and attempts to render the Go templates. @@ -71,6 +74,15 @@ func Render(chrt *chart.Chart, values chartutil.Values) (map[string]string, erro return new(Engine).Render(chrt, values) } +// RenderWithClient takes a chart, optional values, and value overrides, and attempts to +// render the Go templates using the default options. This engine is client aware and so can have template +// functions that interact with the client +func RenderWithClient(chrt *chart.Chart, values chartutil.Values, config *rest.Config) (map[string]string, error) { + return Engine{ + config: config, + }.Render(chrt, values) +} + // renderable is an object that can be rendered. type renderable struct { // tpl is the current template. @@ -157,6 +169,9 @@ func (e Engine) initFunMap(t *template.Template, referenceTpls map[string]render } return val, nil } + if e.config != nil { + funcMap["lookup"] = NewLookupFunction(e.config) + } t.Funcs(funcMap) } diff --git a/pkg/engine/funcs.go b/pkg/engine/funcs.go index 6ff10ea72..dac105e74 100644 --- a/pkg/engine/funcs.go +++ b/pkg/engine/funcs.go @@ -53,7 +53,6 @@ func funcMap() template.FuncMap { "fromYaml": fromYAML, "toJson": toJSON, "fromJson": fromJSON, - "lookup": lookup, // This is a placeholder for the "include" function, which is // late-bound to a template. By declaring it here, we preserve the diff --git a/pkg/engine/lookup_func.go b/pkg/engine/lookup_func.go index f8a47ac38..7c5dc78f1 100644 --- a/pkg/engine/lookup_func.go +++ b/pkg/engine/lookup_func.go @@ -17,10 +17,7 @@ limitations under the License. package engine import ( - "flag" "log" - "os" - "path/filepath" "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -28,67 +25,50 @@ import ( "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" ) -var config *rest.Config +type lookupFunc = func(apiversion string, resource string, namespace string, name string) (map[string]interface{}, error) -func init() { - // try the out-cluster config, this will default to the in-cluster config is not successful - var kubeconfig *string - if home := homeDir(); home != "" { - kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file") - } else { - kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file") - } - flag.Parse() - - // use the current context in kubeconfig - config1, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) - if err == nil { - config = config1 - } -} - -func homeDir() string { - if h := os.Getenv("HOME"); h != "" { - return h - } - return os.Getenv("USERPROFILE") // windows -} - -func lookup(apiversion string, resource string, namespace string, name string) (map[string]interface{}, error) { - var client dynamic.ResourceInterface - c, namespaced, err := getDynamicClientOnKind(apiversion, resource) - if err != nil { - return map[string]interface{}{}, err - } - if namespaced && namespace != "" { - client = c.Namespace(namespace) - } else { - client = c - } - if name != "" { - //this will return a single object - obj, err := client.Get(name, metav1.GetOptions{}) +func NewLookupFunction(config *rest.Config) lookupFunc { + return func(apiversion string, resource string, namespace string, name string) (map[string]interface{}, error) { + var client dynamic.ResourceInterface + c, namespaced, err := getDynamicClientOnKind(apiversion, resource, config) + if err != nil { + return map[string]interface{}{}, err + } + if namespaced && namespace != "" { + client = c.Namespace(namespace) + } else { + client = c + } + if name != "" { + //this will return a single object + obj, err := client.Get(name, metav1.GetOptions{}) + if err != nil { + return map[string]interface{}{}, err + } + return obj.Object, nil + } + //this will return a list + obj, err := client.List(metav1.ListOptions{}) if err != nil { return map[string]interface{}{}, err } return obj.Object, nil } - //this will return a list - obj, err := client.List(metav1.ListOptions{}) - if err != nil { - return map[string]interface{}{}, err - } - return obj.Object, nil - } +// func homeDir() string { +// if h := os.Getenv("HOME"); h != "" { +// return h +// } +// return os.Getenv("USERPROFILE") // windows +// } + // GetDynamicClientOnUnstructured returns a dynamic client on an Unstructured type. This client can be further namespaced. -func getDynamicClientOnKind(apiversion string, kind string) (dynamic.NamespaceableResourceInterface, bool, error) { +func getDynamicClientOnKind(apiversion string, kind string, config *rest.Config) (dynamic.NamespaceableResourceInterface, bool, error) { gvk := schema.FromAPIVersionAndKind(apiversion, kind) - apiRes, err := getAPIReourceForGVK(gvk) + apiRes, err := getAPIReourceForGVK(gvk, config) if err != nil { log.Printf("[ERROR] unable to get apiresource from unstructured: %s , error %s", gvk.String(), err) return nil, false, err @@ -107,7 +87,7 @@ func getDynamicClientOnKind(apiversion string, kind string) (dynamic.Namespaceab return res, apiRes.Namespaced, nil } -func getAPIReourceForGVK(gvk schema.GroupVersionKind) (metav1.APIResource, error) { +func getAPIReourceForGVK(gvk schema.GroupVersionKind, config *rest.Config) (metav1.APIResource, error) { res := metav1.APIResource{} discoveryClient, err := discovery.NewDiscoveryClientForConfig(config) if err != nil {