|
26 | 26 | 'TRANSPORT_ALIASES',
|
27 | 27 | ]
|
28 | 28 |
|
| 29 | +import functools |
| 30 | + |
| 31 | +from nova.i18n import _ |
29 | 32 | from oslo_config import cfg
|
| 33 | +from oslo_log import log as logging |
30 | 34 | import oslo_messaging as messaging
|
31 | 35 | from oslo_serialization import jsonutils
|
32 | 36 |
|
|
45 | 49 |
|
46 | 50 | CONF.register_opts(notification_opts)
|
47 | 51 |
|
| 52 | +LOG = logging.getLogger(__name__) |
| 53 | + |
48 | 54 | TRANSPORT = None
|
49 | 55 | LEGACY_NOTIFIER = None
|
50 | 56 | NOTIFICATION_TRANSPORT = None
|
@@ -179,9 +185,168 @@ def get_notifier(service, host=None, publisher_id=None):
|
179 | 185 | assert LEGACY_NOTIFIER is not None
|
180 | 186 | if not publisher_id:
|
181 | 187 | publisher_id = "%s.%s" % (service, host or CONF.host)
|
182 |
| - return LEGACY_NOTIFIER.prepare(publisher_id=publisher_id) |
| 188 | + return LegacyValidatingNotifier( |
| 189 | + LEGACY_NOTIFIER.prepare(publisher_id=publisher_id)) |
183 | 190 |
|
184 | 191 |
|
185 | 192 | def get_versioned_notifier(publisher_id):
|
186 | 193 | assert NOTIFIER is not None
|
187 | 194 | return NOTIFIER.prepare(publisher_id=publisher_id)
|
| 195 | + |
| 196 | + |
| 197 | +class LegacyValidatingNotifier(object): |
| 198 | + """Wraps an oslo.messaging Notifier and checks for allowed event_types.""" |
| 199 | + |
| 200 | + # If true an exception is thrown if the event_type is not allowed, if false |
| 201 | + # then only a WARNING is logged |
| 202 | + fatal = False |
| 203 | + |
| 204 | + # This list contains the already existing therefore allowed legacy |
| 205 | + # notification event_types. New items shall not be added to the list as |
| 206 | + # Nova does not allow new legacy notifications any more. This list will be |
| 207 | + # removed when all the notification is transformed to versioned |
| 208 | + # notifications. |
| 209 | + allowed_legacy_notification_event_types = [ |
| 210 | + 'aggregate.addhost.end', |
| 211 | + 'aggregate.addhost.start', |
| 212 | + 'aggregate.create.end', |
| 213 | + 'aggregate.create.start', |
| 214 | + 'aggregate.delete.end', |
| 215 | + 'aggregate.delete.start', |
| 216 | + 'aggregate.removehost.end', |
| 217 | + 'aggregate.removehost.start', |
| 218 | + 'aggregate.updatemetadata.end', |
| 219 | + 'aggregate.updatemetadata.start', |
| 220 | + 'aggregate.updateprop.end', |
| 221 | + 'aggregate.updateprop.start', |
| 222 | + 'api.fault', |
| 223 | + 'compute.instance.create.end', |
| 224 | + 'compute.instance.create.error', |
| 225 | + 'compute.instance.create_ip.end', |
| 226 | + 'compute.instance.create_ip.start', |
| 227 | + 'compute.instance.create.start', |
| 228 | + 'compute.instance.delete.end', |
| 229 | + 'compute.instance.delete_ip.end', |
| 230 | + 'compute.instance.delete_ip.start', |
| 231 | + 'compute.instance.delete.start', |
| 232 | + 'compute.instance.evacuate', |
| 233 | + 'compute.instance.exists', |
| 234 | + 'compute.instance.finish_resize.end', |
| 235 | + 'compute.instance.finish_resize.start', |
| 236 | + 'compute.instance.live.migration.abort.start', |
| 237 | + 'compute.instance.live.migration.abort.end', |
| 238 | + 'compute.instance.live_migration.post.dest.end', |
| 239 | + 'compute.instance.live_migration.post.dest.start', |
| 240 | + 'compute.instance.live_migration._post.end', |
| 241 | + 'compute.instance.live_migration._post.start', |
| 242 | + 'compute.instance.live_migration.pre.end', |
| 243 | + 'compute.instance.live_migration.pre.start', |
| 244 | + 'compute.instance.live_migration.rollback.dest.end', |
| 245 | + 'compute.instance.live_migration.rollback.dest.start', |
| 246 | + 'compute.instance.live_migration._rollback.end', |
| 247 | + 'compute.instance.live_migration._rollback.start', |
| 248 | + 'compute.instance.pause.end', |
| 249 | + 'compute.instance.pause.start', |
| 250 | + 'compute.instance.power_off.end', |
| 251 | + 'compute.instance.power_off.start', |
| 252 | + 'compute.instance.power_on.end', |
| 253 | + 'compute.instance.power_on.start', |
| 254 | + 'compute.instance.reboot.end', |
| 255 | + 'compute.instance.reboot.start', |
| 256 | + 'compute.instance.rebuild.end', |
| 257 | + 'compute.instance.rebuild.error', |
| 258 | + 'compute.instance.rebuild.scheduled', |
| 259 | + 'compute.instance.rebuild.start', |
| 260 | + 'compute.instance.rescue.end', |
| 261 | + 'compute.instance.rescue.start', |
| 262 | + 'compute.instance.resize.confirm.end', |
| 263 | + 'compute.instance.resize.confirm.start', |
| 264 | + 'compute.instance.resize.end', |
| 265 | + 'compute.instance.resize.error', |
| 266 | + 'compute.instance.resize.prep.end', |
| 267 | + 'compute.instance.resize.prep.start', |
| 268 | + 'compute.instance.resize.revert.end', |
| 269 | + 'compute.instance.resize.revert.start', |
| 270 | + 'compute.instance.resize.start', |
| 271 | + 'compute.instance.restore.end', |
| 272 | + 'compute.instance.restore.start', |
| 273 | + 'compute.instance.resume.end', |
| 274 | + 'compute.instance.resume.start', |
| 275 | + 'compute.instance.shelve.end', |
| 276 | + 'compute.instance.shelve_offload.end', |
| 277 | + 'compute.instance.shelve_offload.start', |
| 278 | + 'compute.instance.shelve.start', |
| 279 | + 'compute.instance.shutdown.end', |
| 280 | + 'compute.instance.shutdown.start', |
| 281 | + 'compute.instance.snapshot.end', |
| 282 | + 'compute.instance.snapshot.start', |
| 283 | + 'compute.instance.soft_delete.end', |
| 284 | + 'compute.instance.soft_delete.start', |
| 285 | + 'compute.instance.suspend.end', |
| 286 | + 'compute.instance.suspend.start', |
| 287 | + 'compute.instance.trigger_crash_dump.end', |
| 288 | + 'compute.instance.trigger_crash_dump.start', |
| 289 | + 'compute.instance.unpause.end', |
| 290 | + 'compute.instance.unpause.start', |
| 291 | + 'compute.instance.unrescue.end', |
| 292 | + 'compute.instance.unrescue.start', |
| 293 | + 'compute.instance.unshelve.start', |
| 294 | + 'compute.instance.unshelve.end', |
| 295 | + 'compute.instance.update', |
| 296 | + 'compute.instance.volume.attach', |
| 297 | + 'compute.instance.volume.detach', |
| 298 | + 'compute.libvirt.error', |
| 299 | + 'compute_task.build_instances', |
| 300 | + 'compute_task.migrate_server', |
| 301 | + 'compute_task.rebuild_server', |
| 302 | + 'HostAPI.power_action.end', |
| 303 | + 'HostAPI.power_action.start', |
| 304 | + 'HostAPI.set_enabled.end', |
| 305 | + 'HostAPI.set_enabled.start', |
| 306 | + 'HostAPI.set_maintenance.end', |
| 307 | + 'HostAPI.set_maintenance.start', |
| 308 | + 'keypair.create.start', |
| 309 | + 'keypair.create.end', |
| 310 | + 'keypair.delete.start', |
| 311 | + 'keypair.delete.end', |
| 312 | + 'keypair.import.start', |
| 313 | + 'keypair.import.end', |
| 314 | + 'network.floating_ip.allocate', |
| 315 | + 'network.floating_ip.associate', |
| 316 | + 'network.floating_ip.deallocate', |
| 317 | + 'network.floating_ip.disassociate', |
| 318 | + 'scheduler.select_destinations.end', |
| 319 | + 'scheduler.select_destinations.start', |
| 320 | + 'servergroup.addmember', |
| 321 | + 'servergroup.create', |
| 322 | + 'servergroup.delete', |
| 323 | + 'volume.usage', |
| 324 | + ] |
| 325 | + |
| 326 | + message = _('%(event_type)s is not a versioned notification and not ' |
| 327 | + 'whitelisted. See ./doc/source/notification.rst') |
| 328 | + |
| 329 | + def __init__(self, notifier): |
| 330 | + self.notifier = notifier |
| 331 | + for priority in ['debug', 'info', 'warn', 'error', 'critical']: |
| 332 | + setattr(self, priority, |
| 333 | + functools.partial(self._notify, priority)) |
| 334 | + |
| 335 | + def _is_wrap_exception_notification(self, payload): |
| 336 | + # nova.exception.wrap_exception decorator emits notification where the |
| 337 | + # event_type is the name of the decorated function. This is used in |
| 338 | + # many places but it will be converted to versioned notification in one |
| 339 | + # run by updating the decorator so it is pointless to white list all |
| 340 | + # the function names here we white list the notification itself |
| 341 | + # detected by the special payload keys. |
| 342 | + return {'exception', 'args'} == set(payload.keys()) |
| 343 | + |
| 344 | + def _notify(self, priority, ctxt, event_type, payload): |
| 345 | + if (event_type not in self.allowed_legacy_notification_event_types and |
| 346 | + not self._is_wrap_exception_notification(payload)): |
| 347 | + if self.fatal: |
| 348 | + raise AssertionError(self.message % {'event_type': event_type}) |
| 349 | + else: |
| 350 | + LOG.warning(self.message, {'event_type': event_type}) |
| 351 | + |
| 352 | + getattr(self.notifier, priority)(ctxt, event_type, payload) |
0 commit comments