foreman_scc_manager 1.8.20 → 2.1.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 (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
+ }