Merge "Yoga: Change default boot mode to uefi"
Zuul authored 2 years ago
Gerrit Code Review committed 2 years ago
4 | 4 | fi |
5 | 5 | |
6 | 6 | # Whether configure the nodes to boot in Legacy BIOS or UEFI mode. Accepted |
7 | # values are: "bios" or "uefi", defaults to "bios". | |
8 | IRONIC_BOOT_MODE=${IRONIC_BOOT_MODE:-bios} | |
7 | # values are: "bios" or "uefi", defaults to "uefi". | |
8 | IRONIC_BOOT_MODE=${IRONIC_BOOT_MODE:-uefi} | |
9 | 9 | |
10 | 10 | CIRROS_VERSION_DEVSTACK=$(set +o xtrace && |
11 | 11 | source $TOP_DIR/stackrc && |
2369 | 2369 | local node_capabilities="" |
2370 | 2370 | if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then |
2371 | 2371 | node_capabilities+=" --property capabilities=boot_mode:uefi" |
2372 | fi | |
2373 | if [[ "$IRONIC_BOOT_MODE" == "bios" ]]; then | |
2374 | node_capabilities+=" --property capabilities=boot_mode:bios" | |
2372 | 2375 | fi |
2373 | 2376 | if [[ "$IRONIC_SECURE_BOOT" == "True" ]]; then |
2374 | 2377 | if [[ -n "$node_capabilities" ]]; then |
2580 | 2583 | if [[ "$IRONIC_BOOT_MODE" == "uefi" ]]; then |
2581 | 2584 | openstack --os-cloud $OS_CLOUD flavor set baremetal --property "capabilities:boot_mode"="uefi" |
2582 | 2585 | fi |
2583 | ||
2586 | if [[ "$IRONIC_BOOT_MODE" == "bios" ]]; then | |
2587 | openstack --os-cloud $OS_CLOUD flavor set baremetal --property "capabilities:boot_mode"="bios" | |
2588 | fi | |
2584 | 2589 | for trait in $IRONIC_DEFAULT_TRAITS; do |
2585 | 2590 | openstack --os-cloud $OS_CLOUD flavor set baremetal --property "trait:$trait"="required" |
2586 | 2591 | done |
62 | 62 | |
63 | 63 | openstack baremetal node set <node-uuid> --property capabilities='boot_mode:uefi' |
64 | 64 | |
65 | Conversely, to configure a node in ``bios`` mode, then set the | |
66 | ``capabilities`` as below:: | |
67 | ||
68 | openstack baremetal node set <node-uuid> --property capabilities='boot_mode:bios' | |
69 | ||
70 | .. note:: | |
71 | ||
72 | The Ironic project changed the default boot mode setting for nodes from | |
73 | ``bios`` to ``uefi`` during the Yoga development cycle. | |
74 | ||
65 | 75 | Nodes having ``boot_mode`` set to ``uefi`` may be requested by adding an |
66 | 76 | ``extra_spec`` to the Compute service flavor:: |
67 | 77 |
131 | 131 | cfg.StrOpt('default_boot_mode', |
132 | 132 | choices=[(boot_modes.UEFI, _('UEFI boot mode')), |
133 | 133 | (boot_modes.LEGACY_BIOS, _('Legacy BIOS boot mode'))], |
134 | default=boot_modes.LEGACY_BIOS, | |
134 | default=boot_modes.UEFI, | |
135 | 135 | mutable=True, |
136 | 136 | help=_('Default boot mode to use when no boot mode is ' |
137 | 137 | 'requested in node\'s driver_info, capabilities or ' |
138 | 138 | 'in the `instance_info` configuration. Currently the ' |
139 | 'default boot mode is "%(bios)s", but it will be ' | |
140 | 'changed to "%(uefi)s in the future. It is recommended ' | |
141 | 'to set an explicit value for this option. This option ' | |
139 | 'default boot mode is "%(uefi)s", but it was ' | |
140 | '"%(bios)s" previously in Ironic. It is recommended ' | |
141 | 'to set an explicit value for this option, and if the ' | |
142 | 'setting or default differs from nodes, to ensure that ' | |
143 | 'nodes are configured specifically for their desired ' | |
144 | 'boot mode. This option ' | |
142 | 145 | 'only has effect when management interface supports ' |
143 | 146 | 'boot mode management') % { |
144 | 147 | 'bios': boot_modes.LEGACY_BIOS, |
15 | 15 | from oslo_log import log as logging |
16 | 16 | from oslo_utils import excutils |
17 | 17 | |
18 | from ironic.common import boot_modes | |
19 | 18 | from ironic.common import exception |
20 | 19 | from ironic.common.i18n import _ |
21 | 20 | from ironic.common import utils as common_utils |
292 | 291 | boot_mode = get_boot_mode_for_deploy(node) |
293 | 292 | if boot_mode: |
294 | 293 | return boot_mode |
295 | # TODO(hshiina): The default boot mode will be changed to UEFI. | |
296 | global warn_about_default_boot_mode | |
297 | if (not warn_about_default_boot_mode | |
298 | and CONF.deploy.default_boot_mode == boot_modes.LEGACY_BIOS): | |
299 | warn_about_default_boot_mode = True | |
300 | LOG.warning('Boot mode is not configured for node %(node_uuid)s ' | |
301 | 'explicitly. The default boot mode is "%(bios)s", but, ' | |
302 | 'the default will be changed to "%(uefi)s" in the future. ' | |
303 | 'It is recommended to set the boot option into ' | |
304 | 'properties/capabilities/boot_mode for all nodes.', | |
305 | {'node_uuid': node.uuid, | |
306 | 'bios': boot_modes.LEGACY_BIOS, | |
307 | 'uefi': boot_modes.UEFI}) | |
308 | 294 | return CONF.deploy.default_boot_mode |
309 | 295 | |
310 | 296 |
607 | 607 | :raises: InvalidParameterValue if the capabilities string is not a |
608 | 608 | dict or is malformed. |
609 | 609 | :returns: A string representing the boot option type. Defaults to |
610 | 'netboot'. | |
610 | configuration setting [deploy]default_boot_mode. | |
611 | 611 | """ |
612 | 612 | |
613 | 613 | # NOTE(TheJulia): Software raid always implies local deployment |
437 | 437 | unlink_mock.assert_called_once_with('/tftpboot/10.10.0.1.conf') |
438 | 438 | create_link_mock.assert_has_calls(create_link_calls) |
439 | 439 | |
440 | @mock.patch.object(pxe_utils, '_link_ip_address_pxe_configs', | |
441 | autospec=True) | |
440 | 442 | @mock.patch.object(os, 'chmod', autospec=True) |
441 | 443 | @mock.patch('ironic.common.utils.write_to_file', autospec=True) |
442 | 444 | @mock.patch('ironic.common.utils.render_template', autospec=True) |
443 | 445 | @mock.patch('oslo_utils.fileutils.ensure_tree', autospec=True) |
444 | 446 | def test_create_pxe_config(self, ensure_tree_mock, render_mock, |
445 | write_mock, chmod_mock): | |
447 | write_mock, chmod_mock, mock_link_ip_addr): | |
446 | 448 | self.config(tftp_root=tempfile.mkdtemp(), group='pxe') |
447 | 449 | with task_manager.acquire(self.context, self.node.uuid) as task: |
448 | 450 | pxe_utils.create_pxe_config(task, self.pxe_options, |
450 | 452 | render_mock.assert_called_with( |
451 | 453 | CONF.pxe.pxe_config_template, |
452 | 454 | {'pxe_options': self.pxe_options, |
453 | 'ROOT': '{{ ROOT }}', | |
454 | 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}'} | |
455 | 'ROOT': '(( ROOT ))', | |
456 | 'DISK_IDENTIFIER': '(( DISK_IDENTIFIER ))'} | |
455 | 457 | ) |
456 | 458 | node_dir = os.path.join(CONF.pxe.tftp_root, self.node.uuid) |
457 | 459 | pxe_dir = os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg') |
464 | 466 | pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) |
465 | 467 | write_mock.assert_called_with(pxe_cfg_file_path, |
466 | 468 | render_mock.return_value) |
467 | ||
469 | self.assertTrue(mock_link_ip_addr.called) | |
470 | ||
471 | @mock.patch.object(pxe_utils, '_link_ip_address_pxe_configs', | |
472 | autospec=True) | |
468 | 473 | @mock.patch.object(os, 'chmod', autospec=True) |
469 | 474 | @mock.patch('ironic.common.utils.write_to_file', autospec=True) |
470 | 475 | @mock.patch('ironic.common.utils.render_template', autospec=True) |
471 | 476 | @mock.patch('oslo_utils.fileutils.ensure_tree', autospec=True) |
472 | 477 | def test_create_pxe_config_set_dir_permission(self, ensure_tree_mock, |
473 | 478 | render_mock, |
474 | write_mock, chmod_mock): | |
479 | write_mock, chmod_mock, | |
480 | mock_link_ip_addr): | |
475 | 481 | self.config(tftp_root=tempfile.mkdtemp(), group='pxe') |
476 | 482 | self.config(dir_permission=0o755, group='pxe') |
477 | 483 | with task_manager.acquire(self.context, self.node.uuid) as task: |
480 | 486 | render_mock.assert_called_with( |
481 | 487 | CONF.pxe.pxe_config_template, |
482 | 488 | {'pxe_options': self.pxe_options, |
483 | 'ROOT': '{{ ROOT }}', | |
484 | 'DISK_IDENTIFIER': '{{ DISK_IDENTIFIER }}'} | |
489 | 'ROOT': '(( ROOT ))', | |
490 | 'DISK_IDENTIFIER': '(( DISK_IDENTIFIER ))'} | |
485 | 491 | ) |
486 | 492 | node_dir = os.path.join(CONF.pxe.tftp_root, self.node.uuid) |
487 | 493 | pxe_dir = os.path.join(CONF.pxe.tftp_root, 'pxelinux.cfg') |
495 | 501 | pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) |
496 | 502 | write_mock.assert_called_with(pxe_cfg_file_path, |
497 | 503 | render_mock.return_value) |
498 | ||
504 | self.assertTrue(mock_link_ip_addr.called) | |
505 | ||
506 | @mock.patch.object(pxe_utils, '_link_ip_address_pxe_configs', | |
507 | autospec=True) | |
499 | 508 | @mock.patch.object(os.path, 'isdir', autospec=True) |
500 | 509 | @mock.patch.object(os, 'chmod', autospec=True) |
501 | 510 | @mock.patch('ironic.common.utils.write_to_file', autospec=True) |
502 | 511 | @mock.patch('ironic.common.utils.render_template', autospec=True) |
503 | 512 | @mock.patch('oslo_utils.fileutils.ensure_tree', autospec=True) |
504 | def test_create_pxe_config_existing_dirs(self, ensure_tree_mock, | |
505 | render_mock, | |
506 | write_mock, chmod_mock, | |
507 | isdir_mock): | |
513 | def test_create_pxe_config_existing_dirs_uefi( | |
514 | self, ensure_tree_mock, | |
515 | render_mock, | |
516 | write_mock, chmod_mock, | |
517 | isdir_mock, mock_link_ip_address): | |
508 | 518 | self.config(dir_permission=0o755, group='pxe') |
519 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
520 | isdir_mock.return_value = True | |
521 | pxe_utils.create_pxe_config(task, self.pxe_options, | |
522 | CONF.pxe.pxe_config_template) | |
523 | render_mock.assert_called_with( | |
524 | CONF.pxe.pxe_config_template, | |
525 | {'pxe_options': self.pxe_options, | |
526 | 'ROOT': '(( ROOT ))', | |
527 | 'DISK_IDENTIFIER': '(( DISK_IDENTIFIER ))'} | |
528 | ) | |
529 | ensure_tree_mock.assert_has_calls([]) | |
530 | chmod_mock.assert_not_called() | |
531 | isdir_mock.assert_has_calls([]) | |
532 | pxe_cfg_file_path = pxe_utils.get_pxe_config_file_path(self.node.uuid) | |
533 | write_mock.assert_called_with(pxe_cfg_file_path, | |
534 | render_mock.return_value) | |
535 | self.assertTrue(mock_link_ip_address.called) | |
536 | ||
537 | @mock.patch.object(os.path, 'isdir', autospec=True) | |
538 | @mock.patch.object(os, 'chmod', autospec=True) | |
539 | @mock.patch('ironic.common.utils.write_to_file', autospec=True) | |
540 | @mock.patch('ironic.common.utils.render_template', autospec=True) | |
541 | @mock.patch('oslo_utils.fileutils.ensure_tree', autospec=True) | |
542 | def test_create_pxe_config_existing_dirs_bios( | |
543 | self, ensure_tree_mock, | |
544 | render_mock, | |
545 | write_mock, chmod_mock, | |
546 | isdir_mock): | |
547 | self.config(dir_permission=0o755, group='pxe') | |
548 | self.config(default_boot_mode='bios', group='deploy') | |
509 | 549 | with task_manager.acquire(self.context, self.node.uuid) as task: |
510 | 550 | isdir_mock.return_value = True |
511 | 551 | pxe_utils.create_pxe_config(task, self.pxe_options, |
633 | 673 | write_mock.assert_called_with(pxe_cfg_file_path, |
634 | 674 | render_mock.return_value) |
635 | 675 | |
676 | @mock.patch('ironic.dhcp.neutron.NeutronDHCPApi.get_ip_addresses', | |
677 | autospec=True) | |
636 | 678 | @mock.patch('ironic.common.utils.rmtree_without_raise', autospec=True) |
637 | 679 | @mock.patch('ironic_lib.utils.unlink_without_raise', autospec=True) |
638 | def test_clean_up_pxe_config(self, unlink_mock, rmtree_mock): | |
680 | def test_clean_up_pxe_config(self, unlink_mock, rmtree_mock, | |
681 | mock_get_ip_addr): | |
639 | 682 | address = "aa:aa:aa:aa:aa:aa" |
640 | 683 | object_utils.create_test_port(self.context, node_id=self.node.id, |
641 | 684 | address=address) |
653 | 696 | unlink_mock.assert_has_calls(ensure_calls) |
654 | 697 | rmtree_mock.assert_called_once_with( |
655 | 698 | os.path.join(CONF.pxe.tftp_root, self.node.uuid)) |
699 | self.assertTrue(mock_get_ip_addr.called) | |
656 | 700 | |
657 | 701 | @mock.patch.object(os.path, 'isfile', lambda path: False) |
658 | 702 | @mock.patch('ironic.common.utils.file_has_content', autospec=True) |
736 | 780 | self.config(tftp_server='192.0.2.1', group='pxe') |
737 | 781 | elif ip_version == 6: |
738 | 782 | self.config(tftp_server='ff80::1', group='pxe') |
739 | self.config(pxe_bootfile_name='fake-bootfile', group='pxe') | |
783 | if CONF.deploy.default_boot_mode == 'uefi': | |
784 | if ipxe: | |
785 | self.config(uefi_ipxe_bootfile_name='fake-bootfile-ipxe', | |
786 | group='pxe') | |
787 | else: | |
788 | self.config(uefi_pxe_bootfile_name='fake-bootfile', | |
789 | group='pxe') | |
790 | else: | |
791 | if ipxe: | |
792 | self.config(ipxe_bootfile_name='fake-bootfile-ipxe', | |
793 | group='pxe') | |
794 | else: | |
795 | self.config(pxe_bootfile_name='fake-bootfile', group='pxe') | |
740 | 796 | self.config(tftp_root='/tftp-path/', group='pxe') |
741 | 797 | if ipxe: |
742 | 798 | bootfile = 'fake-bootfile-ipxe' |
773 | 829 | pxe_utils.dhcp_options_for_instance(task)) |
774 | 830 | |
775 | 831 | def test_dhcp_options_for_instance(self): |
832 | self.config(default_boot_mode='uefi', group='deploy') | |
833 | self._dhcp_options_for_instance(ip_version=4) | |
834 | ||
835 | def test_dhcp_options_for_instance_bios(self): | |
836 | self.config(default_boot_mode='bios', group='deploy') | |
776 | 837 | self._dhcp_options_for_instance(ip_version=4) |
777 | 838 | |
778 | 839 | def test_dhcp_options_for_instance_ipv6(self): |
779 | 840 | self.config(tftp_server='ff80::1', group='pxe') |
841 | self._dhcp_options_for_instance(ip_version=6) | |
842 | ||
843 | def test_dhcp_options_for_instance_ipv6_bios(self): | |
844 | self.config(tftp_server='ff80::1', group='pxe') | |
845 | self.config(default_boot_mode='bios', group='deploy') | |
780 | 846 | self._dhcp_options_for_instance(ip_version=6) |
781 | 847 | |
782 | 848 | def _test_get_kernel_ramdisk_info(self, expected_dir, mode='deploy', |
1704 | 1770 | def test_dhcp_options_for_instance_ipxe_bios(self): |
1705 | 1771 | self.config(ip_version=4, group='pxe') |
1706 | 1772 | boot_file = 'fake-bootfile-bios-ipxe' |
1773 | self.config(default_boot_mode='bios', group='deploy') | |
1707 | 1774 | self.config(ipxe_bootfile_name=boot_file, group='pxe') |
1708 | 1775 | with task_manager.acquire(self.context, self.node.uuid) as task: |
1709 | 1776 | self._dhcp_options_for_instance_ipxe(task, boot_file) |
1720 | 1787 | self.config(ip_version=6, group='pxe') |
1721 | 1788 | boot_file = 'fake-bootfile-ipxe' |
1722 | 1789 | self.config(ipxe_bootfile_name=boot_file, group='pxe') |
1790 | self.config(default_boot_mode='bios', group='deploy') | |
1791 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
1792 | self._dhcp_options_for_instance_ipxe(task, boot_file, ip_version=6) | |
1793 | ||
1794 | def test_dhcp_options_for_ipxe_ipv6_uefi(self): | |
1795 | self.config(ip_version=6, group='pxe') | |
1796 | boot_file = 'fake-bootfile-ipxe' | |
1797 | self.config(uefi_ipxe_bootfile_name=boot_file, group='pxe') | |
1798 | self.config(default_boot_mode='uefi', group='deploy') | |
1723 | 1799 | with task_manager.acquire(self.context, self.node.uuid) as task: |
1724 | 1800 | self._dhcp_options_for_instance_ipxe(task, boot_file, ip_version=6) |
1725 | 1801 |
241 | 241 | '--private-key=/path/to/key') |
242 | 242 | |
243 | 243 | def test__parse_partitioning_info_root_msdos(self): |
244 | self.config(default_boot_mode='bios', group='deploy') | |
244 | 245 | expected_info = { |
245 | 246 | 'partition_info': { |
246 | 247 | 'label': 'msdos', |
289 | 289 | fake_system.set_system_boot_options.assert_has_calls( |
290 | 290 | [mock.call(sushy.BOOT_SOURCE_TARGET_PXE, |
291 | 291 | enabled=expected), |
292 | mock.call(mode=sushy.BOOT_SOURCE_MODE_BIOS)]) | |
292 | mock.call(mode=sushy.BOOT_SOURCE_MODE_UEFI)]) | |
293 | 293 | else: |
294 | 294 | fake_system.set_system_boot_options.assert_has_calls( |
295 | 295 | [mock.call(sushy.BOOT_SOURCE_TARGET_PXE, |
984 | 984 | with task_manager.acquire(self.context, self.node['uuid'], |
985 | 985 | shared=False) as task: |
986 | 986 | self.deploy.configure_local_boot(task) |
987 | # NOTE(TheJulia): We explicitly call install_bootloader when | |
988 | # we have a whole disk image *and* are in UEFI mode as setting | |
989 | # the internal NVRAM helps negate need to know a root device | |
990 | # hint if the boot order is weird. | |
991 | self.assertTrue(install_bootloader_mock.called) | |
992 | try_set_boot_device_mock.assert_called_once_with( | |
993 | task, boot_devices.DISK, persistent=True) | |
994 | ||
995 | @mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True) | |
996 | @mock.patch.object(agent_client.AgentClient, 'install_bootloader', | |
997 | autospec=True) | |
998 | def test_configure_local_boot_whole_disk_image_bios( | |
999 | self, install_bootloader_mock, try_set_boot_device_mock): | |
1000 | self.config(default_boot_mode='bios', group='deploy') | |
1001 | ||
1002 | with task_manager.acquire(self.context, self.node['uuid'], | |
1003 | shared=False) as task: | |
1004 | self.deploy.configure_local_boot(task) | |
987 | 1005 | self.assertFalse(install_bootloader_mock.called) |
988 | 1006 | try_set_boot_device_mock.assert_called_once_with( |
989 | 1007 | task, boot_devices.DISK, persistent=True) |
1029 | 1047 | def test_configure_local_boot_on_software_raid( |
1030 | 1048 | self, install_bootloader_mock, try_set_boot_device_mock, |
1031 | 1049 | GlanceImageService_mock): |
1050 | image = GlanceImageService_mock.return_value.show.return_value | |
1051 | image.get.return_value = {'rootfs_uuid': 'rootfs'} | |
1052 | with task_manager.acquire(self.context, self.node['uuid'], | |
1053 | shared=False) as task: | |
1054 | task.node.driver_internal_info['is_whole_disk_image'] = True | |
1055 | task.node.target_raid_config = { | |
1056 | "logical_disks": [ | |
1057 | { | |
1058 | "size_gb": 100, | |
1059 | "raid_level": "1", | |
1060 | "controller": "software", | |
1061 | }, | |
1062 | { | |
1063 | "size_gb": 'MAX', | |
1064 | "raid_level": "0", | |
1065 | "controller": "software", | |
1066 | } | |
1067 | ] | |
1068 | } | |
1069 | self.deploy.configure_local_boot(task) | |
1070 | self.assertTrue(GlanceImageService_mock.called) | |
1071 | install_bootloader_mock.assert_called_once_with( | |
1072 | mock.ANY, task.node, | |
1073 | root_uuid='rootfs', | |
1074 | efi_system_part_uuid=None, | |
1075 | prep_boot_part_uuid=None, | |
1076 | target_boot_mode='uefi', | |
1077 | software_raid=True) | |
1078 | try_set_boot_device_mock.assert_called_once_with( | |
1079 | task, boot_devices.DISK, persistent=True) | |
1080 | ||
1081 | @mock.patch.object(image_service, 'GlanceImageService', autospec=True) | |
1082 | @mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True) | |
1083 | @mock.patch.object(agent_client.AgentClient, 'install_bootloader', | |
1084 | autospec=True) | |
1085 | def test_configure_local_boot_on_software_raid_bios( | |
1086 | self, install_bootloader_mock, try_set_boot_device_mock, | |
1087 | GlanceImageService_mock): | |
1088 | self.config(default_boot_mode='bios', group='deploy') | |
1032 | 1089 | image = GlanceImageService_mock.return_value.show.return_value |
1033 | 1090 | image.get.return_value = {'rootfs_uuid': 'rootfs'} |
1034 | 1091 | with task_manager.acquire(self.context, self.node['uuid'], |
1067 | 1124 | def test_configure_local_boot_on_software_raid_explicit_uuid( |
1068 | 1125 | self, install_bootloader_mock, try_set_boot_device_mock, |
1069 | 1126 | GlanceImageService_mock): |
1127 | with task_manager.acquire(self.context, self.node['uuid'], | |
1128 | shared=False) as task: | |
1129 | task.node.driver_internal_info['is_whole_disk_image'] = True | |
1130 | task.node.instance_info['image_rootfs_uuid'] = 'rootfs' | |
1131 | task.node.target_raid_config = { | |
1132 | "logical_disks": [ | |
1133 | { | |
1134 | "size_gb": 100, | |
1135 | "raid_level": "1", | |
1136 | "controller": "software", | |
1137 | }, | |
1138 | { | |
1139 | "size_gb": 'MAX', | |
1140 | "raid_level": "0", | |
1141 | "controller": "software", | |
1142 | } | |
1143 | ] | |
1144 | } | |
1145 | self.deploy.configure_local_boot(task) | |
1146 | self.assertFalse(GlanceImageService_mock.called) | |
1147 | install_bootloader_mock.assert_called_once_with( | |
1148 | mock.ANY, task.node, | |
1149 | root_uuid='rootfs', | |
1150 | efi_system_part_uuid=None, | |
1151 | prep_boot_part_uuid=None, | |
1152 | target_boot_mode='uefi', | |
1153 | software_raid=True) | |
1154 | try_set_boot_device_mock.assert_called_once_with( | |
1155 | task, boot_devices.DISK, persistent=True) | |
1156 | ||
1157 | @mock.patch.object(image_service, 'GlanceImageService', autospec=True) | |
1158 | @mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True) | |
1159 | @mock.patch.object(agent_client.AgentClient, 'install_bootloader', | |
1160 | autospec=True) | |
1161 | def test_configure_local_boot_on_software_raid_explicit_uuid_bios( | |
1162 | self, install_bootloader_mock, try_set_boot_device_mock, | |
1163 | GlanceImageService_mock): | |
1164 | self.config(default_boot_mode='bios', group='deploy') | |
1070 | 1165 | with task_manager.acquire(self.context, self.node['uuid'], |
1071 | 1166 | shared=False) as task: |
1072 | 1167 | task.node.driver_internal_info['is_whole_disk_image'] = True |
1101 | 1196 | @mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True) |
1102 | 1197 | @mock.patch.object(agent_client.AgentClient, 'install_bootloader', |
1103 | 1198 | autospec=True) |
1104 | def test_configure_local_boot_on_software_raid_exception( | |
1199 | def test_configure_local_boot_on_software_raid_exception_uefi( | |
1105 | 1200 | self, install_bootloader_mock, try_set_boot_device_mock, |
1106 | 1201 | GlanceImageService_mock): |
1202 | GlanceImageService_mock.side_effect = Exception('Glance not found') | |
1203 | with task_manager.acquire(self.context, self.node['uuid'], | |
1204 | shared=False) as task: | |
1205 | task.node.driver_internal_info['is_whole_disk_image'] = True | |
1206 | root_uuid = "1efecf88-2b58-4d4e-8fbd-7bef1a40a1b0" | |
1207 | task.node.driver_internal_info['root_uuid_or_disk_id'] = root_uuid | |
1208 | task.node.target_raid_config = { | |
1209 | "logical_disks": [ | |
1210 | { | |
1211 | "size_gb": 100, | |
1212 | "raid_level": "1", | |
1213 | "controller": "software", | |
1214 | }, | |
1215 | { | |
1216 | "size_gb": 'MAX', | |
1217 | "raid_level": "0", | |
1218 | "controller": "software", | |
1219 | } | |
1220 | ] | |
1221 | } | |
1222 | self.deploy.configure_local_boot(task) | |
1223 | self.assertTrue(GlanceImageService_mock.called) | |
1224 | # check if the root_uuid comes from the driver_internal_info | |
1225 | install_bootloader_mock.assert_called_once_with( | |
1226 | mock.ANY, task.node, root_uuid=root_uuid, | |
1227 | efi_system_part_uuid=None, prep_boot_part_uuid=None, | |
1228 | target_boot_mode='uefi', software_raid=True) | |
1229 | try_set_boot_device_mock.assert_called_once_with( | |
1230 | task, boot_devices.DISK, persistent=True) | |
1231 | ||
1232 | @mock.patch.object(image_service, 'GlanceImageService', autospec=True) | |
1233 | @mock.patch.object(deploy_utils, 'try_set_boot_device', autospec=True) | |
1234 | @mock.patch.object(agent_client.AgentClient, 'install_bootloader', | |
1235 | autospec=True) | |
1236 | def test_configure_local_boot_on_software_raid_exception_bios( | |
1237 | self, install_bootloader_mock, try_set_boot_device_mock, | |
1238 | GlanceImageService_mock): | |
1239 | self.config(default_boot_mode='bios', group='deploy') | |
1107 | 1240 | GlanceImageService_mock.side_effect = Exception('Glance not found') |
1108 | 1241 | with task_manager.acquire(self.context, self.node['uuid'], |
1109 | 1242 | shared=False) as task: |
52 | 52 | boot_mode_utils.warn_about_default_boot_mode = False |
53 | 53 | mock_for_deploy.return_value = None |
54 | 54 | boot_mode = boot_mode_utils.get_boot_mode(self.node) |
55 | self.assertEqual(boot_modes.UEFI, boot_mode) | |
56 | boot_mode = boot_mode_utils.get_boot_mode(self.node) | |
57 | self.assertEqual(boot_modes.UEFI, boot_mode) | |
58 | self.assertEqual(0, mock_log.warning.call_count) | |
59 | ||
60 | @mock.patch.object(boot_mode_utils, 'LOG', autospec=True) | |
61 | @mock.patch.object(boot_mode_utils, 'get_boot_mode_for_deploy', | |
62 | autospec=True) | |
63 | def test_get_boot_mode_bios_default(self, mock_for_deploy, mock_log): | |
64 | self.config(default_boot_mode='bios', group='deploy') | |
65 | boot_mode_utils.warn_about_default_boot_mode = False | |
66 | mock_for_deploy.return_value = None | |
67 | boot_mode = boot_mode_utils.get_boot_mode(self.node) | |
55 | 68 | self.assertEqual(boot_modes.LEGACY_BIOS, boot_mode) |
56 | 69 | boot_mode = boot_mode_utils.get_boot_mode(self.node) |
57 | 70 | self.assertEqual(boot_modes.LEGACY_BIOS, boot_mode) |
58 | self.assertEqual(1, mock_log.warning.call_count) | |
71 | self.assertEqual(0, mock_log.warning.call_count) | |
59 | 72 | |
60 | 73 | @mock.patch.object(boot_mode_utils, 'LOG', autospec=True) |
61 | 74 | @mock.patch.object(boot_mode_utils, 'get_boot_mode_for_deploy', |
578 | 578 | self.config(pxe_bootfile_name_by_arch=self.bootfile_by_arch, |
579 | 579 | group='pxe') |
580 | 580 | result = utils.get_pxe_boot_file(self.node) |
581 | self.assertEqual('uefi-bootfile', result) | |
582 | ||
583 | def test_get_pxe_boot_file_emtpy_property_bios_default(self): | |
584 | self.config(default_boot_mode='bios', group='deploy') | |
585 | self.node.properties = {} | |
586 | self.config(pxe_bootfile_name_by_arch=self.bootfile_by_arch, | |
587 | group='pxe') | |
588 | result = utils.get_pxe_boot_file(self.node) | |
581 | 589 | self.assertEqual('bios-bootfile', result) |
582 | 590 | |
583 | def test_get_ipxe_boot_file(self): | |
591 | def test_get_ipxe_boot_uefi(self): | |
592 | self.config(uefi_ipxe_bootfile_name='meow', group='pxe') | |
593 | result = utils.get_ipxe_boot_file(self.node) | |
594 | self.assertEqual('meow', result) | |
595 | ||
596 | def test_get_ipxe_boot_bios(self): | |
597 | self.config(default_boot_mode='bios', group='deploy') | |
584 | 598 | self.config(ipxe_bootfile_name='meow', group='pxe') |
585 | 599 | result = utils.get_ipxe_boot_file(self.node) |
586 | 600 | self.assertEqual('meow', result) |
604 | 618 | def test_get_ipxe_boot_file_fallback(self): |
605 | 619 | self.config(ipxe_bootfile_name=None, group='pxe') |
606 | 620 | self.config(uefi_ipxe_bootfile_name=None, group='pxe') |
621 | self.config(pxe_bootfile_name=None, group='pxe') | |
622 | self.config(uefi_pxe_bootfile_name='lolcat', group='pxe') | |
623 | result = utils.get_ipxe_boot_file(self.node) | |
624 | self.assertEqual('lolcat', result) | |
625 | ||
626 | def test_get_ipxe_boot_file_fallback_bios(self): | |
627 | self.config(default_boot_mode='bios', group='deploy') | |
628 | self.config(ipxe_bootfile_name=None, group='pxe') | |
629 | self.config(uefi_ipxe_bootfile_name=None, group='pxe') | |
607 | 630 | self.config(pxe_bootfile_name='lolcat', group='pxe') |
608 | 631 | result = utils.get_ipxe_boot_file(self.node) |
609 | 632 | self.assertEqual('lolcat', result) |
610 | 633 | |
611 | 634 | def test_get_pxe_config_template_emtpy_property(self): |
635 | self.node.properties = {} | |
636 | self.config(pxe_config_template_by_arch=self.template_by_arch, | |
637 | group='pxe') | |
638 | result = utils.get_pxe_config_template(self.node) | |
639 | self.assertEqual('uefi-template', result) | |
640 | ||
641 | def test_get_pxe_config_template_emtpy_property_bios(self): | |
642 | self.config(default_boot_mode='bios', group='deploy') | |
612 | 643 | self.node.properties = {} |
613 | 644 | self.config(pxe_config_template_by_arch=self.template_by_arch, |
614 | 645 | group='pxe') |
630 | 661 | utils.get_ipxe_config_template(node)) |
631 | 662 | |
632 | 663 | def test_get_ipxe_config_template_none(self): |
664 | self.config(ipxe_config_template=None, group='pxe') | |
665 | self.config(uefi_pxe_config_template='magical_bootloader', | |
666 | group='pxe') | |
667 | node = obj_utils.create_test_node( | |
668 | self.context, driver='fake-hardware') | |
669 | self.assertEqual('magical_bootloader', | |
670 | utils.get_ipxe_config_template(node)) | |
671 | ||
672 | def test_get_ipxe_config_template_none_bios(self): | |
673 | self.config(default_boot_mode='bios', group='deploy') | |
633 | 674 | self.config(ipxe_config_template=None, group='pxe') |
634 | 675 | self.config(pxe_config_template='magical_bootloader', |
635 | 676 | group='pxe') |
1012 | 1053 | inst_info = {'capabilities': {'cat': 'meows'}} |
1013 | 1054 | self.node.instance_info = inst_info |
1014 | 1055 | result = utils.get_disk_label(self.node) |
1056 | self.assertEqual('gpt', result) | |
1057 | ||
1058 | def test_get_disk_label_nothing_set_bios_mode(self): | |
1059 | self.config(default_boot_mode='bios', group='deploy') | |
1060 | inst_info = {'capabilities': {'cat': 'meows'}} | |
1061 | self.node.instance_info = inst_info | |
1062 | result = utils.get_disk_label(self.node) | |
1015 | 1063 | self.assertIsNone(result) |
1016 | 1064 | |
1017 | 1065 | def test_get_disk_label_uefi_mode(self): |
1057 | 1105 | @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True) |
1058 | 1106 | def test_try_set_boot_device_ipmifailure_bios( |
1059 | 1107 | self, node_set_boot_device_mock): |
1108 | self.config(default_boot_mode='bios', group='deploy') | |
1060 | 1109 | node_set_boot_device_mock.side_effect = exception.IPMIFailure(cmd='a') |
1061 | 1110 | with task_manager.acquire(self.context, self.node.uuid, |
1062 | 1111 | shared=False) as task: |
508 | 508 | @mock.patch.object(images, 'create_boot_iso', autospec=True) |
509 | 509 | def test__prepare_iso_image_bios( |
510 | 510 | self, mock_create_boot_iso, mock_publish_image): |
511 | self.config(default_boot_mode='bios', group='deploy') | |
511 | 512 | with task_manager.acquire(self.context, self.node.uuid, |
512 | 513 | shared=True) as task: |
513 | 514 | |
550 | 551 | |
551 | 552 | mock_create_boot_iso.assert_called_once_with( |
552 | 553 | mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img', |
553 | boot_mode='bios', esp_image_href=None, | |
554 | boot_mode='uefi', esp_image_href=None, | |
554 | 555 | kernel_params=kernel_params, |
555 | 556 | root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123', |
556 | 557 | inject_files=None) |
560 | 561 | @mock.patch.object(images, 'create_boot_iso', autospec=True) |
561 | 562 | def test__prepare_iso_image_kernel_params_driver_info( |
562 | 563 | self, mock_create_boot_iso, mock_publish_image): |
564 | with task_manager.acquire(self.context, self.node.uuid, | |
565 | shared=True) as task: | |
566 | kernel_params = 'network-config=base64-cloudinit-blob' | |
567 | ||
568 | task.node.driver_info['kernel_append_params'] = kernel_params | |
569 | ||
570 | image_utils._prepare_iso_image( | |
571 | task, 'http://kernel/img', 'http://ramdisk/img', | |
572 | bootloader_href=None, root_uuid=task.node.uuid) | |
573 | ||
574 | mock_create_boot_iso.assert_called_once_with( | |
575 | mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img', | |
576 | boot_mode='uefi', esp_image_href=None, | |
577 | kernel_params=kernel_params, | |
578 | root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123', | |
579 | inject_files=None) | |
580 | ||
581 | @mock.patch.object(image_utils.ImageHandler, 'publish_image', | |
582 | autospec=True) | |
583 | @mock.patch.object(images, 'create_boot_iso', autospec=True) | |
584 | def test__prepare_iso_image_kernel_params_driver_info_bios( | |
585 | self, mock_create_boot_iso, mock_publish_image): | |
586 | self.config(default_boot_mode='bios', group='deploy') | |
563 | 587 | with task_manager.acquire(self.context, self.node.uuid, |
564 | 588 | shared=True) as task: |
565 | 589 | kernel_params = 'network-config=base64-cloudinit-blob' |
581 | 605 | @mock.patch.object(image_utils.ImageHandler, 'publish_image', |
582 | 606 | autospec=True) |
583 | 607 | @mock.patch.object(images, 'create_boot_iso', autospec=True) |
584 | def test__prepare_iso_image_kernel_params_for_ramdisk( | |
608 | def test__prepare_iso_image_kernel_params_for_ramdisk_uefi( | |
585 | 609 | self, mock_create_boot_iso, mock_publish_image): |
610 | with task_manager.acquire(self.context, self.node.uuid, | |
611 | shared=True) as task: | |
612 | kernel_params = 'network-config=base64-cloudinit-blob' | |
613 | ||
614 | task.node.instance_info['ramdisk_kernel_arguments'] = kernel_params | |
615 | ||
616 | image_utils._prepare_iso_image( | |
617 | task, 'http://kernel/img', 'http://ramdisk/img', | |
618 | bootloader_href=None, root_uuid=task.node.uuid) | |
619 | ||
620 | mock_create_boot_iso.assert_called_once_with( | |
621 | mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img', | |
622 | boot_mode='uefi', esp_image_href=None, | |
623 | kernel_params="root=/dev/ram0 text " + kernel_params, | |
624 | root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123', | |
625 | inject_files=None) | |
626 | ||
627 | @mock.patch.object(deploy_utils, 'get_boot_option', lambda node: 'ramdisk') | |
628 | @mock.patch.object(image_utils.ImageHandler, 'publish_image', | |
629 | autospec=True) | |
630 | @mock.patch.object(images, 'create_boot_iso', autospec=True) | |
631 | def test__prepare_iso_image_kernel_params_for_ramdisk_bios( | |
632 | self, mock_create_boot_iso, mock_publish_image): | |
633 | self.config(default_boot_mode='bios', group='deploy') | |
586 | 634 | with task_manager.acquire(self.context, self.node.uuid, |
587 | 635 | shared=True) as task: |
588 | 636 | kernel_params = 'network-config=base64-cloudinit-blob' |
619 | 667 | |
620 | 668 | mock_create_boot_iso.assert_called_once_with( |
621 | 669 | mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img', |
622 | boot_mode='bios', esp_image_href=None, | |
670 | boot_mode='uefi', esp_image_href=None, | |
623 | 671 | kernel_params=kernel_params, |
624 | 672 | root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123', |
625 | 673 | inject_files=None) |
642 | 690 | |
643 | 691 | mock_create_boot_iso.assert_called_once_with( |
644 | 692 | mock.ANY, mock.ANY, 'http://kernel/img', 'http://ramdisk/img', |
645 | boot_mode='bios', esp_image_href=None, | |
693 | boot_mode='uefi', esp_image_href=None, | |
646 | 694 | kernel_params=kernel_params + ' foo=bar banana', |
647 | 695 | root_uuid='1be26c0b-03f2-4d2e-ae87-c02d7f33c123', |
648 | 696 | inject_files=None) |
2445 | 2445 | self.assertEqual({}, driver_routes) |
2446 | 2446 | |
2447 | 2447 | @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True) |
2448 | def test_management_interface_set_boot_device_ok(self, mock_exec): | |
2448 | def test_management_interface_set_boot_device_ok_bios(self, mock_exec): | |
2449 | 2449 | mock_exec.return_value = [None, None] |
2450 | ||
2450 | self.config(default_boot_mode='bios', group='deploy') | |
2451 | 2451 | with task_manager.acquire(self.context, self.node.uuid) as task: |
2452 | 2452 | self.management.set_boot_device(task, boot_devices.PXE) |
2453 | 2453 | |
2457 | 2457 | |
2458 | 2458 | @mock.patch.object(driver_utils, 'force_persistent_boot', autospec=True) |
2459 | 2459 | @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True) |
2460 | def test_management_interface_no_force_set_boot_device(self, | |
2461 | mock_exec, | |
2462 | mock_force_boot): | |
2460 | def test_management_interface_no_force_set_boot_device_bios( | |
2461 | self, mock_exec, mock_force_boot): | |
2463 | 2462 | mock_exec.return_value = [None, None] |
2463 | self.config(default_boot_mode='bios', group='deploy') | |
2464 | 2464 | |
2465 | 2465 | with task_manager.acquire(self.context, self.node.uuid) as task: |
2466 | 2466 | driver_info = task.node.driver_info |
2475 | 2475 | self.assertFalse(mock_force_boot.called) |
2476 | 2476 | |
2477 | 2477 | @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True) |
2478 | def test_management_interface_force_set_boot_device_ok(self, mock_exec): | |
2478 | def test_management_interface_force_set_boot_device_ok_bios(self, | |
2479 | mock_exec): | |
2479 | 2480 | mock_exec.return_value = [None, None] |
2481 | self.config(default_boot_mode='bios', group='deploy') | |
2480 | 2482 | |
2481 | 2483 | with task_manager.acquire(self.context, self.node.uuid) as task: |
2482 | 2484 | driver_info = task.node.driver_info |
2495 | 2497 | mock_exec.assert_has_calls(mock_calls) |
2496 | 2498 | |
2497 | 2499 | @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True) |
2498 | def test_management_interface_set_boot_device_persistent(self, mock_exec): | |
2500 | def test_management_interface_set_boot_device_persistent_bios(self, | |
2501 | mock_exec): | |
2499 | 2502 | mock_exec.return_value = [None, None] |
2503 | self.config(default_boot_mode='bios', group='deploy') | |
2500 | 2504 | |
2501 | 2505 | with task_manager.acquire(self.context, self.node.uuid) as task: |
2502 | 2506 | driver_info = task.node.driver_info |
2519 | 2523 | task, 'fake-device') |
2520 | 2524 | |
2521 | 2525 | @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True) |
2522 | def test_management_interface_set_boot_device_without_timeout_1(self, | |
2523 | mock_exec): | |
2526 | def test_management_interface_set_boot_device_without_timeout_1_uefi( | |
2527 | self, mock_exec): | |
2524 | 2528 | mock_exec.return_value = [None, None] |
2525 | ||
2526 | 2529 | with task_manager.acquire(self.context, self.node.uuid) as task: |
2527 | 2530 | driver_info = task.node.driver_info |
2528 | 2531 | driver_info['ipmi_disable_boot_timeout'] = 'False' |
2529 | 2532 | task.node.driver_info = driver_info |
2530 | 2533 | self.management.set_boot_device(task, boot_devices.PXE) |
2531 | 2534 | |
2535 | mock_calls = [mock.call(self.info, "raw 0x00 0x08 0x05 0xa0 0x04 " | |
2536 | "0x00 0x00 0x00")] | |
2537 | mock_exec.assert_has_calls(mock_calls) | |
2538 | ||
2539 | @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True) | |
2540 | def test_management_interface_set_boot_device_without_timeout_1_bios( | |
2541 | self, mock_exec): | |
2542 | mock_exec.return_value = [None, None] | |
2543 | self.config(default_boot_mode='bios', group='deploy') | |
2544 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
2545 | driver_info = task.node.driver_info | |
2546 | driver_info['ipmi_disable_boot_timeout'] = 'False' | |
2547 | task.node.driver_info = driver_info | |
2548 | self.management.set_boot_device(task, boot_devices.PXE) | |
2549 | ||
2532 | 2550 | mock_calls = [mock.call(self.info, "chassis bootdev pxe")] |
2533 | 2551 | mock_exec.assert_has_calls(mock_calls) |
2534 | 2552 | |
2535 | 2553 | @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True) |
2536 | def test_management_interface_set_boot_device_without_timeout_2(self, | |
2537 | mock_exec): | |
2554 | def test_management_interface_set_boot_device_without_timeout_2_uefi( | |
2555 | self, mock_exec): | |
2538 | 2556 | CONF.set_override('disable_boot_timeout', False, 'ipmi') |
2557 | mock_exec.return_value = [None, None] | |
2558 | ||
2559 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
2560 | self.management.set_boot_device(task, boot_devices.PXE) | |
2561 | ||
2562 | mock_calls = [mock.call(self.info, "raw 0x00 0x08 0x05 0xa0 0x04 " | |
2563 | "0x00 0x00 0x00")] | |
2564 | mock_exec.assert_has_calls(mock_calls) | |
2565 | ||
2566 | @mock.patch.object(ipmi, '_exec_ipmitool', autospec=True) | |
2567 | def test_management_interface_set_boot_device_without_timeout_2_bios( | |
2568 | self, mock_exec): | |
2569 | CONF.set_override('disable_boot_timeout', False, 'ipmi') | |
2570 | self.config(default_boot_mode='bios', group='deploy') | |
2539 | 2571 | mock_exec.return_value = [None, None] |
2540 | 2572 | |
2541 | 2573 | with task_manager.acquire(self.context, self.node.uuid) as task: |
605 | 605 | task, ipxe_enabled=True, ip_version=6) |
606 | 606 | pxe_config_path = pxe_utils.get_pxe_config_file_path( |
607 | 607 | task.node.uuid, ipxe_enabled=True) |
608 | task.node.properties['capabilities'] = 'boot_mode:uefi' | |
609 | task.node.instance_info['capabilities'] = instance_info | |
610 | task.node.driver_internal_info['root_uuid_or_disk_id'] = ( | |
611 | "30212642-09d3-467f-8e09-21685826ab50") | |
612 | task.node.driver_internal_info['is_whole_disk_image'] = False | |
613 | ||
614 | task.driver.boot.prepare_instance(task) | |
615 | ||
616 | get_image_info_mock.assert_called_once_with( | |
617 | task, ipxe_enabled=True) | |
618 | cache_mock.assert_called_once_with(task, image_info, | |
619 | ipxe_enabled=True) | |
620 | provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts) | |
621 | switch_pxe_config_mock.assert_called_once_with( | |
622 | pxe_config_path, "30212642-09d3-467f-8e09-21685826ab50", | |
623 | 'uefi', False, False, False, False, ipxe_enabled=True, | |
624 | anaconda_boot=False) | |
625 | set_boot_device_mock.assert_called_once_with(task, | |
626 | boot_devices.PXE, | |
627 | persistent=True) | |
628 | ||
629 | @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True) | |
630 | @mock.patch.object(deploy_utils, 'switch_pxe_config', autospec=True) | |
631 | @mock.patch.object(dhcp_factory, 'DHCPFactory', autospec=True) | |
632 | @mock.patch.object(pxe_utils, 'cache_ramdisk_kernel', autospec=True) | |
633 | @mock.patch.object(pxe_utils, 'get_instance_image_info', autospec=True) | |
634 | def test_prepare_instance_netboot_bios( | |
635 | self, get_image_info_mock, cache_mock, | |
636 | dhcp_factory_mock, switch_pxe_config_mock, | |
637 | set_boot_device_mock): | |
638 | provider_mock = mock.MagicMock() | |
639 | dhcp_factory_mock.return_value = provider_mock | |
640 | image_info = {'kernel': ('', '/path/to/kernel'), | |
641 | 'ramdisk': ('', '/path/to/ramdisk')} | |
642 | instance_info = {"boot_option": "netboot", | |
643 | "boot_mode": "bios"} | |
644 | get_image_info_mock.return_value = image_info | |
645 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
608 | 646 | task.node.properties['capabilities'] = 'boot_mode:bios' |
609 | 647 | task.node.instance_info['capabilities'] = instance_info |
610 | 648 | task.node.driver_internal_info['root_uuid_or_disk_id'] = ( |
611 | 649 | "30212642-09d3-467f-8e09-21685826ab50") |
612 | 650 | task.node.driver_internal_info['is_whole_disk_image'] = False |
651 | ||
652 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
653 | task, ipxe_enabled=True) | |
654 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
655 | task, ipxe_enabled=True, ip_version=6) | |
656 | pxe_config_path = pxe_utils.get_pxe_config_file_path( | |
657 | task.node.uuid, ipxe_enabled=True) | |
613 | 658 | |
614 | 659 | task.driver.boot.prepare_instance(task) |
615 | 660 | |
640 | 685 | dhcp_factory_mock.return_value = provider_mock |
641 | 686 | image_info = {'kernel': ('', '/path/to/kernel'), |
642 | 687 | 'ramdisk': ('', '/path/to/ramdisk')} |
643 | i_info_caps = {"boot_option": "ramdisk"} | |
688 | i_info_caps = {"boot_option": "ramdisk", | |
689 | "boot_mode": "bios"} | |
644 | 690 | kernel_arg = "meow" |
645 | 691 | get_image_info_mock.return_value = image_info |
646 | 692 | |
647 | 693 | with task_manager.acquire(self.context, self.node.uuid) as task: |
648 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
649 | task, ipxe_enabled=True) | |
650 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
651 | task, ipxe_enabled=True, ip_version=6) | |
652 | pxe_config_path = pxe_utils.get_pxe_config_file_path( | |
653 | task.node.uuid, ipxe_enabled=True) | |
654 | 694 | task.node.properties['capabilities'] = 'boot_mode:bios' |
655 | 695 | i_info = task.node.instance_info |
656 | 696 | i_info['capabilities'] = i_info_caps |
657 | 697 | i_info['kernel_append_params'] = kernel_arg |
658 | 698 | task.node.instance_info = i_info |
659 | 699 | task.node.save() |
700 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
701 | task, ipxe_enabled=True) | |
702 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
703 | task, ipxe_enabled=True, ip_version=6) | |
704 | pxe_config_path = pxe_utils.get_pxe_config_file_path( | |
705 | task.node.uuid, ipxe_enabled=True) | |
706 | ||
660 | 707 | task.driver.boot.prepare_instance(task) |
661 | 708 | get_image_info_mock.assert_called_once_with( |
662 | 709 | task, ipxe_enabled=True) |
680 | 727 | mock_create_pxe_config.assert_called_once_with( |
681 | 728 | task, expected_params, mock.ANY, ipxe_enabled=True) |
682 | 729 | |
730 | @mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True) | |
731 | @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True) | |
732 | @mock.patch.object(deploy_utils, 'switch_pxe_config', autospec=True) | |
733 | @mock.patch.object(dhcp_factory, 'DHCPFactory', autospec=True) | |
734 | @mock.patch.object(pxe_utils, 'cache_ramdisk_kernel', autospec=True) | |
735 | @mock.patch.object(pxe_utils, 'get_instance_image_info', autospec=True) | |
736 | def test_prepare_instance_ramdisk_bios( | |
737 | self, get_image_info_mock, cache_mock, | |
738 | dhcp_factory_mock, switch_pxe_config_mock, | |
739 | set_boot_device_mock, mock_create_pxe_config): | |
740 | provider_mock = mock.MagicMock() | |
741 | dhcp_factory_mock.return_value = provider_mock | |
742 | image_info = {'kernel': ('', '/path/to/kernel'), | |
743 | 'ramdisk': ('', '/path/to/ramdisk')} | |
744 | i_info_caps = {"boot_option": "ramdisk"} | |
745 | kernel_arg = "meow" | |
746 | get_image_info_mock.return_value = image_info | |
747 | ||
748 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
749 | i_info = task.node.instance_info | |
750 | i_info['capabilities'] = i_info_caps | |
751 | i_info['kernel_append_params'] = kernel_arg | |
752 | task.node.instance_info = i_info | |
753 | task.node.save() | |
754 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
755 | task, ipxe_enabled=True) | |
756 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
757 | task, ipxe_enabled=True, ip_version=6) | |
758 | pxe_config_path = pxe_utils.get_pxe_config_file_path( | |
759 | task.node.uuid, ipxe_enabled=True) | |
760 | ||
761 | task.driver.boot.prepare_instance(task) | |
762 | get_image_info_mock.assert_called_once_with( | |
763 | task, ipxe_enabled=True) | |
764 | cache_mock.assert_called_once_with(task, image_info, | |
765 | ipxe_enabled=True) | |
766 | provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts) | |
767 | switch_pxe_config_mock.assert_called_once_with( | |
768 | pxe_config_path, None, | |
769 | 'uefi', False, iscsi_boot=False, ramdisk_boot=True, | |
770 | ipxe_enabled=True, anaconda_boot=False) | |
771 | set_boot_device_mock.assert_called_once_with(task, | |
772 | boot_devices.PXE, | |
773 | persistent=True) | |
774 | expected_params = { | |
775 | 'aki_path': 'http://myserver/' + task.node.uuid + '/kernel', | |
776 | 'ari_path': 'http://myserver/' + task.node.uuid + '/ramdisk', | |
777 | 'pxe_append_params': 'meow ipa-debug=1 ipa-global-request-id' | |
778 | '=' + task.context.request_id, | |
779 | 'tftp_server': mock.ANY, | |
780 | 'ipxe_timeout': 0} | |
781 | mock_create_pxe_config.assert_called_once_with( | |
782 | task, expected_params, mock.ANY, ipxe_enabled=True) | |
783 | ||
683 | 784 | @mock.patch('os.path.isfile', return_value=False, autospec=True) |
684 | 785 | @mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True) |
685 | 786 | @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True) |
700 | 801 | self.node.provision_state = states.ACTIVE |
701 | 802 | self.node.save() |
702 | 803 | with task_manager.acquire(self.context, self.node.uuid) as task: |
703 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
704 | task, ipxe_enabled=True) | |
705 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
706 | task, ipxe_enabled=True, ip_version=6) | |
707 | pxe_config_path = pxe_utils.get_pxe_config_file_path( | |
708 | task.node.uuid, ipxe_enabled=True) | |
709 | 804 | task.node.properties['capabilities'] = 'boot_mode:bios' |
710 | 805 | task.node.instance_info['capabilities'] = instance_info |
711 | 806 | task.node.driver_internal_info['root_uuid_or_disk_id'] = ( |
712 | 807 | "30212642-09d3-467f-8e09-21685826ab50") |
713 | 808 | task.node.driver_internal_info['is_whole_disk_image'] = False |
809 | ||
810 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
811 | task, ipxe_enabled=True) | |
812 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
813 | task, ipxe_enabled=True, ip_version=6) | |
814 | pxe_config_path = pxe_utils.get_pxe_config_file_path( | |
815 | task.node.uuid, ipxe_enabled=True) | |
714 | 816 | |
715 | 817 | task.driver.boot.prepare_instance(task) |
716 | 818 | |
744 | 846 | get_image_info_mock.return_value = image_info |
745 | 847 | instance_info = {"boot_option": "netboot"} |
746 | 848 | with task_manager.acquire(self.context, self.node.uuid) as task: |
849 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
850 | task.node.instance_info['capabilities'] = instance_info | |
851 | task.node.driver_internal_info['is_whole_disk_image'] = False | |
747 | 852 | dhcp_opts = pxe_utils.dhcp_options_for_instance( |
748 | 853 | task, ipxe_enabled=True, ip_version=4) |
749 | 854 | dhcp_opts += pxe_utils.dhcp_options_for_instance( |
750 | 855 | task, ipxe_enabled=True, ip_version=6) |
751 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
752 | task.node.instance_info['capabilities'] = instance_info | |
856 | ||
857 | task.driver.boot.prepare_instance(task) | |
858 | ||
859 | get_image_info_mock.assert_called_once_with( | |
860 | task, ipxe_enabled=True) | |
861 | cache_mock.assert_called_once_with(task, image_info, | |
862 | ipxe_enabled=True) | |
863 | provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts) | |
864 | self.assertFalse(switch_pxe_config_mock.called) | |
865 | self.assertFalse(set_boot_device_mock.called) | |
866 | ||
867 | @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True) | |
868 | @mock.patch.object(deploy_utils, 'switch_pxe_config', autospec=True) | |
869 | @mock.patch.object(dhcp_factory, 'DHCPFactory', autospec=True) | |
870 | @mock.patch.object(pxe_utils, 'cache_ramdisk_kernel', autospec=True) | |
871 | @mock.patch.object(pxe_utils, 'get_instance_image_info', autospec=True) | |
872 | def test_prepare_instance_netboot_missing_root_uuid_default( | |
873 | self, get_image_info_mock, cache_mock, | |
874 | dhcp_factory_mock, switch_pxe_config_mock, | |
875 | set_boot_device_mock): | |
876 | provider_mock = mock.MagicMock() | |
877 | dhcp_factory_mock.return_value = provider_mock | |
878 | image_info = {'kernel': ('', '/path/to/kernel'), | |
879 | 'ramdisk': ('', '/path/to/ramdisk')} | |
880 | get_image_info_mock.return_value = image_info | |
881 | instance_info = self.node.instance_info | |
882 | instance_info['capabilities'] = {"boot_option": "netboot"} | |
883 | self.node.instance_info = instance_info | |
884 | self.node.save() | |
885 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
753 | 886 | task.node.driver_internal_info['is_whole_disk_image'] = False |
887 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
888 | task, ipxe_enabled=True, ip_version=4) | |
889 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
890 | task, ipxe_enabled=True, ip_version=6) | |
754 | 891 | |
755 | 892 | task.driver.boot.prepare_instance(task) |
756 | 893 | |
777 | 914 | provider_mock = mock.MagicMock() |
778 | 915 | dhcp_factory_mock.return_value = provider_mock |
779 | 916 | get_image_info_mock.return_value = {} |
780 | instance_info = {"boot_option": "netboot"} | |
781 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
782 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
783 | task, ipxe_enabled=True) | |
784 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
785 | task, ipxe_enabled=True, ip_version=6) | |
917 | instance_info = {"boot_option": "netboot", | |
918 | "boot_mode": "bios"} | |
919 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
786 | 920 | task.node.properties['capabilities'] = 'boot_mode:bios' |
787 | 921 | task.node.instance_info['capabilities'] = instance_info |
788 | 922 | task.node.driver_internal_info['is_whole_disk_image'] = True |
923 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
924 | task, ipxe_enabled=True) | |
925 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
926 | task, ipxe_enabled=True, ip_version=6) | |
927 | ||
789 | 928 | task.driver.boot.prepare_instance(task) |
790 | 929 | get_image_info_mock.assert_called_once_with( |
791 | 930 | task, ipxe_enabled=True) |
795 | 934 | clean_up_pxe_mock.assert_called_once_with(task, ipxe_enabled=True) |
796 | 935 | set_boot_device_mock.assert_called_once_with( |
797 | 936 | task, boot_devices.DISK, persistent=True) |
937 | ||
938 | @mock.patch('os.path.isfile', lambda filename: False) | |
939 | @mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True) | |
940 | @mock.patch.object(deploy_utils, 'is_iscsi_boot', lambda task: True) | |
941 | @mock.patch.object(noop_storage.NoopStorage, 'should_write_image', | |
942 | lambda task: False) | |
943 | @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True) | |
944 | @mock.patch.object(deploy_utils, 'switch_pxe_config', autospec=True) | |
945 | @mock.patch.object(dhcp_factory, 'DHCPFactory', autospec=True) | |
946 | @mock.patch.object(pxe_utils, 'cache_ramdisk_kernel', autospec=True) | |
947 | @mock.patch.object(pxe_utils, 'get_instance_image_info', autospec=True) | |
948 | def test_prepare_instance_netboot_iscsi_bios( | |
949 | self, get_image_info_mock, cache_mock, | |
950 | dhcp_factory_mock, switch_pxe_config_mock, | |
951 | set_boot_device_mock, create_pxe_config_mock): | |
952 | http_url = 'http://192.1.2.3:1234' | |
953 | self.config(http_url=http_url, group='deploy') | |
954 | provider_mock = mock.MagicMock() | |
955 | dhcp_factory_mock.return_value = provider_mock | |
956 | vol_id = uuidutils.generate_uuid() | |
957 | obj_utils.create_test_volume_target( | |
958 | self.context, node_id=self.node.id, volume_type='iscsi', | |
959 | boot_index=0, volume_id='1234', uuid=vol_id, | |
960 | properties={'target_lun': 0, | |
961 | 'target_portal': 'fake_host:3260', | |
962 | 'target_iqn': 'fake_iqn', | |
963 | 'auth_username': 'fake_username', | |
964 | 'auth_password': 'fake_password'}) | |
965 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
966 | task.node.driver_internal_info = { | |
967 | 'boot_from_volume': vol_id} | |
968 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
969 | task.node.instance_info['capabilities'] = {'boot_mode': 'bios'} | |
970 | dhcp_opts = pxe_utils.dhcp_options_for_instance(task, | |
971 | ipxe_enabled=True) | |
972 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
973 | task, ipxe_enabled=True, ip_version=6) | |
974 | pxe_config_path = pxe_utils.get_pxe_config_file_path( | |
975 | task.node.uuid, ipxe_enabled=True) | |
976 | ||
977 | task.driver.boot.prepare_instance(task) | |
978 | self.assertFalse(get_image_info_mock.called) | |
979 | self.assertFalse(cache_mock.called) | |
980 | provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts) | |
981 | create_pxe_config_mock.assert_called_once_with( | |
982 | task, mock.ANY, CONF.pxe.ipxe_config_template, | |
983 | ipxe_enabled=True) | |
984 | switch_pxe_config_mock.assert_called_once_with( | |
985 | pxe_config_path, None, boot_modes.LEGACY_BIOS, False, | |
986 | ipxe_enabled=True, iscsi_boot=True, ramdisk_boot=False, | |
987 | anaconda_boot=False) | |
988 | set_boot_device_mock.assert_called_once_with(task, | |
989 | boot_devices.PXE, | |
990 | persistent=True) | |
798 | 991 | |
799 | 992 | @mock.patch('os.path.isfile', lambda filename: False) |
800 | 993 | @mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True) |
823 | 1016 | 'target_iqn': 'fake_iqn', |
824 | 1017 | 'auth_username': 'fake_username', |
825 | 1018 | 'auth_password': 'fake_password'}) |
1019 | ||
826 | 1020 | with task_manager.acquire(self.context, self.node.uuid) as task: |
827 | 1021 | task.node.driver_internal_info = { |
828 | 1022 | 'boot_from_volume': vol_id} |
832 | 1026 | task, ipxe_enabled=True, ip_version=6) |
833 | 1027 | pxe_config_path = pxe_utils.get_pxe_config_file_path( |
834 | 1028 | task.node.uuid, ipxe_enabled=True) |
835 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
1029 | ||
836 | 1030 | task.driver.boot.prepare_instance(task) |
837 | 1031 | self.assertFalse(get_image_info_mock.called) |
838 | 1032 | self.assertFalse(cache_mock.called) |
841 | 1035 | task, mock.ANY, CONF.pxe.ipxe_config_template, |
842 | 1036 | ipxe_enabled=True) |
843 | 1037 | switch_pxe_config_mock.assert_called_once_with( |
844 | pxe_config_path, None, boot_modes.LEGACY_BIOS, False, | |
1038 | pxe_config_path, None, boot_modes.UEFI, False, | |
845 | 1039 | ipxe_enabled=True, iscsi_boot=True, ramdisk_boot=False, |
846 | 1040 | anaconda_boot=False) |
847 | 1041 | set_boot_device_mock.assert_called_once_with(task, |
873 | 1067 | self.node.provision_state = states.DEPLOYING |
874 | 1068 | self.node.save() |
875 | 1069 | with task_manager.acquire(self.context, self.node.uuid) as task: |
876 | print(task.node) | |
877 | 1070 | dhcp_opts = pxe_utils.dhcp_options_for_instance(task, |
878 | 1071 | ipxe_enabled=True) |
879 | 1072 | dhcp_opts += pxe_utils.dhcp_options_for_instance( |
888 | 1081 | task, mock.ANY, CONF.pxe.ipxe_config_template, |
889 | 1082 | ipxe_enabled=True) |
890 | 1083 | switch_pxe_config_mock.assert_called_once_with( |
891 | pxe_config_path, None, boot_modes.LEGACY_BIOS, False, | |
1084 | pxe_config_path, None, boot_modes.UEFI, False, | |
892 | 1085 | ipxe_enabled=True, iscsi_boot=False, ramdisk_boot=True, |
893 | 1086 | anaconda_boot=False) |
894 | 1087 | set_boot_device_mock.assert_called_once_with(task, |
958 | 1151 | persistent=True) |
959 | 1152 | switch_pxe_config_mock.assert_called_once_with( |
960 | 1153 | pxe_config_path, "30212642-09d3-467f-8e09-21685826ab50", |
961 | 'bios', True, False, False, False, ipxe_enabled=True, | |
1154 | 'uefi', True, False, False, False, ipxe_enabled=True, | |
962 | 1155 | anaconda_boot=False) |
963 | 1156 | # No clean up |
964 | 1157 | self.assertFalse(clean_up_pxe_config_mock.called) |
270 | 270 | dhcp_factory_mock, |
271 | 271 | set_boot_device_mock, |
272 | 272 | get_boot_mode_mock, |
273 | uefi=False, | |
273 | uefi=True, | |
274 | 274 | cleaning=False, |
275 | 275 | ipxe_use_swift=False, |
276 | 276 | whole_disk_image=False, |
294 | 294 | driver_internal_info = self.node.driver_internal_info |
295 | 295 | driver_internal_info['is_whole_disk_image'] = whole_disk_image |
296 | 296 | self.node.driver_internal_info = driver_internal_info |
297 | ||
297 | 298 | if mode == 'rescue': |
298 | 299 | mock_deploy_img_info.return_value = { |
299 | 300 | 'rescue_kernel': 'a', |
355 | 356 | self.node.save() |
356 | 357 | self._test_prepare_ramdisk() |
357 | 358 | |
359 | def test_prepare_ramdisk_bios(self): | |
360 | self.node.provision_state = states.DEPLOYING | |
361 | self.node.save() | |
362 | self._test_prepare_ramdisk(uefi=True) | |
363 | ||
358 | 364 | def test_prepare_ramdisk_rescue(self): |
359 | 365 | self.node.provision_state = states.RESCUING |
360 | 366 | self.node.save() |
361 | 367 | self._test_prepare_ramdisk(mode='rescue') |
368 | ||
369 | def test_prepare_ramdisk_rescue_bios(self): | |
370 | self.node.provision_state = states.RESCUING | |
371 | self.node.save() | |
372 | self._test_prepare_ramdisk(mode='rescue', uefi=True) | |
362 | 373 | |
363 | 374 | def test_prepare_ramdisk_uefi(self): |
364 | 375 | self.node.provision_state = states.DEPLOYING |
390 | 401 | self, set_boot_mode_mock): |
391 | 402 | self.node.provision_state = states.DEPLOYING |
392 | 403 | self.node.save() |
393 | self._test_prepare_ramdisk(node_boot_mode=boot_modes.LEGACY_BIOS) | |
404 | self._test_prepare_ramdisk(node_boot_mode=boot_modes.LEGACY_BIOS, | |
405 | uefi=False) | |
394 | 406 | |
395 | 407 | with task_manager.acquire(self.context, self.node.uuid) as task: |
396 | 408 | driver_internal_info = task.node.driver_internal_info |
407 | 419 | |
408 | 420 | self.config(default_boot_mode=boot_modes.LEGACY_BIOS, group='deploy') |
409 | 421 | |
410 | self._test_prepare_ramdisk() | |
411 | ||
422 | self._test_prepare_ramdisk(uefi=False) | |
412 | 423 | with task_manager.acquire(self.context, self.node.uuid) as task: |
413 | 424 | driver_internal_info = task.node.driver_internal_info |
414 | 425 | self.assertIn('deploy_boot_mode', driver_internal_info) |
469 | 480 | properties['capabilities'] = 'boot_mode:uefi' |
470 | 481 | self.node.properties = properties |
471 | 482 | self.node.save() |
472 | self._test_prepare_ramdisk(uefi=True, node_boot_mode=boot_modes.UEFI) | |
483 | self._test_prepare_ramdisk(node_boot_mode=boot_modes.UEFI) | |
473 | 484 | self.assertEqual(set_boot_mode_mock.call_count, 0) |
474 | 485 | |
475 | 486 | @mock.patch.object(pxe_utils, 'clean_up_pxe_env', autospec=True) |
503 | 514 | @mock.patch.object(dhcp_factory, 'DHCPFactory', autospec=True) |
504 | 515 | @mock.patch.object(pxe_utils, 'cache_ramdisk_kernel', autospec=True) |
505 | 516 | @mock.patch.object(pxe_utils, 'get_instance_image_info', autospec=True) |
506 | def test_prepare_instance_netboot( | |
517 | def test_prepare_instance_netboot_bios( | |
507 | 518 | self, get_image_info_mock, cache_mock, |
508 | 519 | dhcp_factory_mock, switch_pxe_config_mock, |
509 | 520 | set_boot_device_mock): |
513 | 524 | 'ramdisk': ('', '/path/to/ramdisk')} |
514 | 525 | get_image_info_mock.return_value = image_info |
515 | 526 | with task_manager.acquire(self.context, self.node.uuid) as task: |
527 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
528 | task.node.driver_internal_info['root_uuid_or_disk_id'] = ( | |
529 | "30212642-09d3-467f-8e09-21685826ab50") | |
530 | task.node.driver_internal_info['is_whole_disk_image'] = False | |
531 | task.node.instance_info = { | |
532 | 'capabilities': {'boot_option': 'netboot', | |
533 | 'boot_mode': 'bios'}} | |
516 | 534 | dhcp_opts = pxe_utils.dhcp_options_for_instance( |
517 | 535 | task, ipxe_enabled=False, ip_version=4) |
518 | 536 | dhcp_opts += pxe_utils.dhcp_options_for_instance( |
519 | 537 | task, ipxe_enabled=False, ip_version=6) |
520 | 538 | pxe_config_path = pxe_utils.get_pxe_config_file_path( |
521 | 539 | task.node.uuid) |
522 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
523 | task.node.driver_internal_info['root_uuid_or_disk_id'] = ( | |
524 | "30212642-09d3-467f-8e09-21685826ab50") | |
525 | task.node.driver_internal_info['is_whole_disk_image'] = False | |
526 | task.node.instance_info = { | |
527 | 'capabilities': {'boot_option': 'netboot'}} | |
528 | 540 | task.driver.boot.prepare_instance(task) |
529 | 541 | |
530 | 542 | get_image_info_mock.assert_called_once_with( |
535 | 547 | switch_pxe_config_mock.assert_called_once_with( |
536 | 548 | pxe_config_path, "30212642-09d3-467f-8e09-21685826ab50", |
537 | 549 | 'bios', False, False, False, False, ipxe_enabled=False, |
550 | anaconda_boot=False) | |
551 | set_boot_device_mock.assert_called_once_with(task, | |
552 | boot_devices.PXE, | |
553 | persistent=True) | |
554 | ||
555 | @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True) | |
556 | @mock.patch.object(deploy_utils, 'switch_pxe_config', autospec=True) | |
557 | @mock.patch.object(dhcp_factory, 'DHCPFactory', autospec=True) | |
558 | @mock.patch.object(pxe_utils, 'cache_ramdisk_kernel', autospec=True) | |
559 | @mock.patch.object(pxe_utils, 'get_instance_image_info', autospec=True) | |
560 | def test_prepare_instance_netboot_uefi( | |
561 | self, get_image_info_mock, cache_mock, | |
562 | dhcp_factory_mock, switch_pxe_config_mock, | |
563 | set_boot_device_mock): | |
564 | provider_mock = mock.MagicMock() | |
565 | dhcp_factory_mock.return_value = provider_mock | |
566 | image_info = {'kernel': ('', '/path/to/kernel'), | |
567 | 'ramdisk': ('', '/path/to/ramdisk')} | |
568 | get_image_info_mock.return_value = image_info | |
569 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
570 | task.node.driver_internal_info['root_uuid_or_disk_id'] = ( | |
571 | "30212642-09d3-467f-8e09-21685826ab50") | |
572 | task.node.driver_internal_info['is_whole_disk_image'] = False | |
573 | task.node.instance_info = { | |
574 | 'capabilities': {'boot_option': 'netboot'}} | |
575 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
576 | task, ipxe_enabled=False, ip_version=4) | |
577 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
578 | task, ipxe_enabled=False, ip_version=6) | |
579 | pxe_config_path = pxe_utils.get_pxe_config_file_path( | |
580 | task.node.uuid) | |
581 | task.driver.boot.prepare_instance(task) | |
582 | ||
583 | get_image_info_mock.assert_called_once_with( | |
584 | task, ipxe_enabled=False) | |
585 | cache_mock.assert_called_once_with( | |
586 | task, image_info, ipxe_enabled=False) | |
587 | provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts) | |
588 | switch_pxe_config_mock.assert_called_once_with( | |
589 | pxe_config_path, "30212642-09d3-467f-8e09-21685826ab50", | |
590 | 'uefi', False, False, False, False, ipxe_enabled=False, | |
538 | 591 | anaconda_boot=False) |
539 | 592 | set_boot_device_mock.assert_called_once_with(task, |
540 | 593 | boot_devices.PXE, |
560 | 613 | self.node.provision_state = states.ACTIVE |
561 | 614 | self.node.save() |
562 | 615 | with task_manager.acquire(self.context, self.node.uuid) as task: |
616 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
617 | task.node.driver_internal_info['root_uuid_or_disk_id'] = ( | |
618 | "30212642-09d3-467f-8e09-21685826ab50") | |
619 | task.node.driver_internal_info['is_whole_disk_image'] = False | |
620 | task.node.instance_info['capabilities'] = instance_info | |
621 | task.driver.boot.prepare_instance(task) | |
563 | 622 | dhcp_opts = pxe_utils.dhcp_options_for_instance( |
564 | 623 | task, ipxe_enabled=False) |
565 | 624 | dhcp_opts += pxe_utils.dhcp_options_for_instance( |
566 | 625 | task, ipxe_enabled=False, ip_version=6) |
567 | 626 | pxe_config_path = pxe_utils.get_pxe_config_file_path( |
568 | 627 | task.node.uuid) |
569 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
570 | task.node.driver_internal_info['root_uuid_or_disk_id'] = ( | |
571 | "30212642-09d3-467f-8e09-21685826ab50") | |
572 | task.node.driver_internal_info['is_whole_disk_image'] = False | |
573 | task.node.instance_info['capabilities'] = instance_info | |
574 | task.driver.boot.prepare_instance(task) | |
575 | 628 | |
576 | 629 | get_image_info_mock.assert_called_once_with( |
577 | 630 | task, ipxe_enabled=False) |
603 | 656 | instance_info = {"boot_option": "netboot"} |
604 | 657 | get_image_info_mock.return_value = image_info |
605 | 658 | with task_manager.acquire(self.context, self.node.uuid) as task: |
659 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
660 | task.node.instance_info['capabilities'] = instance_info | |
661 | task.node.driver_internal_info['is_whole_disk_image'] = False | |
606 | 662 | dhcp_opts = pxe_utils.dhcp_options_for_instance( |
607 | 663 | task, ipxe_enabled=False) |
608 | 664 | dhcp_opts += pxe_utils.dhcp_options_for_instance( |
609 | 665 | task, ipxe_enabled=False, ip_version=6) |
610 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
611 | task.node.instance_info['capabilities'] = instance_info | |
612 | task.node.driver_internal_info['is_whole_disk_image'] = False | |
613 | 666 | |
614 | 667 | task.driver.boot.prepare_instance(task) |
615 | 668 | |
636 | 689 | get_image_info_mock.return_value = {} |
637 | 690 | instance_info = {"boot_option": "netboot"} |
638 | 691 | with task_manager.acquire(self.context, self.node.uuid) as task: |
692 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
693 | task.node.instance_info['capabilities'] = instance_info | |
694 | task.node.driver_internal_info['is_whole_disk_image'] = True | |
639 | 695 | dhcp_opts = pxe_utils.dhcp_options_for_instance( |
640 | 696 | task, ipxe_enabled=False) |
641 | 697 | dhcp_opts += pxe_utils.dhcp_options_for_instance( |
642 | 698 | task, ipxe_enabled=False, ip_version=6) |
643 | task.node.properties['capabilities'] = 'boot_mode:bios' | |
644 | task.node.instance_info['capabilities'] = instance_info | |
645 | task.node.driver_internal_info['is_whole_disk_image'] = True | |
646 | 699 | task.driver.boot.prepare_instance(task) |
647 | 700 | get_image_info_mock.assert_called_once_with(task, |
648 | 701 | ipxe_enabled=False) |
701 | 754 | self, get_image_info_mock, cache_mock, |
702 | 755 | dhcp_factory_mock, create_pxe_config_mock, |
703 | 756 | switch_pxe_config_mock, |
704 | set_boot_device_mock, config_file_exits=False): | |
757 | set_boot_device_mock, config_file_exits=False, | |
758 | uefi=True): | |
705 | 759 | image_info = {'kernel': ['', '/path/to/kernel'], |
706 | 760 | 'ramdisk': ['', '/path/to/ramdisk']} |
707 | 761 | get_image_info_mock.return_value = image_info |
730 | 784 | if config_file_exits: |
731 | 785 | self.assertFalse(create_pxe_config_mock.called) |
732 | 786 | else: |
733 | create_pxe_config_mock.assert_called_once_with( | |
734 | task, mock.ANY, CONF.pxe.pxe_config_template, | |
735 | ipxe_enabled=False) | |
787 | if not uefi: | |
788 | create_pxe_config_mock.assert_called_once_with( | |
789 | task, mock.ANY, CONF.pxe.pxe_config_template, | |
790 | ipxe_enabled=False) | |
791 | else: | |
792 | create_pxe_config_mock.assert_called_once_with( | |
793 | task, mock.ANY, CONF.pxe.uefi_pxe_config_template, | |
794 | ipxe_enabled=False) | |
795 | if uefi: | |
796 | boot_mode = 'uefi' | |
797 | else: | |
798 | boot_mode = 'bios' | |
799 | ||
736 | 800 | switch_pxe_config_mock.assert_called_once_with( |
737 | 801 | pxe_config_path, None, |
738 | 'bios', False, ipxe_enabled=False, iscsi_boot=False, | |
802 | boot_mode, False, ipxe_enabled=False, iscsi_boot=False, | |
739 | 803 | ramdisk_boot=True, anaconda_boot=False) |
740 | 804 | set_boot_device_mock.assert_called_once_with(task, |
741 | 805 | boot_devices.PXE, |
777 | 841 | dhcp_factory_mock.return_value = provider_mock |
778 | 842 | self.node.provision_state = states.DEPLOYING |
779 | 843 | self.config(http_url='http://fake_url', group='deploy') |
844 | with task_manager.acquire(self.context, self.node.uuid) as task: | |
845 | dhcp_opts = pxe_utils.dhcp_options_for_instance( | |
846 | task, ipxe_enabled=False) | |
847 | dhcp_opts += pxe_utils.dhcp_options_for_instance( | |
848 | task, ipxe_enabled=False, ip_version=6) | |
849 | pxe_config_path = pxe_utils.get_pxe_config_file_path( | |
850 | task.node.uuid) | |
851 | ||
852 | task.driver.boot.prepare_instance(task) | |
853 | ||
854 | get_image_info_mock.assert_called_once_with(task, | |
855 | ipxe_enabled=False) | |
856 | cache_mock.assert_called_once_with( | |
857 | task, image_info, False) | |
858 | if os.path.isfile('/usr/bin/ksvalidator'): | |
859 | exec_mock.assert_called_once_with( | |
860 | 'ksvalidator', mock.ANY, check_on_exit=[0], attempts=1 | |
861 | ) | |
862 | provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts) | |
863 | render_mock.assert_called() | |
864 | write_file_mock.assert_called_with( | |
865 | '/path/to/ks.cfg', render_mock.return_value | |
866 | ) | |
867 | create_pxe_config_mock.assert_called_once_with( | |
868 | task, mock.ANY, CONF.pxe.uefi_pxe_config_template, | |
869 | ipxe_enabled=False) | |
870 | switch_pxe_config_mock.assert_called_once_with( | |
871 | pxe_config_path, None, | |
872 | 'uefi', False, ipxe_enabled=False, iscsi_boot=False, | |
873 | ramdisk_boot=False, anaconda_boot=True) | |
874 | set_boot_device_mock.assert_called_once_with(task, | |
875 | boot_devices.PXE, | |
876 | persistent=True) | |
877 | ||
878 | @mock.patch.object(manager_utils, 'node_set_boot_device', autospec=True) | |
879 | @mock.patch.object(deploy_utils, 'switch_pxe_config', autospec=True) | |
880 | @mock.patch.object(pxe_utils, 'create_pxe_config', autospec=True) | |
881 | @mock.patch.object(dhcp_factory, 'DHCPFactory', autospec=True) | |
882 | @mock.patch.object(pxe_utils, 'cache_ramdisk_kernel', autospec=True) | |
883 | @mock.patch.object(pxe_utils, 'get_instance_image_info', autospec=True) | |
884 | @mock.patch('ironic.drivers.modules.deploy_utils.get_boot_option', | |
885 | return_value='kickstart', autospec=True) | |
886 | @mock.patch('ironic.drivers.modules.deploy_utils.get_ironic_api_url', | |
887 | return_value='http://fakeserver/api', autospec=True) | |
888 | @mock.patch('ironic.common.utils.render_template', autospec=True) | |
889 | @mock.patch('ironic.common.utils.write_to_file', autospec=True) | |
890 | @mock.patch('ironic.common.utils.execute', autospec=True) | |
891 | def test_prepare_instance_kickstart_bios( | |
892 | self, exec_mock, write_file_mock, render_mock, api_url_mock, | |
893 | boot_opt_mock, get_image_info_mock, cache_mock, dhcp_factory_mock, | |
894 | create_pxe_config_mock, switch_pxe_config_mock, | |
895 | set_boot_device_mock): | |
896 | image_info = {'kernel': ['ins_kernel_id', '/path/to/kernel'], | |
897 | 'ramdisk': ['ins_ramdisk_id', '/path/to/ramdisk'], | |
898 | 'stage2': ['ins_stage2_id', '/path/to/stage2'], | |
899 | 'ks_cfg': ['', '/path/to/ks.cfg'], | |
900 | 'ks_template': ['template_id', '/path/to/ks_template']} | |
901 | get_image_info_mock.return_value = image_info | |
902 | provider_mock = mock.MagicMock() | |
903 | dhcp_factory_mock.return_value = provider_mock | |
904 | self.node.provision_state = states.DEPLOYING | |
905 | self.config(http_url='http://fake_url', group='deploy') | |
906 | self.config(default_boot_mode='bios', group='deploy') | |
907 | ||
780 | 908 | with task_manager.acquire(self.context, self.node.uuid) as task: |
781 | 909 | dhcp_opts = pxe_utils.dhcp_options_for_instance( |
782 | 910 | task, ipxe_enabled=False) |
105 | 105 | provider_mock.update_dhcp.assert_called_once_with(task, dhcp_opts) |
106 | 106 | switch_pxe_config_mock.assert_called_once_with( |
107 | 107 | pxe_config_path, None, |
108 | 'bios', False, ipxe_enabled=False, iscsi_boot=False, | |
109 | ramdisk_boot=True, anaconda_boot=False) | |
108 | CONF.deploy.default_boot_mode, False, ipxe_enabled=False, | |
109 | iscsi_boot=False, ramdisk_boot=True, anaconda_boot=False) | |
110 | 110 | set_boot_device_mock.assert_called_once_with(task, |
111 | 111 | boot_devices.PXE, |
112 | 112 | persistent=True) |
0 | --- | |
1 | features: | |
2 | - | | |
3 | The default deployment boot mode is *now* UEFI. Legacy BIOS is still | |
4 | supported, however operators who require BIOS nodes will need to | |
5 | set their nodes, or deployment, appropriately. | |
6 | upgrade: | |
7 | - | | |
8 | The default boot mode has been changed and now UEFI. Operators who | |
9 | were explicitly relying upon BIOS based deployments in the past, | |
10 | may wish to consider setting an explicit node level override for | |
11 | the node to only utilize BIOS mode. This can be configured at a | |
12 | conductor level with the ``[deploy]default_boot_mode``. Options | |
13 | to set this at a node level can be found in the | |
14 | `Ironic Installation guide - Advanced features <https://docs.openstack.org/ironic/latest/install/advanced.html#boot-mode-support>`_ | |
15 | documentation. |
212 | 212 | - job: |
213 | 213 | name: ironic-tempest-partition-bios-redfish-pxe |
214 | 214 | description: "Deploy ironic node over PXE using BIOS boot mode" |
215 | parent: ironic-base | |
215 | parent: ironic-tempest-partition-uefi-redfish-vmedia | |
216 | 216 | required-projects: |
217 | 217 | - opendev.org/openstack/sushy-tools |
218 | vars: | |
219 | devstack_localrc: | |
220 | IRONIC_ENABLED_BOOT_INTERFACES: ipxe | |
221 | SWIFT_ENABLE_TEMPURLS: False | |
222 | SWIFT_TEMPURL_KEY: '' | |
223 | # Parent job has a longer timeout due to vmedia usage, | |
224 | # Reset the callback to a normal-ish value. | |
225 | IRONIC_CALLBACK_TIMEOUT: 600 | |
226 | IRONIC_DEFAULT_BOOT_OPTION: netboot | |
227 | IRONIC_BOOT_MODE: bios | |
228 | devstack_services: | |
229 | # Parent job uses swift, this one does not, thus we can turn it off. | |
230 | s-account: False | |
231 | s-container: False | |
232 | s-object: False | |
233 | s-proxy: False | |
234 | ||
235 | - job: | |
236 | name: ironic-tempest-partition-uefi-redfish-vmedia | |
237 | description: "Deploy ironic node over Redfish virtual media using UEFI boot mode" | |
238 | parent: ironic-base | |
218 | 239 | vars: |
219 | 240 | devstack_localrc: |
220 | 241 | IRONIC_DEPLOY_DRIVER: redfish |
222 | 243 | IRONIC_ENABLED_POWER_INTERFACES: redfish |
223 | 244 | IRONIC_ENABLED_MANAGEMENT_INTERFACES: redfish |
224 | 245 | IRONIC_AUTOMATED_CLEAN_ENABLED: False |
246 | # TODO(TheJulia): We need to excise netboot from | |
247 | # jobs at some point. | |
225 | 248 | IRONIC_DEFAULT_BOOT_OPTION: netboot |
226 | ||
227 | - job: | |
228 | name: ironic-tempest-partition-uefi-redfish-vmedia | |
229 | description: "Deploy ironic node over Redfish virtual media using UEFI boot mode" | |
230 | parent: ironic-tempest-partition-bios-redfish-pxe | |
231 | vars: | |
232 | devstack_localrc: | |
233 | IRONIC_BOOT_MODE: uefi | |
234 | 249 | IRONIC_ENABLED_BOOT_INTERFACES: redfish-virtual-media |
235 | 250 | SWIFT_ENABLE_TEMPURLS: True |
236 | 251 | SWIFT_TEMPURL_KEY: secretkey |
237 | IRONIC_AUTOMATED_CLEAN_ENABLED: False | |
238 | 252 | # Ironic has to master a new image, and this CAN take longer as a |
239 | 253 | # result and makes this job VERY sensitive to heavy disk IO of the |
240 | 254 | # underlying hypervisor/cloud. |
296 | 310 | IRONIC_VM_SPECS_RAM: 3096 |
297 | 311 | SWIFT_ENABLE_TEMPURLS: True |
298 | 312 | SWIFT_TEMPURL_KEY: secretkey |
313 | IRONIC_BOOT_MODE: bios | |
299 | 314 | devstack_services: |
300 | 315 | s-account: True |
301 | 316 | s-container: True |
314 | 329 | IRONIC_VM_EPHEMERAL_DISK: 0 |
315 | 330 | IRONIC_AUTOMATED_CLEAN_ENABLED: False |
316 | 331 | IRONIC_ENFORCE_SCOPE: True |
332 | IRONIC_BOOT_MODE: bios | |
317 | 333 | |
318 | 334 | - job: |
319 | 335 | name: ironic-tempest-ipa-partition-uefi-pxe_ipmitool |
321 | 337 | parent: ironic-base |
322 | 338 | vars: |
323 | 339 | devstack_localrc: |
324 | IRONIC_BOOT_MODE: uefi | |
325 | 340 | IRONIC_VM_SPECS_RAM: 4096 |
326 | 341 | IRONIC_AUTOMATED_CLEAN_ENABLED: False |
327 | 342 | IRONIC_DEFAULT_BOOT_OPTION: netboot |
654 | 669 | IRONIC_ENABLED_HARDWARE_TYPES: ipmi |
655 | 670 | IRONIC_ENABLED_BOOT_INTERFACES: pxe |
656 | 671 | IRONIC_IPXE_ENABLED: False |
657 | IRONIC_BOOT_MODE: uefi | |
658 | 672 | IRONIC_RAMDISK_TYPE: tinyipa |
659 | 673 | IRONIC_AUTOMATED_CLEAN_ENABLED: False |
660 | 674 | IRONIC_DEFAULT_BOOT_OPTION: netboot |
699 | 713 | IRONIC_AUTOMATED_CLEAN_ENABLED: False |
700 | 714 | SWIFT_ENABLE_TEMPURLS: True |
701 | 715 | SWIFT_TEMPURL_KEY: secretkey |
716 | IRONIC_BOOT_MODE: bios | |
702 | 717 | |
703 | 718 | - job: |
704 | 719 | name: ironic-tempest-ipxe-ipv6 |
776 | 791 | IRONIC_VM_EPHEMERAL_DISK: 0 |
777 | 792 | SWIFT_ENABLE_TEMPURLS: True |
778 | 793 | SWIFT_TEMPURL_KEY: secretkey |
794 | IRONIC_BOOT_MODE: bios | |
779 | 795 | devstack_services: |
780 | 796 | s-account: True |
781 | 797 | s-container: True |