foreman_scc_manager 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +619 -0
- data/README.md +38 -0
- data/Rakefile +47 -0
- data/app/assets/javascripts/foreman_scc_manager/scc_accounts.js.coffee +46 -0
- data/app/controllers/scc_accounts_controller.rb +118 -0
- data/app/controllers/scc_products_controller.rb +24 -0
- data/app/helpers/scc_accounts_helper.rb +2 -0
- data/app/helpers/scc_product_helper.rb +2 -0
- data/app/lib/actions/scc_manager/subscribe_product.rb +72 -0
- data/app/lib/actions/scc_manager/sync.rb +36 -0
- data/app/lib/actions/scc_manager/sync_products.rb +37 -0
- data/app/lib/actions/scc_manager/sync_repositories.rb +36 -0
- data/app/lib/scc_manager.rb +37 -0
- data/app/models/scc_account.rb +100 -0
- data/app/models/scc_extending.rb +4 -0
- data/app/models/scc_product.rb +46 -0
- data/app/models/scc_repository.rb +25 -0
- data/app/views/scc_accounts/_form.html.erb +36 -0
- data/app/views/scc_accounts/edit.html.erb +3 -0
- data/app/views/scc_accounts/index.html.erb +38 -0
- data/app/views/scc_accounts/new.html.erb +3 -0
- data/app/views/scc_accounts/show.html.erb +41 -0
- data/config/routes.rb +17 -0
- data/db/migrate/20170221100619_create_scc_accounts.rb +11 -0
- data/db/migrate/20170227103408_create_scc_products.rb +16 -0
- data/db/migrate/20170301131641_create_scc_repositories.rb +18 -0
- data/db/migrate/20170301141330_create_scc_products_scc_repositories_join_table.rb +8 -0
- data/db/migrate/20170301163451_add_product_type_to_scc_product.rb +5 -0
- data/db/migrate/20170302082912_remove_repositories_from_scc_products.rb +5 -0
- data/db/migrate/20170302121542_create_scc_extendings.rb +12 -0
- data/db/migrate/20170303085304_add_organization_to_scc_account.rb +22 -0
- data/db/migrate/20170303131704_add_product_id_to_scc_product.rb +6 -0
- data/db/migrate/20170307092057_add_synced_to_scc_account.rb +5 -0
- data/db/migrate/20170418132648_add_name_to_scc_account.rb +5 -0
- data/db/migrate/20170505063726_add_sync_status_to_scc_account.rb +5 -0
- data/lib/foreman_scc_manager.rb +4 -0
- data/lib/foreman_scc_manager/engine.rb +80 -0
- data/lib/foreman_scc_manager/version.rb +3 -0
- data/lib/tasks/foreman_scc_manager_tasks.rake +47 -0
- data/locale/Makefile +60 -0
- data/locale/action_names.rb +61 -0
- data/locale/de/LC_MESSAGES/foreman_scc_manager.mo +0 -0
- data/locale/de/foreman_scc_manager.po +265 -0
- data/locale/en/LC_MESSAGES/foreman_scc_manager.mo +0 -0
- data/locale/en/foreman_scc_manager.po +265 -0
- data/locale/foreman_scc_manager.pot +345 -0
- data/locale/gemspec.rb +2 -0
- data/test/factories/foreman_scc_manager_factories.rb +5 -0
- data/test/test_plugin_helper.rb +6 -0
- data/test/unit/foreman_scc_manager_test.rb +11 -0
- metadata +154 -0
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# ForemanSccManager
|
2
|
+
|
3
|
+
Foreman plugin to sync SUSE Customer Center products and repositories into Katello
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
See [How_to_Install_a_Plugin](http://projects.theforeman.org/projects/foreman/wiki/How_to_Install_a_Plugin)
|
8
|
+
for how to install Foreman plugins
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
*Usage here*
|
13
|
+
|
14
|
+
## TODO
|
15
|
+
|
16
|
+
*Todo list here*
|
17
|
+
|
18
|
+
## Contributing
|
19
|
+
|
20
|
+
Fork and send a Pull Request. Thanks!
|
21
|
+
|
22
|
+
## Copyright
|
23
|
+
|
24
|
+
Copyright (c) 2017 ATIX AG
|
25
|
+
|
26
|
+
This program is free software: you can redistribute it and/or modify
|
27
|
+
it under the terms of the GNU General Public License as published by
|
28
|
+
the Free Software Foundation, either version 3 of the License, or
|
29
|
+
(at your option) any later version.
|
30
|
+
|
31
|
+
This program is distributed in the hope that it will be useful,
|
32
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
33
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
34
|
+
GNU General Public License for more details.
|
35
|
+
|
36
|
+
You should have received a copy of the GNU General Public License
|
37
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
38
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'ForemanSccManager'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
task default: :test
|
37
|
+
|
38
|
+
begin
|
39
|
+
require 'rubocop/rake_task'
|
40
|
+
RuboCop::RakeTask.new
|
41
|
+
rescue => _
|
42
|
+
puts 'Rubocop not loaded.'
|
43
|
+
end
|
44
|
+
|
45
|
+
task :default do
|
46
|
+
Rake::Task['rubocop'].execute
|
47
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
scc_products_after_checked = (target) ->
|
2
|
+
if target.parentNode.dataset.parent
|
3
|
+
parent = $("#" + target.parentNode.dataset.parent + " input")[0]
|
4
|
+
if !parent.checked && !parent.disabled
|
5
|
+
parent.checked = true
|
6
|
+
scc_products_after_checked(parent)
|
7
|
+
|
8
|
+
scc_products_after_unchecked = (target) ->
|
9
|
+
$("span.scc_product_checkbox input", target.parentNode.parentNode).each (index, child) ->
|
10
|
+
if child.checked && !child.disabled
|
11
|
+
child.checked = false
|
12
|
+
scc_products_after_unchecked(child)
|
13
|
+
|
14
|
+
$ ->
|
15
|
+
$("body").on "change", "span.scc_product_checkbox input", (event) ->
|
16
|
+
target = event.target
|
17
|
+
if target.checked
|
18
|
+
scc_products_after_checked target
|
19
|
+
else
|
20
|
+
scc_products_after_unchecked target
|
21
|
+
$("body").on "click", "a.edit_deferrer", (event) ->
|
22
|
+
event.preventDefault()
|
23
|
+
$("a.edit_deferree", $(event.target).closest("tr"))[0].click()
|
24
|
+
$("body").on "click", "#test_scc_connection_btn", (event) ->
|
25
|
+
$('.tab-error').removeClass('tab-error')
|
26
|
+
$('#connection_test_result')[0].innerHTML = ''
|
27
|
+
$('#test_scc_connection_indicator').show()
|
28
|
+
$.ajax event.target.parentNode.dataset['url'],
|
29
|
+
type: 'PUT'
|
30
|
+
dataType: 'JSON'
|
31
|
+
data: $('form').serialize()
|
32
|
+
success: (result) ->
|
33
|
+
$('#test_scc_connection_btn').addClass('btn-success')
|
34
|
+
$('#test_scc_connection_btn').removeClass('btn-default')
|
35
|
+
$('#test_scc_connection_btn').removeClass('btn-danger')
|
36
|
+
error: (result) ->
|
37
|
+
$('#test_scc_connection_btn').addClass('btn-danger')
|
38
|
+
$('#test_scc_connection_btn').removeClass('btn-default')
|
39
|
+
$('#test_scc_connection_btn').removeClass('btn-success')
|
40
|
+
$('#scc_account_login').closest('.form-group').addClass('tab-error')
|
41
|
+
$('#scc_account_password').closest('.form-group').addClass('tab-error')
|
42
|
+
$('#scc_account_base_url').closest('.form-group').addClass('tab-error')
|
43
|
+
$('#connection_test_result')[0].innerHTML = 'Connection test failed!'
|
44
|
+
$('#scc_account_login').focus()
|
45
|
+
complete: (result) ->
|
46
|
+
$('#test_scc_connection_indicator').hide()
|
@@ -0,0 +1,118 @@
|
|
1
|
+
class SccAccountsController < ApplicationController
|
2
|
+
before_filter :find_resource, only: [:show, :edit, :update, :destroy, :sync, :bulk_subscribe]
|
3
|
+
include Api::TaxonomyScope
|
4
|
+
include Foreman::Controller::AutoCompleteSearch
|
5
|
+
|
6
|
+
# GET /scc_accounts
|
7
|
+
def index
|
8
|
+
@scc_accounts = resource_base.search_for(params[:search], order: params[:order])
|
9
|
+
.paginate(page: params[:page])
|
10
|
+
end
|
11
|
+
|
12
|
+
# GET /scc_accounts/new
|
13
|
+
def new
|
14
|
+
@scc_account = SccAccount.new
|
15
|
+
@scc_account.organization = Organization.current
|
16
|
+
end
|
17
|
+
|
18
|
+
# POST /scc_accounts
|
19
|
+
def create
|
20
|
+
@scc_account = SccAccount.new(scc_account_params)
|
21
|
+
if @scc_account.save
|
22
|
+
process_success
|
23
|
+
else
|
24
|
+
process_error
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# GET /scc_accounts/1/edit
|
29
|
+
def edit; end
|
30
|
+
|
31
|
+
# POST /scc_accounts/test_connection
|
32
|
+
def test_connection
|
33
|
+
@scc_account = SccAccount.new(scc_account_params)
|
34
|
+
if params[:scc_account_id].present? && scc_account_params[:password].empty?
|
35
|
+
@scc_account.password = SccAccount.find_by!(id: params[:scc_account_id]).password
|
36
|
+
end
|
37
|
+
respond_to do |format|
|
38
|
+
if @scc_account.test_connection
|
39
|
+
format.json { render json: nil, status: :ok }
|
40
|
+
else
|
41
|
+
format.json { render json: nil, status: 404 }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# PATCH/PUT /scc_accounts/1
|
47
|
+
def update
|
48
|
+
if @scc_account.update(scc_account_params)
|
49
|
+
process_success
|
50
|
+
else
|
51
|
+
process_error
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# DELETE /scc_accounts/1
|
56
|
+
def destroy
|
57
|
+
if @scc_account.destroy
|
58
|
+
process_success
|
59
|
+
else
|
60
|
+
process_error
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# PUT /scc_accounts/1/sync
|
65
|
+
def sync
|
66
|
+
begin
|
67
|
+
sync_task = ForemanTasks.async_task(::Actions::SccManager::Sync, @scc_account)
|
68
|
+
notice _("Sync task started.")
|
69
|
+
rescue ::Foreman::Exception => e
|
70
|
+
error _("Failed to add task to queue: %s") % e.to_s
|
71
|
+
rescue ForemanTasks::Lock::LockConflict => e
|
72
|
+
error _("Lock on SCC account already taken: %s") % e.to_s
|
73
|
+
ensure
|
74
|
+
redirect_to scc_accounts_path
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def bulk_subscribe
|
79
|
+
begin
|
80
|
+
scc_products_to_subscribe =
|
81
|
+
@scc_account.scc_products.where(id: scc_bulk_subscribe_params[:scc_subscribe_product_ids])
|
82
|
+
ForemanTasks.async_task(::Actions::BulkAction,
|
83
|
+
::Actions::SccManager::SubscribeProduct,
|
84
|
+
scc_products_to_subscribe)
|
85
|
+
notice _("Task to subscribe products started.")
|
86
|
+
rescue ::Foreman::Exception => e
|
87
|
+
error _("Failed to add task to queue: %s") % e.to_s
|
88
|
+
rescue ForemanTasks::Lock::LockConflict => e
|
89
|
+
error _("Lock on SCC account already taken: %s") % e.to_s
|
90
|
+
ensure
|
91
|
+
redirect_to scc_accounts_path
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# Use callbacks to share common setup or constraints between actions.
|
98
|
+
# Only allow a trusted parameter "white list" through.
|
99
|
+
def scc_account_params
|
100
|
+
params[:scc_account].delete(:password) if params[:scc_account][:password].blank?
|
101
|
+
params.require(:scc_account).permit(:name, :login, :password, :base_url, :organization_id)
|
102
|
+
end
|
103
|
+
|
104
|
+
def scc_bulk_subscribe_params
|
105
|
+
params.require(:scc_account).permit(:scc_subscribe_product_ids => [])
|
106
|
+
end
|
107
|
+
|
108
|
+
def action_permission
|
109
|
+
case params[:action]
|
110
|
+
when 'sync', 'test_connection'
|
111
|
+
:sync
|
112
|
+
when 'bulk_subscribe'
|
113
|
+
:bulk_subscribe
|
114
|
+
else
|
115
|
+
super
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class SccProductsController < ApplicationController
|
2
|
+
before_filter :find_resource, only: [:show, :subscribe, :unsubscribe]
|
3
|
+
include Api::TaxonomyScope
|
4
|
+
include Foreman::Controller::AutoCompleteSearch
|
5
|
+
|
6
|
+
def index
|
7
|
+
# TODO: Organization...
|
8
|
+
@scc_products = SccProduct.all
|
9
|
+
respond_to do |format|
|
10
|
+
format.json { render json: @scc_products.to_json }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def show
|
15
|
+
respond_to do |format|
|
16
|
+
format.json { render json: @scc_product.to_json }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def subscribe
|
21
|
+
@scc_product.subscribe
|
22
|
+
redirect_to @scc_product.scc_account
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Actions
|
2
|
+
module SccManager
|
3
|
+
class SubscribeProduct < Actions::EntryAction
|
4
|
+
def plan(scc_product)
|
5
|
+
raise _('Product already subscribed!') if scc_product.product
|
6
|
+
::Foreman::Logging.logger('foreman_scc_manager')
|
7
|
+
.info("Initiating subscription for SccProduct '#{scc_product.friendly_name}'.")
|
8
|
+
sequence do
|
9
|
+
product_create_action = plan_action(CreateProduct,
|
10
|
+
product_name: scc_product.uniq_name,
|
11
|
+
product_description: scc_product.description,
|
12
|
+
organization_id: scc_product.organization.id)
|
13
|
+
scc_product.scc_repositories.each do |repo|
|
14
|
+
uniq_name = scc_product.uniq_name + ' ' + repo.description
|
15
|
+
arch = scc_product.arch || 'noarch'
|
16
|
+
plan_action(CreateRepository,
|
17
|
+
:product_id => product_create_action.output[:product_id],
|
18
|
+
:uniq_name => uniq_name,
|
19
|
+
:url => repo.full_url,
|
20
|
+
:arch => arch)
|
21
|
+
end
|
22
|
+
action_subject(scc_product, product_id: product_create_action.output[:product_id])
|
23
|
+
plan_self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def finalize
|
28
|
+
scc_product = SccProduct.find(input[:scc_product][:id])
|
29
|
+
product = ::Katello::Product.find(input[:product_id])
|
30
|
+
scc_product.update!(product: product)
|
31
|
+
end
|
32
|
+
|
33
|
+
def humanized_name
|
34
|
+
_('Subscribe SCC Product')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class CreateProduct < Actions::Base
|
39
|
+
middleware.use ::Actions::Middleware::KeepCurrentUser
|
40
|
+
include ::Dynflow::Action::WithSubPlans
|
41
|
+
|
42
|
+
def create_sub_plans
|
43
|
+
product = ::Katello::Product.new
|
44
|
+
product.name = input[:product_name]
|
45
|
+
product.description = input[:product_description]
|
46
|
+
trigger(::Actions::Katello::Product::Create,
|
47
|
+
product,
|
48
|
+
Organization.find(input[:organization_id])).tap do
|
49
|
+
output[:product_id] = product.id
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class CreateRepository < Actions::Base
|
55
|
+
middleware.use ::Actions::Middleware::KeepCurrentUser
|
56
|
+
include ::Dynflow::Action::WithSubPlans
|
57
|
+
|
58
|
+
def create_sub_plans
|
59
|
+
product = ::Katello::Product.find(input[:product_id])
|
60
|
+
uniq_name = input[:uniq_name]
|
61
|
+
label = ::Katello::Util::Model.labelize(uniq_name)
|
62
|
+
unprotected = true
|
63
|
+
gpg_key = product.gpg_key
|
64
|
+
repository = product.add_repo(label, uniq_name, input[:url], 'yum', unprotected, gpg_key)
|
65
|
+
repository.arch = input[:arch]
|
66
|
+
repository.mirror_on_sync = true
|
67
|
+
repository.verify_ssl_on_sync = true
|
68
|
+
trigger(::Actions::Katello::Repository::Create, repository, false, false)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Actions
|
2
|
+
module SccManager
|
3
|
+
class Sync < Actions::EntryAction
|
4
|
+
def plan(scc_account)
|
5
|
+
::Foreman::Logging.logger('foreman_scc_manager')
|
6
|
+
.info("Initiating 'sync' for SccAccount '#{scc_account.name}'.")
|
7
|
+
action_subject(scc_account)
|
8
|
+
sequence do
|
9
|
+
sync_repo_action = plan_action(::Actions::SccManager::SyncRepositories, scc_account)
|
10
|
+
sync_prod_action = plan_action(::Actions::SccManager::SyncProducts, scc_account)
|
11
|
+
plan_self(repo_status: sync_repo_action.output[:status], prod_status: sync_prod_action.output[:status])
|
12
|
+
end
|
13
|
+
scc_account.update! sync_status: 'running'
|
14
|
+
end
|
15
|
+
|
16
|
+
def finalize
|
17
|
+
scc_account = SccAccount.find(input[:scc_account][:id])
|
18
|
+
if input[:repo_status] == 'SUCCESS' and input[:prod_status] == 'SUCCESS'
|
19
|
+
scc_account.sync_status = 'successful'
|
20
|
+
scc_account.synced = DateTime.current
|
21
|
+
else
|
22
|
+
scc_account.sync_status = 'failed'
|
23
|
+
end
|
24
|
+
scc_account.save!
|
25
|
+
end
|
26
|
+
|
27
|
+
def rescue_strategy
|
28
|
+
Dynflow::Action::Rescue::Fail
|
29
|
+
end
|
30
|
+
|
31
|
+
def humanized_name
|
32
|
+
_('Sync SUSE subscriptions')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Actions
|
2
|
+
module SccManager
|
3
|
+
class SyncProducts < Actions::EntryAction
|
4
|
+
def plan(scc_account)
|
5
|
+
action_subject(scc_account)
|
6
|
+
plan_self(id: scc_account.id,
|
7
|
+
base_url: scc_account.base_url,
|
8
|
+
login: scc_account.login,
|
9
|
+
password: scc_account.password)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
output[:status] = 'SUCCESS'
|
14
|
+
begin
|
15
|
+
output[:data] = ::SccManager.get_scc_data(input.fetch(:base_url),
|
16
|
+
'/connect/organizations/products',
|
17
|
+
input.fetch(:login),
|
18
|
+
input.fetch(:password))
|
19
|
+
rescue
|
20
|
+
output[:status] = 'FAILURE'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def finalize
|
25
|
+
SccAccount.find(input.fetch(:id)).update_scc_products(output.fetch(:data)) if output[:status] == 'SUCCESS'
|
26
|
+
end
|
27
|
+
|
28
|
+
def rescue_strategy
|
29
|
+
Dynflow::Action::Rescue::Fail
|
30
|
+
end
|
31
|
+
|
32
|
+
def humanized_name
|
33
|
+
_('Sync SUSE subscriptions (Products)')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Actions
|
2
|
+
module SccManager
|
3
|
+
class SyncRepositories < Actions::EntryAction
|
4
|
+
def plan(scc_account)
|
5
|
+
action_subject(scc_account)
|
6
|
+
plan_self(base_url: scc_account.base_url,
|
7
|
+
login: scc_account.login,
|
8
|
+
password: scc_account.password)
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
output[:status] = 'SUCCESS'
|
13
|
+
begin
|
14
|
+
output[:data] = ::SccManager.get_scc_data(input[:base_url],
|
15
|
+
'/connect/organizations/repositories',
|
16
|
+
input[:login],
|
17
|
+
input[:password])
|
18
|
+
rescue
|
19
|
+
output[:status] = 'FAILURE'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def finalize
|
24
|
+
SccAccount.find(input[:scc_account][:id]).update_scc_repositories(output[:data]) if output[:status] == 'SUCCESS'
|
25
|
+
end
|
26
|
+
|
27
|
+
def rescue_strategy
|
28
|
+
Dynflow::Action::Rescue::Fail
|
29
|
+
end
|
30
|
+
|
31
|
+
def humanized_name
|
32
|
+
_('Sync SUSE subscriptions (Repositories)')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|