-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathrule-queue-report
executable file
·345 lines (287 loc) · 10.1 KB
/
rule-queue-report
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
#! /bin/bash
#
# This describes the current state of the rule queue. It reports the total
# number of executions in the queue. It also reports the number of executions
# scheduled to run during given hours, the number of executions for each rule,
# and the number of executions scheduled for each user. Finally, it reports the
# number or executions be performed currently and information about them. For
# each execution being performed, it reports the hour the execution was
# scheduled to be performed, the user who triggered the execution, and the
# execution's rule ID, REI ID, and rule. The output is similar to the following.
#
# 202 Rules in Queue
#
# Total Rules by Scheduled Hour
# 1 2021/01/26T02
# 131 2021/01/26T08
# 70 2021/01/26T09
#
# Total of Each Rule
# 200 _syncReplicas
# 1 _ipc_updateQuotaUsage
# 1 _ipc_rmTrash
#
# Total Rules by User
# 199 sriram
# 2 ipc_admin
# 1 tedgin
#
# 2 Running Rules
#
# Sched Hour User Rule Id REI Id Rule
# 2021/01/26T02 sriram 698577101 1078121923 _syncReplicas
# 2021/01/26T08 sriram 699269568 2119481675 _syncReplicas
set -o errexit -o nounset -o pipefail
# Pertenent Internal Data Structures
#
# RULE_EXEC_REPORT
# Internally, this script passes around a RULE_EXEC_REPORT text object. It is a
# set of RULE_EXEC objects where each RULE_EXEC is followed by a line of 60
# hyphens ("-"").
#
# RULE_EXEC
# A RULE_EXEC text object is a description of scheduled rule execution. It
# consists of a sequence of key-value pairs of the form "<key> = <value>" where
# each pair is separated by a line feed. The sequence of keys are the
# following.
#
# RULE_EXEC_ID the rule execution Id
# RULE_EXEC_REI_FILE_PATH the absolute path to the REI file on the rule engine
# host
# RULE_EXEC_STATUS the current status of the rule execution, the only
# value of interest is "RUNNING", which means the
# rule is currently being executed
# RULE_EXEC_TIME the local time when the rule execution is schedule
# in the form "<YYYY>/<MM>/<DD>T<hh>" where <YYYY> is
# the four digit Gregorian year, <MM> is the two digit
# month number, <DD> is the two digit day of the
# month, and <hh> is the two digit 24-hour clock hour
# RULE_EXEC_USER_NAME the user account that caused the rule execution to
# be scheduled
# RULE_EXEC_NAME the rule to be executed
main() {
local queueContents
queueContents="$(mktemp)"
# shellcheck disable=SC2064
trap "rm --force '$queueContents'" EXIT
gather_rules > "$queueContents"
local reportWidth
reportWidth="$(tput cols)"
local numQueued
numQueued="$(count_all < "$queueContents")"
printf '%d Rules in Queue\n' "$numQueued"
if (( numQueued > 0 )); then
printf '\n'
report_time_summary < "$queueContents"
printf '\n'
report_rule_summary "$reportWidth" < "$queueContents"
printf '\n'
report_user_summary < "$queueContents"
# XXX - https://github.com/irods/irods/issues/5785
# printf '\n'
# report_running_rules "$reportWidth" < "$queueContents"
fi
}
# displays the portion of the report on the rules currently being run
# Parameters:
# reportWidth the report row length in characters
report_running_rules() {
local reportWidth="$1"
if (( reportWidth < 50 )); then
reportWidth=50
fi
local runningRules
readarray -t runningRules < <(filter_running)
local runningCount=${#runningRules[@]}
printf '%d Running Rules\n' "$runningCount"
if (( runningCount > 0 )); then
printf '\n'
printf '%-13s %-10s %-9s %-10s %s\n' 'Sched Hour' User 'Rule Id' 'REI Id' Rule
local rule
for rule in "${runningRules[@]}"; do
local id time user rei rule
read -r id time user rei rule <<< "$rule"
printf '%-13s %-10s %-9s %-10s %s\n' "$time" "${user:0:10}" "$id" "$rei" "$rule"
done | cut --characters -"$reportWidth" | sort
fi
}
# displays the portion of the report that breaks down the number of rule
# executions scheduled by rule
# Parameters:
# reportWidth the report row length in characters
report_rule_summary() {
local reportWidth="$1"
printf 'Total of Each Rule\n'
summarize_tasks | cut --characters -"$reportWidth"
}
# displays the portion of the report that breaks down the number of rule
# executions scheduled for a given hour
report_time_summary() {
printf 'Total Rules by Scheduled Hour\n'
summarize_times
}
# displays the portion of the report that breaks down the number of rule
# executions scheduled by user
report_user_summary() {
printf 'Total Rules by User\n'
summarize_users
}
# generates a report describing the rule engine's current set of scheduled rule
# executions.
# Output:
# a RULE_EXEC_REPORT object
gather_rules() {
iquest --no-page \
no-distinct \
'select
RULE_EXEC_ID,
RULE_EXEC_STATUS,
RULE_EXEC_TIME,
RULE_EXEC_USER_NAME,
RULE_EXEC_REI_FILE_PATH,
RULE_EXEC_NAME' \
| clean_rules
}
# converts the raw output of `iquest` into rule execution report
# Input:
# It expects a set of objects delineated by a line of 60 hyphens ("-"). Each
# object consists of a sequence of key-value pairs of the form
# "<key> = <value>" where a <key> is at the beginning of a line. A <value> may
# contain line feeds, The keys are the following: "RULE_EXEC_ID" holds the rule
# execution Id, "RULE_EXEC_REI_FILE_PATH" holds the absolute path to the REI
# file on the rule engine host, "RULE_EXEC_STATUS? holds the current status of
# the rule execution, "RULE_EXEC_TIME" holds the time when the rule execution
# is schedule in seconds since the POSIX epoch, "RULE_EXEC_USER_NAME" holds the
# user account that caused the rule execution to be scheduled, and
# "RULE_EXEC_NAME" holds the rule to be executed.
# Output:
# a RULE_EXEC_REPORT object
clean_rules() {
awk --file - <(cat) <<'EOAWK'
function build_rule_line(startIdx, endIdx) {
line = $startIdx;
for (i = startIdx + 1; i <= endIdx; i++) { line = line " " $i; }
return gensub(/ *(\||\\)$/, "", "1", line);
}
/RULE_EXEC_ID/ {
print $0;
next;
}
/RULE_EXEC_REI_FILE_PATH/ {
print $0;
next;
}
/RULE_EXEC_STATUS/ {
print $0;
next;
}
/RULE_EXEC_TIME/ {
printf "RULE_EXEC_TIME = %s\n", strftime("%Y/%m/%dT%H", $3);
next;
}
/RULE_EXEC_USER_NAME/ {
print $0;
next;
}
/RULE_EXEC_NAME/ {
rule = build_rule_line(3, NF);
next;
}
/------------------------------------------------------------/ {
printf "RULE_EXEC_NAME = %s\n", rule;
print $0;
rule = "";
next;
}
{
if (rule != "") { rule = rule " "; }
rule = rule build_rule_line(1, NF);
}
EOAWK
}
# filter a rule execution report for those currently running
# Input:
# a RULE_EXEC_REPORT object
# Output:
# For each execution, on a single line it writes the <id>, <time>, <user>,
# <rei-id>, and <rule> separated by tabs, where <id> is the rule execution id,
# <time> is the hour or execution, <user> is the account that caused the
# execution to be scheduled, <rei-id> is the REI state Id, and <rule-summary>
# is the rule to be executed. Each execution is separated by a line feed.
filter_running() {
awk --file - <(cat) <<'EOAWK'
/RULE_EXEC_ID/ { id = $3; }
/RULE_EXEC_REI_FILE_PATH/ { rei = gensub(/^.*\./, "", "1", $3); }
/RULE_EXEC_STATUS/ { status = $3; }
/RULE_EXEC_TIME/ { time = $3; }
/RULE_EXEC_USER_NAME/ { user = $3; }
/RULE_EXEC_NAME/ { rule = gensub(/^RULE_EXEC_NAME = /, "", "1", $0); }
/------------------------------------------------------------/ {
if (status == "RE_RUNNING") { printf "%s\t%s\t%s\t%s\t%s\n", id, time, user, rei, rule; }
id = "";
time = "";
user = "";
rei = "";
rule = "";
}
EOAWK
}
# summarizes how many executions of each rule are scheduled
# Input:
# a RULE_EXEC_REPORT object
# Output:
# a two column summary, where the second column is the rule, and the first is
# the number of times its scheduled for execution. The first column is right
# justified with a width of at least seven characters. The two columns are
# separated by a space, and the rows by line feeds. The output is sorted by
# execution count in descending order.
summarize_tasks() {
sed --quiet 's/^RULE_EXEC_NAME = //p' | summarize | sort --numeric --reverse --key 1,1
}
# summarizes how many rule executions are scheduled for each hour in
# chronological order, hours without any rules scheduled are skipped
# Input:
# a RULE_EXEC_REPORT object
# Output:
# a two column summary, where the second column is an hour when rule executions
# are scheduled to happen, and the first is the number of executions scheduled
# for that hour. The hour has the same form as in the input. The first column
# is right justified with a width of at least seven characters. The two columns
# are separated by a space, and the rows by line feeds. The output is in
# chronological order.
summarize_times() {
sed --quiet 's/^RULE_EXEC_TIME = //p' | summarize
}
# summarizes how many rule executions each user has in the rule queue sorted by
# execution count in descending order
# Input:
# a RULE_EXEC_REPORT object
# Ouput:
# a two column summary, where the second column is a username and the first is
# the number of rule executions that username has queued. The first column is
# right justified with a width of at least seven characters. The two columns
# are separated by a space, and the rows by line feeds. The output is sorted by
# execution count in descending order.
summarize_users() {
sed --quiet 's/^RULE_EXEC_USER_NAME = //p' | summarize | sort --numeric --reverse --key 1,1
}
# counts how many times each entries appears in a list
# Input:
# the list of entries deliniated by line feeds.
# Output:
# a two column summary, where the second column is an entry and the first is
# the number of time it appeared in the list. The first column is right
# justified with a width of at least seven characters. The two columns are
# separated by a space, and the rows by line feeds.
summarize() {
sort | uniq --count
}
# counts all of the rules
# Input:
# a RULE_EXEC_REPORT object
# Output:
# the total number executions
count_all() {
sed --quiet '/^------------------------------------------------------------$/p' | wc --lines
}
main "$@"