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;
print "backup old database\n";
mkdir $backupdir;
-
+
my $ctime = time();
my $cmd = [
['echo', '.dump'],
push @bklist, [$fn, $1];
}
}
-
+
@bklist = sort { $b->[1] <=> $a->[1] } @bklist;
while (scalar (@bklist) >= $maxfiles) {
}
__PACKAGE__->register_method ({
- name => 'keygen',
+ name => 'keygen',
path => 'keygen',
method => 'PUT',
description => "Generate new cryptographic key for corosync.",
},
},
returns => { type => 'null' },
-
+
code => sub {
my ($param) = @_;
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.",
},
},
returns => { type => 'null' },
-
+
code => sub {
my ($param) = @_;
$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
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.",
},
},
returns => { type => 'null' },
-
+
code => sub {
my ($param) = @_;
}
} 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;
};
$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);
-
+
exit (0);
}});
__PACKAGE__->register_method ({
- name => 'delnode',
+ name => 'delnode',
path => 'delnode',
method => 'PUT',
description => "Removes a node to the cluster configuration.",
},
},
returns => { type => 'null' },
-
+
code => sub {
my ($param) = @_;
}});
__PACKAGE__->register_method ({
- name => 'add',
+ name => 'add',
path => 'add',
method => 'PUT',
description => "Adds the current node to an existing cluster.",
},
},
returns => { type => 'null' },
-
+
code => sub {
my ($param) = @_;
my $host = $param->{hostname};
if (!$param->{force}) {
-
+
if (-f $authfile) {
die "authentication key already exists\n";
}
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";
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);
}});
__PACKAGE__->register_method ({
- name => 'status',
+ name => 'status',
path => 'status',
method => 'GET',
description => "Displays the local view of the cluster status.",
properties => {},
},
returns => { type => 'null' },
-
+
code => sub {
my ($param) = @_;
}});
__PACKAGE__->register_method ({
- name => 'nodes',
+ name => 'nodes',
path => 'nodes',
method => 'GET',
description => "Displays the local view of the cluster nodes.",
properties => {},
},
returns => { type => 'null' },
-
+
code => sub {
my ($param) = @_;
}});
__PACKAGE__->register_method ({
- name => 'expected',
+ name => 'expected',
path => 'expected',
method => 'PUT',
description => "Tells corosync a new value of expected votes.",
},
},
returns => { type => 'null' },
-
+
code => sub {
my ($param) = @_;
my ($conf, $nodelist) = @_;
delete $conf->{digest};
-
+
my $version = PVE::Cluster::corosync_conf_version($conf);
PVE::Cluster::corosync_conf_version($conf, undef, $version + 1);
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') {
}
}
-
+
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";
}
}
}
}
- }
+ }
return $nodelist;
}
}
__PACKAGE__->register_method ({
- name => 'updatecerts',
+ name => 'updatecerts',
path => 'updatecerts',
method => 'PUT',
description => "Update node certificates (and generate all needed files/directories).",
};
eval {
- PVE::Tools::run_command($cmd, outfunc => $record_output,
+ PVE::Tools::run_command($cmd, outfunc => $record_output,
errfunc => $record_output);
};
my @required_dirs = (
"$basedir/priv",
- "$basedir/nodes",
+ "$basedir/nodes",
"$basedir/nodes/$nodename",
"$basedir/nodes/$nodename/lxc",
"$basedir/nodes/$nodename/qemu-server",
"$basedir/nodes/$nodename/openvz",
"$basedir/nodes/$nodename/priv");
-
+
foreach my $dir (@required_dirs) {
if (! -d $dir) {
mkdir($dir) || $! == EEXIST || die "unable to create directory '$dir' - $!\n";
my $rc = PVE::INotify::read_file('resolvconf');
$names .= ",IP:$ip";
-
+
my $fqdn = $nodename;
$names .= ",DNS:$nodename";
eval {
my $ver = $kvstore->{$node}->{tasklist} if $kvstore->{$node};
my $cd = $tasklistcache->{$node};
- if (!$cd || !$ver || !$cd->{version} ||
+ if (!$cd || !$ver || !$cd->{version} ||
($cd->{version} != $ver)) {
my $raw = &$ipcc_get_status("tasklist", $node) || '[]';
my $data = decode_json($raw);
my $err = RRDs::error;
die "RRD error: $err\n" if $err;
-
- die "got wrong time resolution ($step != $reso)\n"
+
+ die "got wrong time resolution ($step != $reso)\n"
if $step != $reso;
my $res = [];
# Using RRD graph is clumsy - maybe it
# is better to simply fetch the data, and do all display
# related things with javascript (new extjs html5 graph library).
-
+
my $rrddir = "/var/lib/rrdcached/db";
my $rrd = "$rrddir/$rrdname";
sub cfs_read_file {
my ($filename) = @_;
- my ($version, $info) = cfs_file_version($filename);
+ my ($version, $info) = cfs_file_version($filename);
my $parser = $info->{parser};
return &$ccache_read($filename, $parser, $version);
sub cfs_write_file {
my ($filename, $data) = @_;
- my ($version, $info) = cfs_file_version($filename);
+ my ($version, $info) = cfs_file_version($filename);
my $writer = $info->{writer} || die "no writer defined";
if ($err && ($err eq "got lock request timeout\n") &&
!check_cfs_quorum()){
$err = "$msg: no quorum!\n";
- }
+ }
if (!$err || $err !~ /^got lock timeout -/) {
rmdir $filename; # cfs unlock
sub check_vmid_unused {
my ($vmid, $noerr) = @_;
-
+
my $vmlist = get_vmlist();
my $d = $vmlist->{ids}->{$vmid};
return 1 if !defined($d);
-
+
return undef if $noerr;
my $vmtypestr = $d->{type} eq 'qemu' ? 'VM' : 'CT';
my ($start_sshd) = @_;
my $conf = PVE::Tools::file_get_contents($sshd_config_fn);
-
+
return if $conf =~ m/^PermitRootLogin\s+yes\s*$/m;
if ($conf !~ s/^#?PermitRootLogin.*$/PermitRootLogin yes/m) {
chomp $conf;
$conf .= "\nPermitRootLogin yes\n";
- }
+ }
PVE::Tools::file_set_contents($sshd_config_fn, $conf);
}
}
- warn "can't create shared ssh key database '$sshauthkeys'\n"
+ warn "can't create shared ssh key database '$sshauthkeys'\n"
if ! -f $sshauthkeys;
if (-f $rootsshauthkeys && ! -l $rootsshauthkeys) {
die "no node name specified" if !$nodename;
die "no ip address specified" if !$ip_address;
-
+
mkdir $authdir;
if (! -f $sshknownhosts) {
}
}
- my $old = PVE::Tools::file_get_contents($sshknownhosts, 128*1024);
-
+ my $old = PVE::Tools::file_get_contents($sshknownhosts, 128*1024);
+
my $new = '';
-
+
if ((! -l $sshglobalknownhosts) && (-f $sshglobalknownhosts)) {
$new = PVE::Tools::file_get_contents($sshglobalknownhosts, 128*1024);
}
unlink $sshglobalknownhosts;
symlink $sshknownhosts, $sshglobalknownhosts;
-
- warn "can't create symlink for ssh known hosts '$sshglobalknownhosts' -> '$sshknownhosts'\n"
+
+ warn "can't create symlink for ssh known hosts '$sshglobalknownhosts' -> '$sshknownhosts'\n"
if ! -l $sshglobalknownhosts;
}
return PVE::JSONSchema::dump_config($datacenter_schema, $filename, $cfg);
}
-cfs_register_file('datacenter.cfg',
- \&parse_datacenter_config,
+cfs_register_file('datacenter.cfg',
+ \&parse_datacenter_config,
\&write_datacenter_config);
# a very simply parser ...
$raw =~ s/\s+/ /g;
$raw =~ s/^\s+//;
$raw =~ s/\s*$//;
-
+
my @tokens = split(/\s/, $raw);
-
+
my $conf = { section => 'main', children => [] };
my $stack = [];
my $section = $conf;
-
+
while (defined(my $token = shift @tokens)) {
my $nexttok = $tokens[0];
my $key = $token;
die "missing ':' after key '$key'\n" if ! ($key =~ s/:$//);
-
+
die "parse error - no value for '$key'\n" if !defined($nexttok);
my $value = shift @tokens;
my ($section, $prefix) = @_;
my $raw = $prefix . $section->{section} . " {\n";
-
+
my @list = grep { defined($_->{key}) } @{$section->{children}};
foreach my $child (sort {$a->{key} cmp $b->{key}} @list) {
$raw .= $prefix . " $child->{key}: $child->{value}\n";
}
-
+
@list = grep { defined($_->{section}) } @{$section->{children}};
foreach my $child (sort {$a->{section} cmp $b->{section}} @list) {
$raw .= &$dump_corosync_section($child, "$prefix ");
}
$raw .= $prefix . "}\n\n";
-
+
return $raw;
-
+
};
sub write_corosync_conf {
my $raw = '';
my $prefix = '';
-
+
die "no main section" if $conf->{section} ne 'main';
my @list = grep { defined($_->{key}) } @{$conf->{children}};
}
}
}
-
+
return undef if $noerr;
die "invalid corosync config - unable to read version\n";
# read only - use "rename corosync.conf.new corosync.conf" to write
PVE::Cluster::cfs_register_file('corosync.conf', \&parse_corosync_conf);
# this is read/write
-PVE::Cluster::cfs_register_file('corosync.conf.new', \&parse_corosync_conf,
+PVE::Cluster::cfs_register_file('corosync.conf.new', \&parse_corosync_conf,
\&write_corosync_conf);
sub check_corosync_conf_exists {