]> git.proxmox.com Git - pve-storage.git/blobdiff - PVE/Storage.pm
sheepdog : has_feature : clone base
[pve-storage.git] / PVE / Storage.pm
index 39d77c654ed6e569bcd3fb750fea2770734147bf..36d4cb3ef0636debea3fa5c402e32cbe094d0f7e 100755 (executable)
@@ -93,12 +93,6 @@ sub storage_check_enabled {
        return undef;
     }
 
-    my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
-    if (!$plugin->check_connection($storeid, $scfg)) {
-       die "storage '$storeid' is not available\n" if !$noerr;
-       return undef;
-    }
-
     return storage_check_node($cfg, $storeid, $node, $noerr);
 }
 
@@ -129,6 +123,81 @@ sub volume_size_info {
     }
 }
 
+sub volume_resize {
+    my ($cfg, $volid, $size, $running) = @_;
+
+    my ($storeid, $volname) = parse_volume_id($volid, 1);
+    if ($storeid) {
+        my $scfg = storage_config($cfg, $storeid);
+        my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+        return $plugin->volume_resize($scfg, $storeid, $volname, $size, $running);
+    } elsif ($volid =~ m|^(/.+)$| && -e $volid) {
+        die "resize device is not possible";
+    } else {
+        die "can't resize";
+    }
+}
+
+sub volume_snapshot {
+    my ($cfg, $volid, $snap, $running) = @_;
+
+    my ($storeid, $volname) = parse_volume_id($volid, 1);
+    if ($storeid) {
+        my $scfg = storage_config($cfg, $storeid);
+        my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+        return $plugin->volume_snapshot($scfg, $storeid, $volname, $snap, $running);
+    } elsif ($volid =~ m|^(/.+)$| && -e $volid) {
+        die "snapshot device is not possible";
+    } else {
+        die "can't snapshot";
+    }
+}
+
+sub volume_snapshot_rollback {
+    my ($cfg, $volid, $snap) = @_;
+
+    my ($storeid, $volname) = parse_volume_id($volid, 1);
+    if ($storeid) {
+        my $scfg = storage_config($cfg, $storeid);
+        my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+        return $plugin->volume_snapshot_rollback($scfg, $storeid, $volname, $snap);
+    } elsif ($volid =~ m|^(/.+)$| && -e $volid) {
+        die "snapshot rollback device is not possible";
+    } else {
+        die "can't snapshot";
+    }
+}
+
+sub volume_snapshot_delete {
+    my ($cfg, $volid, $snap, $running) = @_;
+
+    my ($storeid, $volname) = parse_volume_id($volid, 1);
+    if ($storeid) {
+        my $scfg = storage_config($cfg, $storeid);
+        my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+        return $plugin->volume_snapshot_delete($scfg, $storeid, $volname, $snap, $running);
+    } elsif ($volid =~ m|^(/.+)$| && -e $volid) {
+        die "snapshot delete device is not possible";
+    } else {
+        die "can't delete snapshot";
+    }
+}
+
+sub volume_has_feature {
+    my ($cfg, $feature, $volid, $snap, $running) = @_;
+
+    my ($storeid, $volname) = parse_volume_id($volid, 1);
+    if ($storeid) {
+        my $scfg = storage_config($cfg, $storeid);
+        my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+        return $plugin->volume_has_feature($scfg, $feature, $storeid, $volname, $snap, $running);
+    } elsif ($volid =~ m|^(/.+)$| && -e $volid) {
+       return undef;
+    } else {
+       return undef;
+    }
+}
+
 sub get_image_dir {
     my ($cfg, $storeid, $vmid) = @_;
 
@@ -188,15 +257,31 @@ sub parse_vmid {
     return int($vmid);
 }
 
-PVE::JSONSchema::register_format('pve-volume-id', \&parse_volume_id);
 sub parse_volume_id {
     my ($volid, $noerr) = @_;
 
-    if ($volid =~ m/^([a-z][a-z0-9\-\_\.]*[a-z0-9]):(.+)$/i) {
-       return wantarray ? ($1, $2) : $1;
+    return PVE::Storage::Plugin::parse_volume_id($volid, $noerr);
+}
+
+sub volume_is_base {
+    my ($cfg, $volid) = @_;
+
+    my ($sid, $volname) = parse_volume_id($volid, 1);
+    return 0 if !$sid;
+
+    if (my $scfg = $cfg->{ids}->{$sid}) {
+       my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+       my ($vtype, $name, $vmid, $basename, $basevmid, $isBase) = 
+           $plugin->parse_volname($volname);
+       return $isBase ? 1 : 0;
+    } else {
+       # stale volid with undefined storage - so we can just guess
+       if ($volid =~ m/base-/) {
+           return 1;
+       }
     }
-    return undef if $noerr;
-    die "unable to parse volume ID '$volid'\n";
+
+    return 0;
 }
 
 # try to map a filesystem path to a volume identifier
@@ -208,7 +293,7 @@ sub path_to_volume_id {
     my ($sid, $volname) = parse_volume_id($path, 1);
     if ($sid) {
        if (my $scfg = $ids->{$sid}) {
-           if (my $path = $scfg->{path}) {
+           if ($scfg->{path}) {
                my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
                my ($vtype, $name, $vmid) = $plugin->parse_volname($volname);
                return ($vtype, $path);
@@ -234,7 +319,15 @@ sub path_to_volume_id {
        if ($path =~ m!^$imagedir/(\d+)/([^/\s]+)$!) {
            my $vmid = $1;
            my $name = $2;
-           return ('images', "$sid:$vmid/$name");
+
+           my $vollist = $plugin->list_images($sid, $scfg, $vmid);
+           foreach my $info (@$vollist) {
+               my ($storeid, $volname) = parse_volume_id($info->{volid});
+               my $volpath = $plugin->path($scfg, $volname, $storeid);
+               if ($volpath eq $path) {
+                   return ('images', $info->{volid});
+               }
+           }
        } elsif ($path =~ m!^$isodir/([^/]+\.[Ii][Ss][Oo])$!) {
            my $name = $1;
            return ('iso', "$sid:iso/$name");   
@@ -244,7 +337,7 @@ sub path_to_volume_id {
        } elsif ($path =~ m!^$privatedir/(\d+)$!) {
            my $vmid = $1;
            return ('rootdir', "$sid:rootdir/$vmid");
-       } elsif ($path =~ m!^$backupdir/([^/]+\.(tar|tar\.gz|tar\.lzo|tgz))$!) {
+       } elsif ($path =~ m!^$backupdir/([^/]+\.(tar|tar\.gz|tar\.lzo|tgz|vma|vma\.gz|vma\.lzo))$!) {
            my $name = $1;
            return ('iso', "$sid:backup/$name");        
        }
@@ -283,8 +376,7 @@ sub storage_migrate {
 
     my $errstr = "unable to migrate '$volid' to '${target_volid}' on host '$target_host'";
 
-    # blowfish is a fast block cipher, much faster then 3des
-    my $sshoptions = "-c blowfish -o 'BatchMode=yes'";
+    my $sshoptions = "-o 'BatchMode=yes'";
     my $ssh = "/usr/bin/ssh $sshoptions";
 
     local $ENV{RSYNC_RSH} = $ssh;
@@ -349,6 +441,42 @@ sub storage_migrate {
     }
 }
 
+sub vdisk_clone {
+    my ($cfg, $volid, $vmid) = @_;
+    
+    my ($storeid, $volname) = parse_volume_id($volid);
+
+    my $scfg = storage_config($cfg, $storeid);
+
+    my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+    
+    activate_storage($cfg, $storeid);
+
+    # lock shared storage
+    return $plugin->cluster_lock_storage($storeid, $scfg->{shared}, undef, sub {
+       my $volname = $plugin->clone_image($scfg, $storeid, $volname, $vmid);
+       return "$storeid:$volname";
+    });
+}
+
+sub vdisk_create_base {
+    my ($cfg, $volid) = @_;
+
+    my ($storeid, $volname) = parse_volume_id($volid);
+
+    my $scfg = storage_config($cfg, $storeid);
+
+    my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
+    
+    activate_storage($cfg, $storeid);
+
+    # lock shared storage
+    return $plugin->cluster_lock_storage($storeid, $scfg->{shared}, undef, sub {
+       my $volname = $plugin->create_base($storeid, $scfg, $volname);
+       return "$storeid:$volname";
+    });
+}
+
 sub vdisk_alloc {
     my ($cfg, $storeid, $vmid, $fmt, $name, $size) = @_;
 
@@ -392,7 +520,28 @@ sub vdisk_free {
 
     # lock shared storage
     $plugin->cluster_lock_storage($storeid, $scfg->{shared}, undef, sub {
-       my $cleanup_worker = $plugin->free_image($storeid, $scfg, $volname);
+
+       my ($vtype, $name, $vmid, undef, undef, $isBase) = 
+           $plugin->parse_volname($volname);
+       if ($isBase) {
+           my $vollist = $plugin->list_images($storeid, $scfg);
+           foreach my $info (@$vollist) {
+               my (undef, $tmpvolname) = parse_volume_id($info->{volid});
+               my $basename = undef;
+               my $basevmid = undef;
+
+               eval{
+                   (undef, undef, undef, $basename, $basevmid) = 
+                       $plugin->parse_volname($tmpvolname);
+               };
+
+               if ($basename && defined($basevmid) && $basevmid == $vmid && $basename eq $name) {
+                   die "base volume '$volname' is still in use " .
+                       "(use by '$tmpvolname')\n";
+               }
+           }
+       }
+       my $cleanup_worker = $plugin->free_image($storeid, $scfg, $volname, $isBase);
     });
 
     return if !$cleanup_worker;
@@ -452,7 +601,7 @@ sub template_list {
                    $info = { volid => "$sid:vztmpl/$1", format => 'tgz' };
 
                } elsif ($tt eq 'backup') {
-                   next if $fn !~ m!/([^/]+\.(tar|tar\.gz|tar\.lzo|tgz))$!;
+                   next if $fn !~ m!/([^/]+\.(tar|tar\.gz|tar\.lzo|tgz|vma|vma\.gz|vma\.lzo))$!;
                    
                    $info = { volid => "$sid:backup/$1", format => $2 };
                }
@@ -530,9 +679,11 @@ sub uevent_seqnum {
     return $seqnum;
 }
 
-sub __activate_storage_full {
+sub activate_storage {
     my ($cfg, $storeid, $cache) = @_;
 
+    $cache = {} if !$cache;
+
     my $scfg = storage_check_enabled($cfg, $storeid);
 
     return if $cache->{activated}->{$storeid};
@@ -543,7 +694,11 @@ sub __activate_storage_full {
 
     if ($scfg->{base}) {
        my ($baseid, undef) = parse_volume_id ($scfg->{base});
-       __activate_storage_full ($cfg, $baseid, $cache);
+       activate_storage($cfg, $baseid, $cache);
+    }
+
+    if (!$plugin->check_connection($storeid, $scfg)) {
+       die "storage '$storeid' is not online\n";
     }
 
     $plugin->activate_storage($storeid, $scfg, $cache);
@@ -566,19 +721,10 @@ sub activate_storage_list {
     $cache = {} if !$cache;
 
     foreach my $storeid (@$storeid_list) {
-       __activate_storage_full ($cfg, $storeid, $cache);
+       activate_storage($cfg, $storeid, $cache);
     }
 }
 
-sub activate_storage {
-    my ($cfg, $storeid) = @_;
-
-    my $cache = {};
-
-    __activate_storage_full ($cfg, $storeid, $cache);
-}
-
-
 sub deactivate_storage {
     my ($cfg, $storeid) = @_;
 
@@ -670,12 +816,16 @@ sub storage_info {
 
     my $cache = {};
 
-    eval { activate_storage_list($cfg, $slist, $cache); };
-
     foreach my $storeid (keys %$ids) {
        my $scfg = $ids->{$storeid};
        next if !$info->{$storeid};
 
+       eval { activate_storage($cfg, $storeid, $cache); };
+       if (my $err = $@) {
+           warn $err;
+           next;
+       }
+
        my $plugin = PVE::Storage::Plugin->lookup($scfg->{type});
        my ($total, $avail, $used, $active);
        eval { ($total, $avail, $used, $active) = $plugin->status($storeid, $scfg, $cache); };