1package Monitoring::GLPlugin::Commandline::Getopt; 2use strict; 3use File::Basename; 4use Getopt::Long qw(:config no_ignore_case bundling); 5 6# Standard defaults 7my %DEFAULT = ( 8 timeout => 15, 9 verbose => 0, 10 license => 11"This monitoring plugin is free software, and comes with ABSOLUTELY NO WARRANTY. 12It may be used, redistributed and/or modified under the terms of the GNU 13General Public Licence (see http://www.fsf.org/licensing/licenses/gpl.txt).", 14); 15# Standard arguments 16my @ARGS = ({ 17 spec => 'usage|?', 18 help => "-?, --usage\n Print usage information", 19 }, { 20 spec => 'help|h', 21 help => "-h, --help\n Print detailed help screen", 22 }, { 23 spec => 'version|V', 24 help => "-V, --version\n Print version information", 25 }, { 26 #spec => 'extra-opts:s@', 27 #help => "--extra-opts=[<section>[@<config_file>]]\n Section and/or config_file from which to load extra options (may repeat)", 28 }, { 29 spec => 'timeout|t=i', 30 help => sprintf("-t, --timeout=INTEGER\n Seconds before plugin times out (default: %s)", $DEFAULT{timeout}), 31 default => $DEFAULT{timeout}, 32 }, { 33 spec => 'verbose|v+', 34 help => "-v, --verbose\n Show details for command-line debugging (can repeat up to 3 times)", 35 default => $DEFAULT{verbose}, 36 }, 37); 38# Standard arguments we traditionally display last in the help output 39my %DEFER_ARGS = map { $_ => 1 } qw(timeout verbose); 40 41sub _init { 42 my ($self, %params) = @_; 43 # Check params 44 my %attr = ( 45 usage => 1, 46 version => 0, 47 url => 0, 48 plugin => { default => $Monitoring::GLPlugin::pluginname }, 49 blurb => 0, 50 extra => 0, 51 'extra-opts' => 0, 52 license => { default => $DEFAULT{license} }, 53 timeout => { default => $DEFAULT{timeout} }, 54 ); 55 56 # Add attr to private _attr hash (except timeout) 57 $self->{timeout} = delete $attr{timeout}; 58 $self->{_attr} = { %attr }; 59 foreach (keys %{$self->{_attr}}) { 60 if (exists $params{$_}) { 61 $self->{_attr}->{$_} = $params{$_}; 62 } else { 63 $self->{_attr}->{$_} = $self->{_attr}->{$_}->{default} 64 if ref ($self->{_attr}->{$_}) eq 'HASH' && 65 exists $self->{_attr}->{$_}->{default}; 66 } 67 } 68 # Chomp _attr values 69 chomp foreach values %{$self->{_attr}}; 70 71 # Setup initial args list 72 $self->{_args} = [ grep { exists $_->{spec} } @ARGS ]; 73 74 $self 75} 76 77sub new { 78 my ($class, @params) = @_; 79 require Monitoring::GLPlugin::Commandline::Extraopts 80 if ! grep /BEGIN/, keys %Monitoring::GLPlugin::Commandline::Extraopts::; 81 my $self = bless {}, $class; 82 $self->_init(@params); 83} 84 85sub decode_rfc3986 { 86 my ($self, $password) = @_; 87 if ($password && $password =~ /^rfc3986:\/\/(.*)/) { 88 $password = $1; 89 $password =~ s/%([A-Za-z0-9]{2})/chr(hex($1))/seg; 90 } 91 return $password; 92} 93 94sub add_arg { 95 my ($self, %arg) = @_; 96 push (@{$self->{_args}}, \%arg); 97} 98 99sub mod_arg { 100 my ($self, $argname, %arg) = @_; 101 foreach my $old_arg (@{$self->{_args}}) { 102 next unless $old_arg->{spec} =~ /(\w+).*/ && $argname eq $1; 103 foreach my $key (keys %arg) { 104 $old_arg->{$key} = $arg{$key}; 105 } 106 } 107} 108 109sub getopts { 110 my ($self) = @_; 111 my %commandline = (); 112 $self->{opts}->{all_my_opts} = {}; 113 my @params = map { $_->{spec} } @{$self->{_args}}; 114 if (! GetOptions(\%commandline, @params)) { 115 $self->print_help(); 116 exit 3; 117 } else { 118 no strict 'refs'; 119 no warnings 'redefine'; 120 if (exists $commandline{'extra-opts'}) { 121 # read the extra file and overwrite other parameters 122 my $extras = Monitoring::GLPlugin::Commandline::Extraopts->new( 123 file => $commandline{'extra-opts'}, 124 commandline => \%commandline 125 ); 126 if (! $extras->is_valid()) { 127 printf "UNKNOWN - extra-opts are not valid: %s\n", $extras->errors(); 128 exit 3; 129 } else { 130 $extras->overwrite(); 131 } 132 } 133 do { $self->print_help(); exit 0; } if $commandline{help}; 134 do { $self->print_version(); exit 0 } if $commandline{version}; 135 do { $self->print_usage(); exit 3 } if $commandline{usage}; 136 foreach (map { $_->{spec} =~ /^([\w\-]+)/; $1; } @{$self->{_args}}) { 137 my $field = $_; 138 *{"$field"} = sub { 139 return $self->{opts}->{$field}; 140 }; 141 } 142 *{"all_my_opts"} = sub { 143 return $self->{opts}->{all_my_opts}; 144 }; 145 foreach (@{$self->{_args}}) { 146 $_->{spec} =~ /^([\w\-]+)/; 147 my $spec = $1; 148 my $envname = uc $spec; 149 $envname =~ s/\-/_/g; 150 if (! exists $commandline{$spec}) { 151 # Kommandozeile hat oberste Prioritaet 152 # Also: --option ueberschreibt NAGIOS__HOSTOPTION 153 # Aaaaber: extra-opts haben immer noch Vorrang vor allem anderen. 154 # https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html 155 # beschreibt das anders, Posix-Tools verhalten sich auch entsprechend. 156 # Irgendwann wird das hier daher umgeschrieben, so dass extra-opts 157 # die niedrigste Prioritaet erhalten. 158 if (exists $ENV{'NAGIOS__SERVICE'.$envname}) { 159 $commandline{$spec} = $ENV{'NAGIOS__SERVICE'.$envname}; 160 } elsif (exists $ENV{'NAGIOS__HOST'.$envname}) { 161 $commandline{$spec} = $ENV{'NAGIOS__HOST'.$envname}; 162 } 163 } 164 $self->{opts}->{$spec} = $_->{default}; 165 } 166 foreach (map { $_->{spec} =~ /^([\w\-]+)/; $1; } 167 grep { exists $_->{required} && $_->{required} } @{$self->{_args}}) { 168 do { $self->print_usage(); exit 3 } if ! exists $commandline{$_}; 169 } 170 foreach (grep { exists $_->{default} } @{$self->{_args}}) { 171 $_->{spec} =~ /^([\w\-]+)/; 172 my $spec = $1; 173 $self->{opts}->{$spec} = $_->{default}; 174 } 175 foreach (keys %commandline) { 176 $self->{opts}->{$_} = $commandline{$_}; 177 $self->{opts}->{all_my_opts}->{$_} = $commandline{$_}; 178 } 179 foreach (grep { exists $_->{env} } @{$self->{_args}}) { 180 $_->{spec} =~ /^([\w\-]+)/; 181 my $spec = $1; 182 if (exists $ENV{'NAGIOS__HOST'.$_->{env}}) { 183 $self->{opts}->{$spec} = $ENV{'NAGIOS__HOST'.$_->{env}}; 184 } 185 if (exists $ENV{'NAGIOS__SERVICE'.$_->{env}}) { 186 $self->{opts}->{$spec} = $ENV{'NAGIOS__SERVICE'.$_->{env}}; 187 } 188 } 189 foreach (grep { exists $_->{aliasfor} } @{$self->{_args}}) { 190 my $field = $_->{aliasfor}; 191 $_->{spec} =~ /^([\w\-]+)/; 192 my $aliasfield = $1; 193 next if $self->{opts}->{$field}; 194 $self->{opts}->{$field} = $self->{opts}->{$aliasfield}; 195 *{"$field"} = sub { 196 return $self->{opts}->{$field}; 197 }; 198 } 199 foreach (grep { exists $_->{decode} } @{$self->{_args}}) { 200 my $decoding = $_->{decode}; 201 $_->{spec} =~ /^([\w\-]+)/; 202 my $spec = $1; 203 if (exists $self->{opts}->{$spec}) { 204 if ($decoding eq "rfc3986") { 205 $self->{opts}->{$spec} = 206 $self->decode_rfc3986($self->{opts}->{$spec}); 207 } 208 } 209 } 210 } 211} 212 213sub create_opt { 214 my ($self, $key) = @_; 215 no strict 'refs'; 216 *{"$key"} = sub { 217 return $self->{opts}->{$key}; 218 }; 219} 220 221sub override_opt { 222 my ($self, $key, $value) = @_; 223 $self->{opts}->{$key} = $value; 224} 225 226sub get { 227 my ($self, $opt) = @_; 228 return $self->{opts}->{$opt}; 229} 230 231sub print_help { 232 my ($self) = @_; 233 $self->print_version(); 234 printf "\n%s\n", $self->{_attr}->{license}; 235 printf "\n%s\n\n", $self->{_attr}->{blurb}; 236 $self->print_usage(); 237 foreach (grep { 238 ! (exists $_->{hidden} && $_->{hidden}) 239 } @{$self->{_args}}) { 240 printf " %s\n", $_->{help}; 241 } 242} 243 244sub print_usage { 245 my ($self) = @_; 246 printf $self->{_attr}->{usage}, $self->{_attr}->{plugin}; 247 print "\n"; 248} 249 250sub print_version { 251 my ($self) = @_; 252 printf "%s %s", $self->{_attr}->{plugin}, $self->{_attr}->{version}; 253 printf " [%s]", $self->{_attr}->{url} if $self->{_attr}->{url}; 254 print "\n"; 255} 256 257sub print_license { 258 my ($self) = @_; 259 printf "%s\n", $self->{_attr}->{license}; 260 print "\n"; 261} 262 2631; 264 265__END__ 266