#!/opt/vmware/bin/python

from lxml import etree
import os
import subprocess
import time
import sys
import platform

# This script prunes sensitive values (e.g., passwords) from
# guestinfo.ovfEnv and install-defaults directory.

# Define the property key(s) to be pruned.
PROPERTIES = [
    'appliance.root.passwd', 'db.password', 'upgrade.source.autodeploy.password',
    'upgrade.source.guest.password', 'upgrade.source.guestops.host.password',
    'upgrade.source.log.password', 'upgrade.source.log.password',
    'upgrade.source.netdump.password', 'upgrade.source.sso.password',
    'upgrade.source.vpxd.ip', 'vmdir.password',
    'vmca.cert.password', 'vc.soluser.pass',
    'vc.pfx.pass', 'ad.domain.password']

# Set whether to delete all install parameters or not.
DELETE_ALL_INSTALL_PARAMETERS = False


def execute(cmd, ofile=subprocess.PIPE, efile=subprocess.PIPE):
    proc = subprocess.Popen(cmd, stdout=ofile, stderr=efile)
    out, err = proc.communicate()
    rc = proc.wait()
    if rc != 0 or err:
        print 'Command failed: %r (rc=%d)' % (cmd, rc)
        print '  Stdout: %s' % out
        print '  Stderr: %s' % err
        exit(1)
    return out


def prune_ovf_env():
    # Path to vmtoolsd
    VMTOOLSD = '/usr/bin/vmtoolsd'

    # Retrieve guestinfo.ovfEnv.
    out = execute([VMTOOLSD, '--cmd', 'info-get guestinfo.ovfEnv'])

    # Parse and transform ovfEnv.
    try:
        root = etree.fromstring(out)
    except etree.XMLSyntaxError:
        sys.stderr.write('Unable to parse ovfEnv:\n%s\n' % out)
        exit(1)

    # Get all the Property elements to be removed.
    elem_str = '{%(oe)s}Property' % root.nsmap
    key_str = '{%(oe)s}key' % root.nsmap
    props = root.findall('.//%s[@%s]' % (elem_str, key_str))

    guest_ovf_rm_properties = ['guestinfo.cis.%s' % p for p in PROPERTIES]
    # Remove them.
    if props:
        del_props = [p for p in props if p.get(key_str) in guest_ovf_rm_properties]

        for prop in del_props:
            prop.getparent().remove(prop)

        # Write transformed value to ovfEnv.
        result = etree.tostring(root, pretty_print=True, xml_declaration=True,
                                encoding='UTF-8')
        execute([VMTOOLSD, '--cmd', 'info-set guestinfo.ovfEnv %s' % result])


def prune_install_defaults():
    """
    Removes files containing sensitive information from install-defaults dir.
    global list "PROPERTIES" determines which files to remove.

    Note:- If global DELETE_ALL_INSTALL_PARAMETERS is set to True, then
    all files under install-default dir are deleted.
    """
    install_defaults_dir = os.path.join(os.environ['VMWARE_CFG_DIR'],
                                        'install-defaults')
    if not os.path.isdir(install_defaults_dir):
        print('%s is not an existing directory. Nothing to Prune here.' %
              install_defaults_dir)
        return

    for prop_file in os.listdir(install_defaults_dir):
        if DELETE_ALL_INSTALL_PARAMETERS or prop_file in PROPERTIES:
            file_path = os.path.join(install_defaults_dir, prop_file)
            for _ in range(0, 5):
                try:
                    if os.path.exists(file_path):
                        # Fill it with zeroes before removing
                        file_stat = os.stat(file_path)
                        with open(file_path, 'r+') as file_handle:
                            file_handle.write('\0' * file_stat.st_size)
                            file_handle.flush()
                        os.remove(file_path)
                    break
                except OSError as e:
                    print 'Warning: Remove file failed %s, Error %s' % (file_path, e)
                # Sleep before retrying to remove prop file.
                time.sleep(0.25)
            else:
                sys.stderr.write('Error: Unable to prune install parameter %s' %
                                 prop_file + os.linesep)
                exit(1)

if __name__ == '__main__':
    prune_install_defaults()
    if os.name == 'posix':
        prune_ovf_env()
    exit(0)
