foreman_scc_manager 1.8.19 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +14 -10
- data/app/controllers/api/v2/scc_accounts_controller.rb +48 -5
- data/app/controllers/api/v2/scc_products_controller.rb +1 -1
- data/app/controllers/scc_accounts_controller.rb +47 -0
- data/app/lib/actions/scc_manager/subscribe_product.rb +61 -19
- data/app/models/scc_account.rb +4 -3
- data/app/models/scc_katello_repository.rb +4 -0
- data/app/models/scc_product.rb +7 -1
- data/app/models/scc_repository.rb +12 -4
- data/app/views/scc_accounts/show.html.erb +7 -51
- data/config/routes.rb +1 -0
- data/db/migrate/20220425132605_add_scc_katello_repository_relation.rb +10 -0
- data/db/migrate/20220429100843_remove_root_repository_id_from_scc_repository.rb +6 -0
- data/db/migrate/20220429102717_populate_scc_katello_repositories.rb +21 -0
- data/db/migrate/20220513132652_populate_upstream_authentication_token.rb +23 -0
- data/db/migrate/20220531120722_add_product_category_to_scc_products.rb +5 -0
- data/lib/foreman_scc_manager/engine.rb +1 -1
- data/lib/foreman_scc_manager/version.rb +1 -1
- data/lib/tasks/republish_repositories.rake +13 -0
- data/lib/tasks/setup_authentication_token.rake +27 -0
- data/package.json +54 -0
- data/test/controllers/scc_accounts_controller_test.rb +6 -0
- data/test/fixtures/models/katello_root_repositories.yml +44 -0
- data/test/fixtures/models/scc_repositories.yml +34 -0
- data/test/support/fixtures_support.rb +3 -1
- data/webpack/components/SCCProductPage/EmptySccProducts.js +46 -0
- data/webpack/components/SCCProductPage/SCCProductPage.js +96 -0
- data/webpack/components/SCCProductPage/SCCProductPageActions.js +27 -0
- data/webpack/components/SCCProductPage/SCCProductPageConstants.js +5 -0
- data/webpack/components/SCCProductPage/SCCProductPageReducer.js +34 -0
- data/webpack/components/SCCProductPage/SCCProductPageSelectors.js +7 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCGenericPicker/index.js +80 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/components/SCCRepoPicker/index.js +174 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/components/SCCRepoPicker/styles.scss +3 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/components/SCCTreePicker/index.js +303 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/index.js +235 -0
- data/webpack/components/SCCProductPage/components/SCCProductPicker/styles.scss +10 -0
- data/webpack/components/SCCProductPage/components/SCCProductPickerModal/index.js +81 -0
- data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/index.js +113 -0
- data/webpack/components/SCCProductPage/components/SCCProductView/components/SCCRepoView/styles.scss +14 -0
- data/webpack/components/SCCProductPage/components/SCCProductView/index.js +236 -0
- data/webpack/components/SCCProductPage/components/common/SCCGenericExpander/index.js +58 -0
- data/webpack/components/SCCProductPage/components/common/SCCProductTreeExpander/index.js +21 -0
- data/webpack/components/SCCProductPage/components/common/SCCSubscribedProductsExpander/index.js +21 -0
- data/webpack/components/SCCProductPage/index.js +18 -0
- data/webpack/components/SCCProductPage/sccProductPage.scss +8 -0
- data/webpack/index.js +11 -0
- data/webpack/reducer.js +7 -0
- metadata +48 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73d2510abbdbe51fef59bba613502fb02ef1fe14eeb441f0bee716b17e2eba8d
|
4
|
+
data.tar.gz: c61b9f852d58033c290204508d0d4653e5379c6c8b73e6d5b58d026ea485b0f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3ce92fbe191d0aaa6f10d0015ed4a3e3320892d1f45a519a965cdbd63a93e49a0fe6918fcc1b7cfb4618b8a8fc016349bfbceba5825a93ca5400dce5dd18e03
|
7
|
+
data.tar.gz: a48593aa198df8fbc5b4c88a2654facb7dc1f77f80373d3cf7a03fa46e84bd5f02af338af0a0e1dd2968da7e7afa6e44548f992e51d1ece7a0a82fa05922f0d9
|
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
|
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-install --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,18 +26,16 @@ foreman-installer
|
|
20
26
|
|
21
27
|
| Foreman Version | Katello Version | Plugin Version |
|
22
28
|
| --------------- | --------------- | -------------- |
|
29
|
+
| 3.5 | 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
|
-
|
28
|
-
|
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
|
|
@@ -47,7 +51,7 @@ Fork and send a Pull Request. Thanks!
|
|
47
51
|
|
48
52
|
## Copyright
|
49
53
|
|
50
|
-
Copyright (c)
|
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
|
@@ -33,7 +33,7 @@ module Api
|
|
33
33
|
param :login, String, :required => true, :desc => N_('Login id of scc_account')
|
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
|
-
param :interval, ['never', 'daily', 'weekly', '
|
36
|
+
param :interval, ['never', 'daily', 'weekly', 'monthly'], :desc => N_('Interval for syncing scc_account')
|
37
37
|
param :sync_date, String, :desc => N_('Date and time relative to which the sync interval is run')
|
38
38
|
param :katello_gpg_key_id, :identifier, :required => false, :desc => N_('Associated GPG key of scc_account')
|
39
39
|
end
|
@@ -105,12 +105,16 @@ module Api
|
|
105
105
|
param :id, :identifier_dottable, :required => true
|
106
106
|
param :scc_subscribe_product_ids, Array, :required => true
|
107
107
|
def bulk_subscribe
|
108
|
-
scc_products_to_subscribe = @scc_account.scc_products.where(:id => params[:scc_subscribe_product_ids])
|
109
108
|
respond_to do |format|
|
110
|
-
if
|
109
|
+
if params[:scc_subscribe_product_ids].count > 0
|
110
|
+
# we need to pass two parameters to the product subscribe task,
|
111
|
+
# the product itself and an array of repo ids
|
112
|
+
# if the id array is empty, all repositories will be subscribed to
|
113
|
+
scc_products = @scc_account.scc_products.where(:id => params[:scc_subscribe_product_ids])
|
111
114
|
subscribe_task = ForemanTasks.async_task(::Actions::BulkAction,
|
112
115
|
::Actions::SccManager::SubscribeProduct,
|
113
|
-
|
116
|
+
scc_products,
|
117
|
+
{})
|
114
118
|
format.json { render json: subscribe_task.to_json, status: :ok }
|
115
119
|
else
|
116
120
|
format.json { render json: { error: 'No Product selected' }, status: :expectation_failed }
|
@@ -122,6 +126,43 @@ module Api
|
|
122
126
|
render json: { error: ('Lock on SCC account already taken: %s' % e).to_s }, status: :unprocessable_entity
|
123
127
|
end
|
124
128
|
|
129
|
+
def_param_group :scc_product_data do
|
130
|
+
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
|
131
|
+
param :scc_product_id, Integer, :required => true, :desc => 'Product ID of SCC product'
|
132
|
+
param :repository_list, Array, of: Integer, :required => false,
|
133
|
+
:desc => 'List of SCC repositories belonging to the SCC product. If the list is empty, all repositories will be subscribed to.'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
api :PUT, '/scc_accounts/:id/bulk_subscribe_with_repos/', N_('Bulk subscription of scc_products with individual repository selection for scc_account.')
|
138
|
+
param :id, :identifier_dottable, :required => true
|
139
|
+
param_group :scc_product_data
|
140
|
+
def bulk_subscribe_with_repos
|
141
|
+
respond_to do |format|
|
142
|
+
# if we want to subscribe to specific repos, we need to pass the product and the
|
143
|
+
# corresponding repository ids instead of scc products only
|
144
|
+
if params[:scc_product_data].count > 0
|
145
|
+
scc_products = @scc_account.scc_products.where(:id => params[:scc_product_data].pluck(:scc_product_id))
|
146
|
+
if scc_products.empty?
|
147
|
+
format.json { render json: { error: _('The selected products cannot be found for this SCC account.') }, status: :unprocessable_entity }
|
148
|
+
else
|
149
|
+
action_args = params[:scc_product_data].map { |p| { p['scc_product_id'] => p['repository_list'] } }.inject(:merge)
|
150
|
+
subscribe_task = ForemanTasks.async_task(::Actions::BulkAction,
|
151
|
+
::Actions::SccManager::SubscribeProduct,
|
152
|
+
scc_products,
|
153
|
+
action_args)
|
154
|
+
format.json { render json: subscribe_task.to_json, status: :ok }
|
155
|
+
end
|
156
|
+
else
|
157
|
+
format.json { render json: { error: 'No Product selected' }, status: :expectation_failed }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
rescue ::Foreman::Exception => e
|
161
|
+
render json: { error: ('Failed to add task to queue: %s' % e).to_s }, status: :unprocessable_entity
|
162
|
+
rescue ForemanTasks::Lock::LockConflict => e
|
163
|
+
render json: { error: ('Lock on SCC account already taken: %s' % e).to_s }, status: :unprocessable_entity
|
164
|
+
end
|
165
|
+
|
125
166
|
private
|
126
167
|
|
127
168
|
def scc_account_params
|
@@ -152,6 +193,8 @@ module Api
|
|
152
193
|
:sync
|
153
194
|
when 'bulk_subscribe'
|
154
195
|
:bulk_subscribe
|
196
|
+
when 'bulk_subscribe_with_repos'
|
197
|
+
:bulk_subscribe_with_repos
|
155
198
|
else
|
156
199
|
super
|
157
200
|
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
|
@@ -1,44 +1,80 @@
|
|
1
1
|
module Actions
|
2
2
|
module SccManager
|
3
3
|
class SubscribeProduct < Actions::EntryAction
|
4
|
-
|
5
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
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
|
-
:url => repo.
|
54
|
+
:url => repo.url,
|
55
|
+
:token => repo.token,
|
23
56
|
:arch => arch)
|
24
57
|
katello_repos[repo.id] = repo_create_action.output[:katello_root_repository_id]
|
25
58
|
end
|
59
|
+
|
26
60
|
# connect action to resource (=> make parameters accessable in input)
|
27
|
-
action_subject(scc_product, product_id: product_create_action.output[:product_id])
|
61
|
+
action_subject(scc_product, product_id: product_create_action.output[:product_id]) if scc_product.product_id.nil?
|
28
62
|
input.update(katello_repos: katello_repos)
|
29
63
|
plan_self
|
30
64
|
end
|
31
65
|
end
|
66
|
+
# rubocop:enable Metrics/MethodLength
|
32
67
|
|
33
68
|
def finalize
|
34
69
|
# connect Scc products and Katello products
|
35
|
-
|
36
|
-
|
37
|
-
|
70
|
+
# it may happen that we only append repos to an existing product
|
71
|
+
unless input[:scc_product].nil?
|
72
|
+
scc_product = SccProduct.find(input[:scc_product][:id])
|
73
|
+
scc_product.update!(product_id: input[:product_id])
|
74
|
+
end
|
38
75
|
# extract Katello repo ids from input hash and store to database
|
39
76
|
input[:katello_repos].each do |scc_repo_id, katello_root_repository_id|
|
40
|
-
|
41
|
-
scc_repo.update!(katello_root_repository_id: katello_root_repository_id)
|
77
|
+
SccKatelloRepository.find_or_create_by(scc_repository_id: scc_repo_id, katello_root_repository_id: katello_root_repository_id)
|
42
78
|
end
|
43
79
|
end
|
44
80
|
|
@@ -79,7 +115,6 @@ module Actions
|
|
79
115
|
gpg_key = product.gpg_key
|
80
116
|
repo_param = { :label => label,
|
81
117
|
:name => input[:pretty_repo_name],
|
82
|
-
:url => input[:url],
|
83
118
|
:content_type => 'yum',
|
84
119
|
:unprotected => unprotected,
|
85
120
|
:gpg_key => gpg_key,
|
@@ -91,6 +126,13 @@ module Actions
|
|
91
126
|
else
|
92
127
|
repository.mirroring_policy = ::Katello::RootRepository::MIRRORING_POLICY_CONTENT
|
93
128
|
end
|
129
|
+
if repository.has_attribute?('upstream_authentication_token')
|
130
|
+
repository.url = input[:url]
|
131
|
+
repository.upstream_authentication_token = input[:token]
|
132
|
+
else
|
133
|
+
repository.url = input[:token].blank? ? input[:url] : "#{input[:url]}?#{input[:token]}"
|
134
|
+
end
|
135
|
+
|
94
136
|
repository.verify_ssl_on_sync = true
|
95
137
|
trigger(::Actions::Katello::Repository::CreateRoot, repository).tap do
|
96
138
|
output[:katello_root_repository_id] = repository.id
|
data/app/models/scc_account.rb
CHANGED
@@ -194,12 +194,13 @@ class SccAccount < ApplicationRecord
|
|
194
194
|
|
195
195
|
# all scc repos that are kept but not available upstream need to be marked invalid
|
196
196
|
# subscription_valid can be set to nil
|
197
|
-
to_invalidate = invalidated_repos.select { |ir| ir.
|
197
|
+
to_invalidate = invalidated_repos.select { |ir| ir.katello_root_repositories.count > 0 && !ir.subscription_valid }
|
198
198
|
::Foreman::Logging.logger('foreman_scc_manager').debug "Invalidating #{to_invalidate.count} expired repositories"
|
199
199
|
invalidate_subscription_status(to_invalidate, save_record: true)
|
200
200
|
|
201
201
|
# delete repositories being removed upstream and that are not subscribed to
|
202
|
-
to_delete = scc_repositories.where.not(scc_id: upstream_repo_ids)
|
202
|
+
to_delete = scc_repositories.where.not(scc_id: upstream_repo_ids).includes(:scc_katello_repositories).where(scc_katello_repositories: { id: nil })
|
203
|
+
|
203
204
|
::Foreman::Logging.logger('foreman_scc_manager').debug "Deleting #{to_delete.count} old repositories"
|
204
205
|
to_delete.destroy_all
|
205
206
|
end
|
@@ -218,8 +219,8 @@ class SccAccount < ApplicationRecord
|
|
218
219
|
cached_product.product_type = up['product_type']
|
219
220
|
cached_product.scc_repositories =
|
220
221
|
scc_repositories.where(scc_id: up['repositories'].map { |repo| repo['id'] })
|
221
|
-
# name should be set after friendly_name because it depends on friendly_name
|
222
222
|
cached_product.name = cached_product.pretty_name
|
223
|
+
cached_product.product_category = up['name']
|
223
224
|
cached_product.description = cached_product.pretty_description
|
224
225
|
cached_product.subscription_valid = true
|
225
226
|
cached_product.save!
|
data/app/models/scc_product.rb
CHANGED
@@ -56,13 +56,19 @@ class SccProduct < ApplicationRecord
|
|
56
56
|
label = Katello::Util::Model.labelize(uniq_repo_name)
|
57
57
|
unprotected = true
|
58
58
|
gpg_key = new_product.gpg_key
|
59
|
-
new_repo = new_product.add_repo(label, uniq_repo_name, repo.
|
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
61
|
if new_repo.has_attribute?('mirror_on_sync')
|
62
62
|
new_repo.mirror_on_sync = true
|
63
63
|
else
|
64
64
|
new_repo.mirroring_policy = ::Katello::RootRepository::MIRRORING_POLICY_CONTENT
|
65
65
|
end
|
66
|
+
if new_repo.has_attribute?('upstream_authentication_token')
|
67
|
+
new_repo.upstream_authentication_token = repo.token
|
68
|
+
new_repo.url = repo.url
|
69
|
+
else
|
70
|
+
new_repo.url = repo.full_url
|
71
|
+
end
|
66
72
|
new_repo.verify_ssl_on_sync = true
|
67
73
|
ForemanTasks.sync_task(::Actions::Katello::Repository::Create, new_repo, false, false)
|
68
74
|
end
|
@@ -4,7 +4,8 @@ class SccRepository < ApplicationRecord
|
|
4
4
|
self.include_root_in_json = false
|
5
5
|
|
6
6
|
belongs_to :scc_account
|
7
|
-
|
7
|
+
has_many :scc_katello_repositories
|
8
|
+
has_many :katello_root_repositories, through: :scc_katello_repositories
|
8
9
|
has_one :organization, through: :scc_account
|
9
10
|
has_and_belongs_to_many :scc_products
|
10
11
|
|
@@ -27,9 +28,16 @@ class SccRepository < ApplicationRecord
|
|
27
28
|
# as uniq_name was changed, we need to look for repo labels that end with the repo name
|
28
29
|
katello_repos = Katello::RootRepository.where('label like ?', "%#{::Katello::Util::Model.labelize(self.description)}%")
|
29
30
|
katello_repos.each do |repo|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
if repo.has_attribute?('upstream_authentication_token')
|
32
|
+
unless repo.url == url && repo.upstream_authentication_token == token
|
33
|
+
ForemanTasks.async_task(::Actions::Katello::Repository::Update, repo, url: url, upstream_authentication_token: token)
|
34
|
+
::Foreman::Logging.logger('foreman_scc_manager').info "Update URL and authentication token for repository '#{repo.name}'."
|
35
|
+
end
|
36
|
+
else
|
37
|
+
unless repo.url == full_url
|
38
|
+
ForemanTasks.async_task(::Actions::Katello::Repository::Update, repo, url: full_url)
|
39
|
+
::Foreman::Logging.logger('foreman_scc_manager').info "Update URL-token for repository '#{repo.name}'."
|
40
|
+
end
|
33
41
|
end
|
34
42
|
end
|
35
43
|
end
|
@@ -1,52 +1,8 @@
|
|
1
1
|
<% title (_("Product Selection for Account %s") % @scc_account) %>
|
2
|
-
|
3
|
-
|
4
|
-
<%=
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
@@ -0,0 +1,10 @@
|
|
1
|
+
class AddSccKatelloRepositoryRelation < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
create_table(:scc_katello_repositories) do |t|
|
4
|
+
t.references :scc_repository, null: false, foreign_key: { on_delete: :cascade }
|
5
|
+
t.references :katello_root_repository, null: false, foreign_key: { on_delete: :cascade }
|
6
|
+
|
7
|
+
t.timestamps null: false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
class RemoveRootRepositoryIdFromSccRepository < ActiveRecord::Migration[6.0]
|
2
|
+
def change
|
3
|
+
remove_foreign_key :scc_repositories, :katello_root_repositories, column: :katello_root_repository_id, on_delete: :nullify
|
4
|
+
remove_column :scc_repositories, :katello_root_repository_id, :integer, index: true, null: true
|
5
|
+
end
|
6
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class PopulateSccKatelloRepositories < ActiveRecord::Migration[6.0]
|
2
|
+
class SccProduct < ApplicationRecord
|
3
|
+
belongs_to :product, class_name: 'Katello::Product'
|
4
|
+
has_and_belongs_to_many :scc_repositories
|
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
|
11
|
+
|
12
|
+
def up
|
13
|
+
SccProduct.where.not(product_id: nil).each do |scc_p|
|
14
|
+
scc_p.scc_repositories.each do |scc_r|
|
15
|
+
# find all Katello repositories that were derived from that SCC repository
|
16
|
+
katello_repos = Katello::RootRepository.where('label like ?', "%#{::Katello::Util::Model.labelize(scc_r.description)}%")
|
17
|
+
scc_r.update!(katello_root_repositories: katello_repos)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class PopulateUpstreamAuthenticationToken < ActiveRecord::Migration[6.0]
|
2
|
+
def up
|
3
|
+
return unless ActiveRecord::Base.connection.column_exists?('katello_root_repositories', 'upstream_authentication_token')
|
4
|
+
|
5
|
+
scc_repositories = SccRepository.includes(:scc_katello_repositories).where.not(scc_katello_repositories: { id: nil })
|
6
|
+
scc_repositories.each do |scc_repo|
|
7
|
+
scc_repo.katello_root_repositories.each do |katello_repo|
|
8
|
+
katello_repo.update!(url: scc_repo.url, upstream_authentication_token: scc_repo.token)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def down
|
14
|
+
return if ActiveRecord::Base.connection.column_exists?('katello_root_repositories', 'upstream_authentication_token')
|
15
|
+
|
16
|
+
scc_repositories = SccRepository.includes(:scc_katello_repositories).where.not(scc_katello_repositories: { id: nil })
|
17
|
+
scc_repositories.each do |scc_repo|
|
18
|
+
scc_repo.katello_root_repositories.each do |katello_repo|
|
19
|
+
katello_repo.update!(url: scc_repo.full_url)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
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,
|
@@ -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
|
@@ -0,0 +1,27 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubocop/rake_task'
|
3
|
+
|
4
|
+
namespace :foreman_scc_manager do
|
5
|
+
desc 'Set up authentication tokens for Katello 4.3.'
|
6
|
+
task :setup_authentication_tokens => ['environment'] do
|
7
|
+
unless ActiveRecord::Base.connection.column_exists?('katello_root_repositories', 'upstream_authentication_token')
|
8
|
+
puts 'Your Katello version needs to be at 4.3 and up to run this task.'
|
9
|
+
return
|
10
|
+
end
|
11
|
+
begin
|
12
|
+
scc_repositories = SccRepository.includes(:scc_katello_repositories).where.not(scc_katello_repositories: { id: nil })
|
13
|
+
scc_repositories.each do |scc_repo|
|
14
|
+
scc_repo.katello_root_repositories.each do |katello_repo|
|
15
|
+
katello_repo.update!(url: scc_repo.url, upstream_authentication_token: scc_repo.token)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
puts 'Authentication tokens created successfully.'
|
19
|
+
rescue StandardError => e
|
20
|
+
puts 'There was an error while creating the authentication tokens.'
|
21
|
+
puts e.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
rescue LoadError
|
26
|
+
puts 'Rubocop not loaded.'
|
27
|
+
end
|