From cef896e8d28d89359d23cae73cd31552420927fd Mon Sep 17 00:00:00 2001 From: Michel Jouvin Date: Sun, 24 Apr 2016 18:42:21 +0200 Subject: [PATCH] RuleBaseEditor.pm: address initial comments by @stdweird in #151 --- src/main/perl/RuleBasedEditor.pm | 328 +++++++++++++++++++------------ 1 file changed, 199 insertions(+), 129 deletions(-) diff --git a/src/main/perl/RuleBasedEditor.pm b/src/main/perl/RuleBasedEditor.pm index a078ec12..64fc5b04 100644 --- a/src/main/perl/RuleBasedEditor.pm +++ b/src/main/perl/RuleBasedEditor.pm @@ -2,124 +2,28 @@ # ${developer-info} # ${author-info} # ${build-info} -# -# -# This module implements a rule-based editor that is used to modify the content -# of an existing file without taking care of the whole file. Each rule -# driving the edition process is applied to all matching lines. The input for -# updating the file is the Quattor configuration and conditions can be defined -# based on the contents of this configuration. -# -# This module is a subclass of the CAF FileEditor: it extends the base methods of -# the CAF FileEditor. In addition to the constructor it has only one public method. -# The methods provided in this module can be used at the same time as the -# base methods of the FileEditor. -# -# -####################################################################### - -package CAF::RuleBasedEditor; - -use strict; -use warnings; -use vars qw(@ISA $EC); -$EC=LC::Exception::Context->new->will_store_all; - -use parent qw(CAF::FileEditor Exporter); - -use EDG::WP4::CCM::Element; - -use Readonly; - -use Encode qw(encode_utf8); - -local(*DTA); - -# Constants from FileEditor -use CAF::FileEditor qw(BEGINNING_OF_FILE ENDING_OF_FILE); - - -######################################################### -# Constants use to format lines in configuration files. # -# These constants are exported. # -######################################################### - -# LINE_FORMAT_xxx: general syntax of the line (key/val format) -# LINE_FORMAT_SH_VAR: key=val (e.g. SH shell family) -# LINE_FORMAT_ENV_VAR: export key=val (e.g. SH shell family) -# LINE_FORMAT_KEY_VAL: key val (e.g. Xrootd, Apache) -# LINE_FORMAT_KEY_VAL_SETENV: setenv key val (used by Xrootd in particular) -# LINE_FORMAT_KEY_VAL_SET: set key val (used by Xrootd in particular) -use enum qw(LINE_FORMAT_SH_VAR=1 - LINE_FORMAT_ENV_VAR - LINE_FORMAT_KEY_VAL - LINE_FORMAT_KEY_VAL_SETENV - LINE_FORMAT_KEY_VAL_SET - ); - -# LINE_VALUE_xxx: how to interpret the configuration value -# LINE_VALUE_INSTANCE_PARAMS is specific to Xrootd. -use enum qw(LINE_VALUE_AS_IS - LINE_VALUE_BOOLEAN - LINE_VALUE_ARRAY - LINE_VALUE_HASH_KEYS - LINE_VALUE_STRING_HASH - LINE_VALUE_INSTANCE_PARAMS - ); - -# LINE_VALUE_OPT_xxx: options for rendering the value -# (mainly apply to lists and dictionnaries) -use enum qw(BITMASK: LINE_VALUE_OPT_SINGLE - LINE_VALUE_OPT_UNIQUE - LINE_VALUE_OPT_SORTED - ); - -# Internal constants -Readonly my $LINE_FORMAT_DEFAULT => LINE_FORMAT_SH_VAR; -Readonly my $LINE_QUATTOR_COMMENT => "\t\t# Line generated by Quattor"; -Readonly my $LINE_OPT_DEF_REMOVE_IF_UNDEF => 0; -Readonly my $LINE_OPT_DEF_ALWAYS_RULES_ONLY => 0; -Readonly my $RULE_CONDITION_ALWAYS => 'ALWAYS'; -Readonly my $RULE_OPTION_SET_GLOBAL => 'GLOBAL'; - - -# Export constants used to build rules -Readonly my @RULE_CONSTANTS => qw(LINE_FORMAT_SH_VAR - LINE_FORMAT_ENV_VAR - LINE_FORMAT_KEY_VAL - LINE_FORMAT_KEY_VAL_SETENV - LINE_FORMAT_KEY_VAL_SET - LINE_VALUE_AS_IS - LINE_VALUE_BOOLEAN - LINE_VALUE_INSTANCE_PARAMS - LINE_VALUE_ARRAY - LINE_VALUE_HASH_KEYS - LINE_VALUE_STRING_HASH - LINE_VALUE_OPT_SINGLE - LINE_VALUE_OPT_UNIQUE - LINE_VALUE_OPT_SORTED - ); -our @EXPORT_OK; -our %EXPORT_TAGS; -push @EXPORT_OK, @RULE_CONSTANTS; -$EXPORT_TAGS{rule_constants} = \@RULE_CONSTANTS; - - -# Backup file extension -Readonly my $BACKUP_FILE_EXT => ".old"; - =pod =head1 DESCRIPTION -This module implements a rule-based editor. It is a subclass of the B -and extends it. In addition to the constructor, it has only -one public method: B (see below). +This module implements a rule-based editor that is used to modify the content +of an existing file without taking care of the whole file. Each rule +driving the edition process is applied to all matching lines. The input for +updating the file is the Quattor configuration and conditions can be defined +based on the contents of this configuration. + +This module is a subclass of the L: it extends the base methods of +the CAF FileEditor. In addition to the constructor it has only one public method. +The methods provided in this module can be used at the same time as the +base methods of the L. Rules used to edit the file are defined as hashes: each entry defines a rule. Multiple rules can be applied to the same file: it is important that they are -orthogonal, else the result is unpredictable. +orthogonal, else the result is unpredictable. The order used to apply rules is undefined. +The result of applying the rules with the same configuration is idempotent when starting +from the same initial file but sucessive edition of a file (with different configuration values) +may not necessarily be idempotent (in general they are). The hash entry key represents the line keyword in configuration file and hash value is the parsing rule for the keyword value. Parsing rule format is : @@ -133,7 +37,7 @@ matching line must be removed/commented out if the option is undefined. =over -=item condtion +=item condition an option or an option set that must exist for the rule to be applied. Both option_set and option_name:option_set are accepted (see below). @@ -162,11 +66,11 @@ supported (see LINE_FORMAT_xxx constants below): =item -a sh shell environment variable definition (export VAR=val) +a SH shell environment variable definition (export key=val). =item -a sh shell variable definition (VAR=val) +a SH shell variable definition (key=val). =item @@ -174,11 +78,11 @@ a 'keyword value' line, as used by Xrootd or Apache config files. =item -a 'setenv keyword value' line, as used by Xrootd config files mainly. +a 'setenv keyword value' line, as used by Xrootd config files mainly. It can also be used in a CSH shell script. =item -a 'set keyword value' line, as used by Xrootd config files mainly. +a 'set keyword value' line, as used by Xrootd config files mainly. It doesn't work in a CSH shell script (C<=> missing). =back @@ -196,31 +100,197 @@ boolean values, list and hashes. See LINE_VALUE_xxx constants below for the poss =back -For an example of rules, look at ncm-dpmlfc or ncm-xrootd source code in +An example of rule declaration is: + + my %dpm_config_rules_2 = ( + "ALLOW_COREDUMP" => "allowCoreDump:dpm;".LINE_FORMAT_SH_VAR.";".LINE_VALUE_BOOLEAN, + "GLOBUS_THREAD_MODEL" => "globusThreadModel:dpm;".LINE_FORMAT_ENV_VAR, + "DISKFLAGS" =>"DiskFlags:dpm;".LINE_FORMAT_SH_VAR.";".LINE_VALUE_ARRAY, + ); + +For more comprehensive examples of rules, look at L or L source code in configuration-modules-grid repository. +=cut + + +package CAF::RuleBasedEditor; + +use strict; +use warnings; +use vars qw($EC); +$EC=LC::Exception::Context->new->will_store_all; + +use parent qw(CAF::FileEditor Exporter); + +use EDG::WP4::CCM::Element; + +use Readonly; + +use Encode qw(encode_utf8); + +# Constants from FileEditor +use CAF::FileEditor qw(BEGINNING_OF_FILE ENDING_OF_FILE); + + +=pod + +=head2 Rule Constants + +The constants described here are used to build the rules. All these +constants are exported. Add the following to use them: + + use RuleBasedEditor qw(:rule_constants); + +There is a different group of constants for each part of the rule. -=head2 Public methods + +=head3 LINE_FORMAT_xxx: general syntax of the line =over -=item new +=item -This is the constructor. It mainly executes the FileEditor constructor and supports the -same arguments. +LINE_FORMAT_SH_VAR: key=val (e.g. SH shell family) -==cut +=item -sub new -{ - my $class = shift; - my $self = $class->SUPER::new (@_); - return $self; -} +LINE_FORMAT_ENV_VAR: export key=val (e.g. SH shell family) + +=item + +LINE_FORMAT_KEY_VAL: key val (e.g. Xrootd, Apache) + +=item +LINE_FORMAT_KEY_VAL_SETENV: setenv key val (used by Xrootd in particular) + +=item + +LINE_FORMAT_KEY_VAL_SET: set key val (used by Xrootd in particular) + +=back + +=cut + +use enum qw(LINE_FORMAT_SH_VAR=1 + LINE_FORMAT_ENV_VAR + LINE_FORMAT_KEY_VAL + LINE_FORMAT_KEY_VAL_SETENV + LINE_FORMAT_KEY_VAL_SET + ); + +=pod + +=head3 + +LINE_VALUE_xxx: how to interpret the configuration value + +=over + +=item + +LINE_VALUE_AS_IS: take the value as it is, do not attempt any conversion + +=item + +LINE_VALUE_BOOLEAN: interpret the value as a boolean rendered as C or C + +=item + +LINE_VALUE_ARRAY: the value is an array. Rendering controlled by LINE_VALUE_OPT_xxx constants. + +=item + +LINE_VALUE_HASH_KEYS: the value is hash whose keys are the value. Rendering similar to arrays. + +=item + +LINE_VALUE_STRING_HASH: the value is a hash of string. Rendering controlled by LINE_VALUE_OPT_xxx constants. + +=item + +LINE_VALUE_INSTANCE_PARAMS: specific to L + +=back + +=cut + +use enum qw(LINE_VALUE_AS_IS + LINE_VALUE_BOOLEAN + LINE_VALUE_ARRAY + LINE_VALUE_HASH_KEYS + LINE_VALUE_STRING_HASH + LINE_VALUE_INSTANCE_PARAMS + ); + +=pod + +=head3 LINE_VALUE_OPT_xxx: options for rendering the value + +These options mainly apply to lists and hashes and are interpreted as a bitmask. +=item + +LINE_VALUE_OPT_SINGLE: each value must be a separate instance of the keyword (multiple lines) + +=item + +LINE_VALUE_OPT_UNIQUE: each values are concataneted as a space-separated string + +=item + +LINE_VALUE_OPT_SORTED: values are sorted + +=cut + +use enum qw(BITMASK: LINE_VALUE_OPT_SINGLE + LINE_VALUE_OPT_UNIQUE + LINE_VALUE_OPT_SORTED + ); + +# Internal constants +Readonly my $LINE_FORMAT_DEFAULT => LINE_FORMAT_SH_VAR; +Readonly my $LINE_QUATTOR_COMMENT => "\t\t# Line generated by Quattor"; +Readonly my $LINE_OPT_DEF_REMOVE_IF_UNDEF => 0; +Readonly my $LINE_OPT_DEF_ALWAYS_RULES_ONLY => 0; +Readonly my $RULE_CONDITION_ALWAYS => 'ALWAYS'; +Readonly my $RULE_OPTION_SET_GLOBAL => 'GLOBAL'; + + +# Export constants used to build rules +# Needs to be updated when a constant is added or removed +Readonly my @RULE_CONSTANTS => qw(LINE_FORMAT_SH_VAR + LINE_FORMAT_ENV_VAR + LINE_FORMAT_KEY_VAL + LINE_FORMAT_KEY_VAL_SETENV + LINE_FORMAT_KEY_VAL_SET + LINE_VALUE_AS_IS + LINE_VALUE_BOOLEAN + LINE_VALUE_INSTANCE_PARAMS + LINE_VALUE_ARRAY + LINE_VALUE_HASH_KEYS + LINE_VALUE_STRING_HASH + LINE_VALUE_OPT_SINGLE + LINE_VALUE_OPT_UNIQUE + LINE_VALUE_OPT_SORTED + ); + + +our @EXPORT_OK; +our %EXPORT_TAGS; +push @EXPORT_OK, @RULE_CONSTANTS; +$EXPORT_TAGS{rule_constants} = \@RULE_CONSTANTS; + + +# Backup file extension +Readonly my $BACKUP_FILE_EXT => ".old"; =pod +=head2 Public methods + +=over + =item updateFile Update configuration file contents, applying configuration rules. @@ -259,9 +329,9 @@ sub updateFile { $self->seek_begin(); # Check that config file has an appropriate header - my $intro_pattern = "# This file is managed by Quattor"; + Readonly my $INTRO_PATTERN => "# This file is managed by Quattor"; my $intro = "# This file is managed by Quattor - DO NOT EDIT lines generated by Quattor"; - $self->add_or_replace_lines(qr/^$intro_pattern/, + $self->add_or_replace_lines(qr/^$INTRO_PATTERN/, qr/^$intro$/, $intro."\n#\n", BEGINNING_OF_FILE,