Skip to content

Commit

Permalink
ncm-metaconfig: support running arbitrary commands in various steps
Browse files Browse the repository at this point in the history
  • Loading branch information
stdweird committed Jun 10, 2020
1 parent 1fbf8a4 commit 2f715a4
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 7 deletions.
15 changes: 15 additions & 0 deletions ncm-metaconfig/src/main/pan/components/metaconfig/schema.pan
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,18 @@ type ${project.artifactId}_textrender_convert = {

type caf_service_action = string with match(SELF, '^(restart|reload|stop_sleep_start)$');

type ${project.artifactId}_commands = {
@{Always run, happens before possible modifications}
'pre' ? string
@{Always run, happens before possible modifications, the file content is passed om stdin.
Runs with 'keeps_state' enabled, so do not modify anything with this command.}
'test' ? string
@{Only run after file is modified, but after daemon action is added}
'changed' ? string
@{Always run, happens after possible modifications (and after 'changed').}
'post' ? string
};

type ${project.artifactId}_config = {
@{File permissions. Defaults to 0644.}
'mode' : long = 0644
Expand Down Expand Up @@ -118,6 +130,9 @@ type ${project.artifactId}_config = {
'contents' : ${project.artifactId}_extension
@{Predefined conversions from EDG::WP4::CCM::TextRender}
'convert' ? ${project.artifactId}_textrender_convert
@{Commands to run on pre, validation and/or post step.
These are independent of daemons and are executed at time of processing each service.}
'commands' ? ${project.artifactId}_commands
} = dict();

type ${project.artifactId}_component = {
Expand Down
56 changes: 54 additions & 2 deletions ncm-metaconfig/src/main/perl/metaconfig.pm
Original file line number Diff line number Diff line change
Expand Up @@ -223,16 +223,61 @@ sub process_actions
}
}

# Run $service shell command of $type (ie a string) (if defined).
# $msg is a reporting prefix
# When $input is not undef, pass it on stdin
# Return 1 on success, undef otherwise.
sub run_shell_command
{
my ($self, $commands, $type, $input) = @_;

my $command = $commands->{$type};
if ($command) {
$self->debug(1, "Going to run $type command '$command'");

my ($err, $out);
my %opts = (
shell => 1,
log => $self,
stdout => \$out,
stderr => \$err,
);
if (defined($input)) {
$opts{stdin} = "$input";
};
if ($type eq 'test') {
$opts{keeps_state} = 1;
};

CAF::Process->new([$command], %opts)->execute();

my $ec = $?;

my $report = $ec ? 'error' : 'verbose';
$self->$report("run $type command '$command' ",
($ec ? 'failed' : 'ok'),
,": stdout '$out'\n stderr '$err'",
($input ? "\n stdin '$input'" : ""));
return $ec ? undef : 1;
} else {
$self->debug(5, "No $type command to run");
return 1;
};
}

# Generate C<$file>, configuring C<$srv> using CAF::TextRender with
# contents C<$contents> (if C<$contents> is not defined,
# C<$srv->{contents}> is used).
# Also tracks the actions that need to be taken via the
# C<$actions> hash-reference.
# Returns undef in case of rendering failure, 1 otherwise.
# Returns undef in case of rendering or other failure, 1 otherwise.
sub handle_service
{
my ($self, $file, $srv, $contents, $actions) = @_;

my $commands = $srv->{commands} || {};
return if ! $self->run_shell_command($commands, 'pre');

$contents = $srv->{contents} if (! defined($contents));

my $trd = EDG::WP4::CCM::TextRender->new($srv->{module},
Expand Down Expand Up @@ -265,16 +310,23 @@ sub handle_service
return;
}

if (! $self->run_shell_command($commands, 'test', "$fh")) {
$fh->cancel();
return;
};

if ($fh->close()) {
$self->info("File $file updated");
$self->prepare_action($srv, $file, $actions);
return if ! $self->run_shell_command($commands, 'changed');
} else {
$self->verbose("File $file up-to-date");
};

return 1;
return $self->run_shell_command($commands, 'post');
}


sub _configure_files
{
my ($self, $config, $root) = @_;
Expand Down
72 changes: 72 additions & 0 deletions ncm-metaconfig/src/test/perl/commands.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use strict;
use warnings;
use Test::More;
use Test::Quattor qw(commands);
use NCM::Component::metaconfig;
use Test::MockModule;

=pod
=head1 DESCRIPTION
Test the configure() method.
=cut

my $orig = 'X';

sub clean
{
set_file_contents("/foo/bar", "$orig");
command_history_reset();
}

my $cmp = NCM::Component::metaconfig->new('metaconfig');
my $cfg = get_config_for_profile('commands');

clean();

is($cmp->Configure($cfg), 1, "Configure succeeds");
my $fh = get_file("/foo/bar");
ok($orig ne "$fh", "orig content is not same as current $fh");

ok($fh, "A file was actually created");
isa_ok($fh, "CAF::FileWriter");

# if default sysv init service changes, also modify the aii_command negative test
ok(command_history_ok(['cmd pre', 'cmd test', 'cmd changed', 'cmd post', 'service foo restart']),
"commands run and serivce foo restarted");

clean();

# changed failed, post does not run, daemons does run
set_command_status('cmd changed', 1);
$cmp->Configure($cfg);
ok(command_history_ok(['cmd pre', 'cmd test', 'cmd changed', 'service foo restart'], ['cmd post']),
"commands except post run and serivce foo restarted");
my $fcnt = get_file_contents("/foo/bar");
ok($orig ne "$fcnt", "orig content is not same as current $fcnt");

clean();

# test failed, changed, post and daemons do not run, content unmodified
set_command_status('cmd test', 1);
$cmp->Configure($cfg);
ok(command_history_ok(['cmd pre', 'cmd test'], ['cmd changed', 'service foo restart', 'cmd post']),
"commands run except changed, post and no serivce foo restarted");
$fcnt = get_file_contents("/foo/bar");
# unmodified
is($orig, "$fcnt", "orig content is same as current $fcnt on test failed");

clean();
# pre failed, test, changed, post and daemons do not run, content unmodified
set_command_status('cmd pre', 1);
$cmp->Configure($cfg);
ok(command_history_ok(['cmd pre'], ['cmd test', 'cmd changed', 'service foo restart', 'cmd post']),
"commands run except test, changed, post and no serivce foo restarted");
$fcnt = get_file_contents("/foo/bar");
# unmodified
is($orig, "$fcnt", "orig content is same as current $fcnt on pre failed");


done_testing();
6 changes: 1 addition & 5 deletions ncm-metaconfig/src/test/perl/configure.t
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
use strict;
use warnings;
use Test::More;
use Test::Quattor qw(configure);
use Test::Quattor qw(configure commands);
use NCM::Component::metaconfig;
use Test::MockModule;
use CAF::Object;

use JSON::XS;

=pod
Expand Down
9 changes: 9 additions & 0 deletions ncm-metaconfig/src/test/resources/commands.pan
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
object template commands;

include 'simple';

prefix "/software/components/metaconfig/services/{/foo/bar}/commands";
"pre" = "cmd pre";
"test" = "cmd test";
"changed" = "cmd changed";
"post" = "cmd post";

0 comments on commit 2f715a4

Please sign in to comment.