namespace :katello do
namespace :upgrades do namespace '4.21' do desc "Destroy all PythonPublication objects from Pulp database" task :cleanup_python_publications => ["environment"] do User.current = User.anonymous_api_admin python_repos = Katello::Repository.joins(:root).where(katello_root_repositories: { content_type: 'python' }) if python_repos.empty? puts "No python repositories found. Skipping upgrade task." next end smart_proxy = SmartProxy.pulp_primary unless smart_proxy puts "ERROR: Primary Pulp smart proxy not found." exit 1 end migrate_distributions(python_repos, smart_proxy) repair_python_metadata(python_repos, smart_proxy) delete_python_publications(smart_proxy) clear_publication_hrefs(python_repos) end # rubocop:disable Metrics/MethodLength def self.migrate_distributions(python_repos, smart_proxy) puts "Migrating Python distributions from publications to repository_versions..." tasks = [] migration_failed = false repos_needing_migration = python_repos.select { |repo| repo.environment.present? && repo.publication_href.present? } repos_needing_migration.each do |repo| begin service = Katello::Pulp3::Repository.instance_for_type(repo, smart_proxy) repo_tasks = service.update_distribution tasks.concat(repo_tasks) if repo_tasks.present? puts "Migrating distribution for repository: #{repo.name} (ID: #{repo.id})" rescue StandardError => e puts "ERROR: Failed to update distribution for repository #{repo.name} (ID: #{repo.id}): #{e.message}" migration_failed = true end end # Wait for all distribution update tasks to complete if tasks.any? puts "Waiting for #{tasks.count} distribution update tasks to complete..." task_objects = tasks.map { |task_response| Katello::Pulp3::Task.new(smart_proxy, { 'task' => task_response.task }) } task_objects.each_with_index do |task, index| max_wait = 600 # 10 minutes per task elapsed = 0 until task.done? if elapsed >= max_wait puts "\nERROR: Task #{index + 1}/#{tasks.count} timed out after #{max_wait} seconds" exit 1 end print "." sleep 1 elapsed += 1 task.poll end if task.error puts "\nERROR: Task #{index + 1}/#{tasks.count} failed: #{task.error}" migration_failed = true else puts "\nTask #{index + 1}/#{tasks.count} completed successfully" end end end if migration_failed puts "ERROR: One or more distribution migrations failed." exit 1 end end # rubocop:enable Metrics/MethodLength # rubocop:disable Metrics/MethodLength def self.repair_python_metadata(python_repos, smart_proxy) puts "Repairing Python package metadata..." tasks = [] python_repos.select { |repo| repo.environment.present? }.each do |repo| begin service = Katello::Pulp3::Repository.instance_for_type(repo, smart_proxy) repository_href = service.repository_reference.repository_href api = service.api response = api.repositories_api.repair_metadata(repository_href) tasks << { task: Katello::Pulp3::Task.new(smart_proxy, { 'task' => response.task }), repo: repo } puts "Queued metadata repair for: #{repo.name}" rescue StandardError => e puts "WARNING: Could not queue metadata repair for #{repo.name}: #{e.message}" end end # Wait for repair tasks and log results tasks.each do |task_info| max_wait = 300 elapsed = 0 until task_info[:task].done? if elapsed >= max_wait puts "WARNING: Metadata repair timed out for #{task_info[:repo].name} after #{max_wait} seconds (Pulp will continue processing in background)" break end sleep 5 elapsed += 5 task_info[:task].poll end if task_info[:task].error puts "WARNING: Metadata repair failed for #{task_info[:repo].name}: #{task_info[:task].error}" elsif task_info[:task].done? puts "Metadata repair completed for #{task_info[:repo].name}" end end end # rubocop:enable Metrics/MethodLength # rubocop:disable Metrics/MethodLength def self.delete_python_publications(smart_proxy) puts "Deleting Python publications from Pulp database..." python_repo_type = Katello::RepositoryTypeManager.find('python') unless python_repo_type puts "WARNING: Python repository type not found. Skipping Pulp cleanup." return end pulp_python_api = Katello::Pulp3::Api::Core.new(smart_proxy, python_repo_type) begin publications = pulp_python_api.publications_list_all rescue StandardError => e puts "ERROR: Failed to list Python publications from Pulp API: #{e.message}" exit 1 end if publications.empty? puts "No Python publications found in Pulp database" else deleted_count = 0 error_count = 0 publications.each do |publication| begin puts "Deleting publication: #{publication.pulp_href}" pulp_python_api.publications_api.delete(publication.pulp_href) deleted_count += 1 rescue RestClient::NotFound # Publication already deleted (404) - count as success deleted_count += 1 rescue StandardError => e puts "ERROR: Failed to delete publication: #{e.message}" error_count += 1 end end puts "Successfully deleted #{deleted_count} Python publications from Pulp" if error_count > 0 puts "#{error_count} publications could not be deleted. Please review errors above. Re-run this rake task: 'katello:upgrades:4.21:cleanup_python_publications'" exit 1 end end end def self.clear_publication_hrefs(python_repos) puts "Clearing publication_href references in Katello database..." begin repos_with_publications = python_repos.where.not(publication_href: nil) if repos_with_publications.any? count = repos_with_publications.count repos_with_publications.update_all(publication_href: nil) puts "Cleared publication_href from #{count} repositories" else puts "No repositories with publication_href found" end rescue StandardError => e puts "ERROR: Failed to clear publication_href from repository records. You may need to manually clear these references: #{e.message}" exit 1 end end end # rubocop:enable Metrics/MethodLength end
end