foreman_scc_manager 1.8.20 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +15 -11
  3. data/app/controllers/api/v2/scc_accounts_controller.rb +55 -4
  4. data/app/controllers/api/v2/scc_products_controller.rb +1 -1
  5. data/app/controllers/scc_accounts_controller.rb +49 -0
  6. data/app/lib/actions/scc_manager/subscribe_product.rb +56 -22
  7. data/app/models/scc_account.rb +22 -1
  8. data/app/models/scc_product.rb +2 -5
  9. data/app/views/api/v2/scc_accounts/main.json.rabl +1 -1
  10. data/app/views/scc_accounts/_form.html.erb +8 -4
  11. data/app/views/scc_accounts/show.html.erb +7 -51
  12. data/config/routes.rb +1 -0
  13. data/db/migrate/20220429102717_populate_scc_katello_repositories.rb +5 -0
  14. data/db/migrate/20220531120722_add_product_category_to_scc_products.rb +5 -0
  15. data/db/migrate/20221013214310_add_sync_options_to_scc_account.rb +11 -0
  16. data/lib/foreman_scc_manager/engine.rb +1 -1
  17. data/lib/foreman_scc_manager/version.rb +1 -1
  18. data/lib/tasks/republish_repositories.rake +13 -0
  19. data/package.json +54 -0
  20. data/test/controllers/scc_accounts_controller_test.rb +7 -1
  21. data/test/fixtures/models/katello_root_repositories.yml +0 -12
  22. data/test/test_plugin_helper.rb +0 -6
  23. data/webpack/components/SCCProductPage/EmptySccProducts.js +46 -0
  24. data/webpack/components/SCCProductPage/SCCProductPage.js +96 -0
  25. data/webpack/components/SCCProductPage/SCCProductPageActions.js +27 -0
  26. data/webpack/components/SCCProductPage/SCCProductPageConstants.js +5 -0
  27. data/webpack/components/SCCProductPage/SCCProductPageReducer.js +34 -0
  28. data/webpack/components/SCCProductPage/SCCProductPageSelectors.js +7 -0
  29. data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCGenericPicker/index.js +80 -0
  30. data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/components/SCCRepoPicker/index.js +174 -0
  31. data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/components/SCCRepoPicker/styles.scss +3 -0
  32. data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/index.js +303 -0
  33. data/webpack/components/SCCProductPage/components/SCCProductPicker/index.js +235 -0
  34. data/webpack/components/SCCProductPage/components/SCCProductPicker/styles.scss +10 -0
  35. data/webpack/components/SCCProductPage/components/SCCProductPickerModal/index.js +81 -0
  36. data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/index.js +113 -0
  37. data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/styles.scss +14 -0
  38. data/webpack/components/SCCProductPage/components/SCCProductView/index.js +236 -0
  39. data/webpack/components/SCCProductPage/components/common/SCCGenericExpander/index.js +58 -0
  40. data/webpack/components/SCCProductPage/components/common/SCCProductTreeExpander/index.js +21 -0
  41. data/webpack/components/SCCProductPage/components/common/SCCSubscribedProductsExpander/index.js +21 -0
  42. data/webpack/components/SCCProductPage/index.js +18 -0
  43. data/webpack/components/SCCProductPage/sccProductPage.scss +8 -0
  44. data/webpack/index.js +11 -0
  45. data/webpack/reducer.js +7 -0
  46. metadata +43 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39d299a2ed13146bd47fda51bfe3b47cccc78a2fe3984f5070b38acfa1d54bb0
4
- data.tar.gz: eb22cc8040b485c69aa0dffd09b91a5ba926e89c9d124f4d9a32800a8db7546f
3
+ metadata.gz: 6946578ff8b15ec04a5c14a78e12107481d47d9f5093a4e1d2501bc79c4c4f94
4
+ data.tar.gz: f800326b64951b7909427f7fa7d126e6300550f5bee9afacbb394f83d5fe1cf7
5
5
  SHA512:
6
- metadata.gz: bf8c718efe53da5e8f8b417e249bfb3826a080f328331bee932af7108b0fea3da7a0f6b2fc5f581dc0c9f1588e056ae19d1dad83a2e3f45e2ba776763f672a1a
7
- data.tar.gz: 83665d655bb8fa02fa9140115b3d6a604c7e18bde4c1bb4cc5d0bda505c2e1df7cb8c34fc515c62894e0964edc78ca0c773ca5ec34ed1d821ffe87304ecdd0b3
6
+ metadata.gz: d90c05393fe090f811d6cfbb038dd2cb5e45f73ed1359e3bd172c422131a9acb53ac17c0e85c253f9a350462fa5a7954d767af01ffdb9baf3766fcae5acee014
7
+ data.tar.gz: acbbdc19ee139f505415d328fe51f463e2d249a82635b75750b73bfbbdd4fd3a84a32f465cac22c806d36b8044f6d07f14045ecb931830af58a39dac19ce94ee
data/README.md CHANGED
@@ -8,7 +8,13 @@ Foreman plugin to sync SUSE Customer Center products and repositories into Katel
8
8
 
9
9
  ## Installation
10
10
 
11
- This plugin installation is not supported by foreman-installer and has to be installed manually:
11
+ This plugin installation is supported since Foreman 3.4 / Katello 4.6 by the foreman-installer, but only with the scenario Katello:
12
+
13
+ ```sh
14
+ foreman-installer --scenario katello --enable-foreman-plugin-scc-manager
15
+ ```
16
+
17
+ You can also install it manually:
12
18
 
13
19
  ```sh
14
20
  yum install tfm-rubygem-foreman_scc_manager
@@ -20,22 +26,20 @@ foreman-installer
20
26
 
21
27
  | Foreman Version | Katello Version | Plugin Version |
22
28
  | --------------- | --------------- | -------------- |
29
+ | 3.3 | 4.5 | ~> 2.0.0 |
30
+ | 3.1 | 4.3 | ~> 1.8.20\* |
31
+ | 3.0 | 4.2 | ~> 1.8.20 |
32
+ | 2.5 | 4.1 | ~> 1.8.20 |
23
33
  | 2.3 | 3.18 | ~> 1.8.9 |
24
34
  | 2.1 | 3.16 | ~> 1.8.5 |
25
35
  | 2.0 | 3.16 | ~> 1.8.4 |
26
36
  | 1.24 | 3.14 | ~> 1.8.0 |
27
- | 1.22 | 3.12 | ~> 1.7.0 |
28
- | 1.21 | 3.10 | ~> 1.6.0 |
29
- | 1.20 | 3.9 | ~> 1.6.0 |
30
- | 1.19 | 3.8 | ~> 1.5.1 |
31
- | 1.18 | 3.7 | ~> 1.5.0 |
32
- | 1.17 | 3.6 | >= 1.3.1 |
33
- | 1.16 | 3.5 | <= 1.3.0 |
34
- | 1.15 | 3.4 | ~> 1.1.0 |
37
+
38
+ \* If you are using foreman_scc_manager in version 1.8.20 and then upgrade to Katello 4.3, you need to manually run the following rake task on your Foreman instance: `foreman-rake foreman_scc_manager:setup_authentication_tokens`.
35
39
 
36
40
  ## Documentation
37
41
 
38
- [Plugin documentation](https://docs.orcharhino.com/or/docs/sources/usage_guides/managing_sles_systems_guide.html#mssg_installing_the_scc_manager_plugin)
42
+ [Plugin documentation](https://docs.orcharhino.com/or/docs/sources/guides/suse_linux_enterprise_server/managing_content/managing_suse_content.html)
39
43
 
40
44
  ## Hammer CLI Extension
41
45
 
@@ -47,7 +51,7 @@ Fork and send a Pull Request. Thanks!
47
51
 
48
52
  ## Copyright
49
53
 
50
- Copyright (c) 2021 ATIX AG - https://atix.de
54
+ Copyright (c) 2022 ATIX AG - https://atix.de
51
55
 
52
56
  This program is free software: you can redistribute it and/or modify
53
57
  it under the terms of the GNU General Public License as published by
@@ -10,7 +10,7 @@ module Api
10
10
  api_base_url '/api/v2'
11
11
  end
12
12
 
13
- before_action :find_resource, :only => [:show, :update, :destroy, :sync, :bulk_subscribe]
13
+ before_action :find_resource, :only => [:show, :update, :destroy, :sync, :bulk_subscribe, :bulk_subscribe_with_repos]
14
14
 
15
15
  api :GET, '/scc_accounts/', N_('List all scc_accounts')
16
16
  param :organization_id, :identifier, :required => true
@@ -34,6 +34,14 @@ module Api
34
34
  param :password, String, :required => true, :desc => N_('Password of scc_account')
35
35
  param :base_url, String, :required => false, :desc => N_('URL of SUSE for scc_account')
36
36
  param :interval, ['never', 'daily', 'weekly', 'monthly'], :desc => N_('Interval for syncing scc_account')
37
+ param :download_policy,
38
+ ::Katello::RootRepository::DOWNLOAD_POLICIES,
39
+ :required => false,
40
+ :desc => N_('The default download policy for repositories which were created using this SCC Account.')
41
+ param :mirroring_policy,
42
+ SccAccount::SCC_MIRRORING_POLICIES,
43
+ :required => false,
44
+ :desc => N_('The default mirroring policy for repositories which were created using this SCC Account.')
37
45
  param :sync_date, String, :desc => N_('Date and time relative to which the sync interval is run')
38
46
  param :katello_gpg_key_id, :identifier, :required => false, :desc => N_('Associated GPG key of scc_account')
39
47
  end
@@ -105,12 +113,16 @@ module Api
105
113
  param :id, :identifier_dottable, :required => true
106
114
  param :scc_subscribe_product_ids, Array, :required => true
107
115
  def bulk_subscribe
108
- scc_products_to_subscribe = @scc_account.scc_products.where(:id => params[:scc_subscribe_product_ids])
109
116
  respond_to do |format|
110
- if scc_products_to_subscribe.count > 0
117
+ if params[:scc_subscribe_product_ids].count > 0
118
+ # we need to pass two parameters to the product subscribe task,
119
+ # the product itself and an array of repo ids
120
+ # if the id array is empty, all repositories will be subscribed to
121
+ scc_products = @scc_account.scc_products.where(:id => params[:scc_subscribe_product_ids])
111
122
  subscribe_task = ForemanTasks.async_task(::Actions::BulkAction,
112
123
  ::Actions::SccManager::SubscribeProduct,
113
- scc_products_to_subscribe)
124
+ scc_products,
125
+ {})
114
126
  format.json { render json: subscribe_task.to_json, status: :ok }
115
127
  else
116
128
  format.json { render json: { error: 'No Product selected' }, status: :expectation_failed }
@@ -122,6 +134,43 @@ module Api
122
134
  render json: { error: ('Lock on SCC account already taken: %s' % e).to_s }, status: :unprocessable_entity
123
135
  end
124
136
 
137
+ def_param_group :scc_product_data do
138
+ param :scc_product_data, Array, :required => true, :desc => 'Array of Hash elements. One hash element contains an scc_product_id and a repository_list.' do
139
+ param :scc_product_id, Integer, :required => true, :desc => 'Product ID of SCC product'
140
+ param :repository_list, Array, of: Integer, :required => false,
141
+ :desc => 'List of SCC repositories belonging to the SCC product. If the list is empty, all repositories will be subscribed to.'
142
+ end
143
+ end
144
+
145
+ api :PUT, '/scc_accounts/:id/bulk_subscribe_with_repos/', N_('Bulk subscription of scc_products with individual repository selection for scc_account.')
146
+ param :id, :identifier_dottable, :required => true
147
+ param_group :scc_product_data
148
+ def bulk_subscribe_with_repos
149
+ respond_to do |format|
150
+ # if we want to subscribe to specific repos, we need to pass the product and the
151
+ # corresponding repository ids instead of scc products only
152
+ if params[:scc_product_data].count > 0
153
+ scc_products = @scc_account.scc_products.where(:id => params[:scc_product_data].pluck(:scc_product_id))
154
+ if scc_products.empty?
155
+ format.json { render json: { error: _('The selected products cannot be found for this SCC account.') }, status: :unprocessable_entity }
156
+ else
157
+ action_args = params[:scc_product_data].map { |p| { p['scc_product_id'] => p['repository_list'] } }.inject(:merge)
158
+ subscribe_task = ForemanTasks.async_task(::Actions::BulkAction,
159
+ ::Actions::SccManager::SubscribeProduct,
160
+ scc_products,
161
+ action_args)
162
+ format.json { render json: subscribe_task.to_json, status: :ok }
163
+ end
164
+ else
165
+ format.json { render json: { error: 'No Product selected' }, status: :expectation_failed }
166
+ end
167
+ end
168
+ rescue ::Foreman::Exception => e
169
+ render json: { error: ('Failed to add task to queue: %s' % e).to_s }, status: :unprocessable_entity
170
+ rescue ForemanTasks::Lock::LockConflict => e
171
+ render json: { error: ('Lock on SCC account already taken: %s' % e).to_s }, status: :unprocessable_entity
172
+ end
173
+
125
174
  private
126
175
 
127
176
  def scc_account_params
@@ -152,6 +201,8 @@ module Api
152
201
  :sync
153
202
  when 'bulk_subscribe'
154
203
  :bulk_subscribe
204
+ when 'bulk_subscribe_with_repos'
205
+ :bulk_subscribe_with_repos
155
206
  else
156
207
  super
157
208
  end
@@ -41,7 +41,7 @@ module Api
41
41
  param :id, :identifier_dottable, :required => true
42
42
  param :scc_account_id, :identifier_dottable, :required => true
43
43
  def subscribe
44
- subcribe_task = ForemanTasks.async_task(::Actions::SccManager::SubscribeProduct, @scc_product) if @scc_product
44
+ subcribe_task = ForemanTasks.async_task(::Actions::SccManager::SubscribeProduct, @scc_product, {}) if @scc_product
45
45
  respond_to do |format|
46
46
  if subcribe_task
47
47
  format.json { render json: subcribe_task.to_json, status: :ok }
@@ -1,5 +1,6 @@
1
1
  class SccAccountsController < ApplicationController
2
2
  helper_method :scc_filtered_products
3
+ helper_method :create_nested_product_tree
3
4
  before_action :find_organization
4
5
  before_action :find_resource, only: %i[show edit update destroy sync bulk_subscribe]
5
6
  before_action :find_available_gpg_keys, only: %i[new edit update create]
@@ -97,6 +98,52 @@ class SccAccountsController < ApplicationController
97
98
  redirect_to scc_accounts_path
98
99
  end
99
100
 
101
+ def create_nested_product_tree(scc_products, subscribed_only:)
102
+ if subscribed_only
103
+ scc_products_base = scc_products.where(:product_type => 'base').where.not(:product_id => nil).includes([:scc_extensions])
104
+ else
105
+ scc_products_base = scc_products.where(:product_type => 'base').includes([:scc_extensions])
106
+ end
107
+ tree = []
108
+ scc_products_base.each do |p|
109
+ tree.push(get_product_tree_hash(p))
110
+ end
111
+
112
+ tree
113
+ end
114
+
115
+ def scc_product_hash(scc_product)
116
+ scc_product_json = scc_product.as_json(:only => [:scc_id, :id, :arch, :version, :product_id, :subscription_valid],
117
+ include: { :scc_repositories => { :only => [:id, :name, :subscription_valid] } })
118
+ .merge('name' => scc_product.pretty_name, 'product_category' => scc_product.product_category)
119
+ # find if and which Katello root repository is associated with this SCC product
120
+ repo_ids_katello = scc_product.product.blank? || scc_product.product.root_repository_ids.blank? ? nil : scc_product.product.root_repository_ids
121
+ scc_product_json['scc_repositories'].each do |repo|
122
+ # byebug
123
+ if repo_ids_katello.blank?
124
+ repo['katello_root_repository_id'] = nil
125
+ else
126
+ repo_ids_scc = scc_product.scc_repositories.find(repo['id']).katello_root_repository_ids
127
+ repo['katello_root_repository_id'] = repo_ids_scc.blank? ? nil : (repo_ids_scc & repo_ids_katello).first
128
+ end
129
+ end
130
+ scc_product_json
131
+ end
132
+
133
+ def get_product_tree_hash(scc_product_base)
134
+ if scc_product_base.scc_extensions.blank?
135
+ scc_product_hash(scc_product_base)
136
+ else
137
+ children = []
138
+ scc_product_base.scc_extensions.each do |ext|
139
+ children.push(get_product_tree_hash(ext))
140
+ end
141
+ scc_product_base_hash = scc_product_hash(scc_product_base)
142
+ scc_product_base_hash['children'] = children
143
+ scc_product_base_hash
144
+ end
145
+ end
146
+
100
147
  private
101
148
 
102
149
  def find_available_gpg_keys
@@ -123,6 +170,8 @@ class SccAccountsController < ApplicationController
123
170
  :password,
124
171
  :base_url,
125
172
  :interval,
173
+ :download_policy,
174
+ :mirroring_policy,
126
175
  :sync_date,
127
176
  :organization_id,
128
177
  :katello_gpg_key_id
@@ -1,41 +1,79 @@
1
1
  module Actions
2
2
  module SccManager
3
3
  class SubscribeProduct < Actions::EntryAction
4
- def plan(scc_product)
5
- raise _('Product already subscribed!') if scc_product.product
4
+ # scc_product is an ActiveRecord object of Class SccProduct
5
+ # scc_repos_to_subscribe is a hash with the product id as keys and an array of
6
+ # repos to subscribe as values
7
+ # rubocop:disable Metrics/MethodLength
8
+ def plan(scc_product, scc_repos_to_subscribe)
9
+ if scc_product.product
10
+ ::Foreman::Logging.logger('foreman_scc_manager')
11
+ .info("SccProduct '#{scc_product.friendly_name}' is already subscribed to.")
12
+ else
13
+ ::Foreman::Logging.logger('foreman_scc_manager')
14
+ .info("Initiating subscription for SccProduct '#{scc_product.friendly_name}'.")
15
+ end
6
16
 
7
- ::Foreman::Logging.logger('foreman_scc_manager')
8
- .info("Initiating subscription for SccProduct '#{scc_product.friendly_name}'.")
9
17
  sequence do
10
- product_create_action = plan_action(CreateProduct,
11
- :product_name => scc_product.pretty_name,
12
- :product_description => scc_product.pretty_description,
13
- :organization_id => scc_product.organization.id,
14
- :gpg_key => scc_product.scc_account.katello_gpg_key_id)
18
+ if scc_product.product_id.nil?
19
+ product_create_action = plan_action(CreateProduct,
20
+ :product_name => scc_product.pretty_name,
21
+ :product_description => scc_product.pretty_description,
22
+ :organization_id => scc_product.organization.id,
23
+ :gpg_key => scc_product.scc_account.katello_gpg_key_id)
24
+ end
15
25
  katello_repos = {}
16
- scc_product.scc_repositories.each do |repo|
26
+ # we need to set the repositories to subscribe to
27
+ scc_repos = []
28
+ if scc_repos_to_subscribe.empty?
29
+ scc_repos = scc_product.scc_repositories
30
+ else
31
+ # at this point, we need to make sure that the repository list is valid
32
+ # we want to subscribe only to repos that we have not subscribed before
33
+ repo_ids_katello = scc_product.product.blank? || scc_product.product.root_repository_ids.blank? ? nil : scc_product.product.root_repository_ids
34
+ scc_repos = scc_product.scc_repositories.where(id: scc_repos_to_subscribe[scc_product.id])
35
+ unless repo_ids_katello.nil? || scc_repos.empty?
36
+ # remove repo if Katello repo is already associated
37
+ scc_repos.reject { |repo| (repo.katello_root_repositories & repo_ids_katello).present? }
38
+ end
39
+ end
40
+ if scc_repos.empty?
41
+ ::Foreman::Logging.logger('foreman_scc_manager')
42
+ .info('The repositories you have selected are either already subscribed to or invalid.')
43
+ else
44
+ ::Foreman::Logging.logger('foreman_scc_manager')
45
+ .info("Subscribing to SCC repositories '#{scc_repos.pluck(:id)}'.
46
+ If you requested more repositories, please check if those are already subscribed to or invalid.")
47
+ end
48
+ scc_repos.each do |repo|
17
49
  arch = scc_product.arch || 'noarch'
18
50
  repo_create_action = plan_action(CreateRepository,
19
- :product_id => product_create_action.output[:product_id],
51
+ :product_id => scc_product.product_id || product_create_action.output[:product_id],
20
52
  :uniq_name => repo.uniq_name(scc_product),
21
53
  :pretty_repo_name => repo.pretty_name,
22
54
  :url => repo.url,
23
55
  :token => repo.token,
24
- :arch => arch)
56
+ :arch => arch,
57
+ :download_policy => scc_product.scc_account.download_policy,
58
+ :mirroring_policy => scc_product.scc_account.mirroring_policy)
25
59
  katello_repos[repo.id] = repo_create_action.output[:katello_root_repository_id]
26
60
  end
61
+
27
62
  # connect action to resource (=> make parameters accessable in input)
28
- action_subject(scc_product, product_id: product_create_action.output[:product_id])
63
+ action_subject(scc_product, product_id: product_create_action.output[:product_id]) if scc_product.product_id.nil?
29
64
  input.update(katello_repos: katello_repos)
30
65
  plan_self
31
66
  end
32
67
  end
68
+ # rubocop:enable Metrics/MethodLength
33
69
 
34
70
  def finalize
35
71
  # connect Scc products and Katello products
36
- scc_product = SccProduct.find(input[:scc_product][:id])
37
- product = ::Katello::Product.find(input[:product_id])
38
- scc_product.update!(product: product)
72
+ # it may happen that we only append repos to an existing product
73
+ unless input[:scc_product].nil?
74
+ scc_product = SccProduct.find(input[:scc_product][:id])
75
+ scc_product.update!(product_id: input[:product_id])
76
+ end
39
77
  # extract Katello repo ids from input hash and store to database
40
78
  input[:katello_repos].each do |scc_repo_id, katello_root_repository_id|
41
79
  SccKatelloRepository.find_or_create_by(scc_repository_id: scc_repo_id, katello_root_repository_id: katello_root_repository_id)
@@ -83,13 +121,9 @@ module Actions
83
121
  :unprotected => unprotected,
84
122
  :gpg_key => gpg_key,
85
123
  :arch => input[:arch],
86
- :download_policy => Setting[:default_download_policy] }
124
+ :download_policy => input[:download_policy],
125
+ :mirroring_policy => input[:mirroring_policy] }
87
126
  repository = product.add_repo(repo_param)
88
- if repository.has_attribute?('mirror_on_sync')
89
- repository.mirror_on_sync = true
90
- else
91
- repository.mirroring_policy = ::Katello::RootRepository::MIRRORING_POLICY_CONTENT
92
- end
93
127
  if repository.has_attribute?('upstream_authentication_token')
94
128
  repository.url = input[:url]
95
129
  repository.upstream_authentication_token = input[:token]
@@ -13,6 +13,11 @@ class SccAccount < ApplicationRecord
13
13
  MONTHLY = 'monthly'.freeze
14
14
  TYPES = [NEVER, DAILY, WEEKLY, MONTHLY].freeze
15
15
 
16
+ # MIRRORING_POLICY_COMPLETE doesn't work for suse repository because deltarpm metadata is not supported by pulp3
17
+ SCC_MIRRORING_POLICIES = ::Katello::RootRepository::MIRRORING_POLICIES.dup
18
+ SCC_MIRRORING_POLICIES.delete(::Katello::RootRepository::MIRRORING_POLICY_COMPLETE)
19
+ SCC_MIRRORING_POLICIES.freeze
20
+
16
21
  self.include_root_in_json = false
17
22
 
18
23
  belongs_to :organization
@@ -29,6 +34,8 @@ class SccAccount < ApplicationRecord
29
34
  validates :password, presence: true
30
35
  validates :base_url, presence: true
31
36
  validates :interval, :inclusion => { :in => TYPES }, :allow_blank => false
37
+ validates :download_policy, :inclusion => { :in => ::Katello::RootRepository::DOWNLOAD_POLICIES }, :allow_blank => false
38
+ validates :mirroring_policy, :inclusion => { :in => SCC_MIRRORING_POLICIES }, :allow_blank => false
32
39
  validate :sync_date_is_valid_datetime
33
40
 
34
41
  after_initialize :init
@@ -219,8 +226,8 @@ class SccAccount < ApplicationRecord
219
226
  cached_product.product_type = up['product_type']
220
227
  cached_product.scc_repositories =
221
228
  scc_repositories.where(scc_id: up['repositories'].map { |repo| repo['id'] })
222
- # name should be set after friendly_name because it depends on friendly_name
223
229
  cached_product.name = cached_product.pretty_name
230
+ cached_product.product_category = up['name']
224
231
  cached_product.description = cached_product.pretty_description
225
232
  cached_product.subscription_valid = true
226
233
  cached_product.save!
@@ -278,4 +285,18 @@ class SccAccount < ApplicationRecord
278
285
  end
279
286
  items_to_invalidate
280
287
  end
288
+
289
+ def self.download_policy_selection_values
290
+ names = { 'on_demand' => _('On Demand'), 'immediate' => _('Immediate') }
291
+ ::Katello::RootRepository::DOWNLOAD_POLICIES.map do |p|
292
+ names.include?(p) ? [names[p], p] : [p, p]
293
+ end
294
+ end
295
+
296
+ def self.mirroring_policy_selection_values
297
+ names = { 'additive' => _('Additive'), 'mirror_content_only' => _('Content Only') }
298
+ SCC_MIRRORING_POLICIES.map do |p|
299
+ names.include?(p) ? [names[p], p] : [p, p]
300
+ end
301
+ end
281
302
  end
@@ -58,11 +58,8 @@ class SccProduct < ApplicationRecord
58
58
  gpg_key = new_product.gpg_key
59
59
  new_repo = new_product.add_repo(label, uniq_repo_name, repo.url, 'yum', unprotected, gpg_key)
60
60
  new_repo.arch = arch || 'noarch'
61
- if new_repo.has_attribute?('mirror_on_sync')
62
- new_repo.mirror_on_sync = true
63
- else
64
- new_repo.mirroring_policy = ::Katello::RootRepository::MIRRORING_POLICY_CONTENT
65
- end
61
+ new_repo.mirroring_policy = scc_account.mirroring_policy
62
+ new_repo.download_policy = scc_account.download_policy
66
63
  if new_repo.has_attribute?('upstream_authentication_token')
67
64
  new_repo.upstream_authentication_token = repo.token
68
65
  new_repo.url = repo.url
@@ -2,4 +2,4 @@
2
2
 
3
3
  object @scc_account
4
4
  extends 'api/v2/scc_accounts/base'
5
- attributes :organization_id, :organization_name, :login, :base_url, :interval, :sync_date
5
+ attributes :organization_id, :organization_name, :login, :base_url, :interval, :download_policy, :mirroring_policy, :sync_date
@@ -19,11 +19,15 @@
19
19
  <%= field f, :sync_date, label: _('Sync Date') do
20
20
  f.datetime_field :sync_date, placeholder: Time.now
21
21
  end %>
22
- <%= selectable_f f, :katello_gpg_key_id, @selectable_gpg_keys, {},
23
- { :include_blank => _("None"),
24
- :label => _('Use GPG key for SUSE products'),
25
- :selected => @scc_account.katello_gpg_key_id,
22
+ <%= selectable_f f, :katello_gpg_key_id, @selectable_gpg_keys, {},
23
+ { :include_blank => _("None"),
24
+ :label => _('Use GPG key for SUSE products'),
25
+ :selected => @scc_account.katello_gpg_key_id,
26
26
  :help_block => _("Use this setting if you want to automatically add a GPG key to your SUSE products upon subscription. You can change this setting in the 'Content' > 'Products' menu, later.") } %>
27
+ <%= selectable_f f, :download_policy, SccAccount::download_policy_selection_values,
28
+ { :label => _('Download Policy'), :help_block => _("The default download policy for repositories which were created using this SCC Account.") } %>
29
+ <%= selectable_f f, :mirroring_policy, SccAccount::mirroring_policy_selection_values,
30
+ { :label => _('Mirroring Policy'), :help_block => _("The default mirroring policy for repositories which were created using this SCC Account.") } %>
27
31
  <div class='clearfix'>
28
32
  <div class='form-group'>
29
33
  <div class='col-md-2'></div>
@@ -1,52 +1,8 @@
1
1
  <% title (_("Product Selection for Account %s") % @scc_account) %>
2
-
3
- <% javascript 'foreman_scc_manager/scc_accounts' %>
4
- <%= form_for([:bulk_subscribe, @scc_account], method: :put) do |f| %>
5
- <% def render_list_node(f, scc_product, parent_id = "") %>
6
- <li>
7
- <span class="scc_product_checkbox" id="<%= "scc_product_span_#{parent_id + "_" + scc_product.id.to_s}" %>" <%= "data-parent=scc_product_span_#{parent_id}" if parent_id != "" %>>
8
- <% if scc_product.product %>
9
- <%= check_box_tag("scc_account[scc_unsubscribe_product_ids][]", scc_product.id, true, disabled: true) %>
10
- <%= link_to(scc_product.pretty_name, "/products/#{scc_product.product_id}") %>
11
- <% else %>
12
- <%= check_box_tag("scc_account[scc_subscribe_product_ids][]", scc_product.id, false) %>
13
- <%= scc_product.pretty_name %>
14
- <% end %>
15
- <% unless scc_product.subscription_valid? %>
16
- <span style="color:red">
17
- <%= _('(WARNING: Please check your SUSE subscription)') %>
18
- </span>
19
- <% end %>
20
- </span>
21
- <% if scc_product.scc_extensions.any? %>
22
- <ul style='padding-left: 20px;'>
23
- <% scc_filtered_products(scc_product.scc_extensions, 'extension').each do |scc_extension| %>
24
- <% render_list_node(f, scc_extension, parent_id + "_" + scc_product.id.to_s) %>
25
- <% end %>
26
- </ul>
27
- <% end %>
28
- </li>
29
- <% end %>
30
-
31
- <%= f.hidden_field :prevent_missing, value: 1 %>
32
- <ul class="nav nav-tabs" data-tabs="tabs">
33
- <li class="active"><a href="#primary" data-toggle="tab"><%= _("SUSE Customer Center") %></a></li>
34
- </ul>
35
-
36
- <div class="tab-content">
37
- <div class="tab-pane active" id="primary">
38
- <ul>
39
- <% if @scc_account.synced %>
40
- <% scc_filtered_products(@scc_account.scc_products).each do |scc_product| %>
41
- <% render_list_node(f, scc_product) %>
42
- <% end %>
43
- <% else %>
44
- <%= _('Please sync your SUSE subscriptions first.') %>
45
- <% submit_disabled = true %>
46
- <% end %>
47
- </ul>
48
- </div>
49
- <%= submit_or_cancel f, false, {disabled: submit_disabled || false} %>
50
- </div>
51
- <% end %>
52
-
2
+ <%= webpacked_plugins_js_for :foreman_scc_manager %>
3
+ <%= webpacked_plugins_css_for :foreman_scc_manager %>
4
+ <%= react_component('SCCProductPage', {
5
+ :canCreate => authorized_for(action: :sync),
6
+ :sccAccountId => @scc_account.id,
7
+ :sccProductsInit => create_nested_product_tree(@scc_account.scc_products, subscribed_only: false)
8
+ }) %>
data/config/routes.rb CHANGED
@@ -32,6 +32,7 @@ Rails.application.routes.draw do
32
32
  put 'test_connection'
33
33
  put 'sync'
34
34
  put 'bulk_subscribe'
35
+ put 'bulk_subscribe_with_repos'
35
36
  end
36
37
  end
37
38
  constraints(:scc_account_id => /[^\/]+/) do
@@ -3,6 +3,11 @@ class PopulateSccKatelloRepositories < ActiveRecord::Migration[6.0]
3
3
  belongs_to :product, class_name: 'Katello::Product'
4
4
  has_and_belongs_to_many :scc_repositories
5
5
  end
6
+ class SccRepository < ApplicationRecord
7
+ has_many :scc_katello_repositories
8
+ has_many :katello_root_repositories, through: :scc_katello_repositories
9
+ has_and_belongs_to_many :scc_products
10
+ end
6
11
 
7
12
  def up
8
13
  SccProduct.where.not(product_id: nil).each do |scc_p|
@@ -0,0 +1,5 @@
1
+ class AddProductCategoryToSccProducts < ActiveRecord::Migration[6.0]
2
+ def change
3
+ add_column :scc_products, :product_category, :string, null: true
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ class AddSyncOptionsToSccAccount < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :scc_accounts, :download_policy, :string, default: ::Katello::RootRepository::DOWNLOAD_IMMEDIATE
4
+ add_column :scc_accounts, :mirroring_policy, :string, default: ::Katello::RootRepository::MIRRORING_POLICY_CONTENT
5
+ SccAccount.all.each do |a|
6
+ a.download_policy = ::Katello::RootRepository::DOWNLOAD_IMMEDIATE
7
+ a.mirroring_policy = ::Katello::RootRepository::MIRRORING_POLICY_CONTENT
8
+ a.save!
9
+ end
10
+ end
11
+ end
@@ -38,7 +38,7 @@ module ForemanSccManager
38
38
 
39
39
  permission :use_scc_accounts,
40
40
  { :scc_accounts => [:bulk_subscribe],
41
- :'api/v2/scc_accounts' => [:bulk_subscribe] },
41
+ :'api/v2/scc_accounts' => [:bulk_subscribe, :bulk_subscribe_with_repos] },
42
42
  :resource_type => 'SccAccount'
43
43
 
44
44
  permission :new_scc_accounts,
@@ -1,3 +1,3 @@
1
1
  module ForemanSccManager
2
- VERSION = '1.8.20'.freeze
2
+ VERSION = '2.1.0'.freeze
3
3
  end
@@ -0,0 +1,13 @@
1
+ namespace :foreman_scc_manager do
2
+ desc 'Republish all SCC-repositories.'
3
+ task :republish_scc_repositories => ['dynflow:client', 'katello:check_ping'] do
4
+ needing_publish = SccKatelloRepository.joins(:katello_root_repository)
5
+ .joins(:katello_root_repository => :repositories)
6
+ .pluck("#{Katello::Repository.table_name}.id")
7
+ if needing_publish.any?
8
+ ForemanTasks.async_task(::Actions::Katello::Repository::BulkMetadataGenerate, Katello::Repository.where(:id => needing_publish))
9
+ else
10
+ puts 'Skipped. No repository found which was created by the SCC plugin.'
11
+ end
12
+ end
13
+ end
data/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "foreman_scc_manager",
3
+ "version": "1.8.16",
4
+ "description": "Foreman plugin to sync SUSE Customer Center products and repositories into Katello ",
5
+ "main": "index.js",
6
+ "directories": {
7
+ "lib": "lib",
8
+ "test": "test"
9
+ },
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1",
12
+ "create-react-component": "yo react-domain"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+ssh://git@github.com/ATIX-AG/foreman_scc_manager.git"
17
+ },
18
+ "peerDependencies": {
19
+ "@theforeman/vendor": "^4.14.0"
20
+ },
21
+ "devDependencies": {
22
+ "@babel/core": "^7.7.0",
23
+ "babel-eslint": "^10.0.0",
24
+ "babel-loader": "^8.0.0",
25
+ "@theforeman/builder": "^4.14.0",
26
+ "@theforeman/eslint-plugin-foreman": "^8.16.0",
27
+ "@theforeman/find-foreman": "^4.14.0",
28
+ "@theforeman/stories": "^4.14.0",
29
+ "@theforeman/test": "^4.14.0",
30
+ "@theforeman/vendor-dev": "^4.14.0",
31
+ "eslint": "^6.7.2",
32
+ "eslint-plugin-spellcheck": "0.0.17",
33
+ "eslint-plugin-react": "^7.27.1",
34
+ "eslint-plugin-react-hooks": "^4.3.0",
35
+ "prettier": "^2.5.1",
36
+ "react-redux-test-utils": "^0.2.0"
37
+ },
38
+ "keywords": [
39
+ "SUSE",
40
+ "Katello",
41
+ "products",
42
+ "repositories"
43
+ ],
44
+ "author": "ATIX AG",
45
+ "license": "GPL-3.0",
46
+ "bugs": {
47
+ "url": "https://github.com/ATIX-AG/foreman_scc_manager/issues"
48
+ },
49
+ "homepage": "https://github.com/ATIX-AG/foreman_scc_manager#readme",
50
+ "dependencies": {
51
+ "react-native-elements": "^3.4.2",
52
+ "react-native-vector-icons": "^9.0.0"
53
+ }
54
+ }