139 lines
5.4 KiB
Python
139 lines
5.4 KiB
Python
# Copyright (c) 2011 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.
|
|
|
|
"""
|
|
Manage hosts in the current zone.
|
|
"""
|
|
|
|
from oslo.config import cfg
|
|
|
|
from nova.openstack.common.gettextutils import _
|
|
from nova.openstack.common import log as logging
|
|
from nova.scheduler import host_manager
|
|
|
|
|
|
CONF = cfg.CONF
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class SolverSchedulerHostState(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 __init__(self, *args, **kwargs):
|
|
super(SolverSchedulerHostState, self).__init__(*args, **kwargs)
|
|
self.projects = []
|
|
|
|
def update_from_compute_node(self, compute):
|
|
super(SolverSchedulerHostState, self).update_from_compute_node(
|
|
compute)
|
|
# Track projects in the compute node
|
|
project_id_keys = [k for k in self.stats.keys() if
|
|
k.startswith("num_proj_")]
|
|
for key in project_id_keys:
|
|
project_id = key[9:]
|
|
if int(self.stats[key]) > 0:
|
|
self.projects.append(project_id)
|
|
|
|
def consume_from_instance(self, instance):
|
|
super(SolverSchedulerHostState, self).consume_from_instance(instance)
|
|
# Track projects in the compute node
|
|
project_id = instance.get('project_id')
|
|
if project_id not in self.projects:
|
|
self.projects.append(project_id)
|
|
|
|
|
|
class SolverSchedulerHostManager(host_manager.HostManager):
|
|
"""HostManager class for solver scheduler."""
|
|
|
|
# Can be overridden in a subclass
|
|
host_state_cls = SolverSchedulerHostState
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(SolverSchedulerHostManager, self).__init__(*args, **kwargs)
|
|
|
|
def get_hosts_stripping_ignored_and_forced(self, hosts,
|
|
filter_properties):
|
|
"""Filter hosts by stripping any ignored hosts and
|
|
matching any forced hosts or nodes.
|
|
"""
|
|
|
|
def _strip_ignore_hosts(host_map, hosts_to_ignore):
|
|
ignored_hosts = []
|
|
for host in hosts_to_ignore:
|
|
for (hostname, nodename) in host_map.keys():
|
|
if host == hostname:
|
|
del host_map[(hostname, nodename)]
|
|
ignored_hosts.append(host)
|
|
ignored_hosts_str = ', '.join(ignored_hosts)
|
|
msg = _('Host filter ignoring hosts: %s')
|
|
LOG.audit(msg % ignored_hosts_str)
|
|
|
|
def _match_forced_hosts(host_map, hosts_to_force):
|
|
forced_hosts = []
|
|
for (hostname, nodename) in host_map.keys():
|
|
if hostname not in hosts_to_force:
|
|
del host_map[(hostname, nodename)]
|
|
else:
|
|
forced_hosts.append(hostname)
|
|
if host_map:
|
|
forced_hosts_str = ', '.join(forced_hosts)
|
|
msg = _('Host filter forcing available hosts to %s')
|
|
else:
|
|
forced_hosts_str = ', '.join(hosts_to_force)
|
|
msg = _("No hosts matched due to not matching "
|
|
"'force_hosts' value of '%s'")
|
|
LOG.audit(msg % forced_hosts_str)
|
|
|
|
def _match_forced_nodes(host_map, nodes_to_force):
|
|
forced_nodes = []
|
|
for (hostname, nodename) in host_map.keys():
|
|
if nodename not in nodes_to_force:
|
|
del host_map[(hostname, nodename)]
|
|
else:
|
|
forced_nodes.append(nodename)
|
|
if host_map:
|
|
forced_nodes_str = ', '.join(forced_nodes)
|
|
msg = _('Host filter forcing available nodes to %s')
|
|
else:
|
|
forced_nodes_str = ', '.join(nodes_to_force)
|
|
msg = _("No nodes matched due to not matching "
|
|
"'force_nodes' value of '%s'")
|
|
LOG.audit(msg % forced_nodes_str)
|
|
|
|
ignore_hosts = filter_properties.get('ignore_hosts', [])
|
|
force_hosts = filter_properties.get('force_hosts', [])
|
|
force_nodes = filter_properties.get('force_nodes', [])
|
|
|
|
if ignore_hosts or force_hosts or force_nodes:
|
|
# NOTE(deva): we can't assume "host" is unique because
|
|
# one host may have many nodes.
|
|
name_to_cls_map = dict([((x.host, x.nodename), x) for x in hosts])
|
|
if ignore_hosts:
|
|
_strip_ignore_hosts(name_to_cls_map, ignore_hosts)
|
|
if not name_to_cls_map:
|
|
return []
|
|
# NOTE(deva): allow force_hosts and force_nodes independently
|
|
if force_hosts:
|
|
_match_forced_hosts(name_to_cls_map, force_hosts)
|
|
if force_nodes:
|
|
_match_forced_nodes(name_to_cls_map, force_nodes)
|
|
hosts = name_to_cls_map.itervalues()
|
|
|
|
return hosts
|