Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ncm-sysconfig: Cleanup and modernise codebase #1288

Merged
merged 3 commits into from
Jun 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions ncm-sysconfig/src/main/pan/components/sysconfig/schema.pan
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,34 @@
# ${developer-info}
# ${author-info}


declaration template components/sysconfig/schema;

include 'quattor/schema';

@documentation{
Contents of a sysconfig file modelled as a dict of key-value pairs.

Two reserved keys `prologue` and `epilogue` are treated specially,
their values will be copied verbatim into the file before or after the key-pair definitions.

Example:

'/software/components/sysconfig/files/scfg' = dict(
'epilogue', 'export LANG=C',
'KEY', 'VALUE',
);

This will create the file `/etc/sysconfig/scfg` which contains:

KEY=VALUE
export LANG=C
}
type component_sysconfig_file = string(1..){};

type component_sysconfig = {
include structure_component
'files' ? string{}{}
@{ dict of dicts with a file name as the first key and the contents of each file as the child dict. }
'files' ? component_sysconfig_file{}
};

bind '/software/components/sysconfig' = component_sysconfig;


207 changes: 109 additions & 98 deletions ncm-sysconfig/src/main/perl/sysconfig.pm
Original file line number Diff line number Diff line change
@@ -1,110 +1,121 @@
#${PMcomponent}

use parent qw(NCM::Component);
=head1 NAME

sysconfig: management of sysconfig files

=head1 DESCRIPTION

The I<sysconfig> component manages system configuration files in
C<< /etc/sysconfig >> . These are files which contain key-value pairs.
However there is the possibility to add verbatim text either before or after the key-value pair definitions.

=cut

use parent qw(NCM::Component CAF::Path);

our $EC = LC::Exception::Context->new->will_store_all;

use LC::Check;
our $NoActionSupported = 1;

use Readonly;

use File::Path;
use File::Basename;
Readonly my $QUOTE => "\"";
Readonly my $SYSCONFIGDIR => "/etc/sysconfig"; # The base directory for sysconfig files.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jrha well, almost nice. can you also add

our $NoActionSupported = 1;

(as per @ned21 request)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, I had added that already... where did it go?!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

sub filelist_read
{
my ($self) = @_;

# Read first the list of sysconfig files which have been
# previously managed by this component. These will have to
# be deleted if no longer in the configuration.
my %filelist;
my $fh = CAF::FileReader->open("$SYSCONFIGDIR/ncm-sysconfig", log => $self);
while (my $line = <$fh>) {
chomp($line);
$filelist{$line} = 1;
}
$fh->close();

return %filelist;
}

sub filelist_write
{
my ($self, %filelist) = @_;

# Write the list of managed configuration files.
my $fh = CAF::FileWriter->open("$SYSCONFIGDIR/ncm-sysconfig", log => $self);
for my $file (keys %filelist) {
print $fh "$file\n";
}
$fh->close();

return 1;
}

sub Configure
{
my ($self, $config) = @_;

# Load configuration into a hash
my $sysconfig_config = $config->getTree($self->prefix());

# Ensure that sysconfig directory exists.
$self->directory($SYSCONFIGDIR, owner=>0, group=>0, mode=>0755);

# This will be a list of the configuration files managed by this component.
my %files_managed;

my %files_previous = $self->filelist_read();

# Loop over all of the defined files, writing each as necessary.
if ( $sysconfig_config->{files} ) {
foreach my $file (sort keys %{$sysconfig_config->{files}}) {

my $pairs = $sysconfig_config->{files}->{$file};

# Start with an empty file.
my $contents = '';

# Add the prologue if it exists.
if (defined($pairs->{prologue})) {
$contents .= "$pairs->{prologue}\n";
}

# Loop over the pairs adding the information to the file.
for my $key (sort keys %$pairs) {
if ($key ne 'prologue' && $key ne 'epilogue') {
$contents .= "$key=$pairs->{$key}\n";
}
}

# Add the epilogue if it exists.
if (defined($pairs->{epilogue})) {
$contents .= "$pairs->{epilogue}\n";
}

# Now actually update the file, if needed.
my $fh = CAF::FileWriter->open("$SYSCONFIGDIR/$file", backup => ".old", log => $self);
print $fh $contents;
$fh->close();

# Remove this file from the list of old configuration
# files add to the new configuration files.
delete($files_previous{"$SYSCONFIGDIR/$file"});
$files_managed{"$SYSCONFIGDIR/$file"} = 1;
}
}

# Remove any old configuration files which haven't been updated.
for my $file (keys %files_previous) {
$self->cleanup($file);
}

$self->filelist_write(%files_managed);

my ($self, $config) = @_;

# Define paths for convenience.
my $base = "/software/components/sysconfig";

# The base directory for sysconfig files.
my $sysconfigdir = "/etc/sysconfig";

# Load configuration into a hash
my $sysconfig_config = $config->getElement($base)->getTree();

# Ensure that sysconfig directory exists.
mkpath($sysconfigdir,0,0755) unless (-e $sysconfigdir);
if (! -d $sysconfigdir) {
$self->error("$sysconfigdir isn't a directory or can't be created");
return 1;
}

# This will be a list of the configuration files managed by this component.
my %newcfg;

# Read first the list of sysconfig files which have been
# previously managed by this component. These will have to
# be deleted if no longer in the configuration.
my %oldcfg;
if (-f "$sysconfigdir/ncm-sysconfig") {
open CONF, "<", "$sysconfigdir/ncm-sysconfig";
while (<CONF>) {
chomp;
$oldcfg{$_} = 1;
}
}

# Loop over all of the defined files, writing each as necessary.
if ( $sysconfig_config->{files} ) {
for my $file (sort keys %{$sysconfig_config->{files}}) {

my $pairs = $sysconfig_config->{files}->{$file};

# Start with an empty file.
my $contents = '';

# Add the prologue if it exists.
if (defined($pairs->{"prologue"})) {
$contents .= $pairs->{"prologue"} . "\n";
}

# Loop over the pairs adding the information to the file.
for my $key (sort keys %{$pairs}) {
if ($key ne 'prologue' && $key ne 'epilogue') {
$contents .= $key . '=' . $pairs->{$key} . "\n";
}
}

# Add the epilogue if it exists.
if (defined($pairs->{"epilogue"})) {
$contents .= $pairs->{"epilogue"} . "\n";
}

# Now actually update the file, if needed.

my $result = LC::Check::file("$sysconfigdir/$file",
backup => ".old",
contents => $contents,
);
unless ( $result >= 0 ) {
$self->error("Error updating file $sysconfigdir/$file");
}

# Remove this file from the list of old configuration
# files add to the new configuration files.
delete($oldcfg{"$sysconfigdir/$file"});
$newcfg{"$sysconfigdir/$file"} = 1;
}
}

# Remove any old configuration files which haven't been updated.
for my $file (keys %oldcfg) {
unlink $file if (-e $file);
}

# Write the list of managed configuration files.
if(open CONF, ">", "$sysconfigdir/ncm-sysconfig") {
for my $file (keys %newcfg) {
print CONF $file . "\n";
}
close CONF;
} else {
$self->error("error writing file $sysconfigdir/ncm-sysconfig");
return 1;
}

return 0;
return 1;
}

1; # Required for PERL modules
1; # Required for PERL modules
46 changes: 0 additions & 46 deletions ncm-sysconfig/src/main/perl/sysconfig.pod

This file was deleted.

29 changes: 29 additions & 0 deletions ncm-sysconfig/src/test/perl/configure.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use strict;
use warnings;
use Test::More;
use Test::Quattor qw(configure);
use NCM::Component::sysconfig;

$CAF::Object::NoAction = 1;

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

# Set up list of previously managed files
set_file_contents('/etc/sysconfig/ncm-sysconfig', "/etc/sysconfig/delete_me\n/etc/sysconfig/examplefile\n");

# Set up existing files with garbage contents
set_file_contents('/etc/sysconfig/delete_me', "DELETE_ME=delete_me\n");
set_file_contents('/etc/sysconfig/examplefile', "NOPE=nope_nope\n");

is($cmp->Configure($cfg), 1, "Does the component run correctly with a test profile?");

isa_ok(get_file('/etc/sysconfig/ncm-sysconfig'), "CAF::FileWriter", "Is the file-handle for the list of managed files the correct class?");
is(get_file_contents('/etc/sysconfig/ncm-sysconfig'), "/etc/sysconfig/examplefile\n", "Is the list of managed files updated correctly?");

is(get_file_contents('/etc/sysconfig/delete_me'), undef, "Has the previously managed file been deleted?");

isa_ok(get_file('/etc/sysconfig/examplefile'), "CAF::FileWriter", "Is the file-handle for the example file the correct class?");
is(get_file_contents('/etc/sysconfig/examplefile'), "key1=testvalue\nkey2=valuetest\n", "Does the example file have the correct contents?");

done_testing();
8 changes: 8 additions & 0 deletions ncm-sysconfig/src/test/resources/configure.pan
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
object template configure;

include 'components/sysconfig/schema';

prefix '/software/components/sysconfig';

'files/examplefile/key1' = 'testvalue';
'files/examplefile/key2' = 'valuetest';