Configd
view release on metacpan or search on metacpan
bin/configd view on Meta::CPAN
# is nothing here to restart.
$opt{restart} //= defined $opt{root} ? 0 : 1;
my %opts = ( configd => $opt{configd} );
$opts{root} = $opt{root} if defined $opt{root};
my %dispatch = (
languages => \&languages,
adopt => \&adopt,
build => \&build,
status => \&status,
release => \&release,
);
my $handler = $dispatch{$command};
unless ($handler) {
warn "No such command '$command'. Try: " . join( ', ', sort keys %dispatch ) . "\n";
return 2;
}
my $result = eval { $handler->( shift(@args), \%opt, \%opts ) };
if ($@) {
warn $@;
return 1;
}
return $result;
}
sub say_unless_quiet {
my ( $opt, @lines ) = @_;
return if $opt->{quiet};
say $_ for @lines;
return;
}
sub languages {
my ( $name, $opt ) = @_;
my @known = Configd->languages();
say_unless_quiet( $opt, @known ? @known : 'No languages installed.' );
return 0;
}
sub build {
my ( $name, $opt, $opts ) = @_;
my @changed = Configd->build( $name, %$opts );
say_unless_quiet( $opt, @changed ? map { "Rebuilt $_" } @changed : "$name is already up to date" );
return 0;
}
sub adopt {
my ( $name, $opt, $opts ) = @_;
my $result = Configd->adopt( $name, %$opts );
say_unless_quiet( $opt,
( map { "Adopted $_ (its fragments are in $_.d)" } @{ $result->{adopted} } ),
( map { "Wrote $_" } @{ $result->{dropins} } ),
);
# Nothing the daemon reads has changed until systemd is told about the
# drop-in, so an adopt that skips this leaves a service running on config it
# will regenerate differently the next time anything restarts it.
return systemd( $result->{services}, $opt ) if $opt->{restart};
say_unless_quiet( $opt, 'Not restarting; run systemctl daemon-reload and restart the service to pick this up.' );
return 0;
}
sub release {
my ( $name, $opt, $opts ) = @_;
my $result = Configd->release( $name, %$opts );
say_unless_quiet( $opt,
( map { "Removed $_" } @{ $result->{dropins} } ),
( map { "Restored $_" } @{ $result->{released} } ),
);
return $opt->{restart} ? systemd( $result->{services}, $opt ) : 0;
}
sub status {
my ( $name, $opt, $opts ) = @_;
my $status = Configd->status( $name, %$opts );
my @lines = ("$status->{language}:");
foreach my $file ( @{ $status->{files} } ) {
my $count = scalar @{ $file->{fragments} };
push @lines, sprintf(
' %-30s %s, %d fragment%s',
$file->{path},
$file->{adopted} ? 'adopted' : 'NOT adopted',
$count, $count == 1 ? q{} : 's',
);
push @lines, " $_" for @{ $file->{fragments} };
}
push @lines, ' ' . join( ', ', @{ $status->{units} } ) . ( $status->{wrapped} ? ': wrapped' : ': NOT wrapped' );
say_unless_quiet( $opt, @lines );
# So that `configd status x && ...` means what it looks like it means.
return $status->{wrapped} ? 0 : 1;
}
sub systemd {
my ( $services, $opt ) = @_;
my @commands = ( [qw{systemctl daemon-reload}] );
# try-restart rather than restart: a service that is not running was not
# meant to be started by a configuration change.
push @commands, [ 'systemctl', 'try-restart', $_ ] for @$services;
foreach my $command (@commands) {
say_unless_quiet( $opt, '+ ' . join( q{ }, @$command ) );
# systemd's real API is DBus, and Net::DBus would be the library answer
# here. It is not worth the dependency for two calls that systemctl
# makes for us: this runs when an administrator adopts or releases a
# service, never from the drop-in, so it is not on any hot path.
system(@$command) == 0 or do { ## no critic (logicLAB::ProhibitShellDispatch)
warn "Failed: " . join( q{ }, @$command ) . "\n";
return 1;
};
}
return 0;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
configd - Adopt a config file that has no conf.d, and keep it generated.
=head1 VERSION
version 0.002
=head1 SYNOPSIS
configd languages
configd adopt postfix
configd status postfix
configd build postfix
configd release postfix
=head1 DESCRIPTION
Postfix, and plenty like it, keeps its configuration in one file with no
C<conf.d> to add to. Two things configuring the same server therefore cannot
both win.
C<configd adopt> puts a fragment directory beside each such file, moves what is
there now into it as C<00-original>, and installs a systemd drop-in that
regenerates the file every time the service starts or reloads. After that,
configuring the service means writing a file into the fragment directory, which
any number of things can do without treading on each other.
=head1 COMMANDS
=head2 languages
What this installation knows how to adopt.
=head2 adopt LANGUAGE
Take the language's files over and wrap its service. Reloads systemd and
restarts the service unless C<--no-restart> says not to.
Running it twice is safe.
=head2 build LANGUAGE
Regenerate the files from their fragments. This is what the drop-in runs; you
would run it by hand to see what a fragment does without restarting anything.
=head2 status LANGUAGE
Whether the files are adopted, how many fragments each has, and whether the
service is wrapped.
=head2 release LANGUAGE
Put the original files back and remove the drop-in. The fragment directories
are left alone, so adopting again picks up where this left off.
=head1 OPTIONS
=over 4
=item B<--root> DIR
Work under DIR rather than C</>. For building an image, or for looking at what
would happen without touching the running system.
=item B<--configd> PATH
The path to this program as the generated unit should invoke it. Defaults to
C</usr/bin/configd>; systemd will not take a relative one.
=item B<--no-restart>
Do not reload systemd or restart the service. Implied by C<--root>, since the
files being configured are not the ones this machine is running on.
=item B<--quiet>
Say nothing unless something is wrong.
=back
=head1 EXIT STATUS
Zero on success. C<status> exits non-zero when the service is not wrapped, so it
can be tested. Two for a usage error, one for anything else.
=head1 SEE ALSO
Please see those modules/websites for more information related to this module.
=over 4
=item *
L<Configd|Configd>
=back
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website
L<https://github.com/teodesian/perl-configd/issues>
When submitting a bug or request, please include a test-file or a
patch to an existing test-file that illustrates the bug or desired
feature.
=head1 AUTHORS
Current Maintainers:
=over 4
=item *
( run in 1.318 second using v1.01-cache-2.11-cpan-364913b4093 )