use test data for Perls probe
[scpubgit/System-Introspector.git] / lib / System / Introspector / State.pm
CommitLineData
60e1cc39 1package System::Introspector::State;
2use Moo;
b079a95d 3use File::Tree::Snapshot;
60e1cc39 4use System::Introspector::Gatherer;
5
0a11cf83 6use JSON::Diffable qw( encode_json );
7
60e1cc39 8has config => (is => 'ro', required => 1);
9
b079a95d 10has root => (is => 'ro', required => 1);
60e1cc39 11
b079a95d 12sub user { $_[0]->config->user }
60e1cc39 13
b079a95d 14sub sudo_user { $_[0]->config->sudo_user }
a5e1e1c6 15
b079a95d 16sub gather {
17 my ($self, @groups) = @_;
18 for my $host ($self->config->hosts) {
19 $self->fetch_and_store($host, @groups);
20 }
21 return 1;
22}
a5e1e1c6 23
b079a95d 24sub introspectors {
25 my ($self, $group) = @_;
26 return $self->config->config_for_group($group)->{introspect};
27}
60e1cc39 28
b079a95d 29sub fetch_and_store {
30 my ($self, $host, @groups) = @_;
31 my $data = $self->fetch($host, @groups);
32 return $self->_store($host, $data);
33}
60e1cc39 34
35sub fetch {
b079a95d 36 my ($self, $host, @groups) = @_;
37 return +{ map {
38 ($_, $self->fetch_group($host, $_));
39 } @groups };
40}
41
42sub fetch_group {
43 my ($self, $host, $group) = @_;
44 my $spec = $self->introspectors($group);
a5e1e1c6 45 my (@sudo, @nosudo);
46 push(@{ $spec->{$_}{sudo} ? \@sudo : \@nosudo}, [$_, $spec->{$_}])
47 for sort keys %$spec;
48 my %report;
49 if (@nosudo) {
b079a95d 50 my $gatherer = $self->_create_gatherer(host => $host);
a5e1e1c6 51 %report = %{ $self->_fetch_with_gatherer($gatherer, @nosudo) || {} };
52 }
53 if (@sudo) {
b079a95d 54 my $gatherer = $self->_create_gatherer(sudo => 1, host => $host);
a5e1e1c6 55 %report = (%report, %{ $self->_fetch_with_gatherer($gatherer, @sudo) || {} });
56 }
57 return \%report;
58}
59
60sub _fetch_with_gatherer {
61 my ($self, $gatherer, @spec) = @_;
60e1cc39 62 my %report;
a5e1e1c6 63 for my $class_spec (@spec) {
64 my ($class_base, $args) = @$class_spec;
65 print "Gathering $class_base data\n";
60e1cc39 66 $report{ $class_base } = $gatherer
a5e1e1c6 67 ->gather($class_base, $args);
60e1cc39 68 }
a5e1e1c6 69 print "All gathered\n";
60e1cc39 70 return \%report;
71}
72
b079a95d 73sub storage {
74 my ($self, @path) = @_;
75 my $storage = File::Tree::Snapshot->new(
76 allow_empty => 0,
77 storage_path => join('/', $self->root, @path),
78 );
79 $storage->create
80 unless $storage->exists;
81 return $storage;
60e1cc39 82}
83
84sub _store {
b079a95d 85 my ($self, $host, $data) = @_;
86 for my $group (sort keys %$data) {
87 my $storage = $self->storage($host, $group);
88 my $gathered = $data->{$group};
89 my @files;
90 for my $class (sort keys %$gathered) {
91 my $file = sprintf '%s.json', join '/',
92 map lc, map {
93 s{([a-z0-9])([A-Z])}{${1}_${2}}g;
94 $_;
95 } split m{::}, $class;
96 my $fh = $storage->open('>:utf8', $file, mkpath => 1);
97 print "Writing $file\n";
98 print $fh encode_json($gathered->{$class});
99 push @files, $storage->file($file);
100 }
101 $self->_cleanup($storage, [@files]);
102 $storage->commit;
60e1cc39 103 }
60e1cc39 104 return 1;
105}
106
107sub _cleanup {
b079a95d 108 my ($self, $storage, $known_files) = @_;
60e1cc39 109 my %known = map { ($_ => 1) } @$known_files;
b079a95d 110 my @files = $storage->find_files('json');
60e1cc39 111 for my $file (@files) {
112 next if $known{$file};
113 print "Removing $file\n";
114 unlink($file)
115 or die "Unable to remove '$file': $!\n";
116 }
117 return 1;
118}
119
120sub _create_gatherer {
a5e1e1c6 121 my ($self, %arg) = @_;
122 return System::Introspector::Gatherer->new_from_spec(
123 user => $self->user,
b079a95d 124 host => $arg{host},
a5e1e1c6 125 sudo_user => $arg{sudo} && $self->sudo_user,
126 );
60e1cc39 127}
128
1291;
cd5c3d43 130
131=head1 NAME
132
133System::Introspector::State - Gather system state
134
135=head1 SYNOPSIS
136
137 my $state = System::Introspector::State->new(
138 host => 'foo.example.com',
139 storage => $storage_obj,
140 config => {
141 introspect => [qw( ProbeName )],
142 },
143 );
144
145 my $data = $state->fetch;
146 $state->fetch_and_store;
147
148=head1 DESCRIPTION
149
150Gathers system introspection data based on configuration and stores
151it with a L<File::Tree::Snapshot> object.
152
153=head1 ATTRIBUTES
154
155=head2 config
156
157A hash reference containing a C<introspect> key with an array reference
158value containing a list of probe names without the
159C<System::Introspector::Probe::> prefix. This attribute is required.
160
161=head2 host
162
163An optional hostname. If no hostname is supplied, the local configuration
164data will be fetched.
165
166=head2 storage
167
168A L<File::Tree::Snapshot> object.
169
170=head1 METHODS
171
172=head2 fetch
173
174 my $data = $state->fetch;
175
176Fetches all probe data.
177
178=head2 fetch_and_store
179
180 $state->fetch_and_store;
181
182Fetches all probe data and stores it in the L</storage>.
183
184=cut