Commit | Line | Data |
60e1cc39 |
1 | package System::Introspector::State; |
2 | use Moo; |
3 | use Data::YAML::Writer; |
4 | use Object::Remote; |
5 | use Object::Remote::Future; |
6 | use System::Introspector::Gatherer; |
7 | |
0a11cf83 |
8 | use JSON::Diffable qw( encode_json ); |
9 | |
60e1cc39 |
10 | has config => (is => 'ro', required => 1); |
11 | |
12 | has introspectors => (is => 'lazy'); |
13 | |
14 | has host => (is => 'ro'); |
15 | |
16 | has storage => (is => 'ro', required => 1); |
17 | |
18 | has node_path => (is => 'lazy'); |
19 | |
20 | sub fetch { |
21 | my ($self) = @_; |
22 | my $gatherer = $self->_create_gatherer; |
23 | my $spec = $self->introspectors; |
24 | my %report; |
25 | for my $class_base (sort keys %$spec) { |
26 | $report{ $class_base } = $gatherer |
27 | ->gather($class_base, $spec->{ $class_base }); |
28 | } |
29 | return \%report; |
30 | } |
31 | |
32 | sub fetch_and_store { |
33 | my ($self) = @_; |
34 | return $self->_store($self->fetch); |
35 | } |
36 | |
37 | sub _build_node_path { |
38 | my ($self) = @_; |
39 | return defined($self->host) |
40 | ? sprintf('host/%s', $self->host) |
41 | : 'local'; |
42 | } |
43 | |
44 | sub _build_introspectors { |
45 | my ($self) = @_; |
46 | return $self->config->{introspect}; |
47 | } |
48 | |
49 | sub _store { |
50 | my ($self, $data) = @_; |
60e1cc39 |
51 | my $storage = $self->storage; |
52 | my @files; |
53 | for my $class (sort keys %$data) { |
0a11cf83 |
54 | my $file = sprintf '%s.json', join '/', |
60e1cc39 |
55 | node => $self->node_path, |
56 | map lc, map { |
57 | s{([a-z0-9])([A-Z])}{${1}_${2}}g; |
58 | $_; |
59 | } split m{::}, $class; |
60 | my $fh = $storage->open('>:utf8', $file, mkpath => 1); |
61 | print "Writing $file\n"; |
0a11cf83 |
62 | print $fh encode_json($data->{$class}); |
60e1cc39 |
63 | push @files, $storage->file($file); |
64 | } |
65 | $self->_cleanup(\@files); |
66 | return 1; |
67 | } |
68 | |
69 | sub _cleanup { |
70 | my ($self, $known_files) = @_; |
71 | my %known = map { ($_ => 1) } @$known_files; |
72 | my $data_dir = $self->storage->file(node => $self->node_path); |
73 | my @files = $self->storage->find_files('yml', node => $self->node_path); |
74 | for my $file (@files) { |
75 | next if $known{$file}; |
76 | print "Removing $file\n"; |
77 | unlink($file) |
78 | or die "Unable to remove '$file': $!\n"; |
79 | } |
80 | return 1; |
81 | } |
82 | |
83 | sub _create_gatherer { |
84 | my ($self) = @_; |
85 | if (defined( my $host = $self->host )) { |
86 | return System::Introspector::Gatherer->new::on($host); |
87 | } |
88 | return System::Introspector::Gatherer->new; |
89 | } |
90 | |
91 | 1; |
cd5c3d43 |
92 | |
93 | =head1 NAME |
94 | |
95 | System::Introspector::State - Gather system state |
96 | |
97 | =head1 SYNOPSIS |
98 | |
99 | my $state = System::Introspector::State->new( |
100 | host => 'foo.example.com', |
101 | storage => $storage_obj, |
102 | config => { |
103 | introspect => [qw( ProbeName )], |
104 | }, |
105 | ); |
106 | |
107 | my $data = $state->fetch; |
108 | $state->fetch_and_store; |
109 | |
110 | =head1 DESCRIPTION |
111 | |
112 | Gathers system introspection data based on configuration and stores |
113 | it with a L<File::Tree::Snapshot> object. |
114 | |
115 | =head1 ATTRIBUTES |
116 | |
117 | =head2 config |
118 | |
119 | A hash reference containing a C<introspect> key with an array reference |
120 | value containing a list of probe names without the |
121 | C<System::Introspector::Probe::> prefix. This attribute is required. |
122 | |
123 | =head2 host |
124 | |
125 | An optional hostname. If no hostname is supplied, the local configuration |
126 | data will be fetched. |
127 | |
128 | =head2 storage |
129 | |
130 | A L<File::Tree::Snapshot> object. |
131 | |
132 | =head1 METHODS |
133 | |
134 | =head2 fetch |
135 | |
136 | my $data = $state->fetch; |
137 | |
138 | Fetches all probe data. |
139 | |
140 | =head2 fetch_and_store |
141 | |
142 | $state->fetch_and_store; |
143 | |
144 | Fetches all probe data and stores it in the L</storage>. |
145 | |
146 | =cut |