Files
pve-storage/PVE/Storage/CIFSPlugin.pm
Wolfgang Link 4792d439ad Add CIFS Storage Plugin.
This Plugin use as template the NFSpluigin.
We do only support smbversion 2 and 3.
Version 3 is default and must override through the config.
2018-03-16 11:57:57 +01:00

216 lines
4.9 KiB
Perl

package PVE::Storage::CIFSPlugin;
use strict;
use warnings;
use Net::IP;
use PVE::Tools qw(run_command);
use PVE::ProcFSTools;
use File::Path;
use PVE::Storage::Plugin;
use PVE::JSONSchema qw(get_standard_option);
use base qw(PVE::Storage::Plugin);
# CIFS helper functions
sub cifs_is_mounted {
my ($server, $share, $mountpoint, $mountdata) = @_;
$server = "[$server]" if Net::IP::ip_is_ipv6($server);
my $source = "//${server}/$share";
$mountdata = PVE::ProcFSTools::parse_proc_mounts() if !$mountdata;
return $mountpoint if grep {
$_->[2] =~ /^cifs/ &&
$_->[0] =~ m|^\Q$source\E/?$| &&
$_->[1] eq $mountpoint
} @$mountdata;
return undef;
}
sub get_cred_file {
my ($storeid) = @_;
my $cred_file = '/etc/pve/priv/'.$storeid.'.cred';
if (-e $cred_file) {
return $cred_file;
}
return undef;
}
sub cifs_mount {
my ($server, $share, $mountpoint, $storeid, $smbver, $user, $domain) = @_;
$server = "[$server]" if Net::IP::ip_is_ipv6($server);
my $source = "//${server}/$share";
my $cmd = ['/bin/mount', '-t', 'cifs', $source, $mountpoint, '-o', 'soft', '-o'];
if (my $cred_file = get_cred_file($storeid)) {
push @$cmd, "username=$user", '-o', "credentials=$cred_file";
push @$cmd, '-o', "domain=$domain" if defined($domain);
} else {
push @$cmd, 'guest,username=guest';
}
push @$cmd, '-o', defined($smbver) ? "vers=$smbver" : "vers=3.0";
run_command($cmd, errmsg => "mount error");
}
# Configuration
sub type {
return 'cifs';
}
sub plugindata {
return {
content => [ { images => 1, rootdir => 1, vztmpl => 1, iso => 1,
backup => 1}, { images => 1 }],
format => [ { raw => 1, qcow2 => 1, vmdk => 1 } , 'raw' ],
};
}
sub properties {
return {
share => {
description => "CIFS share.",
type => 'string',
},
password => {
description => "Password for CIFS share.",
type => 'string',
maxLength => 256,
},
domain => {
description => "CIFS domain.",
type => 'string',
optional => 1,
maxLength => 256,
},
smbversion => {
description => "",
type => 'string',
optional => 1,
},
};
}
sub options {
return {
path => { fixed => 1 },
server => { fixed => 1 },
share => { fixed => 1 },
nodes => { optional => 1 },
disable => { optional => 1 },
maxfiles => { optional => 1 },
content => { optional => 1 },
format => { optional => 1 },
username => { optional => 1 },
password => { optional => 1},
domain => { optional => 1},
smbversion => { optional => 1},
};
}
sub check_config {
my ($class, $sectionId, $config, $create, $skipSchemaCheck) = @_;
$config->{path} = "/mnt/pve/$sectionId" if $create && !$config->{path};
return $class->SUPER::check_config($sectionId, $config, $create, $skipSchemaCheck);
}
# Storage implementation
sub status {
my ($class, $storeid, $scfg, $cache) = @_;
$cache->{mountdata} = PVE::ProcFSTools::parse_proc_mounts()
if !$cache->{mountdata};
my $path = $scfg->{path};
my $server = $scfg->{server};
my $share = $scfg->{share};
return undef
if !cifs_is_mounted($server, $share, $path, $cache->{mountdata});
return $class->SUPER::status($storeid, $scfg, $cache);
}
sub activate_storage {
my ($class, $storeid, $scfg, $cache) = @_;
$cache->{mountdata} = PVE::ProcFSTools::parse_proc_mounts()
if !$cache->{mountdata};
my $path = $scfg->{path};
my $server = $scfg->{server};
my $share = $scfg->{share};
if (!cifs_is_mounted($server, $share, $path, $cache->{mountdata})) {
mkpath $path;
die "unable to activate storage '$storeid' - " .
"directory '$path' does not exist\n" if ! -d $path;
cifs_mount($server, $share, $path, $storeid, $scfg->{smbversion},
$scfg->{username}, $scfg->{domain});
}
$class->SUPER::activate_storage($storeid, $scfg, $cache);
}
sub deactivate_storage {
my ($class, $storeid, $scfg, $cache) = @_;
$cache->{mountdata} = PVE::ProcFSTools::parse_proc_mounts()
if !$cache->{mountdata};
my $path = $scfg->{path};
my $server = $scfg->{server};
my $share = $scfg->{share};
if (cifs_is_mounted($server, $share, $path, $cache->{mountdata})) {
my $cmd = ['/bin/umount', $path];
run_command($cmd, errmsg => 'umount error');
}
}
sub check_connection {
my ($class, $storeid, $scfg) = @_;
my $server = $scfg->{server};
my $cmd = ['/usr/bin/smbclient', '-L', $server, '-d', '0', '-m'];
push @$cmd, $scfg->{smbversion} ? "smb".int($scfg->{smbversion}) : 'smb3';
if (my $cred_file = get_cred_file($storeid)) {
push @$cmd, '-U', $scfg->{username}, '-A', $cred_file;
push @$cmd, '-W', $scfg->{domain} if defined($scfg->{domain});
} else {
push @$cmd, '-U', 'Guest','-N';
}
my $out_str;
eval {
run_command($cmd, timeout => 2, outfunc => sub {$out_str .= shift;},
errfunc => sub {});
};
if (my $err = $@) {
die "$out_str\n" if ($out_str =~ m/NT_STATUS_ACCESS_DENIED/);
return 0;
}
return 1;
}
1;