Beispiel #1
0
    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
Beispiel #2
0
 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([])
Beispiel #3
0
 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([])
Beispiel #4
0
 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()
Beispiel #5
0
 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()
Beispiel #6
0
 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()
Beispiel #7
0
 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()
Beispiel #8
0
 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()
Beispiel #9
0
 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([])
Beispiel #10
0
 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([])
Beispiel #11
0
    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