def exec_cmd(self, command): print "Executing command " + command + " on host " + self.host lib = SSHLibrary() lib.open_connection(self.host) lib.login(username=self.user,password=self.password) lib.execute_command(command) lib.close_connection()
def copy_file(self, src, dest): lib = SSHLibrary() lib.open_connection(self.host) lib.login(username=self.user, password=self.password) print "Copying " + src + " to " + dest + " on " + self.host lib.put_file(src, dest) lib.close_connection()
def execute_ssh_command(ip, username, password, command): print "executing ssh command" lib = SSHLibrary() lib.open_connection(ip) lib.login(username=username,password=password) print "login done" lib.execute_command(command) print "command executed : " + command lib.close_connection()
def execute_ssh_command(ip, username, password, command): print "executing ssh command" lib = SSHLibrary() lib.open_connection(ip) lib.login(username=username, password=password) print "login done" lib.execute_command(command) print "command executed : " + command lib.close_connection()
def _create_ssh_connection_and_login(host, username='******', password='******'): try: ssh = SSHLibrary() ssh.set_default_configuration(timeout='30 seconds') ssh.open_connection(host) ssh.login(username, password) return ssh except: raise AssertionError("Failed to successfully login via ssh to %s" % host)
class IssueCmd(): """ Class to facilitate running commands on remote systems """ def __init__(self): self._ssh_lib = SSHLibrary() def get_creds(self, host): """ Get the server credentials """ user = UserIdentity() cur_dir = os.path.dirname(os.path.abspath(__file__)) creds_file = os.path.join(cur_dir, "../config/", host + ".yaml") with open(creds_file) as creds: try: data = yaml.safe_load(creds) user.username = data["default"]["username"] user.password = data["default"]["password"] return user except yaml.YAMLError as exc: print(exc) def _open_conn(self, host): user = self.get_creds(host) try: self._ssh_lib.open_connection(host) try: self._ssh_lib.login(user.username, user.password) print(f"Connected to host: {host} successfully") except SSHException: print(f"Login to host: {host} failed") except (socket.error, OSError, TimeoutError) as ex: print(f"Connection to host: {host} failed") raise ex def run_cmd(self, command, host): """ Run a command remotely (using ssh) """ print(f"[CMD]: {command}") self._open_conn(host) stdout, stderr, ret_cd = self._ssh_lib.execute_command( command, return_stdout=True, return_stderr=True, return_rc=True) print(f"Exit Value:[{ret_cd}]") print(f"[STDOUT]: {stdout}") if stderr: print(f"[STDERR]: {stderr}") return ret_cd, stdout, stderr
def execute_ssh_command(ip, username, password, command): """Execute SSH Command use username and password of controller server for ssh and need karaf distribution location like /root/Documents/dist """ print "executing ssh command" lib = SSHLibrary() lib.open_connection(ip) lib.login(username=username, password=password) print "login done" cmd_response = lib.execute_command(command) print "command executed : " + command lib.close_connection() return cmd_response
def execute_ssh_command(ip, username, password, command): """Execute SSH Command use username and password of controller server for ssh and need karaf distribution location like /root/Documents/dist """ print("executing ssh command") lib = SSHLibrary() lib.open_connection(ip) lib.login(username=username, password=password) print("login done") cmd_response = lib.execute_command(command) print("command executed : " + command) lib.close_connection() return cmd_response
class RemoteHost: def __init__(self, host, user, password, rootdir, keyfile=None): self.host = host self.user = user self.password = password self.rootdir = rootdir self.keyfile = keyfile self.lib = SSHLibrary() self.lib.open_connection(self.host) if self.keyfile is not None: self.lib.login_with_public_key(username=self.user, keyfile=self.keyfile) else: self.lib.login(username=self.user, password=self.password) def __del__(self): self.lib.close_connection() def exec_cmd(self, command): print "Executing command " + command + " on host " + self.host rc = self.lib.execute_command(command, return_rc=True) if rc[1] != 0: raise Exception('remote command failed [{0}] with exit code {1}.' 'For linux-based vms, Please make sure requiretty is disabled in the /etc/sudoers file' .format(command, rc)) def mkdir(self, dir_name): self.exec_cmd("mkdir -p " + dir_name) def copy_file(self, src, dest): if src is None: print "src is None not copy anything to " + dest return if os.path.exists(src) is False: print "Src file " + src + " was not found" return print "Copying " + src + " to " + dest + " on " + self.host self.lib.put_file(src, dest) def kill_controller(self): self.exec_cmd("sudo ps axf | grep karaf | grep -v grep " "| awk '{print \"kill -9 \" $1}' | sudo sh") def start_controller(self, dir_name): self.exec_cmd(dir_name + "/odl/bin/start")
class SshLibrary(SSHLibrary): def __init__(self): pass @classmethod def ssh_(self, host, user, password): self.ssh = SSHLibrary(timeout=10) try: self.ssh.open_connection(host) self.ssh.login(user, password) command = [ 'show card', 'paginate false', 'show run vlan', 'show version' ] self.session_command(command) except ValueError as e: raise e return self.ssh @classmethod def session_command(self, command): print("command: ", type(command), command) if isinstance(command, list): for com in command: self.ssh.write(com.encode('ascii')) result = self.ssh.read_until('# ') return result if isinstance(command, str): self.ssh.write(command.encode('ascii')) result = self.ssh.read_until('# ') return result else: raise RuntimeError('command type error') @classmethod def reconnection(self, host): if self.ssh: return self.ssh else: self.ssh.open_connection(host) self.ssh.login(b'sysadmin', b'seanwang') return self.ssh def __del__(self): return self.ssh.close_connection()
def RSA_ssh_copy_key(self, host, username, password): """ Login With Public Key(username, keyLocations['privateKey'], 'passphrase') """ sshLibSession = SSHLibrary(loglevel='WARN') fo = open(os.path.join(self.keyStore, self.opensshKeyName), "rb") sshKey = fo.read() fo.close() sshLibSession.open_connection(host) sshLibSession.login(username, password) sshLibSession.execute_command("mkdir .ssh") sshLibSession.execute_command((("echo %s > .ssh/authorized_keys") % (sshKey))) sshLibSession.execute_command("chmod 700 .ssh") sshLibSession.execute_command("chmod 600 .ssh/authorized_keys") sshLibSession.close_connection()
def service_check(hostname, login, password): ssh = SSHLibrary() try: ssh.open_connection(hostname) ssh.login(login, password) except: print('Erro ao conectar no host!') ssh_command = ssh.execute_command('systemctl status nginx') if str(ssh_command).find('(running)') != -1: status = 'Servico ok!' else: status = 'Servico com problemas!' return status
class SSHConnection(): """ This class use robot ssh library to provide a base class for ssh connection """ def __init__(self,hostname,username,password,port,timeout=60,prompt="#"): self.host = hostname self.user = username self.passwd=password self.port=port self.timeout=timeout self.prompt=prompt self.ssh_agent = SSHLibrary(timeout=self.timeout, prompt=self.prompt) def login(self): """ Login to remote ssh server """ try: self.ssh_agent.open_connection(self.host) self.ssh_agent.login(self.user, self.passwd) except Exception,e: raise SSHLoginFailedError(str(e))
def wait_for_controller_stopped(ip, username, password, karafHome): lib = SSHLibrary() lib.open_connection(ip) lib.login(username=username, password=password) # Wait 1 minute for the controller to stop gracefully tries = 20 i = 1 while i <= tries: stdout = lib.execute_command("ps -axf | grep karaf | grep -v grep | wc -l") processCnt = stdout[0].strip('\n') print("processCnt: " + processCnt) if processCnt == '0': break i = i + 1 time.sleep(3) lib.close_connection() if i > tries: print("Killing controller") kill_controller(ip, username, password, karafHome)
def wait_for_controller_stopped(ip, username, password, karafHome): lib = SSHLibrary() lib.open_connection(ip) lib.login(username=username, password=password) # Wait 1 minute for the controller to stop gracefully tries = 20 i = 1 while i <= tries: stdout = lib.execute_command("ps -axf | grep karaf | grep -v grep | wc -l") # print "stdout: "+stdout processCnt = stdout[0].strip('\n') print("processCnt: " + processCnt) if processCnt == '0': break i = i + 1 time.sleep(3) lib.close_connection() if i > tries: print "Killing controller" kill_controller(ip, username, password, karafHome)
def issue_cmd_via_root(command, host, username=HOST_USER, pwd=HOST_PWD, timeout=300, prompt='$ ', sudo=False, sudo_password=None): """ The return value is ["standard output", "error output", return_value] """ sshLib = SSHLibrary() try: # print "[INFO] Begin to open the connection of", str(host) sshLib.open_connection(host) sshLib.login(username, pwd) # http://docs.paramiko.org/en/1.15/api/client.html#paramiko.client.SSHClient.connect except (SSHClientException, paramiko.SSHException, socket.error, socket.timeout) as se: errmsg = "[Error] Failed to connect to {host}".format(host=str(host)) print errmsg os.environ["OUTPUT"] = errmsg sshLib.close_connection() return ["", "", -1] ret = sshLib.execute_command(command, return_stdout=True, return_stderr=True, return_rc=True, sudo=sudo, sudo_password=sudo_password) sshLib.close_connection() if ret[2] == 0: os.environ["OUTPUT"] = ret[0] else: os.environ["OUTPUT"] = ret[1] return ret
class SSHLibraryPlugInWrapper(plugin_runner_abstract, metaclass=ABCMeta): def __init__(self, parameters: DotDict, data_handler, *user_args, **user_options): self._sudo_expected = is_truthy(user_options.pop('sudo', False)) self._sudo_password_expected = is_truthy( user_options.pop('sudo_password', False)) super().__init__(parameters, data_handler, *user_args, **user_options) self._execution_counter = 0 self._ssh = SSHLibrary() @property def content_object(self): return self._ssh @property def sudo_expected(self): return self._sudo_expected @property def sudo_password_expected(self): return self._sudo_password_expected def _close_ssh_library_connection_from_thread(self): try: with self._lock: self._ssh.close_connection() except RuntimeError: pass except Exception as e: if 'Logging background messages is only allowed from the main thread' in str( e): logger.warn(f"Ignore SSHLibrary error: '{e}'") return True raise def _evaluate_tolerance(self): if len(self._session_errors) == self._fault_tolerance: e = PlugInError( f"{self}", "PlugIn stop invoked; Errors count arrived to limit ({})". format( self.host_alias, self._fault_tolerance, ), *self._session_errors) logger.error(f"{e}") GlobalErrors().append(e) return False return True def login(self): host = self.parameters.host port = self.parameters.port username = self.parameters.username password = self.parameters.password certificate = self.parameters.certificate if len(self._session_errors) == 0: logger.info(f"Host '{self.host_alias}': Connecting") else: logger.warn( f"Host '{self.host_alias}': Restoring at {len(self._session_errors)} time" ) self._ssh.open_connection(host, repr(self), port) start_ts = datetime.now() while True: try: if certificate: logger.debug( f"Host '{self.host_alias}': Login with user/certificate" ) self._ssh.login_with_public_key(username, certificate, '') else: logger.debug( f"Host '{self.host_alias}': Login with user/password") self._ssh.login(username, password) except paramiko.AuthenticationException: raise except Exception as e: logger.warn( f"Host '{self.host_alias}': Connection failed; Reason: {e}" ) else: self._is_logged_in = True logger.info( f"Host '{self.host_alias}': Connection established") break finally: duration = (datetime.now() - start_ts).total_seconds() if duration >= self.parameters.timeout: raise TimeoutError( f"Cannot connect to '{self.host_alias}' during {self.parameters.timeout}s" ) def exit(self): if self._is_logged_in: self._ssh.switch_connection(repr(self)) self._close_ssh_library_connection_from_thread() self._is_logged_in = False logger.info( f"Host '{self.id}::{self.host_alias}': Connection closed") else: logger.info( f"Host '{self.id}::{self.host_alias}': Connection close not required (not opened)" )
class PackageLibrary(object): """ @summary:安装包管理类,实现安装包的扫描、拷贝、卸载、安装等操作. """ def __init__(self, ci_addr="10.10.17.49", ci_user="******", ci_passwd="passw0rd"): self.ci_addr = ci_addr self.ci_user = ci_user self.ci_passwd = ci_passwd from SSHLibrary import SSHLibrary self.sshLib = SSHLibrary() @add_logs_for_functions def execute_command_and_verify_results(self, command): command_list = command.split(";") for item in command_list: print "execute command: {0}".format(item) out, error = self.sshLib.execute_command(command, True, True) if out: print "@@@@@@@@output start:@@@@@@@@@@ \n {0} \n@@@@@@@@@output ends@@@@@@".format(out) if error: print error # raise AssertionError("execute command: {0} failed".format(command)) else: return out def ssh_login(self, server_ip, username, passwd): print "***python*** start login server:{0}".format(server_ip) self.sshLib.open_connection(server_ip, server_ip, timeout='3 minute') content = self.sshLib.login(username, passwd, delay='3 seconds') print content if "Last login" not in content: if '#' not in content: raise AssertionError("Fail to login host {0}".format(server_ip)) def _write(self, command): print "***python*** writing command or text to the terminal: {0}".format(command) return self.sshLib.write(command) @add_logs_for_functions def write_cmd(self, command): print "***python*** writing command or text to the terminal: {0}".format(command) return self.sshLib.write(command) @add_logs_for_functions def check_packages_is_update(self, mount_path, log_path): """ @summary:检查安装包更新通用方法 :param mount_path:成果管理处自动编译结果挂载点 :param log_path:存放日志的路径 :return:有更新返回True,没有更新返回False """ history_number = [] with open(log_path, "r+") as fp: read_data = fp.readlines() for date in read_data: history_number = history_number + date.split() print "history version:", history_number history_number.sort() self.ssh_login(self.ci_addr, self.ci_user, self.ci_passwd) # while True: latest_number = [] output = self.execute_command_and_verify_results("ls %s" % mount_path) for item in output.split(): # print item temp_version = filter(str.isdigit, item.encode('utf8')) if temp_version is not None and temp_version != '': latest_number.append(int(temp_version)) print "latest version:", latest_number latest_number.sort() if latest_number: print "latest: {0}, compile history:{1}".format(latest_number[-1], history_number[-1]) if int(latest_number[-1]) > int(history_number[-1]): # with open(log_path, "r+") as fp: # print "open {0} and write value {1}".format(log_path, latest_number[-1]) # fp.seek(0, 2) # fp.write(" " + str(latest_number[-1])) return latest_number[-1] return False @add_logs_and_check_result def check_building_status(self, mount_path, log_path): """ 检查是否编译成功 :param mount_path: 成果管理处自动编译结果挂载点 :param log_path: 存放日志的路径 :return:True/False """ building_number = self.check_packages_is_update(mount_path, log_path) if not building_number: return False else: building_number = str(building_number) sub_dir = building_number[:8] + '-' + building_number[8:] build_scene_path = '{0}/{1}/build_scene.log'.format(mount_path, sub_dir) with open(log_path, "r+") as fp: fp.seek(0, 2) fp.write(" " + str(building_number)) with open(build_scene_path, "r") as rfp: rfp.seek(-50, 2) for lines in rfp.readlines(): print lines if 'successfully' in lines: cp_cmd = 'cp {0}/{1}/result.txt case.html'.format(mount_path, sub_dir) os.system(cp_cmd) # os.system("sed -i 's/代码路径/<p\/>代码路径/g' case.html") os.system("sed -i 's/tmp/128.255.125.71/g' case.html") return True return False @add_logs_for_functions def _check_packages_update_status_common(self, mount_path, ci_local_package_path, log_path): """ @summary:检查安装包更新通用方法 :param mount_path:成果管理处自动编译结果挂载点 :param ci_local_package_path:ci服务器上存放更新的包路径 :param log_path:存放日志的路径 :return:有更新返回True,没有更新返回False """ rtn = False latest_number = self.check_packages_is_update(mount_path, log_path) if latest_number: # sas相关操作 if 'sas' in ci_local_package_path: self.execute_command_and_verify_results("rm -rf {0}/*".format(ci_local_package_path)) cp_cmd = 'cp %s/SERVER_%s/*.sh %s;ls -l %s' % (mount_path, str(latest_number), ci_local_package_path, ci_local_package_path) info = self.execute_command_and_verify_results(cp_cmd) if 'sas' in info: with open(log_path, "r+") as fp: print "open {0} and write value {1}".format(log_path, latest_number) fp.seek(0, 2) fp.write(" " + str(latest_number)) rtn = True # v3r2c01操作 else: self.execute_command_and_verify_results("rm -rf {0}/*".format(ci_local_package_path)) # 需要将日期时间戳处理成为目录 number_str = str(latest_number) sub_dir = number_str[:8] + '-' + number_str[8:] cp_all_cmd = 'cp %s/%s/Maipu-AASV4-CMPPortal*.sh %s;ls %s' % (mount_path, sub_dir, ci_local_package_path, ci_local_package_path) cmp_info = self.execute_command_and_verify_results(cp_all_cmd) print cmp_info if 'Maipu' in cmp_info: with open(log_path, "r+") as fp: print "open {0} and write value {1}".format(log_path, latest_number) fp.seek(0, 2) fp.write(" " + str(latest_number)) rtn = True else: print "The latest build number{0} has recorded in installation log, " \ "enter the next loop scanning".format(str(latest_number)) self.sshLib.close_all_connections() return rtn @add_logs_for_functions def check_muti_packages_update(self, check_update_status_arg_list): """ :summary:同时检查多个包的更新状态 :param check_update_status_arg_list:更新包状态参数列表,将多个包检查参数组装成为一个list,每个元素 :为_check_packages_update_status_common方法中参数的一个字典,字典的key分别为mount_path,ci_local_package_path,log_path :如:[{"字典的key分别为mount_path":"xxx","ci_local_package_path":"xxx","log_path":"xxx"}] :return:无返回值,出错抛出异常 """ check_result = False for arg in check_update_status_arg_list: if self._check_packages_update_status_common(arg["mount_path"], arg["ci_local_package_path"], arg["log_path"]): check_result = True continue if not check_result: raise AssertionError(u"未检测到更新的软件包") @add_logs_for_functions def _copy_pacakges_to_target_srever(self, ci_local_package_path, target_server, target_username, target_passwd, target_path): """ :summary: 拷贝软件包到指定路径 :param ci_local_package_path: ci服务器本地存放包的路径 :param target_server: 目标服务器的地址 :param target_username: 目标服务器的用户名 :param target_passwd: 目标服务器的渺茫 :param target_path: 目标服务器的存放包的路径 :return:返回None """ self.ssh_login(target_server, target_username, target_passwd) self.sshLib.set_client_configuration(prompt="#", timeout="10 minute") self.execute_command_and_verify_results("rm -rf {0}/*".format(target_path)) # empty the old package # self.execute_command_and_verify_results("mkdir {0}".format(om_server_package_path)) # empty the old package self._write( "scp -r {0}@{1}:{2}/* {3}".format(self.ci_user, self.ci_addr, ci_local_package_path, target_path)) output = self.sshLib.read(delay="10s") print output if "yes" in output: print "yes/no" self.sshLib.write('yes') print '-------===================----------' time.sleep(2) self.sshLib.write(self.ci_passwd) print self.sshLib.read_until_prompt("DEBUG") elif "assword" in output: print "enter your password" self.sshLib.write(self.ci_passwd) print '------------------------------------' print self.sshLib.read_until_prompt("DEBUG") elif '#' in output[-10:]: print '====================================' else: print '++++++++++++++++++++++++++++++' print self.sshLib.read_until_prompt("DEBUG") print '++++++++++++++++++++++++++++++' self.sshLib.close_all_connections() @add_logs_for_functions def copy_to_muti_target_server(self, copy_package_arg_list): """ :拷贝软件包到多个服务器的指定目录 :param copy_package_arg_list:_copy_pacakges_to_target_srever方法的参数的为元素组成的一个list :return: """ for arg in copy_package_arg_list: if len(arg.keys()) == 5: for key in arg.keys(): if key not in ["ci_local_package_path", "target_server", "target_username", "target_passwd", "target_path"]: raise AssertionError(u"copy_package_arg_list中的参数的key %s 不正确" % str(key)) else: raise AssertionError(u"copy_package_arg_list中的参数的键值对个数不正确") for arg in copy_package_arg_list: self._copy_pacakges_to_target_srever(arg["ci_local_package_path"], arg["target_server"], arg["target_username"], arg["target_passwd"], arg["target_path"]) @add_logs_for_functions def _common_install_param_input(self, install_param): """ :summary:通用安装参数匹配输入方法 :param install_param: 安装参数,为空表示不需要任何手工输入的参数,否则以[("regexp1","input1"),("regexp2","input2")] 这种形式传入参数 :return:无返回,执行出错抛出异常 """ if install_param: for regexp, input_ in install_param: print regexp, input_ print self.sshLib.read_until(regexp) print self.sshLib.write(input_) print self.sshLib.read_until_regexp(".*#$", "DEBUG") else: print self.sshLib.read_until_regexp(".*#$", "DEBUG") @add_logs_for_functions def send_cmd_by_expect(self, cmd_param): """ :summary:根据顺序匹配输入命令 :param cmd_param: 安装参数,为空表示不需要任何手工输入的参数,否则以[("regexp1","input1"),("regexp2","input2")]这种形式传入参数 :return:无返回,执行出错抛出异常 """ if cmd_param: for regexp, input_ in cmd_param: print regexp, input_ print self.sshLib.read_until(regexp) print self.sshLib.write(input_) print self.sshLib.read_until_regexp(".*#$", "DEBUG") else: print self.sshLib.read_until_regexp(".*#$", "DEBUG") @add_logs_for_functions def _install_pkg_common(self, target_server, target_username, target_passwd, pkg_path, app_name, shell_args): """ :summary: 安装包通用方法 :param target_server: 安装包的目标服务器地址 :param target_username: 安装包的目标服务器用户名 :param target_passwd: 安装包的目标服务器的密码 :param pkg_path: 安装包在目标服务器的路径 :param app_name: 组件名称 :return:成功返回True,否则抛出异常 """ self.ssh_login(target_server, target_username, target_passwd) self.sshLib.set_client_configuration(prompt="#", timeout="15 minute") # self.check_command_results("service srvmgt stop") get_package_cmd = "cd {0};chmod 444 *;pwd;ll |grep {1}".format(pkg_path, app_name) self._write(get_package_cmd) output = self.sshLib.read_until_prompt("DEBUG") print output pattern = "(\S+.sh)" m = re.search(pattern, output) if m: pkg_name = m.group(1) install_command = "cd %s;pwd;ls;sh %s %s" % (pkg_path, pkg_name, shell_args) else: raise AssertionError(u"未匹配到正确的安装包") print self.sshLib.write(install_command) info = '' last_info = '' repeat_time = 1 while True: temp = self.sshLib.read(delay='10s') print temp info += temp if 'Confirm install [y/n]?' in info: print self.sshLib.write('y') info = '' continue if 'Confirm install [Y/n]?' in info: print self.sshLib.write('y') info = '' continue if 'Confirm install? [Y/n]' in info: print self.sshLib.write('y') info = '' continue if 'Confirm uninstall old ver [y/n]?' in info: print self.sshLib.write('y') info = '' continue if 'Input setup dest path: [/opt/mpup]' in info: print self.sshLib.write('') info = '' continue if 'Input setup dest path: [/home/mpup/mpup]' in info: print self.sshLib.write('') info = '' continue if 'please confirm enable Maipu Security (y/n)?' in info: print self.sshLib.write('n') info = '' continue if 'Confirm continue [y/n]?' in info: print self.sshLib.write('y') info = '' continue if re.search(':~/\w+ #', info): return True if repeat_time < 150: if last_info == temp: repeat_time += 1 else: repeat_time = 1 last_info = temp else: print info raise AssertionError(u'已经连续150次,1500s相同输出了,please check!') @add_logs_for_functions def install_muti_package(self, install_package_args): """ :批量安装多个安装包 :param install_package_args:安装多个APP的参数列表:列表中每个元素为字典,字典的键为_install_pkg_common方法 :的参数名,如:[{"target_server":"xx","target_user_name":"xx","target_passwd":"x","pkg_path","xx","app":"xx" :"install_param":[install_param]}] :return:无返回值,出错抛出异常 """ for arg in install_package_args: self._install_pkg_common(arg["target_server"], arg["target_username"], arg["target_passwd"], arg["pkg_path"], arg["app_name"], arg["shell_args"]) @add_logs_for_functions def _uninstall_pacakge_common(self, target_server, target_username, target_passwd): """ :summary:卸载安装包通用方法 :param target_server:卸载包的目标服务器地址 :param target_username:卸载包的目标服务器用户名 :param target_passwd:卸载包的目标服务器密码 :return: """ self.ssh_login(target_server, target_username, target_passwd) self.sshLib.set_client_configuration(prompt="#", timeout="20 minute") self._write('/opt/mpup/bin/mpsetup show') output = self.sshLib.read_until_prompt("DEBUG") service_list = output.split('\n') for service in service_list[:-1]: # 会将最后的匹配算进去,这个去除掉 print 'current info is %s' % service m = re.search('\s+(\w+.*?)\s', service) if not m: print "dot not match any sercice" return True print 'service is %s' % m.group(1) if 'MPUP' in m.group(1): continue self._write('/opt/mpup/bin/mpsetup uninstall ' + m.group(1)) # self._write('mpsetup uninstall ' + m.group(1)) output = self.sshLib.read_until_prompt("DEBUG") print output # uninstall mpup mpupcore self._write('/opt/mpup/bin/mpsetup uninstall MPUPCore') # self._write('mpsetup uninstall MPUPCore') output = self.sshLib.read_until_prompt("DEBUG") print output self._write('/opt/mpup/bin/mpsetup uninstall MPUP') # self._write('mpsetup uninstall MPUP') output = self.sshLib.read_until_prompt("DEBUG") print output self.sshLib.close_all_connections() return True @add_logs_for_functions def uninstall_muti_packages(self, pkg_uninstall_arg): """ :批量卸载多个app的通用方法 :param pkg_uninstall_arg:卸载多个APP的卸载参数列表:列表中每个元素为字典,字典的键为_uninstall_pacakge_common方法 :的参数名,如:[{"target_server":"xx","target_user_name":"xx","target_passwd":"x","pkg_path","xx","app":"xx"}] :return:无返回值,出错抛出异常 """ for arg in pkg_uninstall_arg: if len(arg.keys()) == 3: for key in arg.keys(): if key not in ["target_server", "target_username", "target_passwd"]: raise AssertionError(u"pkg_uninstall_arg中的参数的key %s 不正确" % str(key)) else: raise AssertionError(u"pkg_uninstall_arg中的参数的键值对个数不正确") for arg in pkg_uninstall_arg: self._uninstall_pacakge_common(arg["target_server"], arg["target_username"], arg["target_passwd"]) @add_logs_for_functions def use_install_package_uninstall(self, pkg_uninstall_arg): """ 用安装包卸载程序 :param pkg_uninstall_arg: :return: """ for arg in pkg_uninstall_arg: self.ssh_login(arg["target_server"], arg["target_username"], arg["target_passwd"]) self.sshLib.set_client_configuration(prompt="#", timeout="15 minute") self.sshLib.execute_command('service srvmgt stop') get_package_cmd = "cd {0};chmod 444 *;pwd;ll |grep {1}".format(arg["pkg_path"], arg["app_name"]) self._write(get_package_cmd) output = self.sshLib.read_until_prompt("DEBUG") print output pattern = "(\S+.sh)" m = re.search(pattern, output) if m: pkg_name = m.group(1) uninstall_command = "cd %s;pwd;ls;sh %s uninstall" % (arg["pkg_path"], pkg_name) else: raise AssertionError(u"未匹配到正确的安装包") print self.sshLib.write(uninstall_command) info = '' last_info = '' repeat_time = 1 while True: temp = self.sshLib.read(delay='10s') print temp info += temp if 'Confirm uninstall all installed files and datas [y/n]?' in info: print self.sshLib.write('y') info = '' continue # 匹配结束 if re.search(':~/\w+ #', info): break # 匹配长期暂停 if repeat_time < 100: if last_info == temp: repeat_time += 1 else: repeat_time = 1 last_info = temp else: print info raise AssertionError(u'已经连续100次,1000s相同输出了,please check!') @add_logs_and_check_result def init_system(self, target_server, target_username, target_passwd, init_command_dict_list): """ 初始化系统 :param target_server:服务器地址 :param target_username:用户 :param target_passwd:密码 :param init_command_dict_list:初始化参数字典列表 :return:True/False """ self.ssh_login(target_server, target_username, target_passwd) self.sshLib.set_client_configuration(prompt="#", timeout="10 minute") self._write('service srvmgt init') info = '' last_info = '' repeat_time = 1 while True: temp = self.sshLib.read(delay='10s') print temp info += temp for command_dict in init_command_dict_list: if command_dict[0] in info: print self.sshLib.write(command_dict[1]) init_command_dict_list.remove(command_dict) info = '' break else: # 这里是运行结束 if re.search(':~.*?#', info): return True # 这里判断重复次数 if repeat_time < 40: if last_info == temp: repeat_time += 1 else: repeat_time = 1 last_info = temp else: print info print u'已经连续40次,400s相同输出了,please check!' return False @add_logs_and_check_result def check_file_is_change(self, file_path, limit_time): """ 判断目标文件是否在限制时间内有更改 :param file_path:目标文件 :param limit_time:限制时间,秒为单位,一个小时为3600秒 :return: """ self.ssh_login(self.ci_addr, self.ci_user, self.ci_passwd) output = self.execute_command_and_verify_results('stat -c %Y ' + file_path + """ |awk '{printf $0" "; system("date +%s")}'|awk '{print $2-$1}'""") if int(output) > int(limit_time): return False return True
''' Created on 21-Jul-2015 @author: radhika.goel ''' from robot.libraries.BuiltIn import BuiltIn from SSHLibrary import SSHLibrary from robot.api import logger import re robo = BuiltIn() ssh = SSHLibrary() NameNodeIp = "192.168.162.194" ssh.open_connection(NameNodeIp, timeout="1 hour") ssh.login("root","root@123") ssh.set_client_configuration(prompt=">") ssh.write("",loglevel="DEBUG") #If not use , return nothing #line = ssh.read() #print line #ssh.write("en",loglevel="DEBUG") ssh.set_client_configuration(prompt="#") #IF we not set , can't read upto that prompt line = ssh.read_until_prompt(loglevel="DEBUG") ssh.set_client_configuration(prompt="$") ssh.write("su reflex",loglevel="DEBUG") line = ssh.read_until_prompt(loglevel="DEBUG") print line #ssh.write("cli -m config",loglevel="DEBUG") #line = ssh.read_until_prompt(loglevel="DEBUG") #print "cdscmv",line #line - [reflex@RPM-DN-105 root]$
class LogGrabber(object): """ Получение логов подсистем с удаленных серверов. \n Принцип работы: - перед началом теста происходит подсчет количества строк в логах - после окончания теста, если количество строк изменилось, то будут скачены только добавленные в лог строки. Для работы библиотеки необходимо cоздать переменную server_logs в python [http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-variables-directly|variable file] следующего вида: | server_logs = { | "tmpdir": "/tmp/", | "servers": [ | { | "hostname": "server.com", | "port": 22, | "username": "******", | "password": "******", | "subsystems": [ | { | "name": "Apache_server", | "logs": [ | { | "path_to_log": "/var/log", | "log_name": "access.log" | }, | { | "path_to_log": "/var/log", | "log_name": "error*.log" | } | ] | } | ] | } | ] | } Где: - tmpdir - каталог для временных файлов на удаленном сервере - hostname - имя хоста удаленного сервера - port - порт подключения по ssh - username\password - логин\пароль для подключения по ssh - name - имя подсистемы, для которой собираются логи, должно быть уникальным - path_to_log - путь к логам подсистемы - log_name - имя файла лога; могут использоваться wildcards аналогичные тем, что применяются в linux-команде find. === Ограничения === Логи подсистем должны находится на Linux сервере с возможностью подключения к нему по ssh. === Использование === 1. В качестве [http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-listener-interface|listener]:\n ``pybot --listener LogGrabber /path/to/test_suite``\n При этом нет необходимости изменять тесты. После завершения теста со статусом FAILED будет скачена лишь та часть логов, которая была записана во время его проходжения. 2. В качестве библиотеки:\n В этом случае можно скачивать логи вне зависимости от статуса теста | *** Settings *** | Documentation Пример | Library LogGrabber | Variables variables.py | Suite Setup SuiteSetup | Suite Teardown SuiteTeardown | | *** Test Cases *** | Fail_test | FAIL fail message | | Passed_test | Pass Execution passed message | | | *** Keywords *** | SuiteSetup | LogGrabber.Set connections | LogGrabber.Prepare logs | | | SuiteTeardown | LogGrabber.Download logs | LogGrabber.Close connections === Зависимости === | robot framework | http://robotframework.org | | AdvancedLogging | http://git.billing.ru/cgit/PS_RF.git/tree/library/AdvancedLogging.py | | SSHLibrary | http://robotframework.org/SSHLibrary/latest/SSHLibrary.html | """ ROBOT_LIBRARY_SCOPE = 'GLOBAL' ROBOT_LISTENER_API_VERSION = 2 def __init__(self): # загрузка встроенных библиотек self.bi=BuiltIn() self.ssh=SSHLibrary() self.adv_log=AdvancedLogging() # словарь с подготовленными логами self.prepared_logs = dict() def start_suite(self, name, attrs): self.set_connections() def start_test(self, name, attrs): self.prepare_logs() def end_test(self, name, attrs): if attrs['status'] != 'PASS': self.download_logs() def end_suite(self, name, attrs): self.close_connections() def set_connections(self): """ SSH-соединение с удаленными серверами """ # Получаем информацию о логах подсистем self.logs=self.bi.get_variable_value('${server_logs}') # Системный разделитель для платформы запуска тестов self.sys_separator=self.bi.get_variable_value('${/}') # Разделитель в unix self.nix_separator = '/' # перебираем сервера из словаря настройки # для каждого сервера создаем одтельное ssh-соединение, # которое будет жить в течение всего suite # дописываем alias в словарь для каждого сервера for _, server in enumerate(self.logs["servers"]): hostname = server["hostname"] port = server["port"] username = server["username"] password = server["password"] ssh_alias = str(self.bi.get_time('epoch')) # создаем ssh-соединение - alias = epoch timestamp self.ssh.open_connection(hostname, ssh_alias, port) self.ssh.login(username, password) server["ssh_alias"] = ssh_alias def prepare_logs(self): """ Подготовка логов. В результате для каждого лога, удовлетворяющего настройке, записывается номер послнедней строки. """ # структура с описанием серверов, подсистем и логов self.prepared_logs["servers"] = [] # перебираем сервера из конфигурации for server in self.logs["servers"]: processed_server = dict() hostname = server["hostname"] port = server["port"] username = server["username"] password = server["password"] ssh_alias = server["ssh_alias"] # заполняем словарь, описывающий обработанный сервер processed_server["hostname"] = hostname processed_server["port"] = port processed_server["username"] = username processed_server["password"] = password processed_server["ssh_alias"] = ssh_alias processed_server["subsystems"] = [] # переключаемся на соединение с alias = ssh_alias из словаря настройки self.ssh.switch_connection(ssh_alias) # для каждого сервера обрабатываем набор подсистем for subsystem in server["subsystems"]: # словарь обработанных подсистем processed_subsys = dict() processed_subsys["name"] = subsystem["name"] # список обработанных логов processed_logs = [] # обрабатываем логи для текущей подсистемы for subsys_log in subsystem["logs"]: path_to_log = subsys_log["path_to_log"] log_name_regexp = subsys_log["log_name"] # получаем список лог-файлов по regexp log_name_list_text = self.ssh.execute_command("find {}{}{} -printf '%f\n'".format(path_to_log, self.nix_separator, log_name_regexp), True, True, True) # если список не пуст и код возврата команды 0 (success) if ((len(log_name_list_text[0]) > 0) & (log_name_list_text[2] == 0) ): # формируем массив имен лог-файлов log_name_array = string.split(log_name_list_text[0], '\n') # для каждого файла получаем номер последней строки for log_name in log_name_array: line_number = self.ssh.execute_command("cat {}{}{} | wc -l".format(path_to_log, self.nix_separator, log_name)) processed_logs.append({"path_to_log": path_to_log, "log_name": log_name, "line_number": line_number}) # проверка для исключения "мусора" processed_subsys if (len(processed_logs)>0): processed_subsys["logs"] = processed_logs processed_server["subsystems"].append(processed_subsys) # проверка - есть ли для сервера обработанные подсистемы с логами if (len(processed_server["subsystems"])>0): self.prepared_logs["servers"].append(processed_server) def download_logs(self): """ Формирование и загрузка логов. В результате в директории теста, созданной AdvancedLogging, получаем архив с логами [TIMESTAMP]_logs.zip """ timestamp = self.bi.get_time('epoch') # базовая директория теста base_dir = self.adv_log.Create_Advanced_Logdir() # имя результирующего архива с логами res_arc_name = os.path.join(base_dir, "{}_logs".format(timestamp)) # результирующая директория для логов logs_dir = os.path.join(base_dir, "logs") # временная директория на целевом сервере temp_dir = self.logs['tmpdir'] # обрабатыаем сервера, с подготовленными логами for server in self.prepared_logs["servers"]: # параметры подключения к серверу ssh_alias = server["ssh_alias"] # переключаемся на соединение с alias = ssh_alias из словаря self.ssh.switch_connection(ssh_alias) # обрабатываем подсистемы с подготовленными логами for subsystem in server["subsystems"]: # структура в которую скачиваются логи [Advanced_Logdir]/logs/<подсистема>/ subsys_dir = os.path.join(logs_dir, subsystem["name"]) for log in subsystem["logs"]: abs_log_name = "{}{}{}".format(log["path_to_log"], self.nix_separator, log["log_name"]) # имя файла содержащего интересующую нас часть, лога cut_log_name = "{}_{}".format(timestamp, log["log_name"]) # абсолютный пусть с именем файла (cut_[имя_лога]) - для интересующего нас куска лога cut_abs_log_name = "{}{}{}".format(temp_dir, self.nix_separator, cut_log_name) # текущий номер строки в логе cur_line_number = self.ssh.execute_command("cat {} | wc -l".format(abs_log_name)) # проверяем, появились ли строки в логе с момента подготовки логов if (cur_line_number > log["line_number"]): # вырезаем часть лога, начиная с сохраненного номера строки self.ssh.execute_command("tail -n +{} {} > {}".format(log["line_number"], abs_log_name, cut_abs_log_name)) # gzip self.ssh.execute_command("gzip {}.gz {}".format(cut_abs_log_name, cut_abs_log_name)) # скачиваем файл self.ssh.get_file("{}.gz".format(cut_abs_log_name), "{}{}{}.gz".format(subsys_dir, self.sys_separator, cut_log_name)) # удаляем вырезанную чыасть лога и gz-архив этой части self.ssh.execute_command("rm {}".format(cut_abs_log_name)) self.ssh.execute_command("rm {}.gz".format(cut_abs_log_name )) # если есть результат - упаковываем в единый zip-архив и удаляем папку с логами if (os.path.exists(logs_dir)): self._zip(logs_dir, res_arc_name) shutil.rmtree(logs_dir) def close_connections(self): """ Закрытие ssh-соединений с удаленными серверами """ self.ssh.close_all_connections() def _zip(self, src, dst): """ Упаковка логов единый zip-архив *Args:*\n _src_ - директория для упаковки _dst_ - имя лога """ zf = zipfile.ZipFile("%s.zip" % (dst), "w", zipfile.ZIP_DEFLATED) abs_src = os.path.abspath(src) for root, _, files in os.walk(src): for filename in files: abs_name = os.path.abspath(os.path.join(root, filename)) arc_name = abs_name[len(abs_src) + 1:] zf.write(abs_name, arc_name) zf.close()
''' Created on 21-Jul-2015 @author: radhika.goel ''' from robot.libraries.BuiltIn import BuiltIn from SSHLibrary import SSHLibrary from robot.api import logger import re robo = BuiltIn() ssh = SSHLibrary() NameNodeIp = "192.168.162.130" ssh.open_connection(NameNodeIp, timeout="1 hour") ssh.login("admin","admin@123") ssh.set_client_configuration(prompt=">") ssh.write("",loglevel="DEBUG") #If not use , return nothing line = ssh.read() ssh.write("en",loglevel="DEBUG") ssh.set_client_configuration(prompt="#") #IF we not set , can't read upto that prompt ssh.write("conf t",loglevel="DEBUG") line = ssh.read_until_prompt(loglevel="DEBUG") ssh.write("_shell",loglevel="DEBUG") line = ssh.read_until_prompt(loglevel="DEBUG") m1 = re.search("^(?P<shellPrompt>\[\S+@\S+\s+\S+\]\s*#)\s*",line.strip(),re.MULTILINE) if m1: shellPrompt = m1.group("shellPrompt") print shellPrompt
### Required dependency ### # robotframework-sshlibrary from SSHLibrary import SSHLibrary import time import os, subprocess ssh = SSHLibrary() ssh.open_connection("10.156.4.65") username = input("Username: "******"Password: "******"\033c") ssh.login(username, password) def restartNetAdapter(): p = subprocess.Popen( 'powershell.exe Invoke-Command -Computername JJ-PSRV1 -ScriptBlock {Restart-NetAdapter -Name "Ethernet0"}' ) time.sleep(7) p.terminate() #The loop while True: PSRV1 = ssh.execute_command("vim-cmd vmsvc/power.getstate 20", return_stdout=True) PSRV2 = ssh.execute_command("vim-cmd vmsvc/power.getstate 24", return_stdout=True) time.sleep(2) print("\033c") if "Powered on" in PSRV1:
class FusionLibrary( FusionAPIKeywords, FusionAPIKeywords.ActiveUserSessionsKeywords, FusionAPIKeywords.AlertKeywords, FusionAPIKeywords.AuditLogKeywords, FusionAPIKeywords.AuthorizationsKeywords, FusionAPIKeywords.ApplianceDeviceReadCommunityKeywords, FusionAPIKeywords.ApplianceEulaKeywords, FusionAPIKeywords.ApplianceFactoryResetKeywords, FusionAPIKeywords.ApplianceFirmwareKeywords, FusionAPIKeywords.ApplianceHealthStatusKeywords, FusionAPIKeywords.ApplianceNetworkInterfacesKeywords, FusionAPIKeywords.ApplianceNodeInformationKeywords, FusionAPIKeywords.ApplianceShutdownKeywords, FusionAPIKeywords.ApplianceStateKeywords, FusionAPIKeywords.ApplianceSupportDumpKeywords, FusionAPIKeywords.ApplianceTimeAndLocaleConfigurationKeywords, FusionAPIKeywords.ApplianceTrapDestinationKeywords, FusionAPIKeywords.ApplianceSnmpv3TrapDestinationKeywords, FusionAPIKeywords.ApplianceSnmpv3TrapForwardingUserKeywords, FusionAPIKeywords.ApplianceUpgrade, FusionAPIKeywords.BackupKeywords, FusionAPIKeywords.CertificateAuthorityKeywords, FusionAPIKeywords.CertificateValidationConfigurationKeywords, FusionAPIKeywords.CertificateClientRabbitMqKeywords, FusionAPIKeywords.ClientCertificateKeywords, FusionAPIKeywords.ConnectionsKeywords, FusionAPIKeywords.ConnectionTemplateKeywords, FusionAPIKeywords.DatacenterKeywords, FusionAPIKeywords.DeviceManagerKeywords, FusionAPIKeywords.DeploymentManagerKeywords, FusionAPIKeywords.DriveEnclosureKeywords, FusionAPIKeywords.DomainsKeywords, FusionAPIKeywords.EmailNotificationKeywords, FusionAPIKeywords.EnclosureKeywords, FusionAPIKeywords.RackManagerKeywords, FusionAPIKeywords.EnclosureGroupKeywords, FusionAPIKeywords.EthernetNetworkKeywords, FusionAPIKeywords.EventKeywords, FusionAPIKeywords.FabricKeywords, FusionAPIKeywords.FabricManagerKeywords, FusionAPIKeywords.FcNetworkKeywords, FusionAPIKeywords.FcoeNetworkKeywords, FusionAPIKeywords.FirmwareBundleKeywords, FusionAPIKeywords.FirmwareDriverKeywords, FusionAPIKeywords.GlobalSettingsKeywords, FusionAPIKeywords.HaNodesKeywords, FusionAPIKeywords.HypervisorManagerKeywords, FusionAPIKeywords.HypervisorClusterProfileKeywords, FusionAPIKeywords.HypervisorHostProfileKeywords, FusionAPIKeywords.HypervisorHostKeywords, FusionAPIKeywords.HypervisorClustersKeywords, FusionAPIKeywords.IdPoolKeywords, FusionAPIKeywords.IdPoolsIpv4RangeKeywords, FusionAPIKeywords.IdPoolsIpv4SubnetKeywords, FusionAPIKeywords.IdPoolsVmacRangeKeywords, FusionAPIKeywords.IdPoolsVsnRangeKeywords, FusionAPIKeywords.IdPoolsVwwnRangeKeywords, FusionAPIKeywords.IndexAssociationKeywords, # FusionAPIKeywords.IndexResourceKeywords, FusionAPIKeywords.IndexResourceKeywords, # FusionAPIKeywords.IndexSearchSuggestionKeywords, # FusionAPIKeywords.IndexTreeKeywords, FusionAPIKeywords.InterconnectLinkTopologyKeywords, FusionAPIKeywords.InterconnectKeywords, FusionAPIKeywords.InterconnectTypesKeywords, FusionAPIKeywords.InternalLinkSetKeywords, # FusionAPIKeywords.LabelKeywords, FusionAPIKeywords.LicensesKeywords, FusionAPIKeywords.SecurityStandardsKeywords, FusionAPIKeywords.LoginDetailsKeywords, FusionAPIKeywords.LoginDomainKeywords, FusionAPIKeywords.LogicalDownlinkKeywords, FusionAPIKeywords.LoginDomainsGlobalSettingsKeywords, FusionAPIKeywords.LoginDomainsLoginCertificatesKeywords, FusionAPIKeywords.LoginDomainsGroupToRoleMappingKeywords, FusionAPIKeywords.LoginSessionKeywords, FusionAPIKeywords.LogicalInterconnectKeywords, FusionAPIKeywords.LogicalInterconnectGroupKeywords, FusionAPIKeywords.LogicalSwitchGroupKeywords, FusionAPIKeywords.LogicalSwitchKeywords, FusionAPIKeywords.LogicalEnclosureKeywords, FusionAPIKeywords.ManagedSanKeywords, FusionAPIKeywords.MetricStreamingKeywords, FusionAPIKeywords.NetworkSetKeywords, FusionAPIKeywords.MigratableVcDomainKeywords, FusionAPIKeywords.PingKeywords, FusionAPIKeywords.PowerDeviceKeywords, FusionAPIKeywords.ProviderKeywords, FusionAPIKeywords.RackKeywords, FusionAPIKeywords.RemoteSyslogKeywords, FusionAPIKeywords.RemoteSupportKeywords, FusionAPIKeywords.ConfigurationKeywords, FusionAPIKeywords.ReportKeywords, FusionAPIKeywords.RestoreKeywords, FusionAPIKeywords.RolesKeywords, FusionAPIKeywords.SasInterconnectsKeywords, FusionAPIKeywords.SasInterconnectTypesKeywords, FusionAPIKeywords.SasLogicalInterconnectGroupKeywords, FusionAPIKeywords.SasLogicalInterconnectKeywords, FusionAPIKeywords.ServerHardwareTypesKeywords, FusionAPIKeywords.ServerHardwareKeywords, FusionAPIKeywords.ServerProfileKeywords, FusionAPIKeywords.ServerProfileTemplateKeywords, FusionAPIKeywords.ServiceAccessKeywords, FusionAPIKeywords.SessionsKeywords, FusionAPIKeywords.StartupProgressKeywords, FusionAPIKeywords.StoragePoolKeywords, FusionAPIKeywords.StorageSystemKeywords, FusionAPIKeywords.StorageVolumeKeywords, FusionAPIKeywords.StorageVolumeTemplateKeywords, FusionAPIKeywords.StorageVolumeAttachmentKeywords, FusionAPIKeywords.SwitchKeywords, FusionAPIKeywords.SwitchTypesKeywords, FusionAPIKeywords.TaskKeywords, FusionAPIKeywords.UplinkSetKeywords, FusionAPIKeywords.UserKeywords, FusionAPIKeywords.VersionKeywords, FusionAPIKeywords.SasLogicalJbodsKeywords, FusionAPIKeywords.SasLogicalJbodAttachmentsKeywords, FusionAPIKeywords.WebServerCertificateKeywords, FusionAPIKeywords.HalAPIKeywords, FusionAPIKeywords.PermAPIKeywords, FusionAPIKeywords.ProxyServerKeywords, FusionAPIKeywords.IPKeywords, FusionAPIKeywords.ScopeKeywords, FusionAPIKeywords.RepositoryKeywords, FusionAPIKeywords.SshAccessKeywords, FusionAPIKeywords.ApplianceCertificateKeywords, FusionAPIKeywords.RemoteCertificateKeywords, FusionAPIKeywords.ServerCertificateKeywords, FusionAPIKeywords.CertificateStatusKeywords, FusionUIKeywords, MantraUIKeywords, FusionSRMOaApiKeywords, FusionSRMIloApiKeywords, FusionSanmanagerUIKeywords, FusionSanUIKeywords, DCSAPIKeywords, FusionPMSanUiKeywords, HellfireAPIKeywords.InfrastructureVmsKeywords, HellfireAPIKeywords.StoreVirtualVsaClusterKeywords, OACLIKeywords, FusionCLIKeywords, HellfireAPIKeywords, SVMCAPIKeywords, TrafficLibraryKeywords, TrafficLibraryKeywords.VspLibraryKeywords, TrafficLibraryKeywords.PingTrafficLibraryKeywords, TrafficLibraryKeywords.IPerfTrafficLibraryKeywords, TrafficLibraryKeywords.IOMeterLibraryKeywords, FusionAPIKeywords.OSDeploymentServerKeywords, TRUKeywords, CptPayloadGenerator, NetworkConfigGenerator): """ Main FusionLibrary keyword class definition """ ROBOT_LIBRARY_SCOPE = 'GLOBAL' ROBOT_LIBRARY_VERSION = __version__ ROBOT_LISTENER_API_VERSION = 2 FILTER_LIBRARIES = ['BuiltIn', 'Collections', 'Dialogs', 'OperatingSystem', 'SSHLibrary', 'String', 'XML'] MAX_QUEUE = 1000 # max elk data queue size # Elk data encapsulation object ElkItem = namedtuple("ElkItem", "obj_type, data") def _gather_repo_info(self): """ Private method to initialize variables pertaining to Test repository :return: None """ try: # Invalid error would be thrown if path is not source_root repo = Repo(os.path.dirname(THIS_DIR)) self.repo_commit = str(repo.rev_parse('HEAD')) self.repo_branch_name = repo.git.rev_parse('--abbrev-ref', '--symbolic-full-name', '@{u}') del repo except: # noqa pass def __init__(self): self.ROBOT_LIBRARY_LISTENER = self self.elk_queue_writer = None self.hostname = socket.gethostname() self.uuid = str(uuid.uuid1()) self._ov = None self._ssh = None self.activity_queue = None self.log_activity = False self.log_activity_to_cidebug_log = False self.queue_writer = None self.repo_commit = 'Not Found' self.repo_branch_name = 'Not identified' self._gather_repo_info() logger._log_to_console_and_log_file("Fusion library version %s" % __version__) for base in FusionLibrary.__bases__: base.__init__(self) def __logging_activity(self): """ This private method handles writing to the ElkWriter thread if logging is enabled. Note: log activity with -v LOG_ACTIVITY:True """ # initialize and start the activity logging queue self.log_activity = BuiltIn().get_variable_value("${LOG_ACTIVITY}") if self.log_activity == 'False': return False # initialize queue and queue writer if not self.activity_queue: self.activity_queue = Queue(maxsize=self.MAX_QUEUE) if not self.queue_writer: host = BuiltIn().get_variable_value("${ACTIVITY_LOGGING_SERVER}") index = BuiltIn().get_variable_value("${ACTIVITY_INDEX_NAME}") if not host: host = DEFAULT_ACTIVITY_LOGGING_SERVER if not index: index = DEFAULT_ACTIVITY_INDEX_NAME self.queue_writer = ElkQueueWriter(host, index, self.activity_queue) self.queue_writer.start() return True def __logging_activity_to_cidebug_log(self): """ This private method handles writing to the /ci/logs/ciDebug.log file on the appliance if logging is enabled. Note: log activity with -v LOG_ACTIVITY_TO_CIDEBUG:True """ # initialize and start the activity logging queue self.log_activity_to_cidebug_log = BuiltIn().get_variable_value("${LOG_ACTIVITY_TO_CIDEBUG}") if not self.log_activity_to_cidebug_log: return False # get the appliance host and open ssh session if not self._ov: self._ov = _get_host_variable() if not self._ssh: self.__create_ssh_connection_and_login(self._ov) return True def __create_ssh_connection_and_login(self, host, username='******', password='******'): """ Create a new SSH connection and log in """ try: self._ssh = SSHLibrary() self._ssh.set_default_configuration(timeout='15 seconds', term_type='xterm', prompt='#') self._ssh.open_connection(host) self._ssh.login(username, password) except: # noqa e = sys.exc_info()[0] logger._log_to_console_and_log_file("unable to connect ssh: {} {}".format(host, e)) self._ssh = None def __run_ssh_commands(self, cmds): """ Run an SSH command """ if self._ssh is not None: if self._ssh.get_connection(host=True) is not None: try: self._ssh.write(cmds) except: # noqa e = sys.exc_info()[0] logger._log_to_console_and_log_file("unable to write to ssh: {} {}".format(cmds, e)) self._ssh.close_connection() self._ssh = None else: logger.info("no ssh: session {}".format(cmds)) self._ssh.close_connection() self._ssh = None def _write_log(self, ltype, stat, attrs): """ Write a log entry """ name = None if 'longname' in attrs: name = attrs['longname'] elif 'kwname' in attrs: name = attrs['kwname'] return """date +"%Y-%m-%d %H:%M:%S.%N %Z,INFO,ROBO,{},{},{},{}" >> /ci/logs/ciDebug.log""".format(self.uuid, ltype.upper(), name, stat.upper()) def _add_data_to_attrs(self, name, attrs): """ Add additional data to suite/test/keyword attributes for Elk logging. """ metadata = BuiltIn().get_variable_value("&{SUITE METADATA}") if not self._ov: self._ov = _get_host_variable() if 'kwname' in attrs: attrs['name'] = attrs['kwname'] del attrs['kwname'] else: attrs['name'] = name attrs['suiteName'] = BuiltIn().get_variable_value("${SUITE_NAME)") attrs['suiteSource'] = BuiltIn().get_variable_value("${SUITE_SOURCE)") attrs['testName'] = BuiltIn().get_variable_value("${TEST_NAME)") attrs['oneViewIp'] = self._ov attrs['oneViewVersion'] = metadata.get("OneView Version") if 'starttime' in attrs: attrs['starttime'] = parse_date(attrs['starttime']).replace(tzinfo=tz.tzlocal()).astimezone(tz.tzutc()).isoformat() if 'endtime' in attrs: attrs['endtime'] = parse_date(attrs['endtime']).replace(tzinfo=tz.tzlocal()).astimezone(tz.tzutc()).isoformat() attrs['@timestamp'] = attrs.get('starttime') attrs['hostname'] = self.hostname attrs['runId'] = self.uuid attrs['gitCommitId'] = self.repo_commit attrs['gitRemoteBranch'] = self.repo_branch_name return attrs def _start_suite(self, name, attrs): # pylint: disable=unused-argument """ This listener logs suite start """ if self.__logging_activity_to_cidebug_log(): self.__run_ssh_commands(self._write_log('suite', 'started', attrs)) BuiltIn().set_global_variable("${RUN_UUID}", self.uuid) def _end_suite(self, name, attrs): # pylint: disable=unused-argument """ This listener logs suite activity """ if self.__logging_activity_to_cidebug_log(): self.__run_ssh_commands(self._write_log('suite', 'ended', attrs)) self._ssh.close_connection() if self.__logging_activity(): # If the queue is full, don't write anything (since queue.put blocks, it would halt the test). # Otherwise, write the name and attrs to Elk if not self.activity_queue.full(): self.activity_queue.put_nowait(self.ElkItem('suite', self._add_data_to_attrs(name, attrs))) if attrs.get('id') == 's1': # In order to process all queue items before the test suite exits, # it's necessary to wait for the queue to become empty or until the timer expires. # Otherwise, the test will exit before the queue is fully written. start = datetime.datetime.now() while not self.activity_queue.empty() and (datetime.datetime.now() - start).total_seconds() < 10.0: sleep(1) def _start_test(self, name, attrs): # pylint: disable=unused-argument """ This listener logs test activity """ if self.__logging_activity_to_cidebug_log(): self.__run_ssh_commands(self._write_log('test case', 'started', attrs)) def _end_test(self, name, attrs): """ This listener logs test activity """ if self.__logging_activity_to_cidebug_log(): self.__run_ssh_commands(self._write_log('test case', 'ended', attrs)) # If the queue is full, don't write anything (since queue.put blocks, it would halt the test). # Otherwise, write the name and attrs to Elk if self.__logging_activity() and not self.activity_queue.full(): self.activity_queue.put_nowait(self.ElkItem('test', self._add_data_to_attrs(name, attrs))) def _start_keyword(self, name, attrs): # pylint: disable=unused-argument """ This listener logs keyword activity """ if self.__logging_activity_to_cidebug_log(): # filter out libraries and keyword types we're not interested in if attrs.get('libname') not in self.FILTER_LIBRARIES and attrs.get('type') not in ['For', 'For Item']: self.__run_ssh_commands(self._write_log('keyword', 'started', attrs)) def _end_keyword(self, name, attrs): """ This listener logs keyword activity """ if self.__logging_activity_to_cidebug_log(): # filter out libraries and keyword types we're not interested in if attrs.get('libname') not in self.FILTER_LIBRARIES and attrs.get('type') not in ['For', 'For Item']: self.__run_ssh_commands(self._write_log('keyword', 'ended', attrs)) if self.__logging_activity(): # filter out libraries and keyword types we're not interested in if attrs.get('libname') not in self.FILTER_LIBRARIES and attrs.get('type') not in ['For', 'For Item']: if not self.activity_queue.full(): self.activity_queue.put_nowait(self.ElkItem('keyword', self._add_data_to_attrs(name, attrs)))
class PublicKeywords(PublicLocators, PublicData, PublicUIInfo, Selenium2Library): def __init__(self): super(PublicKeywords, self).__init__(timeout=10) self.blt = BuiltIn() # self.s2l = self.get_library_instance("Selenium2Library") # self.ssh = self.blt.get_library_instance("SSHLibrary") self.ssh = SSHLibrary() def print_info(self, msg, html=True): """ print info on log file and console. :param msg: print message :param html: "True" Print information in html format """ msg = "<span class='label info'>" + msg + "</span>" logger.info(msg, html=html) def print_error(self, msg, html=True): """ print error on log file and console. :param msg: print message :param html: "True" Print information in html format """ msg = "<span class='label fail'>" + msg + "</span>" logger.error(msg, html=html) def open_center_web(self, ip, browser, protocol="https"): """ Enter the vTop Center IP in the new browser and wait for the login button to be visible. """ web_addr = "%s://%s/" % (protocol, ip) self.print_info("open vTop Center on the new browser") self.open_browser(web_addr, browser=browser) self.maximize_browser_window() self.print_info("Wait for the login button to be visible") err_msg = "The login button is not visible!(%s)" % self.LOGIN_BUTTON_ID self.wait_until_element_is_visible(self.LOGIN_BUTTON_ID, error=err_msg) def input_element_txt(self, locator, text): """ Enter the text into the element input box. """ self.print_info("wait for the input box to be visible") err_msg = "The input box not visible!(%s)" % locator self.wait_until_element_is_visible(locator, error=err_msg) self.print_info("clear input box and input %s" % text) self.clear_element_text(locator) self.input_text(locator, text) self.blt.sleep(self.INPUT_SLEEP) def click_center_element(self, locator, sleep_status=True): """ Click the vTop Center UI element. :param locator: vTopCenter element locator. :param sleep_status: Whether to sleep after the click."False" not sleep. """ self.print_info("wait for the click element to be visible") err_msg = "The click elemnt not visible!(%s)" % locator self.wait_until_element_is_visible(locator, error=err_msg) self.click_element(locator) if sleep_status: self.blt.sleep(self.CLICK_SLEEP) def verify_element_title_attribute(self, locator, title): """ Verify the element title attribute value. """ self.print_info("wait for the element '%s' to be visible" % locator) err_msg = "The element '%s' not visible!()" % locator self.wait_until_element_is_visible(locator, error=err_msg) self.print_info("Get the title attribute and verify it(%s)" % locator) ui_title = self.get_element_attribute("%s@title" % locator) title = title.decode("utf8") if ui_title != title: self.capture_page_screenshot() err_msg = "The verification title '%s' is not equal to the actual title '%s'" % ( title, ui_title) raise ValueError(err_msg) else: self.print_info("The title attribute verify successful") def verify_element_text(self, locator, text): """ Verify the value within the element tag. """ self.print_info("verify the element '%s' text" % locator) err_msg = "The element '%s' not visible!" % locator self.wait_until_element_is_visible(locator, error=err_msg) ui_text = self.get_text(locator) ui_text.strip() text = text.decode("utf8") if ui_text != text: self.capture_page_screenshot() err_msg = "The verification text '%s' is not equal to the actual text '%s'" % ( text, ui_text) raise ValueError(err_msg) else: self.print_info("The element '%s' text verify successful" % locator) def verify_login_successful(self, user=None, real_name=None): """ Verify that the user is logged in vTop Center is successful. The default user is admin,the real name is 管理员. """ self.print_info("verify %s login successful" % user) err_msg = "login button must be not visible,but it's visible!" self.wait_until_element_is_not_visible(self.LOGIN_BUTTON_ID, error=err_msg) self.print_info("wait for the loading img not visible") err_msg = "loading img is visible" self.wait_until_element_is_not_visible(self.LOADING_DIV_ID, error=err_msg) self.wait_until_element_is_not_visible(self.LOADING_IMG_ID, error=err_msg) if not user: user = self.CENTER_ADMIN_NAME if user == self.CENTER_ADMIN_NAME: real_name = self.CENTER_ADMIN_REAL_NAME self.print_info("verify navbar info") if real_name: self.verify_element_title_attribute(self.NAVBAR_WELCOME_INFO_ID, real_name) text = self.NAVBAR_WELCOME_LABEL + "\n" + user self.verify_element_text(self.NAVBAR_WELCOME_INFO_ID, text) err_msg = "navbar must be visible,but it is not visible!" self.wait_until_element_is_visible(self.NAVBAR_UI_ID, error=err_msg) def login_center_web(self, user="******", password="******", ip=None, browser=None): """ User login vTop Center. Default user is admin,and default ip is the test vtop center. """ self.print_info("login management center web by %s" % user) if not ip: ip = self.CENTER_IP if not browser: browser = self.TEST_BROWSER self.open_center_web(ip, browser=browser) self.print_info("input user and password,then click login button") self.input_element_txt(self.LOGIN_USER_INPUT_ID, user) self.input_element_txt(self.LOGIN_PASSWORD_INPUT_ID, password) self.click_center_element(self.LOGIN_BUTTON_ID) self.print_info("Verify login successful") self.verify_login_successful() def refresh_center_page(self, times=3): """ refresh vTop Center page,Equivalent to F5 refresh. :param times: When the loaded image is always visible,refresh times. :return: None """ self.print_info("refresh management center web page(F5)") i = 0 while i <= int(times): i += 1 self.reload_page() self.print_info("wait loading images not visible") status_div = self.wait_until_element_is_not_visible( self.LOADING_DIV_ID, timeout=5) if status_div is not None: continue status_img = self.wait_until_element_is_not_visible( self.LOADING_IMG_ID, timeout=5) if status_img is not None: continue status_click = self.click_element(self.HOME_MANAGE_TAB_ID) if status_click is None: break def choose_upload_file(self, file_path): """ Choose upload file on local :param file_path: the file path. """ self.print_info("choose vTop Center ISO:%s" % file_path) self.choose_file(self.UPLOAD_FILE_CHOOSE_ID, file_path=file_path) def wait_until_upload_file_success(self, timeout=600): """ Wait until upload file success. :param timeout: wait the file upload success timeout. """ self.print_info("wait until file upload success") self.wait_until_element_is_visible(self.UPLOAD_FILE_UP100_ID, timeout=timeout) i = 0 while i < 60: i += 1 err_msg = "upload file Prompt information not visible" self.wait_until_element_is_visible(self.UPLOAD_FILE_STATUS_ID, error=err_msg) status = self.get_text(self.UPLOAD_FILE_STATUS_ID) status_success = self.UPLOAD_STATUS_SUCCESS.decode("utf8") if status == status_success: break self.blt.sleep(1) def click_upload_file_button(self): """ click upload file button. """ self.print_info("click upload button on firmware upgrade ui") self.click_center_element(self.UPLOAD_FILE_UPLOAD_BUTTON_ID) def click_button_to_open_layer(self, locator, layer_visible=True, button_name=None): """ click button to open the layer UI. :param locator: The button locator. :param layer_visible: Whether the layer is visible."True" is visible,"False" is not visible. :param button_name: the button name. """ if button_name is None: button_name = locator self.print_info("click the %s button on the management ui" % button_name) err_msg = "the button not visible!" self.wait_until_element_is_visible(locator, error=err_msg) self.click_center_element(locator) if layer_visible: self.unselect_frame() err_msg = "layer ui not visible" self.wait_until_element_is_visible(self.LAYER_FIRST_TITLE_ID, error=err_msg) self.select_frame(self.LAYER_IFRAME_ID) err_msg = "layer ui second title not visible" self.wait_until_element_is_visible(self.LAYER_SECOND_TITLE_ID, error=err_msg) def verify_lobibox_message(self, msg=None, msg_visible=True): """ Verify the bottom right corner box information :param msg: the bottom right corner box body information :param msg_visible: "False" is the bottom right corner box body not visible """ self.print_info("Verify the bottom right corner box information") self.unselect_frame() err_msg = "lobibox not visible" self.wait_until_element_is_visible(self.LOBIBOX_DIV_ID, error=err_msg) if msg is None: msg = self.LOBIBOX_MSG_SUCCESS title = self.LOBIBOX_TITLE_SUCCESS else: title = self.LOBIBOX_TITLE_FRIENDLY self.verify_element_text(self.LOBIBOX_TITLE_ID, title) if msg_visible: self.verify_element_text(self.LOBIBOX_MSG_INFO_ID, msg) def click_layer_save_button(self, layer_visible=False): """ Click layer UI save button. :param layer_visible: "False" layer ui is not visible. "True" layer ui is visible. """ self.print_info("click layer save button") self.unselect_frame() self.click_center_element(self.LAYER_SAVE_BUTTON_ID, sleep_status=False) if layer_visible: self.select_frame(self.LAYER_IFRAME_ID) def open_center_ssh(self, timeout=None): """ Open vtop center ssh :param timeout: ssh timeout """ self.print_info("Use the %s user ssh, and then switch to root" % self.CENTER_SSH_USER) self.ssh.open_connection(self.CENTER_IP, port=self.CENTER_SSH_PORTE, timeout=timeout) i = 0 while i < 10: i += 1 self.blt.sleep(5) try: status_login = self.ssh.login(self.CENTER_SSH_USER, self.CENTER_SSH_PASSWOER) except Exception, e: if i == 9: raise RuntimeError(e) continue status_info = "[%s@localhost ~]$" % self.CENTER_SSH_USER if status_info in status_login: break self.ssh.write("su") self.ssh.read_until("Password:"******"[root@localhost %s]#" % self.CENTER_SSH_USER)
class LogGrabber(object): """ Получение логов подсистем с удаленных серверов. \n Принцип работы: - перед началом теста происходит подсчет количества строк в логах - после окончания теста, если количество строк изменилось, то будут скачены только добавленные в лог строки. Для работы библиотеки необходимо cоздать переменную server_logs в python [http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-variables-directly|variable file] следующего вида: | server_logs = { | "tmpdir": "/tmp/", | "servers": [ | { | "hostname": "server.com", | "port": 22, | "username": "******", | "password": "******", | "subsystems": [ | { | "name": "Apache_server", | "logs": [ | { | "path_to_log": "/var/log", | "log_name": "access.log" | }, | { | "path_to_log": "/var/log", | "log_name": "error*.log" | } | ] | } | ] | } | ] | } Где: - tmpdir - каталог для временных файлов на удаленном сервере - hostname - имя хоста удаленного сервера - port - порт подключения по ssh - username\password - логин\пароль для подключения по ssh - name - имя подсистемы, для которой собираются логи, должно быть уникальным - path_to_log - путь к логам подсистемы - log_name - имя файла лога; могут использоваться wildcards аналогичные тем, что применяются в linux-команде find. === Ограничения === Логи подсистем должны находится на Linux сервере с возможностью подключения к нему по ssh. === Использование === 1. В качестве [http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-listener-interface|listener]:\n ``pybot --listener LogGrabber /path/to/test_suite``\n При этом нет необходимости изменять тесты. После завершения теста со статусом FAILED будет скачена лишь та часть логов, которая была записана во время его проходжения. 2. В качестве библиотеки:\n В этом случае можно скачивать логи вне зависимости от статуса теста | *** Settings *** | Documentation Пример | Library LogGrabber | Variables variables.py | Suite Setup SuiteSetup | Suite Teardown SuiteTeardown | | *** Test Cases *** | Fail_test | FAIL fail message | | Passed_test | Pass Execution passed message | | | *** Keywords *** | SuiteSetup | LogGrabber.Set connections | LogGrabber.Prepare logs | | | SuiteTeardown | LogGrabber.Download logs | LogGrabber.Close connections === Зависимости === | robot framework | http://robotframework.org | | AdvancedLogging | http://git.billing.ru/cgit/PS_RF.git/tree/library/AdvancedLogging.py | | SSHLibrary | http://robotframework.org/SSHLibrary/latest/SSHLibrary.html | """ ROBOT_LIBRARY_SCOPE = 'GLOBAL' ROBOT_LISTENER_API_VERSION = 2 def __init__(self): # загрузка встроенных библиотек self.bi = BuiltIn() self.ssh = SSHLibrary() self.adv_log = AdvancedLogging() # словарь с подготовленными логами self.prepared_logs = dict() def start_suite(self, name, attrs): self.set_connections() def start_test(self, name, attrs): self.prepare_logs() def end_test(self, name, attrs): if attrs['status'] != 'PASS': self.download_logs() def end_suite(self, name, attrs): self.close_connections() def set_connections(self): """ SSH-соединение с удаленными серверами """ # Получаем информацию о логах подсистем self.logs = self.bi.get_variable_value('${server_logs}') # Системный разделитель для платформы запуска тестов self.sys_separator = self.bi.get_variable_value('${/}') # Разделитель в unix self.nix_separator = '/' # перебираем сервера из словаря настройки # для каждого сервера создаем одтельное ssh-соединение, # которое будет жить в течение всего suite # дописываем alias в словарь для каждого сервера for _, server in enumerate(self.logs["servers"]): hostname = server["hostname"] port = server["port"] username = server["username"] password = server["password"] ssh_alias = str(self.bi.get_time('epoch')) # создаем ssh-соединение - alias = epoch timestamp self.ssh.open_connection(hostname, ssh_alias, port) self.ssh.login(username, password) server["ssh_alias"] = ssh_alias def prepare_logs(self): """ Подготовка логов. В результате для каждого лога, удовлетворяющего настройке, записывается номер послнедней строки. """ # структура с описанием серверов, подсистем и логов self.prepared_logs["servers"] = [] # перебираем сервера из конфигурации for server in self.logs["servers"]: processed_server = dict() hostname = server["hostname"] port = server["port"] username = server["username"] password = server["password"] ssh_alias = server["ssh_alias"] # заполняем словарь, описывающий обработанный сервер processed_server["hostname"] = hostname processed_server["port"] = port processed_server["username"] = username processed_server["password"] = password processed_server["ssh_alias"] = ssh_alias processed_server["subsystems"] = [] # переключаемся на соединение с alias = ssh_alias из словаря настройки self.ssh.switch_connection(ssh_alias) # для каждого сервера обрабатываем набор подсистем for subsystem in server["subsystems"]: # словарь обработанных подсистем processed_subsys = dict() processed_subsys["name"] = subsystem["name"] # список обработанных логов processed_logs = [] # обрабатываем логи для текущей подсистемы for subsys_log in subsystem["logs"]: path_to_log = subsys_log["path_to_log"] log_name_regexp = subsys_log["log_name"] # получаем список лог-файлов по regexp log_name_list_text = self.ssh.execute_command( "find {}{}{} -printf '%f\n'".format( path_to_log, self.nix_separator, log_name_regexp), True, True, True) # если список не пуст и код возврата команды 0 (success) if ((len(log_name_list_text[0]) > 0) & (log_name_list_text[2] == 0)): # формируем массив имен лог-файлов log_name_array = string.split(log_name_list_text[0], '\n') # для каждого файла получаем номер последней строки for log_name in log_name_array: line_number = self.ssh.execute_command( "cat {}{}{} | wc -l".format( path_to_log, self.nix_separator, log_name)) processed_logs.append({ "path_to_log": path_to_log, "log_name": log_name, "line_number": line_number }) # проверка для исключения "мусора" processed_subsys if (len(processed_logs) > 0): processed_subsys["logs"] = processed_logs processed_server["subsystems"].append(processed_subsys) # проверка - есть ли для сервера обработанные подсистемы с логами if (len(processed_server["subsystems"]) > 0): self.prepared_logs["servers"].append(processed_server) def download_logs(self): """ Формирование и загрузка логов. В результате в директории теста, созданной AdvancedLogging, получаем архив с логами [TIMESTAMP]_logs.zip """ timestamp = self.bi.get_time('epoch') # базовая директория теста base_dir = self.adv_log.Create_Advanced_Logdir() # имя результирующего архива с логами res_arc_name = os.path.join(base_dir, "{}_logs".format(timestamp)) # результирующая директория для логов logs_dir = os.path.join(base_dir, "logs") # временная директория на целевом сервере temp_dir = self.logs['tmpdir'] # обрабатыаем сервера, с подготовленными логами for server in self.prepared_logs["servers"]: # параметры подключения к серверу ssh_alias = server["ssh_alias"] # переключаемся на соединение с alias = ssh_alias из словаря self.ssh.switch_connection(ssh_alias) # обрабатываем подсистемы с подготовленными логами for subsystem in server["subsystems"]: # структура в которую скачиваются логи [Advanced_Logdir]/logs/<подсистема>/ subsys_dir = os.path.join(logs_dir, subsystem["name"]) for log in subsystem["logs"]: abs_log_name = "{}{}{}".format(log["path_to_log"], self.nix_separator, log["log_name"]) # имя файла содержащего интересующую нас часть, лога cut_log_name = "{}_{}".format(timestamp, log["log_name"]) # абсолютный пусть с именем файла (cut_[имя_лога]) - для интересующего нас куска лога cut_abs_log_name = "{}{}{}".format(temp_dir, self.nix_separator, cut_log_name) # текущий номер строки в логе cur_line_number = self.ssh.execute_command( "cat {} | wc -l".format(abs_log_name)) # проверяем, появились ли строки в логе с момента подготовки логов if (cur_line_number > log["line_number"]): # вырезаем часть лога, начиная с сохраненного номера строки self.ssh.execute_command("tail -n +{} {} > {}".format( log["line_number"], abs_log_name, cut_abs_log_name)) # gzip self.ssh.execute_command("gzip {}.gz {}".format( cut_abs_log_name, cut_abs_log_name)) # скачиваем файл self.ssh.get_file( "{}.gz".format(cut_abs_log_name), "{}{}{}.gz".format(subsys_dir, self.sys_separator, cut_log_name)) # удаляем вырезанную чыасть лога и gz-архив этой части self.ssh.execute_command( "rm {}".format(cut_abs_log_name)) self.ssh.execute_command( "rm {}.gz".format(cut_abs_log_name)) # если есть результат - упаковываем в единый zip-архив и удаляем папку с логами if (os.path.exists(logs_dir)): self._zip(logs_dir, res_arc_name) shutil.rmtree(logs_dir) def close_connections(self): """ Закрытие ssh-соединений с удаленными серверами """ self.ssh.close_all_connections() def _zip(self, src, dst): """ Упаковка логов единый zip-архив *Args:*\n _src_ - директория для упаковки _dst_ - имя лога """ zf = zipfile.ZipFile("%s.zip" % (dst), "w", zipfile.ZIP_DEFLATED) abs_src = os.path.abspath(src) for root, _, files in os.walk(src): for filename in files: abs_name = os.path.abspath(os.path.join(root, filename)) arc_name = abs_name[len(abs_src) + 1:] zf.write(abs_name, arc_name) zf.close()