def post(self): user, user_data = server.is_valid_key(self) if not user: return server.response(self, {"values" : "BADAUTH"}) password_required = True if self.request.get("password") != "" else False group = escape(self.request.get("group")) if group == "": return server.response(self, {"status" : "MISSINGVALUES"}) if password_required: salt = server.generate_salt() password = hashlib.sha1(self.request.get("password") + salt).hexdigest() else: password = None salt = None description = escape(self.request.get("description")) check = models.Group.get_by_key_name(group) if check is not None: return server.response(self, {"status" : "GROUPEXISTS"}) new_group = models.Group(key_name=group, name=group, owner=user, description=description, password_required=password_required, password=password, salt=salt) new_group.put() memcache.delete("user-groups" + user.name) member = models.GroupMember(group=new_group, user=user) member.put() server.response(self)
def get(self, groupname): """Get a list of members for a particular group""" group = models.Group.get_by_key_name(groupname) if group is None: return server.response(self, {"status" : "NOTGROUP"}) members = models.GroupMember.all().filter("group =", group) server.response(self, {"status" : "OK", "members" : members}, template="groupmembers")
def post(self): user, user_data = server.is_valid_key(self) if not user: return server.response(self, values={"status" : "BADAUTH"}) logged_in = memcache.get("logged_in") del(logged_in[user.name]) memcache.set("logged_in", logged_in) server.response(self)
def post(self): user, user_details = server.is_valid_key(self) if not user: return server.response(self, values={"status" : "BADAUTH"}) facebook_session_key = models.FacebookSession.get_by_key_name(user.name) if not facebook_session_key: return server.response(self, values={"status" : "NOFBKEY"}) return server.response(self, values={"status": "OK", "session" : facebook_session_key}, template="session")
def post(self): user, userdata = server.is_valid_key(self) group = models.Group.get_by_key_name(self.request.get("group")) if group is None: return server.response(self, {"status" : "NOGROUP"}) if models.GroupMember.all().filter("group =", group).count(2) > 1: return server.response(self, {"status" : "HASMEMBERS"}) member = models.GroupMember.all().filter("group =", group).get() member.delete() group.delete() memcache.delete("user-groups" + user.name) server.response(self)
def get(self, user): """ Get a list of groups that a user is a member of :Parameters: - user: The name of the user. This is the tail of the url """ user = models.User.get_by_key_name(user) if user is None: return server.response(self, values={"status" : "NOUSER"}) groups = models.GroupMember.all().filter("user ="******"status" : "OK", "groups" : groups, "user" : user, }, template="usr-groups")
def post(self): """Logs the user in so other can see they are online. This should be called at least every 10 minutes otherwise the users status will be set to offline Returns the current ONLINE list""" user, user_data = server.is_valid_key(self) if not user: return server.response(self, values={"status" : "BADAUTH"}) logged_in = memcache.get("logged_in") if logged_in is None: logged_in = {} logged_in[user.name] = time.time() memcache.set("logged_in", logged_in) server.response(self, values={'status' : 'OK', "users" : logged_in}, template="loginlist")
def delete(serve, machine): request = VI.Destroy_TaskRequestMsg() _this = request.new__this(machine._mor) _this.set_attribute_type(machine._mor.get_attribute_type()) request.set_element__this(_this) try: serve._proxy.Destroy_Task(request) except: response(False, log=55)
def post(self): user, userdata = server.is_valid_key(self) group = models.Group.get_by_key_name(self.request.get("group")) if group is None: return server.response(self, {"status" : "NOGROUP"}) member = models.GroupMember.all().filter("group =", group).filter("user ="******"status" : "NONMEMBER"}) #owners cant leave their group if user.name == group.owner.name: return server.response(self, {"status" : "ISOWNER"}) member.delete() memcache.delete("user-groups" + user.name) server.response(self)
def post(self): user, userdata = server.is_valid_key(self) group = models.Group.get_by_key_name(self.request.get("group")) if group is None: return server.response(self, {"status" : "NOGROUP"}) if user.name != group.owner.name: return server.response(self, {"status" : "NOTOWNER"}) owner = models.GroupMember.all().filter("group =", group).filter("user ="******"newowner")) is_member = models.GroupMember.all().filter("group =", group).filter("user = "******"status" : "NONMEMBER"}) owner.owner = new_owner owner.put() server.response(self)
def send_data(self, request): """ Handles sending data to host for PUT or PATCH. :param request: http request object :type request: webob.Request :return: http response object :rtype: webob.Response """ # For now we require range headers; we could lift this restriction # later. If so, be sure to add conditions to request.headers access # below. # Note that webob request.headers is case-insensitive. if 'Content-Range' not in request.headers: raise exc.HTTPBadRequest( "Content-Range header required for {} requests".format( request.method)) resource_id = self.get_resource_id(request) imaged_url = self.get_imaged_url(request) headers = self.get_default_headers(resource_id) headers['Content-Range'] = request.headers['Content-Range'] headers['Content-Length'] = request.headers['Content-Length'] max_transfer_bytes = int(headers['Content-Length']) body = web.CappedStream(request.body_file, max_transfer_bytes) stream = False logging.debug("Resource %s: transferring %d bytes to host", resource_id, max_transfer_bytes) imaged_response = self.make_imaged_request(request.method, imaged_url, headers, body, stream) response = server.response(imaged_response.status_code) response.headers['Cache-Control'] = 'no-cache, no-store' return response
def get(self, res_id): resource_id = self.get_resource_id(self.request) imaged_url = self.get_imaged_url(self.request) headers = self.get_default_headers(resource_id) # Note that webob request.headers is case-insensitive. if 'Range' in self.request.headers: headers['Range'] = self.request.headers['Range'] body = "" stream = True # Don't let Requests read entire body into memory imaged_response = self.make_imaged_request(self.request.method, imaged_url, headers, body, stream) response = server.response(imaged_response.status_code) response.headers['Cache-Control'] = 'no-cache, no-store' response.headers['Content-Range'] = \ imaged_response.headers.get('Content-Range', '') disposition = imaged_response.headers.get('Content-Disposition') if disposition is not None: response.headers['Content-Disposition'] = disposition max_transfer_bytes = int(imaged_response.headers.get('Content-Length')) response.body_file = web.CappedStream( RequestStreamAdapter(imaged_response.iter_content(4096, False)), max_transfer_bytes) response.headers['Content-Length'] = str(max_transfer_bytes) logging.debug("Resource %s: transferring %d bytes from host", resource_id, max_transfer_bytes) return response
def delete(self, res_id): try: auth.remove(res_id) except KeyError as e: raise HTTPNotFound("No such session %r" % res_id) response = server.response(204) return response
def post(self): user, userdata = server.is_valid_key(self) if not user: return server.response(self, {"status": userdata}) if self.request.get("group") == "": return server.response(self, {"status" : "MISSINGVALUES"}) group = models.Group.get_by_key_name(self.request.get("group")) if group is None: return server.response(self, {"status" : "NOTGROUP"}) if group.password_required: password = hashlib.sha1(self.request.get("password") + group.salt).hexdigest() if password != group.password: return server.response(self, {"status" : "BADPASS"}) member = models.GroupMember(group=group, user=user) member.put() memcache.delete("user-groups" + user.name) return server.response(self)
def post(self): user, user_details = server.is_valid_key(self) if not user: return server.response(self, values={"status": "BADAUTH"}) facebook_session_key = models.FacebookSession.get_by_key_name(user.name) if not facebook_session_key: facebook_session_key = models.FacebookSession(key_name=user.name, user=user, uid=self.request.get("uid"), session_key=self.request.get("facebook_session_key"), expires=int(self.request.get("expires"))) else: facebook_session_key.uid = self.request.get("uid") facebook_session_key.session_key = self.request.get("facebook_session_key") facebook_session_key.expires = int(self.request.get("expires")) facebook_session_key.put() return server.response(self)
def post(self): """ Creates a new user Parameters: - name: The name of the new user - password: A sha1 hash of the users password - email: A valid email address for the user """ name = self.request.get("name") salt = server.generate_salt() password = hashlib.sha1(self.request.get("password") + salt).hexdigest() email = self.request.get("email") #check if this user exists already check_user = models.User.get_by_key_name(name) if check_user is not None: return server.response(self, values={"status" : "USEREXISTS"}) if re.search("^\w{5,18}$", name) is None: return server.response(self, values={"status" : "BADUSERNAME"}) if re.search("^(?:[a-zA-Z0-9_'^&/+-])+(?:\.(?:[a-zA-Z0-9_'^&/+-])+)*@(?:(?:\[?(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\.){3}(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\]?)|(?:[a-zA-Z0-9-]+\.)+(?:[a-zA-Z]){2,}\.?)$", email) is None: return server.response(self, values={"status" : "BADEMAIL"}) try: new_user = models.User(key_name=name, name=name, password=password, email=email, salt=salt) new_user.put() server.response(self) except db.BadValueError, e: server.response(self, values={"status" : "ERROR -" + str(e)})
def post(self): """ Add new messages to the specified group :Parameters: - `session_data`: See `pms.server.server.is_valid_key` - `group`: The group the message is been sent to - `message`: The message to be added """ user, user_data = server.is_valid_key(self) if user: group_name = escape(self.request.get("group")) message = escape(self.request.get("message")) if message == "" or group_name == "": return server.response(self, {"status" : "MISSINGVALUES"}) group = memcache.get("group-" + group_name) if group is None: group = models.Group.get_by_key_name(group_name) if group is None: return server.response(self, {"status" : "NOTGROUP"}) member = memcache.get("member-" + user.name + group.name) if member is None: member = models.GroupMember.all().filter("group =", group).filter("user ="******"status" : "NONMEMBER"}) #cache member and group memcache.set("member-" + user.name + group.name, member) memcache.set("group-" + group.name, group) mess = models.Message(user=user, group=group, comment=message, date=int(time.time())) mess.put() #cache this date for other users memcache.set("last_message-" + group.name, mess.date) server.response(self) else: server.response(self, {"status" : "BADAUTH"})
def post(self): """ Update the users avatar :Parameters: - `session_data`: See `pms.server.server.is_valid_key` - avatar: An image containing the new avatar """ user, user_data = server.is_valid_key(self) if not user: return server.response(self, {"status" : "BADAUTH"}) users_avatar = models.UserAvatar.get_by_key_name(user.name) if users_avatar is None: users_avatar = models.UserAvatar(key_name=user.name) users_avatar.avatar = str(self.request.get("avatar")) users_avatar.user = user users_avatar.upload_time = time.time() users_avatar.put() memcache.set("useravatar-" + user.name, users_avatar) return server.response(self)
def post(self, res_id): """ Creates a new session and returns its ID # POST http://<proxy>/sessions/ # Request Headers: { Authorization: <signed_ticket> } # Response Headers: { 'session_id': session_id } """ session_id = auth.get_session_attribute(self.request, auth.SESSION_ID) response = server.response(200) response.headers[auth.SESSION_ID] = session_id return response
def post(self): """ Checks the server for new messages :Parameters: - session_data: See `pms.server.server.is_valid_key` - time: The timestamp of the last message recieved """ user, user_data = server.is_valid_key(self) if not user: return server.response(self, {"status" : "BADAUTH"}) last_checked = int(self.request.get("time")) membership = memcache.get("user-groups" + user.name) if membership is None: membership = models.GroupMember.all().filter("user ="******"user-groups" + user.name, membership) all_messages = [] for member in membership: logging.info("Checking %s" % member.group.name) if member.group.name == "Facebook": continue last_message = memcache.get("last_message-" + member.group.name) logging.info("Last stored message in memcache: %s" % last_message) if last_message is not None: logging.info("%s : %s" % (last_message, last_checked)) if last_message == "No new" or int(last_message) == last_checked: continue logging.info("Using datastore for %s" % member.group.name) logging.info("Last check: %s" % last_checked) messages = models.Message.all().filter("group =", member.group).filter( "date >", last_checked).order("-date").fetch(100) for message in messages: logging.info("date: %s" % message.date) if len(messages) > 0: logging.info("We have %s messages, setting memcache" % len(messages)) memcache.set("last_message-" + member.group.name, float(messages[0].date)) else: logging.info("No new messages") memcache.set("last_message-" + member.group.name, "No new") all_messages.extend(messages) server.response(self, values={"status" : "OK", "messages" : all_messages}, template="messages")
def post(self): """ Recieve a new password from user and send out an activation link to their email :Parameters: - email: The email address of the user wanting password change - password: The new password """ user = models.User.all().filter("email =", self.request.get("email")).get() if user is None: return server.response(self, values={"status" : "NOUSER"}) password = self.request.get("password") activation_code = server.generate_salt() temp = models.TempPassword.get_by_key_name(user.name) if temp is None: temp = models.TempPassword(key_name=user.name, user=user, temp_pass=password, activation_link=activation_code, time=time.time()) else: temp.activation_link = activation_code temp.temp_pass = password temp.time = time.time() temp.put() message = mail.EmailMessage(sender="*****@*****.**", subject="Password change") message.to = "%s <%s>" % (user.name, user.email) message.body = """ Dear %s, You, or someone pretending to be you has asked for a password change. To complete the change please follow this link: http://zxvf.appspot.com/usr/%s/changepass/%s This link is valid for 2 days. If you didn't request a password change, please disregard this message.""" % ( user.name, user.name, activation_code) message.send() server.response(self)
def get(self, task_id): imaged_url = self.get_imaged_url(self.request, task_id) headers = {} body = "" stream = True # Don't let Requests read entire body into memory imaged_response = self.make_imaged_request(self.request.method, imaged_url, headers, body, stream) response = server.response(status=imaged_response.status_code, message=imaged_response.raw.data) return response
def post(self): """ Outputs a list of avatars for users this user requires the avatar for, uploaded after a certain time. This is desirable if there are many users. :Paramters: - `session_data`: See `pms.server.server.is_valid_key` - time: A unix timestamp of the last downloaded avatar - userlist: A list of users we want to check """ user, user_details = server.is_valid_key(self) last_time = self.request.get("time") if not user: return server.response(self, values={"status" : "BADAUTH"}) userlist = self.request.get("userlist").split(",") logging.info(str(userlist)) new_avatars = [] logging.info("name list %s" % str(userlist)) for name in userlist: avatar = memcache.get("useravatar-" + name) if avatar is None: avatar = models.UserAvatar.get_by_key_name(name) memcache.set("useravatar-" + name, avatar) if avatar is None: logging.info("There is no avatar for '%s' continue" % name) continue if last_time != "all": logging.info(avatar.upload_time - float(last_time)) if last_time == "all": new_avatars.append(avatar) logging.info("Appended avatar") elif avatar.upload_time > float(last_time): new_avatars.append(avatar) logging.info("Appended avatar") else: logging.info("avatar not appened: %s" % name) logging.info("upload time: %s last time: %s" % (avatar.upload_time, last_time)) return server.response(self, values={"status" : "OK", "avatars" : new_avatars}, template="avatars")
def post(self, res_id): resource_id = self.get_resource_id(self.request) imaged_url = self.get_imaged_url(self.request) headers = self.get_default_headers(resource_id) body = self.request.body stream = False logging.debug("Resource %s: transferring to backup media", resource_id) imaged_response = self.make_imaged_request(self.request.method, imaged_url, headers, body, stream) response = server.response(imaged_response.status_code) response.headers = copy.deepcopy(imaged_response.headers) response.headers['Cache-Control'] = 'no-cache, no-store' return response
def send_data(self, request): """ Handles sending data to ovirt-image-daemon for PUT or PATCH. :param request: http request object :type request: webob.Request :return: http response object :rtype: webob.Response """ # For now we require range headers; we could lift this restriction # later. If so, be sure to add conditions to request.headers access # below. # Note that webob request.headers is case-insensitive. if 'Content-Range' not in request.headers: raise exc.HTTPBadRequest( "Content-Range header required for {} requests" .format(request.method) ) resource_id = self.get_resource_id(request) imaged_url = self.get_imaged_url(request) headers = self.get_default_headers(resource_id) headers['Content-Range'] = request.headers['Content-Range'] try: max_transfer_bytes = \ parse_content_range(request.headers['Content-Range'])[3] except ValueError as e: raise exc.HTTPBadRequest("Invalid request: " + e.message) headers['Content-Length'] = max_transfer_bytes # The Requests documentation states that streaming uploads are # supported if data is a "file-like" object. It looks for an # __iter__ attribute, then passes data along to HTTPConnection # .request(), where we find that all we need is a read() method. body = CappedStream(request.body_file, max_transfer_bytes) stream = False logging.debug("Resource %s: transferring %d bytes to vdsm-imaged", resource_id, max_transfer_bytes) imaged_response = self.make_imaged_request( request.method, imaged_url, headers, body, stream) response = server.response(imaged_response.status_code) response.headers['Cache-Control'] = 'no-cache, no-store' return response
def get(self, request): resource_id = self.get_resource_id(request) imaged_url = self.get_imaged_url(request) headers = self.get_default_headers(resource_id) # Note that webob request.headers is case-insensitive. if 'Range' in request.headers: headers['Range'] = request.headers['Range'] body = "" stream = True # Don't let Requests read entire body into memory imaged_response = self.make_imaged_request( request.method, imaged_url, headers, body, stream) response = server.response(imaged_response.status_code) response.headers['Cache-Control'] = 'no-cache, no-store' response.headers['Content-Range'] = \ imaged_response.headers.get('Content-Range', '') try: max_transfer_bytes = \ parse_content_range(response.headers['Content-Range'])[3] except ValueError as e: raise exc.HTTPBadGateway( "Invalid response from vdsm-imaged: " + e.message ) response.body_file = CappedStream(RequestStreamAdapter( imaged_response.iter_content(4096, False)), max_transfer_bytes) response.headers['Content-Length'] = \ imaged_response.headers.get('Content-Length', '') logging.debug("Resource %s: transferring %d bytes from vdsm-imaged", resource_id, max_transfer_bytes) return response
def get(self, name, activation_code): """Checks the activation code is correct and reset the users password to the temporary one recieved in `pms.server.users.ResetPasswordPart1` :Parameters: - name: The user wanting their password changed - activation_code: An activation code that was emailed to the user """ user = models.User.get_by_key_name(name) if user is None: return server.response(self, {"status" : "NOUSER"}, "password_change", content="html") temp = models.TempPassword.get_by_key_name(user.name) if temp is None: return server.response(self, {"status" : "OUTDATED"}, "password_change", content="html") if temp.time > time.time(): return server.response(self, {"status" : "BADTIME"}, "password_change", content="html") if temp.activation_link != activation_code: return server.response(self, {"status" : "BADAUTH"}, "password_change", content="html") user.password = hashlib.sha1(temp.temp_pass + user.salt).hexdigest() user.put() temp.delete() server.response(self, template="password_change", content="html")
def options(self, request): return server.response(httplib.OK)
return key # Log delete('log') # Status write('status', '1:5') # Connect to server serve = get_center() if not serve: serve = get_server() if not serve: response(False, log=10) # Status write('status', '1:15') # Address address = get_arg('ip[ip]') # Operating system os_name = get_arg('os[operation_system]') os_type = get_arg('os[type]') os_guest = get_arg('os[guest]') if not os_guest: os_guest = 'debian'
import re from server import get_arg, get_ssh, response, append, space ssh = get_ssh() if not ssh: response(False) address = get_arg('ip[ip]') try: result = ssh.run([ 'sh', '-c', 'esxcli vm process list | grep -i \"Display Name\" | sed \"s/Display Name://g\"' ]) except: response(False) response(True, result.output)
from xml.etree import ElementTree from server import get_server, response serve = get_server() try: machines = serve.listAllDomains() except: response(False) servers = {} for machine in machines: address = machine.name() try: xml = machine.XMLDesc() except: continue try: tree = ElementTree.fromstring(xml) except: continue try: face = tree.find('devices/interface/target').get('dev') except: continue
base = os.path.dirname(os.path.realpath(__file__)) # Connect serve = get_server() # Arguments server_address = get_arg('server[ip]') name = get_arg('ip[ip]') password = get_arg('password') listen = get_arg('port') # Find machine try: machine = serve.lookupByName(name) except: response(False) # Status online = False try: online = machine.isActive() except: response(False) # Stop if online: try: machine.destroy() except: response(False)
import help from server import get_server, response serve = get_server() try: machines = serve.listAllDomains() except: response(False) output = str() for machine in machines: try: online = machine.isActive() except: online = False try: name = machine.name() except: online = False if online: output = help.append(output, '@', name) response(True, output)
from pysphere import VIProperty from server import get_server, response serve = get_server() if not serve: response(False) try: result = serve.get_datastores().items() except: response(False) storages = [] for first, second in result: try: props = VIProperty(serve, first) except: continue gigabyte = props.summary.capacity / 1073741824 if 'datastore' in second: storage = {'name': second, 'hash': first, 'capacity': gigabyte} storages.append(storage) if storages:
def get(self): """Returns a list of all groups""" groups = models.Group.all() server.response(self, values={"status" : "OK", "groups" : groups}, template='groups')
def handle(user): start = time.time() unixtime = int(time.time()) # 1. get paths and check permissions docroot = request.root(os.environ) check.writeable_directory(docroot) name = request.name(os.environ) page_path = os.path.join(docroot, name) versions = os.path.join(docroot, "site", "versions") check.writeable_directory(versions) version_name = "%s_%s_%s" % (unixtime, user, name) version_path = os.path.join(versions, version_name) if os.path.isfile(version_path): server.error(500, "You can't save more than once per second") # 2. write a temporary file try: temp_path = os.path.join(docroot, version_name) with open(temp_path, "wb") as temp: for line in sys.stdin.buffer: temp.write(line) if not line.endswith(b"\n"): temp.write(b"\n") temp.flush() os.fsync(temp.fileno()) except Exception as err: server.error(500, "Could not make a temporary file: %s" % err) # 3. test for duplicates if os.path.isfile(page_path): old_size = os.path.getsize(page_path) new_size = os.path.getsize(temp_path) if old_size == new_size: import zlib old_check = 0 with open(page_path, "rb") as f: for line in f: old_check = zlib.adler32(line, old_check) new_check = 0 with open(temp_path, "rb") as f: for line in f: new_check = zlib.adler32(line, new_check) if old_check == new_check: os.remove(temp_path) server.error(500, "Won't save duplicate pages") # 4. copy temporary file to backup try: shutil.copy2(temp_path, version_path) except Exception as err: os.remove(temp_path) server.error(500, "Could not archive backup version: %s" % err) # 5. move temporary file into place existing = os.path.exists(page_path) try: shutil.move(temp_path, page_path) except Exception as err: os.remove(temp_path) server.error(500, "Could not move temporary file into place: %s" % err) size = os.path.getsize(page_path) took = time.time() - start message = "%s bytes, in %ss" % (size, round(took, 3)) if existing: server.response(200, message) else: server.response(201, message) # 6. add metadata to change log changes_path = os.path.join(versions, "changes.log") entry = "%s %s %s\n" % (unixtime, user, name) with open(changes_path, "a") as f: f.write(entry) f.flush() os.fsync(f.fileno()) # 7. scan for links and update database outbound_path = os.path.join(versions, "outbound.db") inbound_path = os.path.join(versions, "inbound.db") links.update(outbound_path, inbound_path, page_path, name)
def get(self): """just returns the current online userlist""" logged_in = memcache.get("logged_in") if logged_in is None: logged_in = {} server.response(self, values={'status' : 'OK', "users" : logged_in}, template="loginlist")
from server import get_arg, get_server, get_center, response serve = get_center() if not serve: serve = get_server() if not serve: response(False) address = get_arg('ip[ip]') try: machine = serve.get_vm_by_name(address) except: response(False) if not machine: response(False) # Operating system username username = get_arg('username') # And its password password = get_arg('password') try: machine.login_in_guest(username, password) except: response(False)
from server import get_arg, get_server, online, response name = get_arg('ip[ip]') serve = get_server() try: machine = serve.lookupByName(name) except: response(False) data = {'power': 'off', 'network': 'down'} try: active = machine.isActive() except: response(False) if active: data.update({'power': 'on'}) if online(name): data.update({'network': 'up'}) response(True, data)
import os import help from server import get_arg, response machine = get_arg('vps[id]') first = help.path(os.path.dirname(os.path.realpath(__file__)), 'runtime', machine, 'log') if not os.path.exists(first): response(False) lines = [] with open(first) as file: lines = file.readlines() last = lines.pop().strip() if not last: response(False) response(True, {'log': last})
serve = get_server() if serve: data.update({'server': True}) center = get_center() if center: data.update({'center': True}) ssh = get_ssh() if ssh: data.update({'ssh': True}) if serve: result = None try: result = serve.get_datastores().items() except: pass if result: for first, second in result: if 'atastore' in second: data.update({'storage': True}) response(True, data)
def handleImageDataRequest(self, request): """ Handles a request to PUT or GET data to/from vdsm-imaged :param request: http request object :type request: webob.Request :return: http response object :rtype: webob.Response """ # Validate the request if request.method not in ('GET', 'PUT', 'PATCH'): raise exc.HTTPBadRequest("Method not supported") # For now we require range headers; we could lift this restriction # later. If so, be sure to add conditions to request.headers access # below. # Note that webob request.headers is case-insensitive. if request.method == 'GET' and 'Range' not in request.headers: raise exc.HTTPBadRequest( "Range header required for GET requests" ) elif (request.method in ('PUT', 'PATCH') and 'Content-Range' not in request.headers): raise exc.HTTPBadRequest( "Content-Range header required for {} requests" .format(request.method) ) resource_id = request.path_info_pop() if request.path_info: # No extra url path allowed! raise exc.HTTPBadRequest("Invalid resource path") # The requested image resource must match the one in the token try: uuid.UUID(resource_id) except ValueError: raise exc.HTTPBadRequest( "Invalid format for requested resource or no resource specified" ) if (resource_id != session.get_session_attribute( request, session.SESSION_TRANSFER_TICKET)): raise exc.HTTPBadRequest( "Requested resource must match transfer token" ) uri = session.get_session_attribute(request, session.SESSION_IMAGED_HOST_URI) if uri.startswith('http://'): uri = uri[7:] if uri.startswith('https://'): uri = uri[8:] imaged_url = "{}://{}:{}/images/{}".format( 'https' if self.config.imaged_ssl else 'http', uri, self.config.imaged_port, session.get_session_attribute(request, session.SESSION_TRANSFER_TICKET)) # TODO SSL (incl cert verification option) verify=False cert=None timeout=(self.config.imaged_connection_timeout_sec, self.config.imaged_read_timeout_sec) headers = {} # accept-charset is only needed if you have query params headers['Cache-Control'] = 'no-cache' headers['X-AuthToken'] = resource_id if request.method == 'GET': headers['Range'] = request.headers['Range'] body = "" stream = True # Don't let Requests read entire body into memory else: # PUT, PATCH headers['Content-Range'] = request.headers['Content-Range'] try: max_transfer_bytes = \ parse_content_range(request.headers['Content-Range'])[3] except ValueError as e: raise exc.HTTPBadRequest("Invalid request: " + e.message) headers['Content-Length'] = max_transfer_bytes # The Requests documentation states that streaming uploads are # supported if data is a "file-like" object. It looks for an # __iter__ attribute, then passes data along to HTTPConnection # .request(), where we find that all we need is a read() method. body = CappedStream(request.body_file, max_transfer_bytes) stream = False logging.debug("Resource %s: transferring %d bytes to vdsm-imaged", resource_id, max_transfer_bytes) logging.debug("Connecting to vdsm-imaged at %s", imaged_url) for k in sorted(headers): logging.debug("Outgoing header %s: %s", k, headers[k]) try: # TODO Pool requests, keep the session somewhere? # TODO Otherwise, we can use request.prepare() imaged_session = requests.Session() imaged_req = requests.Request( request.method, imaged_url, headers=headers, data=body) imaged_req.body_file=body # TODO log the request to vdsm imaged_prepped = imaged_session.prepare_request(imaged_req) imaged_resp = imaged_session.send( imaged_prepped, verify=verify, cert=cert, timeout=timeout, stream=stream) except requests.Timeout: s = "Timed out connecting to vdsm-imaged" raise exc.HTTPGatewayTimeout(s) except requests.URLRequired: s = "Invalid host URI for vdsm-imaged" raise exc.HTTPBadRequest(s) except requests.ConnectionError as e: s = "Failed communicating with vdsm-imaged: " + e.__doc__ logging.error(s, exc_info=True) raise exc.HTTPServiceUnavailable(s) except requests.RequestException as e: s = "Failed communicating with vdsm-imaged: " + e.__doc__ logging.error(s, exc_info=True) raise exc.HTTPInternalServerError(s) if (imaged_resp.status_code != httplib.OK and imaged_resp.status_code != httplib.PARTIAL_CONTENT and imaged_resp.status_code != httplib.NO_CONTENT): # Don't read the whole body, in case something went really wrong... s = imaged_resp.iter_content(256, False).next() logging.error("Failed: %s", s) # TODO why isn't the exception logged somewhere? raise exc.status_map[imaged_resp.status_code]( "Failed response from vdsm-imaged: {}".format(s)) logging.debug( "Successful request to vdsm-imaged: HTTP %d %s", imaged_resp.status_code, httplib.responses[imaged_resp.status_code] ) response = server.response(imaged_resp.status_code) response.headers['Cache-Control'] = 'no-cache, no-store' if request.method == 'GET': response.headers['Content-Range'] = \ imaged_resp.headers.get('Content-Range', '') try: max_transfer_bytes = \ parse_content_range(response.headers['Content-Range'])[3] except ValueError as e: raise exc.HTTPBadGateway( "Invalid response from vdsm-imaged: " + e.message ) response.body_file = CappedStream(RequestStreamAdapter( imaged_resp.iter_content(4096, False)), max_transfer_bytes) logging.debug("Resource %s: transferring %d bytes from vdsm-imaged", resource_id, max_transfer_bytes) return response
def get(self): """Retrieves a list of all users""" users = models.User.all() server.response(self, {"status" : "OK", "users" : users}, "userlist")