-
Notifications
You must be signed in to change notification settings - Fork 919
Description
ISSUE
Environment
- ManageIQ version: radjabov
- OpenStack provider: Configured with AMQP/Cinder
- Affected operations: All volume operations (create, update, delete, backup)
Problem Summary
When creating CloudVolumes through ManageIQ UI/API, notifications are only visible with audience: global. With audience: tenant or audience: user, notifications are created in the database but have zero recipients, making them invisible to users.
Root cause: The with_notification wrapper in the OpenStack provider gem does not pass :initiator (or :subject) parameters, resulting in Notification.create(subject: nil, initiator: nil).
Expected Behavior
Volume operation notifications should work correctly with all audience types:
- global: All users receive notifications
- tenant: Users in the tenant receive notifications
- user: The initiating user receives notifications
Actual Behavior
With audience: global
ruby
Notification created with nil values
Notification.create(subject: nil, initiator: nil)
subscriber_ids for global audience
User.pluck(:id) # Returns all users [1,2,3...] regardless of nil parameters
Result: Notification visible to all users (works by accident)
With audience: tenant
ruby
Notification created with nil values
Notification.create(subject: nil, initiator: nil)
subscriber_ids for tenant audience
nil.try(:tenant).try(:user_ids) # Returns []
Result: Notification created but zero recipients (invisible!)
With audience: user
ruby
Notification created with nil values
Notification.create(subject: nil, initiator: nil)
subscriber_ids for user audience
[nil.id] # Error or []
Result: Notification fails or has zero recipients
Technical Analysis
Current Code (manageiq-providers-openstack)
File: app/models/manageiq/providers/openstack/storage_manager/cinder_manager/cloud_volume.rb
ruby
def raw_create_volume(ext_management_system, options)
...
with_notification(:cloud_volume_create,
:options => {:volume_name => options[:name]}) do
# Create volume on OpenStack
end
...
end
Problem: Does not pass :initiator or :subject to with_notification.
File: app/models/manageiq/providers/openstack/helper_methods.rb
ruby
def with_notification(type, options: {})
Extract named_options (subject, initiator, cause)
named_options = options.extract!(:subject, :initiator, :cause)
...
Creates notification with extracted parameters
Notification.create(:type => "#{type}_success".to_sym,
:options => success_options,
**named_options) # subject: nil, initiator: nil
end
Problem: Correctly extracts parameters, but they're never provided by calling code.
How subscriber_ids Works (manageiq core)
File: app/models/notification_type.rb
ruby
def subscriber_ids(subject, initiator)
case audience
when AUDIENCE_GLOBAL
User.pluck(:id) # Returns ALL users, ignores parameters
when AUDIENCE_USER
[initiator.id] # Requires initiator!
when AUDIENCE_TENANT
if subject.respond_to?(:tenant)
subject.tenant # Requires subject!
elsif initiator.kind_of?(User)
initiator.current_tenant # Or requires initiator!
end.try(:user_ids).try(:uniq)
end || []
end
Result:
- global works because it doesn't check parameters
- tenant and user fail because parameters are nil
Database Evidence
Query showing notifications created without recipients:
ruby
With audience: tenant
notification = Notification.where(notification_type: NotificationType.find_by(name: 'cloud_volume_create_success')).last
notification.subject # => nil
notification.initiator # => nil
notification.recipients # => [] (empty!)
notification.notification_recipients.count # => 0
The notification exists in the database but is invisible because notification_recipients table has zero entries.
Affected Operations
All volume operations in the OpenStack provider have this issue:
- Volume Create: with_notification(:cloud_volume_create, :options => {:volume_name => options[:name]})
- Volume Update: with_notification(:cloud_volume_update, :options => {:subject => self})
- Volume Delete: with_notification(:cloud_volume_delete, :options => {:subject => self})
- Backup Create: with_notification(:cloud_volume_backup_create, :options => {:subject => self, :backup_name => options[:name]})
- Backup Delete: Similar pattern
- Snapshot operations: Similar pattern
Note: Delete and Update operations pass :subject => self, but still missing :initiator.
Proposed Solution
Option 1: Pass initiator in volume operations
In cloud_volume.rb:
ruby
def raw_create_volume(ext_management_system, options)
cloud_tenant = find_destination_cloud_tenant(ext_management_system, options)
Find initiator from the cloud_tenant
initiator = cloud_tenant&.source_tenant&.users&.first || User.current_user
with_notification(:cloud_volume_create,
:options => {:volume_name => options[:name]},
:initiator => initiator) do # ← ADD THIS
ext_management_system.with_provider_connection(cinder_connection_options(cloud_tenant)) do |service|
volume = service.volumes.new(options)
volume.save
end
end
...
end
Apply similar changes to all volume operations (update, delete, backup, snapshot).
Option 2: Enhanced with_notification helper
Modify helper_methods.rb to automatically determine initiator:
ruby
def with_notification(type, options: {})
If no initiator provided, try to determine it
if options[:initiator].nil?
options[:initiator] = User.current_user
end
Rest of the method...
end
Option 3: Use thread-local User.current_user in subscriber_ids
Modify core ManageIQ notification_type.rb to fallback to current user:
ruby
def subscriber_ids(subject, initiator)
initiator ||= User.current_user # Fallback
case audience
...
end
end
We've identified several potential approaches to fix this issue, but we'd like to hear from the maintainers about the preferred solution
Do you have any?
Thanks