diff --git a/os_cloud_config/cmd/setup_flavors.py b/os_cloud_config/cmd/setup_flavors.py index ee9a0fe..8c9b562 100644 --- a/os_cloud_config/cmd/setup_flavors.py +++ b/os_cloud_config/cmd/setup_flavors.py @@ -48,6 +48,10 @@ def parse_args(): group.add_argument('-f', '--flavors', dest='flavors', help='A JSON file containing a list of flavors to ' 'create directly') + group.add_argument('-i', '--ironic', action='store_true', + help='Pull the registered list of nodes from Ironic ' + 'that distinct flavors will be generated and created ' + 'from') parser.add_argument('-k', '--kernel', dest='kernel', help='ID of the kernel in Glance', required=True) parser.add_argument('-r', '--ramdisk', dest='ramdisk', @@ -74,6 +78,10 @@ def main(): flavors_list = json.load(flavors_file) flavors.create_flavors_from_list( client, flavors_list, args.kernel, args.ramdisk) + elif args.ironic: + ironic_client = clients.get_ironic_client() + flavors.create_flavors_from_ironic( + client, ironic_client, args.kernel, args.ramdisk, root_disk) except Exception: logging.exception("Unexpected error during command execution") return 1 diff --git a/os_cloud_config/flavors.py b/os_cloud_config/flavors.py index baf0240..11aed66 100644 --- a/os_cloud_config/flavors.py +++ b/os_cloud_config/flavors.py @@ -15,6 +15,7 @@ import logging + LOG = logging.getLogger(__name__) @@ -26,6 +27,29 @@ def cleanup_flavors(client, names=('m1.tiny', 'm1.small', 'm1.medium', client.flavors.delete(flavor.id) +def check_node_properties(node): + for node_property in 'memory_mb', 'local_gb', 'cpus', 'cpu_arch': + if not node.properties.get(node_property): + LOG.warning('node %s does not have %s set. Not creating flavor' + 'from node.', node.uuid, node_property) + return False + return True + + +def create_flavors_from_ironic(client, ironic_client, kernel, ramdisk, + root_disk): + node_list = [] + for node in ironic_client.node.list(detail=True): + if not check_node_properties(node): + continue + node_list.append({ + 'memory': node.properties['memory_mb'], + 'disk': node.properties['local_gb'], + 'cpu': node.properties['cpus'], + 'arch': node.properties['cpu_arch']}) + create_flavors_from_nodes(client, node_list, kernel, ramdisk, root_disk) + + def create_flavors_from_nodes(client, node_list, kernel, ramdisk, root_disk): LOG.debug('Populating flavors to create from node list.') node_details = set() diff --git a/os_cloud_config/tests/test_flavors.py b/os_cloud_config/tests/test_flavors.py index f671d31..2f4e5ba 100644 --- a/os_cloud_config/tests/test_flavors.py +++ b/os_cloud_config/tests/test_flavors.py @@ -103,3 +103,39 @@ class FlavorsTest(base.TestCase): 'baremetal:deploy_ramdisk_id': 'bbb', 'key': 'value'} client.flavors.create.return_value.set_keys.assert_called_once_with( metadata=metadata) + + @mock.patch('os_cloud_config.flavors._create_flavor') + def test_create_flavor_from_ironic(self, create_flavor): + node = mock.MagicMock() + node.uuid = 'uuid' + node.properties = {'cpus': '1', 'memory_mb': '2048', 'local_gb': '30', + 'cpu_arch': 'i386'} + client = mock.MagicMock() + ironic_client = mock.MagicMock() + ironic_client.node.list.return_value = [node] + flavors.create_flavors_from_ironic(client, ironic_client, 'aaa', 'bbb', + '10') + self.assertTrue(ironic_client.node.list.called) + + expected_flavor = {'disk': '10', 'ephemeral': '20', + 'kernel': 'aaa', 'ramdisk': 'bbb', + 'name': 'baremetal_2048_10_20_1', + 'memory': '2048', 'arch': 'i386', + 'cpu': '1'} + create_flavor.assert_called_once_with(client, expected_flavor) + + def test_check_node_properties(self): + node = mock.MagicMock() + properties = {'memory_mb': '1024', + 'local_gb': '10', + 'cpus': '1', + 'cpu_arch': 'i386'} + node.properties = properties + + self.assertTrue(flavors.check_node_properties(node)) + + properties['memory_mb'] = None + self.assertFalse(flavors.check_node_properties(node)) + + del properties['memory_mb'] + self.assertFalse(flavors.check_node_properties(node))