"Bug 614173 Update pull changes, fix update command in devicemanager r=jmaher a=NPOTB"

This commit is contained in:
Mark Cote 2010-12-16 15:28:35 -08:00
parent e790251277
commit 630c5928ef

View File

@ -497,69 +497,96 @@ class DeviceManager:
return self.stripPrompt(data)
def pullFile(self, remoteFile):
"""Returns contents of remoteFile using the "pull" command.
The "pull" command is different from other commands in that DeviceManager
has to read a certain number of bytes instead of just reading to the
next prompt. This is more robust than the "cat" command, which will be
confused if the prompt string exists within the file being catted.
However it means we can't use the response-handling logic in sendCMD().
"""
def err(error_msg):
err_str = 'bad response to pull: %s!' % error_msg
err_str = 'error returned from pull: %s' % error_msg
print err_str
self._sock = None
raise FileError(err_str)
def read(to_recv, error_msg):
# FIXME: We could possibly move these socket-reading functions up to
# the class level if we wanted to refactor sendCMD(). For now they are
# only used to pull files.
def uread(to_recv, error_msg):
""" unbuffered read """
data = self._sock.recv(to_recv)
if not data:
err(error_msg)
return None
return data
self.sendCMD(['pull ' + remoteFile])
buffer = ''
while not '\n' in buffer:
data = read(1024, 'could not find metadata')
if data == None:
return
buffer += data
nl = buffer.find('\n')
metadata = buffer[:nl]
print 'metadata: %s' % metadata
filedata = buffer[nl+1:] # skip newline
sep = metadata.rfind(',')
if sep == -1:
err('could not find file size')
return None
filename = metadata[:sep]
filesizestr = metadata[sep+1:]
def read_until_char(c, buffer, error_msg):
""" read until 'c' is found; buffer rest """
while not '\n' in buffer:
data = uread(1024, error_msg)
if data == None:
err(error_msg)
return ('', '', '')
buffer += data
return buffer.partition(c)
def read_exact(total_to_recv, buffer, error_msg):
""" read exact number of 'total_to_recv' bytes """
while len(buffer) < total_to_recv:
to_recv = min(total_to_recv - len(buffer), 1024)
data = uread(to_recv, error_msg)
if data == None:
return None
buffer += data
return buffer
prompt = self.base_prompt + self.prompt_sep
buffer = ''
# expected return value:
# <filename>,<filesize>\n<filedata>
# or, if error,
# <filename>,-1\n<error message>
self.sendCMD(['pull ' + remoteFile])
# read metadata; buffer the rest
metadata, sep, buffer = read_until_char('\n', buffer, 'could not find metadata')
if not metadata:
return None
if self.debug >= 3:
print 'metadata: %s' % metadata
filename, sep, filesizestr = metadata.partition(',')
if sep == '':
err('could not find file size in returned metadata')
return None
try:
filesize = int(filesizestr)
except ValueError:
err('invalid file size')
return None
if filesize == -1:
while not '\n' in filedata:
data = read(1024, 'could not find metadata')
if data == None:
return None
filedata += data
nl = filedata.find('\n')
error_str = filedata[:nl]
filedata = filedata[nl+1:]
while filedata < len(prompt):
data = read(1024, 'could not find metadata')
if data == None:
return None
print 'error pulling file: %s' % error_str
err('invalid file size in returned metadata')
return None
total_to_recv = filesize + len(prompt)
while len(filedata) < total_to_recv:
to_recv = min(total_to_recv - len(filedata), 1024)
data = read(to_recv, 'could not get all file data')
if data == None:
if filesize == -1:
# read error message
error_str, sep, buffer = read_until_char('\n', buffer, 'could not find error message')
if not error_str:
return None
filedata += data
if filedata[-len(prompt):] != prompt:
err('no prompt')
return filedata
return filedata[:-len(prompt)]
# prompt should follow
read_exact(len(prompt), buffer, 'could not find prompt')
print 'DeviceManager: error pulling file: %s' % error_str
return None
# read file data
total_to_recv = filesize + len(prompt)
buffer = read_exact(total_to_recv, buffer, 'could not get all file data')
if buffer == None:
return None
if buffer[-len(prompt):] != prompt:
err('no prompt found after file data--DeviceManager may be out of sync with agent')
return buffer
return buffer[:-len(prompt)]
# copy file from device (remoteFile) to host (localFile)
def getFile(self, remoteFile, localFile = ''):
@ -586,29 +613,28 @@ class DeviceManager:
if (self.debug >= 3): print filelist
if not os.path.exists(localDir):
os.makedirs(localDir)
for f in filelist:
if f == '.' or f == '..':
continue
remotePath = remoteDir + '/' + f
localPath = os.path.join(localDir, f)
print 'remotePath is %s' % remotePath
print 'localPath is %s' % localPath
try:
is_dir = self.isDir(remotePath)
except FileError:
print 'bad file "%s"!' % remotePath
print 'isdir failed on file "%s"; continuing anyway...' % remotePath
continue
if is_dir:
if (self.getDirectory(remotePath, localPath) == None):
print 'aborted when getting directory'
print 'failed to get directory "%s"' % remotePath
return None
else:
# It's sometimes acceptable to have getFile() return None, such as
# when the agent encounters broken symlinks.
# FIXME: This should be improved so we know when a file transfer really
# failed.
self.getFile(remotePath, localPath)
if self.getFile(remotePath, localPath) == None:
print 'failed to get file "%s"; continuing anyway...' % remotePath
return filelist
def isDir(self, remotePath):
@ -624,42 +650,42 @@ class DeviceManager:
localHash = self.getLocalHash(localFile)
if (remoteHash == localHash):
return True
return True
return False
# return the md5 sum of a remote file
def getRemoteHash(self, filename):
data = self.sendCMD(['hash ' + filename])
if (data == None):
return ''
retVal = self.stripPrompt(data)
if (retVal != None):
retVal = retVal.strip('\n')
if (self.debug >= 3): print "remote hash returned: '" + retVal + "'"
return retVal
data = self.sendCMD(['hash ' + filename])
if (data == None):
return ''
retVal = self.stripPrompt(data)
if (retVal != None):
retVal = retVal.strip('\n')
if (self.debug >= 3): print "remote hash returned: '" + retVal + "'"
return retVal
# return the md5 sum of a file on the host
def getLocalHash(self, filename):
file = open(filename, 'rb')
if (file == None):
return None
file = open(filename, 'rb')
if (file == None):
return None
try:
mdsum = hashlib.md5()
except:
return None
try:
mdsum = hashlib.md5()
except:
return None
while 1:
data = file.read(1024)
if not data:
break
mdsum.update(data)
while 1:
data = file.read(1024)
if not data:
break
mdsum.update(data)
file.close()
hexval = mdsum.hexdigest()
if (self.debug >= 3): print "local hash returned: '" + hexval + "'"
return hexval
file.close()
hexval = mdsum.hexdigest()
if (self.debug >= 3): print "local hash returned: '" + hexval + "'"
return hexval
# Gets the device root for the testing area on the device
# For all devices we will use / type slashes and depend on the device-agent
@ -877,18 +903,20 @@ class DeviceManager:
if (destPath):
cmd += " " + destPath
if (self.debug > 3): print "updateApp using command: " + str(cmd)
if (ipAddr is not None):
ip, port = self.getCallbackIpAndPort(ipAddr, port)
cmd += " %s %s" % (ip, port)
if (self.debug > 3): print "updateApp using command: " + str(cmd)
# Set up our callback server
callbacksvr = callbackServer(ip, port, self.debug)
data = self.sendCMD([cmd])
status = callbacksvr.disconnect()
if (self.debug > 3): print "got status back: " + str(status)
else:
status = self.sendCMD([cmd])
return status