def fetch(request): if request.GET.get('from') is not None: time_from = parseATTime(request.GET['from']) else: time_from = epoch_to_dt(0) if request.GET.get('until') is not None: time_until = parseATTime(request.GET['until']) else: time_until = now() set_operation = request.GET.get('set') tags = request.GET.get('tags') if tags is not None: tags = request.GET.get('tags').split(' ') result = [] for x in Event.find_events(time_from, time_until, tags=tags, set_operation=set_operation): # django-tagging's with_intersection() returns matches with unknown tags # this is a workaround to ensure we only return positive matches if set_operation == 'intersection': if len(set(tags) & set(x.as_dict()['tags'])) == len(tags): result.append(x.as_dict()) else: result.append(x.as_dict()) return result
def fetch(request): #XXX we need to move to USE_TZ=True to get rid of naive-time conversions def make_naive(dt): tz = timezone(request.GET.get('tz', settings.TIME_ZONE)) local_dt = dt.astimezone(tz) if hasattr(local_dt, 'normalize'): local_dt = local_dt.normalize() return local_dt.replace(tzinfo=None) if request.GET.get("from", None) is not None: time_from = make_naive(parseATTime(request.GET["from"])) else: time_from = datetime.datetime.fromtimestamp(0) if request.GET.get("until", None) is not None: time_until = make_naive(parseATTime(request.GET["until"])) else: time_until = datetime.datetime.now() tags = request.GET.get("tags", None) if tags is not None: tags = request.GET.get("tags").split(" ") return [x.as_dict() for x in models.Event.find_events(time_from, time_until, tags=tags)]
def _get_latest_graphite(metric): """ Get the latest value of a named graphite metric """ tzinfo = pytz.timezone("UTC") until_time = parseATTime('now', tzinfo) def _get(from_time): series = fetchData({ 'startTime': from_time, 'endTime': until_time, 'now': until_time, 'localOnly': False}, metric ) try: return [k for k in series[0] if k is not None][-1] except IndexError: return None # In case the cluster has been offline for some time, try looking progressively # further back in time for data. This would not be necessary if graphite simply # let us ask for the latest value (Calamari issue #6876) for trange in ['-1min', '-10min', '-60min', '-1d', '-7d']: val = _get(parseATTime(trange, tzinfo)) if val is not None: return val log.warn("No graphite data for %s" % metric)
def parseOptions(request): queryParams = request.REQUEST # Start with some defaults graphOptions = {'width' : 330, 'height' : 250} requestOptions = {} graphType = queryParams.get('graphType','line') assert graphType in GraphTypes, "Invalid graphType '%s', must be one of %s" % (graphType,GraphTypes.keys()) graphClass = GraphTypes[graphType] # Fill in the requestOptions requestOptions['graphType'] = graphType requestOptions['graphClass'] = graphClass requestOptions['targets'] = [] for target in queryParams.getlist('target'): if target.lower().startswith('graphite.'): #Strip leading "Graphite." as a convenience target = target[9:] requestOptions['targets'].append(target) if 'pickle' in queryParams: requestOptions['pickle'] = True if 'rawData' in queryParams: requestOptions['rawData'] = True if 'noCache' in queryParams: requestOptions['noCache'] = True # Fill in the graphOptions for opt in graphClass.customizable: if opt in queryParams: val = queryParams[opt] if (val.isdigit() or (val.startswith('-') and val[1:].isdigit())) and opt not in ('fgcolor','bgcolor','fontColor'): val = int(val) elif '.' in val and (val.replace('.','',1).isdigit() or (val.startswith('-') and val[1:].replace('.','',1).isdigit())): val = float(val) elif val.lower() in ('true','false'): val = eval( val.lower().capitalize() ) elif val.lower() == 'default' or val == '': continue graphOptions[opt] = val # Get the time interval for time-oriented graph types if graphType == 'line': if 'until' in queryParams: endTime = parseATTime( queryParams['until'] ) else: endTime = datetime.now() if 'from' in queryParams: startTime = parseATTime( queryParams['from'] ) else: startTime = endTime - timedelta(days=1) if endTime > datetime.now(): endTime = datetime.now() assert startTime < endTime, "Invalid time range!" requestOptions['startTime'] = startTime requestOptions['endTime'] = endTime return (graphOptions, requestOptions)
def fetch(request): if request.GET.get("from", None) is not None: time_from = parseATTime(request.GET["from"]) else: time_from = datetime.datetime.fromtimestamp(0) if request.GET.get("until", None) is not None: time_until = parseATTime(request.GET["until"]) else: time_until = datetime.datetime.now() tags = request.GET.get("tags", None) if tags is not None: tags = request.GET.get("tags").split(" ") return [x.as_dict() for x in models.Event.find_events(time_from, time_until, tags=tags)]
def fetch(request): #XXX we need to move to USE_TZ=True to get rid of localtime() conversions if request.GET.get("from", None) is not None: time_from = localtime(parseATTime(request.GET["from"])).replace(tzinfo=None) else: time_from = datetime.datetime.fromtimestamp(0) if request.GET.get("until", None) is not None: time_until = localtime(parseATTime(request.GET["until"])).replace(tzinfo=None) else: time_until = now() tags = request.GET.get("tags", None) if tags is not None: tags = request.GET.get("tags").split(" ") return [x.as_dict() for x in models.Event.find_events(time_from, time_until, tags=tags)]
def evaluateTokens(tokens, timeInterval, originalTime = None): if tokens.expression: if tokens[0][0][0] == "timeShift": delta = timeInterval[0] - parseATTime(tokens[0][0][1][1]['string'].strip('"')) delta += timeInterval[1] - timeInterval[0] originalTime = timeInterval timeInterval = (timeInterval[0] - delta, timeInterval[1] - delta) return evaluateTokens(tokens.expression, timeInterval, originalTime) elif tokens.pathExpression: pathExpr = tokens.pathExpression if pathExpr.lower().startswith('graphite.'): pathExpr = pathExpr[9:] seriesList = [] (startTime,endTime) = originalTime or timeInterval for dbFile in settings.STORE.find(pathExpr): log.metric_access(dbFile.metric_path) getCacheResults = CarbonLink.sendRequest(dbFile.real_metric) dbResults = dbFile.fetch( timestamp(startTime), timestamp(endTime) ) results = mergeResults(dbResults, getCacheResults()) if not results: continue (timeInfo,values) = results (start,end,step) = timeInfo series = TimeSeries(dbFile.metric_path, start, end, step, values) series.pathExpression = pathExpr #hack to pass expressions through to render functions series.start = time.mktime(startTime.timetuple()) series.end = time.mktime(endTime.timetuple()) seriesList.append(series) return seriesList elif tokens.call: func = SeriesFunctions[tokens.call.func] args = [evaluateTokens(arg, timeInterval, originalTime) for arg in tokens.call.args] return func(*args) elif tokens.number: if tokens.number.integer: return int(tokens.number.integer) elif tokens.number.float: return float(tokens.number.float) elif tokens.string: return str(tokens.string)[1:-1]
def test_should_return_current_time(self): expected_time = self.default_tz.localize(datetime.strptime("12:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("now") self.assertEqual(actual_time, expected_time)
def test_offset_with_tz(self): expected_time = self.specified_tz.localize(datetime.strptime("1:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight+1h", self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_parse_zone_aware_datetime(self): time_ref = parseATTime(self.specified_tz.localize(datetime(self.MOCK_DATE.year, self.MOCK_DATE.month, self.MOCK_DATE.day, 8, 50)), self.specified_tz, now=self.now) expected = self.specified_tz.localize(datetime(self.MOCK_DATE.year, self.MOCK_DATE.month, self.MOCK_DATE.day, 8, 50)) self.assertEquals(time_ref, expected)
def parseOptions(request): queryParams = request.REQUEST # Start with some defaults graphOptions = {'width' : 330, 'height' : 250} requestOptions = {} graphType = queryParams.get('graphType','line') assert graphType in GraphTypes, "Invalid graphType '%s', must be one of %s" % (graphType,GraphTypes.keys()) graphClass = GraphTypes[graphType] # Fill in the requestOptions requestOptions['graphType'] = graphType requestOptions['graphClass'] = graphClass requestOptions['pieMode'] = queryParams.get('pieMode', 'average') requestOptions['cacheTimeout'] = int( queryParams.get('cacheTimeout', settings.DEFAULT_CACHE_DURATION) ) requestOptions['targets'] = [] for target in queryParams.getlist('target'): requestOptions['targets'].append(target) if 'pickle' in queryParams: requestOptions['pickle'] = True if 'rawData' in queryParams: requestOptions['format'] = 'raw' if 'format' in queryParams: requestOptions['format'] = queryParams['format'] if 'jsonp' in queryParams: requestOptions['jsonp'] = queryParams['jsonp'] if 'noCache' in queryParams: requestOptions['noCache'] = True requestOptions['localOnly'] = queryParams.get('local') == '1' # Fill in the graphOptions for opt in graphClass.customizable: if opt in queryParams: val = queryParams[opt] if (val.isdigit() or (val.startswith('-') and val[1:].isdigit())) and opt not in ('fgcolor','bgcolor','fontColor'): val = int(val) elif '.' in val and (val.replace('.','',1).isdigit() or (val.startswith('-') and val[1:].replace('.','',1).isdigit())): val = float(val) elif val.lower() in ('true','false'): val = val.lower() == 'true' elif val.lower() == 'default' or val == '': continue graphOptions[opt] = val # Get the time interval for time-oriented graph types if graphType == 'line' or graphType == 'pie': if 'until' in queryParams: untilTime = parseATTime( queryParams['until'] ) else: untilTime = parseATTime('now') if 'from' in queryParams: fromTime = parseATTime( queryParams['from'] ) else: fromTime = parseATTime('-1d') startTime = min(fromTime, untilTime) endTime = max(fromTime, untilTime) assert startTime != endTime, "Invalid empty time range" requestOptions['startTime'] = startTime requestOptions['endTime'] = endTime return (graphOptions, requestOptions)
def parseOptions(request): queryParams = request.REQUEST # Start with some defaults graphOptions = {'width': 330, 'height': 250} requestOptions = {} graphType = queryParams.get('graphType', 'line') assert graphType in GraphTypes, "Invalid graphType '%s', must be one of %s" % ( graphType, GraphTypes.keys()) graphClass = GraphTypes[graphType] # Fill in the requestOptions requestOptions['graphType'] = graphType requestOptions['graphClass'] = graphClass requestOptions['pieMode'] = queryParams.get('pieMode', 'average') requestOptions['cacheTimeout'] = int( queryParams.get('cacheTimeout', settings.DEFAULT_CACHE_DURATION)) requestOptions['targets'] = [] # Extract the targets out of the queryParams mytargets = [] # Normal format: ?target=path.1&target=path.2 if len(queryParams.getlist('target')) > 0: mytargets = queryParams.getlist('target') # Rails/PHP/jQuery common practice format: ?target[]=path.1&target[]=path.2 elif len(queryParams.getlist('target[]')) > 0: mytargets = queryParams.getlist('target[]') # Collect the targets for target in mytargets: requestOptions['targets'].append(target) if 'pickle' in queryParams: requestOptions['format'] = 'pickle' if 'rawData' in queryParams: requestOptions['format'] = 'raw' if 'format' in queryParams: requestOptions['format'] = queryParams['format'] if 'jsonp' in queryParams: requestOptions['jsonp'] = queryParams['jsonp'] if 'noCache' in queryParams: requestOptions['noCache'] = True if 'maxDataPoints' in queryParams and queryParams['maxDataPoints'].isdigit( ): requestOptions['maxDataPoints'] = int(queryParams['maxDataPoints']) requestOptions['localOnly'] = queryParams.get('local') == '1' # Fill in the graphOptions for opt in graphClass.customizable: if opt in queryParams: val = queryParams[opt] if (val.isdigit() or (val.startswith('-') and val[1:].isdigit())) and 'color' not in opt.lower(): val = int(val) elif '.' in val and (val.replace('.', '', 1).isdigit() or (val.startswith('-') and val[1:].replace('.', '', 1).isdigit())): val = float(val) elif val.lower() in ('true', 'false'): val = val.lower() == 'true' elif val.lower() == 'default' or val == '': continue graphOptions[opt] = val tzinfo = pytz.timezone(settings.TIME_ZONE) if 'tz' in queryParams: try: tzinfo = pytz.timezone(queryParams['tz']) except pytz.UnknownTimeZoneError: pass requestOptions['tzinfo'] = tzinfo # Get the time interval for time-oriented graph types if graphType == 'line' or graphType == 'pie': if 'until' in queryParams: untilTime = parseATTime(queryParams['until'], tzinfo) else: untilTime = parseATTime('now', tzinfo) if 'from' in queryParams: fromTime = parseATTime(queryParams['from'], tzinfo) else: fromTime = parseATTime('-1d', tzinfo) startTime = min(fromTime, untilTime) endTime = max(fromTime, untilTime) assert startTime != endTime, "Invalid empty time range" requestOptions['startTime'] = startTime requestOptions['endTime'] = endTime return (graphOptions, requestOptions)
def test_relative_time_in_alternate_zone(self): expected_time = self.specified_tz.localize( datetime.strptime("11:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("-1h", self.specified_tz) self.assertEqual(actual_time.hour, expected_time.hour)
def parseOptions(request): queryParams = request.REQUEST # Start with some defaults graphOptions = {'width' : 330, 'height' : 250} requestOptions = {} graphType = queryParams.get('graphType','line') assert graphType in GraphTypes, "Invalid graphType '%s', must be one of %s" % (graphType,GraphTypes.keys()) graphClass = GraphTypes[graphType] # Fill in the requestOptions requestOptions['graphType'] = graphType requestOptions['graphClass'] = graphClass requestOptions['pieMode'] = queryParams.get('pieMode', 'average') requestOptions['cacheTimeout'] = int( queryParams.get('cacheTimeout', settings.DEFAULT_CACHE_DURATION) ) requestOptions['targets'] = [] # Extract the targets out of the queryParams mytargets = [] # Normal format: ?target=path.1&target=path.2 if len(queryParams.getlist('target')) > 0: mytargets = queryParams.getlist('target') # Rails/PHP/jQuery common practice format: ?target[]=path.1&target[]=path.2 elif len(queryParams.getlist('target[]')) > 0: mytargets = queryParams.getlist('target[]') # Collect the targets for target in mytargets: requestOptions['targets'].append(target) template = dict() for key, val in queryParams.items(): if key.startswith("template["): template[key[9:-1]] = val requestOptions['template'] = template if 'pickle' in queryParams: requestOptions['format'] = 'pickle' if 'rawData' in queryParams: requestOptions['format'] = 'raw' if 'format' in queryParams: requestOptions['format'] = queryParams['format'] if 'jsonp' in queryParams: requestOptions['jsonp'] = queryParams['jsonp'] if 'noCache' in queryParams: requestOptions['noCache'] = True if 'maxDataPoints' in queryParams and queryParams['maxDataPoints'].isdigit(): requestOptions['maxDataPoints'] = int(queryParams['maxDataPoints']) requestOptions['localOnly'] = queryParams.get('local') == '1' # Fill in the graphOptions for opt in graphClass.customizable: if opt in queryParams: val = queryParams[opt] if (val.isdigit() or (val.startswith('-') and val[1:].isdigit())) and 'color' not in opt.lower(): val = int(val) elif '.' in val and (val.replace('.','',1).isdigit() or (val.startswith('-') and val[1:].replace('.','',1).isdigit())): val = float(val) elif val.lower() in ('true','false'): val = val.lower() == 'true' elif val.lower() == 'default' or val == '': continue graphOptions[opt] = val tzinfo = pytz.timezone(settings.TIME_ZONE) if 'tz' in queryParams: try: tzinfo = pytz.timezone(queryParams['tz']) except pytz.UnknownTimeZoneError: pass requestOptions['tzinfo'] = tzinfo # Get the time interval for time-oriented graph types if graphType == 'line' or graphType == 'pie': if 'until' in queryParams: untilTime = parseATTime(queryParams['until'], tzinfo) else: untilTime = parseATTime('now', tzinfo) if 'from' in queryParams: fromTime = parseATTime(queryParams['from'], tzinfo) else: fromTime = parseATTime('-1d', tzinfo) startTime = min(fromTime, untilTime) endTime = max(fromTime, untilTime) assert startTime != endTime, "Invalid empty time range" requestOptions['startTime'] = startTime requestOptions['endTime'] = endTime timeRange = endTime - startTime queryTime = timeRange.days * 86400 + timeRange.seconds # convert the time delta to seconds if settings.DEFAULT_CACHE_POLICY and not queryParams.get('cacheTimeout'): requestOptions['cacheTimeout'] = max(timeout for period,timeout in settings.DEFAULT_CACHE_POLICY if period <= queryTime) return (graphOptions, requestOptions)
def test_should_return_absolute_time_short(self): time_string = '9:0020150308' expected_time = self.default_tz.localize( datetime.strptime(time_string, '%H:%M%Y%m%d')) actual_time = parseATTime(time_string, now=self.now) self.assertEqual(actual_time, expected_time)
def test_midnight(self): expected_time = self.default_tz.localize(datetime.strptime("0:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight", self.specified_tz) self.assertEqual(actual_time, expected_time.astimezone(self.specified_tz))
def find_view(request): "View for finding metrics matching a given pattern" queryParams = request.GET.copy() queryParams.update(request.POST) format = queryParams.get('format', 'treejson') local_only = int(queryParams.get('local', 0)) wildcards = int(queryParams.get('wildcards', 0)) tzinfo = pytz.timezone(settings.TIME_ZONE) if 'tz' in queryParams: try: tzinfo = pytz.timezone(queryParams['tz']) except pytz.UnknownTimeZoneError: pass if 'now' in queryParams: now = parseATTime(queryParams['now'], tzinfo) else: now = datetime.now(tzinfo) if 'from' in queryParams and str(queryParams['from']) != '-1': fromTime = int(epoch(parseATTime(queryParams['from'], tzinfo, now))) else: fromTime = -1 if 'until' in queryParams and str(queryParams['from']) != '-1': untilTime = int(epoch(parseATTime(queryParams['until'], tzinfo, now))) else: untilTime = -1 nodePosition = int(queryParams.get('position', -1)) jsonp = queryParams.get('jsonp', False) forward_headers = extractForwardHeaders(request) if fromTime == -1: fromTime = None if untilTime == -1: untilTime = None automatic_variants = int(queryParams.get('automatic_variants', 0)) try: query = str(queryParams['query']) except: return HttpResponseBadRequest( content="Missing required parameter 'query'", content_type='text/plain') if '.' in query: base_path = query.rsplit('.', 1)[0] + '.' else: base_path = '' if format == 'completer': query = query.replace('..', '*.') if not query.endswith('*'): query += '*' if automatic_variants: query_parts = query.split('.') for i, part in enumerate(query_parts): if ',' in part and '{' not in part: query_parts[i] = '{%s}' % part query = '.'.join(query_parts) try: matches = list( STORE.find(query, fromTime, untilTime, local=local_only, headers=forward_headers)) except: log.exception() raise log.info('find_view query=%s local_only=%s matches=%d' % (query, local_only, len(matches))) matches.sort(key=lambda node: node.name) log.info( "received remote find request: pattern=%s from=%s until=%s local_only=%s format=%s matches=%d" % (query, fromTime, untilTime, local_only, format, len(matches))) if format == 'treejson': profile = getProfile(request) content = tree_json(matches, base_path, wildcards=profile.advancedUI or wildcards) response = json_response_for(request, content, jsonp=jsonp) elif format == 'nodelist': content = nodes_by_position(matches, nodePosition) response = json_response_for(request, content, jsonp=jsonp) elif format == 'pickle': content = pickle_nodes(matches) response = HttpResponse(content, content_type='application/pickle') elif format == 'msgpack': content = msgpack_nodes(matches) response = HttpResponse(content, content_type='application/x-msgpack') elif format == 'json': content = json_nodes(matches) response = json_response_for(request, content, jsonp=jsonp) elif format == 'completer': results = [] for node in matches: node_info = dict(path=node.path, name=node.name, is_leaf=str(int(node.is_leaf))) if not node.is_leaf: node_info['path'] += '.' results.append(node_info) if len(results) > 1 and wildcards: wildcardNode = {'name': '*'} results.append(wildcardNode) response = json_response_for(request, {'metrics': results}, jsonp=jsonp) else: return HttpResponseBadRequest( content="Invalid value for 'format' parameter", content_type='text/plain') response['Pragma'] = 'no-cache' response['Cache-Control'] = 'no-cache' return response
def find_view(request): "View for finding metrics matching a given pattern" queryParams = request.GET.copy() queryParams.update(request.POST) format = queryParams.get('format', 'treejson') leaves_only = int( queryParams.get('leavesOnly', 0) ) local_only = int( queryParams.get('local', 0) ) wildcards = int( queryParams.get('wildcards', 0) ) tzinfo = pytz.timezone(settings.TIME_ZONE) if 'tz' in queryParams: try: tzinfo = pytz.timezone(queryParams['tz']) except pytz.UnknownTimeZoneError: pass if 'now' in queryParams: now = parseATTime(queryParams['now'], tzinfo) else: now = datetime.now(tzinfo) if 'from' in queryParams and str(queryParams['from']) != '-1': fromTime = int(epoch(parseATTime(queryParams['from'], tzinfo, now))) else: fromTime = -1 if 'until' in queryParams and str(queryParams['from']) != '-1': untilTime = int(epoch(parseATTime(queryParams['until'], tzinfo, now))) else: untilTime = -1 nodePosition = int( queryParams.get('position', -1) ) jsonp = queryParams.get('jsonp', False) forward_headers = extractForwardHeaders(request) if fromTime == -1: fromTime = None if untilTime == -1: untilTime = None automatic_variants = int( queryParams.get('automatic_variants', 0) ) try: query = str(queryParams['query']) except KeyError: return HttpResponseBadRequest(content="Missing required parameter 'query'", content_type='text/plain') if query == '': return HttpResponseBadRequest(content="Required parameter 'query' is empty", content_type='text/plain') if '.' in query: base_path = query.rsplit('.', 1)[0] + '.' else: base_path = '' if format == 'completer': query = query.replace('..', '*.') if not query.endswith('*'): query += '*' if automatic_variants: query_parts = query.split('.') for i,part in enumerate(query_parts): if ',' in part and '{' not in part: query_parts[i] = '{%s}' % part query = '.'.join(query_parts) try: matches = list(STORE.find( query, fromTime, untilTime, local=local_only, headers=forward_headers, leaves_only=leaves_only, )) except Exception: log.exception() raise log.info('find_view query=%s local_only=%s matches=%d' % (query, local_only, len(matches))) matches.sort(key=lambda node: node.name) log.info("received remote find request: pattern=%s from=%s until=%s local_only=%s format=%s matches=%d" % (query, fromTime, untilTime, local_only, format, len(matches))) if format == 'treejson': profile = getProfile(request) content = tree_json(matches, base_path, wildcards=profile.advancedUI or wildcards) response = json_response_for(request, content, jsonp=jsonp) elif format == 'nodelist': content = nodes_by_position(matches, nodePosition) response = json_response_for(request, content, jsonp=jsonp) elif format == 'pickle': content = pickle_nodes(matches) response = HttpResponse(content, content_type='application/pickle') elif format == 'msgpack': content = msgpack_nodes(matches) response = HttpResponse(content, content_type='application/x-msgpack') elif format == 'json': content = json_nodes(matches) response = json_response_for(request, content, jsonp=jsonp) elif format == 'completer': results = [] for node in matches: node_info = dict(path=node.path, name=node.name, is_leaf=str(int(node.is_leaf))) if not node.is_leaf: node_info['path'] += '.' results.append(node_info) if len(results) > 1 and wildcards: wildcardNode = {'name' : '*'} results.append(wildcardNode) response = json_response_for(request, { 'metrics' : results }, jsonp=jsonp) else: return HttpResponseBadRequest( content="Invalid value for 'format' parameter", content_type='text/plain') response['Pragma'] = 'no-cache' response['Cache-Control'] = 'no-cache' return response
def parseOptions(request): queryParams = request.GET.copy() queryParams.update(request.POST) # Start with some defaults graphOptions = {'width': 330, 'height': 250} requestOptions = {} graphType = queryParams.get('graphType', 'line') if graphType not in GraphTypes: raise AssertionError("Invalid graphType '%s', must be one of %s" % (graphType, list(GraphTypes))) graphClass = GraphTypes[graphType] # Fill in the requestOptions requestOptions['graphType'] = graphType requestOptions['graphClass'] = graphClass requestOptions['pieMode'] = queryParams.get('pieMode', 'average') cacheTimeout = int( queryParams.get('cacheTimeout', settings.DEFAULT_CACHE_DURATION)) requestOptions['targets'] = [] requestOptions['forwardHeaders'] = extractForwardHeaders(request) # Extract the targets out of the queryParams mytargets = [] # Normal format: ?target=path.1&target=path.2 if len(queryParams.getlist('target')) > 0: mytargets = queryParams.getlist('target') # Rails/PHP/jQuery common practice format: ?target[]=path.1&target[]=path.2 elif len(queryParams.getlist('target[]')) > 0: mytargets = queryParams.getlist('target[]') # Collect the targets for target in mytargets: requestOptions['targets'].append(target) template = dict() for key, val in queryParams.items(): if key.startswith("template["): template[key[9:-1]] = val requestOptions['template'] = template if 'pickle' in queryParams: requestOptions['format'] = 'pickle' if 'rawData' in queryParams: requestOptions['format'] = 'raw' if 'format' in queryParams: requestOptions['format'] = queryParams['format'] if 'jsonp' in queryParams: requestOptions['jsonp'] = queryParams['jsonp'] requestOptions['pretty'] = bool(queryParams.get('pretty')) if 'noCache' in queryParams: requestOptions['noCache'] = True if 'maxDataPoints' in queryParams and queryParams['maxDataPoints'].isdigit( ): requestOptions['maxDataPoints'] = int(queryParams['maxDataPoints']) if 'noNullPoints' in queryParams: requestOptions['noNullPoints'] = True requestOptions['localOnly'] = queryParams.get('local') == '1' # Fill in the graphOptions format = requestOptions.get('format') if format == 'svg': graphOptions['outputFormat'] = 'svg' elif format == 'pdf': graphOptions['outputFormat'] = 'pdf' else: graphOptions['outputFormat'] = 'png' for opt in graphClass.customizable: if opt in queryParams: val = queryParams[opt] if (val.isdigit() or (val.startswith('-') and val[1:].isdigit())) and 'color' not in opt.lower(): val = int(val) elif '.' in val and (val.replace('.', '', 1).isdigit() or (val.startswith('-') and val[1:].replace('.', '', 1).isdigit())): val = float(val) elif val.lower() in ('true', 'false'): val = val.lower() == 'true' elif val.lower() == 'default' or val == '': continue graphOptions[opt] = val tzinfo = pytz.timezone(settings.TIME_ZONE) if 'tz' in queryParams: try: tzinfo = pytz.timezone(queryParams['tz']) except pytz.UnknownTimeZoneError: pass requestOptions['tzinfo'] = tzinfo # Get the time interval for time-oriented graph types if graphType == 'line' or graphType == 'pie': if 'now' in queryParams: now = parseATTime(queryParams['now'], tzinfo) else: now = datetime.now(tzinfo) if 'until' in queryParams: untilTime = parseATTime(queryParams['until'], tzinfo, now) else: untilTime = now if 'from' in queryParams: fromTime = parseATTime(queryParams['from'], tzinfo, now) else: fromTime = parseATTime('-1d', tzinfo, now) startTime = min(fromTime, untilTime) endTime = max(fromTime, untilTime) assert startTime != endTime, "Invalid empty time range" requestOptions['startTime'] = startTime requestOptions['endTime'] = endTime timeRange = endTime - startTime queryTime = timeRange.days * 86400 + timeRange.seconds # convert the time delta to seconds if settings.DEFAULT_CACHE_POLICY and not queryParams.get( 'cacheTimeout'): timeouts = [ timeout for period, timeout in settings.DEFAULT_CACHE_POLICY if period <= queryTime ] cacheTimeout = max(timeouts or (0, )) requestOptions['now'] = now if cacheTimeout == 0: requestOptions['noCache'] = True requestOptions['cacheTimeout'] = cacheTimeout requestOptions['xFilesFactor'] = float( queryParams.get('xFilesFactor', settings.DEFAULT_XFILES_FACTOR)) return (graphOptions, requestOptions)
def parseOptions(request): queryParams = request.REQUEST # Start with some defaults graphOptions = {'width' : 330, 'height' : 250} requestOptions = {} graphType = queryParams.get('graphType','line') assert graphType in GraphTypes, "Invalid graphType '%s', must be one of %s" % (graphType,GraphTypes.keys()) graphClass = GraphTypes[graphType] # Fill in the requestOptions requestOptions['graphType'] = graphType requestOptions['graphClass'] = graphClass requestOptions['pieMode'] = queryParams.get('pieMode', 'average') requestOptions['cacheTimeout'] = int( queryParams.get('cacheTimeout', settings.DEFAULT_CACHE_DURATION) ) requestOptions['targets'] = [] for target in queryParams.getlist('target'): requestOptions['targets'].append(target) if 'pickle' in queryParams: requestOptions['format'] = 'pickle' if 'rawData' in queryParams: requestOptions['format'] = 'raw' if 'format' in queryParams: requestOptions['format'] = queryParams['format'] if 'jsonp' in queryParams: requestOptions['jsonp'] = queryParams['jsonp'] if 'noCache' in queryParams: requestOptions['noCache'] = True requestOptions['localOnly'] = queryParams.get('local') == '1' # Fill in the graphOptions for opt in graphClass.customizable: if opt in queryParams: val = queryParams[opt] if (val.isdigit() or (val.startswith('-') and val[1:].isdigit())) and opt not in ('fgcolor','bgcolor','fontColor'): val = int(val) elif '.' in val and (val.replace('.','',1).isdigit() or (val.startswith('-') and val[1:].replace('.','',1).isdigit())): val = float(val) elif val.lower() in ('true','false'): val = val.lower() == 'true' elif val.lower() == 'default' or val == '': continue graphOptions[opt] = val # Get the time interval for time-oriented graph types if graphType == 'line' or graphType == 'pie': if 'until' in queryParams: untilTime = parseATTime( queryParams['until'] ) else: untilTime = parseATTime('now') if 'from' in queryParams: fromTime = parseATTime( queryParams['from'] ) else: fromTime = parseATTime('-1d') startTime = min(fromTime, untilTime) endTime = max(fromTime, untilTime) assert startTime != endTime, "Invalid empty time range" requestOptions['startTime'] = startTime requestOptions['endTime'] = endTime return (graphOptions, requestOptions)
def test_relative_time_in_alternate_zone(self): expected_time = self.specified_tz.localize(datetime.strptime("11:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("-1h", self.specified_tz) self.assertEqual(actual_time.hour, expected_time.hour)
def parseOptions(request): queryParams = request.GET.copy() queryParams.update(request.POST) # Start with some defaults graphOptions = {"width": 330, "height": 250} requestOptions = {} graphType = queryParams.get("graphType", "line") assert graphType in GraphTypes, "Invalid graphType '%s', must be one of %s" % (graphType, GraphTypes.keys()) graphClass = GraphTypes[graphType] # Fill in the requestOptions requestOptions["graphType"] = graphType requestOptions["graphClass"] = graphClass requestOptions["pieMode"] = queryParams.get("pieMode", "average") requestOptions["cacheTimeout"] = int(queryParams.get("cacheTimeout", settings.DEFAULT_CACHE_DURATION)) requestOptions["targets"] = [] # Extract the targets out of the queryParams mytargets = [] # Normal format: ?target=path.1&target=path.2 if len(queryParams.getlist("target")) > 0: mytargets = queryParams.getlist("target") # Rails/PHP/jQuery common practice format: ?target[]=path.1&target[]=path.2 elif len(queryParams.getlist("target[]")) > 0: mytargets = queryParams.getlist("target[]") # Collect the targets for target in mytargets: requestOptions["targets"].append(target) template = dict() for key, val in queryParams.items(): if key.startswith("template["): template[key[9:-1]] = val requestOptions["template"] = template if "pickle" in queryParams: requestOptions["format"] = "pickle" if "rawData" in queryParams: requestOptions["format"] = "raw" if "format" in queryParams: requestOptions["format"] = queryParams["format"] if "jsonp" in queryParams: requestOptions["jsonp"] = queryParams["jsonp"] if "noCache" in queryParams: requestOptions["noCache"] = True if "maxDataPoints" in queryParams and queryParams["maxDataPoints"].isdigit(): requestOptions["maxDataPoints"] = int(queryParams["maxDataPoints"]) requestOptions["localOnly"] = queryParams.get("local") == "1" # Fill in the graphOptions for opt in graphClass.customizable: if opt in queryParams: val = queryParams[opt] if (val.isdigit() or (val.startswith("-") and val[1:].isdigit())) and "color" not in opt.lower(): val = int(val) elif "." in val and ( val.replace(".", "", 1).isdigit() or (val.startswith("-") and val[1:].replace(".", "", 1).isdigit()) ): val = float(val) elif val.lower() in ("true", "false"): val = val.lower() == "true" elif val.lower() == "default" or val == "": continue graphOptions[opt] = val tzinfo = pytz.timezone(settings.TIME_ZONE) if "tz" in queryParams: try: tzinfo = pytz.timezone(queryParams["tz"]) except pytz.UnknownTimeZoneError: pass requestOptions["tzinfo"] = tzinfo # Get the time interval for time-oriented graph types if graphType == "line" or graphType == "pie": if "until" in queryParams: untilTime = parseATTime(queryParams["until"], tzinfo) else: untilTime = parseATTime("now", tzinfo) if "from" in queryParams: fromTime = parseATTime(queryParams["from"], tzinfo) else: fromTime = parseATTime("-1d", tzinfo) startTime = min(fromTime, untilTime) endTime = max(fromTime, untilTime) assert startTime != endTime, "Invalid empty time range" requestOptions["startTime"] = startTime requestOptions["endTime"] = endTime timeRange = endTime - startTime queryTime = timeRange.days * 86400 + timeRange.seconds # convert the time delta to seconds if settings.DEFAULT_CACHE_POLICY and not queryParams.get("cacheTimeout"): requestOptions["cacheTimeout"] = max( timeout for period, timeout in settings.DEFAULT_CACHE_POLICY if period <= queryTime ) return (graphOptions, requestOptions)
def test_midnight(self): expected_time = self.default_tz.localize( datetime.strptime("0:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight", self.specified_tz) self.assertEqual(actual_time, expected_time.astimezone(self.specified_tz))
def test_should_return_absolute_time(self): time_string = "12:0020150308" expected_time = self.default_tz.localize(datetime.strptime(time_string, "%H:%M%Y%m%d")) actual_time = parseATTime(time_string) self.assertEqual(actual_time, expected_time)
def test_parse_last_leap_year(self): time_ref = parseATTime("-4years") expected = self.zone.localize(datetime(2009, 3, 1, 0, 0)) self.assertEquals(time_ref, expected)
def test_should_handle_dst_boundary(self): expected_time = self.specified_tz.localize( datetime.strptime("04:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight+3h", self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_should_return_absolute_time_short(self): time_string = '9:0020150308' expected_time = self.default_tz.localize(datetime.strptime(time_string,'%H:%M%Y%m%d')) actual_time = parseATTime(time_string, now=self.now) self.assertEqual(actual_time, expected_time)
def test_midnight(self): expected_time = self.specified_tz.localize( datetime.strptime("0:00_20171013", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight", self.specified_tz, now=self.now) self.assertEqual(actual_time, expected_time)
def test_midnight(self): expected_time = self.specified_tz.localize(datetime.strptime("0:00_20171013", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight", self.specified_tz, now=self.now) self.assertEqual(actual_time, expected_time)
def test_parse_last_year(self): time_ref = parseATTime("-1year") expected = self.zone.localize(datetime(2012, 2, 29, 0, 0)) self.assertEquals(time_ref, expected)
def test_absolute_time_should_respect_tz(self): time_string = '12:0020150308' expected_time = self.specified_tz.localize( datetime.strptime(time_string, '%H:%M%Y%m%d')) actual_time = parseATTime(time_string, self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_parse_last_month(self): time_ref = parseATTime("-1month") expected = self.zone.localize(datetime(2013, 1, 29, 0, 0)) self.assertEquals(time_ref, expected)
def test_absolute_time_YYYYMMDD(self): time_string = '20150110' expected_time = self.specified_tz.localize( datetime.strptime(time_string, '%Y%m%d')) actual_time = parseATTime(time_string, self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_absolute_time_should_respect_tz_short(self): time_string = '9:0020150308' expected_time = self.specified_tz.localize(datetime.strptime(time_string, '%H:%M%Y%m%d')) actual_time = parseATTime(time_string, self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_relative_day_with_tz(self): expected_time = self.specified_tz.localize(datetime.strptime("0:00_20171014", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight_tomorrow", self.specified_tz, now=self.now) self.assertEqual(actual_time, expected_time)
def test_absolute_time_YYYYMMDD(self): time_string = '20150110' expected_time = self.specified_tz.localize(datetime.strptime(time_string, '%Y%m%d')) actual_time = parseATTime(time_string, self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_relative_day_and_offset_with_tz(self): expected_time = self.specified_tz.localize(datetime.strptime("3:00_20150309", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight_tomorrow+3h", self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_parse_noon_plus_yesterday(self): time_ref = parseATTime("noon+yesterday") expected = datetime(self.MOCK_DATE.year, self.MOCK_DATE.month, self.MOCK_DATE.day - 1, 12, 00) self.assertEquals(time_ref, expected)
def test_now_should_respect_tz(self): expected_time = self.specified_tz.localize(datetime.strptime("12:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("now", self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_offset_with_tz(self): expected_time = self.specified_tz.localize( datetime.strptime("1:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight+1h", self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_should_handle_dst_boundary(self): expected_time = self.specified_tz.localize(datetime.strptime("04:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight+3h", self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_relative_day_and_offset_with_tz(self): expected_time = self.specified_tz.localize( datetime.strptime("3:00_20150309", '%H:%M_%Y%m%d')) actual_time = parseATTime("midnight_tomorrow+3h", self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_should_return_current_time(self): expected_time = self.default_tz.localize( datetime.strptime("12:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("now") self.assertEqual(actual_time, expected_time)
def test_now_should_respect_tz(self): expected_time = self.specified_tz.localize( datetime.strptime("12:00_20150308", '%H:%M_%Y%m%d')) actual_time = parseATTime("now", self.specified_tz) self.assertEqual(actual_time, expected_time)
def test_parse_noon_plus_yesterday(self): time_ref = parseATTime("noon+yesterday") expected = datetime.datetime(MOCK_DATE.year, MOCK_DATE.month, MOCK_DATE.day - 1, 12, 00) self.assertEquals(time_ref, expected)
def parseOptions(request): queryParams = request.REQUEST # Start with some defaults graphOptions = {'width': 330, 'height': 250} requestOptions = {} graphType = queryParams.get('graphType', 'line') assert graphType in GraphTypes, "Invalid graphType '%s', must be one of %s" % ( graphType, GraphTypes.keys()) graphClass = GraphTypes[graphType] # Fill in the requestOptions requestOptions['graphType'] = graphType requestOptions['graphClass'] = graphClass requestOptions['pieMode'] = queryParams.get('pieMode', 'average') requestOptions['targets'] = [] for target in queryParams.getlist('target'): if target.lower().startswith( 'graphite.'): #Strip leading "Graphite." as a convenience target = target[9:] requestOptions['targets'].append(target) if 'pickle' in queryParams: requestOptions['pickle'] = True if 'rawData' in queryParams: requestOptions['rawData'] = True if 'format' in queryParams: requestOptions['format'] = queryParams['format'] if 'noCache' in queryParams: requestOptions['noCache'] = True requestOptions['localOnly'] = queryParams.get('local') == '1' # Fill in the graphOptions for opt in graphClass.customizable: if opt in queryParams: val = queryParams[opt] if (val.isdigit() or (val.startswith('-') and val[1:].isdigit())) and opt not in ( 'fgcolor', 'bgcolor', 'fontColor'): val = int(val) elif '.' in val and (val.replace('.', '', 1).isdigit() or (val.startswith('-') and val[1:].replace('.', '', 1).isdigit())): val = float(val) elif val.lower() in ('true', 'false'): val = val.lower() == 'true' elif val.lower() == 'default' or val == '': continue graphOptions[opt] = val # Get the time interval for time-oriented graph types if graphType == 'line' or graphType == 'pie': if 'until' in queryParams: endTime = parseATTime(queryParams['until']) else: endTime = datetime.now() if 'from' in queryParams: startTime = parseATTime(queryParams['from']) else: startTime = endTime - timedelta(days=1) if endTime > datetime.now(): endTime = datetime.now() assert startTime < endTime, "Invalid time range!" requestOptions['startTime'] = startTime requestOptions['endTime'] = endTime return (graphOptions, requestOptions)