Exemplo n.º 1
0
    def do_validation(self, provision_data, old_schema=False):
        """
        This function takes provision_data, and attempts to validate the
        topologies for that data

        :param provision_data: PinFile data as a dictionary, with
        target information
        """

        results = {}

        return_code = 0

        for target in provision_data.keys():
            if not isinstance(provision_data[target], dict):
                raise LinchpinError("Target '{0}' does not"
                                    " exist.".format(target))

        targets = [x.lower() for x in provision_data.keys()]
        if 'linchpin' in targets:
            raise LinchpinError("Target 'linchpin' is not allowed.")

        for target in provision_data.keys():
            self.ctx.log_debug("Processing target: {0}".format(target))

            results[target] = {}
            self.set_evar('target', target)

            validator = Validator(self.ctx, self.pb_path, self.pb_ext)
            target_dict = provision_data[target]
            ret, results[target] = validator.validate_pretty(
                target_dict, target, old_schema)
            return_code += ret

        return return_code, results
Exemplo n.º 2
0
def setup_validator():
    """
    Perform setup of Validator,
    """

    global validator
    global pinfile

    lpc = LinchpinContext()
    lpc.load_config()
    lpc.load_global_evars()
    lpa = LinchpinAPI(lpc)
    validator = Validator(lpa.ctx, lpa.role_path, lpa.pb_ext)

    schema_file = 'schema.json'
    base_path = '{0}'.format(os.path.dirname(os.path.realpath(__file__)))\
        .rstrip('/')
    lib_path = os.path.realpath(os.path.join(base_path, os.pardir))
    sp = '{0}/{1}/{2}'.format(lib_path, '../provision/roles/dummy/files',
                              schema_file)
    schema = json.load(open(sp))

    pf_name = 'PinFile-complete.yml'
    pf_file = '{0}/{1}/{2}'.format(lib_path, 'mockdata/dummy', pf_name)
    pinfile = yaml.load(open(pf_file), Loader=yaml.FullLoader)
Exemplo n.º 3
0
    def do_validation(self, provision_data, old_schema=False):
        """
        This function takes provision_data, and attempts to validate the
        topologies for that data

        :param provision_data: PinFile data as a dictionary, with
        target information
        """

        results = {}


        return_code = 0

        for target in provision_data.keys():
            if not isinstance(provision_data[target], dict):
                raise LinchpinError("Target '{0}' does not"
                                    " exist.".format(target))

        targets = [x.lower() for x in provision_data.keys()]
        if 'linchpin' in targets:
            raise LinchpinError("Target 'linchpin' is not allowed.")

        for target in provision_data.keys():
            if target == 'cfgs':
                continue

            self.ctx.log_debug("Processing target: {0}".format(target))

            results[target] = {}
            self.set_evar('target', target)

            validator = Validator(self.ctx, self.pb_path, self.pb_ext)
            target_dict = provision_data[target]
            ret, results[target] = validator.validate_pretty(target_dict,
                                                             target,
                                                             old_schema)
            return_code += ret

        return return_code, results
Exemplo n.º 4
0
    def do_action(self, provision_data, action='up', run_id=None, tx_id=None):
        """
        This function takes provision_data, and executes the given
        action for each target within the provision_data disctionary.

        :param provision_data: PinFile data as a dictionary, with
        target information

        :param action: Action taken (up, destroy, etc). (Default: up)

        :param run_id: Provided run_id to duplicate/destroy (Default: None)

        :param tx_id: Provided tx_id to duplicate/destroy (Default: None)

        .. .note:: The `run_id` value differs from the `rundb_id`, in that
                   the `run_id` is an existing value in the database.
                   The `rundb_id` value is created to store the new record.
                   If the `run_id` is passed, it is used to collect an existing
                   `uhash` value from the given `run_id`, which is in turn used
                   to perform an idempotent reprovision, or destroy provisioned
                   resources.
        """
        ansible_console = False
        if self.ctx.cfgs.get('ansible'):
            ansible_console = (
                ast.literal_eval(self.get_cfg('ansible',
                                              'console',
                                              default='False')))

        if not ansible_console:
            ansible_console = bool(self.ctx.verbosity)

        results = {}


        return_code = 99
        vault_pass = self.get_evar('vault_pass')
        if vault_pass == '':
            self.set_evar('vault_pass',
                          self.ctx.get_cfg('evars',
                                           'vault_pass',
                                           default=''))

        targets = [x.lower() for x in list(provision_data.keys())]
        disable_uhash_targets = self.ctx.get_evar('disable_uhash_targets')
        enable_uhash = self.ctx.get_evar('enable_uhash')

        for target in targets:
            if not isinstance(provision_data[target], dict):
                raise LinchpinError("Target '{0}' does not"
                                    " exist.".format(target))

        if 'linchpin' in targets:
            raise LinchpinError("Target 'linchpin' is not allowed.")

        for target in targets:
            if target == 'cfgs':
                continue

            self.ctx.log_debug("Processing target: {0}".format(target))

            results[target] = {}
            self.set_evar('target', target)

            rundb = self.setup_rundb()

            if tx_id:
                record = rundb.get_tx_record(tx_id)
                run_id = (list(record['targets'][0][target].keys())[0])

            rundb_schema = json.loads(self.get_cfg(section='lp',
                                      key='rundb_schema'))
            rundb.schema = rundb_schema
            self.set_evar('rundb_schema', rundb_schema)

            start = time.time()
            st_uhash = int(start * 1000)
            uhash = None

            # generate a new rundb_id
            # (don't confuse it with an already existing run_id)
            rundb_id = rundb.init_table(target)
            orig_run_id = rundb_id

            uhash_length = self.get_cfg('lp', 'rundb_uhash_length')
            uhash_len = int(uhash_length)
            if not run_id:
                hash_str = ':'.join([target, str(tx_id), str(rundb_id),
                                     str(st_uhash)])
                if isinstance(hash_str, text_type):
                    hash_str = hash_str.encode('utf-8')
                uh = hashlib.new(self.rundb_hash, hash_str)
                uhash = uh.hexdigest()[:uhash_len]

            if action == 'destroy' or run_id:
                # look for the action='up' records to destroy
                data, orig_run_id = rundb.get_record(target,
                                                     action='up',
                                                     run_id=run_id)

                if data:
                    uhash = data.get('uhash')
                    self.ctx.log_debug("using data from"
                                       " run_id: {0}".format(run_id))

            elif action not in ['up', 'destroy']:
                # it doesn't appear this code will will execute,
                # but if it does...
                raise LinchpinError("Attempting '{0}' action on"
                                    " target: '{1}' failed. Not an"
                                    " action.".format(action, target))


            self.ctx.log_debug('rundb_id: {0}'.format(rundb_id))
            self.ctx.log_debug('uhash: {0}'.format(uhash))

            rundb.update_record(target, rundb_id, 'uhash', uhash)
            rundb.update_record(target, rundb_id, 'start', str(start))
            rundb.update_record(target, rundb_id, 'action', action)

            self.set_evar('orig_run_id', orig_run_id)
            self.set_evar('rundb_id', rundb_id)
            self.set_evar('uhash', uhash)

            try:
                validator = Validator(self.ctx, self.pb_path, self.pb_ext)
                resources = validator.validate(provision_data[target])
            except SchemaError:
                raise ValidationError("Target '{0}' does not validate.  For"
                                      " more information run `linchpin "
                                      "validate`".format(target))

            topology_data = provision_data[target].get('topology')
            self.set_evar('topo_data', topology_data)

            rundb.update_record(target,
                                rundb_id,
                                'inputs',
                                [
                                    {'topology_data':
                                     provision_data[target]['topology']}
                                ])

            if provision_data[target].get('layout', None):
                l_data = provision_data[target]['layout']
                provision_data[target]['layout'] = self._convert_layout(l_data)
                self.set_evar('layout_data', provision_data[target]['layout'])

                rundb.update_record(target,
                                    rundb_id,
                                    'inputs',
                                    [
                                        {'layout_data':
                                         provision_data[target]['layout']}
                                    ])

            if provision_data[target].get('hooks', None):
                hooks_data = provision_data[target].get('hooks')
                self.set_evar('hooks_data', hooks_data)
                rundb.update_record(target,
                                    rundb_id,
                                    'inputs',
                                    [
                                        {'hooks_data':
                                         provision_data[target]['hooks']}
                                    ])

            if provision_data.get('cfgs', None):
                vars_data = provision_data[target].get('cfgs')
                self.set_evar('cfgs_data', vars_data)
                rundb.update_record(target,
                                    rundb_id,
                                    'cfgs',
                                    [
                                        {'user':
                                         provision_data['cfgs']}
                                    ])

            # note : changing the state triggers the hooks
            self.hooks.rundb = (rundb, rundb_id)
            self.pb_hooks = self.get_cfg('hookstates', action)
            self.ctx.log_debug('calling: {0}{1}'.format('pre', action))

            if (('pre' in self.pb_hooks) and not self.get_cfg('hook_flags',
                                                              'no_hooks')):
                self.hook_state = '{0}{1}'.format('pre', action)

            # FIXME need to add rundb data for hooks results

            # Enable/disable uhash based on provided flag(s)
            if disable_uhash_targets and target in disable_uhash_targets:
                self.ctx.set_evar('use_uhash', False)
            else:
                self.ctx.set_evar('use_uhash', enable_uhash)

            # invoke the appropriate action
            return_code, results[target]['task_results'] = (
                self._invoke_playbooks(resources, action=action,
                                       console=ansible_console)
            )

            # logs the return_code back to console and quits
            # quits if return_code > 0
            self.ctx.log("Playbook Return code {0}".format(str(return_code)))
            if return_code > 0 and action == "up":
                sys.exit(return_code)

            if not return_code:
                self.ctx.log_state("Action '{0}' on Target '{1}' is "
                                   "complete".format(action, target))

            # FIXME Check the result[target] value here, and fail if applicable.
            # It's possible that a flag might allow more targets to run, then
            # return an error code at the end.

            # add post provision hook for inventory generation
            if (('inv' in self.pb_hooks) and not self.get_cfg('hook_flags',
                                                              'no_hooks')):
                self.hook_state = 'postinv'

            if (('post' in self.pb_hooks) and
                    (self.__meta__ == "API") and
                    not self.get_cfg('hook_flags', 'no_hooks')):
                self.hook_state = '{0}{1}'.format('post', action)

            end = time.time()

            rundb.update_record(target, rundb_id, 'end', str(end))
            rundb.update_record(target, rundb_id, 'rc', return_code)

            run_data = rundb.get_record(target,
                                        action=action,
                                        run_id=rundb_id)

            results[target]['rundb_data'] = {rundb_id: run_data[0]}


        # generate the linchpin_id and structure
        lp_schema = ('{"action": "", "targets": []}')

        rundb = self.setup_rundb()
        rundb.schema = json.loads(lp_schema)
        lp_id = rundb.init_table('linchpin')

        summary = {}

        for target, data in results.items():
            for k, v in data['rundb_data'].items():
                summary[target] = {k: {'rc': v['rc'], 'uhash': v['uhash']}}

        rundb.update_record('linchpin', lp_id, 'action', action)
        rundb.update_record('linchpin', lp_id, 'targets', [summary])

        lp_data = {lp_id: {'action': action,
                           'summary_data': summary,
                           'results_data': results}}

        return (return_code, lp_data)
Exemplo n.º 5
0
    def do_action(self, provision_data, action='up', run_id=None, tx_id=None):
        """
        This function takes provision_data, and executes the given
        action for each target within the provision_data disctionary.

        :param provision_data: PinFile data as a dictionary, with
        target information

        :param action: Action taken (up, destroy, etc). (Default: up)

        :param run_id: Provided run_id to duplicate/destroy (Default: None)

        :param tx_id: Provided tx_id to duplicate/destroy (Default: None)

        .. .note:: The `run_id` value differs from the `rundb_id`, in that
                   the `run_id` is an existing value in the database.
                   The `rundb_id` value is created to store the new record.
                   If the `run_id` is passed, it is used to collect an existing
                   `uhash` value from the given `run_id`, which is in turn used
                   to perform an idempotent reprovision, or destroy provisioned
                   resources.
        """

        results = {}
        return_code = 99

        # verify_targets_exist()
        targets = [x.lower() for x in list(provision_data.keys())]

        if 'linchpin' in targets:
            raise LinchpinError("Target 'linchpin' is not allowed.")

        for target in targets:
            if target == 'cfgs':
                continue
            if not isinstance(provision_data[target], dict):
                raise LinchpinError("Target '{0}' does not"
                                    " exist.".format(target))

            self.ctx.log_debug("Processing target: {0}".format(target))
            results[target] = {}
            self.set_evar('target', target)

            rundb_id = self.prepare_rundb(target, action, run_id, tx_id)

            try:
                validator = Validator(self.ctx, self.role_path, self.pb_ext)
                resources = validator.validate(provision_data[target])
            except SchemaError:
                raise ValidationError("Target '{0}' does not validate.  For"
                                      " more information run `linchpin "
                                      "validate`".format(target))

            topology_data = provision_data[target].get('topology')
            self.set_evar('topo_data', topology_data)

            self.update_rundb(rundb_id, target, provision_data)

            # note : changing the state triggers the hooks
            return_code, results[target]['task_results'] = (self.run_target(
                                                            target,
                                                            resources,
                                                            action,
                                                            run_id)
                                                           )

            end = time.time()

            self.rundb.update_record(target, rundb_id, 'end', str(end))
            self.rundb.update_record(target, rundb_id, 'rc', return_code)

            run_data = self.rundb.get_record(target,
                                             action=action,
                                             run_id=rundb_id)

            results[target]['rundb_data'] = {rundb_id: run_data[0]}

        # generate the linchpin_id and structure
        lp_data = self.write_results_to_rundb(results, action)

        return (return_code, lp_data)
Exemplo n.º 6
0
    def do_action(self, provision_data, action='up', run_id=None, tx_id=None):
        """
        This function takes provision_data, and executes the given
        action for each target within the provision_data disctionary.

        :param provision_data: PinFile data as a dictionary, with
        target information

        :param action: Action taken (up, destroy, etc). (Default: up)

        :param run_id: Provided run_id to duplicate/destroy (Default: None)

        :param tx_id: Provided tx_id to duplicate/destroy (Default: None)

        .. .note:: The `run_id` value differs from the `rundb_id`, in that
                   the `run_id` is an existing value in the database.
                   The `rundb_id` value is created to store the new record.
                   If the `run_id` is passed, it is used to collect an existing
                   `uhash` value from the given `run_id`, which is in turn used
                   to perform an idempotent reprovision, or destroy provisioned
                   resources.
        """
        ansible_console = False
        if self.ctx.cfgs.get('ansible'):
            ansible_console = (
                ast.literal_eval(self.get_cfg('ansible',
                                              'console',
                                              default='False')))

        if not ansible_console:
            ansible_console = bool(self.ctx.verbosity)

        results = {}


        return_code = 99
        vault_pass = self.get_evar('vault_pass')
        if vault_pass == '':
            self.set_evar('vault_pass',
                          self.ctx.get_cfg('evars',
                                           'vault_pass',
                                           default=''))

        for target in provision_data.keys():
            if not isinstance(provision_data[target], dict):
                raise LinchpinError("Target '{0}' does not"
                                    " exist.".format(target))

        targets = [x.lower() for x in provision_data.keys()]
        if 'linchpin' in targets:
            raise LinchpinError("Target 'linchpin' is not allowed.")

        for target in provision_data.keys():
            if target == 'cfgs':
                continue

            self.ctx.log_debug("Processing target: {0}".format(target))

            results[target] = {}
            self.set_evar('target', target)

            rundb = self.setup_rundb()

            if tx_id:
                record = rundb.get_tx_record(tx_id)
                run_id = (record['targets'][0][target].keys()[0])


            rundb_schema = json.loads(self.get_cfg(section='lp',
                                      key='rundb_schema'))
            rundb.schema = rundb_schema
            self.set_evar('rundb_schema', rundb_schema)

            start = time.time()
            st_uhash = int(start * 1000)
            uhash = None

            # generate a new rundb_id
            # (don't confuse it with an already existing run_id)
            rundb_id = rundb.init_table(target)
            orig_run_id = rundb_id

            uhash_length = self.get_cfg('lp', 'rundb_uhash_length')
            uhash_len = int(uhash_length)
            if not run_id:
                hash_str = ':'.join([target, str(tx_id), str(rundb_id),
                                     str(st_uhash)])
                if isinstance(hash_str, text_type):
                    hash_str = hash_str.encode('utf-8')
                uh = hashlib.new(self.rundb_hash, hash_str)
                uhash = uh.hexdigest()[:uhash_len]

            if action == 'destroy' or run_id:
                # look for the action='up' records to destroy
                data, orig_run_id = rundb.get_record(target,
                                                     action='up',
                                                     run_id=run_id)

                if data:
                    uhash = data.get('uhash')
                    self.ctx.log_debug("using data from"
                                       " run_id: {0}".format(run_id))

            elif action not in ['up', 'destroy']:
                # it doesn't appear this code will will execute,
                # but if it does...
                raise LinchpinError("Attempting '{0}' action on"
                                    " target: '{1}' failed. Not an"
                                    " action.".format(action, target))


            self.ctx.log_debug('rundb_id: {0}'.format(rundb_id))
            self.ctx.log_debug('uhash: {0}'.format(uhash))

            rundb.update_record(target, rundb_id, 'uhash', uhash)
            rundb.update_record(target, rundb_id, 'start', str(start))
            rundb.update_record(target, rundb_id, 'action', action)

            self.set_evar('orig_run_id', orig_run_id)
            self.set_evar('rundb_id', rundb_id)
            self.set_evar('uhash', uhash)

            try:
                validator = Validator(self.ctx, self.pb_path, self.pb_ext)
                resources = validator.validate(provision_data[target])
            except SchemaError:
                raise ValidationError("Target '{0}' does not validate.  For"
                                      " more information run `linchpin "
                                      "validate`".format(target))

            topology_data = provision_data[target].get('topology')
            self.set_evar('topo_data', topology_data)

            rundb.update_record(target,
                                rundb_id,
                                'inputs',
                                [
                                    {'topology_data':
                                     provision_data[target]['topology']}
                                ])

            if provision_data[target].get('layout', None):
                l_data = provision_data[target]['layout']
                provision_data[target]['layout'] = self._convert_layout(l_data)
                self.set_evar('layout_data', provision_data[target]['layout'])

                rundb.update_record(target,
                                    rundb_id,
                                    'inputs',
                                    [
                                        {'layout_data':
                                         provision_data[target]['layout']}
                                    ])

            if provision_data[target].get('hooks', None):
                hooks_data = provision_data[target].get('hooks')
                self.set_evar('hooks_data', hooks_data)
                rundb.update_record(target,
                                    rundb_id,
                                    'inputs',
                                    [
                                        {'hooks_data':
                                         provision_data[target]['hooks']}
                                    ])

            if provision_data.get('cfgs', None):
                vars_data = provision_data[target].get('cfgs')
                self.set_evar('cfgs_data', vars_data)
                rundb.update_record(target,
                                    rundb_id,
                                    'cfgs',
                                    [
                                        {'user':
                                         provision_data['cfgs']}
                                    ])

            # note : changing the state triggers the hooks
            self.hooks.rundb = (rundb, rundb_id)
            self.pb_hooks = self.get_cfg('hookstates', action)
            self.ctx.log_debug('calling: {0}{1}'.format('pre', action))

            if (('pre' in self.pb_hooks) and not self.get_cfg('hook_flags',
                                                              'no_hooks')):
                self.hook_state = '{0}{1}'.format('pre', action)

            # FIXME need to add rundb data for hooks results

            # invoke the appropriate action
            return_code, results[target]['task_results'] = (
                self._invoke_playbooks(resources, action=action,
                                       console=ansible_console)
            )

            # logs the return_code back to console and quits
            # quits if return_code > 0
            self.ctx.log("Playbook Return code {0}".format(str(return_code)))
            if return_code > 0 and action == "up":
                sys.exit(return_code)

            if not return_code:
                self.ctx.log_state("Action '{0}' on Target '{1}' is "
                                   "complete".format(action, target))

            # FIXME Check the result[target] value here, and fail if applicable.
            # It's possible that a flag might allow more targets to run, then
            # return an error code at the end.

            # add post provision hook for inventory generation
            if (('inv' in self.pb_hooks) and not self.get_cfg('hook_flags',
                                                              'no_hooks')):
                self.hook_state = 'postinv'

            if (('post' in self.pb_hooks) and
                    (self.__meta__ == "API") and
                    not self.get_cfg('hook_flags', 'no_hooks')):
                self.hook_state = '{0}{1}'.format('post', action)

            end = time.time()

            rundb.update_record(target, rundb_id, 'end', str(end))
            rundb.update_record(target, rundb_id, 'rc', return_code)

            run_data = rundb.get_record(target,
                                        action=action,
                                        run_id=rundb_id)

            results[target]['rundb_data'] = {rundb_id: run_data[0]}


        # generate the linchpin_id and structure
        lp_schema = ('{"action": "", "targets": []}')

        rundb = self.setup_rundb()
        rundb.schema = json.loads(lp_schema)
        lp_id = rundb.init_table('linchpin')

        summary = {}

        for target, data in results.iteritems():
            for k, v in data['rundb_data'].iteritems():
                summary[target] = {k: {'rc': v['rc'], 'uhash': v['uhash']}}

        rundb.update_record('linchpin', lp_id, 'action', action)
        rundb.update_record('linchpin', lp_id, 'targets', [summary])

        lp_data = {lp_id: {'action': action,
                           'summary_data': summary,
                           'results_data': results}}

        return (return_code, lp_data)