engineyard-metadata 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -11,20 +11,46 @@ To define an unchanging interface to useful metadata (passwords, IP addresses, e
11
11
  * Get a dynamically updated list of all running app servers so that you can pool memcached over all of them. (<tt>EY::Metadata.app_servers</tt>)
12
12
  * Get the current database password so that you can write a script that connects to it. (<tt>EY::Metadata.database_password</tt>)
13
13
 
14
- Get the full method list in {the engineyard-metadata rdoc}[http://rdoc.info/github/seamusabshere/engineyard-metadata].
14
+ Here's the current method list:
15
+
16
+ EY::Metadata.present_instance_id (only works from cloud instances)
17
+ EY::Metadata.present_security_group (only works from cloud instances)
18
+ EY::Metadata.present_instance_role (only works from cloud instances)
19
+ EY::Metadata.present_public_hostname (only works from cloud instances)
20
+ EY::Metadata.database_password (only works from cloud instances)
21
+ EY::Metadata.database_username
22
+ EY::Metadata.database_name
23
+ EY::Metadata.database_host
24
+ EY::Metadata.ssh_username
25
+ EY::Metadata.ssh_password (only works from cloud instances)
26
+ EY::Metadata.app_servers
27
+ EY::Metadata.db_servers
28
+ EY::Metadata.utilities
29
+ EY::Metadata.app_master
30
+ EY::Metadata.db_master
31
+ EY::Metadata.mysql_command (only works from cloud instances)
32
+ EY::Metadata.mysqldump_command (only works from cloud instances)
33
+ EY::Metadata.app_slaves
34
+ EY::Metadata.db_slaves
35
+ EY::Metadata.solo
36
+ EY::Metadata.environment_name
37
+ EY::Metadata.stack_name
38
+ EY::Metadata.repository_uri
15
39
 
16
40
  == Use
17
41
 
18
- === From the inside
42
+ See the rdoc at {the engineyard-metadata rdoc}[http://rubydoc.info/gems/engineyard-metadata].
43
+
44
+ === When you're executing this gem from INSIDE the cloud
19
45
 
20
46
  When you're executing the gem from your instances, you don't have to configure anything. Just require the gem.
21
47
 
22
- === From the outside
48
+ === When you're executing this gem from OUTSIDE the cloud
23
49
 
24
- You need to provide...
50
+ You must...
25
51
 
26
- * <tt>ENV['EY_CLOUD_TOKEN']</tt> or have <tt>~/.eyrc</tt>
27
- * <tt>ENV['REPOSITORY_URI']</tt> or execute the gem from the local copy of your application's repo.
52
+ * have <tt>~/.eyrc</tt> or set <tt>EY::Metadata.ey_cloud_token=</tt> or set <tt>ENV['EY_CLOUD_TOKEN']</tt>.
53
+ * execute the gem from the local copy of your application's repo or set <tt>EY::Metadata.environment_name=</tt> or set <tt>ENV['EY_ENVIRONMENT_NAME']</tt>.
28
54
 
29
55
  === Where the methods are defined
30
56
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{engineyard-metadata}
8
- s.version = "0.0.5"
8
+ s.version = "0.0.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Seamus Abshere"]
@@ -40,6 +40,11 @@ module EY
40
40
  def database_name
41
41
  data['engineyard']['environment']['apps'][0]['database_name']
42
42
  end
43
+
44
+ # The git repository that you told EngineYard to use for this application.
45
+ def repository_uri
46
+ data['engineyard']['environment']['apps'][0]['repository_name']
47
+ end
43
48
 
44
49
  # Public hostname where you should connect to the database.
45
50
  #
@@ -1,5 +1,3 @@
1
- require 'etc'
2
- require 'yaml'
3
1
  require 'rest' # from nap gem
4
2
  require 'active_support'
5
3
  require 'active_support/version'
@@ -98,7 +96,7 @@ module EY
98
96
  x['public_hostname']
99
97
  end
100
98
  end
101
-
99
+
102
100
  # The name of the EngineYard AppCloud environment.
103
101
  def environment_name
104
102
  data['name']
@@ -109,41 +107,29 @@ module EY
109
107
  data['stack_name']
110
108
  end
111
109
 
112
- # The secret API token to access https://cloud.engineyard.com
113
- def ey_cloud_token
114
- @ey_cloud_token ||= if ENV['EY_CLOUD_TOKEN'].to_s.strip.length > 0
115
- ENV['EY_CLOUD_TOKEN']
116
- elsif File.exist? EY::Metadata.eyrc_path
117
- YAML.load(File.read(EY::Metadata.eyrc_path))['api_token']
118
- else
119
- raise RuntimeError, "[engineyard-metadata gem] You need to download #{eyrc_path} or set ENV['EY_CLOUD_TOKEN']"
120
- end
110
+ # The git repository that you told EngineYard to use for this application.
111
+ def repository_uri
112
+ data['apps'][0]['repository_uri']
121
113
  end
122
114
 
123
- # The URL that EngineYard has on file for your application.
124
- def repository_uri
125
- @repository_uri ||= if ENV['REPOSITORY_URI'].to_s.strip.length > 0
126
- ENV['REPOSITORY_URI']
127
- elsif File.exist? EY::Metadata.git_config_path
128
- `git config --get remote.origin.url`
129
- else
130
- raise RuntimeError, "[engineyard-metadata gem] You need to be inside a app's git repo or set ENV['REPOSITORY_URI']"
131
- end
115
+ def data_loaded?
116
+ @data.is_a? Hash
132
117
  end
133
118
 
134
119
  def data
135
- return @data if @data.is_a? Hash
136
- raw_json = REST.get(URL, 'X-EY-Cloud-Token' => ey_cloud_token).body
120
+ return @data if data_loaded?
121
+ raw_json = REST.get(URL, 'X-EY-Cloud-Token' => EY::Metadata.ey_cloud_token).body
137
122
  raw_data = ActiveSupport::JSON.decode raw_json
138
- catch :found_environment_by_repository_uri do
139
- raw_data['environments'].each do |environment_hsh|
140
- if environment_hsh['apps'].any? { |app_hsh| app_hsh['repository_uri'] == repository_uri }
141
- @data = environment_hsh
142
- throw :found_environment_by_repository_uri
143
- end
123
+ matching_environment_hshs = raw_data['environments'].select do |environment_hsh|
124
+ if EY::Metadata.environment_name
125
+ environment_hsh['name'] == EY::Metadata.environment_name
126
+ else
127
+ environment_hsh['apps'].any? { |app_hsh| app_hsh['repository_uri'] == repository_uri }
144
128
  end
145
129
  end
146
- raise RuntimeError, "[engineyard-metadata gem] Couldn't find an EngineYard environment with the repository uri #{repository_uri}" unless @data.is_a? Hash
130
+ raise RuntimeError, "[engineyard-metadata gem] Found too many environments: #{matching_environment_hshs.map { |hsh| hsh['name'] }.join(', ')}" if matching_environment_hshs.length > 1
131
+ @data = matching_environment_hshs[0]
132
+ raise RuntimeError, "[engineyard-metadata gem] Couldn't find an EngineYard environment with the repository uri #{repository_uri}" unless data_loaded?
147
133
  @data
148
134
  end
149
135
  end
@@ -28,6 +28,7 @@ module EY
28
28
  solo
29
29
  environment_name
30
30
  stack_name
31
+ repository_uri
31
32
  }
32
33
 
33
34
  # This gets raised when you can't get a particular piece of metadata from the execution environment you're in.
@@ -1,18 +1,22 @@
1
+ require 'etc'
2
+ require 'yaml'
3
+
1
4
  module EY
2
5
  module Metadata
3
6
  # This gets pulled in when you're running from your developer machine (i.e., not on a cloud instance).
4
7
  module Outsider
5
- IMPOSSIBLE = KEYS.grep(/present/) + KEYS.grep(/password/) + KEYS.grep(/mysql/)
8
+ LOCALLY_DETERMINED = %w{ environment_name repository_uri }
9
+ UNGETTABLE = KEYS.grep(/present/) + KEYS.grep(/password/) + KEYS.grep(/mysql/)
6
10
 
7
- POSSIBLE = KEYS - IMPOSSIBLE
11
+ GETTABLE = KEYS - LOCALLY_DETERMINED - UNGETTABLE
8
12
 
9
- IMPOSSIBLE.each do |name|
13
+ UNGETTABLE.each do |name|
10
14
  define_method name do
11
15
  raise CannotGetFromHere
12
16
  end
13
17
  end
14
18
 
15
- POSSIBLE.each do |name|
19
+ GETTABLE.each do |name|
16
20
  define_method name do
17
21
  engine_yard_cloud_api.send name
18
22
  end
@@ -25,6 +29,68 @@ module EY
25
29
  def git_config_path
26
30
  File.join Dir.pwd, '.git', 'config'
27
31
  end
32
+
33
+ def clear
34
+ @repository_uri = nil
35
+ @environment_name = nil
36
+ @ey_cloud_token = nil
37
+ @data = nil
38
+ end
39
+
40
+ def environment_name=(str)
41
+ # clear this out in case it was inferred
42
+ @repository_uri = nil
43
+ # clear this out in case we're looking up a new environment
44
+ @data = nil
45
+ @environment_name = str
46
+ end
47
+
48
+ # The name of the EngineYard AppCloud environment.
49
+ def environment_name
50
+ return @environment_name if @environment_name.is_a? String
51
+ @environment_name = if engine_yard_cloud_api.data_loaded?
52
+ # this happens when we don't get any help from the user and the environment has been found based on the repository uri
53
+ engine_yard_cloud_api.environment_name
54
+ elsif ENV['EY_ENVIRONMENT_NAME']
55
+ ENV['EY_ENVIRONMENT_NAME']
56
+ end
57
+ end
58
+
59
+ def ey_cloud_token=(str)
60
+ # clear this out in case it was inferred
61
+ @repository_uri = nil
62
+ # clear this out in case we're looking up a new environment
63
+ @data = nil
64
+ @ey_cloud_token = str
65
+ end
66
+
67
+ # The secret API token to access https://cloud.engineyard.com
68
+ def ey_cloud_token
69
+ return @ey_cloud_token if @ey_cloud_token.is_a? String
70
+ @ey_cloud_token = if ENV['EY_CLOUD_TOKEN']
71
+ ENV['EY_CLOUD_TOKEN']
72
+ elsif File.exist? eyrc_path
73
+ YAML.load(File.read(eyrc_path))['ey_cloud_token']
74
+ else
75
+ raise RuntimeError, "[engineyard-metadata gem] You need to download #{eyrc_path} or set ENV['EY_CLOUD_TOKEN']"
76
+ end
77
+ end
78
+
79
+ # The URL that EngineYard has on file for your application.
80
+ #
81
+ # There's no setter for this because you should really use EY::Metadata.environment_name= or ENV['EY_ENVIRONMENT_NAME']
82
+ def repository_uri
83
+ return @repository_uri if @repository_uri.is_a? String
84
+ @repository_uri = if engine_yard_cloud_api.data_loaded?
85
+ engine_yard_cloud_api.repository_uri
86
+ elsif ENV['EY_REPOSITORY_URI']
87
+ ENV['EY_REPOSITORY_URI']
88
+ elsif File.exist? git_config_path
89
+ `git config --get remote.origin.url`.strip
90
+ else
91
+ raise RuntimeError, "[engineyard-metadata gem] You need to be inside a app's git repo or set ENV['EY_REPOSITORY_URI']"
92
+ end
93
+ end
28
94
 
29
95
  # An adapter that reads from the public EngineYard Cloud API (https://cloud.engineyard.com)
30
96
  def engine_yard_cloud_api
@@ -56,6 +56,64 @@ shared_examples_for "all execution environments" do
56
56
  it 'gets the stack name' do
57
57
  EY::Metadata.stack_name.should == 'FAKE_STACK_NAME'
58
58
  end
59
+
60
+ it 'gets the repository URI' do
61
+ EY::Metadata.repository_uri.should == 'FAKE_REPOSITORY_URI'
62
+ end
63
+ end
64
+
65
+ shared_examples_for "execution outside the cloud" do
66
+ it 'cannot get the present instance ID' do
67
+ lambda {
68
+ EY::Metadata.present_instance_id
69
+ }.should raise_error(EY::Metadata::CannotGetFromHere)
70
+ end
71
+
72
+ it 'cannot get the present instance role (as a string)' do
73
+ lambda {
74
+ EY::Metadata.present_instance_role
75
+ }.should raise_error(EY::Metadata::CannotGetFromHere)
76
+ end
77
+
78
+ it 'cannot get the present public hostname' do
79
+ lambda {
80
+ EY::Metadata.present_public_hostname
81
+ }.should raise_error(EY::Metadata::CannotGetFromHere)
82
+ end
83
+
84
+ it 'cannot get the present security group' do
85
+ lambda {
86
+ EY::Metadata.present_security_group
87
+ }.should raise_error(EY::Metadata::CannotGetFromHere)
88
+ end
89
+
90
+ it 'cannot get the database password' do
91
+ lambda {
92
+ EY::Metadata.database_password
93
+ }.should raise_error(EY::Metadata::CannotGetFromHere)
94
+ end
95
+
96
+ it 'cannot get the ssh password' do
97
+ lambda {
98
+ EY::Metadata.ssh_password
99
+ }.should raise_error(EY::Metadata::CannotGetFromHere)
100
+ end
101
+
102
+ it 'cannot get the mysql command' do
103
+ lambda {
104
+ EY::Metadata.mysql_command
105
+ }.should raise_error(EY::Metadata::CannotGetFromHere)
106
+ end
107
+
108
+ it 'cannot get the mysqldump command' do
109
+ lambda {
110
+ EY::Metadata.mysqldump_command
111
+ }.should raise_error(EY::Metadata::CannotGetFromHere)
112
+ end
113
+
114
+ it 'gets the raw EngineYard Cloud API data' do
115
+ EY::Metadata.engine_yard_cloud_api.data.should be_a(Hash)
116
+ end
59
117
  end
60
118
 
61
119
  describe 'EY::Metadata' do
@@ -70,59 +128,25 @@ describe 'EY::Metadata' do
70
128
  stop_pretending
71
129
  end
72
130
 
73
- it 'cannot get the present instance ID' do
74
- lambda {
75
- EY::Metadata.present_instance_id
76
- }.should raise_error(EY::Metadata::CannotGetFromHere)
77
- end
78
-
79
- it 'cannot get the present instance role (as a string)' do
80
- lambda {
81
- EY::Metadata.present_instance_role
82
- }.should raise_error(EY::Metadata::CannotGetFromHere)
83
- end
84
-
85
- it 'cannot get the present public hostname' do
86
- lambda {
87
- EY::Metadata.present_public_hostname
88
- }.should raise_error(EY::Metadata::CannotGetFromHere)
89
- end
90
-
91
- it 'cannot get the present security group' do
92
- lambda {
93
- EY::Metadata.present_security_group
94
- }.should raise_error(EY::Metadata::CannotGetFromHere)
95
- end
96
-
97
- it 'cannot get the database password' do
98
- lambda {
99
- EY::Metadata.database_password
100
- }.should raise_error(EY::Metadata::CannotGetFromHere)
101
- end
102
-
103
- it 'cannot get the ssh password' do
104
- lambda {
105
- EY::Metadata.ssh_password
106
- }.should raise_error(EY::Metadata::CannotGetFromHere)
107
- end
108
-
109
- it 'cannot get the mysql command' do
110
- lambda {
111
- EY::Metadata.mysql_command
112
- }.should raise_error(EY::Metadata::CannotGetFromHere)
131
+ describe "controlled with environment variables" do
132
+ before(:all) do
133
+ EY::Metadata.clear
134
+ ENV['EY_CLOUD_TOKEN'] = FAKE_CLOUD_TOKEN
135
+ ENV['EY_ENVIRONMENT_NAME'] = FAKE_ENVIRONMENT_NAME
136
+ end
137
+ it_should_behave_like "all execution environments"
138
+ it_should_behave_like "execution outside the cloud"
113
139
  end
114
140
 
115
- it 'cannot get the mysqldump command' do
116
- lambda {
117
- EY::Metadata.mysqldump_command
118
- }.should raise_error(EY::Metadata::CannotGetFromHere)
141
+ describe "controlled with attr writers" do
142
+ before(:all) do
143
+ EY::Metadata.clear
144
+ EY::Metadata.ey_cloud_token = FAKE_CLOUD_TOKEN
145
+ EY::Metadata.environment_name = FAKE_ENVIRONMENT_NAME
146
+ end
147
+ it_should_behave_like "all execution environments"
148
+ it_should_behave_like "execution outside the cloud"
119
149
  end
120
-
121
- it 'gets the raw EngineYard Cloud API data' do
122
- EY::Metadata.engine_yard_cloud_api.data.should be_a(Hash)
123
- end
124
-
125
- it_should_behave_like "all execution environments"
126
150
  end
127
151
 
128
152
  describe "being executed on an EngineYard AppCloud (i.e. Amazon EC2) instance" do
data/spec/spec_helper.rb CHANGED
@@ -9,10 +9,10 @@ require 'fakefs/safe'
9
9
  PRESENT_PUBLIC_HOSTNAME = 'app_master.compute-1.amazonaws.com'
10
10
  PRESENT_SECURITY_GROUP = 'ey-data1_production-1-2-3'
11
11
  PRESENT_INSTANCE_ID = 'i-deadbeef'
12
- REPOSITORY_URI = 'FAKE_REPOSITORY_URI'
12
+ FAKE_CLOUD_TOKEN = 'FAKE_EY_CLOUD_TOKEN'
13
+ FAKE_ENVIRONMENT_NAME = 'FAKE_ENVIRONMENT_NAME'
13
14
 
14
15
  def pretend_we_are_on_a_developer_machine
15
- ENV['REPOSITORY_URI'] = REPOSITORY_URI
16
16
  FakeWeb.allow_net_connect = false
17
17
  FakeWeb.register_uri :get,
18
18
  "https://cloud.engineyard.com/api/v2/environments",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "newrelic": false,
47
47
  "https_bind_port": 443,
48
- "repository_name": "APPS-0-REPOSITORY-NAME",
48
+ "repository_name": "FAKE_REPOSITORY_URI",
49
49
  "type": "rack",
50
50
  "migration_command": "rake db:migrate",
51
51
  "http_bind_port": 80,
@@ -124,7 +124,7 @@
124
124
  "database_name": "FAKE_APP_NAME",
125
125
  "migration_command": "rake db:migrate",
126
126
  "type": "rack",
127
- "repository_name": "APPS-0-REPOSITORY_NAME",
127
+ "repository_name": "FAKE_REPOSITORY_URI",
128
128
  "run_deploy": false,
129
129
  "revision": "",
130
130
  "bundled": null,
@@ -1,5 +1,17 @@
1
1
  {"environments":
2
2
  [
3
+ {"app_master":
4
+ {"public_hostname":"app_master.compute-1.amazonaws.com","name":null,"status":"running","amazon_id":"i-aaaaaaaa","role":"app_master","id":11111
5
+ },"ssh_username":"WRONG_SSH_USERNAME","stack_name":"WRONG_STACK_NAME","framework_env":"production","name":"WRONG_ENVIRONMENT_NAME","account":
6
+ {"name":"WRONG_ACCOUNT_NAME","id":12345
7
+ },"instances_count":0,"apps":
8
+ [
9
+ {"repository_uri":"FAKE_REPOSITORY_URI","name":"WRONG_APP_NAME","account":
10
+ {"name":"WRONG_ACCOUNT_NAME","id":12345
11
+ },"id":292301
12
+ }
13
+ ],"id":382918,"instances":[]
14
+ },
3
15
  {"app_master":
4
16
  {"public_hostname":"app_master.compute-1.amazonaws.com","name":null,"status":"running","amazon_id":"i-aaaaaaaa","role":"app_master","id":11111
5
17
  },"ssh_username":"FAKE_SSH_USERNAME","stack_name":"FAKE_STACK_NAME","framework_env":"production","name":"FAKE_ENVIRONMENT_NAME","account":
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: engineyard-metadata
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 5
10
- version: 0.0.5
9
+ - 6
10
+ version: 0.0.6
11
11
  platform: ruby
12
12
  authors:
13
13
  - Seamus Abshere