katello 3.16.0.rc3.1 → 3.16.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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/registry/registry_proxies_controller.rb +39 -23
  3. data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +2 -2
  4. data/app/controllers/katello/api/v2/api_controller.rb +9 -4
  5. data/app/controllers/katello/api/v2/content_view_filters_controller.rb +5 -1
  6. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +3 -0
  7. data/app/controllers/katello/api/v2/content_views_controller.rb +7 -0
  8. data/app/controllers/katello/api/v2/subscriptions_controller.rb +1 -1
  9. data/app/controllers/katello/api/v2/upstream_subscriptions_controller.rb +13 -1
  10. data/app/controllers/katello/concerns/api/v2/associations_permission_check.rb +67 -0
  11. data/app/controllers/katello/concerns/hosts_controller_extensions.rb +11 -0
  12. data/app/helpers/katello/content_view_helper.rb +15 -0
  13. data/app/lib/actions/katello/capsule_content/refresh_repos.rb +4 -0
  14. data/app/lib/actions/katello/capsule_content/sync.rb +0 -4
  15. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +16 -16
  16. data/app/lib/actions/katello/content_view/incremental_updates.rb +8 -1
  17. data/app/lib/actions/katello/content_view/presenters/incremental_updates_presenter.rb +2 -1
  18. data/app/lib/actions/katello/content_view/publish.rb +55 -16
  19. data/app/lib/actions/katello/content_view_version/incremental_update.rb +120 -26
  20. data/app/lib/actions/katello/host/attach_subscriptions.rb +5 -1
  21. data/app/lib/actions/katello/repository/multi_clone_contents.rb +66 -0
  22. data/app/lib/actions/katello/repository/multi_clone_to_version.rb +30 -0
  23. data/app/lib/actions/katello/sync_plan/run.rb +1 -1
  24. data/app/lib/actions/pulp/abstract_async_task.rb +1 -0
  25. data/app/lib/actions/pulp/consumer/sync_capsule.rb +8 -0
  26. data/app/lib/actions/pulp/repository/presenters/deb_presenter.rb +2 -2
  27. data/app/lib/actions/pulp3/abstract_async_task.rb +62 -58
  28. data/app/lib/actions/pulp3/content_migration.rb +4 -0
  29. data/app/lib/actions/pulp3/orchestration/repository/copy_all_units.rb +1 -2
  30. data/app/lib/actions/pulp3/orchestration/repository/multi_copy_all_units.rb +36 -0
  31. data/app/lib/actions/pulp3/repository/multi_copy_content.rb +28 -0
  32. data/app/lib/actions/pulp3/repository/multi_copy_units.rb +55 -0
  33. data/app/lib/actions/pulp3/repository/presenters/content_unit_presenter.rb +1 -1
  34. data/app/lib/actions/pulp3/repository/save_version.rb +11 -3
  35. data/app/lib/actions/pulp3/repository/save_versions.rb +73 -0
  36. data/app/lib/katello/concerns/base_template_scope_extensions.rb +0 -14
  37. data/app/lib/katello/errors.rb +26 -15
  38. data/app/lib/katello/resources/candlepin.rb +1 -1
  39. data/app/lib/katello/resources/candlepin/upstream_consumer.rb +6 -0
  40. data/app/models/katello/concerns/host_managed_extensions.rb +7 -0
  41. data/app/models/katello/concerns/organization_extensions.rb +14 -0
  42. data/app/models/katello/content_view.rb +18 -6
  43. data/app/models/katello/content_view_erratum_filter.rb +13 -0
  44. data/app/models/katello/content_view_filter.rb +4 -0
  45. data/app/models/katello/content_view_module_stream_filter.rb +30 -3
  46. data/app/models/katello/glue/pulp/repo.rb +1 -0
  47. data/app/models/katello/host/content_facet.rb +10 -5
  48. data/app/models/katello/module_stream.rb +1 -1
  49. data/app/models/katello/pulp3/content_guard.rb +1 -1
  50. data/app/models/katello/repository.rb +11 -0
  51. data/app/models/setting/content.rb +3 -1
  52. data/app/presenters/katello/sync_status_presenter.rb +4 -2
  53. data/app/services/katello/candlepin/message_handler.rb +2 -3
  54. data/app/services/katello/pulp/repository/yum.rb +2 -1
  55. data/app/services/katello/pulp3/api/core.rb +4 -0
  56. data/app/services/katello/pulp3/erratum.rb +3 -1
  57. data/app/services/katello/pulp3/migration.rb +9 -4
  58. data/app/services/katello/pulp3/migration_plan.rb +6 -6
  59. data/app/services/katello/pulp3/repository.rb +17 -1
  60. data/app/services/katello/pulp3/repository/yum.rb +187 -25
  61. data/app/services/katello/pulp3/task.rb +100 -0
  62. data/app/services/katello/pulp3/task_group.rb +79 -0
  63. data/app/services/katello/ui_notifications/subscriptions/manifest_expired_warning.rb +20 -8
  64. data/app/services/katello/upstream_connection_checker.rb +48 -0
  65. data/app/views/katello/api/v2/content_view_filters/base.json.rabl +4 -0
  66. data/app/views/katello/api/v2/srpms/backend.json.rabl +11 -0
  67. data/app/views/katello/api/v2/srpms/base.json.rabl +5 -0
  68. data/app/views/katello/api/v2/srpms/compare.json.rabl +10 -0
  69. data/app/views/katello/api/v2/srpms/index.json.rabl +1 -1
  70. data/app/views/katello/api/v2/srpms/show.json.rabl +3 -3
  71. data/config/routes/api/v2.rb +2 -0
  72. data/db/migrate/20200709021250_add_original_modules_to_content_view_module_stream_filter.rb +5 -0
  73. data/db/migrate/20200721142707_remove_duplicate_katello_pools_index.rb +5 -0
  74. data/db/seeds.d/109-katello-notification-blueprints.rb +1 -1
  75. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/capsule-content/capsule-content.routes.js +1 -13
  76. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/filters/filter-details.controller.js +17 -4
  77. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/filters/views/module-stream-filter-details.html +17 -0
  78. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/errata/errata.routes.js +1 -1
  79. data/engines/bastion_katello/app/assets/stylesheets/bastion_katello/bastion_katello.scss +4 -0
  80. data/lib/katello/engine.rb +0 -1
  81. data/lib/katello/permission_creator.rb +1 -1
  82. data/lib/katello/plugin.rb +2 -0
  83. data/lib/katello/tasks/reports.rake +16 -0
  84. data/lib/katello/version.rb +1 -1
  85. data/package.json +3 -3
  86. data/webpack/components/Content/ContentTable.js +2 -0
  87. data/webpack/components/Content/Details/ContentDetails.js +3 -0
  88. data/webpack/redux/actions/RedHatRepositories/helpers.js +5 -5
  89. data/webpack/scenes/AnsibleCollections/Details/AnsibleCollectionDetails.js +3 -0
  90. data/webpack/scenes/ModuleStreams/Details/ModuleStreamDetails.js +3 -0
  91. data/webpack/scenes/RedHatRepositories/RedHatRepositoriesPage.js +2 -0
  92. data/webpack/scenes/RedHatRepositories/components/EnabledRepository/EnabledRepository.js +2 -0
  93. data/webpack/scenes/RedHatRepositories/components/RepositorySetRepository/RepositorySetRepository.js +2 -0
  94. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailAssociations.js +2 -0
  95. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProductContent.js +2 -0
  96. data/webpack/scenes/Subscriptions/Details/SubscriptionDetailProducts.js +2 -0
  97. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +2 -0
  98. data/webpack/scenes/Subscriptions/SubscriptionActions.js +8 -8
  99. data/webpack/scenes/Subscriptions/SubscriptionConstants.js +3 -1
  100. data/webpack/scenes/Subscriptions/SubscriptionReducer.js +15 -1
  101. data/webpack/scenes/Subscriptions/SubscriptionsPage.js +54 -7
  102. data/webpack/scenes/Subscriptions/SubscriptionsSelectors.js +3 -0
  103. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsActions.js +15 -1
  104. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/{UpstreamSubscriptionsContstants.js → UpstreamSubscriptionsConstants.js} +3 -0
  105. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsPage.js +2 -0
  106. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/UpstreamSubscriptionsReducer.js +1 -1
  107. data/webpack/scenes/Subscriptions/UpstreamSubscriptions/__tests__/UpstreamSubscriptionsReducer.test.js +1 -1
  108. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsActions.test.js +0 -13
  109. data/webpack/scenes/Subscriptions/__tests__/SubscriptionsPage.test.js +6 -1
  110. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +6 -4
  111. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsReducer.test.js.snap +26 -25
  112. data/webpack/scenes/Subscriptions/__tests__/subscriptions.fixtures.js +0 -58
  113. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/SubscriptionsTable.js +10 -4
  114. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/SubscriptionsTable.test.js +1 -0
  115. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/__tests__/__snapshots__/SubscriptionsTable.test.js.snap +1 -68
  116. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Dialogs/UpdateDialog.js +1 -1
  117. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Dialogs/index.js +4 -4
  118. data/webpack/scenes/Subscriptions/components/SubscriptionsTable/components/Table.js +12 -10
  119. data/webpack/scenes/Subscriptions/index.js +6 -3
  120. metadata +44 -27
@@ -19,7 +19,7 @@ module Actions
19
19
  syncable_products = sync_plan.products.syncable
20
20
  syncable_roots = ::Katello::RootRepository.where(:product_id => syncable_products).has_url
21
21
 
22
- plan_action(::Actions::BulkAction, ::Actions::Katello::Repository::Sync, syncable_roots.map(&:library_instance)) unless syncable_roots.empty?
22
+ plan_action(::Actions::BulkAction, ::Actions::Katello::Repository::Sync, syncable_roots.map(&:library_instance).compact) unless syncable_roots.empty?
23
23
  plan_self(:sync_plan_name => sync_plan.name)
24
24
  end
25
25
  end
@@ -74,6 +74,7 @@ module Actions
74
74
  end
75
75
 
76
76
  def cancel!
77
+ output[:cancelled] = true
77
78
  cancel
78
79
  self.external_task = poll_external_task
79
80
  # We suspend the action and the polling will take care of finding
@@ -26,6 +26,14 @@ module Actions
26
26
  self.done? ? 1 : 0.1
27
27
  end
28
28
 
29
+ def rescue_strategy_for_self
30
+ if output[:cancelled]
31
+ Dynflow::Action::Rescue::Fail
32
+ else
33
+ Dynflow::Action::Rescue::Skip
34
+ end
35
+ end
36
+
29
37
  def run_progress_weight
30
38
  100
31
39
  end
@@ -54,11 +54,11 @@ module Actions
54
54
  end
55
55
 
56
56
  def items_done
57
- task_details&.inject(0) { |sum, details| sum + details[:num_success].to_i }
57
+ task_details&.inject(0) { |sum, details| sum + details[:num_success].to_i } || 0
58
58
  end
59
59
 
60
60
  def items_total
61
- task_details&.inject(0) { |sum, details| sum + details[:items_total].to_i }
61
+ task_details&.inject(0) { |sum, details| sum + details[:items_total].to_i } || 0
62
62
  end
63
63
 
64
64
  def size_done
@@ -4,41 +4,6 @@ module Actions
4
4
  include Actions::Base::Polling
5
5
  include ::Dynflow::Action::Cancellable
6
6
 
7
- WAITING = ['waiting',
8
- SKIPPED = 'skipped'.freeze,
9
- RUNNING = 'running'.freeze,
10
- COMPLETED = 'completed'.freeze,
11
- FAILED = 'failed'.freeze,
12
- CANCELED = 'canceled'.freeze].freeze
13
-
14
- FINISHED_STATES = [COMPLETED, FAILED, CANCELED, SKIPPED].freeze
15
-
16
- # A call report Looks like: {"task":"/pulp/api/v3/tasks/5/"}
17
- # {
18
- # "pulp_href":"/pulp/api/v3/tasks/4/",
19
- # "pulp_created":"2019-02-21T19:50:40.476767Z",
20
- # "job_id":"d0359658-d926-47a2-b430-1b2092b3bd86",
21
- # "state":"completed",
22
- # "name":"pulp_file.app.tasks.publishing.publish",
23
- # "started_at":"2019-02-21T19:50:40.556002Z",
24
- # "finished_at":"2019-02-21T19:50:40.618397Z",
25
- # "non_fatal_errors":[
26
- #
27
- # ],
28
- # "error":null,
29
- # "worker":"/pulp/api/v3/workers/1/",
30
- # "parent":null,
31
- # "spawned_tasks":[
32
- #
33
- # ],
34
- # "progress_reports":[
35
- #
36
- # ],
37
- # "created_resources":[
38
- # "/pulp/api/v3/publications/1/"
39
- # ]
40
- # }
41
-
42
7
  def run(event = nil)
43
8
  # do nothing when the action is being skipped
44
9
  unless event == Dynflow::Action::Skip
@@ -49,16 +14,16 @@ module Actions
49
14
  def humanized_state
50
15
  case state
51
16
  when :running
52
- if self.external_task.nil?
17
+ if self.combined_tasks.empty?
53
18
  _("initiating Pulp task")
54
19
  else
55
20
  _("checking Pulp task status")
56
21
  end
57
22
  when :suspended
58
- if external_task&.all? { |task| task[:start_time].nil? }
59
- _("waiting for Pulp to start the task")
60
- else
23
+ if combined_tasks.any?(&:started?)
61
24
  _("waiting for Pulp to finish the task")
25
+ else
26
+ _("waiting for Pulp to start the task")
62
27
  end
63
28
  else
64
29
  super
@@ -66,28 +31,49 @@ module Actions
66
31
  end
67
32
 
68
33
  def done?
69
- external_task&.all? { |task| task[:finish_time] || FINISHED_STATES.include?(task[:state]) }
34
+ combined_tasks&.all? { |task| task.done? }
70
35
  end
71
36
 
72
37
  def external_task
73
- output[:pulp_tasks]
38
+ #this must return nil until external_task= is called
39
+ combined_tasks
40
+ end
41
+
42
+ def combined_tasks
43
+ return nil if pulp_tasks.nil? || task_groups.nil?
44
+ pulp_tasks + task_groups
45
+ end
46
+
47
+ def pulp_tasks
48
+ return nil if output[:pulp_tasks].nil?
49
+ output[:pulp_tasks] = new_or_existing_objects(::Katello::Pulp3::Task, output[:pulp_tasks])
50
+ end
51
+
52
+ def task_groups
53
+ return nil if output[:task_groups].nil?
54
+ output[:task_groups] = new_or_existing_objects(::Katello::Pulp3::TaskGroup, output[:task_groups])
55
+ end
56
+
57
+ def new_or_existing_objects(object_class, objects)
58
+ objects.map do |object|
59
+ if object.is_a?(object_class)
60
+ object
61
+ else
62
+ object_class.new(smart_proxy, object)
63
+ end
64
+ end
74
65
  end
75
66
 
76
67
  def cancel!
77
68
  cancel
78
- self.external_task = poll_external_task
69
+ poll_external_task
79
70
  # We suspend the action and the polling will take care of finding
80
71
  # out if the cancelling was successful
81
72
  suspend unless done?
82
73
  end
83
74
 
84
75
  def cancel
85
- output[:pulp_tasks].each do |pulp_task|
86
- data = PulpcoreClient::Task.new(state: 'canceled')
87
- tasks_api.tasks_cancel(pulp_task['pulp_href'], data)
88
- #the main task may have completed, so cancel spawned tasks too
89
- pulp_task['spawned_tasks']&.each { |spawned| tasks_api.tasks_cancel(spawned['pulp_href'], data) }
90
- end
76
+ pulp_tasks.each { |task| task.cancel }
91
77
  end
92
78
 
93
79
  def rescue_external_task(error)
@@ -109,24 +95,42 @@ module Actions
109
95
  response
110
96
  end
111
97
 
98
+ def check_for_errors
99
+ combined_tasks.each do |task|
100
+ if (message = task.error)
101
+ fail ::Katello::Errors::Pulp3Error, message
102
+ end
103
+ end
104
+ end
105
+
112
106
  def external_task=(external_task_data)
113
- output[:pulp_tasks] = transform_task_response(external_task_data)
114
- output[:pulp_tasks].each do |pulp_task|
115
- if (pulp_exception = ::Katello::Errors::Pulp3Error.from_task(pulp_task))
116
- fail pulp_exception
107
+ #currently we assume everything coming from invoke_external_task_methods are tasks
108
+ tasks = transform_task_response(external_task_data)
109
+ output[:pulp_tasks] = new_or_existing_objects(::Katello::Pulp3::Task, tasks)
110
+
111
+ add_task_groups
112
+ check_for_errors
113
+ end
114
+
115
+ def add_task_groups
116
+ output[:task_groups] ||= []
117
+ pulp_tasks.each do |task|
118
+ if task.task_group_href && !tracking_task_group?(task.task_group_href)
119
+ output[:task_groups] << ::Katello::Pulp3::TaskGroup.new_from_href(smart_proxy, task.task_group_href)
117
120
  end
118
121
  end
119
122
  end
120
123
 
121
- def tasks_api
122
- ::Katello::Pulp3::Api::Core.new(smart_proxy).tasks_api
124
+ def tracking_task_group?(href)
125
+ task_groups&.any? { |group| group.href == href }
123
126
  end
124
127
 
125
128
  def poll_external_task
126
- external_task.map do |task|
127
- task = tasks_api.read(task['pulp_href'] || task['task'])
128
- task.as_json
129
- end
129
+ pulp_tasks.each(&:poll)
130
+ output[:task_groups] = task_groups.each(&:poll) if task_groups
131
+ add_task_groups
132
+ check_for_errors
133
+ pulp_tasks
130
134
  end
131
135
  end
132
136
  end
@@ -12,6 +12,10 @@ module Actions
12
12
  migration_service = ::Katello::Pulp3::Migration.new(smart_proxy)
13
13
  migration_service.create_and_run_migrations
14
14
  end
15
+
16
+ def rescue_strategy
17
+ Dynflow::Action::Rescue::Skip
18
+ end
15
19
  end
16
20
  end
17
21
  end
@@ -21,8 +21,7 @@ module Actions
21
21
  else
22
22
  #if we are not filtering, copy the version to the cv repository, and the units for each additional repo
23
23
  action = plan_action(Actions::Pulp3::Repository::CopyVersion, source_repositories.first, smart_proxy, target_repo)
24
- plan_action(Actions::Pulp3::Repository::SaveVersion, target_repo,
25
- repository_details: { latest_version_href: action.output[:latest_version_output] }, tasks: action.output[:pulp_tasks])
24
+ plan_action(Actions::Pulp3::Repository::SaveVersion, target_repo, tasks: action.output[:pulp_tasks])
26
25
  copy_actions = []
27
26
  #since we're creating a new version from the first repo, start copying at the 2nd
28
27
  source_repositories[1..-1].each do |source_repo|
@@ -0,0 +1,36 @@
1
+ module Actions
2
+ module Pulp3
3
+ module Orchestration
4
+ module Repository
5
+ class MultiCopyAllUnits < Pulp3::Abstract
6
+ def plan(extended_repo_map, smart_proxy, options = {})
7
+ solve_dependencies = options.fetch(:solve_dependencies, false)
8
+ if extended_repo_map.values.pluck(:filters).flatten.present? ||
9
+ extended_repo_map.keys.detect { |source_repos| source_repos.length > 1 }
10
+ sequence do
11
+ copy_action = plan_action(Actions::Pulp3::Repository::MultiCopyContent, extended_repo_map, smart_proxy,
12
+ solve_dependencies: solve_dependencies)
13
+ plan_action(Actions::Pulp3::Repository::SaveVersions, extended_repo_map.values.pluck(:dest_repo),
14
+ tasks: copy_action.output[:pulp_tasks])
15
+ end
16
+ else
17
+ repo_id_map = {}
18
+ extended_repo_map.each do |source_repos, dest_repo_map|
19
+ repo_id_map[source_repos.first.id] = dest_repo_map[:dest_repo].id
20
+ end
21
+ plan_self(repo_id_map: repo_id_map)
22
+ end
23
+ end
24
+
25
+ def run
26
+ input[:repo_id_map].each do |source_repo_id, dest_repo_id|
27
+ dest_repo = ::Katello::Repository.find(dest_repo_id)
28
+ source_repo = ::Katello::Repository.find(source_repo_id)
29
+ dest_repo.update!(version_href: source_repo.version_href)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ module Actions
2
+ module Pulp3
3
+ module Repository
4
+ class MultiCopyContent < Pulp3::AbstractAsyncTask
5
+ def plan(extended_repo_map, smart_proxy, options)
6
+ repo_id_map = {}
7
+
8
+ extended_repo_map.each do |source_repos, dest_repo_map|
9
+ repo_id_map[source_repos&.map(&:id)] = { :dest_repo => dest_repo_map[:dest_repo].id,
10
+ :filter_ids => dest_repo_map[:filters]&.map(&:id) }
11
+ end
12
+
13
+ plan_self(options.merge(:repo_id_map => repo_id_map, :smart_proxy_id => smart_proxy.id))
14
+ end
15
+
16
+ def invoke_external_task
17
+ repo_id_map = {}
18
+
19
+ input[:repo_id_map].each do |source_repo_ids, dest_repo_map|
20
+ repo_id_map[JSON.parse(source_repo_ids)] = dest_repo_map
21
+ end
22
+
23
+ output[:pulp_tasks] = ::Katello::Repository.find(repo_id_map.values.first[:dest_repo]).backend_service(smart_proxy).copy_content_from_mapping(repo_id_map, input)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,55 @@
1
+ module Actions
2
+ module Pulp3
3
+ module Repository
4
+ class MultiCopyUnits < Pulp3::AbstractAsyncTask
5
+ # repo_map example: {
6
+ # [<source_repo_ids>]: {
7
+ # dest_repo: <dest_repo_id>,
8
+ # base_version: <base_version>
9
+ # }
10
+ # }
11
+ def plan(repo_map, unit_map, options = {})
12
+ if unit_map.values.flatten.any?
13
+ action_output = plan_self(repo_map: repo_map,
14
+ unit_map: unit_map,
15
+ dependency_solving: options[:dependency_solving],
16
+ incremental_update: options[:incremental_update],
17
+ smart_proxy_id: SmartProxy.pulp_master.id).output
18
+ plan_action(Pulp3::Repository::SaveVersions, repo_map.values.pluck(:dest_repo),
19
+ tasks: action_output[:pulp_tasks]).output
20
+ end
21
+ end
22
+
23
+ def invoke_external_task
24
+ unit_hrefs = []
25
+ repo_map = {}
26
+
27
+ input[:repo_map].each do |source_repo_ids, dest_repo_map|
28
+ repo_map[JSON.parse(source_repo_ids)] = dest_repo_map
29
+ end
30
+
31
+ if input[:unit_map][:errata].any?
32
+ unit_hrefs << ::Katello::RepositoryErratum.
33
+ joins("inner join katello_errata on katello_repository_errata.erratum_id = katello_errata.id").
34
+ where("katello_repository_errata.repository_id in (#{repo_map.keys.join(',')}) and
35
+ katello_errata.id in (#{input[:unit_map][:errata].join(",")})").map(&:erratum_pulp3_href)
36
+ end
37
+
38
+ if input[:unit_map][:rpms].any?
39
+ unit_hrefs << ::Katello::Rpm.where(:id => input[:unit_map][:rpms]).map(&:pulp_id)
40
+ end
41
+ unit_hrefs.flatten!
42
+
43
+ repo_map.each do |_source_repos, dest_repo_map|
44
+ dest_repo_map[:content_unit_hrefs] = unit_hrefs
45
+ end
46
+
47
+ target_repo = ::Katello::Repository.find(repo_map.values.first[:dest_repo])
48
+ unless unit_hrefs.flatten.empty?
49
+ output[:pulp_tasks] = target_repo.backend_service(SmartProxy.pulp_master).multi_copy_units(repo_map, input[:dependency_solving])
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -12,7 +12,7 @@ module Actions
12
12
  def humanized_details
13
13
  ret = []
14
14
  ret << _("Cancelled.") if cancelled?
15
- ret << _("Total tasks: ") + ": #{finished_units}/#{total_units}"
15
+ ret << _("Total steps: ") + "#{finished_units}/#{total_units}"
16
16
  ret << "--------------------------------"
17
17
  progress_reports = sync_task.try(:[], 'progress_reports') || []
18
18
  progress_reports = progress_reports.sort_by { |pr| pr.try(:[], 'message') }
@@ -9,12 +9,20 @@ module Actions
9
9
  def run
10
10
  repo = ::Katello::Repository.find(input[:repository_id])
11
11
 
12
- if input[:tasks]
12
+ if input[:tasks].present?
13
13
  version_href = input[:tasks].last[:created_resources].first
14
14
  end
15
15
 
16
- if !version_href && input[:repository_details]
17
- version_href = input[:repository_details][:latest_version_href]
16
+ unless version_href
17
+ if input[:repository_details]
18
+ version_href = input[:repository_details][:latest_version_href]
19
+ elsif repo.version_href.nil?
20
+ # Fetch latest Pulp 3 repo version
21
+ repo_backend_service = repo.backend_service(SmartProxy.pulp_master)
22
+ version_href ||= repo_backend_service.api.
23
+ repositories_api.read(repo_backend_service.
24
+ repository_reference.repository_href).latest_version_href
25
+ end
18
26
  end
19
27
 
20
28
  if version_href
@@ -0,0 +1,73 @@
1
+ module Actions
2
+ module Pulp3
3
+ module Repository
4
+ class SaveVersions < Pulp3::Abstract
5
+ def plan(repository_ids, options)
6
+ plan_self(:repository_ids => repository_ids, :tasks => options[:tasks])
7
+ end
8
+
9
+ def run
10
+ return if input[:tasks].empty?
11
+ version_hrefs = input[:tasks].last[:created_resources]
12
+ repositories = find_repositories(input[:repository_ids])
13
+
14
+ output.merge!(contents_changed: false, updated_repositories: [])
15
+ repositories.each do |repo|
16
+ repo_backend_service = repo.backend_service(SmartProxy.pulp_master)
17
+ if repo.version_href
18
+ # Chop off the version number to compare base repo strings
19
+ unversioned_href = repo.version_href[0..-2].rpartition('/').first
20
+ # Could have multiple version_hrefs for the same repo depending on the copy task
21
+ new_version_hrefs = version_hrefs.collect do |version_href|
22
+ version_href if unversioned_href == version_href[0..-2].rpartition('/').first
23
+ end
24
+
25
+ new_version_hrefs.compact!
26
+ if new_version_hrefs.size > 1
27
+ # Find latest version_href by its version number
28
+ new_version_href = version_map(new_version_hrefs).max_by { |_href, version| version }.first
29
+ else
30
+ new_version_href = new_version_hrefs.first
31
+ end
32
+
33
+ # Successive incremental updates won't generate a new repo version, so fetch the latest Pulp 3 repo version
34
+ new_version_href ||= latest_version_href(repo_backend_service)
35
+ else
36
+ new_version_href = latest_version_href(repo_backend_service)
37
+ end
38
+
39
+ unless new_version_href == repo.version_href
40
+ repo.update(version_href: new_version_href)
41
+ repo.index_content
42
+ output[:contents_changed] = true
43
+ output[:updated_repositories] << repo.id
44
+ end
45
+ end
46
+ end
47
+
48
+ def version_map(version_hrefs)
49
+ version_map = {}
50
+ version_hrefs.each do |href|
51
+ version_map[href] = href.split("/")[-1].to_i
52
+ end
53
+ version_map
54
+ end
55
+
56
+ def latest_version_href(repo_backend_service)
57
+ repo_backend_service.api.repositories_api.
58
+ read(repo_backend_service.repository_reference.repository_href).latest_version_href
59
+ end
60
+
61
+ def find_repositories(repository_ids)
62
+ repository_ids.collect do |repo_id|
63
+ if repo_id.is_a?(Hash)
64
+ ::Katello::Repository.find(repo_id.with_indifferent_access[:id])
65
+ else
66
+ ::Katello::Repository.find(repo_id)
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end