Esempio n. 1
0
    def _prepare_issu(self, steps, upgrade_image):
        """Prepare the device for ISSU:

            1. Check currect image version and upgrade image version
            2. Copy upgrade image to standby RP

        Raises:
            Unicon errors
            Exception

        Example:
            >>> _prepare_issu(steps=steps, upgrade_image='someimage')
        """

        # Init
        device = self.device
        filetransfer = FileUtils.from_device(device)

        if not hasattr(self.device, 'filetransfer_attributes'):
            filetransfer = FileUtils.from_device(self.device)
            set_filetransfer_attributes(self, self.device, filetransfer)

        for disk in ['harddisk:', 'stby-harddisk:']:

            # Check for space on RP and SRP
            logger.info("Verify '{}' has enough space".format(disk))
            try:
                self.check_disk_space(device=device,
                                      disk=disk,
                                      image=upgrade_image)
            except Exception as e:
                raise Exception(
                    "FAIL: Device '{}' does not have enough space -"
                    " skipping ISSU".format(disk))

            # Copy ISSU upgrade image to disk
            logger.info("Copy ISSU upgrade image to {}".format(disk))
            from_url = '{protocol}://{address}/{upgrade_image}'.format(
                protocol=device.filetransfer_attributes['protocol'],
                address=device.filetransfer_attributes['server_address'],
                upgrade_image=upgrade_image)
            filetransfer.copyfile(source=from_url,
                                  destination=disk,
                                  device=device,
                                  timeout_seconds='600')

            # Verify location:<filename> exists
            output = device.execute('dir {disk}{image}'.format(
                disk=disk, image=basename(upgrade_image)))
            if 'Error' not in output:
                logger.info("Copied ISSU image to '{}'".format(disk))
            else:
                raise Exception(
                    "Unable to copy ISSU image to '{}'".format(disk))
Esempio n. 2
0
    def upload_core_to_linux(self, core):
        """Upload core files to composed path.

        Args:
          Mandatory:
            core (`str`) : Core file

        Example:
            >>> upload_core_to_linux(core='RP_0_bt_logger_13899_20180112-184444-EST.core.gz')
        """

        # if the setup was not done because the configure subsection did
        # not run, then we do the setup here
        if not hasattr(self.device, 'filetransfer_attributes'):
            filetransfer = FileUtils.from_device(self.device)
            set_filetransfer_attributes(self, self.device, filetransfer)

        filename, core = self.get_upload_cmd(**core)
        message = "Core dump upload attempt: {}".format(filename)

        from_URL = 'core:{core}'.format(core=core)

        to_URL = '{protocol}://{address}/{path}/{filename}'.format(
            protocol=self.device.filetransfer_attributes['protocol'],
            address=self.device.filetransfer_attributes['server_address'],
            path=self.device.filetransfer_attributes['path'],
            filename=filename)

        self.filetransfer.copyfile(device=self.device,
                                   source=from_URL,
                                   destination=to_URL)
Esempio n. 3
0
    def save_configuration(self,
                           device,
                           method,
                           abstract,
                           default_dir,
                           copy_to_standby=False):
        ''' Save current configuration to a checkpoint file '''

        if method == 'checkpoint' or method == 'config_replace':
            # Create unique filename
            self.to_url = self.__class__.__name__ + time.ctime().\
                                                      replace(' ', '_').\
                                                      replace(':', '_')

            # Save configuration
            self.create_checkpoint_file(device=device, file=self.to_url)

            # Instantiate a filetransferutils instance for JunOS device
            self.filetransfer = FileUtils.from_device(device)

            # Verify checkpoint file exists
            if self.to_url in self.filetransfer.dir(target=self.to_url,
                                                    device=device):
                log.info("Successfully created checkpoint/file '{}'".\
                         format(self.to_url))
            else:
                raise Exception("Unable to create checkpoint/file '{}'".\
                                format(self.to_url))

            # Return filename generated to caller
            return self.to_url

        else:
            raise NotImplementedError("save configuration using method '{}'".\
                                      format(method))
Esempio n. 4
0
    def save_configuration(self,
                           device,
                           method,
                           abstract,
                           default_dir,
                           copy_to_standby=False):
        if method == 'checkpoint':
            # compose checkpoint name
            self.ckname = self.__class__.__name__ + \
                          time.ctime().replace(' ', '_').replace(':', '_')
            # Create checkpoint
            self.create_delete_checkpoint(device=device,
                                          name=self.ckname,
                                          abstract=abstract,
                                          action='create')
            # Check if checkpoint is successfully created
            self.check_checkpoint_status(device=device,
                                         name=self.ckname,
                                         abstract=abstract)
        elif method == 'local':
            self.run_config = device.execute('show running-config')

        elif method == 'config_replace':

            # Create unique filename
            self.filename = self.__class__.__name__ + \
                                time.ctime().replace(' ', '_').replace(':', '_')

            # Set from/to locations
            self.from_url = 'running-config'
            self.to_url = '{dir}{filename}'.format(
                filename=self.filename, dir=default_dir[device.name])

            # Instantiate a filetransferutils instance for IOSXE device
            self.filetransfer = FileUtils.from_device(device)

            # Execute copy running-config to location:<filename>
            self.filetransfer.copyconfiguration(source=self.from_url,
                                                destination=self.to_url,
                                                device=device)

            if copy_to_standby:
                self.stby_url = '{dir}{filename}'.format(
                    dir='stby-{}'.format(default_dir[device.name]),
                    filename=self.filename)

                # copy config to stby-bootflash:
                self.filetransfer.copyconfiguration(source=self.from_url,
                                                    destination=self.stby_url,
                                                    device=device)

            # Verify location:<filename> exists
            created = self.filetransfer.stat(target=self.to_url, device=device)
            if created:
                log.info("Successfully created '{}'".format(self.to_url))
            else:
                raise Exception("Unable to create '{}'".format(self.to_url))

            # Return filename generated to caller
            return self.to_url
Esempio n. 5
0
    def _prepare_issu(self, steps, upgrade_image):
        """Prepare the device for ISSU:

            1. Check currect image version and upgrade image version
            2. Copy upgrade image to standby RP

            NXOS:
            1. Copy image onto the device

        Raises:
            Unicon errors
            Exception

        Example:
            >>> _prepare_issu(steps=steps, upgrade_image='someimage')
        """

        # # Init
        device = self.device

        if not hasattr(self.device, 'filetransfer_attributes'):
            filetransfer = FileUtils.from_device(self.device)
            set_filetransfer_attributes(self, self.device, filetransfer)

        disk = "bootflash:"
        timeout_seconds = 600

        with steps.start('Check available diskspace') as step:
            dir_output = filetransfer.parsed_dir(disk, timeout_seconds, Dir)

            if int(dir_output['disk_free_space']) < 4500000000:
                step.failed(
                    "Not enough free space available to copy over the image.Free up atleast 4.5GB of space on {}"
                    .format(disk))

        with steps.start('Copy over the issu image') as step:
            # Copy ISSU upgrade image to disk

            from_url = '{protocol}://{address}/{upgrade_image}'.format(
                protocol=device.filetransfer_attributes['protocol'],
                address=device.filetransfer_attributes['server_address'],
                upgrade_image=upgrade_image)
            filetransfer.copyfile(source=from_url,
                                  destination=disk,
                                  device=device,
                                  vrf='management',
                                  timeout_seconds=600)

            # Verify location:<filename> exists
            output = device.execute('dir {disk}{image}'.format(
                disk=disk, image=basename(upgrade_image)))

            if 'No such file or directory' not in output:
                log.info("Copied ISSU image to '{}'".format(disk))
            else:
                step.failed(
                    'Required ISSU image {} not found on disk. Transfer failed.'
                    .format(basename(upgrade_image)))
 def test_fu_from_device_protocol(self):
     # Instantiate a filetransferutils instance for each os and protocol
     for os_ in ['ios', 'iosxe', 'iosxr', 'nxos']:
         device = AttrDict(os=os_)
         for proto in ['ftp', 'tftp', 'scp', 'sftp', 'http']:
             fu = FileUtils.from_device(device, protocol=proto)
             self.assertIn(
                 'genie.libs.filetransferutils.plugins.{os_}.{proto}.fileutils.FileUtils'
                 .format(os_=os_, proto=proto),
                 str(fu.__class__))
             self.assertEqual(fu.protocol, proto)
             self.assertEqual(fu.os, os_)
Esempio n. 7
0
 def save_configuration_to_file(self, device, default_dir, file_name):
     ''' Save current configuration to file on device
     '''
     file_path = '{}{}'.format(default_dir, file_name)
     try:
         # Instantiate a filetransferutils instance for IOSXE device
         self.filetransfer = FileUtils.from_device(device)
         self.filetransfer.copyconfiguration(source='running-config',
                                             destination=file_path,
                                             device=device)
     except Exception as e:
         log.error(e)
         raise Exception(
             "Issue saving config to {c}".format(c=file_path)) from e
Esempio n. 8
0
def delete_unprotected_files(device,
                             directory,
                             protected,
                             files_to_delete=None,
                             dir_output=None):
    """delete all files not matching regex in the protected list
        Args:
            device ('obj'): Device object
            directory ('str'): working directory to perform the operation
            protected ('list'): list of file patterns that won't be deleted. If it begins
                                and ends with (), it will be considered as a regex
            files_to_delete('list') list of files that should be deleted unless they are not protected
            dir_output ('str'): output of dir command, if not provided execute the cmd on device to get the output
        Returns:
            None
            """

    fu_device = FileUtils.from_device(device)
    file_set = set(
        Dq(device.parse('ls -l {}'.format(directory),
                        output=dir_output)).get_values('files'))

    protected_set, not_protected = _protected_and_unprotected_files(
        file_set, protected, files_to_delete)
    error_messages = []

    if not_protected:
        log.info("The following files will be deleted:\n{}".format(
            '\n'.join(not_protected)))
        dont_delete_list = protected_set.intersection(files_to_delete)
        if dont_delete_list:
            log.info(
                "The following files will not be deleted because they are protected:\n{}"
                .format('\n'.join(dont_delete_list)))
        for file in not_protected:
            # it's a directory, dont delete
            if file.endswith('/'):
                continue
            log.info('Deleting the unprotected file "{}"'.format(file))
            try:
                fu_device.deletefile(file, device=device)
            except Exception as e:
                error_messages.append('Failed to delete file "{}" due '
                                      'to :{}'.format(file, str(e)))
        if error_messages:
            raise Exception('\n'.join(error_messages))
    else:
        log.info(
            "No files will be deleted, the following files are protected:\n{}".
            format('\n'.join(protected_set)))
Esempio n. 9
0
def copy_to_device(device,
                   remote_path,
                   local_path,
                   server,
                   protocol,
                   vrf=None,
                   timeout=300,
                   compact=False,
                   use_kstack=False,
                   username=None,
                   password=None,
                   **kwargs):
    """
    Copy file from linux server to device
        Args:
            device ('Device'): Device object
            remote_path ('str'): remote file path on the server
            local_path ('str'): local file path to copy to on the device
            server ('str'): hostname or address of the server
            protocol('str'): file transfer protocol to be used
            vrf ('str'): vrf to use (optional)
            timeout('int'): timeout value in seconds, default 300
            compact('bool'): compress image option for n9k, defaults False
            username('str'): Username to be used during copy operation
            password('str'): Password to be used during copy operation
            use_kstack('bool'): Use faster version of copy, defaults False
                                Not supported with a file transfer protocol
                                prompting for a username and password
        Returns:
            None
    """
    # aci uses the linux implementation and fileutils doesnt support
    # os/platform abstraction
    setattr(device, 'os', 'linux')
    fu = FileUtils.from_device(device)
    setattr(device, 'os', 'nxos')

    generic_copy_to_device(device=device,
                           remote_path=remote_path,
                           local_path=local_path,
                           server=server,
                           protocol=protocol,
                           vrf=vrf,
                           timeout=timeout,
                           compact=compact,
                           use_kstack=use_kstack,
                           username=username,
                           password=password,
                           fu=fu,
                           **kwargs)
Esempio n. 10
0
def copy_issu_image_to_disk(device,
                            disk,
                            path,
                            address,
                            image,
                            protocol="tftp",
                            timeout_seconds=600,
                            wait_time_after_copy=0,
                            overwrite=False):
    """ Copy image from a server to disk
        Args:
            device ('obj'): Device object
            disk ('str'): Disk name
            address ('str'): Server address
            path ('str'): Path on server
            protocol ('str'): Transfer protocol
            image ('str'): Image name
            timeout_seconds ('int'): Maximum duration to wait for file copy
            wait_time_after_copy ('int'): Wait time after file copy
            overwrite ('bool'): Flag to overwrite existing file
        Raises:
            Exception: Failed copying ISSU image to disk
        Returns:
            None
    """

    from_url = "{protocol}://{address}/{path}/{image}".format(
        protocol=protocol, address=address, path=path, image=image)

    filetransfer = FileUtils.from_device(device)

    filetransfer.copyfile(source=from_url,
                          destination=disk,
                          device=device,
                          timeout_seconds=timeout_seconds,
                          overwrite=overwrite)

    time.sleep(wait_time_after_copy)

    output = device.execute("dir {disk}{image}".format(disk=disk,
                                                       image=basename(image)))
    if "Error" not in output:
        log.info("Copied ISSU image to '{disk}'".format(disk=disk))
    else:
        raise Exception(
            "Unable to copy ISSU image to '{disk}'".format(disk=disk))
Esempio n. 11
0
def copy_from_device(device,
                     remote_path,
                     local_path,
                     server,
                     protocol,
                     vrf=None,
                     timeout=300,
                     **kwargs):
    """
    Copy file from device to linux server (Works for sftp and ftp)
        Args:
            device ('Device'): Device object
            remote_path ('str'): remote file path to copy to on the server
            local_path ('str'): local file path to copy from the device
            server ('str'): hostname or address of the server
            protocol('str'): file transfer protocol to be used
            vrf ('str'): vrf to use (optional)
            timeout('int'): timeout value in seconds, default 300
        Returns:
            None
    """

    fu = FileUtils.from_device(device)

    # build the source address
    destination = '{p}://{s}/{f}'.format(p=protocol, s=server, f=remote_path)
    if vrf:
        fu.copyfile(source=local_path,
                    destination=destination,
                    device=device,
                    vrf=vrf,
                    timeout_seconds=timeout,
                    **kwargs)
    else:
        fu.copyfile(source=local_path,
                    destination=destination,
                    device=device,
                    timeout_seconds=timeout,
                    **kwargs)
Esempio n. 12
0
class test_filetransferutils(unittest.TestCase):
    # Instantiate tesbed and device objects
    tb = Testbed(name='myTestbed')
    device = Device(testbed=tb, name='aDevice', os='junos')

    # Instantiate a filetransferutils instance for Junos device
    fu_device = FileUtils.from_device(device)

    # Add testbed servers for authentication
    device.testbed.servers = AttrDict(server_name=dict(username="******",
                                                       password="******",
                                                       address='1.1.1.1'), )

    # Mock device output
    raw1 = '''
            file copy golden_config ftp://[email protected]:/test/ 
            Password for [email protected]:
            ftp://[email protected]:/test/golden_config     100% of 3040  B   11 MBps

    '''

    outputs = {}
    outputs['file copy golden_config ftp://[email protected]:/test/']\
         = raw1

    def mapper(self, key, timeout=None, reply=None, prompt_recovery=False):
        return self.outputs[key]

    def test_copyfile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        # Call copyfiles
        self.fu_device.copyfile(source='golden_config',
                                destination='ftp://1.1.1.1:/test/',
                                timeout_seconds='300',
                                device=self.device)
class test_filetransferutils(unittest.TestCase):
    # Instantiate tesbed and device objects
    tb = Testbed(name='myTestbed')
    device = Device(testbed=tb, name='aDevice', os='iosxe')

    # Instantiate a filetransferutils instance for IOSXE device
    fu_device = FileUtils.from_device(device)

    # Add testbed servers for authentication
    device.testbed.servers = AttrDict(server_name=dict(username="******",
                                                       password="******",
                                                       address='1.1.1.1'), )

    dir_output = [
        'flash:/nvram_config', 'flash:/.rollback_timer', 'flash:/memleak.tcl',
        'flash:/bootloader_evt_handle.log', 'flash:/ISSUCleanGolden',
        'flash:/gs_script', 'flash:/.prst_sync', 'flash:/nvram_config_bkup',
        'flash:/tech_support', 'flash:/dc_profile_dir',
        'flash:/RestoreTue_Mar_20_12_19_11_2018-Mar-20-11-20-09.900-0',
        'flash:/vlan.dat', 'flash:/core', 'flash:/tools', 'flash:/CRDU',
        'flash:/.dbpersist',
        'flash:/RestoreTue_Mar_20_12_13_39_2018-Mar-20-11-14-38.106-0',
        'flash:/iox', 'flash:/onep', 'flash:/boothelper.log',
        'flash:/stby-vlan.dat', 'flash:/.installer'
    ]

    # Mock device output
    raw1 = '''
        copy flash:/memleak.tcl ftp://1.1.1.1//auto/tftp-ssr/memleak.tcl
        Address or name of remote host [1.1.1.1]? 
        Destination filename [/auto/tftp-ssr/memleak.tcl]? 
        !!
        104260 bytes copied in 0.396 secs (263283 bytes/sec)
    '''

    raw2 = '''
        Directory of flash:/

        69698  drwx             4096  Mar 20 2018 10:25:11 +00:00  .installer
        69720  -rw-          2097152  Mar 20 2018 13:09:24 +00:00  nvram_config
        69700  -rw-            90761  Mar 20 2018 10:25:27 +00:00  bootloader_evt_handle.log
        69701  drwx             4096   Feb 1 2018 13:44:32 +00:00  core
        15489  drwx             4096  Mar 20 2018 10:31:08 +00:00  .prst_sync
        30977  drwx             4096   May 2 2016 07:58:53 +00:00  .rollback_timer
        38722  drwx             4096  Mar 20 2018 10:25:43 +00:00  dc_profile_dir
        69699  -rw-               76  Mar 20 2018 10:25:46 +00:00  boothelper.log
        69705  -rw-           104260  Mar 20 2018 10:26:01 +00:00  memleak.tcl
        69706  drwx             4096   May 2 2016 08:11:23 +00:00  onep
        69714  drwx             4096  Aug 13 2016 08:55:12 +00:00  iox
        69734  -rw-             3496  Mar 11 2018 17:40:26 +00:00  vlan.dat
        69708  -rw-        617329255  Sep 27 2017 09:11:39 +00:00  ISSUCleanGolden
        69709  drwx             4096   Aug 3 2016 08:07:47 +00:00  gs_script
        69712  drwx             4096  Mar 19 2017 09:26:23 +00:00  tools
        69719  drwx             4096  Feb 12 2018 11:20:01 +00:00  .dbpersist
        69703  -rw-          2097152  Mar 20 2018 13:09:25 +00:00  nvram_config_bkup
        69729  -rw-             3496  Feb 12 2018 12:51:01 +00:00  stby-vlan.dat
        69735  -rw-            27145  Mar 20 2018 11:14:45 +00:00  RestoreTue_Mar_20_12_13_39_2018-Mar-20-11-14-38.106-0
        69721  drwx             4096  Sep 25 2017 07:59:54 +00:00  CRDU
        69727  drwx             4096  Oct 23 2017 13:40:11 +00:00  tech_support
        69736  -rw-            27145  Mar 20 2018 11:20:16 +00:00  RestoreTue_Mar_20_12_19_11_2018-Mar-20-11-20-09.900-0

        1621966848 bytes total (906104832 bytes free)
    '''

    raw3 = '''
        delete flash:memleak.tcl
        Delete filename [memleak.tcl]? 
        Delete flash:/memleak.tcl? [confirm]
    '''

    raw4 = '''
        rename flash:memleak.tcl new_file.tcl
        Destination filename [new_file.tcl]? 
    '''

    raw5 = '''
        show clock | redirect ftp://1.1.1.1//auto/tftp-ssr/show_clock
        Writing /auto/tftp-ssr/show_clock 
    '''

    raw6 = {
        'futlinux.check_file.return_value': '',
        'futlinux.deletefile.return_value': ''
    }

    raw7 = '''
         copy running-config tftp://10.1.7.250//auto/tftp-ssr/test_config.py
        Address or name of remote host [10.1.7.250]? 
        Destination filename [/auto/tftp-ssr/test_config.py]? 
        !!
        27092 bytes copied in 6.764 secs (4005 bytes/sec)
    '''

    outputs = {}
    outputs['copy flash:/memleak.tcl ftp://1.1.1.1//auto/tftp-ssr/memleak.tcl']\
      = raw1
    outputs['dir'] = raw2
    outputs['delete flash:memleak.tcl'] = raw3
    outputs['rename flash:memleak.tcl new_file.tcl'] = raw4
    outputs['show clock | redirect ftp://1.1.1.1//auto/tftp-ssr/show_clock'] = \
      raw5
    outputs['copy running-config tftp://10.1.7.250//auto/tftp-ssr/test_config.py'] = \
      raw7

    def mapper(self, key, timeout=None, reply=None, prompt_recovery=False):
        return self.outputs[key]

    def test_copyfile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        # Call copyfiles
        self.fu_device.copyfile(
            source='flash:/memleak.tcl',
            destination='ftp://1.1.1.1//auto/tftp-ssr/memleak.tcl',
            timeout_seconds='300',
            device=self.device)

    def test_dir(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        directory_output = self.fu_device.dir(target='flash:',
                                              timeout_seconds=300,
                                              device=self.device)

        self.assertEqual(sorted(directory_output), sorted(self.dir_output))

    def test_stat(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        file_details = self.fu_device.stat(target='flash:memleak.tcl',
                                           timeout_seconds=300,
                                           device=self.device)

        self.assertEqual(file_details['last_modified_date'],
                         'Mar 20 2018 10:26:01 +00:00')
        self.assertEqual(file_details['permissions'], '-rw-')
        self.assertEqual(file_details['index'], '69705')
        self.assertEqual(file_details['size'], '104260')

    def test_deletefile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.deletefile(target='flash:memleak.tcl',
                                  timeout_seconds=300,
                                  device=self.device)

    def test_renamefile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.renamefile(source='flash:memleak.tcl',
                                  destination='new_file.tcl',
                                  timeout_seconds=300,
                                  device=self.device)

    @patch(
        'genie.libs.filetransferutils.plugins.fileutils.FileUtils.validateserver',
        return_value=raw6)
    def test_validateserver(self, raw6):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.validateserver(
            target='ftp://1.1.1.1//auto/tftp-ssr/show_clock',
            timeout_seconds=300,
            device=self.device)

    def test_copyconfiguration(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.copyconfiguration(
            source='running-config',
            destination='tftp://10.1.7.250//auto/tftp-ssr/test_config.py',
            timeout_seconds=300,
            device=self.device)
Esempio n. 14
0
    def _perform_issu(self, steps, upgrade_image, timeout=300):
        """Perform the ISSU steps in sequence on the ASR1K device:

            1.  Execute 'issu loadversion' to begin ISSU process
            2.  Poll until standby RP reaches 'ok' state
            3.  Verify ISSU state is now 'loadversion'
            4.  Execute 'issu runversion' to initiate RP failover
            5.  Reconnect to the device
            6.  Verify ISSU state is now 'runversion'
            7.  Execute 'issu acceptversion' to cancel rollback timer
            8.  Verify ISSU state is now 'acceptversion'
            9.  Verify ISSU rollback timer has been cancelled
            10. Poll until standby RP reaches 'ok' state
            11. Save running-configuration to startup-configuration
            12. Execute 'issu commitversion' to complete ISSU process
            13. Reload the device and then reconnect to it
            14. Verify device is now booted with ISSU upgrade image

        Raises:
            Unicon errors
            Exception

        Example:
            >>> _perform_issu(steps=steps, upgrade_image='someimage')
        """

        # Init
        device = self.device
        lookup = Lookup.from_device(device)
        filetransfer = FileUtils.from_device(device)
        image_name = basename(upgrade_image)

        # ======================================================================
        #                           Get standby RP
        # ======================================================================
        with steps.start("Get standby RP information", continue_=True) as step:
            platform_dict = lookup.parser.show_platform.\
                            ShowPlatform(device=device).parse()
            # Standby RP
            rs = R([
                'slot', '(?P<val1>.*)', 'rp', '(?P<val2>.*)', 'state',
                'ok, standby'
            ])
            ret = find([platform_dict], rs, filter_=False, all_keys=True)
            if not ret:
                raise Exception(
                    "Device '{}' does not have standby RP - cannot "
                    "perform ISSU".format(device.name))
            standby_rp = ret[0][1][1]
            srp = re.search('(?P<srp>(\d))', standby_rp).groupdict()['srp']
            logger.info("Standby RP on '{dev}' is: '{standby_rp}'".format(
                dev=device.name, standby_rp=standby_rp))

        # ======================================================================
        #                          issu loadversion
        # ======================================================================
        with steps.start("Execute 'issu loadversion' to begin ISSU process",
                         continue_=True) as step:
            try:
                output = device.execute('issu loadversion rp {srp} file '
                                        'stby-harddisk:{image}'.format(
                                            srp=srp, image=image_name),
                                        timeout=600)
                if 'FAILED' in output:
                    device.execute('issu abortversion', timeout=timeout)
                    raise Exception("Unable to execute 'issu loadversion'")
            except Exception as e:
                raise Exception("Unable to execute 'issu loadversion'")

            # Poll until standby RP reaches 'ok' state in 'show platform'
            logger.info("Poll until standby RP reaches 'ok' state")
            platform_timeout = Timeout(max_time=1200, interval=120)
            while platform_timeout.iterate():
                platform_dict = lookup.parser.show_platform.\
                                ShowPlatform(device=device).parse()
                # Create requirement to find standby-RP with 'ok, standby' state
                rs = R([
                    'slot', '(?P<val1>.*)', 'rp', '(?P<val2>.*)', 'state',
                    'ok, standby'
                ])
                ret = find([platform_dict], rs, filter_=False, all_keys=True)
                if ret:
                    logger.info("Stanby RP '{}' is in 'ok' state".\
                                format(standby_rp))
                    break
                # Standby RP is not 'ok' state as yet, sleep and recheck
                platform_timeout.sleep()

            # Verify issu state
            logger.info("Verify ISSU state is now 'loadversion'")
            try:
                self.check_issu_state(device=device,
                                      slot=standby_rp,
                                      expected_state='loadversion')
                logger.info("ISSU state is 'loadversion' as exepcted")
            except Exception as e:
                raise Exception(str(e))

        # ======================================================================
        #                          issu runversion
        # ======================================================================
        with steps.start("Execute 'issu runversion' to initiate RP failover",
                         continue_=True) as step:
            try:
                output = device.execute('issu runversion', timeout=timeout)
            except SubCommandFailure:
                # Timeout Unicon SubCommandFailure expected
                # Wait a bit as the device is booting with the ISSU upgrade image
                time.sleep(timeout)
                pass

            # Reconnect to device
            logger.info("Reconnect to the device after runversion")
            reconnect_timeout = Timeout(max_time=1200, interval=120)
            self._reconnect(steps=steps, timeout=reconnect_timeout)

            # Verify issu state
            logger.info("Verify ISSU state is now 'runversion'")
            try:
                self.check_issu_state(device=device,
                                      slot=standby_rp,
                                      expected_state='runversion')
                logger.info("ISSU state is 'runversion' as exepcted")
            except Exception as e:
                raise Exception(str(e))

        # ======================================================================
        #                          issu acceptversion
        # ======================================================================
        with steps.start(
                "Execute 'issu acceptversion' to cancel rollback timer",
                continue_=True) as step:
            try:
                output = device.execute('issu acceptversion', timeout=timeout)
                if 'FAILED' in output:
                    raise Exception("Unable to execute 'issu acceptversion'")
            except Exception as e:
                raise Exception("Unable to execute 'issu acceptversion'",
                                from_exception=e)

            # Verify issu state
            logger.info("Verify ISSU state is now 'acceptversion'")
            try:
                self.check_issu_state(device=device,
                                      slot=standby_rp,
                                      expected_state='acceptversion')
                logger.info("ISSU state is 'acceptversion' as exepcted")
            except Exception as e:
                raise Exception(str(e))

            # Verify rollback timer
            logger.info("Verify ISSU rollback timer is now 'inactive'")
            try:
                self.check_issu_rollback_timer(device=device,
                                               slot=standby_rp,
                                               expected_state='inactive')
                logger.info("ISSU rollback timer is 'inactive' as exepcted")
            except Exception as e:
                raise Exception(str(e))

            # Poll until standby RP reaches 'ok' state in 'show platform'
            logger.info("Poll until standby RP reaches 'ok' state")
            platform_timeout = Timeout(max_time=1200, interval=120)
            while platform_timeout.iterate():
                platform_dict = lookup.parser.show_platform.\
                                ShowPlatform(device=device).parse()
                # Create requirement to find standby-RP with 'ok, standby' state
                rs = R([
                    'slot', '(?P<val1>.*)', 'rp', '(?P<val2>.*)', 'state',
                    'ok, standby'
                ])
                ret = find([platform_dict], rs, filter_=False, all_keys=True)
                if ret:
                    logger.info("Stanby RP '{}' is in 'ok' state".\
                                format(standby_rp))
                    break
                # Standby RP is not 'ok' state as yet, sleep and recheck
                platform_timeout.sleep()

            # Save running-configuration to startup-configuration
            logger.info("Save running-configuration to startup-configuration")
            filetransfer.copyconfiguration(source='running-config',
                                           destination='startup-config',
                                           device=device)

        # ======================================================================
        #                          issu commitversion
        # ======================================================================
        with steps.start("Execute 'issu commitversion'",
                         continue_=True) as step:
            try:
                output = device.execute('issu commitversion', timeout=timeout)
                if 'FAILED' in output:
                    raise Exception("Unable to execute 'issu commitversion'")
            except Exception as e:
                raise Exception("Unable to execute 'issu commitversion'",
                                from_exception=e)

        # ======================================================================
        #                          reload device
        # ======================================================================
        try:
            reload_timeout = Timeout(max_time=1200, interval=120)
            self.reload(steps=steps, timeout=reload_timeout)
        except Exception as e:
            raise Exception("Unable to reload the device after ISSU completed",
                            from_exception=e)

        # ======================================================================
        #                          verify image version
        # ======================================================================
        with steps.start(
                "Verify device is loaded with upgraded image after ISSU",
                continue_=True) as step:
            try:
                output = device.execute('show version | i image')
                if image_name in output:
                    logger.info("ISSU upgrade image is successfully loaded on "
                                "the device '{}'".format(device.name))
            except Exception as e:
                raise Exception("Unable to execute 'show version'",
                                from_exception=e)
Esempio n. 15
0
def upload_to_server(device, core_list, *args, **kwargs):

    # Init
    status = OK

    # Get info
    port = kwargs['port']
    server = kwargs['server']
    timeout = kwargs['timeout']
    destination = kwargs['destination']
    protocol = kwargs['protocol']
    username = kwargs['username']
    password = kwargs['password']

    # Check values are not None
    for item in kwargs:
        if item in ['protocol', 'server', 'destination', 'username', 'password'] and \
           kwargs[item] is None:
            meta_info = "Unable to upload core dump - parameters `{}` not provided."\
                        " Required parameters are: `protocol`, `server`, "\
                        "`destination`, `username`, `password`".format(item)
            return ERRORED(meta_info)

    # Upload each core found
    for core in core_list:
        # Sample command:
        # copy core://<module-number>/<process-id>[/instance-num]
        #      tftp:[//server[:port]][/path] vrf management
        path = '{dest}/core_{pid}_{process}_{date}_{time}'.format(
            dest=destination,
            pid=core['pid'],
            process=core['process'],
            date=core['date'],
            time=time.time())
        if port:
            server = '{server}:{port}'.format(server=server, port=port)

        if 'instance' in core:
            pid = '{pid}/{instance}'.format(pid=core['pid'],
                                            instance=core['instance'])

        message = "Core dump upload attempt from module {} to {} via server {}".\
                    format(core['module'], destination, server)

        # construction the module/pid for the copy process
        core['core'] = '{module}/{pid}'.format(module=core['module'],
                                               pid=core['pid'])
        try:
            # Check if filetransfer has been added to device before or not
            if not hasattr(device, 'filetransfer'):
                device.filetransfer = FileUtils.from_device(device)

            to_URL = '{protocol}://{address}/{path}'.format(protocol=protocol,
                                                            address=server,
                                                            path=path)

            from_URL = 'core://{core_path}'.format(core_path=core['core'])

            device.filetransfer.copyfile(device=device,
                                         source=from_URL,
                                         destination=to_URL)
        except Exception as e:
            if 'Tftp operation failed' in str(e):
                meta_info = "Core dump upload operation failed: {}".format(
                    message)
                logger.error(meta_info)
                status += ERRORED(meta_info)
            else:
                # Handle exception
                logger.error(e)
                status += ERRORED("Failed: {}".format(message))
        else:
            meta_info = "Core dump upload operation passed: {}".format(message)
            logger.info(meta_info)
            status += OK(meta_info)

    return status
Esempio n. 16
0
def perform_issu(device,
                 image,
                 disk,
                 timeout=1200,
                 reconnect_via=None,
                 steps=Steps()):
    """ Execute ISSU on device
        Args:
            device ('obj'): Device object
            image ('str'): Image name on disk
            disk ('str'): Disk where is located image
            timeout ('int'): Timeout in second for each section
        Raise:
            None
        Returns:
            None
    """

    with steps.start("Command 'issu loadversion'") as step:

        slot_number = get_platform_standby_rp(device=device)

        if not slot_number:
            raise ValueError("Could not retrieve standby rp slot number")

        # Load version
        standby_slot = "R{}".format(slot_number)
        try:
            issu_loadversion(device=device,
                             standby_slot=slot_number,
                             disk=disk,
                             image=image,
                             timeout=timeout)
        except Exception:
            step.failed("Unable to execute 'issu loadversion'")

    with steps.start("Command 'issu runversion'") as step:

        if not is_platform_slot_in_state(
                device=device, slot=standby_slot, state="ok, standby"):
            step.failed("Slot {slot} is not in 'ok, standby' state".format(
                slot=standby_slot))

        if not is_issu_terminal_state_reached_on_slot(device=device,
                                                      slot=standby_slot):
            step.failed("Slot {slot} has not reached terminal state".format(
                slot=standby_slot))

        # Run version
        try:
            issu_runversion(device=device,
                            timeout=timeout,
                            reconnect_via=reconnect_via)
        except (Exception, ConnectionError) as e:
            step.failed(e)

    with steps.start("Command 'issu acceptversion'") as step:

        in_state = is_issu_in_state(device=device,
                                    slot=standby_slot,
                                    expected_state="runversion")

        if not in_state:
            step.failed("Issu is not in state 'runversion'")

        # Accept version
        try:
            issu_acceptversion(device=device, timeout=timeout)
        except Exception as e:
            step.failed(e)

    with steps.start(
            "Save running-configuration to startup-configuration") as step:

        filetransfer = FileUtils.from_device(device)
        filetransfer.copyconfiguration(
            source="running-config",
            destination="startup-config",
            device=device,
        )

    with steps.start("Command 'issu commitversion'") as step:

        in_state = is_issu_in_state(device=device,
                                    slot=standby_slot,
                                    expected_state="acceptversion")

        if not in_state:
            step.failed("Issu is not in state 'acceptversion'")

        in_state = is_issu_rollback_timer_in_state(device=device,
                                                   slot=standby_slot,
                                                   expected_state="inactive")

        if not in_state:
            step.failed("Issu rollback timer is not 'inactive'")

        # Commit version
        try:
            issu_commitversion(device=device, timeout=timeout)
        except Exception as e:
            step.failed(e)

    with steps.start("Reload standby slot") as step:

        slot_number = get_platform_standby_rp(device=device)

        if not slot_number:
            raise ValueError("Could not retrieve standby rp slot number")

        standby_slot = "R{}".format(slot_number)
        try:
            reload_issu_slot(device=device, slot=standby_slot, timeout=timeout)
        except Exception as e:
            step.failed(e)
Esempio n. 17
0
def delete_unprotected_files(device,
                             directory,
                             protected,
                             files_to_delete=None,
                             dir_output=None,
                             allow_failure=False):
    """ Delete all files not matching regex in the protected list
        Args:
            device ('obj'): Device object
            directory ('str'): working directory to perform the operation
            protected ('list'): list of file patterns that won't be deleted. If it begins
                                and ends with (), it will be considered as a regex
            files_to_delete('list') list of files that should be deleted unless they are not protected
            dir_output ('str'): output of dir command, if not provided execute the cmd on device to get the output
            allow_failure (bool, optional): Allow the deletion of a file to silently fail. Defaults to False.
        Returns:
            None
            """

    protected_set = set()
    fu_device = FileUtils.from_device(device)
    file_set = set(
        device.parse('dir {}'.format(directory),
                     output=dir_output).get('files', {}).keys())

    if isinstance(protected, str):
        protected = [protected]
    elif not isinstance(protected, (list, set)):
        raise TypeError("'{p}' must be a list")

    for pattern in protected:
        # it's a regex!
        if pattern.startswith('(') and pattern.endswith(')'):
            regexp = re.compile(pattern)
            protected_set.update(set(filter(regexp.match, file_set)))

        # just file names, exact match only
        elif pattern in file_set:
            protected_set.add(pattern)

    # if files_to_delete is given,updated protected files with the diff of file_set - files_to_delete
    # so that we only delete files that are in files_to_delete and NOT protected
    # in other words we remove the protected files from file_to_delete
    if files_to_delete:
        protected_set.update(file_set - set(files_to_delete))

    not_protected = file_set - protected_set
    error_messages = []
    log.debug("protected patterns : {}".format(protected))
    log.debug("found files : {}".format(file_set))
    log.debug("protected files : {}".format(protected_set))
    log.debug("non-protected files : {}".format(not_protected))
    if not_protected:
        log.info("The following files will be deleted:\n{}".format(
            '\n'.join(not_protected)))
        dont_delete_list = protected_set.intersection(files_to_delete)
        if dont_delete_list:
            log.info(
                "The following files will not be deleted because they are protected:\n{}"
                .format('\n'.join(dont_delete_list)))
        for file in not_protected:
            # it's a directory, dont delete
            if file.endswith('/'):
                continue
            log.info('Deleting the unprotected file "{}"'.format(file))
            try:
                fu_device.deletefile(directory + file, device=device)
            except Exception as e:
                if allow_failure:
                    log.info(
                        'Failed to delete file "{}" but ignoring and moving '
                        'on due to "allow_failure=True"..'.format(file))
                    continue

                error_messages.append('Failed to delete file "{}" due '
                                      'to :{}'.format(file, str(e)))
        if error_messages:
            raise Exception('\n'.join(error_messages))
    else:
        log.info(
            "No files will be deleted, the following files are protected:\n{}".
            format('\n'.join(protected_set)))
Esempio n. 18
0
    def restore_configuration(self,
                              device,
                              method,
                              abstract,
                              iteration=10,
                              interval=60,
                              compare=False,
                              compare_exclude=[],
                              reload_timeout=1200):
        if method == 'checkpoint':
            # Enable the feature
            for i in range(1, iteration):
                try:
                    out = self.rollback_checkpoint(device=device,
                                                   name=self.ckname)
                except Exception as e:
                    raise Exception('Unable to rollback config')

                if out and 'Rollback Done' in out:
                    break
                else:
                    log.info('Rollback configuration failed: sleeping {} '
                             'seconds and retrying...'.format(interval))
                    time.sleep(interval)

            else:
                raise Exception('Unable to rollback config')

            # Delete the checkpoint
            self.create_delete_checkpoint(device=device,
                                          name=self.ckname,
                                          abstract=abstract,
                                          action='delete')

            # Check if checkpoint is successfully deleted
            self.check_checkpoint_status(device=device,
                                         name=self.ckname,
                                         expect='delete',
                                         abstract=abstract)
        elif method == 'local':
            # reover the deivce with whole running-config
            device.configure(self.run_config)
        elif method == 'config_replace':
            # delete the archive file
            dialog = Dialog([
                Statement(pattern=r'This will apply all necessary.*',
                          action='sendline(Y)',
                          loop_continue=True,
                          continue_timer=False),
                Statement(pattern=r'less than running config.*',
                          action='sendline(Y)',
                          loop_continue=True,
                          continue_timer=False),
            ])
            # dialog for plan B
            alt_dialog = Dialog([
                Statement(pattern=r'Destination filename.*',
                          action='sendline()',
                          loop_continue=True,
                          continue_timer=False),
            ])

            for i in range(1, iteration):
                # configure replace location:<filename>
                out = device.execute('configure replace {}'.\
                            format(self.to_url), reply=dialog, error_pattern=[])

                if out and 'Rollback Done' in out:
                    break
                elif 'invalid' in out.lower():
                    # device does not support config replace, do it in different way
                    device.execute('erase startup-config')
                    device.execute('copy {} startup-config'.format(
                        self.to_url),
                                   reply=alt_dialog)
                    device.reload(reload_timeout=reload_timeout)
                    break
                else:
                    log.info(
                        'Config replace failed: sleeping {} seconds before'
                        ' retrying.'.format(interval))
                    time.sleep(interval)

            else:
                raise Exception('Unable to execute config replace')

            # Compare restored configuration to details in file
            if compare:
                log.info(
                    "Comparing current running-config with config-replace file"
                )

                # Default
                exclude = [
                    'device', 'maker', 'diff_ignore', 'callables',
                    '(Current configuration.*)',
                    '(.*Building configuration.*)', '(.*Load for.*)',
                    '(.*Time source.*)'
                ]
                if compare_exclude:
                    if isinstance(compare_exclude, str):
                        exclude.extend([compare_exclude])
                    else:
                        exclude.extend(compare_exclude)

                # show run
                show_run_output = device.execute('show running-config')
                show_run_config = Config(show_run_output)
                show_run_config.tree()

                # location:<filename> contents
                more_file = device.execute('more {}'.format(self.to_url))
                more_file_config = Config(more_file)
                more_file_config.tree()

                # Diff 'show run' and config replace file contents
                diff = Diff(show_run_config.config,
                            more_file_config.config,
                            exclude=exclude)
                diff.findDiff()

                # Check for differences
                if len(diff.diffs):
                    log.error("Differences observed betweenrunning-config and "
                              "config-replce file:'{f}' for device {d}:".\
                              format(f=self.to_url, d=device.name))
                    log.error(str(diff.diffs))
                    raise Exception(
                        "Comparison between running-config and "
                        "config-replace file '{f}' failed for device"
                        " {d}".format(f=self.to_url, d=device.name))
                else:
                    log.info("Comparison between running-config and config-replace"
                             "file '{f}' passed for device {d}".\
                             format(f=self.to_url, d=device.name))

            # Delete location:<filename>
            self.filetransfer = FileUtils.from_device(device)
            self.filename = self.to_url
            self.filetransfer.deletefile(target=self.to_url, device=device)

            # Verify location:<filename> deleted
            dir_output = self.filetransfer.dir(target=self.to_url,
                                               device=device)
            for file in dir_output:
                if self.filename in file:
                    break
            else:
                log.info("Successfully deleted '{}'".format(self.to_url))
                return
            raise Exception("Unable to delete '{}'".format(self.to_url))
        else:
            # modify the device via callable function
            # using Conf object
            self.modify_func(device=device,
                             conf=self.conf,
                             values_dict=self.conf_argument,
                             recover=True,
                             **self.specific_args)
Esempio n. 19
0
    def restore_configuration(self,
                              device,
                              method,
                              abstract,
                              iteration=10,
                              interval=60,
                              compare=False,
                              compare_exclude=[],
                              reload_timeout=None):
        if method == 'checkpoint':
            # Enable the feature
            dialog = Dialog([
                Statement(pattern=r'\[no\]',
                          action='sendline(y)',
                          loop_continue=True,
                          continue_timer=False)
            ])

            for i in range(1, iteration):
                # replace config with checkpoint
                cfg ='load disk0:{name}\n'\
                     'commit replace'.format(name=self.ckname)
                output = device.configure(cfg, reply=dialog)
                if 'fail' not in output:
                    break
                elif i == iteration - 1:
                    raise Exception('Failed to rollback config to checkpoint')
                else:
                    log.info('Rollback checkpoint failed: sleeping {} seconds '
                             'and retrying...'.format(interval))
                    time.sleep(interval)

            # need to delete the config file on the device
            dialog = Dialog([
                Statement(pattern=r'\[confirm\]',
                          action='sendline(y)',
                          loop_continue=True,
                          continue_timer=False)
            ])
            device.execute('delete disk0:{name}'.format(name=self.ckname),
                           reply=dialog)

        # Keeping them for later enhancement
        elif method == 'local':
            pass
        elif method == 'config_replace':
            for i in range(1, iteration):
                # Execute commit replace
                cmd = "load {}\n"\
                      "commit replace".format(self.to_url)
                output = device.configure(cmd)
                if 'Failed to commit' not in output:
                    break
                elif i == iteration - 1:
                    raise Exception('Unable to execute commit replace')
                else:
                    log.info(
                        'Commit replace failed: sleeping {} seconds before'
                        ' retrying.'.format(interval))
                    device.execute('show configuration failed')
                    time.sleep(interval)

            # Compare restored configuration to details in file
            if compare:
                log.info(
                    "Comparing current running-config with config-replace file"
                )

                # Default
                exclude = [
                    'device', 'maker', 'diff_ignore', 'callables',
                    '(Current configuration.*)'
                ]
                if compare_exclude:
                    if isinstance(compare_exclude, str):
                        exclude.extend([compare_exclude])
                    else:
                        exclude.extend(compare_exclude)

                # show run
                show_run_output = device.execute('show running-config')
                show_run_config = Config(show_run_output)
                show_run_config.tree()

                # location:<filename> contents
                more_file = device.execute('more {}'.format(self.to_url))
                more_file_config = Config(more_file)
                more_file_config.tree()

                # Diff 'show run' and config replace file contents
                diff = Diff(show_run_config.config,
                            more_file_config.config,
                            exclude=exclude)
                diff.findDiff()

                # Check for differences
                if len(diff.diffs):
                    log.error("Differences observed betweenrunning-config and "
                              "config-replce file:'{f}' for device {d}:".\
                              format(f=self.to_url, d=device.name))
                    log.error(str(diff.diffs))
                    raise Exception(
                        "Comparison between running-config and "
                        "config-replace file '{f}' failed for device"
                        " {d}".format(f=self.to_url, d=device.name))
                else:
                    log.info("Comparison between running-config and config-replace"
                             "file '{f}' passed for device {d}".\
                             format(f=self.to_url, d=device.name))

            # Delete location:<filename>
            self.filetransfer = FileUtils.from_device(device)
            self.filename = self.to_url
            self.filetransfer.deletefile(target=self.to_url, device=device)

            # Verify location:<filename> deleted
            dir_output = self.filetransfer.dir(target=self.to_url,
                                               device=device)
            for file in dir_output:
                if self.filename in file:
                    break
            else:
                log.info("Successfully deleted '{}'".format(self.to_url))
                return
            raise Exception("Unable to delete '{}'".format(self.to_url))
        else:
            pass
Esempio n. 20
0
def upload_to_server(device, core_list, crashreport_list, **kwargs):

    # Init
    status= OK

    # Get info
    port = kwargs['port']
    server = kwargs['server']
    timeout = kwargs['timeout']
    destination = kwargs['destination']
    protocol = kwargs['protocol']
    username = kwargs['username']
    password = kwargs['password']

    # Check values are not None
    for item in kwargs:
        if item in ['protocol', 'server', 'destination', 'username', 'password'] and \
           kwargs[item] is None:
            meta_info = "Unable to upload core dump - parameters `{}` not provided."\
                        " Required parameters are: `protocol`, `server`, "\
                        "`destination`, `username`, `password`".format(item)
            return ERRORED(meta_info)

    # preparing the full list to iterate over
    full_list = core_list + crashreport_list

    if port:
        server = '{server}:{port}'.format(server=server, port=port)

    # Upload each core/crashinfo report found
    for item in full_list:

        if 'crashinfo' in item['core']:
            file_type = 'Crashreport'
        else:
            file_type = 'Core'

        message = "{} upload attempt from {} to {} via server {}".format(
            file_type, item['location'], destination, server)

        try:
            # Check if filetransfer has been added to device before or not
            if not hasattr(device, 'filetransfer'):
                device.filetransfer = FileUtils.from_device(device)

            to_URL = '{protocol}://{address}/{path}'.format(
                protocol=protocol,
                address=server,
                path=destination)

            from_URL = '{location}//{core_path}'.format(
                location=item['location'], core_path=item['core'])

            device.filetransfer.copyfile(device=device,
                                         source=from_URL,
                                         destination=to_URL)
        except Exception as e:
            if 'Tftp operation failed' in e:
                meta_info = "{} upload operation failed: {}".format(file_type,
                    message)
                logger.error(meta_info)
                status += ERRORED(meta_info)
            else:
                # Handle exception
                logger.warning(e)
                status += ERRORED("Failed: {}".format(message))

        meta_info = "{} upload operation passed: {}".format(file_type, message)
        logger.info(meta_info)
        status += OK(meta_info)

    return status
Esempio n. 21
0
    def restore_configuration(self,
                              device,
                              method,
                              abstract,
                              iteration=10,
                              interval=60,
                              compare=False,
                              compare_exclude=[],
                              reload_timeout=None,
                              delete_after_restore=True):
        ''' Restore configuration from a checkpoint file using load replace'''

        if method == 'checkpoint' or method == 'config_replace':
            # Begin iteration
            for i in range(1, iteration):
                try:
                    self.replace_checkpoint_file(device=device,
                                                 file=self.to_url)
                except Exception as e:
                    log.error(e)
                    if i == iteration - 1:
                        raise Exception(
                            'Unable to load override configuration')
                    else:
                        log.info('Load override configuration failed:\n'
                                 'sleeping {} seconds and retrying...'.\
                                 format(interval))
                        time.sleep(interval)
                else:
                    log.info('Load override configuration passed')
                    break

            # Instantiate a filetransferutils instance for JunOS device
            self.filetransfer = FileUtils.from_device(device)

            # Compare restored configuration to details in file
            if compare:
                log.info(
                    "Comparing current configuration with load override file")
                exclude_failed = False

                # Keys to exclude
                exclude = '(.*Last changed.*)|(.*Last commit.*)|(.*1c1.*)|(.*\-.*)'
                if compare_exclude:
                    if isinstance(compare_exclude, str):
                        exclude += '|{}'.format(compare_exclude)
                    else:
                        for item in compare_exclude:

                            exclude += '|{}'.format(compare_exclude)

                # Copy current configuration to a file on disk
                tempfile = "tempfile{}".format(random.randint(100, 1000))
                self.filetransfer.copyconfiguration(source='configuration',
                                                    destination=tempfile,
                                                    device=device)

                # Compare the files
                diff = device.execute("file compare files {file1} {file2}".\
                                      format(file1=tempfile, file2=self.to_url))

                # Delete file
                self.filetransfer.deletefile(target=tempfile, device=device)

                # Check for differences
                diff = diff.strip().replace('\r', '').splitlines()
                exclude_item = []
                for item in diff:
                    if item and re.match(exclude, item):
                        continue
                    else:
                        exclude_item.append(item)
                        exclude_failed = True
                if exclude_failed:
                    # Print diffs to user
                    log.error("Differences observed between current running "
                              "configuration and load override file:'{f}' for "
                              "device {d}:".format(f=self.to_url,
                                                   d=device.name))
                    log.error(exclude_item)
                    if delete_after_restore:
                        # Delete files
                        self.filetransfer.deletefile(target=self.to_url,
                                                     device=device)
                    # Raise exception
                    raise Exception("Comparison between current running "
                                    "configuration and load override file '{f}' "
                                    "failed for device {d}".\
                                    format(f=self.to_url, d=device.name))
                else:
                    log.info("Comparison between current running configuration "
                             " and load override file '{f}' passed for device {d}".\
                             format(f=self.to_url, d=device.name))

            if delete_after_restore:
                # Delete the checkpoint file
                self.filetransfer.deletefile(target=self.to_url, device=device)

                # Verify checkpoint file deleted
                if self.to_url not in self.filetransfer.dir(target=self.to_url,
                                                            device=device):
                    log.info("Successfully deleted checkpoint/file '{}'".\
                             format(self.to_url))
                else:
                    raise Exception("Unable to delete checkpoint/file '{}'".\
                                    format(self.to_url))
        else:
            raise NotImplementedError("restore configuration using method '{}'".\
                                      format(method))
class test_filetransferutils(unittest.TestCase):
    # Instantiate tesbed and device objects
    tb = Testbed(name='myTestbed')
    device = Device(testbed=tb, name='aDevice', os='nxos')

    # Instantiate a filetransferutils instance for NXOS device
    fu_device = FileUtils.from_device(device)

    # Add testbed servers for authentication
    device.testbed.servers = AttrDict(server_name=dict(username="******",
                                                       password="******",
                                                       address='1.1.1.1'), )

    dir_output = [
        'bootflash:/ISSUCleanGolden.system.gbin',
        'bootflash:/ISSUCleanGolden.cfg', 'bootflash:/platform-sdk.cmd',
        'bootflash:/virt_strg_pool_bf_vdc_1/', 'bootflash:/virtual-instance/',
        'bootflash:/virtual-instance.conf', 'bootflash:/.rpmstore/',
        'bootflash:/.swtam/', 'bootflash:/scripts/'
    ]

    # Mock device output
    raw1 = '''
        copy bootflash:/virtual-instance.conf ftp://10.1.0.213//auto/tftp-ssr/virtual-instance.conf
        Enter username: rcpuser
        Password:
        ***** Transfer of file Completed Successfully *****
        Copy complete.
    '''

    raw2 = '''
        dir
               4096    Jan 25 21:00:53 2017  .rpmstore/
               4096    Jan 25 21:01:08 2017  .swtam/
                390    Jan 25 21:36:20 2017  ISSUCleanGolden.cfg
          752699904    Jan 25 21:36:26 2017  ISSUCleanGolden.system.gbin
                  0    Jan 25 21:35:55 2017  platform-sdk.cmd
               4096    Jan 25 21:01:57 2017  scripts/
               4096    Jan 25 21:02:02 2017  virt_strg_pool_bf_vdc_1/
               4096    Jan 25 21:01:21 2017  virtual-instance/
                 59    Jan 25 21:01:11 2017  virtual-instance.conf

        Usage for bootflash://
         1150812160 bytes used
         2386407424 bytes free
         3537219584 bytes total
    '''

    raw3 = '''
        delete bootflash:new_file.tcl
        Do you want to delete "/new_file.tcl" ? (yes/no/abort)   [y]
    '''

    raw4 = '''
        move bootflash:mem_leak.tcl new_file.tcl
    '''

    raw5 = '''
        show clock > ftp://10.1.7.250//auto/tftp-ssr/show_clock vrf management
        Enter username: rcpuser
        Password:
        ***** Transfer of file Completed Successfully *****
    '''

    raw6 = {
        'futlinux.check_file.return_value': '',
        'futlinux.deletefile.return_value': ''
    }

    raw7 = '''
        copy running-config tftp://10.1.7.250//auto/tftp-ssr/test_config.py vrf management
        Trying to connect to tftp server......
        Connection to Server Established.
        [                         ]         0.50KB[#                        ]         4.50KB[##                       ]         8.50KB[###                      ]        12.50KB                                                                                    TFTP put operation was successful
        Copy complete, now saving to disk (please wait)...
        Copy complete.
    '''
    raw8 = '''
        copy running-config sftp://1.1.1.1//home/virl vrf management
        Enter username: myuser

        The authenticity of host '1.1.1.1 (1.1.1.1)' can't be established.
        ECDSA key fingerprint is SHA256:Q37/fav3nPJT5Y+7IsgST4uN0c2tyToJiDF/gp+wItA.
        Are you sure you want to continue connecting (yes/no)? yes
        Warning: Permanently added '1.1.1.1' (ECDSA) to the list of known hosts.
        Outbound-ReKey for 1.1.1.1:22
        Inbound-ReKey for 1.1.1.1:22
        [email protected]'s password:
        Connected to 1.1.1.1.
        sftp> put  /var/tmp/vsh/R3_nx-running-config  /home/virl
        Uploading /var/tmp/vsh/R3_nx-running-config to /home/virl/R3_nx-running-config
        /var/tmp/vsh/R3_nx-running-config
                                                                                                                                                                                                                                                                                                                                    /var/tmp/vsh/R3_nx-running-config                                                                                                                                                                                                                                                                                                                                                                                                                                                            100%   14KB 355.1KB/s   00:00
    '''
    raw9 = '''
        copy bootflash:/virtual-instance.conf ftp://10.1.0.213//auto/tftp-ssr/virtual-instance.conf
        Enter username: rcpuser
        ftp: connect: No route to host
        ***** Transfer of file aborted, server not connected *****
        Error during copy
        ***** Transfer of file aborted *****

    '''

    outputs = {}
    outputs['copy bootflash:/virtual-instance.conf '
            'ftp://10.1.0.213//auto/tftp-ssr/virtual-instance.conf'] = raw1
    outputs['dir'] = raw2
    outputs['delete bootflash:new_file.tcl'] = raw3
    outputs['move bootflash:mem_leak.tcl new_file.tcl'] = raw4
    outputs[
        'show clock > ftp://1.1.1.1//auto/tftp-ssr/show_clock vrf management'] = raw5
    outputs[
        'copy running-config tftp://10.1.7.250//auto/tftp-ssr/test_config.py vrf management'] = raw7
    outputs[
        'copy running-config sftp://[email protected]//home/virl vrf management'] = raw8
    outputs['copy bootflash:/virtual-instance.conf '
            'ftp://10.1.0.214//auto/tftp-ssr/virtual-instance.conf'] = raw9

    def mapper(self, key, timeout=None, reply=None, prompt_recovery=False):
        return self.outputs[key]

    def is_valid_ip_mapper(self, ip, device=None, vrf=None, cache_ip=None):
        return ip != '2.2.2.2'

    def test_copyfile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        # Call copyfiles
        self.fu_device.copyfile(
            source='bootflash:/virtual-instance.conf',
            destination='ftp://10.1.0.213//auto/tftp-ssr/virtual-instance.conf',
            timeout_seconds='300',
            device=self.device)

    def test_copyfile_exception(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        # Call copyfiles
        with self.assertRaises(SubCommandFailure):
            self.fu_device.copyfile(
                source='bootflash:/virtual-instance.conf',
                destination=
                'ftp://10.1.0.214//auto/tftp-ssr/virtual-instance.conf',
                timeout_seconds='300',
                device=self.device)

    def test_copyfile_sftp(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        # Call copyfiles
        self.fu_device.copyfile(source='running-config',
                                destination='sftp://1.1.1.1//home/virl',
                                vrf='management',
                                device=self.device)

    def test_validate_and_update_url(self):
        self.fu_device.is_valid_ip = Mock()
        self.fu_device.is_valid_ip.side_effect = self.is_valid_ip_mapper
        # set multiple ip for the server
        self.device.testbed.servers.server_name['address'] = [
            '2.2.2.2', '1.1.1.1'
        ]
        not_reachable_url = self.fu_device.validate_and_update_url(
            'sftp://2.2.2.2//home/virl', device=self.device)
        reachable_url = self.fu_device.validate_and_update_url(
            'sftp://1.1.1.1//home/virl', device=self.device)
        servername_url = self.fu_device.validate_and_update_url(
            'sftp://server_name//home/virl', device=self.device)
        self.assertEqual(not_reachable_url, 'sftp://[email protected]//home/virl')
        self.assertEqual(reachable_url, 'sftp://[email protected]//home/virl')
        self.assertEqual(servername_url, 'sftp://[email protected]//home/virl')
        self.device.testbed.servers.server_name['address'] = '1.1.1.1'

    def test_dir(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        directory_output = self.fu_device.dir(target='bootflash:',
                                              timeout_seconds=300,
                                              device=self.device)

        self.assertEqual(sorted(directory_output), sorted(self.dir_output))

    def test_stat(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        file_details = self.fu_device.stat(
            target='bootflash:virtual-instance.conf',
            timeout_seconds=300,
            device=self.device)

        self.assertEqual(file_details['time'], '21:01:11')
        self.assertEqual(file_details['date'], 'Jan 25 2017')
        self.assertEqual(file_details['size'], '59')

    def test_deletefile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.deletefile(target='bootflash:new_file.tcl',
                                  timeout_seconds=300,
                                  device=self.device)

    def test_renamefile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.renamefile(source='bootflash:mem_leak.tcl',
                                  destination='new_file.tcl',
                                  timeout_seconds=300,
                                  device=self.device)

    @patch(
        'genie.libs.filetransferutils.plugins.fileutils.FileUtils.validateserver',
        return_value=raw6)
    def test_validateserver(self, raw6):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.validateserver(
            target='ftp://1.1.1.1//auto/tftp-ssr/show_clock',
            timeout_seconds=300,
            device=self.device)

    def test_copyconfiguration(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.copyconfiguration(
            source='running-config',
            destination='tftp://10.1.7.250//auto/tftp-ssr/test_config.py',
            timeout_seconds=300,
            device=self.device)
Esempio n. 23
0
    def restore_configuration(self,
                              device,
                              method,
                              abstract,
                              iteration=10,
                              interval=60,
                              compare=False,
                              compare_exclude=[],
                              reload_timeout=None):
        if method == 'checkpoint':
            # Enable the feature
            for i in range(1, iteration):
                try:
                    self.rollback_checkpoint(device=device, name=self.ckname)
                    break
                except Exception as e:
                    if i == iteration - 1:
                        raise Exception('Unable to rollback config')
                    else:
                        log.error(e)
                        log.info('Rollback configuration failed: sleeping {} '
                                 'seconds and retrying...'.format(interval))
                        time.sleep(interval)

            # Delete the checkpoint
            self.create_delete_checkpoint(device=device,
                                          name=self.ckname,
                                          action='delete')

            # Check if checkpoint is successfully deleted
            self.check_checkpoint_status(device=device,
                                         name=self.ckname,
                                         expect='delete',
                                         abstract=abstract)
        elif method == 'local':
            # reover the deivce with whole running-config
            device.configure(self.run_config)
        elif method == 'config_replace':
            for i in range(1, iteration):
                # configure replace location:<filename>
                output = device.execute('configure replace {}'.\
                                        format(self.to_url))
                if 'Configure replace completed successfully' in output:
                    break
                elif i == iteration - 1:
                    raise Exception('Unable to execute config replace')
                else:
                    log.info(
                        'Config replace failed: sleeping {} seconds before'
                        ' retrying.'.format(interval))
                    # Execute 'show config-replace log exec|verify'
                    output = device.execute([
                        'show config-replace log exec',
                        'show config-replace log verify'
                    ])
                    time.sleep(interval)

            # Execute 'show config-replace log exec' and 'show config-replace log verify'
            output = device.execute([
                'show config-replace log exec',
                'show config-replace log verify'
            ])

            # Check if reload is required after executing 'configure replace'
            for out in output.values():
                if 'before switch reload' in out:
                    raise GenieConfigReplaceWarning(
                        'Warning: reload needed after '
                        'configure replace')

            # Compare restored configuration to details in file
            if compare:
                log.info(
                    "Comparing current running-config with config-replace file"
                )

                # Default
                exclude = [
                    'device', 'maker', 'diff_ignore', 'callables',
                    '(Current configuration.*)'
                ]
                if compare_exclude:
                    if isinstance(compare_exclude, str):
                        exclude.extend([compare_exclude])
                    else:
                        exclude.extend(compare_exclude)

                # show run
                show_run_output = device.execute('show running-config')
                show_run_config = Config(show_run_output)
                show_run_config.tree()

                # location:<filename> contents
                more_file = device.execute('show file {}'.format(self.to_url))
                more_file_config = Config(more_file)
                more_file_config.tree()

                # Diff 'show run' and config replace file contents
                diff = Diff(show_run_config.config,
                            more_file_config.config,
                            exclude=exclude)
                diff.findDiff()

                # Check for differences
                if len(diff.diffs):
                    log.error("Differences observed betweenrunning-config and "
                              "config-replce file:'{f}' for device {d}:".\
                              format(f=self.to_url, d=device.name))
                    log.error(str(diff.diffs))
                    raise Exception(
                        "Comparison between running-config and "
                        "config-replace file '{f}' failed for device"
                        " {d}".format(f=self.to_url, d=device.name))
                else:
                    log.info("Comparison between running-config and config-replace"
                             "file '{f}' passed for device {d}".\
                             format(f=self.to_url, d=device.name))

            # Delete location:<filename>
            self.filetransfer = FileUtils.from_device(device)
            self.filename = self.to_url
            self.filetransfer.deletefile(target=self.to_url, device=device)

            # Verify location:<filename> deleted
            dir_output = self.filetransfer.dir(target=self.to_url,
                                               device=device)
            for file in dir_output:
                if self.filename in file:
                    break
            else:
                log.info("Successfully deleted '{}'".format(self.to_url))
                return
            raise Exception("Unable to delete '{}'".format(self.to_url))
        else:
            # modify the device via callable function
            # using Conf object
            self.modify_func(device=device,
                             conf=self.conf,
                             values_dict=self.conf_argument,
                             recover=True,
                             **self.specific_args)
Esempio n. 24
0
    def _perform_issu(self, steps, upgrade_image, timeout=300):
        """Perform the ND-ISSU on NXOS device:

            NXOS:
            1. execute install all <> non-disruptive

        Raises:
            Unicon errors
            Exception

        Example:
            >>> _perform_issu(steps=steps, upgrade_image='someimage')
        """

        # Init
        lookup = Lookup.from_device(self.device)
        filetransfer = FileUtils.from_device(self.device)

        statement_list = authentication_statement_list + \
            [Statement(pattern=r'.*Do you want to continue with the installation\s*\(y/n\)\?\s*\[n\]',
                       action='sendline(y)', loop_continue=True, continue_timer=False)] + \
            [Statement(pattern=r'.*Do you want to overwrite\s*\(yes/no\)\?\s* \[no\]',
                       action='sendline(yes)', loop_continue=True, continue_timer=False)]
        dialog = Dialog(statement_list)

        ctrlplane_downtime = self.parameters.get('ctrlplane_downtime')
        user_boot_mode = self.parameters.get('mode')
        issu_timeout = self.parameters.get('issu_timeout')
        cfg_transfer = self.parameters.get('cfg_transfer')
        cfg_timeout = self.parameters.get('cfg_timeout')
        with steps.start("Check boot mode on {}".format(
                self.device.hostname)) as step:
            invalid_cmd = False
            out = self.device.execute('show boot mode')
            # p1 matches line "Current mode is <native/lxc>."
            p1 = re.compile(r'^Current\smode\sis\s(?P<mode>\w+)\.$')
            # p2 matches line "% Invalid command at '^' marker."
            p2 = re.compile(r'.*?\'\^ \'\smarker\.')
            for line in out.splitlines():
                line = line.strip()
                m = p1.match(line)
                if m:
                    sys_boot_mode = m.groupdict()['mode']
                    break
                m = p2.match(line)
                if m:
                    invalid_cmd = True
                    break
            if sys_boot_mode.lower() != user_boot_mode.lower():
                step.failed(
                    "System boot mode {} does not match user expected boot mode {}"
                    .format(sys_boot_mode, user_boot_mode))
            elif invalid_cmd and user_boot_mode.lower() != 'lxc':
                step.failed(
                    "System only supports lxc mode. Invalid user expected boot mode input {}"
                    .format(user_boot_mode))
            else:
                step.passed(
                    "System boot mode {} matches user expected boot mode {}".
                    format(sys_boot_mode, user_boot_mode))

        with steps.start(
                "Take a running-config snapshot pre trigger on {}".format(
                    self.device.hostname)):
            if cfg_transfer:
                self.device.execute('show run > {}_pre_issu_trig.cfg'.format(
                    self.device.hostname),
                                    timeout=cfg_timeout,
                                    reply=dialog)
                to_url = '{protocol}://{address}/{path}'.format(
                    protocol=self.device.filetransfer_attributes['protocol'],
                    address=self.device.
                    filetransfer_attributes['server_address'],
                    path=runtime.directory)
                filetransfer.copyfile(
                    source='bootflash:/{}_pre_issu_trig.cfg'.format(
                        self.device.hostname),
                    destination=to_url,
                    device=self.device,
                    vrf='management',
                    timeout_seconds=600)
                try:
                    with open(
                            "{}/{}_pre_issu_trig.cfg".format(
                                runtime.directory, self.device.hostname),
                            "r") as pre_trig_file:
                        pre_cfg_str = pre_trig_file.read()
                except IOError:
                    step.failed(
                        "file not found.Please check path/content of the file")
                pre_trig_config = get_config_dict(pre_cfg_str)
            else:
                pre_trig_config = self.device.api.get_running_config_dict()
        with steps.start("Perform copy run start on {}".format(
                self.device.hostname)):
            execute_copy_run_to_start(self.device)
        with steps.start(
                "Performing non disruptive issu on the device {}".format(
                    self.device.hostname)):
            image_name = basename(upgrade_image)
            self.device.execute(
                'install all nxos bootflash:{} non-disruptive'.format(
                    image_name),
                timeout=issu_timeout,
                reply=dialog)

        with steps.start("Reconnect back to device {} after ISSU".format(
                self.device.hostname)):
            reconnect_timeout = Timeout(max_time=1200, interval=120)
            self._reconnect(steps=steps, timeout=reconnect_timeout)

        with steps.start("Verify image version on device {} after ISSU".format(
                self.device.hostname)):
            version_dict = lookup.parser.show_platform.\
                ShowVersion(device=self.device).parse()
            # version check
            rs = R([
                'platform', 'software', 'system_image_file',
                'bootflash:///{}'.format(image_name)
            ])
            ret = find([version_dict], rs, filter_=False, all_keys=True)
            if not ret:
                raise Exception(
                    "Image version mismatch after ISSU on device {}".format(
                        self.device.hostname))

        with steps.start(
                "Verify module status and config load status on device {} after ISSU"
                .format(self.device.hostname)):
            self.device.api.verify_module_status()
            config_timeout = Timeout(max_time=180, interval=30)
            while config_timeout.iterate():
                try:
                    parsed = self.device.parse(
                        "show logging logfile | include 'System ready'")
                except SchemaEmptyParserError as e:
                    log.info("command did not return any output\n{}".format(
                        str(e)))
                    config_timeout.sleep()
                    continue
                if parsed is not None:
                    log.info("{}".format(parsed.q.get_values('logs', -1)))
                    break
                config_timeout.sleep()

        with steps.start("Check CP downtime after on {} after ISSU".format(
                self.device.hostname)) as step:
            if user_boot_mode.lower() == 'lxc':
                step.passed(
                    "show install all time-stats detail unsupported on lxc mode and cp downtime is minimal"
                )
            else:
                out = self.device.execute('show install all time-stats detail')
                output_error = False
                cp_downtime = None
                for line in out.splitlines():
                    line = line.rstrip()
                    p1 = re.compile(r'^ERROR:.*$')
                    m = p1.match(line)
                    if m:
                        output_error = True
                        break
                    p2 = re.compile(
                        r'^Total\s+.*?:\s(?P<cp_downtime>\d+)\s+seconds$')
                    m = p2.match(line)
                    if m:
                        cp_downtime = m.groupdict()['cp_downtime']
                        continue
                if output_error:
                    step.failed(
                        "The output shows reset-reason as disruptive. ND ISSU was not performed properly."
                    )
                elif cp_downtime is None:
                    step.failed(
                        "garbled output for show install all time-stats detail so cp_downtime was not calculated properly."
                    )
                elif int(cp_downtime) > int(ctrlplane_downtime):
                    step.failed(
                        "Control plane was down for {} seconds which is longer than user expected at {} seconds"
                        .format(cp_downtime, ctrlplane_downtime))
                else:
                    step.passed(
                        "Control plane was down for {} seconds which is within an user acceptable range of {} seconds"
                        .format(cp_downtime, ctrlplane_downtime))

        with steps.start(
                "Compare post-trigger config with pre trigger config snapshot on {}"
                .format(self.device.hostname)) as step:
            if cfg_transfer:
                self.device.execute('show run > {}_post_issu_trig.cfg'.format(
                    self.device.hostname),
                                    timeout=cfg_timeout,
                                    reply=dialog)
                to_url = '{protocol}://{address}/{path}'.format(
                    protocol=self.device.filetransfer_attributes['protocol'],
                    address=self.device.
                    filetransfer_attributes['server_address'],
                    path=runtime.directory)
                filetransfer.copyfile(
                    source='bootflash:/{}_post_issu_trig.cfg'.format(
                        self.device.hostname),
                    destination=to_url,
                    device=self.device,
                    vrf='management',
                    timeout_seconds=600)
                try:
                    with open(
                            "{}/{}_post_issu_trig.cfg".format(
                                runtime.directory, self.device.hostname),
                            "r") as post_trig_file:
                        post_cfg_str = post_trig_file.read()
                except IOError:
                    step.failed(
                        "file not found. Please check path/content of the file"
                    )
                post_trig_config = get_config_dict(post_cfg_str)
            else:
                post_trig_config = self.device.api.get_running_config_dict()
            output = compare_config_dicts(pre_trig_config, post_trig_config,
                                          [r'(boot|version)'])
            if output:
                step.failed(
                    "Inconsistencies in running config post trigger:{}".format(
                        output))
Esempio n. 25
0
def copy_to_device(device,
                   remote_path,
                   local_path,
                   server,
                   protocol,
                   vrf=None,
                   timeout=300,
                   compact=False,
                   use_kstack=False,
                   **kwargs):
    """
    Copy file from linux server to device
        Args:
            device ('Device'): Device object
            remote_path ('str'): remote file path on the server
            local_path ('str'): local file path to copy to on the device
            server ('str'): hostname or address of the server
            protocol('str'): file transfer protocol to be used
            vrf ('str'): vrf to use (optional)
            timeout('int'): timeout value in seconds, default 300
            compact('bool'): compress image option for n9k, defaults False
            use_kstack('bool'): Use faster version of copy, defaults False
                                Not supported with a file transfer protocol
                                prompting for a username and password
        Returns:
            None
    """
    fu = FileUtils.from_device(device)

    # build the source address
    source = '{p}://{s}/{f}'.format(p=protocol, s=server, f=remote_path)
    try:
        if vrf:
            fu.copyfile(source=source,
                        destination=local_path,
                        device=device,
                        vrf=vrf,
                        timeout_seconds=timeout,
                        compact=compact,
                        use_kstack=use_kstack,
                        **kwargs)
        else:
            fu.copyfile(source=source,
                        destination=local_path,
                        device=device,
                        timeout_seconds=timeout,
                        compact=compact,
                        use_kstack=use_kstack,
                        **kwargs)
    except Exception as e:
        if compact or use_kstack:
            log.info("Failed to copy with compact/use-kstack option, "
                     "retrying again without compact/use-kstack")
            fu.copyfile(source=source,
                        destination=local_path,
                        device=device,
                        vrf=vrf,
                        timeout_seconds=timeout,
                        **kwargs)
        else:
            raise
class test_filetransferutils(unittest.TestCase):
    # Instantiate tesbed and device objects
    tb = Testbed(name='myTestbed')
    device = Device(testbed=tb, name='aDevice', os='iosxr')

    # Instantiate a filetransferutils instance for IOSXE device
    fu_device = FileUtils.from_device(device)

    # Add testbed servers for authentication
    device.testbed.servers = AttrDict(
        server_name = dict(
            username="******", password="******", address='1.1.1.1'),
    )

    dir_output = ['disk0:/status_file', 'disk0:/clihistory', 'disk0:/cvac',
        'disk0:/core', 'disk0:/envoke_log', 'disk0:/lost+found',
        'disk0:/pnet_cfg.log', 'disk0:/oor_aware_process',
        'disk0:/.python-history', 'disk0:/cvac.log', 'disk0:/nvgen_traces',
        'disk0:/fake_config_2.tcl', 'disk0:/ztp',
        'disk0:/config -> /misc/config', 'disk0:/memleak.tcl']


    # Mock device output
    raw1 = '''
        copy disk0:/memleak.tcl ftp://1.1.1.1//auto/tftp-ssr/memleak.tcl
        Address or name of remote host [1.1.1.1]? 
        Destination filename [/auto/tftp-ssr/memleak.tcl]? 
        !!
        104260 bytes copied in 0.396 secs (263283 bytes/sec)
    '''

    raw2 = '''
        dir

        Directory of /misc/scratch
           32 -rw-rw-rw- 1   824 Mar  7 06:29 cvac.log
           43 -rwxr--r-- 1     0 Mar 22 08:58 fake_config_2.tcl
           41 -rw-r--r-- 1  1985 Mar 12 14:35 status_file
           13 -rw-r--r-- 1  1438 Mar  7 14:26 envoke_log
           16 -rw-r--r-- 1    98 Mar  7 06:34 oor_aware_process
         8178 drwxr-xr-x 2  4096 Mar  7 14:27 memleak.tcl
         8177 drwx---r-x 2  4096 Mar  7 14:27 clihistory
           15 lrwxrwxrwx 1    12 Mar  7 14:26 config -> /misc/config
           12 drwxr-xr-x 2  4096 Mar  7 14:26 core
           14 -rw-r--r-- 1 10429 Mar  7 14:26 pnet_cfg.log
           11 drwx------ 2 16384 Mar  7 14:26 lost+found
         8179 drwxr-xr-x 8  4096 Mar  7 07:01 ztp
           42 -rw------- 1     0 Mar 20 11:08 .python-history
        16354 drwxr-xr-x 2  4096 Mar  7 07:22 nvgen_traces
        16353 drwxrwxrwx 3  4096 Mar  7 14:29 cvac

        1012660 kbytes total (938376 kbytes free)
    '''

    raw3 = '''
        delete disk0:fake_config_2.tcl
        Delete disk0:fake_config_2.tcl[confirm]
    '''

    raw4 = '''
        show clock | redirect ftp://1.1.1.1//auto/tftp-ssr/show_clock
        Writing /auto/tftp-ssr/show_clock 
    '''

    raw5 = {'futlinux.check_file.return_value': '',
        'futlinux.deletefile.return_value': ''}

    raw6 = '''
        copy running-config ftp://10.1.6.242//auto/tftp-ssr/fake_config_2.tcl
        Host name or IP address (control-c to abort): [10.1.6.242;default]?
        Destination username: []?rcpuser
        Destination password: 
        Destination file name (control-c to abort): [/auto/tftp-ssr/fake_config_2.tcl]?
        Building configuration.
        349 lines built in 1 second
        [OK]
    '''

    raw7 =  '''
            sftp running-config [email protected]:/home/virl vrf management
            Thu Oct 10 15:45:18.989 UTC
            Connecting to 172.16.1.250...
            Password: 

            /misc/disk1/running-config
              Overwrite /home/virl/running-config on host 172.16.1.250, continu? [
              yes/no]: yes
              Transferred 11332 Bytes
              11332 bytes copied in 0 sec (251822)bytes/sec
    '''
    outputs = {}
    outputs['copy disk0:/fake_config_2.tcl '
        'ftp://1.1.1.1//auto/tftp-ssr/fake_config_2.tcl'] = raw1
    outputs['dir'] = raw2
    outputs['delete disk0:fake_config.tcl'] = raw3
    outputs['show clock | redirect ftp://1.1.1.1//auto/tftp-ssr/show_clock'] = \
        raw4
    outputs['copy running-config ftp://10.1.6.242//auto/tftp-ssr/fake_config_2.tcl'] = \
        raw6
    outputs['sftp running-config [email protected]:/home/virl'] = raw7
    def mapper(self, key, timeout=None, reply= None, prompt_recovery=False):
        return self.outputs[key]

    def test_copyfile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        # Call copyfiles
        self.fu_device.copyfile(source='disk0:/fake_config_2.tcl',
            destination='ftp://1.1.1.1//auto/tftp-ssr/fake_config_2.tcl',
            timeout_seconds='300', device=self.device)

    def test_copyfile_sftp(self):
        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        # Call copyfiles
        self.fu_device.copyfile(source='running-config',
                                destination='sftp://1.1.1.1//home/virl',
                                device=self.device)

    def test_dir(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        directory_output = self.fu_device.dir(target='disk0:',
            timeout_seconds=300, device=self.device)

        self.assertEqual(sorted(directory_output), sorted(self.dir_output))

    def test_stat(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        file_details = self.fu_device.stat(target='disk0:memleak.tcl',
          timeout_seconds=300, device=self.device)

        self.assertEqual(file_details['index'],
          '8178')
        self.assertEqual(file_details['date'], 'Mar 7 14:27')
        self.assertEqual(file_details['permission'], 'drwxr-xr-x')
        self.assertEqual(file_details['size'], '4096')

    def test_deletefile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.deletefile(target='disk0:fake_config.tcl',
          timeout_seconds=300, device=self.device)

    def test_renamefile(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        with self.assertRaisesRegex(
            NotImplementedError, "The fileutils module genie.libs."
            "filetransferutils.plugins.iosxr.fileutils does not implement "
            "renamefile."):
            self.fu_device.renamefile(source='disk0:fake_config.tcl',
              destination='memleak.tcl',
                timeout_seconds=300, device=self.device)

    @patch('genie.libs.filetransferutils.plugins.fileutils.FileUtils.validateserver',
        return_value=raw5)
    def test_validateserver(self, raw5):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.validateserver(
            target='ftp://1.1.1.1//auto/tftp-ssr/show_clock',
            timeout_seconds=300, device=self.device)

    def test_copyconfiguration(self):

        self.device.execute = Mock()
        self.device.execute.side_effect = self.mapper

        self.fu_device.copyconfiguration(source='running-config',
          destination='ftp://10.1.6.242//auto/tftp-ssr/fake_config_2.tcl',
          timeout_seconds=300, device=self.device)