engineyard 1.3.22 → 1.3.25

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -171,3 +171,13 @@ Command:
171
171
  Note: this command is a bit picky about its ordering. To run a command with arguments on all servers, like "rm -f /some/file", you need to order it like so:
172
172
 
173
173
  $ ey ssh "rm -f /some/file" -e my-environment --all
174
+
175
+ Command:
176
+ ey launch
177
+
178
+ Options:
179
+ -e, [--environment=ENVIRONMENT] # Environment to ssh into
180
+ -c, [--account=ACCOUNT] # Name of the account in which the environment can be found
181
+
182
+ Description:
183
+ Open the application in a browser.
@@ -0,0 +1,135 @@
1
+ require 'engineyard/model'
2
+
3
+ module EngineYard
4
+ class APIClient
5
+ attr_reader :token
6
+
7
+ USER_AGENT_STRING = "EngineYardAPIClient/#{VERSION}"
8
+
9
+ def initialize(token = nil)
10
+ @token ||= token
11
+ @token ||= self.class.read_token
12
+ raise ArgumentError, "EY Cloud API token required" unless @token
13
+ end
14
+
15
+ def ==(other)
16
+ raise ArgumentError unless other.is_a?(self.class)
17
+ self.token == other.token
18
+ end
19
+
20
+ def request(url, opts={})
21
+ opts[:headers] ||= {}
22
+ opts[:headers]["X-EY-Cloud-Token"] = token
23
+ EY.ui.debug("Token", token)
24
+ self.class.request(url, opts)
25
+ end
26
+
27
+ def environments
28
+ @environments ||= Environment.from_array(request('/environments')["environments"], :api => self)
29
+ end
30
+
31
+ def apps
32
+ @apps ||= App.from_array(request('/apps')["apps"], :api => self)
33
+ end
34
+
35
+ def resolver
36
+ @resolver ||= Resolver.new(self)
37
+ end
38
+
39
+ def apps_for_repo(repo)
40
+ repo.fail_on_no_remotes!
41
+ apps.find_all {|a| repo.has_remote?(a.repository_uri) }
42
+ end
43
+
44
+ class InvalidCredentials < EY::AppCloudClient::Error; end
45
+ class RequestFailed < EY::AppCloudClient::Error; end
46
+
47
+ def self.request(path, opts={})
48
+ require 'rest_client'
49
+ require 'json'
50
+
51
+ url = EY.config.endpoint + "api/v2#{path}"
52
+ method = (opts.delete(:method) || 'get').to_s.downcase.to_sym
53
+ params = opts.delete(:params) || {}
54
+ headers = opts.delete(:headers) || {}
55
+ headers["Accept"] ||= "application/json"
56
+ headers["User-Agent"] = USER_AGENT_STRING
57
+
58
+ begin
59
+ EY.ui.debug("Request", "#{method.to_s.upcase} #{url}")
60
+ case method
61
+ when :get, :delete, :head
62
+ url.query = RestClient::Payload::UrlEncoded.new(params).to_s
63
+ resp = RestClient.send(method, url.to_s, headers)
64
+ else
65
+ resp = RestClient.send(method, url.to_s, params, headers)
66
+ end
67
+ rescue RestClient::Unauthorized
68
+ raise InvalidCredentials
69
+ rescue Errno::ECONNREFUSED
70
+ raise RequestFailed, "Could not reach the cloud API"
71
+ rescue RestClient::ResourceNotFound
72
+ raise RequestFailed, "The requested resource could not be found"
73
+ rescue RestClient::BadGateway
74
+ raise RequestFailed, "AppCloud API is temporarily unavailable. Please try again soon."
75
+ rescue RestClient::RequestFailed => e
76
+ raise RequestFailed, "#{e.message} #{e.response}"
77
+ rescue OpenSSL::SSL::SSLError
78
+ raise RequestFailed, "SSL is misconfigured on your cloud"
79
+ end
80
+
81
+ if resp.body.empty?
82
+ data = ''
83
+ elsif resp.headers[:content_type] =~ /application\/json/
84
+ begin
85
+ data = JSON.parse(resp.body)
86
+ EY.ui.debug("Response", data)
87
+ rescue JSON::ParserError
88
+ EY.ui.debug("Raw response", resp.body)
89
+ raise RequestFailed, "Response was not valid JSON."
90
+ end
91
+ else
92
+ data = resp.body
93
+ end
94
+
95
+ data
96
+ end
97
+
98
+ def self.fetch_token(email, password)
99
+ api_token = request("/authenticate", :method => "post",
100
+ :params => { :email => email, :password => password })["api_token"]
101
+ save_token(api_token)
102
+ api_token
103
+ end
104
+
105
+ def self.read_token(file = nil)
106
+ file ||= ENV['EYRC'] || File.expand_path("~/.eyrc")
107
+ return false unless File.exists?(file)
108
+
109
+ require 'yaml'
110
+
111
+ data = YAML.load_file(file)
112
+ if EY.config.default_endpoint?
113
+ data["api_token"]
114
+ else
115
+ (data[EY.config.endpoint.to_s] || {})["api_token"]
116
+ end
117
+ end
118
+
119
+ def self.save_token(token, file = nil)
120
+ file ||= ENV['EYRC'] || File.expand_path("~/.eyrc")
121
+ require 'yaml'
122
+
123
+ data = File.exists?(file) ? YAML.load_file(file) : {}
124
+ if EY.config.default_endpoint?
125
+ data.merge!("api_token" => token)
126
+ else
127
+ data.merge!(EY.config.endpoint.to_s => {"api_token" => token})
128
+ end
129
+
130
+ File.open(file, "w"){|f| YAML.dump(data, f) }
131
+ true
132
+ end
133
+
134
+ end # API
135
+ end # EY
@@ -68,6 +68,7 @@ module EY
68
68
 
69
69
  if environment.deploy(app, deploy_ref, deploy_options)
70
70
  EY.ui.info "Deploy complete"
71
+ EY.ui.info "Now you can run `ey launch' to open the application in a browser."
71
72
  else
72
73
  raise EY::Error, "Deploy failed"
73
74
  end
@@ -331,5 +332,15 @@ module EY
331
332
  end
332
333
  end
333
334
 
335
+ desc "launch [--environment ENVIRONMENT] [--account ACCOUNT]", "Open application in browser."
336
+ method_option :environment, :type => :string, :aliases => %w(-e),
337
+ :desc => "Environment with the interesting logs"
338
+ method_option :account, :type => :string, :aliases => %w(-c),
339
+ :desc => "Name of the account in which the environment can be found"
340
+ def launch
341
+ environment = fetch_environment(options[:environment], options[:account])
342
+ environment.launch
343
+ end
344
+
334
345
  end # CLI
335
346
  end # EY
@@ -7,8 +7,8 @@ module EY
7
7
  def initialize(file = nil)
8
8
  require 'yaml'
9
9
  @file = file || CONFIG_FILES.find{|f| File.exists?(f) }
10
- @config = @file ? YAML.load_file(@file) : {}
11
- @config.merge!("environments" => {}) unless @config["environments"]
10
+ @config = (@file ? YAML.load_file(@file) : {}) || {} # load_file returns `false' when the file is empty
11
+ @config["environments"] = {} unless @config["environments"]
12
12
  end
13
13
 
14
14
  def method_missing(meth, *args, &blk)
@@ -1,6 +1,7 @@
1
1
  module EY
2
2
  module Model
3
3
  class Environment < ApiStruct.new(:id, :account, :name, :framework_env, :instances, :instances_count, :apps, :app_master, :username, :app_server_stack_name, :load_balancer_ip_address, :api)
4
+ require 'launchy'
4
5
 
5
6
  attr_accessor :ignore_bad_master
6
7
 
@@ -132,6 +133,10 @@ module EY
132
133
  name.gsub(/^#{Regexp.quote(app.name)}_/, '')
133
134
  end
134
135
 
136
+ def launch
137
+ Launchy.open(app_master!.hostname_url)
138
+ end
139
+
135
140
  private
136
141
 
137
142
  def migration_command(deploy_options)
@@ -44,7 +44,6 @@ module EY
44
44
  invoke rollback
45
45
  end
46
46
 
47
-
48
47
  def put_up_maintenance_page(app, verbose=false)
49
48
  invoke adapter(app, verbose).enable_maintenance_page
50
49
  end
@@ -57,6 +56,10 @@ module EY
57
56
  !["db_master", "db_slave"].include?(role.to_s)
58
57
  end
59
58
 
59
+ def hostname_url
60
+ "http://#{hostname}" if hostname
61
+ end
62
+
60
63
  protected
61
64
 
62
65
  def engineyard_serverside_hostname
@@ -1,3 +1,3 @@
1
1
  module EY
2
- VERSION = '1.3.22'
2
+ VERSION = '1.3.25'
3
3
  end
@@ -4,6 +4,7 @@ describe EY::Repo do
4
4
  before(:all) do
5
5
  FakeFS.deactivate!
6
6
  @path = Pathname.new("/tmp/ey-test/.git/")
7
+ @path.mkpath
7
8
  @r = EY::Repo.new("/tmp/ey-test")
8
9
  end
9
10
  after(:all) { FakeFS.activate! }
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: engineyard
3
3
  version: !ruby/object:Gem::Version
4
- hash: 55
4
+ hash: 41
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 3
9
- - 22
10
- version: 1.3.22
9
+ - 25
10
+ version: 1.3.25
11
11
  platform: ruby
12
12
  authors:
13
13
  - EY Cloud Team
@@ -15,11 +15,11 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-09 00:00:00 -07:00
18
+ date: 2011-09-12 00:00:00 -07:00
19
19
  default_executable: ey
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- version_requirements: &id001 !ruby/object:Gem::Requirement
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
23
  none: false
24
24
  requirements:
25
25
  - - ~>
@@ -30,12 +30,12 @@ dependencies:
30
30
  - 14
31
31
  - 6
32
32
  version: 0.14.6
33
- type: :runtime
34
- requirement: *id001
35
33
  name: thor
36
34
  prerelease: false
35
+ type: :runtime
36
+ version_requirements: *id001
37
37
  - !ruby/object:Gem::Dependency
38
- version_requirements: &id002 !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -46,12 +46,12 @@ dependencies:
46
46
  - 6
47
47
  - 0
48
48
  version: 1.6.0
49
- type: :runtime
50
- requirement: *id002
51
49
  name: rest-client
52
50
  prerelease: false
51
+ type: :runtime
52
+ version_requirements: *id002
53
53
  - !ruby/object:Gem::Dependency
54
- version_requirements: &id003 !ruby/object:Gem::Requirement
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
55
  none: false
56
56
  requirements:
57
57
  - - ~>
@@ -62,12 +62,12 @@ dependencies:
62
62
  - 6
63
63
  - 1
64
64
  version: 1.6.1
65
- type: :runtime
66
- requirement: *id003
67
65
  name: highline
68
66
  prerelease: false
67
+ type: :runtime
68
+ version_requirements: *id003
69
69
  - !ruby/object:Gem::Dependency
70
- version_requirements: &id004 !ruby/object:Gem::Requirement
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
71
  none: false
72
72
  requirements:
73
73
  - - ">="
@@ -76,12 +76,12 @@ dependencies:
76
76
  segments:
77
77
  - 0
78
78
  version: "0"
79
- type: :runtime
80
- requirement: *id004
81
79
  name: json_pure
82
80
  prerelease: false
81
+ type: :runtime
82
+ version_requirements: *id004
83
83
  - !ruby/object:Gem::Dependency
84
- version_requirements: &id005 !ruby/object:Gem::Requirement
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
85
  none: false
86
86
  requirements:
87
87
  - - ~>
@@ -92,28 +92,28 @@ dependencies:
92
92
  - 0
93
93
  - 4
94
94
  version: 0.0.4
95
- type: :runtime
96
- requirement: *id005
97
95
  name: escape
98
96
  prerelease: false
97
+ type: :runtime
98
+ version_requirements: *id005
99
99
  - !ruby/object:Gem::Dependency
100
- version_requirements: &id006 !ruby/object:Gem::Requirement
100
+ requirement: &id006 !ruby/object:Gem::Requirement
101
101
  none: false
102
102
  requirements:
103
103
  - - "="
104
104
  - !ruby/object:Gem::Version
105
- hash: 3
105
+ hash: 5
106
106
  segments:
107
107
  - 1
108
108
  - 4
109
- - 2
110
- version: 1.4.2
111
- type: :runtime
112
- requirement: *id006
109
+ - 1
110
+ version: 1.4.1
113
111
  name: engineyard-serverside-adapter
114
112
  prerelease: false
113
+ type: :runtime
114
+ version_requirements: *id006
115
115
  - !ruby/object:Gem::Dependency
116
- version_requirements: &id007 !ruby/object:Gem::Requirement
116
+ requirement: &id007 !ruby/object:Gem::Requirement
117
117
  none: false
118
118
  requirements:
119
119
  - - ~>
@@ -124,12 +124,28 @@ dependencies:
124
124
  - 1
125
125
  - 0
126
126
  version: 2.1.0
127
- type: :runtime
128
- requirement: *id007
129
127
  name: net-ssh
130
128
  prerelease: false
129
+ type: :runtime
130
+ version_requirements: *id007
131
131
  - !ruby/object:Gem::Dependency
132
- version_requirements: &id008 !ruby/object:Gem::Requirement
132
+ requirement: &id008 !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - "="
136
+ - !ruby/object:Gem::Version
137
+ hash: 5
138
+ segments:
139
+ - 2
140
+ - 0
141
+ - 5
142
+ version: 2.0.5
143
+ name: launchy
144
+ prerelease: false
145
+ type: :runtime
146
+ version_requirements: *id008
147
+ - !ruby/object:Gem::Dependency
148
+ requirement: &id009 !ruby/object:Gem::Requirement
133
149
  none: false
134
150
  requirements:
135
151
  - - "="
@@ -140,12 +156,12 @@ dependencies:
140
156
  - 3
141
157
  - 0
142
158
  version: 1.3.0
143
- type: :development
144
- requirement: *id008
145
159
  name: rspec
146
160
  prerelease: false
161
+ type: :development
162
+ version_requirements: *id009
147
163
  - !ruby/object:Gem::Dependency
148
- version_requirements: &id009 !ruby/object:Gem::Requirement
164
+ requirement: &id010 !ruby/object:Gem::Requirement
149
165
  none: false
150
166
  requirements:
151
167
  - - ">="
@@ -154,12 +170,12 @@ dependencies:
154
170
  segments:
155
171
  - 0
156
172
  version: "0"
157
- type: :development
158
- requirement: *id009
159
173
  name: rake
160
174
  prerelease: false
175
+ type: :development
176
+ version_requirements: *id010
161
177
  - !ruby/object:Gem::Dependency
162
- version_requirements: &id010 !ruby/object:Gem::Requirement
178
+ requirement: &id011 !ruby/object:Gem::Requirement
163
179
  none: false
164
180
  requirements:
165
181
  - - ">="
@@ -168,12 +184,12 @@ dependencies:
168
184
  segments:
169
185
  - 0
170
186
  version: "0"
171
- type: :development
172
- requirement: *id010
173
187
  name: fakeweb
174
188
  prerelease: false
189
+ type: :development
190
+ version_requirements: *id011
175
191
  - !ruby/object:Gem::Dependency
176
- version_requirements: &id011 !ruby/object:Gem::Requirement
192
+ requirement: &id012 !ruby/object:Gem::Requirement
177
193
  none: false
178
194
  requirements:
179
195
  - - ">="
@@ -182,12 +198,12 @@ dependencies:
182
198
  segments:
183
199
  - 0
184
200
  version: "0"
185
- type: :development
186
- requirement: *id011
187
201
  name: fakeweb-matcher
188
202
  prerelease: false
203
+ type: :development
204
+ version_requirements: *id012
189
205
  - !ruby/object:Gem::Dependency
190
- version_requirements: &id012 !ruby/object:Gem::Requirement
206
+ requirement: &id013 !ruby/object:Gem::Requirement
191
207
  none: false
192
208
  requirements:
193
209
  - - ">="
@@ -196,12 +212,12 @@ dependencies:
196
212
  segments:
197
213
  - 0
198
214
  version: "0"
199
- type: :development
200
- requirement: *id012
201
215
  name: fakefs
202
216
  prerelease: false
217
+ type: :development
218
+ version_requirements: *id013
203
219
  - !ruby/object:Gem::Dependency
204
- version_requirements: &id013 !ruby/object:Gem::Requirement
220
+ requirement: &id014 !ruby/object:Gem::Requirement
205
221
  none: false
206
222
  requirements:
207
223
  - - ">="
@@ -210,12 +226,12 @@ dependencies:
210
226
  segments:
211
227
  - 0
212
228
  version: "0"
213
- type: :development
214
- requirement: *id013
215
229
  name: sinatra
216
230
  prerelease: false
231
+ type: :development
232
+ version_requirements: *id014
217
233
  - !ruby/object:Gem::Dependency
218
- version_requirements: &id014 !ruby/object:Gem::Requirement
234
+ requirement: &id015 !ruby/object:Gem::Requirement
219
235
  none: false
220
236
  requirements:
221
237
  - - ~>
@@ -226,12 +242,12 @@ dependencies:
226
242
  - 1
227
243
  - 6
228
244
  version: 0.1.6
229
- type: :development
230
- requirement: *id014
231
245
  name: realweb
232
246
  prerelease: false
247
+ type: :development
248
+ version_requirements: *id015
233
249
  - !ruby/object:Gem::Dependency
234
- version_requirements: &id015 !ruby/object:Gem::Requirement
250
+ requirement: &id016 !ruby/object:Gem::Requirement
235
251
  none: false
236
252
  requirements:
237
253
  - - ~>
@@ -242,10 +258,10 @@ dependencies:
242
258
  - 0
243
259
  - 1
244
260
  version: 1.0.1
245
- type: :development
246
- requirement: *id015
247
261
  name: open4
248
262
  prerelease: false
263
+ type: :development
264
+ version_requirements: *id016
249
265
  description: This gem allows you to deploy your rails application to the Engine Yard cloud directly from the command line.
250
266
  email: cloud@engineyard.com
251
267
  executables:
@@ -282,6 +298,7 @@ files:
282
298
  - lib/engineyard/ruby_ext.rb
283
299
  - lib/engineyard/thor.rb
284
300
  - lib/engineyard/version.rb
301
+ - lib/engineyard-api-client.rb
285
302
  - lib/engineyard.rb
286
303
  - LICENSE
287
304
  - README.rdoc
@@ -361,7 +378,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
361
378
  requirements: []
362
379
 
363
380
  rubyforge_project:
364
- rubygems_version: 1.4.2
381
+ rubygems_version: 1.5.0
365
382
  signing_key:
366
383
  specification_version: 3
367
384
  summary: Command-line deployment for the Engine Yard cloud