]> git.proxmox.com Git - pve-storage.git/blob - PVE/Storage/GlusterfsPlugin.pm
add Glusterfs Plugin
[pve-storage.git] / PVE / Storage / GlusterfsPlugin.pm
1 package PVE::Storage::GlusterfsPlugin;
2
3 use strict;
4 use warnings;
5 use IO::File;
6 use File::Path;
7 use PVE::Tools qw(run_command);
8 use PVE::Storage::Plugin;
9 use PVE::JSONSchema qw(get_standard_option);
10 use Net::Ping;
11
12 use base qw(PVE::Storage::Plugin);
13
14 # Glusterfs helper functions
15
16 sub read_proc_mounts {
17
18 local $/; # enable slurp mode
19
20 my $data = "";
21 if (my $fd = IO::File->new("/proc/mounts", "r")) {
22 $data = <$fd>;
23 close ($fd);
24 }
25
26 return $data;
27 }
28
29 sub glusterfs_is_mounted {
30 my ($server, $volume, $mountpoint, $mountdata) = @_;
31
32 my $source = "$server:$volume";
33
34 $mountdata = read_proc_mounts() if !$mountdata;
35
36 if ($mountdata =~ m|^$source/?\s$mountpoint\sfuse.glusterfs|m) {
37 return $mountpoint;
38 }
39
40 return undef;
41 }
42
43 sub glusterfs_mount {
44 my ($server, $volume, $mountpoint) = @_;
45
46 my $source = "$server:$volume";
47
48 my $cmd = ['/bin/mount', '-t', 'glusterfs', $source, $mountpoint];
49
50 run_command($cmd, errmsg => "mount error");
51 }
52
53 # Configuration
54
55 sub type {
56 return 'glusterfs';
57 }
58
59 sub plugindata {
60 return {
61 content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1},
62 { images => 1 }],
63 format => [ { raw => 1, qcow2 => 1, vmdk => 1 } , 'raw' ],
64 };
65 }
66
67 sub properties {
68 return {
69 volume => {
70 description => "Glusterfs Volume.",
71 type => 'string',
72 },
73 };
74 }
75
76 sub options {
77 return {
78 path => { fixed => 1 },
79 server => { optional => 1 },
80 volume => { fixed => 1 },
81 nodes => { optional => 1 },
82 disable => { optional => 1 },
83 maxfiles => { optional => 1 },
84 content => { optional => 1 },
85 format => { optional => 1 },
86 };
87 }
88
89
90 sub check_config {
91 my ($class, $sectionId, $config, $create, $skipSchemaCheck) = @_;
92
93 $config->{path} = "/mnt/pve/$sectionId" if $create && !$config->{path};
94
95 return $class->SUPER::check_config($sectionId, $config, $create, $skipSchemaCheck);
96 }
97
98 # Storage implementation
99
100 sub path {
101 my ($class, $scfg, $volname, $storeid) = @_;
102
103 my ($vtype, $name, $vmid) = $class->parse_volname($volname);
104
105 my $server = $scfg->{server} ? $scfg->{server} : 'localhost';
106 my $glustervolume = $scfg->{volume};
107
108 my $path = undef;
109 if($vtype eq 'images'){
110 $path = "gluster://$server/$glustervolume/images/$vmid/$name";
111 }else{
112 my $dir = $class->get_subdir($scfg, $vtype);
113 $path = "$dir/$name";
114 }
115
116
117 return wantarray ? ($path, $vmid, $vtype) : $path;
118 }
119
120 sub status {
121 my ($class, $storeid, $scfg, $cache) = @_;
122
123 $cache->{mountdata} = read_proc_mounts() if !$cache->{mountdata};
124
125 my $path = $scfg->{path};
126 my $server = $scfg->{server} ? $scfg->{server} : 'localhost';
127
128 my $volume = $scfg->{volume};
129
130 return undef if !glusterfs_is_mounted($server, $volume, $path, $cache->{mountdata});
131
132 return $class->SUPER::status($storeid, $scfg, $cache);
133 }
134
135 sub activate_storage {
136 my ($class, $storeid, $scfg, $cache) = @_;
137
138 $cache->{mountdata} = read_proc_mounts() if !$cache->{mountdata};
139
140 my $path = $scfg->{path};
141 my $server = $scfg->{server} ? $scfg->{server} : 'localhost';
142 my $volume = $scfg->{volume};
143
144 if (!glusterfs_is_mounted($server, $volume, $path, $cache->{mountdata})) {
145
146 mkpath $path;
147
148 die "unable to activate storage '$storeid' - " .
149 "directory '$path' does not exist\n" if ! -d $path;
150
151 glusterfs_mount($server, $volume, $path, $scfg->{options});
152 }
153
154 $class->SUPER::activate_storage($storeid, $scfg, $cache);
155 }
156
157 sub deactivate_storage {
158 my ($class, $storeid, $scfg, $cache) = @_;
159
160 $cache->{mountdata} = read_proc_mounts() if !$cache->{mountdata};
161
162 my $path = $scfg->{path};
163 my $server = $scfg->{server} ? $scfg->{server} : 'localhost';
164 my $volume = $scfg->{volume};
165
166 if (glusterfs_is_mounted($server, $volume, $path, $cache->{mountdata})) {
167 my $cmd = ['/bin/umount', $path];
168 run_command($cmd, errmsg => 'umount error');
169 }
170 }
171
172 sub activate_volume {
173 my ($class, $storeid, $scfg, $volname, $exclusive, $cache) = @_;
174
175 # do nothing by default
176 }
177
178 sub deactivate_volume {
179 my ($class, $storeid, $scfg, $volname, $cache) = @_;
180
181 # do nothing by default
182 }
183
184 sub check_connection {
185 my ($class, $storeid, $scfg) = @_;
186
187 my $server = $scfg->{server} ? $scfg->{server} : 'localhost';
188 my $volume = $scfg->{volume};
189
190 my $status = 0;
191
192 if($server && $server ne 'localhost' && $server ne '127.0.0.1'){
193 my $p = Net::Ping->new("tcp", 2);
194 $status = $p->ping($server);
195
196 }else{
197
198 my $parser = sub {
199 my $line = shift;
200
201 if ($line =~ m/Status: Started$/) {
202 $status = 1;
203 }
204 };
205
206 my $cmd = ['/usr/sbin/gluster', 'volume', 'info', $volume];
207
208 run_command($cmd, errmsg => "glusterfs error", errfunc => sub {}, outfunc => $parser);
209 }
210
211 return $status;
212 }
213
214 1;