Skip to content

Commit

Permalink
Refs #37552 - save container push distributions for all push endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
ianballou committed Jul 5, 2024
1 parent 7e02baa commit 36b4afb
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 51 deletions.
85 changes: 56 additions & 29 deletions app/controllers/katello/api/registry/registry_proxies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,11 @@ def get_root_repo_from_product(product, root_repo_name)
return product.root_repositories.where(label: root_repo_name)
end

def root_repository
@root_repository ||= get_root_repo_from_product(@product, @container_name)&.first
@root_repository
end

def check_blob_push_container(props)
unless props[:name].present? && props[:name].length > 0
return render_podman_error(
Expand Down Expand Up @@ -354,12 +359,10 @@ def create_container_repo_if_needed
end
end

def blob_push_cleanup
# after manifest upload, index content and set version href using pulp api
root_repo = get_root_repo_from_product(@product, @container_name)&.first
instance_repo = root_repo&.library_instance
def save_pulp_push_repository_href
instance_repo = root_repository&.library_instance

unless root_repo.present? && instance_repo.present?
unless root_repository.present? && instance_repo.present?
return render_podman_error(
"BLOB_UPLOAD_UNKNOWN",
_("Could not locate local uploaded repository for content indexing."),
Expand All @@ -380,7 +383,20 @@ def blob_push_cleanup
:not_found
)
end
instance_repo.update!(version_href: latest_version_href)
# The Pulp repository should not change after first creation
if root_repository.repository_references.empty?
::Katello::Pulp3::RepositoryReference.where(root_repository_id: instance_repo.root_id,
content_view_id: instance_repo.content_view.id,
repository_href: pulp_repo_href).create!
end
return pulp_repo_href
end

def save_pulp_push_distribution_href(pulp_repo_href)
instance_repo = root_repository&.library_instance
pulp_api = instance_repo.backend_service(SmartProxy.pulp_primary).api
instance_repo = root_repository&.library_instance
distribution_api_response = pulp_api.container_push_distribution_for_repository(pulp_repo_href)
pulp_distribution_href = distribution_api_response&.pulp_href

Expand All @@ -391,17 +407,25 @@ def blob_push_cleanup
:not_found
)
end
dist = ::Katello::Pulp3::DistributionReference.where(path: @container_path_input,
href: pulp_distribution_href,
repository_id: instance_repo.id).first
if dist
if dist.href != pulp_distribution_href
dist.update(href: pulp_distribution_href)
end
else
::Katello::Pulp3::DistributionReference.create!(path: @container_path_input,
href: pulp_distribution_href,
repository_id: instance_repo.id)
end
end

instance_repo.update!(version_href: latest_version_href)
::Katello::Pulp3::RepositoryReference.where(root_repository_id: instance_repo.root_id,
content_view_id: instance_repo.content_view.id,
repository_href: pulp_repo_href).create!
::Katello::Pulp3::DistributionReference.where(path: @container_path_input,
href: pulp_distribution_href,
repository_id: instance_repo.id).create!
instance_repo.index_content

true
def save_push_repo_hrefs
# After content upload, save Pulp hrefs.
pulp_repo_href = save_pulp_push_repository_href
return unless pulp_repo_href
save_pulp_push_distribution_href(pulp_repo_href)
end

def find_writable_repository
Expand Down Expand Up @@ -524,6 +548,17 @@ def pull_blob
redirect_client { Resources::Registry::Proxy.get(@_request.fullpath, headers, max_redirects: 0) }
end

def translated_headers_for_proxy
current_headers = {}
env = request.env.select do |key, _value|
key.match("^HTTP_.*")
end
env.each do |header|
current_headers[header[0].split('_')[1..-1].join('-')] = header[1]
end
current_headers
end

def start_upload_blob
headers = translated_headers_for_proxy
headers['Content-Type'] = request.headers['Content-Type'] if request.headers['Content-Type']
Expand All @@ -534,20 +569,10 @@ def start_upload_blob
response.header[key.to_s] = value
end

save_push_repo_hrefs if pulp_response.code.between?(200, 299)
head pulp_response.code
end

def translated_headers_for_proxy
current_headers = {}
env = request.env.select do |key, _value|
key.match("^HTTP_.*")
end
env.each do |header|
current_headers[header[0].split('_')[1..-1].join('-')] = header[1]
end
current_headers
end

def upload_blob
headers = translated_headers_for_proxy
headers['Content-Type'] = request.headers['Content-Type'] if request.headers['Content-Type']
Expand All @@ -560,6 +585,7 @@ def upload_blob
response.header[key.to_s] = value
end

save_push_repo_hrefs if pulp_response.code.between?(200, 299)
head pulp_response.code
end

Expand All @@ -574,6 +600,7 @@ def finish_upload_blob
response.header[key.to_s] = value
end

save_push_repo_hrefs if pulp_response.code.between?(200, 299)
head pulp_response.code
end

Expand All @@ -586,9 +613,9 @@ def push_manifest
response.header[key.to_s] = value
end

cleanup_result = blob_push_cleanup if pulp_response.code.between?(200, 299)
return false unless cleanup_result

save_push_repo_hrefs if pulp_response.code.between?(200, 299)
# Indexing content is only needed after pushing manifests
root_repository.library_instance.index_content
head pulp_response.code
end

Expand Down
69 changes: 47 additions & 22 deletions test/controllers/api/registry/registry_proxies_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,11 @@ def setup_permissions
@controller.expects(:check_blob_push_product_label).returns(true)
@controller.expects(:check_blob_push_container).returns(true)
@controller.expects(:create_container_repo_if_needed)
@controller.expects(:save_push_repo_hrefs).returns(true)
mock_root_repo = mock('root_repo')
mock_instance_repo = mock('instance_repo')
mock_root_repo.stubs(:library_instance).returns(mock_instance_repo)
@controller.stubs(:root_repository).returns(mock_root_repo)

# The content type should be octet-stream, but action controller
# throws a non-existence error since Mime::Type.lookup('application/octet-stream').to_sym is nil.
Expand All @@ -565,6 +570,11 @@ def setup_permissions
@controller.expects(:check_blob_push_product_label).returns(true)
@controller.expects(:check_blob_push_container).returns(true)
@controller.expects(:create_container_repo_if_needed)
@controller.expects(:save_push_repo_hrefs).returns(true)
mock_root_repo = mock('root_repo')
mock_instance_repo = mock('instance_repo')
mock_root_repo.stubs(:library_instance).returns(mock_instance_repo)
@controller.stubs(:root_repository).returns(mock_root_repo)

# The content type should be octet-stream, but action controller
# throws a non-existence error since Mime::Type.lookup('application/octet-stream').to_sym is nil.
Expand Down Expand Up @@ -592,6 +602,11 @@ def setup_permissions
@controller.expects(:check_blob_push_product_label).returns(true)
@controller.expects(:check_blob_push_container).returns(true)
@controller.expects(:create_container_repo_if_needed)
@controller.expects(:save_push_repo_hrefs).returns(true)
mock_root_repo = mock('root_repo')
mock_instance_repo = mock('instance_repo')
mock_root_repo.stubs(:library_instance).returns(mock_instance_repo)
@controller.stubs(:root_repository).returns(mock_root_repo)

# The content type should be octet-stream, but action controller
# throws a non-existence error since Mime::Type.lookup('application/octet-stream').to_sym is nil.
Expand All @@ -611,14 +626,19 @@ def setup_permissions
assert_equal 'Mars', resp.headers['Location']
end

it 'pushes a manifest' do
it 'pushes a manifest and indexes content' do
repo_name = 'test_org/test_product/test_name'
tag = 'latest'
@controller.expects(:check_blob_push_org_label).returns(true)
@controller.expects(:check_blob_push_product_label).returns(true)
@controller.expects(:check_blob_push_container).returns(true)
@controller.expects(:create_container_repo_if_needed)
@controller.expects(:blob_push_cleanup).returns(true)
@controller.expects(:save_push_repo_hrefs).returns(true)
mock_root_repo = mock('root_repo')
mock_instance_repo = mock('instance_repo')
mock_instance_repo.expects(:index_content)
mock_root_repo.stubs(:library_instance).returns(mock_instance_repo)
@controller.stubs(:root_repository).returns(mock_root_repo)

# The content type should be application/vnd.oci.image.manifest.v1+json, but action controller
# throws a non-existence error since Mime::Type.lookup('application/octet-stream').to_sym is nil.
Expand Down Expand Up @@ -1013,7 +1033,7 @@ def setup_permissions
@controller.create_container_repo_if_needed
end

it 'updates hrefs and triggers content indexing' do
it 'updates hrefs' do
container_name = "foo"
container_push_name = "default_org/test/foo"
latest_version_href = "asdfghjk"
Expand All @@ -1030,10 +1050,10 @@ def setup_permissions
mock_instance_repo.expects(:update!).with(version_href: latest_version_href)
mock_instance_repo.stubs(:root_id).returns(root_id)
mock_instance_repo.stubs(:content_view).returns(mock_content_view)
mock_instance_repo.expects(:index_content)
mock_instance_repo.expects(:id).returns(instance_id)
mock_instance_repo.stubs(:id).returns(instance_id)
mock_root_repo = mock('root_repository')
mock_root_repo.stubs(:library_instance).returns(mock_instance_repo)
mock_root_repo.stubs(:repository_references).returns([])
mock_root_repositories = mock('root_repositories')
mock_root_repositories.stubs(:where).with(label: container_name).returns([mock_root_repo])
mock_product = mock('Product')
Expand All @@ -1060,8 +1080,8 @@ def setup_permissions
mock_backend_service = mock('backend_service')
SmartProxy.stubs(:pulp_primary).returns(mock_pulp_primary)
#::Katello::Pulp3::Repository.expects(:api).with(mock_pulp_primary, ::Katello::Repository::DOCKER_TYPE).returns(mock_repo_api)
mock_instance_repo.expects(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.expects(:api).returns(mock_pulp_api)
mock_instance_repo.stubs(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.stubs(:api).returns(mock_pulp_api)
::Katello::Pulp3::RepositoryReference.stubs(:where).with(
root_repository_id: root_id,
content_view_id: content_view_id,
Expand All @@ -1073,12 +1093,15 @@ def setup_permissions
@controller.instance_variable_set(:@container_name, container_name)
@controller.instance_variable_set(:@container_path_input, container_push_name)

assert @controller.blob_push_cleanup
assert @controller.save_push_repo_hrefs
end

it 'rejects missing root repo on content indexing' do
container_name = "foo"

mock_pulp_api = mock('pulp_api')
mock_instance_repo = mock('instance repo')
mock_instance_repo.stubs(:backend_service).returns(mock_pulp_api)
mock_root_repositories = mock('root_repositories')
mock_root_repositories.stubs(:where).with(label: container_name).returns([])
mock_product = mock('Product')
Expand All @@ -1087,7 +1110,7 @@ def setup_permissions
@controller.instance_variable_set(:@product, mock_product)
@controller.instance_variable_set(:@container_name, container_name)
expect_render_podman_error("BLOB_UPLOAD_UNKNOWN", :not_found)
refute @controller.blob_push_cleanup
refute @controller.save_push_repo_hrefs
end

it 'rejects missing instance repo on content indexing' do
Expand All @@ -1103,7 +1126,7 @@ def setup_permissions
@controller.instance_variable_set(:@product, mock_product)
@controller.instance_variable_set(:@container_name, container_name)
expect_render_podman_error("BLOB_UPLOAD_UNKNOWN", :not_found)
refute @controller.blob_push_cleanup
refute @controller.save_push_repo_hrefs
end

it 'rejects missing repo api response on content indexing' do
Expand All @@ -1124,14 +1147,14 @@ def setup_permissions
mock_pulp_primary = mock('pulp_primary')
SmartProxy.stubs(:pulp_primary).returns(mock_pulp_primary)
mock_backend_service = mock('backend_service')
mock_instance_repo.expects(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.expects(:api).returns(mock_pulp_api)
mock_instance_repo.stubs(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.stubs(:api).returns(mock_pulp_api)

@controller.instance_variable_set(:@product, mock_product)
@controller.instance_variable_set(:@container_name, container_name)
@controller.instance_variable_set(:@container_path_input, container_push_name)
expect_render_podman_error("BLOB_UPLOAD_UNKNOWN", :not_found)
refute @controller.blob_push_cleanup
refute @controller.save_push_repo_hrefs
end

it 'rejects missing pulp_distribution_href on content indexing' do
Expand All @@ -1142,6 +1165,7 @@ def setup_permissions

mock_instance_repo = mock('library_instance')
mock_root_repo = mock('root_repository')
mock_root_repo.stubs(:repository_references).returns(['salmon'])
mock_root_repo.stubs(:library_instance).returns(mock_instance_repo)
mock_root_repositories = mock('root_repositories')
mock_root_repositories.stubs(:where).with(label: container_name).returns([mock_root_repo])
Expand All @@ -1161,14 +1185,15 @@ def setup_permissions
mock_pulp_primary = mock('pulp_primary')
SmartProxy.stubs(:pulp_primary).returns(mock_pulp_primary)
mock_backend_service = mock('backend_service')
mock_instance_repo.expects(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.expects(:api).returns(mock_pulp_api)
mock_instance_repo.expects(:update!).with(version_href: latest_version_href)
mock_instance_repo.stubs(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.stubs(:api).returns(mock_pulp_api)

@controller.instance_variable_set(:@product, mock_product)
@controller.instance_variable_set(:@container_name, container_name)
@controller.instance_variable_set(:@container_path_input, container_push_name)
expect_render_podman_error("BLOB_UPLOAD_UNKNOWN", :not_found)
refute @controller.blob_push_cleanup
refute @controller.save_push_repo_hrefs
end

it 'rejects missing latest_version_href on content indexing' do
Expand All @@ -1194,14 +1219,14 @@ def setup_permissions
mock_pulp_primary = mock('pulp_primary')
SmartProxy.stubs(:pulp_primary).returns(mock_pulp_primary)
mock_backend_service = mock('backend_service')
mock_instance_repo.expects(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.expects(:api).returns(mock_pulp_api)
mock_instance_repo.stubs(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.stubs(:api).returns(mock_pulp_api)

@controller.instance_variable_set(:@product, mock_product)
@controller.instance_variable_set(:@container_name, container_name)
@controller.instance_variable_set(:@container_path_input, container_push_name)
expect_render_podman_error("BLOB_UPLOAD_UNKNOWN", :not_found)
refute @controller.blob_push_cleanup
refute @controller.save_push_repo_hrefs
end

it 'rejects missing pulp_href on content indexing' do
Expand All @@ -1227,14 +1252,14 @@ def setup_permissions
mock_pulp_primary = mock('pulp_primary')
SmartProxy.stubs(:pulp_primary).returns(mock_pulp_primary)
mock_backend_service = mock('backend_service')
mock_instance_repo.expects(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.expects(:api).returns(mock_pulp_api)
mock_instance_repo.stubs(:backend_service).with(mock_pulp_primary).returns(mock_backend_service)
mock_backend_service.stubs(:api).returns(mock_pulp_api)

@controller.instance_variable_set(:@product, mock_product)
@controller.instance_variable_set(:@container_name, container_name)
@controller.instance_variable_set(:@container_path_input, container_push_name)
expect_render_podman_error("BLOB_UPLOAD_UNKNOWN", :not_found)
refute @controller.blob_push_cleanup
refute @controller.save_push_repo_hrefs
end

def mock_pulp_response(code, headers)
Expand Down

0 comments on commit 36b4afb

Please sign in to comment.