summaryrefslogtreecommitdiff
path: root/nova/scheduler/ironic_host_manager.py
blob: 84ead7d7a3110d16506a01d615d9d4d313b2118f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Copyright (c) 2012 NTT DOCOMO, INC.
# Copyright (c) 2011-2014 OpenStack Foundation
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

"""
Ironic host manager.

This host manager will consume all cpu's, disk space, and
ram from a host / node as it is supporting Baremetal hosts, which can not be
subdivided into multiple instances.
"""
from oslo_log import log as logging

import nova.conf
from nova import context as context_module
from nova import objects
from nova.objects import fields as obj_fields
from nova.scheduler import host_manager

CONF = nova.conf.CONF

LOG = logging.getLogger(__name__)


class IronicNodeState(host_manager.HostState):
    """Mutable and immutable information tracked for a host.
    This is an attempt to remove the ad-hoc data structures
    previously used and lock down access.
    """

    def _update_from_compute_node(self, compute):
        """Update information about a host from a ComputeNode object."""

        # NOTE(jichenjc): if the compute record is just created but not updated
        # some field such as free_disk_gb can be None
        if 'free_disk_gb' not in compute or compute.free_disk_gb is None:
            LOG.debug('Ignoring compute node %s as its usage has not been '
                      'updated yet.', compute.uuid)
            return

        self.vcpus_total = compute.vcpus
        self.vcpus_used = compute.vcpus_used

        self.free_ram_mb = compute.free_ram_mb
        self.total_usable_ram_mb = compute.memory_mb
        self.free_disk_mb = compute.free_disk_gb * 1024

        self.stats = compute.stats or {}

        self.total_usable_disk_gb = compute.local_gb
        self.hypervisor_type = compute.hypervisor_type
        self.hypervisor_version = compute.hypervisor_version
        self.hypervisor_hostname = compute.hypervisor_hostname
        self.cpu_info = compute.cpu_info
        if compute.supported_hv_specs:
            self.supported_instances = [spec.to_list() for spec
                                        in compute.supported_hv_specs]
        else:
            self.supported_instances = []

        # update allocation ratios given by the ComputeNode object
        self.cpu_allocation_ratio = compute.cpu_allocation_ratio
        self.ram_allocation_ratio = compute.ram_allocation_ratio
        self.disk_allocation_ratio = compute.disk_allocation_ratio

        self.updated = compute.updated_at

    def _locked_consume_from_request(self, spec_obj):
        """Consume nodes entire resources regardless of instance request."""
        self.free_ram_mb = 0
        self.free_disk_mb = 0
        self.vcpus_used = self.vcpus_total


class IronicHostManager(host_manager.HostManager):
    """Ironic HostManager class."""

    @staticmethod
    def _is_ironic_compute(compute):
        ht = compute.hypervisor_type if 'hypervisor_type' in compute else None
        return ht == obj_fields.HVType.IRONIC

    def _load_filters(self):
        if CONF.filter_scheduler.use_baremetal_filters:
            return CONF.filter_scheduler.baremetal_enabled_filters
        return super(IronicHostManager, self)._load_filters()

    def host_state_cls(self, host, node, cell, **kwargs):
        """Factory function/property to create a new HostState."""
        compute = kwargs.get('compute')
        if compute and self._is_ironic_compute(compute):
            return IronicNodeState(host, node, cell)
        else:
            return host_manager.HostState(host, node, cell)

    def _init_instance_info(self, computes_by_cell=None):
        """Ironic hosts should not pass instance info."""
        context = context_module.RequestContext()
        self._load_cells(context)
        if not computes_by_cell:
            computes_by_cell = {}
            for cell in self.cells:
                with context_module.target_cell(context, cell) as cctxt:
                    computes_by_cell[cell] = (
                        objects.ComputeNodeList.get_all(cctxt).objects)

        non_ironic_computes = {cell: [c for c in compute_nodes
                                      if not self._is_ironic_compute(c)]
                               for cell, compute_nodes in
                               computes_by_cell.items()}
        super(IronicHostManager, self)._init_instance_info(non_ironic_computes)

    def _get_instance_info(self, context, compute):
        """Ironic hosts should not pass instance info."""

        if compute and self._is_ironic_compute(compute):
            return {}
        else:
            return super(IronicHostManager, self)._get_instance_info(context,
                                                                     compute)