[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