[pve-devel] [PATCH 3/3] add nexenta plugin

Alexandre Derumier aderumier at odiso.com
Sat Jul 14 15:53:57 CEST 2012


storage definition
------------------
portal 192.168.0.1
target iqn.1986-03.com.sun:....
login myloginwithjsonpermission
password jsonuserpassword
pool Yourpool
blocksize 4K

Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
 PVE/Storage/Makefile         |    2 +-
 PVE/Storage/NexentaPlugin.pm |  344 ++++++++++++++++++++++++++++++++++++++++++
 PVE/Storage/Plugin.pm        |    2 +-
 3 files changed, 346 insertions(+), 2 deletions(-)
 create mode 100644 PVE/Storage/NexentaPlugin.pm

diff --git a/PVE/Storage/Makefile b/PVE/Storage/Makefile
index 407f55c..ed65a18 100644
--- a/PVE/Storage/Makefile
+++ b/PVE/Storage/Makefile
@@ -1,4 +1,4 @@
-SOURCES=Plugin.pm DirPlugin.pm LVMPlugin.pm NFSPlugin.pm ISCSIPlugin.pm RBDPlugin.pm SheepdogPlugin.pm ISCSIDirectPlugin.pm
+SOURCES=Plugin.pm DirPlugin.pm LVMPlugin.pm NFSPlugin.pm ISCSIPlugin.pm RBDPlugin.pm SheepdogPlugin.pm ISCSIDirectPlugin.pm NexentaPlugin.pm
 
 .PHONY: install
 install:
diff --git a/PVE/Storage/NexentaPlugin.pm b/PVE/Storage/NexentaPlugin.pm
new file mode 100644
index 0000000..2943227
--- /dev/null
+++ b/PVE/Storage/NexentaPlugin.pm
@@ -0,0 +1,344 @@
+package PVE::Storage::NexentaPlugin;
+
+use strict;
+use warnings;
+use IO::File;
+use HTTP::Request;
+use LWP::UserAgent;
+use MIME::Base64;
+use JSON;
+use PVE::Tools qw(run_command file_read_firstline trim dir_glob_regex dir_glob_foreach);
+use PVE::Storage::Plugin;
+use PVE::JSONSchema qw(get_standard_option);
+
+use base qw(PVE::Storage::Plugin);
+
+
+
+sub nexenta_request {
+ my ($scfg, $json) = @_;
+
+        my $uri = "http://".$scfg->{portal}.":2000/rest/nms/";
+        my $req = HTTP::Request->new( 'POST', $uri );
+
+        $req->header( 'Content-Type' => 'application/json' );
+        $req->content( $json );
+        my $token = encode_base64("$scfg->{login}:$scfg->{password}");
+        $req->header( Authorization => "Basic $token" );
+
+        my $ua = LWP::UserAgent->new; # You might want some options here
+        my $res = $ua->request($req);
+        if (!$res->is_success) {
+                die $res->content;
+
+        }
+        my $obj = from_json($res->content);
+        print $obj->{error}->{message} if $obj->{error}->{message};
+        return undef if $obj->{error}->{message};
+        return $obj->{result} if $obj->{result};
+        return 1;
+}
+
+
+sub nexenta_list_lun_mapping_entries {
+ my ($zvol, $scfg) = @_;
+       
+
+       my $json = '{"method": "list_lun_mapping_entries","object" : "scsidisk","params": ["'.$scfg->{pool}.'/'.$zvol.'"]}';
+       my $map = nexenta_request($scfg,$json);
+       return $map if $map;
+       return undef;
+
+}
+
+sub nexenta_add_lun_mapping_entry {
+ my ($zvol, $scfg) = @_;
+
+      
+	my $json = '{"method": "add_lun_mapping_entry","object" : "scsidisk","params": ["'.$scfg->{pool}.'/'.$zvol.'",{"target_group": "All"}]}';
+ 
+        return undef if !nexenta_request($scfg, $json);
+	return 1;
+
+}
+
+
+sub nexenta_delete_lu {
+ my ($zvol, $scfg) = @_;
+
+        my $json = '{"method": "delete_lu","object" : "scsidisk","params": ["'.$scfg->{pool}.'/'.$zvol.'"]}';
+        return undef if !nexenta_request($scfg, $json);
+	return 1;
+
+}
+
+sub nexenta_create_lu {
+    my ($zvol, $scfg) = @_;
+
+	my $json = '{"method": "create_lu","object" : "scsidisk","params": ["'.$scfg->{pool}.'/'.$zvol.'",{}]}';
+
+        return undef if !nexenta_request($scfg, $json);
+	return 1;
+
+}
+
+sub nexenta_create_zvol {
+   my ($zvol, $size, $scfg) = @_;
+
+        
+        my $blocksize = $scfg->{blocksize};
+        my $nexentapool = $scfg->{pool};
+
+	my $json = '{"method": "create","object" : "zvol","params": ["'.$nexentapool.'/'.$zvol.'", "'.$size.'KB", "'.$blocksize.'", "1"]}';
+        
+        return undef if !nexenta_request($scfg, $json);
+	return 1;
+
+}
+sub nexenta_delete_zvol {
+    my ($zvol, $scfg) = @_;
+	sleep 5;
+        my $json = '{"method": "destroy","object" : "zvol","params": ["'.$scfg->{pool}.'/'.$zvol.'", ""]}';
+	return undef if !nexenta_request($scfg, $json);
+	return 1;
+
+}
+ 
+
+sub nexenta_list_zvol {
+    my ($scfg) = @_;
+
+
+
+	my $json = '{"method": "get_names","object" : "zvol","params": [""]}';
+	my $volumes = {};
+	
+	my $zvols = nexenta_request($scfg, $json);
+	return undef if !$zvols;
+
+	my $list = {};
+
+	foreach my $zvol (@$zvols) {
+	  my @values = split('/', $zvol);
+	  #$volumes->{$values[0]}->{$values[1]}->{volname} = $values[1];
+
+	  my $pool = $values[0];
+          my $image = $values[1];
+          my $owner;
+          if ($image =~ m/^(vm-(\d+)-\S+)$/) {
+                $owner = $2;
+          }
+
+          $list->{$pool}->{$image} = {
+             name => $image,
+             size => "",
+             vmid => $owner
+           };
+
+	}
+
+
+	return $list;
+
+}
+
+
+
+
+# Configuration 
+
+
+sub type {
+    return 'nexenta';
+}
+
+sub plugindata {
+    return {
+	content => [ {images => 1}, { images => 1 }],
+    };
+}
+
+
+sub properties {
+    return {
+
+	login => {
+	    description => "login",
+	    type => 'string',
+	},
+	password => {
+	    description => "password",
+	    type => 'string',
+	},
+	blocksize => {
+	    description => "block size",
+	    type => 'string',
+	},
+
+    };
+}
+
+sub options {
+    return {
+	target => { fixed => 1 },
+        portal => { fixed => 1 },
+	login => { fixed => 1 },
+	password => { fixed => 1 },
+        pool => { fixed => 1 },
+        blocksize => { fixed => 1 },
+	content => { optional => 1 },
+    };
+}
+
+# Storage implementation
+
+sub parse_volname {
+    my ($class, $volname) = @_;
+
+   
+    if ($volname =~ m/^(vm-(\d+)-\S+)$/) {
+	return ('images', $1, $2);
+    }
+
+    return('images',$volname,'');
+    #die "unable to parse lvm volume name '$volname'\n";
+}
+
+sub path {
+    my ($class, $scfg, $volname) = @_;
+
+    my ($vtype, $name, $vmid) = $class->parse_volname($volname);
+
+    my $target = $scfg->{target};
+    my $portal = $scfg->{portal};
+
+    my $map = nexenta_list_lun_mapping_entries($name,$scfg);
+    die "could not find lun number" if !$map;
+    my $lun = @$map[0]->{lun};
+
+
+    my $path = "iscsi://$portal/$target/$lun";
+
+    return ($path, $vmid, $vtype);
+}
+
+
+sub alloc_image {
+    my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_;
+
+    die "unsupported format '$fmt'" if $fmt ne 'raw';
+
+    die "illegal name '$name' - sould be 'vm-$vmid-*'\n" 
+	if  $name && $name !~ m/^vm-$vmid-/;
+
+  
+
+    my $nexentapool = $scfg->{'pool'};
+
+    if (!$name) {
+	
+	my $volumes = nexenta_list_zvol($scfg);
+	die "unable de get zvol list" if !$volumes;
+
+	for (my $i = 1; $i < 100; $i++) {
+
+	    my $tn = "vm-$vmid-disk-$i";
+	    if (!defined ($volumes->{$nexentapool}->{$tn})) {
+		$name = $tn;
+		last;
+	    }
+	}
+    }
+
+    die "unable to allocate an image name for VM $vmid in storage '$storeid'\n"
+	if !$name;
+
+    nexenta_create_zvol($name, $size, $scfg);
+    sleep 1;
+    nexenta_create_lu($name, $scfg);
+    sleep 1;
+    die "error create zvol" if !nexenta_add_lun_mapping_entry($name, $scfg);
+
+    return $name;
+}
+
+sub free_image {
+    my ($class, $storeid, $scfg, $volname) = @_;
+
+    my ($vtype, $name, $vmid) = $class->parse_volname($volname);
+
+    nexenta_delete_lu($name, $scfg);
+    sleep 5;
+    die "error deleting volume" if !nexenta_delete_zvol($name, $scfg);
+
+
+    return undef;
+}
+
+sub list_images {
+    my ($class, $storeid, $scfg, $vmid, $vollist, $cache) = @_;
+
+    $cache->{nexenta} = nexenta_list_zvol($scfg) if !$cache->{nexenta};
+    my $nexentapool = $scfg->{pool};
+    my $res = [];
+    if (my $dat = $cache->{nexenta}->{$nexentapool}) {
+	foreach my $image (keys %$dat) {
+
+            my $volname = $dat->{$image}->{name};
+
+            my $volid = "$storeid:$volname";
+
+
+            my $owner = $dat->{$volname}->{vmid};
+            if ($vollist) {
+                my $found = grep { $_ eq $volid } @$vollist;
+                next if !$found;
+            } else {
+                next if defined ($vmid) && ($owner ne $vmid);
+            }
+
+            my $info = $dat->{$volname};
+            $info->{volid} = $volid;
+
+            push @$res, $info;
+
+	}
+    }
+
+    return $res;
+}
+
+sub status {
+    my ($class, $storeid, $scfg, $cache) = @_;
+
+    my $total = 0;
+    my $free = 0;
+    my $used = 0;
+    my $active = 1;
+    return ($total,$free,$used,$active);
+
+    return undef;
+}
+
+sub activate_storage {
+    my ($class, $storeid, $scfg, $cache) = @_;
+    return 1;
+}
+
+sub deactivate_storage {
+    my ($class, $storeid, $scfg, $cache) = @_;
+    return 1;
+}
+
+sub activate_volume {
+    my ($class, $storeid, $scfg, $volname, $exclusive, $cache) = @_;
+    return 1;
+}
+
+sub deactivate_volume {
+    my ($class, $storeid, $scfg, $volname, $exclusive, $cache) = @_;
+    return 1;
+}
+
+
+1;
diff --git a/PVE/Storage/Plugin.pm b/PVE/Storage/Plugin.pm
index 2c21a4d..91003c1 100644
--- a/PVE/Storage/Plugin.pm
+++ b/PVE/Storage/Plugin.pm
@@ -300,7 +300,7 @@ sub parse_config {
 	    $d->{content} = $def->{content}->[1] if !$d->{content};
 	}
 
-	if ($type eq 'iscsi' || $type eq 'nfs' || $type eq 'rbd' || $type eq 'sheepdog' || $type eq 'iscsidirect' ) {
+	if ($type eq 'iscsi' || $type eq 'nfs' || $type eq 'rbd' || $type eq 'sheepdog' || $type eq 'iscsidirect' || $type eq 'nexenta' ) {
 	    $d->{shared} = 1;
 	}
     }
-- 
1.7.2.5




More information about the pve-devel mailing list