1#!/usr/bin/env python3
2
3"""CHART system 'activities' web page.
4Show a summary of the currently configured Activities.
5"""
6
7from io import StringIO
8from collections import defaultdict
9
10from django.shortcuts import render
11from django.urls import reverse
12
13from chart.project import settings
14from chart.common.util import nvl
15from chart.common.util import coalesce
16from chart.common.xml import load_xml
17from chart.common.xml import parsechildstr
18from chart.common.xml import parsechildstrs
19from chart.common.prettyprint import Table
20from chart.backend.activity import Activity
21
22
23def index(request):
24 """Compile a table of all Activities, showing a trigger action,
25 brief description and outputs of each one."""
26
27 scheduler = defaultdict(list)
28 for schedule_name in settings.SCHEDULE_DIR.glob('*.xml'):
29 schedule_elem = load_xml(schedule_name)
30 trigger_elem = schedule_elem.find('trigger')
31 if trigger_elem is not None:
32 if trigger_elem.find('directory-monitor') is not None:
33 pattern = parsechildstr(trigger_elem.find('directory-monitor'), 'pattern', None)
34 directory = parsechildstr(trigger_elem.find('directory-monitor'), 'directory', None)
35 if pattern is not None:
36 sched_type = 'File scan {pattern} in {dir}'.format(
37 pattern=pattern[:15], dir=directory)
38
39 else:
40 sched_type = 'Schedule {n}'.format(n=schedule_name.stem)
41
42 # if trigger_elem.find('hourly') is not None:
43 # sched_type = 'Hourly scheduler job'
44
45 # elif trigger_elem.find('daily') is not None:
46 # sched_type = 'Daily scheduler job'
47
48 # elif trigger_elem.find('monthly') is not None:
49 # sched_type = 'Monthly scheduler job'
50
51 # elif trigger_elem.find('weekly') is not None:
52 # sched_type = 'Weekly scheduler job'
53
54 # else:
55 # sched_type = 'Unknown scheduler job'
56
57 for response_elem in schedule_elem.findall('response'):
58 for a in parsechildstrs(response_elem, 'activity'):
59 scheduler[a].append(sched_type)
60
61 res = StringIO()
62
63 t = Table(headings=(
64 'Name', 'Description', 'Triggers', 'Output tables', 'Output events', 'Priority', 'Weight'),
65 cssclass='table table-striped table-bordered')
66 for activity in sorted(Activity.all()):
67 if not activity.enabled:
68 continue
69
70 if activity.name == 'ORBITAL_STATS':
71 input_str = 'All timeseries tables with orbital statistics'
72 output_str = 'All orbital stats tables'
73 event_str = ''
74
75 else:
76 input_str = ''
77 for trigger in activity.triggers:
78 if trigger.table is not None:
79 if trigger.trigger_type is not None:
80 trigger_type = trigger.trigger_type.value
81
82 else:
83 trigger_type = 'direct'
84
85 input_str += '<p>Table change {table} ({type})</p>'.format(
86 table=trigger.table.name, type=trigger_type)
87
88 else:
89 input_str += '<p>Any table</p>'
90
91 for sched in scheduler[activity.name]:
92 input_str += '<p>' + sched + '</p>'
93
94 output_str = ''
95 for output_table in activity.output_tables:
96 output_str += '<p>' + output_table.name + '</p>'
97
98 event_str = ''.join('<p>' + e + '</p>' for e in activity.eventnames)
99
100 if activity.name in ('PDU_INGESTER', 'SF00_INGESTER'):
101 output_str += '<p>All raw timeseries tables</p>'
102
103 name = '<a href=\'' + reverse(
104 'backend:activities/single',
105 kwargs=dict(activityname=activity.name)) + '\'>' + activity.name + '</a>'
106
107 t.append((name,
108 nvl(activity.description),
109 input_str,
110 output_str,
111 event_str,
112 activity.priority,
113 activity.weight))
114
115 t.write_html(res)
116
117 return render(request,
118 'backend/activities.html',
119 dict(table=res.getvalue()))
120
121
122def show_activity(request, activityname):
123 """A more detailed page describing a single Activity."""
124 activity = Activity(activityname)
125
126 schedule_triggers = []
127 for schedule_name in settings.SCHEDULE_DIR.glob('*.xml'):
128 schedule_elem = load_xml(schedule_name)
129 response_elem = schedule_elem.find('response')
130 match = False
131 if response_elem is not None:
132 for a in parsechildstrs(response_elem, 'activity'):
133 if a == activityname:
134 match = True
135
136 if match:
137 trigger_elem = schedule_elem.find('trigger')
138 if trigger_elem is not None:
139 if trigger_elem.find('hourly') is not None:
140 schedule_triggers.append('Hourly scheduler job')
141
142 elif trigger_elem.find('daily') is not None:
143 schedule_triggers.append('Daily scheduler job')
144
145 elif trigger_elem.find('monthly') is not None:
146 schedule_triggers.append('Monthly scheduler job')
147
148 elif trigger_elem.find('weekly') is not None:
149 schedule_triggers.append('Weekly scheduler job')
150
151 elif trigger_elem.find('directory-monitor') is not None:
152 pattern = parsechildstr(trigger_elem.find('directory-monitor'),
153 'pattern',
154 None)
155 directory = parsechildstr(trigger_elem.find('directory-monitor'),
156 'directory',
157 None)
158 if pattern is not None:
159 schedule_triggers.append('File scan {glob} in {dir}'.format(
160 glob=pattern[:15],
161 dir=directory))
162
163 else:
164 schedule_triggers.append('Unknown scheduler job')
165
166 return render(request,
167 'backend/activity.html',
168 dict(name=activity.name,
169 settings=settings,
170 activity=activity,
171 schedule_triggers=schedule_triggers))