task: make helm_home, bin, and kubectl bin configurable

Refs /salt-formulas/salt-formula-helm#2
diff --git a/_modules/helm.py b/_modules/helm.py
index 9e62154..f690b8f 100644
--- a/_modules/helm.py
+++ b/_modules/helm.py
@@ -3,8 +3,6 @@
 from salt.serializers import yaml
 from salt.exceptions import CommandExecutionError
 
-
-HELM_HOME = '/srv/helm/home'
 LOG = logging.getLogger(__name__)
 
 def ok_or_output(cmd, prefix=None):
@@ -17,21 +15,25 @@
     return msg
 
 
-def _helm_cmd(*args, **tiller_kwargs):
-    if tiller_kwargs.get('tiller_host'):
-        tiller_args = ('--host', tiller_kwargs['tiller_host'])
-    elif tiller_kwargs.get('tiller_namespace'):
-        tiller_args = ('--tiller-namespace', tiller_kwargs['tiller_namespace'])
+def _helm_cmd(*args, **kwargs):
+    if kwargs.get('tiller_host'):
+        addtl_args = ('--host', kwargs['tiller_host'])
+    elif kwargs.get('tiller_namespace'):
+        addtl_args = ('--tiller-namespace', kwargs['tiller_namespace'])
     else:
-        tiller_args = ()
-    env = {'HELM_HOME': HELM_HOME}
-    if tiller_kwargs.get('kube_config'):
-        env['KUBECONFIG'] = tiller_kwargs['kube_config']
-    if tiller_kwargs.get('gce_service_token'):
+        addtl_args = ()
+
+    if kwargs.get('helm_home'):
+      addtl_args = addtl_args + ('--home', kwargs['helm_home'])
+
+    env = {}
+    if kwargs.get('kube_config'):
+        env['KUBECONFIG'] = kwargs['kube_config']
+    if kwargs.get('gce_service_token'):
         env['GOOGLE_APPLICATION_CREDENTIALS'] = \
-            tiller_kwargs['gce_service_token']
+            kwargs['gce_service_token']
     return {
-        'cmd': ('helm',) + tiller_args + args,
+        'cmd': ('helm',) + addtl_args + args,
         'env': env,
     }
 
@@ -42,7 +44,7 @@
     "url": split_string[1].strip()
   }
 
-def list_repos():
+def list_repos(**kwargs):
   '''
   Get the result of running `helm repo list` on the target minion, formatted
   as a list of dicts with two keys:
@@ -50,7 +52,7 @@
     * name: the name with which the repository is registered
     * url: the url registered for the repository
   '''
-  cmd = _helm_cmd('repo', 'list')
+  cmd = _helm_cmd('repo', 'list', **kwargs)
   result = __salt__['cmd.run_stdout'](**cmd)
   if result is None:
     return result
@@ -61,7 +63,7 @@
     repo['name']: repo['url'] for repo in [_parse_repo(line) for line in result]
   }
 
-def add_repo(name, url):
+def add_repo(name, url, **kwargs):
   '''
   Register the repository located at the supplied url with the supplied name. 
   Note that re-using an existing name will overwrite the repository url for
@@ -73,13 +75,13 @@
   url
       The url for the chart repository.
   '''
-  cmd = _helm_cmd('repo', 'add', name, url)
+  cmd = _helm_cmd('repo', 'add', name, url, **kwargs)
   ret = __salt__['cmd.run_all'](**cmd)
   if ret['retcode'] != 0:
     raise CommandExecutionError(ret['stderr'])
   return ret['stdout']
 
-def remove_repo(name):
+def remove_repo(name, **kwargs):
   '''
   Remove the repository from the Helm client registered with the supplied
   name.
@@ -87,13 +89,13 @@
   name
       The name (as registered with the Helm client) for the repository to remove
   '''
-  cmd = _helm_cmd('repo', 'remove', name)
+  cmd = _helm_cmd('repo', 'remove', name, **kwargs)
   ret = __salt__['cmd.run_all'](**cmd)
   if ret['retcode'] != 0:
     raise CommandExecutionError(ret['stderr'])
   return ret['stdout']
 
-def manage_repos(present={}, absent=[], exclusive=False):
+def manage_repos(present={}, absent=[], exclusive=False, **kwargs):
   '''
   Manage the repositories registered with the Helm client's local cache. 
 
@@ -147,7 +149,7 @@
       `present` parameter will be registered with the Helm client. Defaults to 
       False.
   '''
-  existing_repos = list_repos()
+  existing_repos = list_repos(**kwargs)
   result = {
     "already_present": [],
     "added": [],
@@ -169,7 +171,7 @@
       result['added'].append({ 
         'name': name, 
         'url': url, 
-        'stdout': add_repo(name, url)
+        'stdout': add_repo(name, url, **kwargs)
       })
       existing_repos = {
         n: u for (n, u) in existing_repos.iteritems() if name != n
@@ -201,7 +203,10 @@
       continue
 
     try:
-      result['removed'].append({ 'name': name, 'stdout': remove_repo(name) })
+      result['removed'].append({ 
+        'name': name, 
+        'stdout': remove_repo(name, **kwargs) 
+      })
     except CommandExecutionError as e:
       result['failed'].append({ 
         "type": "removal", "name": name, "error": '%s' % e 
@@ -209,33 +214,36 @@
 
   return result
 
-def update_repos():
+def update_repos(**kwargs):
   '''
   Ensures the local helm repository cache for each repository is up to date. 
   Proxies the `helm repo update` command.
   '''
-  cmd = _helm_cmd('repo', 'update')
+  cmd = _helm_cmd('repo', 'update', **kwargs)
   return __salt__['cmd.run_stdout'](**cmd)
 
 def release_exists(name, namespace='default',
                    tiller_namespace='kube-system', tiller_host=None,
-                   kube_config=None, gce_service_token=None):
+                   kube_config=None, gce_service_token=None, helm_home=None):
     cmd = _helm_cmd('list', '--short', '--all', '--namespace', namespace, name,
                     tiller_namespace=tiller_namespace, tiller_host=tiller_host,
                     kube_config=kube_config,
-                    gce_service_token=gce_service_token)
+                    gce_service_token=gce_service_token,
+                    helm_home=helm_home)
     return __salt__['cmd.run_stdout'](**cmd) == name
 
 
 def release_create(name, chart_name, namespace='default',
                    version=None, values=None,
                    tiller_namespace='kube-system', tiller_host=None,
-                   kube_config=None, gce_service_token=None):
-    tiller_args = {
+                   kube_config=None, gce_service_token=None,
+                   helm_home=None):
+    kwargs = {
         'tiller_namespace': tiller_namespace,
         'tiller_host': tiller_host,
         'kube_config': kube_config,
         'gce_service_token': gce_service_token,
+        'helm_home': helm_home
     }
     args = []
     if version is not None:
@@ -243,7 +251,7 @@
     if values is not None:
         args += ['--values', '/dev/stdin']
     cmd = _helm_cmd('install', '--namespace', namespace,
-                    '--name', name, chart_name, *args, **tiller_args)
+                    '--name', name, chart_name, *args, **kwargs)
     if values is not None:
         cmd['stdin'] = yaml.serialize(values, default_flow_style=False)
     LOG.debug('Creating release with args: %s', cmd)
@@ -251,23 +259,25 @@
 
 
 def release_delete(name, tiller_namespace='kube-system', tiller_host=None,
-                   kube_config=None, gce_service_token=None):
+                   kube_config=None, gce_service_token=None, helm_home=None):
     cmd = _helm_cmd('delete', '--purge', name,
                     tiller_namespace=tiller_namespace, tiller_host=tiller_host,
                     kube_config=kube_config,
-                    gce_service_token=gce_service_token)
+                    gce_service_token=gce_service_token,
+                    helm_home=helm_home)
     return ok_or_output(cmd, 'Failed to delete release "{}"'.format(name))
 
 
 def release_upgrade(name, chart_name, namespace='default',
                     version=None, values=None,
                     tiller_namespace='kube-system', tiller_host=None,
-                    kube_config=None, gce_service_token=None):
-    tiller_args = {
+                    kube_config=None, gce_service_token=None, helm_home=None):
+    kwargs = {
         'tiller_namespace': tiller_namespace,
         'tiller_host': tiller_host,
         'kube_config': kube_config,
         'gce_service_token': gce_service_token,
+        'helm_home': helm_home
     }
     args = []
     if version is not None:
@@ -275,7 +285,7 @@
     if values is not None:
         args += ['--values', '/dev/stdin']
     cmd = _helm_cmd('upgrade', '--namespace', namespace,
-                    name, chart_name, *args, **tiller_args)
+                    name, chart_name, *args, **kwargs)
     if values is not None:
         cmd['stdin'] = yaml.serialize(values, default_flow_style=False)
     LOG.debug('Upgrading release with args: %s', cmd)
@@ -283,9 +293,10 @@
 
 
 def get_values(name, tiller_namespace='kube-system', tiller_host=None,
-               kube_config=None, gce_service_token=None):
+               kube_config=None, gce_service_token=None, helm_home=None):
     cmd = _helm_cmd('get', 'values', '--all', name,
                     tiller_namespace=tiller_namespace, tiller_host=tiller_host,
                     kube_config=kube_config,
-                    gce_service_token=gce_service_token)
+                    gce_service_token=gce_service_token,
+                    helm_home=helm_home)
     return yaml.deserialize(__salt__['cmd.run_stdout'](**cmd))
diff --git a/_states/helm_release.py b/_states/helm_release.py
index d4a1b69..0fb6468 100644
--- a/_states/helm_release.py
+++ b/_states/helm_release.py
@@ -14,17 +14,18 @@
 
 def present(name, chart_name, namespace, version=None, values=None,
             tiller_namespace='kube-system', tiller_host=None,
-            kube_config=None, gce_service_token=None):
-    tiller_args = {
+            kube_config=None, gce_service_token=None, helm_home=None):
+    kwargs = {
         'tiller_namespace': tiller_namespace,
         'tiller_host': tiller_host,
         'kube_config': kube_config,
         'gce_service_token': gce_service_token,
+        'helm_home': helm_home
     }
-    exists = __salt__['helm.release_exists'](name, namespace, **tiller_args)
+    exists = __salt__['helm.release_exists'](name, namespace, **kwargs)
     if not exists:
         err = __salt__['helm.release_create'](
-            name, chart_name, namespace, version, values, **tiller_args)
+            name, chart_name, namespace, version, values, **kwargs)
         if err:
             return failure(name, err)
         return {
@@ -34,13 +35,13 @@
             'comment': 'Release "{}" was created'.format(name),
         }
 
-    old_values = __salt__['helm.get_values'](name, **tiller_args)
+    old_values = __salt__['helm.get_values'](name, **kwargs)
     err = __salt__['helm.release_upgrade'](
-        name, chart_name, namespace, version, values, **tiller_args)
+        name, chart_name, namespace, version, values, **kwargs)
     if err:
         return failure(name, err)
 
-    new_values = __salt__['helm.get_values'](name, **tiller_args)
+    new_values = __salt__['helm.get_values'](name, **kwargs)
     if new_values == old_values:
         return {
             'name': name,
@@ -62,14 +63,15 @@
 
 
 def absent(name, namespace, tiller_namespace='kube-system', tiller_host=None,
-           kube_config=None, gce_service_token=None):
-    tiller_args = {
+           kube_config=None, gce_service_token=None, helm_home=None):
+    kwargs = {
         'tiller_namespace': tiller_namespace,
         'tiller_host': tiller_host,
         'kube_config': kube_config,
         'gce_service_token': gce_service_token,
+        'helm_home': helm_home
     }
-    exists = __salt__['helm.release_exists'](name, namespace, **tiller_args)
+    exists = __salt__['helm.release_exists'](name, namespace, **kwargs)
     if not exists:
         return {
             'name': name,
@@ -77,7 +79,7 @@
             'result': True,
             'comment': 'Release "{}" doesn\'t exist'.format(name),
         }
-    err = __salt__['helm.release_delete'](name, **tiller_args)
+    err = __salt__['helm.release_delete'](name, **kwargs)
     if err:
         return failure(name, err)
     return {
diff --git a/_states/helm_repos.py b/_states/helm_repos.py
index 88f0894..ee1d556 100644
--- a/_states/helm_repos.py
+++ b/_states/helm_repos.py
@@ -2,7 +2,7 @@
 
 from salt.exceptions import CommandExecutionError
 
-def managed(name, present={}, absent=[], exclusive=False):
+def managed(name, present={}, absent=[], exclusive=False, helm_home=None):
   '''
   Ensure the supplied repositories are available to the helm client. If the
   `exclusive` flag is set to a truthy value, any extra repositories in the 
@@ -17,9 +17,13 @@
   
   absent
       A list of repository names to ensure are unregistered from the Helm client
+  
   exclusive
       A boolean flag indicating whether the state should ensure only the 
       supplied repositories are availabe to the target minion.
+
+  helm_home
+      An optional path to the Helm home directory 
   '''
   ret = {'name': name,
          'changes': {},
@@ -30,7 +34,8 @@
     result = __salt__['helm.manage_repos'](
       present=present, 
       absent=absent, 
-      exclusive=exclusive
+      exclusive=exclusive,
+      helm_home=helm_home
     )
 
     if result['failed']:
@@ -52,7 +57,7 @@
     ret['comment'] = "Failed to add some repositories: %s" % e
     return ret
 
-def updated(name):
+def updated(name, helm_home=None):
   '''
   Ensure the local Helm repository cache is up to date with each of the 
   helm client's configured remote chart repositories. Because the `helm repo 
@@ -63,6 +68,9 @@
 
   name
       The name of the state
+
+  helm_home
+      An optional path to the Helm home directory 
   '''
   ret = {'name': name,
          'changes': {},
@@ -71,7 +79,7 @@
   
   output = None
   try:
-    output = __salt__['helm.update_repos']()
+    output = __salt__['helm.update_repos'](helm_home=helm_home)
   except CommandExecutionError as e:
     ret['result'] = False
     ret['comment'] = "Failed to update repos: %s" % e
diff --git a/helm/client_installed.sls b/helm/client_installed.sls
index 75f9aaa..3c081a1 100644
--- a/helm/client_installed.sls
+++ b/helm/client_installed.sls
@@ -21,26 +21,20 @@
     - require:
       - file: {{ constants.helm.tmp }}
 
-{{ constants.helm.bin }}:
-  file.managed:
+{{ config.bin }}:
+  file.copy:
     - source: {{ constants.helm.tmp }}/{{ config.flavor }}/helm
     - mode: 555
     - user: root
     - group: root
+    - force: true
     - require:
       - archive: {{ constants.helm.tmp }}
-
-/usr/bin/helm:
-  file.symlink:
-    - target: helm-v{{ config.version }}
-    - require:
-      - file: {{ constants.helm.bin }}
+    - unless: cmp -s {{ config.bin }} {{ constants.helm.tmp }}/{{ config.flavor }}/helm
 
 prepare_client:
   cmd.run:
     - name: {{ constants.helm.cmd }} init --client-only
-    - env:
-      - HELM_HOME: {{ constants.helm.home }}
-    - unless: test -d {{ constants.helm.home }}
+    - unless: test -d {{ config.helm_home }}
     - require:
-      - file: {{ constants.helm.bin }}
+      - file: {{ config.bin }}
diff --git a/helm/kubectl_configured.sls b/helm/kubectl_configured.sls
index fbe2c48..26e3215 100644
--- a/helm/kubectl_configured.sls
+++ b/helm/kubectl_configured.sls
@@ -3,7 +3,7 @@
 include:
   - .kubectl_installed
 
-{{ constants.kubectl.config }}:
+{{ config.kubectl.config_file }}:
   file.managed:
     - source: salt://helm/files/kubeconfig.yaml.j2
     - mode: 400
diff --git a/helm/kubectl_installed.sls b/helm/kubectl_installed.sls
index d1b35f0..bdc756d 100644
--- a/helm/kubectl_installed.sls
+++ b/helm/kubectl_installed.sls
@@ -19,7 +19,7 @@
     - onlyif:
           - test ! -e {{ extracted_binary_path }}
 
-{{ constants.kubectl.bin }}:
+{{ config.kubectl.bin }}:
   file.managed:
     - source: {{ extracted_binary_path }}
     - mode: 555
@@ -27,5 +27,5 @@
     - group: root
     - require:
       - archive: extract_kubectl
-    - unless: cmp -s {{ constants.kubectl.bin }} {{ extracted_binary_path }}
+    - unless: cmp -s {{ config.kubectl.bin }} {{ extracted_binary_path }}
 {%- endif %}
\ No newline at end of file
diff --git a/helm/map.jinja b/helm/map.jinja
index 794521a..d74855b 100644
--- a/helm/map.jinja
+++ b/helm/map.jinja
@@ -34,6 +34,8 @@
     # TODO: add parameter for binary installation flavor
     #
     # flavor: linux-amd64
+    bin: /usr/bin/helm
+    helm_home: /srv/helm/home
     tiller:
       install: true
       namespace: kube-system
@@ -41,6 +43,8 @@
       install: false
       version: 1.6.7
       download_hash: sha256=54947ef84181e89f9dbacedd54717cbed5cc7f9c36cb37bc8afc9097648e2c91
+      bin: /usr/bin/kubectl
+      config_file: /srv/helm/kubeconfig.yaml
       config:
         gce_service_token: 
 {%- endload %}
@@ -51,10 +55,11 @@
 
 {%- set constants = {
     "helm": {
-      "home": "/srv/helm/helm",
-      "bin": "/usr/bin/helm-v" + config.version,
       "tmp": "/tmp/helm-v" + config.version,
-      "cmd": "helm --tiller-namespace '{}'".format(config.tiller.namespace),
+      "cmd": config.bin + " --home '{}' --tiller-namespace '{}'".format(
+          config.helm_home,
+          config.tiller.namespace
+      ),
       "tiller_arg": "- tiller_namespace: \"{}\"".format(config.tiller.namespace),
       "gce_state_arg": "",
     },
@@ -62,8 +67,6 @@
       "gce_env_var": "",
     },
     "kubectl": {
-      "bin": "/usr/bin/kubectl",
-      "config": "/srv/helm/kubeconfig.yaml",
       "gce_service_token_path": "/srv/helm/gce_token.json",
     }
   } 
@@ -72,7 +75,7 @@
 {%- if "host" in config.tiller %}
 {%- do constants.update({
      "helm": {
-       "cmd": "helm --host '{}'".format(config.tiller.host),
+       "cmd": config.bin + " --host '{}'".format(config.tiller.host),
        "tiller_arg": "- tiller_host: \"{}\"".format(config.tiller.host)
      }
    })
diff --git a/helm/releases_managed.sls b/helm/releases_managed.sls
index 968a5d5..42e6c5a 100644
--- a/helm/releases_managed.sls
+++ b/helm/releases_managed.sls
@@ -17,7 +17,8 @@
     - name: {{ release_name }}
     - chart_name: {{ release['chart'] }}
     - namespace: {{ namespace }}
-    - kube_config: {{ constants.kubectl.config }}
+    - kube_config: {{ config.kubectl.config_file }}
+    - helm_home: {{ config.helm_home }}
     {{ constants.helm.tiller_arg }}
     {{ constants.helm.gce_state_arg }}
     {%- if release.get('version') %}
@@ -43,7 +44,8 @@
   helm_release.absent:
     - name: {{ release_name }}
     - namespace: {{ namespace }}
-    - kube_config: {{ constants.kubectl.config }}
+    - kube_config: {{ config.kubectl.config_file }}
+    - helm_home: {{ config.helm_home }}
     {{ constants.helm.tiller_arg }}
     {{ constants.helm.gce_state_arg }}
     - require:
diff --git a/helm/repos_managed.sls b/helm/repos_managed.sls
index a870138..7cee1d2 100644
--- a/helm/repos_managed.sls
+++ b/helm/repos_managed.sls
@@ -9,11 +9,13 @@
     - present: 
         {{ config.repos | yaml(false) | indent(8) }}
     - exclusive: true
+    - helm_home: {{ config.helm_home }}
     - require:
       - sls: {{ slspath }}.client_installed
 {%- endif %}
 
 repos_updated:
   helm_repos.updated:
+    - helm_home: {{ config.helm_home }}
     - require:
       - sls: {{ slspath }}.client_installed
\ No newline at end of file
diff --git a/helm/tiller_installed.sls b/helm/tiller_installed.sls
index 673349d..fb7ffce 100644
--- a/helm/tiller_installed.sls
+++ b/helm/tiller_installed.sls
@@ -9,8 +9,7 @@
   cmd.run:
     - name: {{ constants.helm.cmd }} init --upgrade
     - env:
-      - HELM_HOME: {{ constants.helm.home }}
-      - KUBECONFIG: {{ constants.kubectl.config }}
+      - KUBECONFIG: {{ config.kubectl.config_file }}
       {{ constants.tiller.gce_env_var }}
     - unless: "{{ constants.helm.cmd }} version --server --short | grep -E 'Server: v{{ config.version }}(\\+|$)'"
     - require:
@@ -22,8 +21,7 @@
     - name: while ! {{ constants.helm.cmd }} list; do sleep 3; done
     - timeout: 30
     - env:
-      - HELM_HOME: {{ constants.helm.home }}
-      - KUBECONFIG: {{ constants.kubectl.config }}
+      - KUBECONFIG: {{ config.kubectl.config_file }}
       {{ constants.tiller.gce_env_var }}
     - require:
       - sls: {{ slspath }}.client_installed
diff --git a/pillar.example b/pillar.example
index bb0e2fa..2e401ff 100644
--- a/pillar.example
+++ b/pillar.example
@@ -7,6 +7,19 @@
     # version: 2.6.2
     
     #
+    # The path to which the Helm binary should be installed. Defaults to 
+    # /usr/bin/helm
+    #
+    # bin: /usr/bin/helm
+
+    #
+    # The path this formula should use as helm home. Defaults to /srv/helm/home;
+    # it is recommended to set this to /root/.helm if users will be calling 
+    # helm from the command line directly on the target minion
+    #
+    # helm_home: /srv/helm/home
+
+    #
     # The flavor of the helm or kubectl binary to install, as informed by the
     # target minion's OS. For available flavor names, peruse the listing of
     # Helm binaries exposed at:
@@ -76,6 +89,12 @@
       # Defaults to 1.6.7
       #
       # version: 1.6.7
+      
+      #
+      # The path to which the kubectl binary should be installed. Defaults to 
+      # /usr/bin/kubectl
+      #
+      # bin: /usr/bin/kubectl
 
       #
       # The hash for the kubectl binary version to install. You must calculate