engineyard 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/engineyard.rb +2 -2
- data/lib/engineyard/api.rb +19 -0
- data/lib/engineyard/cli.rb +24 -12
- data/lib/engineyard/cli/action/deploy.rb +112 -0
- data/lib/engineyard/cli/api.rb +14 -1
- data/lib/engineyard/error.rb +27 -0
- data/lib/engineyard/model.rb +9 -0
- data/lib/engineyard/{account → model}/api_struct.rb +8 -3
- data/lib/engineyard/{account → model}/app.rb +3 -3
- data/lib/engineyard/{account → model}/environment.rb +14 -7
- data/lib/engineyard/model/instance.rb +91 -0
- data/lib/engineyard/{account → model}/log.rb +1 -1
- data/lib/engineyard/repo.rb +3 -3
- data/spec/engineyard/{account → model}/api_struct_spec.rb +11 -7
- data/spec/engineyard/model/environment_spec.rb +45 -0
- data/spec/engineyard/model/instance_spec.rb +70 -0
- data/spec/engineyard/repo_spec.rb +17 -14
- data/spec/ey/deploy_spec.rb +95 -45
- data/spec/ey/list_environments_spec.rb +11 -1
- data/spec/ey/logs_spec.rb +18 -0
- data/spec/ey/rebuild_spec.rb +21 -4
- data/spec/ey/ssh_spec.rb +28 -3
- data/spec/spec_helper.rb +37 -12
- data/spec/support/fake_awsm.ru +139 -4
- data/spec/support/helpers.rb +19 -8
- metadata +31 -20
- data/lib/engineyard/account.rb +0 -63
- data/lib/engineyard/account/app_master.rb +0 -6
- data/lib/engineyard/account/instance.rb +0 -6
- data/lib/engineyard/action/deploy.rb +0 -138
- data/lib/engineyard/action/rebuild.rb +0 -31
- data/lib/engineyard/action/util.rb +0 -19
- data/spec/engineyard/account/environment_spec.rb +0 -20
- data/spec/engineyard/account_spec.rb +0 -18
data/lib/engineyard/account.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
require 'engineyard/account/api_struct'
|
2
|
-
require 'engineyard/account/app'
|
3
|
-
require 'engineyard/account/app_master'
|
4
|
-
require 'engineyard/account/environment'
|
5
|
-
require 'engineyard/account/log'
|
6
|
-
require 'engineyard/account/instance'
|
7
|
-
|
8
|
-
module EY
|
9
|
-
class Account
|
10
|
-
|
11
|
-
def initialize(api)
|
12
|
-
@api = api
|
13
|
-
end
|
14
|
-
|
15
|
-
def environments
|
16
|
-
@environments ||= begin
|
17
|
-
data = @api.request('/environments')["environments"]
|
18
|
-
Environment.from_array(data, self)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def apps
|
23
|
-
@apps ||= App.from_array(@api.request('/apps')["apps"], self)
|
24
|
-
end
|
25
|
-
|
26
|
-
def environment_named(name)
|
27
|
-
environments.find{|e| e.name == name }
|
28
|
-
end
|
29
|
-
|
30
|
-
def logs_for(env)
|
31
|
-
data = @api.request("/environments/#{env.id}/logs")["logs"]
|
32
|
-
Log.from_array(data)
|
33
|
-
end
|
34
|
-
|
35
|
-
def instances_for(env)
|
36
|
-
@instances ||= begin
|
37
|
-
data = @api.request("/environments/#{env.id}/instances")["instances"]
|
38
|
-
Instance.from_array(data)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def upload_recipes_for(env)
|
43
|
-
@api.request("/environments/#{env.id}/recipes",
|
44
|
-
:method => :post,
|
45
|
-
:params => {:file => env.recipe_file}
|
46
|
-
)
|
47
|
-
end
|
48
|
-
|
49
|
-
def rebuild(env)
|
50
|
-
@api.request("/environments/#{env.id}/rebuild",
|
51
|
-
:method => :put)
|
52
|
-
end
|
53
|
-
|
54
|
-
def app_named(name)
|
55
|
-
apps.find{|a| a.name == name }
|
56
|
-
end
|
57
|
-
|
58
|
-
def app_for_repo(repo)
|
59
|
-
apps.find{|a| repo.urls.include?(a.repository_uri) }
|
60
|
-
end
|
61
|
-
|
62
|
-
end # Account
|
63
|
-
end # EY
|
@@ -1,138 +0,0 @@
|
|
1
|
-
require 'engineyard/action/util'
|
2
|
-
|
3
|
-
module EY
|
4
|
-
module Action
|
5
|
-
class Deploy
|
6
|
-
extend Util
|
7
|
-
|
8
|
-
EYSD_VERSION = "~>0.3.1"
|
9
|
-
|
10
|
-
def self.call(env_name, branch, options)
|
11
|
-
env_name ||= EY.config.default_environment
|
12
|
-
|
13
|
-
app = fetch_app
|
14
|
-
env = fetch_environment(env_name, app)
|
15
|
-
branch = fetch_branch(env.name, branch, options[:force])
|
16
|
-
|
17
|
-
running = env.app_master && env.app_master.status == "running"
|
18
|
-
raise EnvironmentError, "No running instances for environment #{env.name}\nStart one at #{EY.config.endpoint}" unless running
|
19
|
-
|
20
|
-
hostname = env.app_master.public_hostname
|
21
|
-
username = env.username
|
22
|
-
|
23
|
-
EY.ui.info "Connecting to the server..."
|
24
|
-
ensure_eysd_present(hostname, username, options[:install_eysd])
|
25
|
-
|
26
|
-
deploy_cmd = "#{eysd_path} deploy --app #{app.name} --branch #{branch}"
|
27
|
-
if env.config
|
28
|
-
escaped_config_option = env.config.to_json.gsub(/"/, "\\\"")
|
29
|
-
deploy_cmd << " --config '#{escaped_config_option}'"
|
30
|
-
end
|
31
|
-
|
32
|
-
if options['migrate']
|
33
|
-
deploy_cmd << " --migrate='#{options[:migrate]}'"
|
34
|
-
end
|
35
|
-
|
36
|
-
EY.ui.info "Running deploy on server..."
|
37
|
-
deployed = ssh_to(hostname, deploy_cmd, username)
|
38
|
-
|
39
|
-
if deployed
|
40
|
-
EY.ui.info "Deploy complete"
|
41
|
-
else
|
42
|
-
raise EY::Error, "Deploy failed"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def self.fetch_app
|
49
|
-
app = account.app_for_repo(repo)
|
50
|
-
raise NoAppError.new(repo) unless app
|
51
|
-
app
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.fetch_environment(env_name, app)
|
55
|
-
# if the name's not specified and there's not exactly one
|
56
|
-
# environment, we can't figure out which environment to deploy
|
57
|
-
raise DeployArgumentError if !env_name && app.environments.size != 1
|
58
|
-
|
59
|
-
env = if env_name
|
60
|
-
# environment names are unique per-customer, so
|
61
|
-
# there's no danger of finding two here
|
62
|
-
app.environments.find{|e| e.name == env_name }
|
63
|
-
else
|
64
|
-
app.environments.first
|
65
|
-
end
|
66
|
-
|
67
|
-
# the environment exists, but doesn't have this app
|
68
|
-
if !env && account.environment_named(env_name)
|
69
|
-
raise EnvironmentError, "Environment '#{env_name}' doesn't run this application\nYou can add it at #{EY.config.endpoint}"
|
70
|
-
end
|
71
|
-
|
72
|
-
if !env
|
73
|
-
raise NoEnvironmentError.new(env_name)
|
74
|
-
end
|
75
|
-
|
76
|
-
env
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.fetch_branch(env_name, user_specified_branch, force)
|
80
|
-
default_branch = EY.config.default_branch(env_name)
|
81
|
-
|
82
|
-
branch = if user_specified_branch
|
83
|
-
if default_branch && (user_specified_branch != default_branch) && !force
|
84
|
-
raise BranchMismatch.new(default_branch, user_specified_branch)
|
85
|
-
end
|
86
|
-
user_specified_branch
|
87
|
-
else
|
88
|
-
default_branch || repo.current_branch
|
89
|
-
end
|
90
|
-
|
91
|
-
raise DeployArgumentError unless branch
|
92
|
-
branch
|
93
|
-
end
|
94
|
-
|
95
|
-
def self.ensure_eysd_present(hostname, username, install_eysd)
|
96
|
-
ssh_to(hostname, "#{eysd_path} check '#{EY::VERSION}' '#{EYSD_VERSION}'", username, false)
|
97
|
-
case $?.exitstatus
|
98
|
-
when 255
|
99
|
-
raise EnvironmentError, "SSH connection to #{hostname} failed"
|
100
|
-
when 127
|
101
|
-
EY.ui.warn "Server does not have ey-deploy gem installed"
|
102
|
-
eysd_installed = false
|
103
|
-
when 0
|
104
|
-
eysd_installed = true
|
105
|
-
else
|
106
|
-
raise EnvironmentError, "ey-deploy version not compatible"
|
107
|
-
end
|
108
|
-
|
109
|
-
if !eysd_installed || install_eysd
|
110
|
-
EY.ui.info "Installing ey-deploy gem..."
|
111
|
-
ssh_to(hostname,
|
112
|
-
"sudo #{gem_path} install ey-deploy -v '#{EYSD_VERSION}'",
|
113
|
-
username)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def self.eysd_path
|
118
|
-
"/usr/local/ey_resin/ruby/bin/eysd"
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.gem_path
|
122
|
-
"/usr/local/ey_resin/ruby/bin/gem"
|
123
|
-
end
|
124
|
-
|
125
|
-
def self.ssh_to(hostname, remote_cmd, user, output = true)
|
126
|
-
cmd = %{ssh -o StrictHostKeyChecking=no -q #{user}@#{hostname} "#{remote_cmd}"}
|
127
|
-
cmd << %{ &> /dev/null} unless output
|
128
|
-
output ? puts(cmd) : EY.ui.debug(cmd)
|
129
|
-
unless ENV["NO_SSH"]
|
130
|
-
system cmd
|
131
|
-
else
|
132
|
-
true
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'engineyard/action/util'
|
2
|
-
|
3
|
-
module EY
|
4
|
-
module Action
|
5
|
-
class Rebuild
|
6
|
-
extend Util
|
7
|
-
|
8
|
-
def self.call(name)
|
9
|
-
env = fetch_environment_by_name(name) || fetch_environment_from_app
|
10
|
-
EY.ui.debug("Rebuilding #{env.name}")
|
11
|
-
env.rebuild
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
def self.fetch_environment_by_name(name)
|
16
|
-
if name
|
17
|
-
env = account.environment_named(name)
|
18
|
-
return env if env
|
19
|
-
raise NoEnvironmentError.new(name)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.fetch_environment_from_app
|
24
|
-
repo = Repo.new
|
25
|
-
app = account.app_for_repo(repo) or raise NoAppError.new(repo)
|
26
|
-
env = app.one_and_only_environment or raise EnvironmentError, "Unable to determine a single environment for the current application (found #{app.environments.size} environments)"
|
27
|
-
env
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module EY
|
2
|
-
module Action
|
3
|
-
module Util
|
4
|
-
|
5
|
-
protected
|
6
|
-
|
7
|
-
def account
|
8
|
-
# XXX it stinks that we have to use EY::CLI::API explicitly
|
9
|
-
# here; I don't want to have this lateral Action --> CLI reference
|
10
|
-
@account ||= EY::Account.new(EY::CLI::API.new)
|
11
|
-
end
|
12
|
-
|
13
|
-
def repo
|
14
|
-
@repo ||= EY::Repo.new
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "EY::Account::Environment#rebuild" do
|
4
|
-
it_should_behave_like "it has an account"
|
5
|
-
|
6
|
-
it "hits the rebuild action in the API" do
|
7
|
-
env = EY::Account::Environment.from_hash({
|
8
|
-
"id" => 46534,
|
9
|
-
"account" => @account
|
10
|
-
})
|
11
|
-
|
12
|
-
FakeWeb.register_uri(:put,
|
13
|
-
"https://cloud.engineyard.com/api/v2/environments/#{env.id}/rebuild",
|
14
|
-
:body => {}.to_json)
|
15
|
-
|
16
|
-
env.rebuild
|
17
|
-
|
18
|
-
FakeWeb.should have_requested(:put, "https://cloud.engineyard.com/api/v2/environments/#{env.id}/rebuild")
|
19
|
-
end
|
20
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe EY::Account do
|
4
|
-
it_should_behave_like "it has an account"
|
5
|
-
|
6
|
-
it "returns instances" do
|
7
|
-
@env = EY::Account::Environment.from_hash({
|
8
|
-
"id" => 1, "name" => "banana", "instances_count" => 3,
|
9
|
-
"ssh_username" => "monkey", "apps" => {}, "account" => @account
|
10
|
-
})
|
11
|
-
@instance_data = {"id" => "1", "role" => "app_master",
|
12
|
-
"amazon_id" => "amazon_1", "public_hostname" => "banana_master"}
|
13
|
-
FakeWeb.register_uri(:get, "https://cloud.engineyard.com/api/v2/environments/#{@env.id}/instances",
|
14
|
-
:body => {"instances" => [@instance_data]}.to_json)
|
15
|
-
|
16
|
-
@account.instances_for(@env).first.should == EY::Account::Instance.from_hash(@instance_data)
|
17
|
-
end
|
18
|
-
end
|