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