]> git.proxmox.com Git - pve-cluster.git/blobdiff - data/PVE/CLI/pvecm.pm
move corosync config helpers to PVE::Cluster
[pve-cluster.git] / data / PVE / CLI / pvecm.pm
index b26a1eca29298581f5a81fa0599e87ce9c3d3997..a704201407646c3d68fd4f7391e8b22bbf753557 100755 (executable)
@@ -8,7 +8,7 @@ use IO::File;
 use Net::IP;
 use File::Path;
 use File::Basename;
-use Data::Dumper; # fixme: remove 
+use Data::Dumper; # fixme: remove
 use PVE::Tools;
 use PVE::Cluster;
 use PVE::INotify;
@@ -31,15 +31,15 @@ sub backup_database {
     print "backup old database\n";
 
     mkdir $backupdir;
-    
+
     my $ctime = time();
     my $cmd = [
        ['echo', '.dump'],
        ['sqlite3', $dbfile],
-       ['gzip', '-', \">${backupdir}/config-${ctime}.sql.gz"],
+       ['gzip', '-', \ ">${backupdir}/config-${ctime}.sql.gz"],
     ];
 
-    PVE::Tools::run_command($cmd, 'errmsg' => "can't backup old database\n");
+    PVE::Tools::run_command($cmd, 'errmsg' => "cannot backup old database\n");
 
     # purge older backup
     my $maxfiles = 10;
@@ -50,7 +50,7 @@ sub backup_database {
            push @bklist, [$fn, $1];
        }
     }
-       
+
     @bklist = sort { $b->[1] <=> $a->[1] } @bklist;
 
     while (scalar (@bklist) >= $maxfiles) {
@@ -61,7 +61,7 @@ sub backup_database {
 }
 
 __PACKAGE__->register_method ({
-    name => 'keygen', 
+    name => 'keygen',
     path => 'keygen',
     method => 'PUT',
     description => "Generate new cryptographic key for corosync.",
@@ -75,7 +75,7 @@ __PACKAGE__->register_method ({
        },
     },
     returns => { type => 'null' },
-    
+
     code => sub {
        my ($param) = @_;
 
@@ -91,13 +91,13 @@ __PACKAGE__->register_method ({
        File::Path::make_path($dirname) if $dirname;
 
        my $cmd = ['corosync-keygen', '-l', '-k', $filename];
-       PVE::Tools::run_command($cmd);   
+       PVE::Tools::run_command($cmd);
 
        return undef;
     }});
 
 __PACKAGE__->register_method ({
-    name => 'create', 
+    name => 'create',
     path => 'create',
     method => 'PUT',
     description => "Generate new cluster configuration.",
@@ -157,13 +157,13 @@ __PACKAGE__->register_method ({
        },
     },
     returns => { type => 'null' },
-    
+
     code => sub {
        my ($param) = @_;
 
        -f $clusterconf && die "cluster config '$clusterconf' already exists\n";
 
-       PVE::Cluster::setup_sshd_config();
+       PVE::Cluster::setup_sshd_config(1);
        PVE::Cluster::setup_rootsshconfig();
        PVE::Cluster::setup_ssh_keys();
 
@@ -178,7 +178,7 @@ __PACKAGE__->register_method ({
        $param->{votes} = 1 if !defined($param->{votes});
 
        my $nodename = PVE::INotify::nodename();
-       
+
        my $local_ip_address = PVE::Cluster::remote_node_ip($nodename);
 
        $param->{bindnet0_addr} = $local_ip_address
@@ -266,12 +266,12 @@ _EOD
        PVE::Tools::run_command('systemctl restart pve-cluster'); # restart
 
        PVE::Tools::run_command('systemctl restart corosync'); # restart
-       
+
        return undef;
 }});
 
 __PACKAGE__->register_method ({
-    name => 'addnode', 
+    name => 'addnode',
     path => 'addnode',
     method => 'PUT',
     description => "Adds a node to the cluster configuration.",
@@ -311,7 +311,7 @@ __PACKAGE__->register_method ({
        },
     },
     returns => { type => 'null' },
-    
+
     code => sub {
        my ($param) = @_;
 
@@ -319,9 +319,9 @@ __PACKAGE__->register_method ({
 
        my $conf = PVE::Cluster::cfs_read_file("corosync.conf");
 
-       my $nodelist = corosync_nodelist($conf);
+       my $nodelist = PVE::Cluster::corosync_nodelist($conf);
 
-       my $totem_cfg = corosync_totem_config($conf);
+       my $totem_cfg = PVE::Cluster::corosync_totem_config($conf);
 
        my $name = $param->{node};
 
@@ -347,9 +347,9 @@ __PACKAGE__->register_method ({
            }
        } elsif (!$param->{nodeid}) {
            my $nodeid = 1;
-           
+
            while(1) {
-               my $found = 0; 
+               my $found = 0;
                foreach my $v (values %$nodelist) {
                    if ($v->{nodeid} eq $nodeid) {
                        $found = 1;
@@ -377,15 +377,15 @@ __PACKAGE__->register_method ({
        };
        $nodelist->{$name}->{ring1_addr} = $param->{ring1_addr} if $param->{ring1_addr};
        $nodelist->{$name}->{quorum_votes} = $param->{votes} if $param->{votes};
-       
-       corosync_update_nodelist($conf, $nodelist);
-       
+
+       PVE::Cluster::corosync_update_nodelist($conf, $nodelist);
+
        exit (0);
     }});
 
 
 __PACKAGE__->register_method ({
-    name => 'delnode', 
+    name => 'delnode',
     path => 'delnode',
     method => 'PUT',
     description => "Removes a node to the cluster configuration.",
@@ -399,7 +399,7 @@ __PACKAGE__->register_method ({
        },
     },
     returns => { type => 'null' },
-    
+
     code => sub {
        my ($param) = @_;
 
@@ -407,7 +407,7 @@ __PACKAGE__->register_method ({
 
        my $conf = PVE::Cluster::cfs_read_file("corosync.conf");
 
-       my $nodelist = corosync_nodelist($conf);
+       my $nodelist = PVE::Cluster::corosync_nodelist($conf);
 
        my $node;
        my $nodeid;
@@ -430,7 +430,7 @@ __PACKAGE__->register_method ({
 
        delete $nodelist->{$node};
 
-       corosync_update_nodelist($conf, $nodelist);
+       PVE::Cluster::corosync_update_nodelist($conf, $nodelist);
 
        PVE::Tools::run_command(['corosync-cfgtool','-k', $nodeid])
            if defined($nodeid);
@@ -439,7 +439,7 @@ __PACKAGE__->register_method ({
     }});
 
 __PACKAGE__->register_method ({
-    name => 'add', 
+    name => 'add',
     path => 'add',
     method => 'PUT',
     description => "Adds the current node to an existing cluster.",
@@ -482,20 +482,20 @@ __PACKAGE__->register_method ({
        },
     },
     returns => { type => 'null' },
-    
+
     code => sub {
        my ($param) = @_;
 
        my $nodename = PVE::INotify::nodename();
 
-       PVE::Cluster::setup_sshd_config();
+       PVE::Cluster::setup_sshd_config(1);
        PVE::Cluster::setup_rootsshconfig();
        PVE::Cluster::setup_ssh_keys();
 
        my $host = $param->{hostname};
 
        if (!$param->{force}) {
-           
+
            if (-f $authfile) {
                die "authentication key already exists\n";
            }
@@ -542,7 +542,7 @@ __PACKAGE__->register_method ({
 
        eval {
            print "copy corosync auth key\n";
-           $cmd = ['rsync', '--rsh=ssh -l root -o BatchMode=yes', '-lpgoq', 
+           $cmd = ['rsync', '--rsh=ssh -l root -o BatchMode=yes', '-lpgoq',
                    "[$host]:$authfile $clusterconf", $tmpdir];
 
            system(@$cmd) == 0 || die "can't rsync data from host '$host'\n";
@@ -589,7 +589,7 @@ __PACKAGE__->register_method ({
            my $local_ip_address = PVE::Cluster::remote_node_ip($nodename);
 
            print "generating node certificates\n";
-           PVE::Cluster::gen_pve_node_files($nodename, $local_ip_address); 
+           PVE::Cluster::gen_pve_node_files($nodename, $local_ip_address);
 
            print "merge known_hosts file\n";
            PVE::Cluster::ssh_merge_known_hosts($nodename, $local_ip_address, 1);
@@ -612,7 +612,7 @@ __PACKAGE__->register_method ({
     }});
 
 __PACKAGE__->register_method ({
-    name => 'status', 
+    name => 'status',
     path => 'status',
     method => 'GET',
     description => "Displays the local view of the cluster status.",
@@ -621,7 +621,7 @@ __PACKAGE__->register_method ({
        properties => {},
     },
     returns => { type => 'null' },
-    
+
     code => sub {
        my ($param) = @_;
 
@@ -635,7 +635,7 @@ __PACKAGE__->register_method ({
     }});
 
 __PACKAGE__->register_method ({
-    name => 'nodes', 
+    name => 'nodes',
     path => 'nodes',
     method => 'GET',
     description => "Displays the local view of the cluster nodes.",
@@ -644,7 +644,7 @@ __PACKAGE__->register_method ({
        properties => {},
     },
     returns => { type => 'null' },
-    
+
     code => sub {
        my ($param) = @_;
 
@@ -658,7 +658,7 @@ __PACKAGE__->register_method ({
     }});
 
 __PACKAGE__->register_method ({
-    name => 'expected', 
+    name => 'expected',
     path => 'expected',
     method => 'PUT',
     description => "Tells corosync a new value of expected votes.",
@@ -673,7 +673,7 @@ __PACKAGE__->register_method ({
        },
     },
     returns => { type => 'null' },
-    
+
     code => sub {
        my ($param) = @_;
 
@@ -687,108 +687,8 @@ __PACKAGE__->register_method ({
 
     }});
 
-sub corosync_update_nodelist {
-    my ($conf, $nodelist) = @_;
-
-    delete $conf->{digest};
-    
-    my $version = PVE::Cluster::corosync_conf_version($conf);
-    PVE::Cluster::corosync_conf_version($conf, undef, $version + 1);
-
-    my $children = [];
-    foreach my $v (values %$nodelist) {
-       next if !($v->{ring0_addr} || $v->{name});
-       my $kv = [];
-       foreach my $k (keys %$v) {
-           push @$kv, { key => $k, value => $v->{$k} };
-       } 
-       my $ns = { section => 'node', children => $kv };
-       push @$children, $ns;
-    }
-    
-    foreach my $main (@{$conf->{children}}) {
-       next if !defined($main->{section});
-       if ($main->{section} eq 'nodelist') {
-           $main->{children} = $children;
-           last;
-       }
-    }
-
-    
-    PVE::Cluster::cfs_write_file("corosync.conf.new", $conf);
-    
-    rename("/etc/pve/corosync.conf.new", "/etc/pve/corosync.conf")
-       || die "activate  corosync.conf.new failed - $!\n";
-}
-
-sub corosync_nodelist {
-    my ($conf) = @_;
-
-    my $nodelist = {};
-
-    foreach my $main (@{$conf->{children}}) {
-       next if !defined($main->{section});
-       if ($main->{section} eq 'nodelist') {
-           foreach my $ne (@{$main->{children}}) {
-               next if !defined($ne->{section}) || ($ne->{section} ne 'node');
-               my $node = { quorum_votes => 1 };
-               my $name;
-               foreach my $child (@{$ne->{children}}) {
-                   next if !defined($child->{key});
-                   $node->{$child->{key}} = $child->{value};
-                   # use 'name' over 'ring0_addr' if set
-                   if ($child->{key} eq 'name') {
-                       delete $nodelist->{$name} if $name;
-                       $name = $child->{value};
-                       $nodelist->{$name} = $node;
-                   } elsif(!$name && $child->{key} eq 'ring0_addr') {
-                       $name = $child->{value};
-                       $nodelist->{$name} = $node;
-                   }
-               }
-           }
-       }
-    }   
-
-    return $nodelist;
-}
-
-# get a hash representation of the corosync config totem section
-sub corosync_totem_config {
-    my ($conf) = @_;
-
-    my $res = {};
-
-    foreach my $main (@{$conf->{children}}) {
-       next if !defined($main->{section}) ||
-           $main->{section} ne 'totem';
-
-       foreach my $e (@{$main->{children}}) {
-
-           if ($e->{section} && $e->{section} eq 'interface') {
-               my $entry = {};
-
-               $res->{interface} = {};
-
-               foreach my $child (@{$e->{children}}) {
-                   next if !defined($child->{key});
-                   $entry->{$child->{key}} = $child->{value};
-                   if($child->{key} eq 'ringnumber') {
-                       $res->{interface}->{$child->{value}} = $entry;
-                   }
-               }
-
-           } elsif  ($e->{key}) {
-               $res->{$e->{key}} = $e->{value};
-           }
-       }
-    }
-
-    return $res;
-}
-
 __PACKAGE__->register_method ({
-    name => 'updatecerts', 
+    name => 'updatecerts',
     path => 'updatecerts',
     method => 'PUT',
     description => "Update node certificates (and generate all needed files/directories).",
@@ -811,6 +711,7 @@ __PACKAGE__->register_method ({
     code => sub {
        my ($param) = @_;
 
+       PVE::Cluster::setup_sshd_config(0);
        PVE::Cluster::setup_rootsshconfig();
 
        PVE::Cluster::gen_pve_vzdump_symlink();
@@ -834,6 +735,59 @@ __PACKAGE__->register_method ({
        return undef;
     }});
 
+__PACKAGE__->register_method ({
+    name => 'mtunnel',
+    path => 'mtunnel',
+    method => 'POST',
+    description => "Used by VM/CT migration - do not use manually.",
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           get_migration_ip => {
+               type => 'boolean',
+               default => 0,
+               description => 'return the migration IP, if configured',
+               optional => 1,
+           },
+           migration_network => {
+               type => 'string',
+               format => 'CIDR',
+               description => 'the migration network used to detect the local migration IP',
+               optional => 1,
+           },
+       },
+    },
+    returns => { type => 'null'},
+    code => sub {
+       my ($param) = @_;
+
+       if (!PVE::Cluster::check_cfs_quorum(1)) {
+           print "no quorum\n";
+           return undef;
+       }
+
+       if ($param->{get_migration_ip}) {
+           my $network = $param->{migration_network};
+           if (my $ip = PVE::Cluster::get_local_migration_ip($network)) {
+               print "ip: '$ip'\n";
+           } else {
+               print "no ip\n";
+           }
+           # do not keep tunnel open when asked for migration ip
+           return undef;
+       }
+
+       print "tunnel online\n";
+       *STDOUT->flush();
+
+       while (my $line = <>) {
+           chomp $line;
+           last if $line =~ m/^quit$/;
+       }
+
+       return undef;
+    }});
+
 
 our $cmddef = {
     keygen => [ __PACKAGE__, 'keygen', ['filename']],
@@ -845,6 +799,7 @@ our $cmddef = {
     nodes => [ __PACKAGE__, 'nodes' ],
     expected => [ __PACKAGE__, 'expected', ['expected']],
     updatecerts => [ __PACKAGE__, 'updatecerts', []],
+    mtunnel => [ __PACKAGE__, 'mtunnel', []],
 };
 
 1;