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";
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});
#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;
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',
$d->{diskread} = 0;
$d->{diskwrite} = 0;
+
+ $d->{template} = is_template($conf);
}
foreach my $vmid (keys %$list) {
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;
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};
$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);
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';
$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);
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);
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;
$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});
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;