1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2012 Pedro Navarro Perez
6
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7
# not use this file except in compliance with the License. You may obtain
8
# a copy of the License at
10
# http://www.apache.org/licenses/LICENSE-2.0
12
# Unless required by applicable law or agreed to in writing, software
13
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
# License for the specific language governing permissions and limitations
18
Volume driver for Windows Server 2012
20
This driver requires ISCSI target role installed
26
from cinder import exception
27
from cinder import flags
28
from cinder.openstack.common import cfg
29
from cinder.openstack.common import log as logging
30
from cinder.volume import driver
32
# Check needed for unit testing on Unix
37
LOG = logging.getLogger(__name__)
42
cfg.StrOpt('windows_iscsi_lun_path',
43
default='C:\iSCSIVirtualDisks',
44
help='Path to store VHD backed volumes'),
47
FLAGS.register_opts(windows_opts)
50
class WindowsDriver(driver.ISCSIDriver):
51
"""Executes volume driver commands on Windows Storage server."""
54
super(WindowsDriver, self).__init__()
56
def do_setup(self, context):
57
"""Setup the Windows Volume driver.
59
Called one time by the manager after the driver is loaded.
60
Validate the flags we care about
63
self._conn_wmi = wmi.WMI(moniker='//./root/wmi')
64
self._conn_cimv2 = wmi.WMI(moniker='//./root/cimv2')
66
def check_for_setup_error(self):
67
"""Check that the driver is working and can communicate.
69
#Invoking the portal an checking that is listening
70
wt_portal = self._conn_wmi.WT_Portal()[0]
71
listen = wt_portal.Listen
73
raise exception.VolumeBackendAPIException()
75
def initialize_connection(self, volume, connector):
76
"""Driver entry point to attach a volume to an instance.
78
initiator_name = connector['initiator']
79
target_name = volume['provider_location']
81
cl = self._conn_wmi.__getattr__("WT_IDMethod")
82
wt_idmethod = cl.new()
83
wt_idmethod.HostName = target_name
84
wt_idmethod.Method = 4
85
wt_idmethod.Value = initiator_name
87
#Getting the portal and port information
88
wt_portal = self._conn_wmi.WT_Portal()[0]
89
(address, port) = (wt_portal.Address, wt_portal.Port)
90
#Getting the host information
91
hosts = self._conn_wmi.WT_Host(Hostname=target_name)
95
properties['target_discovered'] = False
96
properties['target_portal'] = '%s:%s' % (address, port)
97
properties['target_iqn'] = host.TargetIQN
98
properties['target_lun'] = 0
99
properties['volume_id'] = volume['id']
101
auth = volume['provider_auth']
103
(auth_method, auth_username, auth_secret) = auth.split()
105
properties['auth_method'] = auth_method
106
properties['auth_username'] = auth_username
107
properties['auth_password'] = auth_secret
110
'driver_volume_type': 'iscsi',
114
def terminate_connection(self, volume, connector, **kwargs):
115
"""Driver entry point to unattach a volume from an instance.
117
Unmask the LUN on the storage system so the given intiator can no
120
initiator_name = connector['initiator']
121
#DesAssigning target to initiators
122
wt_idmethod = self._conn_wmi.WT_IDMethod(HostName=volume['name'],
124
Value=initiator_name)
125
wt_idmethod.Delete_()
127
def create_volume(self, volume):
128
"""Driver entry point for creating a new volume."""
129
vhd_path = self._get_vhd_path(volume)
130
vol_name = volume['name']
131
#The WMI procedure returns a Generic failure
132
cl = self._conn_wmi.__getattr__("WT_Disk")
133
cl.NewWTDisk(DevicePath=vhd_path,
134
Description=vol_name,
135
SizeInMB=volume['size'] * 1024)
137
def _get_vhd_path(self, volume):
138
base_vhd_folder = FLAGS.windows_iscsi_lun_path
139
if not os.path.exists(base_vhd_folder):
140
LOG.debug(_('Creating folder %s '), base_vhd_folder)
141
os.makedirs(base_vhd_folder)
142
return os.path.join(base_vhd_folder, str(volume['name']) + ".vhd")
144
def delete_volume(self, volume):
145
"""Driver entry point for destroying existing volumes."""
146
vol_name = volume['name']
147
wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0]
149
vhdfiles = self._conn_cimv2.query(
150
"Select * from CIM_DataFile where Name = '" +
151
self._get_vhd_path(volume) + "'")
152
if len(vhdfiles) > 0:
155
def create_snapshot(self, snapshot):
156
"""Driver entry point for creating a snapshot.
158
#Getting WT_Snapshot class
159
vol_name = snapshot['volume_name']
160
snapshot_name = snapshot['name']
162
wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0]
163
#API Calls gets Generic Failure
164
cl = self._conn_wmi.__getattr__("WT_Snapshot")
165
disk_id = wt_disk.WTD
166
out = cl.Create(WTD=disk_id)
167
#Setting description since it used as a KEY
168
wt_snapshot_created = self._conn_wmi.WT_Snapshot(Id=out[0])[0]
169
wt_snapshot_created.Description = snapshot_name
170
wt_snapshot_created.put()
172
def create_volume_from_snapshot(self, volume, snapshot):
173
"""Driver entry point for exporting snapshots as volumes."""
174
snapshot_name = snapshot['name']
175
wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snapshot_name)[0]
176
disk_id = wt_snapshot.Export()[0]
177
wt_disk = self._conn_wmi.WT_Disk(WTD=disk_id)[0]
178
wt_disk.Description = volume['name']
181
def delete_snapshot(self, snapshot):
182
"""Driver entry point for deleting a snapshot."""
183
snapshot_name = snapshot['name']
184
wt_snapshot = self._conn_wmi.WT_Snapshot(Description=snapshot_name)[0]
185
wt_snapshot.Delete_()
187
def _do_export(self, _ctx, volume, ensure=False):
188
"""Do all steps to get disk exported as LUN 0 at separate target.
190
:param volume: reference of volume to be exported
191
:param ensure: if True, ignore errors caused by already existing
193
:return: iscsiadm-formatted provider location string
195
target_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name'])
196
#ISCSI target creation
198
cl = self._conn_wmi.__getattr__("WT_Host")
199
cl.NewHost(HostName=target_name)
200
except Exception as exc:
201
excep_info = exc.com_error.excepinfo[2]
202
if not ensure or excep_info.find(u'The file exists') == -1:
205
LOG.info(_('Ignored target creation error "%s"'
206
' while ensuring export'), exc)
208
vol_name = volume['name']
209
wt_disk = self._conn_wmi.WT_Disk(Description=vol_name)[0]
210
wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0]
211
wt_host.AddWTDisk(wt_disk.WTD)
215
def ensure_export(self, context, volume):
216
"""Driver entry point to get the export info for an existing volume."""
217
self._do_export(context, volume, ensure=True)
219
def create_export(self, context, volume):
220
"""Driver entry point to get the export info for a new volume."""
221
loc = self._do_export(context, volume, ensure=False)
222
return {'provider_location': loc}
224
def remove_export(self, context, volume):
225
"""Driver exntry point to remove an export for a volume.
227
target_name = "%s%s" % (FLAGS.iscsi_target_prefix, volume['name'])
230
wt_host = self._conn_wmi.WT_Host(HostName=target_name)[0]
231
wt_host.RemoveAllWTDisks()