Problem: Katello depends on 9 pre-packaged Pulp Ruby client gems that the Pulp team struggles to maintain and package. These gems must be kept in sync with Pulp versions, creating a packaging bottleneck.
Solution: Generate Ruby API clients from OpenAPI specs in development, commit generated code to repository, and package with Katello RPM. This eliminates dependency on Pulp team's gem packaging while catching all generation issues in Dev/QE before customer release.
Why This Approach:
- Pulp upgrades occur every 3-6 months (manageable manual process)
- Generation issues caught in Dev/QE, not on customer systems
- Customers get pre-generated, tested code with zero startup delay
- Complete control over when and how API clients are updated
- Eliminates 9 gem RPM dependencies, simplifies packaging
Pulp Client Gems (9 total):
- pulpcore_client, pulp_file_client, pulp_ansible_client, pulp_container_client, pulp_deb_client, pulp_rpm_client, pulp_certguard_client, pulp_python_client, pulp_ostree_client
- All pinned to specific minor versions (e.g.,
>= 3.85.0, < 3.86.0)
Integration Points:
/home/sajha/mnt1/katello/katello.gemspec- Defines gem dependencies/home/sajha/mnt1/katello/app/models/katello/concerns/smart_proxy_extensions.rb:372-398-pulp3_configuration()configures API clients with auth, SSL, timeouts/home/sajha/mnt1/katello/app/services/katello/pulp3/api/core.rb- Base class, instantiatesPulpcoreClient::ApiClientand provides common methods/home/sajha/mnt1/katello/app/services/katello/pulp3/api/{yum,apt,docker,file,ansible_collection,content_guard}.rb- Type-specific classes extend Core, instantiate specialized APIs/home/sajha/mnt1/katello/lib/katello/repository_types/{yum,deb,docker,file,ansible_collection,python,ostree}.rb- Register client module classes, API classes, configuration classes/home/sajha/mnt1/katello/lib/monkeys/pulp_polymorphic_remote_response.rb- Monkey patches for polymorphic remote responses
Current Client Instantiation Pattern:
# In Api::Core
def api_client_class(client)
client.default_headers['Correlation-ID'] = request_id if request_id
client
end
# In repository types
client_module_class PulpRpmClient
api_class PulpRpmClient::ApiClient
configuration_class PulpRpmClient::Configuration
# In type-specific APIs (e.g., Api::Yum)
def copy_api
PulpRpmClient::RpmCopyApi.new(api_client)
end- Remove: 9 Pulp client gem dependencies from katello.gemspec
- Add: Vendored OpenAPI specs in
vendor/pulp_openapi_specs/ - Add: Generated Ruby client code in
lib/pulp_generated_clients/ - Add: Rake tasks for fetching specs and regenerating clients
- Modify: Repository type registrations to require generated clients
- Update: katello.spec (RPM packaging) to include generated code
- SmartProxy configuration methods (no changes needed)
- API class structure (
Api::Core,Api::Yum, etc.) - Client instantiation pattern (same module names, same API classes)
- All business logic using Pulp APIs
lib/pulp_generated_clients/
├── pulpcore/
│ └── lib/
│ ├── pulpcore_client.rb # Main module
│ ├── pulpcore_client/api/
│ │ ├── api_client.rb
│ │ ├── artifacts_api.rb
│ │ └── repositories_api.rb
│ ├── pulpcore_client/models/
│ └── pulpcore_client/configuration.rb
├── pulp_rpm/
│ └── lib/
│ ├── pulp_rpm_client.rb
│ ├── pulp_rpm_client/api/
│ │ ├── api_client.rb
│ │ ├── remotes_rpm_api.rb
│ │ └── repositories_rpm_api.rb
│ └── pulp_rpm_client/models/
└── ... (similar for 7 other plugins)
Key Benefits:
- ✅ Generation issues caught in Dev/QE - Never on customer systems
- ✅ Zero customer startup delay - Pre-generated code ready to use
- ✅ No runtime dependencies - No openapi-generator on customer systems
- ✅ Easy rollback - Git revert if issues found
- ✅ QE validation - Tests run against exact code customers get
- ✅ Simpler packaging - Eliminates 9 gem RPM dependencies
Trade-offs:
- Larger git repository (~30MB generated code)
- Larger git diffs during regeneration (~30K lines)
- Manual regeneration needed (every 3-6 months with Pulp upgrades)
This project divides into 4 parallel workstreams that can be distributed to different team members/agents:
- Create vendored specs directory structure
- Implement rake tasks for fetching specs from Pulp
- Implement rake tasks for generating clients from specs
- Set up proper error handling and logging
- Configure openapi-generator for Ruby client generation
- Generate initial clients from current Pulp version
- Verify generated code structure matches expected pattern
- Update autoload paths to include generated clients
- Update all repository type registrations to use generated clients
- Verify API class mappings
- Update monkey patches if needed
- Test each repository type
- Update katello.gemspec (remove Pulp gem dependencies)
- Update katello.spec for RPM packaging
- Create Pulp upgrade workflow documentation
- Document troubleshooting procedures
File to create: N/A (directory creation)
Actions:
cd /home/sajha/mnt1/katello
mkdir -p vendor/pulp_openapi_specs
mkdir -p lib/pulp_generated_clientsVerification:
ls -la vendor/pulp_openapi_specs
ls -la lib/pulp_generated_clientsDeliverable: Empty directories ready for specs and generated code
File to create: /home/sajha/mnt1/katello/lib/tasks/pulp_client_generation.rake
Requirements:
- Fetch OpenAPI specs from Pulp primary SmartProxy
- Support all 9 Pulp plugins
- Include version in filename
- Handle HTTP errors gracefully
- Log progress
Implementation:
namespace :katello do
namespace :pulp do
desc "Fetch OpenAPI specs from Pulp instance and save to vendor/"
task update_specs: :environment do
require 'json'
require 'net/http'
require 'uri'
smart_proxy = SmartProxy.pulp_primary
unless smart_proxy
puts "ERROR: No Pulp primary SmartProxy configured"
exit 1
end
base_url = smart_proxy.pulp3_uri!.to_s
puts "Fetching specs from: #{base_url}"
specs = {
'pulpcore' => "#{base_url}/pulp/api/v3/docs/api.json",
'pulp_rpm' => "#{base_url}/pulp/api/v3/plugins/rpm/docs/api.json",
'pulp_file' => "#{base_url}/pulp/api/v3/plugins/file/docs/api.json",
'pulp_container' => "#{base_url}/pulp/api/v3/plugins/container/docs/api.json",
'pulp_deb' => "#{base_url}/pulp/api/v3/plugins/deb/docs/api.json",
'pulp_ansible' => "#{base_url}/pulp/api/v3/plugins/ansible/docs/api.json",
'pulp_certguard' => "#{base_url}/pulp/api/v3/plugins/certguard/docs/api.json",
'pulp_python' => "#{base_url}/pulp/api/v3/plugins/python/docs/api.json",
'pulp_ostree' => "#{base_url}/pulp/api/v3/plugins/ostree/docs/api.json"
}
specs.each do |name, url|
begin
puts "\nFetching #{name}..."
spec_json = fetch_spec(url, smart_proxy)
spec = JSON.parse(spec_json)
version = spec.dig('info', 'version') || 'unknown'
filename = Rails.root.join("vendor/pulp_openapi_specs/#{name}-#{version}.json")
File.write(filename, JSON.pretty_generate(spec))
puts "✓ Wrote #{filename} (version #{version})"
rescue => e
puts "✗ ERROR fetching #{name}: #{e.message}"
raise
end
end
puts "\n✓ All specs fetched successfully"
end
private
def fetch_spec(url, smart_proxy)
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
# Use SmartProxy SSL configuration
if http.use_ssl?
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
# Add SSL cert configuration from smart_proxy if needed
end
request = Net::HTTP::Get.new(uri.request_uri)
# Add authentication
username = smart_proxy.setting('Pulp3', 'username')
password = smart_proxy.setting('Pulp3', 'password')
request.basic_auth(username, password) if username && password
response = http.request(request)
unless response.code == '200'
raise "HTTP #{response.code}: #{response.message}"
end
response.body
end
end
endVerification:
cd /home/sajha/mnt1/katello
bundle exec rake katello:pulp:update_specs
# Should create files like:
# vendor/pulp_openapi_specs/pulpcore-3.85.0.json
# vendor/pulp_openapi_specs/pulp_rpm-3.32.0.json
# etc.Deliverable: Rake task that fetches all 9 OpenAPI specs from Pulp
Error Handling:
- Exit with error if no Pulp primary proxy configured
- Show clear error messages for HTTP failures
- Fail fast on first error (don't continue if one fails)
File to modify: /home/sajha/mnt1/katello/lib/tasks/pulp_client_generation.rake
Requirements:
- Generate Ruby clients using openapi-generator
- Output to lib/pulp_generated_clients/{plugin_name}/
- Configure proper module names
- Handle generation errors
- Support incremental regeneration
Add to same file:
namespace :katello do
namespace :pulp do
desc "Generate Pulp API clients from vendored OpenAPI specs"
task generate_clients: :environment do
require 'fileutils'
spec_dir = Rails.root.join('vendor/pulp_openapi_specs')
output_base = Rails.root.join('lib/pulp_generated_clients')
unless Dir.exist?(spec_dir)
puts "ERROR: Spec directory not found: #{spec_dir}"
puts "Run 'rake katello:pulp:update_specs' first"
exit 1
end
specs = Dir.glob(spec_dir.join('*.json')).sort
if specs.empty?
puts "ERROR: No spec files found in #{spec_dir}"
exit 1
end
puts "Generating clients from #{specs.count} specs..."
specs.each do |spec_file|
generate_client_from_spec(spec_file, output_base)
end
puts "\n✓ All clients generated successfully"
puts "Generated code location: #{output_base}"
end
desc "Clear generated clients cache"
task clear_generated: :environment do
output_base = Rails.root.join('lib/pulp_generated_clients')
if Dir.exist?(output_base)
FileUtils.rm_rf(output_base)
puts "✓ Cleared #{output_base}"
else
puts "Nothing to clear"
end
end
desc "Update specs and regenerate clients (combined task)"
task update_and_generate: :environment do
Rake::Task['katello:pulp:update_specs'].invoke
Rake::Task['katello:pulp:generate_clients'].invoke
end
private
def generate_client_from_spec(spec_path, output_base)
# Parse filename: pulpcore-3.85.0.json -> pulpcore
basename = File.basename(spec_path, '.json')
plugin_name = basename.split('-').first
puts "\nGenerating #{plugin_name} client..."
# Determine module name
module_name = case plugin_name
when 'pulpcore'
'PulpcoreClient'
when 'pulp_rpm'
'PulpRpmClient'
when 'pulp_file'
'PulpFileClient'
when 'pulp_container'
'PulpContainerClient'
when 'pulp_deb'
'PulpDebClient'
when 'pulp_ansible'
'PulpAnsibleClient'
when 'pulp_certguard'
'PulpCertguardClient'
when 'pulp_python'
'PulpPythonClient'
when 'pulp_ostree'
'PulpOstreeClient'
else
raise "Unknown plugin: #{plugin_name}"
end
output_dir = output_base.join(plugin_name)
FileUtils.mkdir_p(output_dir)
# Build openapi-generator command
cmd = [
'openapi-generator-cli', 'generate',
'-i', spec_path,
'-g', 'ruby',
'-o', output_dir,
'--skip-validate-spec', # Some Pulp specs have minor issues
"--additional-properties=moduleName=#{module_name}",
"--additional-properties=gemName=#{plugin_name}",
'--additional-properties=gemVersion=1.0.0',
'--additional-properties=gemLicense=GPLv2'
].join(' ')
puts "Running: #{cmd}"
success = system(cmd)
unless success
puts "✗ ERROR: Client generation failed for #{plugin_name}"
exit 1
end
puts "✓ Generated #{module_name} to #{output_dir}"
end
end
endVerification:
# Generate all clients
bundle exec rake katello:pulp:generate_clients
# Should create:
# lib/pulp_generated_clients/pulpcore/lib/pulpcore_client.rb
# lib/pulp_generated_clients/pulp_rpm/lib/pulp_rpm_client.rb
# etc.
# Verify module structure
ls -la lib/pulp_generated_clients/pulpcore/lib/
ls -la lib/pulp_generated_clients/pulp_rpm/lib/Deliverable: Rake task that generates all 9 Ruby clients from specs
Dependencies:
- Requires
openapi-generator-clito be installed - Installation:
gem install openapi_generatorornpm install -g @openapitools/openapi-generator-cli
File to modify: /home/sajha/mnt1/katello/lib/katello/engine.rb
Current state: Engine configuration for Rails autoloading
Changes needed: Add generated client directories to autoload path
Implementation:
# Find the config section (around line 10-30)
# Add after existing autoload_paths configuration:
config.autoload_paths += Dir[
"#{config.root}/lib/pulp_generated_clients/*/lib"
]
# Also add eager_load_paths for production
config.eager_load_paths += Dir[
"#{config.root}/lib/pulp_generated_clients/*/lib"
]Alternative if above doesn't work:
Create initializer /home/sajha/mnt1/katello/config/initializers/pulp_generated_clients.rb:
# Load all generated Pulp clients
Rails.application.config.to_prepare do
Dir.glob(Rails.root.join('lib/pulp_generated_clients', '*', 'lib', '*.rb')).each do |client_file|
require client_file
end
endVerification:
# Start Rails console
bundle exec rails console
# Should be able to access generated classes
> PulpcoreClient::ApiClient
> PulpRpmClient::RemotesRpmApi
> PulpFileClient::RepositoriesFileApiDeliverable: Rails can load and access all generated client modules
Purpose: Ensure generated code matches expected structure for integration
Actions:
-
Check that each plugin has required classes:
# For each plugin, verify these exist: ls lib/pulp_generated_clients/pulpcore/lib/pulpcore_client.rb ls lib/pulp_generated_clients/pulpcore/lib/pulpcore_client/api_client.rb ls lib/pulp_generated_clients/pulpcore/lib/pulpcore_client/configuration.rb ls lib/pulp_generated_clients/pulp_rpm/lib/pulp_rpm_client.rb ls lib/pulp_generated_clients/pulp_rpm/lib/pulp_rpm_client/api_client.rb # etc.
-
Check module names match expectations:
# In Rails console PulpcoreClient.constants # Should include :ApiClient, :Configuration, etc. PulpRpmClient.constants
-
Compare structure to current gems:
# Check current gem structure bundle show pulpcore_client ls $(bundle show pulpcore_client)/lib/ # Compare to generated ls lib/pulp_generated_clients/pulpcore/lib/
-
Verify API classes exist:
PulpcoreClient::ArtifactsApi PulpRpmClient::RemotesRpmApi PulpFileClient::RepositoriesFileApi PulpContainerClient::DistributionsContainerApi
Expected Results:
- All modules loadable
- API classes instantiable
- Configuration classes present
- Structure matches current gem layout
Deliverable: Verification report confirming generated code structure is compatible
- Directories created:
vendor/pulp_openapi_specs/andlib/pulp_generated_clients/ - Rake task
katello:pulp:update_specsimplemented and tested - Rake task
katello:pulp:generate_clientsimplemented and tested - Rake task
katello:pulp:clear_generatedimplemented - Rake task
katello:pulp:update_and_generate(combined) implemented - All 9 OpenAPI specs fetched and saved to vendor/
- All 9 Ruby clients generated to lib/pulp_generated_clients/
- Rails autoload configured for generated clients
- Generated code structure verified and compatible
- All generated modules loadable in Rails console
- Initial commit to git (specs + generated code)
File to modify: /home/sajha/mnt1/katello/lib/katello/repository_types/yum.rb
Current state:
Katello::RepositoryTypeManager.register(::Katello::Repository::YUM_TYPE) do
service_class Katello::Pulp3::Repository::Yum
pulp3_skip_publication false
pulp3_service_class Katello::Pulp3::Rpm
pulp3_plugin 'pulp_rpm'
client_module_class PulpRpmClient # From gem
api_class PulpRpmClient::ApiClient
configuration_class PulpRpmClient::Configuration
# ... more configuration
endChanges needed: None if autoloading works correctly
Verification:
-
Check that PulpRpmClient is accessible without changes:
# In Rails console Katello::RepositoryTypeManager.find(Katello::Repository::YUM_TYPE).client_module # Should return PulpRpmClient (from generated code)
-
If autoloading doesn't work, add explicit require at top of file:
# At top of yum.rb require Rails.root.join('lib/pulp_generated_clients/pulp_rpm/lib/pulp_rpm_client')
-
Test repository type loading:
bundle exec rails console > type = Katello::RepositoryTypeManager.find('yum') > type.client_module_class => PulpRpmClient > type.api_class => PulpRpmClient::ApiClient
Deliverable: YUM repository type works with generated client
Files to check/modify:
-
APT/Deb:
/home/sajha/mnt1/katello/lib/katello/repository_types/deb.rb- Uses:
PulpDebClient - Verify:
Katello::RepositoryTypeManager.find('deb').client_module_class
- Uses:
-
Docker:
/home/sajha/mnt1/katello/lib/katello/repository_types/docker.rb- Uses:
PulpContainerClient - Verify:
Katello::RepositoryTypeManager.find('docker').client_module_class
- Uses:
-
File:
/home/sajha/mnt1/katello/lib/katello/repository_types/file.rb- Uses:
PulpFileClient - Verify:
Katello::RepositoryTypeManager.find('file').client_module_class
- Uses:
-
Ansible:
/home/sajha/mnt1/katello/lib/katello/repository_types/ansible_collection.rb- Uses:
PulpAnsibleClient - Verify:
Katello::RepositoryTypeManager.find('ansible_collection').client_module_class
- Uses:
-
Python:
/home/sajha/mnt1/katello/lib/katello/repository_types/python.rb- Uses:
PulpPythonClient - Verify:
Katello::RepositoryTypeManager.find('python').client_module_class
- Uses:
-
OSTree:
/home/sajha/mnt1/katello/lib/katello/repository_types/ostree.rb- Uses:
PulpOstreeClient - Verify:
Katello::RepositoryTypeManager.find('ostree').client_module_class
- Uses:
Actions for each:
- Verify client module class is accessible
- Add explicit require if autoloading fails
- Test in Rails console
Verification script:
# test_repository_types.rb
types = [
{ name: 'yum', client: PulpRpmClient },
{ name: 'deb', client: PulpDebClient },
{ name: 'docker', client: PulpContainerClient },
{ name: 'file', client: PulpFileClient },
{ name: 'ansible_collection', client: PulpAnsibleClient },
{ name: 'python', client: PulpPythonClient },
{ name: 'ostree', client: PulpOstreeClient }
]
types.each do |type|
rt = Katello::RepositoryTypeManager.find(type[:name])
if rt.client_module_class == type[:client]
puts "✓ #{type[:name]}: #{type[:client]}"
else
puts "✗ #{type[:name]}: Expected #{type[:client]}, got #{rt.client_module_class}"
end
endDeliverable: All 7 repository types use generated clients
Purpose: Ensure API classes from generated clients work with existing code
Test file: Create test/unit/pulp_generated_clients_test.rb
require 'test_helper'
class PulpGeneratedClientsTest < ActiveSupport::TestCase
def setup
@proxy = FactoryBot.create(:smart_proxy, :default_smart_proxy, :with_pulp3)
end
test "pulpcore client instantiation" do
config = @proxy.pulp3_configuration(PulpcoreClient::Configuration)
assert_instance_of PulpcoreClient::Configuration, config
client = PulpcoreClient::ApiClient.new(config)
assert_instance_of PulpcoreClient::ApiClient, client
api = PulpcoreClient::ArtifactsApi.new(client)
assert_instance_of PulpcoreClient::ArtifactsApi, api
end
test "pulp_rpm client instantiation" do
config = @proxy.pulp3_configuration(PulpRpmClient::Configuration)
client = PulpRpmClient::ApiClient.new(config)
api = PulpRpmClient::RemotesRpmApi.new(client)
assert_instance_of PulpRpmClient::RemotesRpmApi, api
end
test "pulp_file client instantiation" do
config = @proxy.pulp3_configuration(PulpFileClient::Configuration)
client = PulpFileClient::ApiClient.new(config)
api = PulpFileClient::RepositoriesFileApi.new(client)
assert_instance_of PulpFileClient::RepositoriesFileApi, api
end
# Add similar tests for other plugins
endRun test:
bundle exec rake test TEST=test/unit/pulp_generated_clients_test.rbExpected: All tests pass
Deliverable: Test suite confirming API classes instantiate correctly
Purpose: Verify generated clients make real API calls to Pulp
Test with File repository (simplest):
bundle exec rails console
# Get Pulp primary proxy
proxy = SmartProxy.pulp_primary
# Create File repository backend service
repo = Katello::Repository.file_type.first || begin
root = Katello::RootRepository.create!(
name: 'TestFileRepo',
product: Katello::Product.first,
content_type: 'file'
)
root.library_instance
end
service = Katello::Pulp3::Repository.new(repo, proxy)
api = service.api # Should use generated PulpFileClient
# Test API call
begin
api.repositories_api.list({limit: 1})
puts "✓ File repository API works"
rescue => e
puts "✗ Error: #{e.message}"
endDeliverable: Confirmation that generated clients make successful API calls
File: /home/sajha/mnt1/katello/lib/monkeys/pulp_polymorphic_remote_response.rb
Current purpose: Patches Remote API update methods for polymorphic responses
Action:
-
Read current monkey patch implementation
-
Check if generated code has same issue
-
Test if patch still applies cleanly:
# Verify patch methods exist in generated code bundle exec rails console > PulpRpmClient::RemotesRpmApi.instance_methods.include?(:update) > PulpAnsibleClient::RemotesCollectionApi.instance_methods.include?(:update)
-
If patch fails, update for generated code structure
Likely outcome: No changes needed (generated code structure should match)
If changes needed:
# Current patch targets gem classes
# May need to adjust for generated code module structure
# But openapi-generator should produce same structureVerification:
bundle exec rake test TEST=test/actions/pulp3/repository/update_remote_test.rbDeliverable: Monkey patches work with generated clients (or updated if needed)
Purpose: Verify generated clients don't break existing functionality
Test suites to run:
-
Repository tests:
bundle exec rake test TEST=test/models/repository_test.rb bundle exec rake test TEST=test/models/repository/file_test.rb bundle exec rake test TEST=test/models/repository/yum_test.rb
-
Service tests:
bundle exec rake test TEST=test/services/katello/pulp3/repository_test.rb
-
Action tests:
bundle exec rake test TEST=test/actions/katello/repository/sync_test.rb bundle exec rake test TEST=test/actions/pulp3/*_test.rb
-
API tests:
bundle exec rake test TEST=test/controllers/api/v2/repositories_controller_test.rb
Expected results:
- All existing tests should pass
- If failures occur, investigate whether issue is with:
- Generated code structure
- Autoloading configuration
- Missing dependencies
- Actual incompatibilities
Deliverable: Test results showing compatibility (or documented issues to fix)
- All 7 repository types verified to use generated clients
- API class instantiation tests created and passing
- Live API calls work with generated clients (tested with File repository)
- Monkey patches reviewed and updated if needed
- Existing repository model tests pass
- Existing service tests pass
- Existing action tests pass
- Existing API controller tests pass
- Any issues documented with resolution plans
Purpose: Verify each content type works end-to-end with generated clients
Test matrix:
| Content Type | Repository | Sync | Create Content | Publish |
|---|---|---|---|---|
| YUM | ✓ | ✓ | ✓ | ✓ |
| Deb | ✓ | ✓ | ✓ | ✓ |
| Docker | ✓ | ✓ | ✓ | ✓ |
| File | ✓ | ✓ | ✓ | ✓ |
| Ansible | ✓ | ✓ | ✓ | ✓ |
| Python | ✓ | ✓ | ✓ | ✓ |
| OSTree | ✓ | ✓ | ✓ | ✓ |
Test script for each type:
# test_yum_repository.rb
repo = Katello::Repository.yum_type.first || create_yum_repo
service = repo.backend_service(SmartProxy.pulp_primary)
# Test repository creation
service.create
# Test sync (if has remote)
service.sync if repo.url
# Test content operations
service.api.repositories_api.list
# Test publication
service.create_publication
puts "✓ YUM repository operations successful"Repeat for each content type.
Run tests:
bundle exec rake test TEST=test/models/repository/yum_test.rb
bundle exec rake test TEST=test/models/repository/deb_test.rb
bundle exec rake test TEST=test/models/repository/docker_test.rb
bundle exec rake test TEST=test/models/repository/file_test.rbDeliverable: Verification that all content types work
Purpose: Update VCR cassettes if request/response structure changed
Background: VCR records HTTP interactions. If generated clients format requests differently, cassettes need regeneration.
Check for VCR cassette failures:
bundle exec rake test:katello 2>&1 | grep "VCR::Errors"If cassettes need updating:
# Regenerate all Pulp-related cassettes
VCR_RECORD=all bundle exec rake test TEST=test/actions/pulp3/
# Or regenerate specific cassettes
VCR_RECORD=all bundle exec rake test TEST=test/actions/pulp3/repository/create_test.rbCassette locations:
test/fixtures/vcr_cassettes/actions/pulp3/test/fixtures/vcr_cassettes/services/pulp3/
Validation:
- Run tests with regenerated cassettes
- Check cassette diffs - should only be formatting differences, not functional changes
- Commit updated cassettes with clear message
Deliverable: All VCR cassettes updated and tests passing
Purpose: Ensure no regressions across entire codebase
Run complete Katello test suite:
cd /home/sajha/mnt1/katello
bundle exec rake test:katelloExpected duration: 30-60 minutes
Monitor for:
- Pulp client-related failures
- Repository operation failures
- Sync/publish failures
- API endpoint failures
If failures occur:
- Categorize by type (client instantiation, API calls, configuration, etc.)
- Create GitHub issues for each category
- Prioritize by severity
- Fix critical issues before proceeding
Deliverable: Full test suite passing (or documented acceptable failures)
Purpose: Verify frontend still works (may use Pulp APIs via backend)
Run JavaScript tests:
cd /home/sajha/mnt1/katello
npm testExpected: No impact (frontend doesn't directly use Ruby clients)
If failures occur: Investigate backend API endpoints that frontend depends on
Deliverable: JavaScript tests passing
Purpose: Manual end-to-end testing
Test scenarios:
1. YUM Repository:
# Create product and repository
product = Katello::Product.create!(
name: 'Test Product',
organization: Organization.first,
provider: Provider.first
)
root = Katello::RootRepository.create!(
name: 'Test YUM Repo',
product: product,
content_type: 'yum',
url: 'https://fixtures.pulpproject.org/rpm-unsigned/'
)
repo = root.library_instance
# Sync repository
ForemanTasks.sync_task(Actions::Katello::Repository::Sync, repo)
# Verify content synced
puts "Packages: #{repo.rpms.count}"
puts "Errata: #{repo.errata.count}"2. Docker Repository:
# Create Docker repository
docker_repo = create_docker_repository
ForemanTasks.sync_task(Actions::Katello::Repository::Sync, docker_repo)
puts "Manifests: #{docker_repo.docker_manifests.count}"3. File Repository:
file_repo = create_file_repository
ForemanTasks.sync_task(Actions::Katello::Repository::Sync, file_repo)
puts "Files: #{file_repo.files.count}"Deliverable: Manual testing confirmation for key workflows
Purpose: Ensure generated clients don't introduce performance regression
Benchmark script:
# benchmark_pulp_clients.rb
require 'benchmark'
repo = Katello::Repository.yum_type.first
service = repo.backend_service(SmartProxy.pulp_primary)
# Benchmark API calls
Benchmark.bm do |x|
x.report("list repositories") do
100.times { service.api.repositories_api.list(limit: 10) }
end
x.report("list remotes") do
100.times { service.api.remotes_api.list(limit: 10) }
end
endBaseline: Compare with current gem-based performance Acceptable: Within 5% of baseline
Deliverable: Performance report showing no significant regression
- All 7 content types tested individually
- Repository create/sync/publish works for each type
- VCR cassettes reviewed and regenerated if needed
- Full Katello test suite passing
- JavaScript test suite passing
- Manual integration tests successful for YUM, Docker, File
- Performance benchmarks acceptable
- All test failures documented and addressed
File to modify: /home/sajha/mnt1/katello/katello.gemspec
Current dependencies (lines 52-63):
s.add_runtime_dependency 'pulpcore_client', '>= 3.85.0', '< 3.86.0'
s.add_runtime_dependency 'pulp_file_client', '>= 3.85.0', '< 3.86.0'
s.add_runtime_dependency 'pulp_ansible_client', '>= 0.28.0', '< 0.29.0'
s.add_runtime_dependency 'pulp_container_client', '>= 2.26.0', '< 2.27.0'
s.add_runtime_dependency 'pulp_deb_client', '>= 3.8.0', '< 3.9.0'
s.add_runtime_dependency 'pulp_rpm_client', '>= 3.32.0', '< 3.33.0'
s.add_runtime_dependency 'pulp_certguard_client', '>= 3.85.0', '< 3.86.0'
s.add_runtime_dependency 'pulp_python_client', '>= 3.19.0', '< 3.20.0'
s.add_runtime_dependency 'pulp_ostree_client', '>= 2.5.0', '< 2.6.0'Changes:
# DELETE all 9 Pulp client dependencies above
# ADD development dependency for regeneration
s.add_development_dependency 'openapi_generator', '~> 6.0'Verification:
bundle install
# Should NOT pull in pulp client gems anymore
bundle list | grep pulp
# Should show nothing (or only local generated code)Deliverable: katello.gemspec updated, no Pulp gem dependencies
File to modify: Packaging repository's katello.spec file
Location: Usually in separate packaging repository (foreman-packaging or katello-packaging)
Current requirements:
Requires: rubygem(pulpcore_client) >= 3.85.0
Requires: rubygem(pulpcore_client) < 3.86.0
Requires: rubygem(pulp_rpm_client) >= 3.32.0
Requires: rubygem(pulp_rpm_client) < 3.33.0
# ... (7 more similar lines)Changes:
# DELETE all Pulp client gem requirements
# REMOVE from BuildRequires if present:
# BuildRequires: rubygem(pulpcore_client)
# etc.
# UPDATE %files section - ADD these lines:
%{katello_dir}/lib/pulp_generated_clients/
%{katello_dir}/vendor/pulp_openapi_specs/
# If using bundler-style installation, ensure these directories are includedNote: Exact spec file location and syntax depends on packaging approach. Coordinate with packaging team.
Deliverable: RPM spec updated to include generated clients
File to create: /home/sajha/mnt1/katello/docs/pulp_client_update_workflow.md
Content:
# Pulp API Client Update Workflow
This document describes how to update Pulp API clients when upgrading Pulp.
## Overview
Katello uses Ruby API clients generated from Pulp's OpenAPI specifications. These clients are:
- Generated from vendored OpenAPI spec files in `vendor/pulp_openapi_specs/`
- Committed to the repository in `lib/pulp_generated_clients/`
- Packaged with Katello RPM (no separate gem dependencies)
## When to Update
Update clients when:
- Upgrading Pulp to a new version
- New Pulp plugin installed
- Pulp API changes require new features
**Typical frequency:** Every 3-6 months with Pulp upgrades
## Prerequisites
- Development environment with Pulp installed and running
- Pulp upgraded to target version
- `openapi-generator-cli` installed (`gem install openapi_generator`)
## Update Procedure
### Step 1: Upgrade Pulp in Development
```bash
# Upgrade Pulp to new version (example)
sudo dnf update pulp-server
systemctl restart pulpcore pulpcore-api pulpcore-contentVerify Pulp is running:
curl -u admin:password https://$(hostname)/pulp/api/v3/status/cd /home/sajha/mnt1/katello
# Fetch updated specs from upgraded Pulp instance
bundle exec rake katello:pulp:update_specsThis will create files like:
vendor/pulp_openapi_specs/pulpcore-3.86.0.json(new version)vendor/pulp_openapi_specs/pulp_rpm-3.33.0.json(new version)- etc.
# See what changed in the specs
git diff vendor/pulp_openapi_specs/
# Look for:
# - New API endpoints
# - Removed endpoints
# - Changed parameter types
# - New required fieldsImportant changes to note:
- New required parameters (may break existing code)
- Removed endpoints (need to update Katello code)
- Changed response formats (may affect parsing)
# Clear old generated code and regenerate
bundle exec rake katello:pulp:clear_generated
bundle exec rake katello:pulp:generate_clientsOr use combined task:
bundle exec rake katello:pulp:update_and_generateGeneration takes 2-5 minutes. Watch for errors.
# See what changed in generated clients
git diff lib/pulp_generated_clients/ | less
# Focus on:
# - New API classes
# - Modified method signatures
# - Changed model attributesLarge diffs are normal (~30K lines). Focus on:
- Method signature changes in APIs you use
- New required parameters
- Deprecated methods
If APIs changed, update Katello code:
Example: New required parameter added
# Before
service.api.remotes_api.update(remote_href, remote_data)
# After (with new required parameter)
service.api.remotes_api.update(remote_href, remote_data, validate: true)Check these locations:
/home/sajha/mnt1/katello/app/services/katello/pulp3//home/sajha/mnt1/katello/app/models/katello/concerns//home/sajha/mnt1/katello/lib/katello/repository_types/
# Run full test suite
bundle exec rake test:katello
# Pay attention to:
# - Repository sync tests
# - Content creation tests
# - Publication testsIf tests fail:
- Check error messages for API-related issues
- Update code to match new API requirements
- Regenerate VCR cassettes if needed:
VCR_RECORD=all bundle exec rake test:katello
Test key workflows in development:
bundle exec rails console
# Test YUM repository sync
repo = Katello::Repository.yum_type.first
ForemanTasks.sync_task(Actions::Katello::Repository::Sync, repo)
# Test Docker repository
docker_repo = Katello::Repository.docker_type.first
ForemanTasks.sync_task(Actions::Katello::Repository::Sync, docker_repo)
# Test content view publish
cv = Katello::ContentView.first
ForemanTasks.sync_task(Actions::Katello::ContentView::Publish, cv)git status
# Should show changes in:
# - vendor/pulp_openapi_specs/
# - lib/pulp_generated_clients/
# - (optionally) Katello code if APIs changed
git add vendor/pulp_openapi_specs/ lib/pulp_generated_clients/
# If you updated Katello code
git add app/services/ app/models/ lib/
git commit -m "Update Pulp API clients to Pulp 3.X
- Updated OpenAPI specs from Pulp 3.X.Y
- Regenerated Ruby clients
- New APIs: [list any new endpoints if applicable]
- Breaking changes: [list any breaking changes]
- Updated Katello code for API changes in [affected areas]
"git push origin pulp-3.x-upgradeCreate PR with:
- Description of Pulp version upgrade
- Summary of API changes
- Test results
- Any manual testing performed
PR review checklist:
- OpenAPI spec versions match target Pulp version
- Generated client code compiles (no syntax errors)
- Test suite passes
- Manual testing successful
- Breaking changes documented
- Katello code updated for API changes
After PR approval:
- Merge to main branch
- Build RPM with updated clients
- Test RPM installation
- Release to customers
Error: openapi-generator-cli: command not found
Solution:
gem install openapi_generator
# or
npm install -g @openapitools/openapi-generator-cliError: ERROR fetching pulp_rpm: Connection refused
Solution:
- Verify Pulp is running:
systemctl status pulpcore - Check Pulp URL in SmartProxy settings
- Verify credentials
Common causes:
- API parameters changed - update Katello code
- VCR cassettes out of date - regenerate:
VCR_RECORD=all - Response format changed - update parsing code
- Endpoint removed - find alternative API
Expected: Generated code diffs can be 20K-40K lines
What to review:
- Don't review every line
- Focus on spec file changes (small, readable)
- Scan generated code for obvious errors
- Rely on tests to catch issues
If issues found after upgrade:
# Revert to previous specs and clients
git revert <commit-hash>
# Or manually:
git checkout HEAD~1 vendor/pulp_openapi_specs/
git checkout HEAD~1 lib/pulp_generated_clients/
# Regenerate from old specs
bundle exec rake katello:pulp:generate_clients
# Test and commit
bundle exec rake test:katello
git commit -m "Rollback Pulp clients to previous version"- Pulp OpenAPI docs:
https://<pulp-server>/pulp/api/v3/docs/ - OpenAPI Generator: https://openapi-generator.tech/
- Katello Pulp3 integration:
/home/sajha/mnt1/katello/app/services/katello/pulp3/
**Deliverable:** Complete workflow documentation for Pulp upgrades
---
#### Task 4.4: Create Troubleshooting Guide (Agent 4)
**File to create:** `/home/sajha/mnt1/katello/docs/pulp_generated_clients_troubleshooting.md`
**Content:**
```markdown
# Pulp Generated Clients Troubleshooting
## Common Issues
### Client Class Not Found
**Error:** `uninitialized constant PulpRpmClient`
**Causes:**
- Generated code not loaded
- Autoload path not configured
- Code not generated yet
**Solutions:**
1. Check if generated code exists:
```bash
ls lib/pulp_generated_clients/pulp_rpm/lib/
-
Regenerate if missing:
bundle exec rake katello:pulp:generate_clients -
Verify autoload configuration in
lib/katello/engine.rb -
Restart Rails server
Error: undefined method 'some_api_method' for PulpRpmClient::RemotesRpmApi
Causes:
- Method removed in new Pulp version
- Wrong API class
- Generated code out of date
Solutions:
-
Check OpenAPI spec for method:
grep -r "some_api_method" vendor/pulp_openapi_specs/ -
Find new method in Pulp docs:
https://<pulp>/pulp/api/v3/docs/ -
Update Katello code to use new API
Error: TypeError: superclass mismatch for class Configuration
Cause: Module name collision between different plugins
Solution: Check generated code module structure - should be namespaced:
PulpcoreClient::ConfigurationPulpRpmClient::Configuration- etc.
Symptom: Slow API calls, timeouts
Debugging:
- Enable debug logging in SmartProxy configuration
- Check Pulp server performance
- Verify network connectivity
- Check Correlation-ID in logs for tracing
Symptom: rake katello:pulp:generate_clients doesn't complete
Solutions:
- Check openapi-generator process:
ps aux | grep openapi - Kill stuck processes:
pkill -f openapi - Clear output directory:
rm -rf lib/pulp_generated_clients/* - Try again
Symptom: Merge conflicts in lib/pulp_generated_clients/
Solution:
# Accept one side
git checkout --theirs lib/pulp_generated_clients/
# OR accept other side
git checkout --ours lib/pulp_generated_clients/
# Then regenerate from merged specs
git checkout --theirs vendor/pulp_openapi_specs/ # or --ours
bundle exec rake katello:pulp:generate_clients
git add lib/pulp_generated_clients/Error: VCR::Errors::UnhandledHTTPRequestError
Cause: API request changed, cassette doesn't match
Solution:
# Regenerate specific cassette
VCR_RECORD=all bundle exec rake test TEST=path/to/specific_test.rb
# Or regenerate all
VCR_RECORD=all bundle exec rake test:katelloError: Methods not found when applying patches
Cause: Generated code structure changed
Solution:
- Review
/home/sajha/mnt1/katello/lib/monkeys/pulp_polymorphic_remote_response.rb - Check if patched methods still exist in generated code
- Update patch for new structure or remove if no longer needed
Should not happen with this approach (code pre-generated)
If it does:
- Check file permissions on
lib/pulp_generated_clients/ - Verify all files packaged in RPM
- Check Rails logs for load errors
Error: PulpRpmClient::ApiError: 404 Not Found
Debugging:
- Check Pulp server status
- Verify endpoint exists in current Pulp version
- Check Correlation-ID in logs
- Compare client code version with Pulp version
- Check generated code matches expectations
- Review Pulp API documentation
- Check Katello integration code
- Ask in #katello-dev
- Create GitHub issue with:
- Pulp version
- Generated client version
- Error message and stack trace
- Steps to reproduce
**Deliverable:** Comprehensive troubleshooting guide
---
#### Task 4.5: Update README and Development Docs (Agent 4)
**File to modify:** `/home/sajha/mnt1/katello/README.md`
**Add section:**
```markdown
## Pulp API Clients
Katello uses Ruby API clients for Pulp that are generated from OpenAPI specifications.
**Key files:**
- `vendor/pulp_openapi_specs/` - OpenAPI spec JSON files (version controlled)
- `lib/pulp_generated_clients/` - Generated Ruby clients (committed to repo)
**For normal development:** You don't need to regenerate clients.
**When updating Pulp:** See [Pulp Client Update Workflow](docs/pulp_client_update_workflow.md)
**Troubleshooting:** See [Troubleshooting Guide](docs/pulp_generated_clients_troubleshooting.md)
Deliverable: README updated with client information
File to modify: /home/sajha/mnt1/katello/.gitignore
Add (if needed):
# Do NOT ignore generated clients - they're committed
# lib/pulp_generated_clients/ # <-- Don't add this
# Ignore temporary generation files
vendor/pulp_openapi_specs/*.tmp
lib/pulp_generated_clients/**/.openapi-generator/
Deliverable: Git ignore configured
- katello.gemspec updated (9 Pulp gem dependencies removed)
- Development dependency on openapi_generator added
- RPM spec file updated (coordinate with packaging team)
- Pulp upgrade workflow documentation complete
- Troubleshooting guide complete
- README updated with client information
- Git ignore rules configured
- Test RPM build successful (if packaging access available)
- Documentation reviewed and approved
Directory layout:
lib/pulp_generated_clients/
├── pulpcore/
│ ├── lib/
│ │ ├── pulpcore_client.rb # Main module
│ │ ├── pulpcore_client/api/
│ │ │ ├── artifacts_api.rb
│ │ │ ├── repositories_api.rb
│ │ │ └── ...
│ │ ├── pulpcore_client/models/
│ │ │ ├── artifact.rb
│ │ │ ├── repository.rb
│ │ │ └── ...
│ │ └── pulpcore_client/configuration.rb
│ └── pulpcore_client.gemspec # Metadata
├── pulp_rpm/
│ ├── lib/
│ │ ├── pulp_rpm_client.rb
│ │ ├── pulp_rpm_client/api/
│ │ │ ├── remotes_rpm_api.rb
│ │ │ ├── repositories_rpm_api.rb
│ │ │ └── ...
│ │ └── ...
│ └── pulp_rpm_client.gemspec
└── ... (similar for other plugins)
Module structure matches current gems:
PulpcoreClient::ApiClientPulpcoreClient::ConfigurationPulpRpmClient::RemotesRpmApi- etc.
Loading generated code:
# In lib/katello.rb or engine.rb
Dir.glob(File.join(__dir__, 'pulp_generated_clients', '*', 'lib', '*.rb')).each do |client|
require client
endEvery 3-6 months when Pulp is upgraded:
# Upgrade Pulp in your dev environment
sudo dnf update pulp-server
systemctl restart pulpcorecd /home/sajha/mnt1/katello
# Fetch updated specs from upgraded Pulp
bundle exec rake katello:pulp:update_specs
# Review what changed
git diff vendor/pulp_openapi_specs/# Regenerate from new specs
bundle exec rake katello:pulp:generate_clients
# Review generated code changes
git diff lib/pulp_generated_clients/ | less
# Look for breaking changes, new APIs, removed APIs# Start Foreman
bundle exec foreman start
# Run tests
bundle exec rake test:katello
# Manual testing
bundle exec rails console
> # Test each repository type
> SmartProxy.pulp_primary.pulp3_api(PulpRpmClient::ApiClient)git add vendor/pulp_openapi_specs/ lib/pulp_generated_clients/
git commit -m "Update Pulp API clients to Pulp 3.X
- Updated OpenAPI specs from Pulp 3.X
- Regenerated Ruby clients
- New APIs: [list any new endpoints]
- Breaking changes: [list any breaking changes]
"
git push origin pulp-3.x-upgrade- Create PR for review
- CI/CD runs full test suite
- QE tests the exact generated code
- Code review can see what changed in generated clients
- Merge to main
- Build RPM with updated clients
- Release to customers
- Zero customer impact - they just get the new RPM
katello.spec:
Requires: rubygem(pulpcore_client) >= 3.85.0, rubygem(pulpcore_client) < 3.86.0
Requires: rubygem(pulp_rpm_client) >= 3.32.0, rubygem(pulp_rpm_client) < 3.33.0
... (7 more)Total download for customers:
- Katello RPM: ~10MB
- 9 Pulp client gem RPMs: ~50MB
- Total: ~60MB
Installation process:
yum install katello
# Resolves 9 Pulp gem dependencies
# Downloads all 9 gems
# Installs Katello + 9 gem RPMskatello.spec:
# No Pulp gem dependencies!
%files
%{katello_bundledir}/lib/pulp_generated_clients/
%{katello_bundledir}/vendor/pulp_openapi_specs/Total download for customers:
- Katello RPM: ~40MB (includes generated clients + specs)
- Total: ~40MB
Installation process:
yum install katello
# No additional dependencies
# Installs single RPM
# Foreman starts normally, zero generation| Component | Current | Variant A | Variant B |
|---|---|---|---|
| Katello RPM | 10MB | 15MB | 40MB |
| Pulp client gems | 9 × ~5MB = 45MB | 0MB | 0MB |
| openapi-generator | 0MB | ~5MB | 0MB |
| Total Download | 60MB | 20MB | 40MB |
| Number of RPMs | 10 | 2 | 1 |
| Startup Delay | None | 5-15s first time | None |
Variant B wins on:
- Fewer RPM packages (simpler dependency tree)
- Moderate download size (between current and Variant A)
- Zero startup delay
- Zero runtime dependencies
Risk Level: Medium
Description: Generated code structure might differ from current gem structure, breaking existing code.
Mitigation:
- Generate clients in Phase 1, test with one repository type before proceeding
- Compare generated code structure to current gem structure
- Adjust openapi-generator config if needed (
--additional-properties) - Monkey patches can bridge any gaps
- Rollback is easy (git revert, use old gems temporarily)
Risk Level: Low
Description: 30K lines of generated code changes hard to review in PRs.
Mitigation:
- Review OpenAPI spec diffs first (small, readable)
- Focus PR review on:
- Spec changes
- Test results
- Any manual code changes
- Generated code review is optional (trust the generator)
- Can use
[skip ci]for pure regeneration commits
Risk Level: Low
Description: Developer updates specs but forgets to regenerate clients.
Mitigation:
- Document workflow clearly
- Add CI check that compares spec versions to generated code versions
- Pre-commit hook that detects spec changes and reminds to regenerate
- Rake task that does both:
rake katello:pulp:update_and_generate
Risk Level: Low
Description: openapi-generator updates might change generated code structure.
Mitigation:
- Pin openapi-generator version in Gemfile.lock
- Test generator upgrades in dev before committing
- Generated code is in git, so changes are visible
- Can revert to previous generator version if needed
Risk Level: Medium
Description: Multiple branches updating generated code creates conflicts.
Mitigation:
- Coordinate Pulp updates (one branch at a time)
- If conflicts occur, regenerate from merged specs:
git checkout --theirs vendor/pulp_openapi_specs/ bundle exec rake katello:pulp:generate_clients - Generated code conflicts are easy to resolve (just regenerate)
- Vendored spec directory created
- All 9 OpenAPI specs fetched and committed
- Rake tasks implemented and tested
- Initial client generation successful
- Generated code structure reviewed and approved
- Repository type registrations updated
- Generated clients loaded correctly
- One repository type (File) fully tested
- API calls work with generated clients
- Monkey patches reviewed/updated if needed
- All repository types updated
- Full test suite passes
- VCR cassettes regenerated if needed
- Manual testing across all content types
- Performance comparable to gem-based approach
- katello.gemspec cleaned up (no Pulp gem deps)
- RPM spec updated
- Documentation complete
- Test RPM builds successfully
- Test RPM installs and runs correctly
- Zero startup delay on customer systems
- All content types work correctly
- No generation errors in production
- Easy Pulp upgrade workflow
- Positive feedback from QE and customers
Total Duration: 3-4 weeks
| Week | Phase | Key Deliverables |
|---|---|---|
| 1 | Setup | Specs vendored, rake tasks, initial generation |
| 2 | Integration | Repository types updated, one type fully tested |
| 3 | Testing | All types tested, test suite passes, VCR updated |
| 4 | Cleanup | Gemspec/RPM updated, docs complete, ready for release |
Buffer: Add 1 week for unexpected issues, edge cases, or additional testing.
This plan implements vendored OpenAPI spec approach with dev-time code generation for Pulp API clients.
Approach: Generate Ruby clients from OpenAPI specs in development, commit generated code to repository, package with Katello RPM.
Key Benefits:
- ✅ Generation issues caught in Dev/QE (never on customer systems)
- ✅ Zero customer startup delay
- ✅ Eliminates 9 gem RPM dependencies
- ✅ Easy rollback via git revert
- ✅ QE tests exact code customers receive
Timeline: 3-4 weeks across 4 phases
Team Distribution:
- Agent 1: Infrastructure and rake tasks (Phase 1)
- Agent 2: Client generation and integration (Phase 1)
- Agent 3: Repository type updates and testing (Phases 2-3)
- Agent 4: Packaging and documentation (Phase 4)
Prerequisites:
- Development environment with Pulp installed
- openapi-generator-cli installed (
gem install openapi_generator) - Access to Pulp primary SmartProxy for fetching specs
Critical Success Factors:
- Generated code structure matches current gem structure
- All existing tests pass with generated clients
- Documentation clear for future Pulp upgrades
- RPM packaging updated correctly
Start with: Phase 1, Task 1.1 - Create directory structure
1st pass impementation results:
● 🎉 Success! All 9 Pulp API Clients Generated!
The vendored OpenAPI specs implementation is now complete. Here's what was accomplished:
Generated Clients
All 9 Ruby API clients have been successfully generated to /home/vagrant/katello/lib/pulp_generated_clients/:
What Changed
Created:
Modified:
Next Steps
cd /home/vagrant/foreman
bundle exec rails console
Then test loading the clients:
Should load without errors
PulpcoreClient::ApiClient
PulpRpmClient::RemotesRpmApi
PulpFileClient::RepositoriesFileApi
Test with repository types
Katello::RepositoryTypeManager.find('yum').client_module_class
=> PulpRpmClient
cd /home/vagrant/katello
git status
git add vendor/pulp_openapi_specs/
git add lib/pulp_generated_clients/
git add lib/katello/tasks/pulp_client_generation.rake
git add lib/katello/engine.rb
git add lib/monkeys/
git add katello.gemspec
git add docs/
git add README.md
git add .gitignore
git commit -m "Implement vendored Pulp API clients with dev-time generation
Generated clients (~30MB) are committed to eliminate runtime
dependencies and catch generation issues in Dev/QE before release.
Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com"
cd /home/vagrant/foreman
bundle exec rake test:katello
Future Pulp Upgrades
When Pulp is upgraded (every 3-6 months), simply run:
cd /home/vagrant/foreman
bundle exec rake katello:pulp:update_and_generate
This will:
See docs/pulp_client_update_workflow.md for detailed upgrade instructions.
The implementation is complete! 🚀