if not series: self.log.info('skipping dataset due to lack of series') continue d = interval_map[min(s.interval for s in series)] self.log.info('ds.name = %s' % (ds.name,)) if ds.name in ('load1', 'load5', 'load15', 'cpu_count'): d['load'][ds.name] = ds.encode() elif ds.name.startswith('cpu_'): _, suffix = ds.name.split('_', 1) if suffix in ('total', 'user', 'system', 'nice', 'iowait'): d['cpu'][suffix] = ds.encode() elif ds.name.startswith('mem_'): _, suffix = ds.name.split('_', 1) if suffix in ('total', 'buffers', 'cached', 'resident', 'used'): d['memory'][suffix] = ds.encode() for k, v in interval_map.iteritems(): if not dict(v): continue r = {'key': self.key, 'interval': int(k / 2.0), 'datasets': {}} for k, v in v.iteritems(): r['datasets'][k] = v result.append(r) s = simplejson.dumps(result, sort_keys=True, indent=2) self.response.headers['Content-Type'] = 'text/plain' self.response.out.write(s + '\n') add_route(CollectorTemplate, '/api/collector.json')
from lexigraph.view import add_route from lexigraph.handler import InteractiveHandler class Home(InteractiveHandler): def get(self): if self.request.path != '/': self.redirect('/') return self.env['use_ssl'] = False self.render_template('home.html') add_route(Home, '/')
# simple and fast code if only one dataset if len(self.datasets) == 1: dataset = self.datasets[0] self.response.out.write('Timestamp,%s\n' % (dataset.name,)) points = self.get_points_for_dataset(dataset) for p in points: self.response.out.write('%s,%s\n' % (p.timestamp.strftime('%s'), p.value)) else: header = ['Timestamp'] + [ds.name for ds in self.datasets] self.response.out.write(','.join(header) + '\n') points = [] for ds in self.datasets: points.append(self.get_points_for_dataset(ds)) times = defaultdict(dict) dataset_names = [ds.name for ds in self.datasets] for name, point_list in zip(dataset_names, points): for p in point_list: time = config.graph_resolution * (int(p.timestamp.strftime('%s')) / config.graph_resolution) times[time][name] = p.value for t in sorted(times.keys()): vals = times[t] self.log.info('vals = %s' % (vals,)) output = [t] for name in dataset_names: output.append(vals.get(name, '')) self.response.out.write(','.join(str(x) for x in output) + '\n') add_route(CSV, '/api/csv')
requires_login = True def post(self): name = self.form_required('name') value = self.form_required('value') if name not in Preference.pref_names: self.render_json({'status': 1, 'msg': 'no such preference'}) return UserPrefs.store_preference(self.user.user_id(), name, value) self.render_json({'status': 0}) class Prefs(InteractiveHandler): requires_login = True def get(self): my_prefs = self.load_prefs() defined_prefs = sorted(Preference.all_prefs, key=lambda x: x.display) all_prefs = [] for pref in defined_prefs: d = {'ref': pref, 'mine': my_prefs[pref.name]} all_prefs.append(d) self.env['message'] = 'sorry, can\'t alter these yet' self.env['all_prefs'] = all_prefs self.render_template('prefs.html') add_route(Prefs, '/prefs') add_route(UpdatePrefs, '/ajax/prefs')
import re from lexigraph.view import add_route from lexigraph.handler import SessionHandler class GraphQuery(SessionHandler): requires_login = True def initialize(self, request, response): super(GraphQuery, self).initialize(request, response) response.headers['Content-Type'] = 'application/json' def get(self): q = self.request.get('q') or '' tags = set(x.strip() for x in q.split(',') if x.strip()) datasets = TagQueryCache().select_by_tags(self.account, self.user, tags) self.render_json({'status': True, 'datasets': datasets}) add_route(GraphQuery, '/graph/query')
requires_login = True def check_allowed(self, datasets): count = 0 for ds in model.DataSet.all().filter('account =', self.account).filter('name IN', datasets): count += 1 if not ds.is_allowed(user=self.user, read=True, write=True): self.session['error_message'] = 'Insufficient privileges' self.redirect('/dashboard') if count < len(set(datasets)): self.session['error_message'] = 'Failed to find all specified datasets' self.redirect('/dashboard') def post(self): name = self.form_required('name') datasets = self.form_required('datasets') datasets = [x.strip() for x in datasets.split(',')] self.check_allowed(datasets) # TODO: validate tags tags = self.form_required('tags') tags = set(x.strip() for x in tags.split(',')) tags.add('composite') composite = model.CompositeDataSet.create(name=name, names=datasets, tags=list(tags), account=self.account) composite.put() self.redirect('/dashboard') add_route(NewCompositeDataSet, '/new/composite_dataset')
import datetime from lexigraph.view import add_route from lexigraph.handler import InteractiveHandler class ShowUnixtime(InteractiveHandler): def initialize(self, request, response): super(ShowUnixtime, self).initialize(request, response) response.headers['Content-Type'] = 'text/plain' def get(self): self.response.out.write(datetime.datetime.now().strftime('%s')) add_route(ShowUnixtime, '/debug/unixtime')
from lexigraph.view import add_route from lexigraph.handler import TagsMixin, InteractiveHandler from lexigraph import model from django.utils import simplejson import contextlib class Dashboard(TagsMixin, InteractiveHandler): requires_login = True def get(self): if self.account is None: self.log.info('No accounts set up for user, redirecting') self.redirect('/account') return self.load_prefs() self.env['groups'] = list(model.AccessGroup.groups_for_user(self.account)) self.env['dashboard_graphs'] = self.datasets_by_tags(['dashboard']) self.env['any_datasets'] = bool(model.DataSet.all().filter('account =', self.account).fetch(1)) self.render_template('dashboard.html') add_route(Dashboard, '/dashboard')
import datetime from lexigraph.view import add_route from lexigraph import model from lexigraph.handler import InteractiveHandler from lexigraph.view.cron import CronRequestHandler class FixAccounts(CronRequestHandler): """Add a display_name to accounts without one.""" def get(self): for account in model.Account.all(): if not getattr(account, 'display_name', None): account.display_name = account.name account.put() if not getattr(account, 'last_login', None): account.last_login = datetime.datetime(2000, 1, 1) account.put() add_route(FixAccounts, '/adhoc/fixaccounts')
def new_composite(name, datasets, tags=[]): dataset_ids = [ds.key().id() for ds in datasets] model.CompositeDataSet(name=name, datasets=dataset_ids, tags=tags, account=self.account, hostname=datasets[0].hostname).put() if populate == 'on': new_composite('load', [ new_dataset('load1', 'max', ['load']), new_dataset('load5', 'max', ['load']), new_dataset('load15', 'max', ['load']), new_dataset('cpu_count', 'new', ['load', 'cpu'])], ['dashboard', 'load']) new_composite('cpu', [ new_dataset('cpu_total', 'min', ['cpu']), new_dataset('cpu_user', 'max', ['cpu']), new_dataset('cpu_system', 'max', ['cpu']), new_dataset('cpu_nice', 'max', ['cpu']), new_dataset('cpu_iowait', 'max', ['cpu'])], ['dashboard', 'cpu']) new_composite('memory', [ new_dataset('mem_total', 'new', ['mem']), new_dataset('mem_buffers', 'new', ['mem']), new_dataset('mem_cached', 'new', ['mem']), new_dataset('mem_resident', 'new', ['mem']), new_dataset('mem_used', 'new', ['mem'])], ['dashboard', 'mem']) self.redirect('/dashboard') add_route(NewHost, '/new/host')
else: t = now ts.append(t) return ts @encode_json def post(self): """Add one or more DataPoints. To add multiple points from a single request, you simply repeat the dataset/value/timestamp form variables. """ datasets = self.request.get_all('dataset') values = self.request.get_all('value') timestamps = self.request.get_all('timestamp') assert datasets if not timestamps: timestamps = [0 for x in xrange(len(datasets))] assert len(datasets) == len(values) assert len(datasets) == len(timestamps) values = [float(v) for v in values] datasets = self.get_datasets(datasets) timestamps = self.get_timestamps(timestamps) for ds, v, t in zip(datasets, values, timestamps): ds.add_points(v, t) return self.add_status({}, StatusCodes.OK) add_route(CreatePoint, '/api/new/datapoint')
requires_login = True def post(self): # XXX: no security here! name = self.form_required('account') account = maybe_one(model.Account.all().filter('name =', name)) if account: model.ActiveAccount.set_active_account(self.user, account) self.redirect('/dashboard') else: self.session['error_message'] = 'invalid choice' self.redirect('/choose/account') class UpdateAccount(InteractiveHandler): requires_login = True def get(self): mail = self.user.email() if config.whitelisted_emails and mail not in config.whitelisted_emails: self.session['error_message'] = 'Sorry, your email (%s) hasn\'t been whitelisted. Ask Evan if you need access.' % (mail,) self.redirect('/') self.env['accounts'] = list(model.Account.all().filter('owner =', self.user)) self.env['support_address'] = lexigraph.mail.support_address self.render_template('account.html') add_route(NewAccount, '/new/account') add_route(ChooseAccount, '/choose/account') add_route(UpdateAccount, '/account')
from google.appengine.api.labs import taskqueue from lexigraph.view.cron._common import * from lexigraph.view import add_route from lexigraph import model class DataPointTrim(CronRequestHandler): def get(self): for s in model.DataSeries.all(): key = s.key() taskqueue.add(url='/tasks/trim_series', params={'series_key': key}) self.response.out.write('queued series_key = %r' % (key,)) add_route(DataPointTrim, '/cron/trim/datapoints')
from lexigraph.view import add_route from lexigraph.handler import SessionHandler, TagsMixin class RenderGraph(TagsMixin, SessionHandler): requires_login = True def get(self): tags = [x.strip() for x in self.request.get('tags').split(',')] self.env['names'] = names = self.datasets_by_tags(tags) self.render_ajax('ajax/graphs.html', extra={'names': names}) add_route(RenderGraph, '/ajax/graphs')
def post(self): dataset = self.get_dataset() assert dataset.is_allowed(self.user, delete=True) if self.env['is_composite']: dataset.delete() self.redirect('/dashboard') # XXX: this is racy (i.e. if someone creates points while we're deleting # the dataset). This ought to be amended by a cron job that looks for # abandoned points, or by implementing locking. # delete all of the data points for s in dataset.series(): while True: points = list(model.DataPoint.all().filter('series =', s)) if not points: break for p in points: p.delete() s.delete() for ac in model.AccessControl.all().filter('dataset =', dataset): ac.delete() dataset.delete() self.redirect('/dashboard') add_route(NewDataSet, '/new/dataset') add_route(EditDataSet, '/edit/dataset') add_route(DeleteDataSet, '/delete/dataset')
from lexigraph.view import add_route from lexigraph.handler import SessionHandler from google.appengine.api.users import create_logout_url class Logout(SessionHandler): def get(self): if self.user: self.session.clear_all() self.redirect(create_logout_url('/'), permanent=False) else: self.redirect('/', permanent=False) add_route(Logout, '/logout')