You've already forked pgbackrest
							
							
				mirror of
				https://github.com/pgbackrest/pgbackrest.git
				synced 2025-10-30 23:37:45 +02:00 
			
		
		
		
	Added validation of pgbackrest.conf to display warnings if options are not valid or are not in the correct section.
Contributed by Cynthia Shang.
This commit is contained in:
		
				
					committed by
					
						 David Steele
						David Steele
					
				
			
			
				
	
			
			
			
						parent
						
							5d2e79242d
						
					
				
				
					commit
					af7e4f4b4b
				
			| @@ -154,6 +154,18 @@ | ||||
|  | ||||
|     <release-list> | ||||
|         <release date="XXXX-XX-XX" version="1.18dev" title="UNDER DEVELOPMENT"> | ||||
|             <release-core-list> | ||||
|                 <release-feature-list> | ||||
|                     <release-item> | ||||
|                         <release-item-contributor-list> | ||||
|                             <release-item-contributor id="shang.cynthia"/> | ||||
|                         </release-item-contributor-list> | ||||
|  | ||||
|                         <p>Added validation of <setting>pgbackrest.conf</setting> to display warnings if options are not valid or are not in the correct section.</p> | ||||
|                     </release-item> | ||||
|                 </release-feature-list> | ||||
|             </release-core-list> | ||||
|  | ||||
|             <release-test-list> | ||||
|                 <release-refactor-list> | ||||
|                     <release-item> | ||||
|   | ||||
| @@ -2691,8 +2691,104 @@ sub optionValidate | ||||
|             confess &log(ERROR, "option '${strOption}' not valid for command '${strCommand}'", ERROR_OPTION_COMMAND); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     # If a config file was loaded then determine if all options are valid in the config file | ||||
|     if (defined($oConfig)) | ||||
|     { | ||||
|         configFileValidate($oConfig); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # configFileValidate | ||||
| # | ||||
| # Determine if the configuration file contains any invalid options or placements | ||||
| #################################################################################################################################### | ||||
| sub configFileValidate | ||||
| { | ||||
|     my $oConfig = shift; | ||||
|  | ||||
|     my $bFileValid = true; | ||||
|  | ||||
|     foreach my $strSectionKey (keys(%$oConfig)) | ||||
|     { | ||||
|         my ($strSection, $strCommand) = ($strSectionKey =~ m/([^:]*):*(\w*-*\w*)/); | ||||
|  | ||||
|         foreach my $strOption (keys(%{$$oConfig{$strSectionKey}})) | ||||
|         { | ||||
|             my $strValue = $$oConfig{$strSectionKey}{$strOption}; | ||||
|  | ||||
|             # Is the option listed as an alternate name for another option? If so, replace it with the recognized option. | ||||
|             my $strOptionAltName = optionAltName($strOption); | ||||
|  | ||||
|             if (defined($strOptionAltName)) | ||||
|             { | ||||
|                 $strOption = $strOptionAltName; | ||||
|             } | ||||
|  | ||||
|             # Is the option a valid pgbackrest option? | ||||
|             if (!(exists($oOptionRule{$strOption}) || defined($strOptionAltName))) | ||||
|             { | ||||
|                 &log(WARN, optionGet(OPTION_CONFIG) . " file contains invalid option '${strOption}'"); | ||||
|                 $bFileValid = false; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 # Is the option valid for the command section in which it is located? | ||||
|                 if (defined($strCommand) && $strCommand ne '') | ||||
|                 { | ||||
|                     if (!defined($oOptionRule{$strOption}{&OPTION_RULE_COMMAND}{$strCommand})) | ||||
|                     { | ||||
|                         &log(WARN, optionGet(OPTION_CONFIG) . " valid option '${strOption}' is not valid for command " . | ||||
|                             "'$strCommand'"); | ||||
|                         $bFileValid = false; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 # Is the valid option a stanza-only option and not located in a global section? | ||||
|                 if ($oOptionRule{$strOption}{&OPTION_RULE_SECTION} eq CONFIG_SECTION_STANZA && | ||||
|                     $strSection eq CONFIG_SECTION_GLOBAL) | ||||
|                 { | ||||
|                     &log(WARN, optionGet(OPTION_CONFIG) . " valid option '${strOption}' is a stanza section option and is not " . | ||||
|                         "valid in section ${strSection}\n" . | ||||
|                         "HINT: global options can be specified in global or stanza sections but not visa-versa"); | ||||
|                     $bFileValid = false; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return $bFileValid; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(configFileValidate); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # optionAltName | ||||
| # | ||||
| # Returns the ALT_NAME for the option if one exists. | ||||
| #################################################################################################################################### | ||||
| sub optionAltName | ||||
| { | ||||
|     my $strOption = shift; | ||||
|  | ||||
|     my $strOptionAltName = undef; | ||||
|  | ||||
|     # Check if the options exists as an alternate name (e.g. db-host has altname db1-host) | ||||
|     foreach my $strKey (keys(%oOptionRule)) | ||||
|     { | ||||
|         if (defined($oOptionRule{$strKey}{&OPTION_RULE_ALT_NAME}) && | ||||
|             $oOptionRule{$strKey}{&OPTION_RULE_ALT_NAME} eq $strOption) | ||||
|         { | ||||
|             $strOptionAltName = $strKey; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return $strOptionAltName; | ||||
| } | ||||
|  | ||||
| push @EXPORT, qw(optionAltName); | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # optionCommandRule | ||||
| # | ||||
|   | ||||
| @@ -35,7 +35,7 @@ use constant BACKREST_BIN                                           => abs_path( | ||||
| # Defines the current version of the BackRest executable.  The version number is used to track features but does not affect what | ||||
| # repositories or manifests can be read - that's the job of the format number. | ||||
| #----------------------------------------------------------------------------------------------------------------------------------- | ||||
| use constant BACKREST_VERSION                                       => '1.17'; | ||||
| use constant BACKREST_VERSION                                       => '1.18dev'; | ||||
|     push @EXPORT, qw(BACKREST_VERSION); | ||||
|  | ||||
| # Format Format Number | ||||
|   | ||||
| @@ -11,7 +11,7 @@ use AutoLoader; | ||||
| our @ISA = qw(Exporter); | ||||
|  | ||||
| # Library version (add .999 during development) | ||||
| our $VERSION = '1.17'; | ||||
| our $VERSION = '1.18.999'; | ||||
|  | ||||
| sub libCVersion {return $VERSION}; | ||||
|  | ||||
|   | ||||
| @@ -97,6 +97,11 @@ my $oTestDef = | ||||
|  | ||||
|             &TESTDEF_TEST => | ||||
|             [ | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'unit', | ||||
|                     &TESTDEF_TEST_TOTAL => 7, | ||||
|                     &TESTDEF_TEST_INDIVIDUAL => false, | ||||
|                 }, | ||||
|                 { | ||||
|                     &TESTDEF_TEST_NAME => 'option', | ||||
|                     &TESTDEF_TEST_TOTAL => 34, | ||||
|   | ||||
							
								
								
									
										96
									
								
								test/lib/pgBackRestTest/Config/ConfigUnitTest.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								test/lib/pgBackRestTest/Config/ConfigUnitTest.pm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| #################################################################################################################################### | ||||
| # ConfigUnitTest.pm - Tests code paths | ||||
| #################################################################################################################################### | ||||
| package pgBackRestTest::Config::ConfigUnitTest; | ||||
| use parent 'pgBackRestTest::Config::ConfigEnvTest'; | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # Perl includes | ||||
| #################################################################################################################################### | ||||
| use strict; | ||||
| use warnings FATAL => qw(all); | ||||
| use Carp qw(confess); | ||||
|  | ||||
| use pgBackRest::Common::Exception; | ||||
| use pgBackRest::Common::Ini; | ||||
| use pgBackRest::Common::Log; | ||||
| use pgBackRest::Config::Config; | ||||
|  | ||||
| use pgBackRestTest::Common::RunTest; | ||||
|  | ||||
| #################################################################################################################################### | ||||
| # run | ||||
| #################################################################################################################################### | ||||
| sub run | ||||
| { | ||||
|     my $self = shift; | ||||
|  | ||||
|     my $oConfig = {}; | ||||
|  | ||||
|     optionSet(OPTION_CONFIG, $self->testPath() . '/pgbackrest.conf', true); | ||||
|  | ||||
|     if ($self->begin('valid option ' . OPTION_DB_PORT . ' under invalid section')) | ||||
|     { | ||||
|         my $oConfig = {}; | ||||
|         $$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_BACKUP}{&OPTION_DB_PORT} = 1234; | ||||
|  | ||||
|         $self->testResult(sub {configFileValidate($oConfig)}, false, | ||||
|             'valid option ' . OPTION_DB_PORT . ' under invalid section'); | ||||
|     } | ||||
|  | ||||
|     if ($self->begin('valid option ' . OPTION_DB_PORT . ' under invalid global section command')) | ||||
|     { | ||||
|         my $oConfig = {}; | ||||
|         $$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_ARCHIVE_PUSH}{&OPTION_DB_PORT} = 1234; | ||||
|  | ||||
|         $self->testResult(sub {configFileValidate($oConfig)}, false, | ||||
|             'valid option ' . OPTION_DB_PORT . ' under invalid global section command'); | ||||
|     } | ||||
|  | ||||
|     if ($self->begin('valid option ' . OPTION_DB_PORT . ' under invalid stanza section command')) | ||||
|     { | ||||
|         my $oConfig = {}; | ||||
|         $$oConfig{$self->stanza() . ':' . &CMD_ARCHIVE_PUSH}{&OPTION_DB_PORT} = 1234; | ||||
|  | ||||
|         $self->testResult(sub {configFileValidate($oConfig)}, false, | ||||
|             'valid option ' . OPTION_DB_PORT . ' under invalid stanza section command'); | ||||
|     } | ||||
|  | ||||
|     if ($self->begin('invalid option')) | ||||
|     { | ||||
|         my $oConfig = {}; | ||||
|         $$oConfig{&CONFIG_SECTION_GLOBAL}{&BOGUS} = BOGUS; | ||||
|  | ||||
|         $self->testResult(sub {configFileValidate($oConfig)}, false, 'invalid option ' . $$oConfig{&CONFIG_SECTION_GLOBAL}{&BOGUS}); | ||||
|     } | ||||
|  | ||||
|     if ($self->begin('valid alt name')) | ||||
|     { | ||||
|         my $oConfig = {}; | ||||
|         $$oConfig{&CONFIG_SECTION_GLOBAL}{'thread-max'} = 3; | ||||
|  | ||||
|         $self->testResult(sub {configFileValidate($oConfig)}, true, 'valid alt name found'); | ||||
|     } | ||||
|  | ||||
|     if ($self->begin('valid config file')) | ||||
|     { | ||||
|         my $oConfig = {}; | ||||
|         $$oConfig{&CONFIG_SECTION_GLOBAL}{&OPTION_LOG_LEVEL_STDERR} = OPTION_DEFAULT_LOG_LEVEL_STDERR; | ||||
|         $$oConfig{$self->stanza()}{&OPTION_DB_PATH} = '/db'; | ||||
|         $$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_ARCHIVE_PUSH}{&OPTION_PROCESS_MAX} = 2; | ||||
|  | ||||
|         $self->testResult(sub {configFileValidate($oConfig)}, true, 'valid config file'); | ||||
|     } | ||||
|  | ||||
|     if ($self->begin('valid unusual section name')) | ||||
|     { | ||||
|         my $oConfig = {}; | ||||
|         $$oConfig{&CONFIG_SECTION_GLOBAL}{&OPTION_LOG_LEVEL_STDERR} = OPTION_DEFAULT_LOG_LEVEL_STDERR; | ||||
|         $$oConfig{&CONFIG_SECTION_GLOBAL . ':' . &CMD_ARCHIVE_PUSH}{&OPTION_PROCESS_MAX} = 2; | ||||
|         $$oConfig{'unusual-section^name!:' . &CMD_CHECK}{&OPTION_DB_PATH} = '/db'; | ||||
|  | ||||
|         $self->testResult(sub {configFileValidate($oConfig)}, true, 'valid unusual section name'); | ||||
|     } | ||||
| } | ||||
|  | ||||
| 1; | ||||
		Reference in New Issue
	
	Block a user