aws_metadata 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0f47a7ac354bc5131d0a0541230d849359b4be02
4
- data.tar.gz: 77b8a99b8ab04b3b6cba8de44ad416f5f9c74ec7
3
+ metadata.gz: 1f0ca59df969c0d034320866c73989b1c0f3cbb5
4
+ data.tar.gz: 3fc7e4c98941ddac033aef01b4764e7378d8710f
5
5
  SHA512:
6
- metadata.gz: f326ea632fbac729bfbf1dac578524da9595bb2672f0e83e7b78536ed5b1137ef6afa33e6c4804ed30f2b4d6ca2b165ccb34baa28943749853c4238618b5ee62
7
- data.tar.gz: 9c7685e8d65f6ddf500814623bb56ed441113d943731c52efd4ee8a1e1cc54b95c0b8794e9df317154e1aaf8cc84dd16485e31f72b739eb53ecb2553aae3a915
6
+ metadata.gz: 6bcda2f9346359f806bb8a0ad052fa965277514f62eafd1afc79ad2f85880eede8d80e84438c44a2ae580339b2545da8b68e3e16b48adc3c6654a20c490b9008
7
+ data.tar.gz: 119731a5c0fbfa70bd4de71a9ac2466d91dbcfd1aae6e41286a823c53aad55bdf053412cc43cf4146bc5e69f20f84dc2db569c4c318b53cf0f04d0a701a78e6c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- aws_metadata (0.1.5)
4
+ aws_metadata (0.2.0)
5
5
  aws-sdk
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -30,6 +30,27 @@ puts AWS::Instance.dynamic.instance_identity.document.account_id
30
30
  puts AWS::Instance.user_data
31
31
  ```
32
32
 
33
+ AWS::Instance is lazy loaded and only makes calls to 169.254.169.254 for the paths requested. In other words, the entire
34
+ object hierarchy is not built at once, thereby reducing the total number of HTTP requests and reducing the chance
35
+ of being throttled by AWS.
36
+
37
+ You can alternatively pass the relative endpoint to `metadata` and `dynamic`
38
+
39
+ ```ruby
40
+ puts AWS::Instance.metadata(path: 'instance-id')
41
+ puts AWS::Instance.dynamic( path: ('instance-identity/document').account_id
42
+ ```
43
+
44
+ This has the added benefit of reducing the number of HTTP calls even further if needed/desired. For instance `AWS::Instance.metadata.instance_id`
45
+ will make 2 calls, 1 for `/meta-data` and another for `meta-data/instance-id`, where `AWS::Instance.metadata(path: 'instance-id')`
46
+ will only make a single call to `/meta-data/instance-id`.
47
+
48
+ All calls are cached.
49
+
50
+ Calls are retried upto 10 times in 1 second intervals if a 200 response is not received.
51
+
52
+
53
+
33
54
  To return stubbed responses, you can add this to an initializer:
34
55
 
35
56
  ```ruby
@@ -135,7 +156,11 @@ The code for `AWS::Instance` is mostly a copy directly from the aws_instmd repo.
135
156
  1. The class name. We removed the MD(metadata) from the name since this gem also has the StackOutput namespace and it's all really metadata.
136
157
  2. `AWS::InstMD.meta_data` to `AWS::Instance.metadata`. We changed meta_data to metadata to be consistent with the naming in our SDK and APIs.
137
158
  3. The `AWS::Instance.dynamic.instance_identity.document` returns a Hashish object you can call methods on, rather than a JSON document that has to be parsed manually into a hash. So `AWS::Instance.dynamic.instance_identity.document.account_id` just works.
138
- 4. We added the ability to have stubbed responses returned. See the usage section below.
159
+ 4. We added the ability to have stubbed responses returned. See the usage section above.
160
+
161
+ ## Dependencies
162
+ Ruby >= 2.0
163
+ aws-sdk gem
139
164
 
140
165
  ## Contributing
141
166
 
data/aws_metadata.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.required_ruby_version = '>= 2.0.0'
21
22
  spec.add_development_dependency "bundler", "~> 1.11"
22
23
  spec.add_development_dependency "rake", "~> 10.0"
23
24
  spec.add_development_dependency 'yard'
@@ -4,11 +4,45 @@
4
4
  require 'net/http'
5
5
 
6
6
  module AWS
7
- class Instance
8
- # @private
9
- def self.method_missing name, *args, &block
10
- @@root ||= Instance.new
11
- @@root.method(name).call(*args, &block)
7
+ module Instance
8
+ def self.metadata(path: nil, version: 'latest', host: '169.254.169.254', port: '80')
9
+ load_stubs
10
+ url_prefix = "/#{version}/meta-data/"
11
+ if path.present?
12
+ @metadata_path ||= Hashish.new
13
+ @metadata_path[path] ||= value_by_path(path, @metadata) do
14
+ query(http(host, port), "#{url_prefix}#{path}")
15
+ end
16
+ else
17
+ @metadata ||= Treeish.new http(host, port), url_prefix
18
+ raise 'no metadata' if @metadata.blank? # There should always be metadata
19
+ @metadata
20
+ end
21
+ end
22
+
23
+ def self.user_data(version: 'latest', host: '169.254.169.254', port: '80')
24
+ load_stubs
25
+ @user_data ||= query(http(host, port), "/#{version}/user-data")
26
+ end
27
+
28
+ def self.dynamic(path: nil, version: 'latest', host: '169.254.169.254', port: '80')
29
+ load_stubs
30
+ url_prefix = "/#{version}/dynamic/"
31
+ if path.present?
32
+ @dynamic_path ||= Hashish.new
33
+ @dynamic_path[path] ||= value_by_path(path, @dynamic) do
34
+ query(http(host, port), "#{url_prefix}#{path}")
35
+ end
36
+ else
37
+ @dynamic ||= Treeish.new http(host, port), url_prefix
38
+ end
39
+ end
40
+
41
+ # All the metadata from 169.254.169.254
42
+ #
43
+ # The hashes are Hashish objects that allows regular method like calls where all method names are the keys underscored.
44
+ def self.to_hash
45
+ { :metadata => metadata.merge(Hash(@metadata_path)), :user_data => user_data, :dynamic => dynamic.merge(Hash(@dynamic_path)) }
12
46
  end
13
47
 
14
48
  # Can't be the first one to make that pun.
@@ -21,115 +55,76 @@ module AWS
21
55
  end
22
56
  end
23
57
 
24
- def method_missing name
25
- if name.to_s == 'document'
26
- Hashish.new(JSON.parse(self['document']))
27
- else
28
- self[name.to_s.gsub('_', '-')]
29
- end
58
+ def method_missing(name)
59
+ attr = name.to_s.gsub('_', '-')
60
+ self[attr] = self[attr].call if self[attr].is_a?(Proc)
61
+ self[attr]
30
62
  end
31
63
  end
32
64
 
33
65
  # @private
34
66
  class Treeish < Hashish
35
67
  private
36
- def initialize http, prefix
37
- entries = Instance.query http, prefix
68
+ def initialize(http, prefix)
69
+ entries = Instance.query(http, prefix)
38
70
  entries.lines.each do |l|
39
71
  l.chomp!
40
72
  if l.end_with? '/'
41
- self[l[0..-2]] = Treeish.new http, "#{prefix}#{l}"
73
+ self[l[0..-2]] = Proc.new { Treeish.new http, "#{prefix}#{l}" }
42
74
  # meta-data/public-keys/ entries have a '0=foo' format
43
75
  elsif l =~ /(\d+)=(.*)/
44
76
  number, name = $1, $2
45
- self[name] = Treeish.new http, "#{prefix}#{number}/"
77
+ self[name] = Proc.new { Treeish.new http, "#{prefix}#{number}/" }
46
78
  else
47
- self[l] = Instance.query http, "#{prefix}#{l}"
79
+ self[l] = Proc.new { Instance.query(http, "#{prefix}#{l}") }
48
80
  end
49
81
  end
50
82
  end
51
83
  end
52
84
 
53
- attr_accessor :user_data, :metadata, :dynamic
85
+ private_class_method
54
86
 
55
- # Amazon, Y U NO trailing slash entries
56
- # in /, /$version and /$version/dynamic/??
57
- # There is waaay too much code here.
58
87
  # @private
59
- def initialize version='latest', host='169.254.169.254', port='80'
60
- if AWS::Metadata.stub_responses
61
- load_stubs
62
- return
63
- end
64
- http = Net::HTTP.new host, port
65
- load_metadata(http, version)
66
- load_user_data(http, version)
67
- load_dynamic(http, version)
88
+ def self.http(host, port)
89
+ @http ||= Net::HTTP.new host, port
68
90
  end
69
91
 
70
92
  # @private
71
- def self.query http, path
72
- rep = http.request Net::HTTP::Get.new path
73
- unless Net::HTTPOK === rep
74
- return nil
75
- end
76
- rep.body
77
- end
78
-
79
- # All the metadata from 169.254.169.254
80
- #
81
- # The hashes are Hashish objects that allows regular method like calls where all method names are the keys underscored.
82
- def to_hash
83
- { :metadata => @metadata, :user_data => @user_data, :dynamic => @dynamic }
84
- end
85
-
86
- private
87
-
88
- # Load data from the meta-data URL
89
- # @private
90
- def load_metadata(http, version)
93
+ def self.query(http, path)
91
94
  tries ||= 1
92
- @metadata = Treeish.new http, "/#{version}/meta-data/"
93
- raise 'no metadata' if @metadata.nil?
95
+ rep = http.request Net::HTTP::Get.new path
96
+ raise "bad request: #{path}" unless Net::HTTPOK === rep
97
+ value = JSON.parse(rep.body)
98
+ value.is_a?(Hash) ? Hashish.new(value) : value
99
+ rescue JSON::ParserError
100
+ rep.body
94
101
  rescue
95
- raise if tries >= 10
102
+ return '' if tries >= 10
96
103
  sleep 1
97
104
  tries += 1
98
105
  retry
99
106
  end
100
107
 
101
- # Load data from the user-data URL
108
+ # Helper method to provide "stubs" for non aws environments, ie. development and test
102
109
  # @private
103
- def load_user_data(http, version)
104
- @user_data = Instance.query http, "/#{version}/user-data"
105
- rescue
106
- @user_data = nil
110
+ def self.load_stubs
111
+ return unless AWS::Metadata.stub_responses && @metadata.blank?
112
+ @yaml ||= Pathname.new(File.join(AWS::Metadata.aws_identity_stubs_path, 'aws_identity_stubs.yml'))
113
+ @responses ||= YAML.load(ERB.new(@yaml.read).result)
114
+ @metadata ||= Hashish.new @responses[:metadata]
115
+ @user_data ||= @responses[:user_data]
116
+ @dynamic ||= Hashish.new @responses[:dynamic]
117
+ @dynamic['instance-identity']['document'] = @dynamic['instance-identity']['document'].to_json
107
118
  end
108
119
 
109
- # Load data from the dynamic URL
110
- # @private
111
- def load_dynamic(http, version)
112
- @dynamic = Hashish.new
113
- begin
114
- dynamic_stuff = Instance.query(http, "/#{version}/dynamic/").lines
115
- rescue
116
- dynamic_stuff = []
117
- end
118
- dynamic_stuff.each do |e|
119
- e = e.chomp.chomp '/'
120
- @dynamic[e] = Treeish.new http, "/#{version}/dynamic/#{e}/"
120
+ def self.value_by_path(path, obj)
121
+ if AWS::Metadata.stub_responses
122
+ path.split('/').inject(obj) do |o, method|
123
+ o.send method.to_s.underscore
124
+ end
125
+ else
126
+ yield
121
127
  end
122
128
  end
123
-
124
- # Helper method to provide "stubs" for non aws deployments
125
- # @private
126
- def load_stubs
127
- yaml = Pathname.new(File.join(AWS::Metadata.aws_identity_stubs_path, 'aws_identity_stubs.yml'))
128
- responses = YAML.load(ERB.new(yaml.read).result)
129
- @metadata = Hashish.new responses[:metadata]
130
- @user_data = responses[:user_data]
131
- @dynamic = Hashish.new responses[:dynamic]
132
- @dynamic['instance-identity']['document'] = @dynamic['instance-identity']['document'].to_json
133
- end
134
129
  end
135
130
  end
@@ -1,5 +1,5 @@
1
1
  module AWS
2
2
  module Metadata
3
- VERSION = "0.1.5"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_metadata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evident.io
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-14 00:00:00.000000000 Z
11
+ date: 2016-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -120,7 +120,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - ">="
122
122
  - !ruby/object:Gem::Version
123
- version: '0'
123
+ version: 2.0.0
124
124
  required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  requirements:
126
126
  - - ">="