Merge lp:~percona-toolkit-dev/percona-toolkit/pt-stalk-plugin into lp:percona-toolkit/2.1

Proposed by Daniel Nichter
Status: Merged
Approved by: Daniel Nichter
Approved revision: 400
Merged at revision: 398
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/pt-stalk-plugin
Merge into: lp:percona-toolkit/2.1
Diff against target: 295 lines (+208/-4)
3 files modified
bin/pt-stalk (+113/-4)
t/pt-stalk/plugin.t (+74/-0)
t/pt-stalk/samples/plugin001.sh (+21/-0)
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/pt-stalk-plugin
Reviewer Review Type Date Requested Status
Daniel Nichter Approve
Review via email: mp+127843@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Daniel Nichter (daniel-nichter) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/pt-stalk'
2--- bin/pt-stalk 2012-09-20 13:59:16 +0000
3+++ bin/pt-stalk 2012-10-03 18:33:24 +0000
4@@ -933,6 +933,30 @@
5 ITER=1
6
7 # ###########################################################################
8+# Plugin hooks
9+# ###########################################################################
10+
11+before_stalk() {
12+ :
13+}
14+
15+before_collect() {
16+ :
17+}
18+
19+after_collect() {
20+ :
21+}
22+
23+after_collect_sleep() {
24+ :
25+}
26+
27+after_stalk() {
28+ :
29+}
30+
31+# ###########################################################################
32 # Subroutines
33 # ###########################################################################
34
35@@ -1016,12 +1040,12 @@
36
37 oktorun() {
38 if [ $OKTORUN -eq 0 ]; then
39- EXIT_REASON="OKTORUN is false"
40+ [ -z "$EXIT_REASON" ] && EXIT_REASON="OKTORUN is false"
41 return 1 # stop running
42 fi
43
44 if [ -n "$OPT_ITERATIONS" ] && [ $ITER -gt $OPT_ITERATIONS ]; then
45- EXIT_REASON="no more iterations"
46+ [ -z "$EXIT_REASON" ] && EXIT_REASON="no more iterations"
47 return 1 # stop running
48 fi
49
50@@ -1136,6 +1160,9 @@
51 log "pt-stalk ran with $RAN_WITH" >> "$OPT_DEST/$prefix-trigger"
52 last_prefix="$prefix"
53
54+ # Plugin hook:
55+ before_collect
56+
57 # Fork and background the collect subroutine which will
58 # run for --run-time seconds. We (the parent) sleep
59 # while its collecting (hopefully --sleep is longer than
60@@ -1143,7 +1170,11 @@
61 (
62 collect "$OPT_DEST" "$prefix"
63 ) >> "$OPT_DEST/$prefix-output" 2>&1 &
64- log "Collector PID $!"
65+ local collector_pid=$!
66+ log "Collector PID $collector_pid"
67+
68+ # Plugin hook:
69+ after_collect $collector_pid
70 else
71 # There will not be enough disk space, so do not collect.
72 warn "Collect canceled because there will not be enough disk space after collecting another $margin MB"
73@@ -1156,6 +1187,9 @@
74 ITER=$((ITER + 1))
75 cycles_true=0
76 sleep_ok "$OPT_SLEEP" "Sleeping $OPT_SLEEP seconds after collect"
77+
78+ # Plugin hook:
79+ after_collect_sleep
80 else
81 # Trigger/check/value is ok, sleep until next check.
82 sleep_ok "$OPT_INTERVAL"
83@@ -1178,7 +1212,7 @@
84 # Note: $$ is the parent's PID, but we're a child proc.
85 # Bash 4 has $BASHPID but we can't rely on that. Consequently,
86 # we don't know our own PID. See the usage of $! below.
87- RAN_WITH="--function=$OPT_FUNCTION --variable=$OPT_VARIABLE --threshold=$OPT_THRESHOLD --match=$OPT_MATCH --cycles=$OPT_CYCLES --interval=$OPT_INTERVAL --iterations=$OPT_ITERATIONS --run-time=$OPT_RUN_TIME --sleep=$OPT_SLEEP --dest=$OPT_DEST --prefix=$OPT_PREFIX --notify-by-email=$OPT_NOTIFY_BY_EMAIL --log=$OPT_LOG --pid=$OPT_PID"
88+ RAN_WITH="--function=$OPT_FUNCTION --variable=$OPT_VARIABLE --threshold=$OPT_THRESHOLD --match=$OPT_MATCH --cycles=$OPT_CYCLES --interval=$OPT_INTERVAL --iterations=$OPT_ITERATIONS --run-time=$OPT_RUN_TIME --sleep=$OPT_SLEEP --dest=$OPT_DEST --prefix=$OPT_PREFIX --notify-by-email=$OPT_NOTIFY_BY_EMAIL --log=$OPT_LOG --pid=$OPT_PID --plugin=$OPT_PLUGIN"
89
90 log "Starting $0 $RAN_WITH"
91
92@@ -1190,9 +1224,15 @@
93 # Make a secure tmpdir.
94 mk_tmpdir
95
96+ # Plugin hook:
97+ before_stalk
98+
99 # Stalk while oktorun.
100 stalk
101
102+ # Plugin hook:
103+ after_stalk
104+
105 # Clean up.
106 rm_tmpdir
107 remove_pid_file "$OPT_PID"
108@@ -1217,6 +1257,15 @@
109 option_error "Invalid --function value: $OPT_FUNCTION"
110 fi
111
112+ # Verify and source the --plugin.
113+ if [ "$OPT_PLUGIN" ]; then
114+ if [ -f "$OPT_PLUGIN" ]; then
115+ . "$OPT_PLUGIN"
116+ else
117+ option_error "Invalid --plugin value: $OPT_PLUGIN is not a file"
118+ fi
119+ fi
120+
121 if [ -z "$OPT_STALK" -a "$OPT_COLLECT" ]; then
122 # Not stalking; do immediate collect once.
123 OPT_ITERATIONS=1
124@@ -1611,6 +1660,66 @@
125
126 Create a PID file when daemonized.
127
128+=item --plugin
129+
130+type: string
131+
132+Load a plugin to hook into the tool and extend is functionality.
133+The specified file does not need to be executable, nor does its first line
134+need to be shebang line. It only needs to define one or more of these
135+Bash functions:
136+
137+=over
138+
139+=item before_stalk
140+
141+Called before stalking.
142+
143+=item before_collect
144+
145+Called when the stalk condition is triggered, before running a collector
146+process as a backgrounded subshell.
147+
148+=item after_collect
149+
150+Called after running a collector process. The PID of the collector process
151+is passed as the first argument. This hook is called before
152+C<after_collect_sleep>.
153+
154+=item after_collect_sleep
155+
156+Called after sleeping L<"--sleep"> seconds for the collector process to finish.
157+This hook is called after C<after_collect>.
158+
159+=item after_stalk
160+
161+Called after stalking. Since pt-stalk stalks forever by default,
162+this hook is only called if L<"--iterations"> is specified.
163+
164+=back
165+
166+For example, a very simple plugin that touches a file when a collector
167+process is triggered:
168+
169+ before_colllect() {
170+ touch /tmp/foo
171+ }
172+
173+Since the plugin is completely sourced (imported) into the tool's namespace,
174+be careful not to define other functions or global variables that already
175+exist in the tool. You should prefix all plugin-specific functions and
176+global variables with C<plugin_> or C<PLUGIN_>.
177+
178+Plugins have access to all command line options but they should not modify
179+them. Each option is a global variable like C<$OPT_DEST> which corresponds
180+to L<"--dest">. Therefore, the global variable for each command line option
181+is C<OPT_> plus the option name in all caps with hyphens replaced by
182+underscores.
183+
184+Plugins can stop the tool by setting the global variable C<OKTORUN>
185+to C<1>. In this case, the global variable C<EXIT_REASON> should also
186+be set to indicate why the tool was stopped.
187+
188 =item --prefix
189
190 type: string
191
192=== added file 't/pt-stalk/plugin.t'
193--- t/pt-stalk/plugin.t 1970-01-01 00:00:00 +0000
194+++ t/pt-stalk/plugin.t 2012-10-03 18:33:24 +0000
195@@ -0,0 +1,74 @@
196+#!/usr/bin/env perl
197+
198+BEGIN {
199+ die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
200+ unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
201+ unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
202+};
203+
204+use strict;
205+use warnings FATAL => 'all';
206+use English qw(-no_match_vars);
207+use Test::More;
208+use Time::HiRes qw(sleep);
209+
210+use PerconaTest;
211+use DSNParser;
212+use Sandbox;
213+
214+my $dp = new DSNParser(opts=>$dsn_opts);
215+my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
216+my $dbh = $sb->get_dbh_for('master');
217+
218+if ( !$dbh ) {
219+ plan skip_all => 'Cannot connect to sandbox master';
220+}
221+
222+my $cnf = "/tmp/12345/my.sandbox.cnf";
223+my $pid_file = "/tmp/pt-stalk.pid.$PID";
224+my $log_file = "/tmp/pt-stalk.log.$PID";
225+my $dest = "/tmp/pt-stalk.collect.$PID";
226+my $output;
227+my $retval;
228+my $pid;
229+
230+diag(`rm $pid_file 2>/dev/null`);
231+diag(`rm $log_file 2>/dev/null`);
232+diag(`mkdir $dest`);
233+
234+# We'll have to watch Uptime since it's the only status var that's going
235+# to be predictable.
236+my (undef, $uptime) = $dbh->selectrow_array("SHOW STATUS LIKE 'Uptime'");
237+my $threshold = $uptime + 2;
238+
239+$retval = system("$trunk/bin/pt-stalk --iterations 1 --dest $dest --variable Uptime --threshold $threshold --cycles 1 --run-time 2 --pid $pid_file --plugin $trunk/t/pt-stalk/samples/plugin001.sh -- --defaults-file=$cnf >$log_file 2>&1");
240+
241+PerconaTest::wait_until(sub { !-f $pid_file });
242+
243+is(
244+ $retval >> 8,
245+ 0,
246+ "Exit 0"
247+);
248+
249+foreach my $hook (qw(
250+ before_stalk
251+ before_collect
252+ after_collect
253+ after_collect_sleep
254+ after_stalk
255+)) {
256+ ok(
257+ -f "$dest/$hook",
258+ "$hook hook called"
259+ );
260+}
261+
262+# #############################################################################
263+# Done.
264+# #############################################################################
265+diag(`rm $pid_file 2>/dev/null`);
266+diag(`rm $log_file 2>/dev/null`);
267+diag(`rm -rf $dest 2>/dev/null`);
268+ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
269+done_testing;
270
271=== added file 't/pt-stalk/samples/plugin001.sh'
272--- t/pt-stalk/samples/plugin001.sh 1970-01-01 00:00:00 +0000
273+++ t/pt-stalk/samples/plugin001.sh 2012-10-03 18:33:24 +0000
274@@ -0,0 +1,21 @@
275+#!/bin/sh
276+
277+before_stalk() {
278+ date >> "$OPT_DEST/before_stalk"
279+}
280+
281+before_collect() {
282+ date >> "$OPT_DEST/before_collect"
283+}
284+
285+after_collect() {
286+ date >> "$OPT_DEST/after_collect"
287+}
288+
289+after_collect_sleep() {
290+ date >> "$OPT_DEST/after_collect_sleep"
291+}
292+
293+after_stalk() {
294+ date >> "$OPT_DEST/after_stalk"
295+}

Subscribers

People subscribed via source and target branches