katello 3.16.0.rc2.1 → 3.16.0.rc5

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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +2 -2
  3. data/app/controllers/katello/api/v2/api_controller.rb +9 -4
  4. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +3 -0
  5. data/app/controllers/katello/api/v2/content_views_controller.rb +7 -0
  6. data/app/controllers/katello/api/v2/subscriptions_controller.rb +1 -1
  7. data/app/controllers/katello/api/v2/upstream_subscriptions_controller.rb +13 -1
  8. data/app/controllers/katello/concerns/api/v2/associations_permission_check.rb +67 -0
  9. data/app/controllers/katello/concerns/hosts_controller_extensions.rb +11 -0
  10. data/app/lib/actions/katello/capsule_content/refresh_repos.rb +4 -0
  11. data/app/lib/actions/katello/capsule_content/sync.rb +0 -4
  12. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +16 -16
  13. data/app/lib/actions/katello/content_view/incremental_updates.rb +5 -0
  14. data/app/lib/actions/katello/content_view/presenters/incremental_updates_presenter.rb +2 -1
  15. data/app/lib/actions/katello/content_view_version/incremental_update.rb +90 -26
  16. data/app/lib/actions/katello/host/upload_profiles.rb +20 -11
  17. data/app/lib/actions/pulp/abstract_async_task.rb +1 -0
  18. data/app/lib/actions/pulp/consumer/sync_capsule.rb +8 -0
  19. data/app/lib/actions/pulp/repository/presenters/deb_presenter.rb +2 -2
  20. data/app/lib/actions/pulp3/repository/multi_copy_units.rb +48 -0
  21. data/app/lib/actions/pulp3/repository/save_versions.rb +39 -0
  22. data/app/lib/katello/concerns/base_template_scope_extensions.rb +4 -14
  23. data/app/lib/katello/errors.rb +25 -0
  24. data/app/lib/katello/logging.rb +14 -0
  25. data/app/lib/katello/resources/candlepin.rb +1 -1
  26. data/app/lib/katello/resources/candlepin/upstream_consumer.rb +6 -0
  27. data/app/models/katello/concerns/host_managed_extensions.rb +7 -0
  28. data/app/models/katello/concerns/http_proxy_extensions.rb +30 -7
  29. data/app/models/katello/concerns/organization_extensions.rb +14 -0
  30. data/app/models/katello/glue/candlepin/candlepin_object.rb +9 -5
  31. data/app/models/katello/glue/candlepin/pool.rb +7 -2
  32. data/app/models/katello/glue/provider.rb +11 -4
  33. data/app/models/katello/glue/pulp/repo.rb +1 -0
  34. data/app/models/katello/host/content_facet.rb +11 -6
  35. data/app/models/katello/pool.rb +1 -1
  36. data/app/models/katello/pulp3/content_guard.rb +1 -1
  37. data/app/models/katello/rhsm_fact_parser.rb +4 -0
  38. data/app/models/katello/root_repository.rb +1 -1
  39. data/app/models/setting/content.rb +3 -1
  40. data/app/services/katello/candlepin/message_handler.rb +2 -3
  41. data/app/services/katello/pulp3/repository.rb +8 -1
  42. data/app/services/katello/pulp3/repository/yum.rb +44 -15
  43. data/app/services/katello/pulp3/rpm.rb +3 -2
  44. data/app/services/katello/ui_notifications/subscriptions/manifest_expired_warning.rb +20 -8
  45. data/app/services/katello/upstream_connection_checker.rb +48 -0
  46. data/app/views/katello/api/v2/srpms/backend.json.rabl +11 -0
  47. data/app/views/katello/api/v2/srpms/base.json.rabl +5 -0
  48. data/app/views/katello/api/v2/srpms/compare.json.rabl +10 -0
  49. data/app/views/katello/api/v2/srpms/index.json.rabl +1 -1
  50. data/app/views/katello/api/v2/srpms/show.json.rabl +3 -3
  51. data/config/routes/api/v2.rb +2 -0
  52. data/db/migrate/20200526200422_encrypt_root_repository_upstream_password.rb +2 -0
  53. data/db/seeds.d/109-katello-notification-blueprints.rb +1 -1
  54. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-repository-sets.html +1 -1
  55. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/versions/content-view-version.factory.js +2 -2
  56. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/errata.routes.js +1 -1
  57. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +367 -450
  58. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +427 -499
  59. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +434 -543
  60. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +434 -558
  61. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +425 -499
  62. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +441 -534
  63. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +425 -493
  64. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +434 -542
  65. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +425 -493
  66. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +441 -524
  67. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +427 -500
  68. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/translations.js +10 -10
  69. data/engines/bastion_katello/app/assets/stylesheets/bastion_katello/bastion_katello.scss +4 -0
  70. data/lib/katello/engine.rb +0 -1
  71. data/lib/katello/permission_creator.rb +1 -1
  72. data/lib/katello/plugin.rb +2 -0
  73. data/lib/katello/version.rb +1 -1
  74. data/locale/action_names.rb +33 -33
  75. data/locale/bn/katello.po +12 -0
  76. data/locale/cs/katello.po +12 -0
  77. data/locale/de/katello.po +12 -0
  78. data/locale/en/katello.po +12 -0
  79. data/locale/es/katello.po +12 -0
  80. data/locale/fr/katello.po +12 -0
  81. data/locale/gu/katello.po +12 -0
  82. data/locale/hi/katello.po +12 -0
  83. data/locale/it/katello.po +12 -0
  84. data/locale/ja/katello.po +12 -0
  85. data/locale/katello.pot +154 -137
  86. data/locale/kn/katello.po +12 -0
  87. data/locale/ko/katello.po +12 -0
  88. data/locale/mr/katello.po +12 -0
  89. data/locale/or/katello.po +12 -0
  90. data/locale/pa/katello.po +12 -0
  91. data/locale/pt/katello.po +12 -0
  92. data/locale/pt_BR/katello.po +12 -0
  93. data/locale/ru/katello.po +12 -0
  94. data/locale/ta/katello.po +12 -0
  95. data/locale/te/katello.po +12 -0
  96. data/locale/zh_CN/katello.po +12 -0
  97. data/locale/zh_TW/katello.po +12 -0
  98. data/package.json +3 -3
  99. data/webpack/components/Content/ContentTable.js +2 -0
  100. data/webpack/components/Content/Details/ContentDetails.js +3 -0
  101. data/webpack/global_test_setup.js +3 -0
  102. data/webpack/scenes/AnsibleCollections/Details/AnsibleCollectionDetails.js +3 -0
  103. data/webpack/scenes/ModuleStreams/Details/ModuleStreamDetails.js +3 -0
  104. data/webpack/scenes/RedHatRepositories/RedHatRepositoriesPage.js +2 -0
  105. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/EnabledRepository.js +2 -0
  106. data/webpack/scenes/RedHatRepositories/components/RepositorySetRepository/RepositorySetRepository.js +2 -0
  107. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailAssociations.js +2 -0
  108. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProductContent.js +2 -0
  109. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProducts.js +2 -0
  110. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +2 -0
  111. data/webpack/scenes/Subscriptions/SubscriptionActions.js +8 -8
  112. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +3 -1
  113. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +15 -1
  114. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +54 -7
  115. data/webpack/scenes/Subscriptions/SubscriptionsSelectors.js +3 -0
  116. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsActions.js +15 -1
  117. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/{UpstreamSubscriptionsContstants.js → UpstreamSubscriptionsConstants.js} +3 -0
  118. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +2 -0
  119. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsReducer.js +1 -1
  120. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsReducer.test.js +1 -1
  121. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsActions.test.js +0 -13
  122. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +6 -1
  123. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +6 -4
  124. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsReducer.test.js.snap +26 -25
  125. data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +0 -58
  126. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +10 -4
  127. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +1 -0
  128. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +1 -68
  129. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Dialogs/UpdateDialog.js +1 -1
  130. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Dialogs/index.js +4 -4
  131. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Table.js +12 -10
  132. data/webpack/scenes/Subscriptions/index.js +6 -3
  133. data/webpack/test-utils/nockWrapper.js +1 -1
  134. metadata +32 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07abcc2d0e780bd3bfee4cd44b73ef4183e0a50daebe6a32cd056e162e3fde52
4
- data.tar.gz: 6c95fe44a013f6e74d36098c3e96f8e669f5670925620a9dc26e6ed674cc2abb
3
+ metadata.gz: d0972a0ce2e400210de115168dd9b0119d5d738eacc73f4854406df2abf853e5
4
+ data.tar.gz: 102cafbfe169374c46933f8a11487ba06d36c029b08fb88cb2857bd9cc0faa59
5
5
  SHA512:
6
- metadata.gz: 17dece7796e9c33d88970ed5eaba5d810db5b84c76ddc03d0767c8bf426013ac9c3e29f14a3bb3be6663e0233e8968551294f51000fb4161e348028add9ecb0b
7
- data.tar.gz: c8b139917779fb48e642270141eb4418c4f668433307cb8097661b581985edc7163f67524328f13368c5cf80d7fc51ef2c856816eacb19ff9a720f40cef595d8
6
+ metadata.gz: 2ffe9b0201453156e10c992b0363feba8079d47b7be06e263b7f9fb9ae333569684532712a7eafe60ea0ae790ee7e512128a0b39051c6c07c5af11c3bb37ad3e
7
+ data.tar.gz: d30abd4cef90402f90122b412451c5dbdafc11da644363e176623f8f37d6f27e5774783c31cd1b6dd9791f208f8177913eae86fc3b4b087de725bb4501c8828f
@@ -268,8 +268,8 @@ module Katello
268
268
  end
269
269
 
270
270
  def get_parent_host(headers)
271
- hostnames = headers["HTTP_X_FORWARDED_SERVER"]
272
- host = hostnames.split(",")[0] if hostnames
271
+ hostnames = headers["HTTP_X_FORWARDED_HOST"]
272
+ host = hostnames.split(/[\,,:]/)[0].strip if hostnames
273
273
  host || URI.parse(Setting[:foreman_url]).host
274
274
  end
275
275
 
@@ -5,6 +5,7 @@ module Katello
5
5
  include Api::V2::Rendering
6
6
  include Api::V2::ErrorHandling
7
7
  include ::Foreman::Controller::CsvResponder
8
+ include Concerns::Api::V2::AssociationsPermissionCheck
8
9
 
9
10
  # support for session (thread-local) variables must be the last filter in this class
10
11
  include Foreman::ThreadSession::Cleaner
@@ -211,10 +212,14 @@ module Katello
211
212
  fail HttpErrors::BadRequest, _("Host has not been registered with subscription-manager") if @host.subscription_facet.nil?
212
213
  end
213
214
 
214
- def check_disconnected
215
- msg = "You are currently operating in disconnected mode where access to Red Hat Subcription Management " \
216
- "is prohibited. If you would like to change this, please update the content setting 'Disconnected mode'."
217
- fail HttpErrors::BadRequest, _(msg) if Setting[:content_disconnected]
215
+ def check_upstream_connection
216
+ checker = Katello::UpstreamConnectionChecker.new(@organization)
217
+
218
+ begin
219
+ checker.assert_connection
220
+ rescue => e
221
+ raise HttpErrors::BadRequest, e.message
222
+ end
218
223
  end
219
224
  end
220
225
  end
@@ -143,6 +143,9 @@ module Katello
143
143
  end
144
144
  end
145
145
  def incremental_update
146
+ if params[:add_content].values.flatten.empty?
147
+ fail HttpErrors::BadRequest, _("Incremental update requires at least one content unit")
148
+ end
146
149
  any_environments = params[:content_view_version_environments].any? { |cvve| cvve[:environment_ids].try(:any?) }
147
150
  if params[:add_content]&.key?(:errata_ids) && params[:update_hosts] && any_environments
148
151
  hosts = calculate_hosts_for_incremental(params[:update_hosts], params[:propagate_to_composites])
@@ -22,6 +22,13 @@ module Katello
22
22
  param :solve_dependencies, :bool, :desc => N_("Solve RPM dependencies by default on Content View publish, defaults to false")
23
23
  end
24
24
 
25
+ def filtered_associations
26
+ {
27
+ :component_ids => Katello::ContentViewVersion,
28
+ :repository_ids => Katello::Repository
29
+ }
30
+ end
31
+
25
32
  api :GET, "/organizations/:organization_id/content_views", N_("List content views")
26
33
  api :GET, "/content_views", N_("List content views")
27
34
  param :organization_id, :number, :desc => N_("organization identifier")
@@ -7,7 +7,7 @@ module Katello
7
7
  before_action :find_optional_organization, :only => [:index, :available, :show]
8
8
  before_action :find_organization, :only => [:upload, :delete_manifest,
9
9
  :refresh_manifest, :manifest_history]
10
- before_action :check_disconnected, only: [:refresh_manifest]
10
+ before_action :check_upstream_connection, only: [:refresh_manifest]
11
11
  before_action :find_provider
12
12
 
13
13
  skip_before_action :check_content_type, :only => [:upload]
@@ -1,6 +1,7 @@
1
1
  module Katello
2
2
  class Api::V2::UpstreamSubscriptionsController < Api::V2::ApiController
3
- before_action :check_disconnected
3
+ before_action :find_organization
4
+ before_action :check_upstream_connection
4
5
 
5
6
  resource_description do
6
7
  description "Red Hat subscriptions management platform."
@@ -65,6 +66,17 @@ module Katello
65
66
  respond_for_async resource: task
66
67
  end
67
68
 
69
+ api :GET, "/organizations/:organization_id/upstream_subscriptions/ping",
70
+ N_("Check if a connection can be made to Red Hat Subscription Management.")
71
+ def ping
72
+ # This API raises an error if:
73
+ # - Katello is in disconnected mode
74
+ # - There is no manifest imported
75
+ # - The local manifest identity certs have expired
76
+ # - The manifest has been deleted upstream
77
+ render json: { status: 'OK' }
78
+ end
79
+
68
80
  private
69
81
 
70
82
  def update_params
@@ -0,0 +1,67 @@
1
+ module Katello
2
+ module Concerns
3
+ module Api::V2::AssociationsPermissionCheck
4
+ extend ActiveSupport::Concern
5
+
6
+ # The purpose of this module is to protect a controller from a user creating or updating some association
7
+ # when they do not have permissions to view the associated items. An example would be adding random repository ids to
8
+ # content view.
9
+ # To support this, within the controller define a method such as:
10
+ # def filtered_associations
11
+ # {
12
+ # :component_ids => Katello::ContentViewVersion,
13
+ # :repository_ids => Katello::Repository
14
+ # }
15
+ # end
16
+ # This assumes that the parameters are 'wrapped'. So the above in the content_views_controller, actually looks at
17
+ # a subhash of 'content_view'
18
+
19
+ included do
20
+ before_action :check_association_ids, :only => [:create, :update]
21
+ end
22
+
23
+ def check_association_ids
24
+ if filtered_associations
25
+ wrapped_params = params[self._wrapper_options.name]
26
+ find_param_arrays(wrapped_params).each do |key_path|
27
+ if (model_class = filtered_associations.with_indifferent_access.dig(*key_path))
28
+ param_ids = wrapped_params.dig(*key_path)
29
+ filtered_ids = model_class.readable.where(:id => param_ids).pluck(:id)
30
+ if (unfound_ids = param_ids_missing(param_ids, filtered_ids)).any?
31
+ fail HttpErrors::NotFound, _("One or more ids (%{ids}) were not found for %{assoc}. You may not have permissions to see them.") %
32
+ {ids: unfound_ids, assoc: key_path.last}
33
+ end
34
+ else
35
+ fail _("Unfiltered params array: %s.") % key_path
36
+ end
37
+ end
38
+ else
39
+ Rails.logger.warn("#{self.class.name} may has unprotected associations, see associations_permission_check.rb for details.") if ENV['RAILS_ENV'] == 'development'
40
+ end
41
+ end
42
+
43
+ def filtered_associations
44
+ #should return {} when supported by all controllers
45
+ nil
46
+ end
47
+
48
+ def param_ids_missing(param_ids, filtered_ids)
49
+ param_ids.map(&:to_i).uniq - filtered_ids.map(&:to_i).uniq
50
+ end
51
+
52
+ #returns an array of list of keys pointing to an array in a params hash i.e.:
53
+ # {"a"=> {"b" => [3]}} => [["a", "b"]]
54
+ def find_param_arrays(hash = params)
55
+ list_of_paths = []
56
+ hash.each do |key, value|
57
+ if value.is_a?(ActionController::Parameters) || value.is_a?(Hash)
58
+ list_of_paths += find_param_arrays(value).compact.map { |inner_keys| [key] + inner_keys }
59
+ elsif value.is_a?(Array)
60
+ list_of_paths << [key]
61
+ end
62
+ end
63
+ list_of_paths.compact
64
+ end
65
+ end
66
+ end
67
+ end
@@ -18,6 +18,17 @@ module Katello
18
18
  included do
19
19
  prepend Overrides
20
20
 
21
+ def update_multiple_taxonomies(type)
22
+ registered_host = @hosts.detect { |host| host.subscription_facet }
23
+ unless registered_host.nil?
24
+ error _("Unregister host %s before assigning an organization") % registered_host.name
25
+ redirect_back_or_to hosts_path
26
+ return
27
+ end
28
+
29
+ super
30
+ end
31
+
21
32
  def destroy
22
33
  if Katello::RegistrationManager.unregister_host(@host, :unregistering => false)
23
34
  process_success redirection_url_on_host_deletion
@@ -10,6 +10,10 @@ module Actions
10
10
  fail NotImplementedError
11
11
  end
12
12
 
13
+ def rescue_strategy
14
+ Dynflow::Action::Rescue::Skip if self.state == 'error'
15
+ end
16
+
13
17
  def plan(smart_proxy, options = {})
14
18
  plan_self(:smart_proxy_id => smart_proxy.id,
15
19
  :environment_id => options[:environment]&.id,
@@ -44,10 +44,6 @@ module Actions
44
44
  plan_action(SyncCapsule, smart_proxy, refresh_options)
45
45
  end
46
46
  end
47
-
48
- def rescue_strategy
49
- Dynflow::Action::Rescue::Skip
50
- end
51
47
  end
52
48
  end
53
49
  end
@@ -11,19 +11,23 @@ module Actions
11
11
  skip_metadata_check = options.fetch(:skip_metadata_check, false)
12
12
 
13
13
  smart_proxy_helper = ::Katello::SmartProxyHelper.new(smart_proxy)
14
- concurrence do
15
- smart_proxy_helper.repos_available_to_capsule(environment, content_view, repository).each do |repo|
16
- plan_pulp_action([Actions::Pulp::Orchestration::Repository::SmartProxySync,
17
- Actions::Pulp3::CapsuleContent::Sync],
18
- repo, smart_proxy,
19
- skip_metadata_check: skip_metadata_check)
14
+ sequence do
15
+ smart_proxy_helper.repos_available_to_capsule(environment, content_view, repository).in_groups_of(Setting[:foreman_proxy_content_batch_size], false) do |repos|
16
+ concurrence do
17
+ repos.each do |repo|
18
+ plan_pulp_action([Actions::Pulp::Orchestration::Repository::SmartProxySync,
19
+ Actions::Pulp3::CapsuleContent::Sync],
20
+ repo, smart_proxy,
21
+ skip_metadata_check: skip_metadata_check)
20
22
 
21
- if repo.is_a?(::Katello::Repository) &&
22
- repo.distribution_bootable? &&
23
- repo.download_policy == ::Runcible::Models::YumImporter::DOWNLOAD_ON_DEMAND
24
- plan_action(Katello::Repository::FetchPxeFiles,
25
- id: repo.id,
26
- capsule_id: smart_proxy.id)
23
+ if repo.is_a?(::Katello::Repository) &&
24
+ repo.distribution_bootable? &&
25
+ repo.download_policy == ::Runcible::Models::YumImporter::DOWNLOAD_ON_DEMAND
26
+ plan_action(Katello::Repository::FetchPxeFiles,
27
+ id: repo.id,
28
+ capsule_id: smart_proxy.id)
29
+ end
30
+ end
27
31
  end
28
32
  end
29
33
  end
@@ -32,10 +36,6 @@ module Actions
32
36
  def resource_locks
33
37
  :link
34
38
  end
35
-
36
- def rescue_strategy
37
- Dynflow::Action::Rescue::Skip
38
- end
39
39
  end
40
40
  end
41
41
  end
@@ -80,6 +80,7 @@ module Actions
80
80
  added_units = version_output.try(:[], :output).try(:[], :added_units)
81
81
  if added_units
82
82
  total_count[:errata_count] = added_units[:erratum].try(:count)
83
+ total_count[:modulemd_count] = added_units[:modulemd].try(:count)
83
84
  total_count[:rpm_count] = added_units[:rpm].try(:count)
84
85
  total_count[:puppet_module_count] = added_units[:puppet_module].try(:count)
85
86
  end
@@ -117,6 +118,10 @@ module Actions
117
118
  errata = _(" %{errata_count} Errata" % {:errata_count => total_count[:errata_count]})
118
119
  content << errata
119
120
  end
121
+ if total_count[:modulemd_count] && total_count[:modulemd_count] > 0
122
+ modulemd = _(" %{modulemd_count} Module Stream(s)" % {:modulemd_count => total_count[:modulemd_count]})
123
+ content << modulemd
124
+ end
120
125
  if total_count[:rpm_count] && total_count[:rpm_count] > 0
121
126
  rpm = _(" %{package_count} Package(s)" % {:package_count => total_count[:rpm_count]})
122
127
  content << rpm
@@ -5,6 +5,7 @@ module Actions
5
5
  class IncrementalUpdatesPresenter < Helpers::Presenter::Base
6
6
  HUMANIZED_TYPES = {
7
7
  ::Katello::Erratum::CONTENT_TYPE => "Errata",
8
+ ::Katello::ModuleStream::CONTENT_TYPE => "Module Streams",
8
9
  ::Katello::Rpm::CONTENT_TYPE => "Packages",
9
10
  ::Katello::PuppetModule::CONTENT_TYPE => "Puppet Modules"
10
11
  }.freeze
@@ -25,7 +26,7 @@ module Actions
25
26
  if cvv
26
27
  humanized_lines << "Content View: #{cvv.content_view.name} version #{cvv.version}"
27
28
  humanized_lines << _("Added Content:")
28
- [::Katello::Erratum, ::Katello::Rpm, ::Katello::PuppetModule].each do |content_type|
29
+ [::Katello::Erratum, ::Katello::ModuleStream, ::Katello::Rpm, ::Katello::PuppetModule].each do |content_type|
29
30
  unless output[:added_units][content_type::CONTENT_TYPE].blank?
30
31
  humanized_lines << " #{HUMANIZED_TYPES[content_type::CONTENT_TYPE]}:"
31
32
  humanized_lines += output[:added_units][content_type::CONTENT_TYPE].sort.map { |unit| " #{unit}" }
@@ -51,11 +51,19 @@ module Actions
51
51
  end
52
52
 
53
53
  concurrence do
54
- repos_to_clone.each do |source_repos|
55
- copy_action_outputs += copy_repos(repository_mapping[source_repos],
56
- new_content_view_version,
57
- content,
58
- dep_solve)
54
+ if SmartProxy.pulp_master.pulp3_support?(repos_to_clone.first.first)
55
+ extended_repo_mapping = pulp3_repo_mapping(repository_mapping, old_version)
56
+ unit_map = pulp3_content_mapping(content)
57
+
58
+ copy_action_outputs << plan_action(Pulp3::Repository::MultiCopyUnits, extended_repo_mapping, unit_map,
59
+ dependency_solving: true).output
60
+ else
61
+ repos_to_clone.each do |source_repos|
62
+ copy_action_outputs += copy_repos(repository_mapping[source_repos],
63
+ new_content_view_version,
64
+ content,
65
+ dep_solve)
66
+ end
59
67
  end
60
68
 
61
69
  sequence do
@@ -68,11 +76,37 @@ module Actions
68
76
  plan_self(:content_view_id => old_version.content_view.id,
69
77
  :new_content_view_version_id => self.new_content_view_version.id,
70
78
  :environment_ids => environments.map(&:id), :user_id => ::User.current.id,
71
- :history_id => history.id, :copy_action_outputs => copy_action_outputs)
79
+ :history_id => history.id, :copy_action_outputs => copy_action_outputs,
80
+ :old_version => old_version.id)
72
81
  promote(new_content_view_version, environments)
73
82
  end
74
83
  end
75
84
 
85
+ def pulp3_content_mapping(content)
86
+ units = ::Katello::Erratum.with_identifiers(content[:errata_ids]) +
87
+ ::Katello::Rpm.with_identifiers(content[:package_ids])
88
+ unit_map = { :errata => [], :rpms => [] }
89
+ units.each do |unit|
90
+ if unit.class.name == "Katello::Erratum"
91
+ unit_map[:errata] << unit.id
92
+ elsif unit.class.name == "Katello::Rpm"
93
+ unit_map[:rpms] << unit.id
94
+ end
95
+ end
96
+ unit_map
97
+ end
98
+
99
+ def pulp3_repo_mapping(repo_mapping, old_version)
100
+ pulp3_repo_mapping = {}
101
+ repo_mapping.each do |source_repo, dest_repo|
102
+ source_repo = source_repo.first.library_instance? ? source_repo : [source_repo.first.library_instance]
103
+ pulp3_repo_mapping[source_repo.first.id] = { dest_repo: dest_repo.id,
104
+ base_version: pulp3_dest_base_version(
105
+ ::Katello::ContentViewVersion.find(old_version.id), dest_repo) }
106
+ end
107
+ pulp3_repo_mapping
108
+ end
109
+
76
110
  def repos_to_copy(old_version, new_components)
77
111
  old_version.archived_repos.map do |source_repo|
78
112
  components_repo_instances(source_repo, new_components)
@@ -142,22 +176,46 @@ module Actions
142
176
  ::Katello::PuppetModule::CONTENT_TYPE => []
143
177
  }
144
178
 
145
- input[:copy_action_outputs].each do |copy_output|
146
- copy_output[:pulp_tasks].each do |pulp_task|
147
- pulp_task[:result][:units_successful].each do |unit|
148
- type = unit['type_id']
149
- unit = unit['unit_key']
150
- case type
151
- when ::Katello::Erratum::CONTENT_TYPE
152
- content[::Katello::Erratum::CONTENT_TYPE] << unit['id']
153
- when ::Katello::ModuleStream::CONTENT_TYPE
154
- content[::Katello::ModuleStream::CONTENT_TYPE] << "#{unit['name']}:#{unit['stream']}:#{unit['version']}"
155
- when ::Katello::Rpm::CONTENT_TYPE
156
- content[::Katello::Rpm::CONTENT_TYPE] << ::Katello::Util::Package.build_nvra(unit)
157
- when ::Katello::Deb::CONTENT_TYPE
158
- content[::Katello::Deb::CONTENT_TYPE] << "#{unit['name']}_#{unit['version']}_#{unit['architecture']}"
159
- when ::Katello::PuppetModule::CONTENT_TYPE
160
- content[::Katello::PuppetModule::CONTENT_TYPE] << "#{unit['author']}-#{unit['name']}-#{unit['version']}"
179
+ base_repos = ::Katello::ContentViewVersion.find(input[:old_version]).repositories
180
+ new_repos = ::Katello::ContentViewVersion.find(input[:new_content_view_version_id]).repositories
181
+
182
+ if input[:copy_action_outputs].last[:pulp_tasks].last[:pulp_href]&.include?("/pulp/api/v3/")
183
+ new_repos.each do |new_repo|
184
+ matched_old_repo = base_repos.where(root_id: new_repo.root_id).first
185
+
186
+ new_errata = new_repo.errata - matched_old_repo.errata
187
+ new_module_streams = new_repo.module_streams - matched_old_repo.module_streams
188
+ new_rpms = new_repo.rpms - matched_old_repo.rpms
189
+
190
+ new_errata.each do |erratum|
191
+ content[::Katello::Erratum::CONTENT_TYPE] << erratum.errata_id
192
+ end
193
+ new_module_streams.each do |module_stream|
194
+ content[::Katello::ModuleStream::CONTENT_TYPE] <<
195
+ "#{module_stream.name}:#{module_stream.stream}:#{module_stream.version}"
196
+ end
197
+ new_rpms.each do |rpm|
198
+ content[::Katello::Rpm::CONTENT_TYPE] << rpm.nvra
199
+ end
200
+ end
201
+ else
202
+ input[:copy_action_outputs].each do |copy_output|
203
+ copy_output[:pulp_tasks].each do |pulp_task|
204
+ pulp_task[:result][:units_successful].each do |unit|
205
+ type = unit['type_id']
206
+ unit = unit['unit_key']
207
+ case type
208
+ when ::Katello::Erratum::CONTENT_TYPE
209
+ content[::Katello::Erratum::CONTENT_TYPE] << unit['id']
210
+ when ::Katello::ModuleStream::CONTENT_TYPE
211
+ content[::Katello::ModuleStream::CONTENT_TYPE] << "#{unit['name']}:#{unit['stream']}:#{unit['version']}"
212
+ when ::Katello::Rpm::CONTENT_TYPE
213
+ content[::Katello::Rpm::CONTENT_TYPE] << ::Katello::Util::Package.build_nvra(unit)
214
+ when ::Katello::Deb::CONTENT_TYPE
215
+ content[::Katello::Deb::CONTENT_TYPE] << "#{unit['name']}_#{unit['version']}_#{unit['architecture']}"
216
+ when ::Katello::PuppetModule::CONTENT_TYPE
217
+ content[::Katello::PuppetModule::CONTENT_TYPE] << "#{unit['author']}-#{unit['name']}-#{unit['version']}"
218
+ end
161
219
  end
162
220
  end
163
221
  end
@@ -174,10 +232,12 @@ module Actions
174
232
  history.status = ::Katello::ContentViewHistory::SUCCESSFUL
175
233
  history.save!
176
234
 
177
- version.repositories.each do |repo|
178
- SmartProxy.pulp_master.pulp_api.extensions.send(:module_default).
179
- copy(repo.library_instance.pulp_id,
180
- repo.pulp_id)
235
+ unless SmartProxy.pulp_master.pulp3_support?(version.repositories.first)
236
+ version.repositories.each do |repo|
237
+ SmartProxy.pulp_master.pulp_api.extensions.send(:module_default).
238
+ copy(repo.library_instance.pulp_id,
239
+ repo.pulp_id)
240
+ end
181
241
  end
182
242
  end
183
243
 
@@ -255,6 +315,10 @@ module Actions
255
315
  copy_outputs
256
316
  end
257
317
 
318
+ def pulp3_dest_base_version(old_cvv, new_repo)
319
+ old_cvv.repositories.archived.find_by(root_id: new_repo.root_id).version_href.split("/")[-1].to_i
320
+ end
321
+
258
322
  def copy_yum_content(new_repo, dep_solve, package_ids, errata_ids)
259
323
  copy_outputs = []
260
324
  if new_repo.content_type == ::Katello::Repository::YUM_TYPE