azure-blob 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94edcaaaa7717925c1fb8238b9e7420949b26c98c90344cbf54930d5e0ff3b19
4
- data.tar.gz: aae153da753212659590ed4a3ae029c86cf7ed66b4f924dac1a5f3a5ff3b2e05
3
+ metadata.gz: 72003b15ad78aeab66adc7aca2e6786ae2921ad1469cf94145e049705f52c33c
4
+ data.tar.gz: a77f87dff2f59a22476f0c5e490540a73166cf88dbf3616de8a15a87132aaa5f
5
5
  SHA512:
6
- metadata.gz: 102c3d5fd08761199413e96bd8e4bae8a84ac5478d7bb1202e232fbff346703f7cb3b8f344553983b607dbacec56942452ce18aa0afc184a4c994d31dc94118c
7
- data.tar.gz: 646636874dd381757595f82999dd0b7b5647a740512c8e2baf86bdc2045e579cdf78354a4690c746452280efb7ff92cbf9c49c95775ccbcf6a690eb0ae05131f
6
+ metadata.gz: 910c2d759b83d7b56168fd42a239ffb5da1b4aced25b8f39bc84a1beb63e736690a72586f64313d5fcebf7250808b27d15e23450e850635e24558891eed375ff
7
+ data.tar.gz: 2d4ecfb6e3e5318d8c6cb07569da7b83bccd49ee3a7d153d43c41e655474dcd43d7a73d28d68fb2baa4124326a1b41562275314348730250610420640c3dc3bd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## [Unreleased]
2
2
 
3
+
4
+ ## [0.5.2] 2024-09-12
5
+
6
+ - Add get_container_properties
7
+ - Add create_container
8
+ - Add delete_container
9
+ - Support for Azure China, US Gov and Germany
10
+
11
+ ## [0.5.1] 2024-09-09
12
+
13
+ - Remove dev files from the release
14
+
3
15
  ## [0.5.0] 2024-09-09
4
16
 
5
17
  - Added support for Managed Identities (Entra ID)
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # AzureBlob
2
2
 
3
- This gem was built to replace azure-storage-blob (deprecated) in Active Storage, but was written to be Rails agnostic.
3
+ Azure Blob client and Active Storage adapter to replace the now abandoned azure-storage-blob
4
+
5
+ An Active Storage is supplied, but the gem is Rails agnostic and can be used in any Ruby project.
4
6
 
5
7
  ## Active Storage
6
8
 
@@ -12,6 +14,16 @@ To migrate from azure-storage-blob to azure-blob:
12
14
  3. Change the `AzureStorage` service to `AzureBlob` in your Active Storage config (`config/storage.yml`)
13
15
  4. Restart or deploy the app.
14
16
 
17
+ Example config:
18
+
19
+ ```
20
+ microsoft:
21
+ service: AzureBlob
22
+ storage_account_name: account_name
23
+ storage_access_key: SECRET_KEY
24
+ container: container_name
25
+ ```
26
+
15
27
  ### Managed Identity (Entra ID)
16
28
 
17
29
  AzureBlob supports managed identities on :
@@ -22,9 +34,7 @@ AzureBlob supports managed identities on :
22
34
 
23
35
  AKS support will likely require more work. Contributions are welcome.
24
36
 
25
- To authenticate through managed identities instead of a shared key, omit `storage_access_key` from your `storage.yml` file.
26
-
27
- It is recommended to add the identity's `principal_id` to the config.
37
+ To authenticate through managed identities instead of a shared key, omit `storage_access_key` from your `storage.yml` file and pass in the identity `principal_id`.
28
38
 
29
39
  ActiveStorage config example:
30
40
 
@@ -79,11 +89,12 @@ A dev environment is supplied through Nix with [devenv](https://devenv.sh/).
79
89
 
80
90
  To test with Entra ID, the `AZURE_ACCESS_KEY` environment variable must be unset and the code must be ran or proxied through a VPS with the proper roles.
81
91
 
82
- For cost saving, the terraform variable `create_vm` is false by default.
83
- To create the VPS, Create a var file `var.tfvars` containing:
92
+ For cost saving, the terraform variable `create_vm` and `create_app_service` are false by default.
93
+ To create the VPS and App service, Create a var file `var.tfvars` containing:
84
94
 
85
95
  ```
86
96
  create_vm = true
97
+ create_app_service = true
87
98
  ```
88
99
  and re-apply terraform: `terraform apply -var-file=var.tfvars`.
89
100
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AzureBlob
4
- # AzureBlob::Blob holds the metada for a given Blob.
4
+ # AzureBlob::Blob holds the metadata for a given Blob.
5
5
  class Blob
6
6
  # You should not instanciate this object directly,
7
7
  # but obtain one when calling relevant methods of AzureBlob::Client.
@@ -32,7 +32,7 @@ module AzureBlob
32
32
  response.code == "200"
33
33
  end
34
34
 
35
- # Returns the custom Azure metada tagged on the blob.
35
+ # Returns the custom Azure metadata tagged on the blob.
36
36
  def metadata
37
37
  @metadata || response
38
38
  .to_hash
@@ -3,6 +3,7 @@
3
3
  require_relative "block_list"
4
4
  require_relative "blob_list"
5
5
  require_relative "blob"
6
+ require_relative "container"
6
7
  require_relative "http"
7
8
  require_relative "shared_key_signer"
8
9
  require_relative "entra_id_signer"
@@ -13,13 +14,22 @@ module AzureBlob
13
14
  # AzureBlob Client class. You interact with the Azure Blob api
14
15
  # through an instance of this class.
15
16
  class Client
16
- def initialize(account_name:, access_key:, container:, **options)
17
+ def initialize(account_name:, access_key: nil, principal_id: nil, container:, **options)
17
18
  @account_name = account_name
18
19
  @container = container
20
+ @cloud_regions = options[:cloud_regions]&.to_sym || :global
19
21
 
20
- @signer = !access_key.nil? && !access_key.empty? ?
21
- AzureBlob::SharedKeySigner.new(account_name:, access_key:) :
22
- AzureBlob::EntraIdSigner.new(account_name:, **options.slice(:principal_id))
22
+ no_access_key = access_key.nil? || access_key&.empty?
23
+ using_managed_identities = no_access_key && !principal_id.nil? || options[:use_managed_identities]
24
+
25
+ if !using_managed_identities && no_access_key
26
+ raise AzureBlob::Error.new(
27
+ "`access_key` cannot be empty. To use managed identities instead, pass a `principal_id` or set `use_managed_identities` to true."
28
+ )
29
+ end
30
+ @signer = using_managed_identities ?
31
+ AzureBlob::EntraIdSigner.new(account_name:, host:, principal_id: ) :
32
+ AzureBlob::SharedKeySigner.new(account_name:, access_key:)
23
33
  end
24
34
 
25
35
  # 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.
@@ -138,7 +148,7 @@ module AzureBlob
138
148
  #
139
149
  # Calls to {Get Blob Properties}[https://learn.microsoft.com/en-us/rest/api/storageservices/get-blob-properties]
140
150
  #
141
- # This can be used to see if the blob exist or obtain metada such as content type, disposition, checksum or Azure custom metadata.
151
+ # This can be used to see if the blob exist or obtain metadata such as content type, disposition, checksum or Azure custom metadata.
142
152
  def get_blob_properties(key, options = {})
143
153
  uri = generate_uri("#{container}/#{key}")
144
154
 
@@ -147,6 +157,37 @@ module AzureBlob
147
157
  Blob.new(response)
148
158
  end
149
159
 
160
+ # Returns a Container object.
161
+ #
162
+ # Calls to {Get Container Properties}[https://learn.microsoft.com/en-us/rest/api/storageservices/get-container-properties]
163
+ #
164
+ # This can be used to see if the container exist or obtain metadata.
165
+ def get_container_properties(options = {})
166
+ uri = generate_uri(container)
167
+ uri.query = URI.encode_www_form(restype: "container")
168
+ response = Http.new(uri, signer:, raise_on_error: false).head
169
+
170
+ Container.new(response)
171
+ end
172
+
173
+ # Create the container
174
+ #
175
+ # Calls to {Create Container}[https://learn.microsoft.com/en-us/rest/api/storageservices/create-container]
176
+ def create_container(options = {})
177
+ uri = generate_uri(container)
178
+ uri.query = URI.encode_www_form(restype: "container")
179
+ response = Http.new(uri, signer:).put
180
+ end
181
+
182
+ # Delete the container
183
+ #
184
+ # Calls to {Delete Container}[https://learn.microsoft.com/en-us/rest/api/storageservices/delete-container]
185
+ def delete_container(options = {})
186
+ uri = generate_uri(container)
187
+ uri.query = URI.encode_www_form(restype: "container")
188
+ response = Http.new(uri, signer:).delete
189
+ end
190
+
150
191
  # Return a URI object to a resource in the container. Takes a path.
151
192
  #
152
193
  # Example: +generate_uri("#{container}/#{key}")+
@@ -299,10 +340,10 @@ module AzureBlob
299
340
  Http.new(uri, headers, metadata: options[:metadata], signer:).put(content.read)
300
341
  end
301
342
 
302
- attr_reader :account_name, :signer, :container, :http
303
-
304
343
  def host
305
- "https://#{account_name}.blob.core.windows.net"
344
+ @host ||= "https://#{account_name}.blob.#{CLOUD_REGIONS_SUFFIX[cloud_regions]}"
306
345
  end
346
+
347
+ attr_reader :account_name, :signer, :container, :http, :cloud_regions
307
348
  end
308
349
  end
@@ -2,7 +2,13 @@
2
2
 
3
3
  module AzureBlob
4
4
  API_VERSION = "2024-05-04"
5
- MAX_UPLOAD_SIZE = 256 * 1024 * 1024
6
- DEFAULT_BLOCK_SIZE = 128 * 1024 * 1024
5
+ MAX_UPLOAD_SIZE = 256 * 1024 * 1024 # 256 Megabytes
6
+ DEFAULT_BLOCK_SIZE = 128 * 1024 * 1024 # 128 Megabytes
7
7
  BLOB_SERVICE = "b"
8
+ CLOUD_REGIONS_SUFFIX = {
9
+ global: "core.windows.net",
10
+ cn: "core.chinacloudapi.cn",
11
+ de: "core.cloudapi.de",
12
+ usgovt: "core.usgovcloudapi.net",
13
+ }
8
14
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AzureBlob
4
+ # AzureBlob::Container holds the metadata for a given Container.
5
+ class Container
6
+ # You should not instanciate this object directly,
7
+ # but obtain one when calling relevant methods of AzureBlob::Client.
8
+ #
9
+ # Expects a Net::HTTPResponse object from a
10
+ # HEAD or GET request to a container uri.
11
+ def initialize(response)
12
+ @response = response
13
+ end
14
+
15
+
16
+ def present?
17
+ response.code == "200"
18
+ end
19
+
20
+ # Returns the custom Azure metadata tagged on the container.
21
+ def metadata
22
+ @metadata || response
23
+ .to_hash
24
+ .select { |key, _| key.start_with?("x-ms-meta") }
25
+ .transform_values(&:first)
26
+ .transform_keys { |key| key.delete_prefix("x-ms-meta-").to_sym }
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :response
32
+ end
33
+ end
@@ -12,10 +12,12 @@ module AzureBlob
12
12
  class EntraIdSigner # :nodoc:
13
13
  attr_reader :token
14
14
  attr_reader :account_name
15
+ attr_reader :host
15
16
 
16
- def initialize(account_name:, principal_id: nil)
17
+ def initialize(account_name:, host:, principal_id: nil)
17
18
  @token = AzureBlob::IdentityToken.new(principal_id:)
18
19
  @account_name = account_name
20
+ @host = host
19
21
  end
20
22
 
21
23
  def authorization_header(uri:, verb:, headers: {})
@@ -12,7 +12,10 @@ module AzureBlob
12
12
  def initialize(body: nil, status: nil)
13
13
  @body = body
14
14
  @status = status
15
- super(body)
15
+ end
16
+
17
+ def inspect
18
+ @body
16
19
  end
17
20
  end
18
21
  class FileNotFoundError < Error; end
@@ -21,7 +24,8 @@ module AzureBlob
21
24
 
22
25
  include REXML
23
26
 
24
- def initialize(uri, headers = {}, signer: nil, metadata: {}, debug: false)
27
+ def initialize(uri, headers = {}, signer: nil, metadata: {}, debug: false, raise_on_error: true)
28
+ @raise_on_error = raise_on_error
25
29
  @date = Time.now.httpdate
26
30
  @uri = uri
27
31
  @signer = signer
@@ -42,7 +46,7 @@ module AzureBlob
42
46
  response.body
43
47
  end
44
48
 
45
- def put(content)
49
+ def put(content = "")
46
50
  sign_request("PUT") if signer
47
51
  @response = http.start do |http|
48
52
  http.put(uri, content, headers)
@@ -51,7 +55,7 @@ module AzureBlob
51
55
  true
52
56
  end
53
57
 
54
- def post(content)
58
+ def post(content = "")
55
59
  sign_request("POST") if signer
56
60
  @response = http.start do |http|
57
61
  http.post(uri, content, headers)
@@ -107,6 +111,7 @@ module AzureBlob
107
111
  end
108
112
 
109
113
  def raise_error
114
+ return unless raise_on_error
110
115
  raise error_from_response.new(body: @response.body, status: @response.code&.to_i)
111
116
  end
112
117
 
@@ -115,13 +120,13 @@ module AzureBlob
115
120
  end
116
121
 
117
122
  def azure_error_code
118
- Document.new(response.body).get_elements("//Error/Code").first.get_text.to_s
123
+ Document.new(response.body).get_elements("//Error/Code").first.get_text.to_s if response.body
119
124
  end
120
125
 
121
126
  def error_from_response
122
127
  ERROR_MAPPINGS[status] || ERROR_CODE_MAPPINGS[azure_error_code] || Error
123
128
  end
124
129
 
125
- attr_accessor :host, :http, :signer, :response, :headers, :uri, :date
130
+ attr_accessor :host, :http, :signer, :response, :headers, :uri, :date, :raise_on_error
126
131
  end
127
132
  end
@@ -6,7 +6,7 @@ module AzureBlob
6
6
  EXPIRATION_BUFFER = 3600 # 1 hours
7
7
  def initialize(account_name:, signer:)
8
8
  @uri = URI.parse(
9
- "https://#{account_name}.blob.core.windows.net/?restype=service&comp=userdelegationkey"
9
+ "#{signer.host}/?restype=service&comp=userdelegationkey"
10
10
  )
11
11
 
12
12
  @signer = signer
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AzureBlob
4
- VERSION = "0.5.0"
4
+ VERSION = "0.5.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: azure-blob
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joé Dupuis
@@ -31,20 +31,10 @@ executables: []
31
31
  extensions: []
32
32
  extra_rdoc_files: []
33
33
  files:
34
- - ".envrc"
35
- - ".rubocop.yml"
36
- - ".standard.yml"
37
- - ".terraform.lock.hcl"
38
34
  - CHANGELOG.md
39
35
  - LICENSE.txt
40
36
  - README.md
41
37
  - Rakefile
42
- - azure-blob.gemspec
43
- - devenv.local.nix.example
44
- - devenv.lock
45
- - devenv.nix
46
- - devenv.yaml
47
- - input.tf
48
38
  - lib/active_storage/service/azure_blob_service.rb
49
39
  - lib/azure_blob.rb
50
40
  - lib/azure_blob/blob.rb
@@ -54,6 +44,7 @@ files:
54
44
  - lib/azure_blob/canonicalized_resource.rb
55
45
  - lib/azure_blob/client.rb
56
46
  - lib/azure_blob/const.rb
47
+ - lib/azure_blob/container.rb
57
48
  - lib/azure_blob/entra_id_signer.rb
58
49
  - lib/azure_blob/errors.rb
59
50
  - lib/azure_blob/http.rb
@@ -62,8 +53,6 @@ files:
62
53
  - lib/azure_blob/shared_key_signer.rb
63
54
  - lib/azure_blob/user_delegation_key.rb
64
55
  - lib/azure_blob/version.rb
65
- - main.tf
66
- - output.tf
67
56
  homepage: https://github.com/testdouble/azure-blob
68
57
  licenses:
69
58
  - MIT
@@ -90,5 +79,5 @@ requirements: []
90
79
  rubygems_version: 3.3.27
91
80
  signing_key:
92
81
  specification_version: 4
93
- summary: Azure blob client
82
+ summary: Azure Blob client and Active Storage adapter
94
83
  test_files: []
data/.envrc DELETED
@@ -1,3 +0,0 @@
1
- source_url "https://raw.githubusercontent.com/cachix/devenv/d1f7b48e35e6dee421cfd0f51481d17f77586997/direnvrc" "sha256-YBzqskFZxmNb3kYVoKD9ZixoPXJh1C9ZvTLGFRkauZ0="
2
-
3
- use devenv
data/.rubocop.yml DELETED
@@ -1,25 +0,0 @@
1
- AllCops:
2
- TargetRubyVersion: 3.1
3
-
4
- # Omakase Ruby styling for Rails
5
- inherit_gem: { rubocop-rails-omakase: rubocop.yml }
6
-
7
- # Overwrite or add rules to create your own house style
8
- #
9
- # # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
10
- # Layout/SpaceInsideArrayLiteralBrackets:
11
- # Enabled: false
12
-
13
- Style/TrailingCommaInArrayLiteral:
14
- Enabled: true
15
- EnforcedStyleForMultiline: consistent_comma
16
-
17
- Style/TrailingCommaInHashLiteral:
18
- Enabled: true
19
- EnforcedStyleForMultiline: consistent_comma
20
-
21
-
22
- Rails/AssertNot:
23
- Enabled: false
24
- Rails/RefuteMethods:
25
- Enabled: false
data/.standard.yml DELETED
@@ -1,3 +0,0 @@
1
- # For available configuration options, see:
2
- # https://github.com/standardrb/standard
3
- ruby_version: 3.1
data/.terraform.lock.hcl DELETED
@@ -1,22 +0,0 @@
1
- # This file is maintained automatically by "terraform init".
2
- # Manual edits may be lost in future updates.
3
-
4
- provider "registry.terraform.io/hashicorp/azurerm" {
5
- version = "3.113.0"
6
- constraints = "~> 3.0"
7
- hashes = [
8
- "h1:eEUtt0lrLdpVaF6FiDq8BGQPgEcykmhj0aNIL7hTOGw=",
9
- "zh:12479f5664288943400447b55e50df675c28ae82ad8d373cc2e5682f3a3411f0",
10
- "zh:1b42a14e80e568429d3b55fed753ca3ef0df9dcdfa107890d7264599c020940f",
11
- "zh:381be6ca617f848de3baa3985a6e1788e91a803afe04a3c5c727453528b6310d",
12
- "zh:3e70e2e07b6db1c363de3e5d0ca47f27fc956473df03329c7d2e54d3ac29176b",
13
- "zh:87c7633aeaa828098c6055da9e67d4acaf4b46748b6b3f0267e105e55f05de25",
14
- "zh:8d0d98226901f874770dd5220d4701a12ae8bd586994615aa7dcba12b9736bec",
15
- "zh:9fd913acd42a60c3a90a18ce803567ef861db8779a59aacced91f2cbd86de9d9",
16
- "zh:b6f3f7ae0a055437fb36c139af9bb3135e7f4dad172157ae1eb0177dc74d703f",
17
- "zh:b927027ba2bf40d34e03d742fd2b6c5299023b5ab8e6f05e50aac76a46ad1094",
18
- "zh:ceb5187b9d2a439f4e48944f3ffeeeaf47a03dbe6f3325ea1775bf659ce0aa88",
19
- "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
20
- "zh:fb9d78dfeca7489bffca9b1a1f3abee7f16dbbcba31388aea1102062c1d6dce8",
21
- ]
22
- }
data/azure-blob.gemspec DELETED
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/azure_blob/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "azure-blob"
7
- spec.version = AzureBlob::VERSION
8
- spec.authors = [ "Joé Dupuis" ]
9
- spec.email = [ "joe@dupuis.io" ]
10
-
11
- spec.summary = "Azure blob client"
12
- spec.homepage = "https://github.com/testdouble/azure-blob"
13
- spec.license = "MIT"
14
- spec.required_ruby_version = ">= 3.1"
15
-
16
- spec.metadata["rubygems_mfa_required"] = "true"
17
- spec.metadata["homepage_uri"] = spec.homepage
18
- spec.metadata["source_code_uri"] = spec.homepage
19
- spec.metadata["changelog_uri"] = "https://github.com/testdouble/azure-blob/blob/main/CHANGELOG.md"
20
-
21
- spec.add_dependency "rexml"
22
-
23
- # Specify which files should be added to the gem when it is released.
24
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
- spec.files = Dir.chdir(__dir__) do
26
- `git ls-files -z`.split("\x0").reject do |f|
27
- (File.expand_path(f) == __FILE__) ||
28
- f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
29
- end
30
- end
31
- spec.bindir = "exe"
32
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
33
- spec.require_paths = [ "lib" ]
34
- end
@@ -1,8 +0,0 @@
1
- {pkgs, lib, ...}:{
2
- env = {
3
- AZURE_ACCOUNT_NAME = "";
4
- AZURE_ACCESS_KEY = "";
5
- AZURE_PRIVATE_CONTAINER = "";
6
- AZURE_PUBLIC_CONTAINER = "";
7
- };
8
- }
data/devenv.lock DELETED
@@ -1,242 +0,0 @@
1
- {
2
- "nodes": {
3
- "devenv": {
4
- "locked": {
5
- "dir": "src/modules",
6
- "lastModified": 1715593316,
7
- "narHash": "sha256-S7XatU9uV3q9bVBcg/ER0VMQcnPZprrVlN209ne7LDw=",
8
- "owner": "cachix",
9
- "repo": "devenv",
10
- "rev": "725c90407ef53cc2a1b53701c6d2d0745cf2484f",
11
- "type": "github"
12
- },
13
- "original": {
14
- "dir": "src/modules",
15
- "owner": "cachix",
16
- "repo": "devenv",
17
- "type": "github"
18
- }
19
- },
20
- "flake-compat": {
21
- "flake": false,
22
- "locked": {
23
- "lastModified": 1696426674,
24
- "owner": "edolstra",
25
- "repo": "flake-compat",
26
- "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
27
- "treeHash": "2addb7b71a20a25ea74feeaf5c2f6a6b30898ecb",
28
- "type": "github"
29
- },
30
- "original": {
31
- "owner": "edolstra",
32
- "repo": "flake-compat",
33
- "type": "github"
34
- }
35
- },
36
- "flake-compat_2": {
37
- "flake": false,
38
- "locked": {
39
- "lastModified": 1696426674,
40
- "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
41
- "owner": "edolstra",
42
- "repo": "flake-compat",
43
- "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
44
- "type": "github"
45
- },
46
- "original": {
47
- "owner": "edolstra",
48
- "repo": "flake-compat",
49
- "type": "github"
50
- }
51
- },
52
- "flake-utils": {
53
- "inputs": {
54
- "systems": "systems"
55
- },
56
- "locked": {
57
- "lastModified": 1710146030,
58
- "owner": "numtide",
59
- "repo": "flake-utils",
60
- "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
61
- "treeHash": "bd263f021e345cb4a39d80c126ab650bebc3c10c",
62
- "type": "github"
63
- },
64
- "original": {
65
- "owner": "numtide",
66
- "repo": "flake-utils",
67
- "type": "github"
68
- }
69
- },
70
- "flake-utils_2": {
71
- "inputs": {
72
- "systems": "systems_2"
73
- },
74
- "locked": {
75
- "lastModified": 1710146030,
76
- "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
77
- "owner": "numtide",
78
- "repo": "flake-utils",
79
- "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
80
- "type": "github"
81
- },
82
- "original": {
83
- "owner": "numtide",
84
- "repo": "flake-utils",
85
- "type": "github"
86
- }
87
- },
88
- "gitignore": {
89
- "inputs": {
90
- "nixpkgs": [
91
- "pre-commit-hooks",
92
- "nixpkgs"
93
- ]
94
- },
95
- "locked": {
96
- "lastModified": 1709087332,
97
- "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
98
- "owner": "hercules-ci",
99
- "repo": "gitignore.nix",
100
- "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
101
- "type": "github"
102
- },
103
- "original": {
104
- "owner": "hercules-ci",
105
- "repo": "gitignore.nix",
106
- "type": "github"
107
- }
108
- },
109
- "nixpkgs": {
110
- "locked": {
111
- "lastModified": 1725001927,
112
- "owner": "NixOS",
113
- "repo": "nixpkgs",
114
- "rev": "6e99f2a27d600612004fbd2c3282d614bfee6421",
115
- "treeHash": "1e85443cc9f0ba302df2cf61cacb8014943e2d19",
116
- "type": "github"
117
- },
118
- "original": {
119
- "owner": "NixOS",
120
- "ref": "nixos-24.05",
121
- "repo": "nixpkgs",
122
- "type": "github"
123
- }
124
- },
125
- "nixpkgs-ruby": {
126
- "inputs": {
127
- "flake-compat": "flake-compat",
128
- "flake-utils": "flake-utils",
129
- "nixpkgs": "nixpkgs_2"
130
- },
131
- "locked": {
132
- "lastModified": 1724737223,
133
- "owner": "bobvanderlinden",
134
- "repo": "nixpkgs-ruby",
135
- "rev": "175b5867babcbc471b94be9fd5576f2973bbdb6d",
136
- "treeHash": "2fe3404ac0eeb7bcb7ac7b5f5f8b9b6a7e460147",
137
- "type": "github"
138
- },
139
- "original": {
140
- "owner": "bobvanderlinden",
141
- "repo": "nixpkgs-ruby",
142
- "type": "github"
143
- }
144
- },
145
- "nixpkgs-stable": {
146
- "locked": {
147
- "lastModified": 1710695816,
148
- "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
149
- "owner": "NixOS",
150
- "repo": "nixpkgs",
151
- "rev": "614b4613980a522ba49f0d194531beddbb7220d3",
152
- "type": "github"
153
- },
154
- "original": {
155
- "owner": "NixOS",
156
- "ref": "nixos-23.11",
157
- "repo": "nixpkgs",
158
- "type": "github"
159
- }
160
- },
161
- "nixpkgs_2": {
162
- "locked": {
163
- "lastModified": 1725001927,
164
- "owner": "NixOS",
165
- "repo": "nixpkgs",
166
- "rev": "6e99f2a27d600612004fbd2c3282d614bfee6421",
167
- "treeHash": "1e85443cc9f0ba302df2cf61cacb8014943e2d19",
168
- "type": "github"
169
- },
170
- "original": {
171
- "owner": "NixOS",
172
- "ref": "nixos-24.05",
173
- "repo": "nixpkgs",
174
- "type": "github"
175
- }
176
- },
177
- "pre-commit-hooks": {
178
- "inputs": {
179
- "flake-compat": "flake-compat_2",
180
- "flake-utils": "flake-utils_2",
181
- "gitignore": "gitignore",
182
- "nixpkgs": [
183
- "nixpkgs"
184
- ],
185
- "nixpkgs-stable": "nixpkgs-stable"
186
- },
187
- "locked": {
188
- "lastModified": 1715609711,
189
- "narHash": "sha256-/5u29K0c+4jyQ8x7dUIEUWlz2BoTSZWUP2quPwFCE7M=",
190
- "owner": "cachix",
191
- "repo": "pre-commit-hooks.nix",
192
- "rev": "c182c876690380f8d3b9557c4609472ebfa1b141",
193
- "type": "github"
194
- },
195
- "original": {
196
- "owner": "cachix",
197
- "repo": "pre-commit-hooks.nix",
198
- "type": "github"
199
- }
200
- },
201
- "root": {
202
- "inputs": {
203
- "devenv": "devenv",
204
- "nixpkgs": "nixpkgs",
205
- "nixpkgs-ruby": "nixpkgs-ruby",
206
- "pre-commit-hooks": "pre-commit-hooks"
207
- }
208
- },
209
- "systems": {
210
- "locked": {
211
- "lastModified": 1681028828,
212
- "owner": "nix-systems",
213
- "repo": "default",
214
- "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
215
- "treeHash": "cce81f2a0f0743b2eb61bc2eb6c7adbe2f2c6beb",
216
- "type": "github"
217
- },
218
- "original": {
219
- "owner": "nix-systems",
220
- "repo": "default",
221
- "type": "github"
222
- }
223
- },
224
- "systems_2": {
225
- "locked": {
226
- "lastModified": 1681028828,
227
- "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
228
- "owner": "nix-systems",
229
- "repo": "default",
230
- "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
231
- "type": "github"
232
- },
233
- "original": {
234
- "owner": "nix-systems",
235
- "repo": "default",
236
- "type": "github"
237
- }
238
- }
239
- },
240
- "root": "root",
241
- "version": 7
242
- }
data/devenv.nix DELETED
@@ -1,36 +0,0 @@
1
- { pkgs, config, ... }:
2
-
3
- {
4
- env = {
5
- LD_LIBRARY_PATH = "${config.devenv.profile}/lib";
6
- };
7
-
8
- packages = with pkgs; [
9
- git
10
- libyaml
11
- terraform
12
- azure-cli
13
- glib
14
- vips
15
- sshuttle
16
- sshpass
17
- rsync
18
- ];
19
-
20
- languages.ruby.enable = true;
21
- languages.ruby.version = "3.1.6";
22
-
23
- scripts.generate-env-file.exec = ''
24
- terraform output -raw devenv_local_nix > devenv.local.nix
25
- '';
26
-
27
- scripts.proxy-vps.exec = ''
28
- exec sshuttle -e "ssh -o CheckHostIP=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" -r "$(terraform output --raw vm_username)@$(terraform output --raw vm_ip)" 0/0
29
- '';
30
-
31
- scripts.start-app-service-ssh.exec = ''
32
- resource_group=$(terraform output --raw "resource_group")
33
- app_name=$(terraform output --raw "app_service_app_name")
34
- exec az webapp create-remote-connection --resource-group $resource_group --name $app_name
35
- '';
36
- }
data/devenv.yaml DELETED
@@ -1,6 +0,0 @@
1
- allowUnfree: true
2
- inputs:
3
- nixpkgs:
4
- url: github:NixOS/nixpkgs/nixos-24.05
5
- nixpkgs-ruby:
6
- url: github:bobvanderlinden/nixpkgs-ruby
data/input.tf DELETED
@@ -1,44 +0,0 @@
1
- variable "location" {
2
- type = string
3
- default = "westus2"
4
- }
5
-
6
- variable "prefix" {
7
- type = string
8
- default = "azure-blob"
9
- }
10
-
11
- variable "storage_account_name" {
12
- type = string
13
- default = "azureblobrubygemdev"
14
- }
15
-
16
- variable "create_vm" {
17
- type = bool
18
- default = false
19
- }
20
-
21
- variable "vm_size" {
22
- type = string
23
- default = "Standard_B2s"
24
- }
25
-
26
- variable "vm_username" {
27
- type = string
28
- default = "azureblob"
29
- }
30
-
31
- variable "vm_password" {
32
- type = string
33
- default = "qwe123QWE!@#"
34
- }
35
-
36
- variable "create_app_service" {
37
- type = bool
38
- default = false
39
- }
40
-
41
- variable "ssh_key" {
42
- type = string
43
- default = ""
44
- }
data/main.tf DELETED
@@ -1,187 +0,0 @@
1
- terraform {
2
- required_providers {
3
- azurerm = {
4
- source = "hashicorp/azurerm"
5
- version = "~>3.0"
6
- }
7
- }
8
- }
9
-
10
- provider "azurerm" {
11
- features {}
12
- }
13
-
14
- locals {
15
- public_ssh_key = var.ssh_key != "" ? var.ssh_key : file("~/.ssh/id_rsa.pub")
16
- }
17
-
18
- resource "azurerm_resource_group" "main" {
19
- name = var.prefix
20
- location = var.location
21
- tags = {
22
- source = "Terraform"
23
- }
24
- }
25
-
26
- resource "azurerm_storage_account" "main" {
27
- name = var.storage_account_name
28
- resource_group_name = azurerm_resource_group.main.name
29
- location = azurerm_resource_group.main.location
30
- account_tier = "Standard"
31
- account_replication_type = "LRS"
32
-
33
- tags = {
34
- source = "Terraform"
35
- }
36
- }
37
-
38
- resource "azurerm_storage_container" "private" {
39
- name = "private"
40
- storage_account_name = azurerm_storage_account.main.name
41
- container_access_type = "private"
42
- }
43
-
44
- resource "azurerm_storage_container" "public" {
45
- name = "public"
46
- storage_account_name = azurerm_storage_account.main.name
47
- container_access_type = "blob"
48
- }
49
-
50
- resource "azurerm_virtual_network" "main" {
51
- count = var.create_vm ? 1 : 0
52
- name = "${var.prefix}-network"
53
- address_space = ["10.0.0.0/16"]
54
- location = azurerm_resource_group.main.location
55
- resource_group_name = azurerm_resource_group.main.name
56
-
57
- tags = {
58
- source = "Terraform"
59
- }
60
- }
61
-
62
- resource "azurerm_subnet" "main" {
63
- count = var.create_vm ? 1 : 0
64
- name = "${var.prefix}-main"
65
- resource_group_name = azurerm_resource_group.main.name
66
- virtual_network_name = azurerm_virtual_network.main[0].name
67
- address_prefixes = ["10.0.2.0/24"]
68
- }
69
-
70
- resource "azurerm_network_interface" "main" {
71
- count = var.create_vm ? 1 : 0
72
- name = "${var.prefix}-nic"
73
- location = azurerm_resource_group.main.location
74
- resource_group_name = azurerm_resource_group.main.name
75
-
76
- ip_configuration {
77
- name = "${var.prefix}-ip-config"
78
- subnet_id = azurerm_subnet.main[0].id
79
- private_ip_address_allocation = "Dynamic"
80
- public_ip_address_id = azurerm_public_ip.main[0].id
81
- }
82
-
83
- tags = {
84
- source = "Terraform"
85
- }
86
- }
87
-
88
- resource "azurerm_public_ip" "main" {
89
- count = var.create_vm ? 1 : 0
90
- name = "${var.prefix}-public-ip"
91
- resource_group_name = azurerm_resource_group.main.name
92
- location = azurerm_resource_group.main.location
93
- allocation_method = "Static"
94
-
95
- tags = {
96
- source = "Terraform"
97
- }
98
- }
99
-
100
- resource "azurerm_user_assigned_identity" "vm" {
101
- location = azurerm_resource_group.main.location
102
- name = "${var.prefix}-vm"
103
- resource_group_name = azurerm_resource_group.main.name
104
- }
105
-
106
-
107
- resource "azurerm_role_assignment" "vm" {
108
- scope = azurerm_storage_account.main.id
109
- role_definition_name = "Storage Blob Data Contributor"
110
- principal_id = azurerm_user_assigned_identity.vm.principal_id
111
- }
112
-
113
- resource "azurerm_linux_virtual_machine" "main" {
114
- count = var.create_vm ? 1 : 0
115
- name = "${var.prefix}-vm"
116
- computer_name = var.prefix
117
- resource_group_name = azurerm_resource_group.main.name
118
- location = azurerm_resource_group.main.location
119
- size = var.vm_size
120
- admin_username = var.vm_username
121
- admin_password = var.vm_password
122
- disable_password_authentication = true
123
- network_interface_ids = [azurerm_network_interface.main[0].id]
124
-
125
- identity {
126
- type = "UserAssigned"
127
- identity_ids = [azurerm_user_assigned_identity.vm.id]
128
- }
129
-
130
- admin_ssh_key {
131
- username = var.vm_username
132
- public_key = local.public_ssh_key
133
- }
134
-
135
- source_image_reference {
136
- publisher = "Canonical"
137
- offer = "0001-com-ubuntu-server-jammy"
138
- sku = "22_04-lts"
139
- version = "latest"
140
- }
141
-
142
- os_disk {
143
- caching = "ReadWrite"
144
- storage_account_type = "Standard_LRS"
145
- }
146
-
147
- tags = {
148
- source = "Terraform"
149
- }
150
- }
151
-
152
- resource "azurerm_service_plan" "main" {
153
- count = var.create_app_service ? 1 : 0
154
- name = "${var.prefix}-appserviceplan"
155
- resource_group_name = azurerm_resource_group.main.name
156
- location = azurerm_resource_group.main.location
157
- os_type = "Linux"
158
- sku_name = "B1"
159
- }
160
-
161
- resource "azurerm_linux_web_app" "main" {
162
- count = var.create_app_service ? 1 : 0
163
- name = "${var.prefix}-app"
164
- service_plan_id = azurerm_service_plan.main[0].id
165
- resource_group_name = azurerm_resource_group.main.name
166
- location = azurerm_resource_group.main.location
167
-
168
- identity {
169
- type = "UserAssigned"
170
- identity_ids = [azurerm_user_assigned_identity.vm.id]
171
- }
172
-
173
- site_config {
174
- application_stack {
175
- node_version = "20-lts"
176
- }
177
- }
178
- }
179
-
180
- resource "azurerm_app_service_source_control" "main" {
181
- count = var.create_app_service ? 1 : 0
182
- app_id = azurerm_linux_web_app.main[0].id
183
- repo_url = "https://github.com/Azure-Samples/nodejs-docs-hello-world"
184
- branch = "master"
185
- use_manual_integration = true
186
- use_mercurial = false
187
- }
data/output.tf DELETED
@@ -1,30 +0,0 @@
1
- output "devenv_local_nix" {
2
- sensitive = true
3
- value = <<EOT
4
- {pkgs, lib, ...}:{
5
- env = {
6
- AZURE_ACCOUNT_NAME = "${azurerm_storage_account.main.name}";
7
- AZURE_ACCESS_KEY = "${azurerm_storage_account.main.primary_access_key}";
8
- AZURE_PRIVATE_CONTAINER = "${azurerm_storage_container.private.name}";
9
- AZURE_PUBLIC_CONTAINER = "${azurerm_storage_container.public.name}";
10
- AZURE_PRINCIPAL_ID = "${azurerm_user_assigned_identity.vm.principal_id}";
11
- };
12
- }
13
- EOT
14
- }
15
-
16
- output "vm_ip" {
17
- value = var.create_vm ? azurerm_public_ip.main[0].ip_address : ""
18
- }
19
-
20
- output "vm_username" {
21
- value = var.vm_username
22
- }
23
-
24
- output "app_service_app_name" {
25
- value = var.create_app_service ? azurerm_linux_web_app.main[0].name : ""
26
- }
27
-
28
- output "resource_group" {
29
- value = azurerm_resource_group.main.name
30
- }