def _get(log_id, start=0, limit=None, order=None): """Get log file. """ instance, uniq, logtype, component = log_id.split('/') with lc.LogContext(_LOGGER, '{}/{}'.format(instance, uniq)): log_f = self._get_logfile(instance, uniq, logtype, component) _LOGGER.info('Requested {} items starting from line {} ' 'in {} order'.format(limit, start, order)) if start is not None and start < 0: raise exc.InvalidInputError( __name__, 'Index cannot be less than 0, got: {}'.format( start)) with io.open(log_f, 'rt', errors='ignore') as log: if order == 'desc': return _fragment_in_reverse(log, start, limit) return _fragment(log, start, limit)
def _fragment_in_reverse(iterable, start=0, limit=None): """ Selects a fragment of the iterable and returns the items in reverse order. The lowest index is 0 and designates the last line of the file. 'Limit' specifies the number of lines to return. """ # TODO: Naive implementation. Needs to be rewritten to a solution with # file pointer moving around etc. if it turns out that this isn't # performant enough. maxlen = None if limit is not None and limit >= 0: maxlen = start + limit fragment = collections.deque(iterable, maxlen) try: for _ in six.moves.range(start): fragment.pop() except IndexError: raise exc.InvalidInputError( __name__, 'Index start=%s is out of range.' % str(start)) fragment.reverse() return fragment
def test_post_instance(self): """Test creating an instance.""" self.impl.create.return_value = ['proid.app#0000000001'] rsrc = { 'services': [{ 'command': '/bin/sleep 60', 'name': 'sleep', 'restart': { 'interval': 60, 'limit': 0 } }], 'cpu': '10%', 'memory': '100M', 'disk': '100M' } resp = self.client.post('/instance/proid.app', data=json.dumps(rsrc), content_type='application/json') resp_json = b''.join(resp.response) self.assertEqual(json.loads(resp_json.decode()), {'instances': ['proid.app#0000000001']}) self.assertEqual(resp.status_code, http_client.OK) self.impl.create.assert_called_once_with('proid.app', rsrc, 1, None, False, None) self.impl.reset_mock() with user_set(self.app, '*****@*****.**'): resp = self.client.post('/instance/proid.app?count=2', data=json.dumps(rsrc), content_type='application/json') self.assertEqual(resp.status_code, http_client.OK) self.impl.create.assert_called_once_with('proid.app', rsrc, 2, '*****@*****.**', False, None) self.impl.reset_mock() resp = self.client.post('/instance/proid.app?count=1&debug=true', data=json.dumps(rsrc), content_type='application/json') self.assertEqual(resp.status_code, http_client.OK) self.impl.create.assert_called_once_with('proid.app', rsrc, 1, None, True, None) self.impl.reset_mock() resp = self.client.post( '/instance/proid.app?count=1&debug_services=test', data=json.dumps(rsrc), content_type='application/json') self.assertEqual(resp.status_code, http_client.OK) self.impl.create.assert_called_once_with('proid.app', rsrc, 1, None, False, ['test']) self.impl.create.side_effect = exc.InvalidInputError('foo', 'bar') resp = self.client.post('/instance/[email protected]', data=json.dumps(rsrc), content_type='application/json') self.assertEqual(resp.status_code, http_client.BAD_REQUEST)
def create(rsrc_id, rsrc, count=1, created_by=None, debug=False, debug_services=None): """Create (configure) instance.""" _LOGGER.info('create: count = %s, %s %r, created_by = %s', count, rsrc_id, rsrc, created_by) # Check scheduled quota. zkclient = context.GLOBAL.zk.conn scheduled_stats = masterapi.get_scheduled_stats(zkclient) if not scheduled_stats: scheduled_stats = {} total_apps = sum(scheduled_stats.values()) if total_apps + count > _TOTAL_SCHEDULED_QUOTA: raise exc.QuotaExceededError( 'Total scheduled apps quota exceeded.') proid_apps = scheduled_stats.get(rsrc_id[:rsrc_id.find('.')], 0) if proid_apps + count > _PROID_SCHEDULED_QUOTA: raise exc.QuotaExceededError( 'Proid scheduled apps quota exceeded.') admin_app = context.GLOBAL.admin.application() if not rsrc: configured = admin_app.get(rsrc_id) else: # Make sure defaults are present configured = admin_app.from_entry(admin_app.to_entry(rsrc)) app.verify_feature(rsrc.get('features', [])) if 'services' in configured and not configured['services']: del configured['services'] if '_id' in configured: del configured['_id'] _LOGGER.info('Configured: %s %r', rsrc_id, configured) _validate(configured) for plugin in self._plugins: configured = plugin.add_attributes(rsrc_id, configured) _check_required_attributes(configured) _set_defaults(configured, rsrc_id) services = { service['name']: service for service in configured.get('services', []) } if not debug_services: debug_services = list(services) if debug else [] for service in debug_services: if service in services: services[service]['downed'] = True _LOGGER.info('Configuring service %s as down', service) else: raise exc.InvalidInputError( __name__, 'Invalid service %s' % service ) scheduled = masterapi.create_apps( zkclient, rsrc_id, configured, count, created_by ) return scheduled
def norm_safe(path): """Returns normalized path, aborts if path is not absolute.""" if not os.path.isabs(path): raise exc.InvalidInputError(path, 'Not absolute path: %r' % path) return os.path.normpath(path)