def _SetConfig(self, destination_file, data, canary): # Canarying is not supported on BROCADE. if canary: raise exceptions.SetConfigCanaryingError( '%s devices do not support ' 'configuration canarying.' % self.vendor_name) # The result object. result = base_device.SetConfigResult() # Check for a connection to the Brocade. if not self._GetConnected(): raise exceptions.SetConfigError('Cannot use unless already ' 'connected to the device.') if destination_file in self.NON_FILE_DESTINATIONS: # Use a random remote file name file_name = 'push.%s' % os.urandom(8).encode('hex') else: # Okay, the user is just copying a file, not a configuraiton into either # startup-config or running-config, therefore we should use the entire # path. file_name = destination_file # Copy the file to the router using SCP. scp = pexpect_connection.ScpPutConnection(host=self.loopback_ipv4, username=self._username, password=self._password) # This is a workaround. Brocade case: 537017. # Brocade changed all the filename to lowercases after scp file_name = file_name.lower() try: scp.Copy(data, destination_file='slot1:' + file_name) except pexpect_connection.Error, e: raise exceptions.SetConfigError( 'Failed to copy configuration to remote device. %s' % str(e))
def _SetConfig(self, destination_file, data, canary): # Canarying is not supported on ASA. if canary: raise exceptions.SetConfigCanaryingError('%s devices do not support ' 'configuration canarying.' % self.vendor_name) # We only support copying to 'running-config' or 'startup-config' on ASA. if destination_file not in ('running-config', 'startup-config'): raise exceptions.SetConfigError('destination_file argument must be ' '"running-config" or "startup-config" ' 'for %s devices.' % self.vendor_name) # Result object. result = base_device.SetConfigResult() # Get the MD5 sum of the file. local_digest = hashlib.md5(data).hexdigest() try: # Get the working path from the remote device remote_path = 'nvram:/' except exceptions.CmdError as e: msg = 'Error obtaining working directory: %s' % e logging.error(msg) raise exceptions.SetConfigError(msg) # Use a random remote file name remote_tmpfile = '%s/push.%s' % ( remote_path.rstrip(), os.urandom(8).encode('hex')) # Upload the file to the device. scp = pexpect_connection.ScpPutConnection( self.loopback_ipv4, username=self._username, password=self._password) try: scp.Copy(data, remote_tmpfile) except pexpect_connection.Error as e: raise exceptions.SetConfigError( 'Failed to copy configuration to remote device. %s' % str(e)) # Get the file size on the router. try: # Get the MD5 hexdigest of the file on the remote device. try: verify_output = self._Cmd('verify /md5 %s' % remote_tmpfile) match = MD5_RE.search(verify_output) if match is not None: remote_digest = match.group(1) else: raise exceptions.SetConfigError( 'The "verify /md5 <filename>" command did not produce ' 'expected results. It returned: %r' % verify_output) except exceptions.CmdError as e: raise exceptions.SetConfigError( 'The MD5 hash command on the router did not succed. ' 'The device may not support: "verify /md5 <filename>"') # Verify the local_digest and remote_digest are the same. if local_digest != remote_digest: raise exceptions.SetConfigError( 'File transfer to remote host corrupted. Local digest: %r, ' 'Remote digest: %r' % (local_digest, remote_digest)) # Copy the file from flash to the # destination(running-config, startup-config). # Catch errors that may occur during application, and report # these to the user. try: self._connection.child.send( 'copy %s %s\r' % (remote_tmpfile, destination_file)) pindex = self._connection.child.expect( [r'Destination filename \[%s\]\?' % destination_file, r'%\s*\S*.*', r'%Error.*', self._connection.re_prompt], timeout=self.timeout_act_user) if pindex == 0: self._connection.child.send('\r') try: pindex = self._connection.child.expect( [r'Invalid input detected', self._connection.re_prompt, r'%Warning:There is a file already existing.*' 'Do you want to over write\? \[confirm\]'], timeout=self.timeout_act_user) if pindex == 0: # Search again using findall to get all bad lines. bad_lines = re.findall( r'^(.*)$[\s\^]+% Invalid input', self._connection.child.match.string, re.MULTILINE) raise exceptions.SetConfigSyntaxError( 'Configuration loaded, but with bad lines:\n%s' % '\n'.join(bad_lines)) if pindex == 2: # Don't over-write. self._connection.child.send('n') raise exceptions.SetConfigError( 'Destination file %r already exists, cannot overwrite.' % destination_file) except (pexpect.EOF, pexpect.TIMEOUT) as e: raise exceptions.SetConfigError( 'Copied file to device, but did not ' 'receive prompt afterwards. %s %s' % (self._connection.child.before, self._connection.child.after)) elif pindex == 2: print "MATCHED 2" # The expect does a re.search, search again using findall to get all raise exceptions.SetConfigError('Could not copy temporary ' 'file to %s.' % destination_file) except (pexpect.EOF, pexpect.TIMEOUT) as e: raise exceptions.SetConfigError( 'Attempted to copy to bootflash, but a timeout occurred.') # We need to 'write memory' if we are doing running-config. if destination_file == 'running-config': logging.debug('Attempting to copy running-config to startup-config ' 'on %s(%s)', self.host, self.loopback_ipv4) try: self._Cmd('wr mem') except exceptions.CmdError as e: raise exceptions.SetConfigError('Failed to write startup-config ' 'for %s(%s). Changes applied. ' 'Error was: %s' % (self.host, self.loopback_ipv4, str(e))) finally: try: self._DeleteFile(remote_tmpfile) except DeleteFileError as e: result.transcript = 'SetConfig warning: %s' % str(e) logging.warn(result.transcript) # And finally, return the result text. return result