katello 3.18.0.rc2.1 → 3.18.2.1

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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/katello/katello.scss +0 -72
  3. data/app/controllers/katello/api/v2/api_controller.rb +1 -2
  4. data/app/controllers/katello/api/v2/capsule_content_controller.rb +2 -2
  5. data/app/controllers/katello/api/v2/content_export_incrementals_controller.rb +98 -0
  6. data/app/controllers/katello/api/v2/content_exports_controller.rb +84 -0
  7. data/app/controllers/katello/api/v2/content_imports_controller.rb +59 -0
  8. data/app/controllers/katello/api/v2/content_view_filters_controller.rb +1 -1
  9. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +56 -94
  10. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +2 -1
  11. data/app/controllers/katello/api/v2/repositories_controller.rb +2 -0
  12. data/app/controllers/katello/concerns/api/v2/authorization.rb +14 -1
  13. data/app/lib/actions/katello/applicability/hosts/bulk_generate.rb +6 -2
  14. data/app/lib/actions/katello/capsule_content/sync.rb +1 -1
  15. data/app/lib/actions/katello/capsule_content/sync_capsule.rb +7 -2
  16. data/app/lib/actions/katello/content_view/promote_to_environment.rb +1 -1
  17. data/app/lib/actions/katello/content_view/publish.rb +1 -1
  18. data/app/lib/actions/katello/content_view_version/import.rb +2 -1
  19. data/app/lib/actions/katello/content_view_version/import_library.rb +17 -0
  20. data/app/lib/actions/katello/content_view_version/incremental_update.rb +19 -3
  21. data/app/lib/actions/katello/host/update_system_purpose.rb +1 -1
  22. data/app/lib/actions/katello/repository/sync.rb +5 -1
  23. data/app/lib/actions/middleware/record_smart_proxy_sync_history.rb +24 -4
  24. data/app/lib/actions/pulp3/content_migration.rb +10 -0
  25. data/app/lib/actions/pulp3/content_migration_presenter.rb +59 -0
  26. data/app/lib/actions/pulp3/content_migration_reset.rb +22 -0
  27. data/app/lib/actions/pulp3/content_view/delete_repository_references.rb +1 -1
  28. data/app/lib/actions/pulp3/content_view_version/export.rb +3 -2
  29. data/app/lib/actions/pulp3/import_migration.rb +6 -1
  30. data/app/lib/actions/pulp3/orchestration/content_view_version/copy_version_units_to_library.rb +2 -1
  31. data/app/lib/actions/pulp3/orchestration/content_view_version/export.rb +17 -13
  32. data/app/lib/actions/pulp3/orchestration/content_view_version/export_library.rb +60 -0
  33. data/app/lib/actions/pulp3/orchestration/content_view_version/import.rb +0 -4
  34. data/app/lib/actions/pulp3/orchestration/repository/import_upload.rb +16 -3
  35. data/app/lib/actions/pulp3/repository/copy_content.rb +1 -1
  36. data/app/lib/actions/pulp3/repository/delete.rb +1 -1
  37. data/app/lib/actions/pulp3/repository/save_version.rb +1 -1
  38. data/app/lib/actions/pulp3/repository/upload_tag.rb +18 -0
  39. data/app/lib/katello/util/pulpcore_content_filters.rb +1 -1
  40. data/app/models/katello/authorization/content_view_version.rb +25 -2
  41. data/app/models/katello/authorization/content_view_version_export_history.rb +1 -1
  42. data/app/models/katello/authorization/organization.rb +8 -0
  43. data/app/models/katello/concerns/operatingsystem_extensions.rb +2 -0
  44. data/app/models/katello/concerns/pulp_database_unit.rb +19 -0
  45. data/app/models/katello/concerns/redhat_extensions.rb +2 -2
  46. data/app/models/katello/concerns/smart_proxy_extensions.rb +7 -5
  47. data/app/models/katello/content_migration_progress.rb +4 -0
  48. data/app/models/katello/content_view.rb +5 -0
  49. data/app/models/katello/content_view_history.rb +2 -1
  50. data/app/models/katello/content_view_package_filter.rb +1 -1
  51. data/app/models/katello/content_view_version_export_history.rb +6 -1
  52. data/app/models/katello/file_unit.rb +4 -0
  53. data/app/models/katello/host/content_facet.rb +9 -31
  54. data/app/models/katello/host/subscription_facet.rb +4 -0
  55. data/app/models/katello/ping.rb +35 -15
  56. data/app/models/katello/repository.rb +7 -0
  57. data/app/models/katello/subscription_status.rb +3 -2
  58. data/app/services/katello/applicability/applicable_content_helper.rb +44 -15
  59. data/app/services/katello/pulp3/api/docker.rb +4 -0
  60. data/app/services/katello/pulp3/content_view_version/export.rb +63 -5
  61. data/app/services/katello/pulp3/content_view_version/import.rb +40 -0
  62. data/app/services/katello/pulp3/content_view_version/import_export_common.rb +0 -16
  63. data/app/services/katello/pulp3/content_view_version/import_validator.rb +26 -49
  64. data/app/services/katello/pulp3/docker_manifest.rb +1 -0
  65. data/app/services/katello/pulp3/docker_tag.rb +1 -0
  66. data/app/services/katello/pulp3/erratum.rb +2 -1
  67. data/app/services/katello/pulp3/migration.rb +95 -12
  68. data/app/services/katello/pulp3/migration_plan.rb +2 -2
  69. data/app/services/katello/pulp3/migration_switchover.rb +23 -5
  70. data/app/services/katello/pulp3/repository.rb +10 -5
  71. data/app/services/katello/pulp3/repository/docker.rb +5 -0
  72. data/app/services/katello/pulp3/repository/yum.rb +23 -8
  73. data/app/services/katello/pulp3/rpm.rb +5 -1
  74. data/app/services/katello/pulp3/task.rb +4 -0
  75. data/app/services/katello/pulp3/task_group.rb +4 -0
  76. data/app/views/katello/api/v2/content_views/show.json.rabl +6 -0
  77. data/app/views/katello/layouts/react.html.erb +3 -2
  78. data/app/views/katello/sync_management/_products.html.erb +1 -1
  79. data/app/views/overrides/activation_keys/_host_tab_pane.html.erb +1 -5
  80. data/config/routes/api/v2.rb +23 -3
  81. data/db/migrate/20150930183738_migrate_content_hosts.rb +1 -1
  82. data/db/migrate/20200514092553_move_katello_fields_from_hostgroups.katello.rb +5 -2
  83. data/db/migrate/20201119211133_pulp3_migration_progress.rb +9 -0
  84. data/db/migrate/20210201165835_add_migration_missing_content.rb +12 -0
  85. data/engines/bastion/app/assets/javascripts/bastion/auth/authorization.service.js +1 -1
  86. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/katello-agent-notice.html +1 -1
  87. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-system-purpose-modal.html +35 -40
  88. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-client.html +1 -1
  89. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/deletion/content-view-version-deletion-activation-keys.controller.js +8 -3
  90. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/deletion/content-view-version-deletion-content-hosts.controller.js +9 -3
  91. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/views/content-view-details.html +1 -1
  92. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/views/content-view-publish.html +4 -0
  93. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +78 -7
  94. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +17 -20
  95. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +17 -24
  96. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +1292 -1170
  97. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +17 -20
  98. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +858 -807
  99. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +18 -19
  100. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +17 -24
  101. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +17 -18
  102. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +986 -971
  103. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +19 -20
  104. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/translations.js +9 -9
  105. data/lib/katello/permission_creator.rb +23 -3
  106. data/lib/katello/tasks/delete_orphaned_content.rake +1 -3
  107. data/lib/katello/tasks/pulp3_content_switchover.rake +3 -1
  108. data/lib/katello/tasks/pulp3_migration.rake +29 -6
  109. data/lib/katello/tasks/pulp3_migration_abort.rake +7 -2
  110. data/lib/katello/tasks/pulp3_migration_approve_corrupted.rake +16 -0
  111. data/lib/katello/tasks/pulp3_migration_reset.rake +26 -0
  112. data/lib/katello/tasks/pulp3_migration_stats.rake +61 -8
  113. data/lib/katello/tasks/pulp3_post_migration_check.rake +1 -3
  114. data/lib/katello/tasks/receptor/extract_orgs.rake +1 -1
  115. data/lib/katello/tasks/reports.rake +4 -1
  116. data/lib/katello/tasks/repository.rake +3 -5
  117. data/lib/katello/version.rb +1 -1
  118. data/locale/action_names.rb +51 -51
  119. data/locale/bn/katello.po +136 -51
  120. data/locale/cs/katello.po +136 -49
  121. data/locale/de/katello.po +136 -48
  122. data/locale/en/katello.po +136 -48
  123. data/locale/es/katello.po +136 -48
  124. data/locale/fr/katello.po +136 -48
  125. data/locale/gu/katello.po +136 -51
  126. data/locale/hi/katello.po +136 -51
  127. data/locale/it/katello.po +136 -48
  128. data/locale/ja/katello.po +136 -48
  129. data/locale/katello.pot +941 -767
  130. data/locale/kn/katello.po +136 -51
  131. data/locale/ko/katello.po +136 -48
  132. data/locale/mr/katello.po +136 -51
  133. data/locale/or/katello.po +136 -51
  134. data/locale/pa/katello.po +136 -51
  135. data/locale/pt/katello.po +136 -51
  136. data/locale/pt_BR/katello.po +136 -48
  137. data/locale/ru/katello.po +136 -48
  138. data/locale/ta/katello.po +136 -51
  139. data/locale/te/katello.po +136 -51
  140. data/locale/zh_CN/katello.po +136 -48
  141. data/locale/zh_TW/katello.po +136 -48
  142. data/webpack/components/TypeAhead/TypeAhead.js +2 -1
  143. data/webpack/components/TypeAhead/pf3Search/TypeAheadSearch.js +2 -1
  144. data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +7 -2
  145. data/webpack/scenes/Subscriptions/Manifest/index.js +1 -0
  146. metadata +31 -19
  147. data/lib/katello/tasks/common.rake +0 -7
@@ -282,6 +282,10 @@ module Katello
282
282
  name.gsub('_', '-').chomp('.').downcase
283
283
  end
284
284
 
285
+ def unsubscribed_hypervisor?
286
+ self.hypervisor && !self.candlepin_consumer.entitlements?
287
+ end
288
+
285
289
  def candlepin_consumer
286
290
  @candlepin_consumer ||= Katello::Candlepin::Consumer.new(self.uuid, self.host.organization.label)
287
291
  end
@@ -23,25 +23,18 @@ module Katello
23
23
  services
24
24
  end
25
25
 
26
- # Calls "status" services in all backend engines.
27
26
  def ping(services: nil, capsule_id: nil)
28
- services ||= self.services(capsule_id)
29
- result = {}
30
- services.each { |service| result[service] = {} }
27
+ ping_services_for_capsule(services, capsule_id)
28
+ end
31
29
 
32
- ping_pulp3_without_auth(result[:pulp3], capsule_id) if result.include?(:pulp3)
33
- ping_pulp_without_auth(result[:pulp], capsule_id) if result.include?(:pulp)
34
- ping_candlepin_without_auth(result[:candlepin]) if result.include?(:candlepin)
30
+ def ping!(services: nil, capsule_id: nil)
31
+ result = ping_services_for_capsule(services, capsule_id)
35
32
 
36
- ping_pulp_with_auth(result[:pulp_auth], result[:pulp][:status]) if result.include?(:pulp_auth)
37
- ping_candlepin_with_auth(result[:candlepin_auth]) if result.include?(:candlepin_auth)
38
- ping_foreman_tasks(result[:foreman_tasks]) if result.include?(:foreman_tasks)
39
- ping_katello_events(result[:katello_events]) if result.include?(:katello_events)
40
- ping_candlepin_events(result[:candlepin_events]) if result.include?(:candlepin_events)
33
+ if result[:status] != OK_RETURN_CODE
34
+ failed_names = failed_services(result).keys
35
+ fail("The following services have not been started or are reporting errors: #{failed_names.join(', ')}")
36
+ end
41
37
 
42
- # set overall status result code
43
- result = {:services => result}
44
- result[:status] = result[:services].each_value.any? { |v| v[:status] == FAIL_RETURN_CODE } ? FAIL_RETURN_CODE : OK_RETURN_CODE
45
38
  result
46
39
  end
47
40
 
@@ -221,6 +214,33 @@ module Katello
221
214
 
222
215
  private
223
216
 
217
+ def failed_services(result)
218
+ result[:services].reject do |_name, details|
219
+ details[:status] != OK_RETURN_CODE
220
+ end
221
+ end
222
+
223
+ def ping_services_for_capsule(services, capsule_id)
224
+ services ||= self.services(capsule_id)
225
+ result = {}
226
+ services.each { |service| result[service] = {} }
227
+
228
+ ping_pulp3_without_auth(result[:pulp3], capsule_id) if result.include?(:pulp3)
229
+ ping_pulp_without_auth(result[:pulp], capsule_id) if result.include?(:pulp)
230
+ ping_candlepin_without_auth(result[:candlepin]) if result.include?(:candlepin)
231
+
232
+ ping_pulp_with_auth(result[:pulp_auth], result[:pulp][:status]) if result.include?(:pulp_auth)
233
+ ping_candlepin_with_auth(result[:candlepin_auth]) if result.include?(:candlepin_auth)
234
+ ping_foreman_tasks(result[:foreman_tasks]) if result.include?(:foreman_tasks)
235
+ ping_katello_events(result[:katello_events]) if result.include?(:katello_events)
236
+ ping_candlepin_events(result[:candlepin_events]) if result.include?(:candlepin_events)
237
+
238
+ # set overall status result code
239
+ result = {:services => result}
240
+ result[:status] = result[:services].each_value.any? { |v| v[:status] == FAIL_RETURN_CODE } ? FAIL_RETURN_CODE : OK_RETURN_CODE
241
+ result
242
+ end
243
+
224
244
  def fetch_proxy(capsule_id)
225
245
  capsule_id ? SmartProxy.unscoped.find(capsule_id) : SmartProxy.pulp_primary
226
246
  end
@@ -122,6 +122,8 @@ module Katello
122
122
 
123
123
  scope :has_url, -> { joins(:root).where.not("#{RootRepository.table_name}.url" => nil) }
124
124
  scope :on_demand, -> { joins(:root).where("#{RootRepository.table_name}.download_policy" => ::Runcible::Models::YumImporter::DOWNLOAD_ON_DEMAND) }
125
+ scope :immediate, -> { joins(:root).where("#{RootRepository.table_name}.download_policy" => ::Runcible::Models::YumImporter::DOWNLOAD_IMMEDIATE) }
126
+ scope :non_immediate, -> { joins(:root).where.not("#{RootRepository.table_name}.download_policy" => ::Runcible::Models::YumImporter::DOWNLOAD_IMMEDIATE) }
125
127
  scope :in_default_view, -> { joins(:content_view_version => :content_view).where("#{Katello::ContentView.table_name}.default" => true) }
126
128
  scope :in_non_default_view, -> { joins(:content_view_version => :content_view).where("#{Katello::ContentView.table_name}.default" => false) }
127
129
  scope :deb_type, -> { with_type(DEB_TYPE) }
@@ -154,6 +156,7 @@ module Katello
154
156
  scoped_search :on => :redhat, :complete_value => { :true => true, :false => false }, :ext_method => :search_by_redhat
155
157
  scoped_search :on => :container_repository_name, :complete_value => true
156
158
  scoped_search :on => :description, :relation => :root, :only_explicit => true
159
+ scoped_search :on => :download_policy, :relation => :root, :only_explicit => true
157
160
  scoped_search :on => :name, :relation => :product, :rename => :product_name
158
161
  scoped_search :on => :id, :relation => :product, :rename => :product_id, :only_explicit => true
159
162
  scoped_search :on => :label, :relation => :root, :complete_value => true, :only_explicit => true
@@ -287,6 +290,10 @@ module Katello
287
290
  root.download_policy == Runcible::Models::YumImporter::DOWNLOAD_ON_DEMAND
288
291
  end
289
292
 
293
+ def immediate?
294
+ root.download_policy == ::Runcible::Models::YumImporter::DOWNLOAD_IMMEDIATE
295
+ end
296
+
290
297
  def yum_gpg_key_url
291
298
  # if the repo has a gpg key return a url to access it
292
299
  if self.root.gpg_key.try(:content).present?
@@ -43,9 +43,10 @@ module Katello
43
43
 
44
44
  def to_status(options = {})
45
45
  return UNKNOWN unless host.subscription_facet.try(:uuid)
46
- status_override = 'unsubscribed_hypervisor' if host.subscription_facet.hypervisor && !host.subscription_facet.candlepin_consumer.entitlements?
46
+ return DISABLED if host.organization.simple_content_access?
47
+ status_override = 'unsubscribed_hypervisor' if host.subscription_facet.unsubscribed_hypervisor?
47
48
  status_override ||= options.fetch(:status_override, nil)
48
- status = status_override || Katello::Candlepin::Consumer.new(host.subscription_facet.uuid, host.organization.label).entitlement_status
49
+ status = status_override || host.subscription_facet.candlepin_consumer.entitlement_status
49
50
 
50
51
  case status
51
52
  when Katello::Candlepin::Consumer::ENTITLEMENTS_DISABLED
@@ -60,17 +60,7 @@ module Katello
60
60
  end
61
61
 
62
62
  def fetch_rpm_content_ids
63
- # Query for applicable RPM ids
64
- # -> Include all non-modular rpms or rpms that exist within installed module streams
65
- enabled_module_stream_ids = ::Katello::ModuleStream.
66
- joins("inner join katello_available_module_streams on
67
- katello_module_streams.name = katello_available_module_streams.name and
68
- katello_module_streams.stream = katello_available_module_streams.stream").
69
- joins("inner join katello_host_available_module_streams on
70
- katello_available_module_streams.id = katello_host_available_module_streams.available_module_stream_id").
71
- where("katello_host_available_module_streams.host_id = :content_facet_id and
72
- katello_host_available_module_streams.status = 'enabled'",
73
- :content_facet_id => self.content_facet.host.id).select(:id)
63
+ enabled_module_stream_ids = fetch_enabled_module_stream_ids
74
64
 
75
65
  ::Katello::Rpm.
76
66
  joins("INNER JOIN katello_repository_rpms ON
@@ -78,7 +68,8 @@ module Katello
78
68
  joins("INNER JOIN katello_installed_packages ON
79
69
  katello_rpms.name = katello_installed_packages.name AND
80
70
  katello_rpms.arch = katello_installed_packages.arch AND
81
- katello_rpms.evr > katello_installed_packages.evr").
71
+ katello_rpms.evr > katello_installed_packages.evr AND
72
+ katello_installed_packages.id in (#{newest_distinct_installed_packages_query})").
82
73
  joins("LEFT JOIN katello_module_stream_rpms ON
83
74
  katello_rpms.id = katello_module_stream_rpms.rpm_id").
84
75
  joins("INNER JOIN katello_host_installed_packages ON
@@ -87,9 +78,47 @@ module Katello
87
78
  :bound_library_repos => self.bound_library_instance_repos).
88
79
  where("katello_host_installed_packages.host_id = :content_facet_id",
89
80
  :content_facet_id => self.content_facet.host.id).
90
- where("katello_module_stream_rpms.module_stream_id is null or
91
- katello_module_stream_rpms.module_stream_id in (:enabled_module_streams)",
92
- :enabled_module_streams => enabled_module_stream_ids).pluck(:id).uniq
81
+ where("(katello_module_stream_rpms.module_stream_id IS NULL AND
82
+ katello_installed_packages.id NOT IN (:locked_modular_installed_packages)) OR
83
+ (katello_module_stream_rpms.module_stream_id IN (:enabled_module_streams)
84
+ AND katello_installed_packages.id IN (:locked_modular_installed_packages))",
85
+ :enabled_module_streams => enabled_module_stream_ids,
86
+ :locked_modular_installed_packages => locked_modular_installed_packages(enabled_module_stream_ids)).pluck(:id).uniq
87
+ end
88
+
89
+ def fetch_enabled_module_stream_ids
90
+ # Query for applicable RPM ids
91
+ # -> Include all non-modular rpms or rpms that exist within installed module streams
92
+ ::Katello::ModuleStream.
93
+ joins("inner join katello_available_module_streams on
94
+ katello_module_streams.name = katello_available_module_streams.name and
95
+ katello_module_streams.stream = katello_available_module_streams.stream").
96
+ joins("inner join katello_host_available_module_streams on
97
+ katello_available_module_streams.id = katello_host_available_module_streams.available_module_stream_id").
98
+ where("katello_host_available_module_streams.host_id = :content_facet_id and
99
+ katello_host_available_module_streams.status = 'enabled'",
100
+ :content_facet_id => self.content_facet.host.id).select(:id)
101
+ end
102
+
103
+ # Installed packages that are locked for the host due to enabled module stream membership
104
+ def locked_modular_installed_packages(enabled_module_streams)
105
+ rpms_in_enabled_module_streams = ::Katello::Rpm.
106
+ joins("INNER JOIN katello_module_stream_rpms ON katello_rpms.id = katello_module_stream_rpms.rpm_id").
107
+ where("katello_module_stream_rpms.module_stream_id IN (:enabled_module_streams)",
108
+ :enabled_module_streams => enabled_module_streams).select(:nvra, :epoch)
109
+
110
+ ::Katello::InstalledPackage.where(nvra: rpms_in_enabled_module_streams.map(&:nvra),
111
+ epoch: rpms_in_enabled_module_streams.map(&:epoch)).select(:id)
112
+ end
113
+
114
+ def newest_distinct_installed_packages_query
115
+ "SELECT DISTINCT ON (katello_installed_packages.name) katello_installed_packages.id " \
116
+ "FROM katello_installed_packages INNER JOIN " \
117
+ "katello_host_installed_packages ON " \
118
+ "katello_installed_packages.id = " \
119
+ "katello_host_installed_packages.installed_package_id " \
120
+ "WHERE katello_host_installed_packages.host_id = " \
121
+ "#{content_facet.host.id} ORDER BY katello_installed_packages.name, katello_installed_packages.evr DESC"
93
122
  end
94
123
 
95
124
  def applicable_differences
@@ -32,6 +32,10 @@ module Katello
32
32
  PulpContainerClient::RecursiveManage
33
33
  end
34
34
 
35
+ def self.tag_image_class
36
+ PulpContainerClient::TagImage
37
+ end
38
+
35
39
  def api_client
36
40
  PulpContainerClient::ApiClient.new(smart_proxy.pulp3_configuration(PulpContainerClient::Configuration))
37
41
  end
@@ -4,13 +4,37 @@ module Katello
4
4
  class Export
5
5
  include ImportExportCommon
6
6
 
7
- def initialize(smart_proxy:, content_view_version: nil, destination_server: nil, from_content_view_version: nil)
7
+ def initialize(smart_proxy:,
8
+ content_view_version: nil,
9
+ destination_server: nil,
10
+ from_content_view_version: nil)
8
11
  @smart_proxy = smart_proxy
9
12
  @content_view_version = content_view_version
10
13
  @destination_server = destination_server
11
14
  @from_content_view_version = from_content_view_version
12
15
  end
13
16
 
17
+ def repository_hrefs
18
+ version_hrefs.map { |href| version_href_to_repository_href(href) }.uniq
19
+ end
20
+
21
+ def version_hrefs
22
+ repositories.pluck(:version_href).compact
23
+ end
24
+
25
+ def repositories(fetch_all: false)
26
+ repos = if @content_view_version.default?
27
+ @content_view_version.repositories.yum_type
28
+ else
29
+ @content_view_version.archived_repos.yum_type
30
+ end
31
+ if fetch_all
32
+ repos
33
+ else
34
+ repos.immediate
35
+ end
36
+ end
37
+
14
38
  def generate_exporter_path
15
39
  export_path = "#{@content_view_version.content_view}/#{@content_view_version.version}/#{@destination_server}/#{date_dir}".gsub(/\s/, '_')
16
40
  "#{@content_view_version.organization.label}/#{export_path}"
@@ -66,12 +90,29 @@ module Katello
66
90
  api.exporter_api.delete(exporter_href)
67
91
  end
68
92
 
93
+ def validate!(fail_on_missing_content: true, validate_incremental: true)
94
+ validate_repositories_immediate! if fail_on_missing_content
95
+ validate_incremental_export! if validate_incremental && !@from_content_view_version.blank?
96
+ end
97
+
98
+ def validate_repositories_immediate!
99
+ non_immediate_repos = repositories(fetch_all: true).non_immediate
100
+ if non_immediate_repos.any?
101
+ fail _("NOTE: Unable to fully export Content View Version '%{content_view} %{current}'"\
102
+ " it contains repositories without the 'immediate' download policy."\
103
+ " Update the download policy and sync affected repositories. Once synced republish the content view"\
104
+ " and export the generated version. \n %{repos}" %
105
+ { content_view: @content_view_version.content_view.name,
106
+ current: @content_view_version.version,
107
+ repos: self.class.generate_product_repo_strings(repositories: non_immediate_repos)})
108
+ end
109
+ end
110
+
69
111
  def validate_incremental_export!
70
- return if @from_content_view_version.blank?
71
112
  from_exporter = Export.new(smart_proxy: @smart_proxy, content_view_version: @from_content_view_version)
72
113
 
73
- from_exporter_repos = generate_repo_mapping(from_exporter.repositories)
74
- to_exporter_repos = generate_repo_mapping(repositories)
114
+ from_exporter_repos = generate_repo_mapping(from_exporter.repositories(fetch_all: true))
115
+ to_exporter_repos = generate_repo_mapping(repositories(fetch_all: true))
75
116
 
76
117
  invalid_repos_exist = (from_exporter_repos.keys & to_exporter_repos.keys).any? do |repo_id|
77
118
  from_exporter_repos[repo_id] != to_exporter_repos[repo_id]
@@ -99,7 +140,8 @@ module Katello
99
140
  ret = { organization: @content_view_version.organization.name,
100
141
  repository_mapping: {},
101
142
  content_view: @content_view_version.content_view.name,
102
- content_view_version: @content_view_version.slice(:major, :minor)
143
+ content_view_version: @content_view_version.slice(:major, :minor),
144
+ incremental: @from_content_view_version.present?
103
145
  }
104
146
 
105
147
  unless @from_content_view_version.blank?
@@ -120,6 +162,22 @@ module Katello
120
162
  end
121
163
  ret
122
164
  end
165
+
166
+ def self.find_library_export_view(create_by_default: false,
167
+ destination_server:,
168
+ organization:)
169
+ name = "Export-Library"
170
+ name += "-#{destination_server}" unless destination_server.blank?
171
+ select_method = create_by_default ? :first_or_create : :first
172
+ ::Katello::ContentView.where(name: name, organization: organization).send(select_method)
173
+ end
174
+
175
+ def self.generate_product_repo_strings(repositories:)
176
+ repositories.map do |repo|
177
+ _("Product: '%{product}', Repository: '%{repository}'" % { product: repo.product.name,
178
+ repository: repo.name})
179
+ end
180
+ end
123
181
  end
124
182
  end
125
183
  end
@@ -46,6 +46,46 @@ module Katello
46
46
  def self.check!(content_view:, metadata:, path:)
47
47
  ImportValidator.new(content_view: content_view, metadata: metadata, path: path).check!
48
48
  end
49
+
50
+ def self.reset_content_view_repositories_from_metadata!(content_view:, metadata:)
51
+ # Given metadata from the dump and a content view
52
+ # this method
53
+ # 1) Fetches ids of the library repos whose product name, repo name amd redhat?
54
+ # => match values provided in the metadata's repository mapping
55
+ # 2) Removes all the repositories associated to this content view
56
+ # 3) Adds the repositories matched from the dump
57
+ # The main intent of this method is to assume that the user intends for the
58
+ # content view to exaclty look like what is specified in metadata
59
+
60
+ repos_in_library = Katello::Repository.
61
+ in_default_view.
62
+ yum_type.
63
+ joins(:product => :provider, :content_view_version => :content_view).
64
+ joins(:root).
65
+ where("#{::Katello::ContentView.table_name}.organization_id" => content_view.organization_id).
66
+ pluck("#{::Katello::Repository.table_name}.id",
67
+ "#{::Katello::RootRepository.table_name}.name",
68
+ "#{::Katello::Product.table_name}.name",
69
+ "#{::Katello::Provider.table_name}.provider_type"
70
+ )
71
+ repos_in_library_map = {}
72
+ # repos_in_library_map is going to look like {['repo1', 'product1', false] => 100, ['repo1', 'product1', true] => 200 }
73
+ repos_in_library.each do |id, repo, product, provider_type|
74
+ repos_in_library_map[[repo, product, provider_type == Katello::Provider::REDHAT]] = id
75
+ end
76
+
77
+ repo_ids = metadata[:repository_mapping].values.map do |repo|
78
+ repos_in_library_map[[repo[:repository], repo[:product], repo[:redhat]]]
79
+ end
80
+ content_view.update!(repository_ids: repo_ids)
81
+ end
82
+
83
+ def self.find_or_create_library_import_view(organization)
84
+ name = ::Katello::ContentView::IMPORT_LIBRARY
85
+ ::Katello::ContentView.where(name: name,
86
+ organization: organization,
87
+ import_only: true).first_or_create
88
+ end
49
89
  end
50
90
  end
51
91
  end
@@ -19,22 +19,6 @@ module Katello
19
19
  repo_api.read(version_href_to_repository_href(version_href))
20
20
  end
21
21
 
22
- def repository_hrefs
23
- version_hrefs.map { |href| version_href_to_repository_href(href) }.uniq
24
- end
25
-
26
- def version_hrefs
27
- repositories.pluck(:version_href).compact
28
- end
29
-
30
- def repositories
31
- if @content_view_version.default?
32
- @content_view_version.repositories.yum_type
33
- else
34
- @content_view_version.archived_repos.yum_type
35
- end
36
- end
37
-
38
22
  def version_href_to_repository_href(version_href)
39
23
  version_href.split("/")[0..-3].join("/") + "/"
40
24
  end
@@ -2,7 +2,6 @@ module Katello
2
2
  module Pulp3
3
3
  module ContentViewVersion
4
4
  class ImportValidator
5
- BASEDIR = '/var/lib/pulp'.freeze
6
5
  attr_accessor :metadata, :path, :content_view
7
6
  def initialize(content_view:, path:, metadata:)
8
7
  self.content_view = content_view
@@ -11,10 +10,11 @@ module Katello
11
10
  end
12
11
 
13
12
  def check!
14
- check_permissions!
15
- ensure_importing_cvv_does_not_exist!
16
- ensure_from_cvv_exists!
17
- ensure_repositories_metadata_and_content_view_match!
13
+ unless content_view.default?
14
+ ensure_importing_cvv_does_not_exist!
15
+ ensure_from_cvv_exists!
16
+ end
17
+ ensure_repositories_metadata_are_in_the_library!
18
18
  end
19
19
 
20
20
  def ensure_importing_cvv_does_not_exist!
@@ -43,55 +43,32 @@ module Katello
43
43
  end
44
44
  end
45
45
 
46
- def ensure_repositories_metadata_and_content_view_match!
47
- product_repos_in_content_view = content_view.repositories.yum_type.map { |repo| [repo.product.name, repo.name, repo.redhat?] }
46
+ def ensure_repositories_metadata_are_in_the_library!
47
+ repos_in_library = Katello::Repository.
48
+ in_default_view.
49
+ yum_type.
50
+ joins(:product => :provider, :content_view_version => :content_view).
51
+ joins(:root).
52
+ where("#{::Katello::ContentView.table_name}.organization_id" => content_view.organization_id).
53
+ pluck("#{::Katello::Product.table_name}.name",
54
+ "#{::Katello::RootRepository.table_name}.name",
55
+ "#{::Katello::Provider.table_name}.provider_type"
56
+ )
57
+
58
+ # repos_in_library look like [["prod1", "repo1", "Anonymous"], ["prod2", "repo2", "Red Hat"]]
59
+ product_repos_in_library = repos_in_library.map { |product, repo, provider| [product, repo, provider == ::Katello::Provider::REDHAT] }
48
60
  product_repos_in_metadata = metadata[:repository_mapping].values.map { |repo| [repo[:product], repo[:repository], repo[:redhat]] }
49
-
50
- product_repos_in_content_view.sort!
51
- product_repos_in_metadata.sort!
52
- # product_repos_in_content_view & product_repos_in_metadata look like [["prod1", "repo1", false], ["prod2", "repo2", false]]
53
-
54
- if product_repos_in_content_view != product_repos_in_metadata
55
- repos_in_content_view = generate_product_repo_i18n_string(product_repos_in_content_view)
56
- repos_in_import = generate_product_repo_i18n_string(product_repos_in_metadata)
57
-
58
- fail _("Repositories in the importing content view do not match the repositories provided in the import metadata.\n "\
59
- "Repositories in Content View '%{content_view}': %{repos_in_content_view}\n "\
60
- "Repositories in the Import Metadata: %{repos_in_import}" % { content_view: content_view.name,
61
- repos_in_content_view: repos_in_content_view.join(""),
62
- repos_in_import: repos_in_import.join("")}
61
+ # product_repos_in_library & product_repos_in_metadata look like [["prod1", "repo1", false], ["prod2", "repo2", false]]
62
+ product_repos_not_in_library = product_repos_in_metadata - product_repos_in_library
63
+ unless product_repos_not_in_library.blank?
64
+ repos_in_import = generate_product_repo_i18n_string(product_repos_not_in_library)
65
+ fail _("The following repositories provided in the import metadata are either not available in the Library or are of incorrect Respository Type. "\
66
+ "Please add or enable the repositories before importing\n "\
67
+ "%{repos}" % { content_view: content_view.name, repos: repos_in_import.join("")}
63
68
  )
64
69
  end
65
70
  end
66
71
 
67
- def check_permissions!
68
- fail _("Invalid path specified.") if path.blank? || !File.directory?(path)
69
- fail _("The import path must be in a subdirectory under '%s'." % BASEDIR) unless path.starts_with?(BASEDIR)
70
- fail _("Pulp user or group unable to read content in '%s'." % path) unless pulp_user_accessible?(path)
71
-
72
- Dir.glob("#{path}/*").each do |file|
73
- fail _("Pulp user or group unable to read '%s'." % file) unless pulp_user_accessible?(file)
74
- end
75
- toc_path = "#{path}/#{metadata[:toc]}"
76
- fail _("The TOC file specified in the metadata does not exist. %s " % toc_path) unless File.exist?(toc_path)
77
- end
78
-
79
- def pulp_user_accessible?(path)
80
- pulp_info = fetch_pulp_user_info
81
- return false if pulp_info.blank?
82
-
83
- stat = File.stat(path)
84
- stat.gid.to_s == pulp_info.gid ||
85
- stat.uid.to_s == pulp_info.uid ||
86
- stat.mode.to_s(8)[-1].to_i >= 4
87
- end
88
-
89
- def fetch_pulp_user_info
90
- pulp_user = nil
91
- Etc.passwd { |u| pulp_user = u if u.name == 'pulp' }
92
- pulp_user
93
- end
94
-
95
72
  def generate_product_repo_i18n_string(product_repos)
96
73
  # product_repos look like [["prod1", "repo1", false], ["prod2", "repo2", false]]
97
74
  product_repos.map do |product, repo, redhat|