Skip to content

Commit

Permalink
Fixes #35848 - Handles content move during manifest (#10388)
Browse files Browse the repository at this point in the history
* Fixes #35848 - Handles content move during manifest

Whenever a manifest is uploaded the candlepin instance
refreshes its products and contents accordingly.
Katello then refreshes its tables based on candlepin data.

This works well if new content is added. But in some instances the provided
manifest content may have moved from one product to another. The sat indexing
logic was not  handling this scenario causing duplicate repository sets.

This commit addresses the move aspect. It tries to find the actual product that
the content belonged to and moves over the product connected to the root repository.

* Refs #35848 - handled no root repo with that content

* Refs #35848 - Fixed rubocop errors

* Refs #35848 - rubocop

* Refs #35848 - Do not create product content if not needed

* removed unnecessary lines
  • Loading branch information
parthaa authored Jan 3, 2023
1 parent db5a820 commit 72a192c
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 8 deletions.
2 changes: 2 additions & 0 deletions app/lib/katello/util/candlepin_repository_checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def self.check_repository_for_sync!(repo)
end

def self.repository_exist_in_backend?(repository)
return false if repository.root.content_id.blank?

::Katello::Resources::Candlepin::Content.get(repository.organization.label, repository.root.content_id)
true
rescue RestClient::NotFound
Expand Down
2 changes: 1 addition & 1 deletion app/models/katello/content.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def self.import_all
cp_products = ::Katello::Resources::Candlepin::Product.all(org.label, [:id, :productContent])
product_hash = cp_products.group_by { |prod| prod['id'] }

prod_content_importer = Katello::ProductContentImporter.new
prod_content_importer = Katello::ProductContentImporter.new(product_hash)
org.products.each do |product|
product_json = product_hash[product.cp_id]&.first

Expand Down
2 changes: 1 addition & 1 deletion app/models/katello/glue/provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def import_products_from_cp
cp_products = ::Katello::Resources::Candlepin::Product.all(organization.label, [:id, :name, :multiplier, :productContent])
cp_products = cp_products.select { |prod| Glue::Candlepin::Product.engineering_product_id?(prod['id']) }

prod_content_importer = Katello::ProductContentImporter.new
prod_content_importer = Katello::ProductContentImporter.new(cp_products)

Katello::Logging.time("Imported #{cp_products.size} products") do
cp_products.each do |product_json|
Expand Down
66 changes: 61 additions & 5 deletions app/services/katello/product_content_importer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,75 @@ class ProductContentImporter
# }
attr_reader :content_url_updated

def initialize
def initialize(cp_products = [])
@contents_to_create = []
@product_contents_to_create = []
@product_mapping = {}
@content_url_updated = []
@cp_products = cp_products
end

def add_product_content(product, product_content_json)
@product_mapping[product] = product_content_json.map(&:with_indifferent_access)
end

def find_product_for_content(content_id)
prod = @cp_products.find do |prod_json|
prod_json['productContent'].any? do |product_content_json|
product_content_json["content"]["id"] == content_id
end
end
::Katello::Product.find_by(cp_id: prod["id"]) if prod
end

def fetch_product_contents_to_move(product, prod_contents_json)
content_ids = prod_contents_json.map { |pc| pc[:content][:id] }
# Identify if there are any product_content that should not be
# part of this product.
product_contents_to_delete_or_move = product.
product_contents.
joins(:content).
where.not(content: { cp_content_id: content_ids })
# Identify if product content actually moved between 2 different products
product_contents_to_delete_or_move.select do |pc|
content_exists?(product.organization, pc.content)
end
end

def handle_product_moves(product, prod_contents_json)
product_contents_to_move = fetch_product_contents_to_move(product, prod_contents_json)
moved_product_contents = []
product_contents_to_move.each do |pc|
content = pc.content
root_repo = product.root_repositories.find_by(content_id: content.cp_content_id)
actual_product = find_product_for_content(content.cp_content_id)
if actual_product.present? && root_repo.present? && root_repo.product != actual_product
root_repo.update!(product_id: actual_product.id)
pc.update!(product_id: actual_product.id)
moved_product_contents << pc
else
pc.destroy!
end
end
product.reload unless product_contents_to_move.blank?

moved_product_contents
end

def import
return if @product_mapping.blank?

moved_product_contents = []
@product_mapping.each do |product, prod_contents_json|
moved_product_contents += handle_product_moves(product, prod_contents_json)
existing_product_contents = product.product_contents.to_a

prod_contents_json.each do |prod_content_json|
content = create_or_update_content(product, prod_content_json)
existing_content_map[content.cp_content_id] = content if content.new_record?
create_or_update_product_content(product, existing_product_contents, content, prod_content_json[:enabled])
end
end

::Katello::Content.import(@contents_to_create, recursive: true)
::Katello::ProductContent.import(@product_contents_to_create)
::Katello::ProductContent.import(fetch_product_contents_to_create(moved_product_contents))
end

private def existing_content_map
Expand All @@ -60,6 +103,19 @@ def import
@existing_content_map
end

private def content_exists?(org, content)
Resources::Candlepin::Content.get(org.label, content.cp_content_id)
true
rescue RestClient::NotFound
false
end

private def fetch_product_contents_to_create(moved_product_contents)
@product_contents_to_create.select do |pc|
moved_product_contents.none? { |mpc| mpc.content_id == pc.content_id && mpc.product_id == pc.product_id }
end
end

private def create_or_update_content(product, prod_content_json)
content = existing_content_map[prod_content_json[:content][:id].to_s]
if content
Expand Down
2 changes: 1 addition & 1 deletion test/models/content_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_import_all
}
end
end

Katello::ProductContentImporter.any_instance.stubs(:content_exists?).returns(false)
Katello::Resources::Candlepin::Product.stubs(:all).returns(*org_products)

Katello::Content.import_all
Expand Down

0 comments on commit 72a192c

Please sign in to comment.