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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +619 -0
  3. data/README.md +38 -0
  4. data/Rakefile +47 -0
  5. data/app/assets/javascripts/foreman_scc_manager/scc_accounts.js.coffee +46 -0
  6. data/app/controllers/scc_accounts_controller.rb +118 -0
  7. data/app/controllers/scc_products_controller.rb +24 -0
  8. data/app/helpers/scc_accounts_helper.rb +2 -0
  9. data/app/helpers/scc_product_helper.rb +2 -0
  10. data/app/lib/actions/scc_manager/subscribe_product.rb +72 -0
  11. data/app/lib/actions/scc_manager/sync.rb +36 -0
  12. data/app/lib/actions/scc_manager/sync_products.rb +37 -0
  13. data/app/lib/actions/scc_manager/sync_repositories.rb +36 -0
  14. data/app/lib/scc_manager.rb +37 -0
  15. data/app/models/scc_account.rb +100 -0
  16. data/app/models/scc_extending.rb +4 -0
  17. data/app/models/scc_product.rb +46 -0
  18. data/app/models/scc_repository.rb +25 -0
  19. data/app/views/scc_accounts/_form.html.erb +36 -0
  20. data/app/views/scc_accounts/edit.html.erb +3 -0
  21. data/app/views/scc_accounts/index.html.erb +38 -0
  22. data/app/views/scc_accounts/new.html.erb +3 -0
  23. data/app/views/scc_accounts/show.html.erb +41 -0
  24. data/config/routes.rb +17 -0
  25. data/db/migrate/20170221100619_create_scc_accounts.rb +11 -0
  26. data/db/migrate/20170227103408_create_scc_products.rb +16 -0
  27. data/db/migrate/20170301131641_create_scc_repositories.rb +18 -0
  28. data/db/migrate/20170301141330_create_scc_products_scc_repositories_join_table.rb +8 -0
  29. data/db/migrate/20170301163451_add_product_type_to_scc_product.rb +5 -0
  30. data/db/migrate/20170302082912_remove_repositories_from_scc_products.rb +5 -0
  31. data/db/migrate/20170302121542_create_scc_extendings.rb +12 -0
  32. data/db/migrate/20170303085304_add_organization_to_scc_account.rb +22 -0
  33. data/db/migrate/20170303131704_add_product_id_to_scc_product.rb +6 -0
  34. data/db/migrate/20170307092057_add_synced_to_scc_account.rb +5 -0
  35. data/db/migrate/20170418132648_add_name_to_scc_account.rb +5 -0
  36. data/db/migrate/20170505063726_add_sync_status_to_scc_account.rb +5 -0
  37. data/lib/foreman_scc_manager.rb +4 -0
  38. data/lib/foreman_scc_manager/engine.rb +80 -0
  39. data/lib/foreman_scc_manager/version.rb +3 -0
  40. data/lib/tasks/foreman_scc_manager_tasks.rake +47 -0
  41. data/locale/Makefile +60 -0
  42. data/locale/action_names.rb +61 -0
  43. data/locale/de/LC_MESSAGES/foreman_scc_manager.mo +0 -0
  44. data/locale/de/foreman_scc_manager.po +265 -0
  45. data/locale/en/LC_MESSAGES/foreman_scc_manager.mo +0 -0
  46. data/locale/en/foreman_scc_manager.po +265 -0
  47. data/locale/foreman_scc_manager.pot +345 -0
  48. data/locale/gemspec.rb +2 -0
  49. data/test/factories/foreman_scc_manager_factories.rb +5 -0
  50. data/test/test_plugin_helper.rb +6 -0
  51. data/test/unit/foreman_scc_manager_test.rb +11 -0
  52. metadata +154 -0
@@ -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
+
@@ -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,2 @@
1
+ module SccAccountsHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module SccProductHelper
2
+ 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