def main():
    parser = argparse.ArgumentParser(
        epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('address',
                        help='hostname or ip address of target appliance')

    args = parser.parse_args()

    ssh_kwargs = {
        'username': credentials['ssh']['username'],
        'password': credentials['ssh']['password'],
        'hostname': args.address
    }

    # Init SSH client
    client = SSHClient(**ssh_kwargs)

    # generate installed rpm list
    status, out = client.run_command(
        'rpm -qa | sort > /tmp/installed_rpms.txt')
    client.get_file('/tmp/installed_rpms.txt', 'installed_rpms.txt')

    # compress logs dir
    status, out = client.run_command(
        'cd /var/www/miq/vmdb; tar zcvf /tmp/appliance_logs.tgz log')
    client.get_file('/tmp/appliance_logs.tgz', 'appliance_logs.tgz')
예제 #2
0
def setup_external_auth_openldap(**data):
    """Sets up the appliance for an external authentication with OpenLdap.

    Keywords:
        get_groups: Get User Groups from External Authentication (httpd).
        ipaserver: IPA server address.
        iparealm: Realm.
        credentials: Key of the credential in credentials.yaml
    """
    connect_kwargs = {
        'username': credentials['host_default']['username'],
        'password': credentials['host_default']['password'],
        'hostname': data['ipaddress'],
    }
    appliance_obj = appliance.IPAppliance()
    appliance_name = 'cfmeappliance{}'.format(fauxfactory.gen_alpha(7).lower())
    appliance_address = appliance_obj.address
    appliance_fqdn = '{}.{}'.format(appliance_name, data['domain_name'])
    ldapserver_ssh = SSHClient(**connect_kwargs)
    # updating the /etc/hosts is a workaround due to the
    # https://bugzilla.redhat.com/show_bug.cgi?id=1360928
    command = 'echo "{}\t{}" >> /etc/hosts'.format(appliance_address, appliance_fqdn)
    ldapserver_ssh.run_command(command)
    ldapserver_ssh.get_file(remote_file=data['cert_filepath'],
                            local_path=conf_path.strpath)
    ldapserver_ssh.close()
    ensure_browser_open()
    login_admin()
    auth = ExternalAuthSetting(get_groups=data.pop("get_groups", True))
    auth.setup()
    appliance_obj.configure_appliance_for_openldap_ext_auth(appliance_fqdn)
    logout()
예제 #3
0
def setup_external_auth_openldap(**data):
    """Sets up the appliance for an external authentication with OpenLdap.

    Keywords:
        get_groups: Get User Groups from External Authentication (httpd).
        ipaserver: IPA server address.
        iparealm: Realm.
        credentials: Key of the credential in credentials.yaml
    """
    connect_kwargs = {
        'username': credentials['host_default']['username'],
        'password': credentials['host_default']['password'],
        'hostname': data['ipaddress'],
    }
    appliance_obj = appliance.IPAppliance()
    appliance_name = 'cfmeappliance{}'.format(fauxfactory.gen_alpha(7).lower())
    appliance_address = appliance_obj.address
    appliance_fqdn = '{}.{}'.format(appliance_name, data['domain_name'])
    ldapserver_ssh = SSHClient(**connect_kwargs)
    # updating the /etc/hosts is a workaround due to the
    # https://bugzilla.redhat.com/show_bug.cgi?id=1360928
    command = 'echo "{}\t{}" >> /etc/hosts'.format(appliance_address,
                                                   appliance_fqdn)
    ldapserver_ssh.run_command(command)
    ldapserver_ssh.get_file(remote_file=data['cert_filepath'],
                            local_path=conf_path.strpath)
    ldapserver_ssh.close()
    ensure_browser_open()
    login_admin()
    auth = ExternalAuthSetting(get_groups=data.pop("get_groups", True))
    auth.setup()
    appliance_obj.configure_appliance_for_openldap_ext_auth(appliance_fqdn)
    logout()
예제 #4
0
def main():
    parser = argparse.ArgumentParser(
        epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('address',
                        help='hostname or ip address of target appliance')
    parser.add_argument('-R',
                        '--reverse',
                        help='flag to indicate the patch should be undone',
                        action='store_true',
                        default=False,
                        dest='reverse')

    args = parser.parse_args()

    # Find the patch file
    patch_file_name = data_path_for_filename('ajax_wait.diff',
                                             scripts_path.strpath)

    # Set up temp dir
    tmpdir = mkdtemp()
    atexit.register(shutil.rmtree, tmpdir)
    source = '/var/www/miq/vmdb/public/javascripts/application.js'
    target = os.path.join(tmpdir, 'application.js')

    # Init SSH client
    ssh_kwargs = {
        'username': credentials['ssh']['username'],
        'password': credentials['ssh']['password'],
        'hostname': args.address
    }
    client = SSHClient(**ssh_kwargs)

    print 'retriving appliance.js from appliance'
    client.get_file(source, target)

    os.chdir(tmpdir)
    # patch, level 4, patch direction (default forward), ignore whitespace, don't output rejects
    direction = '-N -R' if args.reverse else '-N'
    exitcode = subprocess.call('patch -p4 %s -l -r- < %s' %
                               (direction, patch_file_name),
                               shell=True)

    if exitcode == 0:
        # Put it back after successful patching.
        print 'replacing appliance.js on appliance'
        client.put_file(target, source)
    else:
        print 'not changing appliance'

    return exitcode
예제 #5
0
def main():
    parser = argparse.ArgumentParser(epilog=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('address', help='hostname or ip address of target appliance')
    parser.add_argument('-R', '--reverse', help='flag to indicate the patch should be undone',
        action='store_true', default=False, dest='reverse')

    args = parser.parse_args()

    # Find the patch file
    patch_file_name = data_path_for_filename('ajax_wait.diff', scripts_path.strpath)

    # Set up temp dir
    tmpdir = mkdtemp()
    atexit.register(shutil.rmtree, tmpdir)
    source = '/var/www/miq/vmdb/public/javascripts/application.js'
    target = os.path.join(tmpdir, 'application.js')

    # Init SSH client
    ssh_kwargs = {
        'username': credentials['ssh']['username'],
        'password': credentials['ssh']['password'],
        'hostname': args.address
    }
    client = SSHClient(**ssh_kwargs)

    print 'retriving appliance.js from appliance'
    client.get_file(source, target)

    os.chdir(tmpdir)
    # patch, level 4, patch direction (default forward), ignore whitespace, don't output rejects
    direction = '-N -R' if args.reverse else '-N'
    exitcode = subprocess.call('patch -p4 %s -l -r- < %s' % (direction, patch_file_name),
        shell=True)

    if exitcode == 0:
        # Put it back after successful patching.
        print 'replacing appliance.js on appliance'
        client.put_file(target, source)
    else:
        print 'not changing appliance'

    return exitcode
예제 #6
0
def main():
    parser = argparse.ArgumentParser(epilog=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument('address', help='hostname or ip address of target appliance')

    args = parser.parse_args()

    ssh_kwargs = {
        'username': credentials['ssh']['username'],
        'password': credentials['ssh']['password'],
        'hostname': args.address
    }

    # Init SSH client
    client = SSHClient(**ssh_kwargs)

    # generate installed rpm list
    status, out = client.run_command('rpm -qa | sort > /tmp/installed_rpms.txt')
    client.get_file('/tmp/installed_rpms.txt', 'installed_rpms.txt')

    # compress logs dir
    status, out = client.run_command('cd /var/www/miq/vmdb; tar zcvf /tmp/appliance_logs.tgz log')
    client.get_file('/tmp/appliance_logs.tgz', 'appliance_logs.tgz')
예제 #7
0
class UiCoveragePlugin(object):
    def __init__(self):
        self.ssh_client = SSHClient()

    # trylast so that terminalreporter's been configured before ui-coverage
    @pytest.mark.trylast
    def pytest_configure(self, config):
        # Eventually, the setup/teardown work for coverage should be handled by
        # utils.appliance.Appliance to make multi-appliance support easy
        self.reporter = config.pluginmanager.getplugin('terminalreporter')
        self.reporter.write_sep('-', 'Setting up UI coverage reporting')
        self.install_simplecov()
        self.install_coverage_hook()
        self.restart_evm()
        self.touch_all_the_things()
        check_appliance_ui(base_url())

    def pytest_unconfigure(self, config):
        self.reporter.write_sep(
            '-', 'Waiting for coverage to finish and collecting reports')
        self.stop_touching_all_the_things()
        self.merge_reports()
        self.collect_reports()
        self.print_report()

    def install_simplecov(self):
        logger.info('Installing coverage gems on appliance')
        self.ssh_client.put_file(gemfile.strpath, rails_root.strpath)
        x, out = self.ssh_client.run_command(
            'cd {}; bundle'.format(rails_root))
        return x == 0

    def install_coverage_hook(self):
        logger.info('Installing coverage hook on appliance')
        # Put the coverage hook in the miq lib path
        self.ssh_client.put_file(
            coverage_hook.strpath,
            rails_root.join('..', 'lib', coverage_hook.basename).strpath)
        replacements = {
            'require': r"require 'coverage_hook'",
            'config': rails_root.join('config').strpath
        }
        # grep/echo to try to add the require line only once
        # This goes in preinitializer after the miq lib path is set up,
        # which makes it so ruby can actually require the hook
        command_template = (
            'cd {config};'
            'grep -q "{require}" preinitializer.rb || echo -e "\\n{require}" >> preinitializer.rb'
        )
        x, out = self.ssh_client.run_command(
            command_template.format(**replacements))
        return x == 0

    def restart_evm(self, rude=True):
        logger.info('Restarting EVM to enable coverage reporting')
        # This is rude by default (issuing a kill -9 on ruby procs), since the most common use-case
        # will be to set up coverage on a freshly provisioned appliance in a jenkins run
        if rude:
            x, out = self.ssh_client.run_command(
                'killall -9 ruby; service evmserverd start')
        else:
            x, out = self.ssh_client.run_comment('service evmserverd restart')
        return x == 0

    def touch_all_the_things(self):
        logger.info(
            'Establishing baseline overage by requiring ALL THE THINGS')
        # send over the thing toucher
        self.ssh_client.put_file(
            thing_toucher.strpath,
            rails_root.join(thing_toucher.basename).strpath)
        # start it in an async process so we can go one testing while this takes place
        self._thing_toucher_proc = Process(target=_thing_toucher_mp_handler,
                                           args=[self.ssh_client])
        self._thing_toucher_proc.start()

    def stop_touching_all_the_things(self):
        logger.info('Waiting for baseline coverage generator to finish')
        # block while the thing toucher is still running
        self._thing_toucher_proc.join()
        return self._thing_toucher_proc.exitcode == 0

    def merge_reports(self):
        logger.info("Merging coverage reports on appliance")
        # install the merger script
        self.ssh_client.put_file(
            coverage_merger.strpath,
            rails_root.join(coverage_merger.basename).strpath)
        # don't async this one since it's happening in unconfigure
        # merge/clean up the coverage reports
        x, out = self.ssh_client.run_rails_command('coverage_merger.rb')
        return x == 0

    def collect_reports(self):
        coverage_dir = log_path.join('coverage')
        # clean out old coverage dir if it exists
        if coverage_dir.check():
            coverage_dir.remove(rec=True, ignore_errors=True)
        # Then ensure the the empty dir exists
        coverage_dir.ensure(dir=True)
        # then copy the remote coverage dir into it
        logger.info("Collecting coverage reports to {}".format(
            coverage_dir.strpath))
        logger.info("Report collection can take several minutes")
        self.ssh_client.get_file(rails_root.join('coverage').strpath,
                                 log_path.strpath,
                                 recursive=True)

    def print_report(self):
        try:
            last_run = json.load(
                log_path.join('coverage', '.last_run.json').open())
            coverage = last_run['result']['covered_percent']
            # TODO: Make the happy vs. sad coverage color configurable, and set it to something
            # good once we know what good is
            style = {'bold': True}
            if coverage > 40:
                style['green'] = True
            else:
                style['red'] = True
            self.reporter.line('UI Coverage Result: {}%'.format(coverage),
                               **style)
        except KeyboardInterrupt:
            # don't block this, so users can cancel out
            raise
        except:
            logger.error(
                'Error printing coverage report to terminal, traceback follows'
            )
            logger.error(traceback.format_exc())
예제 #8
0
class UiCoveragePlugin(object):
    def __init__(self):
        self.ssh_client = SSHClient()

    # trylast so that terminalreporter's been configured before ui-coverage
    @pytest.mark.trylast
    def pytest_configure(self, config):
        # Eventually, the setup/teardown work for coverage should be handled by
        # utils.appliance.Appliance to make multi-appliance support easy
        self.reporter = config.pluginmanager.getplugin('terminalreporter')
        self.reporter.write_sep('-', 'Setting up UI coverage reporting')
        self.install_simplecov()
        self.install_coverage_hook()
        self.restart_evm()
        self.touch_all_the_things()
        check_appliance_ui(base_url())

    def pytest_unconfigure(self, config):
        self.reporter.write_sep('-', 'Waiting for coverage to finish and collecting reports')
        self.stop_touching_all_the_things()
        self.merge_reports()
        self.collect_reports()
        self.print_report()

    def install_simplecov(self):
        logger.info('Installing coverage gems on appliance')
        self.ssh_client.put_file(gemfile.strpath, rails_root.strpath)
        x, out = self.ssh_client.run_command('cd {}; bundle'.format(rails_root))
        return x == 0

    def install_coverage_hook(self):
        logger.info('Installing coverage hook on appliance')
        # Put the coverage hook in the miq lib path
        self.ssh_client.put_file(
            coverage_hook.strpath, rails_root.join('..', 'lib', coverage_hook.basename).strpath
        )
        replacements = {
            'require': r"require 'coverage_hook'",
            'config': rails_root.join('config').strpath
        }
        # grep/echo to try to add the require line only once
        # This goes in preinitializer after the miq lib path is set up,
        # which makes it so ruby can actually require the hook
        command_template = (
            'cd {config};'
            'grep -q "{require}" preinitializer.rb || echo -e "\\n{require}" >> preinitializer.rb'
        )
        x, out = self.ssh_client.run_command(command_template.format(**replacements))
        return x == 0

    def restart_evm(self, rude=True):
        logger.info('Restarting EVM to enable coverage reporting')
        # This is rude by default (issuing a kill -9 on ruby procs), since the most common use-case
        # will be to set up coverage on a freshly provisioned appliance in a jenkins run
        if rude:
            x, out = self.ssh_client.run_command('killall -9 ruby; service evmserverd start')
        else:
            x, out = self.ssh_client.run_comment('service evmserverd restart')
        return x == 0

    def touch_all_the_things(self):
        logger.info('Establishing baseline overage by requiring ALL THE THINGS')
        # send over the thing toucher
        self.ssh_client.put_file(
            thing_toucher.strpath, rails_root.join(thing_toucher.basename).strpath
        )
        # start it in an async process so we can go one testing while this takes place
        self._thing_toucher_proc = Process(target=_thing_toucher_mp_handler, args=[self.ssh_client])
        self._thing_toucher_proc.start()

    def stop_touching_all_the_things(self):
        logger.info('Waiting for baseline coverage generator to finish')
        # block while the thing toucher is still running
        self._thing_toucher_proc.join()
        return self._thing_toucher_proc.exitcode == 0

    def merge_reports(self):
        logger.info("Merging coverage reports on appliance")
        # install the merger script
        self.ssh_client.put_file(
            coverage_merger.strpath, rails_root.join(coverage_merger.basename).strpath
        )
        # don't async this one since it's happening in unconfigure
        # merge/clean up the coverage reports
        x, out = self.ssh_client.run_rails_command('coverage_merger.rb')
        return x == 0

    def collect_reports(self):
        coverage_dir = log_path.join('coverage')
        # clean out old coverage dir if it exists
        if coverage_dir.check():
            coverage_dir.remove(rec=True, ignore_errors=True)
        # Then ensure the the empty dir exists
        coverage_dir.ensure(dir=True)
        # then copy the remote coverage dir into it
        logger.info("Collecting coverage reports to {}".format(coverage_dir.strpath))
        logger.info("Report collection can take several minutes")
        self.ssh_client.get_file(
            rails_root.join('coverage').strpath,
            log_path.strpath,
            recursive=True
        )

    def print_report(self):
        try:
            last_run = json.load(log_path.join('coverage', '.last_run.json').open())
            coverage = last_run['result']['covered_percent']
            # TODO: Make the happy vs. sad coverage color configurable, and set it to something
            # good once we know what good is
            style = {'bold': True}
            if coverage > 40:
                style['green'] = True
            else:
                style['red'] = True
            self.reporter.line('UI Coverage Result: {}%'.format(coverage), **style)
        except KeyboardInterrupt:
            # don't block this, so users can cancel out
            raise
        except:
            logger.error('Error printing coverage report to terminal, traceback follows')
            logger.error(traceback.format_exc())