katello 3.18.0.rc2 → 3.18.2
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.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/katello/katello.scss +0 -72
- data/app/controllers/katello/api/v2/api_controller.rb +1 -2
- data/app/controllers/katello/api/v2/capsule_content_controller.rb +2 -2
- data/app/controllers/katello/api/v2/content_export_incrementals_controller.rb +98 -0
- data/app/controllers/katello/api/v2/content_exports_controller.rb +84 -0
- data/app/controllers/katello/api/v2/content_imports_controller.rb +59 -0
- data/app/controllers/katello/api/v2/content_view_filters_controller.rb +1 -1
- data/app/controllers/katello/api/v2/content_view_versions_controller.rb +56 -94
- data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +2 -1
- data/app/controllers/katello/api/v2/repositories_controller.rb +2 -0
- data/app/controllers/katello/concerns/api/v2/authorization.rb +14 -1
- data/app/lib/actions/katello/applicability/hosts/bulk_generate.rb +6 -2
- data/app/lib/actions/katello/capsule_content/sync.rb +1 -1
- data/app/lib/actions/katello/capsule_content/sync_capsule.rb +7 -2
- data/app/lib/actions/katello/content_view/promote_to_environment.rb +1 -1
- data/app/lib/actions/katello/content_view/publish.rb +1 -1
- data/app/lib/actions/katello/content_view_version/import.rb +2 -1
- data/app/lib/actions/katello/content_view_version/import_library.rb +17 -0
- data/app/lib/actions/katello/content_view_version/incremental_update.rb +19 -3
- data/app/lib/actions/katello/host/update_system_purpose.rb +1 -1
- data/app/lib/actions/katello/host/upload_package_profile.rb +1 -1
- data/app/lib/actions/katello/host/upload_profiles.rb +1 -1
- data/app/lib/actions/middleware/record_smart_proxy_sync_history.rb +24 -4
- data/app/lib/actions/pulp3/content_migration.rb +10 -0
- data/app/lib/actions/pulp3/content_migration_presenter.rb +59 -0
- data/app/lib/actions/pulp3/content_migration_reset.rb +22 -0
- data/app/lib/actions/pulp3/content_view/delete_repository_references.rb +1 -1
- data/app/lib/actions/pulp3/content_view_version/export.rb +3 -2
- data/app/lib/actions/pulp3/import_migration.rb +6 -1
- data/app/lib/actions/pulp3/orchestration/content_view_version/copy_version_units_to_library.rb +2 -1
- data/app/lib/actions/pulp3/orchestration/content_view_version/export.rb +17 -13
- data/app/lib/actions/pulp3/orchestration/content_view_version/export_library.rb +60 -0
- data/app/lib/actions/pulp3/orchestration/content_view_version/import.rb +0 -4
- data/app/lib/actions/pulp3/orchestration/repository/import_upload.rb +16 -3
- data/app/lib/actions/pulp3/repository/copy_content.rb +1 -1
- data/app/lib/actions/pulp3/repository/delete.rb +1 -1
- data/app/lib/actions/pulp3/repository/save_version.rb +1 -1
- data/app/lib/actions/pulp3/repository/upload_tag.rb +18 -0
- data/app/models/katello/authorization/content_view_version.rb +25 -2
- data/app/models/katello/authorization/content_view_version_export_history.rb +1 -1
- data/app/models/katello/authorization/organization.rb +8 -0
- data/app/models/katello/concerns/operatingsystem_extensions.rb +2 -0
- data/app/models/katello/concerns/pulp_database_unit.rb +19 -0
- data/app/models/katello/concerns/redhat_extensions.rb +2 -2
- data/app/models/katello/concerns/smart_proxy_extensions.rb +7 -5
- data/app/models/katello/content_migration_progress.rb +4 -0
- data/app/models/katello/content_view.rb +5 -0
- data/app/models/katello/content_view_history.rb +2 -1
- data/app/models/katello/content_view_package_filter.rb +1 -1
- data/app/models/katello/content_view_version_export_history.rb +6 -1
- data/app/models/katello/file_unit.rb +4 -0
- data/app/models/katello/host/subscription_facet.rb +4 -0
- data/app/models/katello/repository.rb +7 -0
- data/app/models/katello/subscription_status.rb +3 -2
- data/app/services/katello/applicability/applicable_content_helper.rb +44 -15
- data/app/services/katello/pulp3/api/docker.rb +4 -0
- data/app/services/katello/pulp3/content_view_version/export.rb +63 -5
- data/app/services/katello/pulp3/content_view_version/import.rb +40 -0
- data/app/services/katello/pulp3/content_view_version/import_export_common.rb +0 -16
- data/app/services/katello/pulp3/content_view_version/import_validator.rb +26 -49
- data/app/services/katello/pulp3/docker_manifest.rb +1 -0
- data/app/services/katello/pulp3/docker_tag.rb +1 -0
- data/app/services/katello/pulp3/erratum.rb +2 -1
- data/app/services/katello/pulp3/migration.rb +95 -12
- data/app/services/katello/pulp3/migration_plan.rb +2 -2
- data/app/services/katello/pulp3/migration_switchover.rb +21 -5
- data/app/services/katello/pulp3/repository.rb +10 -5
- data/app/services/katello/pulp3/repository/docker.rb +5 -0
- data/app/services/katello/pulp3/repository/yum.rb +23 -8
- data/app/services/katello/pulp3/task.rb +4 -0
- data/app/services/katello/pulp3/task_group.rb +4 -0
- data/app/views/katello/api/v2/content_views/show.json.rabl +6 -0
- data/app/views/katello/layouts/react.html.erb +3 -2
- data/app/views/katello/sync_management/_products.html.erb +1 -1
- data/app/views/overrides/activation_keys/_host_tab_pane.html.erb +1 -5
- data/config/routes/api/v2.rb +23 -3
- data/db/migrate/20150930183738_migrate_content_hosts.rb +1 -1
- data/db/migrate/20200514092553_move_katello_fields_from_hostgroups.katello.rb +5 -2
- data/db/migrate/20201119211133_pulp3_migration_progress.rb +9 -0
- data/db/migrate/20210201165835_add_migration_missing_content.rb +12 -0
- data/engines/bastion/app/assets/javascripts/bastion/auth/authorization.service.js +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/katello-agent-notice.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/views/content-hosts-bulk-system-purpose-modal.html +35 -40
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/register-client.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/deletion/content-view-version-deletion-activation-keys.controller.js +8 -3
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/deletion/content-view-version-deletion-content-hosts.controller.js +9 -3
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/views/content-view-details.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/views/content-view-publish.html +4 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/bastion_katello.pot +78 -7
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/de.po +17 -20
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/es.po +17 -24
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/fr.po +1292 -1170
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/it.po +17 -20
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ja.po +858 -807
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ko.po +18 -19
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/pt_BR.po +17 -24
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/ru.po +17 -18
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_CN.po +986 -971
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/locale/zh_TW.po +19 -20
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/i18n/translations.js +9 -9
- data/lib/katello/permission_creator.rb +23 -3
- data/lib/katello/tasks/delete_orphaned_content.rake +1 -3
- data/lib/katello/tasks/pulp3_content_switchover.rake +3 -1
- data/lib/katello/tasks/pulp3_migration.rake +25 -6
- data/lib/katello/tasks/pulp3_migration_abort.rake +7 -2
- data/lib/katello/tasks/pulp3_migration_approve_corrupted.rake +16 -0
- data/lib/katello/tasks/pulp3_migration_reset.rake +26 -0
- data/lib/katello/tasks/pulp3_migration_stats.rake +61 -8
- data/lib/katello/tasks/pulp3_post_migration_check.rake +1 -3
- data/lib/katello/tasks/receptor/extract_orgs.rake +1 -1
- data/lib/katello/tasks/reports.rake +4 -1
- data/lib/katello/tasks/repository.rake +3 -5
- data/lib/katello/version.rb +1 -1
- data/locale/action_names.rb +51 -51
- data/locale/bn/katello.po +136 -51
- data/locale/cs/katello.po +136 -49
- data/locale/de/katello.po +136 -48
- data/locale/en/katello.po +136 -48
- data/locale/es/katello.po +136 -48
- data/locale/fr/katello.po +136 -48
- data/locale/gu/katello.po +136 -51
- data/locale/hi/katello.po +136 -51
- data/locale/it/katello.po +136 -48
- data/locale/ja/katello.po +136 -48
- data/locale/katello.pot +941 -767
- data/locale/kn/katello.po +136 -51
- data/locale/ko/katello.po +136 -48
- data/locale/mr/katello.po +136 -51
- data/locale/or/katello.po +136 -51
- data/locale/pa/katello.po +136 -51
- data/locale/pt/katello.po +136 -51
- data/locale/pt_BR/katello.po +136 -48
- data/locale/ru/katello.po +136 -48
- data/locale/ta/katello.po +136 -51
- data/locale/te/katello.po +136 -51
- data/locale/zh_CN/katello.po +136 -48
- data/locale/zh_TW/katello.po +136 -48
- data/webpack/components/TypeAhead/TypeAhead.js +2 -1
- data/webpack/components/TypeAhead/pf3Search/TypeAheadSearch.js +2 -1
- data/webpack/scenes/Subscriptions/Manifest/ManageManifestModal.js +7 -2
- data/webpack/scenes/Subscriptions/Manifest/index.js +1 -0
- metadata +31 -19
- data/lib/katello/tasks/common.rake +0 -7
@@ -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
|
-
|
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 ||
|
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
|
-
|
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
|
91
|
-
|
92
|
-
|
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:,
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
47
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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|
|
@@ -2,6 +2,7 @@ module Katello
|
|
2
2
|
module Pulp3
|
3
3
|
class DockerManifest < PulpContentUnit
|
4
4
|
include LazyAccessor
|
5
|
+
CONTENT_TYPE = "docker_manifest".freeze
|
5
6
|
|
6
7
|
def self.content_api
|
7
8
|
PulpContainerClient::ContentManifestsApi.new(Katello::Pulp3::Api::Docker.new(SmartProxy.pulp_primary!).api_client)
|
@@ -35,7 +35,8 @@ module Katello
|
|
35
35
|
custom_json["issued"] = convert_date_if_epoch(custom_json["issued"])
|
36
36
|
custom_json["updated"] = convert_date_if_epoch(custom_json["updated"]) unless custom_json["updated"].blank?
|
37
37
|
|
38
|
-
if model.updated.blank? ||
|
38
|
+
if model.updated.blank? ||
|
39
|
+
(custom_json['updated'] && (custom_json['updated'].to_datetime != model.updated.to_datetime))
|
39
40
|
custom_json['errata_id'] = custom_json.delete('id')
|
40
41
|
custom_json['errata_type'] = custom_json.delete('type')
|
41
42
|
custom_json['updated'] = custom_json['updated'].blank? ? custom_json['issued'] : custom_json['updated']
|
@@ -3,7 +3,7 @@ require 'pulp_2to3_migration_client'
|
|
3
3
|
module Katello
|
4
4
|
module Pulp3
|
5
5
|
class Migration
|
6
|
-
attr_accessor :smart_proxy, :reimport_all
|
6
|
+
attr_accessor :smart_proxy, :reimport_all, :task_id
|
7
7
|
GET_QUERY_ID_LENGTH = 90
|
8
8
|
|
9
9
|
MUTABLE_CONTENT_TYPES = [
|
@@ -15,14 +15,20 @@ module Katello
|
|
15
15
|
Katello::Erratum
|
16
16
|
].freeze
|
17
17
|
|
18
|
+
CORRUPTABLE_CONTENT_TYPES = [
|
19
|
+
Katello::Rpm, Katello::FileUnit
|
20
|
+
].freeze
|
21
|
+
|
18
22
|
def self.repository_types_for_migration
|
19
23
|
#we can migrate types that pulp3 supports, but are overridden to pulp2. These are in 'migration mode'
|
20
24
|
overridden = (SETTINGS[:katello][:use_pulp_2_for_content_type] || {}).keys.select { |key| SETTINGS[:katello][:use_pulp_2_for_content_type][key] }
|
21
25
|
overridden.select { |type| SmartProxy.pulp_primary.pulp3_repository_type_support?(type.to_s, false) }.map { |t| t.to_s }
|
22
26
|
end
|
23
27
|
|
24
|
-
def initialize(smart_proxy,
|
25
|
-
self.
|
28
|
+
def initialize(smart_proxy, options = {})
|
29
|
+
self.task_id = options.fetch(:task_id, nil)
|
30
|
+
self.reimport_all = options.fetch(:reimport_all, false)
|
31
|
+
repository_types = options.fetch(:repository_types, Migration.repository_types_for_migration)
|
26
32
|
|
27
33
|
if (repository_types - smart_proxy.supported_pulp_types[:pulp3][:overriden_to_pulp2]).any?
|
28
34
|
fail ::Katello::Errors::Pulp3MigrationError, _("Pulp 3 migration cannot run. Types %s have already been migrated.") %
|
@@ -62,6 +68,15 @@ module Katello
|
|
62
68
|
[YumMetadataFile]
|
63
69
|
end
|
64
70
|
|
71
|
+
def last_successful_migration_time
|
72
|
+
task = ForemanTasks::Task.where(:label => Actions::Pulp3::ContentMigration.to_s, :result => 'success').order("started_at desc").first
|
73
|
+
if reimport_all || task.nil?
|
74
|
+
0
|
75
|
+
else
|
76
|
+
task.started_at.to_i
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
65
80
|
def content_types_for_migration
|
66
81
|
content_types = @repository_types.collect do |repository_type_label|
|
67
82
|
Katello::RepositoryTypeManager.repository_types[repository_type_label].content_types_to_index
|
@@ -70,7 +85,20 @@ module Katello
|
|
70
85
|
content_types.flatten - Migration.ignorable_content_types
|
71
86
|
end
|
72
87
|
|
88
|
+
def update_import_status(message, index = nil)
|
89
|
+
#reduce output updating, only update every 20 items
|
90
|
+
if (index.nil? || index % 20 == 0) && self.task_id
|
91
|
+
progress = Katello::ContentMigrationProgress.find_or_create_by(:task_id => self.task_id)
|
92
|
+
progress.update(:progress_message => message)
|
93
|
+
progress.save!
|
94
|
+
|
95
|
+
fail Katello::Errors::Pulp3MigrationError, "Cancelled by user." if progress.canceled?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
73
99
|
def import_pulp3_content
|
100
|
+
update_import_status("Starting katello import phase.")
|
101
|
+
|
74
102
|
Katello::Logging.time("CONTENT_MIGRATION - Total Import Process") do
|
75
103
|
@repository_types.each do |repository_type_label|
|
76
104
|
Katello::Logging.time("CONTENT_MIGRATION - Importing Repository", data: {type: repository_type_label}) do
|
@@ -78,8 +106,9 @@ module Katello
|
|
78
106
|
end
|
79
107
|
|
80
108
|
Katello::RepositoryTypeManager.repository_types[repository_type_label].content_types_to_index.each do |content_type|
|
81
|
-
Katello::Logging.time("CONTENT_MIGRATION - Importing Content", data: {type: content_type}) do
|
109
|
+
Katello::Logging.time("CONTENT_MIGRATION - Importing Content", data: {type: content_type.label}) do
|
82
110
|
import_content_type(content_type)
|
111
|
+
mark_missing_content(content_type)
|
83
112
|
end
|
84
113
|
end
|
85
114
|
end
|
@@ -90,6 +119,44 @@ module Katello
|
|
90
119
|
Katello::Pulp3::MigrationPlan.new(@repository_types).generate.as_json
|
91
120
|
end
|
92
121
|
|
122
|
+
def reset
|
123
|
+
if @repository_types.empty?
|
124
|
+
fail ::Katello::Errors::Pulp3MigrationError, 'There are no Pulp 3 content types to reset'
|
125
|
+
end
|
126
|
+
|
127
|
+
plugins = @repository_types.sort.map do |repository_type|
|
128
|
+
{
|
129
|
+
type: ::Katello::Pulp3::MigrationPlan.pulp2_repository_type(repository_type)
|
130
|
+
}
|
131
|
+
end
|
132
|
+
plan = { plugins: plugins }
|
133
|
+
|
134
|
+
# TODO: Don't provide the plan as a string once this is resolved: https://pulp.plan.io/issues/8211
|
135
|
+
migration_plan_api.reset(migration_plan_api.create(plan: plan).pulp_href, plan.to_json)
|
136
|
+
|
137
|
+
content_types_for_migration.each do |content_type|
|
138
|
+
if content_type.model_class == ::Katello::Erratum
|
139
|
+
::Katello::RepositoryErratum.update_all(erratum_pulp3_href: nil)
|
140
|
+
else
|
141
|
+
content_type.model_class.update_all(migrated_pulp3_href: nil)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
@repository_types.each do |repo_type|
|
146
|
+
if repo_type == "file"
|
147
|
+
::Katello::Repository.file_type.update(remote_href: nil, publication_href: nil, version_href: nil)
|
148
|
+
elsif repo_type == "docker"
|
149
|
+
::Katello::Repository.docker_type.update(remote_href: nil, publication_href: nil, version_href: nil)
|
150
|
+
elsif repo_type == "yum"
|
151
|
+
::Katello::Repository.yum_type.update(remote_href: nil, publication_href: nil, version_href: nil)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
::Katello::Pulp3::RepositoryReference.destroy_all
|
156
|
+
::Katello::Pulp3::DistributionReference.destroy_all
|
157
|
+
::Katello::Pulp3::ContentGuard.destroy_all
|
158
|
+
end
|
159
|
+
|
93
160
|
def create_migrations
|
94
161
|
plan = migration_plan
|
95
162
|
Rails.logger.info("Migration Plan: #{plan}")
|
@@ -103,7 +170,7 @@ module Katello
|
|
103
170
|
end
|
104
171
|
|
105
172
|
def start_migration(plan_href)
|
106
|
-
migration_plan_api.run(plan_href, dry_run: false, validate: true)
|
173
|
+
migration_plan_api.run(plan_href, dry_run: false, validate: true, skip_corrupted: true)
|
107
174
|
end
|
108
175
|
|
109
176
|
def import_repositories(repository_type_label)
|
@@ -114,7 +181,9 @@ module Katello
|
|
114
181
|
if repository_type_label == 'yum'
|
115
182
|
import_yum_repos(imported, katello_repos)
|
116
183
|
else
|
117
|
-
katello_repos.
|
184
|
+
repo_count = katello_repos.count
|
185
|
+
katello_repos.each_with_index do |repo, index|
|
186
|
+
update_import_status("Importing migrated content units #{repository_type_label}: #{index + 1}/#{repo_count}", index)
|
118
187
|
found = imported.find { |migrated_repo| migrated_repo.pulp2_repo_id == repo.pulp_id }
|
119
188
|
import_repo(repo, found) if found
|
120
189
|
end
|
@@ -122,7 +191,9 @@ module Katello
|
|
122
191
|
end
|
123
192
|
|
124
193
|
def import_yum_repos(migrated_repo_items, repos)
|
125
|
-
repos.
|
194
|
+
repo_count = repos.count
|
195
|
+
repos.each_with_index do |yum_repo, index|
|
196
|
+
update_import_status("Importing migrated yum repositories: #{index + 1}/#{repo_count}", index)
|
126
197
|
to_find = nil
|
127
198
|
if yum_repo.content_view.composite?
|
128
199
|
if yum_repo.link?
|
@@ -195,14 +266,16 @@ module Katello
|
|
195
266
|
end
|
196
267
|
|
197
268
|
def operate_on_errata
|
269
|
+
last_migration_time = last_successful_migration_time
|
198
270
|
offset = 0
|
199
|
-
limit =
|
200
|
-
response = pulp2_content_api.list(pulp2_content_type_id: 'erratum', offset: offset, limit: limit)
|
271
|
+
limit = SETTINGS[:katello][:pulp][:bulk_load_size]
|
272
|
+
response = pulp2_content_api.list(pulp2_content_type_id: 'erratum', offset: offset, limit: limit, pulp2_last_updated__gt: last_migration_time)
|
201
273
|
total_count = response.count
|
202
274
|
yield(response.results)
|
203
275
|
until (offset + limit > total_count)
|
204
276
|
offset += limit
|
205
|
-
response = pulp2_content_api.list(pulp2_content_type_id: 'erratum', offset: offset, limit: limit)
|
277
|
+
response = pulp2_content_api.list(pulp2_content_type_id: 'erratum', offset: offset, limit: limit, pulp2_last_updated__gt: last_migration_time)
|
278
|
+
update_import_status("Importing migrated content type erratum: #{offset + limit}/#{total_count}")
|
206
279
|
yield(response.results)
|
207
280
|
end
|
208
281
|
end
|
@@ -231,6 +304,12 @@ module Katello
|
|
231
304
|
on_duplicate_key_update: {conflict_target: [:erratum_id, :repository_id], columns: [:erratum_pulp3_href]})
|
232
305
|
end
|
233
306
|
|
307
|
+
def mark_missing_content(content_type)
|
308
|
+
unless [Katello::DockerTag, Katello::DockerManifest, Katello::Erratum].include?(content_type.model_class)
|
309
|
+
content_type.model_class.where(:migrated_pulp3_href => nil).update_all(:missing_from_migration => true)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
234
313
|
def import_content_type(content_type)
|
235
314
|
if content_type.model_class == Katello::Erratum
|
236
315
|
import_errata
|
@@ -242,11 +321,15 @@ module Katello
|
|
242
321
|
unmigrated_units = unmigrated_units.where(:migrated_pulp3_href => nil)
|
243
322
|
end
|
244
323
|
|
324
|
+
total_count = unmigrated_units.count
|
325
|
+
current_count = 0
|
326
|
+
|
245
327
|
unmigrated_units.select(:id, :pulp_id).find_in_batches(batch_size: GET_QUERY_ID_LENGTH) do |needing_hrefs|
|
328
|
+
current_count += needing_hrefs.count
|
329
|
+
update_import_status("Importing migrated content type #{content_type.label}: #{current_count}/#{total_count}")
|
246
330
|
migrated_units = pulp2_content_api.list(pulp2_id__in: needing_hrefs.map { |unit| unit.pulp_id }.join(','))
|
247
331
|
migrated_units.results.each do |migrated_unit|
|
248
|
-
|
249
|
-
matching_record&.update_column(:migrated_pulp3_href, migrated_unit.pulp3_content)
|
332
|
+
content_type.model_class.where(pulp_id: migrated_unit.pulp2_id).update_all(migrated_pulp3_href: migrated_unit.pulp3_content)
|
250
333
|
end
|
251
334
|
end
|
252
335
|
end
|