Add debug messages

We are having a hard time keeping track of which operations
correspond to which request.  This patch adds the ability to track
operations in the notifier with the message_id of the notification
being processed.  This message_id (which is generated by oslo is
a uuid

For the server, we could also set the message_id to the request_id
of the python-requests object received, but this is already
logged as part of the server logs.

Change-Id: Ie8b885a2b5cba6684e92c49eed4a99d24621402e
This commit is contained in:
Ade Lee 2019-08-16 17:35:22 -04:00 committed by Grzegorz Grasza
parent 9750c363f6
commit ade787b90c
3 changed files with 185 additions and 143 deletions

View File

@ -62,6 +62,7 @@ class IPANovaJoinBase(object):
self.ntries = CONF.connect_retries
self.initial_backoff = CONF.connect_backoff
self.ccache = "MEMORY:" + str(uuid.uuid4())
LOG.debug("cache: %s", self.ccache)
os.environ['KRB5CCNAME'] = self.ccache
if self._ipa_client_configured() and not api.isdone('finalize'):
(hostname, realm) = self.get_host_and_realm()
@ -126,23 +127,24 @@ class IPANovaJoinBase(object):
return (hostname, realm)
def __backoff(self):
LOG.debug("Backing off %s seconds", self.backoff)
def __backoff(self, message_id):
LOG.debug("[%s] Backing off %s seconds", message_id, self.backoff)
time.sleep(self.backoff)
if self.backoff < 512:
self.backoff = self.backoff * 2
def __reset_backoff(self):
def __reset_backoff(self, message_id):
if self.backoff > self.initial_backoff:
LOG.debug("Resetting backoff to %d", self.initial_backoff)
LOG.debug("[%s] Resetting backoff to %d",
message_id, self.initial_backoff)
self.backoff = self.initial_backoff
def __get_connection(self):
def __get_connection(self, message_id):
"""Make a connection to IPA or raise an error."""
tries = 0
while (tries <= self.ntries):
LOG.debug("Attempt %d of %d", tries, self.ntries)
LOG.debug("[%s] Attempt %d of %d", message_id, tries, self.ntries)
if api.Backend.rpcclient.isconnected():
api.Backend.rpcclient.disconnect()
try:
@ -154,7 +156,7 @@ class IPANovaJoinBase(object):
errors.TicketExpired,
errors.KerberosError) as e:
tries += 1
LOG.debug("kinit again: %s", e)
LOG.debug("[%s] kinit again: %s", message_id, e)
# pylint: disable=no-member
try:
kinit_keytab(str('nova/%s@%s' %
@ -162,35 +164,37 @@ class IPANovaJoinBase(object):
CONF.keytab,
self.ccache)
except GSSError as e:
LOG.debug("kinit failed: %s", e)
LOG.debug("[%s] kinit failed: %s", message_id, e)
if self.backoff:
self.__backoff()
self.__backoff(message_id)
except errors.NetworkError:
tries += 1
if self.backoff:
self.__backoff()
self.__backoff(message_id)
except http_client.ResponseNotReady:
# NOTE(xek): This means that the server closed the socket,
# so keep-alive ended and we can't use that connection.
api.Backend.rpcclient.disconnect()
tries += 1
if self.backoff:
self.__backoff()
self.__backoff(message_id)
else:
# successful connection
self.__reset_backoff()
self.__reset_backoff(message_id)
return
LOG.error("Failed to connect to IPA after %d attempts", self.ntries)
LOG.error("[%s] Failed to connect to IPA after %d attempts",
message_id, self.ntries)
raise exception.IPAConnectionError(tries=self.ntries)
def start_batch_operation(self):
def start_batch_operation(self, message_id=0):
"""Start a batch operation.
IPA method calls will be collected in a batch job
and submitted to IPA once all the operations have collected
by a call to _flush_batch_operation().
"""
LOG.debug("[%s] start batch operation", message_id)
self.batch_args = list()
def _add_batch_operation(self, command, *args, **kw):
@ -200,21 +204,21 @@ class IPANovaJoinBase(object):
"params": [args, kw],
})
def flush_batch_operation(self):
def flush_batch_operation(self, message_id=0):
"""Make an IPA batch call."""
LOG.debug("flush_batch_operation")
LOG.debug("[%] flush_batch_operation", message_id)
if not self.batch_args:
return None
kw = {}
LOG.debug(self.batch_args)
LOG.debug("[%s] %s", message_id, self.batch_args)
return self._call_ipa('batch', *self.batch_args, **kw)
return self._call_ipa(message_id, 'batch', *self.batch_args, **kw)
def _call_ipa(self, command, *args, **kw):
def _call_ipa(self, message_id, command, *args, **kw):
"""Make an IPA call."""
if not api.Backend.rpcclient.isconnected():
self.__get_connection()
self.__get_connection(message_id)
if 'version' not in kw:
kw['version'] = u'2.146' # IPA v4.2.0 for compatibility
@ -226,11 +230,11 @@ class IPANovaJoinBase(object):
except (errors.CCacheError,
errors.TicketExpired,
errors.KerberosError):
LOG.debug("Refresh authentication")
self.__get_connection()
LOG.debug("[%s] Refresh authentication", message_id)
self.__get_connection(message_id)
except errors.NetworkError:
if self.backoff:
self.__backoff()
self.__backoff(message_id)
else:
raise
except http_client.ResponseNotReady:
@ -238,7 +242,7 @@ class IPANovaJoinBase(object):
# so keep-alive ended and we can't use that connection.
api.Backend.rpcclient.disconnect()
if self.backoff:
self.__backoff()
self.__backoff(message_id)
else:
raise
@ -259,7 +263,8 @@ class IPAClient(IPANovaJoinBase):
host_cache = cachetools.TTLCache(maxsize=512, ttl=30)
service_cache = cachetools.TTLCache(maxsize=512, ttl=30)
def add_host(self, hostname, ipaotp, metadata=None, image_metadata=None):
def add_host(self, hostname, ipaotp, metadata=None, image_metadata=None,
message_id=0):
"""Add a host to IPA.
If requested in the metadata, add a host to IPA. The assumption
@ -270,10 +275,10 @@ class IPAClient(IPANovaJoinBase):
and if that fails due to NotFound the host is added.
"""
LOG.debug('Adding ' + hostname + ' to IPA.')
LOG.debug("[%s] Adding %s to IPA.", message_id, hostname)
if not self._ipa_client_configured():
LOG.debug('IPA is not configured')
LOG.debug('[%s] IPA is not configured', message_id)
return False
# There's no use in doing any operations if ipalib hasn't been
@ -287,7 +292,7 @@ class IPAClient(IPANovaJoinBase):
image_metadata = {}
if hostname in self.host_cache:
LOG.debug('Host ' + hostname + ' found in cache.')
LOG.debug("[%s] Host %s found in cache.", message_id, hostname)
return self.host_cache[hostname]
params = [hostname]
@ -316,11 +321,11 @@ class IPAClient(IPANovaJoinBase):
}
try:
self._call_ipa('host_mod', *params, **modargs)
self._call_ipa(message_id, 'host_mod', *params, **modargs)
self.host_cache[hostname] = six.text_type(ipaotp)
except errors.NotFound:
try:
self._call_ipa('host_add', *params, **hostargs)
self._call_ipa(message_id, 'host_add', *params, **hostargs)
self.host_cache[hostname] = six.text_type(ipaotp)
except errors.DuplicateEntry:
# We have no idea what the OTP is for the existing host.
@ -337,30 +342,30 @@ class IPAClient(IPANovaJoinBase):
return self.host_cache.get(hostname, False)
def add_subhost(self, hostname):
def add_subhost(self, hostname, message_id=0):
"""Add a subhost to IPA.
Servers can have multiple network interfaces, and therefore can
have multiple aliases. Moreover, they can part of a service using
a virtual host (VIP). These aliases are denoted 'subhosts',
"""
LOG.debug('Adding subhost: ' + hostname)
LOG.debug('[%s] Adding subhost: %s', message_id, hostname)
if hostname not in self.host_cache:
params = [hostname]
hostargs = {'force': True}
self._add_batch_operation('host_add', *params, **hostargs)
self.host_cache[hostname] = True
else:
LOG.debug('subhost ' + hostname + ' found in cache.')
LOG.debug("[%s] subhost %s found in cache.", message_id, hostname)
def delete_subhost(self, hostname, batch=True):
def delete_subhost(self, hostname, batch=True, message_id=0):
"""Delete a subhost from IPA.
Servers can have multiple network interfaces, and therefore can
have multiple aliases. Moreover, they can part of a service using
a virtual host (VIP). These aliases are denoted 'subhosts',
"""
LOG.debug('Deleting subhost: ' + hostname)
LOG.debug(" [%s] Deleting subhost: %s", message_id, hostname)
host_params = [hostname]
(hn, domain) = self.split_hostname(hostname)
@ -381,19 +386,20 @@ class IPAClient(IPANovaJoinBase):
else:
if hostname in self.host_cache:
del self.host_cache[hostname]
self._call_ipa('host_del', *host_params, **host_kw)
self._call_ipa(message_id, 'host_del', *host_params, **host_kw)
try:
self._call_ipa('dnsrecord_del', *dns_params, **dns_kw)
self._call_ipa(message_id, 'dnsrecord_del',
*dns_params, **dns_kw)
except (errors.NotFound, errors.ACIError):
# Ignore DNS deletion errors
pass
def delete_host(self, hostname, metadata=None):
def delete_host(self, hostname, metadata=None, message_id=0):
"""Delete a host from IPA and remove all related DNS entries."""
LOG.debug('Deleting ' + hostname + ' from IPA.')
LOG.debug("[%s] Deleting %s from IPA", message_id, hostname)
if not self._ipa_client_configured():
LOG.debug('IPA is not configured')
LOG.debug('[%s] IPA is not configured', message_id)
return
if metadata is None:
@ -409,7 +415,7 @@ class IPAClient(IPANovaJoinBase):
try:
if hostname in self.host_cache:
del self.host_cache[hostname]
self._call_ipa('host_del', *params, **kw)
self._call_ipa(message_id, 'host_del', *params, **kw)
except (errors.NotFound, errors.ACIError):
# Trying to delete a host that doesn't exist will raise an ACIError
# to hide whether the entry exists or not
@ -422,27 +428,28 @@ class IPAClient(IPANovaJoinBase):
dns_kw = {'del_all': True, }
try:
self._call_ipa('dnsrecord_del', *dns_params, **dns_kw)
self._call_ipa(message_id, 'dnsrecord_del', *dns_params, **dns_kw)
except (errors.NotFound, errors.ACIError):
# Ignore DNS deletion errors
pass
def add_service(self, principal):
def add_service(self, principal, message_id=0):
if principal not in self.service_cache:
try:
(service, hostname, realm) = self.split_principal(principal)
except errors.MalformedServicePrincipal as e:
LOG.error("Unable to split principal %s: %s", principal, e)
LOG.error("[%s] Unable to split principal %s: %s",
message_id, principal, e)
raise
LOG.debug('Adding service: ' + principal)
LOG.debug("[%s] Adding service: %s", message_id, principal)
params = [principal]
service_args = {'force': True}
self._add_batch_operation('service_add', *params, **service_args)
self.service_cache[principal] = [hostname]
else:
LOG.debug('Service ' + principal + ' found in cache.')
LOG.debug("[%s] Service %s found in cache", message_id, principal)
def service_add_host(self, service_principal, host):
def service_add_host(self, service_principal, host, message_id=0):
"""Add a host to a service.
In IPA there is a relationship between a host and the services for
@ -454,8 +461,8 @@ class IPAClient(IPANovaJoinBase):
in IPA this is done using the service-add-host API.
"""
if host not in self.service_cache.get(service_principal, []):
LOG.debug('Adding principal ' + service_principal +
' to host ' + host)
LOG.debug("[%s] Adding principal %s to host %s",
message_id, service_principal, host)
params = [service_principal]
service_args = {'host': (host,)}
self._add_batch_operation('service_add_host', *params,
@ -463,17 +470,19 @@ class IPAClient(IPANovaJoinBase):
self.service_cache[service_principal] = self.service_cache.get(
service_principal, []) + [host]
else:
LOG.debug('Host ' + host + ' managing ' + service_principal +
' found in cache.')
LOG.debug("[%s] Host %s managing %s found in cache",
message_id, host, service_principal)
def service_has_hosts(self, service_principal):
def service_has_hosts(self, service_principal, message_id=0):
"""Return True if hosts other than parent manages this service"""
LOG.debug('Checking if principal ' + service_principal + ' has hosts')
LOG.debug("[%s] Checking if principal %s has hosts",
message_id, service_principal)
params = [service_principal]
service_args = {}
try:
result = self._call_ipa('service_show', *params, **service_args)
result = self._call_ipa(message_id, 'service_show',
*params, **service_args)
except errors.NotFound:
raise KeyError
serviceresult = result['result']
@ -483,7 +492,8 @@ class IPAClient(IPANovaJoinBase):
service_principal
)
except errors.MalformedServicePrincipal as e:
LOG.error("Unable to split principal %s: %s", service_principal, e)
LOG.error("[%s] Unable to split principal %s: %s",
message_id, service_principal, e)
raise
for candidate in serviceresult.get('managedby_host', []):
@ -491,28 +501,30 @@ class IPAClient(IPANovaJoinBase):
return True
return False
def host_get_services(self, service_host):
def host_get_services(self, service_host, message_id=0):
"""Return list of services this host manages"""
LOG.debug('Checking host ' + service_host + ' services')
LOG.debug("[%s] Checking host %s services", message_id, service_host)
params = []
service_args = {'man_by_host': six.text_type(service_host)}
result = self._call_ipa('service_find', *params, **service_args)
result = self._call_ipa(message_id, 'service_find',
*params, **service_args)
return [service['krbprincipalname'][0] for service in result['result']]
def host_has_services(self, service_host):
def host_has_services(self, service_host, message_id=0):
"""Return True if this host manages any services"""
return len(self.host_get_services(service_host)) > 0
return len(self.host_get_services(service_host, message_id)) > 0
def find_host(self, hostname):
def find_host(self, hostname, message_id=0):
"""Return True if this host exists"""
LOG.debug('Checking if host ' + hostname + ' exists')
LOG.debug("[%s] Checking if host %s exists", message_id, hostname)
params = []
service_args = {'fqdn': six.text_type(hostname)}
result = self._call_ipa('host_find', *params, **service_args)
result = self._call_ipa(message_id, 'host_find',
*params, **service_args)
return result['count'] > 0
def delete_service(self, principal, batch=True):
LOG.debug('Deleting service: ' + principal)
def delete_service(self, principal, batch=True, message_id=0):
LOG.debug("[%s] Deleting service: %s", message_id, principal)
params = [principal]
service_args = {}
if batch:
@ -522,14 +534,15 @@ class IPAClient(IPANovaJoinBase):
else:
if principal in self.service_cache:
del self.service_cache[principal]
return self._call_ipa('service_del', *params, **service_args)
return self._call_ipa(message_id, 'service_del',
*params, **service_args)
def add_ip(self, hostname, floating_ip):
def add_ip(self, hostname, floating_ip, message_id=0):
"""Add a floating IP to a given hostname."""
LOG.debug('In add_ip')
LOG.debug("[%s] In add_ip", message_id)
if not self._ipa_client_configured():
LOG.debug('IPA is not configured')
LOG.debug('[%s] IPA is not configured', message_id)
return
params = [six.text_type(get_domain() + '.'),
@ -537,35 +550,39 @@ class IPAClient(IPANovaJoinBase):
kw = {'a_part_ip_address': six.text_type(floating_ip)}
try:
self._call_ipa('dnsrecord_add', *params, **kw)
self._call_ipa(message_id, 'dnsrecord_add', *params, **kw)
except (errors.DuplicateEntry, errors.ValidationError):
pass
def find_record(self, floating_ip):
def find_record(self, floating_ip, message_id=0):
"""Find DNS A record for floating IP address"""
LOG.debug('looking up host for floating ip' + floating_ip)
LOG.debug("[%s] looking up host for floating ip %s",
message_id, floating_ip)
params = [six.text_type(get_domain() + '.')]
service_args = {'arecord': six.text_type(floating_ip)}
result = self._call_ipa('dnsrecord_find', *params, **service_args)
result = self._call_ipa(message_id, 'dnsrecord_find',
*params, **service_args)
if result['count'] == 0:
return
assert(result['count'] == 1)
return result['result'][0]['idnsname'][0].to_unicode()
def remove_ip(self, floating_ip):
def remove_ip(self, floating_ip, message_id=0):
"""Remove a floating IP from a given hostname."""
LOG.debug('In remove_ip')
LOG.debug("[%s] In remove_ip", message_id)
if not self._ipa_client_configured():
LOG.debug('IPA is not configured')
LOG.debug("[%s] IPA is not configured", message_id)
return
hostname = self.find_record(floating_ip)
hostname = self.find_record(floating_ip, message_id)
if not hostname:
LOG.debug('floating IP record not found')
LOG.debug("[%s] floating IP record not found for %s",
message_id, floating_ip)
return
params = [six.text_type(get_domain() + '.'), hostname]
service_args = {'arecord': six.text_type(floating_ip)}
self._call_ipa('dnsrecord_del', *params, **service_args)
self._call_ipa(message_id, 'dnsrecord_del',
*params, **service_args)

View File

@ -108,6 +108,12 @@ class JoinController(Controller):
Options passed in but as yet-unused are and user-data.
"""
# Set message id to zero for now.
# We could set it to the request_id in the python-request,
# but this is already logged as part of the server logs.
message_id = 0
if not body:
LOG.error('No body in create request')
raise base.Fault(webob.exc.HTTPBadRequest())
@ -191,7 +197,8 @@ class JoinController(Controller):
try:
data['ipaotp'] = self.ipaclient.add_host(data['hostname'], ipaotp,
metadata, image_metadata)
metadata, image_metadata,
message_id)
if not data['ipaotp']:
# OTP was not added to host, don't return one
del data['ipaotp']
@ -199,24 +206,26 @@ class JoinController(Controller):
LOG.error('adding host failed %s', e)
LOG.error(traceback.format_exc())
self.ipaclient.start_batch_operation()
self.ipaclient.start_batch_operation(message_id)
# key-per-service
managed_services = [metadata[key] for key in metadata.keys()
if key.startswith('managed_service_')]
if managed_services:
self.add_managed_services(data['hostname'], managed_services)
self.add_managed_services(
data['hostname'], managed_services, message_id)
compact_services = util.get_compact_services(metadata)
if compact_services:
self.add_compact_services(hostname_short, compact_services)
self.add_compact_services(
hostname_short, compact_services, message_id)
self.ipaclient.flush_batch_operation()
self.ipaclient.flush_batch_operation(message_id)
return data
def add_managed_services(self, base_host, services):
def add_managed_services(self, base_host, services, message_id=0):
"""Make any host/principal assignments passed into metadata."""
LOG.debug("In add_managed_services")
LOG.debug("[%s] In add_managed_services", message_id)
hosts_found = list()
services_found = list()
@ -226,17 +235,18 @@ class JoinController(Controller):
# add host if not present
if principal_host not in hosts_found:
self.ipaclient.add_subhost(principal_host)
self.ipaclient.add_subhost(principal_host, message_id)
hosts_found.append(principal_host)
# add service if not present
if principal not in services_found:
self.ipaclient.add_service(principal)
self.ipaclient.add_service(principal, message_id)
services_found.append(principal)
self.ipaclient.service_add_host(principal, base_host)
self.ipaclient.service_add_host(principal, base_host, message_id)
def add_compact_services(self, base_host_short, service_repr):
def add_compact_services(self, base_host_short, service_repr,
message_id=0):
"""Make any host/principal assignments passed from metadata
This takes a dictionary representation of the services and networks
@ -270,7 +280,7 @@ class JoinController(Controller):
This attempts to do a more compact representation since the nova
metadta entries have a limit of 255 characters.
"""
LOG.debug("In add_compact_services")
LOG.debug("[%s] In add_compact_services", message_id)
hosts_found = list()
services_found = list()
@ -284,12 +294,13 @@ class JoinController(Controller):
# add host if not present
if principal_host not in hosts_found:
self.ipaclient.add_subhost(principal_host)
self.ipaclient.add_subhost(principal_host, message_id)
hosts_found.append(principal_host)
# add service if not present
if principal not in services_found:
self.ipaclient.add_service(principal)
self.ipaclient.add_service(principal, message_id)
services_found.append(principal)
self.ipaclient.service_add_host(principal, base_host)
self.ipaclient.service_add_host(
principal, base_host, message_id)

View File

@ -65,9 +65,10 @@ class Registry(dict):
def __call__(self, name, version=None, service='nova'):
def register_event(fun):
if version:
def check_event(sself, payload):
def check_event(sself, payload, message_id):
self.check_version(payload, version, service)
return fun(sself, payload[service + '_object.data'])
return fun(sself, payload[service + '_object.data'],
message_id)
self[name] = check_event
return check_event
self[name] = fun
@ -124,19 +125,22 @@ class NotificationEndpoint(object):
LOG.debug("publisher: %s, event: %s, metadata: %s", publisher_id,
event_type, metadata)
message_id = metadata['message_id']
event_handler = self.event_handlers.get(
event_type, lambda payload: LOG.error("Status update or unknown"))
# run event handler for received notification type
event_handler(self, payload)
event_handler(self, payload, message_id)
@event_handlers('compute.instance.create.end')
def compute_instance_create(self, payload):
def compute_instance_create(self, payload, message_id):
hostname = self._generate_hostname(payload.get('hostname'))
instance_id = payload['instance_id']
LOG.info("Add new host %s (%s)", instance_id, hostname)
LOG.info("[%s] Add new host %s (%s)",
message_id, instance_id, hostname)
@event_handlers('compute.instance.update')
def compute_instance_update(self, payload):
def compute_instance_update(self, payload, message_id):
ipa = ipaclient()
join_controller = join.JoinController(ipa)
hostname_short = payload['hostname']
@ -149,33 +153,37 @@ class NotificationEndpoint(object):
enroll = payload_metadata.get('ipa_enroll', '')
image_enroll = image_metadata.get('ipa_enroll', '')
if enroll.lower() != 'true' and image_enroll.lower() != 'true':
LOG.info('IPA enrollment not requested, skipping update of %s',
hostname)
LOG.info(
'[%s] IPA enrollment not requested, skipping update of %s',
message_id, hostname)
return
# Ensure this instance exists in nova
instance = get_instance(instance_id)
if instance is None:
msg = 'No such instance-id, %s' % instance_id
msg = '[%s] No such instance-id, %s' % (message_id, instance_id)
LOG.error(msg)
return
ipa.start_batch_operation()
LOG.info("[%s] compute instance update for %s", message_id, hostname)
ipa.start_batch_operation(message_id)
# key-per-service
managed_services = [
payload_metadata[key] for key in payload_metadata.keys()
if key.startswith('managed_service_')]
if managed_services:
join_controller.add_managed_services(hostname, managed_services)
join_controller.add_managed_services(
hostname, managed_services, message_id)
compact_services = util.get_compact_services(payload_metadata)
if compact_services:
join_controller.add_compact_services(
hostname_short, compact_services)
hostname_short, compact_services, message_id)
ipa.flush_batch_operation()
ipa.flush_batch_operation(message_id)
@event_handlers('compute.instance.delete.end')
def compute_instance_delete(self, payload):
def compute_instance_delete(self, payload, message_id):
hostname_short = payload['hostname']
instance_id = payload['instance_id']
payload_metadata = payload['metadata']
@ -187,49 +195,51 @@ class NotificationEndpoint(object):
image_enroll = image_metadata.get('ipa_enroll', '')
if enroll.lower() != 'true' and image_enroll.lower() != 'true':
LOG.info('IPA enrollment not requested, skipping delete of %s',
hostname)
LOG.info(
'[%s] IPA enrollment not requested, skipping delete of %s',
message_id, hostname)
return
LOG.info("Delete host %s (%s)", instance_id, hostname)
LOG.info("[%s] Delete host %s (%s)", message_id, instance_id, hostname)
try:
ipa = ipaclient()
ipa.delete_host(hostname, {})
ipa.delete_host(hostname, {}, message_id)
self.delete_subhosts(ipa, hostname_short, payload_metadata)
except exception.IPAConnectionError:
LOG.error("IPA Connection Error when deleting host %s (%s). "
LOG.error("[%s] IPA Connection Error when deleting host %s (%s). "
"Manual cleanup may be required in the IPA server.",
instance_id, hostname)
message_id, instance_id, hostname)
@event_handlers('network.floating_ip.associate')
def floaitng_ip_associate(self, payload):
def floaitng_ip_associate(self, payload, message_id):
floating_ip = payload['floating_ip']
LOG.info("Associate floating IP %s" % floating_ip)
LOG.info("[%s] Associate floating IP %s" % (message_id, floating_ip))
ipa = ipaclient()
nova = novaclient()
server = nova.servers.get(payload['instance_id'])
if server:
ipa.add_ip(server.name, floating_ip)
ipa.add_ip(server.name, floating_ip, message_id)
else:
LOG.error("Could not resolve %s into a hostname",
payload['instance_id'])
LOG.error("[%s] Could not resolve %s into a hostname",
message_id, payload['instance_id'])
@event_handlers('network.floating_ip.disassociate')
def floating_ip_disassociate(self, payload):
def floating_ip_disassociate(self, payload, message_id):
floating_ip = payload['floating_ip']
LOG.info("Disassociate floating IP %s" % floating_ip)
LOG.info("[%s] Disassociate floating IP %s", message_id, floating_ip)
ipa = ipaclient()
ipa.remove_ip(floating_ip)
ipa.remove_ip(floating_ip, message_id)
@event_handlers('floatingip.update.end')
def floating_ip_update(self, payload):
def floating_ip_update(self, payload, message_id):
"""Neutron event"""
floatingip = payload['floatingip']
floating_ip = floatingip['floating_ip_address']
port_id = floatingip['port_id']
ipa = ipaclient()
if port_id:
LOG.info("Neutron floating IP associate: %s" % floating_ip)
LOG.info("[%s] Neutron floating IP associate: %s",
message_id, floating_ip)
nova = novaclient()
neutron = neutronclient()
search_opts = {'id': port_id}
@ -239,14 +249,16 @@ class NotificationEndpoint(object):
if device_id:
server = nova.servers.get(device_id)
if server:
ipa.add_ip(server.name, floating_ip)
ipa.add_ip(server.name, floating_ip, message_id)
else:
LOG.error("Expected 1 port, got %d", len(ports))
LOG.error("[%s] Expected 1 port, got %d",
message_id, len(ports))
else:
LOG.info("Neutron floating IP disassociate: %s" % floating_ip)
ipa.remove_ip(floating_ip)
LOG.info("[%s] Neutron floating IP disassociate: %s",
message_id, floating_ip)
ipa.remove_ip(floating_ip, message_id)
def delete_subhosts(self, ipa, hostname_short, metadata):
def delete_subhosts(self, ipa, hostname_short, metadata, message_id):
"""Delete subhosts and remove VIPs if possible.
Servers can have multiple network interfaces, and therefore can
@ -269,13 +281,15 @@ class NotificationEndpoint(object):
compact_services = util.get_compact_services(metadata)
if compact_services:
self.delete_compact_services(ipa, hostname_short,
compact_services)
compact_services,
message_id)
managed_services = [metadata[key] for key in metadata.keys()
if key.startswith('managed_service_')]
if managed_services:
self.delete_managed_services(ipa, managed_services)
self.delete_managed_services(ipa, managed_services, message_id)
def delete_compact_services(self, ipa, host_short, service_repr):
def delete_compact_services(self, ipa, host_short, service_repr,
message_id):
"""Reconstructs and removes subhosts for compact services.
Data looks like this:
@ -289,10 +303,10 @@ class NotificationEndpoint(object):
services to be automatically deleted through IPA referential
integrity.
"""
LOG.debug("In delete compact services")
LOG.debug("[%s] In delete compact services", message_id)
hosts_found = list()
ipa.start_batch_operation()
ipa.start_batch_operation(message_id)
for service_name, net_list in service_repr.items():
for network in net_list:
host = "%s.%s" % (host_short, network)
@ -302,15 +316,15 @@ class NotificationEndpoint(object):
if principal_host not in hosts_found:
ipa.delete_subhost(principal_host)
hosts_found.append(principal_host)
ipa.flush_batch_operation()
ipa.flush_batch_operation(message_id)
def delete_managed_services(self, ipa, services):
def delete_managed_services(self, ipa, services, message_id):
"""Delete any managed services if possible.
Checks to see if the managed service subhost has no managed hosts
associations and if so, deletes the host.
"""
LOG.debug("In delete_managed_services")
LOG.debug("[%s] In delete_managed_services", message_id)
hosts_deleted = list()
services_deleted = list()
@ -353,15 +367,15 @@ class VersionedNotificationEndpoint(NotificationEndpoint):
event_handlers = Registry(NotificationEndpoint.event_handlers)
@event_handlers('instance.create.end', '1.10')
def instance_create(self, payload):
def instance_create(self, payload, message_id):
newpayload = {
'hostname': payload['host_name'],
'instance_id': payload['uuid'],
}
self.compute_instance_create(newpayload)
self.compute_instance_create(newpayload, message_id)
@event_handlers('instance.update', '1.8')
def instance_update(self, payload):
def instance_update(self, payload, message_id):
glance = glanceclient()
newpayload = {
'hostname': payload['host_name'],
@ -369,10 +383,10 @@ class VersionedNotificationEndpoint(NotificationEndpoint):
'metadata': payload['metadata'],
'image_meta': glance.images.get(payload['image_uuid'])
}
self.compute_instance_update(newpayload)
self.compute_instance_update(newpayload, message_id)
@event_handlers('instance.delete.end', '1.7')
def instance_delete(self, payload):
def instance_delete(self, payload, message_id):
glance = glanceclient()
newpayload = {
'hostname': payload['host_name'],
@ -380,7 +394,7 @@ class VersionedNotificationEndpoint(NotificationEndpoint):
'metadata': payload['metadata'],
'image_meta': glance.images.get(payload['image_uuid'])
}
self.compute_instance_delete(newpayload)
self.compute_instance_delete(newpayload, message_id)
def main():