foreman_scc_manager 1.8.2 → 1.8.7

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -0
  3. data/app/controllers/api/v2/scc_accounts_controller.rb +9 -7
  4. data/app/controllers/scc_accounts_controller.rb +30 -4
  5. data/app/lib/actions/scc_manager/subscribe_product.rb +26 -13
  6. data/app/lib/actions/scc_manager/sync.rb +5 -5
  7. data/app/lib/actions/scc_manager/sync_products.rb +10 -11
  8. data/app/lib/actions/scc_manager/sync_repositories.rb +9 -11
  9. data/app/lib/scc_manager.rb +2 -2
  10. data/app/models/scc_account.rb +70 -11
  11. data/app/models/scc_product.rb +20 -2
  12. data/app/models/scc_repository.rb +11 -9
  13. data/app/views/scc_accounts/_form.html.erb +6 -0
  14. data/app/views/scc_accounts/index.html.erb +4 -3
  15. data/app/views/scc_accounts/show.html.erb +13 -4
  16. data/db/migrate/20200520281300_fix_scc_permissions.rb +22 -0
  17. data/db/migrate/20201119084201_add_gpg_key_to_scc_account.rb +6 -0
  18. data/db/migrate/20210205082733_add_subscription_valid_to_scc_products_and_repos.rb +6 -0
  19. data/db/migrate/20210210104407_add_root_repository_id_to_scc_repository.rb +6 -0
  20. data/db/migrate/20210224095050_connect_katello_root_repository_to_scc_repository.rb +17 -0
  21. data/lib/foreman_scc_manager/engine.rb +36 -25
  22. data/lib/foreman_scc_manager/version.rb +1 -1
  23. data/lib/tasks/test.rake +1 -1
  24. data/locale/de/LC_MESSAGES/foreman_scc_manager.mo +0 -0
  25. data/locale/de/foreman_scc_manager.edit.po +574 -0
  26. data/locale/de/foreman_scc_manager.po +40 -21
  27. data/locale/de/foreman_scc_manager.po.time_stamp +0 -0
  28. data/locale/en/foreman_scc_manager.edit.po +566 -0
  29. data/locale/en/foreman_scc_manager.po +21 -3
  30. data/locale/en/foreman_scc_manager.po.time_stamp +0 -0
  31. data/locale/foreman_scc_manager.pot +65 -38
  32. data/test/controllers/api/v2/scc_accounts_test.rb +9 -3
  33. data/test/controllers/scc_accounts_controller_test.rb +104 -0
  34. data/test/controllers/scc_accounts_controller_test2.rb +51 -0
  35. data/test/fixtures/models/scc_extendings.yml +6 -0
  36. data/test/fixtures/models/scc_products.yml +30 -2
  37. data/test/fixtures/models/scc_repositories.yml +29 -0
  38. data/test/models/scc_account_test.rb +70 -0
  39. data/test/models/scc_product_test.rb +69 -1
  40. data/test/support/fixtures_support.rb +3 -2
  41. data/test/test_controller_helper.rb +15 -0
  42. data/test/test_plugin_helper.rb +9 -0
  43. metadata +33 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fb848728ea3961f30b44e6a02f43b84e73555ff703b0e0c3456e772e66132536
4
- data.tar.gz: e7ca63acbe79ac2def4f203a0f10c269230652a35efd53e08d7fec4c536f2a18
3
+ metadata.gz: 843165a6092fcb04bf69d13131ae44acb02478ce347084c160a8f61891770eba
4
+ data.tar.gz: 892025747b9572a4b31d25f4c96ab28ea9af0099ef3302fe8c7aec07935b588b
5
5
  SHA512:
6
- metadata.gz: 215eaa829b2d7e544d818e421850763f4d78bc2b3e62d38d397980c10d0d066bea28e6a9d1fcacfdcb93486a683c0350fdaa0ea80451aebb99f6a7761cda62cc
7
- data.tar.gz: a93f9a77bcc06abff4e22e78268363f5ae2a71be7d64debd8184ecfdeed412586f9e92bd8a5d7ef11d6308c7149950e7fd0114ef806c6d9717766cc838ed131c
6
+ metadata.gz: 0cb42eeb656e4a0cca5c93d7c83e0fed14fa73a9b0e7f2ad0ddcb07b007156405f0e91d968e4eb38aafd6376551f334340bda0a4ff9d632d13d4818766e7eb75
7
+ data.tar.gz: 700546d7abfdc1ff7fc12f452c69bb6ca8869c41b63ae4e37fef99541dc229bf2287de3435ecd8c09dee32cb79465b8c896af09c78b4d0d498209e35c8a347cf
data/README.md CHANGED
@@ -13,6 +13,8 @@ for how to install Foreman plugins
13
13
 
14
14
  | Foreman Version | Katello Version | Plugin Version |
15
15
  | --------------- | --------------- | -------------- |
16
+ | 2.1 | 3.16 | ~> 1.8.5 |
17
+ | 2.0 | 3.16 | ~> 1.8.4 |
16
18
  | 1.24 | 3.14 | ~> 1.8.0 |
17
19
  | 1.22 | 3.12 | ~> 1.7.0 |
18
20
  | 1.21 | 3.10 | ~> 1.6.0 |
@@ -23,6 +25,9 @@ for how to install Foreman plugins
23
25
  | 1.16 | 3.5 | <= 1.3.0 |
24
26
  | 1.15 | 3.4 | ~> 1.1.0 |
25
27
 
28
+ ## Documentation
29
+ The plugin documentation can be found at https://docs.orcharhino.com/sources/management_ui/the_content_menu/suse_subscriptions.html.
30
+
26
31
  ## Contributing
27
32
 
28
33
  Fork and send a Pull Request. Thanks!
@@ -18,7 +18,7 @@ module Api
18
18
  def index
19
19
  scope = resource_scope
20
20
  scope = scope.where(:organization => params[:organization_id]) if params[:organization_id].present?
21
- @scc_accounts = scope.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
21
+ @scc_accounts = scope.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page], :per_page => params[:per_page])
22
22
  end
23
23
 
24
24
  api :GET, '/scc_accounts/:id/', N_('Show scc_account')
@@ -34,7 +34,8 @@ 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', 'monthy'], :desc => N_('Interval for syncing scc_account')
37
- param :sync_date, String, :desc => N_('Last Sync time of scc_account')
37
+ param :sync_date, String, :desc => N_('Date and time relative to which the sync interval is run')
38
+ param :katello_gpg_key_id, :identifier, :required => false, :desc => N_('Associated GPG key of scc_account')
38
39
  end
39
40
  end
40
41
 
@@ -79,9 +80,9 @@ module Api
79
80
  end
80
81
  respond_to do |format|
81
82
  if @scc_account.test_connection
82
- format.json { render json: 'Success'.to_json, status: :ok }
83
+ format.json { render json: { 'success' => true }.to_json, status: :ok }
83
84
  else
84
- format.json { render json: 'Failed'.to_json, status: :not_found }
85
+ format.json { render json: { 'success' => false, 'error' => 'Test failed. Check your credentials.' }.to_json, status: :not_found }
85
86
  end
86
87
  end
87
88
  end
@@ -102,7 +103,7 @@ module Api
102
103
 
103
104
  api :PUT, '/scc_accounts/:id/bulk_subscribe/', N_('Bulk subscription of scc_products for scc_account')
104
105
  param :id, :identifier_dottable, :required => true
105
- param :scc_subscribe_product_ids, Array
106
+ param :scc_subscribe_product_ids, Array, :required => true
106
107
  def bulk_subscribe
107
108
  scc_products_to_subscribe = @scc_account.scc_products.where(:id => params[:scc_subscribe_product_ids])
108
109
  respond_to do |format|
@@ -112,7 +113,7 @@ module Api
112
113
  scc_products_to_subscribe)
113
114
  format.json { render json: subscribe_task.to_json, status: :ok }
114
115
  else
115
- format.json { render json: 'No Product selected'.to_json, status: :expectation_failed }
116
+ format.json { render json: { error: 'No Product selected' }, status: :expectation_failed }
116
117
  end
117
118
  end
118
119
  rescue ::Foreman::Exception => e
@@ -132,7 +133,8 @@ module Api
132
133
  :base_url,
133
134
  :interval,
134
135
  :sync_date,
135
- :organization_id
136
+ :organization_id,
137
+ :katello_gpg_key_id
136
138
  )
137
139
  end
138
140
 
@@ -1,12 +1,19 @@
1
1
  class SccAccountsController < ApplicationController
2
+ helper_method :scc_filtered_products
2
3
  before_action :find_organization
3
4
  before_action :find_resource, only: %i[show edit update destroy sync bulk_subscribe]
5
+ before_action :find_available_gpg_keys, only: %i[new edit]
4
6
  include Foreman::Controller::AutoCompleteSearch
5
7
 
6
8
  # GET /scc_accounts
7
9
  def index
8
- @scc_accounts = resource_base.search_for(params[:search], order: params[:order])
9
- .paginate(page: params[:page])
10
+ @scc_accounts = resource_base.where(organization: @organization)
11
+ .search_for(params[:search], order: params[:order])
12
+ .paginate(:page => params[:page], :per_page => params[:per_page])
13
+ # overwrite the product list with filtered products that do not include products with empty repositories
14
+ @scc_accounts.each do |scc_account|
15
+ scc_account.scc_products_with_repos_count = scc_account.scc_products.only_products_with_repos.count
16
+ end
10
17
  end
11
18
 
12
19
  # GET /scc_accounts/new
@@ -92,6 +99,11 @@ class SccAccountsController < ApplicationController
92
99
 
93
100
  private
94
101
 
102
+ def find_available_gpg_keys
103
+ @scc_account ? org = @scc_account.organization : org = @organization
104
+ @selectable_gpg_keys = ::Katello::GpgKey.where(organization: org).collect { |p| [p.name, p.id] }.unshift ['None', nil]
105
+ end
106
+
95
107
  def find_organization
96
108
  @organization = Organization.current
97
109
  redirect_to '/select_organization?toState=' + request.path unless @organization
@@ -108,7 +120,8 @@ class SccAccountsController < ApplicationController
108
120
  :base_url,
109
121
  :interval,
110
122
  :sync_date,
111
- :organization_id
123
+ :organization_id,
124
+ :katello_gpg_key_id
112
125
  )
113
126
  end
114
127
 
@@ -121,9 +134,22 @@ class SccAccountsController < ApplicationController
121
134
  when 'sync', 'test_connection'
122
135
  :sync
123
136
  when 'bulk_subscribe'
124
- :bulk_subscribe
137
+ :use
125
138
  else
126
139
  super
127
140
  end
128
141
  end
142
+
143
+ # Function filters a product list and removes all products without valid repositories
144
+ # The .order call is necessary to apply the ordering to repository that have already been loaded from the database.
145
+ # Input parameters:
146
+ # product_list: list of SccProduct
147
+ # product_type: return only base products if type is set (default), else all
148
+ def scc_filtered_products(product_list, product_type = 'base')
149
+ if product_type == 'base'
150
+ product_list.only_products_with_repos.where(product_type: 'base').order(:friendly_name)
151
+ else
152
+ product_list.only_products_with_repos.order(:friendly_name)
153
+ end
154
+ end
129
155
  end
@@ -8,27 +8,38 @@ module Actions
8
8
  .info("Initiating subscription for SccProduct '#{scc_product.friendly_name}'.")
9
9
  sequence do
10
10
  product_create_action = plan_action(CreateProduct,
11
- product_name: scc_product.uniq_name,
12
- product_description: scc_product.description,
13
- organization_id: scc_product.organization.id)
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)
15
+ katello_repos = {}
14
16
  scc_product.scc_repositories.each do |repo|
15
- uniq_name = scc_product.uniq_name + ' ' + repo.description
16
17
  arch = scc_product.arch || 'noarch'
17
- plan_action(CreateRepository,
18
- :product_id => product_create_action.output[:product_id],
19
- :uniq_name => uniq_name,
20
- :url => repo.full_url,
21
- :arch => arch)
18
+ repo_create_action = plan_action(CreateRepository,
19
+ :product_id => product_create_action.output[:product_id],
20
+ :uniq_name => repo.uniq_name(scc_product),
21
+ :pretty_repo_name => repo.pretty_name,
22
+ :url => repo.full_url,
23
+ :arch => arch)
24
+ katello_repos[repo.id] = repo_create_action.output[:katello_root_repository_id]
22
25
  end
26
+ # connect action to resource (=> make parameters accessable in input)
23
27
  action_subject(scc_product, product_id: product_create_action.output[:product_id])
28
+ input.update(katello_repos: katello_repos)
24
29
  plan_self
25
30
  end
26
31
  end
27
32
 
28
33
  def finalize
34
+ # connect Scc products and Katello products
29
35
  scc_product = SccProduct.find(input[:scc_product][:id])
30
36
  product = ::Katello::Product.find(input[:product_id])
31
37
  scc_product.update!(product: product)
38
+ # extract Katello repo ids from input hash and store to database
39
+ input[:katello_repos].each do |scc_repo_id, katello_root_repository_id|
40
+ scc_repo = SccRepository.find(scc_repo_id)
41
+ scc_repo.update!(katello_root_repository_id: katello_root_repository_id)
42
+ end
32
43
  end
33
44
 
34
45
  def humanized_name
@@ -43,6 +54,7 @@ module Actions
43
54
  def create_sub_plans
44
55
  product = ::Katello::Product.new
45
56
  product.name = input[:product_name]
57
+ product.gpg_key = ::Katello::GpgKey.find_by(id: input[:gpg_key], organization: input[:organization_id])
46
58
  product.description = input[:product_description]
47
59
  trigger(::Actions::Katello::Product::Create,
48
60
  product,
@@ -58,12 +70,11 @@ module Actions
58
70
 
59
71
  def create_sub_plans
60
72
  product = ::Katello::Product.find(input[:product_id])
61
- uniq_name = input[:uniq_name]
62
- label = ::Katello::Util::Model.labelize(uniq_name)
73
+ label = ::Katello::Util::Model.labelize(input[:uniq_name])
63
74
  unprotected = true
64
75
  gpg_key = product.gpg_key
65
76
  repo_param = { :label => label,
66
- :name => uniq_name,
77
+ :name => input[:pretty_repo_name],
67
78
  :url => input[:url],
68
79
  :content_type => 'yum',
69
80
  :unprotected => unprotected,
@@ -73,7 +84,9 @@ module Actions
73
84
  repository = product.add_repo(repo_param)
74
85
  repository.mirror_on_sync = true
75
86
  repository.verify_ssl_on_sync = true
76
- trigger(::Actions::Katello::Repository::CreateRoot, repository)
87
+ trigger(::Actions::Katello::Repository::CreateRoot, repository).tap do
88
+ output[:katello_root_repository_id] = repository.id
89
+ end
77
90
  end
78
91
  end
79
92
  end
@@ -1,21 +1,21 @@
1
1
  module Actions
2
2
  module SccManager
3
+ # for dynflow documentation see here: https://dynflow.github.io/documentation/
3
4
  class Sync < Actions::EntryAction
4
5
  def plan(scc_account)
5
6
  ::Foreman::Logging.logger('foreman_scc_manager')
6
7
  .info("Initiating 'sync' for SccAccount '#{scc_account.name}'.")
7
8
  action_subject(scc_account)
8
9
  sequence do
9
- sync_repo_action = plan_action(::Actions::SccManager::SyncRepositories, scc_account)
10
- sync_prod_action = plan_action(::Actions::SccManager::SyncProducts, scc_account)
11
- plan_self(repo_status: sync_repo_action.output[:status], prod_status: sync_prod_action.output[:status])
10
+ plan_action(::Actions::SccManager::SyncRepositories, scc_account)
11
+ plan_action(::Actions::SccManager::SyncProducts, scc_account)
12
+ plan_self
12
13
  end
13
14
  end
14
15
 
15
16
  def finalize
17
+ # this is only executed if run actions of SyncRepositories and SyncProducts were successful
16
18
  scc_account = SccAccount.find(input[:scc_account][:id])
17
- raise 'Updating failed' unless input[:repo_status] == 'SUCCESS' && input[:prod_status] == 'SUCCESS'
18
-
19
19
  scc_account.update! synced: Time.current
20
20
  end
21
21
 
@@ -13,20 +13,19 @@ module Actions
13
13
  end
14
14
 
15
15
  def run
16
- output[:status] = 'SUCCESS'
17
- begin
18
- products = ::SccManager.get_scc_data(input.fetch(:base_url),
19
- '/connect/organizations/products',
20
- input.fetch(:login),
21
- decrypt_field(input.fetch(:password)))
22
- output[:data] = ::SccManager.sanitize_products(products).values
23
- rescue StandardError
24
- output[:status] = 'FAILURE'
25
- end
16
+ products = ::SccManager.get_scc_data(input.fetch(:base_url),
17
+ '/connect/organizations/products',
18
+ input.fetch(:login),
19
+ decrypt_field(input.fetch(:password)))
20
+ output[:data] = ::SccManager.sanitize_products(products).values
21
+ rescue StandardError => e
22
+ ::Foreman::Logging.logger('foreman_scc_manager').error "Error while syncronizing SCC-Products: #{e}"
23
+ error! e.to_s
26
24
  end
27
25
 
28
26
  def finalize
29
- SccAccount.find(input.fetch(:id)).update_scc_products(output.fetch(:data)) if output[:status] == 'SUCCESS'
27
+ # this is only executed if 'run' succeeds
28
+ SccAccount.find(input.fetch(:id)).update_scc_products(output.fetch(:data))
30
29
  end
31
30
 
32
31
  def rescue_strategy
@@ -12,20 +12,18 @@ module Actions
12
12
  end
13
13
 
14
14
  def run
15
- output[:status] = 'IN PROGRESS'
16
- begin
17
- output[:data] = ::SccManager.get_scc_data(input[:base_url],
18
- '/connect/organizations/repositories',
19
- input[:login],
20
- decrypt_field(input[:password]))
21
- output[:status] = 'SUCCESS'
22
- rescue StandardError
23
- output[:status] = 'FAILURE'
24
- end
15
+ output[:data] = ::SccManager.get_scc_data(input[:base_url],
16
+ '/connect/organizations/repositories',
17
+ input[:login],
18
+ decrypt_field(input[:password]))
19
+ rescue StandardError => e
20
+ ::Foreman::Logging.logger('foreman_scc_manager').error "Error while syncronizing SCC-Repositories: #{e}"
21
+ error! e.to_s
25
22
  end
26
23
 
27
24
  def finalize
28
- SccAccount.find(input[:scc_account][:id]).update_scc_repositories(output[:data]) if output[:status] == 'SUCCESS'
25
+ # this is only executed if 'run' succeeds
26
+ SccAccount.find(input[:scc_account][:id]).update_scc_repositories(output[:data])
29
27
  end
30
28
 
31
29
  def rescue_strategy
@@ -8,8 +8,8 @@ module SccManager
8
8
  uri.scheme = URI.parse(proxy_config[:host]).scheme
9
9
  uri.host = URI.parse(proxy_config[:host]).host
10
10
  uri.port = proxy_config[:port].try(:to_s)
11
- uri.user = proxy_config[:user].try(:to_s)
12
- uri.password = proxy_config[:password].try(:to_s)
11
+ uri.user = proxy_config[:user]
12
+ uri.password = proxy_config[:password] if uri.user.present?
13
13
 
14
14
  RestClient.proxy = uri.to_s
15
15
  end
@@ -2,6 +2,9 @@ class SccAccount < ApplicationRecord
2
2
  include Authorizable
3
3
  include Encryptable
4
4
  include ForemanTasks::Concerns::ActionSubject
5
+
6
+ attr_accessor :scc_products_with_repos_count
7
+
5
8
  encrypts :password
6
9
 
7
10
  NEVER = 'never'.freeze
@@ -166,38 +169,53 @@ class SccAccount < ApplicationRecord
166
169
  def test_connection
167
170
  get_scc_data('/connect/organizations/subscriptions')
168
171
  true
169
- rescue StandardError
172
+ rescue StandardError => e
173
+ ::Foreman::Logging.logger('foreman_scc_manager').warn "Error occurred while testing SCC-Connection to Account #{self}: #{e}"
170
174
  false
171
175
  end
172
176
 
173
177
  def update_scc_repositories(upstream_repositories)
174
178
  upstream_repo_ids = []
179
+ # initially invalidate all repositories and validate them during update
180
+ invalidated_repos = invalidate_subscription_status(scc_repositories)
175
181
  # import repositories
176
182
  upstream_repositories.each do |ur|
177
183
  cached_repository = scc_repositories.find_or_initialize_by(scc_id: ur['id'])
178
- cached_repository.name = ur['name']
179
184
  cached_repository.distro_target = ur['distro_target']
180
185
  cached_repository.description = ur['description']
181
186
  cached_repository.url, cached_repository.token = ur['url'].split('?')
182
187
  cached_repository.enabled = ur['enabled']
183
188
  cached_repository.autorefresh = ur['autorefresh']
184
189
  cached_repository.installer_updates = ur['installer_updates']
190
+ # should be called after all attributes are set in case of dependencies (currently: description)
191
+ cached_repository.name = cached_repository.pretty_name
192
+ cached_repository.subscription_valid = true
185
193
  cached_repository.save!
186
194
  upstream_repo_ids << ur['id']
195
+ # set invalidated record to true, if exists
196
+ invalidated_repos = revalidate_subscription_status(invalidated_repos, ur[id])
187
197
  end
188
- logger.debug "Found #{upstream_repo_ids.length} repositories"
189
- # delete repositories beeing removed upstream
198
+ ::Foreman::Logging.logger('foreman_scc_manager').debug "Found #{upstream_repo_ids.length} repositories"
199
+
200
+ # all scc repos that are kept but not available upstream need to be marked invalid
201
+ # subscription_valid can be set to nil
202
+ to_invalidate = invalidated_repos.select { |ir| ir.katello_root_repository_id.present? && !ir.subscription_valid }
203
+ ::Foreman::Logging.logger('foreman_scc_manager').debug "Invalidating #{to_invalidate.count} expired repositories"
204
+ invalidate_subscription_status(to_invalidate, true)
205
+
206
+ # delete repositories being removed upstream and that are not subscribed to
190
207
  to_delete = scc_repositories.where.not(scc_id: upstream_repo_ids)
191
- logger.debug "Deleting #{to_delete.count} old repositories"
208
+ ::Foreman::Logging.logger('foreman_scc_manager').debug "Deleting #{to_delete.count} old repositories"
192
209
  to_delete.destroy_all
193
210
  end
194
211
 
195
212
  def update_scc_products(upstream_products)
196
213
  upstream_product_ids = []
214
+ # initially invalidate all products and validate them during update
215
+ invalidated_products = invalidate_subscription_status(scc_products)
197
216
  # import products
198
217
  upstream_products.each do |up|
199
218
  cached_product = scc_products.find_or_initialize_by(scc_id: up['id'])
200
- cached_product.name = up['name']
201
219
  cached_product.version = up['version']
202
220
  cached_product.arch = up['arch']
203
221
  cached_product.description = up['description']
@@ -205,13 +223,26 @@ class SccAccount < ApplicationRecord
205
223
  cached_product.product_type = up['product_type']
206
224
  cached_product.scc_repositories =
207
225
  scc_repositories.where(scc_id: up['repositories'].map { |repo| repo['id'] })
226
+ # name should be set after friendly_name because it depends on friendly_name
227
+ cached_product.name = cached_product.pretty_name
228
+ cached_product.description = cached_product.pretty_description
229
+ cached_product.subscription_valid = true
208
230
  cached_product.save!
209
231
  upstream_product_ids << up['id']
232
+ # set invalidated record to true, if exists
233
+ invalidated_products = revalidate_subscription_status(invalidated_products, up['id'])
210
234
  end
211
- logger.debug "Found #{upstream_product_ids.length} products"
212
- # delete products beeing removed upstream
213
- to_delete = scc_products.where.not(scc_id: upstream_product_ids)
214
- logger.debug "Deleting #{to_delete.count} old products"
235
+ ::Foreman::Logging.logger('foreman_scc_manager').debug "Found #{upstream_product_ids.length} products"
236
+
237
+ # all scc products that are kept but not available upstream need to be marked invalid
238
+ # subscription_valid can be set to nil
239
+ to_invalidate = invalidated_products.select { |ip| ip.product_id.present? && !ip.subscription_valid }
240
+ ::Foreman::Logging.logger('foreman_scc_manager').debug "Invalidating #{to_invalidate.count} expired products"
241
+ invalidate_subscription_status(to_invalidate, true)
242
+
243
+ # delete products being removed upstream and that are not subscribed to
244
+ to_delete = scc_products.where.not(scc_id: upstream_product_ids).where(product_id: nil)
245
+ ::Foreman::Logging.logger('foreman_scc_manager').debug "Deleting #{to_delete.count} old products"
215
246
  to_delete.destroy_all
216
247
  # rewire product to product relationships
217
248
  upstream_products.each do |up|
@@ -219,8 +250,36 @@ class SccAccount < ApplicationRecord
219
250
  begin
220
251
  scc_products.find_by!(scc_id: up['id']).update!(scc_extensions: extensions)
221
252
  rescue ActiveRecord::RecordNotFound
222
- logger.info "Failed to find parent scc_product '#{up['name']}'."
253
+ ::Foreman::Logging.logger('foreman_scc_manager').info "Failed to find parent scc_product '#{up['name']}'."
254
+ end
255
+ end
256
+ end
257
+
258
+ # validate the subscription status of a product/repo
259
+ # no saving to database
260
+ # params: elements: scc repos or products, Array or ActiveRecord_(*)
261
+ # scc_id: scc_id of the element that should be revalidated
262
+ # return: elements where for the element with scc_id subscription_valid is true
263
+ def revalidate_subscription_status(elements, scc_id)
264
+ return nil if elements.nil?
265
+
266
+ revalidate = elements.find { |e| e.scc_id == scc_id }
267
+ revalidate.subscription_valid = true unless revalidate.nil?
268
+ # return modified list
269
+ elements
270
+ end
271
+
272
+ # set all products/repos invalid
273
+ # params: items_to_invalidate: ActiveRecord_(*)
274
+ # save_record: store in database or not (default)
275
+ # return: ActiveRecord elements with invalidated subscription status
276
+ def invalidate_subscription_status(items_to_invalidate, save_record = false)
277
+ if items_to_invalidate.present?
278
+ items_to_invalidate.each do |inv|
279
+ inv.subscription_valid = false
280
+ inv.save! if save_record
223
281
  end
224
282
  end
283
+ items_to_invalidate
225
284
  end
226
285
  end