Add PyMI as requirement

Since PyMI requires the MI API, available only since Windows 8 /
Windows Server 2012 or as an addon on some previous versions, we
need to ensure that we fall back to the legacy WMI module if PyMI
cannot be loaded.

Partially-Implements: blueprint json-network-config
Change-Id: Ibded4cee3d3d7dc39e53bca12e015c9ef83c7f3d
This commit is contained in:
Alessandro Pilotti 2018-08-29 01:37:53 +03:00
parent fe9aa8247d
commit 148855f74e
9 changed files with 126 additions and 8 deletions

View File

@ -34,7 +34,6 @@ import win32process
import win32security import win32security
import win32service import win32service
import winerror import winerror
import wmi
from cloudbaseinit import exception from cloudbaseinit import exception
from cloudbaseinit.osutils import base from cloudbaseinit.osutils import base
@ -42,7 +41,9 @@ from cloudbaseinit.utils.windows import disk
from cloudbaseinit.utils.windows import network from cloudbaseinit.utils.windows import network
from cloudbaseinit.utils.windows import privilege from cloudbaseinit.utils.windows import privilege
from cloudbaseinit.utils.windows import timezone from cloudbaseinit.utils.windows import timezone
from cloudbaseinit.utils.windows import wmi_loader
wmi = wmi_loader.wmi()
LOG = oslo_logging.getLogger(__name__) LOG = oslo_logging.getLogger(__name__)
AF_INET6 = 23 AF_INET6 = 23

View File

@ -33,7 +33,7 @@ class BootConfigTest(unittest.TestCase):
self._wmi_mock = mock.MagicMock() self._wmi_mock = mock.MagicMock()
self._module_patcher = mock.patch.dict( self._module_patcher = mock.patch.dict(
'sys.modules', { 'sys.modules', {
'wmi': self._wmi_mock}) "wmi": self._wmi_mock})
self.snatcher = testutils.LogSnatcher(MODPATH) self.snatcher = testutils.LogSnatcher(MODPATH)
self._module_patcher.start() self._module_patcher.start()
self.bootconfig = importlib.import_module(MODPATH) self.bootconfig = importlib.import_module(MODPATH)

View File

@ -0,0 +1,67 @@
# Copyright 2018 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 importlib
import os
import unittest
try:
import unittest.mock as mock
except ImportError:
import mock
from cloudbaseinit import exception
MODPATH = "cloudbaseinit.utils.windows.wmi_loader"
class WMILoaderTests(unittest.TestCase):
def test_load_pymi(self):
with mock.patch.dict('sys.modules', {'wmi': mock.sentinel.wmi}):
wmi_loader = importlib.import_module(MODPATH)
self.assertEqual(mock.sentinel.wmi, wmi_loader.wmi())
@mock.patch('imp.load_source')
@mock.patch('os.path.isfile')
def test_load_legacy_wmi(self, mock_isfile, mock_load_source):
mock_isfile.return_value = True
mock_site = mock.MagicMock()
fake_site_path = "fake_site_path"
mock_site.getsitepackages.return_value = [fake_site_path]
mock_load_source.return_value = mock.sentinel.wmi
with mock.patch.dict('sys.modules', {'wmi': None, 'site': mock_site}):
wmi_loader = importlib.import_module(MODPATH)
self.assertEqual(mock.sentinel.wmi, wmi_loader.wmi())
fake_wmi_path = os.path.join(fake_site_path, "wmi.py")
mock_isfile.assert_called_once_with(fake_wmi_path)
mock_load_source.assert_called_once_with("wmi", fake_wmi_path)
@mock.patch('os.path.isfile')
def test_load_legacy_wmi_fail(self, mock_isfile):
mock_isfile.return_value = False
mock_site = mock.MagicMock()
fake_site_path = "fake_site_path"
mock_site.getsitepackages.return_value = [fake_site_path]
with mock.patch.dict('sys.modules', {'wmi': None, 'site': mock_site}):
wmi_loader = importlib.import_module(MODPATH)
self.assertRaises(
exception.ItemNotFoundException, wmi_loader.wmi)
fake_wmi_path = os.path.join(fake_site_path, "wmi.py")
mock_isfile.assert_called_once_with(fake_wmi_path)

View File

@ -13,11 +13,13 @@
# under the License. # under the License.
from oslo_log import log as oslo_logging from oslo_log import log as oslo_logging
import wmi
from cloudbaseinit import constant from cloudbaseinit import constant
from cloudbaseinit import exception from cloudbaseinit import exception
from cloudbaseinit.osutils import factory as osutils_factory from cloudbaseinit.osutils import factory as osutils_factory
from cloudbaseinit.utils.windows import wmi_loader
wmi = wmi_loader.wmi()
LOG = oslo_logging.getLogger(__name__) LOG = oslo_logging.getLogger(__name__)

View File

@ -14,14 +14,15 @@
import os import os
import wmi
from oslo_log import log as oslo_logging from oslo_log import log as oslo_logging
from cloudbaseinit import constant from cloudbaseinit import constant
from cloudbaseinit import exception from cloudbaseinit import exception
from cloudbaseinit.osutils import factory as osutils_factory from cloudbaseinit.osutils import factory as osutils_factory
from cloudbaseinit.utils.windows import productkeys from cloudbaseinit.utils.windows import productkeys
from cloudbaseinit.utils.windows import wmi_loader
wmi = wmi_loader.wmi()
LOG = oslo_logging.getLogger(__name__) LOG = oslo_logging.getLogger(__name__)

View File

@ -12,13 +12,13 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import wmi
from oslo_log import log as oslo_logging from oslo_log import log as oslo_logging
from six.moves import winreg from six.moves import winreg
from cloudbaseinit import exception from cloudbaseinit import exception
from cloudbaseinit.utils.windows import wmi_loader
wmi = wmi_loader.wmi()
LOG = oslo_logging.getLogger(__name__) LOG = oslo_logging.getLogger(__name__)

View File

@ -13,7 +13,6 @@
# under the License. # under the License.
import ctypes import ctypes
import wmi
from oslo_log import log as oslo_logging from oslo_log import log as oslo_logging
from six.moves import winreg from six.moves import winreg
@ -21,6 +20,9 @@ from six.moves import winreg
from cloudbaseinit import exception from cloudbaseinit import exception
from cloudbaseinit.utils.windows import kernel32 from cloudbaseinit.utils.windows import kernel32
from cloudbaseinit.utils.windows.storage import base from cloudbaseinit.utils.windows.storage import base
from cloudbaseinit.utils.windows import wmi_loader
wmi = wmi_loader.wmi()
LOG = oslo_logging.getLogger(__name__) LOG = oslo_logging.getLogger(__name__)

View File

@ -0,0 +1,44 @@
# Copyright 2018 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 imp
import os
import site
from oslo_log import log as oslo_logging
from cloudbaseinit import exception
LOG = oslo_logging.getLogger(__name__)
def wmi():
try:
# PyMI depends on the MI API, not available by default on systems older
# than Windows 8 / Windows Server 2012
import wmi
return wmi
except ImportError:
LOG.debug("Couldn't load PyMI module, using legacy WMI")
wmi_path = None
for packages_path in site.getsitepackages():
path = os.path.join(packages_path, "wmi.py")
if os.path.isfile(path):
wmi_path = path
break
if wmi_path is None:
raise exception.ItemNotFoundException("wmi module not found")
return imp.load_source("wmi", wmi_path)

View File

@ -14,5 +14,6 @@ requests
untangle==1.1.1 untangle==1.1.1
pywin32;sys_platform=="win32" pywin32;sys_platform=="win32"
comtypes;sys_platform=="win32" comtypes;sys_platform=="win32"
pymi;sys_platform=="win32"
wmi;sys_platform=="win32" wmi;sys_platform=="win32"
tzlocal;sys_platform=="win32" tzlocal;sys_platform=="win32"