engineyard-cloud-client 1.0.3 → 1.0.4
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/lib/engineyard-cloud-client.rb +14 -93
- data/lib/engineyard-cloud-client/connection.rb +142 -0
- data/lib/engineyard-cloud-client/models/account.rb +1 -1
- data/lib/engineyard-cloud-client/models/app.rb +2 -2
- data/lib/engineyard-cloud-client/models/app_environment.rb +4 -4
- data/lib/engineyard-cloud-client/models/deployment.rb +6 -6
- data/lib/engineyard-cloud-client/models/environment.rb +13 -11
- data/lib/engineyard-cloud-client/models/keypair.rb +3 -3
- data/lib/engineyard-cloud-client/models/recipes.rb +3 -6
- data/lib/engineyard-cloud-client/test.rb +3 -3
- data/lib/engineyard-cloud-client/test/fake_awsm/config.ru +4 -3
- data/lib/engineyard-cloud-client/test/fake_awsm/views/base_app_environment.rabl +1 -1
- data/lib/engineyard-cloud-client/test/fake_awsm/views/base_environment.rabl +1 -1
- data/lib/engineyard-cloud-client/test/fake_awsm/views/environments.rabl +1 -1
- data/lib/engineyard-cloud-client/test/scenario.rb +2 -3
- data/lib/engineyard-cloud-client/version.rb +1 -1
- data/spec/engineyard-cloud-client/api_spec.rb +15 -33
- data/spec/engineyard-cloud-client/integration/account_spec.rb +0 -1
- data/spec/engineyard-cloud-client/integration/app_environment_spec.rb +0 -1
- data/spec/engineyard-cloud-client/integration/app_spec.rb +0 -1
- data/spec/engineyard-cloud-client/integration/deployment_spec.rb +1 -2
- data/spec/engineyard-cloud-client/integration/environment_spec.rb +0 -1
- data/spec/engineyard-cloud-client/integration/user_spec.rb +6 -9
- data/spec/spec_helper.rb +0 -3
- data/spec/support/helpers.rb +2 -6
- metadata +9 -9
- data/lib/engineyard-cloud-client/test/ui.rb +0 -33
@@ -3,6 +3,7 @@ module EY
|
|
3
3
|
end
|
4
4
|
end
|
5
5
|
|
6
|
+
require 'engineyard-cloud-client/connection'
|
6
7
|
require 'engineyard-cloud-client/model_registry'
|
7
8
|
require 'engineyard-cloud-client/models'
|
8
9
|
require 'engineyard-cloud-client/rest_client_ext'
|
@@ -11,58 +12,33 @@ require 'engineyard-cloud-client/version'
|
|
11
12
|
require 'engineyard-cloud-client/errors'
|
12
13
|
require 'multi_json'
|
13
14
|
require 'pp'
|
15
|
+
require 'forwardable'
|
14
16
|
|
15
17
|
module EY
|
16
18
|
class CloudClient
|
17
|
-
|
18
|
-
attr_accessor :ui
|
19
|
+
extend Forwardable
|
19
20
|
|
20
|
-
|
21
|
+
def_delegators :connection, :head, :get, :post, :put, :delete, :request, :endpoint, :token, :token=, :authenticate!, :authenticated?
|
21
22
|
|
22
|
-
|
23
|
-
@endpoint
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.endpoint=(endpoint)
|
27
|
-
@endpoint = URI.parse(endpoint)
|
28
|
-
unless @endpoint.absolute?
|
29
|
-
raise BadEndpointError.new(endpoint)
|
30
|
-
end
|
31
|
-
@endpoint
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.default_endpoint!
|
35
|
-
self.endpoint = "https://cloud.engineyard.com/"
|
36
|
-
end
|
37
|
-
default_endpoint!
|
23
|
+
attr_reader :connection
|
38
24
|
|
39
|
-
|
40
|
-
|
41
|
-
|
25
|
+
# Initialize a new EY::CloudClient.
|
26
|
+
#
|
27
|
+
# Creates and stores a new Connection for communicating with EY Cloud.
|
28
|
+
#
|
29
|
+
# See EY::CloudClient::Connection for options.
|
30
|
+
def initialize(options={})
|
31
|
+
@connection = Connection.new(options)
|
42
32
|
end
|
43
33
|
|
44
34
|
def ==(other)
|
45
|
-
other.is_a?(self.class) && other.
|
35
|
+
other.is_a?(self.class) && other.connection == connection
|
46
36
|
end
|
47
37
|
|
48
38
|
def registry
|
49
39
|
@registry ||= ModelRegistry.new
|
50
40
|
end
|
51
41
|
|
52
|
-
def token=(new_token)
|
53
|
-
unless new_token
|
54
|
-
raise ArgumentError, "EY Cloud API token required"
|
55
|
-
end
|
56
|
-
@token = new_token
|
57
|
-
end
|
58
|
-
|
59
|
-
def request(url, opts={})
|
60
|
-
opts[:headers] ||= {}
|
61
|
-
opts[:headers]["X-EY-Cloud-Token"] = token
|
62
|
-
ui.debug("Token", token)
|
63
|
-
self.class.request(url, ui, opts)
|
64
|
-
end
|
65
|
-
|
66
42
|
def resolve_environments(constraints)
|
67
43
|
EY::CloudClient::Environment.resolve(self, constraints)
|
68
44
|
end
|
@@ -86,62 +62,7 @@ module EY
|
|
86
62
|
end
|
87
63
|
|
88
64
|
def current_user
|
89
|
-
EY::CloudClient::User.from_hash(self,
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.request(path, ui, opts={})
|
93
|
-
url = self.endpoint + "api/v2#{path}"
|
94
|
-
method = (opts.delete(:method) || 'get').to_s.downcase.to_sym
|
95
|
-
params = opts.delete(:params) || {}
|
96
|
-
headers = opts.delete(:headers) || {}
|
97
|
-
headers["Accept"] ||= "application/json"
|
98
|
-
headers["User-Agent"] = USER_AGENT_STRING
|
99
|
-
|
100
|
-
begin
|
101
|
-
ui.debug("Request", "#{method.to_s.upcase} #{url}")
|
102
|
-
ui.debug("Params", params.inspect)
|
103
|
-
case method
|
104
|
-
when :get, :delete, :head
|
105
|
-
unless params.empty?
|
106
|
-
url.query = RestClient::Payload::UrlEncoded.new(params).to_s
|
107
|
-
end
|
108
|
-
resp = RestClient.send(method, url.to_s, headers)
|
109
|
-
else
|
110
|
-
resp = RestClient.send(method, url.to_s, params, headers)
|
111
|
-
end
|
112
|
-
rescue RestClient::Unauthorized
|
113
|
-
raise InvalidCredentials
|
114
|
-
rescue Errno::ECONNREFUSED
|
115
|
-
raise RequestFailed, "Could not reach the cloud API"
|
116
|
-
rescue RestClient::ResourceNotFound
|
117
|
-
raise ResourceNotFound, "The requested resource could not be found"
|
118
|
-
rescue RestClient::BadGateway
|
119
|
-
raise RequestFailed, "EY Cloud API is temporarily unavailable. Please try again soon."
|
120
|
-
rescue RestClient::RequestFailed => e
|
121
|
-
raise RequestFailed, "#{e.message} #{e.response}"
|
122
|
-
rescue OpenSSL::SSL::SSLError
|
123
|
-
raise RequestFailed, "SSL is misconfigured on your cloud"
|
124
|
-
end
|
125
|
-
|
126
|
-
if resp.body.empty?
|
127
|
-
data = ''
|
128
|
-
elsif resp.headers[:content_type] =~ /application\/json/
|
129
|
-
begin
|
130
|
-
data = MultiJson.load(resp.body)
|
131
|
-
ui.debug("Response", "\n" + data.pretty_inspect)
|
132
|
-
rescue MultiJson::DecodeError
|
133
|
-
ui.debug("Raw response", resp.body)
|
134
|
-
raise RequestFailed, "Response was not valid JSON."
|
135
|
-
end
|
136
|
-
else
|
137
|
-
data = resp.body
|
138
|
-
end
|
139
|
-
|
140
|
-
data
|
141
|
-
end
|
142
|
-
|
143
|
-
def self.authenticate(email, password, ui)
|
144
|
-
request("/authenticate", ui, { :method => "post", :params => { :email => email, :password => password }})["api_token"]
|
65
|
+
EY::CloudClient::User.from_hash(self, get('/current_user')['user'])
|
145
66
|
end
|
146
67
|
|
147
68
|
end # API
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'engineyard-cloud-client/rest_client_ext'
|
2
|
+
require 'multi_json'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module EY
|
6
|
+
class CloudClient
|
7
|
+
class Connection
|
8
|
+
attr_reader :token, :output, :user_agent, :endpoint
|
9
|
+
|
10
|
+
BASE_USER_AGENT = "EngineYardCloudClient/#{EY::CloudClient::VERSION}".freeze
|
11
|
+
DEFAULT_ENDPOINT = "https://cloud.engineyard.com/".freeze
|
12
|
+
|
13
|
+
# Initialize a new EY::CloudClient::Connection with a hash including:
|
14
|
+
#
|
15
|
+
# :token: (optional) Perform authenticated requests with this token
|
16
|
+
# :user_agent: (optional) A user agent name/version pair to add to the User-Agent header. (e.g. EngineYardCLI/2.0.0)
|
17
|
+
# :output: (optional) Send output to a stream other than $stdout
|
18
|
+
# :endpoint: (optional) An alternate Engine Yard Cloud endpoint URI
|
19
|
+
def initialize(options={})
|
20
|
+
@output = options[:output] || $stdout
|
21
|
+
@user_agent = [options[:user_agent], BASE_USER_AGENT].compact.join(' ').strip
|
22
|
+
@endpoint = URI.parse(options[:endpoint] || DEFAULT_ENDPOINT)
|
23
|
+
self.token = options[:token]
|
24
|
+
|
25
|
+
unless @endpoint.absolute?
|
26
|
+
raise BadEndpointError.new(@endpoint)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def token=(new_token)
|
31
|
+
@token = new_token
|
32
|
+
end
|
33
|
+
|
34
|
+
def debug(name, value)
|
35
|
+
return unless ENV['DEBUG']
|
36
|
+
|
37
|
+
indent = 12 # 12 because that's what Thor used.
|
38
|
+
unless String === value
|
39
|
+
value = value.pretty_inspect.rstrip # remove trailing whitespace
|
40
|
+
if value.index("\n") # if the inspect is multi-line
|
41
|
+
value.gsub!(/[\r\n]./, "\n" + ' ' * (indent + 2)) # indent it
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@output << "#{name.to_s.rjust(indent)} #{value.rstrip}\n" # just one newline
|
45
|
+
end
|
46
|
+
|
47
|
+
def ==(other)
|
48
|
+
other.is_a?(self.class) && [other.token, other.user_agent, other.endpoint] == [token, user_agent, endpoint]
|
49
|
+
end
|
50
|
+
|
51
|
+
%w[ get head post put delete ].each do |meth|
|
52
|
+
eval <<-RUBY, binding, __FILE__, __LINE__ + 1
|
53
|
+
def #{meth}(path, params=nil, headers=nil, &block)
|
54
|
+
request("#{meth}", path, params, headers, &block)
|
55
|
+
end
|
56
|
+
RUBY
|
57
|
+
end
|
58
|
+
|
59
|
+
def request(meth, path, params=nil, extra_headers=nil)
|
60
|
+
url = endpoint + "api/v2#{path}"
|
61
|
+
meth ||= 'get'
|
62
|
+
meth = meth.to_s.downcase.to_sym
|
63
|
+
params ||= {}
|
64
|
+
|
65
|
+
headers = {
|
66
|
+
"User-Agent" => user_agent,
|
67
|
+
"Accept" => "application/json",
|
68
|
+
}
|
69
|
+
|
70
|
+
if token
|
71
|
+
headers["X-EY-Cloud-Token"] = token
|
72
|
+
end
|
73
|
+
|
74
|
+
if extra_headers
|
75
|
+
headers.merge!(extra_headers)
|
76
|
+
end
|
77
|
+
|
78
|
+
debug(meth.to_s.upcase, url.to_s)
|
79
|
+
debug("Params", params) if params
|
80
|
+
debug("Headers", headers)
|
81
|
+
|
82
|
+
resp = do_request(meth, url, params, headers)
|
83
|
+
data = parse_response(resp)
|
84
|
+
|
85
|
+
data
|
86
|
+
end
|
87
|
+
|
88
|
+
def authenticate!(email, password)
|
89
|
+
response = post("/authenticate", :email => email, :password => password)
|
90
|
+
self.token = response["api_token"]
|
91
|
+
token
|
92
|
+
end
|
93
|
+
|
94
|
+
def authenticated?
|
95
|
+
!token.nil? && !token.empty?
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def do_request(meth, url, params, headers)
|
101
|
+
case meth
|
102
|
+
when :get, :delete, :head
|
103
|
+
if params
|
104
|
+
url.query = RestClient::Payload::UrlEncoded.new(params).to_s
|
105
|
+
end
|
106
|
+
RestClient.send(meth, url.to_s, headers)
|
107
|
+
else
|
108
|
+
RestClient.send(meth, url.to_s, params, headers)
|
109
|
+
end
|
110
|
+
rescue RestClient::Unauthorized
|
111
|
+
raise InvalidCredentials
|
112
|
+
rescue Errno::ECONNREFUSED
|
113
|
+
raise RequestFailed, "Could not reach the cloud API"
|
114
|
+
rescue RestClient::ResourceNotFound
|
115
|
+
raise ResourceNotFound, "The requested resource could not be found"
|
116
|
+
rescue RestClient::BadGateway
|
117
|
+
raise RequestFailed, "EY Cloud API is temporarily unavailable. Please try again soon."
|
118
|
+
rescue RestClient::RequestFailed => e
|
119
|
+
raise RequestFailed, "#{e.message} #{e.response}"
|
120
|
+
rescue OpenSSL::SSL::SSLError
|
121
|
+
raise RequestFailed, "SSL is misconfigured on your cloud"
|
122
|
+
end
|
123
|
+
|
124
|
+
def parse_response(resp)
|
125
|
+
if resp.body.empty?
|
126
|
+
''
|
127
|
+
elsif resp.headers[:content_type] =~ /application\/json/
|
128
|
+
begin
|
129
|
+
data = MultiJson.load(resp.body)
|
130
|
+
debug("Response", data)
|
131
|
+
data
|
132
|
+
rescue MultiJson::DecodeError
|
133
|
+
debug("Response", resp.body)
|
134
|
+
raise RequestFailed, "Response was not valid JSON."
|
135
|
+
end
|
136
|
+
else
|
137
|
+
resp.body
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -9,7 +9,7 @@ module EY
|
|
9
9
|
|
10
10
|
# Return list of all Apps linked to all current user's accounts
|
11
11
|
def self.all(api)
|
12
|
-
self.from_array(api, api.
|
12
|
+
self.from_array(api, api.get("/apps", 'no_instances' => 'true')["apps"])
|
13
13
|
end
|
14
14
|
|
15
15
|
# An everything-you-need helper to create an App
|
@@ -32,7 +32,7 @@ module EY
|
|
32
32
|
raise EY::CloudClient::AttributeRequiredError.new("name") unless params["name"]
|
33
33
|
raise EY::CloudClient::AttributeRequiredError.new("repository_uri") unless params["repository_uri"]
|
34
34
|
raise EY::CloudClient::AttributeRequiredError.new("app_type_id") unless params["app_type_id"]
|
35
|
-
response = api.
|
35
|
+
response = api.post("/accounts/#{account.id}/apps", "app" => params)
|
36
36
|
from_hash(api, response['app'])
|
37
37
|
end
|
38
38
|
|
@@ -7,15 +7,15 @@ module EY
|
|
7
7
|
|
8
8
|
# Return a constrained list of app_environments given a set of constraints like:
|
9
9
|
#
|
10
|
-
# * app_name
|
11
|
-
# * account_name
|
12
|
-
# * environment_name
|
10
|
+
# * app_name: app name full or partial match string
|
11
|
+
# * account_name: account name full or partial match string
|
12
|
+
# * environment_name: environment name full or partial match string
|
13
13
|
# * remotes: An array of git remote URIs
|
14
14
|
#
|
15
15
|
def self.resolve(api, constraints)
|
16
16
|
clean_constraints = constraints.reject { |k,v| v.nil? }
|
17
17
|
params = {'constraints' => clean_constraints}
|
18
|
-
response = api.
|
18
|
+
response = api.get("/app_environments/resolve", params)['resolver']
|
19
19
|
matches = from_array(api, response['matches'])
|
20
20
|
ResolverResult.new(api, matches, response['errors'], response['suggestions'])
|
21
21
|
end
|
@@ -14,7 +14,7 @@ module EY
|
|
14
14
|
|
15
15
|
def self.get(api, app_environment, id)
|
16
16
|
uri = api_root(app_environment.app.id, app_environment.environment.id) + "/#{id}"
|
17
|
-
response = api.
|
17
|
+
response = api.get(uri)
|
18
18
|
load_from_response api, app_environment, response
|
19
19
|
rescue EY::CloudClient::ResourceNotFound
|
20
20
|
nil
|
@@ -47,16 +47,16 @@ module EY
|
|
47
47
|
alias deployed_by= user_name=
|
48
48
|
|
49
49
|
def created_at
|
50
|
-
|
50
|
+
@created_at ||= super && Time.parse(super)
|
51
51
|
end
|
52
52
|
|
53
53
|
def finished_at
|
54
|
-
|
54
|
+
@finished_at ||= super && Time.parse(super)
|
55
55
|
end
|
56
56
|
|
57
57
|
def config
|
58
58
|
return {} unless deployed_by # not started yet so not all info is here
|
59
|
-
@config ||= {'deployed_by' => deployed_by}.merge(extra_config)
|
59
|
+
@config ||= {'input_ref' => ref, 'deployed_by' => deployed_by}.merge(extra_config)
|
60
60
|
end
|
61
61
|
|
62
62
|
def start
|
@@ -95,11 +95,11 @@ module EY
|
|
95
95
|
private
|
96
96
|
|
97
97
|
def post_to_api(params)
|
98
|
-
update_with_response api.
|
98
|
+
update_with_response api.post(collection_uri, 'deployment' => params)
|
99
99
|
end
|
100
100
|
|
101
101
|
def put_to_api(params)
|
102
|
-
update_with_response api.
|
102
|
+
update_with_response api.put(member_uri("/finished"), 'deployment' => params)
|
103
103
|
end
|
104
104
|
|
105
105
|
def collection_uri
|
@@ -4,27 +4,29 @@ require 'engineyard-cloud-client/errors'
|
|
4
4
|
|
5
5
|
module EY
|
6
6
|
class CloudClient
|
7
|
-
class Environment < ApiStruct.new(:id, :name, :framework_env,
|
7
|
+
class Environment < ApiStruct.new(:id, :name, :framework_env,
|
8
|
+
:instances_count,
|
9
|
+
:instance_status,
|
8
10
|
:username, :app_server_stack_name,
|
9
11
|
:load_balancer_ip_address
|
10
12
|
)
|
11
13
|
|
12
14
|
# Return list of all Environments linked to all current user's accounts
|
13
15
|
def self.all(api)
|
14
|
-
self.from_array(api, api.
|
16
|
+
self.from_array(api, api.get("/environments", "no_instances" => "true")["environments"])
|
15
17
|
end
|
16
18
|
|
17
19
|
# Return a constrained list of environments given a set of constraints like:
|
18
20
|
#
|
19
|
-
# * app_name
|
20
|
-
# * account_name
|
21
|
-
# * environment_name
|
21
|
+
# * app_name: app name full or partial match string
|
22
|
+
# * account_name: account name full or partial match string
|
23
|
+
# * environment_name: environment name full or partial match string
|
22
24
|
# * remotes: An array of git remote URIs
|
23
25
|
#
|
24
26
|
def self.resolve(api, constraints)
|
25
27
|
clean_constraints = constraints.reject { |k,v| v.nil? }
|
26
28
|
params = {'constraints' => clean_constraints}
|
27
|
-
response = api.
|
29
|
+
response = api.get("/environments/resolve", params)['resolver']
|
28
30
|
matches = from_array(api, response['matches'])
|
29
31
|
ResolverResult.new(api, matches, response['errors'], response['suggestions'])
|
30
32
|
end
|
@@ -52,7 +54,7 @@ module EY
|
|
52
54
|
|
53
55
|
params = {"environment" => attrs.dup}
|
54
56
|
unpack_cluster_configuration(params, cluster_configuration)
|
55
|
-
response = api.
|
57
|
+
response = api.post("/apps/#{app.id}/environments", params)
|
56
58
|
self.from_hash(api, response['environment'])
|
57
59
|
end
|
58
60
|
attr_accessor :apps, :account
|
@@ -99,7 +101,7 @@ module EY
|
|
99
101
|
end
|
100
102
|
|
101
103
|
def logs
|
102
|
-
Log.from_array(api, api.
|
104
|
+
Log.from_array(api, api.get("/environments/#{id}/logs")["logs"])
|
103
105
|
end
|
104
106
|
|
105
107
|
def deploy_to_instances
|
@@ -114,13 +116,13 @@ module EY
|
|
114
116
|
if bridge.nil?
|
115
117
|
raise NoBridgeError.new(name)
|
116
118
|
elsif !ignore_bad_bridge && bridge.status != "running"
|
117
|
-
raise BadBridgeStatusError.new(bridge.status,
|
119
|
+
raise BadBridgeStatusError.new(bridge.status, api.endpoint)
|
118
120
|
end
|
119
121
|
bridge
|
120
122
|
end
|
121
123
|
|
122
124
|
def update
|
123
|
-
api.
|
125
|
+
api.put("/environments/#{id}/update_instances")
|
124
126
|
true # raises on failure
|
125
127
|
end
|
126
128
|
alias rebuild update
|
@@ -178,7 +180,7 @@ module EY
|
|
178
180
|
if instances_count.zero?
|
179
181
|
[]
|
180
182
|
else
|
181
|
-
instances_attrs = api.
|
183
|
+
instances_attrs = api.get("/environments/#{id}/instances")["instances"]
|
182
184
|
load_instances(instances_attrs)
|
183
185
|
end
|
184
186
|
end
|
@@ -5,7 +5,7 @@ module EY
|
|
5
5
|
class Keypair < ApiStruct.new(:id, :name, :public_key)
|
6
6
|
|
7
7
|
def self.all(api)
|
8
|
-
self.from_array(api, api.
|
8
|
+
self.from_array(api, api.get("/keypairs")["keypairs"])
|
9
9
|
end
|
10
10
|
|
11
11
|
# Create a Keypair with your SSH public key so that you can access your Instances
|
@@ -24,8 +24,8 @@ module EY
|
|
24
24
|
params = attrs.dup # no default fields
|
25
25
|
raise EY::CloudClient::AttributeRequiredError.new("name") unless params["name"]
|
26
26
|
raise EY::CloudClient::AttributeRequiredError.new("public_key") unless params["public_key"]
|
27
|
-
response = api.
|
28
|
-
self.from_hash(api, response
|
27
|
+
response = api.post("/keypairs", "keypair" => params)['keypair']
|
28
|
+
self.from_hash(api, response)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -12,13 +12,13 @@ module EY
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def run
|
15
|
-
api.
|
15
|
+
api.put("/environments/#{environment.id}/run_custom_recipes")
|
16
16
|
true
|
17
17
|
end
|
18
18
|
|
19
19
|
def download
|
20
20
|
tmp = Tempfile.new("recipes")
|
21
|
-
data = api.
|
21
|
+
data = api.get("/environments/#{environment.id}/recipes")
|
22
22
|
tmp.write(data)
|
23
23
|
tmp.flush
|
24
24
|
tmp.close
|
@@ -37,10 +37,7 @@ module EY
|
|
37
37
|
# Expects a File object opened for binary reading.
|
38
38
|
# i.e. upload(File.open(recipes_path, 'rb'))
|
39
39
|
def upload(file_to_upload)
|
40
|
-
api.
|
41
|
-
:method => :post,
|
42
|
-
:params => {:file => file_to_upload}
|
43
|
-
})
|
40
|
+
api.post("/environments/#{environment.id}/recipes", :file => file_to_upload)
|
44
41
|
true
|
45
42
|
end
|
46
43
|
|
@@ -15,11 +15,12 @@ rescue LoadError
|
|
15
15
|
engineyard-cloud-client needs the following gems to run in test mode:
|
16
16
|
|
17
17
|
group 'engineyard-cloud-client-test' do
|
18
|
-
gem 'dm-core'
|
18
|
+
gem 'dm-core', '~>1.2.0'
|
19
19
|
gem 'dm-migrations'
|
20
20
|
gem 'dm-aggregates'
|
21
|
+
gem 'dm-timestamps'
|
21
22
|
gem 'dm-sqlite-adapter'
|
22
|
-
gem 'ey_resolver',
|
23
|
+
gem 'ey_resolver', '~>0.2.1'
|
23
24
|
gem 'rabl'
|
24
25
|
end
|
25
26
|
|
@@ -27,5 +28,4 @@ Please add the above to your Gemfile.
|
|
27
28
|
ERROR
|
28
29
|
end
|
29
30
|
|
30
|
-
require 'engineyard-cloud-client/test/ui'
|
31
31
|
require 'engineyard-cloud-client/test/scenario'
|
@@ -36,9 +36,10 @@ class FakeAwsm < Sinatra::Base
|
|
36
36
|
before do
|
37
37
|
if env['PATH_INFO'] =~ %r#/api/v2#
|
38
38
|
user_agent = env['HTTP_USER_AGENT']
|
39
|
-
unless user_agent =~ %r
|
40
|
-
|
41
|
-
|
39
|
+
unless user_agent =~ %r#EngineYardCloudClient/\d#
|
40
|
+
msg = "No user agent header, expected EngineYardCloudClient/ got #{user_agent.inspect}"
|
41
|
+
$stderr.puts msg
|
42
|
+
halt 400, msg
|
42
43
|
end
|
43
44
|
end
|
44
45
|
content_type "application/json"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
attributes :id, :domain_name, :uri
|
2
2
|
child :environment do
|
3
|
-
attributes :id, :ssh_username, :name, :instances_count, :app_server_stack_name, :load_balancer_ip_address, :framework_env
|
3
|
+
attributes :id, :ssh_username, :name, :instances_count, :instance_status, :app_server_stack_name, :load_balancer_ip_address, :framework_env
|
4
4
|
child :account do
|
5
5
|
attributes :id, :name
|
6
6
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
attributes :id, :ssh_username, :name, :instances_count, :app_server_stack_name, :load_balancer_ip_address, :framework_env
|
1
|
+
attributes :id, :ssh_username, :name, :instances_count, :instance_status, :app_server_stack_name, :load_balancer_ip_address, :framework_env
|
2
2
|
child :account do
|
3
3
|
attributes :id, :name
|
4
4
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
collection @environments, :root => :environments, :object_root => false
|
2
|
-
attributes :id, :ssh_username, :name, :instances_count, :app_server_stack_name, :load_balancer_ip_address, :framework_env
|
2
|
+
attributes :id, :ssh_username, :name, :instances_count, :instance_status, :app_server_stack_name, :load_balancer_ip_address, :framework_env
|
3
3
|
child :account do
|
4
4
|
attributes :id, :name
|
5
5
|
end
|
@@ -2,7 +2,6 @@ require 'multi_json'
|
|
2
2
|
require 'engineyard-cloud-client/rest_client_ext'
|
3
3
|
require 'engineyard-cloud-client/test'
|
4
4
|
require 'engineyard-cloud-client/test/fake_awsm'
|
5
|
-
require 'engineyard-cloud-client/test/ui'
|
6
5
|
|
7
6
|
module EY::CloudClient::Test
|
8
7
|
class Scenario
|
@@ -32,8 +31,8 @@ module EY::CloudClient::Test
|
|
32
31
|
@api_token = options['api_token']
|
33
32
|
end
|
34
33
|
|
35
|
-
def cloud_client
|
36
|
-
EY::CloudClient.new(@api_token
|
34
|
+
def cloud_client
|
35
|
+
EY::CloudClient.new(:endpoint => EY::CloudClient::Test::FakeAwsm.uri, :token => @api_token)
|
37
36
|
end
|
38
37
|
|
39
38
|
def inspect
|
@@ -2,50 +2,32 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe EY::CloudClient do
|
4
4
|
it "holds an api token" do
|
5
|
-
EY::CloudClient.new('asdf'
|
5
|
+
EY::CloudClient.new(:token => 'asdf').connection.token.should == "asdf"
|
6
6
|
end
|
7
7
|
|
8
|
-
it "
|
9
|
-
|
8
|
+
it "uses production EY Cloud by default" do
|
9
|
+
FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :body => %|{"api_token": "cloudtoken"}|, :content_type => 'application/json')
|
10
|
+
client = EY::CloudClient.new
|
11
|
+
client.authenticate!("a@b.com", "foo")
|
12
|
+
client.connection.token.should == "cloudtoken"
|
10
13
|
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
it "defaults to production EY Cloud" do
|
18
|
-
EY::CloudClient.endpoint.should == URI.parse('https://cloud.engineyard.com')
|
19
|
-
end
|
20
|
-
|
21
|
-
it "accepts a valid endpoint" do
|
22
|
-
EY::CloudClient.endpoint = "http://fake.local/"
|
23
|
-
EY::CloudClient.endpoint.should == URI.parse('http://fake.local')
|
24
|
-
end
|
25
|
-
|
26
|
-
it "uses the endpoint to make requests" do
|
27
|
-
FakeWeb.register_uri(:post, "http://fake.local/api/v2/authenticate", :body => %|{"api_token": "fake.localtoken"}|, :content_type => 'application/json')
|
28
|
-
|
29
|
-
EY::CloudClient.endpoint = "http://fake.local/"
|
30
|
-
EY::CloudClient.authenticate("a@b.com", "foo", test_ui).should == "fake.localtoken"
|
31
|
-
end
|
32
|
-
|
33
|
-
it "raises on an invalid endpoint" do
|
34
|
-
lambda { EY::CloudClient.endpoint = "non/absolute" }.should raise_error(EY::CloudClient::BadEndpointError)
|
35
|
-
end
|
15
|
+
it "uses a custom endpoint to make requests" do
|
16
|
+
FakeWeb.register_uri(:post, "http://fake.local/api/v2/authenticate", :body => %|{"api_token": "fake.localtoken"}|, :content_type => 'application/json')
|
17
|
+
client = EY::CloudClient.new(:endpoint => "http://fake.local/")
|
18
|
+
client.authenticate!("a@b.com", "foo")
|
19
|
+
client.connection.token.should == "fake.localtoken"
|
36
20
|
end
|
37
21
|
|
38
|
-
it "
|
39
|
-
|
40
|
-
|
41
|
-
EY::CloudClient.authenticate("a@b.com", "foo", test_ui).should == "asdf"
|
22
|
+
it "raises on an invalid endpoint" do
|
23
|
+
lambda { EY::CloudClient.new(:endpoint => "non/absolute") }.should raise_error(EY::CloudClient::BadEndpointError)
|
42
24
|
end
|
43
25
|
|
44
26
|
it "raises InvalidCredentials when the credentials are invalid" do
|
45
27
|
FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :status => 401, :content_type => 'application/json')
|
46
28
|
|
47
29
|
lambda {
|
48
|
-
EY::CloudClient.authenticate("a@b.com", "foo"
|
30
|
+
EY::CloudClient.new.authenticate!("a@b.com", "foo")
|
49
31
|
}.should raise_error(EY::CloudClient::InvalidCredentials)
|
50
32
|
end
|
51
33
|
|
@@ -53,7 +35,7 @@ describe EY::CloudClient do
|
|
53
35
|
FakeWeb.register_uri(:post, "https://cloud.engineyard.com/api/v2/authenticate", :status => 502, :content_type => 'text/html')
|
54
36
|
|
55
37
|
lambda {
|
56
|
-
EY::CloudClient.authenticate("a@b.com", "foo"
|
38
|
+
EY::CloudClient.new.authenticate!("a@b.com", "foo")
|
57
39
|
}.should raise_error(EY::CloudClient::RequestFailed, /API is temporarily unavailable/)
|
58
40
|
end
|
59
41
|
end
|
@@ -3,7 +3,6 @@ require 'spec_helper'
|
|
3
3
|
describe EY::CloudClient::AppEnvironment do
|
4
4
|
before(:each) do
|
5
5
|
FakeWeb.allow_net_connect = true
|
6
|
-
EY::CloudClient.endpoint = EY::CloudClient::Test::FakeAwsm.uri
|
7
6
|
end
|
8
7
|
|
9
8
|
describe "deploying" do
|
@@ -31,7 +30,7 @@ describe EY::CloudClient::AppEnvironment do
|
|
31
30
|
|
32
31
|
deployment.created_at.should_not be_nil
|
33
32
|
deployment.finished_at.should be_nil
|
34
|
-
deployment.config.should == {'deployed_by' => 'Multiple Ambiguous Accounts', 'extra' => 'config'}
|
33
|
+
deployment.config.should == {'input_ref' => 'master', 'deployed_by' => 'Multiple Ambiguous Accounts', 'extra' => 'config'}
|
35
34
|
deployment.commit.should =~ /[0-9a-f]{40}/
|
36
35
|
deployment.resolved_ref.should_not be_nil
|
37
36
|
deployment.out << "Test output"
|
@@ -3,16 +3,13 @@ require 'spec_helper'
|
|
3
3
|
describe EY::CloudClient::User do
|
4
4
|
before do
|
5
5
|
FakeWeb.allow_net_connect = true
|
6
|
-
EY::CloudClient.endpoint = EY::CloudClient::Test::FakeAwsm.uri
|
7
6
|
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
user.accounts.first.name.should == 'main'
|
16
|
-
end
|
8
|
+
it "loads current user and returns all accounts" do
|
9
|
+
api = scenario_cloud_client "User Name"
|
10
|
+
user = api.current_user
|
11
|
+
user.name.should == 'User Name'
|
12
|
+
user.accounts.size.should == 1
|
13
|
+
user.accounts.first.name.should == 'main'
|
17
14
|
end
|
18
15
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/helpers.rb
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
require 'rest_client'
|
2
2
|
|
3
3
|
module SpecHelpers
|
4
|
-
def
|
5
|
-
@
|
6
|
-
end
|
7
|
-
|
8
|
-
def cloud_client(token = 'asdf', ui = test_ui)
|
9
|
-
@cloud_client ||= EY::CloudClient.new(token, ui)
|
4
|
+
def cloud_client(token = 'asdf')
|
5
|
+
@cloud_client ||= EY::CloudClient.new(:token => token)
|
10
6
|
end
|
11
7
|
|
12
8
|
def scenario_cloud_client(scenario)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: engineyard-cloud-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
@@ -160,17 +160,17 @@ dependencies:
|
|
160
160
|
requirement: !ruby/object:Gem::Requirement
|
161
161
|
none: false
|
162
162
|
requirements:
|
163
|
-
- -
|
163
|
+
- - ~>
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version:
|
165
|
+
version: 1.2.0
|
166
166
|
type: :development
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
none: false
|
170
170
|
requirements:
|
171
|
-
- -
|
171
|
+
- - ~>
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version:
|
173
|
+
version: 1.2.0
|
174
174
|
- !ruby/object:Gem::Dependency
|
175
175
|
name: dm-migrations
|
176
176
|
requirement: !ruby/object:Gem::Requirement
|
@@ -273,6 +273,7 @@ executables: []
|
|
273
273
|
extensions: []
|
274
274
|
extra_rdoc_files: []
|
275
275
|
files:
|
276
|
+
- lib/engineyard-cloud-client/connection.rb
|
276
277
|
- lib/engineyard-cloud-client/errors.rb
|
277
278
|
- lib/engineyard-cloud-client/model_registry.rb
|
278
279
|
- lib/engineyard-cloud-client/models/account.rb
|
@@ -312,7 +313,6 @@ files:
|
|
312
313
|
- lib/engineyard-cloud-client/test/fake_awsm/views/user.rabl
|
313
314
|
- lib/engineyard-cloud-client/test/fake_awsm.rb
|
314
315
|
- lib/engineyard-cloud-client/test/scenario.rb
|
315
|
-
- lib/engineyard-cloud-client/test/ui.rb
|
316
316
|
- lib/engineyard-cloud-client/test.rb
|
317
317
|
- lib/engineyard-cloud-client/version.rb
|
318
318
|
- lib/engineyard-cloud-client.rb
|
@@ -348,7 +348,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
348
348
|
version: '0'
|
349
349
|
segments:
|
350
350
|
- 0
|
351
|
-
hash:
|
351
|
+
hash: 2753056383473924638
|
352
352
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
353
353
|
none: false
|
354
354
|
requirements:
|
@@ -357,7 +357,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
357
357
|
version: '0'
|
358
358
|
segments:
|
359
359
|
- 0
|
360
|
-
hash:
|
360
|
+
hash: 2753056383473924638
|
361
361
|
requirements: []
|
362
362
|
rubyforge_project:
|
363
363
|
rubygems_version: 1.8.24
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'engineyard-cloud-client/test'
|
2
|
-
|
3
|
-
module EY::CloudClient::Test
|
4
|
-
class QuietUI
|
5
|
-
def info(*)
|
6
|
-
end
|
7
|
-
|
8
|
-
def debug(*)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class VerboseUI
|
13
|
-
def info(name, message = nil)
|
14
|
-
say name, message
|
15
|
-
end
|
16
|
-
|
17
|
-
def debug(name, message = nil)
|
18
|
-
name = name.inspect unless name.nil? or name.is_a?(String)
|
19
|
-
message = message.inspect unless message.nil? or message.is_a?(String)
|
20
|
-
say name, message
|
21
|
-
end
|
22
|
-
|
23
|
-
def say(status, message = nil)
|
24
|
-
if message
|
25
|
-
$stdout.puts "#{status.to_s.rjust(12)} #{message}"
|
26
|
-
else
|
27
|
-
$stdout.puts status
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
UI = ENV['DEBUG'] ? VerboseUI : QuietUI
|
33
|
-
end
|