infrawrench-bulk_instances 1.1.0 → 1.2.0

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: 1d923efcb8b07fa8334b16dc8ecc899b7cd7f47f9ec31a393f589d1565bf5c6b
4
- data.tar.gz: 83dfaa42f5798bd85d7b4e9b829a43a47566d2684ce8caa6edcd0cd645afc462
3
+ metadata.gz: 35025be8d677ed34cdfea296faca613c02d6ffe5c88d35266ad33fc36947d704
4
+ data.tar.gz: 3035dee6a0a3f8f86923ab7fb1b1c16c02fbc0e2aff9798a18d4640b4518138c
5
5
  SHA512:
6
- metadata.gz: 92fd23d69988cad7b8d3c83d2e1118eb3820c843fa533b56ae3d9ecf72de448aada9ff6b86b7916d242fb4b9353bf172353addf3ef6d87bc43fec4d1f33a567d
7
- data.tar.gz: 407c205234c2ab52905ebb3a7fb8a304b92d8a3e73cfbbd8fb5907dd4457348c92d95ef032609244fc713a8afdd418a12079d6a6dfe610811aa04fc54cae5c8c
6
+ metadata.gz: fd9380c0871c15a34ebe92328f868d6347f6a3b6ce3722a137318d44c48b70cc22573fc38d696a9f66584ea604e97feacfeeecd3772bf87d6285ba93167d11fe
7
+ data.tar.gz: 33c0e9e0a4e9855840c34f2a93d4d4903a8f813d495daadf782e0057ba3b9df45f34c2f17699f155a7dd509ad62629cf603f046c07f9f9dea9c1510a684da852
data/README.md CHANGED
@@ -69,6 +69,21 @@ variant fields. On other platforms they are `""`, unless the platform has a fiel
69
69
  Requires Ruby 3.2 or later, and liblzma (part of macOS and of practically every
70
70
  Linux distribution; `xz-utils`/`xz` otherwise) to decompress downloads.
71
71
 
72
+ ## One instance
73
+
74
+ `Infrawrench::BulkInstances.fetch_aws_instance(platform, instance_type, ...)` fetches a single
75
+ instance from the Infrawrench API instead of downloading the platform's whole bundle. It returns
76
+ the same `AWSInstance` that `get` does, or `nil` if the platform has no instance with that name:
77
+
78
+ ```ruby
79
+ m5 = Infrawrench::BulkInstances.fetch_aws_instance("ec2", "m5.large")
80
+ m5&.pricing&.on_demand&.length
81
+ ```
82
+
83
+ It takes `token:` like the bundle download, and `base_url:` for where the API is served from
84
+ (`https://app.infrawrench.com` by default). Nothing is cached. The API syncs each new bundle within
85
+ about half an hour of it being published, so it can briefly trail `download_aws_pricing_data`.
86
+
72
87
  ## Caching
73
88
 
74
89
  The bundle is downloaded xz-compressed (about 20 MB) and kept decompressed (about
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Infrawrench
4
4
  module BulkInstances
5
- VERSION = "1.1.0"
5
+ VERSION = "1.2.0"
6
6
  end
7
7
  end
@@ -17,6 +17,7 @@ module Infrawrench
17
17
  # AWS instance attributes and pricing (EC2, RDS, ElastiCache and more), with full history, from Infrawrench.
18
18
  module BulkInstances
19
19
  DEFAULT_BASE_URL = "https://instances-bundles.infrawrench.com"
20
+ DEFAULT_API_URL = "https://app.infrawrench.com"
20
21
  USER_AGENT = "infrawrench/bulk-instances, ruby, 1.0"
21
22
 
22
23
  # What Net::HTTP raises when the server cannot be reached or the connection breaks.
@@ -128,10 +129,53 @@ module Infrawrench
128
129
  AWSPricingData.new(JSON.parse(json, freeze: true))
129
130
  end
130
131
 
132
+ # Fetches one instance from the Infrawrench API, without downloading the platform's bundle.
133
+ # Nothing is cached.
134
+ #
135
+ # The result is the same as <tt>download_aws_pricing_data(platform).get(instance_type)</tt>, from
136
+ # whichever bundle the API last synced, which can trail the newest bundle by up to half an hour.
137
+ #
138
+ # @param platform [String, Symbol] One of AWS_PLATFORMS, e.g. +"rds"+, or any other lowercase platform name.
139
+ # @param instance_type [String] The instance type, e.g. +"m5.large"+.
140
+ # @param token [String, nil] Your Infrawrench API token. Defaults to the +INFRAWRENCH_API_KEY+ environment variable.
141
+ # @param base_url [String, nil] Where the Infrawrench API is served from. Defaults to https://app.infrawrench.com
142
+ # @return [AWSInstance, nil] +nil+ if the platform has no instance with that name.
143
+ # @raise [AWSPricingDataError]
144
+ def fetch_aws_instance(platform, instance_type, token: nil, base_url: nil)
145
+ unless (platform.is_a?(String) || platform.is_a?(Symbol)) && platform.match?(/\A[a-z0-9]+\z/)
146
+ raise AWSPricingDataError, %("#{platform}" is not a platform name.)
147
+ end
148
+ raise AWSPricingDataError, "The instance type is empty." if instance_type.to_s.empty?
149
+
150
+ token = ENV.fetch("INFRAWRENCH_API_KEY", nil) if token.nil?
151
+ if token.nil? || token.empty?
152
+ raise AWSPricingDataError, "No Infrawrench API token: pass `token:` or set INFRAWRENCH_API_KEY."
153
+ end
154
+
155
+ base_url = (base_url || DEFAULT_API_URL).sub(%r{/+\z}, "")
156
+ # Percent-encoded, with spaces as %20: a + in a path is a plus.
157
+ name = URI.encode_www_form_component(instance_type.to_s).gsub("+", "%20")
158
+ begin
159
+ json = download("#{base_url}/api/v1/aws-bulk-pricing/#{platform}/#{name}", token, &:read_body)
160
+ rescue AWSPricingDataError => e
161
+ return nil if e.status == 404
162
+
163
+ raise
164
+ end
165
+
166
+ # The bundle's tables cut down to what this instance uses, and its row renumbered to match.
167
+ value = JSON.parse(json.to_s.dup.force_encoding(Encoding::UTF_8), freeze: true)
168
+ bundle = value.slice("offer", "compression_table", "regions", "variant_keys", "variants", "reserved_terms")
169
+ bundle["snapshots"] = []
170
+ bundle["instances"] = { value["name"] => value["instance"] }
171
+ AWSPricingData.new(bundle).get(value["name"])
172
+ end
173
+
131
174
  private
132
175
 
133
176
  # GETs +url+ and yields the successful response, retrying the 503 the bundles Worker
134
- # answers when it cannot reach the Infrawrench API.
177
+ # answers when it cannot reach the Infrawrench API (and the API answers when it cannot
178
+ # reach its store).
135
179
  def download(url, token)
136
180
  uri = URI(url)
137
181
  (1..).each do |attempt|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: infrawrench-bulk_instances
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Infrawrench LLC