Example #1
0
def dump_debug_info():
    def dump_external_debug_info(title, args):
        dump_file.write(f'\n\n*****{title}******\n')
        p = subprocess.Popen(args, stdout=subprocess.PIPE)
        out, err = p.communicate()
        lines = filter(lambda x: x.strip(),
                       out.decode("utf-8").splitlines(keepends=True))
        dump_file.writelines(lines)

    try:
        logger = Log('dump_debug_info')
        config = Config()

        timestr = time.strftime("%Y%m%d-%H%M%S")
        dump_path = os.getcwd() + f'/epicli_error_{timestr}.dump'
        dump_file = open(dump_path, 'w')

        dump_file.write('*****EPICLI VERSION******\n')
        dump_file.write(f'{VERSION}')

        dump_file.write('\n\n*****EPICLI ARGS******\n')
        dump_file.write(' '.join([*['epicli'], *sys.argv[1:]]))

        dump_file.write('\n\n*****EPICLI CONFIG******\n')
        for attr in config.__dict__:
            if attr.startswith('_'):
                dump_file.write('%s = %r\n' %
                                (attr[1:], getattr(config, attr)))

        dump_file.write('\n\n*****SYSTEM******\n')
        system_data = {
            'platform': platform.system(),
            'release': platform.release(),
            'type': platform.uname().system,
            'arch': platform.uname().machine,
            'cpus': json.dumps(os.cpu_count()),
            'hostname': socket.gethostname()
        }
        dump_file.write(json.dumps(dict(system_data), indent=2))

        dump_file.write('\n\n*****ENVIROMENT VARS******\n')
        dump_file.write(json.dumps(dict(os.environ), indent=2))

        dump_file.write('\n\n*****PYTHON******\n')
        dump_file.write(f'python_version: {platform.python_version()}\n')
        dump_file.write(f'python_build: {platform.python_build()}\n')
        dump_file.write(f'python_revision: {platform.python_revision()}\n')
        dump_file.write(f'python_compiler: {platform.python_compiler()}\n')
        dump_file.write(f'python_branch: {platform.python_branch()}\n')
        dump_file.write(
            f'python_implementation: {platform.python_implementation()}\n')

        dump_external_debug_info('ANSIBLE VERSION', ['ansible', '--version'])
        dump_external_debug_info('ANSIBLE CONFIG', ['ansible-config', 'dump'])
        dump_external_debug_info('ANSIBLE-VAULT VERSION',
                                 ['ansible-vault', '--version'])
        dump_external_debug_info('TERRAFORM VERSION',
                                 ['terraform', '--version'])
        dump_external_debug_info('SKOPEO VERSION', ['skopeo', '--version'])
        dump_external_debug_info('RUBY VERSION', ['ruby', '--version'])
        dump_external_debug_info('RUBY GEM VERSION', ['gem', '--version'])
        dump_external_debug_info('RUBY INSTALLED GEMS',
                                 ['gem', 'query', '--local'])

        dump_file.write('\n\n*****LOG******\n')
        log_path = os.path.join(get_output_path(), config.log_file)
        dump_file.writelines([l for l in open(log_path).readlines()])
    finally:
        dump_file.close()
        logger.info(f'Error dump has been written to: {dump_path}')
        logger.warning(
            'This dump might contain sensitive information. Check before sharing.'
        )
Example #2
0
class TerraformCommand:
    def __init__(self, working_directory=os.path.dirname(__file__)):
        self.logger = Log(__name__)
        self.APPLY_COMMAND = "apply"
        self.DESTROY_COMMAND = "destroy"
        self.PLAN_COMMAND = "plan"
        self.INIT_COMMAND = "init"
        self.working_directory = working_directory

    def apply(self, auto_approve=False, env=os.environ.copy()):
        self.run(self,
                 self.APPLY_COMMAND,
                 auto_approve=auto_approve,
                 env=env,
                 auto_retries=3)

    def destroy(self, auto_approve=False, env=os.environ.copy()):
        self.run(self,
                 self.DESTROY_COMMAND,
                 auto_approve=auto_approve,
                 env=env)

    def plan(self, env=os.environ.copy()):
        self.run(self, self.PLAN_COMMAND, env=env)

    def init(self, env=os.environ.copy()):
        self.run(self, self.INIT_COMMAND, env=env)

    @staticmethod
    def run(self, command, env, auto_approve=False, auto_retries=1):
        cmd = ['terraform', command]

        if auto_approve:
            cmd.append('--auto-approve')

        if command == self.APPLY_COMMAND or command == self.DESTROY_COMMAND:
            cmd.append(f'-state={self.working_directory}/terraform.tfstate')

        cmd.append('-no-color')

        cmd.append(self.working_directory)

        cmd = ' '.join(cmd)
        self.logger.info(f'Running: "{cmd}"')

        if Config().debug > 0:
            env['TF_LOG'] = terraform_verbosity[Config().debug]

        retries = 1
        do_retry = True
        while ((retries <= auto_retries) and do_retry):
            logpipe = LogPipe(__name__)
            with subprocess.Popen(cmd,
                                  stdout=logpipe,
                                  stderr=logpipe,
                                  env=env,
                                  shell=True) as sp:
                logpipe.close()
            retries = retries + 1
            do_retry = next(
                (True for s in logpipe.stderrstrings if 'RetryableError' in s),
                False)
            if do_retry and retries <= auto_retries:
                self.logger.warning(
                    f'Terraform failed with "RetryableError" error. Retry: ' +
                    str(retries) + '/' + str(auto_retries))

        if sp.returncode != 0:
            raise Exception(f'Error running: "{cmd}"')
        else:
            self.logger.info(f'Done running "{cmd}"')
Example #3
0
class AnsibleCommand:
    def __init__(self, working_directory=os.path.dirname(__file__)):
        self.logger = Log(__name__)
        self.working_directory = working_directory

    def __init__(self):
        self.logger = Log(__name__)

    def run_task(self, hosts, inventory, module, args=None):
        cmd = ['ansible']

        cmd.extend(["-m", module])

        if args is not None and len(args) > 0:
            cmd.extend(["-a", args])

        if inventory is not None and len(inventory) > 0:
            cmd.extend(["-i", inventory])

        cmd.append(hosts)

        if Config().debug > 0:
            cmd.append(ansible_verbosity[Config().debug])

        self.logger.info('Running: "' + ' '.join(module) + '"')

        logpipe = LogPipe(__name__)
        with subprocess.Popen(cmd, stdout=logpipe, stderr=logpipe) as sp:
            logpipe.close()

        if sp.returncode != 0:
            raise Exception('Error running: "' + ' '.join(cmd) + '"')
        else:
            self.logger.info('Done running "' + ' '.join(cmd) + '"')

    def run_task_with_retries(self,
                              inventory,
                              module,
                              hosts,
                              retries,
                              timeout=10,
                              args=None):
        for i in range(retries):
            try:
                self.run_task(hosts=hosts,
                              inventory=inventory,
                              module=module,
                              args=args)
                break
            except Exception as e:
                self.logger.error(e)
                self.logger.warning('Retry running task: ' + str(i + 1) + '/' +
                                    str(retries))
                time.sleep(timeout)
        else:
            raise Exception(
                f'Failed running task after {str(retries)} retries')

    def run_playbook(self, inventory, playbook_path, vault_file=None):
        cmd = ['ansible-playbook']

        if inventory is not None and len(inventory) > 0:
            cmd.extend(["-i", inventory])

        if vault_file is not None:
            cmd.extend(["--vault-password-file", vault_file])

        cmd.append(playbook_path)

        if Config().debug > 0:
            cmd.append(ansible_verbosity[Config().debug])

        self.logger.info('Running: "' + ' '.join(playbook_path) + '"')

        logpipe = LogPipe(__name__)
        with subprocess.Popen(cmd, stdout=logpipe, stderr=logpipe) as sp:
            logpipe.close()

        if sp.returncode != 0:
            raise Exception('Error running: "' + ' '.join(cmd) + '"')
        else:
            self.logger.info('Done running "' + ' '.join(cmd) + '"')

    def run_playbook_with_retries(self,
                                  inventory,
                                  playbook_path,
                                  retries,
                                  timeout=10):
        for i in range(retries):
            try:
                self.run_playbook(inventory=inventory,
                                  playbook_path=playbook_path)
                break
            except Exception as e:
                self.logger.error(e)
                self.logger.warning('Retry running playbook: ' + str(i + 1) +
                                    '/' + str(retries))
                time.sleep(timeout)
        else:
            raise Exception(
                f'Failed running playbook after {str(retries)} retries')