@ -19,14 +19,17 @@ module: vmware_host_datastore
short_description : Manage a datastore on ESXi host
description :
- This module can be used to mount / umount datastore on ESXi host .
- This module only support NFS / VMFS type of datastores .
- This module only support s NFS ( NFS v3 or NFS v4 .1 ) and VMFS datastores .
- For VMFS datastore , available device must already be connected on ESXi host .
- All parameters and VMware object names are case sensitive .
version_added : ' 2.5 '
author :
- Ludovic Rivallain ( @lrivallain ) < ludovic . rivallain @gmail.com >
- Christian Kotte ( @ckotte ) < christian . kotte @gmx.de >
notes :
- Tested on vSphere 6.0 and 6.5
- NFS v4 .1 tested on vSphere 6.5
- Kerberos authentication with NFS v4 .1 isn ' t implemented
requirements :
- python > = 2.6
- PyVmomi
@ -41,21 +44,22 @@ options:
required : true
datastore_type :
description :
- Type of the datastore to configure ( nfs / vmfs) .
- Type of the datastore to configure ( nfs / nfs41/ vmfs) .
required : true
choices : [ ' nfs ' , ' vmfs' ]
choices : [ ' nfs ' , ' nfs41' , ' vmfs' ]
nfs_server :
description :
- NFS host serving nfs datastore .
- Required if datastore type is set to C ( nfs ) and state is set to C ( present ) , else unused .
- Required if datastore type is set to C ( nfs ) / C ( nfs41 ) and state is set to C ( present ) , else unused .
- Two or more servers can be defined if datastore type is set to C ( nfs41 )
nfs_path :
description :
- Resource path on NFS host .
- Required if datastore type is set to C ( nfs ) and state is set to C ( present ) , else unused .
- Required if datastore type is set to C ( nfs ) / C ( nfs41 ) and state is set to C ( present ) , else unused .
nfs_ro :
description :
- ReadOnly or ReadWrite mount .
- Unused if datastore type is not set to C ( nfs ) and state is not set to C ( present ) .
- Unused if datastore type is not set to C ( nfs ) / C ( nfs41 ) and state is not set to C ( present ) .
default : False
type : bool
vmfs_device_name :
@ -112,6 +116,24 @@ EXAMPLES = r'''
- { ' name ' : ' NasDS_vol01 ' , ' server ' : ' nas01 ' , ' path ' : ' /mnt/vol01 ' , ' type ' : ' nfs ' }
- { ' name ' : ' NasDS_vol02 ' , ' server ' : ' nas01 ' , ' path ' : ' /mnt/vol02 ' , ' type ' : ' nfs ' }
- name : Mount NFS v4 .1 datastores to ESXi
vmware_host_datastore :
hostname : ' {{ vcenter_hostname }} '
username : ' {{ vcenter_username }} '
password : ' {{ vcenter_password }} '
datacenter_name : ' {{ datacenter }} '
datastore_name : ' {{ item.name }} '
datastore_type : ' {{ item.type }} '
nfs_server : ' {{ item.server }} '
nfs_path : ' {{ item.path }} '
nfs_ro : no
esxi_hostname : ' {{ inventory_hostname }} '
state : present
delegate_to : localhost
with_items :
- { ' name ' : ' NasDS_vol03 ' , ' server ' : ' nas01,nas02 ' , ' path ' : ' /mnt/vol01 ' , ' type ' : ' nfs41 ' }
- { ' name ' : ' NasDS_vol04 ' , ' server ' : ' nas01,nas02 ' , ' path ' : ' /mnt/vol02 ' , ' type ' : ' nfs41 ' }
- name : Remove / Umount Datastores from ESXi
vmware_host_datastore :
hostname : ' {{ vcenter_hostname }} '
@ -189,61 +211,73 @@ class VMwareHostDatastore(PyVmomi):
ds = find_datastore_by_name ( self . content , self . datastore_name )
if not ds :
self . module . fail_json ( msg = " No datastore found with name %s " % self . datastore_name )
error_message_umount = " Cannot umount datastore %s from host %s " % ( self . datastore_name , self . esxi_hostname )
try :
self . esxi . configManager . datastoreSystem . RemoveDatastore ( ds )
except ( vim . fault . NotFound , vim . fault . HostConfigFault , vim . fault . ResourceInUse ) as fault :
self . module . fail_json ( msg = " %s : %s " % ( error_message_umount , to_native ( fault . msg ) ) )
except Exception as e :
self . module . fail_json ( msg = " %s : %s " % ( error_message_umount , to_native ( e ) ) )
if self . module . check_mode is False :
error_message_umount = " Cannot umount datastore %s from host %s " % ( self . datastore_name , self . esxi_hostname )
try :
self . esxi . configManager . datastoreSystem . RemoveDatastore ( ds )
except ( vim . fault . NotFound , vim . fault . HostConfigFault , vim . fault . ResourceInUse ) as fault :
self . module . fail_json ( msg = " %s : %s " % ( error_message_umount , to_native ( fault . msg ) ) )
except Exception as e :
self . module . fail_json ( msg = " %s : %s " % ( error_message_umount , to_native ( e ) ) )
self . module . exit_json ( changed = True , result = " Datastore %s on host %s " % ( self . datastore_name , self . esxi_hostname ) )
def mount_datastore_host ( self ) :
if self . datastore_type == ' nfs ' :
if self . datastore_type == ' nfs ' or self . datastore_type == ' nfs41 ' :
self . mount_nfs_datastore_host ( )
if self . datastore_type == ' vmfs ' :
self . mount_vmfs_datastore_host ( )
def mount_nfs_datastore_host ( self ) :
mnt_specs = vim . host . NasVolume . Specification ( )
mnt_specs . remoteHost = self . nfs_server
mnt_specs . remotePath = self . nfs_path
mnt_specs . localPath = self . datastore_name
if self . nfs_ro :
mnt_specs . accessMode = " readOnly "
else :
mnt_specs . accessMode = " readWrite "
error_message_mount = " Cannot mount datastore %s on host %s " % ( self . datastore_name , self . esxi_hostname )
try :
ds = self . esxi . configManager . datastoreSystem . CreateNasDatastore ( mnt_specs )
if not ds :
self . module . fail_json ( msg = error_message_mount )
except ( vim . fault . NotFound , vim . fault . DuplicateName ,
vim . fault . AlreadyExists , vim . fault . HostConfigFault ,
vmodl . fault . InvalidArgument , vim . fault . NoVirtualNic ,
vim . fault . NoGateway ) as fault :
self . module . fail_json ( msg = " %s : %s " % ( error_message_mount , to_native ( fault . msg ) ) )
except Exception as e :
self . module . fail_json ( msg = " %s : %s " % ( error_message_mount , to_native ( e ) ) )
if self . module . check_mode is False :
mnt_specs = vim . host . NasVolume . Specification ( )
# NFS v3
if self . datastore_type == ' nfs ' :
mnt_specs . type = " NFS "
mnt_specs . remoteHost = self . nfs_server
# NFS v4.1
if self . datastore_type == ' nfs41 ' :
mnt_specs . type = " NFS41 "
# remoteHost needs to be set to a non-empty string, but the value is not used
mnt_specs . remoteHost = " something "
mnt_specs . remoteHostNames = [ self . nfs_server ]
mnt_specs . remotePath = self . nfs_path
mnt_specs . localPath = self . datastore_name
if self . nfs_ro :
mnt_specs . accessMode = " readOnly "
else :
mnt_specs . accessMode = " readWrite "
error_message_mount = " Cannot mount datastore %s on host %s " % ( self . datastore_name , self . esxi_hostname )
try :
ds = self . esxi . configManager . datastoreSystem . CreateNasDatastore ( mnt_specs )
if not ds :
self . module . fail_json ( msg = error_message_mount )
except ( vim . fault . NotFound , vim . fault . DuplicateName ,
vim . fault . AlreadyExists , vim . fault . HostConfigFault ,
vmodl . fault . InvalidArgument , vim . fault . NoVirtualNic ,
vim . fault . NoGateway ) as fault :
self . module . fail_json ( msg = " %s : %s " % ( error_message_mount , to_native ( fault . msg ) ) )
except Exception as e :
self . module . fail_json ( msg = " %s : %s " % ( error_message_mount , to_native ( e ) ) )
self . module . exit_json ( changed = True , result = " Datastore %s on host %s " % ( self . datastore_name , self . esxi_hostname ) )
def mount_vmfs_datastore_host ( self ) :
ds_path = " /vmfs/devices/disks/ " + str ( self . vmfs_device_name )
host_ds_system = self . esxi . configManager . datastoreSystem
ds_system = vim . host . DatastoreSystem
error_message_mount = " Cannot mount datastore %s on host %s " % ( self . datastore_name , self . esxi_hostname )
try :
vmfs_ds_options = ds_system . QueryVmfsDatastoreCreateOptions ( host_ds_system ,
ds_path ,
self . vmfs_version )
vmfs_ds_options [ 0 ] . spec . vmfs . volumeName = self . datastore_name
ds = ds_system . CreateVmfsDatastore ( host_ds_system ,
vmfs_ds_options [ 0 ] . spec )
except ( vim . fault . NotFound , vim . fault . DuplicateName ,
vim . fault . HostConfigFault , vmodl . fault . InvalidArgument ) as fault :
self . module . fail_json ( msg = " %s : %s " % ( error_message_mount , to_native ( fault . msg ) ) )
except Exception as e :
self . module . fail_json ( msg = " %s : %s " % ( error_message_mount , to_native ( e ) ) )
if self . module . check_mode is False :
ds_path = " /vmfs/devices/disks/ " + str ( self . vmfs_device_name )
host_ds_system = self . esxi . configManager . datastoreSystem
ds_system = vim . host . DatastoreSystem
error_message_mount = " Cannot mount datastore %s on host %s " % ( self . datastore_name , self . esxi_hostname )
try :
vmfs_ds_options = ds_system . QueryVmfsDatastoreCreateOptions ( host_ds_system ,
ds_path ,
self . vmfs_version )
vmfs_ds_options [ 0 ] . spec . vmfs . volumeName = self . datastore_name
ds = ds_system . CreateVmfsDatastore ( host_ds_system ,
vmfs_ds_options [ 0 ] . spec )
except ( vim . fault . NotFound , vim . fault . DuplicateName ,
vim . fault . HostConfigFault , vmodl . fault . InvalidArgument ) as fault :
self . module . fail_json ( msg = " %s : %s " % ( error_message_mount , to_native ( fault . msg ) ) )
except Exception as e :
self . module . fail_json ( msg = " %s : %s " % ( error_message_mount , to_native ( e ) ) )
self . module . exit_json ( changed = True , result = " Datastore %s on host %s " % ( self . datastore_name , self . esxi_hostname ) )
@ -252,7 +286,7 @@ def main():
argument_spec . update (
datacenter_name = dict ( type = ' str ' , required = True ) ,
datastore_name = dict ( type = ' str ' , required = True ) ,
datastore_type = dict ( type = ' str ' , choices = [ ' nfs ' , ' vmfs' ] ) ,
datastore_type = dict ( type = ' str ' , choices = [ ' nfs ' , ' nfs41' , ' vmfs' ] ) ,
nfs_server = dict ( type = ' str ' ) ,
nfs_path = dict ( type = ' str ' ) ,
nfs_ro = dict ( type = ' bool ' , default = False ) ,
@ -276,6 +310,10 @@ def main():
msg = " Missing nfs_server with datastore_type = nfs "
module . fail_json ( msg = msg )
if module . params [ ' datastore_type ' ] == ' nfs41 ' and not module . params [ ' nfs_server ' ] :
msg = " Missing nfs_server with datastore_type = nfs41 "
module . fail_json ( msg = msg )
if module . params [ ' datastore_type ' ] == ' vmfs ' and not module . params [ ' vmfs_device_name ' ] :
msg = " Missing vmfs_device_name with datastore_type = vmfs "
module . fail_json ( msg = msg )