Alessandro Pilotti dd6b4d74c5 Adds Windows Storage Manager API support
This is needed on Nano Server where VDS is not available.
The logic for extending the volumes was decoupled from the plugin to
a windows storage utility (VDS) alongside other extending utility which
is available on Nano and versions greater than ws2012/w8 (WSM).
According to the current Windows version, a suitable utility for extending
will be loaded through a factory manager.

Implements: blueprint windows-storage-manager
Co-Authored-By: Cosmin Poieana <cpoieana@cloudbasesolutions.com>
Change-Id: I7c8eea35a632c812e99808befb5e7528d66363cc
2015-09-14 03:36:51 +03:00

148 lines
5.3 KiB
Python

# Copyright 2013 Cloudbase Solutions Srl
#
# 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 re
from oslo_log import log as oslo_logging
from cloudbaseinit.utils.windows.storage import base
from cloudbaseinit.utils.windows import vds
LOG = oslo_logging.getLogger(__name__)
ole32 = ctypes.windll.ole32
ole32.CoTaskMemFree.restype = None
ole32.CoTaskMemFree.argtypes = [ctypes.c_void_p]
class VDSStorageManager(base.BaseStorageManager):
def _extend_volumes(self, pack, volume_indexes):
enum = pack.QueryVolumes()
while True:
(unk, c) = enum.Next(1)
if not c:
break
volume = unk.QueryInterface(vds.IVdsVolume)
volume_prop = volume.GetProperties()
try:
extend_volume = True
if volume_indexes:
volume_name = ctypes.wstring_at(volume_prop.pwszName)
volume_idx = self._get_volume_index(volume_name)
if volume_idx not in volume_indexes:
extend_volume = False
if extend_volume:
self._extend_volume(pack, volume, volume_prop)
finally:
ole32.CoTaskMemFree(volume_prop.pwszName)
def _get_volume_index(self, volume_name):
m = re.match(r"[^0-9]+([0-9]+)$", volume_name)
if m:
return int(m.group(1))
def _extend_volume(self, pack, volume, volume_prop):
volume_extents = self._get_volume_extents_to_resize(pack,
volume_prop.id)
input_disks = []
for (volume_extent, volume_extend_size) in volume_extents:
input_disk = vds.VDS_INPUT_DISK()
input_disks.append(input_disk)
input_disk.diskId = volume_extent.diskId
input_disk.memberIdx = volume_extent.memberIdx
input_disk.plexId = volume_extent.plexId
input_disk.ullSize = volume_extend_size
if input_disks:
extend_size = sum([i.ullSize for i in input_disks])
volume_name = ctypes.wstring_at(volume_prop.pwszName)
LOG.info('Extending volume "%s" with %s bytes' %
(volume_name, extend_size))
input_disks_ar = (vds.VDS_INPUT_DISK *
len(input_disks))(*input_disks)
async = volume.Extend(input_disks_ar, len(input_disks))
async.Wait()
def _get_volume_extents_to_resize(self, pack, volume_id):
volume_extents = []
enum = pack.QueryDisks()
while True:
(unk, c) = enum.Next(1)
if not c:
break
disk = unk.QueryInterface(vds.IVdsDisk)
(extents_p, num_extents) = disk.QueryExtents()
try:
extents_array_type = vds.VDS_DISK_EXTENT * num_extents
extents_array = extents_array_type.from_address(
ctypes.addressof(extents_p.contents))
volume_extent_extend_size = None
for extent in extents_array:
if extent.volumeId == volume_id:
# Copy the extent in order to return it safely
# after the source is deallocated
extent_copy = vds.VDS_DISK_EXTENT()
ctypes.pointer(extent_copy)[0] = extent
volume_extent_extend_size = [extent_copy, 0]
volume_extents.append(volume_extent_extend_size)
elif (volume_extent_extend_size and
extent.type == vds.VDS_DET_FREE):
volume_extent_extend_size[1] += extent.ullSize
else:
volume_extent_extend_size = None
finally:
ole32.CoTaskMemFree(extents_p)
# Return only the extents that need to be resized
return [ve for ve in volume_extents if ve[1] > 0]
def _query_providers(self, svc):
providers = []
enum = svc.QueryProviders(vds.VDS_QUERY_SOFTWARE_PROVIDERS)
while True:
(unk, c) = enum.Next(1)
if not c:
break
providers.append(unk.QueryInterface(vds.IVdsSwProvider))
return providers
def _query_packs(self, provider):
packs = []
enum = provider.QueryPacks()
while True:
(unk, c) = enum.Next(1)
if not c:
break
packs.append(unk.QueryInterface(vds.IVdsPack))
return packs
def extend_volumes(self, volume_indexes=None):
svc = vds.load_vds_service()
providers = self._query_providers(svc)
for provider in providers:
packs = self._query_packs(provider)
for pack in packs:
self._extend_volumes(pack, volume_indexes)