Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an endpoint in bosh director for download a package with blobstore id #2529

Merged
merged 1 commit into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,37 @@ class PackagesController < BaseController
json_encode(fingerprints)
end

get '/blobs/:id', scope: :read do
blobstore_id = params[:id]

package = find_package_by_blobstore_id(blobstore_id)
if package.nil?
status(400)
body("Package with blobstore id: #{blobstore_id} does not exist")
return
end

blobstore_client = App.instance.blobstores.blobstore
path = Dir.mktmpdir
temp_path = File.join(path, "package-blob-#{blobstore_id}")
File.open(temp_path, 'w') do |file|
blobstore_client.get(blobstore_id, file)
end
send_file(temp_path, disposition: 'attachment')
end

private

def find_package_by_blobstore_id(id)
package = Models::Package.first(blobstore_id: id)

if package.nil?
package = Models::CompiledPackage.first(blobstore_id: id)
end

return package
end

def compiled_package_fingerprints_not_to_be_uploaded(manifest_hash)
compiled_release_manifest = CompiledRelease::Manifest.new(manifest_hash)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@ module Api
include Rack::Test::Methods

subject(:app) { linted_rack_app(described_class.new(config)) }
before { allow(Api::ResourceManager).to receive(:new) }
let(:config) { Config.load_hash(SpecHelper.spec_get_director_config) }
let(:config) do
config = Config.load_hash(SpecHelper.spec_get_director_config)
identity_provider = Support::TestIdentityProvider.new(config.get_uuid_provider)
allow(config).to receive(:identity_provider).and_return(identity_provider)
config
end

let(:release) { Models::Release.make(name: 'fake-release-name') }
let(:release_version) { Models::ReleaseVersion.make(version: 1, release: release, update_completed: true) }

before do
allow(Api::ResourceManager).to receive(:new)
release_version.save
end

Expand Down Expand Up @@ -401,6 +406,101 @@ def perform_matches_compiled(params_compiled)
end
end
end

describe 'GET', '/blobs/:id' do
def perform
get "/blobs/#{blobstore_id}"
end

let(:blobstore) { instance_double(Bosh::Blobstore::BaseClient, get: nil) }
let(:blobstore_id) { 'blobstore-id' }

before do
allow(Bosh::Director::App).to receive_message_chain(:instance, :blobstores, :blobstore).and_return(blobstore)

allow(blobstore).to receive(:get).with('blobstore-id', instance_of(File)) do |id, file|
file.write('FILE CONTENT')
end
end

context 'authenticated read-only access' do
before { authorize 'reader', 'reader' }

context 'when the blobstore id is not associated with a package' do
let(:blobstore_id) { 'non-existent-blob-id' }

it 'returns an error' do
perform
expect(last_response.status).to eq(400)
expect(last_response.body).to eq('Package with blobstore id: non-existent-blob-id does not exist')
end
end

context 'when the blobstore id is for a package' do
before do
Models::Package.make(
release: release,
name: 'fake-pkg1',
version: 'fake-pkg1-version',
blobstore_id: blobstore_id,
sha1: 'fakepkg1sha',
fingerprint: 'fake-pkg1-fingerprint',
)
end

it 'downloads the blob' do
perform
expect(last_response.status).to eq(200)
expect(last_response.headers['Content-Disposition']).to include('attachment')
expect(last_response.body).to include('FILE CONTENT')
end
end

context 'when the blobstore id is for a compiled package' do
before do
package = Models::Package.make(
release: release,
name: 'fake-pkg1',
version: 'fake-pkg1-version',
# Explicitly leave out blobstore_id for pre-compiled packages
sha1: 'fakepkg1sha',
fingerprint: 'fake-pkg1-fingerprint',
)
Models::CompiledPackage.make(
package_id: package.id,
blobstore_id: blobstore_id,
sha1: 'cpkg1sha1',
stemcell_os: 'ubuntu-trusty',
stemcell_version: '3000',
dependency_key: '[["fake-pkg2","fake-pkg2-version"],["fake-pkg3","fake-pkg3-version"]]',
)
end

it 'downloads the blob' do
perform
expect(last_response.status).to eq(200)
expect(last_response.headers['Content-Disposition']).to include('attachment')
expect(last_response.body).to include('FILE CONTENT')
end
end
end

context 'accessing with invalid credentials' do
before { authorize 'invalid-user', 'invalid-password' }

it 'returns 401' do
perform
expect(last_response.status).to eq(401)
end
end

context 'unauthenticated access' do
it 'returns 401' do
perform
expect(last_response.status).to eq(401)
end
end
end
end
end
end