Add TODO comments for problematic bits of code

This commit is contained in:
Richard Hansen 2024-06-24 17:55:15 -04:00
parent ab2e0d7999
commit bd688e9750

View file

@ -1540,6 +1540,11 @@ sub write_recap {
my ($file) = @_; my ($file) = @_;
for my $h (keys %config) { for my $h (keys %config) {
# nic_updateable (called from update_nics for each host) sets `$config{$h}{update}`
# according to whether an update was attempted.
#
# TODO: Why are different variables saved to the recap depending on whether an update was
# attempted or not? Shouldn't the same variables be saved every time?
if (!exists $recap{$h} || $config{$h}{'update'}) { if (!exists $recap{$h} || $config{$h}{'update'}) {
my $vars = $protocols{$config{$h}{protocol}}{variables}; my $vars = $protocols{$config{$h}{protocol}}{variables};
for my $v (keys(%$vars)) { for my $v (keys(%$vars)) {
@ -1602,6 +1607,8 @@ sub read_recap {
for my $h (keys(%recap)) { for my $h (keys(%recap)) {
next if !exists($config->{$h}); next if !exists($config->{$h});
# TODO: Why is this limited to this set of variables? Why not copy every recap var
# defined for the host's protocol?
for (qw(atime mtime wtime ip ipv4 ipv6 status status-ipv4 status-ipv6)) { for (qw(atime mtime wtime ip ipv4 ipv6 status status-ipv4 status-ipv6)) {
# TODO: Isn't $config equal to \%recap here? If so, this is a no-op. What was the # TODO: Isn't $config equal to \%recap here? If so, this is a no-op. What was the
# original intention behind this? To copy %recap values into %config? If so, is # original intention behind this? To copy %recap values into %config? If so, is
@ -1760,6 +1767,8 @@ sub _read_config {
} }
## remove comments ## remove comments
# TODO: This makes it impossible to include '#' in keys or values except as permitted by
# the special password parsing above.
s/#.*//; s/#.*//;
## Handle continuation lines ## Handle continuation lines
@ -1778,6 +1787,8 @@ sub _read_config {
s/^\s+//; # remove leading white space s/^\s+//; # remove leading white space
s/\s+$//; # remove trailing white space s/\s+$//; # remove trailing white space
# TODO: This makes it impossible to include multiple consecutive spaces, tabs, etc. in keys
# or values.
s/\s+/ /g; # canonify s/\s+/ /g; # canonify
next if /^$/; next if /^$/;
@ -1799,6 +1810,7 @@ sub _read_config {
# Set the value to the value of the environment variable # Set the value to the value of the environment variable
$locals{$1} = $ENV{$locals{$k}}; $locals{$1} = $ENV{$locals{$k}};
# Remove the '_env' suffix from the key # Remove the '_env' suffix from the key
# TODO: Shouldn't the *_env entry be deleted from %locals?
$k = $1; $k = $1;
} }
@ -1808,6 +1820,8 @@ sub _read_config {
delete $locals{$k}; delete $locals{$k};
next; next;
} }
# TODO: This might grab an arbitrary protocol-specific variable definition, which could
# cause surprising behavior.
my $def = $variables{'merged'}{$k}; my $def = $variables{'merged'}{$k};
my $value = check_value($locals{$k}, $def); my $value = check_value($locals{$k}, $def);
if (!defined($value)) { if (!defined($value)) {
@ -1872,24 +1886,36 @@ sub init_config {
## infer the IP strategy if possible ## infer the IP strategy if possible
if (!$opt{'use'}) { if (!$opt{'use'}) {
# TODO: I don't think these have any effect. The value is not copied into the
# host-specific %config settings, and $config{$h}{use} is initialized to the variable
# default ("ip"), not set to undef, so opt() won't fall back to this.
$opt{'use'} = 'web' if ($opt{'web'}); $opt{'use'} = 'web' if ($opt{'web'});
$opt{'use'} = 'if' if ($opt{'if'}); $opt{'use'} = 'if' if ($opt{'if'});
$opt{'use'} = 'ip' if ($opt{'ip'}); $opt{'use'} = 'ip' if ($opt{'ip'});
} }
## infer the IPv4 strategy if possible ## infer the IPv4 strategy if possible
if (!$opt{'usev4'}) { if (!$opt{'usev4'}) {
# TODO: I don't think these have any effect. The value is not copied into the
# host-specific %config settings, and $config{$h}{usev4} is initialized to the variable
# default ("disabled"), not set to undef, so opt() won't fall back to this.
$opt{'usev4'} = 'webv4' if ($opt{'webv4'}); $opt{'usev4'} = 'webv4' if ($opt{'webv4'});
$opt{'usev4'} = 'ifv4' if ($opt{'ifv4'}); $opt{'usev4'} = 'ifv4' if ($opt{'ifv4'});
$opt{'usev4'} = 'ipv4' if ($opt{'ipv4'}); $opt{'usev4'} = 'ipv4' if ($opt{'ipv4'});
} }
## infer the IPv6 strategy if possible ## infer the IPv6 strategy if possible
if (!$opt{'usev6'}) { if (!$opt{'usev6'}) {
# TODO: I don't think these have any effect. The value is not copied into the
# host-specific %config settings, and $config{$h}{usev6} is initialized to the variable
# default ("disabled"), not set to undef, so opt() won't fall back to this.
$opt{'usev6'} = 'webv6' if ($opt{'webv6'}); $opt{'usev6'} = 'webv6' if ($opt{'webv6'});
$opt{'usev6'} = 'ifv6' if ($opt{'ifv6'}); $opt{'usev6'} = 'ifv6' if ($opt{'ifv6'});
$opt{'usev6'} = 'ipv6' if ($opt{'ipv6'}); $opt{'usev6'} = 'ipv6' if ($opt{'ipv6'});
} }
## sanity check ## sanity check
# TODO: I don't think these have any effect. The values are not copied into the host-specific
# %config settings, and $config{$h}{$opt} is initialized to the non-undef variable default so
# opt() won't fall back to these.
$opt{'max-interval'} = min(interval(opt('max-interval')), interval(default('max-interval'))); $opt{'max-interval'} = min(interval(opt('max-interval')), interval(default('max-interval')));
$opt{'min-interval'} = max(interval(opt('min-interval')), interval(default('min-interval'))); $opt{'min-interval'} = max(interval(opt('min-interval')), interval(default('min-interval')));
$opt{'min-error-interval'} = max(interval(opt('min-error-interval')), interval(default('min-error-interval'))); $opt{'min-error-interval'} = max(interval(opt('min-error-interval')), interval(default('min-error-interval')));
@ -1911,6 +1937,7 @@ sub init_config {
warning("'$name' is deprecated and does nothing"); warning("'$name' is deprecated and does nothing");
next; next;
} }
# TODO: Shouldn't *_env options be processed like _read_config does?
$options{$name} = $var; $options{$name} = $var;
} }
## determine hosts specified with --host ## determine hosts specified with --host
@ -1928,20 +1955,20 @@ sub init_config {
delete $options{'host'}; delete $options{'host'};
} }
## merge options into host definitions or globals ## merge options into host definitions or globals
# TODO: Keys and values should be validated before mutating %config or %globals.
if (@hosts) { if (@hosts) {
for my $h (@hosts) { for my $h (@hosts) {
$config{$h} = {%{$config{$h} // {}}, %options, 'host' => $h}; $config{$h} = {%{$config{$h} // {}}, %options, 'host' => $h};
} }
$opt{'host'} = join(',', @hosts); $opt{'host'} = join(',', @hosts);
} else { } else {
# TODO: Why not merge the values into %opt?
%globals = (%globals, %options); %globals = (%globals, %options);
} }
} }
## override global options with those on the command-line. ## override global options with those on the command-line.
for my $o (keys %opt) { for my $o (keys %opt) {
# TODO: Isn't $opt{$o} guaranteed to be defined? Otherwise $o wouldn't appear in the keys
# of %opt, right?
# TODO: Why is this limited to $variables{'global-defaults'}? Why not # TODO: Why is this limited to $variables{'global-defaults'}? Why not
# $variables{'merged'}? # $variables{'merged'}?
if (defined $opt{$o} && exists $variables{'global-defaults'}{$o}) { if (defined $opt{$o} && exists $variables{'global-defaults'}{$o}) {
@ -1949,6 +1976,9 @@ sub init_config {
# %opt doesn't have a value, so this shouldn't be necessary. # %opt doesn't have a value, so this shouldn't be necessary.
$globals{$o} = $opt{$o}; $globals{$o} = $opt{$o};
} }
# TODO: Why aren't host configs updated with command-line values (except for $opt{options}
# handled above)? Shouldn't command-line values always override config file values (even
# if they are not associated with a host via `--host=` or `--options=host=`)?
} }
## sanity check ## sanity check
@ -1962,7 +1992,9 @@ sub init_config {
if (opt('host')) { if (opt('host')) {
@hosts = split_by_comma($opt{'host'}); @hosts = split_by_comma($opt{'host'});
} }
# TODO: This function is called before the recap file is read. How is this supposed to work? # TODO: The first two times init_config() is called the cache file has not been read yet, so
# this will not filter out any hosts and thus updates will not be limited to non-good hosts as
# intended.
if (opt('retry')) { if (opt('retry')) {
@hosts = grep(($recap{$_}{'status'} // '') ne 'good', keys(%recap)); @hosts = grep(($recap{$_}{'status'} // '') ne 'good', keys(%recap));
} }
@ -1972,11 +2004,19 @@ sub init_config {
map { $hosts{$_} = undef } @hosts; map { $hosts{$_} = undef } @hosts;
map { delete $config{$_} unless exists $hosts{$_} } keys %config; map { delete $config{$_} unless exists $hosts{$_} } keys %config;
# TODO: Why aren't the hosts specified by --host added to %config except when --options is also
# given?
## sanity check.. ## sanity check..
# TODO: The code below doesn't look like a mere "sanity check", so I'm guessing the above
# comment is out of date. Figure out what this code is actually doing and refactor to improve
# the readability so that a comment isn't necessary.
## make sure config entries have all defaults and they meet minimums ## make sure config entries have all defaults and they meet minimums
## first the globals... ## first the globals...
for my $k (keys %globals) { for my $k (keys %globals) {
# Make sure any _env suffixed variables look at their original entry # Make sure any _env suffixed variables look at their original entry
# TODO: Didn't _read_config already handle *_env? Or is this needed to handle
# the --options command-line option whose values were merged into %globals above?
$k = $1 if $k =~ /^(.*)_env$/; $k = $1 if $k =~ /^(.*)_env$/;
# TODO: This might grab an arbitrary protocol-specific variable, which could cause # TODO: This might grab an arbitrary protocol-specific variable, which could cause
@ -1990,9 +2030,12 @@ sub init_config {
# TODO: Isn't $globals{$k} guaranteed to be defined here? Otherwise $k wouldn't appear in # TODO: Isn't $globals{$k} guaranteed to be defined here? Otherwise $k wouldn't appear in
# %globals. # %globals.
my $ovalue = $globals{$k} // $def->{'default'}; my $ovalue = $globals{$k} // $def->{'default'};
# TODO: Didn't _read_config already check the value? Or is the purpose of this to check # _read_config already checked any value from the config file, so the purpose of this check
# the value of command-line options ($opt{$k}) which were merged into %globals above? # is to validate command-line options which were merged into %globals above.
# TODO: Move this check to where the command-line options are actually processed.
my $value = check_value($ovalue, $def); my $value = check_value($ovalue, $def);
# TODO: If the variable is not required, the value is set to undef but no warning is
# logged. Is that intentional?
if ($def->{'required'} && !defined $value) { if ($def->{'required'} && !defined $value) {
# TODO: What's the point of this? The opt() function will fall back to the default # TODO: What's the point of this? The opt() function will fall back to the default
# value if $globals{$k} is undefined. # value if $globals{$k} is undefined.
@ -2018,13 +2061,26 @@ sub init_config {
my $svars = $protocols{$proto}{'variables'}; my $svars = $protocols{$proto}{'variables'};
my $conf = {'host' => $h, 'protocol' => $proto}; my $conf = {'host' => $h, 'protocol' => $proto};
# TODO: This silently ignores unknown options passed via --options.
for my $k (keys %$svars) { for my $k (keys %$svars) {
# Make sure any _env suffixed variables look at their original entry # Make sure any _env suffixed variables look at their original entry
$k = $1 if $k =~ /^(.*)_env$/; $k = $1 if $k =~ /^(.*)_env$/;
my $def = $svars->{$k}; my $def = $svars->{$k};
# TODO: Why doesn't this try %opt and %globals before falling back to the variable
# default? By ignoring %opt and %globals, `--options` will not have any effect on any
# hosts that are not specified on the command line (via `--host=a,b` and/or
# `--options=host=c,d`).
# TODO: Why not just leave $conf->{$k} undef? Then opt() would automatically fall back
# to %opt, %globals, or the variable default.
my $ovalue = $config{$h}{$k} // $def->{'default'}; my $ovalue = $config{$h}{$k} // $def->{'default'};
# _read_config already checked any value from the config file, so the purpose of this
# check is to validate command-line options from --options which were merged into
# $config{$h} above.
# TODO: Move this check to where --options is actually processed.
my $value = check_value($ovalue, $def); my $value = check_value($ovalue, $def);
# TODO: If the variable is not required, the value is set to undef but no warning is
# logged. Is that intentional?
if ($def->{'required'} && !defined $value) { if ($def->{'required'} && !defined $value) {
$ovalue //= '(not set)'; $ovalue //= '(not set)';
warning("skipping host $h: invalid $def->{type} variable value '$k=$ovalue'"); warning("skipping host $h: invalid $def->{type} variable value '$k=$ovalue'");
@ -2321,17 +2377,24 @@ sub split_by_comma {
sub default { sub default {
my $v = shift; my $v = shift;
return undef if !defined($variables{'merged'}{$v}); return undef if !defined($variables{'merged'}{$v});
# TODO: This might grab an arbitrary protocol-specific variable definition, which could cause
# surprising behavior.
return $variables{'merged'}{$v}{'default'}; return $variables{'merged'}{$v}{'default'};
} }
sub minimum { sub minimum {
my $v = shift; my $v = shift;
return undef if !defined($variables{'merged'}{$v}); return undef if !defined($variables{'merged'}{$v});
# TODO: This might grab an arbitrary protocol-specific variable definition, which could cause
# surprising behavior.
return $variables{'merged'}{$v}{'minimum'}; return $variables{'merged'}{$v}{'minimum'};
} }
sub opt { sub opt {
my $v = shift; my $v = shift;
my $h = shift; my $h = shift;
return $config{$h}{$v} if defined($h) && defined($config{$h}{$v}); return $config{$h}{$v} if defined($h) && defined($config{$h}{$v});
# TODO: Why check %opt before %globals? Valid variables from %opt are merged into %globals by
# init_config(), so it shouldn't be necessary. Also, it runs the risk of collision with a
# non-variable command line option like `--version`, `--help`, etc.
return $opt{$v} // $globals{$v} // default($v); return $opt{$v} // $globals{$v} // default($v);
} }
sub min { sub min {