Merge lp:~percona-toolkit-dev/percona-toolkit/release-2.2.8 into lp:percona-toolkit/2.2

Proposed by Daniel Nichter on 2014-05-30
Status: Merged
Approved by: Daniel Nichter on 2014-05-30
Approved revision: 604
Merged at revision: 605
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/release-2.2.8
Merge into: lp:percona-toolkit/2.2
Diff against target: 5689 lines (+347/-4800) (has conflicts)
59 files modified
Changelog (+10/-0)
bin/pt-archiver (+1/-1)
bin/pt-config-diff (+1/-1)
bin/pt-deadlock-logger (+17/-2)
bin/pt-diskstats (+1/-1)
bin/pt-duplicate-key-checker (+1/-1)
bin/pt-find (+1/-1)
bin/pt-fk-error-logger (+1/-1)
bin/pt-heartbeat (+1/-1)
bin/pt-index-usage (+1/-1)
bin/pt-kill (+1/-1)
bin/pt-online-schema-change (+25/-16)
bin/pt-query-digest (+1/-1)
bin/pt-slave-delay (+1/-1)
bin/pt-slave-restart (+1/-1)
bin/pt-table-checksum (+128/-17)
bin/pt-table-sync (+1/-1)
bin/pt-upgrade (+1/-1)
bin/pt-variable-advisor (+1/-1)
lib/Percona/Agent/Logger.pm (+0/-341)
lib/Percona/Test/Mock/AgentLogger.pm (+0/-129)
lib/Percona/Test/Mock/UserAgent.pm (+0/-71)
lib/Percona/Toolkit.pm (+1/-1)
lib/Percona/WebAPI/Client.pm (+0/-321)
lib/Percona/WebAPI/Exception/Request.pm (+0/-69)
lib/Percona/WebAPI/Exception/Resource.pm (+0/-66)
lib/Percona/WebAPI/Representation.pm (+0/-86)
lib/Percona/WebAPI/Resource/Agent.pm (+0/-77)
lib/Percona/WebAPI/Resource/Config.pm (+0/-55)
lib/Percona/WebAPI/Resource/LogEntry.pm (+0/-66)
lib/Percona/WebAPI/Resource/Service.pm (+0/-94)
lib/Percona/WebAPI/Resource/Task.pm (+0/-62)
t/lib/Percona/WebAPI/Client.t (+0/-236)
t/lib/Percona/WebAPI/Representation.t (+0/-51)
t/pt-agent/basics.t (+0/-101)
t/pt-agent/get_services.t (+0/-423)
t/pt-agent/init_agent.t (+0/-333)
t/pt-agent/make_new_crontab.t (+0/-151)
t/pt-agent/replace_special_vars.t (+0/-73)
t/pt-agent/run_agent.t (+0/-527)
t/pt-agent/run_service.t (+0/-503)
t/pt-agent/samples/crontab001.out (+0/-2)
t/pt-agent/samples/crontab002.in (+0/-1)
t/pt-agent/samples/crontab002.out (+0/-3)
t/pt-agent/samples/crontab003.in (+0/-3)
t/pt-agent/samples/crontab003.out (+0/-3)
t/pt-agent/samples/crontab004.in (+0/-2)
t/pt-agent/samples/crontab004.out (+0/-2)
t/pt-agent/samples/query-history/data001.json (+0/-152)
t/pt-agent/samples/query-history/data001.send (+0/-166)
t/pt-agent/samples/service001 (+0/-19)
t/pt-agent/samples/write_services001 (+0/-19)
t/pt-agent/schedule_services.t (+0/-200)
t/pt-agent/send_data.t (+0/-234)
t/pt-agent/write_services.t (+0/-108)
t/pt-online-schema-change/plugin.t (+1/-0)
t/pt-online-schema-change/samples/plugins/all_hooks.pm (+7/-0)
t/pt-table-checksum/plugin.t (+98/-0)
t/pt-table-checksum/samples/plugins/all_hooks.pm (+45/-0)
Contents conflict in bin/pt-agent
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/release-2.2.8
Reviewer Review Type Date Requested Status
Daniel Nichter Approve on 2014-05-30
Review via email: mp+221476@code.launchpad.net
To post a comment you must log in.
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Changelog'
2--- Changelog 2014-02-20 08:10:16 +0000
3+++ Changelog 2014-05-30 01:02:37 +0000
4@@ -1,5 +1,15 @@
5 Changelog for Percona Toolkit
6
7+ * Removed pt-agent
8+ * Added pt-slave-restart GTID support
9+ * Added pt-table-checksum --plugin
10+ * Fixed bug 1304062: --ignore-tables does not work correctly
11+ * Fixed bug 1295667: pt-deadlock-logger logs incorrect ts
12+ * Fixed bug 1254233: pt-mysql-summary blank InnoDB section for 5.6
13+ * Fixed bug 1286250: pt-online-schema-change requests password twice
14+ * Fixed bug 965553: pt-query-digest dosn't fingerprint true/false literals correctly
15+ * Fixed bug 290911: pt-show-grant --ask-pass prints "Enter password" to STDOUT
16+
17 v2.2.7 released 2014-02-20
18
19 * Fixed bug 1279502: --version-check behaves like spyware
20
21=== renamed file 'bin/pt-agent' => 'bin/pt-agent.THIS'
22=== modified file 'bin/pt-archiver'
23--- bin/pt-archiver 2014-05-24 21:36:33 +0000
24+++ bin/pt-archiver 2014-05-30 01:02:37 +0000
25@@ -43,7 +43,7 @@
26 {
27 package Percona::Toolkit;
28
29-our $VERSION = '2.2.7';
30+our $VERSION = '2.2.8';
31
32 use strict;
33 use warnings FATAL => 'all';
34
35=== modified file 'bin/pt-config-diff'
36--- bin/pt-config-diff 2014-05-24 21:36:33 +0000
37+++ bin/pt-config-diff 2014-05-30 01:02:37 +0000
38@@ -43,7 +43,7 @@
39 {
40 package Percona::Toolkit;
41
42-our $VERSION = '2.2.7';
43+our $VERSION = '2.2.8';
44
45 use strict;
46 use warnings FATAL => 'all';
47
48=== modified file 'bin/pt-deadlock-logger'
49--- bin/pt-deadlock-logger 2014-05-24 21:36:33 +0000
50+++ bin/pt-deadlock-logger 2014-05-30 01:02:37 +0000
51@@ -42,7 +42,7 @@
52 {
53 package Percona::Toolkit;
54
55-our $VERSION = '2.2.7';
56+our $VERSION = '2.2.8';
57
58 use strict;
59 use warnings FATAL => 'all';
60@@ -4440,12 +4440,27 @@
61
62 my $dst;
63 if ( my $dst_dsn = $o->get('dest') ) {
64+
65+ # set time_zone = SYSTEM , addresses https://bugs.launchpad.net/percona-toolkit/+bug/1295667
66+ my $set_tz = sub {
67+ my ($dbh) = @_;
68+ my $sql = "SET time_zone=SYSTEM /* pt-deadlock-logger */";
69+ eval {
70+ PTDEBUG && _d($dbh, $sql);
71+ $dbh->do($sql);
72+ };
73+ if ( $EVAL_ERROR ) {
74+ die "Failed to $sql: $EVAL_ERROR\n";
75+ }
76+ };
77+
78 $dst = Cxn->new(
79 dsn => $dst_dsn,
80 prev_dsn => ($src ? $src->dsn : undef),
81 parent => $o->get('daemonize'),
82 DSNParser => $dp,
83 OptionParser => $o,
84+ set => $set_tz,
85 );
86 }
87
88@@ -5199,7 +5214,7 @@
89
90 CREATE TABLE deadlocks (
91 server char(20) NOT NULL,
92- ts datetime NOT NULL,
93+ ts timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
94 thread int unsigned NOT NULL,
95 txn_id bigint unsigned NOT NULL,
96 txn_time smallint unsigned NOT NULL,
97
98=== modified file 'bin/pt-diskstats'
99--- bin/pt-diskstats 2014-05-24 21:36:33 +0000
100+++ bin/pt-diskstats 2014-05-30 01:02:37 +0000
101@@ -38,7 +38,7 @@
102 {
103 package Percona::Toolkit;
104
105-our $VERSION = '2.2.7';
106+our $VERSION = '2.2.8';
107
108 use strict;
109 use warnings FATAL => 'all';
110
111=== modified file 'bin/pt-duplicate-key-checker'
112--- bin/pt-duplicate-key-checker 2014-05-28 01:15:25 +0000
113+++ bin/pt-duplicate-key-checker 2014-05-30 01:02:37 +0000
114@@ -39,7 +39,7 @@
115 {
116 package Percona::Toolkit;
117
118-our $VERSION = '2.2.7';
119+our $VERSION = '2.2.8';
120
121 use strict;
122 use warnings FATAL => 'all';
123
124=== modified file 'bin/pt-find'
125--- bin/pt-find 2014-05-24 21:36:33 +0000
126+++ bin/pt-find 2014-05-30 01:02:37 +0000
127@@ -35,7 +35,7 @@
128 {
129 package Percona::Toolkit;
130
131-our $VERSION = '2.2.7';
132+our $VERSION = '2.2.8';
133
134 use strict;
135 use warnings FATAL => 'all';
136
137=== modified file 'bin/pt-fk-error-logger'
138--- bin/pt-fk-error-logger 2014-05-24 21:36:33 +0000
139+++ bin/pt-fk-error-logger 2014-05-30 01:02:37 +0000
140@@ -37,7 +37,7 @@
141 {
142 package Percona::Toolkit;
143
144-our $VERSION = '2.2.7';
145+our $VERSION = '2.2.8';
146
147 use strict;
148 use warnings FATAL => 'all';
149
150=== modified file 'bin/pt-heartbeat'
151--- bin/pt-heartbeat 2014-05-24 21:36:33 +0000
152+++ bin/pt-heartbeat 2014-05-30 01:02:37 +0000
153@@ -38,7 +38,7 @@
154 {
155 package Percona::Toolkit;
156
157-our $VERSION = '2.2.7';
158+our $VERSION = '2.2.8';
159
160 use strict;
161 use warnings FATAL => 'all';
162
163=== modified file 'bin/pt-index-usage'
164--- bin/pt-index-usage 2014-05-28 17:03:30 +0000
165+++ bin/pt-index-usage 2014-05-30 01:02:37 +0000
166@@ -45,7 +45,7 @@
167 {
168 package Percona::Toolkit;
169
170-our $VERSION = '2.2.7';
171+our $VERSION = '2.2.8';
172
173 use strict;
174 use warnings FATAL => 'all';
175
176=== modified file 'bin/pt-kill'
177--- bin/pt-kill 2014-05-28 17:03:30 +0000
178+++ bin/pt-kill 2014-05-30 01:02:37 +0000
179@@ -47,7 +47,7 @@
180 {
181 package Percona::Toolkit;
182
183-our $VERSION = '2.2.7';
184+our $VERSION = '2.2.8';
185
186 use strict;
187 use warnings FATAL => 'all';
188
189=== modified file 'bin/pt-online-schema-change'
190--- bin/pt-online-schema-change 2014-05-24 21:36:33 +0000
191+++ bin/pt-online-schema-change 2014-05-30 01:02:37 +0000
192@@ -54,7 +54,7 @@
193 {
194 package Percona::Toolkit;
195
196-our $VERSION = '2.2.7';
197+our $VERSION = '2.2.8';
198
199 use strict;
200 use warnings FATAL => 'all';
201@@ -3771,7 +3771,7 @@
202
203 my $dbh = $self->{dbh};
204 if ( !$dbh || !$dbh->ping() ) {
205- if ( $self->{ask_pass} && !$self->{asked_for_pass} ) {
206+ if ( $self->{ask_pass} && !$self->{asked_for_pass} && !defined $dsn->{p}) {
207 $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: ");
208 $self->{asked_for_pass} = 1;
209 }
210@@ -8105,21 +8105,29 @@
211 return;
212 };
213
214- my $get_lag = sub {
215- my ($cxn) = @_;
216- my $dbh = $cxn->dbh();
217- if ( !$dbh || !$dbh->ping() ) {
218- eval { $dbh = $cxn->connect() }; # connect or die trying
219- if ( $EVAL_ERROR ) {
220- $oktorun = 0; # flag for cleanup tasks
221- chomp $EVAL_ERROR;
222- die "Lost connection to replica " . $cxn->name()
223- . " while attempting to get its lag ($EVAL_ERROR)\n";
224+ my $get_lag;
225+ # The plugin is able to override the slavelag check so tools like
226+ # pt-heartbeat or other replicators (Tungsten...) can be used to
227+ # measure replication lag
228+ if ( $plugin && $plugin->can('get_slave_lag') ) {
229+ $get_lag = $plugin->get_slave_lag(oktorun => \$oktorun);
230+ } else {
231+ $get_lag = sub {
232+ my ($cxn) = @_;
233+ my $dbh = $cxn->dbh();
234+ if ( !$dbh || !$dbh->ping() ) {
235+ eval { $dbh = $cxn->connect() }; # connect or die trying
236+ if ( $EVAL_ERROR ) {
237+ $oktorun = 0; # flag for cleanup tasks
238+ chomp $EVAL_ERROR;
239+ die "Lost connection to replica " . $cxn->name()
240+ . " while attempting to get its lag ($EVAL_ERROR)\n";
241+ }
242 }
243- }
244- return $ms->get_slave_lag($dbh);
245- };
246-
247+ return $ms->get_slave_lag($dbh);
248+ };
249+ }
250+
251 $replica_lag = new ReplicaLagWaiter(
252 slaves => $slave_lag_cxns,
253 max_lag => $o->get('max-lag'),
254@@ -11345,6 +11353,7 @@
255 after_drop_old_table
256 before_drop_triggers
257 before_exit
258+ get_slave_lag
259
260 Each hook is passed different arguments. To see which arguments are passed
261 to a hook, search for the hook's name in the tool's source code, like:
262
263=== modified file 'bin/pt-query-digest'
264--- bin/pt-query-digest 2014-05-28 17:03:30 +0000
265+++ bin/pt-query-digest 2014-05-30 01:02:37 +0000
266@@ -64,7 +64,7 @@
267 {
268 package Percona::Toolkit;
269
270-our $VERSION = '2.2.7';
271+our $VERSION = '2.2.8';
272
273 use strict;
274 use warnings FATAL => 'all';
275
276=== modified file 'bin/pt-slave-delay'
277--- bin/pt-slave-delay 2014-05-24 21:36:33 +0000
278+++ bin/pt-slave-delay 2014-05-30 01:02:37 +0000
279@@ -40,7 +40,7 @@
280 {
281 package Percona::Toolkit;
282
283-our $VERSION = '2.2.7';
284+our $VERSION = '2.2.8';
285
286 use strict;
287 use warnings FATAL => 'all';
288
289=== modified file 'bin/pt-slave-restart'
290--- bin/pt-slave-restart 2014-05-28 22:25:08 +0000
291+++ bin/pt-slave-restart 2014-05-30 01:02:37 +0000
292@@ -41,7 +41,7 @@
293 {
294 package Percona::Toolkit;
295
296-our $VERSION = '2.2.7';
297+our $VERSION = '2.2.8';
298
299 use strict;
300 use warnings FATAL => 'all';
301
302=== modified file 'bin/pt-table-checksum'
303--- bin/pt-table-checksum 2014-05-28 01:15:25 +0000
304+++ bin/pt-table-checksum 2014-05-30 01:02:37 +0000
305@@ -57,7 +57,7 @@
306 {
307 package Percona::Toolkit;
308
309-our $VERSION = '2.2.7';
310+our $VERSION = '2.2.8';
311
312 use strict;
313 use warnings FATAL => 'all';
314@@ -9222,6 +9222,30 @@
315 my $slaves = []; # all slaves (that we can find)
316 my $slave_lag_cxns; # slaves whose lag we'll check
317
318+ # ########################################################################
319+ # Create --plugin.
320+ # ########################################################################
321+ my $plugin;
322+ if ( my $file = $o->get('plugin') ) {
323+ die "--plugin file $file does not exist\n" unless -f $file;
324+ eval {
325+ require $file;
326+ };
327+ die "Error loading --plugin $file: $EVAL_ERROR" if $EVAL_ERROR;
328+ eval {
329+ $plugin = pt_table_checksum_plugin->new(
330+ master_cxn => $master_cxn,
331+ explain => $o->get('explain'),
332+ quiet => $o->get('quiet'),
333+ resume => $o->get('resume'),
334+ Quoter => $q,
335+ TableParser => $tp,
336+ );
337+ };
338+ die "Error creating --plugin: $EVAL_ERROR" if $EVAL_ERROR;
339+ print "Created plugin from $file.\n";
340+ }
341+
342 my $replica_lag; # ReplicaLagWaiter object
343 my $replica_lag_pr; # Progress for ReplicaLagWaiter
344 my $sys_load; # MySQLStatusWaiter object
345@@ -9446,6 +9470,11 @@
346 # #####################################################################
347 if ( $o->get('replicate-check') && $o->get('replicate-check-only') ) {
348 PTDEBUG && _d('Will --replicate-check and exit');
349+
350+ # --plugin hook
351+ if ( $plugin && $plugin->can('before_replicate_check') ) {
352+ $plugin->before_replicate_check();
353+ }
354
355 foreach my $slave ( @$slaves ) {
356 my $diffs = $rc->find_replication_differences(
357@@ -9466,6 +9495,11 @@
358 }
359 }
360
361+ # --plugin hook
362+ if ( $plugin && $plugin->can('after_replicate_check') ) {
363+ $plugin->after_replicate_check();
364+ }
365+
366 PTDEBUG && _d('Exit status', $exit_status, 'oktorun', $oktorun);
367 return $exit_status;
368 }
369@@ -9544,23 +9578,31 @@
370 return;
371 };
372
373- my $get_lag = sub {
374- my ($cxn) = @_;
375- my $dbh = $cxn->dbh();
376- if ( !$dbh || !$dbh->ping() ) {
377- PTDEBUG && _d('Lost connection to slave', $cxn->name(),
378- 'while waiting for slave lag');
379- eval { $dbh = $cxn->connect() }; # connect or die trying
380- if ( $EVAL_ERROR ) {
381- $oktorun = 0; # Fatal error
382- chomp $EVAL_ERROR;
383- die "Lost connection to replica " . $cxn->name()
384- . " while attempting to get its lag ($EVAL_ERROR)";
385+ my $get_lag;
386+ # The plugin is able to override the slavelag check so tools like
387+ # pt-heartbeat or other replicators (Tungsten...) can be used to
388+ # measure replication lag
389+ if ( $plugin && $plugin->can('get_slave_lag') ) {
390+ $get_lag = $plugin->get_slave_lag(oktorun => \$oktorun);
391+ } else {
392+ $get_lag = sub {
393+ my ($cxn) = @_;
394+ my $dbh = $cxn->dbh();
395+ if ( !$dbh || !$dbh->ping() ) {
396+ PTDEBUG && _d('Lost connection to slave', $cxn->name(),
397+ 'while waiting for slave lag');
398+ eval { $dbh = $cxn->connect() }; # connect or die trying
399+ if ( $EVAL_ERROR ) {
400+ $oktorun = 0; # Fatal error
401+ chomp $EVAL_ERROR;
402+ die "Lost connection to replica " . $cxn->name()
403+ . " while attempting to get its lag ($EVAL_ERROR)";
404+ }
405 }
406- }
407- return $ms->get_slave_lag($dbh);
408- };
409-
410+ return $ms->get_slave_lag($dbh);
411+ };
412+ }
413+
414 $replica_lag = new ReplicaLagWaiter(
415 slaves => $slave_lag_cxns,
416 max_lag => $o->get('max-lag'),
417@@ -10168,6 +10210,19 @@
418 };
419
420 # ########################################################################
421+ # Init the --plugin.
422+ # ########################################################################
423+
424+ # --plugin hook
425+ if ( $plugin && $plugin->can('init') ) {
426+ $plugin->init(
427+ slaves => $slaves,
428+ slave_lag_cxns => $slave_lag_cxns,
429+ repl_table => $repl_table,
430+ );
431+ }
432+
433+ # ########################################################################
434 # Checksum each table.
435 # ########################################################################
436
437@@ -10271,6 +10326,12 @@
438 @$all_cols;
439 $tbl->{checksum_cols} = \@cols;
440
441+ # --plugin hook
442+ if ( $plugin && $plugin->can('before_checksum_table') ) {
443+ $plugin->before_checksum_table(
444+ tbl => $tbl);
445+ }
446+
447 # Finally, checksum the table.
448 # The "1 while" loop is necessary because we're executing REPLACE
449 # statements which don't return rows and NibbleIterator only
450@@ -10279,6 +10340,11 @@
451 # from the done callback, uses this start time.
452 $tbl->{checksum_results}->{start_time} = time;
453 1 while $nibble_iter->next();
454+
455+ # --plugin hook
456+ if ( $plugin && $plugin->can('after_checksum_table') ) {
457+ $plugin->after_checksum_table();
458+ }
459 }
460 };
461 if ( $EVAL_ERROR ) {
462@@ -12053,6 +12119,18 @@
463 tool will overwrite the PID file with the current PID. The PID file is
464 removed automatically when the tool exits.
465
466+=item --plugin
467+
468+type: string
469+
470+Perl module file that defines a C<pt_table_checksum_plugin> class.
471+A plugin allows you to write a Perl module that can hook into many parts
472+of pt-table-checksum. This requires a good knowledge of Perl and
473+Percona Toolkit conventions, which are beyond this scope of this
474+documentation. Please contact Percona if you have questions or need help.
475+
476+See L<"PLUGIN"> for more information.
477+
478 =item --port
479
480 short form: -P; type: int; group: Connection
481@@ -12401,6 +12479,39 @@
482
483 =back
484
485+=head1 PLUGIN
486+
487+The file specified by L<"--plugin"> must define a class (i.e. a package)
488+called C<pt_table_checksum_plugin> with a C<new()> subroutine.
489+The tool will create an instance of this class and call any hooks that
490+it defines. No hooks are required, but a plugin isn't very useful without
491+them.
492+
493+These hooks, in this order, are called if defined:
494+
495+ init
496+ before_replicate_check
497+ after_replicate_check
498+ get_slave_lag
499+ before_checksum_table
500+ after_checksum_table
501+
502+Each hook is passed different arguments. To see which arguments are passed
503+to a hook, search for the hook's name in the tool's source code, like:
504+
505+ # --plugin hook
506+ if ( $plugin && $plugin->can('init') ) {
507+ $plugin->init(
508+ slaves => $slaves,
509+ slave_lag_cxns => $slave_lag_cxns,
510+ repl_table => $repl_table,
511+ );
512+ }
513+
514+The comment C<# --plugin hook> precedes every hook call.
515+
516+Please contact Percona if you have questions or need help.
517+
518 =head1 DSN OPTIONS
519
520 These DSN options are used to create a DSN. Each option is given like
521
522=== modified file 'bin/pt-table-sync'
523--- bin/pt-table-sync 2014-05-28 01:15:25 +0000
524+++ bin/pt-table-sync 2014-05-30 01:02:37 +0000
525@@ -55,7 +55,7 @@
526 {
527 package Percona::Toolkit;
528
529-our $VERSION = '2.2.7';
530+our $VERSION = '2.2.8';
531
532 use strict;
533 use warnings FATAL => 'all';
534
535=== modified file 'bin/pt-upgrade'
536--- bin/pt-upgrade 2014-05-28 17:03:30 +0000
537+++ bin/pt-upgrade 2014-05-30 01:02:37 +0000
538@@ -61,7 +61,7 @@
539 {
540 package Percona::Toolkit;
541
542-our $VERSION = '2.2.7';
543+our $VERSION = '2.2.8';
544
545 use strict;
546 use warnings FATAL => 'all';
547
548=== modified file 'bin/pt-variable-advisor'
549--- bin/pt-variable-advisor 2014-05-24 21:36:33 +0000
550+++ bin/pt-variable-advisor 2014-05-30 01:02:37 +0000
551@@ -44,7 +44,7 @@
552 {
553 package Percona::Toolkit;
554
555-our $VERSION = '2.2.7';
556+our $VERSION = '2.2.8';
557
558 use strict;
559 use warnings FATAL => 'all';
560
561=== removed directory 'lib/Percona/Agent'
562=== removed file 'lib/Percona/Agent/Logger.pm'
563--- lib/Percona/Agent/Logger.pm 2013-12-11 03:07:36 +0000
564+++ lib/Percona/Agent/Logger.pm 1970-01-01 00:00:00 +0000
565@@ -1,341 +0,0 @@
566-# This program is copyright 2013 Percona Ireland Ltd.
567-# Feedback and improvements are welcome.
568-#
569-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
570-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
571-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
572-#
573-# This program is free software; you can redistribute it and/or modify it under
574-# the terms of the GNU General Public License as published by the Free Software
575-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
576-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
577-# licenses.
578-#
579-# You should have received a copy of the GNU General Public License along with
580-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
581-# Place, Suite 330, Boston, MA 02111-1307 USA.
582-# ###########################################################################
583-# Percona::Agent::Logger package
584-# ###########################################################################
585-package Percona::Agent::Logger;
586-
587-use strict;
588-use warnings FATAL => 'all';
589-use English qw(-no_match_vars);
590-
591-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
592-
593-use POSIX qw(SIGALRM);
594-
595-use Lmo;
596-use Transformers;
597-use Percona::WebAPI::Resource::LogEntry;
598-
599-Transformers->import(qw(ts));
600-
601-has 'exit_status' => (
602- is => 'rw',
603- isa => 'ScalarRef',
604- required => 1,
605-);
606-
607-has 'pid' => (
608- is => 'ro',
609- isa => 'Int',
610- required => 1,
611-);
612-
613-has 'service' => (
614- is => 'rw',
615- isa => 'Maybe[Str]',
616- required => 0,
617- default => sub { return; },
618-);
619-
620-has 'data_ts' => (
621- is => 'rw',
622- isa => 'Maybe[Int]',
623- required => 0,
624- default => sub { return; },
625-);
626-
627-has 'online_logging' => (
628- is => 'ro',
629- isa => 'Bool',
630- required => 0,
631- default => sub { return 1 },
632-);
633-
634-has 'online_logging_enabled' => (
635- is => 'rw',
636- isa => 'Bool',
637- required => 0,
638- default => sub { return 0 },
639-);
640-
641-has 'quiet' => (
642- is => 'rw',
643- isa => 'Int',
644- required => 0,
645- default => sub { return 0 },
646-);
647-
648-has '_buffer' => (
649- is => 'rw',
650- isa => 'ArrayRef',
651- required => 0,
652- default => sub { return []; },
653-);
654-
655-has '_pipe_write' => (
656- is => 'rw',
657- isa => 'Maybe[FileHandle]',
658- required => 0,
659-);
660-
661-sub read_stdin {
662- my ( $t ) = @_;
663-
664- # Set the SIGALRM handler.
665- POSIX::sigaction(
666- SIGALRM,
667- POSIX::SigAction->new(sub { die 'read timeout'; }),
668- ) or die "Error setting SIGALRM handler: $OS_ERROR";
669-
670- my $timeout = 0;
671- my @lines;
672- eval {
673- alarm $t;
674- while(defined(my $line = <STDIN>)) {
675- push @lines, $line;
676- }
677- alarm 0;
678- };
679- if ( $EVAL_ERROR ) {
680- PTDEBUG && _d('Read error:', $EVAL_ERROR);
681- die $EVAL_ERROR unless $EVAL_ERROR =~ m/read timeout/;
682- $timeout = 1;
683- }
684- return unless scalar @lines || $timeout;
685- return \@lines;
686-}
687-
688-sub start_online_logging {
689- my ($self, %args) = @_;
690- my $client = $args{client};
691- my $log_link = $args{log_link};
692- my $read_timeout = $args{read_timeout} || 3;
693-
694- return unless $self->online_logging;
695-
696- my $pid = open(my $pipe_write, "|-");
697-
698- if ($pid) {
699- # parent
700- select $pipe_write;
701- $OUTPUT_AUTOFLUSH = 1;
702- $self->_pipe_write($pipe_write);
703- $self->online_logging_enabled(1);
704- }
705- else {
706- # child
707- my @log_entries;
708- my $n_errors = 0;
709- my $oktorun = 1;
710- QUEUE:
711- while ($oktorun) {
712- my $lines = read_stdin($read_timeout);
713- last QUEUE unless $lines;
714- LINE:
715- while ( defined(my $line = shift @$lines) ) {
716- # $line = ts,level,n_lines,message
717- my ($ts, $level, $n_lines, $msg) = $line =~ m/^([^,]+),([^,]+),([^,]+),(.+)/s;
718- if ( !$ts || !$level || !$n_lines || !$msg ) {
719- warn "$line\n";
720- next LINE;
721- }
722- if ( $n_lines > 1 ) {
723- $n_lines--; # first line
724- for ( 1..$n_lines ) {
725- $msg .= shift @$lines;
726- }
727- }
728-
729- push @log_entries, Percona::WebAPI::Resource::LogEntry->new(
730- pid => $self->pid,
731- entry_ts => $ts,
732- log_level => $level,
733- message => $msg,
734- ($self->service ? (service => $self->service) : ()),
735- ($self->data_ts ? (data_ts => $self->data_ts) : ()),
736- );
737- } # LINE
738-
739- if ( scalar @log_entries ) {
740- eval {
741- $client->post(
742- link => $log_link,
743- resources => \@log_entries,
744- );
745- };
746- if ( my $e = $EVAL_ERROR ) {
747- # Safegaurd: don't spam the agent log file with errors.
748- if ( ++$n_errors <= 10 ) {
749- warn "Error sending log entry to API: $e";
750- if ( $n_errors == 10 ) {
751- my $ts = ts(time, 1); # 1=UTC
752- warn "$ts WARNING $n_errors consecutive errors, no more "
753- . "error messages will be printed until log entries "
754- . "are sent successfully again.\n";
755- }
756- }
757- }
758- else {
759- @log_entries = ();
760- $n_errors = 0;
761- }
762- } # have log entries
763-
764- # Safeguard: don't use too much memory if we lose connection
765- # to the API for a long time.
766- my $n_log_entries = scalar @log_entries;
767- if ( $n_log_entries > 1_000 ) {
768- warn "$n_log_entries log entries in send buffer, "
769- . "removing first 100 to avoid excessive usage.\n";
770- @log_entries = @log_entries[100..($n_log_entries-1)];
771- }
772- } # QUEUE
773-
774- if ( scalar @log_entries ) {
775- my $ts = ts(time, 1); # 1=UTC
776- warn "$ts WARNING Failed to send these log entries "
777- . "(timestamps are UTC):\n";
778- foreach my $log ( @log_entries ) {
779- warn sprintf("%s %s %s\n",
780- $log->entry_ts,
781- level_name($log->log_level),
782- $log->message,
783- );
784- }
785- }
786-
787- exit 0;
788- } # child
789-
790- return;
791-}
792-
793-sub level_number {
794- my $name = shift;
795- die "No log level name given" unless $name;
796- my $number = $name eq 'DEBUG' ? 1
797- : $name eq 'INFO' ? 2
798- : $name eq 'WARNING' ? 3
799- : $name eq 'ERROR' ? 4
800- : $name eq 'FATAL' ? 5
801- : die "Invalid log level name: $name";
802-}
803-
804-sub level_name {
805- my $number = shift;
806- die "No log level name given" unless $number;
807- my $name = $number == 1 ? 'DEBUG'
808- : $number == 2 ? 'INFO'
809- : $number == 3 ? 'WARNING'
810- : $number == 4 ? 'ERROR'
811- : $number == 5 ? 'FATAL'
812- : die "Invalid log level number: $number";
813-}
814-
815-sub debug {
816- my $self = shift;
817- return if $self->online_logging;
818- return $self->_log(0, 'DEBUG', @_);
819-}
820-
821-sub info {
822- my $self = shift;
823- return $self->_log(1, 'INFO', @_);
824-}
825-
826-sub warning {
827- my $self = shift;
828- $self->_set_exit_status();
829- return $self->_log(1, 'WARNING', @_);
830-}
831-
832-sub error {
833- my $self = shift;
834- $self->_set_exit_status();
835- return $self->_log(1, 'ERROR', @_);
836-}
837-
838-sub fatal {
839- my $self = shift;
840- $self->_set_exit_status();
841- $self->_log(1, 'FATAL', @_);
842- exit $self->exit_status;
843-}
844-
845-sub _set_exit_status {
846- my $self = shift;
847- # exit_status is a scalar ref
848- my $exit_status = $self->exit_status; # get ref
849- $$exit_status |= 1; # deref to set
850- $self->exit_status($exit_status); # save back ref
851- return;
852-}
853-
854-sub _log {
855- my ($self, $online, $level, $msg) = @_;
856-
857- my $ts = ts(time, 1); # 1=UTC
858- my $level_number = level_number($level);
859-
860- return if $self->quiet && $level_number < $self->quiet;
861-
862- chomp($msg);
863- my $n_lines = 1;
864- $n_lines++ while $msg =~ m/\n/g;
865-
866- if ( $online && $self->online_logging_enabled ) {
867- while ( defined(my $log_entry = shift @{$self->_buffer}) ) {
868- $self->_queue_log_entry(@$log_entry);
869- }
870- $self->_queue_log_entry($ts, $level_number, $n_lines, $msg);
871- }
872- else {
873- if ( $online && $self->online_logging ) {
874- push @{$self->_buffer}, [$ts, $level_number, $n_lines, $msg];
875- }
876-
877- if ( $level_number >= 3 ) { # warning
878- print STDERR "$ts $level $msg\n";
879- }
880- else {
881- print STDOUT "$ts $level $msg\n";
882- }
883- }
884-
885- return;
886-}
887-
888-sub _queue_log_entry {
889- my ($self, $ts, $log_level, $n_lines, $msg) = @_;
890- print "$ts,$log_level,$n_lines,$msg\n";
891- return;
892-}
893-
894-sub _d {
895- my ($package, undef, $line) = caller 0;
896- @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
897- map { defined $_ ? $_ : 'undef' }
898- @_;
899- print STDERR "# $package:$line $PID ", join(' ', @_), "\n";
900-}
901-
902-no Lmo;
903-1;
904-# ###########################################################################
905-# End Percona::Agent::Logger package
906-# ###########################################################################
907
908=== removed directory 'lib/Percona/Test'
909=== removed directory 'lib/Percona/Test/Mock'
910=== removed file 'lib/Percona/Test/Mock/AgentLogger.pm'
911--- lib/Percona/Test/Mock/AgentLogger.pm 2013-06-17 00:28:18 +0000
912+++ lib/Percona/Test/Mock/AgentLogger.pm 1970-01-01 00:00:00 +0000
913@@ -1,129 +0,0 @@
914-# This program is copyright 2013 Percona Ireland Ltd.
915-# Feedback and improvements are welcome.
916-#
917-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
918-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
919-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
920-#
921-# This program is free software; you can redistribute it and/or modify it under
922-# the terms of the GNU General Public License as published by the Free Software
923-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
924-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
925-# licenses.
926-#
927-# You should have received a copy of the GNU General Public License along with
928-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
929-# Place, Suite 330, Boston, MA 02111-1307 USA.
930-# ###########################################################################
931-# Percona::Agent::Logger package
932-# ###########################################################################
933-package Percona::Test::Mock::AgentLogger;
934-
935-use strict;
936-use warnings FATAL => 'all';
937-use English qw(-no_match_vars);
938-
939-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
940-
941-sub new {
942- my ($class, %args) = @_;
943- my $self = {
944- log => $args{log},
945-
946- exit_status => $args{exit_status},
947- pid => $args{pid},
948- online_logging => $args{online_logging},
949-
950- service => undef,
951- data_ts => undef,
952- quiet => 0,
953-
954- };
955- return bless $self, $class;
956-}
957-
958-sub service {
959- my $self = shift;
960- my $_service = shift;
961- $self->{service} = $_service if $_service;
962- return $self->{service};
963-}
964-
965-sub data_ts {
966- my $self = shift;
967- my $_data_ts = shift;
968- $self->{data_ts} = $_data_ts if $_data_ts;
969- return $self->{data_ts};
970-}
971-
972-sub quiet {
973- my $self = shift;
974- my $_quiet = shift;
975- $self->{quiet} = $_quiet if $_quiet;
976- return $self->{quiet};
977-}
978-
979-sub start_online_logging {
980- my ($self, %args) = @_;
981- $self->_log('-', 'Called start_online_logging()');
982- return;
983-}
984-
985-sub level_number {
986- my $name = shift;
987- die "No log level name given" unless $name;
988- my $number = $name eq 'DEBUG' ? 1
989- : $name eq 'INFO' ? 2
990- : $name eq 'WARNING' ? 3
991- : $name eq 'ERROR' ? 4
992- : $name eq 'FATAL' ? 5
993- : die "Invalid log level name: $name";
994-}
995-
996-sub level_name {
997- my $number = shift;
998- die "No log level name given" unless $number;
999- my $name = $number == 1 ? 'DEBUG'
1000- : $number == 2 ? 'INFO'
1001- : $number == 3 ? 'WARNING'
1002- : $number == 4 ? 'ERROR'
1003- : $number == 5 ? 'FATAL'
1004- : die "Invalid log level number: $number";
1005-}
1006-
1007-sub debug {
1008- my $self = shift;
1009- return $self->_log('DEBUG', @_);
1010-}
1011-
1012-sub info {
1013- my $self = shift;
1014- return $self->_log('INFO', @_);
1015-}
1016-
1017-sub warning {
1018- my $self = shift;
1019- return $self->_log('WARNING', @_);
1020-}
1021-
1022-sub error {
1023- my $self = shift;
1024- return $self->_log('ERROR', @_);
1025-}
1026-
1027-sub fatal {
1028- my $self = shift;
1029- $self->_log('FATAL', @_);
1030- return 255;
1031-}
1032-
1033-sub _log {
1034- my ($self, $level, $msg) = @_;
1035- push @{$self->{log}}, "$level $msg";
1036- return;
1037-}
1038-
1039-1;
1040-# ###########################################################################
1041-# End Percona::Test::Mock::AgentLogger package
1042-# ###########################################################################
1043
1044=== removed file 'lib/Percona/Test/Mock/UserAgent.pm'
1045--- lib/Percona/Test/Mock/UserAgent.pm 2013-03-21 19:50:49 +0000
1046+++ lib/Percona/Test/Mock/UserAgent.pm 1970-01-01 00:00:00 +0000
1047@@ -1,71 +0,0 @@
1048-# This program is copyright 2012-2013 Percona Inc.
1049-# Feedback and improvements are welcome.
1050-#
1051-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1052-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1053-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1054-#
1055-# This program is free software; you can redistribute it and/or modify it under
1056-# the terms of the GNU General Public License as published by the Free Software
1057-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1058-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1059-# licenses.
1060-#
1061-# You should have received a copy of the GNU General Public License along with
1062-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1063-# Place, Suite 330, Boston, MA 02111-1307 USA.
1064-# ###########################################################################
1065-# Percona::Test::Mock::UserAgent package
1066-# ###########################################################################
1067-{
1068-package Percona::Test::Mock::UserAgent;
1069-
1070-sub new {
1071- my ($class, %args) = @_;
1072- my $self = {
1073- encode => $args{encode} || sub { return $_[0] },
1074- decode => $args{decode} || sub { return $_[0] },
1075- requests => [],
1076- request_objs => [],
1077- responses => {
1078- get => [],
1079- post => [],
1080- put => [],
1081- },
1082- content => {
1083- post => [],
1084- put => [],
1085- },
1086- };
1087- return bless $self, $class;
1088-}
1089-
1090-sub request {
1091- my ($self, $req) = @_;
1092- if ( scalar @{$self->{request_objs}} > 10 ) {
1093- $self->{request_objs} = [];
1094- }
1095- push @{$self->{request_objs}}, $req;
1096- my $type = lc($req->method);
1097- push @{$self->{requests}}, uc($type) . ' ' . $req->uri;
1098- if ( $type eq 'post' || $type eq 'put' ) {
1099- push @{$self->{content}->{$type}}, $req->content;
1100- }
1101- my $r = shift @{$self->{responses}->{$type}};
1102- my $c = $r->{content} ? $self->{encode}->($r->{content}) : '';
1103- my $h = HTTP::Headers->new;
1104- $h->header(%{$r->{headers}}) if exists $r->{headers};
1105- my $res = HTTP::Response->new(
1106- $r->{code} || 200,
1107- '',
1108- $h,
1109- $c,
1110- );
1111- return $res;
1112-}
1113-
1114-1;
1115-}
1116-# ###########################################################################
1117-# End Percona::Test::Mock::UserAgent package
1118-# ###########################################################################
1119
1120=== modified file 'lib/Percona/Toolkit.pm'
1121--- lib/Percona/Toolkit.pm 2014-02-20 03:47:43 +0000
1122+++ lib/Percona/Toolkit.pm 2014-05-30 01:02:37 +0000
1123@@ -18,7 +18,7 @@
1124 # ###########################################################################
1125 package Percona::Toolkit;
1126
1127-our $VERSION = '2.2.7';
1128+our $VERSION = '2.2.8';
1129
1130 use strict;
1131 use warnings FATAL => 'all';
1132
1133=== removed directory 'lib/Percona/WebAPI'
1134=== removed file 'lib/Percona/WebAPI/Client.pm'
1135--- lib/Percona/WebAPI/Client.pm 2013-09-19 04:05:48 +0000
1136+++ lib/Percona/WebAPI/Client.pm 1970-01-01 00:00:00 +0000
1137@@ -1,321 +0,0 @@
1138-# This program is copyright 2012 codenode LLC, 2012-2013 Percona Ireland Ltd.
1139-#
1140-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1141-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1142-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1143-#
1144-# This program is free software; you can redistribute it and/or modify it under
1145-# the terms of the GNU General Public License as published by the Free Software
1146-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1147-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1148-# licenses.
1149-#
1150-# You should have received a copy of the GNU General Public License along with
1151-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1152-# Place, Suite 330, Boston, MA 02111-1307 USA.
1153-# ###########################################################################
1154-# Percona::WebAPI::Client package
1155-# ###########################################################################
1156-{
1157-package Percona::WebAPI::Client;
1158-
1159-our $VERSION = '0.01';
1160-
1161-use strict;
1162-use warnings FATAL => 'all';
1163-use English qw(-no_match_vars);
1164-use constant PTDEBUG => $ENV{PTDEBUG} || 0;
1165-
1166-eval {
1167- require LWP;
1168- require JSON;
1169-};
1170-
1171-use Scalar::Util qw(blessed);
1172-
1173-use Lmo;
1174-use Percona::Toolkit;
1175-use Percona::WebAPI::Representation;
1176-use Percona::WebAPI::Exception::Request;
1177-use Percona::WebAPI::Exception::Resource;
1178-
1179-Percona::WebAPI::Representation->import(qw(as_json));
1180-Percona::Toolkit->import(qw(_d Dumper have_required_args));
1181-
1182-has 'api_key' => (
1183- is => 'ro',
1184- isa => 'Str',
1185- required => 1,
1186-);
1187-
1188-has 'entry_link' => (
1189- is => 'rw',
1190- isa => 'Str',
1191- required => 0,
1192- default => sub { return 'https://cloud-api.percona.com' },
1193-);
1194-
1195-has 'ua' => (
1196- is => 'rw',
1197- isa => 'Object',
1198- lazy => 1,
1199- required => 0,
1200- builder => '_build_ua',
1201-);
1202-
1203-has 'response' => (
1204- is => 'rw',
1205- isa => 'Object',
1206- required => 0,
1207- default => undef,
1208-);
1209-
1210-sub _build_ua {
1211- my $self = shift;
1212- my $ua = LWP::UserAgent->new;
1213- $ua->agent("Percona::WebAPI::Client/$Percona::WebAPI::Client::VERSION");
1214- $ua->default_header('Content-Type', 'application/json');
1215- $ua->default_header('X-Percona-API-Key', $self->api_key);
1216- return $ua;
1217-}
1218-
1219-sub get {
1220- my ($self, %args) = @_;
1221-
1222- have_required_args(\%args, qw(
1223- link
1224- )) or die;
1225- my ($link) = $args{link};
1226-
1227- # Get the resources at the link.
1228- eval {
1229- $self->_request(
1230- method => 'GET',
1231- link => $link,
1232- );
1233- };
1234- if ( my $e = $EVAL_ERROR ) {
1235- if (blessed($e) && $e->isa('Percona::WebAPI::Exception::Request')) {
1236- die $e;
1237- }
1238- else {
1239- die "Unknown error: $e";
1240- }
1241- }
1242-
1243- # The resource should be represented as JSON, decode it.
1244- my $resource = eval {
1245- JSON::decode_json($self->response->content);
1246- };
1247- if ( $EVAL_ERROR ) {
1248- warn sprintf "Error decoding resource: %s: %s",
1249- $self->response->content,
1250- $EVAL_ERROR;
1251- return;
1252- }
1253-
1254- # If the server tells us the resource's type, create a new object
1255- # of that type. Else, if there's no type, there's no resource, so
1256- # we should have received links. This usually only happens for the
1257- # entry link. The returned resource objects ref may be scalar or
1258- # an arrayref; the caller should know.
1259- my $resource_objects;
1260- if ( my $type = $self->response->headers->{'x-percona-resource-type'} ) {
1261- eval {
1262- $type = "Percona::WebAPI::Resource::$type";
1263- if ( ref $resource eq 'ARRAY' ) {
1264- PTDEBUG && _d('Got a list of', $type, 'resources');
1265- $resource_objects = [];
1266- foreach my $attribs ( @$resource ) {
1267- my $obj = $type->new(%$attribs);
1268- push @$resource_objects, $obj;
1269- }
1270- }
1271- else {
1272- PTDEBUG && _d('Got a', $type, 'resource', Dumper($resource));
1273- $resource_objects = $type->new(%$resource);
1274- }
1275- };
1276- if ( my $e = $EVAL_ERROR ) {
1277- die Percona::WebAPI::Exception::Resource->new(
1278- type => $type,
1279- link => $link,
1280- data => (ref $resource eq 'ARRAY' ? $resource : [ $resource ]),
1281- error => $e,
1282- );
1283- }
1284- }
1285- elsif ( exists $resource->{links} ) {
1286- # Lie to the caller: this isn't an object, but the caller can
1287- # treat it like one, e.g. my $links = $api->get(<entry links>);
1288- # then access $links->{self}. A Links object couldn't have
1289- # dynamic attribs anyway, so no use having a real Links obj.
1290- $resource_objects = $resource->{links};
1291- }
1292- elsif ( exists $resource->{pong} ) {
1293- PTDEBUG && _d("Ping pong!");
1294- }
1295- else {
1296- warn "Did not get X-Percona-Resource-Type or links from $link\n";
1297- }
1298-
1299- return $resource_objects;
1300-}
1301-
1302-# For a successful POST, the server sets the Location header with
1303-# the URI of the newly created resource.
1304-sub post {
1305- my $self = shift;
1306- $self->_set(
1307- @_,
1308- method => 'POST',
1309- );
1310- return $self->response->header('Location');
1311-}
1312-
1313-sub put {
1314- my $self = shift;
1315- $self->_set(
1316- @_,
1317- method => 'PUT',
1318- );
1319- return $self->response->header('Location');
1320-}
1321-
1322-sub delete {
1323- my ($self, %args) = @_;
1324- have_required_args(\%args, qw(
1325- link
1326- )) or die;
1327- my ($link) = $args{link};
1328-
1329- eval {
1330- $self->_request(
1331- method => 'DELETE',
1332- link => $link,
1333- headers => { 'Content-Length' => 0 },
1334- );
1335- };
1336- if ( my $e = $EVAL_ERROR ) {
1337- if (blessed($e) && $e->isa('Percona::WebAPI::Exception::Request')) {
1338- die $e;
1339- }
1340- else {
1341- die "Unknown error: $e";
1342- }
1343- }
1344-
1345- return;
1346-}
1347-
1348-# Low-level POST and PUT handler.
1349-sub _set {
1350- my ($self, %args) = @_;
1351- have_required_args(\%args, qw(
1352- method
1353- resources
1354- link
1355- )) or die;
1356- my $method = $args{method};
1357- my $res = $args{resources};
1358- my $link = $args{link};
1359-
1360- # Optional args
1361- my $headers = $args{headers};
1362-
1363- my $content = '';
1364- if ( ref($res) eq 'ARRAY' ) {
1365- PTDEBUG && _d('List of resources');
1366- $content = '[' . join(",\n", map { as_json($_) } @$res) . ']';
1367- }
1368- elsif ( ref($res) ) {
1369- PTDEBUG && _d('Resource object');
1370- $content = as_json($res);
1371- }
1372- elsif ( $res !~ m/\n/ && -f $res ) {
1373- PTDEBUG && _d('List of resources in file', $res);
1374- $content = '[';
1375- my $data = do {
1376- local $INPUT_RECORD_SEPARATOR = undef;
1377- open my $fh, '<', $res
1378- or die "Error opening $res: $OS_ERROR";
1379- <$fh>;
1380- };
1381- $data =~ s/,?\s*$/]/;
1382- $content .= $data;
1383- }
1384- else {
1385- PTDEBUG && _d('Resource text');
1386- $content = $res;
1387- }
1388-
1389- eval {
1390- $self->_request(
1391- method => $method,
1392- link => $link,
1393- content => $content,
1394- headers => $headers,
1395- );
1396- };
1397- if ( my $e = $EVAL_ERROR ) {
1398- if (blessed($e) && $e->isa('Percona::WebAPI::Exception::Request')) {
1399- die $e;
1400- }
1401- else {
1402- die "Unknown error: $e";
1403- }
1404- }
1405-
1406- return;
1407-}
1408-
1409-# Low-level HTTP request handler for all methods. Sets $self->response
1410-# from the request. Returns nothing on success (HTTP status 2xx-3xx),
1411-# else throws an Percona::WebAPI::Exception::Request.
1412-sub _request {
1413- my ($self, %args) = @_;
1414-
1415- have_required_args(\%args, qw(
1416- method
1417- link
1418- )) or die;
1419- my $method = $args{method};
1420- my $link = $args{link};
1421-
1422- # Optional args
1423- my $content = $args{content};
1424- my $headers = $args{headers};
1425-
1426- my $req = HTTP::Request->new($method => $link);
1427- if ( $content ) {
1428- $req->content($content);
1429- }
1430- if ( $headers ) {
1431- map { $req->header($_ => $headers->{$_}) } keys %$headers;
1432- }
1433- PTDEBUG && _d('Request', $method, $link, Dumper($req));
1434-
1435- my $response = $self->ua->request($req);
1436- PTDEBUG && _d('Response', Dumper($response));
1437-
1438- $self->response($response);
1439-
1440- if ( !($response->code >= 200 && $response->code < 400) ) {
1441- die Percona::WebAPI::Exception::Request->new(
1442- method => $method,
1443- url => $link,
1444- content => $content,
1445- status => $response->code,
1446- error => "Failed to $method $link",
1447- );
1448- }
1449-
1450- return;
1451-}
1452-
1453-no Lmo;
1454-1;
1455-}
1456-# ###########################################################################
1457-# End Percona::WebAPI::Client package
1458-# ###########################################################################
1459
1460=== removed directory 'lib/Percona/WebAPI/Exception'
1461=== removed file 'lib/Percona/WebAPI/Exception/Request.pm'
1462--- lib/Percona/WebAPI/Exception/Request.pm 2012-12-26 20:00:46 +0000
1463+++ lib/Percona/WebAPI/Exception/Request.pm 1970-01-01 00:00:00 +0000
1464@@ -1,69 +0,0 @@
1465-# This program is copyright 2012-2013 Percona Inc.
1466-# Feedback and improvements are welcome.
1467-#
1468-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1469-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1470-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1471-#
1472-# This program is free software; you can redistribute it and/or modify it under
1473-# the terms of the GNU General Public License as published by the Free Software
1474-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1475-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1476-# licenses.
1477-#
1478-# You should have received a copy of the GNU General Public License along with
1479-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1480-# Place, Suite 330, Boston, MA 02111-1307 USA.
1481-# ###########################################################################
1482-# Percona::WebAPI::Exception::Request package
1483-# ###########################################################################
1484-{
1485-package Percona::WebAPI::Exception::Request;
1486-
1487-use Lmo;
1488-use overload '""' => \&as_string;
1489-
1490-has 'method' => (
1491- is => 'ro',
1492- isa => 'Str',
1493- required => 1,
1494-);
1495-
1496-has 'url' => (
1497- is => 'ro',
1498- isa => 'Str',
1499- required => 1,
1500-);
1501-
1502-has 'content' => (
1503- is => 'ro',
1504- isa => 'Maybe[Str]',
1505- required => 0,
1506-);
1507-
1508-has 'status' => (
1509- is => 'ro',
1510- isa => 'Int',
1511- required => 1,
1512-);
1513-
1514-has 'error' => (
1515- is => 'ro',
1516- isa => 'Str',
1517- required => 1,
1518-);
1519-
1520-sub as_string {
1521- my $self = shift;
1522- chomp(my $error = $self->error);
1523- $error =~ s/\n/ /g;
1524- return sprintf "%s\nRequest: %s %s %s\nStatus: %d\n",
1525- $error, $self->method, $self->url, $self->content || '', $self->status;
1526-}
1527-
1528-no Lmo;
1529-1;
1530-}
1531-# ###########################################################################
1532-# End Percona::WebAPI::Exception::Request package
1533-# ###########################################################################
1534
1535=== removed file 'lib/Percona/WebAPI/Exception/Resource.pm'
1536--- lib/Percona/WebAPI/Exception/Resource.pm 2013-03-01 16:47:49 +0000
1537+++ lib/Percona/WebAPI/Exception/Resource.pm 1970-01-01 00:00:00 +0000
1538@@ -1,66 +0,0 @@
1539-# This program is copyright 2012-2013 Percona Inc.
1540-# Feedback and improvements are welcome.
1541-#
1542-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1543-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1544-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1545-#
1546-# This program is free software; you can redistribute it and/or modify it under
1547-# the terms of the GNU General Public License as published by the Free Software
1548-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1549-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1550-# licenses.
1551-#
1552-# You should have received a copy of the GNU General Public License along with
1553-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1554-# Place, Suite 330, Boston, MA 02111-1307 USA.
1555-# ###########################################################################
1556-# Percona::WebAPI::Exception::Resource package
1557-# ###########################################################################
1558-{
1559-package Percona::WebAPI::Exception::Resource;
1560-
1561-use Lmo;
1562-use overload '""' => \&as_string;
1563-use Data::Dumper;
1564-
1565-has 'type' => (
1566- is => 'ro',
1567- isa => 'Str',
1568- required => 1,
1569-);
1570-
1571-has 'link' => (
1572- is => 'ro',
1573- isa => 'Str',
1574- required => 1,
1575-);
1576-
1577-has 'data' => (
1578- is => 'ro',
1579- isa => 'ArrayRef',
1580- required => 1,
1581-);
1582-
1583-has 'error' => (
1584- is => 'ro',
1585- isa => 'Str',
1586- required => 1,
1587-);
1588-
1589-sub as_string {
1590- my $self = shift;
1591- chomp(my $error = $self->error);
1592- local $Data::Dumper::Indent = 1;
1593- local $Data::Dumper::Sortkeys = 1;
1594- local $Data::Dumper::Quotekeys = 0;
1595- return sprintf "Invalid %s resource from %s:\n\n%s\nError: %s\n\n",
1596- $self->type, $self->link, Dumper($self->data), $error;
1597-}
1598-
1599-no Lmo;
1600-1;
1601-}
1602-# ###########################################################################
1603-# End Percona::WebAPI::Exception::Resource package
1604-# ###########################################################################
1605
1606=== removed file 'lib/Percona/WebAPI/Representation.pm'
1607--- lib/Percona/WebAPI/Representation.pm 2013-06-15 19:31:38 +0000
1608+++ lib/Percona/WebAPI/Representation.pm 1970-01-01 00:00:00 +0000
1609@@ -1,86 +0,0 @@
1610-# This program is copyright 2012-2013 Percona Inc.
1611-# Feedback and improvements are welcome.
1612-#
1613-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1614-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1615-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1616-#
1617-# This program is free software; you can redistribute it and/or modify it under
1618-# the terms of the GNU General Public License as published by the Free Software
1619-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1620-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1621-# licenses.
1622-#
1623-# You should have received a copy of the GNU General Public License along with
1624-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1625-# Place, Suite 330, Boston, MA 02111-1307 USA.
1626-# ###########################################################################
1627-# Percona::WebAPI::Representation package
1628-# ###########################################################################
1629-{
1630-package Percona::WebAPI::Representation;
1631-
1632-eval {
1633- require JSON;
1634-};
1635-
1636-require Exporter;
1637-our @ISA = qw(Exporter);
1638-our @EXPORT_OK = qw(
1639- as_hashref
1640- as_json
1641- as_config
1642-);
1643-
1644-sub as_hashref {
1645- my ($resource, %args) = @_;
1646-
1647- # Copy the object into a new hashref.
1648- my $as_hashref = { %$resource };
1649-
1650- # Delete the links because they're just for client-side use
1651- # and the caller should be sending this object, not getting it.
1652- # But sometimes for testing we want to keep the links.
1653- if ( !defined $args{with_links} || !$args{with_links} ) {
1654- delete $as_hashref->{links};
1655- }
1656-
1657- return $as_hashref;
1658-}
1659-
1660-sub as_json {
1661- my ($resource, %args) = @_;
1662-
1663- my $json = $args{json} || JSON->new;
1664- $json->allow_blessed([]);
1665- $json->convert_blessed([]);
1666-
1667- my $text = $json->encode(
1668- ref $resource eq 'ARRAY' ? $resource : as_hashref($resource, %args)
1669- );
1670- if ( $args{json} && $text ) { # for testing
1671- chomp($text);
1672- $text .= "\n";
1673- }
1674- return $text;
1675-}
1676-
1677-sub as_config {
1678- my $resource = shift;
1679- if ( !$resource->isa('Percona::WebAPI::Resource::Config') ) {
1680- die "Only Config resources can be represented as config.\n";
1681- }
1682- my $as_hashref = as_hashref($resource);
1683- my $options = $as_hashref->{options};
1684- my $config = join("\n",
1685- map { defined $options->{$_} ? "$_=$options->{$_}" : "$_" }
1686- sort keys %$options
1687- ) . "\n";
1688- return $config;
1689-}
1690-
1691-1;
1692-}
1693-# ###########################################################################
1694-# End Percona::WebAPI::Representation package
1695-# ###########################################################################
1696
1697=== removed directory 'lib/Percona/WebAPI/Resource'
1698=== removed file 'lib/Percona/WebAPI/Resource/Agent.pm'
1699--- lib/Percona/WebAPI/Resource/Agent.pm 2013-06-15 02:59:14 +0000
1700+++ lib/Percona/WebAPI/Resource/Agent.pm 1970-01-01 00:00:00 +0000
1701@@ -1,77 +0,0 @@
1702-# This program is copyright 2012-2013 Percona Inc.
1703-# Feedback and improvements are welcome.
1704-#
1705-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1706-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1707-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1708-#
1709-# This program is free software; you can redistribute it and/or modify it under
1710-# the terms of the GNU General Public License as published by the Free Software
1711-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1712-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1713-# licenses.
1714-#
1715-# You should have received a copy of the GNU General Public License along with
1716-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1717-# Place, Suite 330, Boston, MA 02111-1307 USA.
1718-# ###########################################################################
1719-# Percona::WebAPI::Resource::Agent package
1720-# ###########################################################################
1721-{
1722-package Percona::WebAPI::Resource::Agent;
1723-
1724-use Lmo;
1725-
1726-has 'uuid' => (
1727- is => 'ro',
1728- isa => 'Str',
1729- required => 0,
1730-);
1731-
1732-has 'username' => (
1733- is => 'rw',
1734- isa => 'Str',
1735- required => 0,
1736- default => sub { return $ENV{USER} || $ENV{LOGNAME} },
1737-);
1738-
1739-has 'hostname' => (
1740- is => 'rw',
1741- isa => 'Str',
1742- required => 0,
1743- default => sub {
1744- chomp(my $hostname = `hostname`);
1745- return $hostname;
1746- },
1747-);
1748-
1749-has 'alias' => (
1750- is => 'rw',
1751- isa => 'Str',
1752- required => 0,
1753-);
1754-
1755-has 'versions' => (
1756- is => 'rw',
1757- isa => 'Maybe[HashRef]',
1758- required => 0,
1759-);
1760-
1761-has 'links' => (
1762- is => 'rw',
1763- isa => 'Maybe[HashRef]',
1764- required => 0,
1765- default => sub { return {} },
1766-);
1767-
1768-sub name {
1769- my ($self) = @_;
1770- return $self->alias || $self->hostname || $self->uuid || 'Unknown';
1771-}
1772-
1773-no Lmo;
1774-1;
1775-}
1776-# ###########################################################################
1777-# End Percona::WebAPI::Resource::Agent package
1778-# ###########################################################################
1779
1780=== removed file 'lib/Percona/WebAPI/Resource/Config.pm'
1781--- lib/Percona/WebAPI/Resource/Config.pm 2013-03-01 16:47:49 +0000
1782+++ lib/Percona/WebAPI/Resource/Config.pm 1970-01-01 00:00:00 +0000
1783@@ -1,55 +0,0 @@
1784-# This program is copyright 2012-2013 Percona Inc.
1785-# Feedback and improvements are welcome.
1786-#
1787-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1788-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1789-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1790-#
1791-# This program is free software; you can redistribute it and/or modify it under
1792-# the terms of the GNU General Public License as published by the Free Software
1793-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1794-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1795-# licenses.
1796-#
1797-# You should have received a copy of the GNU General Public License along with
1798-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1799-# Place, Suite 330, Boston, MA 02111-1307 USA.
1800-# ###########################################################################
1801-# Percona::WebAPI::Resource::Config package
1802-# ###########################################################################
1803-{
1804-package Percona::WebAPI::Resource::Config;
1805-
1806-use Lmo;
1807-
1808-has 'ts' => (
1809- is => 'ro',
1810- isa => 'Int',
1811- required => 1,
1812-);
1813-
1814-has 'name' => (
1815- is => 'ro',
1816- isa => 'Str',
1817- required => 1,
1818-);
1819-
1820-has 'options' => (
1821- is => 'ro',
1822- isa => 'HashRef',
1823- required => 1,
1824-);
1825-
1826-has 'links' => (
1827- is => 'rw',
1828- isa => 'Maybe[HashRef]',
1829- required => 0,
1830- default => sub { return {} },
1831-);
1832-
1833-no Lmo;
1834-1;
1835-}
1836-# ###########################################################################
1837-# End Percona::WebAPI::Resource::Config package
1838-# ###########################################################################
1839
1840=== removed file 'lib/Percona/WebAPI/Resource/LogEntry.pm'
1841--- lib/Percona/WebAPI/Resource/LogEntry.pm 2013-06-10 00:15:16 +0000
1842+++ lib/Percona/WebAPI/Resource/LogEntry.pm 1970-01-01 00:00:00 +0000
1843@@ -1,66 +0,0 @@
1844-# This program is copyright 2013 Percona Inc.
1845-# Feedback and improvements are welcome.
1846-#
1847-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1848-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1849-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1850-#
1851-# This program is free software; you can redistribute it and/or modify it under
1852-# the terms of the GNU General Public License as published by the Free Software
1853-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1854-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1855-# licenses.
1856-#
1857-# You should have received a copy of the GNU General Public License along with
1858-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1859-# Place, Suite 330, Boston, MA 02111-1307 USA.
1860-# ###########################################################################
1861-# Percona::WebAPI::Resource::LogEntry package
1862-# ###########################################################################
1863-{
1864-package Percona::WebAPI::Resource::LogEntry;
1865-
1866-use Lmo;
1867-
1868-has 'pid' => (
1869- is => 'ro',
1870- isa => 'Int',
1871- required => 1,
1872-);
1873-
1874-has 'service' => (
1875- is => 'ro',
1876- isa => 'Str',
1877- required => 0,
1878-);
1879-
1880-has 'data_ts' => (
1881- is => 'ro',
1882- isa => 'Int',
1883- required => 0,
1884-);
1885-
1886-has 'entry_ts' => (
1887- is => 'ro',
1888- isa => 'Str',
1889- required => 1,
1890-);
1891-
1892-has 'log_level' => (
1893- is => 'ro',
1894- isa => 'Int',
1895- required => 1,
1896-);
1897-
1898-has 'message' => (
1899- is => 'ro',
1900- isa => 'Str',
1901- required => 1,
1902-);
1903-
1904-no Lmo;
1905-1;
1906-}
1907-# ###########################################################################
1908-# End Percona::WebAPI::Resource::LogEntry package
1909-# ###########################################################################
1910
1911=== removed file 'lib/Percona/WebAPI/Resource/Service.pm'
1912--- lib/Percona/WebAPI/Resource/Service.pm 2013-04-19 20:49:01 +0000
1913+++ lib/Percona/WebAPI/Resource/Service.pm 1970-01-01 00:00:00 +0000
1914@@ -1,94 +0,0 @@
1915-# This program is copyright 2012-2013 Percona Inc.
1916-# Feedback and improvements are welcome.
1917-#
1918-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1919-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1920-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1921-#
1922-# This program is free software; you can redistribute it and/or modify it under
1923-# the terms of the GNU General Public License as published by the Free Software
1924-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1925-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1926-# licenses.
1927-#
1928-# You should have received a copy of the GNU General Public License along with
1929-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1930-# Place, Suite 330, Boston, MA 02111-1307 USA.
1931-# ###########################################################################
1932-# Percona::WebAPI::Resource::Service package
1933-# ###########################################################################
1934-{
1935-package Percona::WebAPI::Resource::Service;
1936-
1937-use Lmo;
1938-
1939-has 'ts' => (
1940- is => 'ro',
1941- isa => 'Int',
1942- required => 1,
1943-);
1944-
1945-has 'name' => (
1946- is => 'ro',
1947- isa => 'Str',
1948- required => 1,
1949-);
1950-
1951-has 'tasks' => (
1952- is => 'ro',
1953- isa => 'ArrayRef[Percona::WebAPI::Resource::Task]',
1954- required => 1,
1955-);
1956-
1957-has 'run_schedule' => (
1958- is => 'ro',
1959- isa => 'Str',
1960- required => 0,
1961-);
1962-
1963-has 'spool_schedule' => (
1964- is => 'ro',
1965- isa => 'Str',
1966- required => 0,
1967-);
1968-
1969-has 'meta' => (
1970- is => 'ro',
1971- isa => 'Bool',
1972- required => 0,
1973- default => sub { return 0 },
1974-);
1975-
1976-has 'run_once' => (
1977- is => 'ro',
1978- isa => 'Bool',
1979- required => 0,
1980- default => sub { return 0 },
1981-);
1982-
1983-has 'links' => (
1984- is => 'rw',
1985- isa => 'Maybe[HashRef]',
1986- required => 0,
1987- default => sub { return {} },
1988-);
1989-
1990-sub BUILDARGS {
1991- my ($class, %args) = @_;
1992- if ( ref $args{tasks} eq 'ARRAY' ) {
1993- my @tasks;
1994- foreach my $run_hashref ( @{$args{tasks}} ) {
1995- my $task = Percona::WebAPI::Resource::Task->new(%$run_hashref);
1996- push @tasks, $task;
1997- }
1998- $args{tasks} = \@tasks;
1999- }
2000- return $class->SUPER::BUILDARGS(%args);
2001-}
2002-
2003-no Lmo;
2004-1;
2005-}
2006-# ###########################################################################
2007-# End Percona::WebAPI::Resource::Service package
2008-# ###########################################################################
2009
2010=== removed file 'lib/Percona/WebAPI/Resource/Task.pm'
2011--- lib/Percona/WebAPI/Resource/Task.pm 2013-04-19 20:49:01 +0000
2012+++ lib/Percona/WebAPI/Resource/Task.pm 1970-01-01 00:00:00 +0000
2013@@ -1,62 +0,0 @@
2014-# This program is copyright 2012-2013 Percona Inc.
2015-# Feedback and improvements are welcome.
2016-#
2017-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
2018-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
2019-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2020-#
2021-# This program is free software; you can redistribute it and/or modify it under
2022-# the terms of the GNU General Public License as published by the Free Software
2023-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
2024-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
2025-# licenses.
2026-#
2027-# You should have received a copy of the GNU General Public License along with
2028-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
2029-# Place, Suite 330, Boston, MA 02111-1307 USA.
2030-# ###########################################################################
2031-# Percona::WebAPI::Resource::Task package
2032-# ###########################################################################
2033-{
2034-package Percona::WebAPI::Resource::Task;
2035-
2036-use Lmo;
2037-
2038-has 'name' => (
2039- is => 'ro',
2040- isa => 'Str',
2041- required => 1,
2042-);
2043-
2044-has 'number' => (
2045- is => 'ro',
2046- isa => 'Int',
2047- required => 1,
2048-);
2049-
2050-has 'program' => (
2051- is => 'ro',
2052- isa => 'Maybe[Str]',
2053- required => 0,
2054-);
2055-
2056-has 'query' => (
2057- is => 'ro',
2058- isa => 'Maybe[Str]',
2059- required => 0,
2060-);
2061-
2062-has 'output' => (
2063- is => 'ro',
2064- isa => 'Maybe[Str]',
2065- required => 0,
2066-);
2067-
2068-sub TO_JSON { return { %{ shift() } }; }
2069-
2070-no Lmo;
2071-1;
2072-}
2073-# ###########################################################################
2074-# End Percona::WebAPI::Resource::Task package
2075-# ###########################################################################
2076
2077=== removed directory 't/lib/Percona/WebAPI'
2078=== removed file 't/lib/Percona/WebAPI/Client.t'
2079--- t/lib/Percona/WebAPI/Client.t 2013-08-08 19:34:29 +0000
2080+++ t/lib/Percona/WebAPI/Client.t 1970-01-01 00:00:00 +0000
2081@@ -1,236 +0,0 @@
2082-#!/usr/bin/env perl
2083-
2084-BEGIN {
2085- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
2086- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
2087- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
2088-};
2089-
2090-use strict;
2091-use warnings FATAL => 'all';
2092-use English qw(-no_match_vars);
2093-use Test::More;
2094-use JSON;
2095-use File::Temp qw(tempdir);
2096-
2097-use Percona::Test;
2098-use Percona::Test::Mock::UserAgent;
2099-use Percona::WebAPI::Client;
2100-use Percona::WebAPI::Resource::Agent;
2101-use Percona::WebAPI::Resource::Config;
2102-use Percona::WebAPI::Resource::Service;
2103-use Percona::WebAPI::Resource::Task;
2104-
2105-Percona::Toolkit->import(qw(Dumper have_required_args));
2106-Percona::WebAPI::Representation->import(qw(as_json as_hashref));
2107-
2108-# #############################################################################
2109-# Create a client with a mock user-agent.
2110-# #############################################################################
2111-
2112-my $json = JSON->new;
2113-$json->allow_blessed([]);
2114-$json->convert_blessed([]);
2115-
2116-my $ua = Percona::Test::Mock::UserAgent->new(
2117- encode => sub { my $c = shift; return $json->encode($c || {}) },
2118-);
2119-
2120-my $client = eval {
2121- Percona::WebAPI::Client->new(
2122- api_key => '123',
2123- ua => $ua,
2124- );
2125-};
2126-
2127-is(
2128- $EVAL_ERROR,
2129- '',
2130- 'Create client'
2131-) or die;
2132-
2133-# #############################################################################
2134-# First thing a client should do is get the entry links.
2135-# #############################################################################
2136-
2137-my $return_links = { # what the server returns
2138- agents => '/agents',
2139-};
2140-
2141-$ua->{responses}->{get} = [
2142- {
2143- content => {
2144- links => $return_links,
2145- }
2146- },
2147-];
2148-
2149-my $links = $client->get(link => $client->entry_link);
2150-
2151-is_deeply(
2152- $links,
2153- $return_links,
2154- "Get entry links"
2155-) or diag(Dumper($links));
2156-
2157-is_deeply(
2158- $ua->{requests},
2159- [
2160- 'GET https://cloud-api.percona.com',
2161- ],
2162- "1 request, 1 GET"
2163-) or diag(Dumper($ua->{requests}));
2164-
2165-
2166-# #############################################################################
2167-# Second, a new client will POST an Agent for itself. The entry links
2168-# should have an "agents" link. The server response is empty but the
2169-# URI for the new Agent resource is given by the Location header.
2170-# #############################################################################
2171-
2172-my $agent = Percona::WebAPI::Resource::Agent->new(
2173- id => '123',
2174- hostname => 'host',
2175-);
2176-
2177-$ua->{responses}->{post} = [
2178- {
2179- headers => { 'Location' => 'agents/5' },
2180- content => '',
2181- },
2182-];
2183-
2184-my $uri = $client->post(resources => $agent, link => $links->{agents});
2185-
2186-is(
2187- $uri,
2188- "agents/5",
2189- "POST Agent, got Location URI"
2190-);
2191-
2192-# #############################################################################
2193-# After successfully creating the new Agent, the client should fetch
2194-# the new Agent resoruce which will have links to the next step: the
2195-# agent's config.
2196-# #############################################################################
2197-
2198-$return_links = {
2199- self => 'agents/5',
2200- config => 'agents/5/config',
2201-};
2202-
2203-my $content = {
2204- %{ as_hashref($agent) },
2205- links => $return_links,
2206-};
2207-
2208-$ua->{responses}->{get} = [
2209- {
2210- headers => { 'X-Percona-Resource-Type' => 'Agent' },
2211- content => $content,
2212- },
2213-];
2214-
2215-# Re-using $agent, i.e. updating it with the actual, newly created
2216-# Agent resource as returned by the server with links.
2217-$agent = $client->get(link => $uri);
2218-
2219-# Need to use with_links=>1 here because by as_hashref() removes
2220-# links by default because it's usually used to encode and send
2221-# resources, and clients never send links; but here we're using
2222-# it for testing.
2223-is_deeply(
2224- as_hashref($agent, with_links => 1),
2225- $content,
2226- "GET Agent with links"
2227-) or diag(Dumper(as_hashref($agent, with_links => 1)));
2228-
2229-# #############################################################################
2230-# Now the agent can get its Config.
2231-# #############################################################################
2232-
2233-$return_links = {
2234- self => 'agents/5/config',
2235- services => 'agents/5/services',
2236-};
2237-
2238-my $return_config = Percona::WebAPI::Resource::Config->new(
2239- ts => '100',
2240- name => 'Default',
2241- options => {},
2242- links => $return_links,
2243-);
2244-
2245-$ua->{responses}->{get} = [
2246- {
2247- headers => { 'X-Percona-Resource-Type' => 'Config' },
2248- content => as_hashref($return_config, with_links => 1),
2249- },
2250-];
2251-
2252-my $config = $client->get(link => $agent->links->{config});
2253-
2254-is_deeply(
2255- as_hashref($config, with_links => 1),
2256- as_hashref($return_config, with_links => 1),
2257- "GET Config"
2258-) or diag(Dumper(as_hashref($config, with_links => 1)));
2259-
2260-# #############################################################################
2261-# Once an agent is configured, i.e. successfully gets a Config resource,
2262-# its Config should have a services link which returns a list of Service
2263-# resources, each with their own links.
2264-# #############################################################################
2265-
2266-$return_links = {
2267- 'send_data' => '/query-monitor',
2268-};
2269-
2270-my $run0 = Percona::WebAPI::Resource::Task->new(
2271- name => 'run-pqd',
2272- number => '0',
2273- program => 'pt-query-digest',
2274- options => '--output json',
2275- output => 'spool',
2276-);
2277-
2278-my $svc0 = Percona::WebAPI::Resource::Service->new(
2279- ts => '123',
2280- name => 'query-monitor',
2281- run_schedule => '1 * * * *',
2282- spool_schedule => '2 * * * *',
2283- tasks => [ $run0 ],
2284- links => $return_links,
2285-);
2286-
2287-$ua->{responses}->{get} = [
2288- {
2289- headers => { 'X-Percona-Resource-Type' => 'Service' },
2290- content => [ as_hashref($svc0, with_links => 1) ],
2291- },
2292-];
2293-
2294-my $services = $client->get(link => $config->links->{services});
2295-
2296-is(
2297- scalar @$services,
2298- 1,
2299- "Got 1 service"
2300-);
2301-
2302-is_deeply(
2303- as_hashref($services->[0], with_links => 1),
2304- as_hashref($svc0, with_links => 1),
2305- "GET Services"
2306-) or diag(Dumper(as_hashref($services, with_links => 1)));
2307-
2308-is(
2309- $services->[0]->links->{send_data},
2310- "/query-monitor",
2311- "send_data link for Service"
2312-);
2313-
2314-# #############################################################################
2315-# Done.
2316-# #############################################################################
2317-done_testing;
2318
2319=== removed file 't/lib/Percona/WebAPI/Representation.t'
2320--- t/lib/Percona/WebAPI/Representation.t 2013-03-01 16:47:49 +0000
2321+++ t/lib/Percona/WebAPI/Representation.t 1970-01-01 00:00:00 +0000
2322@@ -1,51 +0,0 @@
2323-#!/usr/bin/perl
2324-
2325-BEGIN {
2326- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
2327- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
2328- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
2329-};
2330-
2331-use strict;
2332-use warnings FATAL => 'all';
2333-use English qw(-no_match_vars);
2334-use Test::More;
2335-
2336-use PerconaTest;
2337-use Percona::Toolkit;
2338-use Percona::WebAPI::Resource::Agent;
2339-use Percona::WebAPI::Resource::Config;
2340-use Percona::WebAPI::Representation;
2341-
2342-my $agent = Percona::WebAPI::Resource::Agent->new(
2343- id => '123',
2344- hostname => 'pt',
2345- versions => {
2346- Perl => '5.10.1',
2347- },
2348-);
2349-
2350-is(
2351- Percona::WebAPI::Representation::as_json($agent),
2352- q/{"versions":{"Perl":"5.10.1"},"id":"123","hostname":"pt"}/,
2353- "as_json"
2354-);
2355-
2356-my $config = Percona::WebAPI::Resource::Config->new(
2357- ts => '100',
2358- name => 'Default',
2359- options => {
2360- 'check-interval' => 60,
2361- },
2362-);
2363-
2364-is(
2365- Percona::WebAPI::Representation::as_config($config),
2366- "check-interval=60\n",
2367- "as_config"
2368-);
2369-
2370-# #############################################################################
2371-# Done.
2372-# #############################################################################
2373-done_testing;
2374
2375=== removed directory 't/pt-agent'
2376=== removed file 't/pt-agent/basics.t'
2377--- t/pt-agent/basics.t 2013-04-13 17:27:45 +0000
2378+++ t/pt-agent/basics.t 1970-01-01 00:00:00 +0000
2379@@ -1,101 +0,0 @@
2380-#!/usr/bin/env perl
2381-
2382-BEGIN {
2383- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
2384- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
2385- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
2386-};
2387-
2388-use strict;
2389-use warnings FATAL => 'all';
2390-use English qw(-no_match_vars);
2391-use Test::More;
2392-
2393-use File::Temp qw(tempdir);
2394-
2395-use Percona::Test;
2396-use Sandbox;
2397-use Percona::Test::Mock::UserAgent;
2398-require "$trunk/bin/pt-agent";
2399-
2400-my $dp = new DSNParser(opts=>$dsn_opts);
2401-my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
2402-my $dbh = $sb->get_dbh_for('master');
2403-my $dsn = $sb->dsn_for('master');
2404-my $o = new OptionParser();
2405-$o->get_specs("$trunk/bin/pt-agent");
2406-$o->get_opts();
2407-my $cxn = Cxn->new(
2408- dsn_string => $dsn,
2409- OptionParser => $o,
2410- DSNParser => $dp,
2411-);
2412-
2413-Percona::Toolkit->import(qw(Dumper));
2414-Percona::WebAPI::Representation->import(qw(as_hashref));
2415-
2416-# Running the agent is going to cause it to schedule the services,
2417-# i.e. write a real crontab. The test box/user shouldn't have a
2418-# crontab, so we'll warn and clobber it if there is one.
2419-my $crontab = `crontab -l 2>/dev/null`;
2420-if ( $crontab ) {
2421- warn "Removing crontab: $crontab\n";
2422- `crontab -r`;
2423-}
2424-
2425-my $tmp_lib = "/tmp/pt-agent";
2426-my $tmp_log = "/tmp/pt-agent.log";
2427-my $tmp_pid = "/tmp/pt-agent.pid";
2428-
2429-diag(`rm -rf $tmp_lib`) if -d $tmp_lib;
2430-unlink $tmp_log if -f $tmp_log;
2431-unlink $tmp_pid if -f $tmp_pid;
2432-
2433-my $config_file = pt_agent::get_config_file();
2434-unlink $config_file if -f $config_file;
2435-
2436-my $output;
2437-
2438-{
2439- no strict;
2440- no warnings;
2441- local *pt_agent::start_agent = sub {
2442- print "start_agent\n";
2443- return {
2444- agent => 0,
2445- client => 0,
2446- daemon => 0,
2447- };
2448- };
2449- local *pt_agent::run_agent = sub {
2450- print "run_agent\n";
2451- };
2452-
2453- $output = output(
2454- sub {
2455- pt_agent::main(
2456- qw(--api-key 123)
2457- );
2458- },
2459- stderr => 1,
2460- );
2461-}
2462-
2463-like(
2464- $output,
2465- qr/start_agent\nrun_agent\n/,
2466- "Starts and runs without a config file"
2467-);
2468-
2469-# #############################################################################
2470-# Done.
2471-# #############################################################################
2472-
2473-`crontab -r 2>/dev/null`;
2474-
2475-if ( -f $config_file ) {
2476- unlink $config_file
2477- or warn "Error removing $config_file: $OS_ERROR";
2478-}
2479-
2480-done_testing;
2481
2482=== removed file 't/pt-agent/get_services.t'
2483--- t/pt-agent/get_services.t 2013-06-17 04:01:30 +0000
2484+++ t/pt-agent/get_services.t 1970-01-01 00:00:00 +0000
2485@@ -1,423 +0,0 @@
2486-#!/usr/bin/env perl
2487-
2488-BEGIN {
2489- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
2490- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
2491- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
2492-};
2493-
2494-use strict;
2495-use warnings FATAL => 'all';
2496-use English qw(-no_match_vars);
2497-use Test::More;
2498-
2499-use JSON;
2500-use File::Temp qw(tempdir);
2501-
2502-use Percona::Test;
2503-use Percona::Test::Mock::UserAgent;
2504-use Percona::Test::Mock::AgentLogger;
2505-require "$trunk/bin/pt-agent";
2506-
2507-Percona::Toolkit->import(qw(Dumper));
2508-Percona::WebAPI::Representation->import(qw(as_hashref));
2509-
2510-my @log;
2511-my $logger = Percona::Test::Mock::AgentLogger->new(log => \@log);
2512-pt_agent::_logger($logger);
2513-
2514-# Fake --lib and --spool dirs.
2515-my $tmpdir = tempdir("/tmp/pt-agent.$PID.XXXXXX", CLEANUP => 1);
2516-output( sub {
2517- pt_agent::init_lib_dir(lib_dir => $tmpdir);
2518-});
2519-
2520-# #############################################################################
2521-# Create mock client and Agent
2522-# #############################################################################
2523-
2524-# These aren't the real tests yet: to run_agent, first we need
2525-# a client and Agent, so create mock ones.
2526-
2527-my $output;
2528-my $json = JSON->new->canonical([1])->pretty;
2529-$json->allow_blessed([]);
2530-$json->convert_blessed([]);
2531-
2532-my $ua = Percona::Test::Mock::UserAgent->new(
2533- encode => sub { my $c = shift; return $json->encode($c || {}) },
2534-);
2535-
2536-my $client = eval {
2537- Percona::WebAPI::Client->new(
2538- api_key => '123',
2539- ua => $ua,
2540- );
2541-};
2542-
2543-is(
2544- $EVAL_ERROR,
2545- '',
2546- 'Create mock client'
2547-) or die;
2548-
2549-my $agent = Percona::WebAPI::Resource::Agent->new(
2550- uuid => '123',
2551- hostname => 'host',
2552- username => 'user',
2553- links => {
2554- self => '/agents/123',
2555- config => '/agents/123/config',
2556- },
2557-);
2558-
2559-my @cmds;
2560-my $exec_cmd = sub {
2561- my $cmd = shift;
2562- push @cmds, $cmd;
2563- return 0;
2564-};
2565-
2566-# #############################################################################
2567-# Test get_services()
2568-# #############################################################################
2569-
2570-# query-history
2571-
2572-my $run0 = Percona::WebAPI::Resource::Task->new(
2573- name => 'query-history',
2574- number => '0',
2575- program => 'pt-query-digest --output json',
2576- output => 'spool',
2577-);
2578-
2579-my $qh = Percona::WebAPI::Resource::Service->new(
2580- ts => '100',
2581- name => 'query-history',
2582- run_schedule => '1 * * * *',
2583- spool_schedule => '2 * * * *',
2584- tasks => [ $run0 ],
2585- links => {
2586- self => '/query-history',
2587- data => '/query-history/data',
2588- },
2589-);
2590-
2591-my $run1 = Percona::WebAPI::Resource::Task->new(
2592- name => 'start-query-history',
2593- number => '0',
2594- program => 'echo "start-qh"',
2595- output => 'spool',
2596-);
2597-
2598-my $start_qh = Percona::WebAPI::Resource::Service->new(
2599- ts => '100',
2600- name => 'start-query-history',
2601- meta => 1,
2602- tasks => [ $run1 ],
2603- links => {
2604- self => '/query-history',
2605- data => '/query-history/data',
2606- },
2607-);
2608-
2609-$ua->{responses}->{get} = [
2610- {
2611- headers => { 'X-Percona-Resource-Type' => 'Service' },
2612- content => [
2613- as_hashref($qh, with_links => 1),
2614- as_hashref($start_qh, with_links => 1),
2615- ],
2616- },
2617-];
2618-
2619-my $services = {};
2620-my $success = 0;
2621-
2622-$output = output(
2623- sub {
2624- ($services, $success) = pt_agent::get_services(
2625- # Required args
2626- link => '/agents/123/services',
2627- agent => $agent,
2628- client => $client,
2629- lib_dir => $tmpdir,
2630- services => $services,
2631- # Optional args, for testing
2632- json => $json,
2633- bin_dir => "$trunk/bin/",
2634- exec_cmd => $exec_cmd,
2635- );
2636- },
2637- stderr => 1,
2638-);
2639-
2640-is(
2641- $success,
2642- 1,
2643- "Success"
2644-);
2645-
2646-is(
2647- ref $services,
2648- 'HASH',
2649- "Return services as hashref"
2650-) or diag(Dumper($services));
2651-
2652-is(
2653- scalar keys %$services,
2654- 2,
2655- 'Only 2 services'
2656-) or diag(Dumper($services));
2657-
2658-ok(
2659- exists $services->{'query-history'},
2660- "services hashref keyed on service name"
2661-) or diag(Dumper($services));
2662-
2663-isa_ok(
2664- ref $services->{'query-history'},
2665- 'Percona::WebAPI::Resource::Service',
2666- 'services->{query-history}'
2667-);
2668-
2669-my $crontab = -f "$tmpdir/crontab" ? slurp_file("$tmpdir/crontab") : '';
2670-is(
2671- $crontab,
2672- "1 * * * * $trunk/bin/pt-agent --run-service query-history
2673-2 * * * * $trunk/bin/pt-agent --send-data query-history
2674-",
2675- "crontab file"
2676-) or diag($output, `ls -l $tmpdir/*`, Dumper(\@log));
2677-
2678-is_deeply(
2679- \@cmds,
2680- [
2681- "$trunk/bin/pt-agent --run-service start-query-history >> $tmpdir/logs/start-stop.log 2>&1",
2682- "crontab $tmpdir/crontab > $tmpdir/crontab.err 2>&1",
2683- ],
2684- "Ran start-service and crontab"
2685-) or diag(Dumper(\@cmds), Dumper(\@log));
2686-
2687-ok(
2688- -f "$tmpdir/services/query-history",
2689- "Wrote --lib/services/query-history"
2690-);
2691-
2692-# #############################################################################
2693-# A more realistic transaction
2694-# #############################################################################
2695-
2696-# services/query-history should exist from the previous tests. For these
2697-# tests, get_services() should update the file, so we empty it and check
2698-# that it's re-created, i.e. updated.
2699-diag(`echo -n > $tmpdir/services/query-history`);
2700-is(
2701- -s "$tmpdir/services/query-history",
2702- 0,
2703- "Start: empty --lib/services/query-history"
2704-);
2705-
2706-# start-query-history
2707-
2708-my $task1 = Percona::WebAPI::Resource::Task->new(
2709- name => 'disable-slow-query-log',
2710- number => '0',
2711- query => "SET GLOBAL slow_query_log=0",
2712-);
2713-
2714-my $task2 = Percona::WebAPI::Resource::Task->new(
2715- name => 'set-slow-query-log-file',
2716- number => '1',
2717- query => "SET GLOBAL slow_query_log_file='/tmp/slow.log'",
2718-);
2719-
2720-my $task3 = Percona::WebAPI::Resource::Task->new(
2721- name => 'set-long-query-time',
2722- number => '2',
2723- query => "SET GLOBAL long_query_time=0.01",
2724-);
2725-
2726-my $task4 = Percona::WebAPI::Resource::Task->new(
2727- name => 'enable-slow-query-log',
2728- number => '3',
2729- query => "SET GLOBAL slow_query_log=1",
2730-);
2731-
2732-$start_qh = Percona::WebAPI::Resource::Service->new(
2733- ts => '100',
2734- name => 'start-query-history',
2735- tasks => [ $task1, $task2, $task3, $task4 ],
2736- meta => 1,
2737- links => {
2738- self => '/query-history',
2739- data => '/query-history/data',
2740- },
2741-);
2742-
2743-# stop-query-history
2744-
2745-my $task5 = Percona::WebAPI::Resource::Task->new(
2746- name => 'disable-slow-query-log',
2747- number => '0',
2748- query => "SET GLOBAL slow_query_log=0",
2749-);
2750-
2751-my $stop_qh = Percona::WebAPI::Resource::Service->new(
2752- ts => '100',
2753- name => 'stop-query-history',
2754- tasks => [ $task5 ],
2755- meta => 1,
2756- links => {
2757- self => '/query-history',
2758- data => '/query-history/data',
2759- },
2760-);
2761-
2762-# We'll use query-history from the previous tests.
2763-
2764-$ua->{responses}->{get} = [
2765- {
2766- headers => { 'X-Percona-Resource-Type' => 'Service' },
2767- content => [
2768- as_hashref($start_qh, with_links => 1),
2769- as_hashref($stop_qh, with_links => 1),
2770- as_hashref($qh, with_links => 1), # from previous tests
2771- ],
2772- },
2773-];
2774-
2775-@log = ();
2776-@cmds = ();
2777-$services = {};
2778-$success = 0;
2779-
2780-$output = output(
2781- sub {
2782- ($services, $success) = pt_agent::get_services(
2783- # Required args
2784- link => '/agents/123/services',
2785- agent => $agent,
2786- client => $client,
2787- lib_dir => $tmpdir,
2788- services => $services,
2789- # Optional args, for testing
2790- json => $json,
2791- bin_dir => "$trunk/bin/",
2792- exec_cmd => $exec_cmd,
2793- );
2794- },
2795- stderr => 1,
2796-);
2797-
2798-is_deeply(
2799- \@cmds,
2800- [
2801- "$trunk/bin/pt-agent --run-service start-query-history >> $tmpdir/logs/start-stop.log 2>&1",
2802- "crontab $tmpdir/crontab > $tmpdir/crontab.err 2>&1",
2803- ],
2804- "Start: ran start-query-history"
2805-) or diag(Dumper(\@cmds), $output);
2806-
2807-ok(
2808- -f "$tmpdir/services/start-query-history",
2809- "Start: added --lib/services/start-query-history"
2810-) or diag($output);
2811-
2812-ok(
2813- -f "$tmpdir/services/stop-query-history",
2814- "Start: added --lib/services/stop-query-history"
2815-) or diag($output);
2816-
2817-my $contents = slurp_file("$tmpdir/services/query-history");
2818-like(
2819- $contents,
2820- qr/query-history/,
2821- "Start: updated --lib/services/query-history"
2822-) or diag($output);
2823-
2824-$crontab = slurp_file("$tmpdir/crontab");
2825-is(
2826- $crontab,
2827- "1 * * * * $trunk/bin/pt-agent --run-service query-history
2828-2 * * * * $trunk/bin/pt-agent --send-data query-history
2829-",
2830- "Start: only scheduled query-history"
2831-) or diag($output);
2832-
2833-# #############################################################################
2834-# Update and restart a service
2835-# #############################################################################
2836-
2837-# pt-agent should remove a service's --lib/meta/ files when restarting,
2838-# so create one and check that it's removed.
2839-diag(`touch $tmpdir/meta/query-history.foo`);
2840-ok(
2841- -f "$tmpdir/meta/query-history.foo",
2842- "Restart: meta file exists"
2843-);
2844-
2845-$qh = Percona::WebAPI::Resource::Service->new(
2846- ts => '200', # was 100
2847- name => 'query-history',
2848- run_schedule => '1 * * * *',
2849- spool_schedule => '2 * * * *',
2850- tasks => [ $run0 ],
2851- links => {
2852- self => '/query-history',
2853- data => '/query-history/data',
2854- },
2855-);
2856-
2857-$ua->{responses}->{get} = [
2858- {
2859- headers => { 'X-Percona-Resource-Type' => 'Service' },
2860- content => [
2861- as_hashref($start_qh, with_links => 1), # has not changed
2862- as_hashref($stop_qh, with_links => 1), # has not changed
2863- as_hashref($qh, with_links => 1),
2864- ],
2865- },
2866-];
2867-
2868-@log = ();
2869-@cmds = ();
2870-$success = 0;
2871-
2872-$output = output(
2873- sub {
2874- ($services, $success) = pt_agent::get_services(
2875- # Required args
2876- link => '/agents/123/services',
2877- agent => $agent,
2878- client => $client,
2879- lib_dir => $tmpdir,
2880- services => $services, # retval from previous call
2881- # Optional args, for testing
2882- json => $json,
2883- bin_dir => "$trunk/bin/",
2884- exec_cmd => $exec_cmd,
2885- );
2886- },
2887- stderr => 1,
2888-);
2889-
2890-is_deeply(
2891- \@cmds,
2892- [
2893- "$trunk/bin/pt-agent --run-service stop-query-history >> $tmpdir/logs/start-stop.log 2>&1",
2894- "$trunk/bin/pt-agent --run-service start-query-history >> $tmpdir/logs/start-stop.log 2>&1",
2895- "crontab $tmpdir/crontab > $tmpdir/crontab.err 2>&1",
2896- ],
2897- "Restart: ran stop-query-history then start-query-history"
2898-) or diag(Dumper(\@cmds), $output);
2899-
2900-ok(
2901- !-f "$tmpdir/meta/query-history.foo",
2902- "Restart: meta file removed"
2903-) or diag($output);
2904-
2905-# #############################################################################
2906-# Done.
2907-# #############################################################################
2908-done_testing;
2909
2910=== removed file 't/pt-agent/init_agent.t'
2911--- t/pt-agent/init_agent.t 2013-09-23 19:07:34 +0000
2912+++ t/pt-agent/init_agent.t 1970-01-01 00:00:00 +0000
2913@@ -1,333 +0,0 @@
2914-#!/usr/bin/env perl
2915-
2916-BEGIN {
2917- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
2918- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
2919- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
2920-};
2921-
2922-use strict;
2923-use warnings FATAL => 'all';
2924-use English qw(-no_match_vars);
2925-use Test::More;
2926-use JSON;
2927-use File::Temp qw(tempdir);
2928-
2929-use Percona::Test;
2930-use Percona::Test::Mock::UserAgent;
2931-use Percona::Test::Mock::AgentLogger;
2932-require "$trunk/bin/pt-agent";
2933-
2934-Percona::Toolkit->import(qw(Dumper));
2935-Percona::WebAPI::Representation->import(qw(as_hashref));
2936-
2937-my $tmpdir = tempdir("/tmp/pt-agent.$PID.XXXXXX", CLEANUP => 1);
2938-
2939-my $json = JSON->new->canonical([1])->pretty;
2940-$json->allow_blessed([]);
2941-$json->convert_blessed([]);
2942-
2943-my @log;
2944-my $logger = Percona::Test::Mock::AgentLogger->new(log => \@log);
2945-pt_agent::_logger($logger);
2946-
2947-my $ua = Percona::Test::Mock::UserAgent->new(
2948- encode => sub { my $c = shift; return $json->encode($c || {}) },
2949-);
2950-
2951-my $client = eval {
2952- Percona::WebAPI::Client->new(
2953- api_key => '123',
2954- ua => $ua,
2955- );
2956-};
2957-
2958-is(
2959- $EVAL_ERROR,
2960- '',
2961- 'Create Client with mock user agent'
2962-) or die;
2963-
2964-my @ok;
2965-my $oktorun = sub {
2966- return shift @ok;
2967-};
2968-
2969-my @wait;
2970-my $interval = sub {
2971- my $t = shift;
2972- push @wait, $t;
2973-};
2974-
2975-# #############################################################################
2976-# Init a new agent, i.e. create it.
2977-# #############################################################################
2978-
2979-my $post_agent = Percona::WebAPI::Resource::Agent->new(
2980- uuid => '123',
2981- hostname => 'host1',
2982- username => 'name1',
2983- versions => {
2984- },
2985- links => {
2986- self => '/agents/123',
2987- config => '/agents/123/config',
2988- },
2989-);
2990-
2991-my $return_agent = Percona::WebAPI::Resource::Agent->new(
2992- uuid => '123',
2993- hostname => 'host2',
2994- username => 'name2',
2995- versions => {
2996- },
2997- links => {
2998- self => '/agents/123',
2999- config => '/agents/123/config',
3000- },
3001-);
3002-
3003-$ua->{responses}->{post} = [
3004- {
3005- headers => { 'Location' => '/agents/123' },
3006- },
3007-];
3008-
3009-$ua->{responses}->{get} = [
3010- {
3011- headers => { 'X-Percona-Resource-Type' => 'Agent' },
3012- content => as_hashref($return_agent, with_links =>1 ),
3013- },
3014-];
3015-
3016-my $got_agent;
3017-my $output = output(
3018- sub {
3019- ($got_agent) = pt_agent::init_agent(
3020- agent => $post_agent,
3021- action => 'post',
3022- link => "/agents",
3023- client => $client,
3024- interval => $interval,
3025- tries => 4,
3026- );
3027- },
3028- stderr => 1,
3029-);
3030-
3031-is(
3032- $got_agent->hostname,
3033- 'host2',
3034- 'Got and returned Agent'
3035-) or diag($output, Dumper(as_hashref($got_agent, with_links => 1)));
3036-
3037-is(
3038- scalar @wait,
3039- 0,
3040- "Client did not wait (new Agent)"
3041-) or diag($output);
3042-
3043-# #############################################################################
3044-# Repeat this test but this time fake an error, so the tool isn't able
3045-# to create the Agent first time, so it should wait (call interval),
3046-# and try again.
3047-# #############################################################################
3048-
3049-$return_agent->{id} = '456';
3050-$return_agent->{links} = {
3051- self => '/agents/456',
3052- config => '/agents/456/config',
3053-};
3054-
3055-$ua->{responses}->{post} = [
3056- { # 1, the fake error
3057- code => 500,
3058- },
3059- # 2, code should call interval
3060- { # 3, code should try again, then receive this
3061- code => 200,
3062- headers => { 'Location' => '/agents/456' },
3063- },
3064-];
3065- # 4, code will GET the new Agent
3066-$ua->{responses}->{get} = [
3067- {
3068- headers => { 'X-Percona-Resource-Type' => 'Agent' },
3069- content => as_hashref($return_agent, with_links =>1 ),
3070- },
3071-];
3072-
3073-@ok = qw(1 1 0);
3074-@wait = ();
3075-@log = ();
3076-$ua->{requests} = [];
3077-
3078-$output = output(
3079- sub {
3080- ($got_agent) = pt_agent::init_agent(
3081- agent => $post_agent,
3082- action => 'post',
3083- link => "/agents",
3084- client => $client,
3085- interval => $interval,
3086- tries => 5,
3087- oktorun => $oktorun,
3088- );
3089- },
3090- stderr => 1,
3091-);
3092-
3093-is(
3094- ($got_agent ? $got_agent->hostname : ''),
3095- 'host2',
3096- 'Got and returned Agent after error'
3097-) or diag($output, Dumper($got_agent));
3098-
3099-is(
3100- scalar @wait,
3101- 1,
3102- "Client waited after error"
3103-);
3104-
3105-is_deeply(
3106- $ua->{requests},
3107- [
3108- 'POST /agents', # first attempt, 500 error
3109- 'POST /agents', # second attemp, 200 OK
3110- 'GET /agents/456', # GET new Agent
3111- ],
3112- "POST POST GET new Agent after error"
3113-) or diag(Dumper($ua->{requests}));
3114-
3115-like(
3116- $log[1],
3117- qr{WARNING Failed to POST /agents},
3118- "POST /agents failure logged after error"
3119-) or diag(Dumper($ua->{requests}), Dumper(\@log));
3120-
3121-# #############################################################################
3122-# Init an existing agent, i.e. update it.
3123-# #############################################################################
3124-
3125-my $put_agent = Percona::WebAPI::Resource::Agent->new(
3126- uuid => '123',
3127- hostname => 'host3',
3128- username => 'name3',
3129- versions => {
3130- },
3131- links => {
3132- self => '/agents/123',
3133- config => '/agents/123/config',
3134- },
3135-);
3136-
3137-$ua->{responses}->{put} = [
3138- {
3139- code => 200,
3140- headers => {
3141- Location => '/agents/123',
3142- },
3143- },
3144-];
3145-$ua->{responses}->{get} = [
3146- {
3147- code => 200,
3148- headers => { 'X-Percona-Resource-Type' => 'Agent' },
3149- content => as_hashref($return_agent, with_links =>1 ),
3150- }
3151-];
3152-
3153-@wait = ();
3154-$ua->{requests} = [];
3155-
3156-$output = output(
3157- sub {
3158- ($got_agent) = pt_agent::init_agent(
3159- agent => $put_agent,
3160- action => 'put',
3161- link => "/agents/123",
3162- client => $client,
3163- interval => $interval,
3164- tries => 4,
3165- );
3166- },
3167- stderr => 1,
3168-);
3169-
3170-is(
3171- $got_agent->hostname,
3172- 'host2',
3173- 'PUT Agent'
3174-) or diag($output, Dumper(as_hashref($got_agent, with_links => 1)));
3175-
3176-is(
3177- scalar @wait,
3178- 0,
3179- "Client did not wait (saved Agent)"
3180-);
3181-
3182-is_deeply(
3183- $ua->{requests},
3184- [
3185- 'PUT /agents/123',
3186- 'GET /agents/123',
3187- ],
3188- "PUT then GET Agent"
3189-) or diag(Dumper($ua->{requests}));
3190-
3191-# #############################################################################
3192-# Status 403 (too many agents) should abort further attempts.
3193-# #############################################################################
3194-
3195-$ua->{responses}->{post} = [
3196- { # 1, the fake error
3197- code => 403,
3198- },
3199-];
3200-
3201-@ok = qw(1 1 0);
3202-@wait = ();
3203-@log = ();
3204-$ua->{requests} = [];
3205-
3206-$output = output(
3207- sub {
3208- ($got_agent) = pt_agent::init_agent(
3209- agent => $post_agent,
3210- action => 'post',
3211- link => "/agents",
3212- client => $client,
3213- interval => $interval,
3214- tries => 3,
3215- oktorun => $oktorun,
3216- );
3217- },
3218- stderr => 1,
3219-);
3220-
3221-is(
3222- scalar @wait,
3223- 2,
3224- "Too many agents (403): waits"
3225-);
3226-
3227-is_deeply(
3228- $ua->{requests},
3229- [
3230- 'POST /agents',
3231- 'POST /agents',
3232- ],
3233- "Too many agents (403): tries"
3234-) or diag(Dumper($ua->{requests}));
3235-
3236-my $n = grep { $_ =~ m/too many agents/ } @log;
3237-is(
3238- $n,
3239- 1,
3240- "Too many agents (403): does not repeat warning"
3241-) or diag(Dumper(\@log));
3242-
3243-# #############################################################################
3244-# Done.
3245-# #############################################################################
3246-done_testing;
3247
3248=== removed file 't/pt-agent/make_new_crontab.t'
3249--- t/pt-agent/make_new_crontab.t 2013-04-19 20:49:01 +0000
3250+++ t/pt-agent/make_new_crontab.t 1970-01-01 00:00:00 +0000
3251@@ -1,151 +0,0 @@
3252-#!/usr/bin/env perl
3253-
3254-BEGIN {
3255- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
3256- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
3257- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
3258-};
3259-
3260-use strict;
3261-use warnings FATAL => 'all';
3262-use English qw(-no_match_vars);
3263-use Test::More;
3264-use JSON;
3265-use File::Temp qw(tempfile);
3266-
3267-use Percona::Test;
3268-require "$trunk/bin/pt-agent";
3269-
3270-Percona::Toolkit->import(qw(have_required_args Dumper));
3271-
3272-my $sample = "t/pt-agent/samples";
3273-
3274-sub test_make_new_crontab {
3275- my (%args) = @_;
3276- have_required_args(\%args, qw(
3277- file
3278- services
3279- )) or die;
3280- my $file = $args{file};
3281- my $services = $args{services};
3282-
3283- my $crontab_list = slurp_file("$trunk/$sample/$file.in");
3284-
3285- my $new_crontab = pt_agent::make_new_crontab(
3286- services => $services,
3287- crontab_list => $crontab_list,
3288- bin_dir => '',
3289- );
3290-
3291- ok(
3292- no_diff(
3293- $new_crontab,
3294- "$sample/$file.out",
3295- cmd_output => 1,
3296- ),
3297- $args{name} || $file,
3298- ) or diag($new_crontab);
3299-}
3300-
3301-my $run0 = Percona::WebAPI::Resource::Task->new(
3302- name => 'query-history',
3303- number => '0',
3304- program => 'pt-query-digest',
3305- options => '--output json',
3306- output => 'spool',
3307-);
3308-
3309-my $svc0 = Percona::WebAPI::Resource::Service->new(
3310- ts => '100',
3311- name => 'query-history',
3312- run_schedule => '* 8 * * 1,2,3,4,5',
3313- spool_schedule => '* 9 * * 1,2,3,4,5',
3314- tasks => [ $run0 ],
3315-);
3316-
3317-# Empty crontab, add the service.
3318-test_make_new_crontab(
3319- file => "crontab001",
3320- services => [ $svc0 ],
3321-);
3322-
3323-# Crontab has another line, add the service to it.
3324-test_make_new_crontab(
3325- file => "crontab002",
3326- services => [ $svc0 ],
3327-);
3328-
3329-# Crontab has another line and an old service, remove the old service
3330-# and add the current service.
3331-test_make_new_crontab(
3332- file => "crontab003",
3333- services => [ $svc0 ],
3334-);
3335-
3336-# Crontab has old service, remove it and add only new service.
3337-test_make_new_crontab(
3338- file => "crontab004",
3339- services => [ $svc0 ],
3340-);
3341-
3342-# #############################################################################
3343-# Use real crontab.
3344-# #############################################################################
3345-
3346-# The previous tests pass in a crontab file to make testing easier.
3347-# Now test that make_new_crontab() will run `crontab -l' if not given
3348-# input. To test this, we add a fake line to our crontab. If
3349-# make_new_crontab() really runs `crontab -l', then this fake line
3350-# will be in the new crontab it returns.
3351-
3352-my $crontab = `crontab -l 2>/dev/null`;
3353-SKIP: {
3354- skip 'Crontab is not empty', 3 if $crontab;
3355-
3356- # On most systems[1], crontab lines must end with a newline,
3357- # else an error like this happens:
3358- # "/tmp/new_crontab_file":1: premature EOF
3359- # errors in crontab file, can't install.
3360- # [1] Ubuntu 10 and Mac OS X work without the newline.
3361- my ($fh, $file) = tempfile();
3362- print {$fh} "* 0 * * * date > /dev/null\n";
3363- close $fh or warn "Cannot close $file: $OS_ERROR";
3364- my $output = `crontab $file 2>&1`;
3365-
3366- $crontab = `crontab -l 2>&1`;
3367-
3368- is(
3369- $crontab,
3370- "* 0 * * * date > /dev/null\n",
3371- "Set other crontab line"
3372- ) or diag($output);
3373-
3374- unlink $file or warn "Cannot remove $file: $OS_ERROR";
3375-
3376- my $new_crontab = pt_agent::make_new_crontab(
3377- services => [ $svc0 ],
3378- bin_dir => '',
3379- );
3380-
3381- is(
3382- $new_crontab,
3383- "* 0 * * * date > /dev/null
3384-* 8 * * 1,2,3,4,5 pt-agent --run-service query-history
3385-* 9 * * 1,2,3,4,5 pt-agent --send-data query-history
3386-",
3387- "Runs crontab -l by default"
3388- );
3389-
3390- system("crontab -r 2>/dev/null");
3391- $crontab = `crontab -l 2>/dev/null`;
3392- is(
3393- $crontab,
3394- "",
3395- "Removed crontab"
3396- );
3397-};
3398-
3399-# #############################################################################
3400-# Done.
3401-# #############################################################################
3402-done_testing;
3403
3404=== removed file 't/pt-agent/replace_special_vars.t'
3405--- t/pt-agent/replace_special_vars.t 2013-06-17 00:28:18 +0000
3406+++ t/pt-agent/replace_special_vars.t 1970-01-01 00:00:00 +0000
3407@@ -1,73 +0,0 @@
3408-#!/usr/bin/env perl
3409-
3410-BEGIN {
3411- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
3412- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
3413- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
3414-};
3415-
3416-use strict;
3417-use warnings FATAL => 'all';
3418-use English qw(-no_match_vars);
3419-use Test::More;
3420-use JSON;
3421-use File::Temp qw(tempfile);
3422-
3423-use Percona::Test;
3424-use Percona::Test::Mock::AgentLogger;
3425-require "$trunk/bin/pt-agent";
3426-
3427-Percona::Toolkit->import(qw(have_required_args Dumper));
3428-
3429-my @log;
3430-my $logger = Percona::Test::Mock::AgentLogger->new(log => \@log);
3431-pt_agent::_logger($logger);
3432-
3433-my @output_files = ();
3434-my $store = {};
3435-
3436-sub test_replace {
3437- my (%args) = @_;
3438- have_required_args(\%args, qw(
3439- cmd
3440- expect
3441- )) or die;
3442- my $cmd = $args{cmd};
3443- my $expect = $args{expect};
3444-
3445- my $new_cmd = pt_agent::replace_special_vars(
3446- cmd => $cmd,
3447- output_files => \@output_files,
3448- service => 'service-name',
3449- lib_dir => '/var/lib/pt-agent',
3450- meta_dir => '/var/lib/pt-agent/meta',
3451- stage_dir => '/var/spool/.tmp',
3452- spool_dir => '/var/spool',
3453- bin_dir => $trunk,
3454- ts => '123',
3455- store => $store,
3456- );
3457-
3458- is(
3459- $new_cmd,
3460- $expect,
3461- $cmd,
3462- );
3463-};
3464-
3465-@output_files = qw(zero one two);
3466-test_replace(
3467- cmd => "pt-query-digest __RUN_0_OUTPUT__",
3468- expect => "pt-query-digest zero",
3469-);
3470-
3471-$store->{slow_query_log_file} = 'slow.log';
3472-test_replace(
3473- cmd => "echo '__STORE_slow_query_log_file__' > /var/spool/pt-agent/.tmp/1371269644.rotate-slow-query-log-all-5.1.slow_query_log_file",
3474- expect => "echo 'slow.log' > /var/spool/pt-agent/.tmp/1371269644.rotate-slow-query-log-all-5.1.slow_query_log_file",
3475-);
3476-
3477-# #############################################################################
3478-# Done.
3479-# #############################################################################
3480-done_testing;
3481
3482=== removed file 't/pt-agent/run_agent.t'
3483--- t/pt-agent/run_agent.t 2013-06-17 04:01:30 +0000
3484+++ t/pt-agent/run_agent.t 1970-01-01 00:00:00 +0000
3485@@ -1,527 +0,0 @@
3486-#!/usr/bin/env perl
3487-
3488-BEGIN {
3489- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
3490- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
3491- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
3492-};
3493-
3494-use strict;
3495-use warnings FATAL => 'all';
3496-use English qw(-no_match_vars);
3497-use Test::More;
3498-
3499-plan skip_all => "Need to make start-service testable";
3500-
3501-use JSON;
3502-use File::Temp qw(tempdir);
3503-
3504-use Percona::Test;
3505-use Sandbox;
3506-use Percona::Test::Mock::UserAgent;
3507-use Percona::Test::Mock::AgentLogger;
3508-require "$trunk/bin/pt-agent";
3509-
3510-my $dp = new DSNParser(opts=>$dsn_opts);
3511-my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
3512-my $dbh = $sb->get_dbh_for('master');
3513-my $dsn = $sb->dsn_for('master');
3514-my $o = new OptionParser();
3515-$o->get_specs("$trunk/bin/pt-agent");
3516-$o->get_opts();
3517-my $cxn = Cxn->new(
3518- dsn_string => $dsn,
3519- OptionParser => $o,
3520- DSNParser => $dp,
3521-);
3522-
3523-Percona::Toolkit->import(qw(Dumper));
3524-Percona::WebAPI::Representation->import(qw(as_hashref));
3525-
3526-# Running the agent is going to cause it to schedule the services,
3527-# i.e. write a real crontab. The test box/user shouldn't have a
3528-# crontab, so we'll warn and clobber it if there is one.
3529-my $crontab = `crontab -l 2>/dev/null`;
3530-if ( $crontab ) {
3531- warn "Removing crontab: $crontab\n";
3532- `crontab -r`;
3533-}
3534-
3535-# Fake --lib and --spool dirs.
3536-my $tmpdir = tempdir("/tmp/pt-agent.$PID.XXXXXX"); #, CLEANUP => 1);
3537-mkdir "$tmpdir/spool" or die "Error making $tmpdir/spool: $OS_ERROR";
3538-
3539-my @log;
3540-my $logger = Percona::Test::Mock::AgentLogger->new(log => \@log);
3541-pt_agent::_logger($logger);
3542-
3543-# #############################################################################
3544-# Create mock client and Agent
3545-# #############################################################################
3546-
3547-# These aren't the real tests yet: to run_agent, first we need
3548-# a client and Agent, so create mock ones.
3549-
3550-my $output;
3551-my $json = JSON->new->canonical([1])->pretty;
3552-$json->allow_blessed([]);
3553-$json->convert_blessed([]);
3554-
3555-my $ua = Percona::Test::Mock::UserAgent->new(
3556- encode => sub { my $c = shift; return $json->encode($c || {}) },
3557-);
3558-
3559-my $client = eval {
3560- Percona::WebAPI::Client->new(
3561- api_key => '123',
3562- ua => $ua,
3563- );
3564-};
3565-
3566-is(
3567- $EVAL_ERROR,
3568- '',
3569- 'Create mock client'
3570-) or die;
3571-
3572-my $agent = Percona::WebAPI::Resource::Agent->new(
3573- uuid => '123',
3574- hostname => 'host',
3575- username => 'user',
3576- links => {
3577- self => '/agents/123',
3578- config => '/agents/123/config',
3579- },
3580-);
3581-
3582-my $daemon = Daemon->new(
3583- daemonzie => 0,
3584-);
3585-
3586-my @wait;
3587-my $interval = sub {
3588- my $t = shift;
3589- push @wait, $t;
3590- print "interval=" . (defined $t ? $t : 'undef') . "\n";
3591-};
3592-
3593-# #############################################################################
3594-# Test run_agent
3595-# #############################################################################
3596-
3597-my $config = Percona::WebAPI::Resource::Config->new(
3598- ts => 1363720060,
3599- name => 'Default',
3600- options => {
3601- 'lib' => $tmpdir, # required
3602- 'spool' => "$tmpdir/spool", # required
3603- 'check-interval' => "11",
3604- },
3605- links => {
3606- self => '/agents/123/config',
3607- services => '/agents/123/services',
3608- },
3609-);
3610-
3611-my $run0 = Percona::WebAPI::Resource::Task->new(
3612- name => 'query-history',
3613- number => '0',
3614- program => 'pt-query-digest',
3615- options => '--output json',
3616- output => 'spool',
3617-);
3618-
3619-my $svc0 = Percona::WebAPI::Resource::Service->new(
3620- ts => 100,
3621- name => 'query-history',
3622- run_schedule => '1 * * * *',
3623- spool_schedule => '2 * * * *',
3624- tasks => [ $run0 ],
3625- links => {
3626- self => '/query-history',
3627- data => '/query-history/data',
3628- },
3629-);
3630-
3631-my $run1 = Percona::WebAPI::Resource::Task->new(
3632- name => 'start-query-history',
3633- number => '0',
3634- program => 'echo "start-qh"',
3635-);
3636-
3637-my $start_qh = Percona::WebAPI::Resource::Service->new(
3638- ts => '100',
3639- name => 'start-query-history',
3640- meta => 1,
3641- tasks => [ $run1 ],
3642- links => {
3643- self => '/query-history',
3644- data => '/query-history/data',
3645- },
3646-);
3647-
3648-$ua->{responses}->{get} = [
3649- {
3650- headers => { 'X-Percona-Resource-Type' => 'Config' },
3651- content => as_hashref($config, with_links => 1),
3652- },
3653- {
3654- headers => { 'X-Percona-Resource-Type' => 'Service' },
3655- content => [
3656- as_hashref($start_qh, with_links => 1),
3657- as_hashref($svc0, with_links => 1),
3658- ],
3659- },
3660-];
3661-
3662-my $safeguards = Safeguards->new(
3663- disk_bytes_free => 1024,
3664- disk_pct_free => 1,
3665-);
3666-
3667-# The only thing pt-agent must have is the API key in the config file,
3668-# everything else relies on defaults until the first Config is gotten
3669-# from Percona.
3670-my $config_file = pt_agent::get_config_file();
3671-unlink $config_file if -f $config_file;
3672-
3673-like(
3674- $config_file,
3675- qr/$ENV{LOGNAME}\/\.pt-agent.conf$/,
3676- "Default config file is ~/.pt-agent.config"
3677-);
3678-
3679-pt_agent::write_config(
3680- config => $config
3681-);
3682-
3683-diag(`echo 'api-key=123' >> $config_file`);
3684-
3685-is(
3686- `cat $config_file`,
3687- "check-interval=11\nlib=$tmpdir\nspool=$tmpdir/spool\napi-key=123\n",
3688- "Write Config to config file"
3689-);
3690-
3691-pt_agent::save_agent(
3692- agent => $agent,
3693- lib_dir => $tmpdir,
3694-);
3695-
3696-my @ok_code = (); # callbacks
3697-my @oktorun = (
3698- 1, # 1st main loop check
3699- 0, # 2nd main loop check
3700-);
3701-my $oktorun = sub {
3702- my $ok = shift @oktorun;
3703- print "oktorun=" . (defined $ok ? $ok : 'undef') . "\n";
3704- my $code = shift @ok_code;
3705- $code->() if $code;
3706- return $ok
3707-};
3708-
3709-@wait = ();
3710-
3711-$output = output(
3712- sub {
3713- pt_agent::run_agent(
3714- # Required args
3715- agent => $agent,
3716- client => $client,
3717- daemon => $daemon,
3718- interval => $interval,
3719- lib_dir => $tmpdir,
3720- safeguards => $safeguards,
3721- Cxn => $cxn,
3722- # Optional args, for testing
3723- oktorun => $oktorun,
3724- json => $json,
3725- bin_dir => "$trunk/bin",
3726- );
3727- },
3728- stderr => 1,
3729-);
3730-
3731-is(
3732- scalar @wait,
3733- 1,
3734- "Called interval once"
3735-);
3736-
3737-is(
3738- $wait[0],
3739- 11,
3740- "... used Config->options->check-interval"
3741-);
3742-
3743-ok(
3744- -f "$tmpdir/services/query-history",
3745- "Created services/query-history"
3746-) or diag($output);
3747-
3748-chomp(my $n_files = `ls -1 $tmpdir/services| wc -l | awk '{print \$1}'`);
3749-is(
3750- $n_files,
3751- 2,
3752- "... created services/query-history and services/start-query-history"
3753-);
3754-
3755-ok(
3756- no_diff(
3757- "cat $tmpdir/services/query-history",
3758- "t/pt-agent/samples/service001",
3759- ),
3760- "query-history service file"
3761-);
3762-
3763-$crontab = `crontab -l 2>/dev/null`;
3764-like(
3765- $crontab,
3766- qr/pt-agent --run-service query-history$/m,
3767- "Scheduled --run-service with crontab"
3768-) or diag(Dumper(\@log));
3769-
3770-like(
3771- $crontab,
3772- qr/pt-agent --send-data query-history$/m,
3773- "Scheduled --send-data with crontab"
3774-) or diag(Dumper(\@log));
3775-exit;
3776-# #############################################################################
3777-# Run run_agent again, like the agent had been stopped and restarted.
3778-# #############################################################################
3779-
3780-$ua->{responses}->{get} = [
3781- # First check, fail
3782- {
3783- code => 500,
3784- },
3785- # interval
3786- # 2nd check, init with latest Config and Services
3787- {
3788- headers => { 'X-Percona-Resource-Type' => 'Config' },
3789- content => as_hashref($config, with_links => 1),
3790- },
3791- {
3792- headers => { 'X-Percona-Resource-Type' => 'Service' },
3793- content => [ as_hashref($svc0, with_links => 1) ],
3794- },
3795- # interval
3796- # 3rd check, same Config and Services so nothing to do
3797- {
3798- headers => { 'X-Percona-Resource-Type' => 'Config' },
3799- content => as_hashref($config, with_links => 1),
3800- },
3801- {
3802- headers => { 'X-Percona-Resource-Type' => 'Service' },
3803- content => [ as_hashref($svc0, with_links => 1) ],
3804- },
3805- # interval, oktorun=0
3806-];
3807-
3808-@oktorun = (
3809- 1, # 1st main loop check
3810- # First check, error 500
3811- 1, # 2nd main loop check
3812- # Init with latest Config and Services
3813- 1, # 3rd main loop check
3814- # Same Config and services
3815- 0, # 4th main loop check
3816-);
3817-
3818-# Before the 3rd check, remove the config file (~/.pt-agent.conf) and
3819-# query-history service file. When the tool re-GETs these, they'll be
3820-# the same so it won't recreate them. A bug here will cause these files to
3821-# exist again after running.
3822-$ok_code[2] = sub {
3823- unlink "$config_file";
3824- unlink "$tmpdir/services/query-history";
3825- Percona::Test::wait_until(sub { ! -f "$config_file" });
3826- Percona::Test::wait_until(sub { ! -f "$tmpdir/services/query-history" });
3827-};
3828-
3829-@wait = ();
3830-
3831-$output = output(
3832- sub {
3833- pt_agent::run_agent(
3834- # Required args
3835- agent => $agent,
3836- client => $client,
3837- daemon => $daemon,
3838- interval => $interval,
3839- lib_dir => $tmpdir,
3840- Cxn => $cxn,
3841- # Optional args, for testing
3842- oktorun => $oktorun,
3843- json => $json,
3844- );
3845- },
3846- stderr => 1,
3847-);
3848-
3849-is_deeply(
3850- \@wait,
3851- [ 60, 11, 11 ],
3852- "Got Config after error"
3853-) or diag(Dumper(\@wait));
3854-
3855-ok(
3856- ! -f "$config_file",
3857- "No Config diff, no config file change"
3858-);
3859-
3860-ok(
3861- ! -f "$tmpdir/services/query-history",
3862- "No Service diff, no service file changes"
3863-);
3864-
3865-my $new_crontab = `crontab -l 2>/dev/null`;
3866-is(
3867- $new_crontab,
3868- $crontab,
3869- "Crontab is the same"
3870-);
3871-
3872-# #############################################################################
3873-# Test a run_once_on_start service
3874-# #############################################################################
3875-
3876-diag(`rm -f $tmpdir/* >/dev/null 2>&1`);
3877-diag(`rm -rf $tmpdir/services/*`);
3878-diag(`rm -rf $tmpdir/spool/*`);
3879-
3880-# When pt-agent manually runs --run-service test-run-at-start, it's going
3881-# to need an API key because it doesn't call its own run_service(), it runs
3882-# another instance of itself with system(). So put the fake API key in
3883-# the default config file.
3884-unlink $config_file if -f $config_file;
3885-diag(`echo "api-key=123" > $config_file`);
3886-
3887-$config = Percona::WebAPI::Resource::Config->new(
3888- ts => 1363720060,
3889- name => 'Test run_once_on_start',
3890- options => {
3891- 'check-interval' => "15",
3892- 'lib' => $tmpdir,
3893- 'spool' => "$tmpdir/spool",
3894- 'pid' => "$tmpdir/pid",
3895- 'log' => "$tmpdir/log"
3896- },
3897- links => {
3898- self => '/agents/123/config',
3899- services => '/agents/123/services',
3900- },
3901-);
3902-
3903-$run0 = Percona::WebAPI::Resource::Task->new(
3904- name => 'run-at-start',
3905- number => '0',
3906- program => 'date',
3907- output => 'spool',
3908-);
3909-
3910-$svc0 = Percona::WebAPI::Resource::Service->new(
3911- ts => 100,
3912- name => 'test-run-at-start',
3913- run_schedule => '0 0 1 1 *',
3914- run_once => 1, # here's the magic
3915- tasks => [ $run0 ],
3916- links => {
3917- self => '/query-history',
3918- data => '/query-history/data',
3919- },
3920-);
3921-
3922-$ua->{responses}->{get} = [
3923- {
3924- headers => { 'X-Percona-Resource-Type' => 'Config' },
3925- content => as_hashref($config, with_links => 1),
3926- },
3927- {
3928- headers => { 'X-Percona-Resource-Type' => 'Service' },
3929- content => [ as_hashref($svc0, with_links => 1) ],
3930- },
3931- {
3932- headers => { 'X-Percona-Resource-Type' => 'Config' },
3933- content => as_hashref($config, with_links => 1),
3934- },
3935- {
3936- headers => { 'X-Percona-Resource-Type' => 'Service' },
3937- content => [ as_hashref($svc0, with_links => 1) ],
3938- },
3939-];
3940-
3941-@wait = ();
3942-@ok_code = (); # callbacks
3943-@oktorun = (
3944- 1, # 1st main loop check
3945- # Run once
3946- 1, # 2nd main loop check
3947- # Don't run it again
3948- 0, # 3d main loop check
3949-);
3950-
3951-$output = output(
3952- sub {
3953- pt_agent::run_agent(
3954- # Required args
3955- agent => $agent,
3956- client => $client,
3957- daemon => $daemon,
3958- interval => $interval,
3959- lib_dir => $tmpdir,
3960- Cxn => $cxn,
3961- # Optional args, for testing
3962- oktorun => $oktorun,
3963- json => $json,
3964- bin_dir => "$trunk/bin/",
3965- );
3966- },
3967- stderr => 1,
3968-);
3969-
3970-Percona::Test::wait_for_files("$tmpdir/spool/test-run-at-start/test-run-at-start");
3971-
3972-like(
3973- $output,
3974- qr/Starting test-run-at-start service/,
3975- "Ran service on start"
3976-);
3977-
3978-my @runs = $output =~ m/Starting test-run-at-start service/g;
3979-
3980-is(
3981- scalar @runs,
3982- 1,
3983- "... only ran it once"
3984-);
3985-
3986-chomp($output = `cat $tmpdir/spool/test-run-at-start/test-run-at-start 2>/dev/null`);
3987-ok(
3988- $output,
3989- "... service ran at start"
3990-) or diag($output);
3991-
3992-chomp($output = `crontab -l`);
3993-unlike(
3994- $output,
3995- qr/--run-service test-run-at-start/,
3996- "... service was not scheduled"
3997-);
3998-
3999-# #############################################################################
4000-# Done.
4001-# #############################################################################
4002-
4003-# This shouldn't cause an error, but if it does, let it show up
4004-# in the results as an error.
4005-`crontab -r`;
4006-
4007-if ( -f $config_file ) {
4008- unlink $config_file
4009- or warn "Error removing $config_file: $OS_ERROR";
4010-}
4011-
4012-done_testing;
4013
4014=== removed file 't/pt-agent/run_service.t'
4015--- t/pt-agent/run_service.t 2013-06-17 00:28:18 +0000
4016+++ t/pt-agent/run_service.t 1970-01-01 00:00:00 +0000
4017@@ -1,503 +0,0 @@
4018-#!/usr/bin/env perl
4019-
4020-BEGIN {
4021- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
4022- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
4023- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
4024-};
4025-
4026-use strict;
4027-use warnings FATAL => 'all';
4028-use English qw(-no_match_vars);
4029-use Test::More;
4030-use JSON;
4031-use File::Temp qw(tempdir);
4032-
4033-$ENV{PTTEST_PRETTY_JSON} = 1;
4034-
4035-use Percona::Test;
4036-use Sandbox;
4037-use Percona::Test::Mock::UserAgent;
4038-use Percona::Test::Mock::AgentLogger;
4039-require "$trunk/bin/pt-agent";
4040-
4041-my $dp = new DSNParser(opts=>$dsn_opts);
4042-my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
4043-my $dbh = $sb->get_dbh_for('master');
4044-my $dsn = $sb->dsn_for('master');
4045-my $o = new OptionParser();
4046-$o->get_specs("$trunk/bin/pt-agent");
4047-$o->get_opts();
4048-
4049-Percona::Toolkit->import(qw(Dumper have_required_args));
4050-Percona::WebAPI::Representation->import(qw(as_hashref));
4051-
4052-my @log;
4053-my $logger = Percona::Test::Mock::AgentLogger->new(log => \@log);
4054-pt_agent::_logger($logger);
4055-
4056-my $sample = "t/pt-agent/samples";
4057-
4058-# Create fake spool and lib dirs. Service-related subs in pt-agent
4059-# automatically add "/services" to the lib dir, but the spool dir is
4060-# used as-is.
4061-my $tmpdir = tempdir("/tmp/pt-agent.$PID.XXXXXX", CLEANUP => 1);
4062-output(
4063- sub { pt_agent::init_lib_dir(lib_dir => $tmpdir) }
4064-);
4065-my $spool_dir = "$tmpdir/spool";
4066-
4067-sub write_svc_files {
4068- my (%args) = @_;
4069- have_required_args(\%args, qw(
4070- services
4071- )) or die;
4072- my $services = $args{services};
4073-
4074- my $output = output(
4075- sub {
4076- pt_agent::write_services(
4077- sorted_services => { added => $services },
4078- lib_dir => $tmpdir,
4079- );
4080- },
4081- stderr => 1,
4082- die => 1,
4083- );
4084-}
4085-
4086-# #############################################################################
4087-# Create mock client and Agent
4088-# #############################################################################
4089-
4090-my $json = JSON->new->canonical([1])->pretty;
4091-$json->allow_blessed([]);
4092-$json->convert_blessed([]);
4093-
4094-my $ua = Percona::Test::Mock::UserAgent->new(
4095- encode => sub { my $c = shift; return $json->encode($c || {}) },
4096-);
4097-
4098-# Create cilent, get entry links
4099-my $links = {
4100- agents => '/agents',
4101- config => '/agents/1/config',
4102- services => '/agents/1/services',
4103- 'query-history' => '/query-history',
4104-};
4105-
4106-$ua->{responses}->{get} = [
4107- {
4108- content => $links,
4109- },
4110-];
4111-
4112-my $client = eval {
4113- Percona::WebAPI::Client->new(
4114- api_key => '123',
4115- ua => $ua,
4116- );
4117-};
4118-is(
4119- $EVAL_ERROR,
4120- '',
4121- 'Create mock client'
4122-) or die;
4123-
4124-my $agent = Percona::WebAPI::Resource::Agent->new(
4125- uuid => '123',
4126- hostname => 'prod1',
4127- links => $links,
4128-);
4129-
4130-is_deeply(
4131- as_hashref($agent),
4132- {
4133- uuid => '123',
4134- hostname => 'prod1',
4135- },
4136- 'Create mock Agent'
4137-) or die;
4138-
4139-# #############################################################################
4140-# Simple single task service using a program.
4141-# #############################################################################
4142-
4143-my $run0 = Percona::WebAPI::Resource::Task->new(
4144- name => 'query-history',
4145- number => '0',
4146- program => "__BIN_DIR__/pt-query-digest --output json $trunk/t/lib/samples/slowlogs/slow008.txt",
4147- output => 'spool',
4148-);
4149-
4150-my $svc0 = Percona::WebAPI::Resource::Service->new(
4151- ts => 100,
4152- name => 'query-history',
4153- run_schedule => '1 * * * *',
4154- spool_schedule => '2 * * * *',
4155- tasks => [ $run0 ],
4156-);
4157-
4158-write_svc_files(
4159- services => [ $svc0 ],
4160-);
4161-
4162-$ua->{responses}->{get} = [
4163- {
4164- headers => { 'X-Percona-Resource-Type' => 'Agent' },
4165- content => as_hashref($agent, with_links => 1),
4166- },
4167-];
4168-
4169-my $exit_status;
4170-my $output = output(
4171- sub {
4172- $exit_status = pt_agent::run_service(
4173- api_key => '123',
4174- service => 'query-history',
4175- lib_dir => $tmpdir,
4176- spool_dir => $spool_dir,
4177- Cxn => '',
4178- # for testing:
4179- client => $client,
4180- agent => $agent,
4181- entry_links => $links,
4182- prefix => '1',
4183- json => $json,
4184- bin_dir => "$trunk/bin",
4185- );
4186- },
4187-);
4188-
4189-ok(
4190- no_diff(
4191- "cat $tmpdir/spool/query-history/1.query-history.data",
4192- "$sample/query-history/data001.json",
4193- post_pipe => 'grep -v \'"name" :\'',
4194- ),
4195- "1 run: spool data (query-history/data001.json)"
4196-) or diag(
4197- `ls -l $tmpdir/spool/query-history/`,
4198- `cat $tmpdir/logs/query-history.run`,
4199- Dumper(\@log)
4200-);
4201-
4202-chomp(my $n_files = `ls -1 $spool_dir/query-history/*.data | wc -l | awk '{print \$1}'`);
4203-is(
4204- $n_files,
4205- 1,
4206- "1 run: only wrote spool data"
4207-) or diag(`ls -l $spool_dir`);
4208-
4209-is(
4210- $exit_status,
4211- 0,
4212- "1 run: exit 0"
4213-);
4214-
4215-ok(
4216- -f "$tmpdir/spool/query-history/1.query-history.meta",
4217- "1 run: .meta file exists"
4218-);
4219-
4220-# #############################################################################
4221-# Service with two task, both using a program.
4222-# #############################################################################
4223-
4224-diag(`rm -rf $tmpdir/spool/* $tmpdir/services/*`);
4225-@log = ();
4226-
4227-# The result is the same as the previous single-run test, but instead of
4228-# having pqd read the slowlog directly, we have the first run cat the
4229-# log to a tmp file which pt-agent should auto-create. Then pqd in run1
4230-# references this tmp file.
4231-
4232-$run0 = Percona::WebAPI::Resource::Task->new(
4233- name => 'cat-slow-log',
4234- number => '0',
4235- program => "cat $trunk/t/lib/samples/slowlogs/slow008.txt",
4236- output => 'tmp',
4237-);
4238-
4239-my $run1 = Percona::WebAPI::Resource::Task->new(
4240- name => 'query-history',
4241- number => '1',
4242- program => "__BIN_DIR__/pt-query-digest --output json __RUN_0_OUTPUT__",
4243- output => 'spool',
4244-);
4245-
4246-$svc0 = Percona::WebAPI::Resource::Service->new(
4247- ts => 100,
4248- name => 'query-history',
4249- run_schedule => '3 * * * *',
4250- spool_schedule => '4 * * * *',
4251- tasks => [ $run0, $run1 ],
4252-);
4253-
4254-write_svc_files(
4255- services => [ $svc0 ],
4256-);
4257-
4258-$ua->{responses}->{get} = [
4259- {
4260- headers => { 'X-Percona-Resource-Type' => 'Agent' },
4261- content => as_hashref($agent, with_links => 1),
4262- },
4263-];
4264-
4265-$output = output(
4266- sub {
4267- $exit_status = pt_agent::run_service(
4268- api_key => '123',
4269- service => 'query-history',
4270- spool_dir => $spool_dir,
4271- lib_dir => $tmpdir,
4272- Cxn => '',
4273- # for testing:
4274- client => $client,
4275- agent => $agent,
4276- entry_links => $links,
4277- prefix => '2',
4278- json => $json,
4279- bin_dir => "$trunk/bin",
4280- );
4281- },
4282-);
4283-
4284-ok(
4285- no_diff(
4286- "cat $tmpdir/spool/query-history/2.query-history.data",
4287- "$sample/query-history/data001.json",
4288- post_pipe => 'grep -v \'"name" :\'',
4289- ),
4290- "2 runs: spool data (query-history/data001.json)"
4291-) or diag(
4292- `ls -l $tmpdir/spool/query-history/`,
4293- `cat $tmpdir/logs/query-history.run`,
4294- Dumper(\@log)
4295-);
4296-
4297-chomp($n_files = `ls -1 $spool_dir/query-history/*.data | wc -l | awk '{print \$1}'`);
4298-is(
4299- $n_files,
4300- 1,
4301- "2 runs: only wrote spool data"
4302-) or diag(`ls -l $spool_dir`);
4303-
4304-is(
4305- $exit_status,
4306- 0,
4307- "2 runs: exit 0"
4308-);
4309-
4310-my @tmp_files = glob "$tmpdir/spool/.tmp/*";
4311-is_deeply(
4312- \@tmp_files,
4313- [],
4314- "2 runs: temp file removed"
4315-);
4316-
4317-# #############################################################################
4318-# More realistc: 3 services, multiple tasks, using programs and queries.
4319-# #############################################################################
4320-
4321-SKIP: {
4322- skip 'Cannot connect to sandbox master', 5 unless $dbh;
4323- skip 'No HOME environment variable', 5 unless $ENV{HOME};
4324-
4325- diag(`rm -rf $tmpdir/spool/* $tmpdir/services/*`);
4326- @log = ();
4327-
4328- my (undef, $old_genlog) = $dbh->selectrow_array("SHOW VARIABLES LIKE 'general_log_file'");
4329-
4330- my $new_genlog = "$tmpdir/genlog";
4331-
4332- # First service: set up
4333- my $task00 = Percona::WebAPI::Resource::Task->new(
4334- name => 'disable-gen-log',
4335- number => '0',
4336- query => "SET GLOBAL general_log=OFF",
4337- );
4338- my $task01 = Percona::WebAPI::Resource::Task->new(
4339- name => 'set-gen-log-file',
4340- number => '1',
4341- query => "SET GLOBAL general_log_file='$new_genlog'",
4342- );
4343- my $task02 = Percona::WebAPI::Resource::Task->new(
4344- name => 'enable-gen-log',
4345- number => '2',
4346- query => "SET GLOBAL general_log=ON",
4347- );
4348- my $svc0 = Percona::WebAPI::Resource::Service->new(
4349- ts => 100,
4350- name => 'enable-gen-log',
4351- run_schedule => '1 * * * *',
4352- spool_schedule => '2 * * * *',
4353- tasks => [ $task00, $task01, $task02 ],
4354- );
4355-
4356- # Second service: the actual service
4357- my $task10 = Percona::WebAPI::Resource::Task->new(
4358- name => 'query-history',
4359- number => '1',
4360- program => "$trunk/bin/pt-query-digest --output json --type genlog $new_genlog",
4361- output => 'spool',
4362- );
4363- my $svc1 = Percona::WebAPI::Resource::Service->new(
4364- ts => 100,
4365- name => 'query-history',
4366- run_schedule => '3 * * * *',
4367- spool_schedule => '4 * * * *',
4368- tasks => [ $task10 ],
4369- );
4370-
4371- # Third service: tear down
4372- my $task20 = Percona::WebAPI::Resource::Task->new(
4373- name => 'disable-gen-log',
4374- number => '0',
4375- query => "SET GLOBAL general_log=OFF",
4376- );
4377- my $task21 = Percona::WebAPI::Resource::Task->new(
4378- name => 'set-gen-log-file',
4379- number => '1',
4380- query => "SET GLOBAL general_log_file='$old_genlog'",
4381- );
4382- my $task22 = Percona::WebAPI::Resource::Task->new(
4383- name => 'enable-gen-log',
4384- number => '2',
4385- query => "SET GLOBAL general_log=ON",
4386- );
4387- my $svc2 = Percona::WebAPI::Resource::Service->new(
4388- ts => 100,
4389- name => 'disable-gen-log',
4390- run_schedule => '5 * * * *',
4391- spool_schedule => '6 * * * *',
4392- tasks => [ $task20, $task21, $task22 ],
4393- );
4394-
4395- write_svc_files(
4396- services => [ $svc0, $svc1, $svc2 ],
4397- );
4398-
4399- $ua->{responses}->{get} = [
4400- {
4401- headers => { 'X-Percona-Resource-Type' => 'Agent' },
4402- content => as_hashref($agent, with_links => 1),
4403- },
4404- {
4405- headers => { 'X-Percona-Resource-Type' => 'Agent' },
4406- content => as_hashref($agent, with_links => 1),
4407- },
4408- {
4409- headers => { 'X-Percona-Resource-Type' => 'Agent' },
4410- content => as_hashref($agent, with_links => 1),
4411- },
4412- ];
4413-
4414- my $cxn = Cxn->new(
4415- dsn_string => $dsn,
4416- OptionParser => $o,
4417- DSNParser => $dp,
4418- );
4419-
4420- # Run the first service.
4421- $output = output(
4422- sub {
4423- $exit_status = pt_agent::run_service(
4424- api_key => '123',
4425- service => 'enable-gen-log',
4426- spool_dir => $spool_dir,
4427- lib_dir => $tmpdir,
4428- Cxn => $cxn,
4429- # for testing:
4430- client => $client,
4431- agent => $agent,
4432- entry_links => $links,
4433- prefix => '3',
4434- json => $json,
4435- bin_dir => "$trunk/bin",
4436- );
4437- },
4438- );
4439-
4440- my (undef, $genlog) = $dbh->selectrow_array(
4441- "SHOW VARIABLES LIKE 'general_log_file'");
4442- is(
4443- $genlog,
4444- $new_genlog,
4445- "Task set MySQL var"
4446- ) or diag($output);
4447-
4448- # Pretend some time passes...
4449-
4450- # The next service doesn't need MySQL, so it shouldn't connect to it.
4451- # To check this, the genlog before running and after running should
4452- # be identical.
4453- `cp $new_genlog $tmpdir/genlog-before`;
4454-
4455- # Run the second service.
4456- $output = output(
4457- sub {
4458- $exit_status = pt_agent::run_service(
4459- api_key => '123',
4460- service => 'query-history',
4461- spool_dir => $spool_dir,
4462- lib_dir => $tmpdir,
4463- Cxn => $cxn,
4464- # for testing:
4465- client => $client,
4466- agent => $agent,
4467- entry_links => $links,
4468- prefix => '4',
4469- json => $json,
4470- bin_dir => "$trunk/bin",
4471- );
4472- },
4473- );
4474-
4475- `cp $new_genlog $tmpdir/genlog-after`;
4476- my $diff = `diff $tmpdir/genlog-before $tmpdir/genlog-after`;
4477- is(
4478- $diff,
4479- '',
4480- "Tasks didn't need MySQL, didn't connect to MySQL"
4481- ) or diag($output);
4482-
4483- # Pretend more time passes...
4484-
4485- # Run the third service.
4486- $output = output(
4487- sub {
4488- $exit_status = pt_agent::run_service(
4489- api_key => '123',
4490- service => 'disable-gen-log',
4491- spool_dir => $spool_dir,
4492- lib_dir => $tmpdir,
4493- Cxn => $cxn,
4494- # for testing:
4495- client => $client,
4496- agent => $agent,
4497- entry_links => $links,
4498- prefix => '5',
4499- json => $json,
4500- bin_dir => "$trunk/bin",
4501- );
4502- },
4503- );
4504-
4505- (undef, $genlog) = $dbh->selectrow_array(
4506- "SHOW VARIABLES LIKE 'general_log_file'");
4507- is(
4508- $genlog,
4509- $old_genlog,
4510- "Task restored MySQL var"
4511- ) or diag($output);
4512-
4513- $dbh->do("SET GLOBAL general_log=ON");
4514- $dbh->do("SET GLOBAL general_log_file='$old_genlog'");
4515-}
4516-
4517-# #############################################################################
4518-# Done.
4519-# #############################################################################
4520-done_testing;
4521
4522=== removed directory 't/pt-agent/samples'
4523=== removed file 't/pt-agent/samples/crontab001.in'
4524=== removed file 't/pt-agent/samples/crontab001.out'
4525--- t/pt-agent/samples/crontab001.out 2013-03-19 22:35:37 +0000
4526+++ t/pt-agent/samples/crontab001.out 1970-01-01 00:00:00 +0000
4527@@ -1,2 +0,0 @@
4528-* 8 * * 1,2,3,4,5 pt-agent --run-service query-history
4529-* 9 * * 1,2,3,4,5 pt-agent --send-data query-history
4530
4531=== removed file 't/pt-agent/samples/crontab002.in'
4532--- t/pt-agent/samples/crontab002.in 2013-01-08 17:55:58 +0000
4533+++ t/pt-agent/samples/crontab002.in 1970-01-01 00:00:00 +0000
4534@@ -1,1 +0,0 @@
4535-17 3 * * 1 cmd
4536
4537=== removed file 't/pt-agent/samples/crontab002.out'
4538--- t/pt-agent/samples/crontab002.out 2013-03-19 22:35:37 +0000
4539+++ t/pt-agent/samples/crontab002.out 1970-01-01 00:00:00 +0000
4540@@ -1,3 +0,0 @@
4541-17 3 * * 1 cmd
4542-* 8 * * 1,2,3,4,5 pt-agent --run-service query-history
4543-* 9 * * 1,2,3,4,5 pt-agent --send-data query-history
4544
4545=== removed file 't/pt-agent/samples/crontab003.in'
4546--- t/pt-agent/samples/crontab003.in 2013-01-08 17:55:58 +0000
4547+++ t/pt-agent/samples/crontab003.in 1970-01-01 00:00:00 +0000
4548@@ -1,3 +0,0 @@
4549-17 3 * * 1 cmd
4550-* * * * 1 pt-agent --run-service old-service
4551-
4552
4553=== removed file 't/pt-agent/samples/crontab003.out'
4554--- t/pt-agent/samples/crontab003.out 2013-03-19 22:35:37 +0000
4555+++ t/pt-agent/samples/crontab003.out 1970-01-01 00:00:00 +0000
4556@@ -1,3 +0,0 @@
4557-17 3 * * 1 cmd
4558-* 8 * * 1,2,3,4,5 pt-agent --run-service query-history
4559-* 9 * * 1,2,3,4,5 pt-agent --send-data query-history
4560
4561=== removed file 't/pt-agent/samples/crontab004.in'
4562--- t/pt-agent/samples/crontab004.in 2013-01-30 20:25:21 +0000
4563+++ t/pt-agent/samples/crontab004.in 1970-01-01 00:00:00 +0000
4564@@ -1,2 +0,0 @@
4565-1 * * * * pt-agent --run-service foo
4566-2 * * * * pt-agent --send-data foo
4567
4568=== removed file 't/pt-agent/samples/crontab004.out'
4569--- t/pt-agent/samples/crontab004.out 2013-03-19 22:35:37 +0000
4570+++ t/pt-agent/samples/crontab004.out 1970-01-01 00:00:00 +0000
4571@@ -1,2 +0,0 @@
4572-* 8 * * 1,2,3,4,5 pt-agent --run-service query-history
4573-* 9 * * 1,2,3,4,5 pt-agent --send-data query-history
4574
4575=== removed directory 't/pt-agent/samples/query-history'
4576=== removed file 't/pt-agent/samples/query-history/data001.json'
4577--- t/pt-agent/samples/query-history/data001.json 2013-11-08 03:03:01 +0000
4578+++ t/pt-agent/samples/query-history/data001.json 1970-01-01 00:00:00 +0000
4579@@ -1,152 +0,0 @@
4580-
4581-{
4582- "classes" : [
4583- {
4584- "attribute" : "fingerprint",
4585- "checksum" : "C72BF45D68E35A6E",
4586- "distillate" : "SELECT tbl",
4587- "example" : {
4588- "Query_time" : "0.018799",
4589- "query" : "SELECT MIN(id),MAX(id) FROM tbl",
4590- "ts" : null
4591- },
4592- "fingerprint" : "select min(id),max(id) from tbl",
4593- "histograms" : {
4594- "Query_time" : [
4595- 0,
4596- 0,
4597- 0,
4598- 0,
4599- 1,
4600- 0,
4601- 0,
4602- 0
4603- ]
4604- },
4605- "metrics" : {
4606- "Lock_time" : {
4607- "avg" : "0.009453",
4608- "max" : "0.009453",
4609- "median" : "0.009453",
4610- "min" : "0.009453",
4611- "pct" : "0.333333",
4612- "pct_95" : "0.009453",
4613- "stddev" : "0.000000",
4614- "sum" : "0.009453"
4615- },
4616- "Query_length" : {
4617- "avg" : "31",
4618- "max" : "31",
4619- "median" : "31",
4620- "min" : "31",
4621- "pct" : "0",
4622- "pct_95" : "31",
4623- "stddev" : "0",
4624- "sum" : "31"
4625- },
4626- "Query_time" : {
4627- "avg" : "0.018799",
4628- "max" : "0.018799",
4629- "median" : "0.018799",
4630- "min" : "0.018799",
4631- "pct" : "0.333333",
4632- "pct_95" : "0.018799",
4633- "stddev" : "0.000000",
4634- "sum" : "0.018799"
4635- },
4636- "Rows_examined" : {
4637- "avg" : "0",
4638- "max" : "0",
4639- "median" : "0",
4640- "min" : "0",
4641- "pct" : "0",
4642- "pct_95" : "0",
4643- "stddev" : "0",
4644- "sum" : "0"
4645- },
4646- "Rows_sent" : {
4647- "avg" : "0",
4648- "max" : "0",
4649- "median" : "0",
4650- "min" : "0",
4651- "pct" : "0",
4652- "pct_95" : "0",
4653- "stddev" : "0",
4654- "sum" : "0"
4655- },
4656- "db" : {
4657- "value" : "db2"
4658- },
4659- "host" : {
4660- "value" : ""
4661- },
4662- "user" : {
4663- "value" : "meow"
4664- }
4665- },
4666- "query_count" : 1,
4667- "tables" : [
4668- {
4669- "create" : "SHOW CREATE TABLE `db2`.`tbl`\\G",
4670- "status" : "SHOW TABLE STATUS FROM `db2` LIKE 'tbl'\\G"
4671- }
4672- ]
4673- }
4674- ],
4675- "global" : {
4676- "files" : [
4677- {
4678- "size" : 656
4679- }
4680- ],
4681- "metrics" : {
4682- "Lock_time" : {
4683- "avg" : "0.003151",
4684- "max" : "0.009453",
4685- "median" : "0.000000",
4686- "min" : "0.000000",
4687- "pct_95" : "0.009171",
4688- "stddev" : "0.004323",
4689- "sum" : "0.009453"
4690- },
4691- "Query_length" : {
4692- "avg" : "24",
4693- "max" : "31",
4694- "median" : "26",
4695- "min" : "14",
4696- "pct_95" : "30",
4697- "stddev" : "6",
4698- "sum" : "72"
4699- },
4700- "Query_time" : {
4701- "avg" : "0.006567",
4702- "max" : "0.018799",
4703- "median" : "0.000882",
4704- "min" : "0.000002",
4705- "pct_95" : "0.018157",
4706- "stddev" : "0.008359",
4707- "sum" : "0.019700"
4708- },
4709- "Rows_examined" : {
4710- "avg" : "0",
4711- "max" : "0",
4712- "median" : "0",
4713- "min" : "0",
4714- "pct_95" : "0",
4715- "stddev" : "0",
4716- "sum" : "0"
4717- },
4718- "Rows_sent" : {
4719- "avg" : "0",
4720- "max" : "0",
4721- "median" : "0",
4722- "min" : "0",
4723- "pct_95" : "0",
4724- "stddev" : "0",
4725- "sum" : "0"
4726- }
4727- },
4728- "query_count" : 3,
4729- "unique_query_count" : 3
4730- }
4731-}
4732
4733=== removed file 't/pt-agent/samples/query-history/data001.send'
4734--- t/pt-agent/samples/query-history/data001.send 2013-11-08 03:03:01 +0000
4735+++ t/pt-agent/samples/query-history/data001.send 1970-01-01 00:00:00 +0000
4736@@ -1,166 +0,0 @@
4737---Ym91bmRhcnk
4738-Content-Disposition: form-data; name="agent"
4739-
4740-{
4741- "hostname" : "prod1",
4742- "uuid" : "123"
4743-}
4744---Ym91bmRhcnk
4745-Content-Disposition: form-data; name="meta"
4746-
4747-
4748---Ym91bmRhcnk
4749-Content-Disposition: form-data; name="data"
4750-
4751-{
4752- "classes" : [
4753- {
4754- "attribute" : "fingerprint",
4755- "checksum" : "C72BF45D68E35A6E",
4756- "distillate" : "SELECT tbl",
4757- "example" : {
4758- "Query_time" : "0.018799",
4759- "query" : "SELECT MIN(id),MAX(id) FROM tbl",
4760- "ts" : null
4761- },
4762- "fingerprint" : "select min(id),max(id) from tbl",
4763- "histograms" : {
4764- "Query_time" : [
4765- 0,
4766- 0,
4767- 0,
4768- 0,
4769- 1,
4770- 0,
4771- 0,
4772- 0
4773- ]
4774- },
4775- "metrics" : {
4776- "Lock_time" : {
4777- "avg" : "0.009453",
4778- "max" : "0.009453",
4779- "median" : "0.009453",
4780- "min" : "0.009453",
4781- "pct" : "0.333333",
4782- "pct_95" : "0.009453",
4783- "stddev" : "0.000000",
4784- "sum" : "0.009453"
4785- },
4786- "Query_length" : {
4787- "avg" : "31",
4788- "max" : "31",
4789- "median" : "31",
4790- "min" : "31",
4791- "pct" : "0",
4792- "pct_95" : "31",
4793- "stddev" : "0",
4794- "sum" : "31"
4795- },
4796- "Query_time" : {
4797- "avg" : "0.018799",
4798- "max" : "0.018799",
4799- "median" : "0.018799",
4800- "min" : "0.018799",
4801- "pct" : "0.333333",
4802- "pct_95" : "0.018799",
4803- "stddev" : "0.000000",
4804- "sum" : "0.018799"
4805- },
4806- "Rows_examined" : {
4807- "avg" : "0",
4808- "max" : "0",
4809- "median" : "0",
4810- "min" : "0",
4811- "pct" : "0",
4812- "pct_95" : "0",
4813- "stddev" : "0",
4814- "sum" : "0"
4815- },
4816- "Rows_sent" : {
4817- "avg" : "0",
4818- "max" : "0",
4819- "median" : "0",
4820- "min" : "0",
4821- "pct" : "0",
4822- "pct_95" : "0",
4823- "stddev" : "0",
4824- "sum" : "0"
4825- },
4826- "db" : {
4827- "value" : "db2"
4828- },
4829- "host" : {
4830- "value" : ""
4831- },
4832- "user" : {
4833- "value" : "meow"
4834- }
4835- },
4836- "query_count" : 1,
4837- "tables" : [
4838- {
4839- "create" : "SHOW CREATE TABLE `db2`.`tbl`\\G",
4840- "status" : "SHOW TABLE STATUS FROM `db2` LIKE 'tbl'\\G"
4841- }
4842- ]
4843- }
4844- ],
4845- "global" : {
4846- "files" : [
4847- {
4848- "size" : 656
4849- }
4850- ],
4851- "metrics" : {
4852- "Lock_time" : {
4853- "avg" : "0.003151",
4854- "max" : "0.009453",
4855- "median" : "0.000000",
4856- "min" : "0.000000",
4857- "pct_95" : "0.009171",
4858- "stddev" : "0.004323",
4859- "sum" : "0.009453"
4860- },
4861- "Query_length" : {
4862- "avg" : "24",
4863- "max" : "31",
4864- "median" : "26",
4865- "min" : "14",
4866- "pct_95" : "30",
4867- "stddev" : "6",
4868- "sum" : "72"
4869- },
4870- "Query_time" : {
4871- "avg" : "0.006567",
4872- "max" : "0.018799",
4873- "median" : "0.000882",
4874- "min" : "0.000002",
4875- "pct_95" : "0.018157",
4876- "stddev" : "0.008359",
4877- "sum" : "0.019700"
4878- },
4879- "Rows_examined" : {
4880- "avg" : "0",
4881- "max" : "0",
4882- "median" : "0",
4883- "min" : "0",
4884- "pct_95" : "0",
4885- "stddev" : "0",
4886- "sum" : "0"
4887- },
4888- "Rows_sent" : {
4889- "avg" : "0",
4890- "max" : "0",
4891- "median" : "0",
4892- "min" : "0",
4893- "pct_95" : "0",
4894- "stddev" : "0",
4895- "sum" : "0"
4896- }
4897- },
4898- "query_count" : 3,
4899- "unique_query_count" : 3
4900- }
4901-}
4902---Ym91bmRhcnk
4903
4904=== removed file 't/pt-agent/samples/service001'
4905--- t/pt-agent/samples/service001 2013-06-17 04:01:30 +0000
4906+++ t/pt-agent/samples/service001 1970-01-01 00:00:00 +0000
4907@@ -1,19 +0,0 @@
4908-{
4909- "links" : {
4910- "data" : "/query-history/data",
4911- "self" : "/query-history"
4912- },
4913- "name" : "query-history",
4914- "run_schedule" : "1 * * * *",
4915- "spool_schedule" : "2 * * * *",
4916- "tasks" : [
4917- {
4918- "name" : "query-history",
4919- "number" : "0",
4920- "options" : "--output json",
4921- "output" : "spool",
4922- "program" : "pt-query-digest"
4923- }
4924- ],
4925- "ts" : 100
4926-}
4927
4928=== removed file 't/pt-agent/samples/write_services001'
4929--- t/pt-agent/samples/write_services001 2013-06-17 00:28:18 +0000
4930+++ t/pt-agent/samples/write_services001 1970-01-01 00:00:00 +0000
4931@@ -1,19 +0,0 @@
4932-{
4933- "links" : {
4934- "data" : "/query-history/data",
4935- "self" : "/query-history"
4936- },
4937- "name" : "query-history",
4938- "run_schedule" : "1 * * * *",
4939- "spool_schedule" : "2 * * * *",
4940- "tasks" : [
4941- {
4942- "name" : "query-history",
4943- "number" : "0",
4944- "options" : "--report-format profile slow008.txt",
4945- "output" : "spool",
4946- "program" : "pt-query-digest"
4947- }
4948- ],
4949- "ts" : 100
4950-}
4951
4952=== removed file 't/pt-agent/schedule_services.t'
4953--- t/pt-agent/schedule_services.t 2013-06-17 00:28:18 +0000
4954+++ t/pt-agent/schedule_services.t 1970-01-01 00:00:00 +0000
4955@@ -1,200 +0,0 @@
4956-#!/usr/bin/env perl
4957-
4958-BEGIN {
4959- die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
4960- unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
4961- unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
4962-};
4963-
4964-use strict;
4965-use warnings FATAL => 'all';
4966-use English qw(-no_match_vars);
4967-use Test::More;
4968-use JSON;
4969-use File::Temp qw(tempfile tempdir);
4970-
4971-use Percona::Test;
4972-use Percona::Test::Mock::AgentLogger;
4973-require "$trunk/bin/pt-agent";
4974-
4975-my $crontab = `crontab -l 2>/dev/null`;
4976-if ( $crontab ) {
4977- plan skip_all => 'Crontab is not empty';
4978-}
4979-
4980-Percona::Toolkit->import(qw(have_required_args Dumper));
4981-
4982-my $sample = "t/pt-agent/samples";
4983-my $tmpdir = tempdir("/tmp/pt-agent.$PID.XXXXXX", CLEANUP => 1);
4984-
4985-my @log;
4986-my $logger = Percona::Test::Mock::AgentLogger->new(log => \@log);
4987-pt_agent::_logger($logger);
4988-
4989-# #############################################################################
4990-# Schedule a good crontab.
4991-# #############################################################################
4992-
4993-my $run0 = Percona::WebAPI::Resource::Task->new(
4994- name => 'query-history',
4995- number => '0',
4996- program => 'pt-query-digest',
4997- options => '--output json',
4998- output => 'spool',
4999-);
5000-
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches