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
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)
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
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)
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)
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)