katello 3.17.0.rc2.2 → 3.17.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/content_view_versions_controller.rb +9 -1
  3. data/app/controllers/katello/api/v2/host_tracer_controller.rb +16 -36
  4. data/app/controllers/katello/api/v2/hosts_bulk_actions_controller.rb +12 -1
  5. data/app/controllers/katello/concerns/organizations_controller_extensions.rb +23 -0
  6. data/app/lib/actions/katello/content_view/promote.rb +2 -2
  7. data/app/lib/actions/katello/content_view/promote_to_environment.rb +12 -3
  8. data/app/lib/actions/katello/content_view/publish.rb +18 -2
  9. data/app/lib/actions/katello/content_view_version/import.rb +36 -0
  10. data/app/lib/actions/katello/content_view_version/incremental_update.rb +1 -1
  11. data/app/lib/actions/katello/organization/create.rb +1 -1
  12. data/app/lib/actions/katello/organization/simple_content_access/disable.rb +8 -0
  13. data/app/lib/actions/katello/organization/simple_content_access/enable.rb +8 -0
  14. data/app/lib/actions/katello/organization/simple_content_access/toggle.rb +16 -2
  15. data/app/lib/actions/katello/repository/multi_clone_contents.rb +8 -6
  16. data/app/lib/actions/pulp3/abstract_async_task.rb +1 -0
  17. data/app/lib/actions/pulp3/content_view_version/create_importer.rb +20 -0
  18. data/app/lib/actions/pulp3/content_view_version/destroy_importer.rb +16 -0
  19. data/app/lib/actions/pulp3/content_view_version/import.rb +21 -0
  20. data/app/lib/actions/pulp3/orchestration/content_view_version/copy_version_units_to_library.rb +25 -0
  21. data/app/lib/actions/pulp3/orchestration/content_view_version/export.rb +9 -1
  22. data/app/lib/actions/pulp3/orchestration/content_view_version/import.rb +41 -0
  23. data/app/lib/actions/pulp3/repository/copy_content.rb +6 -1
  24. data/app/lib/actions/pulp3/repository/multi_copy_content.rb +1 -1
  25. data/app/lib/katello/resources/cdn.rb +3 -2
  26. data/app/lib/katello/util/cdn_var_substitutor.rb +9 -7
  27. data/app/models/katello/content_view.rb +6 -0
  28. data/app/models/katello/content_view_version.rb +10 -1
  29. data/app/models/katello/glue/pulp/repo.rb +1 -1
  30. data/app/models/katello/root_repository.rb +5 -1
  31. data/app/overrides/add_organization_attributes.rb +12 -0
  32. data/app/services/katello/host_trace_manager.rb +38 -0
  33. data/app/services/katello/pulp3/content_view_version/export.rb +25 -29
  34. data/app/services/katello/pulp3/content_view_version/import.rb +87 -0
  35. data/app/services/katello/pulp3/content_view_version/import_export_common.rb +44 -0
  36. data/app/services/katello/pulp3/repository/yum.rb +72 -4
  37. data/app/services/katello/pulp3/task.rb +4 -4
  38. data/app/services/katello/pulp3/task_group.rb +6 -0
  39. data/app/services/katello/ui_notifications/subscriptions/sca_disable_error.rb +13 -0
  40. data/app/services/katello/ui_notifications/subscriptions/sca_disable_success.rb +13 -0
  41. data/app/services/katello/ui_notifications/subscriptions/sca_enable_error.rb +13 -0
  42. data/app/services/katello/ui_notifications/subscriptions/sca_enable_success.rb +13 -0
  43. data/app/views/overrides/organizations/_edit_override.html.erb +10 -1
  44. data/app/views/overrides/organizations/_index_header_override.html.erb +3 -0
  45. data/app/views/overrides/organizations/_index_row_override.html.erb +3 -0
  46. data/config/routes/api/v2.rb +1 -6
  47. data/config/routes/overrides.rb +4 -0
  48. data/db/seeds.d/109-katello-notification-blueprints.rb +24 -0
  49. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-associations.controller.js +2 -5
  50. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-repository-sets.controller.js +4 -3
  51. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/activation-key-subscriptions.controller.js +2 -4
  52. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-repository-sets.html +1 -1
  53. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/bulk/content-hosts-bulk-traces-modal.controller.js +3 -4
  54. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details-info.controller.js +2 -4
  55. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-repository-sets.controller.js +4 -3
  56. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-subscriptions.controller.js +2 -4
  57. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-repository-sets.html +1 -1
  58. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/hosts/host-bulk-action.factory.js +2 -1
  59. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +1 -1
  60. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +2 -2
  61. data/lib/katello/permission_creator.rb +1 -1
  62. data/lib/katello/permissions/host_permissions.rb +1 -0
  63. data/lib/katello/tasks/pulp3_post_migration_check.rake +2 -1
  64. data/lib/katello/tasks/reimport.rake +1 -1
  65. data/lib/katello/version.rb +1 -1
  66. data/webpack/index.js +0 -1
  67. metadata +19 -5
  68. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/hosts/host-traces-resolve.factory.js +0 -18
@@ -0,0 +1,16 @@
1
+ module Actions
2
+ module Pulp3
3
+ module ContentViewVersion
4
+ class DestroyImporter < Pulp3::Abstract
5
+ input_format do
6
+ param :smart_proxy_id, Integer
7
+ param :importer_data, Hash
8
+ end
9
+
10
+ def run
11
+ ::Katello::Pulp3::ContentViewVersion::Import.new(smart_proxy: smart_proxy).destroy_importer(input[:importer_data][:pulp_href])
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module Actions
2
+ module Pulp3
3
+ module ContentViewVersion
4
+ class Import < Pulp3::AbstractAsyncTask
5
+ input_format do
6
+ param :content_view_version_id, Integer
7
+ param :smart_proxy_id, Integer
8
+ param :importer_data, Hash
9
+ param :path, String
10
+ end
11
+
12
+ def invoke_external_task
13
+ cvv = ::Katello::ContentViewVersion.find(input[:content_view_version_id])
14
+ output[:pulp_tasks] = ::Katello::Pulp3::ContentViewVersion::Import.new(smart_proxy: smart_proxy,
15
+ content_view_version: cvv,
16
+ path: input[:path]).create_import(input[:importer_data][:pulp_href])
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ module Actions
2
+ module Pulp3
3
+ module Orchestration
4
+ module ContentViewVersion
5
+ class CopyVersionUnitsToLibrary < Actions::EntryAction
6
+ def plan(content_view_version)
7
+ concurrence do
8
+ content_view_version.importable_repositories.each do |repo|
9
+ sequence do
10
+ copy_action = plan_action(Actions::Pulp3::Repository::CopyContent, repo, SmartProxy.pulp_primary!,
11
+ repo.library_instance,
12
+ copy_all: true)
13
+ plan_action(Actions::Pulp3::Repository::SaveVersion, repo.library_instance,
14
+ tasks: copy_action.output[:pulp_tasks])
15
+ plan_action(Katello::Repository::IndexContent, id: repo.library_instance_id)
16
+ plan_action(Katello::Repository::MetadataGenerate, repo.library_instance, :force => true)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -50,9 +50,17 @@ module Actions
50
50
  api = ::Katello::Pulp3::Api::Core.new(smart_proxy)
51
51
  export_data = api.export_api.list(input[:exporter_data][:pulp_href]).results.first
52
52
  output[:exported_file_name], output[:exported_file_checksum] = export_data.output_file_info.first
53
+ path = File.dirname(output[:exported_file_name].to_s)
53
54
  ::Katello::ContentViewVersionExportHistory.create!(content_view_version_id: input[:content_view_version_id],
54
55
  destination_server: input[:destination_server],
55
- path: File.dirname(output[:exported_file_name].to_s))
56
+ path: path)
57
+ cvv = ::Katello::ContentViewVersion.find(input[:content_view_version_id])
58
+
59
+ export_metadata = ::Katello::Pulp3::ContentViewVersion::Export.new(:content_view_version => cvv,
60
+ :smart_proxy => smart_proxy).generate_metadata
61
+ toc = Dir.glob("#{path}/*toc.json").first
62
+ export_metadata[:toc] = File.basename(toc) if toc
63
+ File.write("#{path}/#{::Katello::Pulp3::ContentViewVersion::Export::METADATA_FILE}", export_metadata.to_json)
56
64
  end
57
65
 
58
66
  def humanized_name
@@ -0,0 +1,41 @@
1
+ module Actions
2
+ module Pulp3
3
+ module Orchestration
4
+ module ContentViewVersion
5
+ class Import < Actions::EntryAction
6
+ def plan(content_view_version, path:)
7
+ action_subject(content_view_version)
8
+ sequence do
9
+ smart_proxy = SmartProxy.pulp_primary!
10
+ importer_output = plan_action(::Actions::Pulp3::ContentViewVersion::CreateImporter,
11
+ content_view_version_id: content_view_version.id,
12
+ smart_proxy_id: smart_proxy.id,
13
+ path: path).output
14
+
15
+ import_output = plan_action(::Actions::Pulp3::ContentViewVersion::Import,
16
+ content_view_version_id: content_view_version.id,
17
+ smart_proxy_id: smart_proxy.id,
18
+ importer_data: importer_output[:importer_data],
19
+ path: path).output
20
+
21
+ plan_action(Actions::Pulp3::Repository::SaveVersions, content_view_version.importable_repositories.pluck(:id),
22
+ tasks: import_output[:pulp_tasks])
23
+
24
+ plan_action(::Actions::Pulp3::ContentViewVersion::DestroyImporter,
25
+ smart_proxy_id: smart_proxy.id,
26
+ importer_data: importer_output[:importer_data])
27
+ end
28
+ end
29
+
30
+ def humanized_name
31
+ _("Import")
32
+ end
33
+
34
+ def rescue_strategy
35
+ Dynflow::Action::Rescue::Skip
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -11,7 +11,12 @@ module Actions
11
11
  def invoke_external_task
12
12
  source = ::Katello::Repository.find(input[:source_repository_id])
13
13
  target = ::Katello::Repository.find(input[:target_repository_id] || input[:target_repository])
14
- output[:pulp_tasks] = target.backend_service(smart_proxy).copy_content_for_source(source, input)
14
+ service = target.backend_service(smart_proxy)
15
+ output[:pulp_tasks] = if input[:copy_all]
16
+ service.copy_all(source)
17
+ else
18
+ service.copy_content_for_source(source, input)
19
+ end
15
20
  end
16
21
  end
17
22
  end
@@ -17,7 +17,7 @@ module Actions
17
17
  repo_id_map = {}
18
18
 
19
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
20
+ repo_id_map[JSON.parse(source_repo_ids)] = dest_repo_map.deep_dup
21
21
  end
22
22
 
23
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)
@@ -18,7 +18,7 @@ module Katello
18
18
  class CdnResource
19
19
  CDN_DOCKER_CONTAINER_LISTING = "CONTAINER_REGISTRY_LISTING".freeze
20
20
 
21
- attr_reader :url, :product, :options
21
+ attr_reader :url, :product, :options, :proxy
22
22
 
23
23
  def substitutor(logger = nil)
24
24
  @logger = logger
@@ -26,6 +26,7 @@ module Katello
26
26
  end
27
27
 
28
28
  def initialize(url, options = {})
29
+ @proxy = ::HttpProxy.default_global_content_proxy
29
30
  @ssl_version = Setting[:cdn_ssl_version]
30
31
  if @ssl_version && !SUPPORTED_SSL_VERSIONS.include?(@ssl_version)
31
32
  fail("Invalid SSL version specified. Check the 'CDN SSL Version' setting")
@@ -140,7 +141,7 @@ module Katello
140
141
  end
141
142
 
142
143
  def net_http_class
143
- if (proxy = ::HttpProxy.default_global_content_proxy)
144
+ if self.proxy
144
145
  uri = URI(proxy.url) #Net::HTTP::Proxy ignores port as part of the url
145
146
  Net::HTTP::Proxy("#{uri.host}#{uri.path}", uri.port, proxy.username, proxy.password)
146
147
  else
@@ -59,15 +59,17 @@ module Katello
59
59
 
60
60
  return resolved if to_resolve.empty?
61
61
 
62
- futures = to_resolve.map do |path_with_substitution|
63
- Concurrent::Promises.future do
64
- path_with_substitution.resolve_substitutions(@resource)
62
+ to_resolve.in_groups_of(8) do |group|
63
+ futures = group.map do |path_with_substitution|
64
+ Concurrent::Promises.future do
65
+ path_with_substitution.resolve_substitutions(@resource)
66
+ end
65
67
  end
66
- end
67
68
 
68
- futures.each do |future|
69
- resolved << future.value
70
- Rails.logger.error("Failed at scanning for repository: #{future.reason}") if future.rejected?
69
+ futures.each do |future|
70
+ resolved << future.value
71
+ Rails.logger.error("Failed at scanning for repository: #{future.reason}") if future.rejected?
72
+ end
71
73
  end
72
74
 
73
75
  find_substitutions(resolved.compact.flatten)
@@ -579,6 +579,12 @@ module Katello
579
579
  PuppetModule.group_by_repoid(puppet_modules.flatten)
580
580
  end
581
581
 
582
+ def check_ready_to_import!
583
+ fail _("User must be logged in.") if ::User.current.nil?
584
+ fail _("Cannot import a composite content view") if composite?
585
+ true
586
+ end
587
+
582
588
  def check_ready_to_publish!
583
589
  fail _("User must be logged in.") if ::User.current.nil?
584
590
  fail _("Cannot publish default content view") if default?
@@ -1,4 +1,5 @@
1
1
  module Katello
2
+ # rubocop:disable Metrics/ClassLength
2
3
  class ContentViewVersion < Katello::Model
3
4
  include Authorization::ContentViewVersion
4
5
  include ForemanTasks::Concerns::ActionSubject
@@ -25,7 +26,7 @@ module Katello
25
26
  has_many :export_histories, :class_name => "Katello::ContentViewVersionExportHistory", :dependent => :destroy,
26
27
  :inverse_of => :content_view_version, :foreign_key => :content_view_version_id
27
28
 
28
- has_many :repositories, :class_name => "Katello::Repository", :dependent => :destroy
29
+ has_many :repositories, :class_name => "::Katello::Repository", :dependent => :destroy
29
30
  has_many :content_view_puppet_environments, :class_name => "Katello::ContentViewPuppetEnvironment",
30
31
  :dependent => :destroy
31
32
  has_one :task_status, :class_name => "Katello::TaskStatus", :as => :task_owner, :dependent => :destroy
@@ -357,6 +358,14 @@ module Katello
357
358
  true
358
359
  end
359
360
 
361
+ def importable_repositories
362
+ if default?
363
+ repositories.yum_type
364
+ else
365
+ archived_repos.yum_type
366
+ end
367
+ end
368
+
360
369
  def before_promote_hooks
361
370
  run_callbacks :sync do
362
371
  logger.debug "custom hook before_promote on #{name} will be executed if defined."
@@ -369,7 +369,7 @@ module Katello
369
369
  pulp_uri = URI.parse(smart_proxy ? smart_proxy.url : SETTINGS[:katello][:pulp][:url])
370
370
  scheme = (self.unprotected && !force_https) ? 'http' : 'https'
371
371
  if docker?
372
- "#{pulp_uri.host.downcase}:#{Setting['pulp_docker_registry_port']}/#{container_repository_name}"
372
+ "#{pulp_uri.host.downcase}/#{container_repository_name}"
373
373
  elsif file?
374
374
  "#{scheme}://#{pulp_uri.host.downcase}/pulp/isos/#{relative_path}/"
375
375
  elsif puppet?
@@ -321,7 +321,11 @@ module Katello
321
321
 
322
322
  def format_arches
323
323
  if content_type == ::Katello::Repository::DEB_TYPE
324
- self.deb_architectures
324
+ # FIXME: This should be set to self.deb_architectures but it needs to have the
325
+ # subscription-manager PR https://github.com/candlepin/subscription-manager/pull/2213
326
+ # merged. Otherwise subscription-manager returns _NO_ debian repository as described in
327
+ # https://community.theforeman.org/t/katello-3-16-1-1-el7-subscription-manager-doesnt-create-rhsm-repos-for-ubuntu/20928/38
328
+ nil
325
329
  else
326
330
  self.arch == "noarch" ? nil : self.arch
327
331
  end
@@ -22,3 +22,15 @@ Deface::Override.new(:virtual_path => "taxonomies/_form",
22
22
  :name => "add_organization_attributes_on_edit",
23
23
  :insert_after => 'erb[loud]:contains("text_f"):contains(":name")',
24
24
  :partial => 'overrides/organizations/edit_override')
25
+
26
+ # Add Simple Content Access column to org table
27
+ Deface::Override.new(:virtual_path => "taxonomies/index",
28
+ :name => "add_sca_column_on_index",
29
+ :insert_before => 'table th:last-child', # make it the second-to-last column
30
+ :partial => 'overrides/organizations/index_header_override')
31
+
32
+ # Add Simple Content Access cells to org table
33
+ Deface::Override.new(:virtual_path => "taxonomies/index",
34
+ :name => "add_sca_attributes_on_index",
35
+ :insert_before => 'tbody td:last-child',
36
+ :partial => 'overrides/organizations/index_row_override')
@@ -0,0 +1,38 @@
1
+ module Katello
2
+ class HostTraceManager
3
+ def self.resolve_traces(traces)
4
+ traces.each do |trace|
5
+ if trace.reboot_required?
6
+ trace.helper = 'reboot'
7
+ end
8
+ end
9
+
10
+ traces_by_host_id = traces.group_by(&:host_id)
11
+ traces_by_helper = traces.group_by(&:helper)
12
+
13
+ composers = []
14
+
15
+ if traces_by_host_id.size < traces_by_helper.size
16
+ traces_by_host_id.each do |host_id, trace|
17
+ needed_traces = trace.map(&:helper).join(',')
18
+ joined_helpers = { :helper => needed_traces }
19
+ composers << ::JobInvocationComposer.for_feature(:katello_service_restart, [host_id], joined_helpers)
20
+ end
21
+ else
22
+ traces_by_helper.each do |helper, trace|
23
+ helpers = { :helper => helper }
24
+ composers << ::JobInvocationComposer.for_feature(:katello_service_restart, trace.map(&:host_id), helpers)
25
+ end
26
+ end
27
+
28
+ job_invocations = []
29
+
30
+ composers.each do |composer|
31
+ composer.trigger
32
+ job_invocations << composer.job_invocation
33
+ end
34
+
35
+ job_invocations
36
+ end
37
+ end
38
+ end
@@ -2,20 +2,15 @@ module Katello
2
2
  module Pulp3
3
3
  module ContentViewVersion
4
4
  class Export
5
+ include ImportExportCommon
6
+ METADATA_FILE = "metadata.json".freeze
7
+
5
8
  def initialize(smart_proxy:, content_view_version: nil, destination_server: nil)
6
9
  @smart_proxy = smart_proxy
7
10
  @content_view_version = content_view_version
8
11
  @destination_server = destination_server
9
12
  end
10
13
 
11
- def exporter_name
12
- @content_view_version.name.gsub(/\s/, '_')
13
- end
14
-
15
- def generate_exporter_id
16
- "#{@content_view_version.organization.label}_#{exporter_name}"
17
- end
18
-
19
14
  def generate_exporter_path
20
15
  export_path = "#{@content_view_version.content_view}/#{@content_view_version.version}/#{@destination_server}/#{date_dir}".gsub(/\s/, '_')
21
16
  "#{@content_view_version.organization.label}/#{export_path}"
@@ -25,28 +20,8 @@ module Katello
25
20
  DateTime.now.to_s.gsub(/\W/, '-')
26
21
  end
27
22
 
28
- def api
29
- ::Katello::Pulp3::Api::Core.new(@smart_proxy)
30
- end
31
-
32
- def repository_hrefs
33
- version_hrefs.map { |href| version_href_to_repository_href(href) }.uniq
34
- end
35
-
36
- def version_hrefs
37
- if @content_view_version.default?
38
- @content_view_version.repositories.yum_type.pluck(:version_href).compact
39
- else
40
- @content_view_version.archived_repos.yum_type.pluck(:version_href).compact
41
- end
42
- end
43
-
44
- def version_href_to_repository_href(version_href)
45
- version_href.split("/")[0..-3].join("/") + "/"
46
- end
47
-
48
23
  def create_exporter(export_base_dir: Setting['pulpcore_export_destination'])
49
- api.exporter_api.create(name: generate_exporter_id,
24
+ api.exporter_api.create(name: generate_id,
50
25
  path: "#{export_base_dir}/#{generate_exporter_path}",
51
26
  repositories: repository_hrefs)
52
27
  end
@@ -65,6 +40,27 @@ module Katello
65
40
  api.export_api.delete(export_data.pulp_href) unless export_data.blank?
66
41
  api.exporter_api.delete(exporter_href)
67
42
  end
43
+
44
+ def generate_metadata
45
+ ret = { organization: @content_view_version.organization.name,
46
+ repository_mapping: {},
47
+ content_view: @content_view_version.content_view.name,
48
+ content_view_version: {
49
+ major: @content_view_version.major,
50
+ minor: @content_view_version.minor
51
+ }
52
+ }
53
+ repositories.each do |repo|
54
+ next if repo.version_href.blank?
55
+ pulp3_repo = fetch_repository_info(repo.version_href).name
56
+ ret[:repository_mapping][pulp3_repo] = {
57
+ repository: repo.root.name,
58
+ product: repo.root.product.name,
59
+ redhat: repo.redhat?
60
+ }
61
+ end
62
+ ret
63
+ end
68
64
  end
69
65
  end
70
66
  end
@@ -0,0 +1,87 @@
1
+ module Katello
2
+ module Pulp3
3
+ module ContentViewVersion
4
+ class Import
5
+ include ImportExportCommon
6
+ BASEDIR = '/var/lib/pulp'.freeze
7
+
8
+ def initialize(smart_proxy:, content_view_version: nil, path: nil)
9
+ @smart_proxy = smart_proxy
10
+ @content_view_version = content_view_version
11
+ @path = path
12
+ end
13
+
14
+ def repository_mapping
15
+ mapping = {}
16
+ metadata[:repository_mapping].each do |key, value|
17
+ repo = @content_view_version.importable_repositories.joins(:root, :product).
18
+ where("#{::Katello::Product.table_name}" => {:name => value[:product]},
19
+ "#{::Katello::RootRepository.table_name}" => {:name => value[:repository]}).first
20
+ next unless repo&.version_href
21
+ repo_info = fetch_repository_info(repo.version_href)
22
+ mapping[key] = repo_info.name
23
+ end
24
+ mapping
25
+ end
26
+
27
+ def create_importer
28
+ api.importer_api.create(name: generate_id,
29
+ repo_mapping: repository_mapping)
30
+ end
31
+
32
+ def create_import(importer_href)
33
+ [api.import_api.create(importer_href, toc: "#{@path}/#{metadata[:toc]}")]
34
+ end
35
+
36
+ def fetch_import(importer_href)
37
+ api.import_api.list(importer_href).results.first
38
+ end
39
+
40
+ def destroy_importer(importer_href)
41
+ import_data = fetch_import(importer_href)
42
+ api.import_api.delete(import_data.pulp_href) unless import_data.blank?
43
+ api.importer_api.delete(importer_href)
44
+ end
45
+
46
+ def metadata
47
+ @metadata ||= self.class.metadata(@path)
48
+ end
49
+
50
+ class << self
51
+ def metadata(path)
52
+ JSON.parse(File.read("#{path}/#{Export::METADATA_FILE}")).with_indifferent_access
53
+ end
54
+
55
+ def check_permissions!(path)
56
+ fail _("Invalid path specified.") if path.blank? || !File.directory?(path)
57
+ fail _("The import path must be in a subdirectory under '%s'." % BASEDIR) unless path.starts_with?(BASEDIR)
58
+ metadata_file = "#{path}/#{::Katello::Pulp3::ContentViewVersion::Export::METADATA_FILE}"
59
+ fail _("Could not find metadata.json at '%s'." % metadata_file) unless File.exist?(metadata_file)
60
+ fail _("Unable to read the metadata.json at '%s'." % metadata_file) unless File.readable?(metadata_file)
61
+ fail _("Pulp user or group unable to read content in '%s'." % path) unless pulp_user_accessible?(path)
62
+ Dir.glob("#{path}/*").each do |file|
63
+ next if file == metadata_file
64
+ fail _("Pulp user or group unable to read '%s'." % file) unless pulp_user_accessible?(file)
65
+ end
66
+ end
67
+
68
+ def pulp_user_accessible?(path)
69
+ pulp_info = fetch_pulp_user_info
70
+ return false if pulp_info.blank?
71
+
72
+ stat = File.stat(path)
73
+ stat.gid.to_s == pulp_info.gid ||
74
+ stat.uid.to_s == pulp_info.uid ||
75
+ stat.mode.to_s(8)[-1].to_i >= 4
76
+ end
77
+
78
+ def fetch_pulp_user_info
79
+ pulp_user = nil
80
+ Etc.passwd { |u| pulp_user = u if u.name == 'pulp' }
81
+ pulp_user
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end