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