Add merge subcommand to lemonldap-ng-cli (#2780)

This commit is contained in:
Maxime Besson 2022-08-11 16:46:11 +02:00
parent 0c1e58da66
commit 798c80fbf1
2 changed files with 77 additions and 3 deletions

View File

@ -32,7 +32,7 @@ for ( my $i = 0 ; $i < @ARGV ; $i++ ) {
$action ||= "usage";
if ( $action =~
/^(?:[gs]et|del|(?:add|del)Key|(?:add|del)PostVars|save|restore|rollback)$/
/^(?:[gs]et|del|(?:add|del)Key|(?:add|del)PostVars|merge|save|restore|rollback)$/
)
{
eval { require Lemonldap::NG::Manager::Cli; };
@ -80,6 +80,7 @@ Available actions:
delKey KEY SUBKEY : delete subkey of a parameter
addPostVars HOST URI KEY VALUE : add post vars for form replay
delPostVars HOST URI KEY : delete post vars for form replay
merge FILE [FILE ...] : merge JSON/YAML files with existing configuration
save : export configuration to STDOUT
restore - : import configuration from STDIN
restore FILE : import configuration from file
@ -204,6 +205,11 @@ This action lets you add a new POST var in a form replay configuration.
This action lets you delete a new POST var in a form replay configuration.
=item B<merge I<FILE> [I<FILE> ...]>
This action iterates through the given JSON or YAML files and merges the
existing configuration with the keys contained in those files
=item B<save>
Dump the entire LemonLDAP::NG configuration to standard output, in JSON format.

View File

@ -5,6 +5,7 @@ use Crypt::URandom;
use Mouse;
use Data::Dumper;
use JSON;
use Hash::Merge::Simple;
use Lemonldap::NG::Common::Conf::ReConstants;
our $VERSION = '2.0.12';
@ -138,6 +139,73 @@ sub del {
return $self->_save($new);
}
sub merge {
my ( $self, @files ) = @_;
die 'merge requires at least one file' unless (@files);
require Clone;
my $old = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf );
my $new;
my @valid_files;
foreach my $file (@files) {
my $merging;
if ( $file =~ /\.ya?ml/ ) {
eval {
require YAML;
$merging = YAML::LoadFile($file);
};
if ($@) {
print STDERR "Skipping invalid YAML file $file: " . $@;
}
}
else {
eval {
local $/ = undef;
open my $fh, '<', $file or die $!;
$merging = from_json(<$fh>);
};
if ($@) {
print STDERR "Skipping invalid JSON file $file: " . $@;
}
}
if ( ref($merging) eq "HASH" ) {
$new = Hash::Merge::Simple::merge( $new, $merging );
push @valid_files, $file;
}
}
die "Nothing to do" unless ref($new) eq "HASH";
unless ( $self->yes ) {
print "Merge configuration changes from "
. join( " ", @valid_files ) . " \n";
print Dumper($new);
print "Confirm (N/y)? ";
my $c = <STDIN>;
unless ( $c =~ /^y(?:es)?$/ ) {
die "Aborting";
}
}
$new = Hash::Merge::Simple::merge( $old, $new );
_clean_hash_undef($new);
return $self->_save($new);
}
# Remove key => undef from hashes
# This allows you to remove keys from the config
sub _clean_hash_undef {
my ($hash) = @_;
for my $key ( keys %$hash ) {
if ( !defined( $hash->{$key} ) ) {
delete $hash->{$key};
}
if ( ref( $hash->{$key} ) eq "HASH" ) {
_clean_hash_undef( $hash->{$key} );
}
}
}
sub addKey {
my $self = shift;
unless ( @_ % 3 == 0 ) {
@ -512,11 +580,11 @@ sub run {
}
my $action = shift;
unless ( $action =~
/^(?:get|set|del|addKey|delKey|addPostVars|delPostVars|save|restore|rollback)$/
/^(?:get|set|del|addKey|delKey|addPostVars|delPostVars|merge|save|restore|rollback)$/
)
{
die
"Unknown action $action. Only get, set, del, addKey, delKey, addPostVars, delPostVars, save, restore, rollback allowed";
"Unknown action $action. Only get, set, del, addKey, delKey, addPostVars, delPostVars, merge, save, restore, rollback allowed";
}
unless ( $action eq "restore" ) {