Update Nova aggregates on changed host mappings
When creating a subnet on a segment, Nova aggregates are updated with the host information. But when adding a compute node to an existing segment or modifying what segments a node is attached to, Nova was not updated with these changes for ML2/OVN. ML2/OVS has agent code which via report_state() will call create_or_update_agent() which causes the aggregates to eventually get updated via AGENT_AFTER_CREATE events, etc. ML2/OVN does not have "real" agents. It monkeypatches some agent methods to respond to the API requests itself--but it does not use the agents db--which is what create_or_update_agent() modifies. But it shouldn't be necessary to rely on updates from the agent in our case, as the segments code can see segment host mappings being updated and just directly handle notifying nova when those change. Closes-Bug: #2096941 Change-Id: I8112076f8acb821752941396e7aa39ecb1352ca3
This commit is contained in:
@@ -235,6 +235,17 @@ def update_segment_host_mapping(context, host, current_segment_ids):
|
||||
for segment_id in segment_ids:
|
||||
network.SegmentHostMapping(
|
||||
context, segment_id=segment_id, host=host).create()
|
||||
if segment_ids:
|
||||
registry.publish(
|
||||
resources.SEGMENT_HOST_MAPPING,
|
||||
events.AFTER_CREATE,
|
||||
update_segment_host_mapping,
|
||||
payload=events.DBEventPayload(
|
||||
context,
|
||||
metadata={
|
||||
'host': host,
|
||||
'current_segment_ids': segment_ids}))
|
||||
|
||||
LOG.debug('Segments %s mapped to the host %s', segment_ids, host)
|
||||
stale_segment_ids = previous_segment_ids - current_segment_ids
|
||||
if stale_segment_ids:
|
||||
@@ -243,6 +254,15 @@ def update_segment_host_mapping(context, host, current_segment_ids):
|
||||
entry.delete()
|
||||
LOG.debug('Segment %s unmapped from host %s',
|
||||
entry.segment_id, entry.host)
|
||||
registry.publish(
|
||||
resources.SEGMENT_HOST_MAPPING,
|
||||
events.AFTER_DELETE,
|
||||
update_segment_host_mapping,
|
||||
payload=events.DBEventPayload(
|
||||
context,
|
||||
metadata={
|
||||
'host': host,
|
||||
'deleted_segment_ids': stale_segment_ids}))
|
||||
|
||||
|
||||
def get_hosts_mapped_with_segments(context, include_agent_types=None,
|
||||
@@ -352,12 +372,6 @@ def _update_segment_host_mapping_for_agent(resource, event, trigger,
|
||||
segment['id'] for segment in segments
|
||||
if check_segment_for_agent(segment, agent)}
|
||||
update_segment_host_mapping(context, host, current_segment_ids)
|
||||
registry.publish(resources.SEGMENT_HOST_MAPPING, events.AFTER_CREATE,
|
||||
plugin, payload=events.DBEventPayload(
|
||||
context,
|
||||
metadata={
|
||||
'host': host,
|
||||
'current_segment_ids': current_segment_ids}))
|
||||
|
||||
|
||||
def _add_segment_host_mapping_for_segment(resource, event, trigger,
|
||||
|
@@ -393,13 +393,18 @@ class NovaSegmentNotifier:
|
||||
LOG.info('Segment %s resource provider not found; error: %s',
|
||||
event.segment_id, str(exc))
|
||||
|
||||
@staticmethod
|
||||
def _payload_segment_ids(payload, key):
|
||||
# NOTE(twilson) My assumption is that this is to guarantee the subnets
|
||||
# passed exist in at least one subnet
|
||||
subnets = subnet_obj.Subnet.get_objects(
|
||||
payload.context, segment_id=payload.metadata.get(key))
|
||||
return {s.segment_id for s in subnets}
|
||||
|
||||
@registry.receives(resources.SEGMENT_HOST_MAPPING, [events.AFTER_CREATE])
|
||||
def _notify_host_addition_to_aggregate(self, resource, event, trigger,
|
||||
payload=None):
|
||||
subnets = subnet_obj.Subnet.get_objects(
|
||||
payload.context,
|
||||
segment_id=payload.metadata.get('current_segment_ids'))
|
||||
segment_ids = {s.segment_id for s in subnets}
|
||||
segment_ids = self._payload_segment_ids(payload, 'current_segment_ids')
|
||||
self.batch_notifier.queue_event(
|
||||
Event(self._add_host_to_aggregate,
|
||||
segment_ids, host=payload.metadata.get('host')))
|
||||
@@ -420,6 +425,29 @@ class NovaSegmentNotifier:
|
||||
'routed network segment %(segment_id)s',
|
||||
{'host': event.host, 'segment_id': segment_id})
|
||||
|
||||
@registry.receives(resources.SEGMENT_HOST_MAPPING, [events.AFTER_DELETE])
|
||||
def _notify_host_removal_from_aggregate(self, resource, event, trigger,
|
||||
payload=None):
|
||||
segment_ids = self._payload_segment_ids(payload, 'deleted_segment_ids')
|
||||
self.batch_notifier.queue_event(
|
||||
Event(self._remove_host_from_aggregate,
|
||||
segment_ids, host=payload.metadata.get('host')))
|
||||
|
||||
def _remove_host_from_aggregate(self, event):
|
||||
for segment_id in event.segment_ids:
|
||||
aggregate_id = self._get_aggregate_id(segment_id)
|
||||
if not aggregate_id:
|
||||
LOG.info('When removing host %(host)s, aggregate not found '
|
||||
'for routed network segment %(segment_id)s',
|
||||
{'host': event.host, 'segment_id': segment_id})
|
||||
continue
|
||||
try:
|
||||
self.n_client.aggregates.remove_host(aggregate_id, event.host)
|
||||
except nova_exc.NotFound:
|
||||
LOG.info('Host %(host)s is not in aggregate for '
|
||||
'routed network segment %(segment_ids)s',
|
||||
{'host': event.host, 'segment_id': segment_id})
|
||||
|
||||
@registry.receives(resources.PORT, [events.AFTER_CREATE,
|
||||
events.AFTER_DELETE])
|
||||
def _notify_port_created_or_deleted(self, resource, event, trigger,
|
||||
|
Reference in New Issue
Block a user