engineyard-metadata 0.0.5 → 0.0.6
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/README.rdoc +32 -6
- data/VERSION +1 -1
- data/engineyard-metadata.gemspec +1 -1
- data/lib/engineyard-metadata/chef_dna.rb +5 -0
- data/lib/engineyard-metadata/engine_yard_cloud_api.rb +16 -30
- data/lib/engineyard-metadata/metadata.rb +1 -0
- data/lib/engineyard-metadata/outsider.rb +70 -4
- data/spec/metadata_spec.rb +74 -50
- data/spec/spec_helper.rb +2 -2
- data/spec/support/dna.json +2 -2
- data/spec/support/engine_yard_cloud_api_response.json +12 -0
- metadata +3 -3
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
|
-
|
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
|
-
|
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
|
-
===
|
48
|
+
=== When you're executing this gem from OUTSIDE the cloud
|
23
49
|
|
24
|
-
You
|
50
|
+
You must...
|
25
51
|
|
26
|
-
* <tt
|
27
|
-
*
|
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.
|
1
|
+
0.0.6
|
data/engineyard-metadata.gemspec
CHANGED
@@ -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
|
113
|
-
def
|
114
|
-
|
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
|
-
|
124
|
-
|
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
|
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
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
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]
|
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
|
@@ -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
|
-
|
8
|
+
LOCALLY_DETERMINED = %w{ environment_name repository_uri }
|
9
|
+
UNGETTABLE = KEYS.grep(/present/) + KEYS.grep(/password/) + KEYS.grep(/mysql/)
|
6
10
|
|
7
|
-
|
11
|
+
GETTABLE = KEYS - LOCALLY_DETERMINED - UNGETTABLE
|
8
12
|
|
9
|
-
|
13
|
+
UNGETTABLE.each do |name|
|
10
14
|
define_method name do
|
11
15
|
raise CannotGetFromHere
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|
15
|
-
|
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
|
data/spec/metadata_spec.rb
CHANGED
@@ -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
|
-
|
74
|
-
|
75
|
-
EY::Metadata.
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
-
|
116
|
-
|
117
|
-
EY::Metadata.
|
118
|
-
|
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
|
-
|
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",
|
data/spec/support/dna.json
CHANGED
@@ -45,7 +45,7 @@
|
|
45
45
|
},
|
46
46
|
"newrelic": false,
|
47
47
|
"https_bind_port": 443,
|
48
|
-
"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": "
|
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:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 6
|
10
|
+
version: 0.0.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Seamus Abshere
|