Log.warn deprecated in python3, and pep8 errors resolved.

Change-Id: I44c9cbf71b033a2338746c25c50a041aeae4c825
This commit is contained in:
skseeker 2016-02-07 00:12:38 +05:30
parent 3aae5eda0a
commit 63e2de012e
45 changed files with 293 additions and 245 deletions

View File

@ -24,13 +24,13 @@ from nova_solverscheduler.scheduler.solvers import costs
from nova_solverscheduler import solver_scheduler_exception as exception
scheduler_solver_opts = [
cfg.ListOpt('scheduler_solver_costs',
default=['RamCost'],
help='Which cost matrices to use in the '
'scheduler solver.'),
cfg.ListOpt('scheduler_solver_constraints',
default=['ActiveHostsConstraint'],
help='Which constraints to use in scheduler solver'),
cfg.ListOpt('scheduler_solver_costs',
default=['RamCost'],
help='Which cost matrices to use in the '
'scheduler solver.'),
cfg.ListOpt('scheduler_solver_constraints',
default=['ActiveHostsConstraint'],
help='Which constraints to use in scheduler solver'),
]
CONF = cfg.CONF
@ -38,6 +38,7 @@ CONF.register_opts(scheduler_solver_opts, group='solver_scheduler')
class BaseHostSolver(object):
"""Base class for host constraint solvers."""
def __init__(self):
@ -54,7 +55,7 @@ class BaseHostSolver(object):
for cost in expected_costs:
if cost in all_cost_names:
cost_classes.append(all_cost_classes[
all_cost_names.index(cost)])
all_cost_names.index(cost)])
else:
bad_cost_names.append(cost)
if bad_cost_names:
@ -70,17 +71,17 @@ class BaseHostSolver(object):
all_constraint_classes = constraint_handler.get_all_classes()
all_constraint_names = [c.__name__ for c in all_constraint_classes]
expected_constraints = (
CONF.solver_scheduler.scheduler_solver_constraints)
CONF.solver_scheduler.scheduler_solver_constraints)
for constraint in expected_constraints:
if constraint in all_constraint_names:
constraint_classes.append(all_constraint_classes[
all_constraint_names.index(constraint)])
all_constraint_names.index(constraint)])
else:
bad_constraint_names.append(constraint)
if bad_constraint_names:
msg = ", ".join(bad_constraint_names)
raise exception.SchedulerSolverConstraintNotFound(
constraint_name=msg)
constraint_name=msg)
return constraint_classes
def solve(self, hosts, filter_properties):

View File

@ -22,6 +22,7 @@ from nova.scheduler import filters
class BaseConstraint(object):
"""Base class for constraints."""
precedence = 0
@ -32,6 +33,7 @@ class BaseConstraint(object):
class BaseLinearConstraint(BaseConstraint):
"""Base class of LP constraint."""
def __init__(self):
@ -59,6 +61,7 @@ class BaseLinearConstraint(BaseConstraint):
class BaseFilterConstraint(BaseLinearConstraint):
"""Base class for constraints that correspond to 1-time host filters."""
# override this in sub classes
@ -73,11 +76,11 @@ class BaseFilterConstraint(BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts):
host_passes = self.host_filter.host_passes(
hosts[i], filter_properties)
hosts[i], filter_properties)
if not host_passes:
constraint_matrix[i] = [False for j in xrange(num_instances)]
@ -85,6 +88,7 @@ class BaseFilterConstraint(BaseLinearConstraint):
class ConstraintHandler(loadables.BaseLoader):
def __init__(self):
super(ConstraintHandler, self).__init__(BaseConstraint)

View File

@ -18,5 +18,6 @@ from nova_solverscheduler.scheduler.solvers import constraints
class ActiveHostsConstraint(constraints.BaseFilterConstraint):
"""Constraint that only allows active hosts to be selected."""
host_filter_cls = compute_filter.ComputeFilter

View File

@ -18,6 +18,7 @@ from nova_solverscheduler.scheduler.solvers import constraints
class SameHostConstraint(constraints.BaseFilterConstraint):
"""Schedule the instance on the same host as another instance in a set
of instances.
"""
@ -25,10 +26,12 @@ class SameHostConstraint(constraints.BaseFilterConstraint):
class DifferentHostConstraint(constraints.BaseFilterConstraint):
"""Schedule the instance on a different host from a set of instances."""
host_filter_cls = affinity_filter.DifferentHostFilter
class SimpleCidrAffinityConstraint(constraints.BaseFilterConstraint):
"""Schedule the instance on a host with a particular cidr."""
host_filter_cls = affinity_filter.SimpleCIDRAffinityFilter

View File

@ -27,6 +27,7 @@ LOG = logging.getLogger(__name__)
class AggregateDiskConstraint(disk_constraint.DiskConstraint):
"""AggregateDiskConstraint with per-aggregate disk subscription flag.
Fall back to global disk_allocation_ratio if no per-aggregate setting
@ -35,11 +36,11 @@ class AggregateDiskConstraint(disk_constraint.DiskConstraint):
def _get_disk_allocation_ratio(self, host_state, filter_properties):
aggregate_vals = utils.aggregate_values_from_key(
host_state, 'disk_allocation_ratio')
host_state, 'disk_allocation_ratio')
try:
ratio = utils.validate_num_values(
aggregate_vals, CONF.disk_allocation_ratio, cast_to=float)
aggregate_vals, CONF.disk_allocation_ratio, cast_to=float)
except ValueError as e:
LOG.warning(_LW("Could not decode disk_allocation_ratio: '%s'"), e)
ratio = CONF.disk_allocation_ratio

View File

@ -18,7 +18,8 @@ from nova_solverscheduler.scheduler.solvers import constraints
class AggregateImagePropertiesIsolationConstraint(
constraints.BaseFilterConstraint):
constraints.BaseFilterConstraint):
"""AggregateImagePropertiesIsolation works with image properties."""
host_filter_cls = aggregate_image_properties_isolation.\
AggregateImagePropertiesIsolation
AggregateImagePropertiesIsolation

View File

@ -18,6 +18,7 @@ from nova_solverscheduler.scheduler.solvers import constraints
class AggregateInstanceExtraSpecsConstraint(constraints.BaseFilterConstraint):
"""AggregateInstanceExtraSpecsFilter works with InstanceType records."""
host_filter_cls = aggregate_instance_extra_specs.\
AggregateInstanceExtraSpecsFilter
AggregateInstanceExtraSpecsFilter

View File

@ -18,7 +18,8 @@ from nova_solverscheduler.scheduler.solvers import constraints
class AggregateMultiTenancyIsolationConstraint(
constraints.BaseFilterConstraint):
constraints.BaseFilterConstraint):
"""Isolate tenants in specific aggregates."""
host_filter_cls = aggregate_multitenancy_isolation.\
AggregateMultiTenancyIsolation
AggregateMultiTenancyIsolation

View File

@ -18,7 +18,7 @@ from oslo_log import log as logging
from nova.i18n import _LW
from nova_solverscheduler.scheduler.solvers.constraints \
import num_instances_constraint
import num_instances_constraint
from nova_solverscheduler.scheduler.solvers import utils
CONF = cfg.CONF
@ -30,6 +30,7 @@ LOG = logging.getLogger(__name__)
class AggregateNumInstancesConstraint(
num_instances_constraint.NumInstancesConstraint):
"""AggregateNumInstancesConstraint with per-aggregate max num instances
per host.
@ -39,11 +40,11 @@ class AggregateNumInstancesConstraint(
def _get_max_instances_per_host(self, host_state, filter_properties):
aggregate_vals = utils.aggregate_values_from_key(
host_state, 'max_instances_per_host')
host_state, 'max_instances_per_host')
try:
value = utils.validate_num_values(
aggregate_vals, CONF.max_instances_per_host, cast_to=int)
aggregate_vals, CONF.max_instances_per_host, cast_to=int)
except ValueError as e:
LOG.warning(_LW("Could not decode max_instances_per_host: '%s'"),
e)

View File

@ -27,6 +27,7 @@ LOG = logging.getLogger(__name__)
class AggregateRamConstraint(ram_constraint.RamConstraint):
"""AggregateRamConstraint with per-aggregate ram subscription flag.
Fall back to global ram_allocation_ratio if no per-aggregate setting found.
@ -34,11 +35,11 @@ class AggregateRamConstraint(ram_constraint.RamConstraint):
def _get_ram_allocation_ratio(self, host_state, filter_properties):
aggregate_vals = utils.aggregate_values_from_key(
host_state, 'ram_allocation_ratio')
host_state, 'ram_allocation_ratio')
try:
ratio = utils.validate_num_values(
aggregate_vals, CONF.ram_allocation_ratio, cast_to=float)
aggregate_vals, CONF.ram_allocation_ratio, cast_to=float)
except ValueError as e:
LOG.warning(_LW("Could not decode ram_allocation_ratio: '%s'"), e)
ratio = CONF.ram_allocation_ratio

View File

@ -18,6 +18,7 @@ from nova_solverscheduler.scheduler.solvers import constraints
class AggregateTypeAffinityConstraint(constraints.BaseFilterConstraint):
"""AggregateTypeAffinityFilter limits instance_type by aggregate
return True if no instance_type key is set or if the aggregate metadata

View File

@ -27,6 +27,7 @@ LOG = logging.getLogger(__name__)
class AggregateVcpuConstraint(vcpu_constraint.VcpuConstraint):
"""AggregateVcpuConstraint with per-aggregate CPU subscription flag.
Fall back to global cpu_allocation_ratio if no per-aggregate setting found.
@ -34,11 +35,11 @@ class AggregateVcpuConstraint(vcpu_constraint.VcpuConstraint):
def _get_cpu_allocation_ratio(self, host_state, filter_properties):
aggregate_vals = utils.aggregate_values_from_key(
host_state, 'cpu_allocation_ratio')
host_state, 'cpu_allocation_ratio')
try:
ratio = utils.validate_num_values(
aggregate_vals, CONF.cpu_allocation_ratio, cast_to=float)
aggregate_vals, CONF.cpu_allocation_ratio, cast_to=float)
except ValueError as e:
LOG.warning(_LW("Could not decode cpu_allocation_ratio: '%s'"), e)
ratio = CONF.cpu_allocation_ratio

View File

@ -18,6 +18,7 @@ from nova_solverscheduler.scheduler.solvers import constraints
class AvailabilityZoneConstraint(constraints.BaseFilterConstraint):
"""Selects Hosts by availability zone.
Works with aggregate metadata availability zones, using the key

View File

@ -18,5 +18,6 @@ from nova_solverscheduler.scheduler.solvers import constraints
class ComputeCapabilitiesConstraint(constraints.BaseFilterConstraint):
"""Hard-coded to work with InstanceType records."""
host_filter_cls = compute_capabilities_filter.ComputeCapabilitiesFilter

View File

@ -27,6 +27,7 @@ LOG = logging.getLogger(__name__)
class DiskConstraint(constraints.BaseLinearConstraint):
"""Constraint of the maximum total disk demand acceptable on each host."""
def _get_disk_allocation_ratio(self, host_state, filter_properties):
@ -37,26 +38,26 @@ class DiskConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
# get requested disk
instance_type = filter_properties.get('instance_type') or {}
requested_disk = (1024 * (instance_type.get('root_gb', 0) +
instance_type.get('ephemeral_gb', 0)) +
instance_type.get('swap', 0))
instance_type.get('swap', 0))
for inst_type_key in ['root_gb', 'ephemeral_gb', 'swap']:
if inst_type_key not in instance_type:
LOG.warn(_LW("Disk information of requested instances\' %s "
"is incomplete, use 0 as the requested size."),
inst_type_key)
LOG.warning(_LW("Disk information of requested instances\' %s "
"is incomplete, use 0 as the requested size."),
inst_type_key)
if requested_disk <= 0:
LOG.warn(_LW("DiskConstraint is skipped because requested "
LOG.warning(_LW("DiskConstraint is skipped because requested "
"instance disk size is 0 or invalid."))
return constraint_matrix
for i in xrange(num_hosts):
disk_allocation_ratio = self._get_disk_allocation_ratio(
hosts[i], filter_properties)
hosts[i], filter_properties)
# get usable disk
free_disk_mb = hosts[i].free_disk_mb
total_usable_disk_mb = hosts[i].total_usable_disk_gb * 1024
@ -68,13 +69,13 @@ class DiskConstraint(constraints.BaseLinearConstraint):
if acceptable_num_instances < num_instances:
inacceptable_num = (num_instances - acceptable_num_instances)
constraint_matrix[i] = (
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
LOG.debug("%(host)s can accept %(num)s requested instances "
"according to DiskConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
"according to DiskConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
disk_gb_limit = disk_mb_limit / 1024
hosts[i].limits['disk_gb'] = disk_gb_limit

View File

@ -23,6 +23,7 @@ LOG = logging.getLogger(__name__)
class ExactDiskConstraint(constraints.BaseLinearConstraint):
"""Constraint that selects hosts with exact amount of disk space."""
def get_constraint_matrix(self, hosts, filter_properties):
@ -30,27 +31,27 @@ class ExactDiskConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
# get requested disk
instance_type = filter_properties.get('instance_type') or {}
requested_disk = (1024 * (instance_type.get('root_gb', 0) +
instance_type.get('ephemeral_gb', 0)) +
instance_type.get('swap', 0))
instance_type.get('swap', 0))
for inst_type_key in ['root_gb', 'ephemeral_gb', 'swap']:
if inst_type_key not in instance_type:
LOG.warn(_LW("Disk information of requested instances\' %s "
"is incomplete, use 0 as the requested size."),
inst_type_key)
LOG.warning(_LW("Disk information of requested instances\' %s "
"is incomplete, use 0 as the requested size."),
inst_type_key)
if requested_disk <= 0:
LOG.warn(_LW("ExactDiskConstraint is skipped because requested "
LOG.warning(_LW("ExactDiskConstraint is skipped because requested "
"instance disk size is 0 or invalid."))
return constraint_matrix
for i in xrange(num_hosts):
if requested_disk == hosts[i].free_disk_mb:
constraint_matrix[i] = (
[True] + [False for j in xrange(num_instances - 1)])
[True] + [False for j in xrange(num_instances - 1)])
else:
constraint_matrix[i] = [False for j in xrange(num_instances)]
LOG.debug("%(host)s does not have exactly %(requested_disk)s "

View File

@ -23,6 +23,7 @@ LOG = logging.getLogger(__name__)
class ExactRamConstraint(constraints.BaseLinearConstraint):
"""Constraint that selects hosts with exact amount of RAM available."""
def get_constraint_matrix(self, hosts, filter_properties):
@ -30,23 +31,23 @@ class ExactRamConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
# get requested ram
instance_type = filter_properties.get('instance_type') or {}
requested_ram = instance_type.get('memory_mb', 0)
if 'memory_mb' not in instance_type:
LOG.warn(_LW("No information about requested instances\' RAM size "
"was found, default value (0) is used."))
LOG.warning(_LW("No information about requested instances\' RAM size "
"was found, default value (0) is used."))
if requested_ram <= 0:
LOG.warn(_LW("ExactRamConstraint is skipped because requested "
LOG.warning(_LW("ExactRamConstraint is skipped because requested "
"instance RAM size is 0 or invalid."))
return constraint_matrix
for i in xrange(num_hosts):
if requested_ram == hosts[i].free_ram_mb:
constraint_matrix[i] = (
[True] + [False for j in xrange(num_instances - 1)])
[True] + [False for j in xrange(num_instances - 1)])
else:
constraint_matrix[i] = [False for j in xrange(num_instances)]
LOG.debug("%(host)s does not have exactly %(requested_ram)s MB"

View File

@ -22,6 +22,7 @@ LOG = logging.getLogger(__name__)
class ExactVcpuConstraint(constraints.BaseLinearConstraint):
"""Constraint that selects hosts with exact number of vCPUs."""
def get_constraint_matrix(self, hosts, filter_properties):
@ -29,7 +30,7 @@ class ExactVcpuConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
# get requested vcpus
instance_type = filter_properties.get('instance_type') or {}
@ -38,15 +39,15 @@ class ExactVcpuConstraint(constraints.BaseLinearConstraint):
else:
instance_vcpus = instance_type['vcpus']
if instance_vcpus <= 0:
LOG.warn(_LW("ExactVcpuConstraint is skipped because requested "
"instance vCPU number is 0 or invalid."))
LOG.warning(_LW("ExactVcpuConstraint is skipped because requested "
"instance vCPU number is 0 or invalid."))
return constraint_matrix
for i in xrange(num_hosts):
# get available vcpus
if not hosts[i].vcpus_total:
LOG.warn(_LW("vCPUs of %(host)s not set; assuming CPU "
"collection broken."), {'host': hosts[i]})
LOG.warning(_LW("vCPUs of %(host)s not set; assuming CPU "
"collection broken."), {'host': hosts[i]})
constraint_matrix[i] = [False for j in xrange(num_instances)]
continue
else:
@ -54,7 +55,7 @@ class ExactVcpuConstraint(constraints.BaseLinearConstraint):
if instance_vcpus == usable_vcpus:
constraint_matrix[i] = (
[True] + [False for j in xrange(num_instances - 1)])
[True] + [False for j in xrange(num_instances - 1)])
else:
constraint_matrix[i] = [False for j in xrange(num_instances)]
LOG.debug("%(host)s does not have exactly %(requested_num)s "

View File

@ -18,6 +18,7 @@ from nova_solverscheduler.scheduler.solvers import constraints
class ImagePropertiesConstraint(constraints.BaseFilterConstraint):
"""Select compute nodes that satisfy instance image properties.
The ImagePropertiesConstraint selects compute nodes that satisfy

View File

@ -25,6 +25,7 @@ CONF.import_opt('max_io_ops_per_host', 'nova.scheduler.filters.io_ops_filter')
class IoOpsConstraint(constraints.BaseLinearConstraint):
"""A constraint to ensure only those hosts are selected whose number of
concurrent I/O operations are within a set threshold.
"""
@ -36,7 +37,7 @@ class IoOpsConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts):
num_io_ops = hosts[i].num_io_ops
@ -47,12 +48,12 @@ class IoOpsConstraint(constraints.BaseLinearConstraint):
if acceptable_num_instances < num_instances:
inacceptable_num = (num_instances - acceptable_num_instances)
constraint_matrix[i] = (
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
LOG.debug("%(host)s can accept %(num)s requested instances "
"according to IoOpsConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
"according to IoOpsConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
return constraint_matrix

View File

@ -18,5 +18,6 @@ from nova_solverscheduler.scheduler.solvers import constraints
class IsolatedHostsConstraint(constraints.BaseFilterConstraint):
"""Keep specified images to selected hosts."""
host_filter_cls = isolated_hosts_filter.IsolatedHostsFilter

View File

@ -18,6 +18,7 @@ from nova_solverscheduler.scheduler.solvers import constraints
class JsonConstraint(constraints.BaseFilterConstraint):
"""Constraint to allow simple JSON-based grammar for
selecting hosts.
"""

View File

@ -18,6 +18,7 @@ from nova_solverscheduler.scheduler.solvers import constraints
class MetricsConstraint(constraints.BaseFilterConstraint):
"""This constraint is used to filter out those hosts which don't have the
corresponding metrics.
"""

View File

@ -17,6 +17,7 @@ from nova_solverscheduler.scheduler.solvers import constraints
class NoConstraint(constraints.BaseLinearConstraint):
"""No-op constraint that returns empty linear constraint components."""
def get_constraint_matrix(self, hosts, filter_properties):
@ -24,6 +25,6 @@ class NoConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
return constraint_matrix

View File

@ -20,12 +20,13 @@ from nova_solverscheduler.scheduler.solvers import constraints
CONF = cfg.CONF
CONF.import_opt("max_instances_per_host",
"nova.scheduler.filters.num_instances_filter")
"nova.scheduler.filters.num_instances_filter")
LOG = logging.getLogger(__name__)
class NumInstancesConstraint(constraints.BaseLinearConstraint):
"""Constraint that specifies the maximum number of instances that
each host can launch.
"""
@ -38,7 +39,7 @@ class NumInstancesConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts):
max_instances = self._get_max_instances_per_host(hosts[i],
@ -50,12 +51,12 @@ class NumInstancesConstraint(constraints.BaseLinearConstraint):
if acceptable_num_instances < num_instances:
inacceptable_num = num_instances - acceptable_num_instances
constraint_matrix[i] = (
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
LOG.debug("%(host)s can accept %(num)s requested instances "
"according to NumInstancesConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
"according to NumInstancesConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
return constraint_matrix

View File

@ -24,6 +24,7 @@ LOG = logging.getLogger(__name__)
class NUMATopologyConstraint(constraints.BaseLinearConstraint):
"""Constraint on requested NUMA topology."""
def __init__(self):
@ -47,23 +48,23 @@ class NUMATopologyConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts):
host_state = copy.deepcopy(hosts[i])
acceptable_instance_num = self._get_acceptable_instance_num(
host_state, filter_properties, num_instances)
host_state, filter_properties, num_instances)
if acceptable_instance_num < num_instances:
inacceptable_num = num_instances - acceptable_instance_num
constraint_matrix[i] = (
[True for j in xrange(acceptable_instance_num)] +
[False for j in xrange(inacceptable_num)])
[True for j in xrange(acceptable_instance_num)] +
[False for j in xrange(inacceptable_num)])
LOG.debug("%(host)s can accept %(num)s requested instances "
"according to NUMATopologyConstraint.",
{'host': hosts[i],
'num': acceptable_instance_num})
"according to NUMATopologyConstraint.",
{'host': hosts[i],
'num': acceptable_instance_num})
numa_topology_limit = host_state.limits.get('numa_topology')
if numa_topology_limit:

View File

@ -24,6 +24,7 @@ LOG = logging.getLogger(__name__)
class PciPassthroughConstraint(constraints.BaseLinearConstraint):
"""Constraint that schedules instances on a host if the host has devices
to meet the device requests in the 'extra_specs' for the flavor.
@ -38,7 +39,7 @@ class PciPassthroughConstraint(constraints.BaseLinearConstraint):
"""
def _get_acceptable_pci_requests_times(self, max_times_to_try,
pci_requests, host_pci_stats):
pci_requests, host_pci_stats):
acceptable_times = 0
while acceptable_times < max_times_to_try:
if host_pci_stats.support_requests(pci_requests):
@ -53,29 +54,29 @@ class PciPassthroughConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
pci_requests = filter_properties.get('pci_requests')
if not pci_requests:
LOG.warn(_LW("PciPassthroughConstraint check is skipped because "
LOG.warning(_LW("PciPassthroughConstraint check is skipped because "
"requested instance PCI requests is unavailable."))
return constraint_matrix
for i in xrange(num_hosts):
host_pci_stats = copy.deepcopy(hosts[i].pci_stats)
acceptable_num_instances = (
self._get_acceptable_pci_requests_times(num_instances,
pci_requests, host_pci_stats))
self._get_acceptable_pci_requests_times(num_instances,
pci_requests, host_pci_stats))
if acceptable_num_instances < num_instances:
inacceptable_num = num_instances - acceptable_num_instances
constraint_matrix[i] = (
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
LOG.debug("%(host)s can accept %(num)s requested instances "
"according to PciPassthroughConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
"according to PciPassthroughConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
return constraint_matrix

View File

@ -25,6 +25,7 @@ LOG = logging.getLogger(__name__)
class SameRackConstraint(constraints.BaseLinearConstraint):
"""Place instances in the same racks as those of specified instances.
If the specified instances are in hosts without rack config, then place
instances in the same hosts as those of specified instances.
@ -35,7 +36,7 @@ class SameRackConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
scheduler_hints = filter_properties.get('scheduler_hints') or {}
affinity_uuids = scheduler_hints.get('same_rack', [])
@ -63,19 +64,20 @@ class SameRackConstraint(constraints.BaseLinearConstraint):
host_racks = host_racks_map.get(host_name, set([]))
if host_name in affinity_hosts:
LOG.debug(_("%(host)s passed same-rack check."),
{'host': host_name})
{'host': host_name})
continue
elif (len(host_racks) == 0) or any([rack not in affinity_racks
for rack in host_racks]):
constraint_matrix[i] = [False for j in xrange(num_instances)]
else:
LOG.debug(_("%(host)s passed same-rack check."),
{'host': host_name})
{'host': host_name})
return constraint_matrix
class DifferentRackConstraint(constraints.BaseLinearConstraint):
"""Place instances in different racks as those of specified instances.
If the specified instances are in hosts without rack config, then place
instances in different hosts as those of specified instances.
@ -86,7 +88,7 @@ class DifferentRackConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
scheduler_hints = filter_properties.get('scheduler_hints') or {}
affinity_uuids = scheduler_hints.get('different_rack', [])
@ -116,6 +118,6 @@ class DifferentRackConstraint(constraints.BaseLinearConstraint):
host_name in affinity_hosts):
constraint_matrix[i] = [False for j in xrange(num_instances)]
LOG.debug(_("%(host)s didnot pass different-rack check."),
{'host': host_name})
{'host': host_name})
return constraint_matrix

View File

@ -27,6 +27,7 @@ LOG = logging.getLogger(__name__)
class RamConstraint(constraints.BaseLinearConstraint):
"""Constraint of the total ram demand acceptable on each host."""
def _get_ram_allocation_ratio(self, host_state, filter_properties):
@ -37,22 +38,22 @@ class RamConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
# get requested ram
instance_type = filter_properties.get('instance_type') or {}
requested_ram = instance_type.get('memory_mb', 0)
if 'memory_mb' not in instance_type:
LOG.warn(_LW("No information about requested instances\' RAM size "
"was found, default value (0) is used."))
LOG.warning(_LW("No information about requested instances\' RAM size "
"was found, default value (0) is used."))
if requested_ram <= 0:
LOG.warn(_LW("RamConstraint is skipped because requested "
LOG.warning(_LW("RamConstraint is skipped because requested "
"instance RAM size is 0 or invalid."))
return constraint_matrix
for i in xrange(num_hosts):
ram_allocation_ratio = self._get_ram_allocation_ratio(
hosts[i], filter_properties)
hosts[i], filter_properties)
# get available ram
free_ram_mb = hosts[i].free_ram_mb
total_usable_ram_mb = hosts[i].total_usable_ram_mb
@ -64,13 +65,13 @@ class RamConstraint(constraints.BaseLinearConstraint):
if acceptable_num_instances < num_instances:
inacceptable_num = num_instances - acceptable_num_instances
constraint_matrix[i] = (
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
LOG.debug("%(host)s can accept %(num)s requested instances "
"according to RamConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
"according to RamConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
hosts[i].limits['memory_mb'] = memory_mb_limit

View File

@ -18,5 +18,6 @@ from nova_solverscheduler.scheduler.solvers import constraints
class RetryConstraint(constraints.BaseFilterConstraint):
"""Selects nodes that have not been attempted for scheduling purposes."""
host_filter_cls = retry_filter.RetryFilter

View File

@ -21,6 +21,7 @@ LOG = logging.getLogger(__name__)
class ServerGroupAffinityConstraint(constraints.BaseLinearConstraint):
"""Force to select hosts which host given server group."""
def __init__(self, *args, **kwargs):
@ -32,7 +33,7 @@ class ServerGroupAffinityConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
policies = filter_properties.get('group_policies', [])
if self.policy_name not in policies:
@ -45,8 +46,8 @@ class ServerGroupAffinityConstraint(constraints.BaseLinearConstraint):
if not group_hosts:
constraint_matrix = [
([False for j in xrange(num_instances - 1)] + [True])
for i in xrange(num_hosts)]
([False for j in xrange(num_instances - 1)] + [True])
for i in xrange(num_hosts)]
else:
for i in xrange(num_hosts):
if hosts[i].host not in group_hosts:
@ -60,11 +61,12 @@ class ServerGroupAffinityConstraint(constraints.BaseLinearConstraint):
class ServerGroupAntiAffinityConstraint(constraints.BaseLinearConstraint):
"""Force to select hosts which host given server group."""
def __init__(self, *args, **kwargs):
super(ServerGroupAntiAffinityConstraint, self).__init__(
*args, **kwargs)
*args, **kwargs)
self.policy_name = 'anti-affinity'
def get_constraint_matrix(self, hosts, filter_properties):
@ -72,7 +74,7 @@ class ServerGroupAntiAffinityConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
policies = filter_properties.get('group_policies', [])
if self.policy_name not in policies:

View File

@ -21,9 +21,9 @@ from nova_solverscheduler.scheduler.solvers import constraints
from nova_solverscheduler.scheduler.solvers import utils as solver_utils
tenant_rack_opts = [
cfg.IntOpt('max_racks_per_tenant',
default=1,
help='Maximum number of racks each tenant can have.'),
cfg.IntOpt('max_racks_per_tenant',
default=1,
help='Maximum number of racks each tenant can have.'),
]
CONF = cfg.CONF
@ -49,7 +49,7 @@ def _get_sorted_racks(racks, hosts, host_racks_map, filter_properties):
return list(racks)
if not cost_matrix:
cost_matrix = [[0 for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
rack_avail_insts = {}
rack_avg_costs = {}
@ -81,8 +81,8 @@ def _get_sorted_racks(racks, hosts, host_racks_map, filter_properties):
cost_matrix[i][0]) / n
rack_score_tuples = [
(rack, rack_avail_insts[rack], rack_avg_costs[rack]) for
rack in rack_set]
(rack, rack_avail_insts[rack], rack_avg_costs[rack]) for
rack in rack_set]
sorted_rack_tuples = sorted(rack_score_tuples, key=mixed_order)
sorted_racks = [rack for (rack, inst, cost) in sorted_rack_tuples]
@ -91,6 +91,7 @@ def _get_sorted_racks(racks, hosts, host_racks_map, filter_properties):
class TenantRackConstraint(constraints.BaseLinearConstraint):
"""Limit the maximum number of racks that instances of each tenant can
spread across.
If a host doesnot have rack config, it won't be filtered out by this
@ -104,7 +105,7 @@ class TenantRackConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
max_racks = CONF.max_racks_per_tenant
project_id = filter_properties['project_id']
@ -132,7 +133,7 @@ class TenantRackConstraint(constraints.BaseLinearConstraint):
additional_racks = list(other_racks)
else:
sorted_other_racks = _get_sorted_racks(
other_racks, hosts, host_racks_map, filter_properties)
other_racks, hosts, host_racks_map, filter_properties)
additional_racks = sorted_other_racks[0:additional_rack_num]
acceptable_racks = project_racks.union(additional_racks)
@ -144,11 +145,11 @@ class TenantRackConstraint(constraints.BaseLinearConstraint):
constraint_matrix[i] = [False for j in xrange(num_instances)]
LOG.debug(_("%(host)s cannot accept requested instances "
"according to TenantRackConstraint."),
{'host': host_name})
"according to TenantRackConstraint."),
{'host': host_name})
else:
LOG.debug(_("%(host)s can accept requested instances "
"according to TenantRackConstraint."),
{'host': host_name})
"according to TenantRackConstraint."),
{'host': host_name})
return constraint_matrix

View File

@ -18,6 +18,7 @@ from nova_solverscheduler.scheduler.solvers import constraints
class TrustedHostsConstraint(constraints.BaseFilterConstraint):
"""Constraint to add support for Trusted Computing Pools.
Allows a host to be selected by scheduler only when the integrity (trust)

View File

@ -18,5 +18,6 @@ from nova_solverscheduler.scheduler.solvers import constraints
class TypeAffinityConstraint(constraints.BaseFilterConstraint):
"""TypeAffinityConstraint doesn't allow more then one VM type per host."""
host_filter_cls = type_filter.TypeAffinityFilter

View File

@ -26,6 +26,7 @@ LOG = logging.getLogger(__name__)
class VcpuConstraint(constraints.BaseLinearConstraint):
"""Constraint of the total vcpu demand acceptable on each host."""
def _get_cpu_allocation_ratio(self, host_state, filter_properties):
@ -36,7 +37,7 @@ class VcpuConstraint(constraints.BaseLinearConstraint):
num_instances = filter_properties.get('num_instances')
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
# get requested vcpus
instance_type = filter_properties.get('instance_type') or {}
@ -45,16 +46,16 @@ class VcpuConstraint(constraints.BaseLinearConstraint):
else:
instance_vcpus = instance_type['vcpus']
if instance_vcpus <= 0:
LOG.warn(_LW("VcpuConstraint is skipped because requested "
LOG.warning(_LW("VcpuConstraint is skipped because requested "
"instance vCPU number is 0 or invalid."))
return constraint_matrix
for i in xrange(num_hosts):
cpu_allocation_ratio = self._get_cpu_allocation_ratio(
hosts[i], filter_properties)
hosts[i], filter_properties)
# get available vcpus
if not hosts[i].vcpus_total:
LOG.warn(_LW("vCPUs of %(host)s not set; assuming CPU "
LOG.warning(_LW("vCPUs of %(host)s not set; assuming CPU "
"collection broken."), {'host': hosts[i]})
continue
else:
@ -65,13 +66,13 @@ class VcpuConstraint(constraints.BaseLinearConstraint):
if acceptable_num_instances < num_instances:
inacceptable_num = num_instances - acceptable_num_instances
constraint_matrix[i] = (
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
[True for j in xrange(acceptable_num_instances)] +
[False for j in xrange(inacceptable_num)])
LOG.debug("%(host)s can accept %(num)s requested instances "
"according to VcpuConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
"according to VcpuConstraint.",
{'host': hosts[i],
'num': acceptable_num_instances})
if vcpus_total > 0:
hosts[i].limits['vcpu'] = vcpus_total

View File

@ -21,6 +21,7 @@ from nova import loadables
class BaseCost(object):
"""Base class for cost."""
precedence = 0
@ -40,6 +41,7 @@ class BaseCost(object):
class BaseLinearCost(BaseCost):
"""Base class of LP cost."""
def __init__(self):
@ -70,6 +72,7 @@ class BaseLinearCost(BaseCost):
class CostHandler(loadables.BaseLoader):
def __init__(self):
super(CostHandler, self).__init__(BaseCost)

View File

@ -23,14 +23,14 @@ from nova_solverscheduler.scheduler.solvers import costs as solver_costs
from nova_solverscheduler.scheduler.solvers import utils as solver_utils
affinity_cost_opts = [
cfg.FloatOpt('affinity_cost_multiplier',
default=1.0,
help='Multiplier used for affinity cost. Must be a '
'positive number.'),
cfg.FloatOpt('anti_affinity_cost_multiplier',
default=1.0,
help='Multiplier used for anti-affinity cost. Must be '
'a positive number.'),
cfg.FloatOpt('affinity_cost_multiplier',
default=1.0,
help='Multiplier used for affinity cost. Must be a '
'positive number.'),
cfg.FloatOpt('anti_affinity_cost_multiplier',
default=1.0,
help='Multiplier used for anti-affinity cost. Must be '
'a positive number.'),
]
CONF = cfg.CONF
@ -78,7 +78,7 @@ class AffinityCost(solver_costs.BaseLinearCost):
if solver_utils.instance_uuids_overlap(hosts[i],
affinity_uuids):
extended_cost_matrix[i] = [float(-j) / multiplier for j in
xrange(num_instances + 1)]
xrange(num_instances + 1)]
else:
extended_cost_matrix = [[0 for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
@ -125,7 +125,7 @@ class AntiAffinityCost(solver_costs.BaseLinearCost):
if solver_utils.instance_uuids_overlap(hosts[i],
affinity_uuids):
extended_cost_matrix[i] = [1 + (float(j) / multiplier)
for j in xrange(num_instances + 1)]
for j in xrange(num_instances + 1)]
else:
extended_cost_matrix = [[0 for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]

View File

@ -28,10 +28,10 @@ from nova_solverscheduler.scheduler.solvers import costs as solver_costs
from nova_solverscheduler.scheduler.solvers.costs import utils
io_ops_cost_opts = [
cfg.FloatOpt('io_ops_cost_multiplier',
default=1.0,
help='Multiplier used for io ops cost. Negative '
'numbers mean to stack vs spread.'),
cfg.FloatOpt('io_ops_cost_multiplier',
default=1.0,
help='Multiplier used for io ops cost. Negative '
'numbers mean to stack vs spread.'),
]
CONF = cfg.CONF
@ -48,8 +48,8 @@ class IoOpsCost(solver_costs.BaseLinearCost):
num_instances = filter_properties.get('num_instances')
extended_cost_matrix = [
[hosts[i].num_io_ops + j for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
[hosts[i].num_io_ops + j for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
extended_cost_matrix = utils.normalize_cost_matrix(
extended_cost_matrix)
extended_cost_matrix)
return extended_cost_matrix

View File

@ -33,19 +33,19 @@ from nova_solverscheduler.scheduler.solvers import costs as solver_costs
from nova_solverscheduler.scheduler.solvers.costs import utils as cost_utils
metrics_cost_opts = [
cfg.FloatOpt('metrics_cost_multiplier',
default=1.0,
help='Multiplier used for metrics costs.'),
cfg.FloatOpt('metrics_cost_multiplier',
default=1.0,
help='Multiplier used for metrics costs.'),
]
metrics_weight_opts = [
cfg.FloatOpt('weight_multiplier_of_unavailable',
default=(-1.0),
help='If any one of the metrics set by weight_setting '
'is unavailable, the metric weight of the host '
'will be set to (minw + (maxw - minw) * m), '
'where maxw and minw are the max and min weights '
'among all hosts, and m is the multiplier.'),
cfg.FloatOpt('weight_multiplier_of_unavailable',
default=(-1.0),
help='If any one of the metrics set by weight_setting '
'is unavailable, the metric weight of the host '
'will be set to (minw + (maxw - minw) * m), '
'where maxw and minw are the max and min weights '
'among all hosts, and m is the multiplier.'),
]
CONF = cfg.CONF
@ -56,6 +56,7 @@ CONF.import_opt('weight_setting', 'nova.scheduler.weights.metrics',
class MetricsCost(solver_costs.BaseLinearCost):
def __init__(self):
self._parse_setting()
@ -90,7 +91,7 @@ class MetricsCost(solver_costs.BaseLinearCost):
minval = min(numeric_values)
maxval = max(numeric_values)
weight_of_unavailable = (minval + (maxval - minval) *
CONF.metrics.weight_multiplier_of_unavailable)
CONF.metrics.weight_multiplier_of_unavailable)
for i in range(num_hosts):
if host_weights[i] is None:
host_weights[i] = weight_of_unavailable
@ -101,5 +102,5 @@ class MetricsCost(solver_costs.BaseLinearCost):
for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
extended_cost_matrix = cost_utils.normalize_cost_matrix(
extended_cost_matrix)
extended_cost_matrix)
return extended_cost_matrix

View File

@ -29,10 +29,10 @@ from nova_solverscheduler.scheduler.solvers import costs as solver_costs
from nova_solverscheduler.scheduler.solvers.costs import utils
ram_cost_opts = [
cfg.FloatOpt('ram_cost_multiplier',
default=1.0,
help='Multiplier used for ram costs. Negative '
'numbers mean to stack vs spread.'),
cfg.FloatOpt('ram_cost_multiplier',
default=1.0,
help='Multiplier used for ram costs. Negative '
'numbers mean to stack vs spread.'),
]
CONF = cfg.CONF
@ -53,25 +53,25 @@ class RamCost(solver_costs.BaseLinearCost):
instance_type = filter_properties.get('instance_type') or {}
requested_ram = instance_type.get('memory_mb', 0)
if 'memory_mb' not in instance_type:
LOG.warn(_LW("No information about requested instances\' RAM size "
"was found, default value (0) is used."))
LOG.warning(_LW("No information about requested instances\' RAM size "
"was found, default value (0) is used."))
extended_cost_matrix = [[0 for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
if requested_ram == 0:
extended_cost_matrix = [
[(-hosts[i].free_ram_mb)
[(-hosts[i].free_ram_mb)
for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
else:
# we use int approximation here to avoid scaling problems after
# normalization, in the case that the free ram in all hosts are
# of very small values
extended_cost_matrix = [
[-int(hosts[i].free_ram_mb / requested_ram) + j
[-int(hosts[i].free_ram_mb / requested_ram) + j
for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
extended_cost_matrix = utils.normalize_cost_matrix(
extended_cost_matrix)
extended_cost_matrix)
return extended_cost_matrix

View File

@ -21,10 +21,10 @@ from nova_solverscheduler.scheduler.solvers import costs as solver_costs
from nova_solverscheduler.scheduler.solvers import utils as solver_utils
affinity_cost_opts = [
cfg.FloatOpt('tenant_rack_affinity_cost_multiplier',
default=1.0,
help='Multiplier used for tenant rack affinity cost. '
'Must be a positive number.'),
cfg.FloatOpt('tenant_rack_affinity_cost_multiplier',
default=1.0,
help='Multiplier used for tenant rack affinity cost. '
'Must be a positive number.'),
]
CONF = cfg.CONF
@ -34,6 +34,7 @@ LOG = logging.getLogger(__name__)
class TenantRackAffinityCost(solver_costs.BaseLinearCost):
"""Tenant Rack Affinity Cost tends to let scheduler place instances in
the racks that contain existing instances of the tenant.
If a rack has existing instances of the same tenant as that making request,
@ -75,9 +76,9 @@ class TenantRackAffinityCost(solver_costs.BaseLinearCost):
if (not any([rack in affinity_racks for rack in host_racks])) and (
host_name not in affinity_hosts):
extended_cost_matrix[i] = [1 for j
in xrange(num_instances + 1)]
in xrange(num_instances + 1)]
else:
LOG.debug(_("%(host)s is in tenant affinity rack."),
{'host': host_name})
{'host': host_name})
return extended_cost_matrix

View File

@ -29,10 +29,10 @@ from nova_solverscheduler.scheduler.solvers import costs as solver_costs
from nova_solverscheduler.scheduler.solvers.costs import utils
vcpu_cost_opts = [
cfg.FloatOpt('vcpu_cost_multiplier',
default=1.0,
help='Multiplier used for vcpu costs. Negative '
'numbers mean to stack vs spread.'),
cfg.FloatOpt('vcpu_cost_multiplier',
default=1.0,
help='Multiplier used for vcpu costs. Negative '
'numbers mean to stack vs spread.'),
]
CONF = cfg.CONF
@ -53,15 +53,15 @@ class VcpuCost(solver_costs.BaseLinearCost):
instance_type = filter_properties.get('instance_type') or {}
requested_vcpus = instance_type.get('vcpus', 0)
if requested_vcpus <= 0:
LOG.warn(_LW("Requested instances\' vCPU number is 0 or invalid, "
"default value (0) is used."))
LOG.warning(_LW("Requested instances\' vCPU number is 0 or invalid, "
"default value (0) is used."))
remaining_vcpus_list = []
for i in xrange(num_hosts):
vcpus_total = hosts[i].vcpus_total
vcpus_used = hosts[i].vcpus_used
if not vcpus_total:
LOG.warn(_LW("vCPUs of %(host)s not set; assuming CPU "
LOG.warning(_LW("vCPUs of %(host)s not set; assuming CPU "
"collection broken."), {'host': hosts[i]})
vcpus_total = 0
remaining_vcpus = vcpus_total - vcpus_used
@ -72,17 +72,17 @@ class VcpuCost(solver_costs.BaseLinearCost):
if requested_vcpus == 0:
extended_cost_matrix = [
[(-remaining_vcpus_list[i])
[(-remaining_vcpus_list[i])
for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
else:
# we use int approximation here to avoid scaling problems after
# normalization, in the case that the free vcpus in all hosts are
# of very small values
extended_cost_matrix = [
[-int(remaining_vcpus_list[i] / requested_vcpus) + j
[-int(remaining_vcpus_list[i] / requested_vcpus) + j
for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
extended_cost_matrix = utils.normalize_cost_matrix(
extended_cost_matrix)
extended_cost_matrix)
return extended_cost_matrix

View File

@ -31,7 +31,7 @@ class FastSolver(scheduler_solver.BaseHostSolver):
solver_cache = filter_properties['solver_cache']
# initialize cost matrix
cost_matrix = [[0 for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
solver_cache['cost_matrix'] = cost_matrix
cost_objects = [cost() for cost in self.cost_classes]
cost_objects.sort(key=lambda cost: cost.precedence)
@ -47,9 +47,9 @@ class FastSolver(scheduler_solver.BaseHostSolver):
if not this_cost_mat:
continue
cost_matrix = [[cost_matrix[i][j] +
this_cost_mat[i][j] * cost_multiplier
for j in xrange(num_instances)]
for i in xrange(num_hosts)]
this_cost_mat[i][j] * cost_multiplier
for j in xrange(num_instances)]
for i in xrange(num_hosts)]
# update cost matrix in the solver cache
solver_cache['cost_matrix'] = cost_matrix
@ -61,7 +61,7 @@ class FastSolver(scheduler_solver.BaseHostSolver):
solver_cache = filter_properties['solver_cache']
# initialize constraint_matrix
constraint_matrix = [[True for j in xrange(num_instances)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
solver_cache['constraint_matrix'] = constraint_matrix
constraint_objects = [cons() for cons in self.constraint_classes]
constraint_objects.sort(key=lambda cons: cons.precedence)
@ -72,12 +72,12 @@ class FastSolver(scheduler_solver.BaseHostSolver):
solver_cache['constraint_matrix'] = constraint_matrix
precedence_level = constraint_object.precedence
this_cons_mat = constraint_object.get_constraint_matrix(hosts,
filter_properties)
filter_properties)
if not this_cons_mat:
continue
constraint_matrix = [[constraint_matrix[i][j] &
this_cons_mat[i][j] for j in xrange(num_instances)]
for i in xrange(num_hosts)]
this_cons_mat[i][j] for j in xrange(num_instances)]
for i in xrange(num_hosts)]
# update constraint matrix in the solver cache
solver_cache['constraint_matrix'] = constraint_matrix
@ -94,7 +94,7 @@ class FastSolver(scheduler_solver.BaseHostSolver):
filter_properties.setdefault('solver_cache', {})
filter_properties['solver_cache'].update(
{'cost_matrix': [],
{'cost_matrix': [],
'constraint_matrix': []})
cost_matrix = self._get_cost_matrix(hosts, filter_properties)
@ -109,7 +109,7 @@ class FastSolver(scheduler_solver.BaseHostSolver):
inst_num = j + 1
cost_val = cost_matrix[i][j]
placement_cost_tuples.append(
(host_idx, inst_num, cost_val))
(host_idx, inst_num, cost_val))
sorted_placement_costs = sorted(placement_cost_tuples,
key=operator.itemgetter(2))
@ -133,6 +133,6 @@ class FastSolver(scheduler_solver.BaseHostSolver):
num = host_inst_alloc[i]
for n in xrange(num):
host_instance_combinations.append(
(hosts[i], instances_iter.next()))
(hosts[i], instances_iter.next()))
return host_instance_combinations

View File

@ -24,11 +24,11 @@ from nova.i18n import _LW
from nova_solverscheduler.scheduler import solvers as scheduler_solver
pulp_solver_opts = [
cfg.IntOpt('pulp_solver_timeout_seconds',
default=20,
help='How much time in seconds is allowed for solvers to '
'solve the scheduling problem. If this time limit '
'is exceeded the solver will be stopped.'),
cfg.IntOpt('pulp_solver_timeout_seconds',
default=20,
help='How much time in seconds is allowed for solvers to '
'solve the scheduling problem. If this time limit '
'is exceeded the solver will be stopped.'),
]
CONF = cfg.CONF
@ -38,6 +38,7 @@ LOG = logging.getLogger(__name__)
class PulpSolver(scheduler_solver.BaseHostSolver):
"""A LP based pluggable LP solver implemented using PULP modeler."""
def __init__(self):
@ -51,7 +52,7 @@ class PulpSolver(scheduler_solver.BaseHostSolver):
solver_cache = filter_properties['solver_cache']
# initialize cost matrix
cost_matrix = [[0 for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
solver_cache['cost_matrix'] = cost_matrix
cost_objects = [cost() for cost in self.cost_classes]
cost_objects.sort(key=lambda cost: cost.precedence)
@ -63,13 +64,13 @@ class PulpSolver(scheduler_solver.BaseHostSolver):
precedence_level = cost_object.precedence
cost_multiplier = cost_object.cost_multiplier()
this_cost_mat = cost_object.get_extended_cost_matrix(hosts,
filter_properties)
filter_properties)
if not this_cost_mat:
continue
cost_matrix = [[cost_matrix[i][j] +
this_cost_mat[i][j] * cost_multiplier
for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
this_cost_mat[i][j] * cost_multiplier
for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
# update cost matrix in the solver cache
solver_cache['cost_matrix'] = cost_matrix
@ -81,7 +82,7 @@ class PulpSolver(scheduler_solver.BaseHostSolver):
solver_cache = filter_properties['solver_cache']
# initialize constraint_matrix
constraint_matrix = [[True for j in xrange(num_instances + 1)]
for i in xrange(num_hosts)]
for i in xrange(num_hosts)]
solver_cache['constraint_matrix'] = constraint_matrix
constraint_objects = [cons() for cons in self.constraint_classes]
constraint_objects.sort(key=lambda cons: cons.precedence)
@ -92,12 +93,12 @@ class PulpSolver(scheduler_solver.BaseHostSolver):
solver_cache['constraint_matrix'] = constraint_matrix
precedence_level = constraint_object.precedence
this_cons_mat = constraint_object.get_constraint_matrix(hosts,
filter_properties)
filter_properties)
if not this_cons_mat:
continue
for i in xrange(num_hosts):
constraint_matrix[i][1:] = [constraint_matrix[i][j + 1] &
this_cons_mat[i][j] for j in xrange(num_instances)]
this_cons_mat[i][j] for j in xrange(num_instances)]
# update constraint matrix in the solver cache
solver_cache['constraint_matrix'] = constraint_matrix
@ -119,7 +120,7 @@ class PulpSolver(scheduler_solver.BaseHostSolver):
for i in xrange(len(cost_matrix)):
for j in xrange(len(cost_matrix[i])):
new_cost_matrix[i][j] = sign * (
(cost_matrix[i][j] - offset) ** 2)
(cost_matrix[i][j] - offset) ** 2)
return new_cost_matrix
def solve(self, hosts, filter_properties):
@ -134,11 +135,11 @@ class PulpSolver(scheduler_solver.BaseHostSolver):
num_hosts = len(hosts)
instance_uuids = filter_properties.get('instance_uuids') or [
'(unknown_uuid)' + str(i) for i in xrange(num_instances)]
'(unknown_uuid)' + str(i) for i in xrange(num_instances)]
filter_properties.setdefault('solver_cache', {})
filter_properties['solver_cache'].update(
{'cost_matrix': [],
{'cost_matrix': [],
'constraint_matrix': []})
cost_matrix = self._get_cost_matrix(hosts, filter_properties)
@ -152,49 +153,49 @@ class PulpSolver(scheduler_solver.BaseHostSolver):
host_keys = ['Host' + str(i) for i in xrange(num_hosts)]
host_key_map = dict(zip(host_keys, hosts))
instance_num_keys = ['InstanceNum' + str(i) for
i in xrange(num_instances + 1)]
i in xrange(num_instances + 1)]
instance_num_key_map = dict(zip(instance_num_keys,
xrange(num_instances + 1)))
# create the pulp variables
variable_matrix = [
[pulp.LpVariable('HI_' + host_key + '_' + instance_num_key,
0, 1, constants.LpInteger)
[pulp.LpVariable('HI_' + host_key + '_' + instance_num_key,
0, 1, constants.LpInteger)
for instance_num_key in instance_num_keys]
for host_key in host_keys]
for host_key in host_keys]
# create the 'prob' variable to contain the problem data.
prob = pulp.LpProblem("Host Instance Scheduler Problem",
constants.LpMinimize)
constants.LpMinimize)
# add cost function to pulp solver
cost_variables = [variable_matrix[i][j] for i in xrange(num_hosts)
for j in xrange(num_instances + 1)]
for j in xrange(num_instances + 1)]
cost_coefficients = [cost_matrix[i][j] for i in xrange(num_hosts)
for j in xrange(num_instances + 1)]
for j in xrange(num_instances + 1)]
prob += (pulp.lpSum([cost_coefficients[i] * cost_variables[i]
for i in xrange(len(cost_variables))]), "Sum_Costs")
for i in xrange(len(cost_variables))]), "Sum_Costs")
# add constraints to pulp solver
for i in xrange(num_hosts):
for j in xrange(num_instances + 1):
if constraint_matrix[i][j] is False:
prob += (variable_matrix[i][j] == 0,
"Cons_Host_%s" % i + "_NumInst_%s" % j)
"Cons_Host_%s" % i + "_NumInst_%s" % j)
# add additional constraints to ensure the problem is valid
# (1) non-trivial solution: number of all instances == that requested
prob += (pulp.lpSum([variable_matrix[i][j] * j for i in
xrange(num_hosts) for j in xrange(num_instances + 1)]) ==
num_instances, "NonTrivialCons")
xrange(num_hosts) for j in xrange(num_instances + 1)]) ==
num_instances, "NonTrivialCons")
# (2) valid solution: each host is assigned 1 num-instances value
for i in xrange(num_hosts):
prob += (pulp.lpSum([variable_matrix[i][j] for j in
xrange(num_instances + 1)]) == 1, "ValidCons_Host_%s" % i)
xrange(num_instances + 1)]) == 1, "ValidCons_Host_%s" % i)
# The problem is solved using PULP's choice of Solver.
prob.solve(pulp_solver_classes.PULP_CBC_CMD(
maxSeconds=CONF.solver_scheduler.pulp_solver_timeout_seconds))
maxSeconds=CONF.solver_scheduler.pulp_solver_timeout_seconds))
# Create host-instance tuples from the solutions.
if pulp.LpStatus[prob.status] == 'Optimal':
@ -202,19 +203,19 @@ class PulpSolver(scheduler_solver.BaseHostSolver):
for v in prob.variables():
if v.name.startswith('HI'):
(host_key, instance_num_key) = v.name.lstrip('HI').lstrip(
'_').split('_')
'_').split('_')
if v.varValue == 1:
num_insts_on_host[host_key] = (
instance_num_key_map[instance_num_key])
instance_num_key_map[instance_num_key])
instances_iter = iter(instance_uuids)
for host_key in host_keys:
num_insts_on_this_host = num_insts_on_host.get(host_key, 0)
for i in xrange(num_insts_on_this_host):
host_instance_combinations.append(
(host_key_map[host_key], instances_iter.next()))
(host_key_map[host_key], instances_iter.next()))
else:
LOG.warn(_LW("Pulp solver didnot find optimal solution! "
"reason: %s"), pulp.LpStatus[prob.status])
LOG.warning(_LW("Pulp solver didnot find optimal solution! "
"reason: %s"), pulp.LpStatus[prob.status])
host_instance_combinations = []
return host_instance_combinations

View File

@ -25,19 +25,19 @@ from nova.scheduler.filters.utils import * # noqa
rack_config_file_opts = [
cfg.StrOpt('rack_config',
default='',
help='The config file specifying physical rack configuration. By '
'default Cisco\'s Neutron ML2 plugin config is supported, '
'otherwise the format of the config file needs to be '
'compatible with Cisco\'s Neutron ML2 plugin config file.'),
default='',
help='The config file specifying physical rack configuration. By '
'default Cisco\'s Neutron ML2 plugin config is supported, '
'otherwise the format of the config file needs to be '
'compatible with Cisco\'s Neutron ML2 plugin config file.'),
cfg.StrOpt('rack_config_prefix',
default='',
help='The section name in rack config file should start with the '
'prefix, so the config parser can recognize the section as '
'information of a specific rack or ToR switch. For example, '
'in Cisco\'s Neutron ML2 plugin config a section name like '
'[ml2_mech_cisco_nexus:1.1.1.1] identifies a specific ToR '
'switch, then the prefix is \'ml2_mech_cisco_nexus\'.')
default='',
help='The section name in rack config file should start with the '
'prefix, so the config parser can recognize the section as '
'information of a specific rack or ToR switch. For example, '
'in Cisco\'s Neutron ML2 plugin config a section name like '
'[ml2_mech_cisco_nexus:1.1.1.1] identifies a specific ToR '
'switch, then the prefix is \'ml2_mech_cisco_nexus\'.')
]
CONF = cfg.CONF
@ -102,7 +102,7 @@ def get_host_racks_map(hosts):
if host_racks:
host_racks_map.setdefault(host_name, set())
host_racks_map[host_name] = host_racks_map[host_name].union(
host_racks)
host_racks)
if not host_racks_map:
host_racks_map = get_host_racks_config()