def get_file_size_from_server(device, server, path, protocol, timeout=300, fu_session=None): """ Get file size from the server Args: device ('Obj'): Device object server ('str'): server address or hostname path ('str'): file path on server to check protocol ('srt'): protocol used to check file size timeout ('int'): check size timeout in seconds fu_session ('obj'): existing FileUtils object to reuse Returns: integer representation of file size in bytes """ if fu_session: return _get_file_size_from_server(server, path, protocol, timeout=timeout, fu_session=fu_session) else: with FileUtils(testbed=device.testbed) as fu: return _get_file_size_from_server(server, path, protocol, timeout=timeout, fu_session=fu)
def cleanup(self, ip_vm, filename, username_vm): try: with FileUtils(testbed=testbed) as futils: futils.deletefile( f'sftp://{ip_vm}/home/{username_vm}/{filename}') futils.deletefile( f'sftp://{ip_vm}/home/{username_vm}/received_from_host_{filename}' ) # futils.deletefile(target=f'{self.host_path}/received_from_remotevm_{filename}') # futils.deletefile(target=f'{self.host_path}/{filename}') os.remove(f'{self.host_path}/received_from_remotevm_{filename}') os.remove(f'{self.host_path}/{filename}') print( "=========================test files were deleted on both machines" ) except: print("Somthing went wrong while deleting a files...") self.passx("I think it is passed") try: self.vm.disconnect_all() except: print("Somthing went wrong while disconnect all..") self.passx("I think it is passed") self.passed('Cleanup is done')
def delete_file_on_server(testbed, server, path, protocol='sftp', timeout=300, fu_session=None): """ delete the file from server Args: testbed ('obj'): testbed object containing the server info server ('str"): server address or hostname path ('str'): file path on server protocol ('str'): protocol used for deletion, defaults to sftp timeout ('int'): connection timeout Returns: None """ if fu_session: return _delete_file_on_server(server, path, protocol=protocol, timeout=timeout, fu_session=fu_session) else: with FileUtils(testbed=testbed) as fu: return _delete_file_on_server(server, path, protocol=protocol, timeout=timeout, fu_session=fu)
def convert_server_to_linux_device(device, server): """ Args converts a server block to a device object device ('obj'): Device object server ('str'): server hostname Returns: A Device object that can be connected """ with FileUtils(testbed=device.testbed) as fu: server_block = fu.get_server_block(server) hostname = fu.get_hostname(server) device_obj = Device( name=server, os='linux', credentials=server_block.credentials, connections={'linux': { 'ip': hostname, 'protocol': 'ssh' }}, custom={'abstraction': { 'order': ['os'] }}, type='linux', testbed=device.testbed) return device_obj
def stop(self): # Get buffer output = self.device.expect(".*") # send cntrl+c self.device.send('\x03') # Bring back the pcap file if any if self.pcap_file and self.local_dir: # Copy it back to local host # Find server servers = self.device.testbed.servers # Check if there is a self.protocol server if self.protocol not in servers: raise Exception("'{p}' server missing in the testbed " "yaml file".format(p=self.protocol)) # Find ip ip = servers[self.protocol]['address'] port = servers[self.protocol].get('custom', {}).get('port', 22) local_file = os.path.join(self.local_dir, os.path.basename(self.pcap_file)) # Create directory if doesnt exists os.makedirs(self.local_dir, exist_ok=True) with FileUtils(testbed=self.device.testbed) as futils: futils.get_child(self.protocol) futils.children[self.protocol].SSH_DEFAULT_PORT = port futils.copyfile(source='{p}://{i}/{path}'.format( p=self.protocol, i=ip, path=self.pcap_file), destination=self.local_dir) return output
def copy_from(self, env): with FileUtils(testbed=env) as futils: futils.copyfile( source='scp://rrr//home/adminaccount/slavik/3.txt', destination= '/home/jsakhno/github/pyatsTraining/homeworks/yaroslav_sakhno/hw03' )
def verify_file_exists_on_server(device, protocol, file, server=None, size=None, timeout=300, fu_session=None, max_tries=1): """Verify there are enough space on the server Args: device ('obj'): Device object protocol ('str'): Protocol used to check file, ftp or sftp file ('int'): file path server ('str'): Server address or hostname. if not provided it will perform operation on local file system (Optional) size ('int'): expected file size in bytes, if not provided will only check file existence with name (Optional) timeout('int'): timeout in seconds (Optional) fu_session ('obj'): existing FileUtils object to reuse (Optional) max_tries ('int;): max number of attempts (Optional) Returns: True if enough space, false otherwise """ # global session if fu_session: return _verify_file_exists_on_server(device, protocol, file, server=server, size=size, timeout=timeout, fu_session=fu_session, max_tries=max_tries) # no global session, establish a local one else: with FileUtils(testbed=device.testbed) as fu: return _verify_file_exists_on_server(device, protocol, file, server=server, size=size, timeout=timeout, fu_session=fu, max_tries=max_tries)
def verify_enough_server_disk_space(device, protocol, server=None, directory='.', required_space=None, timeout=300, fu_session=None): """Verify there are enough space on the server Args: device ('obj'): Device object protocol ('str'): Protocol used to check disk space, scp or sftp server ('str'): Server address or hostname. if not provided it will perform operation on local file system (Optional) required_space ('int'): required total disk space (Optional) directory ('str'): directory to check file size (Optional) timeout('int'): timeout in seconds (Optional, default 300) fu_session ('obj'): existing FileUtils object to reuse (Optional) Returns: True if enough space, False otherwise """ if fu_session: return _verify_enough_server_disk_space(device, protocol, server=server, directory=directory, required_space=required_space, timeout=timeout, fu_session=fu_session) else: with FileUtils(testbed=device.testbed) as fu: return _verify_enough_server_disk_space(device, protocol, server=server, directory=directory, required_space=required_space, timeout=timeout, fu_session=fu)
def verify_file_size_stable_on_server(device, protocol, file, server=None, max_tries=3, delay=2, timeout=300, fu_session=None): """Verify size stability of given file on the server Args: device ('obj'): Device object server ('str'): Server address or hostname. if not provided it will perform operation on local file system (Optional) protocol ('str'): Protocol used to check file, ftp or sftp file ('int'): file path timeout ('int'): timeout in seconds fu_session ('obj'): existing FileUtils object to reuse max_tries ('int'): number of tries to check file stability, defaults 3 delay ('int'): time delay between tries in seconds, defaults 2 Returns: True if file size is stable, false otherwise """ # global session if fu_session: return _verify_file_size_stable_on_server(device, protocol, file, server=server, max_tries=max_tries, delay=delay, timeout=timeout, fu_session=fu_session) # no global session, establish a local one else: with FileUtils(testbed=device.testbed) as fu: return _verify_file_size_stable_on_server(device, protocol, file, server=server, max_tries=max_tries, delay=delay, timeout=timeout, fu_session=fu)
def copy_file_from_vm_to_host(self, ip_vm, filename, username_vm): try: with FileUtils(testbed=testbed) as futils: futils.copyfile( source=f'sftp://{ip_vm}/home/{username_vm}/{filename}', destination= f'{self.host_path}/received_from_remotevm_{filename}') except: print('while copying file from vm to host...something went wrong')
def copy_to_server(testbed, protocol, server, local_path, remote_path, timeout=300, fu_session=None, quiet=False): """ Copy file from directory to server Args: testbed ('obj'): Testbed object protocol ('str'): Transfer protocol server ('str'): Server name in testbed yaml or server ip address local_path ('str'): File to copy, including path remote_path ('str'): Where to save the file, including file name timeout('int'): timeout value in seconds, default 300 fu_session ('obj'): existing FileUtils object to reuse quiet ('bool'): quiet mode -- does not print copy progress Returns: None Raises: Exception """ if fu_session: _copy_to_server(protocol, server, local_path, remote_path, timeout=timeout, fu_session=fu_session, quiet=quiet) else: with FileUtils(testbed=testbed) as fu: _copy_to_server(protocol, server, local_path, remote_path, timeout=timeout, fu_session=fu, quiet=quiet)
def copy_to_server(testbed, protocol, server, local_path, remote_path): """ Copy file from directory to server Args: testbed ('obj'): Testbed object protocol ('str'): Transfer protocol server ('str'): Server name in testbed yaml or server ip address local_path ('str'): File to copy, including path remote_path ('str'): Where to save the file, including file name Returns: None Raises: Exception """ try: # Check if server argument is an IP address IPAddress(server) except Exception: try: # Check if server argument is a server defined in testbed yaml server = testbed.servers[server]["address"] except Exception: raise Exception( "> For 'server' argument either provide an ip address\n" "> OR\n" "> configure the following in your testbed yaml and provide <protocol>:\n" "> --------------------------------\n" "> testbed:\n" "> servers:\n" "> <protocol>:\n" "> address: <address>\n" "> --------------------------------") # Building remote address remote = "{p}://{s}:/{f}".format(p=protocol, s=server, f=remote_path) log.info("Copying {local_path} to {remote_path}".format( local_path=local_path, remote_path=remote)) with FileUtils(testbed=testbed) as futils: futils.copyfile(source=local_path, destination=remote)
def check_file_existense(self, filename, ip_vm, username_vm): try: if os.path.exists( f'{self.host_path}/received_from_remotevm_{filename}' ) and self.vm.execute( f'ls -la /home/pyast/received_from_host_{filename}'): print( '*****************************************************************File is received on host comp' ) with FileUtils(testbed=testbed) as futils: if futils.checkfile( f'sftp://{ip_vm}/home/{username_vm}/received_from_host_{filename}' ): print( '**************************************************************File is received on remote vm' ) else: raise Exception except: print("Something went wrong while checking copied files") self.passed('Files are copied correctly')
def copy_to_device(self, steps, device, origin, destination, protocol, verify_num_images=VERIFY_NUM_IMAGES, expected_num_images=EXPECTED_NUM_IMAGES, vrf=VRF, timeout=TIMEOUT, compact=COMPACT, use_kstack=USE_KSTACK, protected_files=PROTECTED_FILES, overwrite=OVERWRITE, skip_deletion=SKIP_DELETION, copy_attempts=COPY_ATTEMPTS, copy_attempts_sleep=COPY_ATTEMPTS_SLEEP, check_file_stability=CHECK_FILE_STABILITY, stability_check_tries=STABILITY_CHECK_TRIES, stability_check_delay=STABILITY_CHECK_DELAY, min_free_space_percent=MIN_FREE_SPACE_PERCENT, **kwargs): switch_image = None controller_image = None # ['aci-apic-dk9.5.1.2e.iso', 'aci-n9000-dk9.15.1.2e.bin'] with steps.start('Checking image file versions') as step: controller_image_version = 'unknown' switch_image_version = 'unknown' image_files = origin.get('files') for fn in image_files: if 'apic' in fn: controller_image = fn controller_image_version = apic_get_firmware_version_from_image_name( device, controller_image) elif 'n9000' in fn: switch_image = fn switch_image_version = nxos_aci_get_firmware_version_from_image_name( device, switch_image) log.info(f'Controller image version: {controller_image_version}') log.info(f'Switch image version: {switch_image_version}') with steps.start('Checking fabric versions') as step: if not device.connected: device.connect() version_info = device.parse('show version') try: controller_version = version_info['pod'][1]['node'][1][ 'version'] except KeyError: log.debug('Could not get info from show version', exc_info=True) controller_version = 'unknown' if controller_image_version: with step.start( "Checking controller image version") as substep: if controller_version == controller_image_version: upgrade_msg = ', skipping upgrade' image_files.remove(controller_image) else: upgrade_msg = ', upgrade needed' log.info( 'Controller {} version: {}, controller image version: {}{}' .format(device.name, controller_version, controller_image_version, upgrade_msg)) download_switch_image = False with step.start("Checking switch image versions") as substep: for node_idx in version_info['pod'][1]['node']: if node_idx > 100: node_version = version_info['pod'][1]['node'][ node_idx]['version'] if node_version != switch_image_version: log.info( 'Switch {}, version {}, upgrade needed'.format( node_idx, node_version)) download_switch_image = True break else: log.info('Switch {}, version {}'.format( node_idx, node_version)) if download_switch_image is False and switch_image in image_files: image_files.remove(switch_image) if image_files: log.info(f'Images to download: {image_files}') log.info( "Section steps:\n1- Verify correct number of images provided" "\n2- Get filesize of image files on remote server" "\n3- Check if image files already exist on device" "\n4- (Optional) Verify stability of image files" "\n5- Verify free space on device else delete unprotected files" "\n6- Copy image files to device" "\n7- Verify copied image files are present on device") # list of destination directories destinations = [] # Get args server = origin['hostname'] # Establish FileUtils session for all FileUtils operations file_utils = FileUtils(testbed=device.testbed) string_to_remove = file_utils.get_server_block(server).get('path', '') image_files = remove_string_from_image(images=origin['files'], string=string_to_remove) # Set active node destination directory destination_act = destination['directory'] # Set standby node destination directory if 'standby_directory' in destination: destination_stby = destination['standby_directory'] destinations = [destination_stby, destination_act] else: destination_stby = None destinations = [destination_act] # Check remote server info present in testbed YAML if not file_utils.get_server_block(server): self.failed("Server '{}' was provided in the clean yaml file but " "doesn't exist in the testbed file.\n".format(server)) # Check image files provided if verify_num_images: # Verify correct number of images provided with steps.start( "Verify correct number of images provided") as step: if not verify_num_images_provided( image_list=image_files, expected_images=expected_num_images): step.failed( "Incorrect number of images provided. Please " "provide {} expected image(s) under destination" ".path in clean yaml file.\n".format( expected_num_images)) else: step.passed("Correct number of images provided") # Loop over all image files provided by user for index, file in enumerate(image_files): # Init files_to_copy = {} unknown_size = False # Get filesize of image files on remote server with steps.start("Get filesize of '{}' on remote server '{}'".\ format(file, server)) as step: try: file_size = device.api.get_file_size_from_server( server=file_utils.get_hostname(server), path=file, protocol=protocol, timeout=timeout, fu_session=file_utils) except FileNotFoundError: step.failed( "Can not find file {} on server {}. Terminating clean". format(file, server)) except Exception as e: log.warning(str(e)) # Something went wrong, set file_size to -1 file_size = -1 unknown_size = True err_msg = "\nUnable to get filesize for file '{}' on "\ "remote server {}".format(file, server) if overwrite: err_msg += " - will copy file to device" step.passx(err_msg) else: step.passed("Verified filesize of file '{}' to be " "{} bytes".format(file, file_size)) for dest in destinations: # Execute 'dir' before copying image files dir_before = device.execute('ls -l {}'.format(dest)) # Check if file with same name and size exists on device dest_file_path = os.path.join(dest, os.path.basename(file)) image_mapping = self.history[ 'CopyToDevice'].parameters.setdefault('image_mapping', {}) image_mapping.update({origin['files'][index]: dest_file_path}) with steps.start("Check if file '{}' exists on device {} {}".\ format(dest_file_path, device.name, dest)) as step: # Check if file exists try: exist = device.api.verify_file_exists( file=dest_file_path, size=file_size, dir_output=dir_before) except Exception as e: exist = False log.warning( "Unable to check if image '{}' exists on device {} {}." "Error: {}".format(dest_file_path, device.name, dest, str(e))) if (not exist) or (exist and overwrite): # Update list of files to copy file_copy_info = { file: { 'size': file_size, 'dest_path': dest_file_path, 'exist': exist } } files_to_copy.update(file_copy_info) # Print message to user step.passed("Proceeding with copying image {} to device {}".\ format(dest_file_path, device.name)) else: step.passed( "Image '{}' already exists on device {} {}, " "skipping copy".format(file, device.name, dest)) # Check if any file copy is in progress if check_file_stability: for file in files_to_copy: with steps.start("Verify stability of file '{}'".\ format(file)) as step: # Check file stability try: stable = device.api.verify_file_size_stable_on_server( file=file, server=file_utils.get_hostname(server), protocol=protocol, fu_session=file_utils, delay=stability_check_delay, max_tries=stability_check_tries) if not stable: step.failed( "The size of file '{}' on server is not " "stable\n".format(file), ) else: step.passed( "Size of file '{}' is stable".format( file)) except NotImplementedError: # cannot check using tftp step.passx( "Unable to check file stability over {protocol}" .format(protocol=protocol)) except Exception as e: log.error(str(e)) step.failed( "Error while verifying file stability on " "server\n") # Verify available space on the device is sufficient for image copy, delete # unprotected files if needed, copy file to the device # unless overwrite: False if files_to_copy: with steps.start( "Verify sufficient free space on device '{}' '{}' or delete" " unprotected files".format(device.name, dest)) as step: if unknown_size: total_size = -1 log.warning( "Amount of space required cannot be confirmed, " "copying the files on the device '{}' '{}' may fail" .format(device.name, dest)) if not protected_files: protected_files = [r'^.+$(?<!\.bin)(?<!\.iso)'] # Try to free up disk space if skip_deletion is not set to True if not skip_deletion: # TODO: add golden images, config to protected files once we have golden section golden_config = find_clean_variable( self, 'golden_config') golden_image = find_clean_variable( self, 'golden_image') if golden_config: protected_files.extend(golden_config) if golden_image: protected_files.extend(golden_image) # Only calculate size of file being copied total_size = sum( 0 if file_data['exist'] else file_data['size'] for file_data in files_to_copy.values()) try: free_space = device.api.free_up_disk_space( destination=dest, required_size=total_size, skip_deletion=skip_deletion, protected_files=protected_files, min_free_space_percent= min_free_space_percent) if not free_space: step.failed( "Unable to create enough space for " "image on device {} {}".format( device.name, dest)) else: step.passed( "Device {} {} has sufficient space to " "copy images".format( device.name, dest)) except Exception as e: log.error(str(e)) step.failed( "Error while creating free space for " "image on device {} {}".format( device.name, dest)) # Copy the file to the devices for file, file_data in files_to_copy.items(): with steps.start("Copying image file {} to device {} {}".\ format(file, device.name, dest)) as step: # Copy file unless overwrite is False if not overwrite and file_data['exist']: step.skipped( "File with the same name size exists on " "the device {} {}, skipped copying".format( device.name, dest)) for i in range(1, copy_attempts + 1): try: device.api.\ copy_to_device(protocol=protocol, server=file_utils.get_hostname(server), remote_path=file, local_path=file_data['dest_path'], vrf=vrf, timeout=timeout, compact=compact, use_kstack=use_kstack, **kwargs) except Exception as e: # if user wants to retry if i < copy_attempts: log.warning( "Could not copy file '{file}' to '{d}', {e}\n" "attempt #{iteration}".format( file=file, d=device.name, e=e, iteration=i + 1)) log.info( "Sleeping for {} seconds before retrying" .format(copy_attempts_sleep)) time.sleep(copy_attempts_sleep) else: substep.failed("Could not copy '{file}' to '{d}'\n{e}"\ .format(file=file, d=device.name, e=e)) else: log.info( "File {} has been copied to {} on device {}" " successfully".format( file, dest, device.name)) break # Save the file copied path and size info for future use history = self.history['CopyToDevice'].parameters.\ setdefault('files_copied', {}) history.update({file: file_data}) with steps.start("Verify images successfully copied") as step: # If nothing copied don't need to verify, skip if 'files_copied' not in self.history[ 'CopyToDevice'].parameters: step.skipped( "Image files were not copied for {} {} in previous steps, " "skipping verification steps".format( device.name, dest)) # Execute 'dir' after copying image files dir_after = device.execute('dir {}'.format(dest)) for name, image_data in self.history['CopyToDevice'].\ parameters['files_copied'].items(): with step.start("Verify image '{}' copied to {} on device {}".\ format(image_data['dest_path'], dest, device.name)) as substep: # if size is -1 it means it failed to get the size if image_data['size'] != -1: if not device.api.verify_file_exists( file=image_data['dest_path'], size=image_data['size'], dir_output=dir_after): substep.failed("Size of image file copied to device {} is " "not the same as remote server filesize".\ format(device.name)) else: substep.passed("Size of image file copied to device {} is " "the same as image filesize on remote server".\ format(device.name)) else: substep.skipped( "Image file has been copied to device {} correctly" " but cannot verify file size".format( device.name)) self.passed("Copy to device completed")
def copy_to_local_pc(self, tb): with FileUtils(testbed=tb) as futils: futils.copyfile( source='scp://192.168.195.143/home/adminaccount/some.txt', destination='/home/marian/github/pyatsTraining/homeworks/magurmarian/hw3')
def copy_file_to_server(device: Device) -> None: futils = FileUtils(testbed=device.testbed) futils.copyfile( source=f"{os.path.join(os.getcwd(), 'docker-compose.yaml')}", destination=f"scp://{device.connections.main.ip}/home/vagrant/oct", )
def update_install_repository(self, steps, device, image, tftp_server=TFTP_SERVER, packages=None, install_timeout=INSTALL_TIMEOUT, source_directory=SOURCE_DIRECTORY): if packages is None: packages = [] with steps.start("Adding image and any provided packages to the " "install repository") as step: # Get Ip address of tftp server if tftp_server is provided if tftp_server: if not hasattr(device.testbed, 'servers'): step.failed("Cannot find any servers in the testbed") fu = FileUtils(testbed=device.testbed) tftp_server = fu.get_hostname(tftp_server) # Get Image Files from install_image_and_packages # Get Image Files from TFTP path if tftp_server is provided if tftp_server: # Separate directory and image directory, image = self._getFileNameFromPath(image[0]) pkgs = '' for pkg in packages: _, pkg = self._getFileNameFromPath(pkg) pkgs += ' ' + pkg directory = '{p}://{s}/{f}'.format(p='tftp', s=tftp_server, f=directory) # Get Image Files in device location elif ':' in image[0]: # Separate directory and image directory, image = self._getFileNameFromPath(image[0]) # Get packages and remove directories # pkgs = ' pkg1 pkg2 pkg3 ...' pkgs = '' for pkg in packages: _, pkg = self._getFileNameFromPath(pkg) pkgs += ' ' + pkg else: directory = source_directory _, image = self._getFileNameFromPath(image[0]) # Get packages and remove directories # pkgs = ' pkg1 pkg2 pkg3 ...' pkgs = '' for pkg in packages: _, pkg = self._getFileNameFromPath(pkg) pkgs += ' ' + pkg # install add tftp://tftp_server_ip/tftp_path/ <image> <pkg1> <pkg2> or # install add source flash: <image> <pkg1> <pkg2> cmd = 'install add source {dir} {image} {packages}'.format( dir=directory, image=image, packages=pkgs) try: device.execute(cmd, timeout=install_timeout, error_pattern=self.error_patterns) out = device.expect([self.successful_operation_string], trim_buffer=False, timeout=install_timeout) except Exception as e: step.failed("The command '{cmd}' failed. Error: {e}".format( cmd=cmd, e=str(e))) out = out.match_output # If code execution reaches here the regex has already been matched # via the expect. So we know it will match again here. We just need # to retrieve the operation id for the next steps. p1 = re.compile(self.successful_operation_string) for line in out.splitlines(): m = p1.match(line) if m: self.operation_id = m.groupdict()['id'] break step.passed("The command '{cmd}' succeeded. The " "operation ID is '{operation_id}'".format( cmd=cmd, operation_id=self.operation_id))