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