1
+ #!/usr/bin/python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # Copyright: (c) 2018, Ansible Project
5
+ # Copyright: (c) 2023, Pure Storage, Inc.
6
+ # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
7
+ # SPDX-License-Identifier: GPL-3.0-or-later
8
+
9
+ from __future__ import absolute_import , division , print_function
10
+ __metaclass__ = type
11
+
12
+
13
+ DOCUMENTATION = r'''
14
+ ---
15
+ module: vmware_host_disk
16
+ short_description: Attach or detach disks from an esxi host
17
+ description:
18
+ - This module can be used to attach / detach disks on an ESXi host.
19
+ author:
20
+ - Ryan BADAÏ (@ryanb74) <[email protected] >
21
+ options:
22
+ uuid:
23
+ description:
24
+ - uuid of the disk to attach / detach.
25
+ - Can be obtained using community.vmware.vmware_host_scsidisk_info module.
26
+ required: true
27
+ type: str
28
+ esxi_hostname:
29
+ description:
30
+ - Name of the ESXi host on which the operation is performed.
31
+ - Required when used with a vcenter
32
+ type: str
33
+ required: false
34
+ state:
35
+ description:
36
+ - "attached: Attach disk on esxi host if it is not attached, else do nothing."
37
+ - "detached: Detach disk on esxi host if it is attached, else do nothing."
38
+ default: attached
39
+ choices: [ attached, detached ]
40
+ type: str
41
+ seealso:
42
+ - VMware vSphere API Reference Documentation : https://vdc-repo.vmware.com/vmwb-repository/dcr-public/1ef6c336-7bef-477d-b9bb-caa1767d7e30/82521f49-9d9a-42b7-b19b-9e6cd9b30db1/right-pane.html
43
+ extends_documentation_fragment:
44
+ - community.vmware.vmware.documentation
45
+ '''
46
+
47
+ EXAMPLES = r'''
48
+ - name: Attach disk on esxi host
49
+ vmware_host_disk:
50
+ hostname: "{{ vcenter_hostname }}"
51
+ esxi_hostname: "{{ esxi_hostname }}"
52
+ uuid: "{{ disk_uuid }}"
53
+ state: attached
54
+ username: '{{ vcenter_username }}'
55
+ password: '{{ vcenter_password }}'
56
+ '''
57
+
58
+ RETURN = r'''
59
+ result:
60
+ description: A string that describes whether the mount/unmount was successfully performed.
61
+ returned: success or changed
62
+ type: str
63
+ sample:
64
+ - Disk with uuid 020001000060060e8008783a000050783a000000164f50454e2d56 is already attached.
65
+ - Disk with uuid 020001000060060e8008783a000050783a000000164f50454e2d56 was successfully detached.
66
+ - Disk with uuid 020001000060060e8008783a000050783a000000164f50454e2d56 is already detached.
67
+ - Disk with uuid 020001000060060e8008783a000050783a000000164f50454e2d56 was successfully attached.
68
+ - Disk with uuid FAKE_UUID was not found !
69
+ '''
70
+
71
+ try :
72
+ from pyVmomi import vim , vmodl
73
+ except ImportError :
74
+ pass
75
+
76
+ from ansible .module_utils .basic import AnsibleModule
77
+ from ansible_collections .community .vmware .plugins .module_utils .vmware import vmware_argument_spec , find_obj
78
+ from ansible_collections .community .vmware .plugins .module_utils .vmware_sms import SMS
79
+ from ansible .module_utils ._text import to_native
80
+
81
+
82
+ class VMwareHostDisk (SMS ):
83
+ def __init__ (self , module ):
84
+ super (VMwareHostDisk , self ).__init__ (module )
85
+
86
+ self .uuid = module .params ['uuid' ]
87
+ self .esxi_hostname = module .params ['esxi_hostname' ]
88
+ self .state = module .params ['state' ]
89
+
90
+ if self .is_vcenter ():
91
+ if not self .esxi_hostname :
92
+ self .module .fail_json (msg = "esxi_hostname is mandatory with a vcenter" )
93
+ self .esxi = self .find_hostsystem_by_name (self .esxi_hostname )
94
+ if self .esxi is None :
95
+ self .module .fail_json (msg = "Failed to find ESXi hostname %s" % self .esxi_hostname )
96
+ else :
97
+ self .esxi = find_obj (self .content , [vim .HostSystem ], None )
98
+
99
+ def process_state (self ):
100
+ """Evaluates what must be done based on current state"""
101
+ ds_states = {
102
+ 'detached' : {
103
+ 'attached' : self .detach_disk_from_host ,
104
+ 'detached' : lambda : self .module .exit_json (changed = False , result = "Disk with uuid %s is already detached." % self .uuid )
105
+ },
106
+ 'attached' : {
107
+ 'attached' : lambda : self .module .exit_json (changed = False , result = "Disk with uuid %s is already attached." % self .uuid ),
108
+ 'detached' : self .attach_disk_to_host
109
+ }
110
+ }
111
+ try :
112
+ ds_states [self .state ][self .get_disk_attachment_state ()]()
113
+ except (vmodl .RuntimeFault , vmodl .MethodFault ) as vmodl_fault :
114
+ self .module .fail_json (msg = to_native (vmodl_fault .msg ))
115
+ except Exception as e :
116
+ self .module .fail_json (msg = to_native (e ))
117
+
118
+ def get_disk_attachment_state (self ):
119
+ """Checks whether the disk is attached or not.
120
+ :return: Current attachment state of the disk: "attached" or "detached"
121
+ :rtype: string
122
+ """
123
+ storage_system = self .esxi .configManager .storageSystem # VMware docs : https://vdc-repo.vmware.com/vmwb-repository/dcr-public/1ef6c336-7bef-477d-b9bb-caa1767d7e30/82521f49-9d9a-42b7-b19b-9e6cd9b30db1/vim.host.StorageSystem.html
124
+
125
+ for disk in storage_system .storageDeviceInfo .scsiLun : # VMware docs : https://vdc-repo.vmware.com/vmwb-repository/dcr-public/1ef6c336-7bef-477d-b9bb-caa1767d7e30/82521f49-9d9a-42b7-b19b-9e6cd9b30db1/vim.host.ScsiLun.html
126
+ if disk .uuid == self .uuid :
127
+ if "ok" in disk .operationalState : # https://vdc-repo.vmware.com/vmwb-repository/dcr-public/1ef6c336-7bef-477d-b9bb-caa1767d7e30/82521f49-9d9a-42b7-b19b-9e6cd9b30db1/vim.host.ScsiLun.State.html
128
+ return "attached"
129
+ elif "off" in disk .operationalState :
130
+ return "detached"
131
+ self .module .fail_json (msg = 'Disk is in an unexpected state !{} ' % disk .operationalState )
132
+
133
+ self .module .fail_json (msg = 'Disk with uuid %s was not found !' % self .uuid )
134
+
135
+
136
+ def detach_disk_from_host (self ):
137
+ if self .module .check_mode is False :
138
+ try :
139
+ self .esxi .configManager .storageSystem .DetachScsiLun (self .uuid )
140
+ self .module .exit_json (changed = True , result = "Disk with uuid %s was successfully detached." % self .uuid )
141
+
142
+ except vim .fault .ResourceInUse as e :
143
+ self .module .fail_json (msg = 'Disk with uuid {} is currently used and can\' t be detached ! {}' % self .uuid % e )
144
+ except vim .fault .VimFault as e :
145
+ self .module .fail_json (msg = 'Disk with uuid {} can\' t be detached because of an unexpected error ! {}' % self .uuid % e )
146
+ self .module .exit_json (changed = True , result = "CHECK MODE: Disk with uuid %s would be successfully detached." % self .uuid )
147
+
148
+
149
+ def attach_disk_to_host (self ):
150
+ if self .module .check_mode is False :
151
+ try :
152
+ self .esxi .configManager .storageSystem .AttachScsiLun (self .uuid )
153
+ self .module .exit_json (changed = True , result = "Disk with uuid %s was successfully attached." % self .uuid )
154
+ except vim .fault .VimFault as e :
155
+ self .module .fail_json (msg = 'Disk with uuid {} can\' t be attached because of an unexpected error ! {}' % self .uuid % e )
156
+ self .module .exit_json (changed = True , result = "CHECK MODE: disk with uuid %s would be successfully attached." % self .uuid )
157
+
158
+ def main ():
159
+ argument_spec = vmware_argument_spec ()
160
+ argument_spec .update (
161
+ uuid = dict (type = 'str' , required = True ),
162
+ esxi_hostname = dict (type = 'str' , required = False ),
163
+ state = dict (type = 'str' , default = 'attached' , choices = ['detached' , 'attached' ])
164
+ )
165
+
166
+ module = AnsibleModule (
167
+ argument_spec = argument_spec ,
168
+ supports_check_mode = True
169
+ )
170
+
171
+ vmware_host_datastore = VMwareHostDisk (module )
172
+ vmware_host_datastore .process_state ()
173
+
174
+
175
+ if __name__ == '__main__' :
176
+ main ()
0 commit comments