~rvb/maas/transaction-1.7-bug-1409852

« back to all changes in this revision

Viewing changes to src/maasserver/models/node.py

merged upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
50
50
import djorm_pgarray.fields
51
51
from maasserver import DefaultMeta
52
52
from maasserver.clusterrpc.dhcp import update_host_maps
53
 
from maasserver.clusterrpc.power import power_on_nodes
 
53
from maasserver.clusterrpc.power import (
 
54
    power_off_nodes,
 
55
    power_on_nodes,
 
56
    )
54
57
from maasserver.enum import (
55
58
    NODE_BOOT,
56
59
    NODE_BOOT_CHOICES,
75
78
from maasserver.models.config import Config
76
79
from maasserver.models.dhcplease import DHCPLease
77
80
from maasserver.models.licensekey import LicenseKey
 
81
from maasserver.models.macaddress import update_mac_cluster_interfaces
78
82
from maasserver.models.staticipaddress import (
79
83
    StaticIPAddress,
80
84
    StaticIPAddressExhaustion,
91
95
from provisioningserver.drivers.osystem import OperatingSystemRegistry
92
96
from provisioningserver.logger import get_maas_logger
93
97
from provisioningserver.rpc.exceptions import MultipleFailures
94
 
from provisioningserver.tasks import (
95
 
    power_off,
96
 
    remove_dhcp_host_map,
97
 
    )
 
98
from provisioningserver.tasks import remove_dhcp_host_map
98
99
from provisioningserver.utils import warn_deprecated
99
100
from provisioningserver.utils.enum import map_enum_reverse
100
101
from provisioningserver.utils.twisted import reactor_sync
399
400
        :return: Those Nodes for which shutdown was actually requested.
400
401
        :rtype: list
401
402
        """
402
 
        maaslog.debug("Stopping node(s): %s", ids)
 
403
        # Obtain node model objects for each node specified.
403
404
        nodes = self.get_nodes(by_user, NODE_PERMISSION.EDIT, ids=ids)
404
 
        processed_nodes = []
405
 
        for node in nodes:
406
 
            power_params = node.get_effective_power_parameters()
407
 
            try:
408
 
                node_power_type = node.get_effective_power_type()
409
 
            except UnknownPowerType:
410
 
                # Skip the rest of the loop to avoid creating a power
411
 
                # event for a node that we can't power down.
412
 
                maaslog.warning(
413
 
                    "%s: Node has an unknown power type. Not creating "
414
 
                    "power down event.", node.hostname)
415
 
                continue
416
 
            power_params['power_off_mode'] = stop_mode
417
 
            # WAKE_ON_LAN does not support poweroff.
418
 
            if node_power_type != 'ether_wake':
419
 
                maaslog.info(
420
 
                    "%s: Asking cluster to power off node", node.hostname)
421
 
                power_off.apply_async(
422
 
                    queue=node.work_queue, args=[node_power_type],
423
 
                    kwargs=power_params)
424
 
            processed_nodes.append(node)
425
 
        return processed_nodes
 
405
 
 
406
        # Helper function to whittle the list of nodes down to those that we
 
407
        # can actually stop, and keep hold of their power control info.
 
408
        def gen_power_info(nodes):
 
409
            for node in nodes:
 
410
                power_info = node.get_effective_power_info()
 
411
                if power_info.can_be_stopped:
 
412
                    # Smuggle in a hint about how to power-off the node.
 
413
                    power_info.power_parameters['power_off_mode'] = stop_mode
 
414
                    yield node, power_info
 
415
 
 
416
        # Create info that we can pass into the reactor (no model objects).
 
417
        nodes_start_info = list(
 
418
            (node.system_id, node.hostname, node.nodegroup.uuid, power_info)
 
419
            for node, power_info in gen_power_info(nodes))
 
420
 
 
421
        # Request that these nodes be powered off.
 
422
        deferreds = power_off_nodes(nodes_start_info)
 
423
 
 
424
        # Cap these Deferreds off so that Twisted does not complain about
 
425
        # unhandled errors. We just log errors for now; there are other
 
426
        # channels that will report failures in more detail.
 
427
        with reactor_sync():
 
428
            for system_id, d in deferreds.viewitems():
 
429
                d.addErrback(twisted.python.log.err)
 
430
 
 
431
        # Return a list of those nodes that we've send power commands for.
 
432
        return list(node for node in nodes if node.system_id in deferreds)
426
433
 
427
434
    def start_nodes(self, ids, by_user, user_data=None):
428
435
        """Request on given user's behalf that the given nodes be started up.
500
507
                    yield node, power_info
501
508
 
502
509
        # Create info that we can pass into the reactor (no model objects)
503
 
        nodes_start_info = [
 
510
        nodes_start_info = list(
504
511
            (node.system_id, node.hostname, node.nodegroup.uuid, power_info)
505
 
            for node, power_info in gen_power_info(nodes)
506
 
        ]
 
512
            for node, power_info in gen_power_info(nodes))
507
513
 
508
514
        # Request that these nodes be powered on.
509
515
        deferreds = power_on_nodes(nodes_start_info)
515
521
            for system_id, d in deferreds.viewitems():
516
522
                d.addErrback(twisted.python.log.err)
517
523
 
518
 
        return list(nodes)
 
524
        # Return a list of those nodes that we've send power commands for.
 
525
        return list(node for node in nodes if node.system_id in deferreds)
519
526
 
520
527
 
521
528
def patch_pgarray_types():
876
883
 
877
884
        mac = MACAddress(mac_address=mac_address, node=self)
878
885
        mac.save()
 
886
 
 
887
        # See if there's a lease for this MAC and set its
 
888
        # cluster_interface if so.
 
889
        nodegroup_leases = {
 
890
            lease.ip: lease.mac
 
891
            for lease in DHCPLease.objects.filter(nodegroup=self.nodegroup)}
 
892
        update_mac_cluster_interfaces(nodegroup_leases, self.nodegroup)
 
893
 
879
894
        return mac
880
895
 
881
896
    def remove_mac_address(self, mac_address):