Merge "Refactor Windows API usage"

This commit is contained in:
Jenkins 2017-06-22 11:33:14 +00:00 committed by Gerrit Code Review
commit ff86810181
43 changed files with 2324 additions and 1544 deletions

View File

@ -19,6 +19,8 @@ import sys
from eventlet import patcher
import pbr.version
from os_win.utils.winapi import libs as w_libs
__version__ = pbr.version.VersionInfo(
'os_win').version_string()
@ -27,3 +29,7 @@ if sys.platform == 'win32':
import wmi
# We need to make sure that WMI uses the unpatched threading module.
wmi.threading = patcher.original('threading')
# The following will set the argument and return value types for the
# foreign functions used throughout os_win using ctypes.
w_libs.register()

View File

@ -22,6 +22,9 @@ from os_win import constants
from os_win import exceptions
from os_win.tests.unit import test_base
from os_win.utils.compute import _clusapi_utils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi.libs import clusapi as clusapi_def
from os_win.utils.winapi import wintypes
@ddt.ddt
@ -83,8 +86,8 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
clusprop_val_struct = self._clusapi_utils._get_clusprop_value_struct(
val_type)
expected_fields = [('syntax', _clusapi_utils.DWORD),
('length', _clusapi_utils.DWORD),
expected_fields = [('syntax', wintypes.DWORD),
('length', wintypes.DWORD),
('value', val_type),
('_padding', ctypes.c_ubyte * expected_padding_sz)]
self.assertEqual(expected_fields, clusprop_val_struct._fields_)
@ -100,7 +103,7 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
syntax=fake_prop_syntax,
value=fake_prop_val)
self.assertEqual(_clusapi_utils.CLUSPROP_SYNTAX_NAME,
self.assertEqual(w_const.CLUSPROP_SYNTAX_NAME,
entry.name.syntax)
self.assertEqual(fake_prop_name,
entry.name.value)
@ -116,7 +119,7 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
ctypes.sizeof(fake_prop_val),
entry.value.length)
self.assertEqual(_clusapi_utils.CLUSPROP_SYNTAX_ENDMARK,
self.assertEqual(w_const.CLUSPROP_SYNTAX_ENDMARK,
entry._endmark)
def test_get_property_list(self):
@ -197,11 +200,11 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
self._clusapi.CloseClusterNode.assert_called_once_with(
mock.sentinel.handle)
@ddt.data(0, _clusapi_utils.ERROR_IO_PENDING)
@ddt.data(0, w_const.ERROR_IO_PENDING)
def test_cancel_cluster_group_operation(self, cancel_ret_val):
self._mock_run.return_value = cancel_ret_val
expected_ret_val = cancel_ret_val != _clusapi_utils.ERROR_IO_PENDING
expected_ret_val = cancel_ret_val != w_const.ERROR_IO_PENDING
ret_val = self._clusapi_utils.cancel_cluster_group_operation(
mock.sentinel.group_handle)
@ -211,7 +214,7 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
self._clusapi.CancelClusterGroupOperation,
mock.sentinel.group_handle,
0,
ignored_error_codes=[_clusapi_utils.ERROR_IO_PENDING])
ignored_error_codes=[w_const.ERROR_IO_PENDING])
@ddt.data(mock.sentinel.prop_list, None)
def test_move_cluster_group(self, prop_list):
@ -235,7 +238,7 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
mock.sentinel.move_flags,
expected_prop_list_arg,
expected_prop_list_sz,
ignored_error_codes=[_clusapi_utils.ERROR_IO_PENDING])
ignored_error_codes=[w_const.ERROR_IO_PENDING])
def test_get_cluster_group_state(self):
owner_node = 'fake owner node'
@ -257,15 +260,15 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
node_name_len_arg = ctypes.cast(
node_name_len,
ctypes.POINTER(_clusapi_utils.DWORD)).contents
self.assertEqual(self._clusapi_utils._MAX_NODE_NAME,
wintypes.PDWORD).contents
self.assertEqual(w_const.MAX_PATH,
node_name_len_arg.value)
node_name_arg = ctypes.cast(
node_name_buff,
ctypes.POINTER(
ctypes.c_wchar *
self._clusapi_utils._MAX_NODE_NAME)).contents
w_const.MAX_PATH)).contents
node_name_arg.value = owner_node
return mock.sentinel.group_state
@ -277,9 +280,9 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
owner_node=owner_node)
self.assertEqual(expected_state_info, state_info)
@ddt.data({'notif_filters': (_clusapi_utils.NOTIFY_FILTER_AND_TYPE * 2)(),
@ddt.data({'notif_filters': (clusapi_def.NOTIFY_FILTER_AND_TYPE * 2)(),
'exp_notif_filters_len': 2},
{'notif_filters': _clusapi_utils.NOTIFY_FILTER_AND_TYPE(),
{'notif_filters': clusapi_def.NOTIFY_FILTER_AND_TYPE(),
'notif_port_h': mock.sentinel.notif_port_h,
'notif_key': mock.sentinel.notif_key})
@ddt.unpack
@ -297,7 +300,7 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
notif_key)
exp_notif_key_p = self._ctypes.byref(notif_key) if notif_key else None
exp_notif_port_h = notif_port_h or _clusapi_utils.INVALID_HANDLE_VALUE
exp_notif_port_h = notif_port_h or w_const.INVALID_HANDLE_VALUE
self._mock_run.assert_called_once_with(
self._clusapi.CreateClusterNotifyPortV2,
@ -337,10 +340,10 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
obj_name_buff_sz = ctypes.cast(
p_obj_name_buff_sz,
ctypes.POINTER(_clusapi_utils.DWORD)).contents
wintypes.PDWORD).contents
buff_sz = ctypes.cast(
p_buff_sz,
ctypes.POINTER(_clusapi_utils.DWORD)).contents
wintypes.PDWORD).contents
# We'll just request the tested method to pass us
# a buffer this large.
@ -349,7 +352,7 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
buff_sz.value = requested_buff_sz
obj_name_buff_sz.value = requested_buff_sz
raise exceptions.ClusterWin32Exception(
error_code=_clusapi_utils.ERROR_MORE_DATA,
error_code=w_const.ERROR_MORE_DATA,
func_name='GetClusterNotify',
error_message='error more data')
@ -359,7 +362,7 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
filter_and_type = ctypes.cast(
p_filter_and_type,
ctypes.POINTER(_clusapi_utils.NOTIFY_FILTER_AND_TYPE)).contents
ctypes.POINTER(clusapi_def.NOTIFY_FILTER_AND_TYPE)).contents
filter_and_type.dwObjectType = fake_notif_type
filter_and_type.FilterFlags = fake_filter_flags
@ -404,18 +407,18 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
self.assertEqual(expected_event, event)
def _get_fake_prop_list(self):
syntax = _clusapi_utils.CLUSPROP_SYNTAX_LIST_VALUE_DWORD
migr_type = _clusapi_utils.DWORD(self._LIVE_MIGRATION_TYPE)
syntax = w_const.CLUSPROP_SYNTAX_LIST_VALUE_DWORD
migr_type = wintypes.DWORD(self._LIVE_MIGRATION_TYPE)
prop_entries = [
self._clusapi_utils.get_property_list_entry(
_clusapi_utils.CLUSPROP_NAME_VM, syntax, migr_type),
w_const.CLUS_RESTYPE_NAME_VM, syntax, migr_type),
self._clusapi_utils.get_property_list_entry(
_clusapi_utils.CLUSPROP_NAME_VM_CONFIG, syntax, migr_type),
w_const.CLUS_RESTYPE_NAME_VM_CONFIG, syntax, migr_type),
self._clusapi_utils.get_property_list_entry(
_clusapi_utils.CLUSPROP_GROUP_STATUS_INFO,
_clusapi_utils.CLUSPROP_SYNTAX_LIST_VALUE_ULARGE_INTEGER,
ctypes.c_ulonglong(_clusapi_utils.
w_const.CLUSREG_NAME_GRP_STATUS_INFORMATION,
w_const.CLUSPROP_SYNTAX_LIST_VALUE_ULARGE_INTEGER,
ctypes.c_ulonglong(w_const.
CLUSGRP_STATUS_WAITING_IN_QUEUE_FOR_MOVE)) # noqa
]
@ -444,7 +447,7 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
self._clusapi_utils.get_prop_list_entry_p,
ctypes.byref(prop_list),
ctypes.sizeof(prop_list),
_clusapi_utils.CLUSPROP_NAME_VM)
w_const.CLUS_RESTYPE_NAME_VM)
def test_get_prop_list_entry_p(self):
prop_list = self._get_fake_prop_list()
@ -452,10 +455,10 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
prop_entry = self._clusapi_utils.get_prop_list_entry_p(
ctypes.byref(prop_list),
ctypes.sizeof(prop_list),
_clusapi_utils.CLUSPROP_NAME_VM_CONFIG)
w_const.CLUS_RESTYPE_NAME_VM_CONFIG)
self.assertEqual(
_clusapi_utils.CLUSPROP_SYNTAX_LIST_VALUE_DWORD,
w_const.CLUSPROP_SYNTAX_LIST_VALUE_DWORD,
prop_entry['syntax'])
self.assertEqual(
ctypes.sizeof(ctypes.c_ulong),
@ -483,14 +486,14 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
req_buff_sz = ctypes.cast(
requested_buff_sz_p,
ctypes.POINTER(_clusapi_utils.DWORD)).contents
wintypes.PDWORD).contents
req_buff_sz.value = requested_buff_sz
# We'll just request the tested method to pass us
# a buffer this large.
if (out_buff_sz.value < requested_buff_sz):
raise exceptions.ClusterWin32Exception(
error_code=_clusapi_utils.ERROR_MORE_DATA,
error_code=w_const.ERROR_MORE_DATA,
func_name='ClusterGroupControl',
error_message='error more data')
@ -522,5 +525,5 @@ class ClusApiUtilsTestCase(test_base.OsWinBaseTestCase):
status_info = self._clusapi_utils.get_cluster_group_status_info(
ctypes.byref(prop_list), ctypes.sizeof(prop_list))
self.assertEqual(
_clusapi_utils.CLUSGRP_STATUS_WAITING_IN_QUEUE_FOR_MOVE,
w_const.CLUSGRP_STATUS_WAITING_IN_QUEUE_FOR_MOVE,
status_info)

View File

@ -22,8 +22,10 @@ from six.moves import queue
from os_win import constants
from os_win import exceptions
from os_win.tests.unit import test_base
from os_win.utils.compute import _clusapi_utils
from os_win.utils.compute import clusterutils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi.libs import clusapi as clusapi_def
from os_win.utils.winapi import wintypes
@ddt.ddt
@ -295,7 +297,7 @@ class ClusterUtilsTestCase(test_base.OsWinBaseTestCase):
constants.CLUSTER_GROUP_ONLINE,
mock.sentinel.timeout)
@mock.patch.object(_clusapi_utils, 'DWORD')
@mock.patch.object(wintypes, 'DWORD')
@mock.patch.object(clusterutils.ClusterUtils,
'_wait_for_cluster_group_migration')
@mock.patch.object(clusterutils.ClusterUtils,
@ -327,10 +329,10 @@ class ClusterUtilsTestCase(test_base.OsWinBaseTestCase):
self._clusapi.get_property_list_entry.assert_has_calls(
[mock.call(prop_name,
_clusapi_utils.CLUSPROP_SYNTAX_LIST_VALUE_DWORD,
w_const.CLUSPROP_SYNTAX_LIST_VALUE_DWORD,
mock_dword.return_value)
for prop_name in (_clusapi_utils.CLUSPROP_NAME_VM,
_clusapi_utils.CLUSPROP_NAME_VM_CONFIG)])
for prop_name in (w_const.CLUS_RESTYPE_NAME_VM,
w_const.CLUS_RESTYPE_NAME_VM_CONFIG)])
expected_prop_entries = [
self._clusapi.get_property_list_entry.return_value] * 2
@ -338,9 +340,9 @@ class ClusterUtilsTestCase(test_base.OsWinBaseTestCase):
expected_prop_entries)
expected_migrate_flags = (
_clusapi_utils.CLUSAPI_GROUP_MOVE_RETURN_TO_SOURCE_NODE_ON_ERROR |
_clusapi_utils.CLUSAPI_GROUP_MOVE_QUEUE_ENABLED |
_clusapi_utils.CLUSAPI_GROUP_MOVE_HIGH_PRIORITY_START)
w_const.CLUSAPI_GROUP_MOVE_RETURN_TO_SOURCE_NODE_ON_ERROR |
w_const.CLUSAPI_GROUP_MOVE_QUEUE_ENABLED |
w_const.CLUSAPI_GROUP_MOVE_HIGH_PRIORITY_START)
exp_clus_h = self._clusapi.open_cluster.return_value
exp_clus_node_h = self._clusapi.open_cluster_node.return_value
@ -505,18 +507,18 @@ class ClusterUtilsTestCase(test_base.OsWinBaseTestCase):
{'cancel_exception': test_base.TestingException()},
{'cancel_exception':
exceptions.Win32Exception(
error_code=_clusapi_utils.INVALID_HANDLE_VALUE,
error_code=w_const.INVALID_HANDLE_VALUE,
func_name=mock.sentinel.func_name,
error_message=mock.sentinel.error_message)},
{'cancel_exception':
exceptions.Win32Exception(
error_code=_clusapi_utils.ERROR_INVALID_STATE,
error_code=w_const.ERROR_INVALID_STATE,
func_name=mock.sentinel.func_name,
error_message=mock.sentinel.error_message),
'invalid_state_for_cancel': True},
{'cancel_exception':
exceptions.Win32Exception(
error_code=_clusapi_utils.ERROR_INVALID_STATE,
error_code=w_const.ERROR_INVALID_STATE,
func_name=mock.sentinel.func_name,
error_message=mock.sentinel.error_message),
'invalid_state_for_cancel': True,
@ -589,7 +591,7 @@ class ClusterUtilsTestCase(test_base.OsWinBaseTestCase):
self.assertTrue(
self._clusterutils._is_migration_pending(
group_state=constants.CLUSTER_GROUP_ONLINE,
group_status_info=_clusapi_utils.
group_status_info=w_const.
CLUSGRP_STATUS_WAITING_IN_QUEUE_FOR_MOVE | 1, # noqa
expected_state=constants.CLUSTER_GROUP_ONLINE))
self.assertFalse(
@ -726,7 +728,7 @@ class ClusterUtilsTestCase(test_base.OsWinBaseTestCase):
mock.sentinel.group_handle)
self._clusapi.cluster_group_control.assert_called_once_with(
mock.sentinel.group_handle,
_clusapi_utils.CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES)
w_const.CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES)
self._clusapi.get_cluster_group_status_info.assert_called_once_with(
mock_byref(mock.sentinel.buff), mock.sentinel.buff_sz)
@ -838,7 +840,7 @@ class ClusterEventListenerTestCase(test_base.OsWinBaseTestCase):
mock.sentinel.notif_key_dw_2)])
@mock.patch.object(clusterutils._ClusterEventListener, '_add_filter')
@mock.patch.object(_clusapi_utils, 'NOTIFY_FILTER_AND_TYPE')
@mock.patch.object(clusapi_def, 'NOTIFY_FILTER_AND_TYPE')
def test_setup_notif_port(self, mock_filter_struct_cls, mock_add_filter):
notif_filter = dict(object_type=mock.sentinel.object_type,
filter_flags=mock.sentinel.filter_flags,

View File

@ -20,6 +20,8 @@ import six
from os_win import constants
from os_win import exceptions
from os_win.utils.io import ioutils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi import wintypes
class IOUtilsTestCase(base.BaseTestCase):
@ -84,7 +86,7 @@ class IOUtilsTestCase(base.BaseTestCase):
mock.sentinel.create_disposition,
mock.sentinel.flags,
None,
error_ret_vals=[ioutils.INVALID_HANDLE_VALUE],
error_ret_vals=[w_const.INVALID_HANDLE_VALUE],
**self._run_args)
self.assertEqual(self._mock_run.return_value, handle)
@ -93,8 +95,8 @@ class IOUtilsTestCase(base.BaseTestCase):
mock.sentinel.overlapped_struct,
ignore_invalid_handle=True)
expected_ignored_err_codes = [ioutils.ERROR_NOT_FOUND,
ioutils.ERROR_INVALID_HANDLE]
expected_ignored_err_codes = [w_const.ERROR_NOT_FOUND,
w_const.ERROR_INVALID_HANDLE]
self._mock_run.assert_called_once_with(
ioutils.kernel32.CancelIoEx,
@ -118,7 +120,7 @@ class IOUtilsTestCase(base.BaseTestCase):
mock.sentinel.event,
ioutils.WAIT_INFINITE_TIMEOUT,
True,
error_ret_vals=[ioutils.WAIT_FAILED],
error_ret_vals=[w_const.WAIT_FAILED],
**self._run_args)
def test_set_event(self):
@ -150,8 +152,8 @@ class IOUtilsTestCase(base.BaseTestCase):
**self._run_args)
self.assertEqual(self._mock_run.return_value, event)
@mock.patch.object(ioutils, 'LPOVERLAPPED', create=True)
@mock.patch.object(ioutils, 'LPOVERLAPPED_COMPLETION_ROUTINE',
@mock.patch.object(wintypes, 'LPOVERLAPPED', create=True)
@mock.patch.object(wintypes, 'LPOVERLAPPED_COMPLETION_ROUTINE',
lambda x: x, create=True)
@mock.patch.object(ioutils.IOUtils, 'set_event')
def test_get_completion_routine(self, mock_set_event,
@ -164,12 +166,12 @@ class IOUtilsTestCase(base.BaseTestCase):
mock.sentinel.lpOverLapped)
self._ctypes.cast.assert_called_once_with(mock.sentinel.lpOverLapped,
ioutils.LPOVERLAPPED)
wintypes.LPOVERLAPPED)
mock_overlapped_struct = self._ctypes.cast.return_value.contents
mock_set_event.assert_called_once_with(mock_overlapped_struct.hEvent)
mock_callback.assert_called_once_with(mock.sentinel.num_bytes)
@mock.patch.object(ioutils, 'OVERLAPPED', create=True)
@mock.patch.object(wintypes, 'OVERLAPPED', create=True)
@mock.patch.object(ioutils.IOUtils, '_create_event')
def test_get_new_overlapped_structure(self, mock_create_event,
mock_OVERLAPPED):

View File

@ -21,8 +21,8 @@ from six.moves import builtins
from os_win import constants
from os_win import exceptions
from os_win.utils.io import ioutils
from os_win.utils.io import namedpipe
from os_win.utils.winapi import constants as w_const
class NamedPipeTestCase(base.BaseTestCase):
@ -180,10 +180,10 @@ class NamedPipeTestCase(base.BaseTestCase):
mock.sentinel.pipe_name)
self._ioutils.open.assert_called_once_with(
mock.sentinel.pipe_name,
desired_access=(ioutils.GENERIC_READ | ioutils.GENERIC_WRITE),
share_mode=(ioutils.FILE_SHARE_READ | ioutils.FILE_SHARE_WRITE),
creation_disposition=ioutils.OPEN_EXISTING,
flags_and_attributes=ioutils.FILE_FLAG_OVERLAPPED)
desired_access=(w_const.GENERIC_READ | w_const.GENERIC_WRITE),
share_mode=(w_const.FILE_SHARE_READ | w_const.FILE_SHARE_WRITE),
creation_disposition=w_const.OPEN_EXISTING,
flags_and_attributes=w_const.FILE_FLAG_OVERLAPPED)
self.assertEqual(self._ioutils.open.return_value,
self._handler._pipe_handle)

View File

@ -20,8 +20,8 @@ from oslotest import base
import six
from os_win import exceptions
from os_win.utils.storage.initiator import fc_structures as fc_struct
from os_win.utils.storage.initiator import fc_utils
from os_win.utils.winapi.libs import hbaapi as fc_struct
class FCUtilsTestCase(base.BaseTestCase):
@ -72,62 +72,76 @@ class FCUtilsTestCase(base.BaseTestCase):
self.assertEqual(fc_utils.hbaapi.HBA_GetNumberOfAdapters.return_value,
hba_count)
def _test_open_adapter(self, adapter_name=None, adapter_wwn=None):
def test_open_adapter_by_name(self):
self._ctypes_mocker.stop()
self._mock_run.return_value = mock.sentinel.handle
if adapter_name:
expected_func = fc_utils.hbaapi.HBA_OpenAdapter
elif adapter_wwn:
expected_func = fc_utils.hbaapi.HBA_OpenAdapterByWWN
resulted_handle = self._fc_utils._open_adapter(
adapter_name=adapter_name, adapter_wwn=adapter_wwn)
resulted_handle = self._fc_utils._open_adapter_by_name(
self._FAKE_ADAPTER_NAME)
args_list = self._mock_run.call_args_list[0][0]
self.assertEqual(expected_func, args_list[0])
if adapter_name:
self.assertEqual(six.b(adapter_name),
args_list[1].value)
else:
self.assertEqual(adapter_wwn, list(args_list[1]))
self.assertEqual(fc_utils.hbaapi.HBA_OpenAdapter, args_list[0])
self.assertEqual(six.b(self._FAKE_ADAPTER_NAME), args_list[1].value)
self.assertEqual(mock.sentinel.handle, resulted_handle)
def test_open_adapter_by_name(self):
self._test_open_adapter(adapter_name=self._FAKE_ADAPTER_NAME)
@mock.patch.object(fc_utils.fc_struct, 'HBA_HANDLE')
def test_open_adapter_by_wwn(self, mock_hba_handle_struct):
exp_handle = mock_hba_handle_struct.return_value
resulted_handle = self._fc_utils._open_adapter_by_wwn(
self._FAKE_ADAPTER_WWN)
def test_open_adapter_by_wwn(self):
self._test_open_adapter(adapter_wwn=self._FAKE_ADAPTER_WWN)
self.assertEqual(exp_handle, resulted_handle)
def test_open_adapter_not_specified(self):
self.assertRaises(exceptions.FCException,
self._fc_utils._open_adapter)
args_list = self._mock_run.call_args_list[0][0]
self.assertEqual(fc_utils.hbaapi.HBA_OpenAdapterByWWN,
args_list[0])
self.assertEqual(self._FAKE_ADAPTER_WWN, list(args_list[2].wwn))
self.assertEqual(self._ctypes.byref(exp_handle), args_list[1])
def test_close_adapter(self):
self._fc_utils._close_adapter(mock.sentinel.hba_handle)
fc_utils.hbaapi.HBA_CloseAdapter.assert_called_once_with(
mock.sentinel.hba_handle)
@mock.patch.object(fc_utils.FCUtils, '_open_adapter')
@mock.patch.object(fc_utils.FCUtils, '_open_adapter_by_name')
@mock.patch.object(fc_utils.FCUtils, '_close_adapter')
def test_get_hba_handle(self, mock_close_adapter, mock_open_adapter):
def test_get_hba_handle_by_name(self, mock_close_adapter,
mock_open_adapter):
with self._fc_utils._get_hba_handle(
adapter_name=self._FAKE_ADAPTER_NAME):
adapter_name=self._FAKE_ADAPTER_NAME) as handle:
self.assertEqual(mock_open_adapter.return_value, handle)
mock_open_adapter.assert_called_once_with(
adapter_name=self._FAKE_ADAPTER_NAME)
self._FAKE_ADAPTER_NAME)
mock_close_adapter.assert_called_once_with(
mock_open_adapter.return_value)
@mock.patch.object(ctypes, 'byref')
def test_get_adapter_name(self, mock_byref):
@mock.patch.object(fc_utils.FCUtils, '_open_adapter_by_wwn')
@mock.patch.object(fc_utils.FCUtils, '_close_adapter')
def test_get_hba_handle_by_wwn(self, mock_close_adapter,
mock_open_adapter):
with self._fc_utils._get_hba_handle(
adapter_wwn=self._FAKE_ADAPTER_WWN) as handle:
self.assertEqual(mock_open_adapter.return_value, handle)
mock_open_adapter.assert_called_once_with(
self._FAKE_ADAPTER_WWN)
mock_close_adapter.assert_called_once_with(
mock_open_adapter.return_value)
def test_get_hba_handle_missing_params(self):
self.assertRaises(exceptions.FCException,
self._fc_utils._get_hba_handle().__enter__)
def test_get_adapter_name(self):
self._ctypes_mocker.stop()
fake_adapter_index = 1
def update_buff(buff):
def update_buff(func, adapter_index, buff):
buff.value = six.b(self._FAKE_ADAPTER_NAME)
mock_byref.side_effect = update_buff
self._mock_run.side_effect = update_buff
resulted_adapter_name = self._fc_utils._get_adapter_name(
fake_adapter_index)
@ -139,8 +153,7 @@ class FCUtilsTestCase(base.BaseTestCase):
self.assertIsInstance(args_list[1], ctypes.c_uint32)
self.assertEqual(fake_adapter_index, args_list[1].value)
arg_byref = mock_byref.call_args_list[0][0][0]
buff = ctypes.cast(arg_byref, ctypes.POINTER(
buff = ctypes.cast(args_list[2], ctypes.POINTER(
ctypes.c_char * 256)).contents
self.assertIsInstance(buff, ctypes.c_char * 256)
self.assertEqual(self._FAKE_ADAPTER_NAME, resulted_adapter_name)
@ -228,7 +241,7 @@ class FCUtilsTestCase(base.BaseTestCase):
mock_get_adapter_ports.assert_has_calls(
[mock.call(mock.sentinel.adapter_name)] * 2)
@mock.patch.object(fc_utils.FCUtils, '_open_adapter')
@mock.patch.object(fc_utils.FCUtils, '_open_adapter_by_name')
@mock.patch.object(fc_utils.FCUtils, '_close_adapter')
@mock.patch.object(fc_utils.FCUtils, '_get_adapter_port_attributes')
@mock.patch.object(fc_utils.FCUtils, '_get_adapter_attributes')
@ -245,8 +258,8 @@ class FCUtilsTestCase(base.BaseTestCase):
mock_adapter_attributes = mock.MagicMock()
mock_adapter_attributes.NumberOfPorts = fake_port_count
mock_port_attributes = mock.MagicMock()
mock_port_attributes.NodeWWN = fake_node_wwn
mock_port_attributes.PortWWN = fake_port_wwn
mock_port_attributes.NodeWWN.wwn = fake_node_wwn
mock_port_attributes.PortWWN.wwn = fake_port_wwn
mock_get_adapter_attributes.return_value = mock_adapter_attributes
mock_get_adapter_port_attributes.return_value = mock_port_attributes
@ -260,8 +273,7 @@ class FCUtilsTestCase(base.BaseTestCase):
}]
self.assertEqual(expected_hba_ports, resulted_hba_ports)
mock_open_adapter.assert_called_once_with(
adapter_name=mock.sentinel.adapter_name)
mock_open_adapter.assert_called_once_with(mock.sentinel.adapter_name)
mock_close_adapter.assert_called_once_with(
mock_open_adapter(mock.sentinel.adapter_nam))
mock_get_adapter_attributes.assert_called_once_with(
@ -286,7 +298,7 @@ class FCUtilsTestCase(base.BaseTestCase):
expected_string = '000102'
self.assertEqual(expected_string, resulted_string)
@mock.patch.object(fc_utils.FCUtils, '_open_adapter')
@mock.patch.object(fc_utils.FCUtils, '_open_adapter_by_wwn')
@mock.patch.object(fc_utils.FCUtils, '_close_adapter')
@mock.patch.object(fc_utils.FCUtils, '_get_target_mapping')
def test_get_fc_target_mapping(self, mock_get_target_mapping,
@ -299,8 +311,8 @@ class FCUtilsTestCase(base.BaseTestCase):
mock_fcp_mappings = mock.MagicMock()
mock_entry = mock.MagicMock()
mock_entry.FcpId.NodeWWN = fake_node_wwn
mock_entry.FcpId.PortWWN = fake_port_wwn
mock_entry.FcpId.NodeWWN.wwn = fake_node_wwn
mock_entry.FcpId.PortWWN.wwn = fake_port_wwn
mock_entry.ScsiId.OSDeviceName = mock.sentinel.OSDeviceName
mock_entry.ScsiId.ScsiOSLun = mock.sentinel.ScsiOSLun
mock_fcp_mappings.Entries = [mock_entry]
@ -318,7 +330,7 @@ class FCUtilsTestCase(base.BaseTestCase):
'lun': mock.sentinel.ScsiOSLun
}]
self.assertEqual(expected_mappings, resulted_mappings)
mock_open_adapter.assert_called_once_with(adapter_wwn=mock_node_wwn)
mock_open_adapter.assert_called_once_with(mock_node_wwn)
mock_close_adapter.assert_called_once_with(
mock_open_adapter.return_value)

View File

@ -1,56 +0,0 @@
# Copyright 2015 Cloudbase Solutions Srl
#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
import six
from os_win import constants
from os_win.tests.unit import test_base
from os_win.utils.storage.initiator import iscsidsc_structures as iscsi_struct
class ISCSIStructTestCase(test_base.OsWinBaseTestCase):
def test_iscsi_login_opts_setup(self):
fake_username = 'fake_chap_username'
fake_password = 'fake_chap_secret'
auth_type = constants.ISCSI_CHAP_AUTH_TYPE
login_opts = iscsi_struct.ISCSI_LOGIN_OPTIONS(Username=fake_username,
Password=fake_password,
AuthType=auth_type)
self.assertIsInstance(login_opts.Username, iscsi_struct.PUCHAR)
self.assertIsInstance(login_opts.Password, iscsi_struct.PUCHAR)
self.assertEqual(len(fake_username), login_opts.UsernameLength)
self.assertEqual(len(fake_password), login_opts.PasswordLength)
username_struct_contents = ctypes.cast(
login_opts.Username,
ctypes.POINTER(ctypes.c_char * len(fake_username))).contents.value
pwd_struct_contents = ctypes.cast(
login_opts.Password,
ctypes.POINTER(ctypes.c_char * len(fake_password))).contents.value
self.assertEqual(six.b(fake_username), username_struct_contents)
self.assertEqual(six.b(fake_password), pwd_struct_contents)
expected_info_bitmap = (iscsi_struct.ISCSI_LOGIN_OPTIONS_USERNAME |
iscsi_struct.ISCSI_LOGIN_OPTIONS_PASSWORD |
iscsi_struct.ISCSI_LOGIN_OPTIONS_AUTH_TYPE)
self.assertEqual(expected_info_bitmap,
login_opts.InformationSpecified)

View File

@ -19,14 +19,16 @@ import ctypes
import ddt
import mock
import six
from os_win import _utils
from os_win import constants
from os_win import exceptions
from os_win.tests.unit import test_base
from os_win.utils.storage.initiator import iscsi_utils
from os_win.utils.storage.initiator import iscsidsc_structures as iscsi_struct
from os_win.utils.storage.initiator import iscsierr
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi.errmsg import iscsierr
from os_win.utils.winapi.libs import iscsidsc as iscsi_struct
@ddt.ddt
@ -95,7 +97,7 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
parse_output=False):
insufficient_buff_exc = exceptions.Win32Exception(
message='fake_err_msg',
error_code=iscsi_utils.ERROR_INSUFFICIENT_BUFFER)
error_code=w_const.ERROR_INSUFFICIENT_BUFFER)
func_requests_buff_sz = required_buff_sz is not None
struct_type = ctypes.c_uint
@ -119,19 +121,13 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
# We expect our decorated method to be called exactly two times.
first_call_args_dict = func_side_effect.call_args_list[0][1]
self.assertIsInstance(first_call_args_dict['buff'],
ctypes.c_ubyte * 0)
ctypes.POINTER(struct_type))
self.assertEqual(first_call_args_dict['buff_size_val'], 0)
self.assertEqual(first_call_args_dict['element_count_val'], 0)
if required_buff_sz:
expected_buff_sz = required_buff_sz
else:
expected_buff_sz = ctypes.sizeof(
struct_type) * returned_element_count
second_call_args_dict = func_side_effect.call_args_list[1][1]
self.assertIsInstance(second_call_args_dict['buff'],
ctypes.c_ubyte * expected_buff_sz)
ctypes.POINTER(struct_type))
self.assertEqual(second_call_args_dict['buff_size_val'],
required_buff_sz or 0)
self.assertEqual(second_call_args_dict['element_count_val'],
@ -151,7 +147,7 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
func_side_effect = mock.Mock(side_effect=fake_exc)
fake_func = self._get_fake_iscsi_utils_getter_func(
func_side_effect=func_side_effect,
decorator_args={})
decorator_args={'struct_type': ctypes.c_ubyte})
self.assertRaises(exceptions.Win32Exception, fake_func,
self._initiator)
@ -199,7 +195,7 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
self._mock_run.assert_called_once_with(
self._iscsidsc.ReportIScsiPersistentLoginsW,
self._ctypes.byref(mock.sentinel.element_count),
self._ctypes.byref(mock.sentinel.buff),
mock.sentinel.buff,
self._ctypes.byref(mock.sentinel.buff_size))
@mock.patch.object(iscsi_utils.ISCSIInitiatorUtils,
@ -223,7 +219,7 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
self._iscsidsc.ReportIScsiTargetsW,
mock.sentinel.forced_update,
self._ctypes.byref(mock_el_count),
self._ctypes.byref(mock.sentinel.buff))
mock.sentinel.buff)
mock_parse_string_list.assert_called_once_with(
mock.sentinel.buff, mock.sentinel.element_count)
@ -246,7 +242,7 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
self._mock_run.assert_called_once_with(
self._iscsidsc.ReportIScsiInitiatorListW,
self._ctypes.byref(mock_el_count),
self._ctypes.byref(mock.sentinel.buff))
mock.sentinel.buff)
mock_parse_string_list.assert_called_once_with(
mock.sentinel.buff, mock.sentinel.element_count)
@ -270,14 +266,14 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
self._ctypes.c_wchar = mock.MagicMock()
fake_buff = (self._ctypes.c_wchar * (
iscsi_struct.MAX_ISCSI_NAME_LEN + 1))()
w_const.MAX_ISCSI_NAME_LEN + 1))()
fake_buff.value = mock.sentinel.buff_value
resulted_iscsi_initiator = self._initiator.get_iscsi_initiator()
self._mock_run.assert_called_once_with(
self._iscsidsc.GetIScsiInitiatorNodeNameW,
self._ctypes.byref(fake_buff))
fake_buff)
self.assertEqual(mock.sentinel.buff_value,
resulted_iscsi_initiator)
@ -315,11 +311,10 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
self.assertEqual(fake_target_name, args_list[1].value)
self.assertIsInstance(args_list[4], ctypes.c_ulong)
self.assertEqual(
ctypes.c_ulong(iscsi_struct.ISCSI_ANY_INITIATOR_PORT).value,
ctypes.c_ulong(w_const.ISCSI_ANY_INITIATOR_PORT).value,
args_list[4].value)
self.assertIsInstance(args_list[6], ctypes.c_ulonglong)
self.assertEqual(iscsi_struct.ISCSI_DEFAULT_SECURITY_FLAGS,
args_list[6].value)
self.assertEqual(0, args_list[6].value)
self.assertIsInstance(args_list[9], ctypes.c_ulong)
self.assertEqual(0, args_list[9].value)
@ -348,7 +343,7 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
self._iscsidsc.GetIScsiSessionListW,
self._ctypes.byref(mock.sentinel.buff_size),
self._ctypes.byref(mock.sentinel.element_count),
self._ctypes.byref(mock.sentinel.buff))
mock.sentinel.buff)
@mock.patch.object(iscsi_utils.ISCSIInitiatorUtils,
'_get_iscsi_sessions')
@ -385,14 +380,13 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
self._iscsidsc.GetDevicesForIScsiSessionW,
self._ctypes.byref(mock.sentinel.session_id),
self._ctypes.byref(mock.sentinel.element_count),
self._ctypes.byref(mock.sentinel.buff))
mock.sentinel.buff)
@mock.patch.object(iscsi_utils.ISCSIInitiatorUtils,
'_get_iscsi_session_devices')
def test_get_iscsi_session_luns(self, mock_get_iscsi_session_devices):
fake_device = mock.Mock()
fake_device.StorageDeviceNumber.DeviceType = (
iscsi_struct.FILE_DEVICE_DISK)
fake_device.StorageDeviceNumber.DeviceType = w_const.FILE_DEVICE_DISK
mock_get_iscsi_session_devices.return_value = [fake_device,
mock.Mock()]
@ -533,45 +527,44 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
self._initiator._remove_static_target(mock.sentinel.target_name)
expected_ignored_err_codes = [iscsierr.ISDSC_TARGET_NOT_FOUND]
expected_ignored_err_codes = [w_const.ISDSC_TARGET_NOT_FOUND]
self._mock_run.assert_called_once_with(
self._iscsidsc.RemoveIScsiStaticTargetW,
self._ctypes.c_wchar_p(mock.sentinel.target_name),
ignored_error_codes=expected_ignored_err_codes)
@mock.patch.object(iscsi_struct, 'ISCSI_LOGIN_OPTIONS')
def _test_get_login_opts(self, mock_cls_ISCSI_LOGIN_OPTIONS,
auth_type=None, creds_specified=False):
auth_user = mock.sentinel.auth_user if creds_specified else None
auth_pwd = mock.sentinel.auth_pwd if creds_specified else None
def test_get_login_opts(self):
fake_username = 'fake_chap_username'
fake_password = 'fake_chap_secret'
auth_type = constants.ISCSI_CHAP_AUTH_TYPE
login_flags = w_const.ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED
if not auth_type:
expected_auth_type = (constants.ISCSI_CHAP_AUTH_TYPE
if creds_specified
else constants.ISCSI_NO_AUTH_TYPE)
else:
expected_auth_type = auth_type
login_opts = self._initiator._get_login_opts(
auth_username=fake_username,
auth_password=fake_password,
auth_type=auth_type,
login_flags=login_flags)
resulted_login_opts = self._initiator._get_login_opts(
auth_user, auth_pwd, auth_type,
mock.sentinel.login_flags)
self.assertEqual(len(fake_username), login_opts.UsernameLength)
self.assertEqual(len(fake_password), login_opts.PasswordLength)
expected_login_opts = mock_cls_ISCSI_LOGIN_OPTIONS.return_value
mock_cls_ISCSI_LOGIN_OPTIONS.assert_called_once_with(
Username=auth_user,
Password=auth_pwd,
AuthType=expected_auth_type,
LoginFlags=mock.sentinel.login_flags)
self.assertEqual(expected_login_opts, resulted_login_opts)
username_struct_contents = ctypes.cast(
login_opts.Username,
ctypes.POINTER(ctypes.c_char * len(fake_username))).contents.value
pwd_struct_contents = ctypes.cast(
login_opts.Password,
ctypes.POINTER(ctypes.c_char * len(fake_password))).contents.value
def test_get_login_opts_without_creds_and_explicit_auth_type(self):
self._test_get_login_opts()
self.assertEqual(six.b(fake_username), username_struct_contents)
self.assertEqual(six.b(fake_password), pwd_struct_contents)
def test_get_login_opts_with_creds_and_without_explicit_auth_type(self):
self._test_get_login_opts(creds_specified=True)
def test_get_login_opts_with_explicit_auth_type(self):
self._test_get_login_opts(auth_type=mock.sentinel.auth_type)
expected_info_bitmap = (w_const.ISCSI_LOGIN_OPTIONS_USERNAME |
w_const.ISCSI_LOGIN_OPTIONS_PASSWORD |
w_const.ISCSI_LOGIN_OPTIONS_AUTH_TYPE)
self.assertEqual(expected_info_bitmap,
login_opts.InformationSpecified)
self.assertEqual(login_flags,
login_opts.LoginFlags)
@mock.patch.object(iscsi_utils.ISCSIInitiatorUtils,
'_get_iscsi_session_devices')
@ -687,7 +680,7 @@ class ISCSIInitiatorUtilsTestCase(test_base.OsWinBaseTestCase):
if login_required:
expected_login_flags = (
iscsi_struct.ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED
w_const.ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED
if mpio_enabled else 0)
mock_get_login_opts.assert_called_once_with(
mock.sentinel.auth_username,

View File

@ -1,56 +0,0 @@
# Copyright 2015 Cloudbase Solutions Srl
#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
import six
from os_win import constants
from os_win.tests.unit import test_base
from os_win.utils.storage.initiator import iscsidsc_structures as iscsi_struct
class ISCSIStructTestCase(test_base.OsWinBaseTestCase):
def test_iscsi_login_opts_setup(self):
fake_username = 'fake_chap_username'
fake_password = 'fake_chap_secret'
auth_type = constants.ISCSI_CHAP_AUTH_TYPE
login_opts = iscsi_struct.ISCSI_LOGIN_OPTIONS(Username=fake_username,
Password=fake_password,
AuthType=auth_type)
self.assertIsInstance(login_opts.Username, iscsi_struct.PUCHAR)
self.assertIsInstance(login_opts.Password, iscsi_struct.PUCHAR)
self.assertEqual(len(fake_username), login_opts.UsernameLength)
self.assertEqual(len(fake_password), login_opts.PasswordLength)
username_struct_contents = ctypes.cast(
login_opts.Username,
ctypes.POINTER(ctypes.c_char * len(fake_username))).contents.value
pwd_struct_contents = ctypes.cast(
login_opts.Password,
ctypes.POINTER(ctypes.c_char * len(fake_password))).contents.value
self.assertEqual(six.b(fake_username), username_struct_contents)
self.assertEqual(six.b(fake_password), pwd_struct_contents)
expected_info_bitmap = (iscsi_struct.ISCSI_LOGIN_OPTIONS_USERNAME |
iscsi_struct.ISCSI_LOGIN_OPTIONS_PASSWORD |
iscsi_struct.ISCSI_LOGIN_OPTIONS_AUTH_TYPE)
self.assertEqual(expected_info_bitmap,
login_opts.InformationSpecified)

View File

@ -20,9 +20,8 @@ import six
from os_win import constants
from os_win import exceptions
from os_win.utils.storage.virtdisk import (
virtdisk_constants as vdisk_const)
from os_win.utils.storage.virtdisk import vhdutils
from os_win.utils.winapi import constants as w_const
class VHDUtilsTestCase(base.BaseTestCase):
@ -32,11 +31,12 @@ class VHDUtilsTestCase(base.BaseTestCase):
super(VHDUtilsTestCase, self).setUp()
self._setup_lib_mocks()
self._fake_vst_struct = self._vdisk_struct.Win32_VIRTUAL_STORAGE_TYPE
self._fake_vst_struct = self._vdisk_struct.VIRTUAL_STORAGE_TYPE
self._vhdutils = vhdutils.VHDUtils()
self._vhdutils._win32_utils = mock.Mock()
self._mock_close = self._vhdutils._win32_utils.close_handle
self._mock_run = self._vhdutils._win32_utils.run_and_check_output
self._run_args = self._vhdutils._virtdisk_run_args
@ -57,8 +57,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
vdisk_struct=self._vdisk_struct,
create=True).start()
@mock.patch.object(vhdutils.VHDUtils, '_close')
def _test_run_and_check_output(self, mock_close, raised_exc=None):
def _test_run_and_check_output(self, raised_exc=None):
self._mock_run.side_effect = raised_exc(
func_name='fake_func_name',
error_code='fake_error_code',
@ -80,7 +79,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
self._mock_run.assert_called_once_with(
mock.sentinel.func, mock.sentinel.arg, **self._run_args)
mock_close.assert_called_once_with(mock.sentinel.handle)
self._mock_close.assert_called_once_with(mock.sentinel.handle)
def test_run_and_check_output(self):
self._test_run_and_check_output()
@ -103,7 +102,8 @@ class VHDUtilsTestCase(base.BaseTestCase):
self.assertEqual(vhdutils.wintypes.HANDLE.return_value, handle)
self._fake_vst_struct.assert_called_once_with(
DeviceId=mock.sentinel.device_id)
DeviceId=mock.sentinel.device_id,
VendorId=w_const.VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT)
self._mock_run.assert_called_once_with(
vhdutils.virtdisk.OpenVirtualDisk,
@ -121,14 +121,16 @@ class VHDUtilsTestCase(base.BaseTestCase):
mock.sentinel.handle)
@mock.patch.object(vhdutils.VHDUtils, '_get_vhd_device_id')
@mock.patch.object(vhdutils.VHDUtils, '_close')
def _test_create_vhd(self, mock_close, mock_get_dev_id, new_vhd_type):
def _test_create_vhd(self, mock_get_dev_id, new_vhd_type):
create_params_struct = (
self._vdisk_struct.Win32_CREATE_VIRTUAL_DISK_PARAMETERS)
self._vdisk_struct.CREATE_VIRTUAL_DISK_PARAMETERS)
mock_handle = vhdutils.wintypes.HANDLE.return_value
fake_vst = self._fake_vst_struct.return_value
fake_create_params = create_params_struct.return_value
expected_create_vhd_flag = (
vdisk_const.CREATE_VIRTUAL_DISK_FLAGS.get(new_vhd_type))
vhdutils.CREATE_VIRTUAL_DISK_FLAGS.get(new_vhd_type, 0))
self._vhdutils.create_vhd(
new_vhd_path=mock.sentinel.new_vhd_path,
@ -138,22 +140,41 @@ class VHDUtilsTestCase(base.BaseTestCase):
parent_path=mock.sentinel.parent_path)
self._fake_vst_struct.assert_called_once_with(
DeviceId=mock_get_dev_id.return_value)
create_params_struct.assert_called_once_with(
MaximumSize=mock.sentinel.max_internal_size,
ParentPath=mock.sentinel.parent_path,
SourcePath=mock.sentinel.src_path)
DeviceId=mock_get_dev_id.return_value,
VendorId=w_const.VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT)
self.assertEqual(w_const.CREATE_VIRTUAL_DISK_VERSION_2,
fake_create_params.Version)
self.assertEqual(mock.sentinel.max_internal_size,
fake_create_params.Version2.MaximumSize)
self.assertEqual(mock.sentinel.parent_path,
fake_create_params.Version2.ParentPath)
self.assertEqual(mock.sentinel.src_path,
fake_create_params.Version2.SourcePath)
self.assertEqual(
vhdutils.VIRTUAL_DISK_DEFAULT_PHYS_SECTOR_SIZE,
fake_create_params.Version2.PhysicalSectorSizeInBytes)
self.assertEqual(
w_const.CREATE_VHD_PARAMS_DEFAULT_BLOCK_SIZE,
fake_create_params.Version2.BlockSizeInBytes)
self.assertEqual(
vhdutils.VIRTUAL_DISK_DEFAULT_SECTOR_SIZE,
fake_create_params.Version2.SectorSizeInBytes)
self._mock_run.assert_called_once_with(
vhdutils.virtdisk.CreateVirtualDisk,
self._ctypes.byref(self._fake_vst_struct.return_value),
self._ctypes.c_wchar_p(mock.sentinel.new_vhd_path), None,
None, expected_create_vhd_flag, None,
self._ctypes.byref(create_params_struct.return_value), None,
self._ctypes.byref(fake_vst),
self._ctypes.c_wchar_p(mock.sentinel.new_vhd_path),
0,
None,
expected_create_vhd_flag,
0,
self._ctypes.byref(fake_create_params),
None,
self._ctypes.byref(mock_handle),
**self._run_args)
mock_close.assert_called_once_with(mock_handle)
self._mock_close.assert_called_once_with(mock_handle)
def test_create_dynamic_vhd(self):
self._test_create_vhd(new_vhd_type=constants.VHD_TYPE_DYNAMIC)
@ -230,7 +251,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
dev_id = self._vhdutils._get_vhd_device_id(mock.sentinel.vhd_path)
mock_get_vhd_fmt.assert_called_once_with(mock.sentinel.vhd_path)
self.assertEqual(vdisk_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
self.assertEqual(w_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
dev_id)
def _mock_open(self, read_data=None, curr_f_pos=0):
@ -245,7 +266,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
return mock_open
def test_get_vhd_format_by_sig_vhdx(self):
read_data = (vdisk_const.VHDX_SIGNATURE, )
read_data = (vhdutils.VHDX_SIGNATURE, )
self._mock_open(read_data=read_data)
fmt = self._vhdutils._get_vhd_format_by_signature(
@ -254,7 +275,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
self.assertEqual(constants.DISK_FORMAT_VHDX, fmt)
def test_get_vhd_format_by_sig_vhd(self):
read_data = ('notthesig', vdisk_const.VHD_SIGNATURE)
read_data = ('notthesig', vhdutils.VHD_SIGNATURE)
mock_open = self._mock_open(read_data=read_data, curr_f_pos=1024)
fmt = self._vhdutils._get_vhd_format_by_signature(
@ -282,19 +303,18 @@ class VHDUtilsTestCase(base.BaseTestCase):
mock_open.return_value.seek.assert_called_once_with(0, 2)
@mock.patch.object(vhdutils.VHDUtils, '_open')
@mock.patch.object(vhdutils.VHDUtils, '_close')
@mock.patch.object(vhdutils.VHDUtils, '_get_vhd_info_member')
def test_get_vhd_info(self, mock_get_vhd_info_member,
mock_close, mock_open):
fake_info_member = vdisk_const.GET_VIRTUAL_DISK_INFO_SIZE
mock_open):
fake_info_member = w_const.GET_VIRTUAL_DISK_INFO_SIZE
fake_vhd_info = {'VirtualSize': mock.sentinel.virtual_size}
mock_open.return_value = mock.sentinel.handle
mock_get_vhd_info_member.return_value = fake_vhd_info
expected_open_flag = vdisk_const.OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS
expected_access_mask = (vdisk_const.VIRTUAL_DISK_ACCESS_GET_INFO |
vdisk_const.VIRTUAL_DISK_ACCESS_DETACH)
expected_open_flag = w_const.OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS
expected_access_mask = (w_const.VIRTUAL_DISK_ACCESS_GET_INFO |
w_const.VIRTUAL_DISK_ACCESS_DETACH)
ret_val = self._vhdutils.get_vhd_info(mock.sentinel.vhd_path,
[fake_info_member])
@ -307,16 +327,16 @@ class VHDUtilsTestCase(base.BaseTestCase):
self._vhdutils._get_vhd_info_member.assert_called_once_with(
mock.sentinel.handle,
fake_info_member)
mock_close.assert_called_once_with(mock.sentinel.handle)
self._mock_close.assert_called_once_with(mock.sentinel.handle)
@mock.patch.object(vhdutils.VHDUtils, '_parse_vhd_info')
def test_get_vhd_info_member(self, mock_parse_vhd_info):
get_vd_info_struct = (
self._vdisk_struct.Win32_GET_VIRTUAL_DISK_INFO_PARAMETERS)
self._vdisk_struct.GET_VIRTUAL_DISK_INFO)
fake_params = get_vd_info_struct.return_value
fake_info_size = self._ctypes.sizeof.return_value
info_member = vdisk_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION
info_member = w_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION
vhd_info = self._vhdutils._get_vhd_info_member(
mock.sentinel.vhd_path,
@ -328,7 +348,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
self._ctypes.byref(
self._ctypes.c_ulong(fake_info_size)),
self._ctypes.byref(fake_params), None,
ignored_error_codes=[vdisk_const.ERROR_VHD_INVALID_TYPE],
ignored_error_codes=[w_const.ERROR_VHD_INVALID_TYPE],
**self._run_args)
self.assertEqual(mock_parse_vhd_info.return_value, vhd_info)
@ -336,13 +356,13 @@ class VHDUtilsTestCase(base.BaseTestCase):
info_member)
def test_parse_vhd_info(self):
fake_info_member = vdisk_const.GET_VIRTUAL_DISK_INFO_SIZE
fake_info_member = w_const.GET_VIRTUAL_DISK_INFO_SIZE
fake_info = mock.Mock()
fake_info.VhdInfo.Size._fields_ = [
fake_info.Size._fields_ = [
("VirtualSize", vhdutils.wintypes.ULARGE_INTEGER),
("PhysicalSize", vhdutils.wintypes.ULARGE_INTEGER)]
fake_info.VhdInfo.Size.VirtualSize = mock.sentinel.virt_size
fake_info.VhdInfo.Size.PhysicalSize = mock.sentinel.phys_size
fake_info.Size.VirtualSize = mock.sentinel.virt_size
fake_info.Size.PhysicalSize = mock.sentinel.phys_size
ret_val = self._vhdutils._parse_vhd_info(fake_info,
fake_info_member)
@ -352,10 +372,9 @@ class VHDUtilsTestCase(base.BaseTestCase):
self.assertEqual(expected, ret_val)
def test_parse_vhd_provider_subtype_member(self):
fake_info_member = (
vdisk_const.GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE)
fake_info_member = w_const.GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE
fake_info = mock.Mock()
fake_info.VhdInfo.ProviderSubtype = mock.sentinel.provider_subtype
fake_info.ProviderSubtype = mock.sentinel.provider_subtype
ret_val = self._vhdutils._parse_vhd_info(fake_info, fake_info_member)
expected = {'ProviderSubtype': mock.sentinel.provider_subtype}
@ -369,7 +388,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
self.assertEqual(mock_get_vhd_info.return_value, ret_val)
mock_get_vhd_info.assert_called_once_with(
mock.sentinel.vhd_path,
[vdisk_const.GET_VIRTUAL_DISK_INFO_SIZE])
[w_const.GET_VIRTUAL_DISK_INFO_SIZE])
@mock.patch.object(vhdutils.VHDUtils, 'get_vhd_info')
def test_get_vhd_parent_path(self, mock_get_vhd_info):
@ -381,7 +400,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
self.assertEqual(mock.sentinel.parent_path, ret_val)
mock_get_vhd_info.assert_called_once_with(
mock.sentinel.vhd_path,
[vdisk_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION])
[w_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION])
@mock.patch.object(vhdutils.VHDUtils, 'get_vhd_info')
def test_get_vhd_type(self, mock_get_vhd_info):
@ -393,16 +412,15 @@ class VHDUtilsTestCase(base.BaseTestCase):
self.assertEqual(mock.sentinel.provider_subtype, ret_val)
mock_get_vhd_info.assert_called_once_with(
mock.sentinel.vhd_path,
[vdisk_const.GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE])
[w_const.GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE])
@mock.patch.object(vhdutils.VHDUtils, '_open')
@mock.patch.object(vhdutils.VHDUtils, '_close')
@mock.patch('os.remove')
def test_merge_vhd(self, mock_remove, mock_close, mock_open):
def test_merge_vhd(self, mock_remove, mock_open):
open_params_struct = (
self._vdisk_struct.Win32_OPEN_VIRTUAL_DISK_PARAMETERS_V1)
self._vdisk_struct.OPEN_VIRTUAL_DISK_PARAMETERS)
merge_params_struct = (
self._vdisk_struct.Win32_MERGE_VIRTUAL_DISK_PARAMETERS)
self._vdisk_struct.MERGE_VIRTUAL_DISK_PARAMETERS)
fake_open_params = open_params_struct.return_value
fake_merge_params = merge_params_struct.return_value
@ -410,30 +428,37 @@ class VHDUtilsTestCase(base.BaseTestCase):
self._vhdutils.merge_vhd(mock.sentinel.vhd_path)
open_params_struct.assert_called_once_with(RWDepth=2)
self.assertEqual(w_const.OPEN_VIRTUAL_DISK_VERSION_1,
fake_open_params.Version)
self.assertEqual(2,
fake_open_params.Version1.RWDepth)
mock_open.assert_called_once_with(
mock.sentinel.vhd_path,
open_params=self._ctypes.byref(fake_open_params))
merge_params_struct.assert_called_once_with(MergeDepth=1)
self.assertEqual(w_const.MERGE_VIRTUAL_DISK_VERSION_1,
fake_merge_params.Version)
self.assertEqual(1,
fake_merge_params.Version1.MergeDepth)
self._mock_run.assert_called_once_with(
vhdutils.virtdisk.MergeVirtualDisk,
mock.sentinel.handle,
None,
0,
self._ctypes.byref(fake_merge_params),
None,
**self._run_args)
mock_remove.assert_called_once_with(
mock.sentinel.vhd_path)
mock_close.assert_called_once_with(mock.sentinel.handle)
self._mock_close.assert_called_once_with(mock.sentinel.handle)
@mock.patch.object(vhdutils.VHDUtils, '_open')
@mock.patch.object(vhdutils.VHDUtils, '_close')
def test_reconnect_parent_vhd(self, mock_close, mock_open):
def test_reconnect_parent_vhd(self, mock_open):
set_vdisk_info_struct = (
self._vdisk_struct.Win32_SET_VIRTUAL_DISK_INFO_PARAMETERS)
self._vdisk_struct.SET_VIRTUAL_DISK_INFO)
open_params_struct = (
self._vdisk_struct.Win32_OPEN_VIRTUAL_DISK_PARAMETERS_V2)
self._vdisk_struct.OPEN_VIRTUAL_DISK_PARAMETERS)
fake_set_params = set_vdisk_info_struct.return_value
fake_open_params = open_params_struct.return_value
@ -442,21 +467,27 @@ class VHDUtilsTestCase(base.BaseTestCase):
self._vhdutils.reconnect_parent_vhd(mock.sentinel.vhd_path,
mock.sentinel.parent_path)
open_params_struct.assert_called_once_with(GetInfoOnly=False)
self.assertEqual(w_const.OPEN_VIRTUAL_DISK_VERSION_2,
fake_open_params.Version)
self.assertFalse(fake_open_params.Version2.GetInfoOnly)
self._vhdutils._open.assert_called_once_with(
mock.sentinel.vhd_path,
open_flag=vdisk_const.OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS,
open_access_mask=None,
open_flag=w_const.OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS,
open_access_mask=0,
open_params=vhdutils.ctypes.byref(fake_open_params))
set_vdisk_info_struct.assert_called_once_with(
ParentFilePath=mock.sentinel.parent_path)
self.assertEqual(w_const.SET_VIRTUAL_DISK_INFO_PARENT_PATH,
fake_set_params.Version)
self.assertEqual(mock.sentinel.parent_path,
fake_set_params.ParentFilePath)
self._mock_run.assert_called_once_with(
vhdutils.virtdisk.SetVirtualDiskInformation,
mock.sentinel.handle,
vhdutils.ctypes.byref(fake_set_params),
**self._run_args)
mock_close.assert_called_once_with(mock.sentinel.handle)
self._mock_close.assert_called_once_with(mock.sentinel.handle)
@mock.patch.object(vhdutils.VHDUtils, 'get_internal_vhd_size_by_file_size')
@mock.patch.object(vhdutils.VHDUtils, '_resize_vhd')
@ -520,10 +551,9 @@ class VHDUtilsTestCase(base.BaseTestCase):
self._test_check_resize_needed(current_size=1, new_size=1)
@mock.patch.object(vhdutils.VHDUtils, '_open')
@mock.patch.object(vhdutils.VHDUtils, '_close')
def test_resize_vhd_helper(self, mock_close, mock_open):
def test_resize_vhd_helper(self, mock_open):
resize_vdisk_struct = (
self._vdisk_struct.Win32_RESIZE_VIRTUAL_DISK_PARAMETERS)
self._vdisk_struct.RESIZE_VIRTUAL_DISK_PARAMETERS)
fake_params = resize_vdisk_struct.return_value
mock_open.return_value = mock.sentinel.handle
@ -531,16 +561,19 @@ class VHDUtilsTestCase(base.BaseTestCase):
self._vhdutils._resize_vhd(mock.sentinel.vhd_path,
mock.sentinel.new_size)
resize_vdisk_struct.assert_called_once_with(
NewSize=mock.sentinel.new_size)
self.assertEqual(w_const.RESIZE_VIRTUAL_DISK_VERSION_1,
fake_params.Version)
self.assertEqual(mock.sentinel.new_size,
fake_params.Version1.NewSize)
self._mock_run.assert_called_once_with(
vhdutils.virtdisk.ResizeVirtualDisk,
mock.sentinel.handle,
None,
0,
vhdutils.ctypes.byref(fake_params),
None,
**self._run_args)
mock_close.assert_called_once_with(mock.sentinel.handle)
self._mock_close.assert_called_once_with(mock.sentinel.handle)
@mock.patch.object(vhdutils.VHDUtils, 'get_vhd_info')
@mock.patch.object(vhdutils.VHDUtils,
@ -550,7 +583,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
def _test_get_int_sz_by_file_size(
self, mock_get_vhdx_int_size,
mock_get_vhd_int_size, mock_get_vhd_info,
vhd_dev_id=vdisk_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
vhd_dev_id=w_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
vhd_type=constants.VHD_TYPE_DYNAMIC):
fake_vhd_info = dict(ProviderSubtype=vhd_type,
ParentPath=mock.sentinel.parent_path,
@ -569,7 +602,7 @@ class VHDUtilsTestCase(base.BaseTestCase):
mock.call(mock.sentinel.parent_path))
expected_vhd_checked = mock.sentinel.parent_path
is_vhd = vhd_dev_id == vdisk_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHD
is_vhd = vhd_dev_id == w_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHD
expected_helper = (mock_get_vhd_int_size
if is_vhd
else mock_get_vhdx_int_size)
@ -588,11 +621,11 @@ class VHDUtilsTestCase(base.BaseTestCase):
def test_get_int_sz_by_file_size_vhdx(self):
self._test_get_int_sz_by_file_size(
vhd_dev_id=vdisk_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX)
vhd_dev_id=w_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX)
def test_get_int_sz_by_file_size_differencing(self):
self._test_get_int_sz_by_file_size(
vhd_dev_id=vdisk_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX)
vhd_dev_id=w_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX)
def _mocked_get_internal_vhd_size(self, root_vhd_size, vhd_type):
fake_vhd_info = dict(ProviderSubtype=vhd_type,
@ -672,11 +705,11 @@ class VHDUtilsTestCase(base.BaseTestCase):
offset = self._vhdutils._get_vhdx_current_header_offset(mock_handle)
self.assertEqual(vdisk_const.VHDX_HEADER_OFFSETS[1], offset)
self.assertEqual(vhdutils.VHDX_HEADER_OFFSETS[1], offset)
@mock.patch.object(vhdutils.VHDUtils, '_get_vhdx_current_header_offset')
def test_get_log_size(self, mock_get_vhdx_curr_hd_offset):
fake_curr_header_offset = vdisk_const.VHDX_HEADER_OFFSETS[0]
fake_curr_header_offset = vhdutils.VHDX_HEADER_OFFSETS[0]
fake_log_sz = bytearray(b'\x01\x00\x00\x00')
mock_get_vhdx_curr_hd_offset.return_value = fake_curr_header_offset

View File

@ -18,6 +18,7 @@ import mock
from os_win.tests.unit import test_base
from os_win.utils import _acl_utils
from os_win.utils.winapi import constants as w_const
@ddt.ddt
@ -38,7 +39,7 @@ class ACLUtilsTestCase(test_base.OsWinBaseTestCase):
mock.patch.multiple(_acl_utils,
ctypes=self._ctypes,
advapi=mock.DEFAULT,
advapi32=mock.DEFAULT,
kernel32=mock.DEFAULT,
create=True).start()
@ -52,12 +53,12 @@ class ACLUtilsTestCase(test_base.OsWinBaseTestCase):
@ddt.data(
{'security_info_flags':
(_acl_utils.OWNER_SECURITY_INFORMATION |
_acl_utils.GROUP_SECURITY_INFORMATION |
_acl_utils.DACL_SECURITY_INFORMATION),
(w_const.OWNER_SECURITY_INFORMATION |
w_const.GROUP_SECURITY_INFORMATION |
w_const.DACL_SECURITY_INFORMATION),
'expected_info': ['pp_sid_owner', 'pp_sid_group',
'pp_dacl', 'pp_sec_desc']},
{'security_info_flags': _acl_utils.SACL_SECURITY_INFORMATION,
{'security_info_flags': w_const.SACL_SECURITY_INFORMATION,
'expected_info': ['pp_sacl', 'pp_sec_desc']})
@ddt.unpack
@mock.patch.object(_acl_utils.ACLUtils, '_get_void_pp')
@ -75,10 +76,10 @@ class ACLUtilsTestCase(test_base.OsWinBaseTestCase):
mock_get_void_pp.return_value)
self._mock_run.assert_called_once_with(
_acl_utils.advapi.GetNamedSecurityInfoW,
_acl_utils.advapi32.GetNamedSecurityInfoW,
self._ctypes.c_wchar_p(mock.sentinel.obj_name),
self._ctypes.c_uint(mock.sentinel.obj_type),
self._ctypes.c_uint(security_info_flags),
mock.sentinel.obj_type,
security_info_flags,
sec_info.get('pp_sid_owner'),
sec_info.get('pp_sid_group'),
sec_info.get('pp_dacl'),
@ -96,8 +97,8 @@ class ACLUtilsTestCase(test_base.OsWinBaseTestCase):
self.assertEqual(new_acl, returned_acl)
self._mock_run.assert_called_once_with(
_acl_utils.advapi.SetEntriesInAclW,
self._ctypes.c_ulong(mock.sentinel.entry_count),
_acl_utils.advapi32.SetEntriesInAclW,
mock.sentinel.entry_count,
mock.sentinel.entry_list,
mock.sentinel.old_acl,
new_acl)
@ -114,10 +115,10 @@ class ACLUtilsTestCase(test_base.OsWinBaseTestCase):
mock.sentinel.p_sacl)
self._mock_run.assert_called_once_with(
_acl_utils.advapi.SetNamedSecurityInfoW,
_acl_utils.advapi32.SetNamedSecurityInfoW,
self._ctypes.c_wchar_p(mock.sentinel.obj_name),
self._ctypes.c_uint(mock.sentinel.obj_type),
self._ctypes.c_uint(mock.sentinel.security_info_flags),
mock.sentinel.obj_type,
mock.sentinel.security_info_flags,
mock.sentinel.p_sid_owner,
mock.sentinel.p_sid_group,
mock.sentinel.p_dacl,

View File

@ -51,10 +51,10 @@ class HostUtilsTestCase(test_base.OsWinBaseTestCase):
super(HostUtilsTestCase, self).setUp()
@mock.patch('os_win.utils.hostutils.ctypes')
def test_get_host_tick_count64(self, mock_ctypes):
@mock.patch('os_win.utils.hostutils.kernel32')
def test_get_host_tick_count64(self, mock_kernel32):
tick_count64 = "100"
mock_ctypes.windll.kernel32.GetTickCount64.return_value = tick_count64
mock_kernel32.GetTickCount64.return_value = tick_count64
response = self._hostutils.get_host_tick_count64()
self.assertEqual(tick_count64, response)

View File

@ -21,8 +21,9 @@ import mock
from os_win import constants
from os_win import exceptions
from os_win.tests.unit import test_base
from os_win.utils import _acl_utils
from os_win.utils import pathutils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi.libs import advapi32 as advapi32_def
class PathUtilsTestCase(test_base.OsWinBaseTestCase):
@ -99,7 +100,7 @@ class PathUtilsTestCase(test_base.OsWinBaseTestCase):
@mock.patch.object(pathutils.shutil, 'rmtree')
def test_rmtree(self, mock_rmtree, mock_sleep):
exc = exceptions.WindowsError()
exc.winerror = pathutils.ERROR_DIR_IS_NOT_EMPTY
exc.winerror = w_const.ERROR_DIR_IS_NOT_EMPTY
mock_rmtree.side_effect = [exc] * 5 + [None]
self._pathutils.rmtree(mock.sentinel.FAKE_PATH)
@ -118,7 +119,7 @@ class PathUtilsTestCase(test_base.OsWinBaseTestCase):
def test_rmtree_exceeded(self):
exc = exceptions.WindowsError()
exc.winerror = pathutils.ERROR_DIR_IS_NOT_EMPTY
exc.winerror = w_const.ERROR_DIR_IS_NOT_EMPTY
self._check_rmtree(side_effect=[exc] * 6)
@mock.patch.object(pathutils.PathUtils, 'makedirs')
@ -164,6 +165,7 @@ class PathUtilsTestCase(test_base.OsWinBaseTestCase):
self._mock_run.assert_called_once_with(
pathutils.kernel32.GetFileAttributesW,
fake_path,
error_ret_vals=[w_const.INVALID_FILE_ATTRIBUTES],
kernel32_lib_func=True)
self.assertEqual(is_symlink, ret_value)
@ -287,23 +289,23 @@ class PathUtilsTestCase(test_base.OsWinBaseTestCase):
self._acl_utils.get_named_security_info.assert_called_once_with(
obj_name=mock.sentinel.path,
obj_type=_acl_utils.SE_FILE_OBJECT,
security_info_flags=_acl_utils.DACL_SECURITY_INFORMATION)
obj_type=w_const.SE_FILE_OBJECT,
security_info_flags=w_const.DACL_SECURITY_INFORMATION)
self._acl_utils.set_entries_in_acl.assert_called_once_with(
entry_count=1,
p_explicit_entry_list=mock.ANY,
p_old_acl=mock_sec_info['pp_dacl'].contents)
self._acl_utils.set_named_security_info.assert_called_once_with(
obj_name=mock.sentinel.path,
obj_type=_acl_utils.SE_FILE_OBJECT,
security_info_flags=_acl_utils.DACL_SECURITY_INFORMATION,
obj_type=w_const.SE_FILE_OBJECT,
security_info_flags=w_const.DACL_SECURITY_INFORMATION,
p_dacl=pp_new_dacl.contents)
p_access = self._acl_utils.set_entries_in_acl.call_args_list[0][1][
'p_explicit_entry_list']
access = ctypes.cast(
p_access,
ctypes.POINTER(_acl_utils.EXPLICIT_ACCESS)).contents
ctypes.POINTER(advapi32_def.EXPLICIT_ACCESS)).contents
self.assertEqual(constants.ACE_GENERIC_READ,
access.grfAccessPermissions)
@ -311,7 +313,7 @@ class PathUtilsTestCase(test_base.OsWinBaseTestCase):
access.grfAccessMode)
self.assertEqual(constants.ACE_OBJECT_INHERIT,
access.grfInheritance)
self.assertEqual(_acl_utils.TRUSTEE_IS_NAME,
self.assertEqual(w_const.TRUSTEE_IS_NAME,
access.Trustee.TrusteeForm)
self.assertEqual(fake_trustee,
access.Trustee.pstrName)
@ -336,12 +338,12 @@ class PathUtilsTestCase(test_base.OsWinBaseTestCase):
self._acl_utils.get_named_security_info.assert_called_once_with(
obj_name=mock.sentinel.src,
obj_type=_acl_utils.SE_FILE_OBJECT,
security_info_flags=_acl_utils.DACL_SECURITY_INFORMATION)
obj_type=w_const.SE_FILE_OBJECT,
security_info_flags=w_const.DACL_SECURITY_INFORMATION)
self._acl_utils.set_named_security_info.assert_called_once_with(
obj_name=mock.sentinel.dest,
obj_type=_acl_utils.SE_FILE_OBJECT,
security_info_flags=_acl_utils.DACL_SECURITY_INFORMATION,
obj_type=w_const.SE_FILE_OBJECT,
security_info_flags=w_const.DACL_SECURITY_INFORMATION,
p_dacl=mock_sec_info['pp_dacl'].contents)
self._pathutils._win32_utils.local_free.assert_called_once_with(

View File

@ -21,6 +21,7 @@ from oslotest import base
from os_win import _utils
from os_win import exceptions
from os_win.utils import win32utils
from os_win.utils.winapi import constants as w_const
@ddt.ddt
@ -162,9 +163,9 @@ class Win32UtilsTestCase(base.BaseTestCase):
fake_msg_buff = win32utils.ctypes.c_char_p.return_value
expected_flags = (win32utils.FORMAT_MESSAGE_FROM_SYSTEM |
win32utils.FORMAT_MESSAGE_ALLOCATE_BUFFER |
win32utils.FORMAT_MESSAGE_IGNORE_INSERTS)
expected_flags = (w_const.FORMAT_MESSAGE_FROM_SYSTEM |
w_const.FORMAT_MESSAGE_ALLOCATE_BUFFER |
w_const.FORMAT_MESSAGE_IGNORE_INSERTS)
win32utils.kernel32.FormatMessageA.assert_called_once_with(
expected_flags, None, mock.sentinel.err_code, 0,

View File

@ -14,39 +14,12 @@
# under the License.
import ctypes
import sys
from os_win.utils import win32utils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi import libs as w_lib
if sys.platform == 'win32':
advapi = ctypes.windll.AdvApi32
OWNER_SECURITY_INFORMATION = 0x00000001
GROUP_SECURITY_INFORMATION = 0x00000002
DACL_SECURITY_INFORMATION = 0x00000004
SACL_SECURITY_INFORMATION = 0x00000008
# Trustee form constants
TRUSTEE_IS_NAME = 1
# Indicates a file or directory object.
SE_FILE_OBJECT = 1
class TRUSTEE(ctypes.Structure):
_fields_ = [('pMultipleTrustee', ctypes.c_void_p),
('MultipleTrusteeOperation', ctypes.c_uint),
('TrusteeForm', ctypes.c_uint),
('TrusteeType', ctypes.c_uint),
('pstrName', ctypes.c_wchar_p)]
class EXPLICIT_ACCESS(ctypes.Structure):
_fields_ = [('grfAccessPermissions', ctypes.c_ulong),
('grfAccessMode', ctypes.c_uint),
('grfInheritance', ctypes.c_ulong),
('Trustee', TRUSTEE)]
advapi32 = w_lib.get_shared_lib_handle(w_lib.ADVAPI32)
class ACLUtils(object):
@ -70,21 +43,21 @@ class ACLUtils(object):
"""
sec_info = {}
if security_info_flags & OWNER_SECURITY_INFORMATION:
if security_info_flags & w_const.OWNER_SECURITY_INFORMATION:
sec_info['pp_sid_owner'] = self._get_void_pp()
if security_info_flags & GROUP_SECURITY_INFORMATION:
if security_info_flags & w_const.GROUP_SECURITY_INFORMATION:
sec_info['pp_sid_group'] = self._get_void_pp()
if security_info_flags & DACL_SECURITY_INFORMATION:
if security_info_flags & w_const.DACL_SECURITY_INFORMATION:
sec_info['pp_dacl'] = self._get_void_pp()
if security_info_flags & SACL_SECURITY_INFORMATION:
if security_info_flags & w_const.SACL_SECURITY_INFORMATION:
sec_info['pp_sacl'] = self._get_void_pp()
sec_info['pp_sec_desc'] = self._get_void_pp()
self._win32_utils.run_and_check_output(
advapi.GetNamedSecurityInfoW,
advapi32.GetNamedSecurityInfoW,
ctypes.c_wchar_p(obj_name),
ctypes.c_uint(obj_type),
ctypes.c_uint(security_info_flags),
obj_type,
security_info_flags,
sec_info.get('pp_sid_owner'),
sec_info.get('pp_sid_group'),
sec_info.get('pp_dacl'),
@ -99,8 +72,8 @@ class ACLUtils(object):
pp_new_acl = self._get_void_pp()
self._win32_utils.run_and_check_output(
advapi.SetEntriesInAclW,
ctypes.c_ulong(entry_count),
advapi32.SetEntriesInAclW,
entry_count,
p_explicit_entry_list,
p_old_acl,
pp_new_acl)
@ -111,10 +84,10 @@ class ACLUtils(object):
p_sid_owner=None, p_sid_group=None,
p_dacl=None, p_sacl=None):
self._win32_utils.run_and_check_output(
advapi.SetNamedSecurityInfoW,
advapi32.SetNamedSecurityInfoW,
ctypes.c_wchar_p(obj_name),
ctypes.c_uint(obj_type),
ctypes.c_uint(security_info_flags),
obj_type,
security_info_flags,
p_sid_owner,
p_sid_group,
p_dacl,

View File

@ -14,58 +14,19 @@
# under the License.
import ctypes
import sys
from os_win import constants
from os_win import exceptions
from os_win.utils import win32utils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi import libs as w_lib
from os_win.utils.winapi.libs import clusapi as clusapi_def
from os_win.utils.winapi import wintypes
if sys.platform == 'win32':
clusapi = ctypes.windll.clusapi
resutils = ctypes.windll.resutils
DWORD = ctypes.c_ulong
# TODO(lpetrut): aggregate windows specific constants
INVALID_HANDLE_VALUE = -1
CLUSPROP_SYNTAX_NAME = 262147
CLUSPROP_SYNTAX_ENDMARK = 0
CLUSPROP_SYNTAX_LIST_VALUE_DWORD = 65538
CLUSPROP_SYNTAX_LIST_VALUE_ULARGE_INTEGER = 65542
CLUSAPI_GROUP_MOVE_RETURN_TO_SOURCE_NODE_ON_ERROR = 2
CLUSAPI_GROUP_MOVE_QUEUE_ENABLED = 4
CLUSAPI_GROUP_MOVE_HIGH_PRIORITY_START = 8
CLUSTER_OBJECT_TYPE_GROUP = 2
CLUSTER_CHANGE_GROUP_COMMON_PROPERTY_V2 = 2
CLUSTER_CHANGE_GROUP_STATE_V2 = 8
CLUSGRP_STATUS_WAITING_IN_QUEUE_FOR_MOVE = 4
ERROR_MORE_DATA = 234
ERROR_INVALID_STATE = 5023
ERROR_WAIT_TIMEOUT = 258
ERROR_IO_PENDING = 997
CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES = 0x3000055
CLUSPROP_GROUP_STATUS_INFO = 'StatusInformation'
CLUSPROP_NAME_VM = 'Virtual Machine'
CLUSPROP_NAME_VM_CONFIG = 'Virtual Machine Configuration'
class NOTIFY_FILTER_AND_TYPE(ctypes.Structure):
_fields_ = [('dwObjectType', DWORD),
('FilterFlags', ctypes.c_longlong)]
clusapi = w_lib.get_shared_lib_handle(w_lib.CLUSAPI)
class ClusApiUtils(object):
_MAX_NODE_NAME = 255
_open_handle_check_flags = dict(ret_val_is_err_code=False,
error_on_nonzero_ret_val=False,
error_ret_vals=[0, None])
@ -89,8 +50,8 @@ class ClusApiUtils(object):
# For convenience, as opposed to the homonymous ClusAPI
# structure, we add the actual value as well.
class CLUSPROP_VALUE(ctypes.Structure):
_fields_ = [('syntax', DWORD),
('length', DWORD),
_fields_ = [('syntax', wintypes.DWORD),
('length', wintypes.DWORD),
('value', val_type),
('_padding', ctypes.c_ubyte * _get_padding())]
return CLUSPROP_VALUE
@ -106,11 +67,11 @@ class ClusApiUtils(object):
val_type=ctypes.c_wchar * name_len)),
('value', self._get_clusprop_value_struct(
val_type=ctypes.c_ubyte * val_sz)),
('_endmark', DWORD)
('_endmark', wintypes.DWORD)
]
entry = CLUSPROP_LIST_ENTRY()
entry.name.syntax = CLUSPROP_SYNTAX_NAME
entry.name.syntax = w_const.CLUSPROP_SYNTAX_NAME
entry.name.length = name_len * ctypes.sizeof(ctypes.c_wchar)
entry.name.value = name
@ -118,7 +79,7 @@ class ClusApiUtils(object):
entry.value.length = val_sz
entry.value.value[0:val_sz] = bytearray(value)
entry._endmark = CLUSPROP_SYNTAX_ENDMARK
entry._endmark = w_const.CLUSPROP_SYNTAX_ENDMARK
return entry
@ -127,7 +88,7 @@ class ClusApiUtils(object):
for entry in property_entries])
class CLUSPROP_LIST(ctypes.Structure):
_fields_ = [('count', DWORD),
_fields_ = [('count', wintypes.DWORD),
('entries_buff', ctypes.c_ubyte * prop_entries_sz)]
prop_list = CLUSPROP_LIST(count=len(property_entries))
@ -194,9 +155,9 @@ class ClusApiUtils(object):
clusapi.CancelClusterGroupOperation,
group_handle,
0, # cancel flags (reserved for future use by MS)
ignored_error_codes=[ERROR_IO_PENDING])
ignored_error_codes=[w_const.ERROR_IO_PENDING])
cancel_completed = ret_val != ERROR_IO_PENDING
cancel_completed = ret_val != w_const.ERROR_IO_PENDING
return cancel_completed
def move_cluster_group(self, group_handle, destination_node_handle,
@ -210,16 +171,17 @@ class ClusApiUtils(object):
move_flags,
prop_list_p,
prop_list_sz,
ignored_error_codes=[ERROR_IO_PENDING])
ignored_error_codes=[
w_const.ERROR_IO_PENDING])
def get_cluster_group_state(self, group_handle):
node_name_len = DWORD(self._MAX_NODE_NAME)
node_name_len = wintypes.DWORD(w_const.MAX_PATH)
node_name_buff = (ctypes.c_wchar * node_name_len.value)()
group_state = self._run_and_check_output(
clusapi.GetClusterGroupState,
group_handle,
ctypes.byref(node_name_buff),
node_name_buff,
ctypes.byref(node_name_len),
error_ret_vals=[constants.CLUSTER_GROUP_STATE_UNKNOWN],
error_on_nonzero_ret_val=False,
@ -251,7 +213,7 @@ class ClusApiUtils(object):
while waiting for events.
:return: the requested notify port handle,
"""
notif_port_h = notif_port_h or INVALID_HANDLE_VALUE
notif_port_h = notif_port_h or w_const.INVALID_HANDLE_VALUE
notif_filters_len = (len(notif_filters)
if isinstance(notif_filters, ctypes.Array)
else 1)
@ -275,14 +237,14 @@ class ClusApiUtils(object):
clusapi.CloseClusterNotifyPort(notif_port_h)
def get_cluster_notify_v2(self, notif_port_h, timeout_ms):
filter_and_type = NOTIFY_FILTER_AND_TYPE()
obj_name_buff_sz = ctypes.c_ulong(self._MAX_NODE_NAME)
notif_key_p = ctypes.c_void_p()
buff_sz = ctypes.c_ulong(self._MAX_NODE_NAME)
filter_and_type = clusapi_def.NOTIFY_FILTER_AND_TYPE()
obj_name_buff_sz = ctypes.c_ulong(w_const.MAX_PATH)
notif_key_p = wintypes.PDWORD()
buff_sz = ctypes.c_ulong(w_const.MAX_PATH)
# Event notification buffer. The notification format depends
# on the event type and filter flags.
buff = (ctypes.c_ubyte * buff_sz.value)()
buff = (wintypes.BYTE * buff_sz.value)()
obj_name_buff = (ctypes.c_wchar * obj_name_buff_sz.value)()
def get_args(buff, obj_name_buff):
@ -290,13 +252,13 @@ class ClusApiUtils(object):
notif_port_h,
ctypes.byref(notif_key_p),
ctypes.byref(filter_and_type),
ctypes.byref(buff),
buff,
ctypes.byref(buff_sz),
None, # object id
None, # object id sz
None, # parent id
None, # parent id sz
ctypes.byref(obj_name_buff),
obj_name_buff,
ctypes.byref(obj_name_buff_sz),
None, # object type
None, # object type sz
@ -304,10 +266,10 @@ class ClusApiUtils(object):
try:
self._run_and_check_output(*get_args(buff, obj_name_buff))
except exceptions.ClusterWin32Exception as ex:
if ex.error_code == ERROR_MORE_DATA:
if ex.error_code == w_const.ERROR_MORE_DATA:
# This function will specify the buffer sizes it needs using
# the references we pass.
buff = (ctypes.c_ubyte * buff_sz.value)()
buff = (wintypes.BYTE * buff_sz.value)()
obj_name_buff = (ctypes.c_wchar * obj_name_buff_sz.value)()
self._run_and_check_output(*get_args(buff, obj_name_buff))
@ -317,7 +279,7 @@ class ClusApiUtils(object):
# We'll leverage notification key values instead of their addresses,
# although this returns us the address we passed in when setting up
# the notification port.
notif_key = DWORD.from_address(notif_key_p.value).value
notif_key = notif_key_p.contents.value
event = {'cluster_object_name': obj_name_buff.value,
'object_type': filter_and_type.dwObjectType,
'filter_flags': filter_and_type.FilterFlags,
@ -344,20 +306,22 @@ class ClusApiUtils(object):
raise exceptions.ClusterPropertyListEntryNotFound(
property_name=property_name)
prop_name_len_pos = prop_name_pos - ctypes.sizeof(DWORD)
prop_name_len_pos = prop_name_pos - ctypes.sizeof(wintypes.DWORD)
prop_name_len_addr = prop_list_addr + prop_name_len_pos
prop_name_len = self._dword_align(
DWORD.from_address(prop_name_len_addr).value)
prop_addr = prop_name_len_addr + prop_name_len + ctypes.sizeof(DWORD)
if (prop_addr + ctypes.sizeof(DWORD * 3) >
wintypes.DWORD.from_address(prop_name_len_addr).value)
prop_addr = prop_name_len_addr + prop_name_len + ctypes.sizeof(
wintypes.DWORD)
if (prop_addr + ctypes.sizeof(wintypes.DWORD * 3) >
prop_list_addr + prop_list_sz):
raise exceptions.ClusterPropertyListParsingError()
prop_entry = {
'syntax': DWORD.from_address(prop_addr).value,
'length': DWORD.from_address(
prop_addr + ctypes.sizeof(DWORD)).value,
'val_p': ctypes.c_void_p(prop_addr + 2 * ctypes.sizeof(DWORD))
'syntax': wintypes.DWORD.from_address(prop_addr).value,
'length': wintypes.DWORD.from_address(
prop_addr + ctypes.sizeof(wintypes.DWORD)).value,
'val_p': ctypes.c_void_p(prop_addr + 2 * ctypes.sizeof(
wintypes.DWORD))
}
return prop_entry
@ -365,7 +329,7 @@ class ClusApiUtils(object):
def cluster_group_control(self, group_handle, control_code,
node_handle=None,
in_buff_p=None, in_buff_sz=0):
out_buff_sz = ctypes.c_ulong(self._MAX_NODE_NAME)
out_buff_sz = ctypes.c_ulong(w_const.MAX_PATH)
out_buff = (ctypes.c_ubyte * out_buff_sz.value)()
def get_args(out_buff):
@ -375,14 +339,14 @@ class ClusApiUtils(object):
control_code,
in_buff_p,
in_buff_sz,
ctypes.byref(out_buff),
out_buff,
out_buff_sz,
ctypes.byref(out_buff_sz))
try:
self._run_and_check_output(*get_args(out_buff))
except exceptions.ClusterWin32Exception as ex:
if ex.error_code == ERROR_MORE_DATA:
if ex.error_code == w_const.ERROR_MORE_DATA:
out_buff = (ctypes.c_ubyte * out_buff_sz.value)()
self._run_and_check_output(*get_args(out_buff))
else:
@ -393,11 +357,11 @@ class ClusApiUtils(object):
def get_cluster_group_status_info(self, prop_list_p, prop_list_sz):
prop_entry = self.get_prop_list_entry_p(
prop_list_p, prop_list_sz,
CLUSPROP_GROUP_STATUS_INFO)
w_const.CLUSREG_NAME_GRP_STATUS_INFORMATION)
if (prop_entry['length'] != ctypes.sizeof(ctypes.c_ulonglong) or
prop_entry['syntax'] !=
CLUSPROP_SYNTAX_LIST_VALUE_ULARGE_INTEGER):
w_const.CLUSPROP_SYNTAX_LIST_VALUE_ULARGE_INTEGER):
raise exceptions.ClusterPropertyListParsingError()
status_info_p = prop_entry['val_p']

View File

@ -35,6 +35,9 @@ from os_win import constants
from os_win import exceptions
from os_win.utils import baseutils
from os_win.utils.compute import _clusapi_utils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi.libs import clusapi as clusapi_def
from os_win.utils.winapi import wintypes
LOG = logging.getLogger(__name__)
@ -194,21 +197,21 @@ class ClusterUtils(baseutils.BaseUtils):
def _migrate_vm(self, vm_name, new_host, migration_type,
exp_state_after_migr, timeout):
syntax = _clusapi_utils.CLUSPROP_SYNTAX_LIST_VALUE_DWORD
migr_type = _clusapi_utils.DWORD(migration_type)
syntax = w_const.CLUSPROP_SYNTAX_LIST_VALUE_DWORD
migr_type = wintypes.DWORD(migration_type)
prop_entries = [
self._clusapi_utils.get_property_list_entry(
_clusapi_utils.CLUSPROP_NAME_VM, syntax, migr_type),
w_const.CLUS_RESTYPE_NAME_VM, syntax, migr_type),
self._clusapi_utils.get_property_list_entry(
_clusapi_utils.CLUSPROP_NAME_VM_CONFIG, syntax, migr_type)
w_const.CLUS_RESTYPE_NAME_VM_CONFIG, syntax, migr_type)
]
prop_list = self._clusapi_utils.get_property_list(prop_entries)
flags = (
_clusapi_utils.CLUSAPI_GROUP_MOVE_RETURN_TO_SOURCE_NODE_ON_ERROR |
_clusapi_utils.CLUSAPI_GROUP_MOVE_QUEUE_ENABLED |
_clusapi_utils.CLUSAPI_GROUP_MOVE_HIGH_PRIORITY_START)
w_const.CLUSAPI_GROUP_MOVE_RETURN_TO_SOURCE_NODE_ON_ERROR |
w_const.CLUSAPI_GROUP_MOVE_QUEUE_ENABLED |
w_const.CLUSAPI_GROUP_MOVE_HIGH_PRIORITY_START)
cluster_handle = None
group_handle = None
@ -319,7 +322,7 @@ class ClusterUtils(baseutils.BaseUtils):
group_state_info['status_info'],
expected_state)
if (ex.error_code == _clusapi_utils.ERROR_INVALID_STATE and
if (ex.error_code == w_const.ERROR_INVALID_STATE and
not migration_pending):
LOG.debug('Ignoring group migration cancel error. '
'No migration is pending.')
@ -343,7 +346,7 @@ class ClusterUtils(baseutils.BaseUtils):
def _is_migration_queued(self, group_status_info):
return bool(
group_status_info &
_clusapi_utils.CLUSGRP_STATUS_WAITING_IN_QUEUE_FOR_MOVE)
w_const.CLUSGRP_STATUS_WAITING_IN_QUEUE_FOR_MOVE)
def _is_migration_pending(self, group_state, group_status_info,
expected_state):
@ -431,7 +434,7 @@ class ClusterUtils(baseutils.BaseUtils):
buff, buff_sz = self._clusapi_utils.cluster_group_control(
group_handle,
_clusapi_utils.CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES)
w_const.CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES)
status_info = self._clusapi_utils.get_cluster_group_status_info(
ctypes.byref(buff), buff_sz)
@ -528,7 +531,7 @@ class _ClusterEventListener(object):
def _get_notif_key_dw(self, notif_key):
notif_key_dw = self._notif_keys.get(notif_key)
if notif_key_dw is None:
notif_key_dw = _clusapi_utils.DWORD(notif_key)
notif_key_dw = wintypes.DWORD(notif_key)
# We have to make sure those addresses are preserved.
self._notif_keys[notif_key] = notif_key_dw
return notif_key_dw
@ -543,7 +546,7 @@ class _ClusterEventListener(object):
def _setup_notif_port(self):
for notif_filter in self._notif_filters_list:
filter_struct = _clusapi_utils.NOTIFY_FILTER_AND_TYPE(
filter_struct = clusapi_def.NOTIFY_FILTER_AND_TYPE(
dwObjectType=notif_filter['object_type'],
FilterFlags=notif_filter['filter_flags'])
notif_key = notif_filter.get('notif_key', 0)
@ -617,12 +620,11 @@ class _ClusterGroupStateChangeListener(_ClusterEventListener):
_NOTIF_KEY_GROUP_COMMON_PROP = 1
_notif_filters_list = [
dict(object_type=_clusapi_utils.CLUSTER_OBJECT_TYPE_GROUP,
filter_flags=_clusapi_utils.CLUSTER_CHANGE_GROUP_STATE_V2,
dict(object_type=w_const.CLUSTER_OBJECT_TYPE_GROUP,
filter_flags=w_const.CLUSTER_CHANGE_GROUP_STATE_V2,
notif_key=_NOTIF_KEY_GROUP_STATE),
dict(object_type=_clusapi_utils.CLUSTER_OBJECT_TYPE_GROUP,
filter_flags=_clusapi_utils.
CLUSTER_CHANGE_GROUP_COMMON_PROPERTY_V2, # noqa
dict(object_type=w_const.CLUSTER_OBJECT_TYPE_GROUP,
filter_flags=w_const.CLUSTER_CHANGE_GROUP_COMMON_PROPERTY_V2,
notif_key=_NOTIF_KEY_GROUP_COMMON_PROP)]
def __init__(self, cluster_handle, group_name=None):
@ -642,10 +644,9 @@ class _ClusterGroupStateChangeListener(_ClusterEventListener):
notif_key = event['notif_key']
if notif_key == self._NOTIF_KEY_GROUP_STATE:
if event['buff_sz'] != ctypes.sizeof(_clusapi_utils.DWORD):
if event['buff_sz'] != ctypes.sizeof(wintypes.DWORD):
raise exceptions.ClusterPropertyRetrieveFailed()
state_p = ctypes.cast(event['buff'],
ctypes.POINTER(_clusapi_utils.DWORD))
state_p = ctypes.cast(event['buff'], wintypes.PDWORD)
state = state_p.contents.value
processed_event['state'] = state
return processed_event

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
import socket
from oslo_log import log as logging
@ -23,6 +22,9 @@ from os_win import _utils
from os_win import constants
from os_win import exceptions
from os_win.utils import baseutils
from os_win.utils.winapi import libs as w_lib
kernel32 = w_lib.get_shared_lib_handle(w_lib.KERNEL32)
LOG = logging.getLogger(__name__)
@ -75,7 +77,7 @@ class HostUtils(baseutils.BaseUtilsVirt):
def is_cpu_feature_present(self, feature_key):
"""Checks if the host's CPUs have the given feature."""
return ctypes.windll.kernel32.IsProcessorFeaturePresent(feature_key)
return kernel32.IsProcessorFeaturePresent(feature_key)
def get_memory_info(self):
"""Returns a tuple with total visible memory and free physical memory.
@ -129,7 +131,7 @@ class HostUtils(baseutils.BaseUtilsVirt):
def get_host_tick_count64(self):
"""Returns host uptime in miliseconds."""
return ctypes.windll.kernel32.GetTickCount64()
return kernel32.GetTickCount64()
def host_power_action(self, action):
win32_os = self._conn_cimv2.Win32_OperatingSystem()[0]

View File

@ -26,6 +26,11 @@ from os_win import _utils
from os_win import constants
from os_win import exceptions
from os_win.utils import win32utils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi import libs as w_lib
from os_win.utils.winapi import wintypes
kernel32 = w_lib.get_shared_lib_handle(w_lib.KERNEL32)
LOG = logging.getLogger(__name__)
@ -35,55 +40,6 @@ if sys.version_info > (3, 0):
else:
Queue = patcher.original('Queue')
if sys.platform == 'win32':
from ctypes import wintypes
kernel32 = ctypes.windll.kernel32
class OVERLAPPED(ctypes.Structure):
_fields_ = [
('Internal', wintypes.ULONG),
('InternalHigh', wintypes.ULONG),
('Offset', wintypes.DWORD),
('OffsetHigh', wintypes.DWORD),
('hEvent', wintypes.HANDLE)
]
def __init__(self):
self.Offset = 0
self.OffsetHigh = 0
LPOVERLAPPED = ctypes.POINTER(OVERLAPPED)
LPOVERLAPPED_COMPLETION_ROUTINE = ctypes.WINFUNCTYPE(
None, wintypes.DWORD, wintypes.DWORD, LPOVERLAPPED)
kernel32.ReadFileEx.argtypes = [
wintypes.HANDLE, wintypes.LPVOID, wintypes.DWORD,
LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE]
kernel32.WriteFileEx.argtypes = [
wintypes.HANDLE, wintypes.LPCVOID, wintypes.DWORD,
LPOVERLAPPED, LPOVERLAPPED_COMPLETION_ROUTINE]
FILE_FLAG_OVERLAPPED = 0x40000000
FILE_SHARE_READ = 1
FILE_SHARE_WRITE = 2
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
OPEN_EXISTING = 3
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
INVALID_HANDLE_VALUE = -1
WAIT_FAILED = 0xFFFFFFFF
WAIT_FINISHED = 0
ERROR_INVALID_HANDLE = 6
ERROR_PIPE_BUSY = 231
ERROR_PIPE_NOT_CONNECTED = 233
ERROR_NOT_FOUND = 1168
WAIT_PIPE_DEFAULT_TIMEOUT = 5 # seconds
WAIT_IO_COMPLETION_TIMEOUT = 2 * units.k
WAIT_INFINITE_TIMEOUT = 0xFFFFFFFF
@ -115,7 +71,7 @@ class IOUtils(object):
def open(self, path, desired_access=None, share_mode=None,
creation_disposition=None, flags_and_attributes=None):
error_ret_vals = [INVALID_HANDLE_VALUE]
error_ret_vals = [w_const.INVALID_HANDLE_VALUE]
handle = self._run_and_check_output(kernel32.CreateFileW,
ctypes.c_wchar_p(path),
desired_access,
@ -139,9 +95,9 @@ class IOUtils(object):
"""
# Ignore errors thrown when there are no requests
# to be canceled.
ignored_error_codes = [ERROR_NOT_FOUND]
ignored_error_codes = [w_const.ERROR_NOT_FOUND]
if ignore_invalid_handle:
ignored_error_codes.append(ERROR_INVALID_HANDLE)
ignored_error_codes.append(w_const.ERROR_INVALID_HANDLE)
lp_overlapped = (ctypes.byref(overlapped_structure)
if overlapped_structure else None)
@ -154,7 +110,7 @@ class IOUtils(object):
# In order to cancel this, we simply set the event.
self._run_and_check_output(kernel32.WaitForSingleObjectEx,
event, WAIT_INFINITE_TIMEOUT,
True, error_ret_vals=[WAIT_FAILED])
True, error_ret_vals=[w_const.WAIT_FAILED])
def set_event(self, event):
self._run_and_check_output(kernel32.SetEvent, event)
@ -172,20 +128,21 @@ class IOUtils(object):
def get_completion_routine(self, callback=None):
def _completion_routine(error_code, num_bytes, lpOverLapped):
"""Sets the completion event and executes callback, if passed."""
overlapped = ctypes.cast(lpOverLapped, LPOVERLAPPED).contents
overlapped = ctypes.cast(lpOverLapped,
wintypes.LPOVERLAPPED).contents
self.set_event(overlapped.hEvent)
if callback:
callback(num_bytes)
return LPOVERLAPPED_COMPLETION_ROUTINE(_completion_routine)
return wintypes.LPOVERLAPPED_COMPLETION_ROUTINE(_completion_routine)
def get_new_overlapped_structure(self):
"""Structure used for asyncronous IO operations."""
# Event used for signaling IO completion
hEvent = self._create_event()
overlapped_structure = OVERLAPPED()
overlapped_structure = wintypes.OVERLAPPED()
overlapped_structure.hEvent = hEvent
return overlapped_structure

View File

@ -23,6 +23,7 @@ from os_win._i18n import _
from os_win import constants
from os_win import exceptions
from os_win.utils.io import ioutils
from os_win.utils.winapi import constants as w_const
threading = patcher.original('threading')
time = patcher.original('time')
@ -136,10 +137,10 @@ class NamedPipeHandler(object):
self._pipe_handle = self._ioutils.open(
self._pipe_name,
desired_access=(ioutils.GENERIC_READ | ioutils.GENERIC_WRITE),
share_mode=(ioutils.FILE_SHARE_READ | ioutils.FILE_SHARE_WRITE),
creation_disposition=ioutils.OPEN_EXISTING,
flags_and_attributes=ioutils.FILE_FLAG_OVERLAPPED)
desired_access=(w_const.GENERIC_READ | w_const.GENERIC_WRITE),
share_mode=(w_const.FILE_SHARE_READ | w_const.FILE_SHARE_WRITE),
creation_disposition=w_const.OPEN_EXISTING,
flags_and_attributes=w_const.FILE_FLAG_OVERLAPPED)
def _close_pipe(self):
if self._pipe_handle:

View File

@ -29,18 +29,17 @@ from os_win import _utils
from os_win import exceptions
from os_win.utils import _acl_utils
from os_win.utils import win32utils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi import libs as w_lib
from os_win.utils.winapi.libs import advapi32 as advapi32_def
from os_win.utils.winapi import wintypes
if sys.platform == 'win32':
from ctypes import wintypes
kernel32 = ctypes.windll.kernel32
kernel32 = w_lib.get_shared_lib_handle(w_lib.KERNEL32)
LOG = logging.getLogger(__name__)
ERROR_DIR_IS_NOT_EMPTY = 145
class PathUtils(object):
_FILE_ATTRIBUTE_REPARSE_POINT = 0x0400
def __init__(self):
self._win32_utils = win32utils.Win32Utils()
@ -126,7 +125,7 @@ class PathUtils(object):
self.rename(src, os.path.join(dest_dir, fname))
@_utils.retry_decorator(exceptions=exceptions.OSWinException,
error_codes=[ERROR_DIR_IS_NOT_EMPTY])
error_codes=[w_const.ERROR_DIR_IS_NOT_EMPTY])
def rmtree(self, path):
try:
shutil.rmtree(path)
@ -152,11 +151,12 @@ class PathUtils(object):
file_attr = self._win32_utils.run_and_check_output(
kernel32.GetFileAttributesW,
six.text_type(path),
path,
error_ret_vals=[w_const.INVALID_FILE_ATTRIBUTES],
kernel32_lib_func=True)
return bool(os.path.isdir(path) and (
file_attr & self._FILE_ATTRIBUTE_REPARSE_POINT))
file_attr & w_const.FILE_ATTRIBUTE_REPARSE_POINT))
def create_sym_link(self, link, target, target_is_dir=True):
"""If target_is_dir is True, a junction will be created.
@ -164,15 +164,7 @@ class PathUtils(object):
NOTE: Juctions only work on same filesystem.
"""
create_symlink = kernel32.CreateSymbolicLinkW
create_symlink.argtypes = (
ctypes.c_wchar_p,
ctypes.c_wchar_p,
ctypes.c_ulong,
)
create_symlink.restype = ctypes.c_ubyte
self._win32_utils.run_and_check_output(create_symlink,
self._win32_utils.run_and_check_output(kernel32.CreateSymbolicLinkW,
link,
target,
target_is_dir,
@ -211,15 +203,15 @@ class PathUtils(object):
try:
sec_info = self._acl_utils.get_named_security_info(
obj_name=path,
obj_type=_acl_utils.SE_FILE_OBJECT,
security_info_flags=_acl_utils.DACL_SECURITY_INFORMATION)
obj_type=w_const.SE_FILE_OBJECT,
security_info_flags=w_const.DACL_SECURITY_INFORMATION)
p_to_free.append(sec_info['pp_sec_desc'].contents)
access = _acl_utils.EXPLICIT_ACCESS()
access = advapi32_def.EXPLICIT_ACCESS()
access.grfAccessPermissions = access_rights
access.grfAccessMode = access_mode
access.grfInheritance = inheritance_flags
access.Trustee.TrusteeForm = _acl_utils.TRUSTEE_IS_NAME
access.Trustee.TrusteeForm = w_const.TRUSTEE_IS_NAME
access.Trustee.pstrName = ctypes.c_wchar_p(trustee_name)
pp_new_dacl = self._acl_utils.set_entries_in_acl(
@ -230,8 +222,8 @@ class PathUtils(object):
self._acl_utils.set_named_security_info(
obj_name=path,
obj_type=_acl_utils.SE_FILE_OBJECT,
security_info_flags=_acl_utils.DACL_SECURITY_INFORMATION,
obj_type=w_const.SE_FILE_OBJECT,
security_info_flags=w_const.DACL_SECURITY_INFORMATION,
p_dacl=pp_new_dacl.contents)
finally:
for p in p_to_free:
@ -241,16 +233,16 @@ class PathUtils(object):
p_to_free = []
try:
sec_info_flags = _acl_utils.DACL_SECURITY_INFORMATION
sec_info_flags = w_const.DACL_SECURITY_INFORMATION
sec_info = self._acl_utils.get_named_security_info(
obj_name=source_path,
obj_type=_acl_utils.SE_FILE_OBJECT,
obj_type=w_const.SE_FILE_OBJECT,
security_info_flags=sec_info_flags)
p_to_free.append(sec_info['pp_sec_desc'].contents)
self._acl_utils.set_named_security_info(
obj_name=dest_path,
obj_type=_acl_utils.SE_FILE_OBJECT,
obj_type=w_const.SE_FILE_OBJECT,
security_info_flags=sec_info_flags,
p_dacl=sec_info['pp_dacl'].contents)
finally:

View File

@ -17,7 +17,6 @@ import collections
import ctypes
import os
import re
import sys
from oslo_log import log as logging
@ -26,9 +25,9 @@ from os_win import _utils
from os_win import exceptions
from os_win.utils import baseutils
from os_win.utils import win32utils
from os_win.utils.winapi import libs as w_lib
if sys.platform == 'win32':
kernel32 = ctypes.windll.kernel32
kernel32 = w_lib.get_shared_lib_handle(w_lib.KERNEL32)
LOG = logging.getLogger(__name__)

View File

@ -15,7 +15,6 @@
import contextlib
import ctypes
import sys
import textwrap
from oslo_log import log as logging
@ -25,13 +24,14 @@ from os_win._i18n import _
from os_win import _utils
import os_win.conf
from os_win import exceptions
from os_win.utils.storage.initiator import fc_structures as fc_struct
from os_win.utils import win32utils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi import libs as w_lib
from os_win.utils.winapi.libs import hbaapi as fc_struct
CONF = os_win.conf.CONF
if sys.platform == 'win32':
hbaapi = ctypes.cdll.LoadLibrary(CONF.os_win.hbaapi_lib_path)
hbaapi = w_lib.get_shared_lib_handle(w_lib.HBAAPI)
LOG = logging.getLogger(__name__)
@ -50,40 +50,51 @@ class FCUtils(object):
def get_fc_hba_count(self):
return hbaapi.HBA_GetNumberOfAdapters()
def _open_adapter(self, adapter_name=None, adapter_wwn=None):
if adapter_name:
func = hbaapi.HBA_OpenAdapter
arg = ctypes.c_char_p(six.b(adapter_name))
elif adapter_wwn:
func = hbaapi.HBA_OpenAdapterByWWN
arg = fc_struct.HBA_WWN(*adapter_wwn)
else:
err_msg = _("Could not open HBA adapter. "
"No HBA name or WWN was specified")
raise exceptions.FCException(err_msg)
def _open_adapter_by_name(self, adapter_name):
handle = self._run_and_check_output(
hbaapi.HBA_OpenAdapter,
ctypes.c_char_p(six.b(adapter_name)),
ret_val_is_err_code=False,
error_on_nonzero_ret_val=False,
error_ret_vals=[0])
return handle
def _open_adapter_by_wwn(self, adapter_wwn):
handle = fc_struct.HBA_HANDLE()
hba_wwn = fc_struct.HBA_WWN()
hba_wwn.wwn[:] = adapter_wwn
self._run_and_check_output(
hbaapi.HBA_OpenAdapterByWWN,
ctypes.byref(handle),
hba_wwn)
handle = self._run_and_check_output(func, arg,
ret_val_is_err_code=False,
error_on_nonzero_ret_val=False,
error_ret_vals=[0])
return handle
def _close_adapter(self, hba_handle):
hbaapi.HBA_CloseAdapter(hba_handle)
@contextlib.contextmanager
def _get_hba_handle(self, *args, **kwargs):
hba_handle = self._open_adapter(*args, **kwargs)
def _get_hba_handle(self, adapter_name=None, adapter_wwn=None):
if adapter_name:
hba_handle = self._open_adapter_by_name(adapter_name)
elif adapter_wwn:
hba_handle = self._open_adapter_by_wwn(adapter_wwn)
else:
err_msg = _("Could not open HBA adapter. "
"No HBA name or WWN was specified")
raise exceptions.FCException(err_msg)
try:
yield hba_handle
finally:
self._close_adapter(hba_handle)
def _get_adapter_name(self, adapter_index):
buff = (ctypes.c_char * 256)()
buff = (ctypes.c_char * w_const.MAX_ISCSI_HBANAME_LEN)()
self._run_and_check_output(hbaapi.HBA_GetAdapterName,
ctypes.c_uint32(adapter_index),
ctypes.byref(buff))
buff)
return buff.value.decode('utf-8')
@ -130,8 +141,8 @@ class FCUtils(object):
port_attributes = self._get_adapter_port_attributes(
hba_handle,
port_index)
wwnn = self._wwn_array_to_hex_str(port_attributes.NodeWWN)
wwpn = self._wwn_array_to_hex_str(port_attributes.PortWWN)
wwnn = self._wwn_array_to_hex_str(port_attributes.NodeWWN.wwn)
wwpn = self._wwn_array_to_hex_str(port_attributes.PortWWN.wwn)
hba_port_info = dict(node_name=wwnn,
port_name=wwpn)
@ -176,8 +187,8 @@ class FCUtils(object):
with self._get_hba_handle(adapter_wwn=node_wwn) as hba_handle:
fcp_mappings = self._get_target_mapping(hba_handle)
for entry in fcp_mappings.Entries:
wwnn = self._wwn_array_to_hex_str(entry.FcpId.NodeWWN)
wwpn = self._wwn_array_to_hex_str(entry.FcpId.PortWWN)
wwnn = self._wwn_array_to_hex_str(entry.FcpId.NodeWWN.wwn)
wwpn = self._wwn_array_to_hex_str(entry.FcpId.PortWWN.wwn)
mapping = dict(node_name=wwnn,
port_name=wwpn,
device_name=entry.ScsiId.OSDeviceName,

View File

@ -18,28 +18,32 @@ import ctypes
import functools
import inspect
import socket
import sys
import time
from oslo_log import log as logging
import six
from os_win import _utils
from os_win import constants
from os_win import exceptions
from os_win.utils.storage import diskutils
from os_win.utils.storage.initiator import iscsidsc_structures as iscsi_struct
from os_win.utils.storage.initiator import iscsierr
from os_win.utils import win32utils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi.errmsg import iscsierr
from os_win.utils.winapi import libs as w_lib
from os_win.utils.winapi.libs import iscsidsc as iscsi_struct
if sys.platform == 'win32':
iscsidsc = ctypes.windll.iscsidsc
iscsidsc = w_lib.get_shared_lib_handle(w_lib.ISCSIDSC)
LOG = logging.getLogger(__name__)
ERROR_INSUFFICIENT_BUFFER = 0x7a
def _get_buff(size, item_type):
buff = (ctypes.c_ubyte * size)()
return ctypes.cast(buff, ctypes.POINTER(item_type))
def ensure_buff_and_retrieve_items(struct_type=None,
def ensure_buff_and_retrieve_items(struct_type,
func_requests_buff_sz=True,
parse_output=True):
# The iscsidsc.dll functions retrieving data accept a buffer, which will
@ -47,12 +51,17 @@ def ensure_buff_and_retrieve_items(struct_type=None,
# the error code will show it. In this case, the decorator will adjust the
# buffer size based on the buffer size or the element count provided by
# the function, attempting to call it again.
#
# We need to provide a buffer large enough to store the retrieved data.
# This may be more than the size of the retrieved structures as those
# may contain pointers. We're also casting the buffer to the appropriate
# type as function parameters are validated.
def wrapper(f):
@functools.wraps(f)
def inner(*args, **kwargs):
call_args = inspect.getcallargs(f, *args, **kwargs)
call_args['element_count'] = ctypes.c_ulong(0)
call_args['buff'] = (ctypes.c_ubyte * 0)()
call_args['buff'] = _get_buff(0, struct_type)
call_args['buff_size'] = ctypes.c_ulong(0)
while True:
@ -66,13 +75,14 @@ def ensure_buff_and_retrieve_items(struct_type=None,
else:
return ret_val
except exceptions.Win32Exception as ex:
if (ex.error_code & 0xFFFF) == ERROR_INSUFFICIENT_BUFFER:
if (ex.error_code & 0xFFFF ==
w_const.ERROR_INSUFFICIENT_BUFFER):
if func_requests_buff_sz:
buff_size = call_args['buff_size'].value
else:
buff_size = (ctypes.sizeof(struct_type) *
call_args['element_count'].value)
call_args['buff'] = (ctypes.c_ubyte * buff_size)()
call_args['buff'] = _get_buff(buff_size, struct_type)
else:
raise
return inner
@ -93,6 +103,7 @@ retry_decorator = functools.partial(
class ISCSIInitiatorUtils(object):
_DEFAULT_RESCAN_ATTEMPTS = 3
_MS_IQN_PREFIX = "iqn.1991-05.com.microsoft"
_DEFAULT_ISCSI_PORT = 3260
def __init__(self):
self._win32utils = win32utils.Win32Utils()
@ -110,7 +121,7 @@ class ISCSIInitiatorUtils(object):
self._run_and_check_output(
iscsidsc.ReportIScsiPersistentLoginsW,
ctypes.byref(element_count),
ctypes.byref(buff),
buff,
ctypes.byref(buff_size))
@ensure_buff_and_retrieve_items(
@ -124,15 +135,15 @@ class ISCSIInitiatorUtils(object):
iscsidsc.ReportIScsiTargetsW,
forced_update,
ctypes.byref(element_count),
ctypes.byref(buff))
buff)
return self._parse_string_list(buff, element_count.value)
def get_iscsi_initiator(self):
"""Returns the initiator node name."""
try:
buff = (ctypes.c_wchar * (iscsi_struct.MAX_ISCSI_NAME_LEN + 1))()
buff = (ctypes.c_wchar * (w_const.MAX_ISCSI_NAME_LEN + 1))()
self._run_and_check_output(iscsidsc.GetIScsiInitiatorNodeNameW,
ctypes.byref(buff))
buff)
return buff.value
except exceptions.ISCSIInitiatorAPIException as ex:
LOG.info("The ISCSI initiator node name can't be found. "
@ -149,7 +160,7 @@ class ISCSIInitiatorUtils(object):
self._run_and_check_output(
iscsidsc.ReportIScsiInitiatorListW,
ctypes.byref(element_count),
ctypes.byref(buff))
buff)
return self._parse_string_list(buff, element_count.value)
@staticmethod
@ -160,7 +171,7 @@ class ISCSIInitiatorUtils(object):
str_list = str_list.split('\x00') if str_list else []
return str_list
@retry_decorator(error_codes=iscsi_struct.ERROR_INSUFFICIENT_BUFFER)
@retry_decorator(error_codes=w_const.ERROR_INSUFFICIENT_BUFFER)
def _login_iscsi_target(self, target_name, portal=None, login_opts=None,
is_persistent=True, initiator_name=None):
session_id = iscsi_struct.ISCSI_UNIQUE_SESSION_ID()
@ -177,10 +188,9 @@ class ISCSIInitiatorUtils(object):
ctypes.c_wchar_p(target_name),
False, # IsInformationalSession
initiator_name_ref,
ctypes.c_ulong(iscsi_struct.ISCSI_ANY_INITIATOR_PORT),
ctypes.c_ulong(w_const.ISCSI_ANY_INITIATOR_PORT),
portal_ref,
iscsi_struct.ISCSI_SECURITY_FLAGS(
iscsi_struct.ISCSI_DEFAULT_SECURITY_FLAGS),
iscsi_struct.ISCSI_SECURITY_FLAGS(),
None, # Security flags / mappings (using default / auto)
login_opts_ref,
ctypes.c_ulong(0),
@ -188,7 +198,7 @@ class ISCSIInitiatorUtils(object):
is_persistent,
ctypes.byref(session_id),
ctypes.byref(connection_id),
ignored_error_codes=[iscsierr.ISDSC_TARGET_ALREADY_LOGGED_IN])
ignored_error_codes=[w_const.ISDSC_TARGET_ALREADY_LOGGED_IN])
return session_id, connection_id
@ensure_buff_and_retrieve_items(
@ -199,7 +209,7 @@ class ISCSIInitiatorUtils(object):
iscsidsc.GetIScsiSessionListW,
ctypes.byref(buff_size),
ctypes.byref(element_count),
ctypes.byref(buff))
buff)
def _get_iscsi_target_sessions(self, target_name, connected_only=True):
sessions = self._get_iscsi_sessions()
@ -208,8 +218,8 @@ class ISCSIInitiatorUtils(object):
and session.TargetNodeName.upper() == target_name.upper()
and (session.ConnectionCount > 0 or not connected_only)]
@retry_decorator(error_codes=(iscsierr.ISDSC_SESSION_BUSY,
iscsierr.ISDSC_DEVICE_BUSY_ON_SESSION))
@retry_decorator(error_codes=(w_const.ISDSC_SESSION_BUSY,
w_const.ISDSC_DEVICE_BUSY_ON_SESSION))
@ensure_buff_and_retrieve_items(
struct_type=iscsi_struct.ISCSI_DEVICE_ON_SESSION,
func_requests_buff_sz=False)
@ -220,13 +230,13 @@ class ISCSIInitiatorUtils(object):
iscsidsc.GetDevicesForIScsiSessionW,
ctypes.byref(session_id),
ctypes.byref(element_count),
ctypes.byref(buff))
buff)
def _get_iscsi_session_disk_luns(self, session_id):
devices = self._get_iscsi_session_devices(session_id)
luns = [device.ScsiAddress.Lun for device in devices
if (device.StorageDeviceNumber.DeviceType ==
iscsi_struct.FILE_DEVICE_DISK)]
w_const.FILE_DEVICE_DISK)]
return luns
def _get_iscsi_device_from_session(self, session_id, target_lun):
@ -272,7 +282,7 @@ class ISCSIInitiatorUtils(object):
def get_target_lun_count(self, target_name):
return len(self.get_target_luns(target_name))
@retry_decorator(error_codes=iscsierr.ISDSC_SESSION_BUSY)
@retry_decorator(error_codes=w_const.ISDSC_SESSION_BUSY)
def _logout_iscsi_target(self, session_id):
self._run_and_check_output(
iscsidsc.LogoutIScsiTarget,
@ -289,21 +299,37 @@ class ISCSIInitiatorUtils(object):
None) # Portal group
def _remove_static_target(self, target_name):
ignored_error_codes = [iscsierr.ISDSC_TARGET_NOT_FOUND]
ignored_error_codes = [w_const.ISDSC_TARGET_NOT_FOUND]
self._run_and_check_output(iscsidsc.RemoveIScsiStaticTargetW,
ctypes.c_wchar_p(target_name),
ignored_error_codes=ignored_error_codes)
def _get_login_opts(self, auth_username, auth_password, auth_type,
login_flags=0):
def _get_login_opts(self, auth_username=None, auth_password=None,
auth_type=None, login_flags=0):
if auth_type is None:
auth_type = (constants.ISCSI_CHAP_AUTH_TYPE
if auth_username and auth_password
else constants.ISCSI_NO_AUTH_TYPE)
login_opts = iscsi_struct.ISCSI_LOGIN_OPTIONS(Username=auth_username,
Password=auth_password,
AuthType=auth_type,
LoginFlags=login_flags)
login_opts = iscsi_struct.ISCSI_LOGIN_OPTIONS()
info_bitmap = 0
if auth_username:
login_opts.Username = six.b(auth_username)
login_opts.UsernameLength = len(auth_username)
info_bitmap |= w_const.ISCSI_LOGIN_OPTIONS_USERNAME
if auth_password:
login_opts.Password = six.b(auth_password)
login_opts.PasswordLength = len(auth_password)
info_bitmap |= w_const.ISCSI_LOGIN_OPTIONS_PASSWORD
login_opts.AuthType = auth_type
info_bitmap |= w_const.ISCSI_LOGIN_OPTIONS_AUTH_TYPE
login_opts.InformationSpecified = info_bitmap
login_opts.LoginFlags = login_flags
return login_opts
def _session_on_path_exists(self, target_sessions, portal_addr,
@ -354,7 +380,7 @@ class ISCSIInitiatorUtils(object):
rescan_attempts=_DEFAULT_RESCAN_ATTEMPTS):
portal_addr, portal_port = _utils.parse_server_string(target_portal)
portal_port = (int(portal_port)
if portal_port else iscsi_struct.DEFAULT_ISCSI_PORT)
if portal_port else self._DEFAULT_ISCSI_PORT)
known_targets = self.get_targets()
if target_iqn not in known_targets:
@ -370,7 +396,7 @@ class ISCSIInitiatorUtils(object):
# If the multipath flag is set, multiple sessions to the same
# target may be estabilished. MPIO must be enabled and configured
# to claim iSCSI disks, otherwise data corruption can occur.
login_flags = (iscsi_struct.ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED
login_flags = (w_const.ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED
if mpio_enabled else 0)
login_opts = self._get_login_opts(auth_username,
auth_password,
@ -432,8 +458,8 @@ class ISCSIInitiatorUtils(object):
raise exceptions.ISCSILunNotAvailable(target_lun=target_lun,
target_iqn=target_iqn)
@retry_decorator(error_codes=(iscsierr.ISDSC_SESSION_BUSY,
iscsierr.ISDSC_DEVICE_BUSY_ON_SESSION))
@retry_decorator(error_codes=(w_const.ISDSC_SESSION_BUSY,
w_const.ISDSC_DEVICE_BUSY_ON_SESSION))
def logout_storage_target(self, target_iqn):
LOG.debug("Logging out iSCSI target %(target_iqn)s",
dict(target_iqn=target_iqn))

View File

@ -1,189 +0,0 @@
# Copyright 2016 Cloudbase Solutions Srl
#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
import sys
from os_win.utils.io import ioutils
if sys.platform == 'win32':
iscsidsc = ctypes.windll.iscsidsc
DEFAULT_ISCSI_PORT = 3260
ISCSI_ANY_INITIATOR_PORT = -1
ISCSI_ALL_INITIATOR_PORTS = -1
ISCSI_DEFAULT_SECURITY_FLAGS = 0
MAX_ISCSI_PORTAL_NAME_LEN = 256
MAX_ISCSI_PORTAL_ADDRESS_LEN = 256
MAX_ISCSI_NAME_LEN = 223
MAX_ISCSI_HBANAME_LEN = 256
MAX_PATH = 260
SENSE_BUFF_SIZE = 18
PUCHAR = ctypes.POINTER(ctypes.c_ubyte)
ISCSI_SECURITY_FLAGS = ctypes.c_ulonglong
ISCSI_LOGIN_FLAGS = ctypes.c_uint32
ISCSI_LOGIN_OPTIONS_INFO_SPECIFIED = ctypes.c_uint32
ISCSI_AUTH_TYPES = ctypes.c_int
ISCSI_DIGEST_TYPES = ctypes.c_int
DEVICE_TYPE = ctypes.c_ulong
FILE_DEVICE_DISK = 7
ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED = 2
ISCSI_LOGIN_OPTIONS_USERNAME = 0x00000020
ISCSI_LOGIN_OPTIONS_PASSWORD = 0x00000040
ISCSI_LOGIN_OPTIONS_AUTH_TYPE = 0x00000080
ERROR_INSUFFICIENT_BUFFER = 122
class GUID(ctypes.Structure):
# This is also used in virdisk_structures.py, we should move
# common structures to a common module.
_fields_ = [("Data1", ctypes.c_ulong),
("Data2", ctypes.c_ushort),
("Data3", ctypes.c_ushort),
("Data4", ctypes.c_byte * 8)]
class ISCSI_TARGET_PORTAL(ctypes.Structure):
_fields_ = [('SymbolicName', ctypes.c_wchar * MAX_ISCSI_PORTAL_NAME_LEN),
('Address', ctypes.c_wchar * MAX_ISCSI_PORTAL_ADDRESS_LEN),
('Socket', ctypes.c_ushort)]
class ISCSI_LOGIN_OPTIONS(ctypes.Structure):
_fields_ = [('Version', ctypes.c_ulong),
('InformationSpecified', ISCSI_LOGIN_OPTIONS_INFO_SPECIFIED),
('LoginFlags', ISCSI_LOGIN_FLAGS),
('AuthType', ISCSI_AUTH_TYPES),
('HeaderDigest', ISCSI_DIGEST_TYPES),
('DataDigest', ISCSI_DIGEST_TYPES),
('MaximumConnections', ctypes.c_ulong),
('DefaultTime2Wait', ctypes.c_ulong),
('DefaultTime2Retain', ctypes.c_ulong),
('UsernameLength', ctypes.c_ulong),
('PasswordLength', ctypes.c_ulong),
('Username', PUCHAR),
('Password', PUCHAR)]
def __init__(self, Username=None, Password=None, AuthType=None,
LoginFlags=0):
info_bitmap = 0
if Username:
username_buff = ioutils.IOUtils.get_buffer(len(Username),
Username)
self.Username = ctypes.cast(username_buff, PUCHAR)
self.UsernameLength = len(Username)
info_bitmap |= ISCSI_LOGIN_OPTIONS_USERNAME
if Password:
pwd_buff = ioutils.IOUtils.get_buffer(len(Password),
Password)
self.Password = ctypes.cast(pwd_buff, PUCHAR)
self.PasswordLength = len(Password)
info_bitmap |= ISCSI_LOGIN_OPTIONS_PASSWORD
if AuthType is not None:
self.AuthType = AuthType
info_bitmap |= ISCSI_LOGIN_OPTIONS_AUTH_TYPE
self.InformationSpecified = info_bitmap
self.LoginFlags = LoginFlags
class SCSI_LUN_LIST(ctypes.Structure):
_fields_ = [('OSLUN', ctypes.c_ulonglong),
('TargetLUN', ctypes.c_ulonglong)]
class ISCSI_UNIQUE_SESSION_ID(ctypes.Structure):
_fields_ = [('AdapterUnique', ctypes.c_ulonglong),
('AdapterSpecific', ctypes.c_ulonglong)]
class ISCSI_UNIQUE_CONNECTION_ID(ISCSI_UNIQUE_SESSION_ID):
pass
class ISCSI_TARGET_MAPPING(ctypes.Structure):
_fields_ = [('InitiatorName', ctypes.c_wchar * MAX_ISCSI_HBANAME_LEN),
('TargetName', ctypes.c_wchar * (MAX_ISCSI_NAME_LEN + 1)),
('OSDeviceName', ctypes.c_wchar * MAX_PATH),
('SessionId', ISCSI_UNIQUE_SESSION_ID),
('OSBusNumber', ctypes.c_ulong),
('OSTargetNumber', ctypes.c_ulong),
('LUNCount', ctypes.c_ulong),
('LUNList', ctypes.POINTER(SCSI_LUN_LIST))]
PISCSI_TARGET_PORTAL = ctypes.POINTER(ISCSI_TARGET_PORTAL)
PISCSI_TARGET_MAPPING = ctypes.POINTER(ISCSI_TARGET_MAPPING)
class PERSISTENT_ISCSI_LOGIN_INFO(ctypes.Structure):
_fields_ = [('TargetName', ctypes.c_wchar * (MAX_ISCSI_NAME_LEN + 1)),
('IsInformationalSession', ctypes.c_bool),
('InitiatorInstance', ctypes.c_wchar * MAX_ISCSI_HBANAME_LEN),
('InitiatorPortNumber', ctypes.c_ulong),
('TargetPortal', ISCSI_TARGET_PORTAL),
('SecurityFlags', ISCSI_SECURITY_FLAGS),
('Mappings', PISCSI_TARGET_MAPPING),
('LoginOptions', ISCSI_LOGIN_OPTIONS)]
class ISCSI_CONNECTION_INFO(ctypes.Structure):
_fields_ = [('ConnectionId', ISCSI_UNIQUE_CONNECTION_ID),
('InitiatorAddress', ctypes.c_wchar_p),
('TargetAddress', ctypes.c_wchar_p),
('InitiatorSocket', ctypes.c_ushort),
('TargetSocket', ctypes.c_ushort),
('CID', ctypes.c_ubyte * 2)]
class ISCSI_SESSION_INFO(ctypes.Structure):
_fields_ = [('SessionId', ISCSI_UNIQUE_SESSION_ID),
('InitiatorName', ctypes.c_wchar_p),
('TargetName', ctypes.c_wchar_p),
('TargetNodeName', ctypes.c_wchar_p),
('ISID', ctypes.c_ubyte * 6),
('TSID', ctypes.c_ubyte * 2),
('ConnectionCount', ctypes.c_ulong),
('Connections', ctypes.POINTER(ISCSI_CONNECTION_INFO))]
class SCSI_ADDRESS(ctypes.Structure):
_fields_ = [('Length', ctypes.c_ulong),
('PortNumber', ctypes.c_ubyte),
('PathId', ctypes.c_ubyte),
('TargetId', ctypes.c_ubyte),
('Lun', ctypes.c_ubyte)]
class STORAGE_DEVICE_NUMBER(ctypes.Structure):
_fields_ = [('DeviceType', DEVICE_TYPE),
('DeviceNumber', ctypes.c_long),
('PartitionNumber', ctypes.c_ulong)]
class ISCSI_DEVICE_ON_SESSION(ctypes.Structure):
_fields_ = [('InitiatorName', ctypes.c_wchar * MAX_ISCSI_HBANAME_LEN),
('TargetName', ctypes.c_wchar * (MAX_ISCSI_NAME_LEN + 1)),
('ScsiAddress', SCSI_ADDRESS),
('DeviceInterfaceType', GUID),
('DeviceInterfaceName', ctypes.c_wchar * MAX_PATH),
('LegacyName', ctypes.c_wchar * MAX_PATH),
('StorageDeviceNumber', STORAGE_DEVICE_NUMBER),
('DeviceInstance', ctypes.c_ulong)]

View File

@ -1,330 +0,0 @@
# Copyright 2016 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Error codes and descriptions, as provided by iscsierr.h
from os_win._i18n import _
ISDSC_NON_SPECIFIC_ERROR = 0xEFFF0001
ISDSC_LOGIN_FAILED = 0xEFFF0002
ISDSC_CONNECTION_FAILED = 0xEFFF0003
ISDSC_INITIATOR_NODE_ALREADY_EXISTS = 0xEFFF0004
ISDSC_INITIATOR_NODE_NOT_FOUND = 0xEFFF0005
ISDSC_TARGET_MOVED_TEMPORARILY = 0xEFFF0006
ISDSC_TARGET_MOVED_PERMANENTLY = 0xEFFF0007
ISDSC_INITIATOR_ERROR = 0xEFFF0008
ISDSC_AUTHENTICATION_FAILURE = 0xEFFF0009
ISDSC_AUTHORIZATION_FAILURE = 0xEFFF000A
ISDSC_NOT_FOUND = 0xEFFF000B
ISDSC_TARGET_REMOVED = 0xEFFF000C
ISDSC_UNSUPPORTED_VERSION = 0xEFFF000D
ISDSC_TOO_MANY_CONNECTIONS = 0xEFFF000E
ISDSC_MISSING_PARAMETER = 0xEFFF000F
ISDSC_CANT_INCLUDE_IN_SESSION = 0xEFFF0010
ISDSC_SESSION_TYPE_NOT_SUPPORTED = 0xEFFF0011
ISDSC_TARGET_ERROR = 0xEFFF0012
ISDSC_SERVICE_UNAVAILABLE = 0xEFFF0013
ISDSC_OUT_OF_RESOURCES = 0xEFFF0014
ISDSC_CONNECTION_ALREADY_EXISTS = 0xEFFF0015
ISDSC_SESSION_ALREADY_EXISTS = 0xEFFF0016
ISDSC_INITIATOR_INSTANCE_NOT_FOUND = 0xEFFF0017
ISDSC_TARGET_ALREADY_EXISTS = 0xEFFF0018
ISDSC_DRIVER_BUG = 0xEFFF0019
ISDSC_INVALID_TEXT_KEY = 0xEFFF001A
ISDSC_INVALID_SENDTARGETS_TEXT = 0xEFFF001B
ISDSC_INVALID_SESSION_ID = 0xEFFF001C
ISDSC_SCSI_REQUEST_FAILED = 0xEFFF001D
ISDSC_TOO_MANY_SESSIONS = 0xEFFF001E
ISDSC_SESSION_BUSY = 0xEFFF001F
ISDSC_TARGET_MAPPING_UNAVAILABLE = 0xEFFF0020
ISDSC_ADDRESS_TYPE_NOT_SUPPORTED = 0xEFFF0021
ISDSC_LOGON_FAILED = 0xEFFF0022
ISDSC_SEND_FAILED = 0xEFFF0023
ISDSC_TRANSPORT_ERROR = 0xEFFF0024
ISDSC_VERSION_MISMATCH = 0xEFFF0025
ISDSC_TARGET_MAPPING_OUT_OF_RANGE = 0xEFFF0026
ISDSC_TARGET_PRESHAREDKEY_UNAVAILABLE = 0xEFFF0027
ISDSC_TARGET_AUTHINFO_UNAVAILABLE = 0xEFFF0028
ISDSC_TARGET_NOT_FOUND = 0xEFFF0029
ISDSC_LOGIN_USER_INFO_BAD = 0xEFFF002A
ISDSC_TARGET_MAPPING_EXISTS = 0xEFFF002B
ISDSC_HBA_SECURITY_CACHE_FULL = 0xEFFF002C
ISDSC_INVALID_PORT_NUMBER = 0xEFFF002D
ISDSC_OPERATION_NOT_ALL_SUCCESS = 0xAFFF002E
ISDSC_HBA_SECURITY_CACHE_NOT_SUPPORTED = 0xEFFF002F
ISDSC_IKE_ID_PAYLOAD_TYPE_NOT_SUPPORTED = 0xEFFF0030
ISDSC_IKE_ID_PAYLOAD_INCORRECT_SIZE = 0xEFFF0031
ISDSC_TARGET_PORTAL_ALREADY_EXISTS = 0xEFFF0032
ISDSC_TARGET_ADDRESS_ALREADY_EXISTS = 0xEFFF0033
ISDSC_NO_AUTH_INFO_AVAILABLE = 0xEFFF0034
ISDSC_NO_TUNNEL_OUTER_MODE_ADDRESS = 0xEFFF0035
ISDSC_CACHE_CORRUPTED = 0xEFFF0036
ISDSC_REQUEST_NOT_SUPPORTED = 0xEFFF0037
ISDSC_TARGET_OUT_OF_RESORCES = 0xEFFF0038
ISDSC_SERVICE_DID_NOT_RESPOND = 0xEFFF0039
ISDSC_ISNS_SERVER_NOT_FOUND = 0xEFFF003A
ISDSC_OPERATION_REQUIRES_REBOOT = 0xAFFF003B
ISDSC_NO_PORTAL_SPECIFIED = 0xEFFF003C
ISDSC_CANT_REMOVE_LAST_CONNECTION = 0xEFFF003D
ISDSC_SERVICE_NOT_RUNNING = 0xEFFF003E
ISDSC_TARGET_ALREADY_LOGGED_IN = 0xEFFF003F
ISDSC_DEVICE_BUSY_ON_SESSION = 0xEFFF0040
ISDSC_COULD_NOT_SAVE_PERSISTENT_LOGIN_DATA = 0xEFFF0041
ISDSC_COULD_NOT_REMOVE_PERSISTENT_LOGIN_DATA = 0xEFFF0042
ISDSC_PORTAL_NOT_FOUND = 0xEFFF0043
ISDSC_INITIATOR_NOT_FOUND = 0xEFFF0044
ISDSC_DISCOVERY_MECHANISM_NOT_FOUND = 0xEFFF0045
ISDSC_IPSEC_NOT_SUPPORTED_ON_OS = 0xEFFF0046
ISDSC_PERSISTENT_LOGIN_TIMEOUT = 0xEFFF0047
ISDSC_SHORT_CHAP_SECRET = 0xAFFF0048
ISDSC_EVALUATION_PEROID_EXPIRED = 0xEFFF0049
ISDSC_INVALID_CHAP_SECRET = 0xEFFF004A
ISDSC_INVALID_TARGET_CHAP_SECRET = 0xEFFF004B
ISDSC_INVALID_INITIATOR_CHAP_SECRET = 0xEFFF004C
ISDSC_INVALID_CHAP_USER_NAME = 0xEFFF004D
ISDSC_INVALID_LOGON_AUTH_TYPE = 0xEFFF004E
ISDSC_INVALID_TARGET_MAPPING = 0xEFFF004F
ISDSC_INVALID_TARGET_ID = 0xEFFF0050
ISDSC_INVALID_ISCSI_NAME = 0xEFFF0051
ISDSC_INCOMPATIBLE_ISNS_VERSION = 0xEFFF0052
ISDSC_FAILED_TO_CONFIGURE_IPSEC = 0xEFFF0053
ISDSC_BUFFER_TOO_SMALL = 0xEFFF0054
ISDSC_INVALID_LOAD_BALANCE_POLICY = 0xEFFF0055
ISDSC_INVALID_PARAMETER = 0xEFFF0056
ISDSC_DUPLICATE_PATH_SPECIFIED = 0xEFFF0057
ISDSC_PATH_COUNT_MISMATCH = 0xEFFF0058
ISDSC_INVALID_PATH_ID = 0xEFFF0059
ISDSC_MULTIPLE_PRIMARY_PATHS_SPECIFIED = 0xEFFF005A
ISDSC_NO_PRIMARY_PATH_SPECIFIED = 0xEFFF005B
ISDSC_DEVICE_ALREADY_PERSISTENTLY_BOUND = 0xEFFF005C
ISDSC_DEVICE_NOT_FOUND = 0xEFFF005D
ISDSC_DEVICE_NOT_ISCSI_OR_PERSISTENT = 0xEFFF005E
ISDSC_DNS_NAME_UNRESOLVED = 0xEFFF005F
ISDSC_NO_CONNECTION_AVAILABLE = 0xEFFF0060
ISDSC_LB_POLICY_NOT_SUPPORTED = 0xEFFF0061
ISDSC_REMOVE_CONNECTION_IN_PROGRESS = 0xEFFF0062
ISDSC_INVALID_CONNECTION_ID = 0xEFFF0063
ISDSC_CANNOT_REMOVE_LEADING_CONNECTION = 0xEFFF0064
ISDSC_RESTRICTED_BY_GROUP_POLICY = 0xEFFF0065
ISDSC_ISNS_FIREWALL_BLOCKED = 0xEFFF0066
ISDSC_FAILURE_TO_PERSIST_LB_POLICY = 0xEFFF0067
ISDSC_INVALID_HOST = 0xEFFF0068
err_msg_dict = {
ISDSC_NON_SPECIFIC_ERROR: _('A non specific error occurred.'),
ISDSC_LOGIN_FAILED: _('Login Failed.'),
ISDSC_CONNECTION_FAILED: _('Connection Failed.'),
ISDSC_INITIATOR_NODE_ALREADY_EXISTS: _('Initiator Node Already Exists.'),
ISDSC_INITIATOR_NODE_NOT_FOUND: _('Initiator Node Does Not Exist.'),
ISDSC_TARGET_MOVED_TEMPORARILY: _('Target Moved Temporarily.'),
ISDSC_TARGET_MOVED_PERMANENTLY: _('Target Moved Permanently.'),
ISDSC_INITIATOR_ERROR: _('Initiator Error.'),
ISDSC_AUTHENTICATION_FAILURE: _('Authentication Failure.'),
ISDSC_AUTHORIZATION_FAILURE: _('Authorization Failure.'),
ISDSC_NOT_FOUND: _('Not Found.'),
ISDSC_TARGET_REMOVED: _('Target Removed.'),
ISDSC_UNSUPPORTED_VERSION: _('Unsupported Version.'),
ISDSC_TOO_MANY_CONNECTIONS: _('Too many Connections.'),
ISDSC_MISSING_PARAMETER: _('Missing Parameter.'),
ISDSC_CANT_INCLUDE_IN_SESSION: _('Can not include in session.'),
ISDSC_SESSION_TYPE_NOT_SUPPORTED: _('Session type not supported.'),
ISDSC_TARGET_ERROR: _('Target Error.'),
ISDSC_SERVICE_UNAVAILABLE: _('Service Unavailable.'),
ISDSC_OUT_OF_RESOURCES: _('Out of Resources.'),
ISDSC_CONNECTION_ALREADY_EXISTS: _('Connections already exist '
'on initiator node.'),
ISDSC_SESSION_ALREADY_EXISTS: _('Session Already Exists.'),
ISDSC_INITIATOR_INSTANCE_NOT_FOUND: _('Initiator Instance '
'Does Not Exist.'),
ISDSC_TARGET_ALREADY_EXISTS: _('Target Already Exists.'),
ISDSC_DRIVER_BUG: _('The iscsi driver implementation did '
'not complete an operation correctly.'),
ISDSC_INVALID_TEXT_KEY: _('An invalid key text was encountered.'),
ISDSC_INVALID_SENDTARGETS_TEXT: _('Invalid SendTargets response '
'text was encountered.'),
ISDSC_INVALID_SESSION_ID: _('Invalid Session Id.'),
ISDSC_SCSI_REQUEST_FAILED: _('The scsi request failed.'),
ISDSC_TOO_MANY_SESSIONS: _('Exceeded max sessions for this initiator.'),
ISDSC_SESSION_BUSY: _('Session is busy since a request '
'is already in progress.'),
ISDSC_TARGET_MAPPING_UNAVAILABLE: _('The target mapping requested '
'is not available.'),
ISDSC_ADDRESS_TYPE_NOT_SUPPORTED: _('The Target Address type given '
'is not supported.'),
ISDSC_LOGON_FAILED: _('Logon Failed.'),
ISDSC_SEND_FAILED: _('TCP Send Failed.'),
ISDSC_TRANSPORT_ERROR: _('TCP Transport Error'),
ISDSC_VERSION_MISMATCH: _('iSCSI Version Mismatch'),
ISDSC_TARGET_MAPPING_OUT_OF_RANGE: _('The Target Mapping Address passed '
'is out of range for the '
'adapter configuration.'),
ISDSC_TARGET_PRESHAREDKEY_UNAVAILABLE: _('The preshared key for the '
'target or IKE identification '
'payload is not available.'),
ISDSC_TARGET_AUTHINFO_UNAVAILABLE: _('The authentication information for '
'the target is not available.'),
ISDSC_TARGET_NOT_FOUND: _('The target name is not found or is '
'marked as hidden from login.'),
ISDSC_LOGIN_USER_INFO_BAD: _('One or more parameters specified in '
'LoginTargetIN structure is invalid.'),
ISDSC_TARGET_MAPPING_EXISTS: _('Given target mapping already exists.'),
ISDSC_HBA_SECURITY_CACHE_FULL: _('The HBA security information cache '
'is full.'),
ISDSC_INVALID_PORT_NUMBER: _('The port number passed is '
'not valid for the initiator.'),
ISDSC_OPERATION_NOT_ALL_SUCCESS: _('The operation was not successful '
'for all initiators or discovery '
'methods.'),
ISDSC_HBA_SECURITY_CACHE_NOT_SUPPORTED: _('The HBA security information '
'cache is not supported by '
'this adapter.'),
ISDSC_IKE_ID_PAYLOAD_TYPE_NOT_SUPPORTED: _('The IKE id payload type '
'specified is not supported.'),
ISDSC_IKE_ID_PAYLOAD_INCORRECT_SIZE: _('The IKE id payload size '
'specified is not correct.'),
ISDSC_TARGET_PORTAL_ALREADY_EXISTS: _('Target Portal Structure '
'Already Exists.'),
ISDSC_TARGET_ADDRESS_ALREADY_EXISTS: _('Target Address Structure '
'Already Exists.'),
ISDSC_NO_AUTH_INFO_AVAILABLE: _('There is no IKE authentication '
'information available.'),
ISDSC_NO_TUNNEL_OUTER_MODE_ADDRESS: _('There is no tunnel mode outer '
'address specified.'),
ISDSC_CACHE_CORRUPTED: _('Authentication or tunnel '
'address cache is corrupted.'),
ISDSC_REQUEST_NOT_SUPPORTED: _('The request or operation '
'is not supported.'),
ISDSC_TARGET_OUT_OF_RESORCES: _('The target does not have enough '
'resources to process the '
'given request.'),
ISDSC_SERVICE_DID_NOT_RESPOND: _('The initiator service did '
'not respond to the request '
'sent by the driver.'),
ISDSC_ISNS_SERVER_NOT_FOUND: _('The Internet Storage Name Server (iSNS) '
'server was not found or is unavailable.'),
ISDSC_OPERATION_REQUIRES_REBOOT: _('The operation was successful but '
'requires a driver reload or reboot '
'to become effective.'),
ISDSC_NO_PORTAL_SPECIFIED: _('There is no target portal available '
'to complete the login.'),
ISDSC_CANT_REMOVE_LAST_CONNECTION: _('Cannot remove the last '
'connection for a session.'),
ISDSC_SERVICE_NOT_RUNNING: _('The Microsoft iSCSI initiator '
'service has not been started.'),
ISDSC_TARGET_ALREADY_LOGGED_IN: _('The target has already been '
'logged in via an iSCSI session.'),
ISDSC_DEVICE_BUSY_ON_SESSION: _('The session cannot be logged out '
'since a device on that session is '
'currently being used.'),
ISDSC_COULD_NOT_SAVE_PERSISTENT_LOGIN_DATA: _('Failed to save persistent '
'login information.'),
ISDSC_COULD_NOT_REMOVE_PERSISTENT_LOGIN_DATA: _('Failed to remove '
'persistent login '
'information.'),
ISDSC_PORTAL_NOT_FOUND: _('The specified portal was not found.'),
ISDSC_INITIATOR_NOT_FOUND: _('The specified initiator '
'name was not found.'),
ISDSC_DISCOVERY_MECHANISM_NOT_FOUND: _('The specified discovery '
'mechanism was not found.'),
ISDSC_IPSEC_NOT_SUPPORTED_ON_OS: _('iSCSI does not support IPSEC '
'for this version of the OS.'),
ISDSC_PERSISTENT_LOGIN_TIMEOUT: _('The iSCSI service timed out waiting '
'for all persistent logins to '
'complete.'),
ISDSC_SHORT_CHAP_SECRET: _('The specified CHAP secret is less than '
'96 bits and will not be usable for '
'authenticating over non ipsec connections.'),
ISDSC_EVALUATION_PEROID_EXPIRED: _('The evaluation period for the '
'iSCSI initiator service has '
'expired.'),
ISDSC_INVALID_CHAP_SECRET: _('CHAP secret given does not conform '
'to the standard. Please see system '
'event log for more information.'),
ISDSC_INVALID_TARGET_CHAP_SECRET:
_('Target CHAP secret given is invalid. Maximum size of CHAP secret'
'is 16 bytes. Minimum size is 12 bytes if IPSec is not used.'),
ISDSC_INVALID_INITIATOR_CHAP_SECRET: _('Initiator CHAP secret given is '
'invalid. Maximum size of CHAP '
'secret is 16 bytes. Minimum size '
'is 12 bytes if IPSec is '
'not used.'),
ISDSC_INVALID_CHAP_USER_NAME: _('CHAP Username given is invalid.'),
ISDSC_INVALID_LOGON_AUTH_TYPE: _('Logon Authentication type '
'given is invalid.'),
ISDSC_INVALID_TARGET_MAPPING: _('Target Mapping information '
'given is invalid.'),
ISDSC_INVALID_TARGET_ID: _('Target Id given in '
'Target Mapping is invalid.'),
ISDSC_INVALID_ISCSI_NAME: _('The iSCSI name specified contains '
'invalid characters or is too long.'),
ISDSC_INCOMPATIBLE_ISNS_VERSION: _('The version number returned from the '
'Internet Storage Name Server (iSNS) '
'server is not compatible with this '
'version of the iSNS client.'),
ISDSC_FAILED_TO_CONFIGURE_IPSEC: _('Initiator failed to configure IPSec '
'for the given connection. This could '
'be because of low resources.'),
ISDSC_BUFFER_TOO_SMALL: _('The buffer given for processing '
'the request is too small.'),
ISDSC_INVALID_LOAD_BALANCE_POLICY: _('The given Load Balance '
'policy is not recognized '
'by iScsi initiator.'),
ISDSC_INVALID_PARAMETER: _('One or more paramaters '
'specified is not valid.'),
ISDSC_DUPLICATE_PATH_SPECIFIED: _('Duplicate PathIds were '
'specified in the call to '
'set Load Balance Policy.'),
ISDSC_PATH_COUNT_MISMATCH: _('Number of paths specified in '
'Set Load Balance Policy does not '
'match the number of paths to the target.'),
ISDSC_INVALID_PATH_ID: _('Path Id specified in the call to '
'set Load Balance Policy is not valid'),
ISDSC_MULTIPLE_PRIMARY_PATHS_SPECIFIED: _('Multiple primary paths '
'specified when only one '
'primary path is expected.'),
ISDSC_NO_PRIMARY_PATH_SPECIFIED: _('No primary path specified when '
'at least one is expected.'),
ISDSC_DEVICE_ALREADY_PERSISTENTLY_BOUND: _('Device is already a '
'persistently bound device.'),
ISDSC_DEVICE_NOT_FOUND: _('Device was not found.'),
ISDSC_DEVICE_NOT_ISCSI_OR_PERSISTENT: _('The device specified does not '
'originate from an iSCSI disk '
'or a persistent iSCSI login.'),
ISDSC_DNS_NAME_UNRESOLVED: _('The DNS name specified was not resolved.'),
ISDSC_NO_CONNECTION_AVAILABLE: _('There is no connection available '
'in the iSCSI session to '
'process the request.'),
ISDSC_LB_POLICY_NOT_SUPPORTED: _('The given Load Balance '
'policy is not supported.'),
ISDSC_REMOVE_CONNECTION_IN_PROGRESS: _('A remove connection request '
'is already in progress for '
'this session.'),
ISDSC_INVALID_CONNECTION_ID: _('Given connection was not '
'found in the session.'),
ISDSC_CANNOT_REMOVE_LEADING_CONNECTION: _('The leading connection in '
'the session cannot be '
'removed.'),
ISDSC_RESTRICTED_BY_GROUP_POLICY: _('The operation cannot be performed '
'since it does not conform with '
'the group policy assigned to '
'this computer.'),
ISDSC_ISNS_FIREWALL_BLOCKED: _('The operation cannot be performed since '
'the Internet Storage Name Server '
'(iSNS) firewall exception has '
'not been enabled.'),
ISDSC_FAILURE_TO_PERSIST_LB_POLICY: _('Failed to persist load '
'balancing policy parameters.'),
ISDSC_INVALID_HOST: _('The name could not be resolved to an IP Address.'),
}

View File

@ -16,7 +16,6 @@
import ctypes
import os
import socket
import sys
from oslo_log import log as logging
@ -25,9 +24,9 @@ from os_win import _utils
from os_win import exceptions
from os_win.utils import baseutils
from os_win.utils import win32utils
from os_win.utils.winapi import libs as w_lib
if sys.platform == 'win32':
kernel32 = ctypes.windll.kernel32
kernel32 = w_lib.get_shared_lib_handle(w_lib.KERNEL32)
LOG = logging.getLogger(__name__)

View File

@ -26,39 +26,67 @@ http://www.microsoft.com/en-us/download/details.aspx?id=34750
import ctypes
import os
import struct
import sys
from oslo_log import log as logging
from oslo_utils import units
from os_win._i18n import _
from os_win import constants
from os_win import exceptions
from os_win.utils.storage.virtdisk import (
virtdisk_constants as vdisk_const)
from os_win.utils import win32utils
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi import libs as w_lib
from os_win.utils.winapi.libs import virtdisk as vdisk_struct
from os_win.utils.winapi import wintypes
if sys.platform == 'win32':
from ctypes import wintypes
kernel32 = ctypes.windll.kernel32
virtdisk = ctypes.windll.virtdisk
from os_win.utils.storage.virtdisk import (
virtdisk_structures as vdisk_struct) # noqa
kernel32 = w_lib.get_shared_lib_handle(w_lib.KERNEL32)
virtdisk = w_lib.get_shared_lib_handle(w_lib.VIRTDISK)
LOG = logging.getLogger(__name__)
VHD_SIGNATURE = b'conectix'
VHDX_SIGNATURE = b'vhdxfile'
DEVICE_ID_MAP = {
constants.DISK_FORMAT_VHD: w_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
constants.DISK_FORMAT_VHDX: w_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX,
}
VHD_HEADER_SIZE_FIX = 512
VHD_BAT_ENTRY_SIZE = 4
VHD_DYNAMIC_DISK_HEADER_SIZE = 1024
VHD_HEADER_SIZE_DYNAMIC = 512
VHD_FOOTER_SIZE_DYNAMIC = 512
VHDX_BAT_ENTRY_SIZE = 8
VHDX_HEADER_OFFSETS = [64 * units.Ki, 128 * units.Ki]
VHDX_HEADER_SECTION_SIZE = units.Mi
VHDX_LOG_LENGTH_OFFSET = 68
VHDX_METADATA_SIZE_OFFSET = 64
VHDX_REGION_TABLE_OFFSET = 192 * units.Ki
VHDX_BS_METADATA_ENTRY_OFFSET = 48
VIRTUAL_DISK_DEFAULT_SECTOR_SIZE = 0x200
VIRTUAL_DISK_DEFAULT_PHYS_SECTOR_SIZE = 0x200
CREATE_VIRTUAL_DISK_FLAGS = {
constants.VHD_TYPE_FIXED:
w_const.CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION,
}
class VHDUtils(object):
def __init__(self):
self._win32_utils = win32utils.Win32Utils()
self._vhd_info_members = {
vdisk_const.GET_VIRTUAL_DISK_INFO_SIZE: 'Size',
vdisk_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION:
w_const.GET_VIRTUAL_DISK_INFO_SIZE: 'Size',
w_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION:
'ParentLocation',
vdisk_const.GET_VIRTUAL_DISK_INFO_VIRTUAL_STORAGE_TYPE:
w_const.GET_VIRTUAL_DISK_INFO_VIRTUAL_STORAGE_TYPE:
'VirtualStorageType',
vdisk_const.GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE:
w_const.GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE:
'ProviderSubtype'}
# Describes the way error handling is performed
@ -76,15 +104,17 @@ class VHDUtils(object):
return self._win32_utils.run_and_check_output(*args, **kwargs)
finally:
if cleanup_handle:
self._close(cleanup_handle)
self._win32_utils.close_handle(cleanup_handle)
def _open(self, vhd_path,
open_flag=None,
open_access_mask=vdisk_const.VIRTUAL_DISK_ACCESS_ALL,
open_flag=0,
open_access_mask=w_const.VIRTUAL_DISK_ACCESS_ALL,
open_params=None):
device_id = self._get_vhd_device_id(vhd_path)
vst = vdisk_struct.Win32_VIRTUAL_STORAGE_TYPE(DeviceId=device_id)
vst = vdisk_struct.VIRTUAL_STORAGE_TYPE(
DeviceId=device_id,
VendorId=w_const.VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT)
handle = wintypes.HANDLE()
self._run_and_check_output(virtdisk.OpenVirtualDisk,
@ -103,24 +133,33 @@ class VHDUtils(object):
max_internal_size=0, parent_path=None):
new_device_id = self._get_vhd_device_id(new_vhd_path)
vst = vdisk_struct.Win32_VIRTUAL_STORAGE_TYPE(DeviceId=new_device_id)
vst = vdisk_struct.VIRTUAL_STORAGE_TYPE(
DeviceId=new_device_id,
VendorId=w_const.VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT)
params = vdisk_struct.Win32_CREATE_VIRTUAL_DISK_PARAMETERS(
MaximumSize=max_internal_size,
ParentPath=parent_path,
SourcePath=src_path)
params = vdisk_struct.CREATE_VIRTUAL_DISK_PARAMETERS()
params.Version = w_const.CREATE_VIRTUAL_DISK_VERSION_2
params.Version2.MaximumSize = max_internal_size
params.Version2.ParentPath = parent_path
params.Version2.SourcePath = src_path
params.Version2.PhysicalSectorSizeInBytes = (
VIRTUAL_DISK_DEFAULT_PHYS_SECTOR_SIZE)
params.Version2.BlockSizeInBytes = (
w_const.CREATE_VHD_PARAMS_DEFAULT_BLOCK_SIZE)
params.Version2.SectorSizeInBytes = (
VIRTUAL_DISK_DEFAULT_SECTOR_SIZE)
handle = wintypes.HANDLE()
create_virtual_disk_flag = (
vdisk_const.CREATE_VIRTUAL_DISK_FLAGS.get(new_vhd_type))
create_virtual_disk_flag = CREATE_VIRTUAL_DISK_FLAGS.get(
new_vhd_type, 0)
self._run_and_check_output(virtdisk.CreateVirtualDisk,
ctypes.byref(vst),
ctypes.c_wchar_p(new_vhd_path),
None,
0,
None,
create_virtual_disk_flag,
None,
0,
ctypes.byref(params),
None,
ctypes.byref(handle),
@ -142,7 +181,7 @@ class VHDUtils(object):
def get_vhd_format(self, vhd_path):
vhd_format = os.path.splitext(vhd_path)[1][1:].upper()
device_id = vdisk_const.DEVICE_ID_MAP.get(vhd_format)
device_id = DEVICE_ID_MAP.get(vhd_format)
# If the disk format is not recognised by extension,
# we attempt to retrieve it by seeking the signature.
if not device_id and os.path.exists(vhd_path):
@ -156,13 +195,13 @@ class VHDUtils(object):
def _get_vhd_device_id(self, vhd_path):
vhd_format = self.get_vhd_format(vhd_path)
return vdisk_const.DEVICE_ID_MAP.get(vhd_format)
return DEVICE_ID_MAP.get(vhd_format)
def _get_vhd_format_by_signature(self, vhd_path):
with open(vhd_path, 'rb') as f:
# print f.read()
# Read header
if f.read(8) == vdisk_const.VHDX_SIGNATURE:
if f.read(8) == VHDX_SIGNATURE:
return constants.DISK_FORMAT_VHDX
# Read footer
@ -170,7 +209,7 @@ class VHDUtils(object):
file_size = f.tell()
if file_size >= 512:
f.seek(-512, 2)
if f.read(8) == vdisk_const.VHD_SIGNATURE:
if f.read(8) == VHD_SIGNATURE:
return constants.DISK_FORMAT_VHD
def get_vhd_info(self, vhd_path, info_members=None,
@ -197,10 +236,10 @@ class VHDUtils(object):
vhd_info = {}
info_members = info_members or self._vhd_info_members
open_flag = (vdisk_const.OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS
open_flag = (w_const.OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS
if not open_parents else 0)
open_access_mask = (vdisk_const.VIRTUAL_DISK_ACCESS_GET_INFO |
vdisk_const.VIRTUAL_DISK_ACCESS_DETACH)
open_access_mask = (w_const.VIRTUAL_DISK_ACCESS_GET_INFO |
w_const.VIRTUAL_DISK_ACCESS_DETACH)
handle = self._open(
vhd_path,
open_flag=open_flag,
@ -211,13 +250,13 @@ class VHDUtils(object):
info = self._get_vhd_info_member(handle, member)
vhd_info.update(info)
finally:
self._close(handle)
self._win32_utils.close_handle(handle)
return vhd_info
def _get_vhd_info_member(self, vhd_file, info_member):
virt_disk_info = vdisk_struct.Win32_GET_VIRTUAL_DISK_INFO_PARAMETERS()
virt_disk_info.VERSION = ctypes.c_uint(info_member)
virt_disk_info = vdisk_struct.GET_VIRTUAL_DISK_INFO()
virt_disk_info.Version = ctypes.c_uint(info_member)
infoSize = ctypes.sizeof(virt_disk_info)
@ -226,8 +265,8 @@ class VHDUtils(object):
# Note(lpetrut): If the vhd has no parent image, this will
# return an error. No need to raise an exception in this case.
ignored_error_codes = []
if info_member == vdisk_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION:
ignored_error_codes.append(vdisk_const.ERROR_VHD_INVALID_TYPE)
if info_member == w_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION:
ignored_error_codes.append(w_const.ERROR_VHD_INVALID_TYPE)
self._run_and_check_output(virtdisk.GetVirtualDiskInformation,
vhd_file,
@ -241,7 +280,7 @@ class VHDUtils(object):
def _parse_vhd_info(self, virt_disk_info, info_member):
vhd_info = {}
vhd_info_member = self._vhd_info_members[info_member]
info = getattr(virt_disk_info.VhdInfo, vhd_info_member)
info = getattr(virt_disk_info, vhd_info_member)
if hasattr(info, '_fields_'):
for field in info._fields_:
@ -258,13 +297,13 @@ class VHDUtils(object):
block size and sector size of the vhd.
"""
size = self.get_vhd_info(vhd_path,
[vdisk_const.GET_VIRTUAL_DISK_INFO_SIZE])
[w_const.GET_VIRTUAL_DISK_INFO_SIZE])
return size
def get_vhd_parent_path(self, vhd_path):
vhd_info = self.get_vhd_info(
vhd_path,
[vdisk_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION])
[w_const.GET_VIRTUAL_DISK_INFO_PARENT_LOCATION])
parent_path = vhd_info['ParentPath']
return parent_path if parent_path else None
@ -272,23 +311,26 @@ class VHDUtils(object):
def get_vhd_type(self, vhd_path):
vhd_info = self.get_vhd_info(
vhd_path,
[vdisk_const.GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE])
[w_const.GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE])
return vhd_info['ProviderSubtype']
def merge_vhd(self, vhd_path, delete_merged_image=True):
"""Merges a VHD/x image into the immediate next parent image."""
open_params = vdisk_struct.Win32_OPEN_VIRTUAL_DISK_PARAMETERS_V1(
RWDepth=2)
open_params = vdisk_struct.OPEN_VIRTUAL_DISK_PARAMETERS()
open_params.Version = w_const.OPEN_VIRTUAL_DISK_VERSION_1
open_params.Version1.RWDepth = 2
handle = self._open(vhd_path,
open_params=ctypes.byref(open_params))
params = vdisk_struct.Win32_MERGE_VIRTUAL_DISK_PARAMETERS(MergeDepth=1)
params = vdisk_struct.MERGE_VIRTUAL_DISK_PARAMETERS()
params.Version = w_const.MERGE_VIRTUAL_DISK_VERSION_1
params.Version1.MergeDepth = 1
self._run_and_check_output(
virtdisk.MergeVirtualDisk,
handle,
None,
0,
ctypes.byref(params),
None,
cleanup_handle=handle)
@ -297,17 +339,19 @@ class VHDUtils(object):
os.remove(vhd_path)
def reconnect_parent_vhd(self, child_path, parent_path):
open_params = vdisk_struct.Win32_OPEN_VIRTUAL_DISK_PARAMETERS_V2(
GetInfoOnly=False)
open_params = vdisk_struct.OPEN_VIRTUAL_DISK_PARAMETERS()
open_params.Version = w_const.OPEN_VIRTUAL_DISK_VERSION_2
open_params.Version2.GetInfoOnly = False
handle = self._open(
child_path,
open_flag=vdisk_const.OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS,
open_access_mask=None,
open_flag=w_const.OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS,
open_access_mask=0,
open_params=ctypes.byref(open_params))
params = vdisk_struct.Win32_SET_VIRTUAL_DISK_INFO_PARAMETERS(
ParentFilePath=parent_path)
params = vdisk_struct.SET_VIRTUAL_DISK_INFO()
params.Version = w_const.SET_VIRTUAL_DISK_INFO_PARENT_PATH
params.ParentFilePath = parent_path
self._run_and_check_output(virtdisk.SetVirtualDiskInformation,
handle,
@ -350,13 +394,14 @@ class VHDUtils(object):
def _resize_vhd(self, vhd_path, new_max_size):
handle = self._open(vhd_path)
params = vdisk_struct.Win32_RESIZE_VIRTUAL_DISK_PARAMETERS(
NewSize=new_max_size)
params = vdisk_struct.RESIZE_VIRTUAL_DISK_PARAMETERS()
params.Version = w_const.RESIZE_VIRTUAL_DISK_VERSION_1
params.Version1.NewSize = new_max_size
self._run_and_check_output(
virtdisk.ResizeVirtualDisk,
handle,
None,
0,
ctypes.byref(params),
None,
cleanup_handle=handle)
@ -373,7 +418,7 @@ class VHDUtils(object):
return self.get_internal_vhd_size_by_file_size(
vhd_parent, new_vhd_file_size)
if vhd_dev_id == vdisk_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHD:
if vhd_dev_id == w_const.VIRTUAL_STORAGE_TYPE_DEVICE_VHD:
func = self._get_internal_vhd_size_by_file_size
else:
func = self._get_internal_vhdx_size_by_file_size
@ -403,14 +448,14 @@ class VHDUtils(object):
vhd_type = vhd_info['ProviderSubtype']
if vhd_type == constants.VHD_TYPE_FIXED:
vhd_header_size = vdisk_const.VHD_HEADER_SIZE_FIX
vhd_header_size = VHD_HEADER_SIZE_FIX
return new_vhd_file_size - vhd_header_size
else:
bs = vhd_info['BlockSize']
bes = vdisk_const.VHD_BAT_ENTRY_SIZE
ddhs = vdisk_const.VHD_DYNAMIC_DISK_HEADER_SIZE
hs = vdisk_const.VHD_HEADER_SIZE_DYNAMIC
fs = vdisk_const.VHD_FOOTER_SIZE_DYNAMIC
bes = VHD_BAT_ENTRY_SIZE
ddhs = VHD_DYNAMIC_DISK_HEADER_SIZE
hs = VHD_HEADER_SIZE_DYNAMIC
fs = VHD_FOOTER_SIZE_DYNAMIC
max_internal_size = (new_vhd_file_size -
(hs + ddhs + fs)) * bs // (bes + bs)
@ -435,8 +480,8 @@ class VHDUtils(object):
try:
with open(vhd_path, 'rb') as f:
hs = vdisk_const.VHDX_HEADER_SECTION_SIZE
bes = vdisk_const.VHDX_BAT_ENTRY_SIZE
hs = VHDX_HEADER_SECTION_SIZE
bes = VHDX_BAT_ENTRY_SIZE
lss = vhd_info['SectorSize']
bs = self._get_vhdx_block_size(f)
@ -460,23 +505,22 @@ class VHDUtils(object):
def _get_vhdx_current_header_offset(self, vhdx_file):
sequence_numbers = []
for offset in vdisk_const.VHDX_HEADER_OFFSETS:
for offset in VHDX_HEADER_OFFSETS:
vhdx_file.seek(offset + 8)
sequence_numbers.append(struct.unpack('<Q',
vhdx_file.read(8))[0])
current_header = sequence_numbers.index(max(sequence_numbers))
return vdisk_const.VHDX_HEADER_OFFSETS[current_header]
return VHDX_HEADER_OFFSETS[current_header]
def _get_vhdx_log_size(self, vhdx_file):
current_header_offset = self._get_vhdx_current_header_offset(vhdx_file)
offset = current_header_offset + vdisk_const.VHDX_LOG_LENGTH_OFFSET
offset = current_header_offset + VHDX_LOG_LENGTH_OFFSET
vhdx_file.seek(offset)
log_size = struct.unpack('<I', vhdx_file.read(4))[0]
return log_size
def _get_vhdx_metadata_size_and_offset(self, vhdx_file):
offset = (vdisk_const.VHDX_METADATA_SIZE_OFFSET +
vdisk_const.VHDX_REGION_TABLE_OFFSET)
offset = VHDX_METADATA_SIZE_OFFSET + VHDX_REGION_TABLE_OFFSET
vhdx_file.seek(offset)
metadata_offset = struct.unpack('<Q', vhdx_file.read(8))[0]
metadata_size = struct.unpack('<I', vhdx_file.read(4))[0]
@ -484,7 +528,7 @@ class VHDUtils(object):
def _get_vhdx_block_size(self, vhdx_file):
metadata_offset = self._get_vhdx_metadata_size_and_offset(vhdx_file)[1]
offset = metadata_offset + vdisk_const.VHDX_BS_METADATA_ENTRY_OFFSET
offset = metadata_offset + VHDX_BS_METADATA_ENTRY_OFFSET
vhdx_file.seek(offset)
file_parameter_offset = struct.unpack('<I', vhdx_file.read(4))[0]

View File

@ -1,79 +0,0 @@
# Copyright 2015 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from oslo_utils import units
from os_win import constants
VHD_SIGNATURE = b'conectix'
VHDX_SIGNATURE = b'vhdxfile'
VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1
VIRTUAL_STORAGE_TYPE_DEVICE_VHD = 2
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 3
DEVICE_ID_MAP = {
constants.DISK_FORMAT_VHD: VIRTUAL_STORAGE_TYPE_DEVICE_VHD,
constants.DISK_FORMAT_VHDX: VIRTUAL_STORAGE_TYPE_DEVICE_VHDX,
}
VHD_HEADER_SIZE_FIX = 512
VHD_BAT_ENTRY_SIZE = 4
VHD_DYNAMIC_DISK_HEADER_SIZE = 1024
VHD_HEADER_SIZE_DYNAMIC = 512
VHD_FOOTER_SIZE_DYNAMIC = 512
VHDX_BAT_ENTRY_SIZE = 8
VHDX_HEADER_OFFSETS = [64 * units.Ki, 128 * units.Ki]
VHDX_HEADER_SECTION_SIZE = units.Mi
VHDX_LOG_LENGTH_OFFSET = 68
VHDX_METADATA_SIZE_OFFSET = 64
VHDX_REGION_TABLE_OFFSET = 192 * units.Ki
VHDX_BS_METADATA_ENTRY_OFFSET = 48
VIRTUAL_DISK_ACCESS_NONE = 0
VIRTUAL_DISK_ACCESS_ALL = 0x003f0000
VIRTUAL_DISK_ACCESS_CREATE = 0x00100000
VIRTUAL_DISK_ACCESS_GET_INFO = 0x80000
VIRTUAL_DISK_ACCESS_DETACH = 0x00040000
VIRTUAL_DISK_DEFAULT_SECTOR_SIZE = 0x200
VIRTUAL_DISK_DEFAULT_PHYS_SECTOR_SIZE = 0x200
OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS = 1
OPEN_VIRTUAL_DISK_VERSION_1 = 1
OPEN_VIRTUAL_DISK_VERSION_2 = 2
RESIZE_VIRTUAL_DISK_VERSION_1 = 1
CREATE_VIRTUAL_DISK_VERSION_2 = 2
CREATE_VHD_PARAMS_DEFAULT_BLOCK_SIZE = 0
CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION = 1
CREATE_VIRTUAL_DISK_FLAGS = {
constants.VHD_TYPE_FIXED:
CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION,
}
MERGE_VIRTUAL_DISK_VERSION_1 = 1
GET_VIRTUAL_DISK_INFO_SIZE = 1
GET_VIRTUAL_DISK_INFO_PARENT_LOCATION = 3
GET_VIRTUAL_DISK_INFO_VIRTUAL_STORAGE_TYPE = 6
GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE = 7
SET_VIRTUAL_DISK_INFO_PARENT_PATH = 1
ERROR_VHD_INVALID_TYPE = 0xC03A001B

View File

@ -1,178 +0,0 @@
# Copyright 2015 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
from ctypes import wintypes
from os_win.utils.storage.virtdisk import (
virtdisk_constants as vdisk_const)
class Win32_GUID(ctypes.Structure):
_fields_ = [("Data1", wintypes.DWORD),
("Data2", wintypes.WORD),
("Data3", wintypes.WORD),
("Data4", wintypes.BYTE * 8)]
WIN32_VIRTUAL_STORAGE_TYPE_MSFT = Win32_GUID(
Data1=0xec984aec,
Data2=0xa0f9,
Data3=0x47e9,
Data4=(wintypes.BYTE * 8)(0x90, 0x1f, 0x71, 0x41,
0x5a, 0x66, 0x34, 0x5b))
class Win32_VIRTUAL_STORAGE_TYPE(ctypes.Structure):
_fields_ = [
('DeviceId', wintypes.ULONG),
('VendorId', Win32_GUID)
]
def __init__(self, *args, **kwargs):
self.VendorId = WIN32_VIRTUAL_STORAGE_TYPE_MSFT
super(Win32_VIRTUAL_STORAGE_TYPE, self).__init__(*args, **kwargs)
class Win32_RESIZE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('NewSize', ctypes.c_ulonglong)
]
def __init__(self, *args, **kwargs):
self.Version = vdisk_const.RESIZE_VIRTUAL_DISK_VERSION_1
super(Win32_RESIZE_VIRTUAL_DISK_PARAMETERS, self).__init__(
*args, **kwargs)
class Win32_OPEN_VIRTUAL_DISK_PARAMETERS_V1(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('RWDepth', ctypes.c_ulong),
]
def __init__(self, *args, **kwargs):
self.Version = vdisk_const.OPEN_VIRTUAL_DISK_VERSION_1
super(Win32_OPEN_VIRTUAL_DISK_PARAMETERS_V1, self).__init__(
*args, **kwargs)
class Win32_OPEN_VIRTUAL_DISK_PARAMETERS_V2(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('GetInfoOnly', wintypes.BOOL),
('ReadOnly', wintypes.BOOL),
('ResiliencyGuid', Win32_GUID)
]
def __init__(self, *args, **kwargs):
self.Version = vdisk_const.OPEN_VIRTUAL_DISK_VERSION_2
super(Win32_OPEN_VIRTUAL_DISK_PARAMETERS_V2, self).__init__(
*args, **kwargs)
class Win32_MERGE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('MergeDepth', ctypes.c_ulong)
]
def __init__(self, *args, **kwargs):
self.Version = vdisk_const.MERGE_VIRTUAL_DISK_VERSION_1
super(Win32_MERGE_VIRTUAL_DISK_PARAMETERS, self).__init__(
*args, **kwargs)
class Win32_CREATE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('UniqueId', Win32_GUID),
('MaximumSize', ctypes.c_ulonglong),
('BlockSizeInBytes', wintypes.ULONG),
('SectorSizeInBytes', wintypes.ULONG),
('PhysicalSectorSizeInBytes', wintypes.ULONG),
('ParentPath', wintypes.LPCWSTR),
('SourcePath', wintypes.LPCWSTR),
('OpenFlags', wintypes.DWORD),
('ParentVirtualStorageType', Win32_VIRTUAL_STORAGE_TYPE),
('SourceVirtualStorageType', Win32_VIRTUAL_STORAGE_TYPE),
('ResiliencyGuid', Win32_GUID)
]
def __init__(self, *args, **kwargs):
self.Version = vdisk_const.CREATE_VIRTUAL_DISK_VERSION_2
# The kwargs can override the defaults specified bellow.
self.PhysicalSectorSizeInBytes = (
vdisk_const.VIRTUAL_DISK_DEFAULT_PHYS_SECTOR_SIZE)
self.BlockSizeInBytes = (
vdisk_const.CREATE_VHD_PARAMS_DEFAULT_BLOCK_SIZE)
self.SectorSizeInBytes = (
vdisk_const.VIRTUAL_DISK_DEFAULT_SECTOR_SIZE)
super(Win32_CREATE_VIRTUAL_DISK_PARAMETERS, self).__init__(
*args, **kwargs)
class Win32_SIZE(ctypes.Structure):
_fields_ = [("VirtualSize", wintypes.ULARGE_INTEGER),
("PhysicalSize", wintypes.ULARGE_INTEGER),
("BlockSize", wintypes.ULONG),
("SectorSize", wintypes.ULONG)]
class Win32_PARENT_LOCATION(ctypes.Structure):
_fields_ = [('ParentResolved', wintypes.BOOL),
('ParentPath', wintypes.WCHAR * 512)]
class Win32_PHYSICAL_DISK(ctypes.Structure):
_fields_ = [("LogicalSectorSize", wintypes.ULONG),
("PhysicalSectorSize", wintypes.ULONG),
("IsRemote", wintypes.BOOL)]
class Win32_VHD_INFO(ctypes.Union):
_fields_ = [("Size", Win32_SIZE),
("Identifier", Win32_GUID),
("ParentLocation", Win32_PARENT_LOCATION),
("ParentIdentifier", Win32_GUID),
("ParentTimestamp", wintypes.ULONG),
("VirtualStorageType", Win32_VIRTUAL_STORAGE_TYPE),
("ProviderSubtype", wintypes.ULONG),
("Is4kAligned", wintypes.BOOL),
("PhysicalDisk", Win32_PHYSICAL_DISK),
("VhdPhysicalSectorSize", wintypes.ULONG),
("SmallestSafeVirtualSize",
wintypes.ULARGE_INTEGER),
("FragmentationPercentage", wintypes.ULONG)]
class Win32_GET_VIRTUAL_DISK_INFO_PARAMETERS(ctypes.Structure):
_fields_ = [("VERSION", wintypes.UINT),
("VhdInfo", Win32_VHD_INFO)]
class Win32_SET_VIRTUAL_DISK_INFO_PARAMETERS(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('ParentFilePath', wintypes.LPCWSTR)
]
def __init__(self, *args, **kwargs):
self.Version = vdisk_const.SET_VIRTUAL_DISK_INFO_PARENT_PATH
super(Win32_SET_VIRTUAL_DISK_INFO_PARAMETERS, self).__init__(
*args, **kwargs)

View File

@ -15,22 +15,18 @@
# under the License.
import ctypes
import sys
from oslo_log import log as logging
from os_win import _utils
from os_win import exceptions
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi import libs as w_lib
if sys.platform == 'win32':
kernel32 = ctypes.windll.kernel32
kernel32 = w_lib.get_shared_lib_handle(w_lib.KERNEL32)
LOG = logging.getLogger(__name__)
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
class Win32Utils(object):
def __init__(self):
@ -99,8 +95,9 @@ class Win32Utils(object):
message_buffer = ctypes.c_char_p()
kernel32.FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
w_const.FORMAT_MESSAGE_FROM_SYSTEM |
w_const.FORMAT_MESSAGE_ALLOCATE_BUFFER |
w_const.FORMAT_MESSAGE_IGNORE_INSERTS,
None, error_code, 0, ctypes.byref(message_buffer), 0, None)
error_message = message_buffer.value
@ -128,3 +125,6 @@ class Win32Utils(object):
except exceptions.Win32Exception:
LOG.exception("Could not deallocate memory. "
"There could be a memory leak.")
def close_handle(self, handle):
kernel32.CloseHandle(handle)

View File

View File

@ -0,0 +1,258 @@
# Copyright 2017 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from os_win.utils.winapi import wintypes
# Windows.h
# ----------
# winerror.h
ERROR_INVALID_HANDLE = 6
ERROR_INSUFFICIENT_BUFFER = 122
ERROR_DIR_IS_NOT_EMPTY = 145
ERROR_PIPE_BUSY = 231
ERROR_PIPE_NOT_CONNECTED = 233
ERROR_MORE_DATA = 234
ERROR_WAIT_TIMEOUT = 258
ERROR_IO_PENDING = 997
ERROR_NOT_FOUND = 1168
ERROR_INVALID_STATE = 5023
ERROR_VHD_INVALID_TYPE = 0xC03A001B
# winbase.h
WAIT_FAILED = 0xFFFFFFFF
FILE_FLAG_OVERLAPPED = 0x40000000
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200
# FileAPI.h
OPEN_EXISTING = 3
INVALID_FILE_ATTRIBUTES = 4294967295
# winnt.h
FILE_ATTRIBUTE_REPARSE_POINT = 0x0400
FILE_SHARE_READ = 1
FILE_SHARE_WRITE = 2
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
OWNER_SECURITY_INFORMATION = 0x00000001
GROUP_SECURITY_INFORMATION = 0x00000002
DACL_SECURITY_INFORMATION = 0x00000004
SACL_SECURITY_INFORMATION = 0x00000008
# winioctl.h
FILE_DEVICE_DISK = 7
# handleapi.h
INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
# minwindef.h
MAX_PATH = 260
# AccCtrl.h
TRUSTEE_IS_NAME = 1
# Indicates a file or directory object.
SE_FILE_OBJECT = 1
# ---------
# ClusApi.h
# ---------
CLUSPROP_SYNTAX_NAME = 262147
CLUSPROP_SYNTAX_ENDMARK = 0
CLUSPROP_SYNTAX_LIST_VALUE_DWORD = 65538
CLUSPROP_SYNTAX_LIST_VALUE_ULARGE_INTEGER = 65542
CLUSAPI_GROUP_MOVE_RETURN_TO_SOURCE_NODE_ON_ERROR = 2
CLUSAPI_GROUP_MOVE_QUEUE_ENABLED = 4
CLUSAPI_GROUP_MOVE_HIGH_PRIORITY_START = 8
CLUSTER_OBJECT_TYPE_GROUP = 2
CLUSTER_CHANGE_GROUP_COMMON_PROPERTY_V2 = 2
CLUSTER_CHANGE_GROUP_STATE_V2 = 8
CLUSGRP_STATUS_WAITING_IN_QUEUE_FOR_MOVE = 4
CLUS_RESTYPE_NAME_VM = "Virtual Machine"
CLUS_RESTYPE_NAME_VM_CONFIG = "Virtual Machine Configuration"
CLUSREG_NAME_GRP_STATUS_INFORMATION = 'StatusInformation'
CLUSCTL_GROUP_GET_RO_COMMON_PROPERTIES = 0x3000055
# iscsidsc.h
# ----------
ISCSI_ANY_INITIATOR_PORT = wintypes.ULONG(-1).value
ISCSI_ALL_INITIATOR_PORTS = wintypes.ULONG(-1).value
MAX_ISCSI_PORTAL_NAME_LEN = 256
MAX_ISCSI_PORTAL_ADDRESS_LEN = 256
MAX_ISCSI_NAME_LEN = 223
MAX_ISCSI_HBANAME_LEN = 256
ISCSI_LOGIN_FLAG_MULTIPATH_ENABLED = 2
ISCSI_LOGIN_OPTIONS_USERNAME = 0x00000020
ISCSI_LOGIN_OPTIONS_PASSWORD = 0x00000040
ISCSI_LOGIN_OPTIONS_AUTH_TYPE = 0x00000080
# iscsierr.h
# ----------
ISDSC_NON_SPECIFIC_ERROR = 0xEFFF0001
ISDSC_LOGIN_FAILED = 0xEFFF0002
ISDSC_CONNECTION_FAILED = 0xEFFF0003
ISDSC_INITIATOR_NODE_ALREADY_EXISTS = 0xEFFF0004
ISDSC_INITIATOR_NODE_NOT_FOUND = 0xEFFF0005
ISDSC_TARGET_MOVED_TEMPORARILY = 0xEFFF0006
ISDSC_TARGET_MOVED_PERMANENTLY = 0xEFFF0007
ISDSC_INITIATOR_ERROR = 0xEFFF0008
ISDSC_AUTHENTICATION_FAILURE = 0xEFFF0009
ISDSC_AUTHORIZATION_FAILURE = 0xEFFF000A
ISDSC_NOT_FOUND = 0xEFFF000B
ISDSC_TARGET_REMOVED = 0xEFFF000C
ISDSC_UNSUPPORTED_VERSION = 0xEFFF000D
ISDSC_TOO_MANY_CONNECTIONS = 0xEFFF000E
ISDSC_MISSING_PARAMETER = 0xEFFF000F
ISDSC_CANT_INCLUDE_IN_SESSION = 0xEFFF0010
ISDSC_SESSION_TYPE_NOT_SUPPORTED = 0xEFFF0011
ISDSC_TARGET_ERROR = 0xEFFF0012
ISDSC_SERVICE_UNAVAILABLE = 0xEFFF0013
ISDSC_OUT_OF_RESOURCES = 0xEFFF0014
ISDSC_CONNECTION_ALREADY_EXISTS = 0xEFFF0015
ISDSC_SESSION_ALREADY_EXISTS = 0xEFFF0016
ISDSC_INITIATOR_INSTANCE_NOT_FOUND = 0xEFFF0017
ISDSC_TARGET_ALREADY_EXISTS = 0xEFFF0018
ISDSC_DRIVER_BUG = 0xEFFF0019
ISDSC_INVALID_TEXT_KEY = 0xEFFF001A
ISDSC_INVALID_SENDTARGETS_TEXT = 0xEFFF001B
ISDSC_INVALID_SESSION_ID = 0xEFFF001C
ISDSC_SCSI_REQUEST_FAILED = 0xEFFF001D
ISDSC_TOO_MANY_SESSIONS = 0xEFFF001E
ISDSC_SESSION_BUSY = 0xEFFF001F
ISDSC_TARGET_MAPPING_UNAVAILABLE = 0xEFFF0020
ISDSC_ADDRESS_TYPE_NOT_SUPPORTED = 0xEFFF0021
ISDSC_LOGON_FAILED = 0xEFFF0022
ISDSC_SEND_FAILED = 0xEFFF0023
ISDSC_TRANSPORT_ERROR = 0xEFFF0024
ISDSC_VERSION_MISMATCH = 0xEFFF0025
ISDSC_TARGET_MAPPING_OUT_OF_RANGE = 0xEFFF0026
ISDSC_TARGET_PRESHAREDKEY_UNAVAILABLE = 0xEFFF0027
ISDSC_TARGET_AUTHINFO_UNAVAILABLE = 0xEFFF0028
ISDSC_TARGET_NOT_FOUND = 0xEFFF0029
ISDSC_LOGIN_USER_INFO_BAD = 0xEFFF002A
ISDSC_TARGET_MAPPING_EXISTS = 0xEFFF002B
ISDSC_HBA_SECURITY_CACHE_FULL = 0xEFFF002C
ISDSC_INVALID_PORT_NUMBER = 0xEFFF002D
ISDSC_OPERATION_NOT_ALL_SUCCESS = 0xAFFF002E
ISDSC_HBA_SECURITY_CACHE_NOT_SUPPORTED = 0xEFFF002F
ISDSC_IKE_ID_PAYLOAD_TYPE_NOT_SUPPORTED = 0xEFFF0030
ISDSC_IKE_ID_PAYLOAD_INCORRECT_SIZE = 0xEFFF0031
ISDSC_TARGET_PORTAL_ALREADY_EXISTS = 0xEFFF0032
ISDSC_TARGET_ADDRESS_ALREADY_EXISTS = 0xEFFF0033
ISDSC_NO_AUTH_INFO_AVAILABLE = 0xEFFF0034
ISDSC_NO_TUNNEL_OUTER_MODE_ADDRESS = 0xEFFF0035
ISDSC_CACHE_CORRUPTED = 0xEFFF0036
ISDSC_REQUEST_NOT_SUPPORTED = 0xEFFF0037
ISDSC_TARGET_OUT_OF_RESORCES = 0xEFFF0038
ISDSC_SERVICE_DID_NOT_RESPOND = 0xEFFF0039
ISDSC_ISNS_SERVER_NOT_FOUND = 0xEFFF003A
ISDSC_OPERATION_REQUIRES_REBOOT = 0xAFFF003B
ISDSC_NO_PORTAL_SPECIFIED = 0xEFFF003C
ISDSC_CANT_REMOVE_LAST_CONNECTION = 0xEFFF003D
ISDSC_SERVICE_NOT_RUNNING = 0xEFFF003E
ISDSC_TARGET_ALREADY_LOGGED_IN = 0xEFFF003F
ISDSC_DEVICE_BUSY_ON_SESSION = 0xEFFF0040
ISDSC_COULD_NOT_SAVE_PERSISTENT_LOGIN_DATA = 0xEFFF0041
ISDSC_COULD_NOT_REMOVE_PERSISTENT_LOGIN_DATA = 0xEFFF0042
ISDSC_PORTAL_NOT_FOUND = 0xEFFF0043
ISDSC_INITIATOR_NOT_FOUND = 0xEFFF0044
ISDSC_DISCOVERY_MECHANISM_NOT_FOUND = 0xEFFF0045
ISDSC_IPSEC_NOT_SUPPORTED_ON_OS = 0xEFFF0046
ISDSC_PERSISTENT_LOGIN_TIMEOUT = 0xEFFF0047
ISDSC_SHORT_CHAP_SECRET = 0xAFFF0048
ISDSC_EVALUATION_PEROID_EXPIRED = 0xEFFF0049
ISDSC_INVALID_CHAP_SECRET = 0xEFFF004A
ISDSC_INVALID_TARGET_CHAP_SECRET = 0xEFFF004B
ISDSC_INVALID_INITIATOR_CHAP_SECRET = 0xEFFF004C
ISDSC_INVALID_CHAP_USER_NAME = 0xEFFF004D
ISDSC_INVALID_LOGON_AUTH_TYPE = 0xEFFF004E
ISDSC_INVALID_TARGET_MAPPING = 0xEFFF004F
ISDSC_INVALID_TARGET_ID = 0xEFFF0050
ISDSC_INVALID_ISCSI_NAME = 0xEFFF0051
ISDSC_INCOMPATIBLE_ISNS_VERSION = 0xEFFF0052
ISDSC_FAILED_TO_CONFIGURE_IPSEC = 0xEFFF0053
ISDSC_BUFFER_TOO_SMALL = 0xEFFF0054
ISDSC_INVALID_LOAD_BALANCE_POLICY = 0xEFFF0055
ISDSC_INVALID_PARAMETER = 0xEFFF0056
ISDSC_DUPLICATE_PATH_SPECIFIED = 0xEFFF0057
ISDSC_PATH_COUNT_MISMATCH = 0xEFFF0058
ISDSC_INVALID_PATH_ID = 0xEFFF0059
ISDSC_MULTIPLE_PRIMARY_PATHS_SPECIFIED = 0xEFFF005A
ISDSC_NO_PRIMARY_PATH_SPECIFIED = 0xEFFF005B
ISDSC_DEVICE_ALREADY_PERSISTENTLY_BOUND = 0xEFFF005C
ISDSC_DEVICE_NOT_FOUND = 0xEFFF005D
ISDSC_DEVICE_NOT_ISCSI_OR_PERSISTENT = 0xEFFF005E
ISDSC_DNS_NAME_UNRESOLVED = 0xEFFF005F
ISDSC_NO_CONNECTION_AVAILABLE = 0xEFFF0060
ISDSC_LB_POLICY_NOT_SUPPORTED = 0xEFFF0061
ISDSC_REMOVE_CONNECTION_IN_PROGRESS = 0xEFFF0062
ISDSC_INVALID_CONNECTION_ID = 0xEFFF0063
ISDSC_CANNOT_REMOVE_LEADING_CONNECTION = 0xEFFF0064
ISDSC_RESTRICTED_BY_GROUP_POLICY = 0xEFFF0065
ISDSC_ISNS_FIREWALL_BLOCKED = 0xEFFF0066
ISDSC_FAILURE_TO_PERSIST_LB_POLICY = 0xEFFF0067
ISDSC_INVALID_HOST = 0xEFFF0068
# virtdisk.h
# ----------
VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT = wintypes.GUID(
Data1=0xec984aec,
Data2=0xa0f9,
Data3=0x47e9,
Data4=(wintypes.BYTE * 8)(0x90, 0x1f, 0x71, 0x41,
0x5a, 0x66, 0x34, 0x5b))
VIRTUAL_STORAGE_TYPE_DEVICE_ISO = 1
VIRTUAL_STORAGE_TYPE_DEVICE_VHD = 2
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 3
VIRTUAL_DISK_ACCESS_NONE = 0
VIRTUAL_DISK_ACCESS_ALL = 0x003f0000
VIRTUAL_DISK_ACCESS_CREATE = 0x00100000
VIRTUAL_DISK_ACCESS_GET_INFO = 0x80000
VIRTUAL_DISK_ACCESS_DETACH = 0x00040000
OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS = 1
OPEN_VIRTUAL_DISK_VERSION_1 = 1
OPEN_VIRTUAL_DISK_VERSION_2 = 2
RESIZE_VIRTUAL_DISK_VERSION_1 = 1
CREATE_VIRTUAL_DISK_VERSION_2 = 2
CREATE_VHD_PARAMS_DEFAULT_BLOCK_SIZE = 0
CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION = 1
MERGE_VIRTUAL_DISK_VERSION_1 = 1
GET_VIRTUAL_DISK_INFO_SIZE = 1
GET_VIRTUAL_DISK_INFO_PARENT_LOCATION = 3
GET_VIRTUAL_DISK_INFO_VIRTUAL_STORAGE_TYPE = 6
GET_VIRTUAL_DISK_INFO_PROVIDER_SUBTYPE = 7
SET_VIRTUAL_DISK_INFO_PARENT_PATH = 1

View File

View File

@ -0,0 +1,321 @@
# Copyright 2016 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Error codes and descriptions, as provided by iscsierr.h
from os_win._i18n import _
from os_win.utils.winapi import constants as w_const
err_msg_dict = {
w_const.ISDSC_NON_SPECIFIC_ERROR:
_('A non specific error occurred.'),
w_const.ISDSC_LOGIN_FAILED:
_('Login Failed.'),
w_const.ISDSC_CONNECTION_FAILED:
_('Connection Failed.'),
w_const.ISDSC_INITIATOR_NODE_ALREADY_EXISTS:
_('Initiator Node Already Exists.'),
w_const.ISDSC_INITIATOR_NODE_NOT_FOUND:
_('Initiator Node Does Not Exist.'),
w_const.ISDSC_TARGET_MOVED_TEMPORARILY:
_('Target Moved Temporarily.'),
w_const.ISDSC_TARGET_MOVED_PERMANENTLY:
_('Target Moved Permanently.'),
w_const.ISDSC_INITIATOR_ERROR:
_('Initiator Error.'),
w_const.ISDSC_AUTHENTICATION_FAILURE:
_('Authentication Failure.'),
w_const.ISDSC_AUTHORIZATION_FAILURE:
_('Authorization Failure.'),
w_const.ISDSC_NOT_FOUND:
_('Not Found.'),
w_const.ISDSC_TARGET_REMOVED:
_('Target Removed.'),
w_const.ISDSC_UNSUPPORTED_VERSION:
_('Unsupported Version.'),
w_const.ISDSC_TOO_MANY_CONNECTIONS:
_('Too many Connections.'),
w_const.ISDSC_MISSING_PARAMETER:
_('Missing Parameter.'),
w_const.ISDSC_CANT_INCLUDE_IN_SESSION:
_('Can not include in session.'),
w_const.ISDSC_SESSION_TYPE_NOT_SUPPORTED:
_('Session type not supported.'),
w_const.ISDSC_TARGET_ERROR:
_('Target Error.'),
w_const.ISDSC_SERVICE_UNAVAILABLE:
_('Service Unavailable.'),
w_const.ISDSC_OUT_OF_RESOURCES:
_('Out of Resources.'),
w_const.ISDSC_CONNECTION_ALREADY_EXISTS:
_('Connections already exist on initiator node.'),
w_const.ISDSC_SESSION_ALREADY_EXISTS:
_('Session Already Exists.'),
w_const.ISDSC_INITIATOR_INSTANCE_NOT_FOUND:
_('Initiator Instance Does Not Exist.'),
w_const.ISDSC_TARGET_ALREADY_EXISTS:
_('Target Already Exists.'),
w_const.ISDSC_DRIVER_BUG:
_('The iscsi driver implementation did '
'not complete an operation correctly.'),
w_const.ISDSC_INVALID_TEXT_KEY:
_('An invalid key text was encountered.'),
w_const.ISDSC_INVALID_SENDTARGETS_TEXT:
_('Invalid SendTargets response text was encountered.'),
w_const.ISDSC_INVALID_SESSION_ID:
_('Invalid Session Id.'),
w_const.ISDSC_SCSI_REQUEST_FAILED:
_('The scsi request failed.'),
w_const.ISDSC_TOO_MANY_SESSIONS:
_('Exceeded max sessions for this initiator.'),
w_const.ISDSC_SESSION_BUSY:
_('Session is busy since a request is already in progress.'),
w_const.ISDSC_TARGET_MAPPING_UNAVAILABLE:
_('The target mapping requested is not available.'),
w_const.ISDSC_ADDRESS_TYPE_NOT_SUPPORTED:
_('The Target Address type given is not supported.'),
w_const.ISDSC_LOGON_FAILED:
_('Logon Failed.'),
w_const.ISDSC_SEND_FAILED:
_('TCP Send Failed.'),
w_const.ISDSC_TRANSPORT_ERROR:
_('TCP Transport Error'),
w_const.ISDSC_VERSION_MISMATCH:
_('iSCSI Version Mismatch'),
w_const.ISDSC_TARGET_MAPPING_OUT_OF_RANGE:
_('The Target Mapping Address passed is out of range for the '
'adapter configuration.'),
w_const.ISDSC_TARGET_PRESHAREDKEY_UNAVAILABLE:
_('The preshared key for the target or IKE identification '
'payload is not available.'),
w_const.ISDSC_TARGET_AUTHINFO_UNAVAILABLE:
_('The authentication information for '
'the target is not available.'),
w_const.ISDSC_TARGET_NOT_FOUND:
_('The target name is not found or is '
'marked as hidden from login.'),
w_const.ISDSC_LOGIN_USER_INFO_BAD:
_('One or more parameters specified in '
'LoginTargetIN structure is invalid.'),
w_const.ISDSC_TARGET_MAPPING_EXISTS:
_('Given target mapping already exists.'),
w_const.ISDSC_HBA_SECURITY_CACHE_FULL:
_('The HBA security information cache '
'is full.'),
w_const.ISDSC_INVALID_PORT_NUMBER:
_('The port number passed is '
'not valid for the initiator.'),
w_const.ISDSC_OPERATION_NOT_ALL_SUCCESS:
_('The operation was not successful '
'for all initiators or discovery '
'methods.'),
w_const.ISDSC_HBA_SECURITY_CACHE_NOT_SUPPORTED:
_('The HBA security information '
'cache is not supported by '
'this adapter.'),
w_const.ISDSC_IKE_ID_PAYLOAD_TYPE_NOT_SUPPORTED:
_('The IKE id payload type '
'specified is not supported.'),
w_const.ISDSC_IKE_ID_PAYLOAD_INCORRECT_SIZE:
_('The IKE id payload size '
'specified is not correct.'),
w_const.ISDSC_TARGET_PORTAL_ALREADY_EXISTS:
_('Target Portal Structure '
'Already Exists.'),
w_const.ISDSC_TARGET_ADDRESS_ALREADY_EXISTS:
_('Target Address Structure '
'Already Exists.'),
w_const.ISDSC_NO_AUTH_INFO_AVAILABLE:
_('There is no IKE authentication '
'information available.'),
w_const.ISDSC_NO_TUNNEL_OUTER_MODE_ADDRESS:
_('There is no tunnel mode outer '
'address specified.'),
w_const.ISDSC_CACHE_CORRUPTED:
_('Authentication or tunnel '
'address cache is corrupted.'),
w_const.ISDSC_REQUEST_NOT_SUPPORTED:
_('The request or operation '
'is not supported.'),
w_const.ISDSC_TARGET_OUT_OF_RESORCES:
_('The target does not have enough '
'resources to process the '
'given request.'),
w_const.ISDSC_SERVICE_DID_NOT_RESPOND:
_('The initiator service did '
'not respond to the request '
'sent by the driver.'),
w_const.ISDSC_ISNS_SERVER_NOT_FOUND:
_('The Internet Storage Name Server (iSNS) '
'server was not found or is unavailable.'),
w_const.ISDSC_OPERATION_REQUIRES_REBOOT:
_('The operation was successful but '
'requires a driver reload or reboot '
'to become effective.'),
w_const.ISDSC_NO_PORTAL_SPECIFIED:
_('There is no target portal available '
'to complete the login.'),
w_const.ISDSC_CANT_REMOVE_LAST_CONNECTION:
_('Cannot remove the last '
'connection for a session.'),
w_const.ISDSC_SERVICE_NOT_RUNNING:
_('The Microsoft iSCSI initiator '
'service has not been started.'),
w_const.ISDSC_TARGET_ALREADY_LOGGED_IN:
_('The target has already been '
'logged in via an iSCSI session.'),
w_const.ISDSC_DEVICE_BUSY_ON_SESSION:
_('The session cannot be logged out '
'since a device on that session is '
'currently being used.'),
w_const.ISDSC_COULD_NOT_SAVE_PERSISTENT_LOGIN_DATA:
_('Failed to save persistent '
'login information.'),
w_const.ISDSC_COULD_NOT_REMOVE_PERSISTENT_LOGIN_DATA:
_('Failed to remove '
'persistent login '
'information.'),
w_const.ISDSC_PORTAL_NOT_FOUND:
_('The specified portal was not found.'),
w_const.ISDSC_INITIATOR_NOT_FOUND:
_('The specified initiator '
'name was not found.'),
w_const.ISDSC_DISCOVERY_MECHANISM_NOT_FOUND:
_('The specified discovery '
'mechanism was not found.'),
w_const.ISDSC_IPSEC_NOT_SUPPORTED_ON_OS:
_('iSCSI does not support IPSEC '
'for this version of the OS.'),
w_const.ISDSC_PERSISTENT_LOGIN_TIMEOUT:
_('The iSCSI service timed out waiting '
'for all persistent logins to '
'complete.'),
w_const.ISDSC_SHORT_CHAP_SECRET:
_('The specified CHAP secret is less than '
'96 bits and will not be usable for '
'authenticating over non ipsec connections.'),
w_const.ISDSC_EVALUATION_PEROID_EXPIRED:
_('The evaluation period for the '
'iSCSI initiator service has '
'expired.'),
w_const.ISDSC_INVALID_CHAP_SECRET:
_('CHAP secret given does not conform '
'to the standard. Please see system '
'event log for more information.'),
w_const.ISDSC_INVALID_TARGET_CHAP_SECRET:
_('Target CHAP secret given is invalid. Maximum size of CHAP secret'
'is 16 bytes. Minimum size is 12 bytes if IPSec is not used.'),
w_const.ISDSC_INVALID_INITIATOR_CHAP_SECRET:
_('Initiator CHAP secret given is '
'invalid. Maximum size of CHAP '
'secret is 16 bytes. Minimum size '
'is 12 bytes if IPSec is '
'not used.'),
w_const.ISDSC_INVALID_CHAP_USER_NAME:
_('CHAP Username given is invalid.'),
w_const.ISDSC_INVALID_LOGON_AUTH_TYPE:
_('Logon Authentication type '
'given is invalid.'),
w_const.ISDSC_INVALID_TARGET_MAPPING:
_('Target Mapping information '
'given is invalid.'),
w_const.ISDSC_INVALID_TARGET_ID:
_('Target Id given in '
'Target Mapping is invalid.'),
w_const.ISDSC_INVALID_ISCSI_NAME:
_('The iSCSI name specified contains '
'invalid characters or is too long.'),
w_const.ISDSC_INCOMPATIBLE_ISNS_VERSION:
_('The version number returned from the '
'Internet Storage Name Server (iSNS) '
'server is not compatible with this '
'version of the iSNS client.'),
w_const.ISDSC_FAILED_TO_CONFIGURE_IPSEC:
_('Initiator failed to configure IPSec '
'for the given connection. This could '
'be because of low resources.'),
w_const.ISDSC_BUFFER_TOO_SMALL:
_('The buffer given for processing '
'the request is too small.'),
w_const.ISDSC_INVALID_LOAD_BALANCE_POLICY:
_('The given Load Balance '
'policy is not recognized '
'by iScsi initiator.'),
w_const.ISDSC_INVALID_PARAMETER:
_('One or more paramaters '
'specified is not valid.'),
w_const.ISDSC_DUPLICATE_PATH_SPECIFIED:
_('Duplicate PathIds were '
'specified in the call to '
'set Load Balance Policy.'),
w_const.ISDSC_PATH_COUNT_MISMATCH:
_('Number of paths specified in '
'Set Load Balance Policy does not '
'match the number of paths to the target.'),
w_const.ISDSC_INVALID_PATH_ID:
_('Path Id specified in the call to '
'set Load Balance Policy is not valid'),
w_const.ISDSC_MULTIPLE_PRIMARY_PATHS_SPECIFIED:
_('Multiple primary paths '
'specified when only one '
'primary path is expected.'),
w_const.ISDSC_NO_PRIMARY_PATH_SPECIFIED:
_('No primary path specified when '
'at least one is expected.'),
w_const.ISDSC_DEVICE_ALREADY_PERSISTENTLY_BOUND:
_('Device is already a '
'persistently bound device.'),
w_const.ISDSC_DEVICE_NOT_FOUND:
_('Device was not found.'),
w_const.ISDSC_DEVICE_NOT_ISCSI_OR_PERSISTENT:
_('The device specified does not '
'originate from an iSCSI disk '
'or a persistent iSCSI login.'),
w_const.ISDSC_DNS_NAME_UNRESOLVED:
_('The DNS name specified was not resolved.'),
w_const.ISDSC_NO_CONNECTION_AVAILABLE:
_('There is no connection available '
'in the iSCSI session to '
'process the request.'),
w_const.ISDSC_LB_POLICY_NOT_SUPPORTED:
_('The given Load Balance '
'policy is not supported.'),
w_const.ISDSC_REMOVE_CONNECTION_IN_PROGRESS:
_('A remove connection request '
'is already in progress for '
'this session.'),
w_const.ISDSC_INVALID_CONNECTION_ID:
_('Given connection was not '
'found in the session.'),
w_const.ISDSC_CANNOT_REMOVE_LEADING_CONNECTION:
_('The leading connection in '
'the session cannot be '
'removed.'),
w_const.ISDSC_RESTRICTED_BY_GROUP_POLICY:
_('The operation cannot be performed '
'since it does not conform with '
'the group policy assigned to '
'this computer.'),
w_const.ISDSC_ISNS_FIREWALL_BLOCKED:
_('The operation cannot be performed since '
'the Internet Storage Name Server '
'(iSNS) firewall exception has '
'not been enabled.'),
w_const.ISDSC_FAILURE_TO_PERSIST_LB_POLICY:
_('Failed to persist load '
'balancing policy parameters.'),
w_const.ISDSC_INVALID_HOST:
_('The name could not be resolved to an IP Address.'),
}

View File

@ -0,0 +1,49 @@
# Copyright 2017 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import importlib
from os_win._i18n import _
from os_win import exceptions
ADVAPI32 = 'advapi32'
CLUSAPI = 'clusapi'
HBAAPI = 'hbaapi'
ISCSIDSC = 'iscsidsc'
KERNEL32 = 'kernel32'
VIRTDISK = 'virtdisk'
libs = [ADVAPI32, CLUSAPI, HBAAPI, ISCSIDSC, KERNEL32, VIRTDISK]
def _get_shared_lib_module(lib_name):
if lib_name not in libs:
err_msg = _("Unsupported library: %s.")
raise exceptions.OSWinException(err_msg % lib_name)
module = importlib.import_module('os_win.utils.winapi.libs.%s' % lib_name)
return module
def register():
for lib_name in libs:
module = _get_shared_lib_module(lib_name)
module.register()
def get_shared_lib_handle(lib_name):
module = _get_shared_lib_module(lib_name)
return module.lib_handle

View File

@ -0,0 +1,78 @@
# Copyright 2017 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
from os_win.utils.winapi import wintypes
lib_handle = None
class TRUSTEE(ctypes.Structure):
_fields_ = [
('pMultipleTrustee', wintypes.PVOID),
('MultipleTrusteeOperation', wintypes.INT),
('TrusteeForm', wintypes.INT),
('TrusteeType', wintypes.INT),
('pstrName', wintypes.LPWSTR)
]
class EXPLICIT_ACCESS(ctypes.Structure):
_fields_ = [
('grfAccessPermissions', wintypes.DWORD),
('grfAccessMode', wintypes.INT),
('grfInheritance', wintypes.DWORD),
('Trustee', TRUSTEE)
]
PEXPLICIT_ACCESS = ctypes.POINTER(EXPLICIT_ACCESS)
def register():
global lib_handle
lib_handle = ctypes.windll.advapi32
lib_handle.GetNamedSecurityInfoW.argtypes = [
wintypes.LPCWSTR,
wintypes.INT,
wintypes.DWORD,
wintypes.PVOID,
wintypes.PVOID,
wintypes.PVOID,
wintypes.PVOID,
wintypes.PVOID
]
lib_handle.GetNamedSecurityInfoW.restype = wintypes.DWORD
lib_handle.SetEntriesInAclW.argtypes = [
wintypes.ULONG,
PEXPLICIT_ACCESS,
wintypes.PVOID,
wintypes.PVOID
]
lib_handle.SetEntriesInAclW.restype = wintypes.DWORD
lib_handle.SetNamedSecurityInfoW.argtypes = [
wintypes.LPWSTR,
wintypes.INT,
wintypes.DWORD,
wintypes.PVOID,
wintypes.PVOID,
wintypes.PVOID,
wintypes.PVOID
]
lib_handle.SetNamedSecurityInfoW.restype = wintypes.DWORD

View File

@ -0,0 +1,123 @@
# Copyright 2017 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
from os_win.utils.winapi import wintypes
lib_handle = None
class NOTIFY_FILTER_AND_TYPE(ctypes.Structure):
_fields_ = [
('dwObjectType', wintypes.DWORD),
('FilterFlags', wintypes.LONGLONG)
]
PNOTIFY_FILTER_AND_TYPE = ctypes.POINTER(NOTIFY_FILTER_AND_TYPE)
def register():
global lib_handle
lib_handle = ctypes.windll.clusapi
lib_handle.CancelClusterGroupOperation.argtypes = [
wintypes.HANDLE,
wintypes.DWORD
]
lib_handle.CancelClusterGroupOperation.restype = wintypes.DWORD
lib_handle.CloseCluster.argtypes = [wintypes.HANDLE]
lib_handle.CloseCluster.restype = wintypes.BOOL
lib_handle.CloseClusterGroup.argtypes = [wintypes.HANDLE]
lib_handle.CloseClusterGroup.restype = wintypes.BOOL
lib_handle.CloseClusterNode.argtypes = [wintypes.HANDLE]
lib_handle.CloseClusterNode.restype = wintypes.BOOL
lib_handle.CloseClusterNotifyPort.argtypes = [wintypes.HANDLE]
lib_handle.CloseClusterNotifyPort.restype = wintypes.BOOL
lib_handle.ClusterGroupControl.argtypes = [
wintypes.HANDLE,
wintypes.HANDLE,
wintypes.DWORD,
wintypes.LPVOID,
wintypes.DWORD,
wintypes.LPVOID,
wintypes.DWORD,
wintypes.LPVOID
]
lib_handle.ClusterGroupControl.restype = wintypes.DWORD
lib_handle.GetClusterGroupState.argtypes = [
wintypes.HANDLE,
wintypes.LPWSTR,
wintypes.PDWORD
]
lib_handle.GetClusterGroupState.restype = wintypes.DWORD
lib_handle.CreateClusterNotifyPortV2.argtypes = [
wintypes.HANDLE,
wintypes.HANDLE,
PNOTIFY_FILTER_AND_TYPE,
wintypes.DWORD,
wintypes.PDWORD
]
lib_handle.CreateClusterNotifyPortV2.restype = wintypes.HANDLE
lib_handle.GetClusterNotifyV2.argtypes = [
wintypes.HANDLE,
ctypes.POINTER(wintypes.PDWORD),
PNOTIFY_FILTER_AND_TYPE,
wintypes.PBYTE,
wintypes.LPDWORD,
wintypes.LPWSTR,
wintypes.LPDWORD,
wintypes.LPWSTR,
wintypes.LPDWORD,
wintypes.LPWSTR,
wintypes.LPDWORD,
wintypes.LPWSTR,
wintypes.LPDWORD,
wintypes.DWORD
]
lib_handle.GetClusterNotifyV2.restype = wintypes.DWORD
lib_handle.MoveClusterGroupEx.argtypes = [
wintypes.HANDLE,
wintypes.HANDLE,
wintypes.DWORD,
wintypes.PVOID,
wintypes.DWORD
]
lib_handle.MoveClusterGroupEx.restype = wintypes.DWORD
lib_handle.OpenCluster.argtypes = [wintypes.LPCWSTR]
lib_handle.OpenCluster.restype = wintypes.HANDLE
lib_handle.OpenClusterGroup.argtypes = [
wintypes.HANDLE,
wintypes.LPCWSTR
]
lib_handle.OpenClusterGroup.restype = wintypes.HANDLE
lib_handle.OpenClusterNode.argtypes = [
wintypes.HANDLE,
wintypes.LPCWSTR
]
lib_handle.OpenClusterNode.restype = wintypes.HANDLE

View File

@ -1,4 +1,4 @@
# Copyright 2015 Cloudbase Solutions Srl
# Copyright 2016 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -15,15 +15,25 @@
import ctypes
import os_win.conf
from os_win.utils.winapi import wintypes
CONF = os_win.conf.CONF
lib_handle = None
HBA_STATUS = ctypes.c_uint32
HBA_HANDLE = ctypes.c_uint32
HBA_PortType = ctypes.c_uint32
HBA_PortSpeed = ctypes.c_uint32
HBA_PortState = ctypes.c_uint32
HBA_COS = ctypes.c_uint32
HBA_WWN = ctypes.c_ubyte * 8
HBA_FC4Types = ctypes.c_uint32 * 32
HBA_FCPBindingType = ctypes.c_int
HBA_FCPBindingType = wintypes.INT
class HBA_WWN(ctypes.Structure):
_fields_ = [('wwn', ctypes.c_ubyte * 8)]
class HBA_PortAttributes(ctypes.Structure):
@ -34,8 +44,8 @@ class HBA_PortAttributes(ctypes.Structure):
('PortState', HBA_PortState),
('PortSupportedClassofService', HBA_COS),
('PortSupportedFc4Types', HBA_FC4Types),
('PortSymbolicName', ctypes.c_char * 256),
('OSDeviceName', ctypes.c_char * 256),
('PortSymbolicName', wintypes.CHAR * 256),
('OSDeviceName', wintypes.CHAR * 256),
('PortSupportedSpeed', HBA_PortSpeed),
('PortSpeed', HBA_PortSpeed),
('PortMaxFrameSize', ctypes.c_uint32),
@ -51,7 +61,7 @@ class HBA_FCPId(ctypes.Structure):
class HBA_ScsiId(ctypes.Structure):
_fields_ = [('OSDeviceName', ctypes.c_char * 256),
_fields_ = [('OSDeviceName', wintypes.CHAR * 256),
('ScsiBusNumber', ctypes.c_uint32),
('ScsiTargetNumber', ctypes.c_uint32),
('ScsiOSLun', ctypes.c_uint32)]
@ -75,16 +85,62 @@ def get_target_mapping_struct(entry_count=0):
class HBA_AdapterAttributes(ctypes.Structure):
_fields_ = [('Manufacturer', ctypes.c_char * 64),
('SerialNumber', ctypes.c_char * 64),
('Model', ctypes.c_char * 256),
('ModelDescription', ctypes.c_char * 256),
_fields_ = [('Manufacturer', wintypes.CHAR * 64),
('SerialNumber', wintypes.CHAR * 64),
('Model', wintypes.CHAR * 256),
('ModelDescription', wintypes.CHAR * 256),
('NodeWWN', HBA_WWN),
('NodeSymbolicName', ctypes.c_char * 256),
('HardwareVersion', ctypes.c_char * 256),
('DriverVersion', ctypes.c_char * 256),
('OptionROMVersion', ctypes.c_char * 256),
('FirmwareVersion', ctypes.c_char * 256),
('NodeSymbolicName', wintypes.CHAR * 256),
('HardwareVersion', wintypes.CHAR * 256),
('DriverVersion', wintypes.CHAR * 256),
('OptionROMVersion', wintypes.CHAR * 256),
('FirmwareVersion', wintypes.CHAR * 256),
('VendorSpecificID', ctypes.c_uint32),
('NumberOfPorts', ctypes.c_uint32),
('DriverName', ctypes.c_char * 256)]
('DriverName', wintypes.CHAR * 256)]
def register():
global lib_handle
lib_handle = ctypes.cdll.LoadLibrary(CONF.os_win.hbaapi_lib_path)
lib_handle.HBA_CloseAdapter.argtypes = [HBA_HANDLE]
lib_handle.HBA_CloseAdapter.restype = None
lib_handle.HBA_GetAdapterAttributes.argtypes = [
HBA_HANDLE,
ctypes.POINTER(HBA_AdapterAttributes)]
lib_handle.HBA_GetAdapterAttributes.restype = HBA_STATUS
lib_handle.HBA_GetAdapterName.argtypes = [
ctypes.c_uint32,
wintypes.PCHAR
]
lib_handle.HBA_GetAdapterName.restype = HBA_STATUS
lib_handle.HBA_GetAdapterPortAttributes.argtypes = [
HBA_HANDLE,
ctypes.c_uint32,
ctypes.POINTER(HBA_PortAttributes)
]
lib_handle.HBA_GetAdapterPortAttributes.restype = HBA_STATUS
lib_handle.HBA_GetFcpTargetMapping.argtypes = [
HBA_HANDLE,
wintypes.PVOID
]
lib_handle.HBA_GetFcpTargetMapping.restype = HBA_STATUS
lib_handle.HBA_GetNumberOfAdapters.argtypes = []
lib_handle.HBA_GetNumberOfAdapters.restype = ctypes.c_uint32
lib_handle.HBA_OpenAdapter.argtypes = [wintypes.PCHAR]
lib_handle.HBA_OpenAdapter.restype = HBA_HANDLE
lib_handle.HBA_OpenAdapterByWWN.argtypes = [
ctypes.POINTER(HBA_HANDLE),
HBA_WWN]
lib_handle.HBA_OpenAdapterByWWN.restype = HBA_STATUS
lib_handle.HBA_RefreshAdapterConfiguration.argtypes = []
lib_handle.HBA_RefreshAdapterConfiguration.restype = None

View File

@ -0,0 +1,267 @@
# Copyright 2017 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
from os_win.utils.winapi import constants as w_const
from os_win.utils.winapi import wintypes
lib_handle = None
ISCSI_SECURITY_FLAGS = ctypes.c_uint64
ISCSI_LOGIN_FLAGS = ctypes.c_uint32
ISCSI_LOGIN_OPTIONS_INFO_SPECIFIED = ctypes.c_uint32
ISCSI_AUTH_TYPES = wintypes.UINT
ISCSI_DIGEST_TYPES = wintypes.UINT
DEVICE_TYPE = wintypes.ULONG
class ISCSI_TARGET_PORTAL(ctypes.Structure):
_fields_ = [
('SymbolicName', wintypes.WCHAR * w_const.MAX_ISCSI_PORTAL_NAME_LEN),
('Address', wintypes.WCHAR * w_const.MAX_ISCSI_PORTAL_ADDRESS_LEN),
('Socket', wintypes.USHORT)
]
PISCSI_TARGET_PORTAL = ctypes.POINTER(ISCSI_TARGET_PORTAL)
class ISCSI_LOGIN_OPTIONS(ctypes.Structure):
_fields_ = [
('Version', wintypes.ULONG),
('InformationSpecified', ISCSI_LOGIN_OPTIONS_INFO_SPECIFIED),
('LoginFlags', ISCSI_LOGIN_FLAGS),
('AuthType', ISCSI_AUTH_TYPES),
('HeaderDigest', ISCSI_DIGEST_TYPES),
('DataDigest', ISCSI_DIGEST_TYPES),
('MaximumConnections', wintypes.ULONG),
('DefaultTime2Wait', wintypes.ULONG),
('DefaultTime2Retain', wintypes.ULONG),
('UsernameLength', wintypes.ULONG),
('PasswordLength', wintypes.ULONG),
('Username', wintypes.PSTR),
('Password', wintypes.PSTR)
]
PISCSI_LOGIN_OPTIONS = ctypes.POINTER(ISCSI_LOGIN_OPTIONS)
class SCSI_LUN_LIST(ctypes.Structure):
_fields_ = [
('OSLUN', wintypes.ULONG),
('TargetLUN', wintypes.ULONGLONG)
]
PSCSI_LUN_LIST = ctypes.POINTER(SCSI_LUN_LIST)
class ISCSI_UNIQUE_SESSION_ID(ctypes.Structure):
_fields_ = [
('AdapterUnique', wintypes.ULONGLONG),
('AdapterSpecific', wintypes.ULONGLONG)
]
PISCSI_UNIQUE_SESSION_ID = ctypes.POINTER(ISCSI_UNIQUE_SESSION_ID)
class ISCSI_UNIQUE_CONNECTION_ID(ISCSI_UNIQUE_SESSION_ID):
pass
PISCSI_UNIQUE_CONNECTION_ID = ctypes.POINTER(ISCSI_UNIQUE_CONNECTION_ID)
class ISCSI_TARGET_MAPPING(ctypes.Structure):
_fields_ = [
('InitiatorName', wintypes.WCHAR * w_const.MAX_ISCSI_HBANAME_LEN),
('TargetName', wintypes.WCHAR * (w_const.MAX_ISCSI_NAME_LEN + 1)),
('OSDeviceName', wintypes.WCHAR * w_const.MAX_PATH),
('SessionId', ISCSI_UNIQUE_SESSION_ID),
('OSBusNumber', wintypes.ULONG),
('OSTargetNumber', wintypes.ULONG),
('LUNCount', wintypes.ULONG),
('LUNList', PSCSI_LUN_LIST)
]
PISCSI_TARGET_MAPPING = ctypes.POINTER(ISCSI_TARGET_MAPPING)
class PERSISTENT_ISCSI_LOGIN_INFO(ctypes.Structure):
_fields_ = [
('TargetName', wintypes.WCHAR * (w_const.MAX_ISCSI_NAME_LEN + 1)),
('IsInformationalSession', wintypes.BOOLEAN),
('InitiatorInstance', wintypes.WCHAR * w_const.MAX_ISCSI_HBANAME_LEN),
('InitiatorPortNumber', wintypes.ULONG),
('TargetPortal', ISCSI_TARGET_PORTAL),
('SecurityFlags', ISCSI_SECURITY_FLAGS),
('Mappings', PISCSI_TARGET_MAPPING),
('LoginOptions', ISCSI_LOGIN_OPTIONS)
]
PPERSISTENT_ISCSI_LOGIN_INFO = ctypes.POINTER(PERSISTENT_ISCSI_LOGIN_INFO)
class ISCSI_CONNECTION_INFO(ctypes.Structure):
_fields_ = [
('ConnectionId', ISCSI_UNIQUE_CONNECTION_ID),
('InitiatorAddress', wintypes.PWSTR),
('TargetAddress', wintypes.PWSTR),
('InitiatorSocket', wintypes.USHORT),
('TargetSocket', wintypes.USHORT),
('CID', ctypes.c_ubyte * 2)
]
PISCSI_CONNECTION_INFO = ctypes.POINTER(ISCSI_CONNECTION_INFO)
class ISCSI_SESSION_INFO(ctypes.Structure):
_fields_ = [
('SessionId', ISCSI_UNIQUE_SESSION_ID),
('InitiatorName', wintypes.PWSTR),
('TargetName', wintypes.PWSTR),
('TargetNodeName', wintypes.PWSTR),
('ISID', ctypes.c_ubyte * 6),
('TSID', ctypes.c_ubyte * 2),
('ConnectionCount', wintypes.ULONG),
('Connections', PISCSI_CONNECTION_INFO)
]
PISCSI_SESSION_INFO = ctypes.POINTER(ISCSI_SESSION_INFO)
class SCSI_ADDRESS(ctypes.Structure):
_fields_ = [
('Length', wintypes.ULONG),
('PortNumber', ctypes.c_ubyte),
('PathId', ctypes.c_ubyte),
('TargetId', ctypes.c_ubyte),
('Lun', ctypes.c_ubyte)
]
class STORAGE_DEVICE_NUMBER(ctypes.Structure):
_fields_ = [
('DeviceType', DEVICE_TYPE),
('DeviceNumber', wintypes.DWORD),
('PartitionNumber', wintypes.DWORD)
]
class ISCSI_DEVICE_ON_SESSION(ctypes.Structure):
_fields_ = [
('InitiatorName', wintypes.WCHAR * w_const.MAX_ISCSI_HBANAME_LEN),
('TargetName', wintypes.WCHAR * (w_const.MAX_ISCSI_NAME_LEN + 1)),
('ScsiAddress', SCSI_ADDRESS),
('DeviceInterfaceType', wintypes.GUID),
('DeviceInterfaceName', wintypes.WCHAR * w_const.MAX_PATH),
('LegacyName', wintypes.WCHAR * w_const.MAX_PATH),
('StorageDeviceNumber', STORAGE_DEVICE_NUMBER),
('DeviceInstance', wintypes.ULONG)
]
PISCSI_DEVICE_ON_SESSION = ctypes.POINTER(ISCSI_DEVICE_ON_SESSION)
def register():
global lib_handle
lib_handle = ctypes.windll.iscsidsc
lib_handle.AddIScsiStaticTargetW.argtypes = [
wintypes.PWSTR,
wintypes.PWSTR,
wintypes.ULONG,
wintypes.BOOLEAN,
PISCSI_TARGET_MAPPING,
PISCSI_LOGIN_OPTIONS,
wintypes.LPVOID # unused
]
lib_handle.AddIScsiStaticTargetW.restype = wintypes.ULONG
lib_handle.GetDevicesForIScsiSessionW.argtypes = [
PISCSI_UNIQUE_SESSION_ID,
wintypes.PULONG,
PISCSI_DEVICE_ON_SESSION
]
lib_handle.GetDevicesForIScsiSessionW.restype = wintypes.ULONG
lib_handle.GetIScsiInitiatorNodeNameW.argtypes = [wintypes.PWCHAR]
lib_handle.GetIScsiInitiatorNodeNameW.restype = wintypes.ULONG
lib_handle.GetIScsiSessionListW.argtypes = [
wintypes.PULONG,
wintypes.PULONG,
PISCSI_SESSION_INFO
]
lib_handle.GetIScsiSessionListW.restype = wintypes.ULONG
lib_handle.LoginIScsiTargetW.argtypes = [
wintypes.PWSTR,
wintypes.BOOLEAN,
wintypes.PWSTR,
wintypes.ULONG,
PISCSI_TARGET_PORTAL,
ISCSI_SECURITY_FLAGS,
PISCSI_TARGET_MAPPING,
PISCSI_LOGIN_OPTIONS,
wintypes.ULONG,
wintypes.PCHAR,
wintypes.BOOLEAN,
PISCSI_UNIQUE_SESSION_ID,
PISCSI_UNIQUE_CONNECTION_ID
]
lib_handle.LoginIScsiTargetW.restype = wintypes.ULONG
lib_handle.LogoutIScsiTarget.argtypes = [PISCSI_UNIQUE_SESSION_ID]
lib_handle.LogoutIScsiTarget.restype = wintypes.ULONG
lib_handle.RemoveIScsiPersistentTargetW.argtypes = [
wintypes.PWSTR,
wintypes.ULONG,
wintypes.PWSTR,
PISCSI_TARGET_PORTAL
]
lib_handle.RemoveIScsiPersistentTargetW.restype = wintypes.ULONG
lib_handle.RemoveIScsiStaticTargetW.argtypes = [wintypes.PWSTR]
lib_handle.RemoveIScsiStaticTargetW.restype = wintypes.ULONG
lib_handle.ReportIScsiInitiatorListW.argtypes = [
wintypes.PULONG,
wintypes.PWCHAR
]
lib_handle.ReportIScsiInitiatorListW.restype = wintypes.ULONG
lib_handle.ReportIScsiPersistentLoginsW.argtypes = [
wintypes.PULONG,
PPERSISTENT_ISCSI_LOGIN_INFO,
wintypes.PULONG
]
lib_handle.ReportIScsiPersistentLoginsW.restype = wintypes.ULONG
lib_handle.ReportIScsiTargetsW.argtypes = [
wintypes.BOOLEAN,
wintypes.PULONG,
wintypes.PWCHAR
]
lib_handle.ReportIScsiTargetsW.restype = wintypes.ULONG

View File

@ -0,0 +1,141 @@
# Copyright 2017 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
from os_win.utils.winapi import wintypes
lib_handle = None
def register():
global lib_handle
lib_handle = ctypes.windll.kernel32
lib_handle.CancelIoEx.argtypes = [
wintypes.HANDLE,
wintypes.LPOVERLAPPED
]
lib_handle.CancelIoEx.restype = wintypes.BOOL
lib_handle.CloseHandle.argtypes = [wintypes.HANDLE]
lib_handle.CloseHandle.restype = wintypes.BOOL
lib_handle.CopyFileW.argtypes = [
wintypes.LPCWSTR,
wintypes.LPCWSTR,
wintypes.BOOL
]
lib_handle.CopyFileW.restype = wintypes.BOOL
lib_handle.CreateEventW.argtypes = [
wintypes.PVOID, # unused
wintypes.BOOL,
wintypes.BOOL,
wintypes.LPCWSTR
]
lib_handle.CreateEventW.restype = wintypes.HANDLE
lib_handle.CreateFileW.argtypes = [
wintypes.LPCWSTR,
wintypes.DWORD,
wintypes.DWORD,
wintypes.PVOID, # unused
wintypes.DWORD,
wintypes.DWORD,
wintypes.HANDLE
]
lib_handle.CreateFileW.restype = wintypes.HANDLE
lib_handle.CreateSymbolicLinkW.argtypes = [
wintypes.LPCWSTR,
wintypes.LPCWSTR,
wintypes.DWORD
]
lib_handle.CreateSymbolicLinkW.restype = wintypes.BOOL
lib_handle.FormatMessageA.argtypes = [
wintypes.DWORD,
wintypes.LPCVOID,
wintypes.DWORD,
wintypes.DWORD,
wintypes.PVOID,
wintypes.DWORD,
wintypes.PVOID
]
lib_handle.FormatMessageA.restype = wintypes.DWORD
lib_handle.GetDiskFreeSpaceExW.argtypes = [
wintypes.LPCWSTR,
wintypes.PULARGE_INTEGER,
wintypes.PULARGE_INTEGER,
wintypes.PULARGE_INTEGER
]
lib_handle.GetDiskFreeSpaceExW.restype = wintypes.BOOL
lib_handle.GetFileAttributesW.argtypes = [wintypes.LPCWSTR]
lib_handle.GetFileAttributesW.restype = wintypes.DWORD
lib_handle.GetLastError.argtypes = []
lib_handle.GetLastError.restype = wintypes.DWORD
lib_handle.GetTickCount64.argtypes = []
lib_handle.GetTickCount64.restype = wintypes.ULONGLONG
lib_handle.IsProcessorFeaturePresent.argtypes = [wintypes.DWORD]
lib_handle.IsProcessorFeaturePresent.restype = wintypes.BOOL
lib_handle.LocalFree.argtypes = [wintypes.HANDLE]
lib_handle.LocalFree.restype = wintypes.HANDLE
lib_handle.ReadFileEx.argtypes = [
wintypes.HANDLE,
wintypes.LPVOID,
wintypes.DWORD,
wintypes.LPOVERLAPPED,
wintypes.LPOVERLAPPED_COMPLETION_ROUTINE
]
lib_handle.ReadFileEx.restype = wintypes.BOOL
lib_handle.ResetEvent.argtypes = [wintypes.HANDLE]
lib_handle.ResetEvent.restype = wintypes.BOOL
lib_handle.SetEvent.argtypes = [wintypes.HANDLE]
lib_handle.SetEvent.restype = wintypes.BOOL
lib_handle.SetLastError.argtypes = [wintypes.DWORD]
lib_handle.SetLastError.restype = None
lib_handle.WaitForSingleObjectEx.argtypes = [
wintypes.HANDLE,
wintypes.DWORD,
wintypes.BOOL
]
lib_handle.WaitForSingleObjectEx.restype = wintypes.DWORD
lib_handle.WaitNamedPipeW.argtypes = [
wintypes.LPCWSTR,
wintypes.DWORD
]
lib_handle.WaitNamedPipeW.restype = wintypes.BOOL
lib_handle.WriteFileEx.argtypes = [
wintypes.HANDLE,
wintypes.LPCVOID,
wintypes.DWORD,
wintypes.LPOVERLAPPED,
wintypes.LPOVERLAPPED_COMPLETION_ROUTINE
]
lib_handle.WriteFileEx.restype = wintypes.BOOL

View File

@ -0,0 +1,248 @@
# Copyright 2017 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ctypes
from os_win.utils.winapi import wintypes
lib_handle = None
class VIRTUAL_STORAGE_TYPE(ctypes.Structure):
_fields_ = [
('DeviceId', wintypes.DWORD),
('VendorId', wintypes.GUID)
]
PVIRTUAL_STORAGE_TYPE = ctypes.POINTER(VIRTUAL_STORAGE_TYPE)
class _RESIZE_VIRTUAL_DISK_PARAMETERS_V1(ctypes.Structure):
_fields_ = [
('NewSize', wintypes.ULONGLONG)
]
# Only V1 is used, we avoid defining an union.
class RESIZE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('Version1', _RESIZE_VIRTUAL_DISK_PARAMETERS_V1)
]
PRESIZE_VIRTUAL_DISK_PARAMETERS = ctypes.POINTER(
RESIZE_VIRTUAL_DISK_PARAMETERS)
class _OPEN_VIRTUAL_DISK_PARAMETERS_V1(ctypes.Structure):
_fields_ = [
('RWDepth', wintypes.ULONG),
]
class _OPEN_VIRTUAL_DISK_PARAMETERS_V2(ctypes.Structure):
_fields_ = [
('GetInfoOnly', wintypes.BOOL),
('ReadOnly', wintypes.BOOL),
('ResiliencyGuid', wintypes.GUID)
]
class _OPEN_VIRTUAL_DISK_PARAMETERS_U(ctypes.Union):
_fields_ = [
('Version1', _OPEN_VIRTUAL_DISK_PARAMETERS_V1),
('Version2', _OPEN_VIRTUAL_DISK_PARAMETERS_V2)
]
class OPEN_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
_anonymous_ = ['_parameters']
_fields_ = [
('Version', wintypes.DWORD),
('_parameters', _OPEN_VIRTUAL_DISK_PARAMETERS_U)
]
POPEN_VIRTUAL_DISK_PARAMETERS = ctypes.POINTER(
OPEN_VIRTUAL_DISK_PARAMETERS)
class _MERGE_VIRTUAL_DISK_PARAMETERS_V1(ctypes.Structure):
_fields_ = [
('MergeDepth', wintypes.ULONG)
]
# Only V1 is used, we avoid defining an union.
class MERGE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('Version1', _MERGE_VIRTUAL_DISK_PARAMETERS_V1)
]
PMERGE_VIRTUAL_DISK_PARAMETERS = ctypes.POINTER(
MERGE_VIRTUAL_DISK_PARAMETERS)
class _CREATE_VIRTUAL_DISK_PARAMETERS_V2(ctypes.Structure):
_fields_ = [
('UniqueId', wintypes.GUID),
('MaximumSize', wintypes.ULONGLONG),
('BlockSizeInBytes', wintypes.ULONG),
('SectorSizeInBytes', wintypes.ULONG),
('PhysicalSectorSizeInBytes', wintypes.ULONG),
('ParentPath', wintypes.LPCWSTR),
('SourcePath', wintypes.LPCWSTR),
('OpenFlags', wintypes.DWORD),
('ParentVirtualStorageType', VIRTUAL_STORAGE_TYPE),
('SourceVirtualStorageType', VIRTUAL_STORAGE_TYPE),
('ResiliencyGuid', wintypes.GUID)
]
# Only V2 is used, we avoid defining an union.
class CREATE_VIRTUAL_DISK_PARAMETERS(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('Version2', _CREATE_VIRTUAL_DISK_PARAMETERS_V2)
]
PCREATE_VIRTUAL_DISK_PARAMETERS = ctypes.POINTER(
CREATE_VIRTUAL_DISK_PARAMETERS)
class _VHD_INFO_SIZE(ctypes.Structure):
_fields_ = [
("VirtualSize", wintypes.ULARGE_INTEGER),
("PhysicalSize", wintypes.ULARGE_INTEGER),
("BlockSize", wintypes.ULONG),
("SectorSize", wintypes.ULONG)
]
class _VHD_INFO_PARENT_LOCATION(ctypes.Structure):
_fields_ = [
('ParentResolved', wintypes.BOOL),
('ParentPath', wintypes.WCHAR * 512)
]
class _VHD_INFO_PHYSICAL_DISK(ctypes.Structure):
_fields_ = [
("LogicalSectorSize", wintypes.ULONG),
("PhysicalSectorSize", wintypes.ULONG),
("IsRemote", wintypes.BOOL)
]
class _VHD_INFO(ctypes.Union):
_fields_ = [
("Size", _VHD_INFO_SIZE),
("Identifier", wintypes.GUID),
("ParentLocation", _VHD_INFO_PARENT_LOCATION),
("ParentIdentifier", wintypes.GUID),
("ParentTimestamp", wintypes.ULONG),
("VirtualStorageType", VIRTUAL_STORAGE_TYPE),
("ProviderSubtype", wintypes.ULONG),
("Is4kAligned", wintypes.BOOL),
("PhysicalDisk", _VHD_INFO_PHYSICAL_DISK),
("VhdPhysicalSectorSize", wintypes.ULONG),
("SmallestSafeVirtualSize", wintypes.ULARGE_INTEGER),
("FragmentationPercentage", wintypes.ULONG)
]
class GET_VIRTUAL_DISK_INFO(ctypes.Structure):
_anonymous_ = ['_vhdinfo']
_fields_ = [
("Version", wintypes.UINT),
("_vhdinfo", _VHD_INFO)
]
PGET_VIRTUAL_DISK_INFO = ctypes.POINTER(GET_VIRTUAL_DISK_INFO)
# Only this version is used, we avoid defining an union.
class SET_VIRTUAL_DISK_INFO(ctypes.Structure):
_fields_ = [
('Version', wintypes.DWORD),
('ParentFilePath', wintypes.LPCWSTR)
]
PSET_VIRTUAL_DISK_INFO = ctypes.POINTER(SET_VIRTUAL_DISK_INFO)
def register():
global lib_handle
lib_handle = ctypes.windll.virtdisk
lib_handle.CreateVirtualDisk.argtypes = [
PVIRTUAL_STORAGE_TYPE,
wintypes.LPCWSTR,
wintypes.INT,
wintypes.PVOID,
wintypes.INT,
wintypes.ULONG,
PCREATE_VIRTUAL_DISK_PARAMETERS,
wintypes.LPOVERLAPPED,
wintypes.PHANDLE
]
lib_handle.CreateVirtualDisk.restype = wintypes.DWORD
lib_handle.GetVirtualDiskInformation.argtypes = [
wintypes.HANDLE,
wintypes.PULONG,
PGET_VIRTUAL_DISK_INFO,
wintypes.PULONG
]
lib_handle.GetVirtualDiskInformation.restype = wintypes.DWORD
lib_handle.MergeVirtualDisk.argtypes = [
wintypes.HANDLE,
wintypes.INT,
PMERGE_VIRTUAL_DISK_PARAMETERS,
wintypes.LPOVERLAPPED
]
lib_handle.MergeVirtualDisk.restype = wintypes.DWORD
lib_handle.OpenVirtualDisk.argtypes = [
PVIRTUAL_STORAGE_TYPE,
wintypes.LPCWSTR,
wintypes.INT,
wintypes.INT,
POPEN_VIRTUAL_DISK_PARAMETERS,
wintypes.PHANDLE
]
lib_handle.OpenVirtualDisk.restype = wintypes.DWORD
lib_handle.ResizeVirtualDisk.argtypes = [
wintypes.HANDLE,
wintypes.INT,
PRESIZE_VIRTUAL_DISK_PARAMETERS,
wintypes.LPOVERLAPPED
]
lib_handle.ResizeVirtualDisk.restype = wintypes.DWORD
lib_handle.SetVirtualDiskInformation.argtypes = [
wintypes.HANDLE,
PSET_VIRTUAL_DISK_INFO
]
lib_handle.SetVirtualDiskInformation.restype = wintypes.DWORD

View File

@ -0,0 +1,103 @@
# Copyright 2017 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# This module contains some common types extracted from ctypes.wintypes
# plus some extra ones that we are using throughout os-win.
#
# In order to avoid portability issues more easily, we avoid using
# ctypes.wintypes directly.
import ctypes
import sys
BYTE = ctypes.c_byte
WORD = ctypes.c_ushort
DWORD = ctypes.c_ulong
CHAR = ctypes.c_char
WCHAR = ctypes.c_wchar
UINT = ctypes.c_uint
INT = ctypes.c_int
DOUBLE = ctypes.c_double
FLOAT = ctypes.c_float
BOOLEAN = BYTE
BOOL = ctypes.c_long
ULONG = ctypes.c_ulong
LONG = ctypes.c_long
USHORT = ctypes.c_ushort
SHORT = ctypes.c_short
LONGLONG = _LARGE_INTEGER = LARGE_INTEGER = ctypes.c_longlong
ULONGLONG = _ULARGE_INTEGER = ULARGE_INTEGER = ctypes.c_ulonglong
LPCOLESTR = LPOLESTR = OLESTR = ctypes.c_wchar_p
LPCWSTR = LPWSTR = PWSTR = ctypes.c_wchar_p
LPCSTR = LPSTR = PSTR = ctypes.c_char_p
LPCVOID = LPVOID = PVOID = ctypes.c_void_p
HANDLE = ctypes.c_void_p
LPBOOL = PBOOL = ctypes.POINTER(BOOL)
PBOOLEAN = ctypes.POINTER(BOOLEAN)
LPBYTE = PBYTE = ctypes.POINTER(BYTE)
PCHAR = ctypes.POINTER(CHAR)
LPDWORD = PDWORD = ctypes.POINTER(DWORD)
PFLOAT = ctypes.POINTER(FLOAT)
LPHANDLE = PHANDLE = ctypes.POINTER(HANDLE)
LPINT = PINT = ctypes.POINTER(INT)
PLARGE_INTEGER = ctypes.POINTER(LARGE_INTEGER)
LPLONG = PLONG = ctypes.POINTER(LONG)
PLONGLONG = ctypes.POINTER(LONGLONG)
PSHORT = ctypes.POINTER(SHORT)
LPUINT = PUINT = ctypes.POINTER(UINT)
PULARGE_INTEGER = ctypes.POINTER(ULARGE_INTEGER)
PULONG = ctypes.POINTER(ULONG)
PUSHORT = ctypes.POINTER(USHORT)
# Warning: PWCHAR behaves differently than c_wchar_p. Accessing
# a PWCHAR structure attribute won't give us back a Python string.
PWCHAR = ctypes.POINTER(WCHAR)
LPWORD = PWORD = ctypes.POINTER(WORD)
class GUID(ctypes.Structure):
_fields_ = [
("Data1", ULONG),
("Data2", USHORT),
("Data3", USHORT),
("Data4", BYTE * 8)
]
class OVERLAPPED(ctypes.Structure):
_fields_ = [
('Internal', ULONG),
('InternalHigh', ULONG),
('Offset', DWORD),
('OffsetHigh', DWORD),
('hEvent', HANDLE)
]
LPOVERLAPPED = ctypes.POINTER(OVERLAPPED)
if sys.platform == 'win32':
LPOVERLAPPED_COMPLETION_ROUTINE = ctypes.WINFUNCTYPE(
None, DWORD, DWORD, LPOVERLAPPED)
else:
LPOVERLAPPED_COMPLETION_ROUTINE = PVOID