File Coverage

blib/lib/Csistck.pm
Criterion Covered Total %
statement 82 98 83.6
branch 12 24 50.0
condition 3 15 20.0
subroutine 20 21 95.2
pod 3 4 75.0
total 120 162 74.0


line stmt bran cond sub pod time code
1             package Csistck;
2              
3 17     17   541330 use 5.010;
  17         63  
  17         797  
4 17     17   99 use strict;
  17         28  
  17         1091  
5 17     17   86 use warnings;
  17         39  
  17         839  
6              
7             our $VERSION = '0.1003';
8              
9             # We export function in the main namespace
10 17     17   79 use base 'Exporter';
  17         36  
  17         2208  
11             our @EXPORT = qw(
12             host
13             role
14             check
15             option
16              
17             file
18             noop
19             pkg
20             script
21             template
22             );
23              
24             # Imports for base
25 17     17   9941 use Csistck::Config qw/option/;
  17         42  
  17         1384  
26 17     17   10307 use Csistck::Test::NOOP qw/noop/;
  17         52  
  17         1340  
27 17     17   10928 use Csistck::Test::File qw/file/;
  17         109  
  17         1879  
28 17     17   15846 use Csistck::Test::Pkg qw/pkg/;
  17         55  
  17         1288  
29 17     17   10120 use Csistck::Test::Script qw/script/;
  17         48  
  17         1101  
30 17     17   9496 use Csistck::Test::Template qw/template/;
  17         41  
  17         1036  
31              
32 17     17   8658 use Csistck::Role;
  17         45  
  17         421  
33 17     17   9749 use Csistck::Term;
  17         113  
  17         813  
34              
35 17     17   113 use Sys::Hostname::Long qw//;
  17         36  
  17         573  
36 17     17   22435 use Data::Dumper;
  17         145311  
  17         1431  
37 17     17   280 use Scalar::Util qw/blessed reftype/;
  17         41  
  17         954  
38 17     17   159 use List::Util qw/sum/;
  17         38  
  17         19956  
39              
40             # Package wide
41             my $Hosts = {};
42             my $Roles = {};
43              
44              
45             =head1 NAME
46              
47             Csistck - Perl system consistency check framework
48              
49             =head1 SYNOPSIS
50              
51             use Csistck;
52            
53             sub sig_hup_mysql { $ENV{'MAINT_HUP_MYSQL'} = 1; }
54              
55             for (qw/a b/) {
56             host "$_.example.com" => role('mysql');
57             }
58              
59             host 'c' => role('mysql');
60            
61             role 'mysql' =>
62             pkg({
63             dpkg => 'mysql-server',
64             emerge => 'mysql'
65             }),
66             template(
67             '/etc/mysql/my.cnf',
68             src => 'mysql/my.cnf',
69             mysql => {
70             bind => '127.0.0.1',
71             keysize => '1G'
72             },
73             mode => '0644',
74             uid => 100,
75             gid => 100,
76             on_restart => \&sig_hup_mysql
77             ),
78             script('services.sh');
79            
80             check;
81              
82             The script can then be called directly, using command line arguments below
83              
84             =head1 DESCRIPTION
85              
86             Csistck is a small Perl framework for writing scripts to maintain system
87             configuration and consistency. The focus of csistck is to stay lightweight,
88             simple, and flexible.
89              
90             =head1 EXTENDING ROLES
91              
92             Roles can be defined using the C keyword syntax, however a more flexible
93             method is to extend a new object from L:
94              
95             use Csistck;
96             use base 'Csistck::Role';
97              
98             sub defaults {
99             my $self = shift;
100             $self->{config} = '/etc/example.conf';
101             }
102              
103             sub tests {
104             my $self = shift;
105             $self->add(pkg({
106             dpkg => 'test-server',
107             pkg_info => 'net-test'
108             }),
109             template(
110             $self->{config},
111             src => 'files/example.conf',
112             example => $self
113             );
114              
115             }
116              
117             1;
118              
119             See L for information on extending roles
120              
121              
122             =head1 METHODS
123              
124              
125             =head2 host($host, $checks)
126              
127             Add tests to host C<$host> test array. Tests are Csistck::Test blessed references, code
128             references, or arrays of either. To process host tests, use C.
129              
130             =cut
131              
132             sub host {
133 3     3 1 775 my $hostname = shift;
134              
135             # Add domain if option is set?
136 3         15 my $domain_name = Csistck::Config::option('domain_name');
137 3 50       12 $hostname = join '.', $hostname, $domain_name
138             if (defined $domain_name);
139              
140 3         25 while (my $require = shift) {
141 3         5 push(@{$Hosts->{$hostname}}, $require);
  3         13  
142             }
143              
144 3         9 return $Hosts->{$hostname};
145             }
146              
147             =head2 role($role, $checks)
148              
149             Define a weak role. Constructed similar to a host check, however roles are not
150             called directly, rather they are used to define groups of common tests that can
151             be used by multiple hosts.
152              
153             See L above for an object-based style of defining roles, which
154             allows for passing role configuration.
155              
156             =cut
157              
158             sub role {
159 1     1 1 2 my $role = shift;
160              
161             # If tests specified, add now
162 1         11 while (my $require = shift) {
163 1         2 push(@{$Roles->{$role}}, $require);
  1         7  
164             }
165              
166             return sub {
167             # Run required role or die
168 0 0   0   0 die ("What's this, \"${role}\"? That role is bupkis.")
169             unless (defined $Roles->{$role});
170            
171 0         0 process($Roles->{$role});
172             }
173 1         9 }
174              
175             =head2 check($target)
176              
177             Runs processing on C<$target>. If C<$target> is C, then look up the
178             system's full hostname. If C<$target> is a string, use that string for a
179             hostname lookup. If C<$target> is a C reference, a coderef, or an
180             arrayref, then process that object directly. This is useful for writing scripts
181             where hostname is not important.
182              
183             =cut
184              
185             sub check {
186 5   33 5 1 765 my $target = shift // Sys::Hostname::Long::hostname_long();
187              
188             # Process cli arguments for mode/etc, usage
189 5         19 Csistck::Oper::set_mode_by_cli();
190 5 50       14 return if (Csistck::Oper::usage());
191              
192             # Role names specified on the command line via --role have priority. If
193             # target is a string, process as hostname reference. Otherwise, assume a
194             # test object was passed
195 5 50       7 if (scalar @{$Csistck::Oper::Roles} gt 0) {
  5 100       33  
196 0         0 return process(
197 0         0 map { role($_) } @{$Csistck::Oper::Roles}
  0         0  
198             );
199             }
200             elsif (!defined(reftype($target))) {
201 2 100       20 die ("What's this, \"${target}\"? That host is bupkis.")
202             unless (defined $Hosts->{$target});
203 1         5 return process($Hosts->{$target});
204             }
205             else {
206 3         9 return process($target);
207             }
208             }
209              
210             # For recursive testing based on type
211             sub process {
212 7     7 0 13 my $obj = shift;
213            
214             # Iterate through array and recursively call process, call code refs,
215             # and run tests
216              
217 7         12 given (ref $obj) {
218 7         21 when ('ARRAY') {
219 2         3 return map(process($_), @{$obj});
  2         9  
220             }
221 5         8 when ('CODE') {
222 0         0 return &{$obj};
  0         0  
223             }
224 5         6 default {
225 5 50 33     58 if (blessed($obj) and $obj->isa('Csistck::Test')) {
    0 0        
226             # Check is mandatory, if auto repair is set, repair, otherwise prompt
227 5         22 my $check = $obj->execute('check');
228 5 100       18 return if ($check->passed);
229            
230 1 50       6 if (Csistck::Oper::repair()) {
231 1         5 my $repair = $obj->execute('repair');
232 1 50 33     11 if ($repair->passed and $obj->on_repair) {
233 0         0 &{$obj->on_repair};
  0         0  
234             }
235 1         15 return $repair;
236             }
237             else {
238 0           my $repair = Csistck::Term::prompt($obj);
239 0 0 0       if ($repair->passed and $obj->on_repair) {
240 0           &{$obj->on_repair};
  0            
241             }
242 0           return $repair;
243             }
244             }
245             elsif (blessed($obj) and $obj->isa('Csistck::Role')) {
246 0           return process($obj->get_tests);
247             }
248             else {
249 0           die(sprintf("Unkown object reference: ref=<%s>", ref $obj));
250             }
251             }
252             }
253             }
254              
255             1;
256             __END__