Add ports scheduler filter
This filter will check whether the node ports satisfy the specified networks requirements including ports quantity and types. Change-Id: I793a3a78d6c59ae4eb57dc6bdd49af4eef545820
This commit is contained in:
parent
c0124c5421
commit
0a0ffe2c4e
@ -35,7 +35,8 @@ opts = [
|
||||
default=[
|
||||
'AvailabilityZoneFilter',
|
||||
'InstanceTypeFilter',
|
||||
'CapabilitiesFilter'
|
||||
'CapabilitiesFilter',
|
||||
'PortsFilter'
|
||||
],
|
||||
help=_('Which filter class names to use for filtering nodes '
|
||||
'when not specified in the request.')),
|
||||
|
@ -87,6 +87,7 @@ class API(object):
|
||||
'instance_properties': {
|
||||
'availability_zone': instance.availability_zone,
|
||||
'instance_type_uuid': instance.instance_type_uuid,
|
||||
'networks': requested_networks,
|
||||
},
|
||||
'instance_type': dict(instance_type),
|
||||
}
|
||||
|
@ -144,6 +144,22 @@ def get_node_list(ironicclient, **kwargs):
|
||||
return node_list
|
||||
|
||||
|
||||
def get_port_list(ironicclient, **kwargs):
|
||||
"""Helper function to return the list of ports.
|
||||
|
||||
If unable to connect ironic server, an empty list is returned.
|
||||
|
||||
:returns: a list of raw port from ironic
|
||||
|
||||
"""
|
||||
try:
|
||||
port_list = ironicclient.call("port.list", **kwargs)
|
||||
except client_e.ClientException as e:
|
||||
LOG.exception(_LE("Could not get ports from ironic. Reason: "
|
||||
"%(detail)s"), {'detail': e.message})
|
||||
port_list = []
|
||||
return port_list
|
||||
|
||||
|
||||
def set_power_state(ironicclient, node_uuid, state):
|
||||
ironicclient.call("node.set_power_state", node_uuid, state)
|
||||
# Do we need to catch NotFound exception.
|
||||
|
@ -61,7 +61,13 @@ class EngineManager(base_manager.BaseEngineManager):
|
||||
maintenance=False,
|
||||
provision_state=ironic_states.AVAILABLE,
|
||||
associated=False, limit=0)
|
||||
ports = ironic.get_port_list(self.ironicclient, limit=0,
|
||||
fields=('uuid', 'node_uuid', 'extra',
|
||||
'address'))
|
||||
for node in nodes:
|
||||
# Add ports to the associated node
|
||||
node.ports = [port for port in ports
|
||||
if node.uuid == port.node_uuid]
|
||||
node_cache[node.uuid] = node
|
||||
|
||||
with self._lock:
|
||||
|
64
mogan/engine/scheduler/filters/ports_filter.py
Normal file
64
mogan/engine/scheduler/filters/ports_filter.py
Normal file
@ -0,0 +1,64 @@
|
||||
# Copyright 2016 Huawei Technologies Co.,LTD.
|
||||
# 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.
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from mogan.engine.scheduler import filters
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PortsFilter(filters.BaseNodeFilter):
|
||||
"""NodeFilter to work with resource instance type records."""
|
||||
|
||||
def _find_port_type(self, ports, port_type):
|
||||
"""Check if ports has the specified port type."""
|
||||
|
||||
for port in ports:
|
||||
if port_type == port.extra.get('port_type'):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _satisfies_networks(self, ports, networks):
|
||||
"""Check if ports satisfy networks requirements.
|
||||
|
||||
Check that the ports provided by the nodes satisfy
|
||||
the networks associated with the request spec.
|
||||
"""
|
||||
|
||||
if not networks:
|
||||
return True
|
||||
|
||||
if len(ports) < len(networks):
|
||||
return False
|
||||
|
||||
for net in networks:
|
||||
if 'port_type' in net:
|
||||
if not self._find_port_type(ports, net.get('port_type')):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def node_passes(self, node_state, filter_properties):
|
||||
"""Return a list of nodes that can create resource_type."""
|
||||
spec = filter_properties.get('request_spec', {})
|
||||
props = spec.get('instance_properties', {})
|
||||
networks = props.get('networks')
|
||||
if not self._satisfies_networks(node_state.ports, networks):
|
||||
LOG.debug("%(node_state)s fails network ports "
|
||||
"requirements", {'node_state': node_state})
|
||||
return False
|
||||
return True
|
@ -38,6 +38,7 @@ class NodeState(object):
|
||||
self.availability_zone = node.properties.get('availability_zone') \
|
||||
or CONF.engine.default_schedule_zone
|
||||
self.instance_type = node.properties.get('instance_type')
|
||||
self.ports = node.ports
|
||||
|
||||
|
||||
class NodeManager(object):
|
||||
|
@ -18,7 +18,7 @@ Fakes For Scheduler tests.
|
||||
"""
|
||||
|
||||
from oslo_versionedobjects import base as object_base
|
||||
|
||||
from oslo_versionedobjects import fields
|
||||
|
||||
from mogan.engine.scheduler import filter_scheduler
|
||||
from mogan.engine.scheduler import node_manager
|
||||
@ -38,21 +38,25 @@ class FakeNode(base.MoganObject, object_base.VersionedObjectDictCompat):
|
||||
'id': object_fields.IntegerField(),
|
||||
'uuid': object_fields.UUIDField(nullable=True),
|
||||
'properties': object_fields.FlexibleDictField(nullable=True),
|
||||
'ports': fields.ListOfDictOfNullableStringsField(nullable=True),
|
||||
}
|
||||
|
||||
|
||||
fakenode1 = FakeNode(id=1, uuid='1a617131-cdbc-45dc-afff-f21f17ae054e',
|
||||
properties={'capabilities': '',
|
||||
'availability_zone': 'az1',
|
||||
'instance_type': 'type1'})
|
||||
'instance_type': 'type1'},
|
||||
ports=[])
|
||||
fakenode2 = FakeNode(id=2, uuid='2a617131-cdbc-45dc-afff-f21f17ae054e',
|
||||
properties={'capabilities': '',
|
||||
'availability_zone': 'az2',
|
||||
'instance_type': 'type2'})
|
||||
'instance_type': 'type2'},
|
||||
ports=[])
|
||||
fakenode3 = FakeNode(id=3, uuid='3a617131-cdbc-45dc-afff-f21f17ae054e',
|
||||
properties={'capabilities': '',
|
||||
'availability_zone': 'az3',
|
||||
'instance_type': 'type3'})
|
||||
'instance_type': 'type3'},
|
||||
ports=[])
|
||||
|
||||
|
||||
class FakeNodeState(node_manager.NodeState):
|
||||
|
@ -385,7 +385,7 @@ expected_object_fingerprints = {
|
||||
'Instance': '1.0-c3a73e3ec189aa09dc430b389c81b11f',
|
||||
'InstanceType': '1.0-589b096651fcdb30898ff50f748dd948',
|
||||
'MyObj': '1.1-aad62eedc5a5cc8bcaf2982c285e753f',
|
||||
'FakeNode': '1.0-295d1b08ce3048535926c47dedd27211',
|
||||
'FakeNode': '1.0-07813a70fee67557d8a71ad96f31cee7',
|
||||
}
|
||||
|
||||
|
||||
|
@ -29,6 +29,7 @@ mogan.engine.scheduler.filters =
|
||||
AvailabilityZoneFilter = mogan.engine.scheduler.filters.availability_zone_filter:AvailabilityZoneFilter
|
||||
InstanceTypeFilter = mogan.engine.scheduler.filters.instance_type_filter:InstanceTypeFilter
|
||||
CapabilitiesFilter = mogan.engine.scheduler.filters.capabilities_filter:CapabilitiesFilter
|
||||
PortsFilter = mogan.engine.scheduler.filters.ports_filter:PortsFilter
|
||||
JsonFilter = mogan.engine.scheduler.filters.json_filter:JsonFilter
|
||||
|
||||
oslo.config.opts =
|
||||
|
Loading…
x
Reference in New Issue
Block a user