katello 4.12.1 → 4.13.0.rc1

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 (222) 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 +51 -124
  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 +18 -12
  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/verify_checksum.rb +75 -0
  71. data/app/lib/actions/katello/content_view/promote.rb +1 -1
  72. data/app/lib/actions/katello/content_view/publish.rb +1 -1
  73. data/app/lib/actions/katello/content_view_version/verify_checksum.rb +29 -0
  74. data/app/lib/actions/katello/host/hypervisors_update.rb +1 -0
  75. data/app/lib/actions/katello/host/update_content_view.rb +2 -2
  76. data/app/lib/actions/katello/organization/manifest_import.rb +5 -0
  77. data/app/lib/actions/katello/organization/manifest_refresh.rb +3 -0
  78. data/app/lib/actions/katello/repository/metadata_generate.rb +7 -1
  79. data/app/lib/actions/katello/repository/remove_content.rb +1 -0
  80. data/app/lib/actions/katello/repository/sync.rb +2 -1
  81. data/app/lib/actions/katello/repository/upload_files.rb +1 -0
  82. data/app/lib/actions/pulp3/capsule_content/verify_checksum.rb +27 -0
  83. data/app/lib/actions/pulp3/orchestration/content_view_version/export_repository.rb +7 -9
  84. data/app/lib/actions/pulp3/orchestration/content_view_version/syncable_export.rb +5 -4
  85. data/app/lib/katello/concerns/base_template_scope_extensions.rb +7 -2
  86. data/app/lib/katello/http_resource.rb +6 -1
  87. data/app/lib/katello/resources/candlepin/consumer.rb +1 -1
  88. data/app/lib/katello/resources/candlepin/upstream_consumer.rb +18 -6
  89. data/app/lib/katello/resources/candlepin/upstream_job.rb +1 -1
  90. data/app/lib/katello/resources/registry.rb +25 -0
  91. data/app/mailers/katello/subscription_mailer.rb +3 -6
  92. data/app/models/katello/concerns/organization_extensions.rb +42 -3
  93. data/app/models/katello/content_view.rb +28 -0
  94. data/app/models/katello/content_view_environment_content_facet.rb +4 -2
  95. data/app/models/katello/glue/provider.rb +19 -12
  96. data/app/models/katello/glue/pulp/repos.rb +3 -2
  97. data/app/models/katello/host/content_facet.rb +1 -1
  98. data/app/models/katello/host/subscription_facet.rb +1 -1
  99. data/app/models/katello/ping.rb +1 -1
  100. data/app/models/katello/repository.rb +27 -0
  101. data/app/models/katello/root_repository.rb +0 -4
  102. data/app/services/katello/content_unit_indexer.rb +9 -0
  103. data/app/services/katello/pulp3/alternate_content_source.rb +4 -6
  104. data/app/services/katello/pulp3/api/core.rb +13 -0
  105. data/app/services/katello/pulp3/api/yum.rb +11 -0
  106. data/app/services/katello/pulp3/docker_manifest.rb +5 -1
  107. data/app/services/katello/pulp3/repository/generic.rb +1 -1
  108. data/app/services/katello/pulp3/repository.rb +26 -6
  109. data/app/services/katello/pulp3/repository_mirror.rb +13 -12
  110. data/app/services/katello/pulp3/service_common.rb +2 -10
  111. data/app/services/katello/pulp3/smart_proxy_repository.rb +0 -2
  112. data/app/services/katello/ui_notifications/subscriptions/manifest_expire_soon_warning.rb +75 -0
  113. data/app/views/foreman/job_templates/update_package_-_katello_ansible_default.erb +5 -1
  114. data/app/views/foreman/job_templates/update_packages_by_search_query_-_katello_ansible_default.erb +2 -2
  115. data/app/views/foreman/job_templates/upload_profile.erb +16 -0
  116. data/app/views/katello/api/v2/content_view_filter_rules/show.json.rabl +9 -0
  117. data/app/views/katello/api/v2/docker_manifests/show.json.rabl +1 -0
  118. data/app/views/katello/api/v2/organizations/show.json.rabl +9 -1
  119. data/app/views/overrides/activation_keys/_host_environment_select.html.erb +1 -1
  120. data/app/views/overrides/activation_keys/_host_media_type_select.html.erb +15 -5
  121. data/config/routes/api/registry.rb +4 -8
  122. data/config/routes/api/v2.rb +2 -0
  123. data/db/migrate/20240423112842_add_fields_to_katello_docker_manifest.rb +8 -0
  124. data/db/migrate/20240502192021_change_katello_repository_rpms_id_seq_to_big_int.rb +9 -0
  125. data/db/seeds.d/109-katello-notification-blueprints.rb +6 -0
  126. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-repository-sets.controller.js +3 -3
  127. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-credentials/new/views/new-content-credential.html +2 -1
  128. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-repository-sets.controller.js +3 -3
  129. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +0 -15
  130. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +8 -6
  131. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +12 -10
  132. data/lib/katello/permission_creator.rb +3 -3
  133. data/lib/katello/permissions/registry_permissions.rb +4 -7
  134. data/lib/katello/plugin.rb +9 -8
  135. data/lib/katello/repository_types/ostree.rb +7 -0
  136. data/lib/katello/scheduled_jobs.rb +7 -1
  137. data/lib/katello/tasks/clean_backend_objects.rake +1 -1
  138. data/lib/katello/tasks/repository.rake +22 -0
  139. data/lib/katello/version.rb +1 -1
  140. data/locale/action_names.rb +4 -3
  141. data/locale/bn/katello.po +166 -151
  142. data/locale/bn_IN/katello.po +166 -151
  143. data/locale/ca/katello.po +166 -151
  144. data/locale/cs/katello.po +166 -151
  145. data/locale/cs_CZ/LC_MESSAGES/katello.mo +0 -0
  146. data/locale/cs_CZ/katello.po +172 -157
  147. data/locale/de/LC_MESSAGES/katello.mo +0 -0
  148. data/locale/de/katello.po +178 -163
  149. data/locale/de_AT/katello.po +166 -151
  150. data/locale/de_DE/katello.po +166 -151
  151. data/locale/el/katello.po +166 -151
  152. data/locale/en/katello.po +166 -151
  153. data/locale/en_GB/katello.po +166 -151
  154. data/locale/en_US/katello.po +166 -151
  155. data/locale/es/LC_MESSAGES/katello.mo +0 -0
  156. data/locale/es/katello.po +178 -163
  157. data/locale/et_EE/katello.po +166 -151
  158. data/locale/fr/LC_MESSAGES/katello.mo +0 -0
  159. data/locale/fr/katello.po +179 -164
  160. data/locale/gl/katello.po +166 -151
  161. data/locale/gu/katello.po +166 -151
  162. data/locale/he_IL/katello.po +166 -151
  163. data/locale/hi/katello.po +166 -151
  164. data/locale/id/katello.po +166 -151
  165. data/locale/it/LC_MESSAGES/katello.mo +0 -0
  166. data/locale/it/katello.po +169 -154
  167. data/locale/ja/LC_MESSAGES/katello.mo +0 -0
  168. data/locale/ja/katello.po +179 -164
  169. data/locale/ka/LC_MESSAGES/katello.mo +0 -0
  170. data/locale/ka/katello.po +177 -162
  171. data/locale/katello.pot +1119 -1062
  172. data/locale/kn/katello.po +166 -151
  173. data/locale/ko/LC_MESSAGES/katello.mo +0 -0
  174. data/locale/ko/katello.po +174 -159
  175. data/locale/ml_IN/katello.po +166 -151
  176. data/locale/mr/katello.po +166 -151
  177. data/locale/nl_NL/katello.po +166 -151
  178. data/locale/or/katello.po +166 -151
  179. data/locale/pa/katello.po +166 -151
  180. data/locale/pl/katello.po +166 -151
  181. data/locale/pl_PL/katello.po +166 -151
  182. data/locale/pt/katello.po +166 -151
  183. data/locale/pt_BR/LC_MESSAGES/katello.mo +0 -0
  184. data/locale/pt_BR/katello.po +178 -163
  185. data/locale/ro/katello.po +166 -151
  186. data/locale/ro_RO/katello.po +166 -151
  187. data/locale/ru/LC_MESSAGES/katello.mo +0 -0
  188. data/locale/ru/katello.po +171 -156
  189. data/locale/sl/katello.po +166 -151
  190. data/locale/sv_SE/katello.po +166 -151
  191. data/locale/ta/katello.po +166 -151
  192. data/locale/ta_IN/katello.po +166 -151
  193. data/locale/te/katello.po +166 -151
  194. data/locale/tr/katello.po +166 -151
  195. data/locale/vi/katello.po +166 -151
  196. data/locale/vi_VN/katello.po +166 -151
  197. data/locale/zh/katello.po +166 -151
  198. data/locale/zh_CN/LC_MESSAGES/katello.mo +0 -0
  199. data/locale/zh_CN/katello.po +179 -164
  200. data/locale/zh_TW/LC_MESSAGES/katello.mo +0 -0
  201. data/locale/zh_TW/katello.po +171 -156
  202. data/webpack/ForemanColumnExtensions/index.js +129 -0
  203. data/webpack/components/Table/TableWrapper.js +14 -0
  204. data/webpack/components/extensions/HostDetails/ActionsBar/index.js +1 -1
  205. data/webpack/components/extensions/Hosts/ActionsBar/index.js +20 -1
  206. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/BulkChangeHostCVModal.js +220 -0
  207. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/actions.js +23 -0
  208. data/webpack/components/extensions/Hosts/BulkActions/BulkChangeHostCVModal/index.js +25 -0
  209. data/webpack/components/extensions/Hosts/BulkActions/__tests__/bulkChangeHostCVModal.test.js +133 -0
  210. data/webpack/global_index.js +9 -0
  211. data/webpack/scenes/Hosts/ChangeContentSource/actions.js +3 -1
  212. data/webpack/scenes/Hosts/ChangeContentSource/components/ContentSourceForm.js +62 -24
  213. data/webpack/scenes/Hosts/ChangeContentSource/index.js +24 -16
  214. data/webpack/scenes/RedHatRepositories/__tests__/__snapshots__/RedHatRepositoriesPage.test.js.snap +1 -0
  215. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +64 -5
  216. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +16 -13
  217. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/__snapshots__/UpstreamSubscriptionsPage.test.js.snap +14 -8
  218. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +1 -0
  219. data/webpack/scenes/Subscriptions/components/SubscriptionsToolbar/SubscriptionsToolbar.js +1 -1
  220. metadata +59 -41
  221. data/app/lib/actions/katello/host/upload_package_profile.rb +0 -45
  222. data/app/lib/actions/katello/host/upload_profiles.rb +0 -47
@@ -634,6 +634,7 @@ module Katello
634
634
  check_ready_to_import!
635
635
  else
636
636
  fail _("Import-only content views can not be published directly") if import_only? && !syncable
637
+ check_repositories_blocking_publish!
637
638
  check_composite_action_allowed!(organization.library)
638
639
  check_docker_repository_names!([organization.library])
639
640
  check_orphaned_content_facets!(environments: self.environments)
@@ -642,6 +643,16 @@ module Katello
642
643
  true
643
644
  end
644
645
 
646
+ def check_repositories_blocking_publish!
647
+ blocking_tasks = repositories&.map { |repo| repo.blocking_task }&.compact
648
+
649
+ if blocking_tasks&.any?
650
+ errored_tasks = blocking_tasks.uniq.map { |task| "- #{Setting['foreman_url']}/foreman_tasks/tasks/#{task&.id}" }.join("\n")
651
+ fail _("Pending tasks detected in repositories of this content view. Please wait for the tasks: " +
652
+ errored_tasks + " before publishing.")
653
+ end
654
+ end
655
+
645
656
  def check_docker_repository_names!(environments)
646
657
  environments.each do |environment|
647
658
  repositories = []
@@ -789,6 +800,10 @@ module Katello
789
800
  repositories.any? { |repo| repo.last_indexed && repo.last_indexed > latest_version_object.created_at }
790
801
  end
791
802
 
803
+ def unpublishable?
804
+ default? || import_only? || generated?
805
+ end
806
+
792
807
  def needs_publish?
793
808
  #Returns
794
809
  # True:
@@ -808,7 +823,9 @@ module Katello
808
823
  # a) No changes were detected via audits *and*
809
824
  # Audit for CV publish exists (Audits haven't been cleaned up)
810
825
  # *and* applied_filters field is set(Published after upgrade)
826
+ # b) Default, import only and generated CVs can not be published, hence these will always return false.
811
827
  #
828
+ return false if unpublishable?
812
829
  return true unless latest_version_object
813
830
  return nil unless last_publish_task_success?
814
831
  return composite_cv_components_changed? if composite?
@@ -868,6 +885,17 @@ module Katello
868
885
  filters.present?
869
886
  end
870
887
 
888
+ def blocking_task
889
+ blocking_task_labels = [
890
+ ::Actions::Katello::ContentView::Publish.name
891
+ ]
892
+ ForemanTasks::Task::DynflowTask.where(:label => blocking_task_labels)
893
+ .where.not(state: 'stopped')
894
+ .for_resource(self)
895
+ .order(:started_at)
896
+ .last
897
+ end
898
+
871
899
  protected
872
900
 
873
901
  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
@@ -44,7 +44,7 @@ module Katello
44
44
 
45
45
  validates_with ::AssociationExistsValidator, attributes: [:content_source]
46
46
  validates_with Katello::Validators::GeneratedContentViewValidator
47
- validates_associated :content_view_environment_content_facets
47
+ validates_associated :content_view_environment_content_facets, :message => _("invalid: The content source must sync the lifecycle environment assigned to the host. See the logs for more information.")
48
48
  validates :host, :presence => true, :allow_blank => false
49
49
 
50
50
  attr_accessor :cves_changed
@@ -67,7 +67,7 @@ module Katello
67
67
  self.purpose_addon_ids = consumer_params['addOns'].map { |addon_name| ::Katello::PurposeAddon.find_or_create_by(name: addon_name).id }
68
68
  end
69
69
 
70
- unless consumer_params['releaseVer'].blank?
70
+ unless consumer_params['releaseVer'].nil?
71
71
  release = consumer_params['releaseVer']
72
72
  release = release['releaseVer'] if release.is_a?(Hash)
73
73
  self.release_version = release
@@ -2,7 +2,7 @@ module Katello
2
2
  class Ping
3
3
  OK_RETURN_CODE = 'ok'.freeze
4
4
  FAIL_RETURN_CODE = 'FAIL'.freeze
5
- PACKAGES = %w(katello candlepin pulp foreman hammer).freeze
5
+ PACKAGES = %w(katello candlepin pulp foreman hammer dynflow).freeze
6
6
 
7
7
  class << self
8
8
  def services(capsule_id = nil)
@@ -651,6 +651,33 @@ module Katello
651
651
  for_resource(self).order(:started_at).last
652
652
  end
653
653
 
654
+ def blocking_task
655
+ blocking_task_labels = [
656
+ ::Actions::Katello::Repository::Sync.name,
657
+ ::Actions::Katello::Repository::UploadFiles.name,
658
+ ::Actions::Katello::Repository::RemoveContent.name,
659
+ ::Actions::Katello::Repository::MetadataGenerate.name
660
+ ]
661
+ ForemanTasks::Task::DynflowTask.where(:label => blocking_task_labels)
662
+ .where.not(state: 'stopped')
663
+ .for_resource(self)
664
+ .order(:started_at)
665
+ .last
666
+ end
667
+
668
+ def check_ready_to_act!
669
+ blocking_tasks = content_views&.map { |cv| cv.blocking_task }&.compact
670
+
671
+ if blocking_tasks&.any?
672
+ errored_tasks = blocking_tasks
673
+ .uniq
674
+ .map { |task| "- #{Setting['foreman_url']}/foreman_tasks/tasks/#{task&.id}" }
675
+ .join("\n")
676
+ fail _("This repository has pending tasks in associated content views. Please wait for the tasks: " + errored_tasks +
677
+ " to complete before proceeding.")
678
+ end
679
+ end
680
+
654
681
  # returns other instances of this repo with the same library
655
682
  # equivalent of repo
656
683
  def environmental_instances(view)
@@ -387,10 +387,6 @@ module Katello
387
387
  Katello::RepositoryTypeManager.generic_repository_types(false).values.map(&:id).map(&:to_s).flatten.include? self.content_type
388
388
  end
389
389
 
390
- def metadata_generate_needed?
391
- (%w(unprotected checksum_type container_repsoitory_name) & previous_changes.keys).any?
392
- end
393
-
394
390
  def using_mirrored_content?
395
391
  self.mirroring_policy != Katello::RootRepository::MIRRORING_POLICY_ADDITIVE
396
392
  end
@@ -55,6 +55,15 @@ module Katello
55
55
  end
56
56
  end
57
57
 
58
+ def reimport_units
59
+ units_from_pulp.each do |units|
60
+ to_update = units.map do |unit|
61
+ @service_class.generate_model_row(unit)
62
+ end
63
+ @model_class.upsert_all(to_update, unique_by: :pulp_id)
64
+ end
65
+ end
66
+
58
67
  def import_associations(units)
59
68
  pulp_id_to_id = self.class.pulp_id_to_id_map(@content_type, units.map { |unit| unit[@service_class.unit_identifier] })
60
69
  @service_class.insert_child_associations(units, pulp_id_to_id) if @service_class.respond_to?(:insert_child_associations)
@@ -88,18 +88,16 @@ module Katello
88
88
  end
89
89
 
90
90
  def get_remote(href = smart_proxy_acs.remote_href)
91
- acs.base_url&.start_with?('uln') ? api.remotes_uln_api.read(href) : api.remotes_api.read(href)
91
+ api.get_remotes_api(href: href).read(href)
92
92
  end
93
93
 
94
- def update_remote
95
- api.remotes_api.partial_update(smart_proxy_acs.remote_href, remote_options)
94
+ def update_remote(href = smart_proxy_acs.remote_href)
95
+ api.get_remotes_api(href: href).partial_update(href, remote_options)
96
96
  end
97
97
 
98
- # The old repo URL is needed to determine which remote API to use.
99
98
  def delete_remote(options = {})
100
99
  options[:href] ||= smart_proxy_acs.remote_href
101
- options[:old_url] ||= remote_options[:url]
102
- ignore_404_exception { options[:old_url]&.start_with?('uln') ? api.remotes_uln_api.delete(options[:href]) : api.remotes_api.delete(options[:href]) } if options[:href]
100
+ ignore_404_exception { api.get_remotes_api(href: options[:href]).delete(options[:href]) } if options[:href]
103
101
  end
104
102
 
105
103
  def create
@@ -47,6 +47,11 @@ module Katello
47
47
  fail NotImplementedError
48
48
  end
49
49
 
50
+ # Method is called with either :url or :href parameters for the sake of yum content.
51
+ def get_remotes_api(*)
52
+ remotes_api
53
+ end
54
+
50
55
  def publications_api
51
56
  repository_type.publications_api_class.new(api_client) #Optional
52
57
  end
@@ -136,6 +141,10 @@ module Katello
136
141
  client
137
142
  end
138
143
 
144
+ def repair_api
145
+ PulpcoreClient::RepairApi.new(core_api_client)
146
+ end
147
+
139
148
  def uploads_api
140
149
  PulpcoreClient::UploadsApi.new(core_api_client)
141
150
  end
@@ -230,6 +239,10 @@ module Katello
230
239
  end
231
240
  end
232
241
 
242
+ def repair
243
+ repair_api.post(PulpcoreClient::Repair.new(verify_checksums: true))
244
+ end
245
+
233
246
  def self.fetch_from_list
234
247
  page_size = Setting[:bulk_load_size]
235
248
  page_opts = { "offset" => 0, limit: page_size }
@@ -32,6 +32,17 @@ module Katello
32
32
  PulpRpmClient::RemotesUlnApi.new(api_client)
33
33
  end
34
34
 
35
+ def get_remotes_api(href: nil, url: nil)
36
+ fail 'Provide exactly one of href or url for yum remote selection!' if url.blank? && href.blank?
37
+ fail 'The href must be a pulp_rpm remote href!' if href && !href.start_with?('/pulp/api/v3/remotes/rpm/')
38
+
39
+ if href&.start_with?('/pulp/api/v3/remotes/rpm/uln/') || url&.start_with?('uln')
40
+ remotes_uln_api
41
+ else
42
+ remotes_api
43
+ end
44
+ end
45
+
35
46
  def copy_api
36
47
  PulpRpmClient::RpmCopyApi.new(api_client)
37
48
  end
@@ -26,7 +26,11 @@ module Katello
26
26
  {
27
27
  schema_version: unit['schema_version'],
28
28
  digest: unit['digest'],
29
- pulp_id: unit[unit_identifier]
29
+ pulp_id: unit[unit_identifier],
30
+ annotations: unit['annotations'],
31
+ labels: unit['labels'],
32
+ is_bootable: unit['is_bootable'],
33
+ is_flatpak: unit['is_flatpak']
30
34
  }
31
35
  end
32
36
  end
@@ -3,7 +3,7 @@ module Katello
3
3
  class Repository
4
4
  class Generic < ::Katello::Pulp3::Repository
5
5
  def copy_content_for_source(source_repository, _options = {})
6
- copy_units_by_href(source_repository.files.pluck(:pulp_id))
6
+ copy_units_by_href(source_repository.generic_content_units&.pluck(:pulp_id))
7
7
  end
8
8
 
9
9
  def distribution_options(path)
@@ -91,16 +91,21 @@ module Katello
91
91
  end
92
92
 
93
93
  def remote_partial_update
94
- if remote_options[:url]&.start_with?('uln')
95
- api.remotes_uln_api.partial_update(repo.remote_href, remote_options)
96
- else
97
- api.remotes_api.partial_update(repo.remote_href, remote_options)
94
+ url_type = remote_options[:url]&.start_with?('uln') ? 'uln' : 'default'
95
+ remote_type = repo.remote_href.start_with?('/pulp/api/v3/remotes/rpm/uln/') ? 'uln' : 'default'
96
+ href = repo.remote_href
97
+
98
+ if url_type == remote_type
99
+ api.get_remotes_api(href: href).partial_update(href, remote_options)
100
+ else # We need to recreate a remote of the correct type!
101
+ create_remote
102
+ delete_remote(href: href)
98
103
  end
99
104
  end
100
105
 
101
106
  def delete_remote(options = {})
102
107
  options[:href] ||= repo.remote_href
103
- ignore_404_exception { remote_options[:url]&.start_with?('uln') ? api.remotes_uln_api.delete(options[:href]) : api.remotes_api.delete(options[:href]) } if options[:href]
108
+ ignore_404_exception { api.get_remotes_api(href: options[:href]).delete(options[:href]) } if options[:href]
104
109
  end
105
110
 
106
111
  def self.instance_for_type(repo, smart_proxy)
@@ -139,7 +144,7 @@ module Katello
139
144
  end
140
145
 
141
146
  def get_remote(href = repo.remote_href)
142
- repo.url&.start_with?('uln') ? api.remotes_uln_api.read(href) : api.remotes_api.read(href)
147
+ api.get_remotes_api(href: href).read(href)
143
148
  end
144
149
 
145
150
  def get_distribution(href = distribution_reference.href)
@@ -210,6 +215,10 @@ module Katello
210
215
  api.publications_api.create(publication_data)
211
216
  end
212
217
 
218
+ def delete_publication
219
+ ignore_404_exception { api.publications_api.delete(repo.publication_href) } if repo.publication_href
220
+ end
221
+
213
222
  def publication_options(repository_version)
214
223
  {
215
224
  repository_version: repository_version
@@ -329,6 +338,17 @@ module Katello
329
338
 
330
339
  def delete_version
331
340
  ignore_404_exception { api.repository_versions_api.delete(repo.version_href) } unless version_zero?
341
+ rescue api.api_exception_class => e
342
+ if e.message.include?("are currently being used to distribute content")
343
+ Rails.logger.warn "Exception when calling repository_versions_api->delete: #{e}"
344
+ publication_href = repo.publication_href
345
+ Rails.logger.warn "Trying to delete publication #{publication_href} for repository #{repo.id}}"
346
+ Rails.logger.error "Could not delete version: #{repo.version_href} because conflicting publication could not be looked up" unless publication_href
347
+ if publication_href
348
+ ignore_404_exception { api.publications_api.delete(publication_href) }
349
+ ignore_404_exception { api.repository_versions_api.delete(repo.version_href) }
350
+ end
351
+ end
332
352
  end
333
353
 
334
354
  def create_version(options = {})
@@ -24,11 +24,9 @@ module Katello
24
24
  def refresh_entities
25
25
  href = remote_href
26
26
  if href
27
- if remote_options[:url]&.start_with?('uln')
28
- [api.remotes_uln_api.partial_update(href, remote_options)]
29
- else
30
- [api.remotes_api.partial_update(href, remote_options)]
31
- end
27
+ # Do not consider remotes_uln_api, since the Katello server is not a ULN server. Even if the sync
28
+ # to Katello used ULN, the sync from Katello server to smart proxy will use a normal RPM remote!
29
+ [api.remotes_api.partial_update(href, remote_options)]
32
30
  else
33
31
  create_remote
34
32
  []
@@ -111,13 +109,10 @@ module Katello
111
109
  end
112
110
 
113
111
  def create_remote
114
- if remote_options[:url]&.start_with?('uln')
115
- remote_file_data = @repo_service.api.class.remote_uln_class.new(remote_options)
116
- api.remotes_uln_api.create(remote_file_data)
117
- else
118
- remote_file_data = @repo_service.api.remote_class.new(remote_options)
119
- api.remotes_api.create(remote_file_data)
120
- end
112
+ # Do not consider remotes_uln_api, since the Katello server is not a ULN server. Even if the sync
113
+ # to Katello used ULN, the sync from Katello server to smart proxy will use a normal RPM remote!
114
+ remote_file_data = @repo_service.api.remote_class.new(remote_options)
115
+ api.remotes_api.create(remote_file_data)
121
116
  end
122
117
 
123
118
  def compute_remote_options
@@ -240,6 +235,12 @@ module Katello
240
235
  distribution_data = api.distribution_class.new(distribution_options(path))
241
236
  repo_service.distributions_api.create(distribution_data)
242
237
  end
238
+
239
+ def repair
240
+ data = api.repair_class.new
241
+ fail "Could not lookup a version_href for repo #{repo_service.repo.id}" if version_href.nil?
242
+ api.repository_versions_api.repair(version_href, data)
243
+ end
243
244
  end
244
245
  end
245
246
  end
@@ -9,11 +9,7 @@ module Katello
9
9
  remote_file_data = api.remote_class.new(remote_options)
10
10
  end
11
11
  reformat_api_exception do
12
- if remote_options[:url]&.start_with?('uln')
13
- response = api.remotes_uln_api.create(remote_file_data)
14
- else
15
- response = api.remotes_api.create(remote_file_data)
16
- end
12
+ response = api.get_remotes_api(url: remote_options[:url]).create(remote_file_data)
17
13
  end
18
14
  response
19
15
  end
@@ -37,11 +33,7 @@ module Katello
37
33
  end
38
34
 
39
35
  reformat_api_exception do
40
- if remote_options[:url]&.start_with?('uln')
41
- response = api.remotes_uln_api.create(remote_file_data)
42
- else
43
- response = api.remotes_api.create(remote_file_data)
44
- end
36
+ response = api.get_remotes_api(url: remote_options[:url]).create(remote_file_data)
45
37
  #delete is async, but if its not properly deleted, orphan cleanup will take care of it later
46
38
  delete_remote(href: response.pulp_href)
47
39
  end
@@ -35,13 +35,11 @@ module Katello
35
35
 
36
36
  def delete_orphan_repository_versions
37
37
  tasks = []
38
-
39
38
  orphan_repository_versions.each do |api, version_hrefs|
40
39
  tasks << version_hrefs.collect do |href|
41
40
  api.repository_versions_api.delete(href)
42
41
  end
43
42
  end
44
-
45
43
  tasks.flatten
46
44
  end
47
45
 
@@ -0,0 +1,75 @@
1
+ module Katello
2
+ module UINotifications
3
+ module Subscriptions
4
+ class ManifestExpireSoonWarning
5
+ class << self
6
+ def deliver!
7
+ ::Organization.unscoped.all.each do |organization|
8
+ if (notification = existing_notification(organization))
9
+ days_remaining = organization.manifest_expire_days_remaining
10
+ if days_remaining == 0 || days_remaining > Setting[:expire_soon_days].to_i
11
+ # if the manifest has already expired, delete the notification;
12
+ # user will have a ManifestExpiredWarning instead.
13
+ # If user changes the expire_soon_days setting, remove notifications
14
+ # that are no longer relevant.
15
+ Rails.logger.debug("ManifestExpireSoonWarning: deleting notification for #{organization.name}")
16
+ notification.destroy
17
+ next
18
+ end
19
+ # don't update if the message hasn't changed
20
+ next unless message(organization).to_s !=
21
+ notification.message.to_s
22
+ notification.update(
23
+ :message => message(organization),
24
+ :actions => actions
25
+ )
26
+ else
27
+ next unless organization.manifest_expiring_soon?
28
+ ::Notification.create!(
29
+ :subject => organization,
30
+ :initiator => User.anonymous_admin,
31
+ :audience => Notification::AUDIENCE_SUBJECT,
32
+ :message => message(organization),
33
+ :actions => actions,
34
+ :notification_blueprint => blueprint
35
+ )
36
+ end
37
+ end
38
+ end
39
+
40
+ def existing_notification(subject)
41
+ matching_notification = Notification.unscoped.find_by(:subject => subject, :notification_blueprint => blueprint)
42
+ return false if matching_notification.blank?
43
+ matching_notification
44
+ end
45
+
46
+ def message(organization)
47
+ ::UINotifications::StringParser.new(
48
+ blueprint.message,
49
+ :manifest_expire_date => organization.manifest_expiration_date&.to_date,
50
+ :subject => organization,
51
+ :days_remaining => organization.manifest_expire_days_remaining
52
+ )
53
+ end
54
+
55
+ def actions
56
+ {
57
+ :links => [
58
+ {
59
+ :href => "/subscriptions",
60
+ :title => _('Subscriptions'),
61
+ :external => false
62
+ }
63
+ ]
64
+ }
65
+ end
66
+
67
+ def blueprint
68
+ @blueprint ||= NotificationBlueprint.unscoped.find_by(
69
+ :name => 'manifest_expire_soon_warning')
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -13,4 +13,8 @@ provider_type: Ansible
13
13
  kind: job_template
14
14
  %>
15
15
 
16
- <%= render_template('Run Command - Ansible Default', :command => "yum -y update #{input('package')}") %>
16
+ <%
17
+ pkgs = input('package')
18
+ pkgs = '"*"' if pkgs.empty?
19
+ -%>
20
+ <%= render_template('Package Action - Ansible Default', :state => 'latest', :name => pkgs) %>
@@ -3,7 +3,7 @@ kind: job_template
3
3
  name: Update packages by search query - Katello Ansible Default
4
4
  job_category: Katello
5
5
  description_format: 'Update package(s) %{Packages search query}'
6
- feature: katello_package_remove_by_search
6
+ feature: katello_package_update_by_search
7
7
  provider_type: Ansible
8
8
  template_inputs:
9
9
  - name: Packages search query
@@ -22,7 +22,7 @@ template_inputs:
22
22
  versions: input('Selected update versions')
23
23
  ) -%>
24
24
  <% if package_names.empty? -%>
25
- <%= render_template('Run Command - Ansible Default', :command => "yum -y update") %>
25
+ <%= render_template('Package Action - Ansible Default', :state => 'latest', :name => '"*"') %>
26
26
  <% else -%>
27
27
  ---
28
28
  - hosts: all
@@ -0,0 +1,16 @@
1
+ <%#
2
+ kind: job_template
3
+ name: Upload profile - Katello Script Default
4
+ job_category: Katello
5
+ model: JobTemplate
6
+ provider_type: script
7
+ description_format: Upload package profile for a host
8
+ feature: katello_upload_profile
9
+ %>
10
+ #!/bin/sh
11
+ <% if @host.operatingsystem.family == 'Redhat' -%>
12
+ dnf uploadprofile --force-upload
13
+ <% else -%>
14
+ package-profile-upload --force-upload
15
+ <% end -%>
16
+ subscription-manager repos
@@ -15,4 +15,13 @@ attributes :architecture, :if => lambda { |rule| rule.respond_to?(:architecture)
15
15
  attributes :types, :if => lambda { |rule| rule.respond_to?(:types) && !rule.types.blank? }
16
16
  attributes :date_type, :if => lambda { |rule| rule.respond_to?(:date_type) }
17
17
  attributes :module_stream_id, :if => lambda { |rule| rule.respond_to?(:module_stream_id) && !rule.module_stream_id.blank? }
18
+ if @resource&.try(:module_stream)
19
+ node :module_stream do |rule|
20
+ {
21
+ :module_stream_id => rule.module_stream.id,
22
+ :module_stream_name => rule.module_stream.name,
23
+ :module_stream_stream => rule.module_stream.stream
24
+ }
25
+ end
26
+ end
18
27
  extends 'katello/api/v2/common/timestamps'