def get_hosts(self): """ Called by main function, it extracts main config file and also check for database Reads the yaml config file given by user and pass the extracted data to login function to read device details and connect them. Also checks sqlite key to check if user wants to create database for snapshots """ self.logger.debug( colorama.Fore.BLUE + "jsnapy.cfg file location used : %s" % get_config_location(), extra=self.log_detail) self.logger.debug(colorama.Fore.BLUE + "Configuration file location used : %s" % get_path('DEFAULT', 'config_file_path'), extra=self.log_detail) if self.args.pre_snapfile is not None: output_file = self.args.pre_snapfile elif self.args.snapcheck is True and self.args.pre_snapfile is None: output_file = "snap_temp" self.snap_del = True else: output_file = "" conf_file = self.args.file check = self.args.check snap = self.args.snap if os.path.isfile(conf_file): config_file = open(conf_file, 'r') self.main_file = yaml.load(config_file) elif os.path.isfile( os.path.join(get_path('DEFAULT', 'config_file_path'), conf_file)): fpath = get_path('DEFAULT', 'config_file_path') config_file = open(os.path.join(fpath, conf_file), 'r') self.main_file = yaml.load(config_file) else: self.logger.error( colorama.Fore.RED + "ERROR!! Config file '%s' is not present " % conf_file, extra=self.log_detail) sys.exit(1) #### if --check option is given for sqlite, then snap file name is not compulsory #### #### else exit the function saying arguments not correct #### if self.main_file.__contains__('sqlite') and self.main_file[ 'sqlite'] and self.main_file['sqlite'][0]: self.chk_database(self.main_file, self.args.pre_snapfile, self.args.post_snapfile, check, snap) else: if (self.args.check is True and (self.args.file is None or self.args.pre_snapfile is None or self.args.post_snapfile is None)): self.logger.error( colorama.Fore.RED + "Arguments not given correctly, Please refer help message", extra=self.log_detail) self.parser.print_help() sys.exit(1) self.login(output_file)
def get_config_file(self): """ It extracts main config file and also check for database Checks sqlite key to check if user wants to create database for snapshots By end of this function, self.main_file has the passed file or arguments details """ conf_file = self.args.file if conf_file is not None: if os.path.isfile(conf_file): config_file = open(conf_file, 'r') self.main_file = yaml.load(config_file, Loader=yaml.FullLoader) elif os.path.isfile( os.path.join(get_path('DEFAULT', 'config_file_path'), conf_file)): fpath = get_path('DEFAULT', 'config_file_path') config_file = open(os.path.join(fpath, conf_file), 'r') self.main_file = yaml.load(config_file, Loader=yaml.FullLoader) else: self.logger.error( colorama.Fore.RED + "ERROR!! Config file '%s' is not present " % conf_file, extra=self.log_detail) sys.exit(1) else: if self.args.hostname and self.args.testfiles: temp_dict = { 'hosts': [{ 'device': '', 'username': '', 'passwd': '' }], 'tests': [] } temp_dict['hosts'][0]['device'] = self.args.hostname temp_dict['hosts'][0]['username'] = self.args.login temp_dict['hosts'][0]['passwd'] = self.args.passwd for tfile in self.args.testfiles: temp_dict['tests'].append(tfile) self.main_file = temp_dict if self.main_file.__contains__('sqlite') and self.main_file[ 'sqlite'] and self.main_file['sqlite'][0]: self.chk_database(self.main_file, self.args.pre_snapfile, self.args.post_snapfile, self.args.check, self.args.snap) else: # if --check option is given for sqlite, then snap file name is not compulsory # else exit the function saying arguments not correct if (self.args.check is True and (self.args.pre_snapfile is None or self.args.post_snapfile is None)): self.logger.error( colorama.Fore.RED + "Arguments not given correctly, Please refer help message", extra=self.log_detail) self.parser.print_help() sys.exit(1)
def test_get_path_custom(self, mock_config_loc): DirStore.custom_dir = '~/bogus' HOME = os.path.join(os.path.expanduser('~'), 'bogus/') conf_loc = get_path('DEFAULT', 'config_file_path') snap_loc = get_path('DEFAULT', 'snapshot_path') test_loc = get_path('DEFAULT', 'test_file_path') self.assertEqual(conf_loc, HOME) self.assertEqual(snap_loc, os.path.join(HOME, 'snapshots')) self.assertEqual(test_loc, os.path.join(HOME, 'testfiles')) self.assertFalse(mock_config_loc.called)
def test_get_path_custom(self, mock_config_loc): DirStore.custom_dir = '~/bogus' if 'win' in sys.platform: HOME = os.path.join(os.path.expanduser('~'), 'bogus\\') else: HOME = os.path.join(os.path.expanduser('~'), 'bogus/') conf_loc = get_path('DEFAULT', 'config_file_path') snap_loc = get_path('DEFAULT', 'snapshot_path') test_loc = get_path('DEFAULT', 'test_file_path') self.assertEqual(conf_loc, HOME) self.assertEqual(snap_loc, os.path.join(HOME, 'snapshots')) self.assertEqual(test_loc, os.path.join(HOME, 'testfiles'))
def generate_rpc_reply(self, dev, output_file, hostname, config_data): """ Generates rpc-reply based on command/rpc given and stores them in snap_files :param dev: device handler :param output_file: filename to store snapshots :param hostname: hostname of device :param config_data : data of main config file """ val = None test_files = [] for tfile in config_data.get('tests'): if not os.path.isfile(tfile): tfile = os.path.join( expanduser(get_path( 'DEFAULT', 'test_file_path')), tfile) if os.path.isfile(tfile): test_file = open(tfile, 'r') test_files.append(yaml.load(test_file)) else: self.logger.error( colorama.Fore.RED + "ERROR!! File %s is not found for taking snapshots" % tfile, extra=self.log_detail) g = Parser() for tests in test_files: val = g.generate_reply(tests, dev, output_file, hostname, self.db) return val
def setup_logging( default_path='logging.yml', default_level=logging.INFO, env_key='LOG_CFG'): config_location = get_config_location('logging.yml') path = os.path.join(config_location, default_path) value = os.getenv(env_key, None) if value: path = value if os.path.exists(path): with open(path, 'rt') as f: config = yaml.load(f.read()) logging.config.dictConfig(config) else: logging.basicConfig(level=default_level) ################################### # Creating Folder path for SNAPSHOT ################################### if 'win32' not in sys.platform and not hasattr(sys, 'real_prefix'): snapshots_path = get_path('DEFAULT', 'snapshot_path') snapshots_path = os.path.expanduser(snapshots_path) if not os.path.isdir(snapshots_path): os.makedirs(snapshots_path) HOME = os.path.expanduser("~") # correct cross platform way to do it home_folder = os.path.join(HOME, '.jsnapy') if not os.path.isdir(home_folder): os.mkdir(home_folder)
def test_get_path_normal(self, mock_config_location): DirStore.custom_dir = None mock_config_location.return_value = os.path.join( os.path.dirname(__file__), 'configs') loc = get_path('DEFAULT', 'config_file_path') self.assertTrue(mock_config_location.called) self.assertEqual(loc, '/throgus')
def setup_logging(default_path='logging.yml', default_level=logging.INFO, env_key='LOG_CFG'): config_location = get_config_location('logging.yml') path = os.path.join(config_location, default_path) value = os.getenv(env_key, None) if value: path = value if os.path.exists(path): with open(path, 'rt') as f: config = yaml.load(f.read(), Loader=yaml.FullLoader) logging.config.dictConfig(config) else: logging.basicConfig(level=default_level) ################################### # Creating Folder path for SNAPSHOT ################################### # Modified by @gcasella to use the function created on lines 24-29 in the __init__.py. if 'win32' not in sys.platform and not venv_check: snapshots_path = get_path('DEFAULT', 'snapshot_path') snapshots_path = os.path.expanduser(snapshots_path) if not os.path.isdir(snapshots_path): os.makedirs(snapshots_path) HOME = os.path.expanduser("~") # correct cross platform way to do it home_folder = os.path.join(HOME, '.jsnapy') if not os.path.isdir(home_folder): os.mkdir(home_folder)
def generate_rpc_reply(self, dev, output_file, hostname, config_data): """ Generates rpc-reply based on command/rpc given and stores them in snap_files :param dev: device handler :param output_file: filename to store snapshots :param hostname: hostname of device :param config_data : data of main config file """ val = None test_files = [] for tfile in config_data.get('tests'): if not os.path.isfile(tfile): tfile = os.path.join(get_path('DEFAULT', 'test_file_path'), tfile) if os.path.isfile(tfile): test_file = open(tfile, 'r') test_files.append(yaml.load(test_file)) else: self.logger.error( colorama.Fore.RED + "ERROR!! File %s is not found for taking snapshots" % tfile, extra=self.log_detail) g = Parser() for tests in test_files: val = g.generate_reply(tests, dev, output_file, hostname, self.db) return val
def __init__(self, host, db_name): self.logger_storesqlite = logging.getLogger(__name__) host = host.replace(".", "__") self.table_name = "table_" + host # Creating Schema self.db_filename = os.path.join( os.path.expanduser(get_path("DEFAULT", "snapshot_path")), db_name ) try: with sqlite3.connect(self.db_filename) as conn: # Creating schema if it does not exists sqlstr = ( """create table if not exists '%s' ( id integer not null, filename text, cli_command text, snap_name text, data_format text, data text );""" % self.table_name ) conn.execute(sqlstr) except Exception as ex: self.logger_storesqlite.error( "\nERROR occurred in database: %s" % str(ex) )
def __init__(self, db_name): self.logger_sqlite = logging.getLogger(__name__) self.sqlite_logs = {'hostname': None} self.db_filename = os.path.join( os.path.expanduser(get_path('DEFAULT', 'snapshot_path')), db_name) if not os.path.isfile(self.db_filename): self.logger_sqlite.error(colorama.Fore.RED + "Database %s does not exist." % db_name, extra=self.sqlite_logs) sys.exit(1)
def pre_process_information(self): """ The function provides the information mentioned in the configuration files """ self.logger.debug( colorama.Fore.BLUE + "jsnapy.cfg file location used : %s" % get_config_location(), extra=self.log_detail) self.logger.debug(colorama.Fore.BLUE + "Configuration file location used : %s" % get_path('DEFAULT', 'config_file_path'), extra=self.log_detail)
def generate_snap_file(self, device, prefix, name, reply_format): """ This function generates name of snapshot files """ if os.path.isfile(prefix): return prefix else: cmd_rpc_name = re.sub('/|\*|\.|-', '_', name) sfile = str(device) + '_' + prefix + '_' + \ cmd_rpc_name + '.' + reply_format snapfile = os.path.join( expanduser(get_path('DEFAULT', 'snapshot_path')), sfile) return snapfile
def get_hosts_list(self, hosts_val, host_dict): """ Function extracts list of hosts from the data given. :param hosts_val: has the list of hosts to be parsed :param host_dict: The dictionary to be created to store the parsed values """ first_entry = hosts_val[0] if 'include' in first_entry: # check if hosts are group based devices_file_name = first_entry['include'] if os.path.isfile(devices_file_name): lfile = devices_file_name else: lfile = os.path.join( expanduser(get_path('DEFAULT', 'test_file_path')), devices_file_name) login_file = open(lfile, 'r') dev_file = yaml.load(login_file, Loader=yaml.FullLoader) gp = first_entry.get('group', 'all') dgroup = [i.strip().lower() for i in gp.split(',')] iter = 0 # initialize the counter from 0 to keep count of hosts for dgp in dev_file: if dgroup[0].lower() == 'all' or dgp.lower() in dgroup: for val in dev_file[dgp]: hostname = list(val)[0] iter += 1 if val.get( hostname ) is not None and hostname not in self.host_list: self.host_list.append(hostname) host_dict[iter] = deepcopy(val.get(hostname)) host_dict[iter]["device"] = hostname else: iter = -1 # iterator keeps count of number of hosts for host in hosts_val: iter += 1 try: hostname = host['device'] self.log_detail = {'hostname': hostname} except KeyError as ex: self.logger.error( colorama.Fore.RED + "ERROR!! KeyError 'device' key not found", extra=self.log_detail) except Exception as ex: self.logger.error(colorama.Fore.RED + "ERROR!! %s" % ex, extra=self.log_detail) else: if hostname not in self.host_list: self.host_list.append(hostname) host_dict[iter] = deepcopy(host)
def __init__(self, db_name): self.logger_sqlite = logging.getLogger(__name__) self.sqlite_logs = {'hostname': None} self.db_filename = os.path.join( os.path.expanduser(get_path( 'DEFAULT', 'snapshot_path')), db_name) if not os.path.isfile(self.db_filename): self.logger_sqlite.error( colorama.Fore.RED + "Database %s does not exist." % db_name, extra=self.sqlite_logs) sys.exit(1)
def generate_snap_file(self, device, prefix, name, reply_format): """ This function generates name of snapshot files """ if self.port is not None: device = "{}_{}".format(device, self.port) if os.path.isfile(prefix): return prefix else: cmd_rpc_name = re.sub("/|\*|\.|-", "_", name) sfile = str(device) + "_" + prefix + "_" + cmd_rpc_name + "." + reply_format snapfile = os.path.join( expanduser(get_path("DEFAULT", "snapshot_path")), sfile ) return snapfile
def generate_snap_file(self, output_file, hostname, name, cmd_format): """ This will generate snapshot file name :param output_file: either complete file or file tag :param name: command or RPC :param cmd_format: xml/text :return: return output file """ name = name.split('|')[0].strip() cmd_rpc = re.sub('/|\*|\.|-|\|', '_', name) if os.path.isfile(output_file): return output_file else: filename = hostname + '_' + output_file + \ '_' + cmd_rpc + '.' + cmd_format output_file = os.path.join(get_path('DEFAULT', 'snapshot_path'), filename) return output_file
def multiple_device_details(self, host, config_data, pre_name, action, post_name): """ Called when multiple devices are given in config file :param host: hostname :param config_data: data of main config file :param pre_name: pre snapshot filename or file tag :param action: action to be taken, snap, snapcheck, check :param post_name: post snapshot filename or file tag :return: return object of testop.Operator containing test details """ res_obj = [] self.host_list = [] login_file = host['include'] login_file = login_file if os.path.isfile( host.get('include')) else os.path.join( get_path('DEFAULT', 'test_file_path'), login_file) login_file = open(login_file, 'r') dev_file = yaml.load(login_file) gp = host.get('group', 'all') dgroup = [i.strip().lower() for i in gp.split(',')] for dgp in dev_file: if dgroup[0].lower() == 'all' or dgp.lower() in dgroup: for val in dev_file[dgp]: hostname = val.keys()[0] self.host_list.append(hostname) self.log_detail['hostname'] = hostname username = val.get(hostname).get('username') password = val.get(hostname).get('passwd') key_value = val.get(hostname) key_value = self.get_values(key_value) t = Thread(target=self.connect, args=(hostname, username, password, pre_name, config_data, action, post_name), kwargs=key_value) t.start() if action == "snap": res_obj.append(self.snap_q.get()) elif action in ["snapcheck", "check"]: res_obj.append(self.q.get()) else: res_obj.append(None) t.join() return res_obj
def generate_snap_file(self, output_file, hostname, name, cmd_format): """ This will generate snapshot file name :param output_file: either complete file or file tag :param name: command or RPC :param cmd_format: xml/text :return: return output file """ if self.port is not None: hostname = "{}_{}".format(hostname, self.port) name = name.split("|")[0].strip() cmd_rpc = re.sub("/|\*|\.|-|\|", "_", name) if os.path.isfile(output_file): return output_file else: filename = hostname + "_" + output_file + "_" + cmd_rpc + "." + cmd_format output_file = os.path.join( os.path.expanduser(get_path("DEFAULT", "snapshot_path")), filename ) return output_file
def generate_snap_file(self, output_file, hostname, name, cmd_format): """ This will generate snapshot file name :param output_file: either complete file or file tag :param name: command or RPC :param cmd_format: xml/text :return: return output file """ name = name.split('|')[0].strip() cmd_rpc = re.sub('/|\*|\.|-|\|', '_', name) if os.path.isfile(output_file): return output_file else: filename = hostname + '_' + output_file + \ '_' + cmd_rpc + '.' + cmd_format output_file = os.path.join( os.path.expanduser(get_path( 'DEFAULT', 'snapshot_path')), filename) return output_file
def extract_test_cases(self, config_data): """ :param config_data: the data passed in the config file :return: the list of testcases """ test_files = [] for tfile in config_data.get('tests'): # tfile gets details of the test/files to be parsed. if not os.path.isfile(tfile): tfile = os.path.join( expanduser(get_path('DEFAULT', 'test_file_path')), tfile) if os.path.isfile(tfile): test_file = open(tfile, 'r') test_files.append(yaml.load(test_file, Loader=yaml.FullLoader)) else: self.logger.error( colorama.Fore.RED + "ERROR!! File %s is not found for extracting test case" % tfile, extra=self.log_detail) return test_files
def get_test(self, config_data, hostname, snap_file, post_snap, action): """ Analyse testfile and return object of testop.Operator containing test details called by connect() function and other functions of Jsnapy module functions :param config_data: data of main config file :param hostname: hostname :param snap_file: pre snapshot file name :param post_snap: post snapshot file name :param action: action to be taken (check, snapcheck, snap) :return: object of testop.Operator containing test details """ res = Operator() if config_data.get("mail") and self.args.diff is not True: mfile = os.path.join(get_path('DEFAULT', 'test_file_path'), config_data.get('mail'))\ if os.path.isfile(config_data.get('mail')) is False else config_data.get('mail') if os.path.isfile(mfile): mail_file = open(mfile, 'r') mail_file = yaml.load(mail_file) if "passwd" not in mail_file: passwd = getpass.getpass("Please enter ur email password ") else: passwd = mail_file['passwd'] res = self.compare_tests(hostname, config_data, snap_file, post_snap, action) send_mail = Notification() send_mail.notify(mail_file, hostname, passwd, res) else: self.logger.error( colorama.Fore.RED + "ERROR!! Path of file containing mail content is not correct", extra=self.log_detail) else: res = self.compare_tests(hostname, config_data, snap_file, post_snap, action) self.q.put(res) return res
def get_hosts(self): """ Called by main function, it extracts main config file and also check for database Reads the yaml config file given by user and pass the extracted data to login function to read device details and connect them. Also checks sqlite key to check if user wants to create database for snapshots """ self.logger.debug(colorama.Fore.BLUE + "jsnapy.cfg file location used : %s" % get_config_location(), extra=self.log_detail) self.logger.debug(colorama.Fore.BLUE + "Configuration file location used : %s" % get_path('DEFAULT', 'config_file_path'), extra=self.log_detail) if self.args.pre_snapfile is not None: output_file = self.args.pre_snapfile elif self.args.snapcheck is True and self.args.pre_snapfile is None: output_file = "snap_temp" self.snap_del = True else: output_file = "" conf_file = self.args.file check = self.args.check snap = self.args.snap if conf_file is not None: if os.path.isfile(conf_file): config_file = open(conf_file, 'r') self.main_file = yaml.load(config_file) elif os.path.isfile(os.path.join(get_path('DEFAULT', 'config_file_path'), conf_file)): fpath = get_path('DEFAULT', 'config_file_path') config_file = open(os.path.join(fpath, conf_file), 'r') self.main_file = yaml.load(config_file) else: self.logger.error( colorama.Fore.RED + "ERROR!! Config file '%s' is not present " % conf_file, extra=self.log_detail) sys.exit(1) else: if self.args.hostname and self.args.testfiles: temp_dict = {'hosts':[{'device':'', 'username':'', 'passwd':''}], 'tests':[]} temp_dict['hosts'][0]['device'] = self.args.hostname temp_dict['hosts'][0]['username'] = self.args.login temp_dict['hosts'][0]['passwd'] = self.args.passwd for tfile in self.args.testfiles: temp_dict['tests'].append(tfile) self.main_file = temp_dict #### if --check option is given for sqlite, then snap file name is not compulsory #### #### else exit the function saying arguments not correct #### if self.main_file.__contains__( 'sqlite') and self.main_file['sqlite'] and self.main_file['sqlite'][0]: self.chk_database( self.main_file, self.args.pre_snapfile, self.args.post_snapfile, check, snap) else: if (self.args.check is True and ( self.args.file is None or self.args.pre_snapfile is None or self.args.post_snapfile is None)): self.logger.error(colorama.Fore.RED + "Arguments not given correctly, Please refer help message", extra=self.log_detail) self.parser.print_help() sys.exit(1) self.login(output_file)
def login(self, output_file): """ Extract device information from main config file. Stores device information and call connect function, device can be single or multiple. Instead of connecting to all devices mentioned in yaml file, user can connect to some particular group of device also. :param output_file: name of snapshot file """ self.host_list = [] if self.args.hostname is None: host_dict={} try: hosts_val = self.main_file['hosts'] except KeyError as ex: self.logger.error(colorama.Fore.RED + "\nERROR occurred !! Hostname not given properly %s" % str(ex), extra=self.log_detail) #raise Exception(ex) except Exception as ex: self.logger.error(colorama.Fore.RED + "\nERROR occurred !! %s" % str(ex), extra=self.log_detail) #raise Exception(ex) else: # when group of devices are given, searching for include keyword in # hosts in main.yaml file first_entry = hosts_val[0] if 'include' in first_entry: devices_file_name = first_entry['include'] if os.path.isfile(devices_file_name): lfile = devices_file_name else: lfile = os.path.join( expanduser(get_path( 'DEFAULT', 'test_file_path')), devices_file_name) login_file = open(lfile, 'r') dev_file = yaml.load(login_file) gp = first_entry.get('group', 'all') dgroup = [i.strip().lower() for i in gp.split(',')] for dgp in dev_file: if dgroup[0].lower() == 'all' or dgp.lower() in dgroup: for val in dev_file[dgp]: hostname = list(val)[0] self.log_detail = {'hostname': hostname} if val.get(hostname) is not None and hostname not in host_dict: host_dict[hostname] = deepcopy(val.get(hostname)) self.host_list.append(hostname) # login credentials are given in main config file, can connect to multiple devices else: #key_value = deepcopy(k) for host in hosts_val: try: hostname = host['device'] self.log_detail = {'hostname': hostname} except KeyError as ex: self.logger.error( colorama.Fore.RED + "ERROR!! KeyError 'device' key not found", extra=self.log_detail) #raise Exception(ex) except Exception as ex: self.logger.error( colorama.Fore.RED + "ERROR!! %s" % ex, extra=self.log_detail) #raise Exception(ex) else: if hostname not in host_dict: self.host_list.append(hostname) # host.pop('device') host_dict[hostname] = deepcopy(host) for (hostname, key_value) in iteritems(host_dict): #The file config takes precedence over cmd line params -- no changes made username = self.args.login or key_value.get('username') password = self.args.passwd or key_value.get('passwd') #if --port arg is given on the cmd then that takes precedence port = self.args.port if port is not None: key_value['port'] = port key_value = self.get_values(key_value) t = Thread( target=self.connect, args=( hostname, username, password, output_file ), kwargs= key_value ) t.start() t.join() # login credentials are given from command line else: hostname = self.args.hostname self.log_detail = {'hostname': hostname} username = self.args.login password = self.args.passwd # if self.args.passwd is not None else getpass.getpass("\nEnter # Password: ") self.host_list.append(hostname) port = self.args.port key_value = {'port': port} if port is not None else {} self.connect(hostname, username, password, output_file, **key_value)
def login(self, output_file): """ Extract device information from main config file. Stores device information and call connect function, device can be single or multiple. Instead of connecting to all devices mentioned in yaml file, user can connect to some particular group of device also. :param output_file: name of snapshot file """ self.host_list = [] if self.args.hostname is None: try: k = self.main_file['hosts'][0] except KeyError as ex: self.logger.error( colorama.Fore.RED + "\nERROR occurred !! Hostname not given properly %s" % str(ex), extra=self.log_detail) #raise Exception(ex) except Exception as ex: self.logger.error(colorama.Fore.RED + "\nERROR occurred !! %s" % str(ex), extra=self.log_detail) #raise Exception(ex) else: # when group of devices are given, searching for include keyword in # hosts in main.yaml file if k.__contains__('include'): file_tag = k['include'] if os.path.isfile(file_tag): lfile = file_tag else: lfile = os.path.join( get_path('DEFAULT', 'test_file_path'), file_tag) login_file = open(lfile, 'r') dev_file = yaml.load(login_file) gp = k.get('group', 'all') dgroup = [i.strip().lower() for i in gp.split(',')] for dgp in dev_file: if dgroup[0].lower() == 'all' or dgp.lower() in dgroup: for val in dev_file[dgp]: hostname = val.keys()[0] self.log_detail = {'hostname': hostname} self.host_list.append(hostname) key_value = deepcopy(val.get(hostname)) if val.get( hostname ) is not None and 'username' in val.get( hostname).keys(): username = val.get(hostname).get( 'username') else: username = self.args.login if val.get( hostname ) is not None and 'passwd' in val.get( hostname).keys(): password = val.get(hostname).get('passwd') else: password = self.args.passwd # if self.args.passwd is not None else # getpass.getpass("\nEnter Password for # username: %s " %username) key_value = self.get_values(key_value) t = Thread(target=self.connect, args=(hostname, username, password, output_file), kwargs=key_value) t.start() t.join() # login credentials are given in main config file, can connect to only # one device else: key_value = deepcopy(k) try: hostname = k['device'] self.log_detail = {'hostname': hostname} except KeyError as ex: self.logger.error( colorama.Fore.RED + "ERROR!! KeyError 'device' key not found", extra=self.log_detail) #raise Exception(ex) except Exception as ex: self.logger.error(colorama.Fore.RED + "ERROR!! %s" % ex, extra=self.log_detail) #raise Exception(ex) else: username = k.get('username') or self.args.login password = k.get('passwd') or self.args.passwd self.host_list.append(hostname) key_value = self.get_values(key_value) self.connect(hostname, username, password, output_file, **key_value) # login credentials are given from command line else: hostname = self.args.hostname self.log_detail = {'hostname': hostname} username = self.args.login password = self.args.passwd # if self.args.passwd is not None else getpass.getpass("\nEnter # Password: ") self.host_list.append(hostname) port = self.args.port key_value = {'port': port} if port is not None else {} self.connect(hostname, username, password, output_file, **key_value)
def generate_test_files( self, main_file, device, check, diff, db, snap_del, pre=None, action=None, post=None): """ generate names of snap files from hostname and out files given by user, tests are performed on values stored in these snap files, in which test is to be performed :param main_file: main config file, to extract test files user wants to run :param device: device name :param check: variable to check if --check option is given or not :param diff: variable to check if --diff option is given or not :param db: database object :param snap_del: if --snapcheck operator is used without any test file name it will create temprory file and then will delete it at the end :param pre: file name of pre snapshot :param post: file name of post snapshot :param action: given by module version, either snap, snapcheck or check :return: object of testop.Operator containing test details """ op = Operator() op.device = device tests_files = [] self.log_detail['hostname'] = device # get the test files from config.yml if main_file.get('tests') is None: self.logger_check.error( colorama.Fore.RED + "\nERROR!! No test file found, Please mention test files !!", extra=self.log_detail) else: # extract test files, first search in path given in jsnapy.cfg for tfile in main_file.get('tests'): if not os.path.isfile(tfile): tfile = os.path.join( get_path( 'DEFAULT', 'test_file_path'), tfile) if os.path.isfile(tfile): test_file = open(tfile, 'r') tests_files.append(yaml.load(test_file)) else: self.logger_check.error( colorama.Fore.RED + "ERROR!! File %s not found for testing" % tfile, extra=self.log_detail) # check what all test cases need to be included, if nothing given # then include all test cases #### for tests in tests_files: tests_included = [] if 'tests_include' in tests: tests_included = tests.get('tests_include') else: for t in tests: tests_included.append(t) message= self._print_testmssg("Device: "+device, "*") self.logger_check.info(colorama.Fore.BLUE + message, extra=self.log_detail) for val in tests_included: self.logger_check.info( "Tests Included: %s " % (val), extra=self.log_detail) try: if tests[val][0].keys()[0] == 'command': command = tests[val][0].get('command').split('|')[0].strip() reply_format = tests[val][0].get('format', 'xml') message = self._print_testmssg("Command: "+command, "*") self.logger_check.info( colorama.Fore.BLUE + message, extra=self.log_detail) name = '_'.join(command.split()) teston = command else: rpc = tests[val][0]['rpc'] reply_format = tests[val][0].get('format', 'xml') self.logger_check.info(colorama.Fore.BLUE + (25) * "*" + "RPC is " + rpc + (25) * '*', extra=self.log_detail) name = rpc teston = rpc except KeyError: self.logger_check.error( colorama.Fore.RED + "ERROR occurred, test keys 'command' or 'rpc' not defined properly", extra=self.log_detail) except Exception as ex: self.logger_check.error( colorama.Fore.RED + "ERROR Occurred: %s" % str(ex), extra=self.log_detail) else: # extract snap files, if check from sqlite is true t if db.get( 'check_from_sqlite') is True and (check is True or diff is True or action in ["check", "diff"]): a = SqliteExtractXml(db.get('db_name')) # while checking from database, preference is given # to id and then snap name if (db['first_snap_id'] is not None) and ( db['second_snap_id'] is not None): snapfile1, data_format1 = a.get_xml_using_snap_id( str(device), name, db['first_snap_id']) snapfile2, data_format2 = a.get_xml_using_snap_id( str(device), name, db['second_snap_id']) else: snapfile1, data_format1 = a.get_xml_using_snapname( str(device), name, pre) snapfile2, data_format2 = a.get_xml_using_snapname( str(device), name, post) if reply_format != data_format1 or reply_format != data_format2: self.logger_check.error(colorama.Fore.RED + "ERROR!! Data stored in database is not in %s format." % reply_format, extra=self.log_detail) pass # sys.exit(1) ###### taking snapshot for --snapcheck operation #### elif db.get('check_from_sqlite') is True: a = SqliteExtractXml(db.get('db_name')) snapfile1, data_format1 = a.get_xml_using_snapname( str(device), name, pre) if reply_format != data_format1: self.logger_check.error( colorama.Fore.RED + "ERROR!! Data stored in database is not in %s format." % reply_format, extra=self.log_detail) pass # sys.exit(1) else: snapfile1 = self.generate_snap_file( device, pre, name, reply_format) # if check is true then call function to compare two # snapshots #### if (check is True or action is "check") and reply_format == 'xml': if db.get('check_from_sqlite') is False: snapfile2 = self.generate_snap_file( device, post, name, reply_format) self.compare_reply( op, tests[val], teston, check, db, snapfile1, snapfile2, action) # if --diff is true then call compare_diff to compare # two snapshots word by word #### elif(diff is True): if db.get('check_from_sqlite') is False: snapfile2 = self.generate_snap_file( device, post, name, reply_format) self.compare_diff( snapfile1, snapfile2, db.get('check_from_sqlite')) # else call --snapcheck test operation, it works only # for xml reply format #### elif (reply_format == 'xml'): self.compare_reply( op, tests[val], teston, check, db, snapfile1, action) ######## bug here ############ # multiple testcases for single command and same device, its deleting that file #################### """ if snap_del is True: snapfile1 = snapfile1 if os.path.isfile(snapfile1) else self.generate_snap_file(device, pre, name, reply_format) os.remove(snapfile1) """ else: # give error message if snapshot in text format is # used with operations other than --diff #### self.logger_check.error( colorama.Fore.RED + "ERROR!! for checking snapshots in text format use '--diff' option ", extra=self.log_detail) # print final result, if operation is --diff then message gets # printed compare_diff function only #### if (diff is not True): op.final_result(self.log_detail) return op
def generate_test_files(self, main_file, device, check, diff, db, snap_del, pre=None, action=None, post=None): """ generate names of snap files from hostname and out files given by user, tests are performed on values stored in these snap files, in which test is to be performed :param main_file: main config file, to extract test files user wants to run :param device: device name :param check: variable to check if --check option is given or not :param diff: variable to check if --diff option is given or not :param db: database object :param snap_del: if --snapcheck operator is used without any test file name it will create temprory file and then will delete it at the end :param pre: file name of pre snapshot :param post: file name of post snapshot :param action: given by module version, either snap, snapcheck or check :return: object of operator.Operator containing test details """ op = Operator() op.device = device tests_files = [] self.log_detail['hostname'] = device # pre_user and post_user are the names of the snapshot files # that the user wants to keep and store the snapfiles # with these names pre_user = pre post_user = post # get the test files from config.yml if main_file.get('tests') is None: self.logger_check.error( colorama.Fore.RED + "\nERROR!! No test file found, Please mention test files !!", extra=self.log_detail) else: # extract test files, first search in path given in jsnapy.cfg for tfile in main_file.get('tests'): if not os.path.isfile(tfile): tfile = os.path.join( expanduser(get_path('DEFAULT', 'test_file_path')), tfile) if os.path.isfile(tfile): test_file = open(tfile, 'r') tests_files.append( yaml.load(test_file, Loader=yaml.FullLoader)) else: self.logger_check.error( colorama.Fore.RED + "ERROR!! File %s not found for testing" % tfile, extra=self.log_detail) # check what all test cases need to be included, if nothing given # then include all test cases #### for tests in tests_files: tests_included = [] if 'tests_include' in tests: tests_included = tests.get('tests_include') else: for t in tests: tests_included.append(t) message = self._print_testmssg("Device: " + device, "*") self.logger_check.info(colorama.Fore.BLUE + message, extra=self.log_detail) for val in tests_included: self.logger_check.info("Tests Included: %s " % (val), extra=self.log_detail) # This is Where we are going to print the description mentioned by the user for the testcase # Enumerate generate a tuple of index and corresponding element in the list # index[0] is index and index[1] is the dictionary in which it will search. description_index = [ index[0] for index in enumerate(tests[val]) if 'description' in index[1] ] if len(description_index) > 0: description_index = description_index[0] description = tests[val][description_index][ 'description'] if description is not None: self.logger_check.info("Description: %s " % (description), extra=self.log_detail) try: if any('command' in d for d in tests[val]): index = next((i for i, x in enumerate(tests[val]) if 'command' in x), 0) command = tests[val][index].get('command').split( '|')[0].strip() reply_format = tests[val][0].get('format', 'xml') message = self._print_testmssg( "Command: " + command, "*") self.logger_check.info(colorama.Fore.BLUE + message, extra=self.log_detail) name = '_'.join(command.split()) teston = command # this is necessary for the pre and post to be the same that user specified # In a case when there are multiple rpc's with kwargs and a rpc with no kwargs pre = pre_user post = post_user else: index = next((i for i, x in enumerate(tests[val]) if 'rpc' in x), 0) index_kwargs = next( (i for i, x in enumerate(tests[val]) if 'kwargs' in x or 'args' in x), 1) rpc = tests[val][index]['rpc'] reply_format = tests[val][index].get( 'format', 'xml') self.logger_check.info(colorama.Fore.BLUE + (25) * "*" + "RPC is " + rpc + (25) * '*', extra=self.log_detail) name = rpc teston = rpc # this is necessary for the pre and post to be the same that user specified # In a case when there are multiple rpc's with kwargs and a rpc with no kwargs pre = pre_user post = post_user # here the user specified name is being used and the hash value generated for # kwargs part is appended to the name if 'kwargs' in tests[val][index_kwargs] and tests[ val][index_kwargs].get('kwargs') is None: del tests[val][index_kwargs]['kwargs'] if 'args' in tests[val][index_kwargs] and tests[ val][index_kwargs].get('args') is None: del tests[val][index_kwargs]['args'] if 'kwargs' in tests[val][ index_kwargs] or 'args' in tests[val][ index_kwargs]: if tests[val][index_kwargs].get('kwargs'): data = tests[val][index_kwargs].get( 'kwargs') elif tests[val][index_kwargs].get('args'): data = tests[val][index_kwargs].get('args') hash_kwargs = hashlib.md5( json.dumps(data, sort_keys=True).encode( 'utf-8')).digest() hash_kwargs = base64.urlsafe_b64encode( hash_kwargs).strip() if action == 'check' and pre_user is not None and post_user is not None: pre = pre_user + '_' + hash_kwargs.decode( 'utf-8') post = post_user + '_' + hash_kwargs.decode( 'utf-8') elif action == 'snapcheck' and pre_user is not None and post_user is None: pre = pre_user + '_' + hash_kwargs.decode( 'utf-8') elif diff is True and pre_user is not None and post_user is not None: pre = pre_user + '_' + hash_kwargs.decode( 'utf-8') post = post_user + '_' + hash_kwargs.decode( 'utf-8') except KeyError: self.logger_check.error( colorama.Fore.RED + "ERROR occurred, test keys 'command' or 'rpc' not defined properly", extra=self.log_detail) except Exception as ex: self.logger_check.error(colorama.Fore.RED + "ERROR Occurred: %s" % str(ex), extra=self.log_detail) else: # extract snap files, if check from sqlite is true t if db.get('check_from_sqlite') is True and ( check is True or diff is True or action in ["check", "diff"]): a = SqliteExtractXml(db.get('db_name')) # while checking from database, preference is given # to id and then snap name if (db['first_snap_id'] is not None) and (db['second_snap_id'] is not None): snapfile1, data_format1 = a.get_xml_using_snap_id( str(device), name, db['first_snap_id']) snapfile2, data_format2 = a.get_xml_using_snap_id( str(device), name, db['second_snap_id']) else: snapfile1, data_format1 = a.get_xml_using_snapname( str(device), name, pre) snapfile2, data_format2 = a.get_xml_using_snapname( str(device), name, post) if reply_format != data_format1 or reply_format != data_format2: self.logger_check.error( colorama.Fore.RED + "ERROR!! Data stored in database is not in %s format." % reply_format, extra=self.log_detail) pass # sys.exit(1) ###### taking snapshot for --snapcheck operation #### elif db.get('check_from_sqlite') is True: a = SqliteExtractXml(db.get('db_name')) snapfile1, data_format1 = a.get_xml_using_snapname( str(device), name, pre) if reply_format != data_format1: self.logger_check.error( colorama.Fore.RED + "ERROR!! Data stored in database is not in %s format." % reply_format, extra=self.log_detail) pass # sys.exit(1) else: snapfile1 = self.generate_snap_file( device, pre, name, reply_format) # if check is true then call function to compare two # snapshots #### if (check is True or action == "check") and reply_format == 'xml': if db.get('check_from_sqlite') is False: snapfile2 = self.generate_snap_file( device, post, name, reply_format) self.compare_reply(op, tests[val], val, teston, check, db, snapfile1, snapfile2, action) # if --diff is true then call compare_diff to compare # two snapshots word by word #### elif (diff is True): if db.get('check_from_sqlite') is False: snapfile2 = self.generate_snap_file( device, post, name, reply_format) self.compare_diff(snapfile1, snapfile2, db.get('check_from_sqlite')) # else call --snapcheck test operation, it works only # for xml reply format #### elif (reply_format == 'xml'): self.compare_reply(op, tests[val], val, teston, check, db, snapfile1, action) ######## bug here ############ # multiple testcases for single command and same device, its deleting that file #################### """ if snap_del is True: snapfile1 = snapfile1 if os.path.isfile(snapfile1) else self.generate_snap_file(device, pre, name, reply_format) os.remove(snapfile1) """ else: # give error message if snapshot in text format is # used with operations other than --diff #### self.logger_check.error( colorama.Fore.RED + "ERROR!! for checking snapshots in text format use '--diff' option ", extra=self.log_detail) # print final result, if operation is --diff then message gets # printed compare_diff function only #### if (diff is not True): op.final_result(self.log_detail) return op
def multiple_device_details( self, hosts, config_data, pre_name, action, post_name): """ Called when multiple devices are given in config file :param hosts: List of devices or a includes a file :param config_data: data of main config file :param pre_name: pre snapshot filename or file tag :param action: action to be taken, snap, snapcheck, check :param post_name: post snapshot filename or file tag :return: return object of testop.Operator containing test details """ res_obj = [] self.host_list = [] host_dict={} first_entry = hosts[0] if 'include' in first_entry: devices_file_name = first_entry['include'] if os.path.isfile(devices_file_name): lfile = devices_file_name else: lfile = os.path.join( expanduser(get_path( 'DEFAULT', 'test_file_path')), devices_file_name) login_file = open(lfile, 'r') dev_file = yaml.load(login_file) gp = first_entry.get('group', 'all') dgroup = [i.strip().lower() for i in gp.split(',')] for dgp in dev_file: if dgroup[0].lower() == 'all' or dgp.lower() in dgroup: for val in dev_file[dgp]: hostname = list(val)[0] self.log_detail = {'hostname': hostname} if val.get(hostname) is not None and hostname not in host_dict: host_dict[hostname] = deepcopy(val.get(hostname)) self.host_list.append(hostname) else: for host in hosts: try: hostname = host['device'] self.log_detail = {'hostname': hostname} except KeyError as ex: self.logger.error( colorama.Fore.RED + "ERROR!! KeyError 'device' key not found", extra=self.log_detail) except Exception as ex: self.logger.error( colorama.Fore.RED + "ERROR!! %s" % ex, extra=self.log_detail) else: if hostname not in host_dict: self.host_list.append(hostname) host_dict[hostname] = deepcopy(host) for (hostname, key_value) in iteritems(host_dict): username = key_value.get('username') password = key_value.get('passwd') key_value = self.get_values(key_value) t = Thread( target=self.connect, args=( hostname, username, password, pre_name, config_data, action, post_name), kwargs= key_value ) t.start() t.join() if action == "snap": if not self.snap_q.empty(): res_obj.append(self.snap_q.get()) elif action in ["snapcheck", "check"]: if not self.q.empty(): res_obj.append(self.q.get()) else: res_obj.append(None) return res_obj
def get_test(self, config_data, hostname, snap_file, post_snap, action): """ Analyse testfile and return object of operator.Operator containing test details called by connect() function and other functions of Jsnapy module functions :param config_data: data of main config file :param hostname: hostname :param snap_file: pre snapshot file name :param post_snap: post snapshot file name :param action: action to be taken (check, snapcheck, snap) :return: object of testop.Operator containing test details """ res = Operator() res = self.compare_tests( hostname, config_data, snap_file, post_snap, action) result_status = res.result mail_condition = 'all' if result_status == 'Passed': mail_condition = 'pass' elif result_status == 'Failed': mail_condition = 'fail' mail_pref = config_data.get("mail") #we don't want to send mail when diff operation is run if mail_pref is not None and self.args.diff is False: mail_file_path = None if type(mail_pref) is str: mail_file_path = mail_pref elif type(mail_pref) is dict: if mail_condition in mail_pref: mail_file_path = mail_pref.get(mail_condition) else: self.logger.error( colorama.Fore.RED + "ERROR!! Type of mail preferences should be either dictionary or string", extra=self.log_detail) if mail_file_path is not None and mail_file_path != '' : mfile = os.path.join(expanduser(get_path('DEFAULT', 'test_file_path')), mail_file_path)\ if os.path.isfile(mail_file_path) is False else mail_file_path if os.path.isfile(mfile): mail_file = open(mfile, 'r') mail_file = yaml.load(mail_file) if "passwd" not in mail_file: passwd = getpass.getpass( "Please enter ur email password ") else: passwd = mail_file['passwd'] send_mail = Notification() send_mail.notify(mail_file, hostname, passwd, res) else: self.logger.error( colorama.Fore.RED + "ERROR!! Path of file containing mail content is not correct", extra=self.log_detail) # else: # res = self.compare_tests( # hostname, # config_data, # snap_file, # post_snap, # action) self.q.put(res) return res
def multiple_device_details( self, hosts, config_data, pre_name, action, post_name): """ Called when multiple devices are given in config file :param hosts: List of devices or a includes a file :param config_data: data of main config file :param pre_name: pre snapshot filename or file tag :param action: action to be taken, snap, snapcheck, check :param post_name: post snapshot filename or file tag :return: return object of testop.Operator containing test details """ res_obj = [] self.host_list = [] host_dict={} first_entry = hosts[0] if 'include' in first_entry: devices_file_name = first_entry['include'] if os.path.isfile(devices_file_name): lfile = devices_file_name else: lfile = os.path.join( expanduser(get_path( 'DEFAULT', 'test_file_path')), devices_file_name) login_file = open(lfile, 'r') dev_file = yaml.load(login_file, Loader=yaml.FullLoader) gp = first_entry.get('group', 'all') dgroup = [i.strip().lower() for i in gp.split(',')] iter = 0 for dgp in dev_file: if dgroup[0].lower() == 'all' or dgp.lower() in dgroup: for val in dev_file[dgp]: hostname = list(val)[0] self.log_detail = {'hostname': hostname} iter += 1 if val.get(hostname) is not None and hostname not in self.host_list: self.host_list.append(hostname) host_dict[iter] = deepcopy(val.get(hostname)) host_dict[iter]["device"] = hostname else: # changes to support port self.get_hosts_list(hosts, host_dict) test_cases = self.extract_test_cases(config_data) for (iter, key_value) in iteritems(host_dict): hostname = key_value.get('device') username = key_value.get('username') password = key_value.get('passwd') key_value = self.get_values(key_value) t = Thread( target=self.connect, args=( hostname, username, password, pre_name, test_cases, config_data, action, post_name), kwargs= key_value ) t.start() t.join() if action == "snap": if not self.snap_q.empty(): res_obj.append(self.snap_q.get()) elif action in ["snapcheck", "check"]: if not self.q.empty(): res_obj.append(self.q.get()) else: res_obj.append(None) return res_obj
def test_get_path_config_exception(self, mock_config_location): with self.assertRaises(Exception): DirStore.custom_dir = None mock_config_location.return_value = None loc = get_path('DEFAULT', 'config_file_path')
def login(self, output_file): """ Extract device information from main config file. Stores device information and call connect function, device can be single or multiple. Instead of connecting to all devices mentioned in yaml file, user can connect to some particular group of device also. :param output_file: name of snapshot file """ self.host_list = [] if self.args.hostname is None: host_dict = {} try: hosts_val = self.main_file['hosts'] except KeyError as ex: self.logger.error( colorama.Fore.RED + "\nERROR occurred !! Hostname not given properly %s" % str(ex), extra=self.log_detail) #raise Exception(ex) except Exception as ex: self.logger.error(colorama.Fore.RED + "\nERROR occurred !! %s" % str(ex), extra=self.log_detail) #raise Exception(ex) else: # when group of devices are given, searching for include keyword in # hosts in main.yaml file first_entry = hosts_val[0] if 'include' in first_entry: devices_file_name = first_entry['include'] if os.path.isfile(devices_file_name): lfile = devices_file_name else: lfile = os.path.join( expanduser(get_path('DEFAULT', 'test_file_path')), devices_file_name) login_file = open(lfile, 'r') dev_file = yaml.load(login_file) gp = first_entry.get('group', 'all') dgroup = [i.strip().lower() for i in gp.split(',')] for dgp in dev_file: if dgroup[0].lower() == 'all' or dgp.lower() in dgroup: for val in dev_file[dgp]: hostname = list(val)[0] self.log_detail = {'hostname': hostname} if val.get( hostname ) is not None and hostname not in host_dict: host_dict[hostname] = deepcopy( val.get(hostname)) self.host_list.append(hostname) # login credentials are given in main config file, can connect to multiple devices else: #key_value = deepcopy(k) for host in hosts_val: try: hostname = host['device'] self.log_detail = {'hostname': hostname} except KeyError as ex: self.logger.error( colorama.Fore.RED + "ERROR!! KeyError 'device' key not found", extra=self.log_detail) #raise Exception(ex) except Exception as ex: self.logger.error(colorama.Fore.RED + "ERROR!! %s" % ex, extra=self.log_detail) #raise Exception(ex) else: if hostname not in host_dict: self.host_list.append(hostname) # host.pop('device') host_dict[hostname] = deepcopy(host) for (hostname, key_value) in iteritems(host_dict): #The file config takes precedence over cmd line params -- no changes made username = self.args.login or key_value.get('username') password = self.args.passwd or key_value.get('passwd') #if --port arg is given on the cmd then that takes precedence port = self.args.port if port is not None: key_value['port'] = port key_value = self.get_values(key_value) t = Thread(target=self.connect, args=(hostname, username, password, output_file), kwargs=key_value) t.start() t.join() # login credentials are given from command line else: hostname = self.args.hostname self.log_detail = {'hostname': hostname} username = self.args.login password = self.args.passwd # if self.args.passwd is not None else getpass.getpass("\nEnter # Password: ") self.host_list.append(hostname) port = self.args.port key_value = {'port': port} if port is not None else {} self.connect(hostname, username, password, output_file, **key_value)
def multiple_device_details(self, hosts, config_data, pre_name, action, post_name): """ Called when multiple devices are given in config file :param hosts: List of devices or a includes a file :param config_data: data of main config file :param pre_name: pre snapshot filename or file tag :param action: action to be taken, snap, snapcheck, check :param post_name: post snapshot filename or file tag :return: return object of testop.Operator containing test details """ res_obj = [] self.host_list = [] host_dict = {} first_entry = hosts[0] if 'include' in first_entry: devices_file_name = first_entry['include'] if os.path.isfile(devices_file_name): lfile = devices_file_name else: lfile = os.path.join( expanduser(get_path('DEFAULT', 'test_file_path')), devices_file_name) login_file = open(lfile, 'r') dev_file = yaml.load(login_file) gp = first_entry.get('group', 'all') dgroup = [i.strip().lower() for i in gp.split(',')] for dgp in dev_file: if dgroup[0].lower() == 'all' or dgp.lower() in dgroup: for val in dev_file[dgp]: hostname = list(val)[0] self.log_detail = {'hostname': hostname} if val.get(hostname ) is not None and hostname not in host_dict: host_dict[hostname] = deepcopy(val.get(hostname)) self.host_list.append(hostname) else: for host in hosts: try: hostname = host['device'] self.log_detail = {'hostname': hostname} except KeyError as ex: self.logger.error( colorama.Fore.RED + "ERROR!! KeyError 'device' key not found", extra=self.log_detail) except Exception as ex: self.logger.error(colorama.Fore.RED + "ERROR!! %s" % ex, extra=self.log_detail) else: if hostname not in host_dict: self.host_list.append(hostname) host_dict[hostname] = deepcopy(host) for (hostname, key_value) in iteritems(host_dict): username = key_value.get('username') password = key_value.get('passwd') key_value = self.get_values(key_value) t = Thread(target=self.connect, args=(hostname, username, password, pre_name, config_data, action, post_name), kwargs=key_value) t.start() t.join() if action == "snap": if not self.snap_q.empty(): res_obj.append(self.snap_q.get()) elif action in ["snapcheck", "check"]: if not self.q.empty(): res_obj.append(self.q.get()) else: res_obj.append(None) return res_obj
def get_test(self, config_data, hostname, snap_file, post_snap, action): """ Analyse testfile and return object of operator.Operator containing test details called by connect() function and other functions of Jsnapy module functions :param config_data: data of main config file :param hostname: hostname :param snap_file: pre snapshot file name :param post_snap: post snapshot file name :param action: action to be taken (check, snapcheck, snap) :return: object of testop.Operator containing test details """ res = Operator() res = self.compare_tests(hostname, config_data, snap_file, post_snap, action) result_status = res.result mail_condition = 'all' if result_status == 'Passed': mail_condition = 'pass' elif result_status == 'Failed': mail_condition = 'fail' mail_pref = config_data.get("mail") #we don't want to send mail when diff operation is run if mail_pref is not None and self.args.diff is False: mail_file_path = None if type(mail_pref) is str: mail_file_path = mail_pref elif type(mail_pref) is dict: if mail_condition in mail_pref: mail_file_path = mail_pref.get(mail_condition) else: self.logger.error( colorama.Fore.RED + "ERROR!! Type of mail preferences should be either dictionary or string", extra=self.log_detail) if mail_file_path is not None and mail_file_path != '': mfile = os.path.join(expanduser(get_path('DEFAULT', 'test_file_path')), mail_file_path)\ if os.path.isfile(mail_file_path) is False else mail_file_path if os.path.isfile(mfile): mail_file = open(mfile, 'r') mail_file = yaml.load(mail_file) if "passwd" not in mail_file: passwd = getpass.getpass( "Please enter ur email password ") else: passwd = mail_file['passwd'] send_mail = Notification() send_mail.notify(mail_file, hostname, passwd, res) else: self.logger.error( colorama.Fore.RED + "ERROR!! Path of file containing mail content is not correct", extra=self.log_detail) # else: # res = self.compare_tests( # hostname, # config_data, # snap_file, # post_snap, # action) self.q.put(res) return res