katello 4.12.1 → 4.13.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of katello might be problematic. Click here for more details.

Files changed (245) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/katello/locale/bn/katello.js +3365 -3350
  3. data/app/assets/javascripts/katello/locale/bn_IN/katello.js +3136 -3121
  4. data/app/assets/javascripts/katello/locale/ca/katello.js +3588 -3576
  5. data/app/assets/javascripts/katello/locale/cs/katello.js +3499 -3487
  6. data/app/assets/javascripts/katello/locale/cs_CZ/katello.js +4186 -4186
  7. data/app/assets/javascripts/katello/locale/de/katello.js +5553 -5562
  8. data/app/assets/javascripts/katello/locale/de_AT/katello.js +3008 -2993
  9. data/app/assets/javascripts/katello/locale/de_DE/katello.js +3066 -3051
  10. data/app/assets/javascripts/katello/locale/el/katello.js +3376 -3370
  11. data/app/assets/javascripts/katello/locale/en/katello.js +3008 -2993
  12. data/app/assets/javascripts/katello/locale/en_GB/katello.js +3076 -3073
  13. data/app/assets/javascripts/katello/locale/en_US/katello.js +3008 -2993
  14. data/app/assets/javascripts/katello/locale/es/katello.js +5366 -5372
  15. data/app/assets/javascripts/katello/locale/et_EE/katello.js +3008 -2993
  16. data/app/assets/javascripts/katello/locale/fr/katello.js +5975 -5984
  17. data/app/assets/javascripts/katello/locale/gl/katello.js +3125 -3113
  18. data/app/assets/javascripts/katello/locale/gu/katello.js +3119 -3104
  19. data/app/assets/javascripts/katello/locale/he_IL/katello.js +3020 -3005
  20. data/app/assets/javascripts/katello/locale/hi/katello.js +3137 -3122
  21. data/app/assets/javascripts/katello/locale/id/katello.js +3008 -2993
  22. data/app/assets/javascripts/katello/locale/it/katello.js +4469 -4466
  23. data/app/assets/javascripts/katello/locale/ja/katello.js +5969 -5978
  24. data/app/assets/javascripts/katello/locale/ka/katello.js +5649 -5652
  25. data/app/assets/javascripts/katello/locale/kn/katello.js +3136 -3121
  26. data/app/assets/javascripts/katello/locale/ko/katello.js +4717 -4720
  27. data/app/assets/javascripts/katello/locale/locale/katello.js +1050 -1084
  28. data/app/assets/javascripts/katello/locale/ml_IN/katello.js +3008 -2993
  29. data/app/assets/javascripts/katello/locale/mr/katello.js +3136 -3121
  30. data/app/assets/javascripts/katello/locale/nl_NL/katello.js +3116 -3101
  31. data/app/assets/javascripts/katello/locale/or/katello.js +3137 -3122
  32. data/app/assets/javascripts/katello/locale/pa/katello.js +3136 -3121
  33. data/app/assets/javascripts/katello/locale/pl/katello.js +3210 -3195
  34. data/app/assets/javascripts/katello/locale/pl_PL/katello.js +3008 -2993
  35. data/app/assets/javascripts/katello/locale/pt/katello.js +3009 -2994
  36. data/app/assets/javascripts/katello/locale/pt_BR/katello.js +5362 -5368
  37. data/app/assets/javascripts/katello/locale/ro/katello.js +3008 -2993
  38. data/app/assets/javascripts/katello/locale/ro_RO/katello.js +3008 -2993
  39. data/app/assets/javascripts/katello/locale/ru/katello.js +4638 -4641
  40. data/app/assets/javascripts/katello/locale/sl/katello.js +3051 -3036
  41. data/app/assets/javascripts/katello/locale/sv_SE/katello.js +3156 -3144
  42. data/app/assets/javascripts/katello/locale/ta/katello.js +3365 -3350
  43. data/app/assets/javascripts/katello/locale/ta_IN/katello.js +3121 -3106
  44. data/app/assets/javascripts/katello/locale/te/katello.js +3136 -3121
  45. data/app/assets/javascripts/katello/locale/tr/katello.js +3025 -3010
  46. data/app/assets/javascripts/katello/locale/vi/katello.js +3008 -2993
  47. data/app/assets/javascripts/katello/locale/vi_VN/katello.js +3008 -2993
  48. data/app/assets/javascripts/katello/locale/zh/katello.js +3008 -2993
  49. data/app/assets/javascripts/katello/locale/zh_CN/katello.js +5968 -5977
  50. data/app/assets/javascripts/katello/locale/zh_TW/katello.js +4694 -4697
  51. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +370 -132
  52. data/app/controllers/katello/api/rhsm/candlepin_dynflow_proxy_controller.rb +12 -20
  53. data/app/controllers/katello/api/v2/activation_keys_controller.rb +10 -4
  54. data/app/controllers/katello/api/v2/capsule_content_controller.rb +24 -0
  55. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +9 -2
  56. data/app/controllers/katello/api/v2/debs_controller.rb +1 -1
  57. data/app/controllers/katello/api/v2/errata_controller.rb +1 -1
  58. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +12 -4
  59. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +3 -3
  60. data/app/controllers/katello/api/v2/organizations_controller.rb +0 -11
  61. data/app/controllers/katello/api/v2/packages_controller.rb +1 -1
  62. data/app/controllers/katello/api/v2/repositories_controller.rb +19 -13
  63. data/app/controllers/katello/api/v2/repository_sets_controller.rb +2 -1
  64. data/app/controllers/katello/api/v2/simple_content_access_controller.rb +9 -22
  65. data/app/controllers/katello/concerns/api/v2/authorization.rb +1 -1
  66. data/app/helpers/katello/subscription_mailer_helper.rb +1 -1
  67. data/app/jobs/create_manifest_expire_soon_warning_notifications.rb +11 -0
  68. data/app/lib/actions/candlepin/owner/regenerate_upstream_identity_cert.rb +21 -0
  69. data/app/lib/actions/katello/capsule_content/sync.rb +1 -1
  70. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +7 -2
  71. data/app/lib/actions/katello/capsule_content/verify_checksum.rb +75 -0
  72. data/app/lib/actions/katello/content_view/promote.rb +1 -1
  73. data/app/lib/actions/katello/content_view/publish.rb +1 -1
  74. data/app/lib/actions/katello/content_view_version/verify_checksum.rb +29 -0
  75. data/app/lib/actions/katello/host/hypervisors_update.rb +1 -0
  76. data/app/lib/actions/katello/host/update_content_view.rb +2 -2
  77. data/app/lib/actions/katello/organization/manifest_delete.rb +6 -1
  78. data/app/lib/actions/katello/organization/manifest_import.rb +5 -0
  79. data/app/lib/actions/katello/organization/manifest_refresh.rb +3 -0
  80. data/app/lib/actions/katello/repository/create.rb +17 -11
  81. data/app/lib/actions/katello/repository/create_root.rb +4 -2
  82. data/app/lib/actions/katello/repository/metadata_generate.rb +7 -1
  83. data/app/lib/actions/katello/repository/remove_content.rb +1 -0
  84. data/app/lib/actions/katello/repository/sync.rb +2 -1
  85. data/app/lib/actions/katello/repository/upload_files.rb +1 -0
  86. data/app/lib/actions/katello/upstream_subscriptions/bind_entitlement.rb +1 -1
  87. data/app/lib/actions/pulp3/capsule_content/verify_checksum.rb +27 -0
  88. data/app/lib/actions/pulp3/orchestration/content_view_version/export_repository.rb +7 -9
  89. data/app/lib/actions/pulp3/orchestration/content_view_version/syncable_export.rb +5 -4
  90. data/app/lib/actions/pulp3/orchestration/orphan_cleanup/remove_orphans.rb +1 -0
  91. data/app/lib/actions/pulp3/orphan_cleanup/purge_completed_tasks.rb +15 -0
  92. data/app/lib/katello/concerns/base_template_scope_extensions.rb +7 -2
  93. data/app/lib/katello/http_resource.rb +6 -1
  94. data/app/lib/katello/resources/candlepin/consumer.rb +1 -1
  95. data/app/lib/katello/resources/candlepin/upstream_consumer.rb +18 -6
  96. data/app/lib/katello/resources/candlepin/upstream_job.rb +1 -1
  97. data/app/lib/katello/resources/registry.rb +25 -0
  98. data/app/mailers/katello/subscription_mailer.rb +3 -6
  99. data/app/models/katello/concerns/organization_extensions.rb +42 -3
  100. data/app/models/katello/content_view.rb +30 -0
  101. data/app/models/katello/content_view_environment_content_facet.rb +4 -2
  102. data/app/models/katello/glue/provider.rb +19 -12
  103. data/app/models/katello/glue/pulp/repos.rb +11 -3
  104. data/app/models/katello/host/content_facet.rb +1 -1
  105. data/app/models/katello/host/subscription_facet.rb +1 -1
  106. data/app/models/katello/ping.rb +1 -1
  107. data/app/models/katello/repository.rb +32 -1
  108. data/app/models/katello/root_repository.rb +4 -6
  109. data/app/models/katello/trace_status.rb +1 -1
  110. data/app/services/katello/content_unit_indexer.rb +9 -0
  111. data/app/services/katello/pulp3/alternate_content_source.rb +4 -6
  112. data/app/services/katello/pulp3/api/core.rb +21 -0
  113. data/app/services/katello/pulp3/api/docker.rb +4 -0
  114. data/app/services/katello/pulp3/api/yum.rb +11 -0
  115. data/app/services/katello/pulp3/docker_manifest.rb +5 -1
  116. data/app/services/katello/pulp3/repository/generic.rb +1 -1
  117. data/app/services/katello/pulp3/repository/yum.rb +1 -6
  118. data/app/services/katello/pulp3/repository.rb +26 -6
  119. data/app/services/katello/pulp3/repository_mirror.rb +13 -12
  120. data/app/services/katello/pulp3/service_common.rb +2 -10
  121. data/app/services/katello/pulp3/smart_proxy_repository.rb +0 -2
  122. data/app/services/katello/ui_notifications/subscriptions/manifest_expire_soon_warning.rb +75 -0
  123. data/app/views/foreman/job_templates/update_package_-_katello_ansible_default.erb +5 -1
  124. data/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb +2 -2
  125. data/app/views/foreman/job_templates/upload_profile.erb +16 -0
  126. data/app/views/foreman/smart_proxies/_content_tab.html.erb +3 -1
  127. data/app/views/katello/api/v2/content_view_filter_rules/show.json.rabl +9 -0
  128. data/app/views/katello/api/v2/docker_manifests/show.json.rabl +1 -0
  129. data/app/views/katello/api/v2/organizations/show.json.rabl +9 -1
  130. data/app/views/overrides/activation_keys/_host_environment_select.html.erb +1 -1
  131. data/app/views/overrides/activation_keys/_host_media_type_select.html.erb +15 -5
  132. data/config/routes/api/registry.rb +4 -8
  133. data/config/routes/api/v2.rb +2 -0
  134. data/db/migrate/20240423112842_add_fields_to_katello_docker_manifest.rb +8 -0
  135. data/db/migrate/20240502192021_change_katello_repository_rpms_id_seq_to_big_int.rb +9 -0
  136. data/db/migrate/20240520142245_add_container_push_props_to_repo.rb +7 -0
  137. data/db/migrate/20240531193030_remove_sha1_repository_checksum_type.rb +10 -0
  138. data/db/seeds.d/109-katello-notification-blueprints.rb +6 -0
  139. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-repository-sets.controller.js +3 -3
  140. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/new/views/new-content-credential.html +2 -1
  141. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-repository-sets.controller.js +3 -3
  142. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +0 -15
  143. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/checksum.service.js +6 -1
  144. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +8 -6
  145. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +12 -13
  146. data/lib/katello/permission_creator.rb +3 -3
  147. data/lib/katello/permissions/registry_permissions.rb +4 -7
  148. data/lib/katello/plugin.rb +21 -8
  149. data/lib/katello/repository_types/ostree.rb +7 -0
  150. data/lib/katello/scheduled_jobs.rb +7 -1
  151. data/lib/katello/tasks/clean_backend_objects.rake +1 -1
  152. data/lib/katello/tasks/repository.rake +22 -0
  153. data/lib/katello/version.rb +1 -1
  154. data/locale/action_names.rb +4 -3
  155. data/locale/bn/katello.po +166 -151
  156. data/locale/bn_IN/katello.po +166 -151
  157. data/locale/ca/katello.po +166 -151
  158. data/locale/cs/katello.po +166 -151
  159. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  160. data/locale/cs_CZ/katello.po +172 -157
  161. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  162. data/locale/de/katello.po +178 -163
  163. data/locale/de_AT/katello.po +166 -151
  164. data/locale/de_DE/katello.po +166 -151
  165. data/locale/el/katello.po +166 -151
  166. data/locale/en/katello.po +166 -151
  167. data/locale/en_GB/katello.po +166 -151
  168. data/locale/en_US/katello.po +166 -151
  169. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  170. data/locale/es/katello.po +178 -163
  171. data/locale/et_EE/katello.po +166 -151
  172. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  173. data/locale/fr/katello.po +179 -164
  174. data/locale/gl/katello.po +166 -151
  175. data/locale/gu/katello.po +166 -151
  176. data/locale/he_IL/katello.po +166 -151
  177. data/locale/hi/katello.po +166 -151
  178. data/locale/id/katello.po +166 -151
  179. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  180. data/locale/it/katello.po +169 -154
  181. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  182. data/locale/ja/katello.po +179 -164
  183. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  184. data/locale/ka/katello.po +177 -162
  185. data/locale/katello.pot +1119 -1062
  186. data/locale/kn/katello.po +166 -151
  187. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  188. data/locale/ko/katello.po +174 -159
  189. data/locale/ml_IN/katello.po +166 -151
  190. data/locale/mr/katello.po +166 -151
  191. data/locale/nl_NL/katello.po +166 -151
  192. data/locale/or/katello.po +166 -151
  193. data/locale/pa/katello.po +166 -151
  194. data/locale/pl/katello.po +166 -151
  195. data/locale/pl_PL/katello.po +166 -151
  196. data/locale/pt/katello.po +166 -151
  197. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  198. data/locale/pt_BR/katello.po +178 -163
  199. data/locale/ro/katello.po +166 -151
  200. data/locale/ro_RO/katello.po +166 -151
  201. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  202. data/locale/ru/katello.po +171 -156
  203. data/locale/sl/katello.po +166 -151
  204. data/locale/sv_SE/katello.po +166 -151
  205. data/locale/ta/katello.po +166 -151
  206. data/locale/ta_IN/katello.po +166 -151
  207. data/locale/te/katello.po +166 -151
  208. data/locale/tr/katello.po +166 -151
  209. data/locale/vi/katello.po +166 -151
  210. data/locale/vi_VN/katello.po +166 -151
  211. data/locale/zh/katello.po +166 -151
  212. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  213. data/locale/zh_CN/katello.po +179 -164
  214. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  215. data/locale/zh_TW/katello.po +171 -156
  216. data/package.json +0 -1
  217. data/webpack/ForemanColumnExtensions/index.js +129 -0
  218. data/webpack/components/Content/ContentTable.js +0 -1
  219. data/webpack/components/Content/__tests__/__snapshots__/ContentTable.test.js.snap +0 -1
  220. data/webpack/components/Table/TableWrapper.js +14 -0
  221. data/webpack/components/extensions/HostDetails/ActionsBar/index.js +1 -1
  222. data/webpack/components/extensions/Hosts/ActionsBar/index.js +20 -1
  223. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/BulkChangeHostCVModal.js +220 -0
  224. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/actions.js +23 -0
  225. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/index.js +25 -0
  226. data/webpack/components/extensions/Hosts/BulkActions/__tests__/bulkChangeHostCVModal.test.js +133 -0
  227. data/webpack/global_index.js +9 -0
  228. data/webpack/scenes/Hosts/ChangeContentSource/actions.js +3 -1
  229. data/webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceForm.js +62 -24
  230. data/webpack/scenes/Hosts/ChangeContentSource/index.js +24 -16
  231. data/webpack/scenes/ModuleStreams/ModuleStreamsPage.js +33 -39
  232. data/webpack/scenes/ModuleStreams/__tests__/ModuleStreamPage.test.js +4 -2
  233. data/webpack/scenes/ModuleStreams/__tests__/__snapshots__/ModuleStreamsTable.test.js.snap +0 -1
  234. data/webpack/scenes/RedHatRepositories/__tests__/__snapshots__/RedHatRepositoriesPage.test.js.snap +1 -0
  235. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +66 -5
  236. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +16 -13
  237. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +14 -8
  238. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +1 -0
  239. data/webpack/scenes/Subscriptions/components/SubscriptionsToolbar/SubscriptionsToolbar.js +1 -1
  240. metadata +60 -42
  241. data/app/lib/actions/katello/host/upload_package_profile.rb +0 -45
  242. data/app/lib/actions/katello/host/upload_profiles.rb +0 -47
  243. data/webpack/utils/__tests__/useParamsWithHash.test.js +0 -22
  244. data/webpack/utils/paramsFromHash.js +0 -16
  245. data/webpack/utils/useUrlParams.js +0 -14
@@ -13,10 +13,13 @@ module Actions
13
13
 
14
14
  org = repository.organization
15
15
  sequence do
16
- create_action = plan_action(Pulp3::Orchestration::Repository::Create,
17
- repository, SmartProxy.pulp_primary, force_repo_create)
18
-
19
- return if create_action.error
16
+ # Container push repositories will already be in pulp. The version_href is
17
+ # directly updated after a push.
18
+ unless root.is_container_push
19
+ create_action = plan_action(Pulp3::Orchestration::Repository::Create,
20
+ repository, SmartProxy.pulp_primary, force_repo_create)
21
+ return if create_action.error
22
+ end
20
23
 
21
24
  # when creating a clone, the following actions are handled by the
22
25
  # publish/promote process
@@ -32,13 +35,16 @@ module Actions
32
35
  end
33
36
  end
34
37
 
35
- concurrence do
36
- plan_self(:repository_id => repository.id, :clone => clone)
37
- if !clone && repository.url.present?
38
- repository.product.alternate_content_sources.with_type(repository.content_type).each do |acs|
39
- acs.smart_proxies.each do |smart_proxy|
40
- smart_proxy_acs = ::Katello::SmartProxyAlternateContentSource.create(alternate_content_source_id: acs.id, smart_proxy_id: smart_proxy.id, repository_id: repository.id)
41
- plan_action(Pulp3::Orchestration::AlternateContentSource::Create, smart_proxy_acs)
38
+ # Container push repos do not need metadata generation or ACS (they do not sync)
39
+ unless root.is_container_push
40
+ concurrence do
41
+ plan_self(:repository_id => repository.id, :clone => clone)
42
+ if !clone && repository.url.present?
43
+ repository.product.alternate_content_sources.with_type(repository.content_type).each do |acs|
44
+ acs.smart_proxies.each do |smart_proxy|
45
+ smart_proxy_acs = ::Katello::SmartProxyAlternateContentSource.create(alternate_content_source_id: acs.id, smart_proxy_id: smart_proxy.id, repository_id: repository.id)
46
+ plan_action(Pulp3::Orchestration::AlternateContentSource::Create, smart_proxy_acs)
47
+ end
42
48
  end
43
49
  end
44
50
  end
@@ -2,13 +2,15 @@ module Actions
2
2
  module Katello
3
3
  module Repository
4
4
  class CreateRoot < Actions::EntryAction
5
- def plan(root)
5
+ def plan(root, relative_path = nil)
6
6
  root.save!
7
7
  repository = ::Katello::Repository.new(:environment => root.organization.library,
8
8
  :content_view_version => root.organization.library.default_content_view_version,
9
9
  :root => root)
10
- repository.relative_path = repository.custom_repo_path
10
+ repository.container_repository_name = relative_path
11
+ repository.relative_path = relative_path || repository.custom_repo_path
11
12
  repository.save!
13
+
12
14
  action_subject(repository)
13
15
  plan_action(::Actions::Katello::Repository::Create, repository)
14
16
  end
@@ -1,8 +1,10 @@
1
1
  module Actions
2
2
  module Katello
3
3
  module Repository
4
- class MetadataGenerate < Actions::Base
4
+ class MetadataGenerate < Actions::EntryAction
5
5
  def plan(repository, options = {})
6
+ action_subject(repository)
7
+ repository.check_ready_to_act!
6
8
  source_repository = options.fetch(:source_repository, nil)
7
9
  source_repository ||= repository.target_repository if repository.link?
8
10
  smart_proxy = options.fetch(:smart_proxy, SmartProxy.pulp_primary)
@@ -15,6 +17,10 @@ module Actions
15
17
  :source_repository => source_repository,
16
18
  :matching_content => matching_content)
17
19
  end
20
+
21
+ def resource_locks
22
+ :link
23
+ end
18
24
  end
19
25
  end
20
26
  end
@@ -5,6 +5,7 @@ module Actions
5
5
  include Dynflow::Action::WithSubPlans
6
6
 
7
7
  def plan(repository, content_units, options = {})
8
+ repository.check_ready_to_act!
8
9
  sync_capsule = options.fetch(:sync_capsule, true)
9
10
  if repository.redhat?
10
11
  fail _("Cannot remove content from a non-custom repository")
@@ -20,6 +20,7 @@ module Actions
20
20
  # of Katello and we just need to finish the rest of the orchestration
21
21
  def plan(repo, options = {})
22
22
  action_subject(repo)
23
+ repo.check_ready_to_act!
23
24
 
24
25
  validate_contents = options.fetch(:validate_contents, false)
25
26
  skip_metadata_check = options.fetch(:skip_metadata_check, false) || (validate_contents && (repo.yum? || repo.deb?))
@@ -100,7 +101,7 @@ module Actions
100
101
  def notify_on_failure(_plan)
101
102
  notification = MailNotification[:repository_sync_failure]
102
103
  repo = ::Katello::Repository.find(input.fetch(:repository, {})[:id])
103
- notification.users.where(disabled: [nil, false], mail_enabled: true).each do |user|
104
+ notification.users.with_enabled_email.each do |user|
104
105
  notification.deliver(user: user, repo: repo, task: task)
105
106
  end
106
107
  end
@@ -8,6 +8,7 @@ module Actions
8
8
  class UploadFiles < Actions::EntryAction
9
9
  def plan(repository, files, content_type = nil, options = {})
10
10
  action_subject(repository)
11
+ repository.check_ready_to_act!
11
12
  repository.clear_smart_proxy_sync_histories
12
13
  tmp_files = prepare_tmp_files(files)
13
14
 
@@ -4,7 +4,7 @@ module Actions
4
4
  class BindEntitlement < Actions::Base
5
5
  def run
6
6
  output[:response] = ::Katello::Resources::Candlepin::UpstreamConsumer
7
- .bind_entitlement(pool)
7
+ .bind_entitlement(**pool)
8
8
  end
9
9
 
10
10
  def humanized_name
@@ -0,0 +1,27 @@
1
+ module Actions
2
+ module Pulp3
3
+ module CapsuleContent
4
+ class VerifyChecksum < Pulp3::AbstractAsyncTask
5
+ def plan(repository, smart_proxy)
6
+ plan_self(:repository_id => repository.id, :smart_proxy_id => smart_proxy.id)
7
+ end
8
+
9
+ def invoke_external_task
10
+ repo = ::Katello::Repository.find(input[:repository_id])
11
+ output[:pulp_tasks] = repo.backend_service(smart_proxy).with_mirror_adapter.repair
12
+ end
13
+
14
+ def repos_to_repair(smart_proxy, environment, content_view, repository)
15
+ smart_proxy_helper = ::Katello::SmartProxyHelper.new(smart_proxy)
16
+ smart_proxy_helper.lifecycle_environment_check(environment, repository)
17
+ if repository
18
+ [repository]
19
+ else
20
+ repositories = smart_proxy_helper.repositories_available_to_capsule(environment, content_view).by_rpm_count
21
+ repositories
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -3,26 +3,24 @@ module Actions
3
3
  module Orchestration
4
4
  module ContentViewVersion
5
5
  class ExportRepository < Actions::EntryAction
6
- def plan(repository,
7
- chunk_size: nil,
8
- from_history: nil,
9
- format: ::Katello::Pulp3::ContentViewVersion::Export::IMPORTABLE)
6
+ def plan(repository, opts = {})
7
+ opts[:format] ||= ::Katello::Pulp3::ContentViewVersion::Export::IMPORTABLE
10
8
  action_subject(repository)
11
9
  validate_repositories_immediate!(repository)
12
- validate_export_types!(repository, format)
10
+ validate_export_types!(repository, opts[:format])
13
11
  content_view = ::Katello::Pulp3::ContentViewVersion::Export.find_repository_export_view(
14
12
  repository: repository,
15
13
  create_by_default: true,
16
- format: format)
14
+ format: opts[:format])
17
15
  content_view.update!(repository_ids: [repository.library_instance_or_self.id])
18
16
 
19
17
  sequence do
20
18
  publish_action = plan_action(::Actions::Katello::ContentView::Publish, content_view, '')
21
19
  export_action = plan_action(Actions::Katello::ContentViewVersion::Export,
22
20
  content_view_version: publish_action.version,
23
- chunk_size: chunk_size,
24
- from_history: from_history,
25
- format: format)
21
+ chunk_size: opts[:chunk_size],
22
+ from_history: opts[:from_history],
23
+ format: opts[:format])
26
24
  plan_self(export_action_output: export_action.output)
27
25
  end
28
26
  end
@@ -16,10 +16,11 @@ module Actions
16
16
  param :export_history_id, Integer
17
17
  end
18
18
 
19
- def plan(content_view_version:,
20
- smart_proxy:,
21
- destination_server:,
22
- from_content_view_version:)
19
+ def plan(opts = {})
20
+ content_view_version = opts[:content_view_version]
21
+ smart_proxy = opts[:smart_proxy]
22
+ destination_server = opts[:destination_server]
23
+ from_content_view_version = opts[:from_content_view_version]
23
24
  format = ::Katello::Pulp3::ContentViewVersion::Export::SYNCABLE
24
25
  sequence do
25
26
  export_service = ::Katello::Pulp3::ContentViewVersion::Export.create(
@@ -14,6 +14,7 @@ module Actions
14
14
  plan_action(Actions::Pulp3::OrphanCleanup::DeleteOrphanRemotes, proxy)
15
15
  end
16
16
  plan_action(Actions::Pulp3::OrphanCleanup::RemoveOrphans, proxy)
17
+ plan_action(Actions::Pulp3::OrphanCleanup::PurgeCompletedTasks, proxy)
17
18
  end
18
19
  end
19
20
  end
@@ -0,0 +1,15 @@
1
+ module Actions
2
+ module Pulp3
3
+ module OrphanCleanup
4
+ class PurgeCompletedTasks < Pulp3::AbstractAsyncTask
5
+ def plan(smart_proxy)
6
+ plan_self(:smart_proxy_id => smart_proxy.id)
7
+ end
8
+
9
+ def run
10
+ output[:pulp_tasks] = ::Katello::Pulp3::Api::Core.new(smart_proxy).purge_completed_tasks
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -216,9 +216,14 @@ module Katello
216
216
  keyword :includes, Array, of: [String, Symbol], desc: 'An array of associations represented by strings or symbols, to be included in the SQL query. The list can be extended
217
217
  from plugins and can not be fully documented here. Most used associations are :subscription, :products, :organization', default: nil
218
218
  returns array_of: 'Pool', desc: 'The collection that can be iterated over using each_record'
219
+ keyword :expiring_in_days, String, desc: "Return subscriptions expiring in the given number of days. Leave blank to return all subscriptions.", default: nil
219
220
  end
220
- def load_pools(search: '', includes: nil)
221
- load_resource(klass: Pool.readable, search: search, permission: nil, includes: includes)
221
+ def load_pools(search: '', includes: nil, expiring_in_days: nil)
222
+ pools = Pool.readable
223
+ if expiring_in_days
224
+ pools = pools.expiring_in_days(expiring_in_days)
225
+ end
226
+ load_resource(klass: pools, search: search, permission: nil, includes: includes)
222
227
  end
223
228
 
224
229
  apipie :method, 'Returns the last time the host checked in via RHSM' do
@@ -38,6 +38,7 @@ module Katello
38
38
  get: Net::HTTP::Get,
39
39
  post: Net::HTTP::Post,
40
40
  put: Net::HTTP::Put,
41
+ patch: Net::HTTP::Patch,
41
42
  delete: Net::HTTP::Delete
42
43
  }.freeze
43
44
 
@@ -84,7 +85,11 @@ module Katello
84
85
  def issue_request(method:, path:, headers: {}, payload: nil)
85
86
  logger.debug("Resource #{method.upcase} request: #{path}")
86
87
  logger.debug "Headers: #{headers.to_json}"
87
- logger.debug "Body: #{filter_sensitive_data(payload.to_json)}"
88
+ begin
89
+ logger.debug "Body: #{filter_sensitive_data(payload.to_json)}"
90
+ rescue JSON::GeneratorError, Encoding::UndefinedConversionError
91
+ logger.debug "Body: Error: could not render payload as json"
92
+ end
88
93
 
89
94
  client = rest_client(REQUEST_MAP[method], method, path)
90
95
  args = [method, payload, headers].compact
@@ -7,7 +7,7 @@ module Katello
7
7
  class << self
8
8
  def all_uuids
9
9
  cp_consumers = Organization.all.map do |org|
10
- ::Katello::Resources::Candlepin::Consumer.get('owner' => org.label, :include_only => [:uuid])
10
+ ::Katello::Resources::Candlepin::Consumer.get('owner' => org.label, :include_only => [:uuid], :sort_by => "uuid")
11
11
  end
12
12
  cp_consumers.flatten!
13
13
  cp_consumers.map { |consumer| consumer["uuid"] }
@@ -40,19 +40,31 @@ module Katello
40
40
  raise ::Katello::Errors::UpstreamEntitlementGone
41
41
  end
42
42
 
43
- def get_export(url, client_cert, client_key, ca_file)
43
+ def start_upstream_export(url, client_cert, client_key, ca_file)
44
44
  logger.debug "Sending GET request to upstream Candlepin: #{url}"
45
- return resource(url: url, client_cert: client_cert, client_key: client_key, ca_file: ca_file).get
45
+ resource(url: url, client_cert: client_cert, client_key: client_key, ca_file: ca_file).get
46
46
  rescue RestClient::Exception => e
47
47
  raise e
48
48
  end
49
49
 
50
+ alias_method :retrieve_upstream_export, :start_upstream_export
51
+
50
52
  def update(url, client_cert, client_key, ca_file, attributes)
51
53
  logger.debug "Sending PUT request to upstream Candlepin: #{url} #{attributes.to_json}"
52
- return resource(url: url, client_cert: client_cert, client_key: client_key, ca_file: ca_file).put(attributes.to_json,
53
- 'accept' => 'application/json',
54
- 'accept-language' => I18n.locale,
55
- 'content-type' => 'application/json')
54
+ resource(
55
+ url: url,
56
+ client_cert: client_cert,
57
+ client_key: client_key,
58
+ ca_file: ca_file).put(
59
+ attributes.to_json,
60
+ 'accept' => 'application/json',
61
+ 'accept-language' => I18n.locale,
62
+ 'content-type' => 'application/json')
63
+ end
64
+
65
+ def regenerate_upstream_identity(url, client_cert, client_key, ca_file)
66
+ logger.debug "Sending POST request to upstream Candlepin: #{url}"
67
+ resource(url: url, client_cert: client_cert, client_key: client_key, ca_file: ca_file).post(nil)
56
68
  end
57
69
 
58
70
  def bind_entitlement(**pool)
@@ -12,7 +12,7 @@ module Katello
12
12
 
13
13
  def get(id, upstream)
14
14
  url = API_URL
15
- response = Resources::Candlepin::UpstreamConsumer.get_export("#{url}#{path(id)}", upstream['idCert']['cert'],
15
+ response = Resources::Candlepin::UpstreamConsumer.start_upstream_export("#{url}#{path(id)}", upstream['idCert']['cert'],
16
16
  upstream['idCert']['key'], nil)
17
17
  job = JSON.parse(response)
18
18
  job.with_indifferent_access
@@ -18,10 +18,35 @@ module Katello
18
18
  client.options.merge!(options)
19
19
  client.get(headers)
20
20
  end
21
+
22
+ def self.put(path, body, headers)
23
+ logger.debug "Sending PUT request to Registry: #{path}"
24
+ resource = RegistryResource.load_class
25
+ joined_path = resource.prefix.chomp("/") + path
26
+ resource.issue_request(method: :put, path: joined_path, headers: headers, payload: body)
27
+ end
28
+
29
+ def self.patch(path, body, headers)
30
+ logger.debug "Sending PATCH request to Registry: #{path}"
31
+ resource = RegistryResource.load_class
32
+ joined_path = resource.prefix.chomp("/") + path
33
+ resource.issue_request(method: :patch, path: joined_path, headers: headers, payload: body)
34
+ end
35
+
36
+ def self.post(path, body, headers)
37
+ logger.debug "Sending PUT request to Registry: #{path}"
38
+ resource = RegistryResource.load_class
39
+ joined_path = resource.prefix.chomp("/") + path
40
+ resource.issue_request(method: :post, path: joined_path, headers: headers, payload: body)
41
+ end
21
42
  end
22
43
 
23
44
  class RegistryResource < HttpResource
24
45
  class << self
46
+ def logger
47
+ ::Foreman::Logging.logger('katello/registry_proxy')
48
+ end
49
+
25
50
  def load_class
26
51
  pulp_primary = ::SmartProxy.pulp_primary
27
52
  content_app_url = pulp_primary.setting(SmartProxy::PULP3_FEATURE, 'content_app_url')
@@ -10,14 +10,11 @@ module Katello
10
10
 
11
11
  ::User.as(user.login) do
12
12
  @pools = Katello::Pool.readable.expiring_in_days(days_from_now)
13
- @affected_hosts = ::Host::Managed.with_pools_expiring_in_days(days_from_now)
14
13
  end
15
14
 
16
- if @affected_hosts.any?
17
- start_report_task(days_from_now)
18
- @report_url = report_url
19
- @report_link = report_link
20
- end
15
+ start_report_task(days_from_now)
16
+ @report_url = report_url
17
+ @report_link = report_link
21
18
 
22
19
  set_locale_for(user) do
23
20
  mail(:to => user.mail, :subject => _("You have subscriptions expiring within %s days") % days_from_now)
@@ -100,16 +100,55 @@ module Katello
100
100
  end
101
101
  end
102
102
 
103
- def manifest_expired?
104
- manifest_expiry = owner_details.dig(:upstreamConsumer, :idCert, :serial, :expiration)
103
+ def manifest_expiration_date(cached: true)
104
+ Rails.cache.fetch("#{self.label}_manifest_expiration_date", expires_in: 1.minute, force: !cached) do
105
+ unless manifest_imported?(cached: cached)
106
+ Rails.logger.error "Manifest not imported for organization #{self.label}"
107
+ return nil
108
+ end
109
+ manifest_expiry = owner_details.dig(:upstreamConsumer, :idCert, :serial, :expiration)
110
+
111
+ if manifest_expiry.present?
112
+ DateTime.parse(manifest_expiry)
113
+ else
114
+ Rails.logger.error "Unable to parse manifest expiration date from owner details"
115
+ nil
116
+ end
117
+ end
118
+ end
119
+
120
+ def manifest_expired?(cached: true)
121
+ manifest_expiry = manifest_expiration_date(cached: cached)
105
122
 
106
123
  if manifest_expiry
107
- DateTime.parse(manifest_expiry) < DateTime.now
124
+ manifest_expiry < DateTime.now
108
125
  else
109
126
  false
110
127
  end
111
128
  end
112
129
 
130
+ def manifest_expiring_soon?(days = Setting[:expire_soon_days])
131
+ return false if !manifest_imported? || manifest_expired?
132
+ manifest_expiry = manifest_expiration_date
133
+
134
+ if manifest_expiry
135
+ manifest_expiry < DateTime.now + days.days
136
+ else
137
+ false
138
+ end
139
+ end
140
+
141
+ def manifest_expire_days_remaining
142
+ manifest_expiry = manifest_expiration_date
143
+ return 0 if manifest_expired?
144
+
145
+ if manifest_expiry
146
+ (manifest_expiry - DateTime.now).to_i
147
+ else
148
+ 0
149
+ end
150
+ end
151
+
113
152
  def manifest_history
114
153
  imports.map { |i| OpenStruct.new(i) }
115
154
  end
@@ -454,6 +454,8 @@ module Katello
454
454
  ).each do |facet|
455
455
  facet.update_applicability_counts
456
456
  facet.update_errata_status
457
+ rescue NoMethodError
458
+ Rails.logger.warn _('Errata statuses not updated for deleted content facet with UUID %s') % facet.uuid
457
459
  end
458
460
  end
459
461
  end
@@ -634,6 +636,7 @@ module Katello
634
636
  check_ready_to_import!
635
637
  else
636
638
  fail _("Import-only content views can not be published directly") if import_only? && !syncable
639
+ check_repositories_blocking_publish!
637
640
  check_composite_action_allowed!(organization.library)
638
641
  check_docker_repository_names!([organization.library])
639
642
  check_orphaned_content_facets!(environments: self.environments)
@@ -642,6 +645,16 @@ module Katello
642
645
  true
643
646
  end
644
647
 
648
+ def check_repositories_blocking_publish!
649
+ blocking_tasks = repositories&.map { |repo| repo.blocking_task }&.compact
650
+
651
+ if blocking_tasks&.any?
652
+ errored_tasks = blocking_tasks.uniq.map { |task| "- #{Setting['foreman_url']}/foreman_tasks/tasks/#{task&.id}" }.join("\n")
653
+ fail _("Pending tasks detected in repositories of this content view. Please wait for the tasks: " +
654
+ errored_tasks + " before publishing.")
655
+ end
656
+ end
657
+
645
658
  def check_docker_repository_names!(environments)
646
659
  environments.each do |environment|
647
660
  repositories = []
@@ -789,6 +802,10 @@ module Katello
789
802
  repositories.any? { |repo| repo.last_indexed && repo.last_indexed > latest_version_object.created_at }
790
803
  end
791
804
 
805
+ def unpublishable?
806
+ default? || import_only? || generated?
807
+ end
808
+
792
809
  def needs_publish?
793
810
  #Returns
794
811
  # True:
@@ -808,7 +825,9 @@ module Katello
808
825
  # a) No changes were detected via audits *and*
809
826
  # Audit for CV publish exists (Audits haven't been cleaned up)
810
827
  # *and* applied_filters field is set(Published after upgrade)
828
+ # b) Default, import only and generated CVs can not be published, hence these will always return false.
811
829
  #
830
+ return false if unpublishable?
812
831
  return true unless latest_version_object
813
832
  return nil unless last_publish_task_success?
814
833
  return composite_cv_components_changed? if composite?
@@ -868,6 +887,17 @@ module Katello
868
887
  filters.present?
869
888
  end
870
889
 
890
+ def blocking_task
891
+ blocking_task_labels = [
892
+ ::Actions::Katello::ContentView::Publish.name
893
+ ]
894
+ ForemanTasks::Task::DynflowTask.where(:label => blocking_task_labels)
895
+ .where.not(state: 'stopped')
896
+ .for_resource(self)
897
+ .order(:started_at)
898
+ .last
899
+ end
900
+
871
901
  protected
872
902
 
873
903
  def remove_repository(repository)
@@ -5,7 +5,7 @@ module Katello
5
5
 
6
6
  validates :content_view_environment_id, presence: true
7
7
  validates :content_facet_id, presence: true, unless: :new_record?
8
- validate :ensure_valid_content_source
8
+ validate :ensure_valid_content_source, if: proc { Setting['validate_host_lce_content_source_coherence'] }
9
9
 
10
10
  def ensure_valid_content_source
11
11
  source = self.content_facet&.content_source
@@ -14,7 +14,9 @@ module Katello
14
14
  hostname = self.content_facet&.host&.name
15
15
  return unless [source, env].all? { |x| x.present? }
16
16
  unless source.lifecycle_environments.include?(env)
17
- errors.add(:base, _("Host %{hostname}: Cannot add content view environment to content facet. The host's content source '%{content_source}' does not sync lifecycle environment '%{lce}'.") % { hostname: hostname, content_source: source.name, lce: env.name })
17
+ error_msg = _("Host %{hostname}: Cannot add content view environment to content facet. The host's content source '%{content_source}' does not sync lifecycle environment '%{lce}'.") % { hostname: hostname, content_source: source.name, lce: env.name }
18
+ Rails.logger.warn error_msg
19
+ errors.add(:base, error_msg)
18
20
  end
19
21
  end
20
22
  end
@@ -32,6 +32,10 @@ module Katello
32
32
 
33
33
  module InstanceMethods
34
34
  API_URL = 'https://subscription.rhsm.redhat.com/subscription/consumers/'.freeze
35
+ def api_url(upstream = {})
36
+ # Default to Red Hat
37
+ upstream['apiUrl'] || API_URL
38
+ end
35
39
 
36
40
  def sync
37
41
  Rails.logger.debug "Syncing provider #{name}"
@@ -62,34 +66,37 @@ module Katello
62
66
  fail _("Upstream identity certificate not available")
63
67
  end
64
68
 
65
- # Default to Red Hat
66
- url = upstream['apiUrl'] || API_URL
67
-
68
69
  params = {}
69
70
  params[:capabilities] = Resources::Candlepin::CandlepinPing.ping['managerCapabilities'].inject([]) do |result, element|
70
71
  result << {'name' => element}
71
72
  end
72
73
  params[:facts] = {:distributor_version => DISTRIBUTOR_VERSION }
73
- Resources::Candlepin::UpstreamConsumer.update("#{url}#{upstream['uuid']}", upstream['idCert']['cert'],
74
+ Resources::Candlepin::UpstreamConsumer.update("#{api_url(upstream)}#{upstream['uuid']}", upstream['idCert']['cert'],
74
75
  upstream['idCert']['key'], ca_file, params)
75
76
  end
76
77
 
77
- def start_owner_upstream_export(upstream)
78
+ def owner_upstream_regenerate_identity_cert(upstream)
78
79
  validate_upstream_identity_cert!(upstream)
79
- url = upstream['apiUrl'] || API_URL
80
+ Rails.logger.debug "Sending request to regenerate identity certificate for upstream consumer: #{upstream['uuid']}"
81
+ response = Resources::Candlepin::UpstreamConsumer.regenerate_upstream_identity("#{api_url(upstream)}#{upstream['uuid']}", upstream['idCert']['cert'],
82
+ upstream['idCert']['key'], ca_file)
83
+ JSON.parse(response)
84
+ end
80
85
 
81
- response = Resources::Candlepin::UpstreamConsumer.get_export("#{url}#{upstream['uuid']}/export/async", upstream['idCert']['cert'],
86
+ def start_owner_upstream_export(upstream)
87
+ validate_upstream_identity_cert!(upstream)
88
+ response = Resources::Candlepin::UpstreamConsumer.start_upstream_export("#{api_url(upstream)}#{upstream['uuid']}/export/async", upstream['idCert']['cert'],
82
89
  upstream['idCert']['key'], ca_file)
83
90
  JSON.parse(response)
84
91
  end
85
92
 
86
93
  def retrieve_owner_upstream_export(upstream, zip_file_path, export_id)
87
94
  validate_upstream_identity_cert!(upstream)
88
- url = upstream['apiUrl'] || API_URL
89
-
90
- data = Resources::Candlepin::UpstreamConsumer.get_export("#{url}#{upstream['uuid']}/export/#{export_id}", upstream['idCert']['cert'],
91
- upstream['idCert']['key'], ca_file)
92
-
95
+ data = Resources::Candlepin::UpstreamConsumer.retrieve_upstream_export(
96
+ "#{api_url(upstream)}#{upstream['uuid']}/export/#{export_id}",
97
+ upstream['idCert']['cert'],
98
+ upstream['idCert']['key'], ca_file
99
+ )
93
100
  File.write(zip_file_path, data, mode: 'wb')
94
101
 
95
102
  true
@@ -50,7 +50,7 @@ module Katello
50
50
  end
51
51
 
52
52
  def last_sync_audit
53
- Audited::Audit.where(:auditable_id => self.repositories, :auditable_type => Katello::Repository.name).order(:created_at).last
53
+ Audited::Audit.where(:auditable_id => self.repositories, :auditable_type => Katello::Repository.name, :action => "sync").order(:created_at).last
54
54
  end
55
55
 
56
56
  def last_sync
@@ -58,13 +58,14 @@ module Katello
58
58
  end
59
59
 
60
60
  def last_repo_sync_task
61
- @last_sync_task ||= last_repo_sync_tasks.first
61
+ @last_sync_task ||= last_repo_sync_tasks&.first
62
62
  end
63
63
 
64
64
  def last_repo_sync_tasks
65
65
  ids = repos(self.library, nil, false).pluck(:id).join(',')
66
66
  label = ::Actions::Katello::Repository::Sync.name
67
67
  type = ::Katello::Repository.name
68
+ return nil if ids.empty?
68
69
  ForemanTasks::Task.search_for("label = #{label} and resource_type = #{type} and resource_id ^ (#{ids})")
69
70
  .order("started_at desc")
70
71
  end
@@ -132,7 +133,14 @@ module Katello
132
133
 
133
134
  repo_param[:mirroring_policy] = Katello::RootRepository::MIRRORING_POLICY_ADDITIVE if repo_param[:mirroring_policy].blank?
134
135
 
135
- RootRepository.new(repo_param.merge(:product_id => self.id))
136
+ repo_param = repo_param.merge(:product_id => self.id)
137
+
138
+ # Container push may concurrently call root add several times before the db can update.
139
+ if repo_param[:is_container_push]
140
+ RootRepository.create_or_find_by!(repo_param)
141
+ else
142
+ RootRepository.new(repo_param)
143
+ end
136
144
  end
137
145
  end
138
146
  end