def prepare_certs_and_keys_on_host(session, host, certs_dir, key_name): """ Prepare certificates and keys on the host :param session: RemoteSession object for host connection :param host: dictionary with the host information :param certs_dir: path pointing to directory with certificates :param key_name: string with a name used for a key and certificate :returns: tuple of paths for key and certificate """ libvirt_pki_private_dir = '/etc/pki/libvirt/private' libvirt_pki_dir = '/etc/pki/libvirt' cmd = "mkdir -p {}".format(libvirt_pki_private_dir) status, output = session.cmd_status_output(cmd) logging.debug( "Making directory for certificates has failed due to: {}".format( output)) src_key_path = os.path.join(certs_dir, key_name + 'key.pem') src_cert_path = os.path.join(certs_dir, key_name + 'cert.pem') dest_key_path = os.path.join(libvirt_pki_private_dir, key_name[:-1] + 'key.pem') dest_cert_path = os.path.join(libvirt_pki_dir, key_name[:-1] + 'cert.pem') # SCP server cert and server key to server remote.copy_files_to(host['ip'], 'scp', host['user'], host['pwd'], '22', src_key_path, dest_key_path) remote.copy_files_to(host['ip'], 'scp', host['user'], host['pwd'], '22', src_cert_path, dest_cert_path) return dest_key_path, dest_cert_path
def _reset_file(self): """ Copy backup from local to remote. """ if self.client == "test": shutil.copy(self.backup_path, self.remote_path) else: remote.copy_files_to(self.address, self.client, self.username, self.password, self.port, self.backup_path, self.remote_path, self.limit, self.log_filename, self.verbose, self.timeout)
def push_file(self, local_path, timeout=600): """ Copy file from local to remote. """ logging.debug("Push local: '%s' to remote: '%s'." % (local_path, self.remote_path)) remote.copy_files_to(self.address, self.cp_client, self.username, self.password, self.cp_port, local_path, self.remote_path, timeout=timeout)
def copy_ca_certs_to_hosts(certs_dir, *host_info): """ Copy certificates to required destination path :param certs_dir: path pointing to directory with certificates :param host_info: multiple dictionaries with the host information :returns: path to destination CA certificate """ ca_cert_path = os.path.join(certs_dir, 'cacert.pem') remote_ca_cert_path = '/etc/pki/CA/cacert.pem' try: for host in host_info: remote.copy_files_to(host['ip'], 'scp', host['user'], host['pwd'], '22', ca_cert_path, remote_ca_cert_path) except remote.SCPError as detail: raise exceptions.TestError(detail) return remote_ca_cert_path
def _copy_control(session, control_path, is_utility=False): remote_dir = REMOTE_PYTHON_PATH if is_utility else REMOTE_CONTROL_DIR # run on remote Linux hosts if session.client == "ssh": transfer_client = "scp" transfer_port = 22 remote_control_path = os.path.join(remote_dir, os.path.basename(control_path)) # run on remote Windows hosts elif session.client == "nc": transfer_client = "rss" transfer_port = 10023 # ..todo:: use `remote_dir` here remote_control_path = "%TEMP%\\" + os.path.basename(control_path) else: raise NotImplementedError( "run_subcontrol not implemented for client %s" % session.client) remote.copy_files_to(session.host, transfer_client, session.username, session.password, transfer_port, control_path, remote_control_path) return remote_control_path
def share_remote_objects(session, control_path, host="localhost", port=9090, os_type="windows", extra_params=None): """ Create and share remote objects from a remote location over the network. :param session: remote session to the platform :type session: RemoteSession :param str control_path: path to the control on the host :param str host: ip address of the remote sharing server :param int port: port of the remote sharing server :param str os_type: OS type of the session, either "linux" or "windows" :param extra_params: extra parameters to pass to the remote object sharing control file (sismilarly to subcontrol setting above), with keys usually prepended with "ro_" prefix :type extra_params: {str, str} :returns: newly created middleware session for the remote object server :rtype: :py:class:`RemoteSession` :raises: :py:class:`RuntimeError` if the object server failed to start In comparison to :py:func:`share_local_object`, this function fires up a name server from a second spawned session (not remote util call) and uses static (template) control as a remote object server which has to be preprogrammed but thus also customized (e.g. sharing multiple objects). In comparison to :py:func:`share_local_objects`, this function is not an internal implementation sharing everything on the other side but only what is dicated by the remote object server module and thus its creator. .. note:: Created and works specifically for Windows and Linux. """ LOG.info("Sharing the remote objects over the network") extra_params = {} if extra_params is None else extra_params # setup remote objects server LOG.info("Starting nameserver for the remote objects") cmd = "python -m Pyro4.naming -n %s -p %s" % (host, port) session.cmd("START " + cmd if os_type == "windows" else cmd + " &") LOG.info("Starting the server daemon for the remote objects") # ..todo:: later on we can dynamize this further depending on usage of this alternative function transfer_client = "rss" if os_type == "windows" else "scp" transfer_port = 10023 if os_type == "windows" else 22 local_path = set_subcontrol_parameter(control_path, "ro_server_ip", host) # optional parameters (set only if present and/or available) for key in extra_params.keys(): local_path = set_subcontrol_parameter(local_path, key, extra_params[key]) remote_path = os.path.join(REMOTE_CONTROL_DIR, os.path.basename(control_path)) # NOTE: since we are creating the path in Linux but use it in Windows, # we replace some of the backslashes if os_type == "windows": remote_path = remote_path.replace("/", "\\") remote.copy_files_to(session.host, transfer_client, session.username, session.password, transfer_port, local_path, remote_path, timeout=10) middleware_session = remote.wait_for_login(session.client, session.host, session.port, session.username, session.password, session.prompt, session.linesep) middleware_session.set_status_test_command(session.status_test_command) middleware_session.set_output_func(LOG.info) middleware_session.set_output_params(()) middleware_session.sendline("python %s" % remote_path) # HACK: not the best way to do this but the stderr and stdout are mixed and we # cannot get the exit status so we rely on the mixed stdout/stderr output output, attempts = "", 30 while "Remote objects shared over the network" not in output: output = middleware_session.get_output() LOG.debug(output) if attempts <= 0 or "Traceback (most recent call last):" in output: raise RuntimeError("The remote objects server failed to start") attempts -= 1 time.sleep(1) Pyro4.config.NS_HOST = host logging.getLogger("Pyro4").setLevel(10) return middleware_session
def sync_directories(self): """ Synchronize the directories between the local and remote machines :returns: True if any files needed to be copied; False otherwise. Does not support symlinks. """ def get_local_hashes(path): """ Create a dict of the hashes of all files in path on the local machine. :param path: Path to search """ def hash_file(file_name): """ Calculate hex-encoded hash of a file :param file_name: File to hash """ f = open(file_name, mode='r') h = hashlib.sha1() while True: buf = f.read(4096) if not buf: break h.update(buf) return h.hexdigest() def visit(arg, dir_name, file_names): """ Callback function to calculate and store hashes :param arg: Tuple with base path and the hash that will contain the results. :param dir_name: Current directory :param file_names: File names in the current directory """ (base_path, result) = arg for file_name in file_names: path = os.path.join(dir_name, file_name) if os.path.isfile(path): result[os.path.relpath(path, base_path)] = hash_file(path) result = {} os.path.walk(path, visit, (path, result)) return result def get_remote_hashes(path, session, linesep): """ Create a dict of the hashes of all files in path on the remote machine. :param path: Path to search :param session: Session object to use :param linesep: Line separation string for the remote system """ cmd = 'test \! -d %s || find %s -type f | xargs sha1sum' % (path, path) status, output = session.cmd_status_output(cmd) if not status == 0: raise BuildError("Unable to get hashes of remote files: '%s'" % output) result = {} # Output is "<sum> <filename><linesep><sum> <filename>..." for line in output.split(linesep): if re.match("^[a-f0-9]{32,} [^ ].*$", line): (h, f) = line.split(None, 1) result[os.path.relpath(f, path)] = h return result def list_recursive_dirnames(path): """ List all directories that exist in path on the local machine :param path: Path to search """ def visit(arg, dir_name, file_names): """ Callback function list all directories :param arg: Tuple with base path and the list that will contain the results. :param dir_name: Current directory :param file_names: File names in the current directory """ (base_path, result) = arg for file_name in file_names: path = os.path.join(dir_name, file_name) if os.path.isdir(path): result.append(os.path.relpath(path, base_path)) result = [] os.path.walk(path, visit, (path, result)) return result remote_hashes = get_remote_hashes(self.full_build_path, self.session, self.linesep) local_hashes = get_local_hashes(self.source) to_transfer = [] for rel_path in list(local_hashes.keys()): rhash = remote_hashes.get(rel_path) if rhash is None or not rhash == local_hashes[rel_path]: to_transfer.append(rel_path) need_build = False if to_transfer: logging.info("Need to copy files to %s on target" % self.full_build_path) need_build = True # Create all directories dirs = list_recursive_dirnames(self.source) if dirs: dirs_text = " ".join(dirs) fmt_arg = (self.full_build_path, self.full_build_path, dirs_text) cmd = 'mkdir -p %s && cd %s && mkdir -p %s' % fmt_arg else: cmd = 'mkdir -p %s' % self.full_build_path status, output = self.session.cmd_status_output(cmd) if not status == 0: raise BuildError("Unable to create remote directories: '%s'" % output) # Copy files for file_name in to_transfer: local_path = os.path.join(self.source, file_name) remote_path = os.path.join(self.full_build_path, file_name) remote.copy_files_to(self.address, self.file_transfer_client, self.username, self.password, self.file_transfer_port, local_path, remote_path) else: logging.info("Directory %s on target already up-to-date" % self.full_build_path) return need_build