]> git.proxmox.com Git - pve-storage.git/blobdiff - PVE/Storage.pm
sheepdog : has_feature : clone base
[pve-storage.git] / PVE / Storage.pm
index 4afdf15e6106a43dd8164fe4290a27f51a9e79c5..36d4cb3ef0636debea3fa5c402e32cbe094d0f7e 100755 (executable)
@@ -138,6 +138,66 @@ sub volume_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) = @_;
 
@@ -197,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
@@ -217,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);
@@ -243,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");   
@@ -253,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");        
        }
@@ -292,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;
@@ -358,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) = @_;
 
@@ -401,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;
@@ -461,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 };
                }