]> git.proxmox.com Git - pve-container.git/blobdiff - src/PVE/LXC.pm
format_disk: call activate_volume()
[pve-container.git] / src / PVE / LXC.pm
index a29216c3e7dfd423f9e420f0b005f9b56acfacf4..f34447023664c355cfe04ac530e05167ab62d4fd 100644 (file)
@@ -15,6 +15,7 @@ use PVE::JSONSchema qw(get_standard_option);
 use PVE::Tools qw($IPV6RE $IPV4RE dir_glob_foreach);
 use PVE::Network;
 use PVE::AccessControl;
+use PVE::ProcFSTools;
 
 use Data::Dumper;
 
@@ -175,6 +176,12 @@ my $confdesc = {
        enum => ['shell', 'console', 'tty'],
        default => 'tty',
     },
+    protection => {
+       optional => 1,
+       type => 'boolean',
+       description => "Sets the protection flag of the container. This will prevent the remove operation.",
+       default => 0,
+    },
 };
 
 my $valid_lxc_conf_keys = {
@@ -748,6 +755,23 @@ my $parse_size = sub {
     return int($size);
 };
 
+my $format_size = sub {
+    my ($size) = @_;
+
+    $size = int($size);
+
+    my $kb = int($size/1024);
+    return $size if $kb*1024 != $size;
+
+    my $mb = int($kb/1024);
+    return "${kb}K" if $mb*1024 != $kb;
+
+    my $gb = int($mb/1024);
+    return "${mb}M" if $gb*1024 != $mb;
+
+    return "${gb}G";
+};
+
 sub parse_ct_mountpoint {
     my ($data) = @_;
 
@@ -789,9 +813,14 @@ sub print_ct_mountpoint {
 
     die "missing volume\n" if !$info->{volume};
 
-    foreach my $o ('size', 'backup') {
+    foreach my $o (qw(backup)) {
        $opts .= ",$o=$info->{$o}" if defined($info->{$o});
     }
+
+    if ($info->{size}) {
+       $opts .= ",size=" . &$format_size($info->{size});
+    }
+
     $opts .= ",mp=$info->{mp}" if !$nomp;
 
     return "$info->{volume}$opts";
@@ -1100,6 +1129,8 @@ sub update_pct_config {
                next if !$running;
                my $netid = $1;
                PVE::Network::veth_delete("veth${vmid}i$netid");
+           } elsif ($opt eq 'protection') {
+               delete $conf->{$opt};
            } elsif ($opt =~ m/^mp(\d+)$/) {
                delete $conf->{$opt};
                push @nohotplug, $opt;
@@ -1172,6 +1203,8 @@ sub update_pct_config {
            } else {
                update_net($vmid, $conf, $opt, $net, $netid, $rootdir);
            }
+       } elsif ($opt eq 'protection') {
+           $conf->{$opt} = $value ? 1 : 0;
         } elsif ($opt =~ m/^mp(\d+)$/) {
            $conf->{$opt} = $value;
            push @$new_disks, $opt;
@@ -1285,9 +1318,6 @@ sub vm_stop_cleanup {
        if (!$keepActive) {
 
             my $vollist = get_vm_volumes($conf);
-            my $loopdevlist = get_vm_volumes($conf, 'rootfs');
-
-           detach_loops($storage_cfg, $loopdevlist);
            PVE::Storage::deactivate_volumes($storage_cfg, $vollist);
        }
     };
@@ -1820,42 +1850,6 @@ sub foreach_mountpoint_reverse {
     foreach_mountpoint_full($conf, 1, $func);
 }
 
-sub loopdevices_list {
-
-    my $loopdev = {};
-    my $parser = sub {
-       my $line = shift;
-       if ($line =~ m/^(\/dev\/loop\d+)\s+\d\s+\d\s+\d\s+\d\s(\S+)$/) {
-           $loopdev->{$1} = $2;
-       }
-    };
-
-    PVE::Tools::run_command(['losetup'], outfunc => $parser);
-
-    return $loopdev;
-}
-
-sub blockdevices_list {
-
-    my $bdevs = {};
-    dir_glob_foreach("/sys/dev/block/", '(\d+):(\d+)', sub {
-        my (undef, $major, $minor) = @_;
-        my $bdev = readlink("/sys/dev/block/$major:$minor");
-        $bdev =~ s/\.\.\/\.\.\/devices\/virtual\/block\//\/dev\//;
-        $bdevs->{$bdev}->{major} = $major;
-        $bdevs->{$bdev}->{minor} = $minor;
-    });
-    return $bdevs;
-}
-
-sub find_loopdev {
-    my ($loopdevs, $path) = @_;
-
-    foreach my $dev (keys %$loopdevs){
-       return $dev if $loopdevs->{$dev} eq $path;
-    }
-}
-
 sub check_ct_modify_config_perm {
     my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_;
 
@@ -1880,62 +1874,8 @@ sub check_ct_modify_config_perm {
     return 1;
 }
 
-sub attach_loops {
-    my ($storage_cfg, $vollist, $snapname) = @_;
-
-    my $loopdevs = {};
-
-    foreach my $volid (@$vollist) {
-
-       my ($storage, $volname) = PVE::Storage::parse_volume_id($volid);
-       my $scfg = PVE::Storage::storage_config($storage_cfg, $storage);
-
-       my ($vtype, undef, undef, undef, undef, $isBase, $format) =
-           PVE::Storage::parse_volname($storage_cfg, $volid);
-
-       if ($format eq 'raw' && $scfg->{path}) {
-           my $path = PVE::Storage::path($storage_cfg, $volid, $snapname);
-           my $loopdev;
-
-           my $parser = sub {
-               my $line = shift;
-               $loopdev = $line if $line =~m|^/dev/loop\d+$|;
-               $loopdevs->{$loopdev} = $path;
-           };
-
-           PVE::Tools::run_command(['losetup', '--find', '--show', $path], outfunc => $parser);
-       }
-    }
-
-    return $loopdevs;
-}
-
-sub detach_loops {
-    my ($storage_cfg, $vollist, $snapname) = @_;
-
-    my $loopdevs = loopdevices_list();
-
-    foreach my $volid (@$vollist) {
-
-       my ($storage, $volname) = PVE::Storage::parse_volume_id($volid);
-       my $scfg = PVE::Storage::storage_config($storage_cfg, $storage);
-
-       my ($vtype, undef, undef, undef, undef, $isBase, $format) =
-           PVE::Storage::parse_volname($storage_cfg, $volid);
-
-       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;
-           }
-       }
-    }
-}
-
 sub umount_all {
-    my ($vmid, $storage_cfg, $conf, $noerr, $loopdevs) = @_;
-
-    $loopdevs ||= loopdevices_list();
+    my ($vmid, $storage_cfg, $conf, $noerr) = @_;
 
     my $rootdir = "/var/lib/lxc/$vmid/rootfs";
     my $volid_list = get_vm_volumes($conf);
@@ -1951,7 +1891,8 @@ sub umount_all {
        my $mount_path = "$rootdir/$mount";
        $mount_path =~ s!/+!/!g;
 
-       # fixme: test if mounted?
+       return if !PVE::ProcFSTools::is_mounted($mount_path);
+
        eval {
            PVE::Tools::run_command(['umount', '-d', $mount_path]);
        };
@@ -1963,22 +1904,18 @@ sub umount_all {
            }
        }
     });
-
-    PVE::LXC::detach_loops($storage_cfg, $volid_list);
 }
 
 sub mount_all {
     my ($vmid, $storage_cfg, $conf, $mkdirs) = @_;
 
     my $rootdir = "/var/lib/lxc/$vmid/rootfs";
+    File::Path::make_path($rootdir);
 
     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) = @_;
 
@@ -1994,7 +1931,7 @@ sub mount_all {
            die "unable to mount base volume - internal error" if $isBase;
 
            File::Path::make_path "$rootdir/$mount" if $mkdirs;
-           mountpoint_mount($mountpoint, $rootdir, $storage_cfg, $loopdevs);
+           mountpoint_mount($mountpoint, $rootdir, $storage_cfg);
         });
     };
     if (my $err = $@) {
@@ -2002,19 +1939,19 @@ sub mount_all {
        umount_all($vmid, $storage_cfg, $conf, 1);
     }
 
-    return wantarray ? ($rootdir, $loopdevs) : $rootdir;
+    return $rootdir;
 }
 
 
 sub mountpoint_mount_path {
-    my ($mountpoint, $storage_cfg, $loopdevs, $snapname) = @_;
+    my ($mountpoint, $storage_cfg, $snapname) = @_;
 
-    return mountpoint_mount($mountpoint, undef, $storage_cfg, $loopdevs, $snapname);
+    return mountpoint_mount($mountpoint, undef, $storage_cfg, $snapname);
 }
 
 # use $rootdir = undef to just return the corresponding mount path
 sub mountpoint_mount {
-    my ($mountpoint, $rootdir, $storage_cfg, $loopdevs, $snapname) = @_;
+    my ($mountpoint, $rootdir, $storage_cfg, $snapname) = @_;
 
     my $volid = $mountpoint->{volume};
     my $mount = $mountpoint->{mp};
@@ -2038,42 +1975,37 @@ sub mountpoint_mount {
 
        my $scfg = PVE::Storage::storage_config($storage_cfg, $storage);
        my $path = PVE::Storage::path($storage_cfg, $volid, $snapname);
+       return $path if !$mount_path;
 
        my ($vtype, undef, undef, undef, undef, $isBase, $format) =
            PVE::Storage::parse_volname($storage_cfg, $volid);
 
        if ($format eq 'subvol') {
-           
-           if ($mount_path) {
-               if ($snapname) {
-                   if ($scfg->{type} eq 'zfspool') {
-                       my $path_arg = $path;
-                       $path_arg =~ s!^/+!!;
-                       PVE::Tools::run_command(['mount', '-o', 'ro', '-t', 'zfs', $path_arg, $mount_path]);
-                   } else {
-                       die "cannot mount subvol snapshots for storage type '$scfg->{type}'\n";
-                   }           
+           if ($snapname) {
+               if ($scfg->{type} eq 'zfspool') {
+                   my $path_arg = $path;
+                   $path_arg =~ s!^/+!!;
+                   PVE::Tools::run_command(['mount', '-o', 'ro', '-t', 'zfs', $path_arg, $mount_path]);
                } else {
-                   PVE::Tools::run_command(['mount', '-o', 'bind', $path, $mount_path]);
-               }
+                   die "cannot mount subvol snapshots for storage type '$scfg->{type}'\n";
+               }               
+           } else {
+               PVE::Tools::run_command(['mount', '-o', 'bind', $path, $mount_path]);
            }
            return $path;
-           
        } elsif ($format eq 'raw') {
-
+           my @extra_opts;
            if ($scfg->{path}) {
-               $path = find_loopdev($loopdevs, $path) if $loopdevs;
+               push @extra_opts, '-o', 'loop';
            } elsif ($scfg->{type} eq 'drbd' || $scfg->{type} eq 'rbd') {
                # do nothing
            } else {
                die "unsupported storage type '$scfg->{type}'\n";
            }
-           if ($mount_path) {
-               if ($isBase || defined($snapname)) {
-                   PVE::Tools::run_command(['mount', '-o', 'ro', $path, $mount_path]);
-               } else {
-                   PVE::Tools::run_command(['mount', $path, $mount_path]);
-               }
+           if ($isBase || defined($snapname)) {
+               PVE::Tools::run_command(['mount', '-o', "ro", @extra_opts, $path, $mount_path]);
+           } else {
+               PVE::Tools::run_command(['mount', @extra_opts, $path, $mount_path]);
            }
            return $path;
        } else {
@@ -2131,6 +2063,8 @@ sub format_disk {
 
     die "cannot format volume '$volid' with no storage\n" if !$storage;
 
+    PVE::Storage::activate_volumes($storage_cfg, [$volid]);
+
     my $path = PVE::Storage::path($storage_cfg, $volid);
 
     my ($vtype, undef, undef, undef, undef, $isBase, $format) =
@@ -2168,17 +2102,17 @@ sub create_disks {
            return if !$storage;
 
            if ($volid =~ m/^([^:\s]+):(\d+(\.\d+)?)$/) {
-               my ($storeid, $size) = ($1, $2);
+               my ($storeid, $size_gb) = ($1, $2);
 
-               $size = int($size*1024) * 1024;
+               my $size_kb = int(${size_gb}*1024) * 1024;
 
                my $scfg = PVE::Storage::storage_config($storecfg, $storage);
                # fixme: use better naming ct-$vmid-disk-X.raw?
 
                if ($scfg->{type} eq 'dir' || $scfg->{type} eq 'nfs') {
-                   if ($size > 0) {
+                   if ($size_kb > 0) {
                        $volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'raw',
-                                                          undef, $size);
+                                                          undef, $size_kb);
                        format_disk($storecfg, $volid);
                    } else {
                        $volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'subvol',
@@ -2187,22 +2121,23 @@ sub create_disks {
                } elsif ($scfg->{type} eq 'zfspool') {
 
                    $volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'subvol',
-                                              undef, $size);
+                                                      undef, $size_kb);
                } elsif ($scfg->{type} eq 'drbd') {
 
-                   $volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'raw', undef, $size);
+                   $volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'raw', undef, $size_kb);
                    format_disk($storecfg, $volid);
 
                } elsif ($scfg->{type} eq 'rbd') {
 
                    die "krbd option must be enabled on storage type '$scfg->{type}'\n" if !$scfg->{krbd};
-                   $volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'raw', undef, $size);
+                   $volid = PVE::Storage::vdisk_alloc($storecfg, $storage, $vmid, 'raw', undef, $size_kb);
                    format_disk($storecfg, $volid);
                } else {
                    die "unable to create containers on storage type '$scfg->{type}'\n";
                }
                push @$vollist, $volid;
-               $conf->{$ms} = print_ct_mountpoint({volume => $volid, size => $size, mp => $mp });
+                my $new_mountpoint = { volume => $volid, size => $size_kb*1024, mp => $mp };
+               $conf->{$ms} = print_ct_mountpoint($new_mountpoint, $ms eq 'rootfs');
            } else {
                # use specified/existing volid
            }
@@ -2242,19 +2177,6 @@ sub complete_os_templates {
     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) = @_;