'c|config=s' => \my $config_file,
's|storage=s' => \my $storage_dir,
'H|host=s' => \my $hostname,
+ 'U|user=s' => \my $username,
'allow-empty' => \my $allow_empty,
'a|all' => \my $update_all,
'g|group=s' => \my @update_groups,
die "Requires --all or --group option\n"
unless $update_all or @update_groups;
+die "The --user option also requires a --host to be set\n"
+ if defined($username) and not defined($hostname);
+
my $config = System::Introspector::Config->new(
config_file => (defined($config_file)
? $config_file
@update_groups = $config->groups
if $update_all;
+
+my $sudo_user = $config->sudo_user;
for my $group (@update_groups) {
my $group_dir = "$storage_dir/$group";
$storage->create
unless $storage->exists;
my $state = System::Introspector::State->new(
- defined($hostname) ? (host => $hostname) : (),
+ defined($hostname) ? (host => $hostname) : (),
+ defined($username) ? (user => $username) : (),
+ defined($sudo_user) ? (sudo_user => $sudo_user) : (),
storage => $storage,
config => $config->config_for_group($group),
);
eval { $state->fetch_and_store };
if (my $error = $@) {
+ warn "Error: $error\n";
$storage->reset;
}
else {
return \%config;
}
+sub sudo_user { $_[0]->config->{sudo_user} }
+
sub groups { keys %{ $_[0]->config->{group} || {} } }
sub has_group { exists $_[0]->config->{group}{ $_[1] } }
-sub config_for_group { $_[0]->config->{group}{ $_[1] } }
+my $_get_inherited = sub {
+ my $data = shift;
+ $data ||= {};
+ return
+ map { ($_ => $data->{$_}) }
+ grep { exists $data->{$_} }
+ qw( sudo );
+};
+
+sub config_for_group {
+ my ($self, $name) = @_;
+ my %common;
+ my $config = $self->config;
+ %common = (%common, $config->$_get_inherited);
+ my $group = $config->{group}{ $name };
+ %common = (%common, $group->$_get_inherited);
+ return {
+ introspect => {
+ map {
+ ($_ => {
+ %common,
+ %{ $group->{introspect}{ $_ } || {} },
+ });
+ } keys %{ $group->{introspect} || {} },
+ },
+ };
+}
1;
package System::Introspector::Gatherer;
use Moo;
+use Object::Remote;
+use Object::Remote::Future;
+use System::Introspector::Gatherer::Bridge;
use Module::Runtime qw( use_module );
sub gather {
my ($self, $class, $args) = @_;
- return use_module("System::Introspector::$class")
+ return use_module("System::Introspector::Probe::$class")
->new($args)
->gather;
}
+sub _new_direct {
+ my ($class, $remote) = @_;
+ return $class->new::on($remote);
+}
+
+sub _new_bridged {
+ my ($class, $bridge, $remote) = @_;
+ return System::Introspector::Gatherer::Bridge->new::on($bridge,
+ remote_spec => $remote,
+ remote_class => $class,
+ );
+}
+
+sub new_from_spec {
+ my ($class, %arg) = @_;
+ my ($user, $host, $sudo_user) = @arg{qw( user host sudo_user )};
+ my $sudo = defined($sudo_user) ? sprintf('%s@', $sudo_user) : undef;
+ if (defined $host) {
+ my $remote = join '@', grep defined, $user, $host;
+ if (defined $sudo_user) {
+ return $class->_new_bridged($remote, $sudo);
+ }
+ else {
+ return $class->_new_direct($remote);
+ }
+ }
+ else {
+ if (defined $sudo_user) {
+ return $class->_new_direct($sudo);
+ }
+ else {
+ return $class->new;
+ }
+ }
+}
+
1;
--- /dev/null
+package System::Introspector::Gatherer::Bridge;
+use Object::Remote;
+use Object::Remote::Future;
+use Moo;
+
+has remote_spec => (is => 'ro', required => 1);
+has remote_class => (is => 'ro', required => 1);
+has remote => (is => 'lazy');
+
+sub _build_remote {
+ my ($self) = @_;
+ return $self->remote_class->new::on($self->remote_spec);
+}
+
+sub gather { (shift)->remote->gather(@_) }
+
+1;
package System::Introspector::State;
use Moo;
-use Data::YAML::Writer;
-use Object::Remote;
-use Object::Remote::Future;
use System::Introspector::Gatherer;
use JSON::Diffable qw( encode_json );
has host => (is => 'ro');
+has user => (is => 'ro');
+
+has sudo_user => (is => 'ro');
+
has storage => (is => 'ro', required => 1);
has node_path => (is => 'lazy');
sub fetch {
my ($self) = @_;
- my $gatherer = $self->_create_gatherer;
- my $spec = $self->introspectors;
+ my $spec = $self->introspectors;
+ my (@sudo, @nosudo);
+ push(@{ $spec->{$_}{sudo} ? \@sudo : \@nosudo}, [$_, $spec->{$_}])
+ for sort keys %$spec;
my %report;
- for my $class_base (sort keys %$spec) {
+ if (@nosudo) {
+ my $gatherer = $self->_create_gatherer;
+ %report = %{ $self->_fetch_with_gatherer($gatherer, @nosudo) || {} };
+ }
+ if (@sudo) {
+ my $gatherer = $self->_create_gatherer(sudo => 1);
+ %report = (%report, %{ $self->_fetch_with_gatherer($gatherer, @sudo) || {} });
+ }
+ return \%report;
+}
+
+sub _fetch_with_gatherer {
+ my ($self, $gatherer, @spec) = @_;
+ my %report;
+ for my $class_spec (@spec) {
+ my ($class_base, $args) = @$class_spec;
+ print "Gathering $class_base data\n";
$report{ $class_base } = $gatherer
- ->gather($class_base, $spec->{ $class_base });
+ ->gather($class_base, $args);
}
+ print "All gathered\n";
return \%report;
}
sub fetch_and_store {
my ($self) = @_;
- return $self->_store($self->fetch);
+ my $data = $self->fetch;
+ return $self->_store($data);
}
sub _build_node_path {
}
sub _create_gatherer {
- my ($self) = @_;
- if (defined( my $host = $self->host )) {
- return System::Introspector::Gatherer->new::on($host);
- }
- return System::Introspector::Gatherer->new;
+ my ($self, %arg) = @_;
+ return System::Introspector::Gatherer->new_from_spec(
+ user => $self->user,
+ host => $self->host,
+ sudo_user => $arg{sudo} && $self->sudo_user,
+ );
}
1;