text: import difflib
  import os
  import logging
  
  from salt.exceptions import CommandExecutionError
  from salt.serializers import yaml
  
  LOG = logging.getLogger(__name__)
  
  def _get_values_from_file(values_file=None):
      if values_file:
          try:
              with open(values_file) as values_stream:
                  values = yaml.deserialize(values_stream)
              return values
          except e:
              raise CommandExecutionError("encountered error reading from values "
                                          "file (%s): %s" % (values_file, e))
      return None
  
  def _get_yaml_diff(new_yaml=None, old_yaml=None):
      if not new_yaml and not old_yaml:
          return None
  
      old_str = yaml.serialize(old_yaml, default_flow_style=False)
      new_str = yaml.serialize(new_yaml, default_flow_style=False)
      return difflib.unified_diff(old_str.split('\n'), new_str.split('\n'))
  
  def _failure(name, message, changes={}):
      return {
          'name': name,
          'changes': changes,
          'result': False,
          'comment': message,
      }
  
  def present(name, chart_name, namespace, version=None, values_file=None,
              tiller_namespace='kube-system', **kwargs):
      '''
      Ensure that a release with the supplied name is in the desired state in the
      Tiller installation. This state will handle change detection to determine
      whether an installation or update needs to be made.
  
      In the event the namespace to which a release is installed changes, the
      state will first delete and purge the release and the re-install it into
      the new namespace, since Helm does not support updating a release into a
      new namespace.
  
      name
          The name of the release to ensure is present
  
      chart_name
          The name of the chart to install, including the repository name as
          applicable (such as `stable/mysql`)
  
      namespace
          The namespace to which the release should be (re-)installed
  
      version
          The version of the chart to install. Defaults to the latest version
  
      values_file
          The path to the a values file containing all the chart values that
          should be applied to the release. Note that this should not be passed
          if there are not chart value overrides required.
  
      '''
      kwargs['tiller_namespace'] = tiller_namespace
      if __opts__['test'] == True:
          return {
              'result': None,
              'name': name,
              'comment': 'Helm chart "{0}" will be installed'.format(chart_name),
              'changes': {
              'chart_name': chart_name,
              'namespace': namespace,
            }
          }
      old_release = __salt__['k8s_helm.get_release'](name, **kwargs)
      if not old_release:
          try:
              result = __salt__['k8s_helm.release_create'](
                  name, chart_name, namespace, version, values_file, **kwargs
              )
              return {
                  'name': name,
                  'changes': {
                  'name': name,
                  'chart_name': chart_name,
                  'namespace': namespace,
                  'version': version,
                  'values': _get_values_from_file(values_file),
                  'stdout': result.get('stdout')
                },
                'result': True,
                'comment': ('Release "%s" was created' % name +
                            '\nExecuted command: %s' % result['cmd'])
              }
          except CommandExecutionError as e:
              msg = (("Failed to create new release: %s" % e.error) +
                     "\nExecuted command: %s" % e.cmd)
              return _failure(name, msg)
  
      changes = {}
      warnings = []
      if old_release.get('chart') != chart_name.split("/")[1]:
          changes['chart'] = { 'old': old_release['chart'], 'new': chart_name }
  
      if old_release.get('version') != version:
          changes['version'] = { 'old': old_release['version'], 'new': version }
  
      if old_release.get('namespace') != namespace:
          changes['namespace'] = { 'old': old_release['namespace'], 'new': namespace }
  
      if (not values_file and old_release.get("values") or
          not old_release.get("values") and values_file):
          changes['values'] = { 'old': old_release['values'], 'new': values_file }
  
      values = _get_values_from_file(values_file)
      diff = _get_yaml_diff(values, old_release.get('values'))
  
      if diff:
          diff_string = '\n'.join(diff)
          if diff_string:
              changes['values'] = diff_string
  
      if not changes:
          return {
              'name': name,
            'result': True,
            'changes': {},
            'comment': 'Release "{}" is already in the desired state'.format(name)
          }
  
      module_fn = 'k8s_helm.release_upgrade'
      if changes.get("namespace"):
          LOG.debug("purging old release (%s) due to namespace change" % name)
          try:
              result = __salt__['k8s_helm.release_delete'](name, **kwargs)
          except CommandExecutionError as e:
              msg = ("Failed to delete release for namespace change: %s" % e.error +
                     "\nExecuted command: %s" % e.cmd)
              return _failure(name, msg, changes)
  
          module_fn = 'k8s_helm.release_create'
          warnings.append('Release (%s) was replaced due to namespace change' % name)
  
      try:
          result = __salt__[module_fn](
              name, chart_name, namespace, version, values_file, **kwargs
          )
          changes.update({ 'stdout': result.get('stdout') })
          ret = {
              'name': name,
            'changes': changes,
            'result': True,
            'comment': 'Release "%s" was updated\nExecuted command: %s' % (name, result['cmd'])
          }
          if warnings:
              ret['warnings'] = warnings
  
          return ret
      except CommandExecutionError as e:
          msg = ("Failed to delete release for namespace change: %s" % e.error +
                 "\nExecuted command: %s" % e.cmd)
          return _failure(name, msg, changes)
  
  
  def absent(name, tiller_namespace='kube-system', **kwargs):
      '''
      Ensure that any release with the supplied release name is absent from the
      tiller installation.
  
      name
          The name of the release to ensure is absent
      '''
      kwargs['tiller_namespace'] = tiller_namespace
      exists = __salt__['k8s_helm.release_exists'](name, **kwargs)
      if not exists:
          return {
              'name': name,
              'changes': {},
              'result': True,
              'comment': 'Release "%s" doesn\'t exist' % name
          }
      try:
          result = __salt__['k8s_helm.release_delete'](name, **kwargs)
          return {
              'name': name,
            'changes': { name: 'DELETED', 'stdout': result['stdout'] },
            'result': True,
            'comment': 'Release "%s" was deleted\nExecuted command: %s' % (name, result['cmd'])
          }
      except CommandExecutionError as e:
          return _failure(e.cmd, e.error)
  
  