Skip to content

Commit c44030d

Browse files
authored
Merge pull request #5 from d-a-v-e/adds-get-blob-tags
adds `get_blob_tags` to client
2 parents 5308523 + e34af31 commit c44030d

File tree

6 files changed

+71
-7
lines changed

6 files changed

+71
-7
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## [Unreleased]
22

3+
- Add support for setting tags when uploading a blob
4+
- Add get_blob_tags
35

46
## [0.5.2] 2024-09-12
57

lib/azure_blob/client.rb

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require_relative "blob_list"
55
require_relative "blob"
66
require_relative "container"
7+
require_relative "tags"
78
require_relative "http"
89
require_relative "shared_key_signer"
910
require_relative "entra_id_signer"
@@ -28,7 +29,7 @@ def initialize(account_name:, access_key: nil, principal_id: nil, container:, **
2829
)
2930
end
3031
@signer = using_managed_identities ?
31-
AzureBlob::EntraIdSigner.new(account_name:, host:, principal_id: ) :
32+
AzureBlob::EntraIdSigner.new(account_name:, host:, principal_id:) :
3233
AzureBlob::SharedKeySigner.new(account_name:, access_key:)
3334
end
3435

@@ -157,6 +158,20 @@ def get_blob_properties(key, options = {})
157158
Blob.new(response)
158159
end
159160

161+
# Returns the tags associated with a blob
162+
#
163+
# Calls to the {Get Blob Tags}[https://learn.microsoft.com/en-us/rest/api/storageservices/get-blob-tags] endpoint.
164+
#
165+
# Takes a key (path) of the blob.
166+
#
167+
# Returns a hash of the blob's tags.
168+
def get_blob_tags(key)
169+
uri = generate_uri("#{container}/#{key}?comp=tags")
170+
response = Http.new(uri, signer:).get
171+
172+
Tags.from_response(response).to_h
173+
end
174+
160175
# Returns a Container object.
161176
#
162177
# Calls to {Get Container Properties}[https://learn.microsoft.com/en-us/rest/api/storageservices/get-container-properties]
@@ -230,7 +245,7 @@ def create_append_blob(key, options = {})
230245
"x-ms-blob-content-disposition": options[:content_disposition],
231246
}
232247

233-
Http.new(uri, headers, metadata: options[:metadata], signer:).put(nil)
248+
Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(nil)
234249
end
235250

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

308-
Http.new(uri, headers, metadata: options[:metadata], signer:).put(content)
323+
Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(content)
309324
end
310325

311326
private
@@ -337,7 +352,7 @@ def put_blob_single(key, content, options = {})
337352
"x-ms-blob-content-disposition": options[:content_disposition],
338353
}
339354

340-
Http.new(uri, headers, metadata: options[:metadata], signer:).put(content.read)
355+
Http.new(uri, headers, signer:, **options.slice(:metadata, :tags)).put(content.read)
341356
end
342357

343358
def host

lib/azure_blob/http.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ class IntegrityError < Error; end
2424

2525
include REXML
2626

27-
def initialize(uri, headers = {}, signer: nil, metadata: {}, debug: false, raise_on_error: true)
27+
def initialize(uri, headers = {}, signer: nil, metadata: {}, tags: {}, debug: false, raise_on_error: true)
2828
@raise_on_error = raise_on_error
2929
@date = Time.now.httpdate
3030
@uri = uri
3131
@signer = signer
32-
@headers = headers.merge(Metadata.new(metadata).headers)
32+
@headers = headers.merge(
33+
Metadata.new(metadata).headers,
34+
Tags.new(tags).headers,
35+
)
36+
3337
sanitize_headers
3438

3539
@http = Net::HTTP.new(uri.hostname, uri.port)

lib/azure_blob/tags.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
require "rexml/document"
2+
3+
module AzureBlob
4+
class Tags # :nodoc:
5+
def self.from_response(response)
6+
document = REXML::Document.new(response)
7+
tags = {}
8+
document.elements.each("Tags/TagSet/Tag") do |tag|
9+
key = tag.elements["Key"].text
10+
value = tag.elements["Value"].text
11+
tags[key] = value
12+
end
13+
new(tags)
14+
end
15+
16+
def initialize(tags = nil)
17+
@tags = tags || {}
18+
end
19+
20+
def headers
21+
return {} if @tags.empty?
22+
23+
{
24+
"x-ms-tags":
25+
@tags.map do |key, value|
26+
%(#{key}=#{value})
27+
end.join("&"),
28+
}
29+
end
30+
31+
def to_h
32+
@tags
33+
end
34+
end
35+
end

main.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ resource "azurerm_user_assigned_identity" "vm" {
106106

107107
resource "azurerm_role_assignment" "vm" {
108108
scope = azurerm_storage_account.main.id
109-
role_definition_name = "Storage Blob Data Contributor"
109+
role_definition_name = "Storage Blob Data Owner"
110110
principal_id = azurerm_user_assigned_identity.vm.principal_id
111111
}
112112

test/client/test_client.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,4 +350,12 @@ def test_create_container
350350
container = client.get_container_properties
351351
refute container.present?
352352
end
353+
354+
def test_get_blob_tags
355+
client.create_block_blob(key, content, tags: { tag1: "value 1", "tag 2": "value 2" })
356+
357+
tags = client.get_blob_tags(key)
358+
359+
assert_equal({ "tag1" => "value 1", "tag 2" => "value 2" }, tags)
360+
end
353361
end

0 commit comments

Comments
 (0)