]> git.proxmox.com Git - pve-container.git/blobdiff - src/PVE/LXC.pm
disk formatting and mounting changed
[pve-container.git] / src / PVE / LXC.pm
index 718fcbfdd36a4acf683cb58fc726acf60c3dbe9d..c54b491f3861411080d3f61a4448bab8a3258086 100644 (file)
@@ -87,7 +87,7 @@ my $confdesc = {
     ostype => {
        optional => 1,
        type => 'string',
-       enum => ['debian', 'ubuntu', 'centos'],
+       enum => ['debian', 'ubuntu', 'centos', 'archlinux'],
        description => "OS type. Corresponds to lxc setup scripts in /usr/share/lxc/config/<ostype>.common.conf.",
     },
     console => {
@@ -378,7 +378,7 @@ sub parse_pct_config {
            next;
        }
 
-       if ($line =~ m/^(lxc\.[a-z0-9\.]+)(:|\s*=)\s*(.*?)\s*$/) {
+       if ($line =~ m/^(lxc\.[a-z0-9_\.]+)(:|\s*=)\s*(.*?)\s*$/) {
            my $key = $1;
            my $value = $3;
            if ($valid_lxc_conf_keys->{$key} || $key =~ m/^lxc\.cgroup\./) {
@@ -1244,11 +1244,12 @@ sub get_primary_ips {
 sub destroy_lxc_container {
     my ($storage_cfg, $vmid, $conf) = @_;
 
-    my $rootinfo = parse_ct_mountpoint($conf->{rootfs});
-    if (defined($rootinfo->{volume})) {
-       my ($vtype, $name, $owner) = PVE::Storage::parse_volname($storage_cfg, $rootinfo->{volume});
-       PVE::Storage::vdisk_free($storage_cfg, $rootinfo->{volume}) if $vmid == $owner;;
-    }
+    foreach_mountpoint($conf, sub {
+       my ($ms, $mountpoint) = @_;
+       my ($vtype, $name, $owner) = PVE::Storage::parse_volname($storage_cfg, $mountpoint->{volume});
+       PVE::Storage::vdisk_free($storage_cfg, $mountpoint->{volume}) if $vmid == $owner;
+    });
+
     rmdir "/var/lib/lxc/$vmid/rootfs";
     unlink "/var/lib/lxc/$vmid/config";
     rmdir "/var/lib/lxc/$vmid";
@@ -1267,7 +1268,7 @@ sub vm_stop_cleanup {
             my $vollist = get_vm_volumes($conf);
             my $loopdevlist = get_vm_volumes($conf, 'rootfs');
 
-           dettach_loops($storage_cfg, $loopdevlist);
+           detach_loops($storage_cfg, $loopdevlist);
            PVE::Storage::deactivate_volumes($storage_cfg, $vollist);
        }
     };
@@ -1764,21 +1765,42 @@ sub is_template {
     return 1 if defined $conf->{template} && $conf->{template} == 1;
 }
 
-sub foreach_mountpoint {
-    my ($conf, $func) = @_;
+sub mountpoint_names {
+    my ($reverse) = @_;
 
-    my $mountpoint = parse_ct_mountpoint($conf->{rootfs});
-    $mountpoint->{mp} = '/'; # just to be sure
-    &$func('rootfs', $mountpoint);
+    my @names = ('rootfs');
 
     for (my $i = 0; $i < $MAX_MOUNT_POINTS; $i++) {
-       my $key = "mp$i";
-       next if !defined($conf->{$key});
-       $mountpoint = parse_ct_mountpoint($conf->{$key});
+       push @names, "mp$i";
+    }
+
+    return $reverse ? reverse @names : @names;
+}
+
+sub foreach_mountpoint_full {
+    my ($conf, $reverse, $func) = @_;
+
+    foreach my $key (mountpoint_names($reverse)) {
+       my $value = $conf->{$key};
+       next if !defined($value);
+       my $mountpoint = parse_ct_mountpoint($value);
+       $mountpoint->{mp} = '/' if $key eq 'rootfs'; # just to be sure
        &$func($key, $mountpoint);
     }
 }
 
+sub foreach_mountpoint {
+    my ($conf, $func) = @_;
+
+    foreach_mountpoint_full($conf, 0, $func);
+}
+
+sub foreach_mountpoint_reverse {
+    my ($conf, $func) = @_;
+
+    foreach_mountpoint_full($conf, 1, $func);
+}
+
 sub loopdevices_list {
 
     my $loopdev = {};
@@ -1852,8 +1874,7 @@ sub attach_loops {
        my ($vtype, undef, undef, undef, undef, $isBase, $format) =
            PVE::Storage::parse_volname($storage_cfg, $volid);
 
-       if (($format ne 'subvol') &&
-           ($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs')) {
+       if ($format eq 'raw' && $scfg->{path}) {
            my $path = PVE::Storage::path($storage_cfg, $volid, $snapname);
            my $loopdev;
 
@@ -1870,7 +1891,7 @@ sub attach_loops {
     return $loopdevs;
 }
 
-sub dettach_loops {
+sub detach_loops {
     my ($storage_cfg, $vollist, $snapname) = @_;
 
     my $loopdevs = loopdevices_list();
@@ -1883,7 +1904,7 @@ sub dettach_loops {
        my ($vtype, undef, undef, undef, undef, $isBase, $format) =
            PVE::Storage::parse_volname($storage_cfg, $volid);
 
-       if($format ne 'subvol' && ($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs')) {
+       if ($format eq 'raw' && $scfg->{path}) {
            my $path = PVE::Storage::path($storage_cfg, $volid, $snapname);
             foreach my $dev (keys %$loopdevs){
                PVE::Tools::run_command(['losetup', '-d', $dev]) if $loopdevs->{$dev} eq $path;
@@ -1892,6 +1913,80 @@ sub dettach_loops {
     }
 }
 
+sub umount_all {
+    my ($vmid, $storage_cfg, $conf, $noerr, $loopdevs) = @_;
+
+    $loopdevs ||= loopdevices_list();
+
+    my $rootdir = "/var/lib/lxc/$vmid/rootfs";
+    my $volid_list = get_vm_volumes($conf);
+
+    foreach_mountpoint_reverse($conf, sub {
+       my ($ms, $mountpoint) = @_;
+
+       my $volid = $mountpoint->{volume};
+       my $mount = $mountpoint->{mp};
+
+       return if !$volid || !$mount;
+
+       my $mount_path = "$rootdir/$mount";
+       $mount_path =~ s!/+!/!g;
+
+       # fixme: test if mounted?
+       eval {
+           PVE::Tools::run_command(['umount', '-d', $mount_path]);
+       };
+       if (my $err = $@) {
+           if ($noerr) {
+               warn $err;
+           } else {
+               die $err;
+           }
+       }
+    });
+
+    PVE::LXC::detach_loops($storage_cfg, $volid_list);
+}
+
+sub mount_all {
+    my ($vmid, $storage_cfg, $conf) = @_;
+
+    my $rootdir = "/var/lib/lxc/$vmid/rootfs";
+
+    my $volid_list = get_vm_volumes($conf);
+    PVE::Storage::activate_volumes($storage_cfg, $volid_list);
+
+    my $loopdevs;
+    eval {
+       $loopdevs = attach_loops($storage_cfg, $volid_list);
+
+       foreach_mountpoint($conf, sub {
+           my ($ms, $mountpoint) = @_;
+
+           my $volid = $mountpoint->{volume};
+           my $mount = $mountpoint->{mp};
+
+           return if !$volid || !$mount;
+
+           my $image_path = PVE::Storage::path($storage_cfg, $volid);
+           my ($vtype, undef, undef, undef, undef, $isBase, $format) =
+               PVE::Storage::parse_volname($storage_cfg, $volid);
+
+           die "unable to mount base volume - internal error" if $isBase;
+
+           mountpoint_mount($mountpoint, $rootdir, $storage_cfg, $loopdevs);
+        });
+    };
+    if (my $err = $@) {
+       warn "mounting container failed - $err";
+       umount_all($vmid, $storage_cfg, $conf, 1);
+    }
+
+    return ($rootdir, $loopdevs) if wantarray;
+    return $rootdir;
+}
+
+
 sub mountpoint_mount_path {
     my ($mountpoint, $storage_cfg, $loopdevs, $snapname) = @_;
 
@@ -1912,6 +2007,7 @@ sub mountpoint_mount {
     if (defined($rootdir)) {
        $rootdir =~ s!/+$!!;
        $mount_path = "$rootdir/$mount";
+       $mount_path =~ s!/+!/!g;
        File::Path::mkpath($mount_path);
     }
     
@@ -1998,4 +2094,77 @@ sub get_vm_volumes {
     return $vollist;
 }
 
+# bash completion helper
+
+sub complete_os_templates {
+    my ($cmdname, $pname, $cvalue) = @_;
+
+    my $cfg = PVE::Storage::config();
+
+    my $storeid;
+
+    if ($cvalue =~ m/^([^:]+):/) {
+       $storeid = $1;
+    }
+
+    my $vtype = $cmdname eq 'restore' ? 'backup' : 'vztmpl';
+    my $data = PVE::Storage::template_list($cfg, $storeid, $vtype);
+
+    my $res = [];
+    foreach my $id (keys %$data) {
+       foreach my $item (@{$data->{$id}}) {
+           push @$res, $item->{volid} if defined($item->{volid});
+       }
+    }
+
+    return $res;
+}
+
+sub complete_migration_target {
+
+    my $res = [];
+
+    my $nodelist = PVE::Cluster::get_nodelist();
+    foreach my $node (@$nodelist) {
+       next if $node eq $nodename;
+       push @$res, $node;
+    }
+
+    return $res;
+}
+
+my $complete_ctid_full = sub {
+    my ($running) = @_;
+
+    my $idlist = vmstatus();
+
+    my $active_hash = list_active_containers();
+
+    my $res = [];
+
+    foreach my $id (keys %$idlist) {
+       my $d = $idlist->{$id};
+       if (defined($running)) {
+           next if $d->{template};
+           next if $running && !$active_hash->{$id};
+           next if !$running && $active_hash->{$id};
+       }
+       push @$res, $id;
+
+    }
+    return $res;
+};
+
+sub complete_ctid {
+    return &$complete_ctid_full();
+}
+
+sub complete_ctid_stopped {
+    return &$complete_ctid_full(0);
+}
+
+sub complete_ctid_running {
+    return &$complete_ctid_full(1);
+}
+
 1;