def __init__(self):
        '''
        Constructor
        '''
        self.logger = logging.getLogger('GemUtil')
        # Embebed Chef installation
        self.command = "c:\\opscode\\chef\\embedded\\bin\\gem"
        self.rubyEmbeddedInChef = True
        self.sys_gemrc = "/etc/gemrc"

        self.commandUtil = CommandUtil()
        self.pm = PackageManager()
    def removeCertificateFromTrustedCAs(self, certificate):
        ''' Removing certificate from trusted CAs '''

        if certificate is None:
            return
        if not os.path.isdir('/usr/share/ca-certificates/'):
            raise Exception(
                'There is no /usr/share/ca-certificates/ directory')
        if not os.path.isfile('/etc/ca-certificates.conf'):
            raise Exception('There is no /etc/ca-certificates.conf file')
        if not os.path.isdir('/usr/share/ca-certificates/gecos'):
            # There are no certificates to remove
            return
        # Check if there is a line for this certificate
        # in /etc/ca-certificates.conf
        info = self.getCertificateInfo(certificate)
        filename = 'unknown'
        if info.get_subject().commonName is not None:
            filename = ("{}.crt".format(info.get_subject().commonName.lower()))
        if not self.isSelfSigned(info):
            # Is not a self signed certificate
            # We must get the Issuer CA certificate
            url = self.getIssuerCertificateURL(info)
            if url is None:
                raise Exception('Can\'t find issuer CA certificate URL!')
            filename = os.path.basename(url)
        fd = codecs.open('/etc/ca-certificates.conf', 'r', encoding='utf-8')
        ca_certificates_conf = fd.read()
        fd.close()
        found = False
        ca_certificates = []
        for line in ca_certificates_conf.split('\n'):
            if line.startswith(u'gecos/{}'.format(filename)):
                # The certificate already exist
                found = True
            elif len(line.strip()) > 0:
                ca_certificates.append(line)
        if found:
            ca_certificates.append(u'!gecos/{}'.format(filename))
            ca_certificates.append(u'')
            ca_certificates_conf = '\n'.join(ca_certificates)
            # Overwrite the  /etc/ca-certificates.conf file
            fd = codecs.open('/etc/ca-certificates.conf',
                             'w',
                             encoding='utf-8')
            fd.write(ca_certificates_conf)
            fd.close()
            # Run update-ca-certificates
            commandUtil = CommandUtil()
            commandUtil.execute_command('/usr/sbin/update-ca-certificates')
        if os.path.lexists('/etc/chef/trusted_certs/{}'.format(filename)):
            os.unlink('/etc/chef/trusted_certs/{}'.format(filename))
    def get_system_manager():
        '''
        Detecting which system manager is running
        ''' 
        sysmanager = None
        commandUtil = CommandUtil()

        output = commandUtil.get_command_output('ls -l /proc/1/exe')
        line = output[0]

        if line.endswith('/sbin/init'):
            sysmanager = System_Manager.SYSV
        elif line.endswith('/sbin/upstart'):
            sysmanager = System_Manager.UPSTART
        elif line.endswith('/lib/systemd/systemd'):
            sysmanager = System_Manager.SYSTEMD

        return sysmanager
    def runTest(self):
        commandUtil = CommandUtil()
		
		self.assertFalse(commandUtil.execute_command('non existent command'))
		self.assertTrue(commandUtil.execute_command('ls'))
		
		self.assertFalse(commandUtil.get_command_output('non existent command'), [])
		self.assertNotEqual(commandUtil.get_command_output('ls'), [])

		self.assertTrue(commandUtil.execute_command('echo "Asking a yes no question (y/n)?" & read choice'))
		self.assertTrue(commandUtil.get_command_output('echo "Asking a yes no question (y/n)?" & read choice'))
    def __init__(self):
        '''
        Constructor
        '''
        self.logger = logging.getLogger('GemUtil')
        # Embebed Chef installation
        self.command = "/opt/chef/embedded/bin/gem"
        self.rubyEmbeddedInChef = True
        self.sys_gemrc = "/opt/chef/embedded/etc/gemrc"

        if not os.path.isfile(self.command):
            # Linux distribution Chef installation
            self.command = "/usr/bin/gem"
            self.sys_gemrc = "/etc/gemrc"
            self.rubyEmbeddedInChef = False

        if self.rubyEmbeddedInChef and not os.path.isdir(
                "/opt/chef/embedded/etc"):
            os.mkdir("/opt/chef/embedded/etc", 0755)

        self.commandUtil = CommandUtil()
        self.pm = PackageManager()
    def _delete_active_directory(self, method):
        ''' Deleting active directory user authentication method '''
        self.logger.debug(
            'Deleting active directory user authentication method')
        data = method.get_data()

        commandUtil = CommandUtil()

        # Run "net ads leave" command
        command = 'net ads leave -U {0}%{1}'.format(
            data.get_ad_administrator_user(), data.get_ad_administrator_pass())
        self.logger.debug('running: %s', command)
        if not commandUtil.execute_command(command, {}):
            self.logger.warn('Error running command: %s', command)

        # Delete configuration files
        self.logger.debug('Delete %s file', self.samba_conf_file)
        if os.path.isfile(self.samba_conf_file):
            os.remove(self.samba_conf_file)

        self.logger.debug('Delete %s file', self.krb_conf_file)
        if os.path.isfile(self.krb_conf_file):
            os.remove(self.krb_conf_file)

        extra_conf_lines = ''
        if self.sssd_version is not None:
            major, minor, _ = self.pm.parse_version_number(self.sssd_version)

            if major > 1 or (major == 1 and minor > 11):
                extra_conf_lines = '[domain/DEFAULT]\n'
                extra_conf_lines = extra_conf_lines + 'enumerate = TRUE\n'
                extra_conf_lines = extra_conf_lines + 'min_id = 500\n'
                extra_conf_lines = extra_conf_lines + 'max_id = 999\n'
                extra_conf_lines = extra_conf_lines + 'id_provider = local\n'
                extra_conf_lines = extra_conf_lines + 'auth_provider = local\n'
                extra_conf_lines = extra_conf_lines + '\n'

        self.logger.debug('Save /etc/sssd/sssd.conf file')
        # Save /etc/samba/sssd.conf file
        self._back_to_local_users()

        # Restart SSSD service
        self.logger.debug('Restart SSSD service')
        p = subprocess.Popen('service sssd restart',
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)

        for line in p.stdout.readlines():
            self.logger.debug(line)

        retval = p.wait()
        if retval != 0:
            self.logger.error('Error running command: ' +
                              'service sssd restart')
            return False

        self.logger.debug('Delete /etc/gca-sssd.control file')
        if os.path.isfile('/etc/gca-sssd.control'):
            os.remove('/etc/gca-sssd.control')

        return True
    def _save_active_directory_normal(self, method):
        ''' Saving active directory user authentication method '''

        self.logger.debug('Saving active directory user authentication method')
        data = method.get_data()

        # Check data values
        if (data.get_ad_administrator_user() is None
                or data.get_ad_administrator_user().strip() == ''):
            raise ValueError('Active directory administrator user is empty!')

        if (data.get_ad_administrator_pass() is None
                or data.get_ad_administrator_pass().strip() == ''):
            raise ValueError(
                'Active directory administrator password is empty!')

        if (data.get_domain() is None or data.get_domain().strip() == ''):
            raise ValueError('Active directory domain name is empty!')

        if (data.get_workgroup() is None
                or data.get_workgroup().strip() == ''):
            raise ValueError('Active directory workgroup is empty!')

        self.logger.debug('Save /etc/samba/smb.conf file')
        # Save /etc/samba/smb.conf file
        template = Template()
        template.source = get_data_file('templates/smb.conf')
        template.destination = self.samba_conf_file
        template.owner = 'root'
        template.group = 'root'
        template.mode = 00644
        template.variables = {
            'ad_domain': data.get_domain().upper(),
            'ad_workgroup': data.get_workgroup()
        }

        if not template.save():
            self.logger.error('Error saving /etc/samba/smb.conf file')
            return False

        self.logger.debug('Save /etc/krb5.conf file')
        # Save /etc/krb5.conf file
        template = Template()
        template.source = get_data_file('templates/krb5.conf')
        template.destination = self.krb_conf_file
        template.owner = 'root'
        template.group = 'root'
        template.mode = 00644
        template.variables = {
            'ad_domain': data.get_domain(),
            'ad_domain_upper': data.get_domain().upper()
        }

        if not template.save():
            self.logger.error('Error saving /etc/krb5.conf file')
            return False

        commandUtil = CommandUtil()
        # Run "net ads join" command
        command = 'net ads join -U {0}%{1}'.format(
            data.get_ad_administrator_user(), data.get_ad_administrator_pass())
        self.logger.debug('running: %s', command)
        if not commandUtil.execute_command(command, {}):
            self.logger.warn('Error running command: %s', command)
            self.logger.warn('Check if the configuration was OK')

            command = 'net ads testjoin'
            self.logger.debug('running: %s', command)
            if not commandUtil.execute_command(command, {}):
                self.logger.error(
                    'Error testing if the workstation was joined to ' +
                    'the domain with command: %s', command)
                return False

        extra_conf_lines = ''
        if self.sssd_version is not None:
            major, minor, _ = self.pm.parse_version_number(self.sssd_version)

            if major > 1 or (major == 1 and minor > 11):
                extra_conf_lines = 'ad_gpo_map_interactive = +mdm, +polkit-1'

        self.logger.debug('Save /etc/sssd/sssd.conf file')
        # Save /etc/samba/sssd.conf file
        template = Template()
        template.source = get_data_file('templates/sssd.conf.ad')
        template.destination = self.main_data_file
        template.owner = 'root'
        template.group = 'root'
        template.mode = 00600
        template.variables = {
            'ad_domain': data.get_domain(),
            'extra_conf_lines': extra_conf_lines
        }

        if not template.save():
            self.logger.error('Error saving /etc/sssd/sssd.conf file')
            return False

        # Restart SSSD service
        self.logger.debug('Restart SSSD service')
        p = subprocess.Popen('service sssd restart',
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)

        for line in p.stdout.readlines():
            self.logger.debug(line)

        retval = p.wait()
        if retval != 0:
            self.logger.error('Error running command: ' +
                              'service sssd restart')
            return False

        self.logger.debug('Save /usr/share/pam-configs/my_mkhomedir file')
        # Save /usr/share/pam-configs/my_mkhomedir file
        template = Template()
        template.source = get_data_file('templates/my_mkhomedir')
        template.destination = '/usr/share/pam-configs/my_mkhomedir'
        template.owner = 'root'
        template.group = 'root'
        template.mode = 00644
        template.variables = {}

        if not template.save():
            self.logger.error(
                'Error saving /usr/share/pam-configs/my_mkhomedir file')
            return False

        # Execute command pam-auth-update
        self.logger.debug('Execute command pam-auth-update')
        p = subprocess.Popen('pam-auth-update --package',
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)

        for line in p.stdout.readlines():
            self.logger.debug(line)

        retval = p.wait()
        if retval != 0:
            self.logger.error('Error running command: ' + 'pam-auth-update')
            return False

        self.logger.debug('Save /etc/gca-sssd.control file')
        # Save /etc/gca-sssd.control file
        template = Template()
        template.source = get_data_file('templates/gca-sssd.control')
        template.destination = '/etc/gca-sssd.control'
        template.owner = 'root'
        template.group = 'root'
        template.mode = 00644
        template.variables = {'auth_type': 'ad'}

        if not template.save():
            self.logger.error('Error saving /etc/gca-sssd.control file')
            return False

        return True
    def _save_active_directory_specific(self, method):
        ''' Saving specific active directory user authentication method '''

        self.logger.debug(
            'Saving specific active directory user authentication method')
        data = method.get_data()

        # Check data values
        if (data.get_ad_administrator_user() is None
                or data.get_ad_administrator_user().strip() == ''):
            raise ValueError('Active directory administrator user is empty!')

        if (data.get_ad_administrator_pass() is None
                or data.get_ad_administrator_pass().strip() == ''):
            raise ValueError(
                'Active directory administrator password is empty!')

        if (data.get_krb_5_conf() is None
                or data.get_krb_5_conf().strip() == ''):
            raise ValueError('krb5.conf file is empty!')

        if (data.get_sssd_conf() is None
                or data.get_sssd_conf().strip() == ''):
            raise ValueError('sssd.conf file is empty!')

        if (data.get_smb_conf() is None or data.get_smb_conf().strip() == ''):
            raise ValueError('smb.conf file is empty!')

        if (data.get_pam_conf() is None or data.get_pam_conf().strip() == ''):
            raise ValueError('pam.conf file is empty!')

        # Save files
        if not self._save_base64_file(self.main_data_file,
                                      data.get_sssd_conf()):
            self.logger.error("Error saving sssd.conf file!")
            return False

        if not self._save_base64_file(self.samba_conf_file,
                                      data.get_smb_conf()):
            self.logger.error("Error saving smb.conf file!")
            return False

        if not (self._save_base64_file(self.krb_conf_file,
                                       data.get_krb_5_conf())):
            self.logger.error("Error saving krb5.conf file!")
            return False

        if not self._save_base64_file('/etc/pam.conf', data.get_pam_conf()):
            self.logger.error("Error saving pam.conf file!")
            return False

        # Run "net ads join" command
        commandUtil = CommandUtil()
        command = 'net ads join -U {0}%{1}'.format(
            data.get_ad_administrator_user(), data.get_ad_administrator_pass())
        self.logger.debug('running: %s', command)

        if not commandUtil.execute_command(command, {}):
            self.logger.warn('Error running command: %s', command)
            self.logger.warn('Check if the configuration was OK')

            command = 'net ads testjoin'
            self.logger.debug('running: %s', command)
            if not commandUtil.execute_command(command, {}):
                self.logger.error(
                    'Error testing if the workstation was joined ' +
                    'to the domain with command: %s', command)
                return False

        # Restart SSSD service
        self.logger.debug('Restart SSSD service')
        p = subprocess.Popen('service sssd restart',
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)

        for line in p.stdout.readlines():
            self.logger.debug(line)

        retval = p.wait()
        if retval != 0:
            self.logger.error('Error running command: ' +
                              'service sssd restart')
            return False

        self.logger.debug('Save /usr/share/pam-configs/my_mkhomedir file')
        # Save /usr/share/pam-configs/my_mkhomedir file
        template = Template()
        template.source = get_data_file('templates/my_mkhomedir')
        template.destination = '/usr/share/pam-configs/my_mkhomedir'
        template.owner = 'root'
        template.group = 'root'
        template.mode = 00644
        template.variables = {}

        if not template.save():
            self.logger.error(
                'Error saving /usr/share/pam-configs/my_mkhomedir file')
            return False

        # Execute command pam-auth-update
        self.logger.debug('Execute command pam-auth-update')
        p = subprocess.Popen('pam-auth-update --package',
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)

        for line in p.stdout.readlines():
            self.logger.debug(line)

        retval = p.wait()
        if retval != 0:
            self.logger.error('Error running command: ' + 'pam-auth-update')
            return False

        self.logger.debug('Save /etc/gca-sssd.control file')
        # Save /etc/gca-sssd.control file
        template = Template()
        template.source = get_data_file('templates/gca-sssd.control')
        template.destination = '/etc/gca-sssd.control'
        template.owner = 'root'
        template.group = 'root'
        template.mode = 00644
        template.variables = {'auth_type': 'ad'}

        if not template.save():
            self.logger.error('Error saving /etc/gca-sssd.control file')
            return False

        return True
class GemUtil(object):
    '''
    Utility class to configure Ruby GEMs.
    '''
    def __init__(self):
        '''
        Constructor
        '''
        self.logger = logging.getLogger('GemUtil')
        # Embebed Chef installation
        self.command = "/opt/chef/embedded/bin/gem"
        self.rubyEmbeddedInChef = True
        self.sys_gemrc = "/opt/chef/embedded/etc/gemrc"

        if not os.path.isfile(self.command):
            # Linux distribution Chef installation
            self.command = "/usr/bin/gem"
            self.sys_gemrc = "/etc/gemrc"
            self.rubyEmbeddedInChef = False

        if self.rubyEmbeddedInChef and not os.path.isdir(
                "/opt/chef/embedded/etc"):
            os.mkdir("/opt/chef/embedded/etc", 0755)

        self.commandUtil = CommandUtil()
        self.pm = PackageManager()

    def get_gem_sources_list(self):
        ''' Getting gem sources '''

        lst = []

        output = self.commandUtil.get_command_output(
            '{} source --list --config-file "{}"'.format(
                self.command, self.sys_gemrc))

        for line in output:
            if line.startswith('http'):
                lst.append(line.strip())

        return lst

    def clear_cache_gem_sources(self):
        ''' Cleaning up gem sources cache '''

        return self.commandUtil.execute_command(
            '{} source -c --config-file "{}"'.format(self.command,
                                                     self.sys_gemrc))

    def remove_all_gem_sources(self):
        ''' Removing all gem sources '''

        sources = self.get_gem_sources_list()
        for source in sources:
            print "removing %s", source
            self.commandUtil.execute_command(
                '{} source -r "{}" --config-file "{}"'.format(
                    self.command, source, self.sys_gemrc))

        if os.path.exists(self.sys_gemrc):
            os.remove(self.sys_gemrc)

    # Adding only gecoscc.ini source ("gem_repo")
    # The gem add command adds https://rubygems.org source
    # by default. We must manually delete it.
    def add_gem_only_one_source(self, url):
        ''' Adding only gecoscc.ini gem source '''

        sources = self.get_gem_sources_list()

        self.logger.debug("adding gem source from gecoscc.ini: %s", url)
        res = self.add_gem_source(url)

        self.logger.debug("deleting all the other sources")
        for source in sources:
            if source != url:
                self.logger.debug("removing %s from gem sources", source)
                res &= self.commandUtil.execute_command(
                    '{} source -r "{}" --config-file "{}"'.format(
                        self.command, source, self.sys_gemrc))

        return res

    def add_gem_source(self, url):
        ''' Adding gem sources '''

        return self.commandUtil.execute_command(
            '{} source -a "{}" --config-file "{}"'.format(
                self.command, url, self.sys_gemrc))

    def remove_gem_source(self, url):
        ''' Removing gem source '''

        return self.commandUtil.execute_command(
            '{} source -r "{}" --config-file "{}"'.format(
                self.command, url, self.sys_gemrc))

    def is_gem_intalled(self, gem_name):
        ''' Is gem installed? '''

        output = self.commandUtil.get_command_output('{} list'.format(
            self.command))
        res = False
        if output != False:
            for line in output:
                if line.startswith(gem_name + ' '):
                    res = True

        return res

    def install_gem(self, gem_name):
        ''' Installing gem '''

        if not self.rubyEmbeddedInChef:
            # Try to install the GEM by using the package manager
            package_name = gem_name
            if not package_name.startswith('ruby-'):
                package_name = 'ruby-{}'.format(package_name)

            if (self.pm.exists_package(package_name)
                    and not self.pm.is_package_installed(package_name)):
                self.pm.install_package(package_name)

            if self.is_gem_intalled(gem_name):
                # GEM installed successfully by using the package manager
                return True

            # GEM is not installed successfully
            if not self.pm.is_package_installed('build-essential'):
                # We will need 'build-essential' package to build GEMs
                self.pm.install_package('build-essential')

        return self.commandUtil.execute_command(
            '{} install "{}"'.format(self.command, gem_name), os.environ)

    def uninstall_gem(self, gem_name):
        ''' Uninstall gem '''

        if not self.rubyEmbeddedInChef:
            # Try to uninstall the GEM by using the package manager
            package_name = gem_name
            if not package_name.startswith('ruby-'):
                package_name = 'ruby-{}'.format(package_name)

            if (self.pm.exists_package(package_name)
                    and self.pm.is_package_installed(package_name)):
                self.pm.remove_package(package_name)

            if not self.is_gem_intalled(gem_name):
                # GEM uninstalled successfully by using the package manager
                return True

        return self.commandUtil.execute_command('{} uninstall "{}"'.format(
            self.command, gem_name))
    def addCertificateToTrustedCAs(self, certificate, isChefCertificate=False):
        ''' Adding certificate to trusted CAs '''

        if certificate is None:
            return
        if not os.path.isdir('/usr/share/ca-certificates/'):
            raise Exception(
                'There is no /usr/share/ca-certificates/ directory')
        if not os.path.isfile('/etc/ca-certificates.conf'):
            raise Exception('There is no /etc/ca-certificates.conf file')
        if not os.path.isdir('/usr/share/ca-certificates/gecos'):
            os.mkdir('/usr/share/ca-certificates/gecos')
        info = self.getCertificateInfo(certificate)
        filename = 'unknown'
        if info.get_subject().commonName is not None:
            filename = ("%s.crt" % (info.get_subject().commonName.lower()))
        if not self.isSelfSigned(info):
            # Is not a self signed certificate
            # We must get the Issuer CA certificate
            url = self.getIssuerCertificateURL(info)
            if url is None:
                raise Exception('Can\'t find issuer CA certificate URL!')
            certificate = self.getCertificateFromURL(url)
            filename = os.path.basename(url)
            info = self.getCertificateInfo(certificate)
            if self.getIssuerCertificateURL(info) is not None:
                # Recursively add certificate to trusted CA
                self.addCertificateToTrustedCAs(certificate)
        # Write PEM certificate into
        # /usr/share/ca-certificates/gecos/<certificate CN>.crt
        fd = open('/usr/share/ca-certificates/gecos/%s' % (filename), 'w')
        fd.write(self.convertDERcertificateToPEM(certificate))
        fd.close()
        # Chef server certificates must be also included inside
        # /etc/chef/trusted_certs path (at least for embedded Chef clients
        # that use /opt/chef/embedded/ssl/certs)
        if (isChefCertificate and not os.path.exists(
                '/etc/chef/trusted_certs/{}'.format(filename))):
            if not os.path.isdir('/etc/chef'):
                os.mkdir('/etc/chef')
            if not os.path.isdir('/etc/chef/trusted_certs'):
                os.mkdir('/etc/chef/trusted_certs')
            os.symlink('/usr/share/ca-certificates/gecos/{}'.format(filename),
                       '/etc/chef/trusted_certs/{}'.format(filename))
        # Check if there is a line for this certificate
        # in /etc/ca-certificates.conf
        fd = codecs.open('/etc/ca-certificates.conf', 'r', encoding='utf-8')
        ca_certificates_conf = fd.read()
        fd.close()
        found = False
        ca_certificates = []
        for line in ca_certificates_conf.split('\n'):
            if line.startswith(u'gecos/{}'.format(filename)):
                # The certificate already existed
                found = True
            if (not line.startswith(u'!gecos/{}'.format(filename))
                    and len(line.strip()) > 0):
                # Skip the deleted certificate
                ca_certificates.append(line)
        if not found:
            ca_certificates.append(u'gecos/{}'.format(filename))
            ca_certificates.append(u'')
            ca_certificates_conf = '\n'.join(ca_certificates)
            # Overwrite the  /etc/ca-certificates.conf file
            fd = codecs.open('/etc/ca-certificates.conf',
                             'w',
                             encoding='utf-8')
            fd.write(ca_certificates_conf)
            fd.close()
            # Run update-ca-certificates
            commandUtil = CommandUtil()
            commandUtil.execute_command('/usr/sbin/update-ca-certificates')