katello 4.9.1 → 4.9.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.

Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/katello/api/v2/host_subscriptions_controller.rb +1 -1
  3. data/app/controllers/katello/api/v2/products_controller.rb +4 -4
  4. data/app/controllers/katello/api/v2/repositories_bulk_actions_controller.rb +12 -5
  5. data/app/controllers/katello/api/v2/repositories_controller.rb +10 -7
  6. data/app/controllers/katello/concerns/content_facet_hosts_controller_extensions.rb +7 -9
  7. data/app/helpers/katello/hosts_and_hostgroups_helper.rb +13 -1
  8. data/app/lib/actions/katello/agent_action.rb +4 -3
  9. data/app/lib/actions/katello/bulk_agent_action.rb +4 -1
  10. data/app/lib/actions/katello/content_view_environment/destroy.rb +5 -3
  11. data/app/lib/actions/katello/content_view_version/destroy.rb +5 -1
  12. data/app/lib/actions/katello/host/update_content_view.rb +4 -2
  13. data/app/lib/actions/katello/product/destroy.rb +15 -11
  14. data/app/lib/actions/katello/repository/destroy.rb +10 -2
  15. data/app/lib/actions/katello/repository/index_content.rb +0 -1
  16. data/app/lib/actions/katello/repository/sync.rb +1 -3
  17. data/app/lib/actions/katello/repository/verify_checksum.rb +2 -10
  18. data/app/lib/actions/pulp3/orchestration/repository/generate_metadata.rb +12 -5
  19. data/app/models/katello/candlepin/repository_mapper.rb +1 -0
  20. data/app/models/katello/concerns/host_managed_extensions.rb +55 -3
  21. data/app/models/katello/content_view.rb +16 -2
  22. data/app/models/katello/docker_meta_tag.rb +3 -1
  23. data/app/models/katello/host/content_facet.rb +3 -1
  24. data/app/models/katello/kt_environment.rb +1 -1
  25. data/app/models/katello/product_content.rb +14 -1
  26. data/app/models/katello/repository.rb +1 -0
  27. data/app/views/katello/api/v2/products/show.json.rabl +3 -0
  28. data/app/views/katello/api/v2/repositories/base.json.rabl +18 -0
  29. data/app/views/katello/api/v2/repository_sets/show.json.rabl +2 -2
  30. data/app/views/overrides/activation_keys/_host_environment_select.html.erb +4 -5
  31. data/db/migrate/20220228173251_remove_drpm_from_ignorable_content.rb +1 -0
  32. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/common/views/katello-agent-notice.html +1 -1
  33. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-errata.html +0 -2
  34. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-actions.html +0 -1
  35. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-applicable.html +0 -1
  36. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content/views/content-host-packages-installed.html +0 -2
  37. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/content-hosts.controller.js +4 -2
  38. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/content-host-details.controller.js +4 -2
  39. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-details.html +1 -0
  40. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/views/content-hosts.html +4 -0
  41. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/product-details.controller.js +2 -0
  42. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/repository-details.controller.js +17 -4
  43. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-details.html +55 -6
  44. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/details/views/repository-info.html +2 -2
  45. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +2 -2
  46. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/views/product-repositories.html +4 -1
  47. data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/views/product-details.html +5 -0
  48. data/lib/katello/version.rb +1 -1
  49. data/webpack/components/extensions/HostDetails/Tabs/ErrataTab/ErrataTab.js +4 -0
  50. data/webpack/components/extensions/HostDetails/Tabs/PackagesTab/PackagesTab.js +4 -0
  51. data/webpack/components/extensions/HostDetails/common/KatelloAgentDeprecationAlert.js +23 -0
  52. data/webpack/scenes/AlternateContentSources/Create/Steps/AcsUrlPaths.js +1 -1
  53. data/webpack/scenes/AlternateContentSources/Details/EditModals/ACSEditURLPaths.js +1 -1
  54. data/webpack/scenes/ContentViews/Details/Versions/Compare/CVVersionCompareConfig.js +1 -1
  55. data/webpack/scenes/RedHatRepositories/__tests__/__snapshots__/RedHatRepositoriesPage.test.js.snap +0 -8
  56. data/webpack/scenes/Subscriptions/__tests__/__snapshots__/SubscriptionsPage.test.js.snap +0 -8
  57. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2725e254c69e3a52955ec2e85605097ad13751770b46de79a14bb6153451e5b7
4
- data.tar.gz: a59ffe3ac6b743b36ac2207a44c333dc504975b54d23efb2d9d04aa13741c575
3
+ metadata.gz: feee4d277c7c10e872fb0a6b78e3b1c3c774f108b5c6d2dd715bfc5519e9e2be
4
+ data.tar.gz: 91fa39a6da658fa21bb51ca6eab3c4080d8098654ae731194861457f7e7ce9cc
5
5
  SHA512:
6
- metadata.gz: 78951d090b4e05283c65ebb11d2c18475ffc2afa26cb2c1f981a425f18cd85bf9a82c84c06e33dc8c05348a1b9f8af845adb482fd0075116f75da85c847e5d31
7
- data.tar.gz: 5c2acdd95ed253669357a68142f42c8b09ba5b34603bfa9acf1e029cdc32c9696d1edb40a8e616e032747c6771110ca54bd048b4108a342d755b1d000270766c
6
+ metadata.gz: 70fc4051a751c9f8df528de6a4acf4ca9588a60cecc7297dd7a826b01adfc22f5ea3994457a535e4b8405f5873d7307e4e6e126c8413e4f061c7cc39a11aa926
7
+ data.tar.gz: '09b5eb9678d9028bfb96fe4a293ecad609b2d01b9889a1f4dda6002f27bb8db0259229560bc7b42f18a9ea7e2a52404f9b6f2c5e295c74a00bc515e9eb7ec5f6'
@@ -81,7 +81,7 @@ module Katello
81
81
  def create
82
82
  rhsm_params = params_to_rhsm_params
83
83
 
84
- host = Katello::RegistrationManager.process_registration(rhsm_params, @content_view_environment)
84
+ host = Katello::RegistrationManager.process_registration(rhsm_params, [@content_view_environment])
85
85
  host.reload
86
86
  ::Katello::Host::SubscriptionFacet.update_facts(host, rhsm_params[:facts]) unless rhsm_params[:facts].blank?
87
87
 
@@ -17,10 +17,10 @@ module Katello
17
17
 
18
18
  def_param_group :product do
19
19
  param :description, String, :desc => N_("Product description")
20
- param :gpg_key_id, :number, :desc => N_("Identifier of the GPG key")
21
- param :ssl_ca_cert_id, :number, :desc => N_("Idenifier of the SSL CA Cert")
22
- param :ssl_client_cert_id, :number, :desc => N_("Identifier of the SSL Client Cert")
23
- param :ssl_client_key_id, :number, :desc => N_("Identifier of the SSL Client Key")
20
+ param :gpg_key_id, :number, :desc => N_("Identifier of the GPG key"), :allow_nil => true
21
+ param :ssl_ca_cert_id, :number, :desc => N_("Idenifier of the SSL CA Cert"), :allow_nil => true
22
+ param :ssl_client_cert_id, :number, :desc => N_("Identifier of the SSL Client Cert"), :allow_nil => true
23
+ param :ssl_client_key_id, :number, :desc => N_("Identifier of the SSL Client Key"), :allow_nil => true
24
24
  param :sync_plan_id, :number, :desc => N_("Plan numeric identifier"), :allow_nil => true
25
25
  end
26
26
 
@@ -7,7 +7,7 @@ module Katello
7
7
  def destroy_repositories
8
8
  deletion_authorized_repositories = @repositories.deletable
9
9
  unpromoted_repos = deletion_authorized_repositories.reject { |repo| repo.promoted? && repo.content_views.generated_for_none.exists? }
10
-
10
+ unpromoted_repos_non_last_affected_repo = unpromoted_repos.reject { |repo| repo.filters.any? { |filter| filter.repositories.size == 1 } }
11
11
  messages1 = format_bulk_action_messages(
12
12
  :success => "",
13
13
  :error => _("You do not have permissions to delete %s"),
@@ -17,16 +17,23 @@ module Katello
17
17
 
18
18
  messages2 = format_bulk_action_messages(
19
19
  :success => "",
20
- :error => _("Repository %s cannot be deleted since it has already been included in a published Content View."),
20
+ :error => _("Repository %s cannot be deleted since it has already been included in a published Content View. Use repository details page to delete"),
21
21
  :models => deletion_authorized_repositories,
22
22
  :authorized => unpromoted_repos
23
23
  )
24
24
 
25
- errors = messages1[:error] + messages2[:error]
25
+ messages3 = format_bulk_action_messages(
26
+ :success => "",
27
+ :error => _("Repository %s cannot be deleted since it is the last affected repository in a filter. Use repository details page to delete."),
28
+ :models => unpromoted_repos,
29
+ :authorized => unpromoted_repos_non_last_affected_repo
30
+ )
31
+
32
+ errors = messages1[:error] + messages2[:error] + messages3[:error]
26
33
 
27
34
  task = nil
28
- if unpromoted_repos.any?
29
- task = async_task(::Actions::BulkAction, ::Actions::Katello::Repository::Destroy, unpromoted_repos)
35
+ if unpromoted_repos_non_last_affected_repo.any?
36
+ task = async_task(::Actions::BulkAction, ::Actions::Katello::Repository::Destroy, unpromoted_repos_non_last_affected_repo)
30
37
  else
31
38
  status = 400
32
39
  end
@@ -41,12 +41,12 @@ module Katello
41
41
 
42
42
  def_param_group :repo do
43
43
  param :url, String, :desc => N_("repository source url")
44
- param :os_versions, Array,
45
- :desc => N_("Identifies whether the repository should be disabled on a client with a non-matching OS version. Pass [] to enable regardless of OS version. Maximum length 1; allowed tags are: %s") % Katello::RootRepository::ALLOWED_OS_VERSIONS.join(', ')
46
- param :gpg_key_id, :number, :desc => N_("id of the gpg key that will be assigned to the new repository")
47
- param :ssl_ca_cert_id, :number, :desc => N_("Identifier of the content credential containing the SSL CA Cert")
48
- param :ssl_client_cert_id, :number, :desc => N_("Identifier of the content credential containing the SSL Client Cert")
49
- param :ssl_client_key_id, :number, :desc => N_("Identifier of the content credential containing the SSL Client Key")
44
+ param :os_versions, Array, :desc => N_("Identifies whether the repository should be unavailable on a client with a non-matching OS version.
45
+ Pass [] to make repo available for clients regardless of OS version. Maximum length 1; allowed tags are: %s") % Katello::RootRepository::ALLOWED_OS_VERSIONS.join(', ')
46
+ param :gpg_key_id, :number, :desc => N_("id of the gpg key that will be assigned to the new repository"), :allow_nil => true
47
+ param :ssl_ca_cert_id, :number, :desc => N_("Identifier of the content credential containing the SSL CA Cert"), :allow_nil => true
48
+ param :ssl_client_cert_id, :number, :desc => N_("Identifier of the content credential containing the SSL Client Cert"), :allow_nil => true
49
+ param :ssl_client_key_id, :number, :desc => N_("Identifier of the content credential containing the SSL Client Key"), :allow_nil => true
50
50
  param :unprotected, :bool, :desc => N_("true if this repository can be published via HTTP")
51
51
  param :checksum_type, String, :desc => N_("Checksum of the repository, currently 'sha1' & 'sha256' are supported")
52
52
  param :docker_upstream_name, String, :desc => N_("Name of the upstream docker repository")
@@ -416,9 +416,12 @@ module Katello
416
416
  api :DELETE, "/repositories/:id", N_("Destroy a custom repository")
417
417
  param :id, :number, :required => true
418
418
  param :remove_from_content_view_versions, :bool, :required => false, :desc => N_("Force delete the repository by removing it from all content view versions")
419
+ param :delete_empty_repo_filters, :bool, :required => false, :desc => N_("Delete content view filters that have this repository as the last associated repository. Defaults to true. If false, such filters will now apply to all repositories in the content view.")
419
420
  def destroy
420
421
  sync_task(::Actions::Katello::Repository::Destroy, @repository,
421
- remove_from_content_view_versions: ::Foreman::Cast.to_bool(params.fetch(:remove_from_content_view_versions, false)))
422
+ remove_from_content_view_versions: ::Foreman::Cast.to_bool(params.fetch(:remove_from_content_view_versions, false)),
423
+ delete_empty_repo_filters: ::Foreman::Cast.to_bool(params.fetch(:delete_empty_repo_filters, true))
424
+ )
422
425
  respond_for_destroy
423
426
  end
424
427
 
@@ -6,17 +6,15 @@ module Katello
6
6
  before_action :set_up_content_view_environment, only: [:update]
7
7
 
8
8
  def set_up_content_view_environment
9
- return unless params[:host] && params[:host][:content_facet_attributes]
9
+ return unless @host&.content_facet.present? && params[:host]&.[](:content_facet_attributes)&.present?
10
10
  cv_id = params[:host][:content_facet_attributes].delete(:content_view_id)
11
11
  env_id = params[:host][:content_facet_attributes].delete(:lifecycle_environment_id)
12
- Rails.logger.info "set_up_content_view_environment: cv_id=#{cv_id}, env_id=#{env_id}"
13
- if (cv_id.present? && env_id.present?)
14
- @host.content_facet.assign_single_environment(
15
- lifecycle_environment_id: env_id,
16
- content_view_id: cv_id
17
- )
18
- Rails.logger.info "set_up_content_view_environment: done"
19
- end
12
+ Rails.logger.info "#{__method__}: cv_id=#{cv_id}, env_id=#{env_id}"
13
+ @host.content_facet.assign_single_environment(
14
+ lifecycle_environment_id: env_id,
15
+ content_view_id: cv_id
16
+ )
17
+ Rails.logger.info "#{__method__}: done"
20
18
  end
21
19
  end
22
20
  end
@@ -4,6 +4,18 @@ module Katello
4
4
  "kt_activation_keys"
5
5
  end
6
6
 
7
+ def edit_action?
8
+ params[:action] == 'edit'
9
+ end
10
+
11
+ def cv_lce_disabled?
12
+ edit_action? && !using_discovered_hosts_page?
13
+ end
14
+
15
+ def using_discovered_hosts_page?
16
+ controller.controller_name == "discovered_hosts"
17
+ end
18
+
7
19
  def using_hostgroups_page?
8
20
  controller.controller_name == "hostgroups"
9
21
  end
@@ -164,7 +176,7 @@ module Katello
164
176
 
165
177
  views = []
166
178
  if lifecycle_environment
167
- views = Katello::ContentView.in_environment(lifecycle_environment).readable.order(:name)
179
+ views = Katello::ContentView.in_environment(lifecycle_environment).ignore_generated.readable.order(:name)
168
180
  views |= [content_view] if content_view.present? && content_view.in_environment?(lifecycle_environment)
169
181
  elsif content_view
170
182
  views = [content_view]
@@ -14,8 +14,10 @@ module Actions
14
14
 
15
15
  def plan(host, options)
16
16
  action_subject(host, :hostname => host.name, :content => options[:content])
17
-
18
- dispatch_history_id = options.dig(:dispatch_histories, host.id.to_s) || ::Katello::Agent::Dispatcher.create_histories(
17
+ # options[:dispatch_histories] keys might be strings or integers
18
+ dispatch_history_id = options.dig(:dispatch_histories, host.id.to_s) ||
19
+ options.dig(:dispatch_histories, host.id.to_i) ||
20
+ ::Katello::Agent::Dispatcher.create_histories(
19
21
  host_ids: [host.id]
20
22
  ).first.id
21
23
 
@@ -44,7 +46,6 @@ module Actions
44
46
  history.dynflow_execution_plan_id = suspended_action.execution_plan_id
45
47
  history.dynflow_step_id = suspended_action.step_id
46
48
  history.save!
47
-
48
49
  dispatch_message(history) unless input[:bulk]
49
50
 
50
51
  schedule_timeout(timeout, optional: true)
@@ -21,7 +21,10 @@ module Actions
21
21
 
22
22
  def spawn_plans
23
23
  args = input[:args].first
24
- histories = ::Katello::Agent::DispatchHistory.where(id: args[:dispatch_histories].slice(*current_batch.map(&:to_s)).values)
24
+ # args[:dispatch_histories] keys are numeric host ids; they may be integer or string
25
+ # Hash#slice will return a filtered hash only with the specified keys, and ignore keys that don't exist
26
+ possible_keys = [*current_batch.map(&:to_i), *current_batch.map(&:to_s)]
27
+ histories = ::Katello::Agent::DispatchHistory.where(id: args[:dispatch_histories].slice(*possible_keys).values)
25
28
  ::Katello::Agent::Dispatcher.dispatch(
26
29
  args[:type].to_sym,
27
30
  histories,
@@ -8,19 +8,20 @@ module Actions
8
8
  content_view = cv_env.content_view
9
9
  environment = cv_env.environment
10
10
  content_view.check_remove_from_environment!(environment) unless organization_destroy
11
-
11
+ docker_cleanup = false
12
12
  sequence do
13
13
  concurrence do
14
14
  unless skip_repo_destroy
15
15
  content_view.repos(environment).each do |repo|
16
16
  # no need to update the content view environment since it's
17
17
  # getting destroyed so skip_environment_update
18
- plan_action(Repository::Destroy, repo, skip_environment_update: true)
18
+ plan_action(Repository::Destroy, repo, skip_environment_update: true, docker_cleanup: false)
19
+ docker_cleanup ||= repo.docker?
19
20
  end
20
21
  end
21
22
  end
22
23
  plan_action(Candlepin::Environment::Destroy, cp_id: cv_env.cp_id) unless organization_destroy
23
- plan_self(:id => cv_env.id)
24
+ plan_self(:id => cv_env.id, :docker_cleanup => docker_cleanup)
24
25
  end
25
26
  end
26
27
 
@@ -31,6 +32,7 @@ module Actions
31
32
  else
32
33
  cv_env.destroy!
33
34
  end
35
+ ::Katello::DockerMetaTag.cleanup_tags if input[:docker_cleanup]
34
36
  end
35
37
  end
36
38
  end
@@ -7,22 +7,26 @@ module Actions
7
7
 
8
8
  destroy_env_content = !options.fetch(:skip_destroy_env_content, false)
9
9
  repos = destroy_env_content ? version.repositories : version.archived_repos
10
+ docker_cleanup = false
10
11
 
11
12
  sequence do
12
13
  concurrence do
13
14
  repos.each do |repo|
14
15
  repo_options = options.clone
16
+ repo_options[:docker_cleanup] = false
15
17
  plan_action(Repository::Destroy, repo, repo_options)
18
+ docker_cleanup ||= repo.docker?
16
19
  end
17
20
  end
18
21
  end
19
22
 
20
- plan_self(:id => version.id)
23
+ plan_self(:id => version.id, :docker_cleanup => docker_cleanup)
21
24
  end
22
25
 
23
26
  def finalize
24
27
  version = ::Katello::ContentViewVersion.find_by(id: input[:id])
25
28
  version&.destroy!
29
+ ::Katello::DockerMetaTag.cleanup_tags if input[:docker_cleanup]
26
30
  end
27
31
  end
28
32
  end
@@ -4,8 +4,10 @@ module Actions
4
4
  class UpdateContentView < Actions::EntryAction
5
5
  def plan(host, content_view_id, lifecycle_environment_id)
6
6
  if host.content_facet
7
- host.content_facet.content_view = ::Katello::ContentView.find(content_view_id)
8
- host.content_facet.lifecycle_environment = ::Katello::KTEnvironment.find(lifecycle_environment_id)
7
+ host.content_facet.assign_single_environment(
8
+ content_view_id: content_view_id,
9
+ lifecycle_environment_id: lifecycle_environment_id
10
+ )
9
11
  host.update_candlepin_associations
10
12
  plan_self(:hostname => host.name)
11
13
  else
@@ -2,21 +2,11 @@ module Actions
2
2
  module Katello
3
3
  module Product
4
4
  class Destroy < Actions::EntryAction
5
- # rubocop:disable Metrics/MethodLength
6
5
  def plan(product, options = {})
7
6
  organization_destroy = options.fetch(:organization_destroy, false)
8
7
  skip_environment_update = options.fetch(:skip_environment_update, false) ||
9
8
  options.fetch(:organization_destroy, false)
10
-
11
- unless organization_destroy || product.user_deletable?
12
- if product.redhat?
13
- fail _("Cannot delete Red Hat product: %{product}") % { :product => product.name }
14
- elsif !product.published_content_view_versions.not_ignorable.empty?
15
- fail _("Cannot delete product with repositories published in a content view. Product: %{product}, %{view_versions}") %
16
- { :product => product.name, :view_versions => view_versions(product) }
17
- end
18
- end
19
-
9
+ check_ready_to_delete(product, organization_destroy)
20
10
  action_subject(product)
21
11
 
22
12
  # Candlepin::Product::ContentRemove is called with Katello::Repository::Destroy, so we only want to run ContentRemove
@@ -99,6 +89,20 @@ module Actions
99
89
  end
100
90
  results.join(', ')
101
91
  end
92
+
93
+ def check_ready_to_delete(product, organization_destroy)
94
+ unless organization_destroy || product.user_deletable?
95
+ if product.redhat?
96
+ fail _("Cannot delete Red Hat product: %{product}") % { :product => product.name }
97
+ elsif !product.published_content_view_versions.not_ignorable.empty?
98
+ fail _("Cannot delete product with repositories published in a content view. Product: %{product}, %{view_versions}") %
99
+ { :product => product.name, :view_versions => view_versions(product) }
100
+ elsif product.repositories.any? { |repo| repo.filters.any? { |filter| filter.repositories.size == 1 } }
101
+ fail _("Cannot delete product: %{product} with repositories that are the last affected repository in content view filters. Delete these repositories before deleting product.") %
102
+ { :product => product.name }
103
+ end
104
+ end
105
+ end
102
106
  end
103
107
  end
104
108
  end
@@ -15,6 +15,8 @@ module Actions
15
15
  options.fetch(:organization_destroy, false)
16
16
  destroy_content = options.fetch(:destroy_content, true)
17
17
  remove_from_content_view_versions = options.fetch(:remove_from_content_view_versions, false)
18
+ delete_empty_repo_filters = options.fetch(:delete_empty_repo_filters, true)
19
+ docker_cleanup = options.fetch(:docker_cleanup, true)
18
20
  action_subject(repository)
19
21
  check_destroyable!(repository, remove_from_content_view_versions)
20
22
  remove_generated_content_views(repository)
@@ -29,8 +31,9 @@ module Actions
29
31
 
30
32
  handle_acs_product_removal(repository)
31
33
  handle_alternate_content_sources(repository)
34
+ delete_empty_repo_filters(repository) if delete_empty_repo_filters
32
35
 
33
- plan_self(:user_id => ::User.current.id, :affected_cvv_ids => affected_cvv_ids)
36
+ plan_self(:user_id => ::User.current.id, :affected_cvv_ids => affected_cvv_ids, :docker_cleanup => docker_cleanup)
34
37
  sequence do
35
38
  if repository.redhat?
36
39
  handle_redhat_content(repository) unless skip_environment_update
@@ -45,7 +48,7 @@ module Actions
45
48
  def finalize
46
49
  repository = ::Katello::Repository.find_by(id: input[:repository][:id])
47
50
  if repository
48
- docker_cleanup = repository.content_type == ::Katello::Repository::DOCKER_TYPE
51
+ docker_cleanup = repository.docker? && input[:docker_cleanup]
49
52
  delete_record(repository, {docker_cleanup: docker_cleanup})
50
53
 
51
54
  if (affected_cvv_ids = input[:affected_cvv_ids]).any?
@@ -81,6 +84,11 @@ module Actions
81
84
  end
82
85
  end
83
86
 
87
+ def delete_empty_repo_filters(repository)
88
+ filters_to_delete = repository.filters.select { |filter| filter.repositories.size == 1 }
89
+ ::Katello::ContentViewFilter.where(id: filters_to_delete).destroy_all
90
+ end
91
+
84
92
  def handle_custom_content(repository, remove_from_content_view_versions)
85
93
  #if this is the last instance of a custom repo, destroy the content
86
94
  if remove_from_content_view_versions || repository.root.repositories.where.not(id: repository.id).empty?
@@ -20,7 +20,6 @@ module Actions
20
20
 
21
21
  if input[:force_index] || (repo.last_contents_changed >= repo.last_indexed)
22
22
  repo.index_content(source_repository: source_repository, full_index: input[:full_index].present?)
23
- repo.update(:last_indexed => DateTime.now)
24
23
  else
25
24
  output[:index_skipped] = true
26
25
  end
@@ -26,7 +26,6 @@ module Actions
26
26
 
27
27
  validate_repo!(repo: repo,
28
28
  source_url: source_url,
29
- validate_contents: validate_contents,
30
29
  skip_metadata_check: skip_metadata_check,
31
30
  skip_candlepin_check: options.fetch(:skip_candlepin_check, false))
32
31
 
@@ -81,9 +80,8 @@ module Actions
81
80
  end
82
81
  end
83
82
 
84
- def validate_repo!(repo:, source_url:, validate_contents:, skip_metadata_check:, skip_candlepin_check:)
83
+ def validate_repo!(repo:, source_url:, skip_metadata_check:, skip_candlepin_check:)
85
84
  fail ::Katello::Errors::InvalidActionOptionError, _("Unable to sync repo. This repository does not have a feed url.") if repo.url.blank? && source_url.blank?
86
- fail ::Katello::Errors::InvalidActionOptionError, _("Cannot validate contents on non-yum/deb repositories.") if validate_contents && !repo.yum? && !repo.deb?
87
85
  fail ::Katello::Errors::InvalidActionOptionError, _("Cannot skip metadata check on non-yum/deb repositories.") if skip_metadata_check && !repo.yum? && !repo.deb?
88
86
  ::Katello::Util::CandlepinRepositoryChecker.check_repository_for_sync!(repo) if repo.yum? && !skip_candlepin_check
89
87
  end
@@ -6,19 +6,11 @@ module Actions
6
6
 
7
7
  def plan(repo)
8
8
  action_subject(repo)
9
-
10
- if SmartProxy.pulp_primary.pulp3_support?(repo)
11
- plan_action(Actions::Pulp3::Repository::Repair, repo.id, SmartProxy.pulp_primary)
12
- else
13
- options = {}
14
- options[:validate_contents] = true
15
- plan_action(Actions::Katello::Repository::Sync, repo, options)
16
- end
9
+ plan_action(Actions::Pulp3::Repository::Repair, repo.id, SmartProxy.pulp_primary)
17
10
  end
18
11
 
19
12
  def presenter
20
- found = all_planned_actions(Katello::Repository::Sync)
21
- found = all_planned_actions(Pulp3::Repository::Repair) if found.empty?
13
+ found = all_planned_actions(Pulp3::Repository::Repair)
22
14
  Helpers::Presenter::Delegated.new(self, found)
23
15
  end
24
16
  end
@@ -14,6 +14,8 @@ module Actions
14
14
  plan_self(source_repository_id: options[:source_repository].id, target_repository_id: repository.id, smart_proxy_id: smart_proxy.id)
15
15
  elsif publication_content_type && (force_publication || repository.publication_href.nil? || !repository.using_mirrored_metadata?)
16
16
  plan_action(Actions::Pulp3::Repository::CreatePublication, repository, smart_proxy, options)
17
+ elsif !publication_content_type
18
+ plan_self(target_repository_id: repository.id, contents_changed: options[:contents_changed], skip_publication: true)
17
19
  end
18
20
  plan_action(Actions::Pulp3::ContentGuard::Refresh, smart_proxy) unless repository.unprotected
19
21
  plan_action(Actions::Pulp3::Repository::RefreshDistribution, repository, smart_proxy, :contents_changed => options[:contents_changed]) if Setting[:distribute_archived_cvv] || repository.environment
@@ -21,13 +23,18 @@ module Actions
21
23
  end
22
24
 
23
25
  def run
24
- #we don't have to actually generate a publication, we can reuse the old one
25
26
  target_repo = ::Katello::Repository.find(input[:target_repository_id])
26
- source_repo = ::Katello::Repository.find(input[:source_repository_id])
27
- if (target_repo.publication_href != source_repo.publication_href && smart_proxy.pulp_primary?)
28
- target_repo.clear_smart_proxy_sync_histories
27
+ if input[:skip_publication]
28
+ #Need to clear smart proxy sync histories for non-publication content_types: docker, ansible collection
29
+ target_repo.clear_smart_proxy_sync_histories if input[:contents_changed]
30
+ else
31
+ #we don't have to actually generate a publication, we can reuse the old one
32
+ source_repo = ::Katello::Repository.find(input[:source_repository_id])
33
+ if (target_repo.publication_href != source_repo.publication_href && smart_proxy.pulp_primary?)
34
+ target_repo.clear_smart_proxy_sync_histories
35
+ end
36
+ target_repo.update!(publication_href: source_repo.publication_href)
29
37
  end
30
- target_repo.update!(publication_href: source_repo.publication_href)
31
38
  end
32
39
  end
33
40
  end
@@ -56,6 +56,7 @@ module Katello
56
56
  end
57
57
 
58
58
  def substitutor
59
+ fail _("Manifest does not have a valid subscription") if product.cdn_resource.nil?
59
60
  product.cdn_resource.substitutor
60
61
  end
61
62
 
@@ -1,22 +1,40 @@
1
1
  module Katello
2
2
  module Concerns
3
+ # rubocop:disable Metrics/ModuleLength
3
4
  module HostManagedExtensions
4
5
  extend ActiveSupport::Concern
5
6
  include Katello::KatelloUrlsHelper
6
7
  include ForemanTasks::Concerns::ActionSubject
7
8
 
8
9
  module Overrides
9
- def update(attrs)
10
+ def check_cve_attributes(attrs)
10
11
  if attrs[:content_facet_attributes]
11
12
  cv_id = attrs[:content_facet_attributes].delete(:content_view_id)
12
13
  lce_id = attrs[:content_facet_attributes].delete(:lifecycle_environment_id)
14
+ # Running validations on a host will clear out any existing errors, and then
15
+ # validate all attributes. As we know, running update or save will run validations.
16
+ # Since we've just removed two attributes that may
17
+ # have caused an error, we need to save those so we can explicitly validate
18
+ # them below in add_back_cve_errors.
19
+ @pending_cve_attrs = { content_view_id: cv_id, lifecycle_environment_id: lce_id }
13
20
  if cv_id && lce_id
14
- content_facet.assign_single_environment(content_view_id: cv_id, lifecycle_environment_id: lce_id)
21
+ cve = content_facet&.assign_single_environment(content_view_id: cv_id, lifecycle_environment_id: lce_id)
22
+ Rails.logger.warn "Couldn't assign content view environment; host has no content facet" if cve.blank?
23
+ @pending_cve_attrs = {}
15
24
  end
16
25
  if (cv_id.present? && lce_id.blank?) || (cv_id.blank? && lce_id.present?)
17
- fail "content_view_id and lifecycle_environment_id must be provided together"
26
+ errors.add(:base, _("Content view and lifecycle environment must be provided together"))
18
27
  end
19
28
  end
29
+ end
30
+
31
+ def attributes=(attrs)
32
+ check_cve_attributes(attrs)
33
+ super
34
+ end
35
+
36
+ def update(attrs)
37
+ check_cve_attributes(attrs) unless self.content_facet.blank?
20
38
  super
21
39
  end
22
40
 
@@ -30,6 +48,28 @@ module Katello
30
48
  inherited_attrs
31
49
  end
32
50
 
51
+ def apply_inherited_attributes(attributes, initialized = true)
52
+ attributes = super(attributes, initialized) || {}
53
+ facet_attrs = attributes&.[]('content_facet_attributes')
54
+ return attributes if facet_attrs.blank?
55
+ cv_id = facet_attrs['content_view_id']
56
+ lce_id = facet_attrs['lifecycle_environment_id']
57
+ if initialized && (cv_id.blank? || lce_id.blank?)
58
+ if cv_id.blank?
59
+ Rails.logger.info "Hostgroup has no content view assigned; using host's existing content view"
60
+ facet_attrs['content_view_id'] = content_facet&.single_content_view&.id
61
+ end
62
+ if lce_id.blank?
63
+ Rails.logger.info "Hostgroup has no lifecycle environment assigned; using host's existing lifecycle environment"
64
+ facet_attrs['lifecycle_environment_id'] = content_facet&.single_lifecycle_environment&.id
65
+ end
66
+ attributes['content_facet_attributes'] = facet_attrs
67
+ else
68
+ Rails.logger.debug "Hostgroup has content view and lifecycle environment assigned; using those"
69
+ end
70
+ attributes
71
+ end
72
+
33
73
  def smart_proxy_ids
34
74
  ids = super
35
75
  ids << content_source_id
@@ -90,6 +130,8 @@ module Katello
90
130
  has_many :hypervisor_pools, :class_name => '::Katello::Pool', :foreign_key => :hypervisor_id, :dependent => :nullify
91
131
 
92
132
  before_validation :correct_kickstart_repository
133
+ after_validation :add_back_cve_errors
134
+ after_update :clear_pending_cve_attributes
93
135
  before_update :check_host_registration, :if => proc { organization_id_changed? }
94
136
 
95
137
  after_validation :queue_reset_content_host_status
@@ -118,6 +160,16 @@ module Katello
118
160
 
119
161
  scoped_search relation: :pools, on: :pools_expiring_in_days, ext_method: :find_with_expiring_pools, only_explicit: true
120
162
 
163
+ def add_back_cve_errors
164
+ if @pending_cve_attrs&.[](:content_view_id).present? || @pending_cve_attrs&.[](:lifecycle_environment_id).present?
165
+ check_cve_attributes({ content_facet_attributes: @pending_cve_attrs })
166
+ end
167
+ end
168
+
169
+ def clear_pending_cve_attributes
170
+ @pending_cve_attrs = {}
171
+ end
172
+
121
173
  def self.find_with_expiring_pools(_key, _operator, days_from_now)
122
174
  host_ids = with_pools_expiring_in_days(days_from_now).ids
123
175
  if host_ids.any?
@@ -794,12 +794,20 @@ module Katello
794
794
  return last_publish_result.present? && last_publish_result == 'success'
795
795
  end
796
796
 
797
+ def cv_repo_indexed_after_last_published?
798
+ repositories.any? { |repo| repo.last_indexed && repo.last_indexed > latest_version_object.created_at }
799
+ end
800
+
797
801
  def needs_publish?
798
802
  #Returns
799
803
  # True:
800
804
  # a) When content/repo/filter change audit records exist
801
805
  # b) CV hasn't ever been published
802
806
  # c) CV dependency_solving != latest_version.applied_filters.dependency_solving
807
+ # d) If repo was indexed after cv publish. This can happen under 3 cases:
808
+ # i) Index runs because last index(before publish) had failed and repo is picked up for index even if pulp publication hasn't changed.
809
+ # ii) Complete sync runs or sync adds/removes new content (Already true because new pulp publication/version gets created)
810
+ # iii) repo.index_content is run. (This doesn't necessarily indicate contents changed. Corner case where we play safe and return true)
803
811
  # nil:
804
812
  # a) When CV version creation audit is missing(Indicating audit cleanup)
805
813
  # b) Version doesn't have audited_filters set indicating
@@ -814,10 +822,11 @@ module Katello
814
822
  return nil unless last_publish_task_success?
815
823
  return composite_cv_components_changed? if composite?
816
824
  # return true if the audit records clearly show we have unpublished changes
817
- return true if (audited_cv_repositories_since_last_publish.present? || audited_cv_repository_changed.present? ||
818
- audited_cv_filters_changed.present? || audited_cv_filter_rules_changed.present?)
825
+ return true if audited_changes_present?
819
826
  # return true if the dependency solving changed for CV between last publish and now
820
827
  return true if dependency_solving_changed?
828
+ # return true if any child repo's indexed_at > last_version.created_at
829
+ return true if cv_repo_indexed_after_last_published?
821
830
  # if we didn't return `true` already, either the audit records show that we don't need to publish, or we may
822
831
  # have insufficient data to make the determination (either audits were cleaned, or never got created at all).
823
832
  # first, check for the `create` audit record; its absence indicates that audits were cleaned some time after
@@ -834,6 +843,11 @@ module Katello
834
843
  latest_version_object.applied_filters.nil? ? nil : false
835
844
  end
836
845
 
846
+ def audited_changes_present?
847
+ audited_cv_repositories_since_last_publish.present? || audited_cv_repository_changed.present? ||
848
+ audited_cv_filters_changed.present? || audited_cv_filter_rules_changed.present?
849
+ end
850
+
837
851
  def dependency_solving_changed?
838
852
  latest_version_object.applied_filters && solve_dependencies != latest_version_object.applied_filters['dependency_solving']
839
853
  end
@@ -134,7 +134,9 @@ module Katello
134
134
  end
135
135
 
136
136
  def self.cleanup_tags
137
- self.where("id not in (?) OR (schema2_id IS NULL AND schema1_id IS NULL)", Katello::RepositoryDockerMetaTag.pluck(:docker_meta_tag_id) + [0]).delete_all
137
+ #Cleanup RepositoryMetaTag for nil schema meta tags
138
+ RepositoryDockerMetaTag.where(docker_meta_tag: where(schema1: nil, schema2: nil)).delete_all
139
+ self.where.not(id: RepositoryDockerMetaTag.select(:docker_meta_tag_id)).or(where(schema1: nil, schema2: nil)).delete_all
138
140
  end
139
141
 
140
142
  def self.import_meta_tags(repositories)
@@ -375,7 +375,9 @@ module Katello
375
375
  class Jail < ::Safemode::Jail
376
376
  allow :applicable_deb_count, :applicable_module_stream_count, :applicable_rpm_count, :content_source, :content_source_id, :content_source_name,
377
377
  :errata_counts, :id, :kickstart_repository, :kickstart_repository_id, :kickstart_repository_name,
378
- :upgradable_deb_count, :upgradable_module_stream_count, :upgradable_rpm_count, :uuid
378
+ :upgradable_deb_count, :upgradable_module_stream_count, :upgradable_rpm_count, :uuid,
379
+ :installable_security_errata_count, :installable_bugfix_errata_count, :installable_enhancement_errata_count,
380
+ :single_content_view, :single_lifecycle_environment
379
381
  end
380
382
  end
381
383
  end
@@ -278,7 +278,7 @@ module Katello
278
278
  prop_group :katello_basic_props, Katello::Model, meta: { friendly_name: 'Katello Environment' }
279
279
  end
280
280
  class Jail < ::Safemode::Jail
281
- allow :name, :label
281
+ allow :id, :name, :label
282
282
  end
283
283
 
284
284
  private