class AzureBlob::Client
through an instance of this class.
AzureBlob Client class. You interact with the Azure Blob api
def append_blob_block(key, content, options = {})
Will ensure integrity of the upload. The checksum must be a base64 digest. Can be produced with +OpenSSL::Digest::MD5.base64digest+.
[+:content_md5+]
Options:
Calls to {Append Block}[https://learn.microsoft.com/en-us/rest/api/storageservices/append-block]
Append a block to an Append Blob
def append_blob_block(key, content, options = {}) uri = generate_uri("#{container}/#{key}") uri.query = URI.encode_www_form(comp: "appendblock") headers = { "Content-Length": content.size, "Content-Type": options[:content_type], "Content-MD5": options[:content_md5], } Http.new(uri, headers, signer:).put(content) end
def commit_blob_blocks(key, block_ids, options = {})
This is the checksum for the whole blob. The checksum is saved on the blob, but it is not validated!
[+:content_md5+]
Options:
Takes a key (path) and an array of block ids
Calls to {Put Block List}[https://learn.microsoft.com/en-us/rest/api/storageservices/put-block-list]
Commits the list of blocks to a blob.
def commit_blob_blocks(key, block_ids, options = {}) block_list = BlockList.new(block_ids) content = block_list.to_s uri = generate_uri("#{container}/#{key}") uri.query = URI.encode_www_form(comp: "blocklist") headers = { "Content-Length": content.size, "Content-Type": options[:content_type], "x-ms-blob-content-md5": options[:content_md5], "x-ms-blob-content-disposition": options[:content_disposition], } Http.new(uri, headers, metadata: options[:metadata], signer:).put(content) end
def create_append_blob(key, options = {})
[+:content_disposition+]
Will be saved on the blob in Azure.
[+:content_type+]
Options:
You are expected to append blocks to the blob with append_blob_block after creating the blob.
Calls to {Put Blob}[https://learn.microsoft.com/en-us/rest/api/storageservices/put-blob]
Creates a Blob of type append.
def create_append_blob(key, options = {}) uri = generate_uri("#{container}/#{key}") headers = { "x-ms-blob-type": "AppendBlob", "Content-Length": 0, "Content-Type": options[:content_type], "Content-MD5": options[:content_md5], "x-ms-blob-content-disposition": options[:content_disposition], } Http.new(uri, headers, metadata: options[:metadata], signer:).put(nil) end
def create_block_blob(key, content, options = {})
[+:block_size+]
a checksum for each block, then commit the blocks with commit_blob_blocks.
The checksum is only checked on a single upload! To verify checksum when uploading multiple blocks, call directly put_blob_block with
Will ensure integrity of the upload. The checksum must be a base64 digest. Can be produced with +OpenSSL::Digest::MD5.base64digest+.
[+:content_md5+]
Will be saved on the blob in Azure.
[+:content_disposition+]
Will be saved on the blob in Azure.
[+:content_type+]
Options:
Takes a key (path), the content (String or IO object), and options.
followed by a {Put Block List}[https://learn.microsoft.com/en-us/rest/api/storageservices/put-block-list] to commit the block list.
If the blob is too big, the blob is split in blocks sent through a series of {Put Block}[https://learn.microsoft.com/en-us/rest/api/storageservices/put-block] requests
When the blob is small enough this method will send the blob through {Put Blob}[https://learn.microsoft.com/en-us/rest/api/storageservices/put-blob]
Create a blob of type block. Will automatically split the the blob in multiple block and send the blob in pieces (blocks) if the blob is too big.
def create_block_blob(key, content, options = {}) if content.size > (options[:block_size] || DEFAULT_BLOCK_SIZE) put_blob_multiple(key, content, **options) else put_blob_single(key, content, **options) end end
def delete_blob(key, options = {})
[+:delete_snapshots+]
Options:
Takes a key (path) and options.
Calls to {Delete Blob}[https://learn.microsoft.com/en-us/rest/api/storageservices/delete-blob]
Delete a blob
def delete_blob(key, options = {}) uri = generate_uri("#{container}/#{key}") headers = { "x-ms-delete-snapshots": options[:delete_snapshots] || "include", } Http.new(uri, headers, signer:).delete end
def delete_prefix(prefix, options = {})
Takes a prefix and options
followed to a series of calls to {Delete Blob}[https://learn.microsoft.com/en-us/rest/api/storageservices/delete-blob]
Calls to {List blobs}[https://learn.microsoft.com/en-us/rest/api/storageservices/list-blobs]
Delete all blobs prefixed by the given prefix.
def delete_prefix(prefix, options = {}) results = list_blobs(prefix:) results.each { |key| delete_blob(key) } end
def generate_block_id(index)
def generate_block_id(index) Base64.urlsafe_encode64(index.to_s.rjust(6, "0")) end
def generate_uri(path)
Return a URI object to a resource in the container. Takes a path.
def generate_uri(path) URI.parse(URI::DEFAULT_PARSER.escape(File.join(host, path))) end
def get_blob(key, options = {})
[+:end+]
Starting point in bytes
[+:start+]
Options:
Takes a key (path) and options.
Calls to the {Get Blob}[https://learn.microsoft.com/en-us/rest/api/storageservices/get-blob] endpoint.
Returns the full or partial content of the blob
def get_blob(key, options = {}) uri = generate_uri("#{container}/#{key}") headers = { "x-ms-range": options[:start] && "bytes=#{options[:start]}-#{options[:end]}", } Http.new(uri, headers, signer:).get end
def get_blob_properties(key, options = {})
Calls to {Get Blob Properties}[https://learn.microsoft.com/en-us/rest/api/storageservices/get-blob-properties]
Returns a Blob object without the content.
def get_blob_properties(key, options = {}) uri = generate_uri("#{container}/#{key}") response = Http.new(uri, signer:).head Blob.new(response) end
def host
def host "https://#{account_name}.blob.core.windows.net" end
def initialize(account_name:, access_key:, container:, **options)
def initialize(account_name:, access_key:, container:, **options) @account_name = account_name @container = container @signer = !access_key.nil? && !access_key.empty? ? AzureBlob::SharedKeySigner.new(account_name:, access_key:) : AzureBlob::EntraIdSigner.new(account_name:, **options.slice(:principal_id)) end
def list_blobs(options = {})
[:+max_results+]
Prefix of the blobs to be listed. Defaults to listing everything in the container.
[+:prefix+]
Options:
Calls to {List blobs}[https://learn.microsoft.com/en-us/rest/api/storageservices/list-blobs]
Returns a BlobList containing a list of keys (paths)
def list_blobs(options = {}) uri = generate_uri(container) query = { comp: "list", restype: "container", prefix: options[:prefix].to_s.gsub(/\\/, "/"), } query[:maxresults] = options[:max_results] if options[:max_results] uri.query = URI.encode_www_form(**query) fetcher = ->(marker) do query[:marker] = marker query.reject! { |key, value| value.to_s.empty? } uri.query = URI.encode_www_form(**query) response = Http.new(uri, signer:).get end BlobList.new(fetcher) end
def put_blob_block(key, index, content, options = {})
[+:content_md5+]
Options:
Returns the id of the block. Required to commit the list of blocks to a blob.
Calls to {Put Block}[https://learn.microsoft.com/en-us/rest/api/storageservices/put-block]
Uploads a block to a blob.
def put_blob_block(key, index, content, options = {}) block_id = generate_block_id(index) uri = generate_uri("#{container}/#{key}") uri.query = URI.encode_www_form(comp: "block", blockid: block_id) headers = { "Content-Length": content.size, "Content-Type": options[:content_type], "Content-MD5": options[:content_md5], } Http.new(uri, headers, signer:).put(content) block_id end
def put_blob_multiple(key, content, options = {})
def put_blob_multiple(key, content, options = {}) content = StringIO.new(content) if content.is_a? String block_size = options[:block_size] || DEFAULT_BLOCK_SIZE block_count = (content.size.to_f / block_size).ceil block_ids = block_count.times.map do |i| put_blob_block(key, i, content.read(block_size)) end commit_blob_blocks(key, block_ids, options) end
def put_blob_single(key, content, options = {})
def put_blob_single(key, content, options = {}) content = StringIO.new(content) if content.is_a? String uri = generate_uri("#{container}/#{key}") headers = { "x-ms-blob-type": "BlockBlob", "Content-Length": content.size, "Content-Type": options[:content_type], "x-ms-blob-content-md5": options[:content_md5], "x-ms-blob-content-disposition": options[:content_disposition], } Http.new(uri, headers, metadata: options[:metadata], signer:).put(content.read) end
def signed_uri(key, permissions:, expiry:, **options)
- expiry as a UTC iso8601 time string
- A permission string (+"r"+, +"rw"+)
- key (path)
Takes a
Returns an SAS signed URI
def signed_uri(key, permissions:, expiry:, **options) uri = generate_uri("#{container}/#{key}") uri.query = signer.sas_token(uri, permissions:, expiry:, **options) uri end