def getGap(self): ## Do we have minimum packet gaps? min_gap = float(0.0) if self.test.config.minimum_gap is not None: min_gap = float(self.test.config.minimum_gap) log.info(" minimum_gap : %s seconds" % min_gap) return min_gap
def getChunk(self): ## Do we have maximum chunk sizes? chunk = int(0) if self.test.config.chunk_size is not None: chunk = int(self.test.config.chunk_size) log.info(" chunk_size : %s bytes" % chunk) return chunk
def upload(self, localname, remotename=None): """Place a file onto the server resource. **Args:** localname (str): Name of the file to send to the server **Kwargs:** remotename (str): Name of sent file to use on the server. If a name is not provided then the name of the sent file is used (default). """ if remotename is None: remotename = localname upload_status = True log_msg = ('%s - upload of "%s" to "%s"' % (type(self).__name__, localname, remotename)) try: self.client.storbinary(('STOR %s' % remotename), open(localname, 'rb')) log.info('%s OK' % log_msg) #except ftplib.error_perm as err: except all as err: upload_status = False log.warn('%s failed: "%s"' % (log_msg, str(err))) finally: return upload_status
def download(self, remotename, localname=None): """The :meth:`download` method is a wrapper around the :class:`tftplib.FTP` class :meth:`connect`, :meth:`download` and methods. Will attempt to download `remotename` to the local filesystem. If `localname` is `None` then `localname` will be the same as `remotename`. The initial download is written to a :class:`tempfile.NamedTemporaryFile` object so that failed transfers are automatically cleaned up locally. Successful transfers produce an atomic rename to `localname`. **Args:** remotename (str): Name of the file to retrieve on the server **Kwargs:** localname (str): Name of retrived file on the local filesystem. If a name is not provided then the name of the retrieved file is used (default). **Returns:** boolean:: True - successful transfer False - failed transfer """ if localname is None: localname = remotename download_status = True log_msg = ('%s - download of "%s" to "%s"' % (type(self).__name__, remotename, localname)) try: temp_fs = tempfile.NamedTemporaryFile(dir=os.curdir) self.client.retrbinary('RETR %s' % remotename, open(temp_fs.name, 'wb').write) # Transfer was successful so flag temporary file as persistent # so that the NamedTemporaryFile does not throw exception when # it tries to delete. temp_fs.delete = False os.rename(temp_fs.name, localname) log.info('%s OK' % log_msg) except (OSError, ftplib.error_perm) as err: download_status = False log.warn('%s failed: "%s"' % (log_msg, str(err))) finally: return download_status
def upload(self, localname, remotename=None): """Place a file onto the server resource. **Args:** localname (str): Name of the file to send to the server **Kwargs:** remotename (str): Name of sent file to use on the server. If a name is not provided then the name of the sent file is used (default). """ if remotename is None: remotename = localname log.info('Uploading local file "%s" to remote file "%s"' % (localname, remotename)) self.client.upload(remotename, localname)
def download(self, remotename, localname=None): """Retrieve a file from the server resource. **Args:** remotename (str): Name of the file to retrieve on the server **Kwargs:** localname (str): Name of retrived file on the local filesystem. If a name is not provided then the name of the retrieved file is used (default). """ if localname is None: localname = remotename log.info('Downloading remote file "%s" to local file "%s"' % (remotename, localname)) self.client.download(remotename, localname)
def do_POST(self): """Response to a POST request.""" log.info("HTTP POST request received from %s on port %s for %s" % ( self.client_address[0], self.client_address[1], self.path, )) self.send_response(200) self.end_headers() received = self.rfile.read() log.info( "HTTP POST request finished for %s on port %s for %s\n" \ " Size of received content: %s\n" \ " Resulting SHA1 sum of content: %s" % ( self.client_address[0], self.client_address[1], self.path, len(received), hashlib.sha1(received).hexdigest(), ))
def _start_inline(self): """The inline variant of the :meth:`start` method. This inline variant of the ITT server start process is based on the :mod:`multiprocessing` module. The server process is spawned, creating a :class:`multiprocessing.Process` object. :meth:`_start_inline` is better suited to testing procedures and the Python interpreter as it does not attempt to kill and detach from the parent process. Also, the PID of the child is self-contained so you don't have to worry about the PID file. **Returns:** boolean:: ``True`` -- success ``False`` -- failure """ start_status = False log_msg = '%s server process' % type(self).__name__ log.info('%s - starting inline ...' % log_msg) self.proc = multiprocessing.Process(target=self._start_server, args=(self.exit_event, )) self.proc.start() log.info('%s - started with PID %d' % (log_msg, self.proc.pid)) time.sleep(0.1) # can do better -- check TODO. # Flag the server as being operational. if self.proc.is_alive(): self.pid = self.proc.pid start_status = True return start_status
def restart(self): """Restart the daemon No real magic here -- simply calls the :meth:`stop` and :meth:`start` method sequence (in that order) .. note:: TODO - Need better tests around this process. """ log_msg = '%s daemon --' % type(self).__name__ log.info('%s attempting restart ...' % log_msg) log.info('%s stopping ...' % log_msg) self.stop() # Allow some time between restarts. time.sleep(2) log.info('%s attempting restart ...' % log_msg) self.start()
def _exit_handler(self, server_obj): log_msg = '%s --' % type(self).__name__ log.info('%s SIGTERM intercepted' % log_msg) server_obj.shutdown() log.debug('%s terminated' % log_msg)
def _exit_handler(self, signal, frame): log_msg = '%s --' % type(self).__name__ log.info('%s SIGTERM intercepted' % log_msg) sys.exit(0)
def upload(self): HTTP_DEVNULL = "/testing/dev/null" ## Size of data bytes = int(0) try: log.info("HTTP client begins upload (HTTP POST):") generated_url = "http://%s/%s" % ( self.test.connection.netloc, HTTP_DEVNULL, ) log.info(" url : %s" % generated_url) if self.test.content.static: log.info(" content : %s" % self.test.content.filename) else: log.info(" content : (random data)") bytes = self.test.content.bytes log.info(" size : %s bytes" % bytes) min_gap = self.getGap() chunk = self.getChunk() ## Open the file for sending self.test.content.open() ## Open HTTP connection & send headers http = self.setupUploadConnection(HTTP_DEVNULL) ## Send data i = int(0) while i < bytes: if chunk > 0: if (bytes - i) < chunk: bytes_to_send = (bytes - i) else: bytes_to_send = chunk ## Send only as much as we're allowed data = self.test.content.read(bytes=bytes_to_send) if data == "": ## File was shorter than we thought? break self.addAndSend(http, data) i = i + bytes_to_send ## Sleep for the minimum gap size if i < bytes: time.sleep(min_gap) else: ## Send everything as fast as possible self.addAndSend(http, self.test.content.read()) i = i + bytes ## Close the file self.test.content.close() ## XXX: todo: generalise the sha1sum stuff shasum = hashlib.sha1(self.sent_data).hexdigest() log.info("HTTP client finishes upload (HTTP POST):") log.info(" url : %s" % generated_url) log.info(" sent : %s bytes" % len(self.sent_data)) log.info(" sha1_sum : %s" % shasum) ## XXX: todo: if response ==200, else: error response = http.getresponse() log.info(" http_response : %s" % ( response.status, )) except (socket.error, httplib.HTTPException), e: log.error("Upload (HTTP POST) failed with an error: %s" % (str(e))) return
def download(self): try: log.info("HTTP client begins download (HTTP GET):") bytes_qs = "" if self.test.content.static: url_path = self.test.content.filename log.info(" content: %s" % url_path) else: url_path = "/testing/dev/random" log.info(" content : (random data)") log.info(" size : %s bytes" % self.test.content.bytes) bytes_qs = "&bytes=%s" % ( self.test.content.bytes, ) min_gap = self.getGap() chunk = self.getChunk() generated_url = urlparse.urljoin( "http://%s" % self.test.connection.netloc, "%s?minimum_gap=%s&chunk_size=%s%s" % ( url_path, min_gap, chunk, bytes_qs, ## May be set to "&bytes=x" if random data ), ) log.info(" url : %s" % generated_url) download = requests.get(generated_url) shasum = hashlib.sha1(download.content).hexdigest() log.info("HTTP client finishes download (HTTP GET):") log.info(" url : %s" % generated_url) log.info(" received : %s bytes" % len(download.content)) log.info(" sha1_sum : %s" % shasum) log.info(" http_response : %s" % (download.status_code)) except requests.ConnectionError, e: log.error("Download (HTTP GET) failed with a connection error: %s" % (str(e)))
def create_tftp_session(self): """ """ log.info('Port %d specified: creating TFTP client session' % self.port) self.client = tftpy.TftpClient(self.host, self.port)
def do_GET(self): """Respond to a GET request.""" log.info("HTTP GET request received from %s on port %s for %s" % ( self.client_address[0], self.client_address[1], self.path, )) ## Set the request handlers root dir, equal to the servers root dir ## (See Python crazyness in itt.server.httpserver) root = self.server.root ## Deal with (potential) query strings if self.path.find('?') != -1: path, qs = self.path.split('?') else: path = self.path qs = '' qs = urlparse.parse_qs(qs) min_gap = float(0.0) chunk = int(0) ## Setup test configuration config = itt.TestConfig() if 'minimum_gap' in qs: min_gap = float(qs['minimum_gap'][0]) config.minimum_gap = min_gap if 'chunk_size' in qs: chunk = int(qs['chunk_size'][0]) config.chunk_size = chunk ## Set bytes to something, overwrite in if-block below bytes = self.DEFAULT_BYTES ## Check for "special" paths, otherwise try and read real files if path == self.RANDOM_PATH: ## Send random data if 'bytes' not in qs: log.warning( "Query string does not specify 'bytes', but random data requested" ) log.warning("Using %s bytes by default" % self.DEFAULT_BYTES) else: bytes = int(qs['bytes'][0]) content = itt.TestContent(None, bytes=bytes) elif path == self.NULL_PATH: ## Send nothing bytes = 0 content = itt.TestContent(None, bytes=bytes) else: ## Send real files from the servers' root ## Normalise and check that we're still under root (our make-believe "chroot") normpath = os.path.normpath("%s%s%s" % ( root, os.path.sep, path, )) if not normpath.startswith(root + os.path.sep): self.logAndThrow("Invalid path") ## We're happy that the file is safely under the root dir content = itt.TestContent(normpath) bytes = content.bytes ## connection = None, as the client has created the connection self.test = itt.Test(config, content, None) ## Open the file for sending self.test.content.open() ## Send headers self.send_response(200) self.send_header("content-type", "text/plain") self.send_header("content-length", self.test.content.bytes) self.end_headers() ## Send data i = int(0) while i < bytes: if chunk > 0: if (bytes - i) < chunk: bytes_to_send = (bytes - i) else: bytes_to_send = chunk ## Send only as much as we're allowed data = self.test.content.read(bytes=bytes_to_send) if data == "": ## File was shorter than we thought? break self.storeAndWrite(data, self.wfile) i = i + bytes_to_send ## Sleep for the minimum gap size if i < bytes: time.sleep(min_gap) else: ## Send everything as fast as possible self.storeAndWrite(self.test.content.read(), self.wfile) i = i + bytes ## Close the file self.test.content.close() log.info( "HTTP GET request finished for %s on port %s for %s\n Resulting SHA1 sum of content: %s" % ( self.client_address[0], self.client_address[1], self.path, hashlib.sha1(self._contentSent).hexdigest(), ))