def ssh_to_stx(lab=None, set_client=False): if not lab: lab = ProjVar.get_var('LAB') user = HostLinuxUser.get_user() password = HostLinuxUser.get_password() if ProjVar.get_var('IPV6_OAM'): lab = convert_to_ipv6(lab) LOG.info("SSH to IPv6 system {} via tuxlab2".format(lab['short_name'])) tuxlab2_ip = YOW_TUXLAB2['ip'] tux_user = TestFileServer.get_user() tuxlab_prompt = r'{}@{}\:(.*)\$ '.format(tux_user, YOW_TUXLAB2['name']) tuxlab2_ssh = SSHClient(host=tuxlab2_ip, user=tux_user, password=TestFileServer.get_password(), initial_prompt=tuxlab_prompt) tuxlab2_ssh.connect(retry_timeout=300, retry_interval=30, timeout=60) con_ssh = SSHFromSSH(ssh_client=tuxlab2_ssh, host=lab['floating ip'], user=user, password=password, initial_prompt=Prompt.CONTROLLER_PROMPT) else: con_ssh = SSHClient(lab['floating ip'], user=HostLinuxUser.get_user(), password=HostLinuxUser.get_password(), initial_prompt=Prompt.CONTROLLER_PROMPT) con_ssh.connect(retry=True, retry_timeout=30, use_current=False) if set_client: ControllerClient.set_active_controller(con_ssh) return con_ssh
def test_linux_user_lockout(): """ Verify linux user account will be lockout after 5? failed attempts Test Steps: - attempt to login with invalid password as sysadmin 5 times - verify cannot login as sysadmin anymore Returns: """ LOG.tc_step( 'Attempt to login with WRONG password as sysadmin {} times'.format( MAX_FAILED_LOGINS)) user = '******' if HostLinuxUser.get_user() != user: skip( 'Error: user name from HostLinuxCreds.get_user() != sysadmin, it is:{}' .format(HostLinuxUser.get_user())) password = HostLinuxUser.get_password() invalid_password = '******' host = lab_info.get_lab_floating_ip() LOG.info('verify we can login in at beginning') connect = log_in_raw(host, user, password, expect_fail=False) assert connect, 'Failed to login in at beginning with password'.format( password) for n in range(1, MAX_FAILED_LOGINS + 1): message = '{}: Expecting to fail to login with invalid password, host:{}, user:{}, password:{}\n'.format( n, host, user, invalid_password) LOG.info(message) connect = log_in_raw(host, user, invalid_password, expect_fail=True) assert not connect, 'Expecting to fail but not.' + message LOG.info( 'OK, failed {} times to login with invalid password:{} as user:{} to host:{}\n' .format(MAX_FAILED_LOGINS, invalid_password, user, host)) LOG.tc_step( 'Now attempt to login with CORRECT password:{}, expecting to fail\n'. format(password)) connect = log_in_raw(host, user, password, expect_fail=True) message = 'host:{}, user:{}, password:{}\n'.format(host, user, password) assert not connect, 'Expecting to fail but not.' + message LOG.info( 'OK, failed to login with CORRECT password due to the user account was locked down\n' ) LOG.tc_step( 'Wait for 5 minutes + 20 seconds for the account been automatically unlocked\n' ) time.sleep(320) LOG.info('verify we can login again after waiting for 5 minutes') connect = log_in_raw(host, user, password, expect_fail=False) assert connect, 'Failed to login again after waiting for 5 minutes.' + message
def scp_from_local(source_path, dest_ip, dest_path=None, dest_user=None, dest_password=None, timeout=900, is_dir=False): """ Scp file(s) from localhost (i.e., from where the automated tests are executed). Args: source_path (str): source file/directory path dest_ip (str): ip of the destination host dest_user (str): username of destination host. dest_password (str): password of destination host dest_path (str): destination directory path to copy the file(s) to timeout (int): max time to wait for scp finish in seconds is_dir (bool): whether to copy a single file or a directory """ if not dest_path: dest_path = HostLinuxUser.get_home() if not dest_user: dest_user = HostLinuxUser.get_user() if not dest_password: dest_password = HostLinuxUser.get_password() dir_option = '-r ' if is_dir else '' cmd = 'scp -oStrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' \ '{}{} {}@{}:{}'.\ format(dir_option, source_path, dest_user, dest_ip, dest_path) _scp_on_local(cmd, remote_password=dest_password, timeout=timeout)
def __get_lab_ssh(labname, log_dir=None): """ Args: labname: log_dir: Returns (SSHClient): """ lab = get_lab_dict(labname) # Doesn't have to save logs # if log_dir is None: # log_dir = temp_dir = "/tmp/CGCSAUTO/" if log_dir is not None: ProjVar.set_var(log_dir=log_dir) ProjVar.set_var(lab=lab) ProjVar.set_var(source_openrc=True) con_ssh = SSHClient(lab.get('floating ip'), HostLinuxUser.get_user(), HostLinuxUser.get_password(), CONTROLLER_PROMPT) con_ssh.connect() # if 'auth_url' in lab: # Tenant._set_url(lab['auth_url']) return con_ssh
def prep_test_on_host(target_ssh, target, file_path, active_controller_name, cyclictest_dir=CYCLICTEST_DIR): LOG.tc_step( "Copy cyclictest executable to target if not already exist: {}".format( target)) target_ssh.exec_cmd('mkdir -p {}; rm -f {}/*.*'.format( cyclictest_dir, cyclictest_dir)) dest_path = '{}/{}'.format(cyclictest_dir, os.path.basename(file_path)) if not target_ssh.file_exists(dest_path): LOG.info('Copy CYCLICTEST to selected host {}:{}'.format( target, dest_path)) target_ssh.scp_on_dest(HostLinuxUser.get_user(), active_controller_name, dest_path=dest_path, source_path=file_path, source_pswd=HostLinuxUser.get_password()) LOG.info('Check if CYCLICTEST was copied to target host') assert target_ssh.file_exists(dest_path), \ 'Failed to find CYCLICTEST executable on target host after copied' LOG.info('-successfully copied to {}:{}'.format(target, file_path))
def delete_test_users(): global _host_users restore_sysadmin_password(target_password=TARGET_PASSWORD) LOG.info('Deleting users created for testing\n') conn_to_ac = ControllerClient.get_active_controller() count = 0 for (host, user), _ in _host_users.items(): if user == 'sysadmin' or user == HostLinuxUser.get_user(): LOG.info('-do not delete user:{} on host:{}\n'.format( user, host)) continue LOG.info('-deleting user:{} on host:{}\n'.format(user, host)) count += 1 if host == 'active-controller': conn_to_ac.exec_sudo_cmd('userdel -r {}'.format(user)) else: # sleep a bit so controller-1 have same password as controller-0 time.sleep(30) with host_helper.ssh_to_host(host, password='******') as conn: LOG.info( 'TODO: delete user:{} on host:{} by CLI: userdel -r {}\n' .format(user, host, user)) conn.exec_sudo_cmd("userdel -r '{}'".format(user)) LOG.info('{} test user deleted'.format(count))
def test_patch_log_upload_dir(get_patch_name): """ Checks that the correct logs are added when uploading a directory of patches Test Steps: - Upload patches from a directory - Check the log files for the expected logs """ patch_name = get_patch_name con_ssh = ControllerClient.get_active_controller() LOG.tc_step("Uploading patches from directory") code = con_ssh.exec_sudo_cmd('sw-patch upload-dir test_patches')[0] if code is not 0: skip("No patches found. Cannot test.") res_1 = check_dir(patch_name) search_for = ['sw-patch-controller-daemon.*INFO: Importing patches:.*{}'.format(patch_name), 'sw-patch-controller-daemon.*INFO: Importing patch:.*{}'.format(patch_name)] res_2 = check_logs(search_for, lines=20, api=False) user = HostLinuxUser.get_user() search_for = ['sw-patch-controller-daemon.*INFO: User: {}/admin Action: ' 'Importing patches:.*{}.patch'.format(user, patch_name), 'sw-patch-controller-daemon.*INFO: User: {}/admin Action: ' 'Importing patch:.*{}.patch'.format(user, patch_name)] res_3 = check_logs(search_for, lines=10, api=True) LOG.tc_step("Deleting patch {}".format(patch_name)) con_ssh.exec_sudo_cmd('sw-patch delete {}'.format(patch_name)) assert res_1, "FAIL: The patch was not in \"sw-patch query\"" assert res_2, "FAIL: uploading patches did not generate the expected logs in patching.log" assert res_3, "FAIL: uploading patches did not generate the expected logs in patching-api.log"
def test_patch_log_what_requires(get_patch_name): """ Checks that the what_requires query is logged Test Steps: - Upload a patch and execute 'sw-patch what-requires' - Check log files for the expected logs """ patch_name = get_patch_name con_ssh = ControllerClient.get_active_controller() LOG.tc_step("Uploading patch {}".format(patch_name)) con_ssh.exec_sudo_cmd('sw-patch upload test_patches/{}.patch'.format(patch_name)) con_ssh.exec_sudo_cmd('sw-patch what-requires {}'.format(patch_name)) user = HostLinuxUser.get_user() search_for = ['sw-patch-controller-daemon.*INFO: Querying what requires patches:.*{}'.format(patch_name)] res_1 = check_logs(search_for, lines=10, api=False) search_for = ['sw-patch-controller-daemon.*INFO: User: {}/admin Action: ' 'Querying what requires patches:.*{}'.format(user, patch_name)] res_2 = check_logs(search_for, lines=10, api=True) LOG.tc_step("Deleting patch {}".format(patch_name)) con_ssh.exec_sudo_cmd('sw-patch delete {}'.format(patch_name)) assert res_1, "FAIL: uploading patches did not generate the expected " \ "logs in patching.log" assert res_2, "FAIL: uploading patches did not generate the expected logs " \ "in patching-api.log"
def get_current_user_password(cls, con_ssh=None): if not con_ssh: con_ssh = ControllerClient.get_active_controller() user = con_ssh.get_current_user() if user == HostLinuxUser.get_user(): return user, HostLinuxUser.get_password() return user, cls.__users[user]
def login_as_linux_user(user, password, host, cmd='whoami', expecting_fail=False): if is_on_action_controller(host): LOG.info('Login to the active controller:{}\n'.format(host)) if user != HostLinuxUser.get_user(): skip( 'Login to the active controller(will not skip if controller-1 is active), ' 'host:{}, user:{}'.format(host, user)) return False, '' if user == 'sysadmin': LOG.info('Login to the host:{} as "sysadmin"!\n'.format(host)) LOG.info('Attempt to login to host:{}, user:{}, password:{}\n'.format( host, user, password)) # todo: if host is the active-controller, ssh_to_host will ignore username # and using 'sysadmin', which leads to error cmd = '(date; uuid; hostname; {}) 2>/dev/null'.format(cmd) try: with host_helper.ssh_to_host(host, username=user, password=password) as conn: code, output = conn.exec_cmd(cmd, fail_ok=True) LOG.info('code={}, output={}\n'.format(code, output)) if 0 != code: msg = 'Failed to execute cmd:{} on host:{} as user:{}, password:{}'.format( cmd, host, user, password) LOG.info(msg) assert expecting_fail, msg return False, output else: assert not expecting_fail, \ 'Expecting logged in but failed: host:{} as user:{} with password:{}'.format(host, user, password) return True, output except Exception as e: # LOG.info('Caught exception:\n{}\n'.format(e)) msg = 'Expecting to login but failed with exception:{}'.format(e) assert expecting_fail, msg if not 'Permission denied,' in str(e): LOG.warning( 'Login as {}/{} failed without Permission denied error.'. format(user, password)) else: LOG.info( 'Failed to login as expected on host:{}, user:{}, password:{}, for "Permission denied"' .format(host, user, password)) return False, str(e)
def setup_tis_ssh(lab): con_ssh = ControllerClient.get_active_controller(fail_ok=True) if con_ssh is None: con_ssh = SSHClient(lab['floating ip'], HostLinuxUser.get_user(), HostLinuxUser.get_password(), CONTROLLER_PROMPT) con_ssh.connect(retry=True, retry_timeout=30) ControllerClient.set_active_controller(con_ssh) return con_ssh
def test_auth_log_sudo_cmd(): """ TC5202 Test the logs created during successful and failed sudo commands Test Steps: - Ssh to a controller and execute a sudo command - Search through the logs to find the log that should be created from the sudo command - Exit ssh and ssh to controller again - Execute sudo command using incorrect password - Find the log that should be created from the failed sudo command """ log_path = '/var/log/auth.log' con_ssh = ControllerClient.get_active_controller() LOG.tc_step("Get timestamp for last line in auth.log") start_time = con_ssh.exec_cmd( "tail -1 {} | awk '{{print $1}}'".format(log_path))[1] cmd = '-k ls -l' LOG.tc_step("Executing sudo command {}".format(cmd)) con_ssh.exec_sudo_cmd(cmd, fail_ok=True) user = HostLinuxUser.get_user() searching_for = [ 'sudo: notice {}.*PWD=/home/{} ; USER=root ; ' 'COMMAND=/usr/bin/ls -l'.format(user, user) ] found = wait_for_log(log_path=log_path, ssh_client=con_ssh, patterns=searching_for, start_time=start_time) assert len(searching_for) == len(found), "FAIL: The sudo command was not logged. " \ "Expecting to find: {} found: {}".format(searching_for, found) LOG.tc_step("Executing sudo command {} with wrong password".format(cmd)) start_time = con_ssh.exec_cmd( "tail -1 {} | awk '{{print $1}}'".format(log_path))[1] exec_sudo_cmd_fail(con_ssh, cmd) searching_for = [ 'sudo: notice pam_unix\(sudo:auth\): authentication ' 'failure; logname={} .* ' 'ruser={} rhost= user={}'.format(user, user, user) ] found = wait_for_log(log_path=log_path, ssh_client=con_ssh, patterns=searching_for, start_time=start_time) assert len(searching_for) == len(found), "FAIL: The failed sudo command was not logged. " \ "Expecting to find: {} found: {}".format(searching_for, found)
def test_auth_log_sudo_su(): """ TC5205 Test logs created by sudo su Test Steps: - Ssh to a controller and execute 'sudo su' - Check that logs are created by the command - Logout and ssh to the controller again - Attempt to execute 'sudo su' with an incorrect password - Check that there are logs created by the failed command """ con_ssh = ControllerClient.get_active_controller() user = HostLinuxUser.get_user() searching_for = [ 'sudo: notice {}.*PWD=/home/{} ; USER=root ; ' 'COMMAND=/usr/bin/su \-'.format(user, user), 'su: notice \(to root\) {} on'.format(user), # uses su-l:session because login_as_root calls 'sudo su -' 'su: info pam_unix\(su-l:session\): session opened for ' 'user root by {}\(uid=0\)'.format(user) ] log_path = '/var/log/auth.log' start_time = con_ssh.exec_cmd( "tail -1 {} | awk '{{print $1}}'".format(log_path))[1] LOG.tc_step("Logging in as su") with con_ssh.login_as_root() as root: LOG.info("Logged in as root") found = wait_for_log(con_ssh, patterns=searching_for, log_path=log_path, start_time=start_time) assert len(searching_for) == len(found), "FAIL: The sudo su command was not logged. " \ "Looking for logs resembling: {} found: {}".format(searching_for,found) cmd = '-k su' LOG.tc_step("Executing sudo command {} with wrong password".format(cmd)) searching_for = [ 'sudo: notice pam_unix\(sudo:auth\): authentication failure; ' 'logname={}.*ruser={} rhost= user={}'.format(user, user, user) ] start_time = con_ssh.exec_cmd( "tail -1 {} | awk '{{print $1}}'".format(log_path))[1] exec_sudo_cmd_fail(con_ssh, cmd) found = wait_for_log(con_ssh, searching_for, log_path=log_path, start_time=start_time) assert len(searching_for) == len(found), "FAIL: The failed sudo su command was not logged. " \ "Looking for logs resembling: {} found: {}".format(searching_for, found)
def ssh_to_stx(lab=None, set_client=False): if not lab: lab = ProjVar.get_var('LAB') con_ssh = SSHClient(lab['floating ip'], user=HostLinuxUser.get_user(), password=HostLinuxUser.get_password(), initial_prompt=Prompt.CONTROLLER_PROMPT) con_ssh.connect(retry=True, retry_timeout=30, use_current=False) if set_client: ControllerClient.set_active_controller(con_ssh) return con_ssh
def test_configure_external_ceph(ceph_lab, ceph_services): """ This test will configure external ceph on a system. Currently this is only supported on wcp3-6, using wcp7-12 as the external ceph system. In order to support this, the user will need to install wcp7-12 in Region mode, then wcp3-6 needs to be installed with a custom config that includes an infrastructure interface. The ceph.conf file needs to be then copied from wcp7-12 onto wcp3-6. This conf file needs to be renamed to something other than ceph.conf and then used to enable external ceph. Only the following services can be enabled on external ceph: cinder, nova and glance. Swift is not supported. Once external ceph is enabled, a new cinder type will be added and resource creation will default to the external ceph backend (depending on what services were provisioned in the first place). Test Steps: 1. Copy ceph.conf from wcp7-12 2. Provision external ceph services on wcp3-6 TODO: - Add an infra ping test from regular lab to ceph lab - skip if fails """ LOG.tc_step("Retrieve ceph.conf from the external ceph system") con_ssh = ControllerClient.get_active_controller() ceph_lab = get_lab_dict(ceph_lab) source_server = ceph_lab['floating ip'] source_lab_name = ceph_lab['short_name'] source_filepath = "/etc/ceph/ceph.conf" dest_filepath = "/home/sysadmin/ceph_{}.conf".format(source_lab_name) con_ssh.scp_on_dest(source_user=HostLinuxUser.get_user(), source_ip=source_server, source_pswd=HostLinuxUser.get_password(), source_path=source_filepath, dest_path=dest_filepath, timeout=60) LOG.tc_step( "Confirm ceph.conf file was successfully copied before proceeding") if not con_ssh.file_exists(dest_filepath): skip("External ceph.conf not present on the system") LOG.tc_step("Provision storage-backend for external ceph") add_external_ceph(dest_filepath, ceph_services.split(sep='_'))
def __init__(self, host, prompt=None, port=0, timeout=30, hostname=None, user=HostLinuxUser.get_user(), password=HostLinuxUser.get_password(), negotiate=False, vt100query=False, console_log_file=None): self.logger = LOG super(TelnetClient, self).__init__(host=host, port=port, timeout=timeout) if not hostname: self.send('\r\n\r\n') prompts = [LOGIN_REGEX, LOGGED_IN_REGEX] index, re_obj, matched_text = super().expect(prompts, timeout=10) if index in (0, 1): hostname = prompts[index].search(matched_text).group(1).decode( errors='ignore') if not prompt: prompt = r':~\$ ' #-- mod begins self.console_log_file = self.get_log_file(console_log_file) self.negotiate = negotiate self.vt100query = vt100query if self.vt100query: self.vt100querybuffer = b'' # Buffer for VT100 queries #-- mod ends self.flush(timeout=1) self.logger = telnet_logger(hostname) if hostname else telnet_logger( host + ":" + str(port)) self.hostname = hostname self.prompt = prompt self.cmd_output = '' self.cmd_sent = '' self.timeout = timeout self.user = user self.password = password self.logger.info( 'Telnet connection to {}:{} ({}) is established'.format( host, port, hostname))
def scp_from_active_controller_to_localhost( source_path, dest_path='', src_user=None, src_password=None, timeout=900, is_dir=False): active_cont_ip = ControllerClient.get_active_controller().host if not src_user: src_user = HostLinuxUser.get_user() if not src_password: src_password = HostLinuxUser.get_password() return scp_to_local(source_path=source_path, source_ip=active_cont_ip, source_user=src_user, source_password=src_password, dest_path=dest_path, timeout=timeout, is_dir=is_dir)
def _get_nonroot_group(con_ssh, user=None): if not user: user = HostLinuxUser.get_user() groups = con_ssh.exec_cmd('groups {}'.format(user), fail_ok=False)[1] err = 'Please ensure linux_user {} belongs to both root and non_root ' \ 'groups'.format(user) if 'root' not in groups: raise ValueError(err) groups = groups.split(': ')[-1].split() for group in groups: if group.strip() != 'root': return group raise ValueError('Please ensure linux_user {} belongs to both root ' 'and at least one non-root groups'.format(user))
def scp_from_localhost_to_active_controller( source_path, dest_path=None, dest_user=None, dest_password=None, timeout=900, is_dir=False): active_cont_ip = ControllerClient.get_active_controller().host if not dest_path: dest_path = HostLinuxUser.get_home() if not dest_user: dest_user = HostLinuxUser.get_user() if not dest_password: dest_password = HostLinuxUser.get_password() return scp_from_local(source_path, active_cont_ip, dest_path=dest_path, dest_user=dest_user, dest_password=dest_password, timeout=timeout, is_dir=is_dir)
def restore_sysadmin_password(current_password=None, target_password=None): global _host_users old_passwords = _host_users[('active-controller', 'sysadmin')] LOG.info('Restoring password for sysadmin, old_passwords:{}\n'.format( old_passwords)) if not old_passwords or len( old_passwords) <= 1 or current_password == target_password: LOG.info('Password for sysadmin did not change, no need to restore') return current_password = old_passwords[ -1] if current_password is None else current_password current_host = system_helper.get_active_controller_name() exclude_list = deque(old_passwords[0 - MAX_NUM_PASSWORDS_TRACKED:], MAX_NUM_PASSWORDS_TRACKED) for n in range(1, MAX_NUM_PASSWORDS_TRACKED + 1): new_password = security_helper.gen_linux_password( exclude_list=list(exclude_list), length=PASSWORD_LEGNTH) LOG.info('chaning password {} times: from:{} to:{}\n'.format( n, current_password, new_password)) security_helper.change_linux_user_password(current_password, new_password, host=current_host) current_password = new_password exclude_list.append(new_password) LOG.info('wait after chaning password of sysadmin\n') wait_after_change_sysadmin_password() # original_password = old_passwords[0] if old_passwords else 'Li69nux*' original_password = '******' if target_password is None else target_password LOG.info('Restore password of sysadmin to:{}'.format(original_password)) security_helper.change_linux_user_password(current_password, original_password, user=HostLinuxUser.get_user(), host=current_host) LOG.info( 'Password for sysadmin is restored to:{}'.format(original_password)) return original_password
def setup_vbox_tis_ssh(lab): if 'external_ip' in lab.keys(): con_ssh = ControllerClient.get_active_controller(fail_ok=True) if con_ssh: con_ssh.disconnect() con_ssh = SSHClient(lab['external_ip'], HostLinuxUser.get_user(), HostLinuxUser.get_password(), CONTROLLER_PROMPT, port=lab['external_port']) con_ssh.connect(retry=True, retry_timeout=30) ControllerClient.set_active_controller(con_ssh) else: con_ssh = setup_tis_ssh(lab) return con_ssh
def delete_object_file(object_path, rm_dir=False, client=None): def _delete_on_client(client_): cmd = "ls {}".format(object_path) rc, output = client_.exec_cmd(cmd) if rc == 0: cmd = 'rm {} {}'.format('-r' if rm_dir else '', object_path) client_.exec_cmd(cmd) LOG.info("Files deleted {}: {}".format(object_path, output)) if not client: client = get_cli_client() _delete_on_client(client_=client) if not ProjVar.get_var('REMOTE_CLI'): standby_controller = system_helper.get_standby_controller_name() with host_helper.ssh_to_host( standby_controller, username=HostLinuxUser.get_user(), password=HostLinuxUser.get_password()) as standby_ssh: _delete_on_client(client_=standby_ssh) return True
def scp_to_local(dest_path, source_path, source_server=None, source_user=None, source_password=None, timeout=900, is_dir=False, ipv6=None): """ Scp file(s) to localhost (i.e., to where the automated tests are executed). Args: source_path (str): source file/directory path source_server (str): ip of the source host. source_user (str): username of source host. source_password (str): password of source host dest_path (str): destination directory path to copy the file(s) to timeout (int): max time to wait for scp finish in seconds is_dir (bool): whether to copy a single file or a directory ipv6 """ if not source_user: source_user = HostLinuxUser.get_user() if not source_password: source_password = HostLinuxUser.get_password() dir_option = '-r ' if is_dir else '' ipv6_arg = '' if get_ip_version(source_server) == 6: ipv6_arg = '-6 ' source_server = '[{}]'.format(source_server) elif ipv6: ipv6_arg = '-6 ' cmd = 'scp {}-oStrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ' \ '{}{}@{}:{} {}'.\ format(ipv6_arg, dir_option, source_user, source_server, source_path, dest_path) _scp_on_local(cmd, remote_password=source_password, timeout=timeout)
class LinuxUser: users = {HostLinuxUser.get_user(): HostLinuxUser.get_password()} con_ssh = None def __init__(self, user, password, con_ssh=None): self.user = user self.password = password self.added = False self.con_ssh = con_ssh if con_ssh is not None else \ ControllerClient.get_active_controller() def add_user(self): self.added = True LinuxUser.users[self.user] = self.password raise NotImplementedError def modify_password(self): raise NotImplementedError def delete_user(self): raise NotImplementedError def login(self): raise NotImplementedError @classmethod def get_user_password(cls): raise NotImplementedError @classmethod def get_current_user_password(cls, con_ssh=None): if con_ssh: cls.con_ssh = con_ssh elif not cls.con_ssh: cls.con_ssh = ControllerClient.get_active_controller() user = cls.con_ssh.get_current_user() return user, cls.users[user]
def test_patch_log_host_install(setup_host_install): """ Checks that host_install produces the correct logs Setup: - Lock a compute node - Upload and apply a patch Test Steps: - Execute 'sw-patch host-install' - Check the log files for the expected logs Teardown: - Remove and delete the patch - Execute 'sw-patch host-install' again to update it to having no patches - Unlock compute """ patch_name, host = setup_host_install con_ssh = ControllerClient.get_active_controller() con_ssh.exec_sudo_cmd('sw-patch host-install {}'.format(host), expect_timeout=timeout.CLI_TIMEOUT) res = check_install(host) assert res, "FAIL: The patch was not in \"sw-patch query-hosts\"" search_for = ['sw-patch-controller-daemon.*INFO: Running host-install for {}'.format(host), 'sw-patch-controller-daemon.*INFO.*Patch installation request sent to {}'.format(host)] res = check_logs(search_for, lines=50, api=False) assert res, "FAIL: uploading patches did not generate the expected logs in patching.log" search_for = ['sw-patch-controller-daemon.*INFO: User: {}/admin ' 'Action: Running host-install for {}'. format(HostLinuxUser.get_user(), host)] res = check_logs(search_for, lines=25, api=True) assert res, "FAIL: uploading patches did not generate the expected " \ "logs in patching-api.log"
def _get_large_heat(con_ssh=None, heat_template='system'): """ copy the heat templates to TiS server. Args: con_ssh (SSHClient): Returns (str): TiS file path of the heat template """ file_dir = StxPath.CUSTOM_HEAT_TEMPLATES file_name = HeatTemplate.SYSTEM_TEST_HEAT if heat_template is 'patch': file_name = HeatTemplate.LARGE_HEAT file_path = file_dir + file_name source_file = TestServerPath.CUSTOM_HEAT_TEMPLATES + file_name if con_ssh is None: con_ssh = ControllerClient.get_active_controller() LOG.info('Check if file already exists on TiS') if con_ssh.file_exists(file_path=file_path): LOG.info('dest path {} already exists. Return existing path'.format( file_path)) return file_path with host_helper.ssh_to_test_server() as ssh_to_server: ssh_to_server.rsync(source_file, html_helper.get_ip_addr(), file_dir, dest_user=HostLinuxUser.get_user(), dest_password=HostLinuxUser.get_password(), timeout=1200) return file_path
def fetch_cert_file(ssh_client, search_path=None): save_cert_to = os.path.dirname(SecurityPath.ALT_CERT_PATH) code, output = ssh_client.exec_cmd('mkdir -p {}'.format(save_cert_to), fail_ok=True) if code != 0: msg = 'failed to create path for certificate files:{}, error:'.format( save_cert_to, output) LOG.warn(msg) return code, msg from_server = build_server.DEFAULT_BUILD_SERVER['ip'] prompt = r'\[{}@.* \~\]\$'.format(TestFileServer.get_user()) ssh_to_server = SSHFromSSH(ssh_client, from_server, TestFileServer.get_user(), TestFileServer.get_password(), initial_prompt=prompt) ssh_to_server.connect(retry=5) if search_path is None: search_path = os.path.join(BuildServerPath.DEFAULT_HOST_BUILD_PATH, BuildServerPath.LAB_CONF_DIR_PREV) search_cmd = "\\find {} -maxdepth 5 -type f -name '*.pem'".format( search_path) code, output = ssh_to_server.exec_cmd(search_cmd, fail_ok=True) lab_name = ProjVar.get_var('lab')['name'] LOG.info('Get the PEM for current lab ({}) first'.format(lab_name)) if code == 0 and output: for file in output.splitlines(): exiting_lab_name = os.path.basename(os.path.dirname(file)) if exiting_lab_name in lab_name or lab_name in exiting_lab_name: certificate_file = file break else: certificate_file = output.splitlines()[0] else: msg = 'failed to fetch cert-file from build server, tried path:{}, server:{}'.format( search_path, from_server) LOG.warn(msg) return -1, msg LOG.info( 'found cert-file on build server, trying to scp to current active controller\ncert-file:{}' .format(certificate_file)) scp_cmd = \ 'scp -oStrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null {} ' \ '{}@{}:{}'.format( certificate_file, HostLinuxUser.get_user(), lab_info.get_lab_floating_ip(), save_cert_to) ssh_to_server.send(scp_cmd) timeout = 60 output_index = ssh_to_server.expect( [ssh_to_server.prompt, Prompt.PASSWORD_PROMPT], timeout=timeout) if output_index == 2: ssh_to_server.send('yes') output_index = ssh_to_server.expect( [ssh_to_server.prompt, Prompt.PASSWORD_PROMPT], timeout=timeout) if output_index == 1: ssh_to_server.send(HostLinuxUser.get_password()) output_index = ssh_to_server.expect(timeout=timeout) assert output_index == 0, "Failed to scp files" exit_code = ssh_to_server.get_exit_code() assert 0 == exit_code, "scp not fully succeeded" ssh_to_server.close() copied_cert_file = os.path.join(save_cert_to, os.path.basename(certificate_file)) ssh_client.exec_cmd('ls -l {}; mv {} {}.bk'.format(copied_cert_file, copied_cert_file, copied_cert_file)) return 0, copied_cert_file + '.bk'
'disabled': 'ssl', 'murano': 'murano', 'murano_ca': 'murano_ca', } default_ssl_file = '/etc/ssl/private/server-cert.pem' testing_ssl_file = 'server-cert.pem.bk' conf_backup_dir = 'bk-conf' local_conf_backup_dir = '/tmp/bk-conf' cert_id_line = r'^\|\s* uuid \s*\|\s* ([a-z0-9-]+) \s*\|$' fmt_password = r'{password}' expected_install = ( ('Password: '******'Enter password for the CA-Signed certificate file \[Enter <CR> for no password\]', fmt_password), (r'Enter \[sudo\] password for {}'.format(HostLinuxUser.get_user()), fmt_password), ('Installing certificate file ', ''), ('WARNING, Installing an invalid or expired certificate', ''), (r'OK to Proceed\? \(yes/NO\)', 'yes'), ('In {mode} mode...', ''), ('WARNING, For security reasons, the original certificate', ''), (r'OK to Proceed\? \(yes/NO\)', 'yes'), ('Configuring TPM on all enabled controller hosts...', ''), ('Auditing TPM configuration state...', ''), (r'^done$', ''), ) file_changes = { 'haproxy': { r'/etc/haproxy/haproxy.cfg': (
def change_linux_user_password(password, new_password, user=None, host=None): if not user: user = HostLinuxUser.get_user() LOG.info( 'Attempt to change password, from password:{}, to new-password:{}, ' 'on host:{}'.format(password, new_password, host)) input_outputs = ( ( 'passwd', (r'\(current\) UNIX password: '******'New password: '******': Authentication token manipulation error', EOF, ), ), ( new_password, ('Retype new password:'******'BAD PASSWORD: The password is too similar to the old one', 'BAD PASSWORD: No password supplied', 'passwd: Have exhausted maximum number of retries for service', EOF, ), ), ( new_password, ( ': all authentication tokens updated successfully.', Prompt.CONTROLLER_PROMPT, ), (), ), ) conn_to_ac = ControllerClient.get_active_controller() initial_prompt = r'.*{}\:~\$ '.format(host) LOG.info('Will login as user:"******", password:"******", to host:"{}"'.format( user, password, host)) conn = SSHFromSSH(conn_to_ac, host, user, password, force_password=True, initial_prompt=initial_prompt) passed = True try: conn.connect(retry=False, use_password=True) for cmd, expected, errors in input_outputs: # conn.flush() LOG.info("Send '{}'\n".format(cmd)) conn.send(cmd) blob_list = list(expected) + list(errors) LOG.info("Expect: {}\n".format(blob_list)) index = conn.expect(blob_list=blob_list) LOG.info('returned index:{}\n'.format(index)) if len(expected) <= index: passed = False break except Exception as e: LOG.warn('Caught exception when connecting to host:{} as user:{} with ' 'pasword:{}\n{}\n'.format(host, user, password, e)) raise finally: if user != HostLinuxUser.get_user(): conn.close() # flush the output to the cli so the next cli is correctly registered conn.flush() LOG.info('Successfully changed password from:\n{}\nto:{} for user:{} on ' 'host:{}'.format(password, new_password, user, host)) return passed, new_password
def setup_keypair(con_ssh, natbox_client=None): """ copy private keyfile from controller-0:/opt/platform to natbox: priv_keys/ Args: natbox_client (SSHClient): NATBox client con_ssh (SSHClient) """ """ copy private keyfile from controller-0:/opt/platform to natbox: priv_keys/ Args: natbox_client (SSHClient): NATBox client con_ssh (SSHClient) """ if not container_helper.is_stx_openstack_deployed(con_ssh=con_ssh): LOG.info("stx-openstack is not applied. Skip nova keypair config.") return # ssh private key should now exist under keyfile_path if not natbox_client: natbox_client = NATBoxClient.get_natbox_client() LOG.info("scp key file from controller to NATBox") # keyfile path that can be specified in testcase config keyfile_stx_origin = os.path.normpath(ProjVar.get_var('STX_KEYFILE_PATH')) # keyfile will always be copied to sysadmin home dir first and update file # permission keyfile_stx_final = os.path.normpath( ProjVar.get_var('STX_KEYFILE_SYS_HOME')) public_key_stx = '{}.pub'.format(keyfile_stx_final) # keyfile will also be saved to /opt/platform as well, so it won't be # lost during system upgrade. keyfile_opt_pform = '/opt/platform/{}'.format( os.path.basename(keyfile_stx_final)) # copy keyfile to following NatBox location. This can be specified in # testcase config keyfile_path_natbox = os.path.normpath( ProjVar.get_var('NATBOX_KEYFILE_PATH')) auth_info = Tenant.get_primary() keypair_name = auth_info.get('nova_keypair', 'keypair-{}'.format(auth_info['user'])) nova_keypair = nova_helper.get_keypairs(name=keypair_name, auth_info=auth_info) linux_user = HostLinuxUser.get_user() nonroot_group = _get_nonroot_group(con_ssh=con_ssh, user=linux_user) if not con_ssh.file_exists(keyfile_stx_final): with host_helper.ssh_to_host('controller-0', con_ssh=con_ssh) as con_0_ssh: if not con_0_ssh.file_exists(keyfile_opt_pform): if con_0_ssh.file_exists(keyfile_stx_origin): # Given private key file exists. Need to ensure public # key exists in same dir. if not con_0_ssh.file_exists('{}.pub'.format( keyfile_stx_origin)) and not nova_keypair: raise FileNotFoundError( '{}.pub is not found'.format(keyfile_stx_origin)) else: # Need to generate ssh key if nova_keypair: raise FileNotFoundError( "Cannot find private key for existing nova " "keypair {}".format(nova_keypair)) con_0_ssh.exec_cmd( "ssh-keygen -f '{}' -t rsa -N ''".format( keyfile_stx_origin), fail_ok=False) if not con_0_ssh.file_exists(keyfile_stx_origin): raise FileNotFoundError( "{} not found after ssh-keygen".format( keyfile_stx_origin)) # keyfile_stx_origin and matching public key should now exist # on controller-0 # copy keyfiles to home dir and opt platform dir con_0_ssh.exec_cmd('cp {} {}'.format(keyfile_stx_origin, keyfile_stx_final), fail_ok=False) con_0_ssh.exec_cmd('cp {}.pub {}'.format( keyfile_stx_origin, public_key_stx), fail_ok=False) con_0_ssh.exec_sudo_cmd('cp {} {}'.format( keyfile_stx_final, keyfile_opt_pform), fail_ok=False) # Make sure owner is sysadmin # If private key exists in opt platform, then it must also exist # in home dir con_0_ssh.exec_sudo_cmd('chown {}:{} {}'.format( linux_user, nonroot_group, keyfile_stx_final), fail_ok=False) # ssh private key should now exists under home dir and opt platform # on controller-0 if con_ssh.get_hostname() != 'controller-0': # copy file from controller-0 home dir to controller-1 con_ssh.scp_on_dest(source_user=HostLinuxUser.get_user(), source_ip='controller-0', source_path=keyfile_stx_final, source_pswd=HostLinuxUser.get_password(), dest_path=keyfile_stx_final, timeout=60) if not nova_keypair: LOG.info("Create nova keypair {} using public key {}".format( nova_keypair, public_key_stx)) if not con_ssh.file_exists(public_key_stx): con_ssh.scp_on_dest(source_user=HostLinuxUser.get_user(), source_ip='controller-0', source_path=public_key_stx, source_pswd=HostLinuxUser.get_password(), dest_path=public_key_stx, timeout=60) con_ssh.exec_sudo_cmd('chown {}:{} {}'.format( linux_user, nonroot_group, public_key_stx), fail_ok=False) if ProjVar.get_var('REMOTE_CLI'): dest_path = os.path.join(ProjVar.get_var('TEMP_DIR'), os.path.basename(public_key_stx)) common.scp_from_active_controller_to_localhost( source_path=public_key_stx, dest_path=dest_path, timeout=60) public_key_stx = dest_path LOG.info("Public key file copied to localhost: {}".format( public_key_stx)) nova_helper.create_keypair(keypair_name, public_key=public_key_stx, auth_info=auth_info) natbox_client.exec_cmd('mkdir -p {}'.format( os.path.dirname(keyfile_path_natbox))) tis_ip = ProjVar.get_var('LAB').get('floating ip') for i in range(10): try: natbox_client.scp_on_dest(source_ip=tis_ip, source_user=HostLinuxUser.get_user(), source_pswd=HostLinuxUser.get_password(), source_path=keyfile_stx_final, dest_path=keyfile_path_natbox, timeout=120) LOG.info("private key is copied to NatBox: {}".format( keyfile_path_natbox)) break except exceptions.SSHException as e: if i == 9: raise LOG.info(e.__str__()) time.sleep(10)