145
165
self.assertEqual('instance_ramdisk_uuid',
146
166
self.node.instance_info.get('ramdisk'))
168
def test__get_image_info(self):
169
# Tests when 'is_whole_disk_image' exists in driver_internal_info
170
self._test__get_image_info()
172
def test__get_image_info_without_is_whole_disk_image(self):
173
# Tests when 'is_whole_disk_image' doesn't exists in
174
# driver_internal_info
175
del self.node.driver_internal_info['is_whole_disk_image']
177
self._test__get_image_info()
179
@mock.patch.object(base_image_service.BaseImageService, '_show')
180
def test__get_image_info_whole_disk_image(self, show_mock):
181
properties = {'properties': None}
183
expected_info = {'deploy_ramdisk':
184
(DRV_INFO_DICT['deploy_ramdisk'],
185
os.path.join(CONF.pxe.tftp_root,
189
(DRV_INFO_DICT['deploy_kernel'],
190
os.path.join(CONF.pxe.tftp_root,
193
show_mock.return_value = properties
194
self.node.driver_internal_info['is_whole_disk_image'] = True
195
image_info = pxe._get_image_info(self.node, self.context)
196
self.assertEqual(expected_info, image_info)
148
198
@mock.patch.object(iscsi_deploy, 'build_deploy_ramdisk_options')
149
199
@mock.patch.object(pxe_utils, '_build_pxe_config')
150
200
def _test_build_pxe_config_options(self, build_pxe_mock, deploy_opts_mock,
151
201
ipxe_enabled=False):
152
202
self.config(pxe_append_params='test_param', group='pxe')
153
203
# NOTE: right '/' should be removed from url string
154
self.config(api_url='http://192.168.122.184:6385/', group='conductor')
204
self.config(api_url='http://192.168.122.184:6385', group='conductor')
155
205
self.config(disk_devices='sda', group='pxe')
157
fake_deploy_opts = {'iscsi_target_iqn': 'fake-iqn',
208
'iscsi_target_iqn': 'fake-iqn',
158
209
'deployment_id': 'fake-deploy-id',
159
210
'deployment_key': 'fake-deploy-key',
160
211
'disk': 'fake-disk',
161
'ironic_api_url': 'fake-api-url'}
212
'ironic_api_url': 'fake-api-url',
213
'boot_option': 'netboot',
163
217
deploy_opts_mock.return_value = fake_deploy_opts
226
283
def test__build_pxe_config_options_ipxe(self):
227
284
self._test_build_pxe_config_options(ipxe_enabled=True)
286
def test__build_pxe_config_options_without_is_whole_disk_image(self):
287
del self.node.driver_internal_info['is_whole_disk_image']
289
self._test_build_pxe_config_options(ipxe_enabled=False)
291
@mock.patch.object(iscsi_deploy, 'build_deploy_ramdisk_options')
292
@mock.patch.object(pxe_utils, '_build_pxe_config')
293
def _test_build_pxe_config_options_whole_disk_image(self, build_pxe_mock,
294
deploy_opts_mock, ipxe_enabled=False):
295
self.config(pxe_append_params='test_param', group='pxe')
296
# NOTE: right '/' should be removed from url string
297
self.config(api_url='http://192.168.122.184:6385/', group='conductor')
298
self.config(disk_devices='sda', group='pxe')
300
fake_deploy_opts = {'iscsi_target_iqn': 'fake-iqn',
301
'deployment_id': 'fake-deploy-id',
302
'deployment_key': 'fake-deploy-key',
304
'ironic_api_url': 'fake-api-url'}
306
deploy_opts_mock.return_value = fake_deploy_opts
308
tftp_server = CONF.pxe.tftp_server
311
http_url = 'http://192.1.2.3:1234'
312
self.config(ipxe_enabled=True, group='pxe')
313
self.config(http_url=http_url, group='pxe')
315
deploy_kernel = os.path.join(http_url, self.node.uuid,
317
deploy_ramdisk = os.path.join(http_url, self.node.uuid,
319
root_dir = CONF.pxe.http_root
321
deploy_kernel = os.path.join(CONF.pxe.tftp_root, self.node.uuid,
323
deploy_ramdisk = os.path.join(CONF.pxe.tftp_root, self.node.uuid,
325
root_dir = CONF.pxe.tftp_root
328
'deployment_ari_path': deploy_ramdisk,
329
'pxe_append_params': 'test_param',
330
'deployment_aki_path': deploy_kernel,
331
'tftp_server': tftp_server,
334
expected_options.update(fake_deploy_opts)
336
image_info = {'deploy_kernel': ('deploy_kernel',
337
os.path.join(root_dir,
340
'deploy_ramdisk': ('deploy_ramdisk',
341
os.path.join(root_dir,
345
self.node.driver_internal_info['is_whole_disk_image'] = True
346
options = pxe._build_pxe_config_options(self.node,
349
self.assertEqual(expected_options, options)
229
351
def test_get_token_file_path(self):
230
352
node_uuid = self.node.uuid
231
353
self.assertEqual('/tftpboot/token-' + node_uuid,
479
631
mock_cache_r_k.assert_called_once_with(self.context,
634
@mock.patch.object(pxe, '_get_image_info')
635
@mock.patch.object(pxe, '_cache_ramdisk_kernel')
636
@mock.patch.object(pxe, '_build_pxe_config_options')
637
@mock.patch.object(pxe_utils, 'create_pxe_config')
638
@mock.patch.object(pxe_utils, 'get_pxe_config_file_path')
639
@mock.patch.object(deploy_utils, 'switch_pxe_config')
640
def test_prepare_node_active_missing_root_uuid(self,
647
mock_build_pxe.return_value = None
648
mock_img_info.return_value = None
649
self.node.provision_state = states.ACTIVE
652
with task_manager.acquire(self.context, self.node.uuid) as task:
653
task.driver.deploy.prepare(task)
654
mock_img_info.assert_called_once_with(task.node,
656
mock_pxe_config.assert_called_once_with(
657
task, None, CONF.pxe.pxe_config_template)
658
mock_cache_r_k.assert_called_once_with(self.context,
660
self.assertFalse(mock_pxe_get_cfg.called)
661
self.assertFalse(mock_switch.called)
663
@mock.patch.object(pxe, '_get_image_info')
664
@mock.patch.object(pxe, '_cache_ramdisk_kernel')
665
@mock.patch.object(pxe, '_build_pxe_config_options')
666
@mock.patch.object(pxe_utils, 'create_pxe_config')
667
@mock.patch.object(pxe_utils, 'get_pxe_config_file_path')
668
@mock.patch.object(deploy_utils, 'switch_pxe_config')
669
@mock.patch.object(driver_utils, 'get_node_capability')
670
def _test_prepare_node_active(self,
678
mock_build_pxe.return_value = None
679
mock_img_info.return_value = None
680
mock_pxe_get_cfg.return_value = '/path'
681
mock_get_cap.return_value = None
683
self.node.provision_state = states.ACTIVE
686
with task_manager.acquire(self.context, self.node.uuid) as task:
687
task.driver.deploy.prepare(task)
688
mock_img_info.assert_called_once_with(task.node,
690
mock_pxe_config.assert_called_once_with(
691
task, None, CONF.pxe.pxe_config_template)
692
mock_cache_r_k.assert_called_once_with(self.context,
695
mock_pxe_get_cfg.assert_called_once_with(task.node.uuid)
696
iwdi = task.node.driver_internal_info.get('is_whole_disk_image')
697
mock_switch.assert_called_once_with('/path', 'abcd', None, iwdi)
699
def test_prepare_node_active(self):
700
self.node.driver_internal_info = {'root_uuid_or_disk_id': 'abcd',
701
'is_whole_disk_image': False}
703
self._test_prepare_node_active()
705
def test_prepare_node_active_without_is_whole_disk_image(self):
706
self.node.driver_internal_info = {'root_uuid_or_disk_id': 'abcd'}
708
self._test_prepare_node_active()
482
710
@mock.patch.object(keystone, 'token_expires_soon')
483
711
@mock.patch.object(deploy_utils, 'get_image_mb')
484
712
@mock.patch.object(iscsi_deploy, '_get_image_file_path')
571
799
self.assertEqual(states.DELETED, state)
572
800
node_power_mock.assert_called_once_with(task, states.POWER_OFF)
802
@mock.patch.object(pxe_utils, 'clean_up_pxe_config')
574
803
@mock.patch.object(dhcp_factory.DHCPFactory, 'update_dhcp')
575
def test_take_over(self, update_dhcp_mock):
804
def test_take_over(self, update_dhcp_mock, clean_pxe_mock):
576
805
with task_manager.acquire(
577
806
self.context, self.node.uuid, shared=True) as task:
578
807
dhcp_opts = pxe_utils.dhcp_options_for_instance(task)
579
808
task.driver.deploy.take_over(task)
580
update_dhcp_mock.assert_called_once_with(
810
# Assert we update the DHCP server
811
update_dhcp_mock.assert_called_once_with(task, dhcp_opts)
813
# Assert we don't clean the PXE config files in
814
# case it's not local boot
815
self.assertFalse(clean_pxe_mock.called)
817
@mock.patch.object(pxe_utils, 'clean_up_pxe_config')
818
@mock.patch.object(dhcp_factory.DHCPFactory, 'update_dhcp')
819
def test_take_over_localboot(self, update_dhcp_mock, clean_pxe_mock):
820
with task_manager.acquire(
821
self.context, self.node.uuid, shared=True) as task:
822
task.node.instance_info['capabilities'] = {"boot_option": "local"}
823
task.driver.deploy.take_over(task)
825
# Assert we are not attempting to update the DHCP
826
# server in case it's local boot
827
self.assertFalse(update_dhcp_mock.called)
829
# Assert we are cleaning the PXE config files
830
clean_pxe_mock.assert_called_once_with(task)
832
@mock.patch.object(pxe_utils, 'clean_up_pxe_config')
833
@mock.patch.object(manager_utils, 'node_set_boot_device')
583
834
@mock.patch.object(deploy_utils, 'notify_deploy_complete')
584
835
@mock.patch.object(deploy_utils, 'switch_pxe_config')
585
836
@mock.patch.object(iscsi_deploy, 'InstanceImageCache')
586
def test_continue_deploy_good(self, mock_image_cache, mock_switch_config,
837
@mock.patch.object(deploy_utils, 'deploy_partition_image')
838
def _test_pass_deploy_info_deploy(self, is_localboot, mock_deploy,
839
mock_image_cache, mock_switch_config,
840
notify_mock, mock_node_boot_dev,
588
842
token_path = self._create_token_file()
846
i_info = self.node.instance_info
847
i_info['capabilities'] = '{"boot_option": "local"}'
848
self.node.instance_info = i_info
589
850
self.node.power_state = states.POWER_ON
590
851
self.node.provision_state = states.DEPLOYWAIT
591
852
self.node.target_provision_state = states.ACTIVE
594
855
root_uuid = "12345678-1234-1234-1234-1234567890abcxyz"
597
def fake_deploy(**kwargs):
600
self.useFixture(fixtures.MonkeyPatch(
601
'ironic.drivers.modules.deploy_utils.deploy',
604
with task_manager.acquire(self.context, self.node.uuid) as task:
605
task.driver.vendor._continue_deploy(
606
task, address='123456', iqn='aaa-bbb', key='fake-56789')
609
self.assertEqual(states.ACTIVE, self.node.provision_state)
610
self.assertEqual(states.NOSTATE, self.node.target_provision_state)
611
self.assertEqual(states.POWER_ON, self.node.power_state)
612
self.assertIsNone(self.node.last_error)
613
self.assertFalse(os.path.exists(token_path))
614
mock_image_cache.assert_called_once_with()
615
mock_image_cache.return_value.clean_up.assert_called_once_with()
616
pxe_config_path = pxe_utils.get_pxe_config_file_path(self.node.uuid)
617
mock_switch_config.assert_called_once_with(pxe_config_path, root_uuid,
619
notify_mock.assert_called_once_with('123456')
621
@mock.patch.object(iscsi_deploy, 'InstanceImageCache')
622
def test_continue_deploy_fail(self, mock_image_cache):
623
token_path = self._create_token_file()
624
self.node.power_state = states.POWER_ON
625
self.node.provision_state = states.DEPLOYWAIT
626
self.node.target_provision_state = states.ACTIVE
629
def fake_deploy(**kwargs):
630
raise exception.InstanceDeployFailure("test deploy error")
632
self.useFixture(fixtures.MonkeyPatch(
633
'ironic.drivers.modules.deploy_utils.deploy',
636
with task_manager.acquire(self.context, self.node.uuid) as task:
637
task.driver.vendor._continue_deploy(
638
task, address='123456', iqn='aaa-bbb', key='fake-56789')
641
self.assertEqual(states.DEPLOYFAIL, self.node.provision_state)
642
self.assertEqual(states.ACTIVE, self.node.target_provision_state)
643
self.assertEqual(states.POWER_OFF, self.node.power_state)
644
self.assertIsNotNone(self.node.last_error)
645
self.assertFalse(os.path.exists(token_path))
646
mock_image_cache.assert_called_once_with()
647
mock_image_cache.return_value.clean_up.assert_called_once_with()
649
@mock.patch.object(iscsi_deploy, 'InstanceImageCache')
650
def test_continue_deploy_ramdisk_fails(self, mock_image_cache):
651
token_path = self._create_token_file()
652
self.node.power_state = states.POWER_ON
653
self.node.provision_state = states.DEPLOYWAIT
654
self.node.target_provision_state = states.ACTIVE
657
def fake_deploy(**kwargs):
660
self.useFixture(fixtures.MonkeyPatch(
661
'ironic.drivers.modules.deploy_utils.deploy',
664
with task_manager.acquire(self.context, self.node.uuid) as task:
665
task.driver.vendor._continue_deploy(
666
task, address='123456', iqn='aaa-bbb',
667
key='fake-56789', error='test ramdisk error')
670
self.assertEqual(states.DEPLOYFAIL, self.node.provision_state)
671
self.assertEqual(states.ACTIVE, self.node.target_provision_state)
672
self.assertEqual(states.POWER_OFF, self.node.power_state)
673
self.assertIsNotNone(self.node.last_error)
674
self.assertFalse(os.path.exists(token_path))
675
mock_image_cache.assert_called_once_with()
676
mock_image_cache.return_value.clean_up.assert_called_once_with()
678
def test_continue_deploy_invalid(self):
856
mock_deploy.return_value = {'root uuid': root_uuid}
858
is_whole_disk_image = False
860
with task_manager.acquire(self.context, self.node.uuid) as task:
861
task.driver.vendor.pass_deploy_info(
862
task, address='123456', iqn='aaa-bbb', key='fake-56789')
865
self.assertEqual(states.ACTIVE, self.node.provision_state)
866
self.assertEqual(states.NOSTATE, self.node.target_provision_state)
867
self.assertEqual(states.POWER_ON, self.node.power_state)
868
self.assertIn('root_uuid_or_disk_id', self.node.driver_internal_info)
869
self.assertIsNone(self.node.last_error)
870
self.assertFalse(os.path.exists(token_path))
871
mock_image_cache.assert_called_once_with()
872
mock_image_cache.return_value.clean_up.assert_called_once_with()
873
pxe_config_path = pxe_utils.get_pxe_config_file_path(self.node.uuid)
874
notify_mock.assert_called_once_with('123456')
876
mock_node_boot_dev.assert_called_once_with(
877
mock.ANY, boot_devices.DISK, persistent=True)
878
mock_clean_pxe.assert_called_once_with(mock.ANY)
879
self.assertFalse(mock_switch_config.called)
881
mock_switch_config.assert_called_once_with(pxe_config_path,
885
self.assertFalse(mock_node_boot_dev.called)
886
self.assertFalse(mock_clean_pxe.called)
888
@mock.patch.object(pxe_utils, 'clean_up_pxe_config')
889
@mock.patch.object(manager_utils, 'node_set_boot_device')
890
@mock.patch.object(deploy_utils, 'notify_deploy_complete')
891
@mock.patch.object(deploy_utils, 'switch_pxe_config')
892
@mock.patch.object(iscsi_deploy, 'InstanceImageCache')
893
@mock.patch.object(deploy_utils, 'deploy_disk_image')
894
def _test_pass_deploy_info_whole_disk_image(self, is_localboot,
901
token_path = self._create_token_file()
905
i_info = self.node.instance_info
906
i_info['capabilities'] = '{"boot_option": "local"}'
907
self.node.instance_info = i_info
909
self.node.power_state = states.POWER_ON
910
self.node.provision_state = states.DEPLOYWAIT
911
self.node.target_provision_state = states.ACTIVE
915
is_whole_disk_image = True
916
disk_id = '0x12345678'
917
mock_deploy.return_value = {'disk identifier': disk_id}
919
with task_manager.acquire(self.context, self.node.uuid) as task:
920
task.node.driver_internal_info['is_whole_disk_image'] = True
921
task.driver.vendor.pass_deploy_info(task, address='123456',
926
self.assertEqual(states.ACTIVE, self.node.provision_state)
927
self.assertEqual(states.NOSTATE, self.node.target_provision_state)
928
self.assertEqual(states.POWER_ON, self.node.power_state)
929
self.assertIsNone(self.node.last_error)
930
self.assertFalse(os.path.exists(token_path))
931
mock_image_cache.assert_called_once_with()
932
mock_image_cache.return_value.clean_up.assert_called_once_with()
933
pxe_config_path = pxe_utils.get_pxe_config_file_path(self.node.uuid)
934
notify_mock.assert_called_once_with('123456')
936
mock_node_boot_dev.assert_called_once_with(
937
mock.ANY, boot_devices.DISK, persistent=True)
938
mock_clean_pxe.assert_called_once_with(mock.ANY)
939
self.assertFalse(mock_switch_config.called)
941
mock_switch_config.assert_called_once_with(pxe_config_path,
945
self.assertFalse(mock_node_boot_dev.called)
946
self.assertFalse(mock_clean_pxe.called)
948
def test_pass_deploy_info_deploy(self):
949
self._test_pass_deploy_info_deploy(False)
951
def test_pass_deploy_info_localboot(self):
952
self._test_pass_deploy_info_deploy(True)
954
def test_pass_deploy_info_whole_disk_image(self):
955
self._test_pass_deploy_info_whole_disk_image(False)
957
def test_pass_deploy_info_whole_disk_image_localboot(self):
958
self._test_pass_deploy_info_whole_disk_image(True)
960
def test_pass_deploy_info_invalid(self):
679
961
self.node.power_state = states.POWER_ON
680
962
self.node.provision_state = states.AVAILABLE
681
963
self.node.target_provision_state = states.NOSTATE
846
1133
self.assertFalse(os.path.exists(path),
847
1134
'%s is not expected to exist' % path)
1137
class TestAgentVendorPassthru(db_base.DbTestCase):
1140
super(TestAgentVendorPassthru, self).setUp()
1141
mgr_utils.mock_the_extension_manager()
1142
self.driver = driver_factory.get_driver("fake")
1143
self.driver.vendor = pxe.VendorPassthru()
1144
self.node = obj_utils.create_test_node(
1145
self.context, driver='fake',
1146
instance_info=INST_INFO_DICT,
1147
driver_info=DRV_INFO_DICT,
1148
driver_internal_info=DRV_INTERNAL_INFO_DICT,
1150
self.node.driver_internal_info['agent_url'] = 'http://1.2.3.4:1234'
1151
self.task = mock.Mock(spec=task_manager.TaskManager)
1152
self.task.shared = False
1153
self.task.node = self.node
1154
self.task.driver = self.driver
1155
self.task.context = self.context
1157
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
1158
'reboot_and_finish_deploy')
1159
@mock.patch.object(deploy_utils, 'switch_pxe_config')
1160
@mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy')
1161
@mock.patch.object(pxe, '_destroy_token_file')
1162
def test_continue_deploy_netboot(self, destroy_token_file_mock,
1163
do_agent_iscsi_deploy_mock,
1164
switch_pxe_config_mock,
1165
reboot_and_finish_deploy_mock):
1167
uuid_dict_returned = {'root uuid': 'some-root-uuid'}
1168
do_agent_iscsi_deploy_mock.return_value = uuid_dict_returned
1169
self.driver.vendor.continue_deploy(self.task)
1170
destroy_token_file_mock.assert_called_once_with(self.node)
1171
do_agent_iscsi_deploy_mock.assert_called_once_with(
1172
self.task, self.driver.vendor._client)
1173
tftp_config = '/tftpboot/%s/config' % self.node.uuid
1174
switch_pxe_config_mock.assert_called_once_with(tftp_config,
1177
reboot_and_finish_deploy_mock.assert_called_once_with(self.task)
1179
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
1180
'reboot_and_finish_deploy')
1181
@mock.patch.object(pxe_utils, 'clean_up_pxe_config')
1182
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
1183
'configure_local_boot')
1184
@mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy')
1185
@mock.patch.object(pxe, '_destroy_token_file')
1186
def test_continue_deploy_localboot(self, destroy_token_file_mock,
1187
do_agent_iscsi_deploy_mock,
1188
configure_local_boot_mock,
1189
clean_up_pxe_config_mock,
1190
reboot_and_finish_deploy_mock):
1192
self.node.instance_info = {
1193
'capabilities': {'boot_option': 'local'}}
1195
uuid_dict_returned = {'root uuid': 'some-root-uuid'}
1196
do_agent_iscsi_deploy_mock.return_value = uuid_dict_returned
1198
self.driver.vendor.continue_deploy(self.task)
1199
destroy_token_file_mock.assert_called_once_with(self.node)
1200
do_agent_iscsi_deploy_mock.assert_called_once_with(
1201
self.task, self.driver.vendor._client)
1202
configure_local_boot_mock.assert_called_once_with(
1203
self.task, root_uuid='some-root-uuid', efi_system_part_uuid=None)
1204
clean_up_pxe_config_mock.assert_called_once_with(self.task)
1205
reboot_and_finish_deploy_mock.assert_called_once_with(self.task)
1207
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
1208
'reboot_and_finish_deploy')
1209
@mock.patch.object(pxe_utils, 'clean_up_pxe_config')
1210
@mock.patch.object(agent_base_vendor.BaseAgentVendor,
1211
'configure_local_boot')
1212
@mock.patch.object(iscsi_deploy, 'do_agent_iscsi_deploy')
1213
@mock.patch.object(pxe, '_destroy_token_file')
1214
def test_continue_deploy_localboot_uefi(self, destroy_token_file_mock,
1215
do_agent_iscsi_deploy_mock,
1216
configure_local_boot_mock,
1217
clean_up_pxe_config_mock,
1218
reboot_and_finish_deploy_mock):
1220
self.node.instance_info = {
1221
'capabilities': {'boot_option': 'local'}}
1223
uuid_dict_returned = {'root uuid': 'some-root-uuid',
1224
'efi system partition uuid': 'efi-part-uuid'}
1225
do_agent_iscsi_deploy_mock.return_value = uuid_dict_returned
1227
self.driver.vendor.continue_deploy(self.task)
1228
destroy_token_file_mock.assert_called_once_with(self.node)
1229
do_agent_iscsi_deploy_mock.assert_called_once_with(
1230
self.task, self.driver.vendor._client)
1231
configure_local_boot_mock.assert_called_once_with(
1232
self.task, root_uuid='some-root-uuid',
1233
efi_system_part_uuid='efi-part-uuid')
1234
clean_up_pxe_config_mock.assert_called_once_with(self.task)
1235
reboot_and_finish_deploy_mock.assert_called_once_with(self.task)