Skip to content

Commit

Permalink
Opt-in email notifications when {repo sync, cv promote, cv publish, p…
Browse files Browse the repository at this point in the history
…roxy sync} fails (#10742)

* Fixes #17748 - Opt-in email notification on repo sync failure

* Fixes #17748 - Opt-in email notification on cv publish failure

* Fixes #17748 - Opt-in email notification on cv promote failure

* Fixes #17748 - Opt-in email notification on proxy sync failure

* Refs #17748 - Make rubocop happy

* Refs #17748 - Expose capsule content sync in events

to be consumed from webhooks

* Refs #17748 - Send emails also when things go into paused
  • Loading branch information
adamruzicka authored Oct 4, 2023
1 parent 9d03ca6 commit fbf7739
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 9 deletions.
39 changes: 30 additions & 9 deletions app/lib/actions/katello/capsule_content/sync.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ module Actions
module Katello
module CapsuleContent
class Sync < ::Actions::EntryAction
include ::Actions::ObservableAction
def resource_locks
:link
end

execution_plan_hooks.use :notify_on_failure, :on => [:failure, :paused]

input_format do
param :name
end
Expand All @@ -19,20 +22,16 @@ def humanized_input
end

def plan(smart_proxy, options = {})
input[:options] = options

action_subject(smart_proxy)
smart_proxy.verify_ueber_certs
environment_id = options.fetch(:environment_id, nil)
environment = ::Katello::KTEnvironment.find(environment_id) if environment_id
repository_id = options.fetch(:repository_id, nil)
repository = ::Katello::Repository.find(repository_id) if repository_id
content_view_id = options.fetch(:content_view_id, nil)
content_view = ::Katello::ContentView.find(content_view_id) if content_view_id

subjects = subjects(options)

fail _("Action not allowed for the default smart proxy.") if smart_proxy.pulp_primary?

refresh_options = options.merge(content_view: content_view,
environment: environment,
repository: repository)
refresh_options = options.merge(subjects)
sequence do
if smart_proxy.has_feature?(SmartProxy::PULP3_FEATURE)
plan_action(Actions::Pulp3::ContentGuard::Refresh, smart_proxy)
Expand All @@ -49,6 +48,28 @@ def finalize
smart_proxy&.audit_capsule_sync
end
end

def notify_on_failure(_plan)
notification = MailNotification[:proxy_sync_failure]
proxy = SmartProxy.find(input.fetch(:smart_proxy, {})[:id])
subjects = subjects(input[:options]).merge(smart_proxy: proxy)
notification.users.each do |user|
notification.deliver(subjects.merge(user: user, task: task))
end
end

def subjects(options = {})
environment_id = options.fetch(:environment_id, nil)
environment = ::Katello::KTEnvironment.find(environment_id) if environment_id

repository_id = options.fetch(:repository_id, nil)
repository = ::Katello::Repository.find(repository_id) if repository_id

content_view_id = options.fetch(:content_view_id, nil)
content_view = ::Katello::ContentView.find(content_view_id) if content_view_id

{content_view: content_view, environment: environment, repository: repository}
end
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions app/lib/actions/katello/content_view/promote.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module ContentView
class Promote < Actions::EntryAction
extend ApipieDSL::Class
include ::Actions::ObservableAction
execution_plan_hooks.use :notify_on_failure, :on => [:failure, :paused]

def plan(version, environments, is_force = false, description = nil, incremental_update = false)
action_subject(version.content_view)
Expand All @@ -23,6 +24,14 @@ def plan(version, environments, is_force = false, description = nil, incremental
end
end

def notify_on_failure(_plan)
notification = MailNotification[:content_view_promote_failure]
view = ::Katello::ContentView.find(input.fetch(:content_view, {})[:id])
notification.users.each do |user|
notification.deliver(user: user, content_view: view, task: task)
end
end

def environments
input['environments']
end
Expand Down
9 changes: 9 additions & 0 deletions app/lib/actions/katello/content_view/publish.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class Publish < Actions::EntryAction
include ::Actions::ObservableAction
attr_accessor :version
execution_plan_hooks.use :trigger_capsule_sync, :on => :success
execution_plan_hooks.use :notify_on_failure, :on => [:failure, :paused]

# rubocop:disable Metrics/MethodLength,Metrics/AbcSize,Metrics/CyclomaticComplexity
def plan(content_view, description = "", options = {importing: false, syncable: false}) # rubocop:disable Metrics/PerceivedComplexity
Expand Down Expand Up @@ -132,6 +133,14 @@ def trigger_capsule_sync(_execution_plan)
end
end

def notify_on_failure(_plan)
notification = MailNotification[:content_view_publish_failure]
view = ::Katello::ContentView.find(input.fetch(:content_view, {})[:id])
notification.users.each do |user|
notification.deliver(user: user, content_view: view, task: task)
end
end

def content_view_version_id
input['content_view_version_id']
end
Expand Down
10 changes: 10 additions & 0 deletions app/lib/actions/katello/repository/sync.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Sync < Actions::EntryAction
include ::Actions::ObservableAction
middleware.use Actions::Middleware::ExecuteIfContentsChanged

execution_plan_hooks.use :notify_on_failure, :on => [:failure, :paused]

input_format do
param :id, Integer
param :sync_result, Hash
Expand Down Expand Up @@ -96,6 +98,14 @@ def rescue_strategy
Dynflow::Action::Rescue::Skip
end

def notify_on_failure(_plan)
notification = MailNotification[:repository_sync_failure]
repo = ::Katello::Repository.find(input.fetch(:repository, {})[:id])
notification.users.each do |user|
notification.deliver(user: user, repo: repo, task: task)
end
end

def repository_id
input['repository']['id']
end
Expand Down
54 changes: 54 additions & 0 deletions app/mailers/katello/task_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module Katello
class TaskMailer < ApplicationMailer
helper ApplicationHelper
include Rails.application.routes.url_helpers

def repo_sync_failure(options)
user, @repo, @task = options.values_at(:user, :repo, :task)

::User.as(user.login) do
subject = _("Repository %{label} failed to synchronize") % { :label => @repo.label }

set_locale_for(user) do
mail(:to => user.mail, :subject => subject)
end
end
end

def cv_publish_failure(options)
user, @content_view, @task = options.values_at(:user, :content_view, :task)

::User.as(user.login) do
subject = _("%{label} failed") % { :label => @task.action }

set_locale_for(user) do
mail(:to => user.mail, :subject => subject)
end
end
end

def cv_promote_failure(options)
user, @content_view, @task = options.values_at(:user, :content_view, :task)

::User.as(user.login) do
subject = _("%{label} failed") % { :label => @task.action }

set_locale_for(user) do
mail(:to => user.mail, :subject => subject)
end
end
end

def proxy_sync_failure(options)
user, @environment, @repo, @content_view, @task, @smart_proxy = options.values_at(:user, :environment, :repository, :content_view, :task, :smart_proxy)

::User.as(user.login) do
subject = _("%{label} failed") % { :label => @task.action }

set_locale_for(user) do
mail(:to => user.mail, :subject => subject)
end
end
end
end
end
31 changes: 31 additions & 0 deletions app/views/katello/task_mailer/cv_promote_failure.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<p>
<%= _("%{label} failed.") % { :label => @task.action } %>
</p>

<div class="dashboard">
<table>
<tr>
<td><%= _('Content view') %></td>
<td><%= link_to @content_view.name, "#{katello_url}content_views/#{@content_view.id}" %></td>
</tr>
<tr>
<td><%= _('Task ID') %></td>
<td><%= link_to @task.id, foreman_tasks_task_url(@task.id) %></td>
</tr>
<tr>
<td><%= _('Task state') %></td>
<td><%= @task.state %></td>
</tr>
<tr>
<td><%= _('Task result') %></td>
<td><%= @task.result %></td>
</tr>
</table>

Errors:
<ul>
<% @task.execution_plan.errors.each do |error| %>
<li><%= error.exception_class %>: <%= error.message %></li>
<% end %>
</ul>
</div>
13 changes: 13 additions & 0 deletions app/views/katello/task_mailer/cv_promote_failure.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<%= _("%{label} failed.") % { :label => @task.action } %>

<%= _('Content view ID') %>: <%= @content_view.id %>
<%= _('Content view name') %>: <%= @content_view.name %>
<%= _('Task ID') %>: <%= @task.id %>
<%= _('Task state') %>: <%= @task.state %>
<%= _('Task result') %>: <%= @task.result %>
<%= _('Task details') %>: <%= foreman_tasks_task_url(@task) %>

Errors:
<% @task.execution_plan.errors.each do |error| %>
- <%= error.exception_class %>: <%= error.message %>
<% end %>
31 changes: 31 additions & 0 deletions app/views/katello/task_mailer/cv_publish_failure.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<p>
<%= _("%{label} failed.") % { :label => @task.action } %>
</p>

<div class="dashboard">
<table>
<tr>
<td><%= _('Content view') %></td>
<td><%= link_to @content_view.name, "#{katello_url}content_views/#{@content_view.id}" %></td>
</tr>
<tr>
<td><%= _('Task ID') %></td>
<td><%= link_to @task.id, foreman_tasks_task_url(@task.id) %></td>
</tr>
<tr>
<td><%= _('Task state') %></td>
<td><%= @task.state %></td>
</tr>
<tr>
<td><%= _('Task result') %></td>
<td><%= @task.result %></td>
</tr>
</table>

Errors:
<ul>
<% @task.execution_plan.errors.each do |error| %>
<li><%= error.exception_class %>: <%= error.message %></li>
<% end %>
</ul>
</div>
13 changes: 13 additions & 0 deletions app/views/katello/task_mailer/cv_publish_failure.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<%= _("%{label} failed.") % { :label => @task.action } %>

<%= _('Content view ID') %>: <%= @content_view.id %>
<%= _('Content view name') %>: <%= @content_view.name %>
<%= _('Task ID') %>: <%= @task.id %>
<%= _('Task state') %>: <%= @task.state %>
<%= _('Task result') %>: <%= @task.result %>
<%= _('Task details') %>: <%= foreman_tasks_task_url(@task) %>

Errors:
<% @task.execution_plan.errors.each do |error| %>
- <%= error.exception_class %>: <%= error.message %>
<% end %>
45 changes: 45 additions & 0 deletions app/views/katello/task_mailer/proxy_sync_failure.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<p>
<%= _("%{label} failed.") % { :label => @task.action } %>
</p>

<div class="dashboard">
<table>
<% if @environment %>
<tr>
<td><%= _('Environment') %></td>
<td><%= link_to @environment.name, "#{katello_url}lifecycle_environments/#{@environment.id}" %></td>
</tr>
<% end %>
<% if @content_view %>
<tr>
<td><%= _('Content view') %></td>
<td><%= link_to @content_view.name, "#{katello_url}content_views/#{@content_view.id}" %></td>
</tr>
<% end %>
<% if @repo %>
<tr>
<td><%= _('Repository') %></td>
<td><%= link_to @repo.name, "#{katello_url}products/#{@repo.product.id}/repositories/#{@repo.id}" %></td>
</tr>
<% end %>
<tr>
<td><%= _('Task ID') %></td>
<td><%= link_to @task.id, foreman_tasks_task_url(@task.id) %></td>
</tr>
<tr>
<td><%= _('Task state') %></td>
<td><%= @task.state %></td>
</tr>
<tr>
<td><%= _('Task result') %></td>
<td><%= @task.result %></td>
</tr>
</table>

Errors:
<ul>
<% @task.execution_plan.errors.each do |error| %>
<li><%= error.exception_class %>: <%= error.message %></li>
<% end %>
</ul>
</div>
25 changes: 25 additions & 0 deletions app/views/katello/task_mailer/proxy_sync_failure.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<%= _("%{label} failed.") % { :label => @task.action } %>

<%= _('Smart proxy ID') %>: <%= @smart_proxy.id %>
<%= _('Smart proxy name') %>: <%= @smart_proxy.name %>
<% if @environment %>
<%= _('Environment ID') %>: <%= @environment&.id %>
<%= _('Environment name') %>: <%= @environment&.name %>
<% end %>
<% if @content_view %>
<%= _('Content view ID') %>: <%= @content_view&.id %>
<%= _('Content view name') %>: <%= @content_view&.name %>
<% end %>
<% if @repo %>
<%= _('Repository ID') %>: <%= @repo&.id %>
<%= _('Repository name') %>: <%= @repo&.name %>
<% end %>
<%= _('Task ID') %>: <%= @task.id %>
<%= _('Task state') %>: <%= @task.state %>
<%= _('Task result') %>: <%= @task.result %>
<%= _('Task details') %>: <%= foreman_tasks_task_url(@task) %>

Errors:
<% @task.execution_plan.errors.each do |error| %>
- <%= error.exception_class %>: <%= error.message %>
<% end %>
35 changes: 35 additions & 0 deletions app/views/katello/task_mailer/repo_sync_failure.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<p>
<%= _("%{label} failed.") % { :label => @task.action } %>
</p>

<div class="dashboard">
<table>
<tr>
<td><%= _('Repository') %></td>
<td><%= link_to @repo.label, "#{katello_url}products/#{@repo.product.id}/repositories/#{@repo.id}" %></td>
</tr>
<tr>
<td><%= _('Product') %></td>
<td><%= link_to @repo.product.label, "#{katello_url}products/#{@repo.product.id}" %></td>
</tr>
<tr>
<td><%= _('Task ID') %></td>
<td><%= link_to @task.id, foreman_tasks_task_url(@task.id) %></td>
</tr>
<tr>
<td><%= _('Task state') %></td>
<td><%= @task.state %></td>
</tr>
<tr>
<td><%= _('Task result') %></td>
<td><%= @task.result %></td>
</tr>
</table>

Errors:
<ul>
<% @task.execution_plan.errors.each do |error| %>
<li><%= error.exception_class %>: <%= error.message %></li>
<% end %>
</ul>
</div>
Loading

0 comments on commit fbf7739

Please sign in to comment.