Esempio n. 1
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule idempotence` and
        return a tuple.

        :param exit: An optional flag to toggle the exiting of the module
         on command failure.
        :return: Return a tuple of (`exit status`, `command output`), otherwise
         sys.exit on command failure.
        """
        msg = 'Idempotence test in progress (can take a few minutes)...'
        util.print_info(msg)

        c = converge.Converge(self.args, self.command_args, self.molecule)
        status, output = c.execute(idempotent=True,
                                   exit=False,
                                   hide_errors=True)
        if status is not None:
            msg = 'Skipping due to errors during converge.'
            util.print_info(msg)
            util.print_info(output)
            return status, None

        idempotent = self._is_idempotent(output)
        if idempotent:
            util.print_success('Idempotence test passed.')
            return None, None
        else:
            msg = 'Idempotence test failed because of the following tasks:'
            util.print_error(msg)
            util.print_error('\n'.join(self._non_idempotent_tasks(output)))
            if exit:
                util.sysexit()

            return 1, None
Esempio n. 2
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule verify` and
        return a tuple.

        :param exit: An optional flag to toggle the exiting of the module
         on command failure.
        :return: Return a tuple of None, otherwise sys.exit on command failure.
        """
        try:
            v = ansible_lint.AnsibleLint(self.molecule)
            v.execute()
        except sh.ErrorReturnCode:
            util.sysexit()
        v = trailing.Trailing(self.molecule)
        v.execute()

        self.molecule.write_ssh_config()

        try:
            if self.molecule.verifier == 'serverspec':
                v = serverspec.Serverspec(self.molecule)
            elif self.molecule.verifier == 'goss':
                v = goss.Goss(self.molecule)
            else:
                v = testinfra.Testinfra(self.molecule)

            v.execute()
        except sh.ErrorReturnCode as e:
            util.print_error(str(e))
            if exit:
                util.sysexit(e.exit_code)
            return e.exit_code, e.stdout

        return None, None
Esempio n. 3
0
    def _rake(self,
              rakefile,
              debug=False,
              out=util.callback_info,
              err=util.callback_error):
        """
        Executes rake against specified rakefile and returns a :func:`sh`
        response object.

        :param rakefile: A string containing path to the rakefile.
        :param debug: An optional bool to toggle debug output.
        :param out: An optional function to process STDOUT for underlying
         :func:`sh` call.
        :param err: An optional function to process STDERR for underlying
         :func:`sh` call.
        :return: :func:`sh` response object.
        """
        kwargs = {
            '_out': out,
            '_err': err,
            'trace': debug,
            'rakefile': rakefile
        }

        msg = 'Executing serverspec tests found in {}/...'.format(
            self._serverspec_dir)
        util.print_info(msg)

        try:
            cmd = sh.rake.bake(**kwargs)
        except sh.CommandNotFound:
            msg = 'Verifier missing, gem install rake.'
            util.print_error(msg)
            util.sysexit()
        return util.run_command(cmd, debug=self._debug)
Esempio n. 4
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule init` and exit.

        :param exit: (Unused) Provided to complete method signature.
        :return: None
        """
        role = self.command_args.get('role')
        role_path = os.getcwd()
        driver = self._get_driver()
        verifier = self._get_verifier()
        if not role:
            role = os.getcwd().split(os.sep)[-1]
            role_path = os.path.abspath(os.path.join(os.getcwd(), os.pardir))
            self._init_existing_role(role, role_path, driver, verifier)
        else:
            if os.path.isdir(role):
                msg = ('The directory {} exists. '
                       'Cannot create new role.').format(role)
                util.print_error(msg)
                util.sysexit()
            self._init_new_role(role, role_path, driver, verifier)

        path = os.path.join(role_path, role)
        msg = 'Successfully initialized new role in {}.'.format(path)
        util.print_success(msg)
        util.sysexit(0)
Esempio n. 5
0
    def _rubocop(self,
                 serverspec_dir,
                 debug=False,
                 pattern='/**/*.rb',
                 out=util.callback_info,
                 err=util.callback_error):
        """
        Executes rubocop against specified directory/pattern and returns a
        :func:`sh` response object.

        :param serverspec_dir: A string containing the directory with files
        to lint.
        :param debug: An optional bool to toggle debug output.
        :param pattern: A string containing the pattern of files to lint.
        :param out: An optional function to process STDOUT for underlying
         :func:`sh` call.
        :param err: An optional function to process STDERR for underlying
         :func:`sh` call.
        :return: :func:`sh` response object.
        """
        kwargs = {'_out': out, '_err': err, 'debug': debug}

        msg = 'Executing rubocop on *.rb files found in {}/...'.format(
            serverspec_dir)
        util.print_info(msg)
        match = serverspec_dir + pattern

        try:
            cmd = sh.rubocop.bake(match, **kwargs)
        except sh.CommandNotFound:
            msg = 'Verifier missing, gem install rubocop.'
            util.print_error(msg)
            util.sysexit()
        return util.run_command(cmd, debug=self._debug)
Esempio n. 6
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule create` and
        return a tuple.

        :param exit: An optional flag to toggle the exiting of the module
         on command failure.
        :return: Return a tuple of None, otherwise sys.exit on command failure.
        """
        self.molecule.remove_inventory_file()
        self.molecule.create_templates()
        try:
            util.print_info('Creating instances...')
            self.molecule.driver.up(no_provision=True)
            self.molecule.state.change_state('created', True)
            if self.command_args.get('platform') == 'all':
                self.molecule.state.change_state('multiple_platforms', True)
        except subprocess.CalledProcessError as e:
            util.print_error(str(e))
            if exit:
                util.sysexit(e.returncode)
            return e.returncode, e.message
        self.molecule.create_inventory_file()
        self.molecule.write_instances_state()
        return None, None
Esempio n. 7
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule init` and exit.

        :param exit: (Unused) Provided to complete method signature.
        :return: None
        """
        role = self.command_args.get('role')
        role_path = os.getcwd()
        driver = self._get_driver()
        verifier = self._get_verifier()
        if not role:
            role = os.getcwd().split(os.sep)[-1]
            role_path = os.path.abspath(os.path.join(os.getcwd(), os.pardir))
            self._init_existing_role(role, role_path, driver, verifier)
        else:
            if os.path.isdir(role):
                msg = ('The directory {} exists. '
                       'Cannot create new role.').format(role)
                util.print_error(msg)
                util.sysexit()
            self._init_new_role(role, role_path, driver, verifier)

        path = os.path.join(role_path, role)
        msg = 'Successfully initialized new role in {}.'.format(path)
        util.print_success(msg)
        util.sysexit(0)
Esempio n. 8
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule idempotence` and
        return a tuple.

        :param exit: An optional flag to toggle the exiting of the module
         on command failure.
        :return: Return a tuple of (`exit status`, `command output`), otherwise
         sys.exit on command failure.
        """
        msg = 'Idempotence test in progress (can take a few minutes)...'
        util.print_info(msg)

        c = converge.Converge(self.args, self.command_args, self.molecule)
        status, output = c.execute(
            idempotent=True, exit=False, hide_errors=True)
        if status is not None:
            msg = 'Skipping due to errors during converge.'
            util.print_info(msg)
            return status, None

        idempotent = self._is_idempotent(output)
        if idempotent:
            util.print_success('Idempotence test passed.')
            return None, None
        else:
            msg = 'Idempotence test failed because of the following tasks:'
            util.print_error(msg)
            util.print_error('\n'.join(self._non_idempotent_tasks(output)))
            if exit:
                util.sysexit()

            return 1, None
Esempio n. 9
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule check` and
        return a tuple.

        :param exit: (Unused) Provided to complete method signature.
        :return: Return a tuple provided by :meth:`.AnsiblePlaybook.execute`.
        """
        if not self.molecule.state.created:
            msg = ('Instance(s) not created, `check` should be run '
                   'against created instance(s).')
            util.print_error(msg)
            util.sysexit()

        debug = self.args.get('debug')
        ansible = ansible_playbook.AnsiblePlaybook(
            self.molecule.config.config['ansible'],
            self.molecule.driver.ansible_connection_params,
            debug=debug)
        ansible.add_cli_arg('check', True)

        util.print_info("Performing a 'Dry Run' of playbook...")
        return ansible.execute(hide_errors=True)

        return (None, None)
Esempio n. 10
0
def test_print_error(capsys):
    util.print_error("test")
    result, _ = capsys.readouterr()

    print "{}ERROR: {}".format(colorama.Fore.RED, "test".rstrip())
    expected, _ = capsys.readouterr()

    assert expected == result
Esempio n. 11
0
def test_print_error(capsys):
    util.print_error('test')
    result, _ = capsys.readouterr()

    print '{}ERROR: {}'.format(colorama.Fore.RED, 'test'.rstrip())
    expected, _ = capsys.readouterr()

    assert expected == result
Esempio n. 12
0
def test_print_error_without_pretty(capsys):
    util.print_error('test', pretty=False)
    result, _ = capsys.readouterr()

    print '{}{}'.format(colorama.Fore.RED, 'test'.rstrip())
    expected, _ = capsys.readouterr()

    assert expected == result
Esempio n. 13
0
def test_print_error_without_pretty(capsys):
    util.print_error('test', pretty=False)
    result, _ = capsys.readouterr()

    print '{}{}'.format(colorama.Fore.RED, 'test'.rstrip())
    expected, _ = capsys.readouterr()

    assert expected == result
Esempio n. 14
0
def test_print_error(capsys):
    util.print_error('test')
    result, _ = capsys.readouterr()

    print '{}ERROR: {}'.format(colorama.Fore.RED, 'test'.rstrip())
    expected, _ = capsys.readouterr()

    assert expected == result
Esempio n. 15
0
    def up(self, no_provision=True):
        self.molecule.state.change_state('driver', self.name)
        kpn = self._get_keypair()

        active_instances = self._openstack.list_servers()
        active_instance_names = {
            instance['name']: instance['status']
            for instance in active_instances
        }

        util.print_warn('Creating openstack instances...')
        for instance in self.instances:

            try:
                # We divide the ssh_timeout by 2, because the connect
                # itself takes at least a second and is followed by
                # a 1 sec sleep
                ssh_timeout = int(
                    instance.get('ssh_timeout', self.ssh_timeout) / 2)
            except TypeError:
                util.print_error('Can not cast ssh_timeout setting "%s"'
                                 ' to int' %
                                 instance.get('ssh_timeout', self.ssh_timeout))
                util.sysexit()

            if instance['name'] not in active_instance_names:
                msg = '\tBringing up {}...'.format(instance['name'])
                util.print_info(msg)
                server = self._openstack.create_server(
                    name=instance['name'],
                    image=self._openstack.get_image(instance['image']),
                    flavor=self._openstack.get_flavor(instance['flavor']),
                    auto_ip=True,
                    wait=True,
                    key_name=kpn,
                    ip_pool=instance.get('ip_pool')
                    if instance.get('ip_pool') else self.ip_pool,
                    network=instance.get('networks', []),
                    security_groups=instance.get('security_groups', []))
                instance['created'] = True
                instance['reachable'] = False

                for _ in range(ssh_timeout):
                    util.print_info('\t Waiting for ssh availability...')
                    if self._check_ssh_availability(
                            server['interface_ip'],
                            instance['sshuser'],
                            timeout=1,
                            sshkey_filename=self._get_keyfile()):
                        instance['reachable'] = True
                        break
                if not instance['reachable']:
                    util.print_error(
                        'Could not reach instance "%s"'
                        ' within limit of %s seconds' %
                        (instance['name'],
                         instance.get('ssh_timeout', self.ssh_timeout)))
                    util.sysexit()
Esempio n. 16
0
 def _cleanup_temp_keypair(self):
     # if we don't have a keypair config, delete the temp one
     if ('keypair' not in self.molecule.config.config['openstack']):
         kpn = self._get_temp_keyname()
         if self._openstack.search_keypairs(kpn):
             msg = '\tRemoving openstack keypair {}...'.format(kpn)
             util.print_warn(msg)
             if not self._openstack.delete_keypair(kpn):
                 msg = 'Unable to remove openstack keypair {}.'.format(kpn)
                 util.print_error(msg)
             else:
                 msg = '\tRemoved openstack keypair {}.'.format(kpn)
                 util.print_success(msg)
Esempio n. 17
0
 def _cleanup_temp_keypair(self):
     # if we don't have a keypair config, delete the temp one
     if ('keypair' not in self.molecule.config.config['openstack']):
         kpn = self._get_temp_keyname()
         if self._openstack.search_keypairs(kpn):
             msg = '\tRemoving openstack keypair {}...'.format(kpn)
             util.print_warn(msg)
             if not self._openstack.delete_keypair(kpn):
                 msg = 'Unable to remove openstack keypair {}.'.format(kpn)
                 util.print_error(msg)
             else:
                 msg = '\tRemoved openstack keypair {}.'.format(kpn)
                 util.print_success(msg)
Esempio n. 18
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule status` and
        return a tuple.

        :param exit: (Unused) Provided to complete method signature.
        :return: Return a tuple of None.
        """
        display_all = not any([
            self.command_args.get('hosts'),
            self.command_args.get('platforms'),
            self.command_args.get('providers')
        ])

        # Retrieve the status.
        try:
            status = self.molecule.driver.status()
        # TODO(retr0h): Pretty sure this handling is wrong.  We don't always
        # shell out for status.
        except subprocess.CalledProcessError as e:
            util.print_error(e.message)
            return e.returncode, e.message

        # Display the results in procelain mode.
        porcelain = self.command_args.get('porcelain')

        # Display hosts information.
        if display_all or self.command_args.get('hosts'):
            # Prepare the table for the results.
            headers = [] if porcelain else ['Name', 'State', 'Provider']
            data = []

            for item in status:
                if item.state != 'not_created':  # pragma: no cover
                    state = item.state
                else:
                    state = item.state

                data.append([item.name, state, item.provider])

            self.molecule.display_tabulate_data(data, headers=headers)

        # Display the platforms.
        if display_all or self.command_args.get('platforms'):
            self.molecule.print_valid_platforms(porcelain=porcelain)

        # Display the providers.
        if display_all or self.command_args.get('providers'):
            self.molecule.print_valid_providers(porcelain=porcelain)

        return None, None
Esempio n. 19
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule status` and
        return a tuple.

        :param exit: (Unused) Provided to complete method signature.
        :return: Return a tuple of None.
        """
        display_all = not any([
            self.command_args.get('hosts'), self.command_args.get('platforms'),
            self.command_args.get('providers')
        ])

        # Retrieve the status.
        try:
            status = self.molecule.driver.status()
        # TODO(retr0h): Pretty sure this handling is wrong.  We don't always
        # shell out for status.
        except subprocess.CalledProcessError as e:
            util.print_error(e.message)
            return e.returncode, e.message

        # Display the results in procelain mode.
        porcelain = self.command_args.get('porcelain')

        # Display hosts information.
        if display_all or self.command_args.get('hosts'):
            # Prepare the table for the results.
            headers = [] if porcelain else ['Name', 'State', 'Provider']
            data = []

            for item in status:
                if item.state != 'not_created':  # pragma: no cover
                    state = item.state
                else:
                    state = item.state

                data.append([item.name, state, item.provider])

            self.molecule.display_tabulate_data(data, headers=headers)

        # Display the platforms.
        if display_all or self.command_args.get('platforms'):
            self.molecule.print_valid_platforms(porcelain=porcelain)

        # Display the providers.
        if display_all or self.command_args.get('providers'):
            self.molecule.print_valid_providers(porcelain=porcelain)

        return None, None
Esempio n. 20
0
    def main(self):
        """
        A mechanism to initialize molecule by calling its main method.  This
        can be redefined by classes which do not want this behavior
        (:class:`.Init`).

        :returns: None
        """
        if not self._config.molecule_file_exists():
            msg = ('Unable to find {}. '
                   'Exiting.').format(self._config.molecule_file)
            util.print_error(msg)
            util.sysexit()
        self.molecule.main()
Esempio n. 21
0
    def execute(self):
        """
        Executes shell command and returns the command's stdout.

        :return: The command's output, otherwise sys.exit on command failure.
        """

        if self._command is None:
            self.bake()

        try:
            return util.run_command(self._command, debug=self._debug).stdout
        except sh.ErrorReturnCode as e:
            util.print_error(str(e))
            util.sysexit(e.exit_code)
Esempio n. 22
0
    def execute(self):
        """
        Executes shell command and returns the command's stdout.

        :return: The command's output, otherwise sys.exit on command failure.
        """

        if self._command is None:
            self.bake()

        try:
            return util.run_command(self._command, debug=self._debug).stdout
        except sh.ErrorReturnCode as e:
            util.print_error(str(e))
            util.sysexit(e.exit_code)
Esempio n. 23
0
    def execute(self, hide_errors=False):
        """
        Executes ansible-playbook and returns command's stdout.

        :param hide_errors: An optional bool to toggle output of errors.
        :return: The command's output, otherwise sys.exit on command failure.
        """
        if self._ansible is None:
            self.bake()

        try:
            return None, util.run_command(
                self._ansible, debug=self._debug).stdout
        except sh.ErrorReturnCode as e:
            if not hide_errors:
                util.print_error(str(e))

            return e.exit_code, None
Esempio n. 24
0
    def execute(self, hide_errors=False):
        """
        Executes ansible-playbook and returns command's stdout.

        :param hide_errors: An optional bool to toggle output of errors.
        :return: The command's output, otherwise sys.exit on command failure.
        """
        if self._ansible is None:
            self.bake()

        try:
            return None, unicode(util.run_command(
                self._ansible, debug=self._debug))
        except sh.ErrorReturnCode as e:
            if not hide_errors:
                util.print_error(str(e))

            return e.exit_code, None
Esempio n. 25
0
    def main(self):
        """
        A mechanism to initialize molecule by calling its main method.  This
        can be redefined by classes which do not want this behavior
        (:class:`.Init`).

        :returns: None
        """
        if (not self._config.molecule_file_exists() and
                not self._config.molecule_local_config_file_exists()):
            msg = ('Unable to find {}. '
                   'Exiting.').format(self._config.molecule_file)
            util.print_error(msg)
            util.sysexit()
        elif (not self._config.molecule_file_exists() and
              self._config.molecule_local_config_file_exists()):
            util.print_warn('No molecule.yml found in project, '
                            'using config file at %s only' %
                            self._config.molecule_local_config_file)
        self.molecule.main()
Esempio n. 26
0
    def main(self):
        """
        A mechanism to initialize molecule by calling its main method.  This
        can be redefined by classes which do not want this behavior
        (:class:`.Init`).

        :returns: None
        """
        if (not self._config.molecule_file_exists()
                and not self._config.molecule_local_config_file_exists()):
            msg = ('Unable to find {}. '
                   'Exiting.').format(self._config.molecule_file)
            util.print_error(msg)
            util.sysexit()
        elif (not self._config.molecule_file_exists()
              and self._config.molecule_local_config_file_exists()):
            util.print_warn('No molecule.yml found in project, '
                            'using config file at %s only' %
                            self._config.molecule_local_config_file)
        self.molecule.main()
Esempio n. 27
0
    def main(self):
        if not os.path.exists(self.config.config['molecule']['molecule_dir']):
            os.makedirs(self.config.config['molecule']['molecule_dir'])

        self.state = state.State(
            state_file=self.config.config.get('molecule').get('state_file'))

        try:
            self.driver = self._get_driver()
        except basedriver.InvalidDriverSpecified:
            msg = "Invalid driver '{}'.".format(self._get_driver_name())
            util.print_error(msg)
            # TODO(retr0h): Print valid drivers.
            util.sysexit()
        except basedriver.InvalidProviderSpecified:
            msg = "Invalid provider '{}'.".format(self.args['provider'])
            util.print_error(msg)
            self.args['provider'] = None
            self.args['platform'] = None
            self.driver = self._get_driver()
            self.print_valid_providers()
            util.sysexit()
        except basedriver.InvalidPlatformSpecified:
            msg = "Invalid platform '{}'.".format(self.args['platform'])
            util.print_error(msg)
            self.args['provider'] = None
            self.args['platform'] = None
            self.driver = self._get_driver()
            self.print_valid_platforms()
            util.sysexit()

        self.config.populate_instance_names(self.driver.platform)
        self._add_or_update_vars('group_vars')
        self._add_or_update_vars('host_vars')
Esempio n. 28
0
    def main(self):
        if not os.path.exists(self.config.config['molecule']['molecule_dir']):
            os.makedirs(self.config.config['molecule']['molecule_dir'])

        self.state = state.State(
            state_file=self.config.config.get('molecule').get('state_file'))

        try:
            self.driver = self._get_driver()
        except basedriver.InvalidDriverSpecified:
            msg = "Invalid driver '{}'.".format(self._get_driver_name())
            util.print_error(msg)
            # TODO(retr0h): Print valid drivers.
            util.sysexit()
        except basedriver.InvalidProviderSpecified:
            msg = "Invalid provider '{}'.".format(self.args['provider'])
            util.print_error(msg)
            self.args['provider'] = None
            self.args['platform'] = None
            self.driver = self._get_driver()
            self.print_valid_providers()
            util.sysexit()
        except basedriver.InvalidPlatformSpecified:
            msg = "Invalid platform '{}'.".format(self.args['platform'])
            util.print_error(msg)
            self.args['provider'] = None
            self.args['platform'] = None
            self.driver = self._get_driver()
            self.print_valid_platforms()
            util.sysexit()

        self.config.populate_instance_names(self.driver.platform)
        self._add_or_update_vars('group_vars')
        self._add_or_update_vars('host_vars')
Esempio n. 29
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule test` and
        return a tuple.

        :param exit: (Unused) Provided to complete method signature.
        :return: Return a tuple of (`exit status`, `command output`), otherwise
         sys.exit on command failure.
        """
        if self.command_args.get('all') == True:
            ts = self.molecule.config.config['molecule']['test']['sequence']
        else:
            ts = ['destroy', 'create', 'converge']

        for task in ts:
            command_module = getattr(molecule.command, task)
            command = getattr(command_module, task.capitalize())

            # in case we want to re-work on an already existing vm
            if task == 'destroy' and self.command_args.get('from_scratch') == False:
                util.print_info('Keep instance up...')
                continue

            c = command(self.args, self.command_args, self.molecule)
            status, output = c.execute(exit=False)

            # Fail fast
            if status is not 0 and status is not None:
                if output:
                    util.print_error(output)
                util.sysexit(status)

        if self.command_args.get('clean') == True:
            c = molecule.command.destroy.Destroy(self.args, self.command_args)
            c.execute()
            return None, None

        # passing (default)
        if status is None:
            return None, None
Esempio n. 30
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule destroy` and
        return a tuple.

        Clears state file of all info (default platform).

        :param exit: An optional flag to toggle the exiting of the module
         on command failure.
        :return: Return a tuple of None, otherwise sys.exit on command failure.
        """
        try:
            util.print_info('Destroying instances...')
            self.molecule.driver.destroy()
            self.molecule.state.reset()
        except subprocess.CalledProcessError as e:
            util.print_error(str(e))
            if exit:
                util.sysexit(e.returncode)
            return e.returncode, e.message
        self.molecule.remove_templates()
        self.molecule.remove_inventory_file()
        return None, None
Esempio n. 31
0
    def destroy(self):
        util.print_info('Deleting openstack instances...')

        active_instances = self._openstack.list_servers()
        active_instance_names = {
            instance['name']: instance['id']
            for instance in active_instances
        }

        for instance in self.instances:
            util.print_warn('\tRemoving {}...'.format(instance['name']))
            if instance['name'] in active_instance_names:
                if not self._openstack.delete_server(
                        active_instance_names[instance['name']], wait=True):
                    msg = 'Unable to remove {}.'.format(instance['name'])
                    util.print_error(msg)
                else:
                    util.print_success('\tRemoved {}.'.format(instance[
                        'name']))
                    instance['created'] = False

        # cleanup any molecule generated ssh keysfiles
        self._cleanup_temp_keypair()
        self._cleanup_temp_keyfile()
Esempio n. 32
0
    def destroy(self):
        util.print_info('Deleting openstack instances...')

        active_instances = self._openstack.list_servers()
        active_instance_names = {
            instance['name']: instance['id']
            for instance in active_instances
        }

        for instance in self.instances:
            util.print_warn('\tRemoving {}...'.format(instance['name']))
            if instance['name'] in active_instance_names:
                if not self._openstack.delete_server(
                        active_instance_names[instance['name']], wait=True):
                    msg = 'Unable to remove {}.'.format(instance['name'])
                    util.print_error(msg)
                else:
                    util.print_success('\tRemoved {}.'.format(
                        instance['name']))
                    instance['created'] = False

        # cleanup any molecule generated ssh keysfiles
        self._cleanup_temp_keypair()
        self._cleanup_temp_keyfile()
Esempio n. 33
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule test` and
        return a tuple.

        :param exit: (Unused) Provided to complete method signature.
        :return: Return a tuple of (`exit status`, `command output`), otherwise
         sys.exit on command failure.
        """
        ts = self.molecule.config.config['molecule']['test']['sequence']
        for task in ts:
            command_module = getattr(molecule.command, task)
            command = getattr(command_module, task.capitalize())
            c = command(self.args, self.command_args, self.molecule)

            status, output = c.execute(exit=False)

            # Fail fast
            if status is not 0 and status is not None:
                if output:
                    util.print_error(output)
                util.sysexit(status)

        if self.command_args.get('destroy') == 'always':
            c = molecule.command.destroy.Destroy(self.args, self.command_args)
            c.execute()
            return None, None

        if self.command_args.get('destroy') == 'never':
            return None, None

        # passing (default)
        if status is None:
            c = molecule.command.destroy.Destroy(self.args, self.command_args)
            c.execute()
            return None, None
Esempio n. 34
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule test` and
        return a tuple.

        :param exit: (Unused) Provided to complete method signature.
        :return: Return a tuple of (`exit status`, `command output`), otherwise
         sys.exit on command failure.
        """
        ts = self.molecule.config.config["molecule"]["test"]["sequence"]
        for task in ts:
            command_module = getattr(molecule.command, task)
            command = getattr(command_module, task.capitalize())
            c = command(self.args, self.command_args, self.molecule)

            status, output = c.execute(exit=False)

            # Fail fast
            if status is not 0 and status is not None:
                if output:
                    util.print_error(output)
                util.sysexit(status)

        if self.command_args.get("destroy") == "always":
            c = molecule.command.destroy.Destroy(self.args, self.command_args)
            c.execute()
            return None, None

        if self.command_args.get("destroy") == "never":
            return None, None

        # passing (default)
        if status is None:
            c = molecule.command.destroy.Destroy(self.args, self.command_args)
            c.execute()
            return None, None
Esempio n. 35
0
    def _get_driver(self):
        """
        Return an instance of the driver as returned by `_get_driver_name()`.

        .. todo:: Implement a pluggable solution vs inline imports.
        """
        driver = self._get_driver_name()

        if (self.state.driver is not None) and (self.state.driver != driver):
            msg = ("Instance(s) were converged with the '{}' driver, "
                   "but the subcommand is using '{}' driver.")
            util.print_error(msg.format(self.state.driver, driver))
            util.sysexit()

        if driver == 'vagrant':
            from molecule.driver import vagrantdriver
            return vagrantdriver.VagrantDriver(self)
        elif driver == 'docker':
            from molecule.driver import dockerdriver
            return dockerdriver.DockerDriver(self)
        elif driver == 'openstack':
            from molecule.driver import openstackdriver
            return openstackdriver.OpenstackDriver(self)
        raise basedriver.InvalidDriverSpecified()
Esempio n. 36
0
    def _get_driver(self):
        """
        Return an instance of the driver as returned by `_get_driver_name()`.

        .. todo:: Implement a pluggable solution vs inline imports.
        """
        driver = self._get_driver_name()

        if (self.state.driver is not None) and (self.state.driver != driver):
            msg = ("Instance(s) were converged with the '{}' driver, "
                   "but the subcommand is using '{}' driver.")
            util.print_error(msg.format(self.state.driver, driver))
            util.sysexit()

        if driver == 'vagrant':
            from molecule.driver import vagrantdriver
            return vagrantdriver.VagrantDriver(self)
        elif driver == 'docker':
            from molecule.driver import dockerdriver
            return dockerdriver.DockerDriver(self)
        elif driver == 'openstack':
            from molecule.driver import openstackdriver
            return openstackdriver.OpenstackDriver(self)
        raise basedriver.InvalidDriverSpecified()
Esempio n. 37
0
    def execute(self, exit=True):  # pragma: no cover
        """
        Executes trailing linters and returns None, otherwise sys.exit on
        command failure.

        :return: None
        :param ignore_paths: List of paths to ignore during checks.
        :return: None, otherwise sys.exit on command failure.
        """
        filenames = []
        pruned_filenames = []
        found_error = False
        valid_extensions = ['py', 'yml', 'rb']
        for root, dirs, files in os.walk('.'):
            # gets ./subdirectory/filename
            filenames.extend([
                os.path.join(root, name) for name in files
                if name.split(os.extsep)[-1] in valid_extensions
            ])
            # gets ./filename
            filenames.extend([
                os.path.join(root, name) for name in dirs
                if name.split(os.extsep)[-1] in valid_extensions
            ])

        # only work on files not in our ignore paths
        for f in filenames:
            f_parts = f.split(os.sep)

            try:
                if f_parts[1] in self._ignore_paths:
                    continue
            except IndexError:
                continue

            # don't add directories
            if os.path.isfile(f):
                pruned_filenames.append(f)

        for filename in pruned_filenames:
            # don't process blank files
            if os.path.getsize(filename) < 1:
                continue

            data = [line for line in open(filename, 'r')]
            newline = self._trailing_newline(data)
            whitespace = self._trailing_whitespace(data)

            if newline:
                msg = 'Trailing newline found at the end of {}.'.format(
                    filename)
                util.print_error(msg)
                found_error = True

            if len(whitespace) > 0:
                msg = 'Trailing whitespace found in {} on lines: {}'
                lines = ', '.join(str(x) for x in whitespace)
                util.print_error(msg.format(filename, lines))
                found_error = True

        if exit and found_error:
            util.sysexit()
Esempio n. 38
0
    def up(self, no_provision=True):
        self.molecule.state.change_state('driver', self.name)
        kpn = self._get_keypair()

        active_instances = self._openstack.list_servers()
        active_instance_names = {
            instance['name']: instance['interface_ip']
            for instance in active_instances
        }

        util.print_warn('Creating openstack instances...')
        for instance in self.instances:

            try:
                # We divide the ssh_timeout by 2, because the connect
                # itself takes at least a second and is followed by
                # a 1 sec sleep
                ssh_timeout = int(
                    instance.get('ssh_timeout', self.ssh_timeout) / 2)
            except TypeError:
                util.print_error('Can not cast ssh_timeout setting "%s"'
                                 ' to int' %
                                 instance.get('ssh_timeout', self.ssh_timeout))
                util.sysexit()

            if instance['name'] not in active_instance_names:
                msg = '\tBringing up {}...'.format(instance['name'])
                util.print_info(msg)
                server = self._openstack.create_server(
                    name=instance['name'],
                    image=self._openstack.get_image(instance['image']),
                    flavor=self._openstack.get_flavor(instance['flavor']),
                    auto_ip=True,
                    wait=False,
                    key_name=kpn,
                    ip_pool=instance.get('ip_pool')
                    if instance.get('ip_pool') else self.ip_pool,
                    network=instance.get('networks', []),
                    security_groups=instance.get('security_groups', []))
                instance['created'] = True
                instance['reachable'] = False
                instance['server'] = server
            else:
                instance['address'] = active_instance_names[instance['name']]
                instance['reachable'] = True

        for instance in self.instances:
            if not instance.get('server'):
                instance['server'] = self._openstack.get_server(instance[
                    'name'])
            if not instance.get('address'):
                util.print_info(
                    '\t Waiting for instance %s to be in state active...' %
                    instance['name'])
                server = self._openstack.wait_for_server(
                    instance['server'], auto_ip=True)
                instance['address'] = server['interface_ip']

        for instance in self.instances:
            for _ in range(ssh_timeout):
                util.print_info(
                    '\t  Waiting for ssh availability of instance %s...' %
                    instance['name'])
                if self._check_ssh_availability(
                        instance['address'],
                        instance['sshuser'],
                        timeout=1,
                        sshkey_filename=self._get_keyfile()):
                    instance['reachable'] = True
                    break
            if not instance['reachable']:
                util.print_error(
                    'Could not reach instance "%s"'
                    ' within limit of %s seconds' %
                    (instance['name'],
                     instance.get('ssh_timeout', self.ssh_timeout)))
                util.sysexit()
Esempio n. 39
0
    def execute(self, exit=True):
        """
        Execute the actions necessary to perform a `molecule login` and
        return a tuple.

        :param exit: (Unused) Provided to complete method signature.
        :return: Return a tuple of None, otherwise sys.exit on command failure.
        """
        # get list of running hosts from state
        if self.molecule.state.hosts:
            hosts = [k for k, v in self.molecule.state.hosts.iteritems()]
        else:
            hosts = []

        try:
            # Nowhere to login to if there is no running host.
            if len(hosts) == 0:
                raise base.InvalidHost('There are no running hosts.')

            # Check whether a host was specified.
            if self.command_args.get('host') is None:
                # One running host is perfect. Login to it.
                if len(hosts) == 1:
                    hostname = hosts[0]

                # But too many hosts is trouble as well.
                else:
                    message = ('There are {} running hosts. Please specify '
                               'which with --host.\n\n'
                               'Available hosts:\n{}'.format(
                                   len(hosts), '\n'.join(sorted(hosts))))
                    raise base.InvalidHost(message)

            else:
                # If the host was specified, try to use it.
                hostname = self.command_args.get('host')
                match = [x for x in hosts if x.startswith(hostname)]
                if len(match) == 0:
                    raise subprocess.CalledProcessError(1, None)
                elif len(match) != 1:
                    # If there are multiple matches, but one of them is an
                    # exact string match, assume this is the one they're
                    # looking for and use it
                    if hostname in match:
                        match = [
                            hostname,
                        ]
                    else:
                        message = ("There are {} hosts that match '{}'. You "
                                   'can only login to one at a time.\n\n'
                                   'Available hosts:\n{}'.format(
                                       len(match), hostname,
                                       '\n'.join(sorted(hosts))))
                        raise base.InvalidHost(message)
                hostname = match[0]

        except subprocess.CalledProcessError:
            msg = ("Unknown host '{}'.\n\n"
                   'Available hosts:\n{}').format(
                       self.command_args.get('host'), '\n'.join(hosts))
            util.print_error(msg)
            util.sysexit()
        except base.InvalidHost as e:
            util.print_error(e.message)
            util.sysexit()

        self._get_login(hostname)
        return None, None
Esempio n. 40
0
    def _build_ansible_compatible_image(self):
        available_images = [
            tag.encode('utf-8') for image in self._docker.images()
            for tag in image.get('RepoTags', [])
        ]

        for container in self.instances:
            if container.get('build_image'):
                msg = ('Creating Ansible compatible '
                       'image of {}:{} ...').format(container['image'],
                                                    container['image_version'])
                util.print_info(msg)

            if 'registry' in container:
                container['registry'] += '/'
            else:
                container['registry'] = ''

            dockerfile = '''
            FROM {container_image}:{container_version}
            {container_environment}
            RUN bash -c 'if [ -x "$(command -v apt-get)" ]; then apt-get update && apt-get install -y python sudo; fi'
            RUN bash -c 'if [ -x "$(command -v yum)" ]; then yum makecache fast && yum update -y && yum install -y python sudo which yum-plugin-ovl && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf; fi'
            RUN bash -c 'if [ -x "$(command -v zypper)" ]; then zypper refresh && zypper update -y && zypper install -y python sudo; fi'

            '''  # noqa

            if 'dockerfile' in container:
                dockerfile = container['dockerfile']
                f = io.open(dockerfile)

            else:
                environment = container.get('environment')
                if environment:
                    environment = '\n'.join(
                        'ENV {} {}'.format(k, v)
                        for k, v in environment.iteritems())
                else:
                    environment = ''

                dockerfile = dockerfile.format(
                    container_image=container['registry'] + container['image'],
                    container_version=container['image_version'],
                    container_environment=environment)

                f = io.BytesIO(dockerfile.encode('utf-8'))

                container['image'] = container['registry'].replace(
                    '/', '_').replace(':', '_') + container['image']

            tag_string = self.image_tag.format(container['image'],
                                               container['image_version'])

            errors = False

            if tag_string not in available_images or 'dockerfile' in container:
                util.print_info('Building ansible compatible image...')
                previous_line = ''
                for line in self._docker.build(fileobj=f, tag=tag_string):
                    for line_split in line.split('\n'):
                        if len(line_split) > 0:
                            line = json.loads(line_split)
                            if 'stream' in line:
                                msg = '\t{}'.format(line['stream'])
                                util.print_warn(msg)
                            if 'errorDetail' in line:
                                ed = line['errorDetail']['message']
                                msg = '\t{}'.format(ed)
                                util.print_warn(msg)
                                errors = True
                            if 'status' in line:
                                if previous_line not in line['status']:
                                    msg = '\t{} ...'.format(line['status'])
                                    util.print_warn(msg)
                                previous_line = line['status']

                if errors:
                    msg = 'Build failed for {}.'.format(tag_string)
                    util.print_error(msg)
                    return
                else:
                    util.print_success(
                        'Finished building {}.'.format(tag_string))
Esempio n. 41
0
    def _build_ansible_compatible_image(self, container):
        available_images = [
            tag.encode('utf-8') for image in self._docker.images()
            if image.get('RepoTags') is not None
            for tag in image.get('RepoTags')
        ]

        msg = ('Creating Ansible compatible '
               'image of {}:{} ...').format(container['image'],
                                            container['image_version'])
        util.print_info(msg)

        if 'registry' in container:
            container['registry'] += '/'
        else:
            container['registry'] = ''

        dockerfile = '''
        FROM {container_image}:{container_version}
        {container_environment}
        RUN /bin/sh -c 'if [ -x "$(command -v apt-get)" ]; then apt-get update && apt-get install -y python sudo bash; fi'
        RUN /bin/sh -c 'if [ -x "$(command -v yum)" ]; then touch /var/lib/rpm/* && yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl bash && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf; fi'
        RUN /bin/sh -c 'if [ -x "$(command -v zypper)" ]; then zypper refresh && zypper update -y && zypper install -y python sudo bash; fi'
        RUN /bin/sh -c 'if [ -x "$(command -v apk)" ]; then apk update && apk add python sudo bash; fi'
        RUN /bin/sh -c 'if [ -x "$(command -v pacman)" ]; then pacman --sync --noconfirm --refresh python2 bash; fi'
        RUN /bin/sh -c 'if [ -x "$(command -v dnf)" ]; then dnf makecache fast; dnf --assumeyes install python python-devel python2-dnf bash; fi'
        RUN /bin/sh -c 'if [ -x "$(command -v emerge)" ]; then emerge --ask n =dev-lang/python-2\* gentoolkit; fi'
        '''  # noqa

        if 'dockerfile' in container:
            dockerfile = container['dockerfile']
            f = io.open(dockerfile)

        else:
            environment = container.get('environment')
            if environment:
                environment = '\n'.join('ENV {} {}'.format(k, v)
                                        for k, v in environment.iteritems())
            else:
                environment = ''

            dockerfile = dockerfile.format(
                container_image=container['registry'] + container['image'],
                container_version=container['image_version'],
                container_environment=environment)

            f = io.BytesIO(dockerfile.encode('utf-8'))

            container['image'] = container['registry'].replace(
                '/', '_').replace(':', '_') + container['image']

        tag_string = container['image_tag'].format(container['image'],
                                                   container['image_version'])

        errors = False

        if tag_string not in available_images or 'dockerfile' in container:
            util.print_info('Building ansible compatible image...')
            previous_line = ''
            for line in self._docker.build(fileobj=f, tag=tag_string):
                for line_split in line.split('\n'):
                    if len(line_split) > 0:
                        line = json.loads(line_split)
                        if 'stream' in line:
                            msg = '\t{}'.format(line['stream'])
                            util.print_warn(msg)
                        if 'errorDetail' in line:
                            ed = line['errorDetail']['message']
                            msg = '\t{}'.format(ed)
                            util.print_warn(msg)
                            errors = True
                        if 'status' in line:
                            if previous_line not in line['status']:
                                msg = '\t{} ...'.format(line['status'])
                                util.print_warn(msg)
                            previous_line = line['status']

            if errors:
                msg = 'Build failed for {}.'.format(tag_string)
                util.print_error(msg)
                return
            else:
                util.print_success('Finished building {}.'.format(tag_string))
Esempio n. 42
0
    def _build_ansible_compatible_image(self):
        available_images = [
            tag.encode('utf-8')
            for image in self._docker.images()
            for tag in image.get('RepoTags', [])
        ]

        for container in self.instances:
            if container.get('build_image'):
                msg = ('Creating Ansible compatible '
                       'image of {}:{} ...').format(container['image'],
                                                    container['image_version'])
                util.print_info(msg)

            if 'registry' in container:
                container['registry'] += '/'
            else:
                container['registry'] = ''

            dockerfile = '''
            FROM {container_image}:{container_version}
            {container_environment}
            RUN bash -c 'if [ -x "$(command -v apt-get)" ]; then apt-get update && apt-get install -y python sudo; fi'
            RUN bash -c 'if [ -x "$(command -v yum)" ]; then yum makecache fast && yum update -y && yum install -y python sudo yum-plugin-ovl && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf; fi'
            RUN bash -c 'if [ -x "$(command -v zypper)" ]; then zypper refresh && zypper update -y && zypper install -y python sudo; fi'

            '''  # noqa

            if 'dockerfile' in container:
                dockerfile = container['dockerfile']
                f = io.open(dockerfile)

            else:
                environment = container.get('environment')
                if environment:
                    environment = '\n'.join(
                        'ENV {} {}'.format(k, v)
                        for k, v in environment.iteritems())
                else:
                    environment = ''

                dockerfile = dockerfile.format(
                    container_image=container['registry'] + container['image'],
                    container_version=container['image_version'],
                    container_environment=environment)

                f = io.BytesIO(dockerfile.encode('utf-8'))

                container['image'] = container['registry'].replace(
                    '/', '_').replace(':', '_') + container['image']

            tag_string = self.image_tag.format(container['image'],
                                               container['image_version'])

            errors = False

            if tag_string not in available_images or 'dockerfile' in container:
                util.print_info('Building ansible compatible image...')
                previous_line = ''
                for line in self._docker.build(fileobj=f, tag=tag_string):
                    for line_split in line.split('\n'):
                        if len(line_split) > 0:
                            line = json.loads(line_split)
                            if 'stream' in line:
                                msg = '\t{}'.format(line['stream'])
                                util.print_warn(msg)
                            if 'errorDetail' in line:
                                ed = line['errorDetail']['message']
                                msg = '\t{}'.format(ed)
                                util.print_warn(msg)
                                errors = True
                            if 'status' in line:
                                if previous_line not in line['status']:
                                    msg = '\t{} ...'.format(line['status'])
                                    util.print_warn(msg)
                                previous_line = line['status']

                if errors:
                    msg = 'Build failed for {}.'.format(tag_string)
                    util.print_error(msg)
                    return
                else:
                    util.print_success('Finished building {}.'.format(
                        tag_string))