def get_props(): impls = mount(method='GET', document='implementation', context=guid, stability='stable', order_by='-version', limit=1, reply=['guid'])['result'] enforce(impls, ad.NotFound, 'No implementations') impl_id = impls[0]['guid'] props = mount(method='GET', document='context', guid=guid, reply=['title', 'description']) props['preview'] = mount(method='GET', document='context', guid=guid, prop='preview') data_response = ad.Response() props['data'] = mount(data_response, method='GET', document='implementation', guid=impl_id, prop='data') props['mime_type'] = data_response.content_type or \ 'application/octet' props['activity_id'] = impl_id return props
def __getitem__(self, name): directory = self.get(name) if directory is None: enforce(name in self._to_open, env.BadRequest, 'Unknown %r document', name) directory = self[name] = self._open(name, self._to_open.pop(name)) return directory
def __init__(self, cls): """ :param cls: class inherited from `active_document.Document` """ self._name = cls.__name__.lower() slots = {} prefixes = {} for attr in [getattr(cls, i) for i in dir(cls)]: if not hasattr(attr, '_is_active_property'): continue prop = attr.prop if hasattr(prop, 'slot'): enforce(prop.slot is None or prop.slot not in slots, 'Property %r has a slot already defined for %r in %r', prop.name, slots.get(prop.slot), self.name) slots[prop.slot] = prop.name if hasattr(prop, 'prefix'): enforce(not prop.prefix or prop.prefix not in prefixes, 'Property %r has a prefix already defined for %r', prop.name, prefixes.get(prop.prefix)) prefixes[prop.prefix] = prop.name if prop.setter is not None: setattr(cls, attr.name, property(attr, prop.setter)) else: setattr(cls, attr.name, property(attr)) self[prop.name] = prop
def _post(self, request, access): enforce(isinstance(request.content, dict), 'Invalid value') directory = self.volume[request['document']] if 'guid' in request: doc = directory.get(request['guid']) else: doc = directory.document_class(None, {}) doc.request = request blobs = [] for name, value in request.content.items(): prop = directory.metadata[name] if isinstance(prop, BlobProperty) and access == env.ACCESS_WRITE: if doc.meta(name) is None: prop.assert_access(env.ACCESS_CREATE) else: prop.assert_access(env.ACCESS_WRITE) else: prop.assert_access(access) if prop.on_set is not None: value = prop.on_set(doc, value) if isinstance(prop, BlobProperty): enforce(PropertyMeta.is_blob(value), 'Invalid BLOB value') blobs.append((name, value)) else: if prop.localized and isinstance(value, basestring): value = {request.accept_language[0]: value} try: doc.props[name] = prop.decode(value) except Exception, error: error = 'Value %r for %r property is invalid: %s' % \ (value, prop.name, error) util.exception(error) raise RuntimeError(error)
def to_int(value): if isinstance(value, basestring): if not value: return 0 enforce(value.isdigit(), 'Argument should be an integer value') return int(value) return value
def _exclude(self, range_start, range_end): if range_start is None: range_start = 1 enforce(range_end is not None) enforce(range_start <= range_end and range_start > 0, 'Start value %r is less than 0 or not less than %r', range_start, range_end) for i, interval in enumerate(self): start, end = interval if end is not None and end < range_start: # Current `interval` is below than new one continue if end is None or end > range_end: # Current `interval` will exist after changing self[i] = [range_end + 1, end] if start < range_start: self.insert(i, [start, range_start - 1]) else: if start < range_start: self[i] = [start, range_start - 1] else: del self[i] if end is not None: range_start = end + 1 if range_start < range_end: self.exclude(range_start, range_end) break
def __init__(self, spec=None, root=None): self.path = None self.commands = {} self.bindings = set() self.requires = {} self.build_requires = [] self.source_requires = [] self.archives = [] self.applications = [] self.activity = None self.library = None self._fields = {} self._noarch = True self._config = ConfigParser() if hasattr(spec, 'readline'): self._config.readfp(spec) else: if spec is not None: enforce(exists(spec), 'Recipe file %s does not exist', spec) self.path = spec elif root is not None: # TODO Handle sweets.recipe specs self.path = join(root, 'activity', 'activity.info') self._config.read(self.path) self._read()
def journal_update(self, guid, data=None, **kwargs): enforce(self._ds is not None, 'Journal is inaccessible') preview = kwargs.get('preview') if preview: if hasattr(preview, 'read'): preview = preview.read() if hasattr(preview, 'close'): preview.close() elif isinstance(preview, dict): with file(preview['path'], 'rb') as f: preview = f.read() import dbus kwargs['preview'] = dbus.ByteArray(preview) if hasattr(data, 'read'): with NamedTemporaryFile(delete=False) as f: while True: chunk = data.read(BUFFER_SIZE) if not chunk: break f.write(chunk) data = f.name transfer_ownership = True elif isinstance(data, dict): data = data['path'] transfer_ownership = False elif data is not None: with NamedTemporaryFile(delete=False) as f: f.write(data) data = f.name transfer_ownership = True self._ds.update(guid, kwargs, data or '', transfer_ownership)
def launch(self, mountpoint, document, guid, args, activity_id=None, object_id=None, uri=None, color=None, no_spawn=None): enforce(document == 'context', 'Only contexts can be launched') def do_launch(): for event in injector.launch(mountpoint, guid, args, activity_id=activity_id, object_id=object_id, uri=uri, color=color): event['event'] = 'launch' self.publish(event) if no_spawn: do_launch() else: self._jobs.spawn(do_launch)
def upload_blob(self, document, guid, prop, path, pass_ownership=False): directory = self.volume[document] directory.metadata[prop].assert_access(ad.ACCESS_WRITE) enforce(isabs(path), 'Path is not absolute') try: directory.set_blob(guid, prop, path) finally: if pass_ownership and exists(path): os.unlink(path)
def _stats_upload(self, request): enforce(request.principal == self['guid'], ad.Forbidden, 'Operation is permitted only for authors') name = request.content['name'] values = request.content['values'] rrd = stats.get_rrd(self.guid) for timestamp, values in values: rrd[name].put(values, timestamp)
def _new_command(self, section, requires, name): cmdline = self._get(section, 'exec') enforce(cmdline, 'Option "exec" should exist for [%s] section', section) command = self.commands[name] = _Command(name, cmdline) if ':' in section: command.requires.update(requires) else: self.requires.update(requires)
def upload_blob(self, prop, content, content_type): enforce(self._guid, 'Object needs to be posted first') Client.call('PUT', mountpoint=self.mountpoint, document=self.document, guid=self._guid, prop=prop, content=content, content_type=content_type)
def __init__(self, root=None, stream=None, limit=None, compress_mode=None, seqno=None, filename=None, **kwargs): if compress_mode is None: compress_mode = _PACKET_COMPRESS_MODE self._stream = None self._file = None self._path = None self._tarball = None self.header = kwargs self._size_to_flush = 0 self._file_num = 0 self._empty = True if filename: self._basename = filename else: if 'src' in kwargs: self._basename = kwargs['src'] if seqno is not None: self._basename += '-%s' % seqno else: self._basename = ad.uuid() self._basename += _PACKET_SUFFIX kwargs['filename'] = self._basename if root is not None: if not exists(root): os.makedirs(root) self._path = util.unique_filename(root, self._basename) self._file = stream = file(self._path, 'wb+') elif hasattr(stream, 'fileno'): self._file = stream self._path = stream.name else: limit = limit or _MAX_PACKET_SIZE self._limit = limit enforce(stream is not None) self._tarball = tarfile.open(mode='w:' + compress_mode, fileobj=stream) self._stream = stream if compress_mode == 'gz': self.content_type = 'application/x-compressed-tar' elif compress_mode == 'bz2': self.content_type = 'application/x-bzip-compressed-tar' else: self.content_type = 'application/x-tar' _logger.trace('Writing %r output packet', self)
def route(method, path): path = path.strip('/').split('/') # Only top level paths for now enforce(len(path) == 1) def decorate(func): func.route = (method, path[0]) return func return decorate
def upload_blob(self, document, guid, prop, path, pass_ownership=False): enforce(isabs(path), 'Path is not absolute') try: with file(path, 'rb') as f: self._client.request('PUT', [document, guid, prop], files={'file': f}) finally: if pass_ownership and exists(path): os.unlink(path)
def pubkey(): pubkey_path = privkey_path() + '.pub' enforce(exists(pubkey_path), 'Sugar session was never started, no privkey') with file(pubkey_path) as f: for line in f.readlines(): line = line.strip() if line.startswith('ssh-'): return line raise RuntimeError('Valid SSH public key was not found in %s' % pubkey_path)
def journal(self, request, response): enforce(self._ds is not None, 'Journal is inaccessible') enforce(len(request.path) <= 3, 'Invalid request') if len(request.path) == 1: return self._find(request, response) elif len(request.path) == 2: return self._get(request, response) elif len(request.path) == 3: return self._get_prop(request, response)
def get(self, prop): if prop == 'guid': return self._guid result = self._props.get(prop) if result is None: enforce(prop in self._reply, 'Access to not requested %r property in %r from %r mount', prop, self.document, self.mountpoint) self.fetch() result = self._props.get(prop) return result
def decorate_getter(func): enforce(func.__name__ != 'guid', "Active property should not have 'guid' name") attr = lambda self: getter(func, self) attr.setter = lambda func: decorate_setter(func, attr) attr._is_active_property = True attr.name = func.__name__ attr.prop = (property_class or ActiveProperty)(attr.name, *args, **kwargs) attr.prop.on_get = func return attr
def create(self, request): with self._post(request, env.ACCESS_CREATE) as (directory, doc): enforce('guid' not in doc.props, env.Forbidden, "Property 'guid' cannot be set manually") self.before_create(request, doc.props) for prop in directory.metadata.values(): if prop.on_set is not None and \ not prop.permissions & env.ACCESS_CREATE: doc[prop.name] = prop.on_set(doc, prop.default) doc.guid = directory.create(doc.props) return doc.guid
def request(self, method, path=None, data=None, headers=None, allowed=None, params=None, **kwargs): if not path: path = [''] if not isinstance(path, basestring): path = '/'.join([i.strip('/') for i in [self.api_url] + path]) if params is None: params = self.params else: params.update(self.params) while True: try: response = requests.request(method, path, data=data, headers=headers, session=self._session, params=params, **kwargs) except requests.exceptions.SSLError: _logger.warning('Use --no-check-certificate to avoid checks') raise if response.status_code != 200: if response.status_code == 401: enforce(self._sugar_auth, 'Operation is not available in anonymous mode') _logger.info('User is not registered on the server, ' 'registering') self._register() continue if allowed and response.status_code in allowed: return response content = response.content try: error = json.loads(content) except Exception: _logger.debug('Got %s HTTP error for %r request:\n%s', response.status_code, path, content) response.raise_for_status() else: raise RuntimeError(error['error']) return response
def _new_archive(self, section): arch = self._get(section, 'arch') or 'all' enforce(arch in _ARCHES, 'Unknown arch %s in [%s], it should be %r', arch, section, _ARCHES) self._noarch = self._noarch and (arch == 'all') if self._get(section, 'lang'): assert False, 'Not yet implemented' """ for lang in get_list('langs', section): result.add(SubPackage(section, lang)) """ else: self.archives.append(_Archive(self._config, section))
def __getitem__(self, key): """Get object by key. :param key: `key` value might be an `int` value (offset within the cursor), or a string to treat it as GUID :returns: `Object` value or raise `KeyError` exception if key is not found """ result = self.get(key) enforce(result is not None, KeyError, 'Key is out of range') return result
def __getitem__(self, key): section = None if isinstance(key, tuple): if len(key) == 2: section, key = key else: enforce(len(key) == 1) key = key[0] if not section: if key in _FIELDS: return self._fields.get(key) section = 'DEFAULT' return self._config.get(section, key)
def assert_access(self, mode): """Is access to the property permitted. If there are no permissions, function should raise `active_document.Forbidden` exception. :param mode: one of `active_document.ACCESS_*` constants to specify the access mode """ enforce(mode & self.permissions, env.Forbidden, '%s access is disabled for %r property', env.ACCESS_NAMES[mode], self.name)
def journal_share(self, request, response): enforce(self._ds is not None, 'Journal is inaccessible') enforce( len(request.path) == 2 and request.get('cmd') == 'share', 'Invalid request') guid = request.path[1] preview_path = _prop_path(guid, 'preview') enforce(os.access(preview_path, os.R_OK), 'No preview') data_path = _ds_path(guid, 'data') enforce(os.access(data_path, os.R_OK), 'No data') subrequest = Request(method='POST', document='artifact') subrequest.content = request.content subrequest.content_type = 'application/json' # pylint: disable-msg=E1101 subguid = self.call(subrequest, response) subrequest = Request(method='PUT', document='artifact', guid=subguid, prop='preview') subrequest.content_type = 'image/png' with file(preview_path, 'rb') as subrequest.content_stream: self.call(subrequest, response) subrequest = Request(method='PUT', document='artifact', guid=subguid, prop='data') subrequest.content_type = get(guid, 'mime_type') or 'application/octet' with file(data_path, 'rb') as subrequest.content_stream: self.call(subrequest, response)
def __init__(self, name, slot=None, prefix=None, full_text=False, boolean=False, **kwargs): enforce(name == 'guid' or slot != 0, "For %r property, slot '0' is reserved for internal needs", name) enforce(name == 'guid' or prefix != env.GUID_PREFIX, 'For %r property, prefix %r is reserved for internal needs', name, env.GUID_PREFIX) enforce( slot is not None or prefix or full_text, 'For %r property, either slot, prefix or full_text ' 'need to be set', name) enforce( slot is None or _is_sloted_prop(kwargs.get('typecast')), 'Slot can be set only for properties for str, int, float, ' 'bool types, or, for list of these types') StoredProperty.__init__(self, name, **kwargs) self._slot = slot self._prefix = prefix self._full_text = full_text self._boolean = boolean
def stats(self, start, end, resolution, source): if not source: return {} enforce(self._stats is not None, 'Node stats is disabled') enforce(start < end, "Argument 'start' should be less than 'end'") enforce(resolution > 0, "Argument 'resolution' should be more than 0") min_resolution = (end - start) / _MAX_STATS_LENGTH if resolution < min_resolution: _logger.debug('Resulution is too short, use %s instead', min_resolution) resolution = min_resolution dbs = {} for i in source: enforce('.' in i, 'Misnamed source name') db_name, ds_name = i.split('.', 1) dbs.setdefault(db_name, []).append(ds_name) result = {} for db in self._stats.rrd: if db.name not in dbs: continue stats = result[db.name] = [] for ts, ds_values in db.get(start, end, resolution): values = {} for name in dbs[db.name]: values[name] = ds_values.get(name) stats.append((ts, values)) return result
def _stats_info(self, request): enforce(request.principal == self['guid'], ad.Forbidden, 'Operation is permitted only for authors') status = {} for db in stats.get_rrd(self.guid): status[db.name] = db.last + stats.stats_user_step.value # TODO Process client configuration in more general manner return { 'enable': True, 'step': stats.stats_user_step.value, 'rras': ['RRA:AVERAGE:0.5:1:4320', 'RRA:AVERAGE:0.5:5:2016'], 'status': status, }