]> git.proxmox.com Git - pve-container.git/commitdiff
implement template creation
authorDietmar Maurer <dietmar@proxmox.com>
Thu, 13 Aug 2015 10:31:33 +0000 (12:31 +0200)
committerDietmar Maurer <dietmar@proxmox.com>
Thu, 13 Aug 2015 10:31:33 +0000 (12:31 +0200)
src/PVE/API2/LXC.pm
src/PVE/LXC.pm
src/PVE/LXCCreate.pm
src/pct

index 7a65402003d856735df0cb5f4d97570f8d05924b..fc7580e3f8f1db64940fd166b5b0e53879399d6e 100644 (file)
@@ -322,7 +322,7 @@ __PACKAGE__->register_method({
                PVE::LXCCreate::create_rootfs($storage_cfg, $storage, $volid, $vmid, $conf,
                                              $archive, $password, $restore);
 
-               $conf->{rootfs} = "$volid,size=$disksize";
+               $conf->{rootfs} = print_ct_mountpount({volume => $volid, size => $disksize });
 
                # set some defaults
                $conf->{hostname} ||= "CT$vmid";
@@ -995,6 +995,10 @@ __PACKAGE__->register_method({
                syslog('info', "starting CT $vmid: $upid\n");
 
                my $conf = PVE::LXC::load_config($vmid);
+
+               die "you can't start a CT if it's a template\n"
+                   if PVE::LXC::is_template($conf);
+
                my $storage_cfg = cfs_read_file("storage.cfg");
 
                my $rootinfo = PVE::LXC::parse_ct_mountpoint($conf->{rootfs});
@@ -1761,4 +1765,67 @@ __PACKAGE__->register_method({
            #nodes => [ keys %$nodelist ],
        };
     }});
+
+__PACKAGE__->register_method({
+    name => 'template',
+    path => '{vmid}/template',
+    method => 'POST',
+    protected => 1,
+    proxyto => 'node',
+    description => "Create a Template.",
+    permissions => {
+       description => "You need 'VM.Allocate' permissions on /vms/{vmid}",
+       check => [ 'perm', '/vms/{vmid}', ['VM.Allocate']],
+    },
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           node => get_standard_option('pve-node'),
+           vmid => get_standard_option('pve-vmid'),
+       },
+    },
+    returns => { type => 'null'},
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $authuser = $rpcenv->get_user();
+
+       my $node = extract_param($param, 'node');
+
+       my $vmid = extract_param($param, 'vmid');
+
+       my $updatefn =  sub {
+
+           my $conf = PVE::LXC::load_config($vmid);
+           PVE::LXC::check_lock($conf);
+
+           die "unable to create template, because CT contains snapshots\n"
+               if $conf->{snapshots} && scalar(keys %{$conf->{snapshots}});
+
+           die "you can't convert a template to a template\n"
+               if PVE::LXC::is_template($conf);
+
+           die "you can't convert a CT to template if the CT is running\n"
+               if PVE::LXC::check_running($vmid);
+
+           my $realcmd = sub {
+               PVE::LXC::template_create($vmid, $conf);
+           };
+
+           $conf->{template} = 1;
+
+           PVE::LXC::write_config($vmid, $conf);
+           # and remove lxc config
+           PVE::LXC::update_lxc_config(undef, $vmid, $conf);
+
+           return $rpcenv->fork_worker('vztemplate', $vmid, $authuser, $realcmd);
+       };
+
+       PVE::LXC::lock_container($vmid, undef, $updatefn);
+
+       return undef;
+    }});
+
 1;
index a1a5197a03013e23b6773f1f6502d2e8bb416f49..552fc8019c6d73ba3bd239a5b1e60ea86709de24 100644 (file)
@@ -64,6 +64,12 @@ my $confdesc = {
        default => 0,
     },
     startup => get_standard_option('pve-startup-order'),
+    template => {
+       optional => 1,
+       type => 'boolean',
+       description => "Enable/disable Template.",
+       default => 0,
+    },
     arch => {
        optional => 1,
        type => 'string',
@@ -667,6 +673,8 @@ sub vmstatus {
 
        $d->{diskread} = 0;
        $d->{diskwrite} = 0;
+
+       $d->{template} = is_template($conf);
     }
 
     foreach my $vmid (keys %$list) {
@@ -742,6 +750,20 @@ sub parse_ct_mountpoint {
     return $res;
 }
 
+sub print_ct_mountpount {
+    my ($info) = @_;
+
+    my $opts = '';
+
+    die "missing volume\n" if !$info->{volume};
+
+    foreach my $o ('size', 'backup') {
+       $opts .= ",$o=info->{$o}" if defined($info->{$o});
+    }
+
+    return "$info->{volume}$opts";
+}
+
 sub print_lxc_network {
     my $net = shift;
 
@@ -896,6 +918,15 @@ sub check_lock {
 sub update_lxc_config {
     my ($storage_cfg, $vmid, $conf) = @_;
 
+    my $dir = "/var/lib/lxc/$vmid";
+
+    if ($conf->{template}) {
+
+       unlink "$dir/config";
+
+       return;
+    }
+
     my $raw = '';
 
     die "missing 'arch' - internal error" if !$conf->{arch};
@@ -973,7 +1004,6 @@ sub update_lxc_config {
 
     $raw .= "lxc.network.type = empty\n" if !$netcount;
     
-    my $dir = "/var/lib/lxc/$vmid";
     File::Path::mkpath("$dir/rootfs");
 
     PVE::Tools::file_set_contents("$dir/config", $raw);
@@ -1401,6 +1431,9 @@ my $snapshot_prepare = sub {
 
        my $conf = load_config($vmid);
 
+       die "you can't take a snapshot if it's a template\n"
+           if is_template($conf);
+
        check_lock($conf);
 
        $conf->{lock} = 'snapshot';
@@ -1510,6 +1543,9 @@ sub snapshot_delete {
 
        $conf = load_config($vmid);
 
+       die "you can't delete a snapshot if vm is a template\n"
+           if is_template($conf);
+
        $snap = $conf->{snapshots}->{$snapname};
 
        check_lock($conf);
@@ -1566,6 +1602,8 @@ sub snapshot_rollback {
 
     my $conf = load_config($vmid);
 
+    die "you can't rollback if vm is a template\n" if is_template($conf);
+
     my $snap = $conf->{snapshots}->{$snapname};
 
     die "snapshot '$snapname' does not exist\n" if !defined($snap);
@@ -1616,4 +1654,30 @@ sub snapshot_rollback {
     lock_container($vmid, 5, $unlockfn);
 }
 
+sub template_create {
+    my ($vmid, $conf) = @_;
+
+    my $storecfg = PVE::Storage::config();
+
+    my $rootinfo = PVE::LXC::parse_ct_mountpoint($conf->{rootfs});
+    my $volid = $rootinfo->{volume};
+
+    die "Template feature is not available for '$volid'\n"
+       if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
+
+    PVE::Storage::activate_volumes($storecfg, [$volid]);
+
+    my $template_volid = PVE::Storage::vdisk_create_base($storecfg, $volid);
+    $rootinfo->{volume} = $template_volid;
+    $conf->{rootfs} = print_ct_mountpount($rootinfo);
+
+    write_config($vmid, $conf);
+}
+
+sub is_template {
+    my ($conf) = @_;
+
+    return 1 if defined $conf->{template} && $conf->{template} == 1;
+}
+
 1;
index 4e742c098bdd30c572a4490e817568b3af9b6549..5ae76c2f654fa20384ff115b5881ad9a202dfcae 100644 (file)
@@ -111,6 +111,7 @@ sub recover_config {
        $conf = PVE::LXC::parse_pct_config("/lxc/0.conf" , $raw);
 
        delete $conf->{snapshots};
+       delete $conf->{template}; # restored CT is never a template
        
        if (defined($conf->{rootfs})) {
            my $rootinfo = PVE::LXC::parse_ct_mountpoint($conf->{rootfs});
diff --git a/src/pct b/src/pct
index 3a186f4111c89260c16c967a6ef25282a478f42f..a5af4e33c9523cc1d95e6c5e9802c1843556fb83 100755 (executable)
--- a/src/pct
+++ b/src/pct
@@ -129,6 +129,8 @@ my $cmddef = {
     delsnapshot => [ "PVE::API2::LXC", 'delsnapshot', ['vmid', 'snapname'], { node => $nodename } , $upid_exit ],
 
     rollback => [ "PVE::API2::LXC", 'rollback', ['vmid', 'snapname'], { node => $nodename } , $upid_exit ],
+
+    template => [ "PVE::API2::LXC", 'template', ['vmid'], { node => $nodename }],
 };
                              
 my $cmd = shift;