def brand(self, *rest): brand_id = conf['branding'].get('brand_id', 'default') # return doc if request.path.startswith('/brand/doc/'): tmpl = normpath( request.path.replace('/brand', conf.app.assets_root + '/' + brand_id)) if brand_id != 'default' and isfile(tmpl): f = open(tmpl) response.headers['Content-Type'] = 'text/html' response.app_iter = FileIter(f) return else: tmpl = request.path.replace('/brand', '') return render(tmpl, _gen_context_()) # return requested brand asset path = normpath( request.path.replace('/brand', conf.app.assets_root + '/' + brand_id)) if not isfile(path): path = request.path.replace('/brand', conf.app.assets_root + '/default/') if not isfile(path): abort(404) f = open(path) response.headers['Content-Type'] = guess_type(f.name) response.app_iter = FileIter(f)
def key(self): """ Serves the public SSH key for the user that own the current service """ # look for the ssh key of the current user public_key_path = os.path.expanduser('~/.ssh/id_rsa.pub') ssh_dir = os.path.dirname(public_key_path) if not os.path.isdir(ssh_dir): msg = '.ssh directory not found: %s' % ssh_dir logger.error(msg) error(500, msg) if not os.path.exists(public_key_path): msg = 'expected public key not found: %s' % public_key_path logger.error(msg) error(500, msg) # define the file to download response.headers[ 'Content-Disposition'] = 'attachment; filename=id_rsa.pub' with open(public_key_path) as key_contents: key = StringIO() key.write(key_contents.read()) key.seek(0) response.app_iter = FileIter(key)
def __call__(self, req): if req.method not in ('GET', 'HEAD'): return exc.HTTPMethodNotAllowed("You cannot %s a file" % req.method) disposition = req.GET.get('disposition', 'attachment') try: file = self.open() except (IOError, OSError) as e: msg = "You are not permitted to view this file (%s)" % e return exc.HTTPForbidden(msg) if 'wsgi.file_wrapper' in req.environ: app_iter = req.environ['wsgi.file_wrapper'](file, BLOCK_SIZE) else: app_iter = FileIter(file) return Response( app_iter=app_iter, content_length=self.get_size(), content_type=self.mimetype, content_encoding=self.encoding, content_disposition='%s; filename="%s"' % ( disposition, self.filename), # @@ etag ).conditional_response_app
def get(self, id): LOG.info("Fetch resource.", resource={'type': self.type, 'id': id}) download = strutils.bool_from_string( pecan.request.GET.get('download', False)) func_db = db_api.get_function(id) ctx = context.get_ctx() if not download: pecan.override_template('json') return resources.Function.from_dict(func_db.to_dict()).to_dict() else: source = func_db.code['source'] if source == 'package': f = self.storage_provider.retrieve(ctx.projectid, id) elif source == 'swift': container = func_db.code['swift']['container'] obj = func_db.code['swift']['object'] f = swift_util.download_object(container, obj) else: msg = 'Download image function is not allowed.' pecan.abort(status_code=405, detail=msg, headers={'Server-Error-Message': msg}) pecan.response.app_iter = (f if isinstance(f, collections.Iterable) else FileIter(f)) pecan.response.headers['Content-Type'] = 'application/zip' pecan.response.headers['Content-Disposition'] = ( 'attachment; filename="%s"' % os.path.basename(func_db.name))
def index(self, **kw): try: conf.build_map[self.name] except (AttributeError, KeyError): abort(404) script = make_setup_script(self.name, **kw) response.headers[ 'Content-Disposition'] = 'attachment; filename=setup.sh' response.app_iter = FileIter(script)
def ansible(self): """ Servers the pre-made ansible source to avoid installation of packages """ try: conf.setup_ansible except (AttributeError, KeyError): abort(404, 'setup_ansible value is not configured') response.headers[ 'Content-Disposition'] = 'attachment; filename=ansible.tar.gz' f = open(conf.setup_ansible, 'rb') response.app_iter = FileIter(f)
def vendor_passthru(ident, method, topic, data=None, driver_passthru=False): """Call a vendor passthru API extension. Call the vendor passthru API extension and process the method response to set the right return code for methods that are asynchronous or synchronous; Attach the return value to the response object if it's being served statically. :param ident: The resource identification. For node's vendor passthru this is the node's UUID, for driver's vendor passthru this is the driver's name. :param method: The vendor method name. :param topic: The RPC topic. :param data: The data passed to the vendor method. Defaults to None. :param driver_passthru: Boolean value. Whether this is a node or driver vendor passthru. Defaults to False. :returns: A WSME response object to be returned by the API. """ if not method: raise wsme.exc.ClientSideError(_("Method not specified")) if data is None: data = {} http_method = pecan.request.method.upper() params = (pecan.request.context, ident, method, http_method, data, topic) if driver_passthru: response = pecan.request.rpcapi.driver_vendor_passthru(*params) else: response = pecan.request.rpcapi.vendor_passthru(*params) status_code = 202 if response['async'] else 200 return_value = response['return'] response_params = {'status_code': status_code} # Attach the return value to the response object if response.get('attach'): if isinstance(return_value, six.text_type): # If unicode, convert to bytes return_value = return_value.encode('utf-8') file_ = wsme.types.File(content=return_value) pecan.response.app_iter = FileIter(file_.file) # Since we've attached the return value to the response # object the response body should now be empty. return_value = None response_params['return_type'] = None return wsme.api.Response(return_value, **response_params)
def index(self): """ Special method for internal redirect URI's so that webservers (like Nginx) can serve downloads to clients while the app just delegates. This method will require an Nginx configuration that points to resources and match `binary_root` URIs:: location /home/ubuntu/repos/ { internal; alias /files/; } `alias` can be anything, it would probably make sense to have a set of rules that allow distinct URIs, like:: location /home/ubuntu/repos/rpm-firefly/ { internal; alias /files/rpm-firefly/; } There are two ways to get binaries into this app: via existing files in certain paths POSTing JSON to the arch/ endpoint, or via actual upload of the binary. So if many locations need to be supported, they each need to have a corresponding section in Nginx to be configured. """ if not self.binary: abort(404) # we need to slap some headers so Nginx can serve this # TODO: maybe disable this for testing? # XXX Maybe we don't need to set Content-Disposition here? response.headers[ 'Content-Disposition'] = 'attachment; filename=%s' % str( self.binary.name) if conf.delegate_downloads is False: f = open(self.binary.path, 'rb') response.app_iter = FileIter(f) else: relative_path = self.binary.path.split( pecan.conf.binary_root)[-1].strip('/') # FIXME: this should be read from configuration, this is not configurable # at the moment and relies on the nginx config being properly set path = os.path.join('/b/', relative_path) logger.info('setting path header: %s', path) response.headers['X-Accel-Redirect'] = path
def save_file(self, file_obj): dir_path = self.create_directory() if self.binary_name in os.listdir(dir_path): # resource exists so we will update it response.status = 200 else: # we will create a resource response.status = 201 destination = os.path.join(dir_path, self.binary_name) with open(destination, 'wb') as f: file_iterable = FileIter(file_obj) for chunk in file_iterable: f.write(chunk) # return the full path to the saved object: return destination
def get(self, id): """Get function information or download function package. This method can support HTTP request using either 'Accept:application/json' or no 'Accept' header. """ ctx = context.get_ctx() acl.enforce('function:get', ctx) download = strutils.bool_from_string( pecan.request.GET.get('download', False) ) func_db = db_api.get_function(id) if not download: LOG.info("Getting function %s.", id) pecan.override_template('json') return resources.Function.from_db_obj(func_db).to_dict() LOG.info("Downloading function %s", id) source = func_db.code['source'] if source == constants.PACKAGE_FUNCTION: f = self.storage_provider.retrieve(func_db.project_id, id, func_db.code['md5sum']) elif source == constants.SWIFT_FUNCTION: container = func_db.code['swift']['container'] obj = func_db.code['swift']['object'] f = swift_util.download_object(container, obj) else: msg = 'Download image function is not allowed.' pecan.abort( status_code=405, detail=msg, headers={'Server-Error-Message': msg} ) pecan.response.app_iter = (f if isinstance(f, collections.Iterable) else FileIter(f)) pecan.response.headers['Content-Type'] = 'application/zip' pecan.response.headers['Content-Disposition'] = ( 'attachment; filename="%s"' % id )
def key(self): """ Serves the public SSH key for the user that own the current service """ # look for the ssh key of the current user private_key_path = os.path.expanduser('~/.ssh/id_rsa') public_key_path = os.path.expanduser('~/.ssh/id_rsa.pub') ssh_dir = os.path.dirname(public_key_path) if not os.path.isdir(ssh_dir): logger.warning('.ssh directory not found, creating one at: %s', ssh_dir) mkdir(ssh_dir) # if there isn't one create it if not os.path.exists(public_key_path): logger.warning('expected public key not found: %s', public_key_path) logger.warning('will create new ssh key pair') # create one command = [ 'ssh-keygen', '-q', '-t', 'rsa', '-N', '', '-f', private_key_path, ] out, err, code = process.run(command, send_input='y\n') if code != 0: error(500, err) # define the file to download response.headers[ 'Content-Disposition'] = 'attachment; filename=id_rsa.pub' with open(public_key_path) as key_contents: key = StringIO() key.write(key_contents.read()) key.seek(0) response.app_iter = FileIter(key)
def get(self, id): LOG.info("Fetch function [id=%s]", id) download = strutils.bool_from_string( pecan.request.GET.get('download', False)) func_db = db_api.get_function(id) ctx = context.get_ctx() if not download: pecan.override_template('json') return resources.Function.from_dict(func_db.to_dict()).to_dict() else: f = self.storage_provider.retrieve( ctx.projectid, id, ) pecan.response.app_iter = FileIter(f) pecan.response.headers['Content-Type'] = 'application/zip' pecan.response.headers['Content-Disposition'] = ( 'attachment; filename="%s"' % os.path.basename(f.name))
def save_file(self, file_obj): # TODO: we should just use self.binary.path for this dir_path = self.create_directory() if self.binary_name in os.listdir(dir_path): # resource exists so we will update it response.status = 200 else: # TODO: enforce this. # we will create a resource, but this SHOULD NOT HAPPEN # because we are PUT not POST response.status = 201 destination = os.path.join(dir_path, self.binary_name) with open(destination, 'wb') as f: file_iterable = FileIter(file_obj) for chunk in file_iterable: f.write(chunk) # return the full path to the saved object: return destination
def index(self, **kw): try: conf.build_map[self.name] except (AttributeError, KeyError): abort(404) playbook = conf.build_map[self.name]['playbook'] playbook_path = conf.build_map[self.name]['playbook_path'] files_to_compress = [] tmp_dir = tempfile.mkdtemp() yml_file = os.path.join(tmp_dir, 'main.yml') copyfile(playbook, yml_file) files_to_compress.append(playbook_path) files_to_compress.append(yml_file) playbook = tar_czf(files_to_compress) response.headers[ 'Content-Disposition'] = 'attachment; filename=playbook.tar.gz' f = open(playbook, 'rb') response.app_iter = FileIter(f)
def __call__(self, req): # Adapted from `FileApp.__call__()`. if 'wsgi.file_wrapper' in req.environ: app_iter = req.environ['wsgi.file_wrapper'](self.file, BLOCK_SIZE) else: app_iter = FileIter(self.file) last_modified = datetime.datetime.now() # Need to seek to end of cStringIO.StringIO buffer to get size. self.file.seek(0, os.SEEK_END) content_length = self.file.tell() # Remember to seek back to the beginning before the buffer is sent! self.file.seek(0) content_type, content_encoding = mimetypes.guess_type(self.filename) content_disposition = "attachment; filename=%s" % self.filename accept_ranges = 'bytes' return Response(app_iter=app_iter, last_modified=last_modified, content_length=content_length, content_type=content_type, content_encoding=content_encoding, content_disposition=content_disposition, accept_ranges=accept_ranges, conditional_response=True)
def get(self, function_id, version): """Get function version or download function version package. This method can support HTTP request using either 'Accept:application/json' or no 'Accept' header. """ ctx = context.get_ctx() acl.enforce('function_version:get', ctx) download = strutils.bool_from_string( pecan.request.GET.get('download', False) ) version = int(version) version_db = db_api.get_function_version(function_id, version) if not download: LOG.info("Getting version %s for function %s.", version, function_id) pecan.override_template('json') return resources.FunctionVersion.from_db_obj(version_db).to_dict() LOG.info("Downloading version %s for function %s.", version, function_id) f = self.storage_provider.retrieve(version_db.project_id, function_id, None, version=version) if isinstance(f, collections.Iterable): pecan.response.app_iter = f else: pecan.response.app_iter = FileIter(f) pecan.response.headers['Content-Type'] = 'application/zip' pecan.response.headers['Content-Disposition'] = ( 'attachment; filename="%s_%s"' % (function_id, version) )
def _default(self, view, *remainder): body = media.get_file(request.path[12:]) mime_type = guess_type(request.path[12:])[0] r = Response(content_type=mime_type) r.app_iter = FileIter(body) return r
def agent(self): script = make_agent_script(request.url, request.client_addr) response.headers[ 'Content-Disposition'] = 'attachment; filename=agent-setup.sh' response.app_iter = FileIter(script)
def index(self): script = make_setup_script(request.url) response.headers[ 'Content-Disposition'] = 'attachment; filename=setup.sh' response.app_iter = FileIter(script)