
This covers the following updates to fix CI currently broken. * Fix compatibility with tox 4 * Update hacking to 6.1.0 * Clean up python 2 support and bump minimum supported version to 3.8 * Remove six because python 2 support is removed * Update job template to use the recent tested python versions * Replace items by prefixItems to fix schema error * Build documentation by sphinx command * Remove "Change Log" section from documentation * Split requirements for documentation build * Ensure tox is installed in functional tests * Fix devstack job Change-Id: I3b9c5b20aca55332c721d34fd4c41c5b886f60c5
225 lines
8.2 KiB
Python
225 lines
8.2 KiB
Python
# 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.
|
|
|
|
from unittest import mock
|
|
|
|
import jsonschema
|
|
|
|
import os_faults
|
|
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 service
|
|
from os_faults.drivers.cloud import devstack
|
|
from os_faults.drivers.power import libvirt
|
|
from os_faults.tests.unit import test
|
|
|
|
|
|
class OSFaultsTestCase(test.TestCase):
|
|
|
|
def setUp(self):
|
|
super(OSFaultsTestCase, self).setUp()
|
|
self.cloud_config = {
|
|
'cloud_management': {
|
|
'driver': 'devstack',
|
|
'args': {
|
|
'address': '10.30.00.5',
|
|
'auth': {
|
|
'username': 'root',
|
|
'private_key_file': '/my/path/pk.key',
|
|
},
|
|
}
|
|
},
|
|
'power_managements': [{
|
|
'driver': 'libvirt',
|
|
'args': {
|
|
'connection_uri': "qemu+ssh://user@10.30.20.21/system"
|
|
}
|
|
}]
|
|
}
|
|
|
|
@mock.patch('os_faults.ansible.executor.AnsibleRunner')
|
|
def test_connect_devstack(self, _):
|
|
cloud_config = {
|
|
'cloud_management': {
|
|
'driver': 'devstack',
|
|
'args': {
|
|
'address': 'devstack.local',
|
|
'auth': {
|
|
'username': 'developer',
|
|
'private_key_file': '/my/path/pk.key',
|
|
},
|
|
}
|
|
}
|
|
}
|
|
destructor = os_faults.connect(cloud_config)
|
|
self.assertIsInstance(destructor, devstack.DevStackCloudManagement)
|
|
|
|
@mock.patch('os_faults.ansible.executor.AnsibleRunner')
|
|
def test_config_with_services(self, _):
|
|
self.cloud_config['services'] = {
|
|
'app': {
|
|
'driver': 'process',
|
|
'args': {'grep': 'myapp'}
|
|
}
|
|
}
|
|
destructor = os_faults.connect(self.cloud_config)
|
|
app = destructor.get_service('app')
|
|
self.assertIsNotNone(app)
|
|
|
|
@mock.patch('os_faults.ansible.executor.AnsibleRunner')
|
|
def test_config_with_services_and_hosts(self, _):
|
|
self.cloud_config['node_discover'] = {
|
|
'driver': 'node_list',
|
|
'args': [
|
|
{
|
|
'ip': '10.0.0.11',
|
|
'mac': '01:ab:cd:01:ab:cd',
|
|
'fqdn': 'node-1'
|
|
}, {
|
|
'ip': '10.0.0.12',
|
|
'mac': '02:ab:cd:02:ab:cd',
|
|
'fqdn': 'node-2'
|
|
},
|
|
]
|
|
}
|
|
self.cloud_config['services'] = {
|
|
'app': {
|
|
'driver': 'process',
|
|
'args': {'grep': 'myapp'},
|
|
'hosts': ['10.0.0.11', '10.0.0.12']
|
|
}
|
|
}
|
|
destructor = os_faults.connect(self.cloud_config)
|
|
app = destructor.get_service('app')
|
|
self.assertIsNotNone(app)
|
|
nodes = app.get_nodes()
|
|
self.assertEqual(['10.0.0.11', '10.0.0.12'], nodes.get_ips())
|
|
self.assertEqual(['node-1', 'node-2'], nodes.get_fqdns())
|
|
self.assertEqual(['01:ab:cd:01:ab:cd', '02:ab:cd:02:ab:cd'],
|
|
nodes.get_macs())
|
|
|
|
@mock.patch('os_faults.ansible.executor.AnsibleRunner')
|
|
def test_connect_with_libvirt(self, _):
|
|
destructor = os_faults.connect(self.cloud_config)
|
|
self.assertIsInstance(destructor, devstack.DevStackCloudManagement)
|
|
self.assertEqual(1, len(destructor.power_manager.power_drivers))
|
|
self.assertIsInstance(destructor.power_manager.power_drivers[0],
|
|
libvirt.LibvirtDriver)
|
|
|
|
def test_connect_driver_not_found(self):
|
|
cloud_config = {
|
|
'cloud_management': {
|
|
'driver': 'non-existing',
|
|
'args': {},
|
|
}
|
|
}
|
|
self.assertRaises(
|
|
error.OSFDriverNotFound, os_faults.connect, cloud_config)
|
|
|
|
def test_connect_driver_not_specified(self):
|
|
cloud_config = {'foo': 'bar'}
|
|
self.assertRaises(
|
|
jsonschema.ValidationError, os_faults.connect, cloud_config)
|
|
|
|
@mock.patch('os.path.exists', return_value=False)
|
|
def test_connect_no_config_files(self, mock_os_path_exists):
|
|
self.assertRaises(error.OSFError, os_faults.connect)
|
|
|
|
@mock.patch('os.path.exists', side_effect=lambda x: 'bad' not in x)
|
|
@mock.patch('os.walk', side_effect=lambda x: ([x, [], []],
|
|
[x + 'subdir', [], []]))
|
|
@mock.patch.object(executor, 'MODULE_PATHS', set())
|
|
def test_register_ansible_modules(self, mock_os_walk, mock_os_path_exists):
|
|
os_faults.register_ansible_modules(['/my/path/', '/other/path/'])
|
|
self.assertEqual(executor.get_module_paths(),
|
|
{'/my/path/', '/my/path/subdir',
|
|
'/other/path/', '/other/path/subdir'})
|
|
|
|
self.assertRaises(error.OSFError, os_faults.register_ansible_modules,
|
|
['/my/bad/path/'])
|
|
|
|
@mock.patch('os_faults.connect')
|
|
def test_discover(self, mock_connect):
|
|
cloud_config = {
|
|
'cloud_management': {
|
|
'driver': 'devstack',
|
|
'args': {
|
|
'address': 'devstack.local',
|
|
'username': 'developer',
|
|
'private_key_file': '/my/path/pk.key',
|
|
}
|
|
}
|
|
}
|
|
cloud_management_mock = mock.create_autospec(
|
|
cloud_management.CloudManagement)
|
|
mock_connect.return_value = cloud_management_mock
|
|
cloud_management_mock.get_nodes.return_value.hosts = [
|
|
node_collection.Host(
|
|
ip='10.0.0.2', mac='09:7b:74:90:63:c1', fqdn='node1.local'),
|
|
node_collection.Host(
|
|
ip='10.0.0.3', mac='09:7b:74:90:63:c2', fqdn='node2.local')]
|
|
cloud_management_mock.list_supported_services.return_value = [
|
|
'srv1', 'srv2']
|
|
|
|
def mock_service(name, config, ips):
|
|
m = mock.create_autospec(service.Service)
|
|
m.NAME = name
|
|
m.config = config
|
|
m.get_nodes.return_value.get_ips.return_value = ips
|
|
return m
|
|
|
|
srv1 = mock_service('process', {'grep': 'srv1'}, [])
|
|
srv2 = mock_service('linux_service',
|
|
{'grep': 'srv2', 'linux_service': 'srv2'},
|
|
['10.0.0.2'])
|
|
services = {'srv1': srv1, 'srv2': srv2}
|
|
cloud_management_mock.get_service.side_effect = services.get
|
|
|
|
discovered_config = os_faults.discover(cloud_config)
|
|
self.assertEqual({
|
|
'cloud_management': {
|
|
'driver': 'devstack',
|
|
'args': {
|
|
'address': 'devstack.local',
|
|
'private_key_file': '/my/path/pk.key',
|
|
'username': 'developer'
|
|
}
|
|
},
|
|
'node_discover': {
|
|
'driver': 'node_list',
|
|
'args': [
|
|
{
|
|
'fqdn': 'node1.local',
|
|
'ip': '10.0.0.2',
|
|
'mac': '09:7b:74:90:63:c1'
|
|
}, {
|
|
'fqdn': 'node2.local',
|
|
'ip': '10.0.0.3',
|
|
'mac': '09:7b:74:90:63:c2'
|
|
}
|
|
]
|
|
},
|
|
'services': {
|
|
'srv1': {
|
|
'driver': 'process',
|
|
'args': {'grep': 'srv1'},
|
|
},
|
|
'srv2': {
|
|
'driver': 'linux_service',
|
|
'args': {'grep': 'srv2', 'linux_service': 'srv2'},
|
|
'hosts': ['10.0.0.2']
|
|
}
|
|
}
|
|
}, discovered_config)
|