def put(self, ticket_id): # TODO # - reject invalid or expired ticket # - start expire timer if not ticket_id: raise HTTPBadRequest("Ticket id is required") try: ticket = self.request.json except ValueError as e: raise HTTPBadRequest("Invalid ticket: %s" % e) try: timeout = ticket["timeout"] except KeyError: raise HTTPBadRequest("Missing timeout key") try: timeout = int(timeout) except ValueError as e: raise HTTPBadRequest("Invalid timeout value: %s" % e) try: url_str = ticket["url"] except KeyError: raise HTTPBadRequest("Missing url key in ticket") try: ticket["url"] = urllib_parse.urlparse(url_str) except (ValueError, AttributeError, TypeError): raise HTTPBadRequest("Invalid url string %r" % url_str) if ticket["url"].scheme not in supported_schemes: raise HTTPBadRequest("url scheme is not supported " "for url: %s" % ticket["url"].scheme) ticket["expires"] = int(util.monotonic_time()) + timeout tickets.add(ticket_id, ticket) return response()
def __init__(self, ticket_dict): if not isinstance(ticket_dict, dict): raise errors.InvalidTicket( "Invalid ticket: %r, expecting a dict" % ticket_dict) self._uuid = _required(ticket_dict, "uuid", six.string_types) self._size = _required(ticket_dict, "size", six.integer_types) self._ops = _required(ticket_dict, "ops", list) self._timeout = _required(ticket_dict, "timeout", six.integer_types) now = int(util.monotonic_time()) self._expires = now + self._timeout self._access_time = now url_str = _required(ticket_dict, "url", six.string_types) try: self._url = urllib_parse.urlparse(url_str) except (ValueError, AttributeError, TypeError) as e: raise errors.InvalidTicketParameter("url", url_str, e) if self._url.scheme not in supported_schemes: raise errors.InvalidTicketParameter( "url", url_str, "Unsupported url scheme: %s" % self._url.scheme) self._filename = _optional(ticket_dict, "filename", six.string_types) self._sparse = _optional(ticket_dict, "sparse", bool, default=False) self._operations = [] self._lock = threading.Lock() # Set holding ongoing operations. self._ongoing = set() # Ranges transferred by completed operations. self._completed = []
def __init__(self, ticket_dict): if not isinstance(ticket_dict, dict): raise errors.InvalidTicket( "Invalid ticket: %r, expecting a dict" % ticket_dict) self._uuid = _required(ticket_dict, "uuid") self._size = _required(ticket_dict, "size") self._ops = _required(ticket_dict, "ops") timeout = _required(ticket_dict, "timeout") try: timeout = int(timeout) except ValueError as e: raise errors.InvalidTicketParameter("timeout", timeout, e) now = int(util.monotonic_time()) self._expires = now + timeout self._access_time = now url_str = _required(ticket_dict, "url") try: self._url = urllib_parse.urlparse(url_str) except (ValueError, AttributeError, TypeError) as e: raise errors.InvalidTicketParameter("url", url_str, e) if self._url.scheme not in supported_schemes: raise errors.InvalidTicketParameter( "url", url_str, "Unsupported url scheme: %s" % self._url.scheme) self._filename = ticket_dict.get("filename") self._operations = [] self._lock = threading.Lock()
def add_ticket(ticket): # Simulate adding a ticket to the server, without modifying the source # ticket. ticket = json.loads(json.dumps(ticket)) ticket["expires"] = int(util.monotonic_time()) + ticket["timeout"] ticket["url"] = urllib_parse.urlparse(ticket["url"]) tickets.add(ticket["uuid"], ticket)
def idle_time(self): """ Return the time in which the ticket became inactive. """ if self.active(): return 0 return int(util.monotonic_time()) - self._access_time
def idle_time(self): """ Return the time in which the ticket became inactive. """ if self.active(): return 0 return int(util.monotonic_time()) - self._access_time
def touch(self): """ Extend the ticket and update the last access time. Must be called when an operation is completed. """ now = int(util.monotonic_time()) self._expires = now + self._timeout self._access_time = now
def touch(self): """ Extend the ticket and update the last access time. Must be called when an operation is completed. """ now = int(util.monotonic_time()) self._expires = now + self._timeout self._access_time = now
def test_tickets_put(fake_time): ticket = testutils.create_ticket() body = json.dumps(ticket) res = unix_request("PUT", "/tickets/%(uuid)s" % ticket, body) # Server adds expires key ticket["expires"] = int(util.monotonic_time()) + ticket["timeout"] ticket["active"] = False server_ticket = get_ticket(ticket["uuid"]) assert res.status == 200 assert server_ticket == ticket
def test_tickets_put(monkeypatch): monkeypatch.setattr(util, "monotonic_time", lambda: 123456789) ticket = create_ticket() body = json.dumps(ticket) res = unix_request("PUT", "/tickets/%(uuid)s" % ticket, body) # Server adds expires key ticket["expires"] = int(util.monotonic_time()) + ticket["timeout"] server_ticket = get_ticket(ticket["uuid"]) assert res.status == 200 assert server_ticket == ticket
def test_tickets_put(fake_time): ticket = testutils.create_ticket(sparse=False) body = json.dumps(ticket) res = http.unix_request( config.tickets.socket, "PUT", "/tickets/%(uuid)s" % ticket, body) # Server adds expires key ticket["expires"] = int(util.monotonic_time()) + ticket["timeout"] ticket["active"] = False ticket["idle_time"] = 0 server_ticket = auth.get(ticket["uuid"]).info() assert res.status == 200 assert res.getheader("content-length") == "0" assert server_ticket == ticket
def test_tickets_put(fake_time): ticket = testutils.create_ticket(sparse=False) body = json.dumps(ticket) res = http.unix_request( config.tickets.socket, "PUT", "/tickets/%(uuid)s" % ticket, body) # Server adds expires key ticket["expires"] = int(util.monotonic_time()) + ticket["timeout"] ticket["active"] = False ticket["idle_time"] = 0 server_ticket = auth.get(ticket["uuid"]).info() assert res.status == 200 assert res.getheader("content-length") == "0" assert server_ticket == ticket
def info(self): info = { "active": self.active(), "expires": self._expires, "ops": list(self._ops), "size": self._size, "timeout": self.expires - int(util.monotonic_time()), "url": urllib_parse.urlunparse(self._url), "uuid": self._uuid, } if self.filename: info["filename"] = self.filename transferred = self.transferred() if transferred is not None: info["transferred"] = transferred return info
def authorize(ticket_id, op, size): """ Authorizing a ticket operation """ log.debug("Authorizing %r to offset %d for ticket %s", op, size, ticket_id) try: ticket = _tickets[ticket_id] except KeyError: raise HTTPForbidden("No such ticket %r" % ticket_id) if ticket["expires"] <= util.monotonic_time(): raise HTTPForbidden("Ticket %r expired" % ticket_id) if op not in ticket["ops"]: raise HTTPForbidden("Ticket %r forbids %r" % (ticket_id, op)) if size > ticket["size"]: raise HTTPForbidden("Content-Length out of allowed range") return ticket
def authorize(ticket_id, op, offset, size): """ Authorizing a ticket operation """ log.debug("Authorizing op=%r, offset=%r, size=%r, for ticket %s", op, offset, size, ticket_id) try: ticket = _tickets[ticket_id] except KeyError: raise HTTPForbidden("No such ticket %r" % ticket_id) if ticket.expires <= util.monotonic_time(): raise HTTPForbidden("Ticket %r expired" % ticket_id) if not ticket.may(op): raise HTTPForbidden("Ticket %r forbids %r" % (ticket_id, op)) end = (offset + size) if size else offset if end > ticket.size: raise HTTPForbidden("Requested range out of allowed range") return ticket
def authorize(ticket_id, op): """ Authorizing a ticket operation """ log.debug("AUTH op=%s ticket=%s", op, ticket_id) try: ticket = _tickets[ticket_id] except KeyError: raise errors.AuthorizationError("No such ticket {}".format(ticket_id)) if ticket.expires <= util.monotonic_time(): raise errors.AuthorizationError("Ticket {} expired".format(ticket_id)) if not ticket.may(op): raise errors.AuthorizationError("Ticket {} forbids {}".format( ticket_id, op)) return ticket
def authorize(ticket_id, op, offset, size): """ Authorizing a ticket operation """ log.debug("AUTH op=%s offset=%s size=%s ticket=%s", op, offset, size, ticket_id) try: ticket = _tickets[ticket_id] except KeyError: raise errors.AuthorizationError("No such ticket {}".format(ticket_id)) if ticket.expires <= util.monotonic_time(): raise errors.AuthorizationError("Ticket {} expired".format(ticket_id)) if not ticket.may(op): raise errors.AuthorizationError( "Ticket {} forbids {}".format(ticket_id, op)) end = (offset + size) if size else offset if end > ticket.size: raise errors.AuthorizationError("Requested range out of allowed range") return ticket
def __init__(self, ticket_dict): if not isinstance(ticket_dict, dict): raise errors.InvalidTicket( "Invalid ticket: %r, expecting a dict" % ticket_dict) self._uuid = _required(ticket_dict, "uuid", six.string_types) self._size = _required(ticket_dict, "size", six.integer_types) self._ops = _required(ticket_dict, "ops", list) self._timeout = _required(ticket_dict, "timeout", six.integer_types) now = int(util.monotonic_time()) self._expires = now + self._timeout self._access_time = now url_str = _required(ticket_dict, "url", six.string_types) try: self._url = urllib_parse.urlparse(url_str) except (ValueError, AttributeError, TypeError) as e: raise errors.InvalidTicketParameter("url", url_str, e) if not backends.supports(self._url.scheme): raise errors.InvalidTicketParameter( "url", url_str, "Unsupported url scheme: %s" % self._url.scheme) self._transfer_id = _optional( ticket_dict, "transfer_id", six.string_types) self._filename = _optional(ticket_dict, "filename", six.string_types) self._sparse = _optional(ticket_dict, "sparse", bool, default=False) self._operations = [] self._lock = threading.Lock() # Set holding ongoing operations. self._ongoing = set() # Ranges transferred by completed operations. self._completed = []
def patch(self, ticket_id): # TODO: restart expire timer if not ticket_id: raise HTTPBadRequest("Ticket id is required") try: patch = self.request.json except ValueError as e: raise HTTPBadRequest("Invalid patch: %s" % e) try: timeout = patch["timeout"] except KeyError: raise HTTPBadRequest("Missing timeout key") try: timeout = int(timeout) except ValueError as e: raise HTTPBadRequest("Invalid timeout value: %s" % e) try: ticket = tickets.get(ticket_id) except KeyError: raise HTTPNotFound("No such ticket: %s" % ticket_id) ticket["expires"] = int(util.monotonic_time()) + timeout self.log.info("Extending ticket %s, new expiration in %d", ticket_id, ticket["expires"]) return response()
def test_monotonic_time(): t1 = util.monotonic_time() time.sleep(0.01) t2 = util.monotonic_time() assert t1 <= t2
def test_monotonic_time(): t1 = util.monotonic_time() time.sleep(0.01) t2 = util.monotonic_time() assert t1 <= t2
def extend(self, timeout): expires = int(util.monotonic_time()) + timeout self._expires = expires
def extend(self, timeout): expires = int(util.monotonic_time()) + timeout log.info("Extending ticket %s, new expiration in %d", self._uuid, expires) self._expires = expires
def touch(self): """ Update the ticket access time. Must be called when an operation is completed. """ self._access_time = int(util.monotonic_time())
def extend(self, timeout): expires = int(util.monotonic_time()) + timeout self._expires = expires