def _process_commissioning(self, node, request, status): # node.status_expires is only used to ensure the node boots into # commissioning. After commissioning has started the script_reaper # makes sure the node is still operating. if node.status_expires is not None: node.status_expires = None node.save(update_fields=['status_expires']) self._store_results( node, node.current_commissioning_script_set, request, status) # This is skipped when its the rack controller using this endpoint. if node.node_type not in ( NODE_TYPE.RACK_CONTROLLER, NODE_TYPE.REGION_AND_RACK_CONTROLLER): # Commissioning was successful, setup the default storage layout # and the initial networking configuration for the node. if status in (SIGNAL_STATUS.TESTING, SIGNAL_STATUS.OK): # XXX 2016-05-10 ltrager, LP:1580405 - Exceptions raised # here are not logged or shown to the user. node.set_default_storage_layout() node.set_initial_networking_configuration() # XXX 2014-10-21 newell, bug=1382075 # Auto detection for IPMI tries to save power parameters # for Moonshot and RSD. This causes issues if the node's power # type is already mscm or rsd as it uses SSH instead of IPMI. # This fix is temporary as power parameters should not be # overwritten during commissioning because MAAS already has # knowledge to boot the node. # See MP discussion bug=1389808, for further details on why # we are using bug fix 1382075 here. if node.power_type not in ("mscm", "rsd"): store_node_power_parameters(node, request) signaling_statuses = { SIGNAL_STATUS.OK: NODE_STATUS.READY, SIGNAL_STATUS.FAILED: NODE_STATUS.FAILED_COMMISSIONING, SIGNAL_STATUS.TESTING: NODE_STATUS.TESTING, } target_status = signaling_statuses.get(status) if target_status == NODE_STATUS.TESTING: node.current_testing_script_set.regenerate() if target_status in [NODE_STATUS.READY, NODE_STATUS.TESTING]: # Recalculate tags when commissioning ends. populate_tags_for_single_node(Tag.objects.all(), node) elif (target_status == NODE_STATUS.FAILED_COMMISSIONING and node.current_testing_script_set is not None): # If commissioning failed testing doesn't run, mark any pending # scripts as aborted. qs = node.current_testing_script_set.scriptresult_set.filter( status=SCRIPT_STATUS.PENDING) for script_result in qs: script_result.status = SCRIPT_STATUS.ABORTED script_result.save(update_fields=['status']) return target_status
def test_power_type_not_given(self): # When power_type is not specified, nothing happens. self.request.POST = {} self.node.power_type = '' store_node_power_parameters(self.node, self.request) self.assertEqual('', self.node.power_type) self.assertEqual({}, self.node.power_parameters) self.save.assert_has_calls([])
def test_power_type_redfish_no_parameters(self): self.node.set_power_config("redfish", {"node_id": "1"}) self.request.POST = {} store_node_power_parameters(self.node, self.request) self.assertEqual("redfish", self.node.power_type) self.assertEqual(self.node.instance_power_parameters, self.node.power_parameters) self.save.assert_has_calls([])
def test_unknown_power_type(self): # Sometimes a node doesn't know its power type, and will declare its # powertype as ''; store_node_power_parameters will store that # appropriately. power_type = "" self.request.POST = {"power_type": ""} store_node_power_parameters(self.node, self.request) self.assertEqual(power_type, self.node.power_type) self.save.assert_called_once_with()
def test_power_type_set_but_no_parameters(self): # When power_type is valid, it is set. However, if power_parameters is # not specified, the node's power_parameters is left alone, and the # node is saved. power_type = factory.pick_power_type() self.request.POST = {"power_type": power_type} store_node_power_parameters(self.node, self.request) self.assertEqual(power_type, self.node.power_type) self.assertEqual({}, self.node.power_parameters) self.save.assert_called_once_with()
def test_power_type_set_but_no_parameters(self): # When power_type is valid, it is set. However, if power_parameters is # not specified, the node's power_parameters is left alone, and the # node is saved. self.node.set_power_config("ipmi", {"some": "param"}) self.request.POST = {"power_type": "virsh"} store_node_power_parameters(self.node, self.request) self.assertEqual(self.node.power_type, "virsh") self.assertEqual({"some": "param"}, self.node.power_parameters) self.save.assert_called_once_with()
def test_power_type_set_with_parameters(self): # When power_type is valid, and power_parameters is valid JSON, both # fields are set on the node, and the node is saved. power_type = factory.pick_power_type() power_parameters = {"foo": [1, 2, 3]} self.request.POST = { "power_type": power_type, "power_parameters": json.dumps(power_parameters), } store_node_power_parameters(self.node, self.request) self.assertEqual(power_type, self.node.power_type) self.assertEqual(power_parameters, self.node.power_parameters) self.save.assert_called_once_with()
def test_power_type_redfish_update_parameters_from_ipmi(self): self.node.set_power_config("redfish", {"foo": 1}) power_parameters = {"foo": 2, "bar": 3} self.request.POST = { "power_type": "ipmi", "power_parameters": json.dumps(power_parameters), } store_node_power_parameters(self.node, self.request) self.assertEqual("redfish", self.node.power_type) self.assertEqual(self.node.power_parameters, power_parameters) self.assertEqual(self.node.instance_power_parameters, self.node.power_parameters) self.save.assert_called_once_with()
def test_power_type_redfish(self): power_parameters = {"foo": [1, 2, 3]} self.request.POST = { "power_type": "ipmi", "power_parameters": json.dumps(power_parameters), } self.node.set_power_config("redfish", {"node_id": "1"}) store_node_power_parameters(self.node, self.request) self.assertEqual("redfish", self.node.power_type) self.assertEqual( {**power_parameters, **self.node.instance_power_parameters}, self.node.power_parameters, ) self.save.assert_has_calls([])
def test_power_type_redfish(self): power_parameters = {"foo": [1, 2, 3]} self.request.POST = { "power_type": 'ipmi', "power_parameters": json.dumps(power_parameters), } self.node.set_power_config('redfish', {'node_id': '1'}) store_node_power_parameters(self.node, self.request) self.assertEqual('redfish', self.node.power_type) self.assertEqual( { **power_parameters, **self.node.instance_power_parameters }, self.node.power_parameters) self.save.assert_has_calls([])
def _process_commissioning(self, node, request, status): # node.status_expires is only used to ensure the node boots into # commissioning. After commissioning has started the script_reaper # makes sure the node is still operating. if node.status_expires is not None: node.status_expires = None node.save(update_fields=['status_expires']) self._store_results(node, node.current_commissioning_script_set, request, status) # This is skipped when its the rack controller using this endpoint. if node.node_type not in (NODE_TYPE.RACK_CONTROLLER, NODE_TYPE.REGION_CONTROLLER, NODE_TYPE.REGION_AND_RACK_CONTROLLER): # Commissioning was successful, setup the default storage layout # and the initial networking configuration for the node. if status in (SIGNAL_STATUS.TESTING, SIGNAL_STATUS.OK): status = try_or_log_event( node, status, "Failed to set default storage layout.", node.set_default_storage_layout) status = try_or_log_event( node, status, "Failed to set default networking configuration.", node.set_initial_networking_configuration) # XXX 2014-10-21 newell, bug=1382075 # Auto detection for IPMI tries to save power parameters # for Moonshot and RSD. This causes issues if the node's power # type is already mscm or rsd as it uses SSH instead of IPMI. # This fix is temporary as power parameters should not be # overwritten during commissioning because MAAS already has # knowledge to boot the node. # See MP discussion bug=1389808, for further details on why # we are using bug fix 1382075 here. if node.power_type not in ("mscm", "rsd"): store_node_power_parameters(node, request) signaling_statuses = { SIGNAL_STATUS.OK: NODE_STATUS.READY, SIGNAL_STATUS.FAILED: NODE_STATUS.FAILED_COMMISSIONING, SIGNAL_STATUS.TESTING: NODE_STATUS.TESTING, } target_status = signaling_statuses.get(status) enlisting = NodeMetadata.objects.get(node=node, key='enlisting') if enlisting is not None and target_status in [ NODE_STATUS.READY, NODE_STATUS.FAILED_COMMISSIONING ]: enlisting.delete() if target_status == NODE_STATUS.READY: target_status = NODE_STATUS.NEW if target_status in [ NODE_STATUS.NEW, NODE_STATUS.READY, NODE_STATUS.TESTING ]: # Commissioning has ended. Check if any scripts failed during # post-processing; if so, the commissioning counts as a failure. qs = node.current_commissioning_script_set.scriptresult_set.filter( status=SCRIPT_STATUS.FAILED) if qs.count() > 0: target_status = NODE_STATUS.FAILED_COMMISSIONING else: # Recalculate tags when commissioning ends. try_or_log_event(node, status, "Failed to update tags.", populate_tags_for_single_node, Tag.objects.exclude(definition=None), node) if (target_status == NODE_STATUS.FAILED_COMMISSIONING and node.current_testing_script_set is not None): # If commissioning failed, testing doesn't run; mark any pending # scripts as aborted. qs = node.current_testing_script_set.scriptresult_set.filter( status=SCRIPT_STATUS.PENDING) qs.update(status=SCRIPT_STATUS.ABORTED, updated=now()) return target_status