[pve-devel] r5111 - in qemu-server/pve2: . PVE/API2
svn-commits at proxmox.com
svn-commits at proxmox.com
Fri Sep 10 14:01:44 CEST 2010
Author: dietmar
Date: 2010-09-10 12:01:44 +0000 (Fri, 10 Sep 2010)
New Revision: 5111
Modified:
qemu-server/pve2/ChangeLog
qemu-server/pve2/PVE/API2/QemuServer.pm
qemu-server/pve2/QemuServer.pm
qemu-server/pve2/nqm
qemu-server/pve2/qm
Log:
Modified: qemu-server/pve2/ChangeLog
===================================================================
--- qemu-server/pve2/ChangeLog 2010-09-10 11:44:39 UTC (rev 5110)
+++ qemu-server/pve2/ChangeLog 2010-09-10 12:01:44 UTC (rev 5111)
@@ -1,5 +1,7 @@
2010-09-10 Proxmox Support Team <support at proxmox.com>
+ * PVE/API2/QemuServer.pm: implement 'update_vm'
+
* QemuServer.pm: use a JSON Schema to describe all options. We can
now auto-generate the complete API doc.
Modified: qemu-server/pve2/PVE/API2/QemuServer.pm
===================================================================
--- qemu-server/pve2/PVE/API2/QemuServer.pm 2010-09-10 11:44:39 UTC (rev 5110)
+++ qemu-server/pve2/PVE/API2/QemuServer.pm 2010-09-10 12:01:44 UTC (rev 5111)
@@ -3,6 +3,8 @@
use strict;
use warnings;
+use PVE::SafeSyslog;
+use PVE::Exception qw(raise raise_param_exc);
use PVE::INotify qw(read_file);
use PVE::RESTHandler;
use PVE::QemuServer;
@@ -98,7 +100,15 @@
description => "Create new virtual machine.",
parameters => {
additionalProperties => 0,
- properties => PVE::QemuServer::json_config_properties(),
+ properties => PVE::QemuServer::json_config_properties(
+ {
+ node => { type => 'string', format => 'pve-node' },
+ vmid => {
+ description => "The (unique) ID of the VM.",
+ type => 'integer', format => 'pve-vmid',
+ minimum => 1,
+ },
+ }),
},
returns => { type => 'null'},
code => sub {
@@ -107,18 +117,155 @@
my $node = $param->{node};
delete $param->{node};
+ # fixme: proxy to correct node
+ # fixme: fork worker?
+
my $vmid = $param->{vmid};
delete $param->{vmid};
- print "create $vmid on node $node\n";
+ my $filename = PVE::QemuServer::config_file ($vmid);
+ # first test (befor locking)
+ die "unable to create vm $vmid: config file already exists\n"
+ if -f $filename;
+
my $storecfg = read_file('storagecfg');
my $opts = PVE::QemuServer::parse_options_new($storecfg, $param->{vmid}, $param, 1);
+ PVE::QemuServer::add_random_macs ($opts);
+
+ #fixme: ? syslog ('info', "VM $vmid creating new virtual machine");
+
+ my $vollist = [];
+
+ my $createfn = sub {
+
+ # second test (after locking test is accurate)
+ die "unable to create vm $vmid: config file already exists\n"
+ if -f $filename;
+
+ $vollist = PVE::QemuServer::create_disks ($storecfg, $vmid, $opts);
+
+ # try to be smart about bootdisk
+ my @disks = PVE::QemuServer::disknames();
+ my $firstdisk;
+ foreach my $ds (reverse @disks) {
+ next if !$opts->{$ds};
+ my $disk = PVE::QemuServer::parse_drive ($ds, $opts->{$ds});
+ next if PVE::QemuServer::drive_is_cdrom ($disk);
+ $firstdisk = $ds;
+ }
+
+ if (!$opts->{bootdisk} && $firstdisk) {
+ $opts->{bootdisk} = $firstdisk;
+ }
+
+ PVE::QemuServer::create_conf_nolock($vmid, $opts);
+ };
+
+ eval { PVE::QemuServer::lock_config ($vmid, $createfn); };
+ my $err = $@;
+
+ if ($err) {
+ # fixme ? syslog ('err', "VM $vmid create failed - $err");
+ foreach my $volid (@$vollist) {
+ eval { PVE::Storage::vdisk_free ($storecfg, $volid); };
+ warn $@ if $@;
+ }
+ die "create failed - $err";
+ }
+
+ return undef;
+ }});
+
+__PACKAGE__->register_method ({
+ name => 'update_vm',
+ path => '{node}/{vmid}',
+ method => 'PUT',
+ description => "Set virtual machine options.",
+ parameters => {
+ additionalProperties => 0,
+ properties => PVE::QemuServer::json_config_properties(
+ {
+ node => { type => 'string', format => 'pve-node' },
+ vmid => {
+ description => "The (unique) ID of the VM.",
+ type => 'integer', format => 'pve-vmid',
+ minimum => 1,
+ },
+ skiplock => {
+ description => "Ignore locks - only root is allowed to use this option.",
+ type => 'boolean',
+ optional => 1,
+ },
+ delete => {
+ type => 'string', format => 'pve-configid-list',
+ description => "A list of settings you want to delete.",
+ optional => 1,
+ },
+ }),
+ },
+ returns => { type => 'null'},
+ code => sub {
+ my ($param) = @_;
+
+ my $node = $param->{node};
+ delete $param->{node};
+
+ # fixme: proxy to correct node
+ # fixme: fork worker?
+
+ my $vmid = $param->{vmid};
+ delete $param->{vmid};
+
+ my $skiplock = $param->{skiplock};
+ delete $param->{skiplock};
+
+ my $delete = $param->{delete};
+ delete $param->{delete};
+
+ die "no options specified\n" if !$delete && !scalar(keys %$param);
+
+ my $storecfg = read_file('storagecfg');
+
+ my $opts = PVE::QemuServer::parse_options_new($storecfg, $param->{vmid}, $param, 1);
+
print Dumper($opts);
+ my $updatefn = sub {
+
+ my $conf = PVE::QemuServer::load_config ($vmid);
+
+ PVE::QemuServer::check_lock($conf) if !$skiplock;
+
+ my $unset = {};
+
+ foreach my $opt (PVE::Tools::split_list($delete)) {
+ if (!PVE::QemuServer::option_exists($opt)) {
+ raise_param_exc({ delete => "unknown option '$opt'" });
+ }
+ next if !defined ($conf->{$opt});
+ if (PVE::QemuServer::valid_drivename($opt)) {
+ my $disk = $conf->{diskinfo}->{$opt};
+ if ($disk && !PVE::QemuServer::drive_is_cdrom ($disk)) {
+ PVE::QemuServer::unlink_image($storecfg, $vmid, $disk->{file});
+ }
+ }
+ $unset->{$opt} = 1;
+ }
+
+ PVE::QemuServer::add_random_macs ($opts);
+
+ PVE::QemuServer::create_disks ($storecfg, $vmid, $opts);
+
+ PVE::QemuServer::change_config_nolock ($vmid, $opts, $unset, 1);
+ };
+
+ PVE::QemuServer::lock_config ($vmid, $updatefn);
+
return undef;
}});
+
1;
Modified: qemu-server/pve2/QemuServer.pm
===================================================================
--- qemu-server/pve2/QemuServer.pm 2010-09-10 11:44:39 UTC (rev 5110)
+++ qemu-server/pve2/QemuServer.pm 2010-09-10 12:01:44 UTC (rev 5111)
@@ -504,6 +504,11 @@
return defined ($drivename_hash->{$dev});
}
+sub option_exists {
+ my $key = shift;
+ return defined($confdesc->{$key});
+}
+
sub nic_models {
return $nic_model_list;
}
@@ -749,6 +754,7 @@
}
}
+ # fixme: howto implement this?
if (!$create && ($value eq '' || $value eq 'undef')) {
$settings->{$opt} = $value;
return;
@@ -781,7 +787,7 @@
}
sub create_conf_nolock {
- my ($self, $vmid, $settings) = @_;
+ my ($vmid, $settings) = @_;
my $filename = config_file ($vmid);
@@ -794,19 +800,17 @@
$settings->{memory} = $defaults->{memory} || $default_memory;
}
- my $fh = new IO::File ($filename, "w") ||
- die "unable to create config for VM $vmid - $!\n";
-
+ my $data = '';
foreach my $opt (keys %$settings) {
next if !$confdesc->{$opt};
my $value = $settings->{$opt};
next if !$value;
- print $fh "$opt: $value\n";
+ $data .= "$opt: $value\n";
}
- $fh->close();
+ PVE::Tools::file_set_contents($filename, $data);
}
# ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
@@ -924,8 +928,8 @@
return $drive && $drive->{media} && ($drive->{media} eq 'cdrom');
}
+
# vlanX: e1000=XX:XX:XX:XX:XX:XX,pcnet=XX:XX:XX:XX:XX:XX,...
-
sub parse_vlan {
my ($data) = @_;
@@ -946,7 +950,6 @@
return undef if !$res->{nics};
return $res;
-
}
sub print_vlan {
@@ -962,13 +965,25 @@
return $res;
}
+sub add_random_macs {
+ my ($settings) = @_;
+
+ foreach my $opt (keys %$settings) {
+ next if $opt !~ m/^vlan(\d+|u)$/;
+ my $vlan = parse_vlan ($settings->{$opt});
+ next if !$vlan;
+ $settings->{$opt} = print_vlan ($vlan);
+ }
+}
+
+# fixme: remove all thos $noerr parameters?
+
PVE::JSONSchema::register_format('pve-qm-bootdisk', \&verify_bootdisk);
sub verify_bootdisk {
my ($value, $noerr) = @_;
- foreach my $ds (disknames()) {
- return $value if $value eq $ds;
- }
+ return $value if valid_drivename($value);
+
return undef if $noerr;
die "invalid boot disk '$value'\n";
@@ -1052,27 +1067,14 @@
return $value;
}
-# JSON properties for create and set function
-my $json_config_properties_cache;
+# add JSON properties for create and set function
sub json_config_properties {
-
- return $json_config_properties_cache if $json_config_properties_cache;
+ my $prop = shift;
- my $prop = {
- node => { type => 'string', format => 'pve-node' },
- vmid => {
- description => "The (unique) ID of the VM.",
- type => 'integer', format => 'pve-vmid',
- minimum => 1,
- },
- };
-
foreach my $opt (keys %$confdesc) {
$prop->{$opt} = $confdesc->{$opt};
}
- $json_config_properties_cache = $prop;
-
return $prop;
}
@@ -1144,20 +1146,77 @@
utime undef, undef, $conf;
}
+sub create_disks {
+ my ($storecfg, $vmid, $settings) = @_;
+
+ my $vollist = [];
+
+ eval {
+ foreach my $ds (keys %$settings) {
+ next if !valid_drivename($ds); # only drives
+
+ my $disk = parse_drive ($ds, $settings->{$ds});
+
+ next if drive_is_cdrom ($disk);
+
+ my $file = $disk->{file};
+
+ if ($file =~ m/^(([^:\s]+):)?(\d+(\.\d+)?)$/) {
+ my $storeid = $2 || 'local';
+ my $size = $3;
+ my $defformat = PVE::Storage::storage_default_format ($storecfg, $storeid);
+ my $fmt = $disk->{format} || $defformat;
+ syslog ('info', "VM $vmid creating new disk - size is $size GB");
+
+ my $volid = PVE::Storage::vdisk_alloc ($storecfg, $storeid, $vmid,
+ $fmt, undef, $size*1024*1024);
+
+ $disk->{file} = $volid;
+ delete ($disk->{format}); # no longer needed
+ push @$vollist, $volid;
+ $settings->{$ds} = PVE::QemuServer::print_drive ($vmid, $disk);
+ } else {
+ my $path;
+ if ($disk->{file} =~ m|^/dev/.+|) {
+ $path = $disk->{file};
+ } else {
+ $path = PVE::Storage::path ($storecfg, $disk->{file});
+ }
+ if (!(-f $path || -b $path)) {
+ die "image '$path' does not exists\n";
+ }
+ }
+ }
+ };
+
+ my $err = $@;
+
+ if ($err) {
+ syslog ('err', "VM $vmid creating disks failed");
+ foreach my $volid (@$vollist) {
+ eval { PVE::Storage::vdisk_free ($storecfg, $volid); };
+ warn $@ if $@;
+ }
+ die $err;
+ }
+
+ return $vollist;
+}
+
sub unlink_image {
- my ($self, $vmid, $volid) = @_;
+ my ($storecfg, $vmid, $volid) = @_;
die "reject to unlink absolute path '$volid'"
if $volid =~ m|^/|;
- my ($path, $owner) = PVE::Storage::path ($self->{storecfg}, $volid);
+ my ($path, $owner) = PVE::Storage::path ($storecfg, $volid);
die "reject to unlink '$volid' - not owned by this VM"
if !$owner || ($owner != $vmid);
syslog ('info', "VM $vmid deleting volume '$volid'");
- PVE::Storage::vdisk_free ($self->{storecfg}, $volid);
+ PVE::Storage::vdisk_free ($storecfg, $volid);
touch_config ($vmid);
}
@@ -1167,7 +1226,7 @@
my $conffile = config_file ($vmid);
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf);
@@ -1252,7 +1311,7 @@
}
sub load_config {
- my ($self, $vmid) = @_;
+ my ($vmid) = @_;
my $filename = config_file ($vmid);
@@ -1985,7 +2044,7 @@
my ($self, $vmid, $statefile, $skiplock) = @_;
lock_config ($vmid, sub {
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf) if !$skiplock;
@@ -2187,7 +2246,7 @@
sub vm_commandline {
my ($self, $vmid) = @_;
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
my $defaults = load_defaults();
@@ -2201,7 +2260,7 @@
lock_config ($vmid, sub {
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf) if !$skiplock;
@@ -2235,7 +2294,7 @@
lock_config ($vmid, sub {
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf) if !$skiplock;
@@ -2257,7 +2316,7 @@
return;
}
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf) if !$skiplock;
@@ -2309,7 +2368,7 @@
lock_config ($vmid, sub {
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf) if !$skiplock;
@@ -2324,7 +2383,7 @@
lock_config ($vmid, sub {
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf) if !$skiplock;
@@ -2339,7 +2398,7 @@
lock_config ($vmid, sub {
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf) if !$skiplock;
@@ -2354,7 +2413,7 @@
lock_config ($vmid, sub {
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf);
@@ -2370,7 +2429,7 @@
return if !check_running ($vmid); # do nothing
- $conf = $self->load_config ($vmid);# reload
+ $conf = load_config ($vmid);# reload
my $qdn;
eval {
@@ -2408,7 +2467,7 @@
lock_config ($vmid, sub {
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
check_lock ($conf) if !$skiplock;
@@ -2441,7 +2500,7 @@
next if $vzlist->{$vmid}->{pid}; # already running
eval {
- my $conf = $self->load_config ($vmid);
+ my $conf = load_config ($vmid);
if ($conf->{onboot}) {
print STDERR "Starting Qemu VM $vmid\n";
$self->vm_start ($vmid);
Modified: qemu-server/pve2/nqm
===================================================================
--- qemu-server/pve2/nqm 2010-09-10 11:44:39 UTC (rev 5110)
+++ qemu-server/pve2/nqm 2010-09-10 12:01:44 UTC (rev 5111)
@@ -47,6 +47,8 @@
} ],
create => [ "PVE::API2::QemuServer", 'create_vm', ['vmid'], { node => $hostname } ],
+
+ set => [ "PVE::API2::QemuServer", 'update_vm', ['vmid'], { node => $hostname } ],
};
Modified: qemu-server/pve2/qm
===================================================================
--- qemu-server/pve2/qm 2010-09-10 11:44:39 UTC (rev 5110)
+++ qemu-server/pve2/qm 2010-09-10 12:01:44 UTC (rev 5111)
@@ -298,7 +298,7 @@
PVE::QemuServer::lock_config ($vmid, sub {
- my $conf = $qm->load_config ($vmid);
+ my $conf = PVE::QemuServer::load_config ($vmid);
PVE::QemuServer::check_lock ($conf) if !$skiplock;
@@ -312,7 +312,7 @@
my $disk = $conf->{diskinfo}->{$opt};
next if !$disk;
if (!PVE::QemuServer::drive_is_cdrom ($disk)) {
- $qm->unlink_image ($vmid, $disk->{file});
+ PVE::QemuServer::unlink_image ($qm->{storecfg}, $vmid, $disk->{file});
}
last;
}
@@ -385,7 +385,7 @@
$settings->{bootdisk} = $firstdisk;
}
- $qm->create_conf_nolock ($vmid, $settings);
+ PVE::QemuServer::create_conf_nolock ($vmid, $settings);
});
my $err = $@;
@@ -410,7 +410,7 @@
PVE::QemuServer::lock_config ($vmid, sub {
- my $conf = $qm->load_config ($vmid);
+ my $conf = PVE::QemuServer::load_config ($vmid);
PVE::QemuServer::check_lock ($conf) if !$skiplock;
@@ -426,7 +426,7 @@
}
die "disk image '$file' is used - unable to unlink\n" if $found;
- $qm->unlink_image ($vmid, $file);
+ PVE::QemuServer::unlink_image ($qm->{storecfg}, $vmid, $file);
}
});
@@ -674,7 +674,7 @@
qw(VMID NAME STATUS MEM(MB) BOOTDISK(GB) PID);
foreach my $vmid (sort keys %$vzlist) {
- my $conf = $qm->load_config ($vmid);
+ my $conf = PVE::QemuServer::load_config ($vmid);
my $name = $conf->{name} || '-';
my $status = $vzlist->{$vmid}->{pid} ? 'running' : 'stopped';
More information about the pve-devel
mailing list