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