small nit inline On November 20, 2019 5:43 pm, Stefan Reiter wrote: > add_corosync_link_properties/extract_corosync_link_args are introduced > as helpers to avoid hardcoding links in parameters=>properties on > several occasions, while still providing autocompletion with pvecm by > being seperate parameters instead of an array. > > Maximum number of links is given as constant MAX_LINK_COUNT, should it > change in the future. > > All necessary functions have been updated to > use the new $links array format instead of seperate $link0/$link1 > parameters, and call sites changed accordingly. > > Signed-off-by: Stefan Reiter <s.rei...@proxmox.com> > --- > > This patch intentionally removes some verification and fallback code to be > reintroduced in the next one. > > data/PVE/API2/ClusterConfig.pm | 51 +++++++------------ > data/PVE/CLI/pvecm.pm | 20 ++++---- > data/PVE/Cluster/Setup.pm | 22 +++++---- > data/PVE/Corosync.pm | 89 +++++++++++++++++++++++----------- > 4 files changed, 100 insertions(+), 82 deletions(-) > > diff --git a/data/PVE/API2/ClusterConfig.pm b/data/PVE/API2/ClusterConfig.pm > index 3d778b8..241c14e 100644 > --- a/data/PVE/API2/ClusterConfig.pm > +++ b/data/PVE/API2/ClusterConfig.pm > @@ -68,10 +68,11 @@ __PACKAGE__->register_method ({ > path => '', > method => 'POST', > protected => 1, > - description => "Generate new cluster configuration.", > + description => "Generate new cluster configuration. If no links given," > + . " default to local IP address as link0.", > parameters => { > additionalProperties => 0, > - properties => { > + properties => PVE::Corosync::add_corosync_link_properties({ > clustername => { > description => "The name of the cluster.", > type => 'string', format => 'pve-node', > @@ -84,9 +85,7 @@ __PACKAGE__->register_method ({ > minimum => 1, > optional => 1, > }, > - link0 => get_standard_option('corosync-link'), > - link1 => get_standard_option('corosync-link'), > - }, > + }), > }, > returns => { type => 'string' }, > code => sub { > @@ -110,7 +109,7 @@ __PACKAGE__->register_method ({ > my $nodename = PVE::INotify::nodename(); > > # get the corosync basis config for the new cluster > - my $config = PVE::Corosync::create_conf($nodename, %$param); > + my $config = PVE::Corosync::create_conf($nodename, $param); > > print "Writing corosync config to /etc/pve/corosync.conf\n"; > PVE::Corosync::atomic_write_conf($config); > @@ -194,7 +193,7 @@ __PACKAGE__->register_method ({ > description => "Adds a node to the cluster configuration. This call is > for internal use.", > parameters => { > additionalProperties => 0, > - properties => { > + properties => PVE::Corosync::add_corosync_link_properties({ > node => get_standard_option('pve-node'), > nodeid => get_standard_option('corosync-nodeid'), > votes => { > @@ -208,9 +207,7 @@ __PACKAGE__->register_method ({ > description => "Do not throw error if node already exists.", > optional => 1, > }, > - link0 => get_standard_option('corosync-link'), > - link1 => get_standard_option('corosync-link'), > - }, > + }), > }, > returns => { > type => "object", > @@ -256,7 +253,7 @@ __PACKAGE__->register_method ({ > while (my ($k, $v) = each %$nodelist) { > next if $k eq $name; # allows re-adding a node if force is > set > > - for my $linknumber (0..1) { > + for my $linknumber (0..$PVE::Corosync::max_link_iter) { > my $id = "ring${linknumber}_addr"; > next if !defined($v->{$id}); > > @@ -266,20 +263,10 @@ __PACKAGE__->register_method ({ > } > }; > > - my $link0 = PVE::Corosync::parse_corosync_link($param->{link0}); > - my $link1 = PVE::Corosync::parse_corosync_link($param->{link1}); > - > - $check_duplicate_addr->($link0); > - $check_duplicate_addr->($link1); > - > - # FIXME: handle all links (0-7), they're all independent now > - $link0->{address} //= $name if exists($totem_cfg->{interface}->{0}); > - > - die "corosync: using 'link1' parameter needs a interface with > linknumber '1' configured!\n" > - if $link1 && !defined($totem_cfg->{interface}->{1}); > - > - die "corosync: totem interface with linknumber 1 configured but > 'link1' parameter not defined!\n" > - if defined($totem_cfg->{interface}->{1}) && !defined($link1); > + my $links = PVE::Corosync::extract_corosync_link_args($param); > + foreach my $link (values %$links) { > + $check_duplicate_addr->($link); > + } > > if (defined(my $res = $nodelist->{$name})) { > $param->{nodeid} = $res->{nodeid} if !$param->{nodeid}; > @@ -317,13 +304,15 @@ __PACKAGE__->register_method ({ > warn $@ if $@; > > $nodelist->{$name} = { > - ring0_addr => $link0->{address}, > nodeid => $param->{nodeid}, > name => $name, > }; > - $nodelist->{$name}->{ring1_addr} = $link1->{address} if > defined($link1); > $nodelist->{$name}->{quorum_votes} = $param->{votes} if > $param->{votes}; > > + foreach my $link (keys %$links) { > + $nodelist->{$name}->{"ring${link}_addr"} = > $links->{$link}->{address}; > + } > + > PVE::Cluster::log_msg('notice', 'root@pam', "adding node $name to > cluster"); > > PVE::Corosync::update_nodelist($conf, $nodelist); > @@ -495,7 +484,7 @@ __PACKAGE__->register_method ({ > description => "Joins this node into an existing cluster.", > parameters => { > additionalProperties => 0, > - properties => { > + properties => PVE::Corosync::add_corosync_link_properties({ > hostname => { > type => 'string', > description => "Hostname (or IP) of an existing cluster member." > @@ -512,17 +501,13 @@ __PACKAGE__->register_method ({ > description => "Do not throw error if node already exists.", > optional => 1, > }, > - link0 => get_standard_option('corosync-link', { > - default => "IP resolved by node's hostname", > - }), > - link1 => get_standard_option('corosync-link'), > fingerprint => get_standard_option('fingerprint-sha256'), > password => { > description => "Superuser (root) password of peer node.", > type => 'string', > maxLength => 128, > }, > - }, > + }), > }, > returns => { type => 'string' }, > code => sub { > diff --git a/data/PVE/CLI/pvecm.pm b/data/PVE/CLI/pvecm.pm > index 172ef8c..5856b56 100755 > --- a/data/PVE/CLI/pvecm.pm > +++ b/data/PVE/CLI/pvecm.pm > @@ -316,7 +316,7 @@ __PACKAGE__->register_method ({ > description => "Adds the current node to an existing cluster.", > parameters => { > additionalProperties => 0, > - properties => { > + properties => PVE::Corosync::add_corosync_link_properties({ > hostname => { > type => 'string', > description => "Hostname (or IP) of an existing cluster member." > @@ -333,8 +333,6 @@ __PACKAGE__->register_method ({ > description => "Do not throw error if node already exists.", > optional => 1, > }, > - link0 => get_standard_option('corosync-link'), > - link1 => get_standard_option('corosync-link'), > fingerprint => get_standard_option('fingerprint-sha256', { > optional => 1, > }), > @@ -343,7 +341,7 @@ __PACKAGE__->register_method ({ > description => "Always use SSH to join, even if peer may do it > over API.", > optional => 1, > }, > - }, > + }), > }, > returns => { type => 'null' }, > > @@ -355,8 +353,7 @@ __PACKAGE__->register_method ({ > my $host = $param->{hostname}; > my $local_ip_address = PVE::Cluster::remote_node_ip($nodename); > > - my $link0 = PVE::Corosync::parse_corosync_link($param->{link0}); > - my $link1 = PVE::Corosync::parse_corosync_link($param->{link1}); > + my $links = PVE::Corosync::extract_corosync_link_args($param); > > my $worker = sub { > > @@ -381,7 +378,7 @@ __PACKAGE__->register_method ({ > > # allow fallback to old ssh only join if wished or needed > > - PVE::Cluster::Setup::assert_joinable($local_ip_address, $link0, > $link1, $param->{force}); > + PVE::Cluster::Setup::assert_joinable($local_ip_address, $links, > $param->{force}); > > PVE::Cluster::Setup::setup_sshd_config(); > PVE::Cluster::Setup::setup_rootsshconfig(); > @@ -399,10 +396,11 @@ __PACKAGE__->register_method ({ > > push @$cmd, '--nodeid', $param->{nodeid} if $param->{nodeid}; > push @$cmd, '--votes', $param->{votes} if defined($param->{votes}); > - # just pass the un-parsed string through, or as we've address as > - # the default_key, we can just pass the fallback directly too > - push @$cmd, '--link0', $param->{link0} // $local_ip_address; > - push @$cmd, '--link1', $param->{link1} if defined($param->{link1}); > + > + foreach my $link (keys %$links) { > + push @$cmd, "--link$link", > PVE::JSONSchema::print_property_string( > + $links->{$link}, get_standard_option('corosync-link')); > + } > > if (system (@$cmd) != 0) { > my $cmdtxt = join (' ', @$cmd); > diff --git a/data/PVE/Cluster/Setup.pm b/data/PVE/Cluster/Setup.pm > index 5569d6c..e8c5eca 100644 > --- a/data/PVE/Cluster/Setup.pm > +++ b/data/PVE/Cluster/Setup.pm > @@ -561,7 +561,7 @@ sub gen_pve_vzdump_files { > # join helpers > > sub assert_joinable { > - my ($local_addr, $link0, $link1, $force) = @_; > + my ($local_addr, $links, $force) = @_; > > my $errors = ''; > my $error = sub { $errors .= "* $_[0]\n"; }; > @@ -604,8 +604,12 @@ sub assert_joinable { > }; > > $check_ip->($local_addr, 'local node address'); > - $check_ip->($link0->{address}, 'ring0') if defined($link0); > - $check_ip->($link1->{address}, 'ring1') if defined($link1); > + > + if ($links) { > + foreach my $link (keys %$links) { > + $check_ip->($links->{$link}->{address}, "link$link"); > + } > + } > > if ($errors) { > warn "detected the following error(s):\n$errors"; > @@ -619,11 +623,10 @@ sub join { > my $nodename = PVE::INotify::nodename(); > my $local_ip_address = PVE::Cluster::remote_node_ip($nodename); > > - my $link0 = PVE::Corosync::parse_corosync_link($param->{link0}); > - my $link1 = PVE::Corosync::parse_corosync_link($param->{link1}); > + my $links = PVE::Corosync::extract_corosync_link_args($param); > > # check if we can join with the given parameters and current node state > - assert_joinable($local_ip_address, $link0, $link1, $param->{force}); > + assert_joinable($local_ip_address, $links, $param->{force}); > > setup_sshd_config(); > setup_rootsshconfig(); > @@ -661,10 +664,9 @@ sub join { > $args->{force} = $param->{force} if defined($param->{force}); > $args->{nodeid} = $param->{nodeid} if $param->{nodeid}; > $args->{votes} = $param->{votes} if defined($param->{votes}); > - # just pass the un-parsed string through, or as we've address as the > - # default_key, we can just pass the fallback directly too > - $args->{link0} = $param->{link0} // $local_ip_address; > - $args->{link1} = $param->{link1} if defined($param->{link1}); > + foreach my $link (keys %$links) { > + $args->{"link$link"} = > PVE::Corosync::print_corosync_link($links->{$link}); > + } > > print "Request addition of this node\n"; > my $res = eval { $conn->post("/cluster/config/nodes/$nodename", $args); > }; > diff --git a/data/PVE/Corosync.pm b/data/PVE/Corosync.pm > index 5973aaf..69927ff 100644 > --- a/data/PVE/Corosync.pm > +++ b/data/PVE/Corosync.pm > @@ -35,12 +35,15 @@ my $corosync_link_format = { > minimum => 0, > maximum => 255, > default => 0, > - description => "The priority for the link when knet is used in > 'passive' mode. Lower value means higher priority.", > + description => "The priority for the link when knet is used in > 'passive'" > + . " mode (default). Lower value means higher priority. > Only" > + . " valid for cluster create, ignored on node add.", > }, > }; > my $corosync_link_desc = { > type => 'string', format => $corosync_link_format, > - description => "Address and priority information of a single corosync > link.", > + description => "Address and priority information of a single corosync > link." > + . " (up to 8 links supported; link0..link7)", > optional => 1, > }; > PVE::JSONSchema::register_standard_option("corosync-link", > $corosync_link_desc); > @@ -53,6 +56,39 @@ sub parse_corosync_link { > return PVE::JSONSchema::parse_property_string($corosync_link_format, > $value); > } > > +sub print_corosync_link { > + my ($link) = @_; > + > + return undef if !defined($link); > + > + return PVE::JSONSchema::print_property_string($link, > $corosync_link_format); > +} > + > +use constant MAX_LINK_COUNT => 8; > +our $max_link_iter = MAX_LINK_COUNT - 1;
why not export a constant of 7 for MAX_LINK_INDEX , since only that ever gets used? we know that arrays start their indices at 0 ;) > + > +sub add_corosync_link_properties { > + my ($prop) = @_; > + > + for my $lnum (0..$max_link_iter) { > + $prop->{"link$lnum"} = > PVE::JSONSchema::get_standard_option("corosync-link"); > + } > + > + return $prop; > +} > + > +sub extract_corosync_link_args { > + my ($args) = @_; > + > + my $links = {}; > + for my $lnum (0..$max_link_iter) { > + $links->{$lnum} = parse_corosync_link($args->{"link$lnum"}) > + if $args->{"link$lnum"}; > + } > + > + return $links; > +} > + > # a very simply parser ... > sub parse_conf { > my ($filename, $raw) = @_; > @@ -234,16 +270,19 @@ sub atomic_write_conf { > # for creating a new cluster with the current node > # params are those from the API/CLI cluster create call > sub create_conf { > - my ($nodename, %param) = @_; > + my ($nodename, $param) = @_; > > - my $clustername = $param{clustername}; > - my $nodeid = $param{nodeid} || 1; > - my $votes = $param{votes} || 1; > + my $clustername = $param->{clustername}; > + my $nodeid = $param->{nodeid} || 1; > + my $votes = $param->{votes} || 1; > > my $local_ip_address = PVE::Cluster::remote_node_ip($nodename); > > - my $link0 = PVE::Cluster::parse_corosync_link($param{link0}); > - $link0->{address} //= $local_ip_address; > + my $links = extract_corosync_link_args($param); > + > + # if no links given, fall back to local IP as link0 > + $links->{0} = { address => $local_ip_address } > + if !%$links; > > my $conf = { > totem => { > @@ -252,11 +291,8 @@ sub create_conf { > cluster_name => $clustername, > config_version => 0, > ip_version => 'ipv4-6', > - interface => { > - 0 => { > - linknumber => 0, > - }, > - }, > + link_mode => 'passive', > + interface => {}, > }, > nodelist => { > node => { > @@ -264,7 +300,6 @@ sub create_conf { > name => $nodename, > nodeid => $nodeid, > quorum_votes => $votes, > - ring0_addr => $link0->{address}, > }, > }, > }, > @@ -277,19 +312,17 @@ sub create_conf { > }, > }; > my $totem = $conf->{totem}; > + my $node = $conf->{nodelist}->{node}->{$nodename}; > + > + foreach my $lnum (keys %$links) { > + my $link = $links->{$lnum}; > + > + $totem->{interface}->{$lnum} = { linknumber => $lnum }; > + > + my $prio = $link->{priority}; > + $totem->{interface}->{$lnum}->{knet_link_priority} = $prio if $prio; > > - $totem->{interface}->{0}->{knet_link_priority} = $link0->{priority} > - if defined($link0->{priority}); > - > - my $link1 = PVE::Cluster::parse_corosync_link($param{link1}); > - if ($link1->{address}) { > - $conf->{totem}->{interface}->{1} = { > - linknumber => 1, > - }; > - $totem->{link_mode} = 'passive'; > - $totem->{interface}->{1}->{knet_link_priority} = $link1->{priority} > - if defined($link1->{priority}); > - $conf->{nodelist}->{node}->{$nodename}->{ring1_addr} = > $link1->{address}; > + $node->{"ring${lnum}_addr"} = $link->{address}; > } > > return { main => $conf }; > @@ -354,7 +387,7 @@ sub verify_conf { > if (%$interfaces) { > # if interfaces are defined, *all* links must have a matching interface > # definition, and vice versa > - for my $link (0..1) { > + for my $link (0..$max_link_iter) { > my $have_interface = defined($interfaces->{$link}); > foreach my $node (@node_names) { > my ($optname, $addr) = $find_option->($nodelist->{$node}, > $link); > @@ -372,7 +405,7 @@ sub verify_conf { > } > } else { > # without interfaces, only check that links are consistent among nodes > - for my $link (0..1) { > + for my $link (0..$max_link_iter) { > my $nodes_with_link = {}; > foreach my $node (@node_names) { > my ($optname, $addr) = $find_option->($nodelist->{$node}, > $link); > -- > 2.20.1 > > > _______________________________________________ > pve-devel mailing list > pve-devel@pve.proxmox.com > https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel > > _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel