]> git.proxmox.com Git - pve-storage.git/blobdiff - PVE/Storage/Plugin.pm
Include new storage function volume_snapshot_list.
[pve-storage.git] / PVE / Storage / Plugin.pm
index 8341fd3bab52478a8d999315d70dab5c924a3a4b..641ab045a8b85581f6e8b8b72b93f8d4b2c24027 100644 (file)
@@ -20,12 +20,15 @@ cfs_register_file ('storage.cfg',
 my $defaultData = {
     propertyList => {
        type => { description => "Storage type." },
-       storage => get_standard_option('pve-storage-id'),
+       storage => get_standard_option('pve-storage-id',
+           { completion => \&PVE::Storage::complete_storage }),
        nodes => get_standard_option('pve-node-list', { optional => 1 }),
        content => {
-           description => "Allowed content types. Note: value 'rootdir' is used for Containers, and value 'images' for KVM-Qemu VM's.\n",
+           description => "Allowed content types.\n\nNOTE: the value " .
+               "'rootdir' is used for Containers, and value 'images' for VMs.\n",
            type => 'string', format => 'pve-storage-content-list',
            optional => 1,
+           completion => \&PVE::Storage::complete_content_type,
        },
        disable => {
            description => "Flag to disable the storage.",
@@ -44,7 +47,7 @@ my $defaultData = {
            optional => 1,
        },
        'format' => {
-           description => "Default Image format.",
+           description => "Default image format.",
            type => 'string', format => 'pve-storage-format',
            optional => 1,
        },
@@ -115,6 +118,18 @@ sub verify_server {
     return $server;
 }
 
+PVE::JSONSchema::register_format('pve-storage-vgname', \&parse_lvm_name);
+sub parse_lvm_name {
+    my ($name, $noerr) = @_;
+
+    if ($name !~ m/^[a-z][a-z0-9\-\_\.]*[a-z0-9]$/i) {
+       return undef if $noerr;
+       die "lvm name '$name' contains illegal characters\n";
+    }
+
+    return $name;
+}
+
 # fixme: do we need this
 #PVE::JSONSchema::register_format('pve-storage-portal', \&verify_portal);
 #sub verify_portal {
@@ -133,7 +148,7 @@ sub verify_portal_dns {
     my ($portal, $noerr) = @_;
 
     # IP or DNS name with optional port
-    if ($portal !~ m/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|[[:alnum:]\-\.]+)(:\d+)?$/) {
+    if (!PVE::Tools::parse_host_and_port($portal)) {
        return undef if $noerr;
        die "value does not look like a valid portal address\n";
     }
@@ -221,7 +236,8 @@ sub decode_value {
 
        foreach my $c (PVE::Tools::split_list($value)) {
            if (!$valid_content->{$c}) {
-               die "storage does not support content type '$c'\n";
+               warn "storage does not support content type '$c'\n";
+               next;
            }
            $res->{$c} = 1;
        }
@@ -235,7 +251,8 @@ sub decode_value {
        my $valid_formats = $def->{format}->[0];
 
        if (!$valid_formats->{$value}) {
-           die "storage does not support format '$value'\n";
+           warn "storage does not support format '$value'\n";
+           next;
        }
 
        return $value;
@@ -280,7 +297,7 @@ sub parse_config {
     my $ids = $cfg->{ids};
 
     # make sure we have a reasonable 'local:' storage
-    # openvz expects things to be there
+    # we want 'local' to be always the same 'type' (on all cluster nodes)
     if (!$ids->{local} || $ids->{local}->{type} ne 'dir' ||
        ($ids->{local}->{path} && $ids->{local}->{path} ne '/var/lib/vz')) {
        $ids->{local} = {
@@ -292,11 +309,6 @@ sub parse_config {
        };
     }
 
-    # we always need this for OpenVZ
-    $ids->{local}->{content}->{rootdir} = 1;
-    $ids->{local}->{content}->{vztmpl} = 1;
-    delete ($ids->{local}->{disable});
-
     # make sure we have a path
     $ids->{local}->{path} = '/var/lib/vz' if !$ids->{local}->{path};
 
@@ -403,9 +415,15 @@ sub get_subdir {
 }
 
 sub filesystem_path {
-    my ($class, $scfg, $volname, $storeid) = @_;
+    my ($class, $scfg, $volname, $snapname) = @_;
 
-    my ($vtype, $name, $vmid) = $class->parse_volname($volname);
+    my ($vtype, $name, $vmid, undef, undef, $isBase, $format) =
+       $class->parse_volname($volname);
+
+    # Note: qcow2/qed has internal snapshot, so path is always
+    # the same (with or without snapshot => same file).
+    die "can't snapshot this image format\n"
+       if defined($snapname) && $format !~ m/^(qcow2|qed)$/;
 
     my $dir = $class->get_subdir($scfg, $vtype);
 
@@ -417,16 +435,16 @@ sub filesystem_path {
 }
 
 sub path {
-    my ($class, $scfg, $volname, $storeid) = @_;
+    my ($class, $scfg, $volname, $storeid, $snapname) = @_;
 
-    return $class->filesystem_path($scfg, $volname, $storeid);
+    return $class->filesystem_path($scfg, $volname, $snapname);
 }
 
 sub create_base {
     my ($class, $storeid, $scfg, $volname) = @_;
 
     # this only works for file based storage types
-    die "storage definintion has no path\n" if !$scfg->{path};
+    die "storage definition has no path\n" if !$scfg->{path};
 
     my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $format) =
        $class->parse_volname($volname);
@@ -556,7 +574,11 @@ sub alloc_image {
        # only allow this if size = 0, so that user knows what he is doing
        die "storage does not support subvol quotas\n" if $size != 0;
        
-       (mkdir $path) || die "unable to create subvol '$path' - $!\n";
+       my $old_umask = umask(0022);
+       my $err;
+       mkdir($path) or $err = "unable to create subvol '$path' - $!\n";
+       umask $old_umask;
+       die $err if $err;
     } else {
        my $cmd = ['/usr/bin/qemu-img', 'create'];
 
@@ -575,7 +597,13 @@ sub free_image {
 
     my $path = $class->filesystem_path($scfg, $volname);
 
-    if ($format eq 'subvol') {
+    if ($isBase) {
+       # try to remove immutable flag
+       eval { run_command(['/usr/bin/chattr', '-i', $path]); };
+       warn $@ if $@;
+    }
+
+    if (defined($format) && ($format eq 'subvol')) {
        File::Path::remove_tree($path);
     } else {
     
@@ -584,12 +612,6 @@ sub free_image {
            return undef;
        }
 
-       if ($isBase) {
-           # try to remove immutable flag
-           eval { run_command(['/usr/bin/chattr', '-i', $path]); };
-           warn $@ if $@;
-       }
-
        unlink($path) || die "unlink '$path' failed - $!\n";
     }
     
@@ -652,7 +674,9 @@ sub volume_resize {
 
     my $path = $class->filesystem_path($scfg, $volname);
 
-    my $cmd = ['/usr/bin/qemu-img', 'resize', $path , $size];
+    my $format = ($class->parse_volname($volname))[6];
+
+    my $cmd = ['/usr/bin/qemu-img', 'resize', '-f', $format, $path , $size];
 
     run_command($cmd, timeout => 10);
 
@@ -673,6 +697,14 @@ sub volume_snapshot {
     return undef;
 }
 
+sub volume_send {
+    my ($class, $scfg, $storeid, $volname, $ip, $snap,
+       $incremental_snap, $verbose, $limit, $target_path) = @_;
+
+    # implement in subclass
+    die "Volume_send is not implemented for $class";
+}
+
 sub volume_rollback_is_possible {
     my ($class, $scfg, $storeid, $volname, $snap) = @_; 
 
@@ -702,6 +734,8 @@ sub volume_snapshot_delete {
 
     my $path = $class->filesystem_path($scfg, $volname);
 
+    $class->deactivate_volume($storeid, $scfg, $volname, $snap, {});
+
     my $cmd = ['/usr/bin/qemu-img', 'snapshot','-d', $snap, $path];
 
     run_command($cmd);
@@ -719,6 +753,8 @@ sub volume_has_feature {
        copy => { base => {qcow2 => 1, raw => 1, vmdk => 1},
                  current => {qcow2 => 1, raw => 1, vmdk => 1},
                  snap => {qcow2 => 1} },
+       sparseinit => { base => {qcow2 => 1, raw => 1, vmdk => 1},
+                       current => {qcow2 => 1, raw => 1, vmdk => 1} },
     };
 
     my ($vtype, $name, $vmid, $basename, $basevmid, $isBase, $format) =
@@ -796,6 +832,15 @@ sub status {
     return ($res->{total}, $res->{avail}, $res->{used}, 1);
 }
 
+sub volume_snapshot_list {
+    my ($class, $scfg, $storeid, $volname, $prefix, $ip) = @_;
+
+    # implement in subclass
+    die "Volume_snapshot_list is not implemented for $class";
+
+    # retrun an empty array if dataset does not exist.
+}
+
 sub activate_storage {
     my ($class, $storeid, $scfg, $cache) = @_;
 
@@ -806,6 +851,8 @@ sub activate_storage {
     die "unable to activate storage '$storeid' - " .
        "directory '$path' does not exist\n" if ! -d $path;
 
+    return if defined($scfg->{mkdir}) && !$scfg->{mkdir};
+
     if (defined($scfg->{content})) {
        foreach my $vtype (keys %$vtype_subdirs) {
            # OpenVZMigrate uses backup (dump) dir
@@ -825,9 +872,9 @@ sub deactivate_storage {
 }
 
 sub activate_volume {
-    my ($class, $storeid, $scfg, $volname, $exclusive, $cache) = @_;
+    my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
 
-    my $path = $class->filesystem_path($scfg, $volname);
+    my $path = $class->filesystem_path($scfg, $volname, $snapname);
 
     # check is volume exists
     if ($scfg->{path}) {
@@ -838,7 +885,7 @@ sub activate_volume {
 }
 
 sub deactivate_volume {
-    my ($class, $storeid, $scfg, $volname, $cache) = @_;
+    my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_;
 
     # do nothing by default
 }