foreman_scc_manager 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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