Skip to content

Commit

Permalink
Merge pull request #5 from d-a-v-e/adds-get-blob-tags
Browse files Browse the repository at this point in the history
adds `get_blob_tags` to client
  • Loading branch information
JoeDupuis authored Nov 1, 2024
2 parents 5308523 + e34af31 commit c44030d
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## [Unreleased]

- Add support for setting tags when uploading a blob
- Add get_blob_tags

## [0.5.2] 2024-09-12

Expand Down
23 changes: 19 additions & 4 deletions lib/azure_blob/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_relative "blob_list"
require_relative "blob"
require_relative "container"
require_relative "tags"
require_relative "http"
require_relative "shared_key_signer"
require_relative "entra_id_signer"
Expand All @@ -28,7 +29,7 @@ def initialize(account_name:, access_key: nil, principal_id: nil, container:, **
)
end
@signer = using_managed_identities ?
AzureBlob::EntraIdSigner.new(account_name:, host:, principal_id: ) :
AzureBlob::EntraIdSigner.new(account_name:, host:, principal_id:) :
AzureBlob::SharedKeySigner.new(account_name:, access_key:)
end

Expand Down Expand Up @@ -157,6 +158,20 @@ def get_blob_properties(key, options = {})
Blob.new(response)
end

# Returns the tags associated with a blob
#
# Calls to the {Get Blob Tags}[https://learn.microsoft.com/en-us/rest/api/storageservices/get-blob-tags] endpoint.
#
# Takes a key (path) of the blob.
#
# Returns a hash of the blob's tags.
def get_blob_tags(key)
uri = generate_uri("#{container}/#{key}?comp=tags")
response = Http.new(uri, signer:).get

Tags.from_response(response).to_h
end

# Returns a Container object.
#
# Calls to {Get Container Properties}[https://learn.microsoft.com/en-us/rest/api/storageservices/get-container-properties]
Expand Down Expand Up @@ -230,7 +245,7 @@ def create_append_blob(key, options = {})
"x-ms-blob-content-disposition": options[:content_disposition],
}

Http.new(uri, headers, metadata: options[:metadata], signer:).put(nil)
Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(nil)
end

# Append a block to an Append Blob
Expand Down Expand Up @@ -305,7 +320,7 @@ def commit_blob_blocks(key, block_ids, options = {})
"x-ms-blob-content-disposition": options[:content_disposition],
}

Http.new(uri, headers, metadata: options[:metadata], signer:).put(content)
Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(content)
end

private
Expand Down Expand Up @@ -337,7 +352,7 @@ def put_blob_single(key, content, options = {})
"x-ms-blob-content-disposition": options[:content_disposition],
}

Http.new(uri, headers, metadata: options[:metadata], signer:).put(content.read)
Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(content.read)
end

def host
Expand Down
8 changes: 6 additions & 2 deletions lib/azure_blob/http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@ class IntegrityError < Error; end

include REXML

def initialize(uri, headers = {}, signer: nil, metadata: {}, debug: false, raise_on_error: true)
def initialize(uri, headers = {}, signer: nil, metadata: {}, tags: {}, debug: false, raise_on_error: true)
@raise_on_error = raise_on_error
@date = Time.now.httpdate
@uri = uri
@signer = signer
@headers = headers.merge(Metadata.new(metadata).headers)
@headers = headers.merge(
Metadata.new(metadata).headers,
Tags.new(tags).headers,
)

sanitize_headers

@http = Net::HTTP.new(uri.hostname, uri.port)
Expand Down
35 changes: 35 additions & 0 deletions lib/azure_blob/tags.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require "rexml/document"

module AzureBlob
class Tags # :nodoc:
def self.from_response(response)
document = REXML::Document.new(response)
tags = {}
document.elements.each("Tags/TagSet/Tag") do |tag|
key = tag.elements["Key"].text
value = tag.elements["Value"].text
tags[key] = value
end
new(tags)
end

def initialize(tags = nil)
@tags = tags || {}
end

def headers
return {} if @tags.empty?

{
"x-ms-tags":
@tags.map do |key, value|
%(#{key}=#{value})
end.join("&"),
}
end

def to_h
@tags
end
end
end
2 changes: 1 addition & 1 deletion main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ resource "azurerm_user_assigned_identity" "vm" {

resource "azurerm_role_assignment" "vm" {
scope = azurerm_storage_account.main.id
role_definition_name = "Storage Blob Data Contributor"
role_definition_name = "Storage Blob Data Owner"
principal_id = azurerm_user_assigned_identity.vm.principal_id
}

Expand Down
8 changes: 8 additions & 0 deletions test/client/test_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -350,4 +350,12 @@ def test_create_container
container = client.get_container_properties
refute container.present?
end

def test_get_blob_tags
client.create_block_blob(key, content, tags: { tag1: "value 1", "tag 2": "value 2" })

tags = client.get_blob_tags(key)

assert_equal({ "tag1" => "value 1", "tag 2" => "value 2" }, tags)
end
end

0 comments on commit c44030d

Please sign in to comment.