diff --git a/os_faults/drivers/cloud/universal.py b/os_faults/drivers/cloud/universal.py index 06813a9..466193c 100644 --- a/os_faults/drivers/cloud/universal.py +++ b/os_faults/drivers/cloud/universal.py @@ -16,40 +16,17 @@ import logging from os_faults.ansible import executor from os_faults.api import cloud_management from os_faults.api import error -from os_faults.api import node_collection -from os_faults.api import node_discover -from os_faults.drivers import shared_schemas LOG = logging.getLogger(__name__) -class UniversalCloudManagement(cloud_management.CloudManagement, - node_discover.NodeDiscover): +class UniversalCloudManagement(cloud_management.CloudManagement): """Universal cloud management driver This driver is suitable for the most abstract (and thus universal) case. - The driver does not have any built-in services, all services need - to be listed explicitly in a config file. - - By default the Universal driver works with only one node. To specify - more nodes use `node_list` node discovery driver. Authentication - parameters can be shared or overridden by corresponding parameters - from node discovery. - - **Example of single node configuration:** - - .. code-block:: yaml - - cloud_management: - driver: universal - args: - address: 192.168.1.10 - auth: - username: ubuntu - private_key_file: devstack_key - become_password: my_secret_password - iface: eth1 - serial: 10 + The driver does not have any built-in services nor node discovery + capabilities. All services need to be listed explicitly in a config file. + Node list is specified using `node_list` node discovery driver. **Example of multi-node configuration:** @@ -68,23 +45,12 @@ class UniversalCloudManagement(cloud_management.CloudManagement, username: developer private_key_file: cloud_key become_password: my_secret_password + - ip: 192.168.5.150 + auth: + username: developer + private_key_file: cloud_key + become_password: my_secret_password - parameters: - - - **address** - address of the node (optional, but if not set - a node discovery driver is mandatory) - - **auth** - SSH related parameters (optional): - - **username** - SSH username (optional) - - **password** - SSH password (optional) - - **private_key_file** - SSH key file (optional) - - **become_password** - privilege escalation password (optional) - - **jump** - SSH proxy parameters (optional): - - **host** - SSH proxy host - - **username** - SSH proxy user - - **private_key_file** - SSH proxy key file (optional) - - **iface** - network interface name to retrieve mac address (optional) - - **serial** - how many hosts Ansible should manage at a single time - (optional) default: 10 """ NAME = 'universal' @@ -92,38 +58,14 @@ class UniversalCloudManagement(cloud_management.CloudManagement, CONFIG_SCHEMA = { 'type': 'object', '$schema': 'http://json-schema.org/draft-04/schema#', - 'properties': { - 'address': {'type': 'string'}, - 'auth': shared_schemas.AUTH_SCHEMA, - 'iface': {'type': 'string'}, - 'serial': {'type': 'integer', 'minimum': 1}, - }, + 'properties': {}, 'additionalProperties': False, } def __init__(self, cloud_management_params): super(UniversalCloudManagement, self).__init__() - self.node_discover = self # by default can discover itself - self.address = cloud_management_params.get('address') - self.iface = cloud_management_params.get('iface') - serial = cloud_management_params.get('serial') - - auth = cloud_management_params.get('auth') or {} - jump = auth.get('jump') or {} - - self.cloud_executor = executor.AnsibleRunner( - remote_user=auth.get('username'), - password=auth.get('password'), - private_key_file=auth.get('private_key_file'), - become=auth.get('become'), - become_password=auth.get('become_password'), - jump_host=jump.get('host'), - jump_user=jump.get('user'), - serial=serial, - ) - - self.cached_hosts = None # cache for node discovery + self.cloud_executor = executor.AnsibleRunner() def verify(self): """Verify connection to the cloud.""" @@ -150,32 +92,3 @@ class UniversalCloudManagement(cloud_management.CloudManagement, return self.cloud_executor.execute(hosts, task) else: return self.cloud_executor.execute(hosts, task, []) - - def discover_hosts(self): - # this function is called when no node-discovery driver is specified; - # discover the default host set in config for this driver - - if not self.address: - raise error.OSFError('Cloud has no nodes. Specify address in ' - 'cloud management driver or add node ' - 'discovery driver') - - if not self.cached_hosts: - LOG.info('Discovering host name and MAC address for %s', - self.address) - host = node_collection.Host(ip=self.address) - - mac = None - if self.iface: - cmd = 'cat /sys/class/net/{}/address'.format(self.iface) - res = self.execute_on_cloud([host], {'command': cmd}) - mac = res[0].payload['stdout'] - - res = self.execute_on_cloud([host], {'command': 'hostname'}) - hostname = res[0].payload['stdout'] - - # update my hosts - self.cached_hosts = [node_collection.Host( - ip=self.address, mac=mac, fqdn=hostname)] - - return self.cached_hosts diff --git a/os_faults/drivers/shared_schemas.py b/os_faults/drivers/shared_schemas.py index 20576a8..ce23cc0 100644 --- a/os_faults/drivers/shared_schemas.py +++ b/os_faults/drivers/shared_schemas.py @@ -42,3 +42,5 @@ AUTH_SCHEMA = { }, 'additionalProperties': False, } + +SERIAL = {'type': 'integer', 'minimum': 1} diff --git a/os_faults/tests/unit/drivers/cloud/test_universal.py b/os_faults/tests/unit/drivers/cloud/test_universal.py index 6705d88..4704b7b 100644 --- a/os_faults/tests/unit/drivers/cloud/test_universal.py +++ b/os_faults/tests/unit/drivers/cloud/test_universal.py @@ -14,27 +14,19 @@ import ddt import mock -from os_faults.api import node_collection +from os_faults.api import error from os_faults.drivers.cloud import universal from os_faults.tests.unit import fakes from os_faults.tests.unit import test @ddt.ddt -class UniversalManagementTestCase(test.TestCase): +class UniversalCloudManagementTestCase(test.TestCase): @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) @ddt.data(( - dict(address='os.local', auth=dict(username='root')), - dict(remote_user='root', private_key_file=None, password=None, - become=None, become_password=None, jump_host=None, - jump_user=None, serial=None), - ), ( - dict(address='os.local', auth=dict(username='user', become=True, - become_password='secret'), serial=42), - dict(remote_user='user', private_key_file=None, password=None, - become=True, become_password='secret', jump_host=None, - jump_user=None, serial=42), + dict(), + dict(), )) @ddt.unpack def test_init(self, config, expected_runner_call, mock_ansible_runner): @@ -46,9 +38,7 @@ class UniversalManagementTestCase(test.TestCase): self.assertIs(cloud.cloud_executor, ansible_runner_inst) @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - @mock.patch('os_faults.drivers.cloud.universal.UniversalCloudManagement.' - 'discover_hosts') - def test_verify(self, mock_discover_hosts, mock_ansible_runner): + def test_no_discovery(self, mock_ansible_runner): address = '10.0.0.10' ansible_result = fakes.FakeAnsibleResult( payload=dict(stdout='openstack.local')) @@ -56,50 +46,6 @@ class UniversalManagementTestCase(test.TestCase): ansible_runner_inst.execute.side_effect = [ [ansible_result] ] - hosts = [node_collection.Host(ip=address)] - mock_discover_hosts.return_value = hosts cloud = universal.UniversalCloudManagement(dict(address=address)) - cloud.verify() - - ansible_runner_inst.execute.assert_has_calls([ - mock.call(hosts, {'command': 'hostname'}), - ]) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - def test_discover_hosts(self, mock_ansible_runner): - address = '10.0.0.10' - hostname = 'openstack.local' - - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [fakes.FakeAnsibleResult( - payload=dict(stdout=hostname))] - ] - expected_hosts = [node_collection.Host( - ip=address, mac=None, fqdn=hostname)] - - cloud = universal.UniversalCloudManagement(dict(address=address)) - - self.assertEqual(expected_hosts, cloud.discover_hosts()) - - @mock.patch('os_faults.ansible.executor.AnsibleRunner', autospec=True) - def test_discover_hosts_with_iface(self, mock_ansible_runner): - address = '10.0.0.10' - hostname = 'openstack.local' - mac = '0b:fe:fe:13:12:11' - - ansible_runner_inst = mock_ansible_runner.return_value - ansible_runner_inst.execute.side_effect = [ - [fakes.FakeAnsibleResult( - payload=dict(stdout=mac))], - [fakes.FakeAnsibleResult( - payload=dict(stdout=hostname))], - ] - expected_hosts = [node_collection.Host( - ip=address, mac=mac, fqdn=hostname)] - - cloud = universal.UniversalCloudManagement( - dict(address=address, iface='eth1')) - - self.assertEqual(expected_hosts, cloud.discover_hosts()) + self.assertRaises(error.OSFError, cloud.verify) diff --git a/os_faults/tests/unit/test_os_faults.py b/os_faults/tests/unit/test_os_faults.py index 902197f..9d115c4 100644 --- a/os_faults/tests/unit/test_os_faults.py +++ b/os_faults/tests/unit/test_os_faults.py @@ -20,7 +20,6 @@ from os_faults.api import error from os_faults.api import node_collection from os_faults.api import service from os_faults.drivers.cloud import devstack -from os_faults.drivers.cloud import universal from os_faults.drivers.power import libvirt from os_faults.tests.unit import test @@ -31,7 +30,7 @@ class OSFaultsTestCase(test.TestCase): super(OSFaultsTestCase, self).setUp() self.cloud_config = { 'cloud_management': { - 'driver': 'universal', + 'driver': 'devstack', 'args': { 'address': '10.30.00.5', 'auth': { @@ -108,7 +107,7 @@ class OSFaultsTestCase(test.TestCase): def test_connect_fuel_with_libvirt(self): destructor = os_faults.connect(self.cloud_config) - self.assertIsInstance(destructor, universal.UniversalCloudManagement) + self.assertIsInstance(destructor, devstack.DevStackManagement) self.assertEqual(1, len(destructor.power_manager.power_drivers)) self.assertIsInstance(destructor.power_manager.power_drivers[0], libvirt.LibvirtDriver)