]> git.proxmox.com Git - pve-storage.git/blame - PVE/Storage/NFSPlugin.pm
NFSPlugin: deal with ipv6 addresses and fix regexps
[pve-storage.git] / PVE / Storage / NFSPlugin.pm
CommitLineData
1dc01b9f
DM
1package PVE::Storage::NFSPlugin;
2
3use strict;
4use warnings;
5use IO::File;
da63f588 6use Net::IP;
d9e4e1ce 7use File::Path;
be2e0c16 8use PVE::Tools qw(run_command);
1dc01b9f
DM
9use PVE::Storage::Plugin;
10use PVE::JSONSchema qw(get_standard_option);
11
12use base qw(PVE::Storage::Plugin);
13
14# NFS helper functions
15
16sub 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
29sub nfs_is_mounted {
30 my ($server, $export, $mountpoint, $mountdata) = @_;
31
da63f588 32 $server = "[$server]" if Net::IP::ip_is_ipv6($server);
1dc01b9f
DM
33 my $source = "$server:$export";
34
35 $mountdata = read_proc_mounts() if !$mountdata;
36
da63f588 37 if ($mountdata =~ m|^\Q$source\E/?\s\Q$mountpoint\E\snfs|m) {
1dc01b9f
DM
38 return $mountpoint;
39 }
40
41 return undef;
42}
43
44sub nfs_mount {
45 my ($server, $export, $mountpoint, $options) = @_;
46
da63f588 47 $server = "[$server]" if Net::IP::ip_is_ipv6($server);
1dc01b9f
DM
48 my $source = "$server:$export";
49
50 my $cmd = ['/bin/mount', '-t', 'nfs', $source, $mountpoint];
51 if ($options) {
52 push @$cmd, '-o', $options;
53 }
54
55 run_command($cmd, errmsg => "mount error");
56}
57
58# Configuration
59
60sub type {
61 return 'nfs';
62}
63
64sub plugindata {
65 return {
66 content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1, backup => 1},
67 { images => 1 }],
68 format => [ { raw => 1, qcow2 => 1, vmdk => 1 } , 'raw' ],
69 };
70}
71
72sub properties {
73 return {
74 export => {
75 description => "NFS export path.",
76 type => 'string', format => 'pve-storage-path',
77 },
78 server => {
79 description => "Server IP or DNS name.",
80 type => 'string', format => 'pve-storage-server',
81 },
82 options => {
83 description => "NFS mount options (see 'man nfs')",
84 type => 'string', format => 'pve-storage-options',
85 },
86 };
87}
88
89sub options {
90 return {
91 path => { fixed => 1 },
92 server => { fixed => 1 },
93 export => { fixed => 1 },
94 nodes => { optional => 1 },
95 disable => { optional => 1 },
96 maxfiles => { optional => 1 },
97 options => { optional => 1 },
98 content => { optional => 1 },
99 format => { optional => 1 },
100 };
101}
102
103
104sub check_config {
105 my ($class, $sectionId, $config, $create, $skipSchemaCheck) = @_;
106
107 $config->{path} = "/mnt/pve/$sectionId" if $create && !$config->{path};
108
109 return $class->SUPER::check_config($sectionId, $config, $create, $skipSchemaCheck);
110}
111
112# Storage implementation
113
114sub status {
115 my ($class, $storeid, $scfg, $cache) = @_;
116
117 $cache->{mountdata} = read_proc_mounts() if !$cache->{mountdata};
118
119 my $path = $scfg->{path};
120 my $server = $scfg->{server};
121 my $export = $scfg->{export};
122
123 return undef if !nfs_is_mounted($server, $export, $path, $cache->{mountdata});
124
125 return $class->SUPER::status($storeid, $scfg, $cache);
126}
127
128sub activate_storage {
129 my ($class, $storeid, $scfg, $cache) = @_;
130
131 $cache->{mountdata} = read_proc_mounts() if !$cache->{mountdata};
132
133 my $path = $scfg->{path};
134 my $server = $scfg->{server};
135 my $export = $scfg->{export};
136
137 if (!nfs_is_mounted($server, $export, $path, $cache->{mountdata})) {
138
139 # NOTE: only call mkpath when not mounted (avoid hang
140 # when NFS server is offline
141
142 mkpath $path;
143
144 die "unable to activate storage '$storeid' - " .
145 "directory '$path' does not exist\n" if ! -d $path;
146
147 nfs_mount($server, $export, $path, $scfg->{options});
148 }
149
150 $class->SUPER::activate_storage($storeid, $scfg, $cache);
151}
152
153sub deactivate_storage {
154 my ($class, $storeid, $scfg, $cache) = @_;
155
156 $cache->{mountdata} = read_proc_mounts() if !$cache->{mountdata};
157
158 my $path = $scfg->{path};
159 my $server = $scfg->{server};
160 my $export = $scfg->{export};
161
162 if (nfs_is_mounted($server, $export, $path, $cache->{mountdata})) {
163 my $cmd = ['/bin/umount', $path];
164 run_command($cmd, errmsg => 'umount error');
165 }
166}
167
4d284721
AD
168sub check_connection {
169 my ($class, $storeid, $scfg) = @_;
170
171 my $server = $scfg->{server};
4d284721 172
86a9a680 173 # test connection to portmapper
37121146 174 my $cmd = ['/usr/sbin/rpcinfo', '-p', $server];
86a9a680
DM
175
176 eval {
177 run_command($cmd, timeout => 2, outfunc => sub {}, errfunc => sub {});
178 };
179 if (my $err = $@) {
180 return 0;
181 }
182
183 return 1;
4d284721 184}
86a9a680 185
1dc01b9f 1861;