Add support for specific network configuration

The networkconfig plugin can now handle custom NetworkDetails
objects that contain data like IP address, gateway, broadcast etc.

Change-Id: Ife3f8f62b47704e7f25e0304b15953d6f06e8620
This commit is contained in:
Cosmin Poieana 2014-11-07 01:26:03 +02:00
parent c1a3f38e80
commit 8befa6c833
6 changed files with 286 additions and 122 deletions

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Cloudbase Solutions Srl # Copyright 2012 Cloudbase Solutions Srl
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,13 +12,17 @@
# 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 abc import abc
import collections
import time import time
import warnings
from oslo.config import cfg from oslo.config import cfg
from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.openstack.common import log as logging
opts = [ opts = [
cfg.IntOpt('retry_count', default=5, cfg.IntOpt('retry_count', default=5,
help='Max. number of attempts for fetching metadata in ' help='Max. number of attempts for fetching metadata in '
@ -35,6 +37,20 @@ CONF.register_opts(opts)
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
# Both the custom service(s) and the networking plugin
# should know about the entries of these kind of objects.
NetworkDetails = collections.namedtuple(
"NetworkDetails",
[
"mac",
"address",
"netmask",
"broadcast",
"gateway",
"dnsnameservers",
]
)
class NotExistingMetadataException(Exception): class NotExistingMetadataException(Exception):
pass pass
@ -82,6 +98,7 @@ class BaseMetadataService(object):
pass pass
def get_content(self, name): def get_content(self, name):
# this will also be deprecated due to `get_network_config`
pass pass
def get_user_data(self): def get_user_data(self):
@ -94,7 +111,17 @@ class BaseMetadataService(object):
pass pass
def get_network_config(self): def get_network_config(self):
pass """Deprecated, use `get_network_details` instead."""
warnings.warn("deprecated method, use `get_network_details`",
DeprecationWarning)
def get_network_details(self):
"""Return a list of `NetworkDetails` objects.
These objects provide details regarding static
network configuration, details which can be found
in the namedtuple defined above.
"""
def get_admin_password(self): def get_admin_password(self):
pass pass

View File

@ -70,7 +70,7 @@ class BaseOSUtils(object):
def get_network_adapters(self): def get_network_adapters(self):
raise NotImplementedError() raise NotImplementedError()
def set_static_network_config(self, adapter_name, address, netmask, def set_static_network_config(self, mac_address, address, netmask,
broadcast, gateway, dnsnameservers): broadcast, gateway, dnsnameservers):
raise NotImplementedError() raise NotImplementedError()

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Cloudbase Solutions Srl # Copyright 2012 Cloudbase Solutions Srl
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -15,33 +13,33 @@
# under the License. # under the License.
import ctypes import ctypes
from ctypes import wintypes
import os import os
import re import re
import six
import time import time
import six
from six.moves import winreg
from win32com import client
import win32process import win32process
import win32security import win32security
import wmi import wmi
from ctypes import windll
from ctypes import wintypes
from six.moves import winreg
from win32com import client
from cloudbaseinit import exception from cloudbaseinit import exception
from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.osutils import base from cloudbaseinit.osutils import base
from cloudbaseinit.utils.windows import network from cloudbaseinit.utils.windows import network
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
advapi32 = windll.advapi32 advapi32 = ctypes.windll.advapi32
kernel32 = windll.kernel32 kernel32 = ctypes.windll.kernel32
netapi32 = windll.netapi32 netapi32 = ctypes.windll.netapi32
userenv = windll.userenv userenv = ctypes.windll.userenv
iphlpapi = windll.iphlpapi iphlpapi = ctypes.windll.iphlpapi
Ws2_32 = windll.Ws2_32 Ws2_32 = ctypes.windll.Ws2_32
setupapi = windll.setupapi setupapi = ctypes.windll.setupapi
msvcrt = ctypes.cdll.msvcrt msvcrt = ctypes.cdll.msvcrt
@ -454,7 +452,7 @@ class WindowsUtils(base.BaseOSUtils):
raise exception.CloudbaseInitException("Cannot set host name") raise exception.CloudbaseInitException("Cannot set host name")
def get_network_adapters(self): def get_network_adapters(self):
l = [] """Return available adapters as a list of tuples of (name, mac)."""
conn = wmi.WMI(moniker='//./root/cimv2') conn = wmi.WMI(moniker='//./root/cimv2')
# Get Ethernet adapters only # Get Ethernet adapters only
wql = ('SELECT * FROM Win32_NetworkAdapter WHERE ' wql = ('SELECT * FROM Win32_NetworkAdapter WHERE '
@ -464,9 +462,7 @@ class WindowsUtils(base.BaseOSUtils):
wql += ' AND PhysicalAdapter = True' wql += ' AND PhysicalAdapter = True'
q = conn.query(wql) q = conn.query(wql)
for r in q: return [(r.Name, r.MACAddress) for r in q]
l.append(r.Name)
return l
def get_dhcp_hosts_in_use(self): def get_dhcp_hosts_in_use(self):
dhcp_hosts = [] dhcp_hosts = []
@ -524,14 +520,12 @@ class WindowsUtils(base.BaseOSUtils):
'value "%(mtu)s" failed' % {'mac_address': mac_address, 'value "%(mtu)s" failed' % {'mac_address': mac_address,
'mtu': mtu}) 'mtu': mtu})
def set_static_network_config(self, adapter_name, address, netmask, def set_static_network_config(self, mac_address, address, netmask,
broadcast, gateway, dnsnameservers): broadcast, gateway, dnsnameservers):
conn = wmi.WMI(moniker='//./root/cimv2') conn = wmi.WMI(moniker='//./root/cimv2')
adapter_name_san = self._sanitize_wmi_input(adapter_name) q = conn.query("SELECT * FROM Win32_NetworkAdapter WHERE "
q = conn.query('SELECT * FROM Win32_NetworkAdapter WHERE ' "MACAddress = '{}'".format(mac_address))
'MACAddress IS NOT NULL AND '
'Name = \'%s\'' % adapter_name_san)
if not len(q): if not len(q):
raise exception.CloudbaseInitException( raise exception.CloudbaseInitException(
"Network adapter not found") "Network adapter not found")

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Cloudbase Solutions Srl # Copyright 2012 Cloudbase Solutions Srl
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,35 +12,49 @@
# 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 re import re
from oslo.config import cfg from oslo.config import cfg
from cloudbaseinit import exception from cloudbaseinit import exception
from cloudbaseinit.metadata.services import base as service_base
from cloudbaseinit.openstack.common import log as logging from cloudbaseinit.openstack.common import log as logging
from cloudbaseinit.osutils import factory as osutils_factory from cloudbaseinit.osutils import factory as osutils_factory
from cloudbaseinit.plugins import base from cloudbaseinit.plugins import base as plugin_base
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
opts = [ opts = [
cfg.StrOpt('network_adapter', default=None, help='Network adapter to ' cfg.StrOpt('network_adapter', default=None, help='Network adapter to '
'configure. If not specified, the first available ethernet ' 'configure. If not specified, the first available ethernet '
'adapter will be chosen'), 'adapter will be chosen.\n'
'WARNING: This option is deprecated and will be removed soon.'),
] ]
CONF = cfg.CONF CONF = cfg.CONF
CONF.register_opts(opts) CONF.register_opts(opts)
class NetworkConfigPlugin(base.BasePlugin): class NetworkConfigPlugin(plugin_base.BasePlugin):
def execute(self, service, shared_data): def execute(self, service, shared_data):
# FIXME(cpoieana): `network_config` is deprecated
# * refactor all services by providing NetworkDetails objects *
# Also, the old method is not supporting multiple NICs.
osutils = osutils_factory.get_os_utils()
network_details = service.get_network_details()
if not network_details:
network_config = service.get_network_config() network_config = service.get_network_config()
if not network_config: if not network_config:
return (base.PLUGIN_EXECUTION_DONE, False) return (plugin_base.PLUGIN_EXECUTION_DONE, False)
# ---- BEGIN deprecated code ----
if not network_details:
if 'content_path' not in network_config: if 'content_path' not in network_config:
return (base.PLUGIN_EXECUTION_DONE, False) return (plugin_base.PLUGIN_EXECUTION_DONE, False)
content_path = network_config['content_path'] content_path = network_config['content_path']
content_name = content_path.rsplit('/', 1)[-1] content_name = content_path.rsplit('/', 1)[-1]
@ -56,33 +68,76 @@ class NetworkConfigPlugin(base.BasePlugin):
r'netmask\s+(?P<netmask>[^\s]+)\s+' r'netmask\s+(?P<netmask>[^\s]+)\s+'
r'broadcast\s+(?P<broadcast>[^\s]+)\s+' r'broadcast\s+(?P<broadcast>[^\s]+)\s+'
r'gateway\s+(?P<gateway>[^\s]+)\s+' r'gateway\s+(?P<gateway>[^\s]+)\s+'
r'dns\-nameservers\s+(?P<dnsnameservers>[^\r\n]+)\s+', r'dns\-nameservers\s+'
r'(?P<dnsnameservers>[^\r\n]+)\s+',
debian_network_conf) debian_network_conf)
if not m: if not m:
raise exception.CloudbaseInitException( raise exception.CloudbaseInitException(
"network_config format not recognized") "network_config format not recognized")
address = m.group('address') mac = None
netmask = m.group('netmask') network_adapters = osutils.get_network_adapters()
broadcast = m.group('broadcast') if network_adapters:
gateway = m.group('gateway') adapter_name = CONF.network_adapter
dnsnameservers = m.group('dnsnameservers').strip().split(' ') if adapter_name:
# configure with the specified one
for network_adapter in network_adapters:
if network_adapter[0] == adapter_name:
mac = network_adapter[1]
break
else:
# configure with the first one
mac = network_adapters[0][1]
network_details = [
service_base.NetworkDetails(
mac,
m.group('address'),
m.group('netmask'),
m.group('broadcast'),
m.group('gateway'),
m.group('dnsnameservers').strip().split(' ')
)
]
# ---- END deprecated code ----
osutils = osutils_factory.get_os_utils() # check NICs' type and save them by MAC
macnics = {}
network_adapter_name = CONF.network_adapter for nic in network_details:
if not network_adapter_name: if not isinstance(nic, service_base.NetworkDetails):
# Get the first available one
available_adapters = osutils.get_network_adapters()
if not len(available_adapters):
raise exception.CloudbaseInitException( raise exception.CloudbaseInitException(
"No network adapter available") "invalid NetworkDetails object {!r}"
network_adapter_name = available_adapters[0] .format(type(nic))
)
# assuming that the MAC address is unique
macnics[nic.mac] = nic
# try configuring all the available adapters
adapter_macs = [pair[1] for pair in
osutils.get_network_adapters()]
if not adapter_macs:
raise exception.CloudbaseInitException(
"no network adapters available")
# configure each one
reboot_required = False
configured = False
for mac in adapter_macs:
nic = macnics.pop(mac, None)
if not nic:
LOG.warn("Missing details for adapter %s", mac)
continue
LOG.info("Configuring network adapter %s", mac)
reboot = osutils.set_static_network_config(
mac,
nic.address,
nic.netmask,
nic.broadcast,
nic.gateway,
nic.dnsnameservers
)
reboot_required = reboot or reboot_required
configured = True
for mac in macnics:
LOG.warn("Details not used for adapter %s", mac)
if not configured:
LOG.error("No adapters were configured")
LOG.info('Configuring network adapter: \'%s\'' % network_adapter_name) return (plugin_base.PLUGIN_EXECUTION_DONE, reboot_required)
reboot_required = osutils.set_static_network_config(
network_adapter_name, address, netmask, broadcast,
gateway, dnsnameservers)
return (base.PLUGIN_EXECUTION_DONE, reboot_required)

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Cloudbase Solutions Srl # Copyright 2013 Cloudbase Solutions Srl
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,16 +12,18 @@
# 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 importlib import importlib
import mock
import os import os
import six
import unittest import unittest
import mock
from oslo.config import cfg from oslo.config import cfg
import six
from cloudbaseinit import exception from cloudbaseinit import exception
CONF = cfg.CONF CONF = cfg.CONF
@ -517,7 +517,8 @@ class WindowsUtilsTest(unittest.TestCase):
response = self._winutils.get_network_adapters() response = self._winutils.get_network_adapters()
conn.return_value.query.assert_called_with(wql) conn.return_value.query.assert_called_with(wql)
self.assertEqual([mock_response.Name], response) self.assertEqual([(mock_response.Name, mock_response.MACAddress)],
response)
def test_get_network_adapters(self): def test_get_network_adapters(self):
self._test_get_network_adapters(False) self._test_get_network_adapters(False)
@ -532,7 +533,7 @@ class WindowsUtilsTest(unittest.TestCase):
ret_val2=None, ret_val3=None): ret_val2=None, ret_val3=None):
conn = self._wmi_mock.WMI conn = self._wmi_mock.WMI
address = '10.10.10.10' address = '10.10.10.10'
adapter_name = 'adapter_name' mac_address = '54:EE:75:19:F4:61'
broadcast = '0.0.0.0' broadcast = '0.0.0.0'
dns_list = ['8.8.8.8'] dns_list = ['8.8.8.8']
@ -540,10 +541,9 @@ class WindowsUtilsTest(unittest.TestCase):
self.assertRaises( self.assertRaises(
exception.CloudbaseInitException, exception.CloudbaseInitException,
self._winutils.set_static_network_config, self._winutils.set_static_network_config,
adapter_name, address, self._NETMASK, mac_address, address, self._NETMASK,
broadcast, self._GATEWAY, dns_list) broadcast, self._GATEWAY, dns_list)
else: else:
mock_sanitize_wmi_input.return_value = adapter_name
conn.return_value.query.return_value = adapter conn.return_value.query.return_value = adapter
adapter_config = adapter[0].associators()[0] adapter_config = adapter[0].associators()[0]
adapter_config.EnableStatic.return_value = ret_val1 adapter_config.EnableStatic.return_value = ret_val1
@ -555,26 +555,26 @@ class WindowsUtilsTest(unittest.TestCase):
self.assertRaises( self.assertRaises(
exception.CloudbaseInitException, exception.CloudbaseInitException,
self._winutils.set_static_network_config, self._winutils.set_static_network_config,
adapter_name, address, self._NETMASK, mac_address, address, self._NETMASK,
broadcast, self._GATEWAY, dns_list) broadcast, self._GATEWAY, dns_list)
elif ret_val2[0] > 1: elif ret_val2[0] > 1:
self.assertRaises( self.assertRaises(
exception.CloudbaseInitException, exception.CloudbaseInitException,
self._winutils.set_static_network_config, self._winutils.set_static_network_config,
adapter_name, address, self._NETMASK, mac_address, address, self._NETMASK,
broadcast, self._GATEWAY, dns_list) broadcast, self._GATEWAY, dns_list)
elif ret_val3[0] > 1: elif ret_val3[0] > 1:
self.assertRaises( self.assertRaises(
exception.CloudbaseInitException, exception.CloudbaseInitException,
self._winutils.set_static_network_config, self._winutils.set_static_network_config,
adapter_name, address, self._NETMASK, mac_address, address, self._NETMASK,
broadcast, self._GATEWAY, dns_list) broadcast, self._GATEWAY, dns_list)
else: else:
response = self._winutils.set_static_network_config( response = self._winutils.set_static_network_config(
adapter_name, address, self._NETMASK, mac_address, address, self._NETMASK,
broadcast, self._GATEWAY, dns_list) broadcast, self._GATEWAY, dns_list)
if ret_val1[0] or ret_val2[0] or ret_val3[0] == 1: if ret_val1[0] or ret_val2[0] or ret_val3[0] == 1:
@ -588,14 +588,12 @@ class WindowsUtilsTest(unittest.TestCase):
adapter_config.SetDNSServerSearchOrder.assert_called_with( adapter_config.SetDNSServerSearchOrder.assert_called_with(
dns_list) dns_list)
self._winutils._sanitize_wmi_input.assert_called_with(
adapter_name)
adapter[0].associators.assert_called_with( adapter[0].associators.assert_called_with(
wmi_result_class='Win32_NetworkAdapterConfiguration') wmi_result_class='Win32_NetworkAdapterConfiguration')
conn.return_value.query.assert_called_with( conn.return_value.query.assert_called_with(
'SELECT * FROM Win32_NetworkAdapter WHERE MACAddress IS ' "SELECT * FROM Win32_NetworkAdapter WHERE "
'NOT NULL AND Name = \'%(adapter_name_san)s\'' % "MACAddress = '{}'".format(mac_address)
{'adapter_name_san': adapter_name}) )
def test_set_static_network_config(self): def test_set_static_network_config(self):
adapter = mock.MagicMock() adapter = mock.MagicMock()

View File

@ -1,5 +1,3 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 Cloudbase Solutions Srl # Copyright 2013 Cloudbase Solutions Srl
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may # Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -14,21 +12,24 @@
# 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 mock
import re import re
import unittest import unittest
import mock
from oslo.config import cfg from oslo.config import cfg
from cloudbaseinit import exception from cloudbaseinit import exception
from cloudbaseinit.plugins import base from cloudbaseinit.metadata.services import base as service_base
from cloudbaseinit.plugins import base as plugin_base
from cloudbaseinit.plugins.windows import networkconfig from cloudbaseinit.plugins.windows import networkconfig
from cloudbaseinit.tests.metadata import fake_json_response from cloudbaseinit.tests.metadata import fake_json_response
CONF = cfg.CONF CONF = cfg.CONF
class NetworkConfigPluginPluginTests(unittest.TestCase): class TestNetworkConfigPlugin(unittest.TestCase):
def setUp(self): def setUp(self):
self._network_plugin = networkconfig.NetworkConfigPlugin() self._network_plugin = networkconfig.NetworkConfigPlugin()
@ -36,50 +37,139 @@ class NetworkConfigPluginPluginTests(unittest.TestCase):
'2013-04-04') '2013-04-04')
@mock.patch('cloudbaseinit.osutils.factory.get_os_utils') @mock.patch('cloudbaseinit.osutils.factory.get_os_utils')
def _test_execute(self, mock_get_os_utils, search_result, no_adapters): def _test_execute(self, mock_get_os_utils,
CONF.set_override('network_adapter', 'fake adapter') search_result=mock.MagicMock(),
no_adapter_name=False, no_adapters=False,
using_content=0, details_list=None,
missing_content_path=False):
fake_adapter = ("fake_name_0", "fake_mac_0")
mock_service = mock.MagicMock() mock_service = mock.MagicMock()
mock_osutils = mock.MagicMock() mock_osutils = mock.MagicMock()
mock_ndetails = mock.Mock()
re.search = mock.MagicMock(return_value=search_result) re.search = mock.MagicMock(return_value=search_result)
fake_shared_data = 'fake shared data' fake_shared_data = 'fake shared data'
network_config = self.fake_data['network_config'] network_config = self.fake_data['network_config']
mock_service.get_network_config.return_value = network_config if not details_list:
mock_service.get_content.return_value = search_result details_list = [None] * 6
details_list[0] = fake_adapter[1] # set MAC for matching
if no_adapter_name: # nothing provided in the config file
CONF.set_override("network_adapter", None)
else:
CONF.set_override("network_adapter", fake_adapter[0])
mock_osutils.get_network_adapters.return_value = [
fake_adapter,
# and other adapters
("name1", "mac1"),
("name2", "mac2")
]
mock_get_os_utils.return_value = mock_osutils mock_get_os_utils.return_value = mock_osutils
mock_osutils.set_static_network_config.return_value = False mock_osutils.set_static_network_config.return_value = False
if search_result is None: # service method setup
methods = ["get_network_config", "get_content", "get_network_details"]
for method in methods:
mock_method = getattr(mock_service, method)
mock_method.return_value = None
if using_content == 1:
mock_service.get_network_config.return_value = network_config
mock_service.get_content.return_value = search_result
elif using_content == 2:
mock_service.get_network_details.return_value = [mock_ndetails]
# actual tests
if search_result is None and using_content == 1:
self.assertRaises(exception.CloudbaseInitException, self.assertRaises(exception.CloudbaseInitException,
self._network_plugin.execute, self._network_plugin.execute,
mock_service, fake_shared_data) mock_service, fake_shared_data)
elif no_adapters: return
CONF.set_override('network_adapter', None) if no_adapters:
mock_osutils.get_network_adapters.return_value = [] mock_osutils.get_network_adapters.return_value = []
self.assertRaises(exception.CloudbaseInitException, self.assertRaises(exception.CloudbaseInitException,
self._network_plugin.execute, self._network_plugin.execute,
mock_service, fake_shared_data) mock_service, fake_shared_data)
return
else: attrs = [
"address",
"netmask",
"broadcast",
"gateway",
"dnsnameservers",
]
if using_content == 0:
response = self._network_plugin.execute(mock_service, response = self._network_plugin.execute(mock_service,
fake_shared_data) fake_shared_data)
elif using_content == 1:
if missing_content_path:
mock_service.get_network_config.return_value.pop(
"content_path", None
)
response = self._network_plugin.execute(mock_service,
fake_shared_data)
if not missing_content_path:
mock_service.get_network_config.assert_called_once_with() mock_service.get_network_config.assert_called_once_with()
mock_service.get_content.assert_called_once_with( mock_service.get_content.assert_called_once_with(
network_config['content_path']) network_config['content_path'])
adapters = mock_osutils.get_network_adapters()
if CONF.network_adapter:
mac = [pair[1] for pair in adapters
if pair == fake_adapter][0]
else:
mac = adapters[0][1]
(
address,
netmask,
broadcast,
gateway,
dnsnameserver
) = map(search_result.group, attrs)
dnsnameservers = dnsnameserver.strip().split(" ")
elif using_content == 2:
with self.assertRaises(exception.CloudbaseInitException):
self._network_plugin.execute(mock_service,
fake_shared_data)
mock_service.get_network_details.reset_mock()
mock_ndetails = service_base.NetworkDetails(*details_list)
mock_service.get_network_details.return_value = [mock_ndetails]
response = self._network_plugin.execute(mock_service,
fake_shared_data)
mock_service.get_network_details.assert_called_once_with()
mac = mock_ndetails.mac
(
address,
netmask,
broadcast,
gateway,
dnsnameservers
) = map(lambda attr: getattr(mock_ndetails, attr), attrs)
if using_content in (1, 2) and not missing_content_path:
mock_osutils.set_static_network_config.assert_called_once_with( mock_osutils.set_static_network_config.assert_called_once_with(
'fake adapter', search_result.group('address'), mac,
search_result.group('netmask'), address,
search_result.group('broadcast'), netmask,
search_result.group('gateway'), broadcast,
search_result.group('dnsnameservers').strip().split(' ')) gateway,
self.assertEqual((base.PLUGIN_EXECUTION_DONE, False), response) dnsnameservers
)
self.assertEqual((plugin_base.PLUGIN_EXECUTION_DONE, False),
response)
def test_execute(self): def test_execute(self):
m = mock.MagicMock() self._test_execute(using_content=1)
self._test_execute(search_result=m, no_adapters=False)
def test_execute_missing_content_path(self):
self._test_execute(using_content=1, missing_content_path=True)
def test_execute_no_debian(self): def test_execute_no_debian(self):
self._test_execute(search_result=None, no_adapters=False) self._test_execute(search_result=None, using_content=1)
def test_execute_no_adapters(self): def test_execute_no_adapter_name(self):
m = mock.MagicMock() self._test_execute(no_adapter_name=True, using_content=1)
self._test_execute(search_result=m, no_adapters=True)
def test_execute_no_adapter_name_or_adapters(self):
self._test_execute(no_adapter_name=True, no_adapters=True,
using_content=1)
def test_execute_network_details(self):
self._test_execute(using_content=2)
def test_execute_no_config_or_details(self):
self._test_execute(using_content=0)