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_ignores_tags_with_unrecognised_namespaces(self): node = factory.make_Node() make_lshw_result(node, b"<foo/>") tags = [ factory.make_Tag("foo", "/foo", populate=False), factory.make_Tag("lou", "//nge:bar", populate=False), ] populate_tags_for_single_node(tags, node) # Look mom, no exception! self.assertSequenceEqual(["foo"], [tag.name for tag in node.tags.all()])
def test_ignores_tags_without_definition(self): node = factory.make_Node() make_lshw_result(node, b"<foo/>") tags = [ factory.make_Tag("foo", "/foo", populate=False), Tag(name="empty", definition=""), Tag(name="null", definition=None), ] populate_tags_for_single_node(tags, node) # Look mom, no exception! self.assertSequenceEqual(["foo"], [tag.name for tag in node.tags.all()])
def signal(self, request, version=None, mac=None): """Signal commissioning status. A commissioning node can call this to report progress of the commissioning process to the metadata server. Calling this from a node that is not Commissioning, Ready, or Failed Tests is an error. Signaling completion more than once is not an error; all but the first successful call are ignored. :param status: A commissioning status code. This can be "OK" (to signal that commissioning has completed successfully), or "FAILED" (to signal failure), or "WORKING" (for progress reports). :param script_result: If this call uploads files, this parameter must be provided and will be stored as the return value for the script which produced these files. :param error: An optional error string. If given, this will be stored (overwriting any previous error string), and displayed in the MAAS UI. If not given, any previous error string will be cleared. """ node = get_queried_node(request, for_mac=mac) status = get_mandatory_param(request.POST, 'status') if node.status not in self.signalable_states: raise NodeStateViolation( "Node wasn't commissioning (status is %s)" % NODE_STATUS_CHOICES_DICT[node.status]) if status not in self.signaling_statuses: raise MAASAPIBadRequest( "Unknown commissioning status: '%s'" % status) if node.status != NODE_STATUS.COMMISSIONING: # Already registered. Nothing to be done. return rc.ALL_OK self._store_commissioning_results(node, request) store_node_power_parameters(node, request) target_status = self.signaling_statuses.get(status) if target_status in (None, node.status): # No status change. Nothing to be done. return rc.ALL_OK node.status = target_status # When moving to a terminal state, remove the allocation. node.owner = None node.error = request.POST.get('error', '') # When moving to a successful terminal state, recalculate tags. populate_tags_for_single_node(Tag.objects.all(), node) # Done. node.save() return rc.ALL_OK
def test_ignores_tags_with_unrecognised_namespaces(self): node = factory.make_node() factory.make_node_commission_result( node, commissioningscript.LSHW_OUTPUT_NAME, 0, b"<foo/>") tags = [ factory.make_tag("foo", "/foo"), factory.make_tag("lou", "//nge:bar"), ] populate_tags_for_single_node(tags, node) # Look mom, no exception! self.assertSequenceEqual( ["foo"], [tag.name for tag in node.tags.all()])
def test_updates_node_with_all_applicable_tags(self): node = factory.make_Node() make_lshw_result(node, b"<foo/>") make_lldp_result(node, b"<bar/>") tags = [ factory.make_Tag("foo", "/foo", populate=False), factory.make_Tag("bar", "//lldp:bar", populate=False), factory.make_Tag("baz", "/foo/bar", populate=False), ] populate_tags_for_single_node(tags, node) self.assertItemsEqual(["foo", "bar"], [tag.name for tag in node.tags.all()])
def test_ignores_tags_without_definition(self): node = factory.make_node() factory.make_node_commission_result( node, commissioningscript.LSHW_OUTPUT_NAME, 0, b"<foo/>") tags = [ factory.make_tag("foo", "/foo"), Tag(name="empty", definition=""), Tag(name="null", definition=None), ] populate_tags_for_single_node(tags, node) # Look mom, no exception! self.assertSequenceEqual( ["foo"], [tag.name for tag in node.tags.all()])
def test_updates_node_with_all_applicable_tags(self): node = factory.make_node() factory.make_node_commission_result( node, commissioningscript.LSHW_OUTPUT_NAME, 0, b"<foo/>") factory.make_node_commission_result( node, commissioningscript.LLDP_OUTPUT_NAME, 0, b"<bar/>") tags = [ factory.make_tag("foo", "/foo"), factory.make_tag("bar", "//lldp:bar"), factory.make_tag("baz", "/foo/bar"), ] populate_tags_for_single_node(tags, node) self.assertItemsEqual( ["foo", "bar"], [tag.name for tag in node.tags.all()])