
Some plugins support only a given platform and / or a minimum OS version. ExtendVolumesPlugin is not supported on Windows XP. This commit adds support for filtering the plugins based on OS requirements.
174 lines
6.2 KiB
Python
174 lines
6.2 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright (c) 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 cloudbaseinit.openstack.common import cfg
|
|
from cloudbaseinit.openstack.common import log as logging
|
|
from cloudbaseinit.plugins import base
|
|
from cloudbaseinit.plugins.windows import vds
|
|
|
|
ole32 = ctypes.windll.ole32
|
|
ole32.CoTaskMemFree.restype = None
|
|
ole32.CoTaskMemFree.argtypes = [ctypes.c_void_p]
|
|
|
|
opts = [
|
|
cfg.ListOpt('volumes_to_extend',
|
|
default=None,
|
|
help='List of volumes that need to be extended '
|
|
'if contiguous space is available on the disk. By default '
|
|
'all the available volumes can be extended. Volumes must '
|
|
'be specified using a comma separated list of volume indexes, '
|
|
'e.g.: "1,2"'),
|
|
]
|
|
|
|
CONF = cfg.CONF
|
|
CONF.register_opts(opts)
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class ExtendVolumesPlugin(base.BasePlugin):
|
|
def _extend_volumes(self, pack, volume_idxs=None):
|
|
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_idxs is not None:
|
|
volume_name = ctypes.wstring_at(volume_prop.pwszName)
|
|
volume_idx = self._get_volume_index(volume_name)
|
|
if not volume_idx in volume_idxs:
|
|
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 _get_volumes_to_extend(self):
|
|
if CONF.volumes_to_extend is not None:
|
|
return map(int, CONF.volumes_to_extend)
|
|
|
|
def execute(self, service):
|
|
svc = vds.load_vds_service()
|
|
providers = self._query_providers(svc)
|
|
|
|
volumes_to_extend = self._get_volumes_to_extend()
|
|
|
|
for provider in providers:
|
|
packs = self._query_packs(provider)
|
|
for pack in packs:
|
|
self._extend_volumes(pack, volumes_to_extend)
|
|
|
|
return (base.PLUGIN_EXECUTE_ON_NEXT_BOOT, False)
|
|
|
|
def get_os_requirements(self):
|
|
return ('win32', (5, 2))
|