ec2-metadata 0.1.0 → 0.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.
data/.gitignore CHANGED
@@ -1,21 +1,22 @@
1
- ## MAC OS
2
- .DS_Store
3
1
 
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
2
 
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
3
 
13
- ## VIM
14
- *.swp
15
4
 
5
+
6
+ ## EMACS
7
+ ## MAC OS
16
8
  ## PROJECT::GENERAL
9
+ ## PROJECT::SPECIFIC
10
+ ## TEXTMATE
11
+ ## VIM
12
+ *.swp
13
+ *.tmproj
14
+ *~
15
+ .DS_Store
16
+ .\#*
17
+ /ec2-metadata-0.1.0.gem
18
+ \#*
17
19
  coverage
18
- rdoc
19
20
  pkg
20
-
21
- ## PROJECT::SPECIFIC
21
+ rdoc
22
+ tmtags
data/README.rdoc CHANGED
@@ -1,6 +1,50 @@
1
1
  = ec2-metadata
2
2
 
3
- Description goes here.
3
+ == Install
4
+ $ [sudo] gem install ec2-metadata
5
+
6
+ == As ruby library
7
+ ec-metadata provides a way to access meta-data and user-data on EC2 instance.
8
+
9
+ Ec2Metadata[:instance_id]
10
+ Ec2Metadata['instance_id']
11
+ Ec2Metadata[:'instance-id']
12
+ Ec2Metadata['instance-id']
13
+
14
+ If you want to specify API version, you can get data like this:
15
+ Ec2Metadata['1.0'][:instance_id]
16
+
17
+ If you can also get it like this:
18
+ Ec2Metadata['1.0']['meta-data'][:instance_id]
19
+
20
+ For more detail, see also:
21
+ http://github.com/akm/ec2-metadata/blob/master/spec/introduction_spec.rb
22
+
23
+
24
+ == As a command
25
+ ec2-metadata shows various meta-data and user-data
26
+ $ ec2-metadata
27
+
28
+ For more detail, type
29
+ $ ec2-metadata -h
30
+
31
+
32
+ == Dummy YAML
33
+ If you want to access meta-data or user-data not on EC2 Instance like on it,
34
+ make one of these files
35
+ ./config/ec2_metadata.yml
36
+ ./ec2_metadata.yml
37
+ ~/ec2_metadata.yml
38
+ /etc/ec2_metadata.yml
39
+
40
+ Dummy YAML file must be like output of ec2-metadata on EC2 instance.
41
+ You can export it on EC2 instance like this:
42
+ $ ec2-medatata > ec2_metadata.yml
43
+ $ cp ec2_metadata.yml /path/to/dir/for/non/ec2/instance
44
+
45
+ Or if you don't have EC2 instance, you can get an example by
46
+ $ ec2-metadata -d
47
+
4
48
 
5
49
  == Note on Patches/Pull Requests
6
50
 
data/Rakefile CHANGED
@@ -10,6 +10,8 @@ begin
10
10
  gem.email = "akm2000@gmail.com"
11
11
  gem.homepage = "http://github.com/akm/ec2-metadata"
12
12
  gem.authors = ["Takeshi AKIMA"]
13
+ gem.bindir = 'bin'
14
+ gem.executables = ['ec2-metadata']
13
15
  gem.add_development_dependency "rspec", ">= 1.2.9"
14
16
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
17
  end
@@ -28,6 +30,9 @@ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
30
  spec.libs << 'lib' << 'spec'
29
31
  spec.pattern = 'spec/**/*_spec.rb'
30
32
  spec.rcov = true
33
+ spec.rcov_opts = lambda do
34
+ IO.readlines("spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
35
+ end
31
36
  end
32
37
 
33
38
  task :spec => :check_dependencies
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
data/bin/ec2-metadata ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'ec2_metadata'
5
+ require 'yaml'
6
+ require 'optparse'
7
+
8
+ options = {:api_version => 'latest'}
9
+
10
+ ARGV.options do |o|
11
+ o.banner = 'Usage: ec2-metadata [options]'
12
+
13
+ o.on("-a [api-version]", '--api-version',
14
+ "Specify an API version. default is 'latest'.") do |v|
15
+ options[:api_version] = v
16
+ end
17
+
18
+ o.on("-V", '--display-api-versions',
19
+ "Display API versions and quit.") do
20
+ Ec2Metadata::Command.show_api_versions
21
+ exit
22
+ end
23
+
24
+ o.on("-d", '--display-dummy-yaml',
25
+ "Display a dummy YAML and quit.") do
26
+ Ec2Metadata::Command.show_dummy_yaml
27
+ exit
28
+ end
29
+
30
+ o.separator("General Options:")
31
+
32
+ o.on("-v", '--version', "Show the version number.") do
33
+ puts("ec2-metadata " <<
34
+ IO.read(File.join(File.dirname(__FILE__), "../VERSION")))
35
+ exit
36
+ end
37
+
38
+ o.on("-h", '--help', "Show this help message."){ puts o; exit}
39
+
40
+ o.parse!
41
+ end
42
+
43
+ Ec2Metadata::Command.show(options[:api_version])
44
+
@@ -0,0 +1,85 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ec2-metadata}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Takeshi AKIMA"]
12
+ s.date = %q{2010-04-08}
13
+ s.default_executable = %q{ec2-metadata}
14
+ s.description = %q{ec2-metadata provides to access metadata, and you can use in outside of ec2 like in ec2}
15
+ s.email = %q{akm2000@gmail.com}
16
+ s.executables = ["ec2-metadata"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ "LICENSE",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "bin/ec2-metadata",
29
+ "ec2-metadata.gemspec",
30
+ "lib/ec2_metadata.rb",
31
+ "lib/ec2_metadata/base.rb",
32
+ "lib/ec2_metadata/command.rb",
33
+ "lib/ec2_metadata/dummy.rb",
34
+ "lib/ec2_metadata/dummy.yml",
35
+ "lib/ec2_metadata/http_client.rb",
36
+ "lib/ec2_metadata/revision.rb",
37
+ "lib/ec2_metadata/root.rb",
38
+ "lib/hash_key_orderable.rb",
39
+ "spec/ec2_metadata/base_spec.rb",
40
+ "spec/ec2_metadata/command_spec.rb",
41
+ "spec/ec2_metadata/dummy_spec.rb",
42
+ "spec/ec2_metadata/http_client_spec.rb",
43
+ "spec/ec2_metadata/revision_spec.rb",
44
+ "spec/ec2_metadata/root_spec.rb",
45
+ "spec/ec2_metadata_spec.rb",
46
+ "spec/hash_key_orderable_spec.rb",
47
+ "spec/introduction_spec.rb",
48
+ "spec/rcov.opts",
49
+ "spec/spec.opts",
50
+ "spec/spec_helper.rb",
51
+ "spec/to_hash_spec.rb"
52
+ ]
53
+ s.homepage = %q{http://github.com/akm/ec2-metadata}
54
+ s.rdoc_options = ["--charset=UTF-8"]
55
+ s.require_paths = ["lib"]
56
+ s.rubygems_version = %q{1.3.6}
57
+ s.summary = %q{ec2-metadata provides to access metadata}
58
+ s.test_files = [
59
+ "spec/ec2_metadata/base_spec.rb",
60
+ "spec/ec2_metadata/command_spec.rb",
61
+ "spec/ec2_metadata/dummy_spec.rb",
62
+ "spec/ec2_metadata/http_client_spec.rb",
63
+ "spec/ec2_metadata/revision_spec.rb",
64
+ "spec/ec2_metadata/root_spec.rb",
65
+ "spec/ec2_metadata_spec.rb",
66
+ "spec/hash_key_orderable_spec.rb",
67
+ "spec/introduction_spec.rb",
68
+ "spec/spec_helper.rb",
69
+ "spec/to_hash_spec.rb"
70
+ ]
71
+
72
+ if s.respond_to? :specification_version then
73
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
74
+ s.specification_version = 3
75
+
76
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
77
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
78
+ else
79
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
80
+ end
81
+ else
82
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
83
+ end
84
+ end
85
+
data/lib/ec2_metadata.rb CHANGED
@@ -1,12 +1,19 @@
1
1
  require 'net/http'
2
+ Net::HTTP.version_1_2
2
3
 
3
4
  module Ec2Metadata
4
5
  DEFAULT_HOST = "169.254.169.254".freeze
5
6
 
7
+ autoload :HttpClient, 'ec2_metadata/http_client'
6
8
  autoload :Base, 'ec2_metadata/base'
7
- autoload :NamedBase, 'ec2_metadata/named_base'
8
9
  autoload :Root, 'ec2_metadata/root'
9
10
  autoload :Revision, 'ec2_metadata/revision'
11
+ autoload :Dummy, 'ec2_metadata/dummy'
12
+ autoload :Command, 'ec2_metadata/command'
13
+
14
+ DEFAULT_REVISION = 'latest'
15
+
16
+ extend HttpClient
10
17
 
11
18
  class << self
12
19
  def instance
@@ -21,10 +28,21 @@ module Ec2Metadata
21
28
  instance[key]
22
29
  end
23
30
 
24
- def get(path)
25
- logging("Ec2Metadata.get(#{path.inspect})") do
26
- Net::HTTP.get(DEFAULT_HOST, path)
27
- end
31
+ def to_hash(revision = DEFAULT_REVISION)
32
+ self[revision].to_hash
33
+ end
34
+
35
+ def from_hash(hash, revision = DEFAULT_REVISION)
36
+ # hash = {revision => hash}
37
+ # instance.from_hash(hash)
38
+ rev_obj = instance.new_child(revision)
39
+ instance.instance_variable_set(:@children, {revision => rev_obj})
40
+ instance.instance_variable_set(:@child_keys, [revision])
41
+ rev_obj.from_hash(hash)
42
+ end
43
+
44
+ def formalize_key(key)
45
+ key.to_s.gsub(/_/, '-')
28
46
  end
29
47
 
30
48
  def logging(msg)
@@ -46,3 +64,7 @@ module Ec2Metadata
46
64
  end
47
65
 
48
66
  end
67
+
68
+ unless ENV['EC2_METADATA_DUMMY_DISABLED'] =~ /yes|true|on/i
69
+ Ec2Metadata::Dummy.search_and_load_yaml
70
+ end
@@ -36,7 +36,7 @@ module Ec2Metadata
36
36
 
37
37
  def get(child_key)
38
38
  logging("#{self.class.name}.get(#{child_key.inspect})") do
39
- child_key = child_key.to_s.gsub(/_/, '-')
39
+ child_key = Ec2Metadata.formalize_key(child_key)
40
40
  if children.has_key?(child_key)
41
41
  result = children[child_key]
42
42
  else
@@ -61,13 +61,17 @@ module Ec2Metadata
61
61
  end
62
62
 
63
63
  def is_struct?(child_key)
64
- k = child_key.to_s.gsub(/_/, '-') << '/'
64
+ k = Ec2Metadata.formalize_key(child_key) << '/'
65
65
  child_keys.include?(k) || (defined?(@child_names) && @child_names.keys.include?(child_key))
66
66
  end
67
67
 
68
68
  def new_child(child_key)
69
69
  if defined?(@child_names) && (name = @child_names[child_key])
70
- NamedBase.new(name, "#{path}#{child_key}/")
70
+ grandchild = Base.new("#{path}#{child_key}/")
71
+ child = Base.new("#{path}#{child_key}/")
72
+ child.instance_variable_set(:@children, {name => grandchild})
73
+ child.instance_variable_set(:@child_keys, [name])
74
+ child
71
75
  else
72
76
  Base.new("#{path}#{child_key}/")
73
77
  end
@@ -81,6 +85,35 @@ module Ec2Metadata
81
85
  end
82
86
  end
83
87
 
88
+ def to_hash
89
+ keys.inject({}) do |dest, key|
90
+ key = key.sub(/\/$/, '')
91
+ value = get(key)
92
+ dest[key] = value.respond_to?(:to_hash) ? value.to_hash : value
93
+ dest
94
+ end
95
+ end
96
+
97
+ def from_hash(hash)
98
+ hash = hash.inject({}){|d, (k, v)| d[Ec2Metadata.formalize_key(k)] = v; d}
99
+ @child_keys = hash.keys
100
+ @children = {}
101
+ hash.each do |key, value|
102
+ if value.is_a?(Array)
103
+ idx = 0
104
+ value = value.inject({}){|d, v| d[idx] = v; idx += 1; d}
105
+ end
106
+ if value.is_a?(Hash)
107
+ child = new_child(key)
108
+ @children[key] = child
109
+ child.from_hash(value)
110
+ else
111
+ @children[key] = value
112
+ end
113
+ end
114
+ end
115
+
116
+
84
117
  private
85
118
  def logging(msg, &block)
86
119
  Ec2Metadata.logging(msg, &block)
@@ -0,0 +1,68 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'ec2_metadata'
3
+ require 'hash_key_orderable'
4
+
5
+ module Ec2Metadata
6
+ module Command
7
+ class << self
8
+ DATA_KEY_ORDER = %w(meta-data user-data)
9
+ # %w(...)の中に改行を入れるとrcovがパスしていることを認識してくれないので、各行毎に%w(..)します
10
+ META_DATA_KEY_ORDER =
11
+ %w(ami-id ami-launch-index ami-manifest-path ancestor-ami-ids) +
12
+ %w(instance-id instance-type instance-action) +
13
+ %w(public-keys/ placement/ security-groups) +
14
+ %w(hostname) +
15
+ %w(public-hostname public-ipv4) +
16
+ %w(local-hostname local-ipv4) +
17
+ %w(block-device-mapping/) +
18
+ %w(kernel-id) +
19
+ %w(ramdisk-id) +
20
+ %w(reservation-id)
21
+
22
+ def show(api_version = 'latest')
23
+ timeout do
24
+ v = (api_version || '').strip
25
+ unless Ec2Metadata.instance.keys.include?(v)
26
+ raise ArgumentError, "API version must be one of #{Ec2Metadata.instance.keys.inspect} but was #{api_version.inspect}"
27
+ end
28
+ show_yaml_path_if_loaded
29
+ data = Ec2Metadata[v].to_hash
30
+ data.extend(HashKeyOrderable)
31
+ data.key_order = DATA_KEY_ORDER
32
+ meta_data = data['meta-data']
33
+ meta_data.extend(HashKeyOrderable)
34
+ meta_data.key_order = META_DATA_KEY_ORDER
35
+ puts YAML.dump(data)
36
+ end
37
+ end
38
+
39
+ def show_api_versions
40
+ timeout do
41
+ show_yaml_path_if_loaded
42
+ puts Ec2Metadata.instance.keys
43
+ end
44
+ end
45
+
46
+ def show_dummy_yaml
47
+ show_yaml_path_if_loaded
48
+ puts IO.read(File.expand_path(File.join(File.dirname(__FILE__), 'dummy.yml')))
49
+ end
50
+
51
+ private
52
+ def timeout
53
+ begin
54
+ yield
55
+ rescue Timeout::Error, SystemCallError => error
56
+ puts "HTTP request timed out. You can use dummy YAML for non EC2 Instance. #{Dummy.yaml_paths.inspect}"
57
+ end
58
+ end
59
+
60
+ def show_yaml_path_if_loaded
61
+ if path = Ec2Metadata::Dummy.loaded_yaml_path
62
+ puts "Actually these data is based on a DUMMY yaml file: #{path}"
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,38 @@
1
+ module Ec2Metadata
2
+ module Dummy
3
+ YAML_FILENAME = 'ec2_metadata.yml'.freeze
4
+ YAML_SEARCH_DIRS = ['./config', '.', '~', '/etc'].freeze
5
+ ENV_SPECIFIED_PATH = "EC2_METADATA_DUMMY_YAML".freeze
6
+
7
+ class << self
8
+ def yaml_paths
9
+ dirs = YAML_SEARCH_DIRS.dup
10
+ if Module.constants.include?('RAILS_ROOT')
11
+ dirs.unshift(File.join(Module.const_get('RAILS_ROOT'), 'config'))
12
+ end
13
+ result = dirs.map{|d| File.join(d, YAML_FILENAME)}
14
+ if specified_path = ENV[ENV_SPECIFIED_PATH]
15
+ result.unshift(specified_path)
16
+ end
17
+ result
18
+ end
19
+
20
+ def search_and_load_yaml
21
+ paths = Dir.glob(yaml_paths.map{|path| File.expand_path(path)})
22
+ load_yaml(paths.first) unless paths.empty?
23
+ end
24
+
25
+ def load_yaml(path)
26
+ erb = ERB.new(IO.read(path))
27
+ erb.filename = path
28
+ text = erb.result
29
+ Ec2Metadata.from_hash(YAML.load(text))
30
+ @loaded_yaml_path = path
31
+ end
32
+
33
+ def loaded_yaml_path
34
+ @loaded_yaml_path
35
+ end
36
+ end
37
+ end
38
+ end