engineyard 1.2.1 → 1.2.2
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/api.rb +5 -1
- data/lib/engineyard/cli.rb +1 -1
- data/lib/engineyard/cli/recipes.rb +3 -3
- data/lib/engineyard/collection/abstract.rb +9 -1
- data/lib/engineyard/error.rb +27 -6
- data/lib/engineyard/model/#api_struct.rb# +31 -0
- data/lib/engineyard/model/api_struct.rb +1 -0
- data/lib/engineyard/thor.rb +11 -1
- data/lib/engineyard/version.rb +1 -1
- data/spec/engineyard/#resolver_spec.rb# +41 -0
- data/spec/engineyard/api_spec.rb +30 -0
- data/spec/engineyard/collection/apps_spec.rb +2 -0
- data/spec/engineyard/collection/environments_spec.rb +2 -0
- data/spec/ey/list_environments_spec.rb +6 -0
- data/spec/ey/recipes/apply_spec.rb +6 -0
- data/spec/ey/recipes/download_spec.rb +6 -0
- data/spec/ey/recipes/upload_spec.rb +6 -0
- data/spec/ey/ssh_spec.rb +6 -0
- data/spec/spec_helper.rb +2 -6
- data/spec/support/#shared_behavior.rb# +275 -0
- data/spec/support/bundled_ey +4 -7
- data/spec/support/fake_awsm.ru +197 -313
- data/spec/support/git_repo.rb +0 -1
- data/spec/support/helpers.rb +1 -2
- data/spec/support/shared_behavior.rb +28 -1
- metadata +48 -43
data/lib/engineyard/api.rb
CHANGED
@@ -31,7 +31,11 @@ module EY
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def app_for_repo(repo)
|
34
|
-
apps.
|
34
|
+
candidates = apps.find_all {|a| repo.urls.include?(a.repository_uri) }
|
35
|
+
if candidates.size > 1
|
36
|
+
raise EY::AmbiguousGitUriError.new(repo.urls, candidates.map{|x| x.name})
|
37
|
+
end
|
38
|
+
candidates.first
|
35
39
|
end
|
36
40
|
|
37
41
|
def app_for_repo!(repo)
|
data/lib/engineyard/cli.rb
CHANGED
@@ -180,7 +180,7 @@ module EY
|
|
180
180
|
:desc => "Run command on the utility servers with the given names. If no names are given, run on all utility servers."
|
181
181
|
|
182
182
|
def ssh(cmd=nil)
|
183
|
-
env
|
183
|
+
env = fetch_environment_without_app(options[:environment])
|
184
184
|
hosts = ssh_hosts(options, env)
|
185
185
|
|
186
186
|
raise NoCommandError.new if cmd.nil? and hosts.count != 1
|
@@ -11,7 +11,7 @@ module EY
|
|
11
11
|
method_option :environment, :type => :string, :aliases => %w(-e),
|
12
12
|
:desc => "Environment in which to apply recipes"
|
13
13
|
def apply
|
14
|
-
environment =
|
14
|
+
environment = fetch_environment_without_app(options[:environment])
|
15
15
|
environment.run_custom_recipes
|
16
16
|
EY.ui.say "Uploaded recipes started for #{environment.name}"
|
17
17
|
end
|
@@ -26,7 +26,7 @@ module EY
|
|
26
26
|
method_option :environment, :type => :string, :aliases => %w(-e),
|
27
27
|
:desc => "Environment that will receive the recipes"
|
28
28
|
def upload
|
29
|
-
environment =
|
29
|
+
environment = fetch_environment_without_app(options[:environment])
|
30
30
|
environment.upload_recipes
|
31
31
|
EY.ui.say "Recipes uploaded successfully for #{environment.name}"
|
32
32
|
end
|
@@ -42,7 +42,7 @@ module EY
|
|
42
42
|
method_option :environment, :type => :string, :aliases => %w(-e),
|
43
43
|
:desc => "Environment for which to download the recipes"
|
44
44
|
def download
|
45
|
-
environment =
|
45
|
+
environment = fetch_environment_without_app(options[:environment])
|
46
46
|
environment.download_recipes
|
47
47
|
EY.ui.say "Recipes downloaded successfully for #{environment.name}"
|
48
48
|
end
|
@@ -3,9 +3,17 @@ require 'engineyard/error'
|
|
3
3
|
module EY
|
4
4
|
module Collection
|
5
5
|
class Abstract < Array
|
6
|
+
COLLAB_MESSAGE = <<-MSG
|
7
|
+
\nThis error is due to having access to another account's resources via the beta collaboration feature.
|
8
|
+
We are working on letting you specify the account name to resolve this ambiguity.
|
9
|
+
MSG
|
6
10
|
|
7
11
|
def named(name)
|
8
|
-
|
12
|
+
candidates = find_all {|x| x.name == name }
|
13
|
+
if candidates.size > 1
|
14
|
+
raise ambiguous_error(name, candidates.map {|e| e.name}, COLLAB_MESSAGE )
|
15
|
+
end
|
16
|
+
candidates.first
|
9
17
|
end
|
10
18
|
|
11
19
|
def match_one(name_part)
|
data/lib/engineyard/error.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module EY
|
2
2
|
class Error < RuntimeError
|
3
|
-
def ambiguous(type, name, matches)
|
3
|
+
def ambiguous(type, name, matches, desc="")
|
4
4
|
pretty_names = matches.map {|x| "'#{x}'"}.join(', ')
|
5
5
|
"The name '#{name}' is ambiguous; it matches all of the following #{type} names: #{pretty_names}.\n" +
|
6
|
-
"Please use a longer, unambiguous substring or the entire #{type} name."
|
6
|
+
"Please use a longer, unambiguous substring or the entire #{type} name." + desc
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
@@ -36,8 +36,20 @@ module EY
|
|
36
36
|
end
|
37
37
|
|
38
38
|
class AmbiguousAppNameError < EY::Error
|
39
|
-
def initialize(name, matches)
|
40
|
-
super ambiguous("app", name, matches)
|
39
|
+
def initialize(name, matches, desc="")
|
40
|
+
super ambiguous("app", name, matches, desc)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class AmbiguousGitUriError < EY::Error
|
45
|
+
def initialize(uris, matches)
|
46
|
+
message = "The following Git Remote urls match multiple Applications in AppCloud\n"
|
47
|
+
uris.each { |uri| message << "\t#{uri}\n" }
|
48
|
+
|
49
|
+
message << "Please use -a <appname> to specify one of the following applications:\n"
|
50
|
+
matches.each { |app| message << "\t#{app}\n" }
|
51
|
+
|
52
|
+
super message
|
41
53
|
end
|
42
54
|
end
|
43
55
|
|
@@ -63,8 +75,17 @@ module EY
|
|
63
75
|
end
|
64
76
|
|
65
77
|
class AmbiguousEnvironmentNameError < EY::EnvironmentError
|
66
|
-
def initialize(name, matches)
|
67
|
-
super ambiguous("environment", name, matches)
|
78
|
+
def initialize(name, matches, desc="")
|
79
|
+
super ambiguous("environment", name, matches, desc)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class AmbiguousEnvironmentGitUriError < EY::EnvironmentError
|
84
|
+
def initialize(environments)
|
85
|
+
message = "The repository url in this directory is ambiguous.\n"
|
86
|
+
message << "Please use -e <envname> to specify one of the following environments:\n"
|
87
|
+
environments.each { |env| message << "\t#{env.name}\n" }
|
88
|
+
super message
|
68
89
|
end
|
69
90
|
end
|
70
91
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module EY
|
2
|
+
module Model
|
3
|
+
class ApiStruct < Struct
|
4
|
+
|
5
|
+
def self.new(*args, &block)
|
6
|
+
super(*args) do |*block_args|
|
7
|
+
block.call(*block_args) if block
|
8
|
+
|
9
|
+
def self.from_array(array, common_values = {})
|
10
|
+
array.map do |values|
|
11
|
+
from_hash(values.merge(common_values))
|
12
|
+
end if array
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.from_hash(hash)
|
16
|
+
return nil unless hash
|
17
|
+
members = new.members
|
18
|
+
values = members.map{|a| hash.has_key?(a.to_sym) ? hash[a.to_sym] : hash[a] }
|
19
|
+
new(*values)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def api_get(uri, options = {})
|
26
|
+
api.request(uri, options.merge(:method => :get))
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/engineyard/thor.rb
CHANGED
@@ -35,6 +35,12 @@ module EY
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
def fetch_environment_without_app(env_name)
|
39
|
+
fetch_environment(env_name)
|
40
|
+
rescue EY::AmbiguousGitUriError
|
41
|
+
raise EY::AmbiguousEnvironmentGitUriError.new(api.environments)
|
42
|
+
end
|
43
|
+
|
38
44
|
def fetch_app(app_name = nil)
|
39
45
|
if app_name
|
40
46
|
api.apps.match_one!(app_name)
|
@@ -47,7 +53,11 @@ module EY
|
|
47
53
|
if all_apps
|
48
54
|
api.apps
|
49
55
|
else
|
50
|
-
|
56
|
+
begin
|
57
|
+
[api.app_for_repo(repo)].compact
|
58
|
+
rescue EY::AmbiguousGitUriError
|
59
|
+
raise EY::AmbiguousEnvironmentGitUriError.new(api.environments)
|
60
|
+
end
|
51
61
|
end
|
52
62
|
end
|
53
63
|
|
data/lib/engineyard/version.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'engineyard/cli'
|
3
|
+
|
4
|
+
describe EY::Resolver do
|
5
|
+
|
6
|
+
let(:repo) { 'git://engineyard/ey-cloud.git' }
|
7
|
+
|
8
|
+
let(:ey) do
|
9
|
+
EY::Deployment.new(:account => 'ey',
|
10
|
+
:repo => repo,
|
11
|
+
:app => 'ey-cloud',
|
12
|
+
:environment => 'production')
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:me) do
|
16
|
+
EY::Deployment.new(:account => 'me',
|
17
|
+
:repo => repo,
|
18
|
+
:app => 'my-app',
|
19
|
+
:environment => 'production')
|
20
|
+
end
|
21
|
+
|
22
|
+
context "ambiguous account" do
|
23
|
+
it do
|
24
|
+
resolver = EY::Resolver.new([one, two], :repo => repo)
|
25
|
+
resolver.resolve.should be_nil
|
26
|
+
resolver.optoins.should == []
|
27
|
+
end
|
28
|
+
|
29
|
+
it do
|
30
|
+
EY::Resolver.new([one, two], :repo => repo, :account => 'me').resolve.should == me
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
deployments = EY::Deployment::Collection.new(get_deployments)
|
38
|
+
matched_deps = deployments.resolve(params)
|
39
|
+
|
40
|
+
matched_deps.message.should == "no matches"
|
41
|
+
|
data/spec/engineyard/api_spec.rb
CHANGED
@@ -53,4 +53,34 @@ describe EY::API do
|
|
53
53
|
}.should raise_error(EY::Error)
|
54
54
|
end
|
55
55
|
|
56
|
+
it "raises an error when using a git repo that is attached to multiple applications" do
|
57
|
+
repo = mock("repo", :urls => %w[git://github.com/engineyard/dup.git])
|
58
|
+
apps = {"apps" => [
|
59
|
+
{"id" => 1234, "name" => "app_production", :repository_uri => 'git://github.com/engineyard/prod.git'},
|
60
|
+
{"id" => 4532, "name" => "app_dup1", :repository_uri => 'git://github.com/engineyard/dup.git'},
|
61
|
+
{"id" => 4533, "name" => "app_dup2", :repository_uri => 'git://github.com/engineyard/dup.git'},
|
62
|
+
]}
|
63
|
+
|
64
|
+
FakeWeb.register_uri(:get, "https://cloud.engineyard.com/api/v2/apps", :status => 200, :content_type => 'application/json',
|
65
|
+
:body => apps.to_json)
|
66
|
+
|
67
|
+
lambda do
|
68
|
+
EY::API.new("asdf").app_for_repo(repo)
|
69
|
+
end.should raise_error(EY::AmbiguousGitUriError)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns the application when given a unique git repo" do
|
73
|
+
repo = mock("repo", :urls => %w[git://github.com/engineyard/prod.git])
|
74
|
+
apps = {"apps" => [
|
75
|
+
{"id" => 1234, "name" => "app_production", :repository_uri => 'git://github.com/engineyard/prod.git'},
|
76
|
+
{"id" => 4532, "name" => "app_dup1", :repository_uri => 'git://github.com/engineyard/dup.git'},
|
77
|
+
{"id" => 4533, "name" => "app_dup2", :repository_uri => 'git://github.com/engineyard/dup.git'},
|
78
|
+
]}
|
79
|
+
|
80
|
+
FakeWeb.register_uri(:get, "https://cloud.engineyard.com/api/v2/apps", :status => 200, :content_type => 'application/json',
|
81
|
+
:body => apps.to_json)
|
82
|
+
|
83
|
+
EY::API.new("asdf").app_for_repo(repo).name.should == "app_production"
|
84
|
+
end
|
85
|
+
|
56
86
|
end
|
@@ -7,6 +7,8 @@ describe EY::Collection::Apps do
|
|
7
7
|
EY::Model::App.from_hash("id" => 1234, "name" => "app_production"),
|
8
8
|
EY::Model::App.from_hash("id" => 4321, "name" => "app_staging"),
|
9
9
|
EY::Model::App.from_hash("id" => 8765, "name" => "bigapp_staging"),
|
10
|
+
EY::Model::App.from_hash("id" => 4532, "name" => "app_duplicate"),
|
11
|
+
EY::Model::App.from_hash("id" => 4533, "name" => "app_duplicate"),
|
10
12
|
])
|
11
13
|
end
|
12
14
|
|
@@ -7,6 +7,8 @@ describe EY::Collection::Environments do
|
|
7
7
|
EY::Model::Environment.from_hash("id" => 1234, "name" => "app_production"),
|
8
8
|
EY::Model::Environment.from_hash("id" => 4321, "name" => "app_staging"),
|
9
9
|
EY::Model::Environment.from_hash("id" => 8765, "name" => "bigapp_staging"),
|
10
|
+
EY::Model::Environment.from_hash("id" => 4532, "name" => "app_duplicate"),
|
11
|
+
EY::Model::Environment.from_hash("id" => 4533, "name" => "app_duplicate"),
|
10
12
|
])
|
11
13
|
end
|
12
14
|
|
@@ -15,3 +15,9 @@ describe "ey recipes apply" do
|
|
15
15
|
|
16
16
|
it_should_behave_like "it takes an environment name"
|
17
17
|
end
|
18
|
+
|
19
|
+
describe "ey recipes apply with an ambiguous git repo" do
|
20
|
+
given "integration"
|
21
|
+
def command_to_run(_) "recipes apply" end
|
22
|
+
it_should_behave_like "it requires an unambiguous git repo"
|
23
|
+
end
|
@@ -27,3 +27,9 @@ describe "ey recipes download" do
|
|
27
27
|
@err.should match(/cookbooks.*already exists/i)
|
28
28
|
end
|
29
29
|
end
|
30
|
+
|
31
|
+
describe "ey recipes download with an ambiguous git repo" do
|
32
|
+
given "integration"
|
33
|
+
def command_to_run(_) "recipes download" end
|
34
|
+
it_should_behave_like "it requires an unambiguous git repo"
|
35
|
+
end
|
@@ -21,3 +21,9 @@ describe "ey recipes upload" do
|
|
21
21
|
|
22
22
|
it_should_behave_like "it takes an environment name"
|
23
23
|
end
|
24
|
+
|
25
|
+
describe "ey recipes upload with an ambiguous git repo" do
|
26
|
+
given "integration"
|
27
|
+
def command_to_run(_) "recipes upload" end
|
28
|
+
it_should_behave_like "it requires an unambiguous git repo"
|
29
|
+
end
|
data/spec/ey/ssh_spec.rb
CHANGED
@@ -66,6 +66,12 @@ describe "ey ssh" do
|
|
66
66
|
|
67
67
|
end
|
68
68
|
|
69
|
+
describe "ey ssh with an ambiguous git repo" do
|
70
|
+
it_should_behave_like "running ey ssh"
|
71
|
+
def command_to_run(_) "ssh ls" end
|
72
|
+
it_should_behave_like "it requires an unambiguous git repo"
|
73
|
+
end
|
74
|
+
|
69
75
|
describe "ey ssh without a command" do
|
70
76
|
it_should_behave_like "running ey ssh"
|
71
77
|
|
data/spec/spec_helper.rb
CHANGED
@@ -3,12 +3,8 @@ if self.class.const_defined?(:EY_ROOT)
|
|
3
3
|
end
|
4
4
|
|
5
5
|
EY_ROOT = File.expand_path("../..", __FILE__)
|
6
|
-
|
7
|
-
|
8
|
-
rescue LoadError
|
9
|
-
puts "Can't load bundler environment. You need to run `bundle lock`."
|
10
|
-
exit
|
11
|
-
end
|
6
|
+
require 'rubygems'
|
7
|
+
require 'bundler/setup'
|
12
8
|
|
13
9
|
# Bundled gems
|
14
10
|
require 'fakeweb'
|
@@ -0,0 +1,275 @@
|
|
1
|
+
module Spec
|
2
|
+
module Helpers
|
3
|
+
module SharedIntegrationTestUtils
|
4
|
+
|
5
|
+
def run_ey(command_options, ey_options={})
|
6
|
+
if respond_to?(:extra_ey_options) # needed for ssh tests
|
7
|
+
ey_options.merge!(extra_ey_options)
|
8
|
+
end
|
9
|
+
|
10
|
+
ey(command_to_run(command_options), ey_options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def make_scenario(hash)
|
14
|
+
# since nil will silently turn to empty string when interpolated,
|
15
|
+
# and there's a lot of string matching involved in integration
|
16
|
+
# testing, it would be nice to have early notification of typos.
|
17
|
+
scenario = Hash.new { |h,k| raise "Tried to get key #{k.inspect}, but it's missing!" }
|
18
|
+
scenario.merge!(hash)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
shared_examples_for "it requires an unambiguous git repo" do
|
26
|
+
include Spec::Helpers::SharedIntegrationTestUtils
|
27
|
+
|
28
|
+
define_git_repo("dup test") do
|
29
|
+
system("git remote add dup git://github.com/engineyard/dup.git")
|
30
|
+
end
|
31
|
+
|
32
|
+
use_git_repo("dup test")
|
33
|
+
|
34
|
+
before(:all) do
|
35
|
+
api_scenario "two apps, same git uri"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "lists disambiguating environments to choose from" do
|
39
|
+
run_ey({}, {:expect_failure => true})
|
40
|
+
@err.should =~ /ambiguous/
|
41
|
+
@err.should =~ /specify one of the following environments/
|
42
|
+
@err.should =~ /giblets/
|
43
|
+
@err.should =~ /keycollector_production/
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
shared_examples_for "it takes an environment name" do
|
48
|
+
include Spec::Helpers::SharedIntegrationTestUtils
|
49
|
+
|
50
|
+
it "operates on the current environment by default" do
|
51
|
+
api_scenario "one app, one environment"
|
52
|
+
run_ey({:env => nil}, {:debug => true})
|
53
|
+
verify_ran(make_scenario({
|
54
|
+
:environment => 'giblets',
|
55
|
+
:application => 'rails232app',
|
56
|
+
:master_hostname => 'app_master_hostname.compute-1.amazonaws.com',
|
57
|
+
:ssh_username => 'turkey',
|
58
|
+
}))
|
59
|
+
end
|
60
|
+
|
61
|
+
it "complains when you specify a nonexistent environment" do
|
62
|
+
api_scenario "one app, one environment"
|
63
|
+
run_ey({:env => 'typo-happens-here'}, {:expect_failure => true})
|
64
|
+
@err.should match(/no environment named 'typo-happens-here'/i)
|
65
|
+
end
|
66
|
+
|
67
|
+
context "given a piece of the environment name" do
|
68
|
+
before(:all) do
|
69
|
+
api_scenario "one app, many similarly-named environments"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "complains when the substring is ambiguous" do
|
73
|
+
run_ey({:env => 'staging'}, {:expect_failure => true})
|
74
|
+
@err.should match(/'staging' is ambiguous/)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "works when the substring is unambiguous" do
|
78
|
+
api_scenario "one app, many similarly-named environments"
|
79
|
+
run_ey({:env => 'prod'}, {:debug => true})
|
80
|
+
verify_ran(make_scenario({
|
81
|
+
:environment => 'railsapp_production',
|
82
|
+
:application => 'rails232app',
|
83
|
+
:master_hostname => 'app_master_hostname.compute-1.amazonaws.com',
|
84
|
+
:ssh_username => 'turkey',
|
85
|
+
}))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "complains when it can't guess the environment and its name isn't specified" do
|
90
|
+
api_scenario "one app, one environment, not linked"
|
91
|
+
run_ey({:env => nil}, {:expect_failure => true})
|
92
|
+
@err.should =~ /single environment/i
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
shared_examples_for "it takes an app name" do
|
97
|
+
include Spec::Helpers::SharedIntegrationTestUtils
|
98
|
+
|
99
|
+
it "allows you to specify a valid app" do
|
100
|
+
api_scenario "one app, one environment"
|
101
|
+
Dir.chdir(Dir.tmpdir) do
|
102
|
+
run_ey({:env => 'giblets', :app => 'rails232app', :ref => 'master'}, {})
|
103
|
+
verify_ran(make_scenario({
|
104
|
+
:environment => 'giblets',
|
105
|
+
:application => 'rails232app',
|
106
|
+
:master_hostname => 'app_master_hostname.compute-1.amazonaws.com',
|
107
|
+
:ssh_username => 'turkey',
|
108
|
+
}))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it "can guess the environment from the app" do
|
113
|
+
api_scenario "two apps"
|
114
|
+
Dir.chdir(Dir.tmpdir) do
|
115
|
+
run_ey({:app => 'rails232app', :ref => 'master'}, {})
|
116
|
+
verify_ran(make_scenario({
|
117
|
+
:environment => 'giblets',
|
118
|
+
:application => 'rails232app',
|
119
|
+
:master_hostname => 'app_master_hostname.compute-1.amazonaws.com',
|
120
|
+
:ssh_username => 'turkey',
|
121
|
+
}))
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
it "complains when you specify a nonexistant app" do
|
126
|
+
api_scenario "one app, one environment"
|
127
|
+
run_ey({:env => 'giblets', :app => 'P-time-SAT-solver', :ref => 'master'},
|
128
|
+
{:expect_failure => true})
|
129
|
+
@err.should =~ /no app.*P-time-SAT-solver/i
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
shared_examples_for "it invokes engineyard-serverside" do
|
135
|
+
include Spec::Helpers::SharedIntegrationTestUtils
|
136
|
+
|
137
|
+
context "with arguments" do
|
138
|
+
before(:all) do
|
139
|
+
api_scenario "one app, one environment"
|
140
|
+
run_ey({:env => 'giblets', :verbose => true})
|
141
|
+
end
|
142
|
+
|
143
|
+
it "passes --verbose to engineyard-serverside" do
|
144
|
+
@ssh_commands.should have_command_like(/engineyard-serverside.*deploy.*--verbose/)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "passes along instance information to engineyard-serverside" do
|
148
|
+
instance_args = [
|
149
|
+
Regexp.quote("app_master_hostname.compute-1.amazonaws.com,app_master"),
|
150
|
+
Regexp.quote("app_hostname.compute-1.amazonaws.com,app"),
|
151
|
+
Regexp.quote("util_fluffy_hostname.compute-1.amazonaws.com,util,fluffy"),
|
152
|
+
]
|
153
|
+
|
154
|
+
db_instance = Regexp.quote("db_master_hostname.compute-1.amazonaws.com,db_master")
|
155
|
+
|
156
|
+
# apps + utilities are all mentioned
|
157
|
+
instance_args.each do |i|
|
158
|
+
@ssh_commands.last.should =~ /#{i}/
|
159
|
+
end
|
160
|
+
|
161
|
+
# but not database instances
|
162
|
+
@ssh_commands.last.should_not =~ /#{db_instance}/
|
163
|
+
|
164
|
+
# and it's all after the option '--instances'
|
165
|
+
@ssh_commands.last.should match(/--instances (#{instance_args.join('|')})/)
|
166
|
+
end
|
167
|
+
|
168
|
+
it "passes the framework environment" do
|
169
|
+
@ssh_commands.last.should match(/--framework-env production/)
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
context "engineyard-serverside installation" do
|
176
|
+
before(:all) do
|
177
|
+
api_scenario "one app, one environment"
|
178
|
+
end
|
179
|
+
|
180
|
+
before(:each) do
|
181
|
+
ENV.delete "NO_SSH"
|
182
|
+
end
|
183
|
+
|
184
|
+
after(:each) do
|
185
|
+
ENV['NO_SSH'] = "true"
|
186
|
+
end
|
187
|
+
|
188
|
+
def exiting_ssh(exit_code)
|
189
|
+
"#!/usr/bin/env ruby\n exit!(#{exit_code}) if ARGV.to_s =~ /gem list engineyard-serverside/"
|
190
|
+
end
|
191
|
+
|
192
|
+
it "raises an error if SSH fails" do
|
193
|
+
run_ey({:env => 'giblets'},
|
194
|
+
{:prepend_to_path => {'ssh' => exiting_ssh(255)}, :expect_failure => true})
|
195
|
+
@err.should =~ /SSH connection to \S+ failed/
|
196
|
+
end
|
197
|
+
|
198
|
+
it "installs engineyard-serverside if it's missing" do
|
199
|
+
run_ey({:env => 'giblets'}, {:prepend_to_path => {'ssh' => exiting_ssh(1)}})
|
200
|
+
|
201
|
+
gem_install_command = @ssh_commands.find do |command|
|
202
|
+
command =~ /gem install engineyard-serverside/
|
203
|
+
end
|
204
|
+
gem_install_command.should_not be_nil
|
205
|
+
gem_install_command.should =~ %r{/usr/local/ey_resin/ruby/bin/gem install.*engineyard-serverside}
|
206
|
+
end
|
207
|
+
|
208
|
+
it "does not try to install engineyard-serverside if it's already there" do
|
209
|
+
run_ey({:env => 'giblets'}, {:prepend_to_path => {'ssh' => exiting_ssh(0)}})
|
210
|
+
@ssh_commands.should_not have_command_like(/gem install engineyard-serverside/)
|
211
|
+
ver = Regexp.quote(EY::ENGINEYARD_SERVERSIDE_VERSION)
|
212
|
+
@ssh_commands.should have_command_like(/engineyard-serverside _#{ver}_ deploy/)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
shared_examples_for "model collections" do
|
218
|
+
describe "#match_one" do
|
219
|
+
it "works when given an unambiguous substring" do
|
220
|
+
@collection.match_one("prod").name.should == "app_production"
|
221
|
+
end
|
222
|
+
|
223
|
+
it "raises an error when given an ambiguous substring" do
|
224
|
+
lambda {
|
225
|
+
@collection.match_one("staging")
|
226
|
+
}.should raise_error(@collection_class.ambiguous_error)
|
227
|
+
end
|
228
|
+
|
229
|
+
it "returns an exact match if one exists" do
|
230
|
+
@collection.match_one("app_staging").name.should == "app_staging"
|
231
|
+
end
|
232
|
+
|
233
|
+
it "returns nil when it can't find anything" do
|
234
|
+
@collection.match_one("dev-and-production").should be_nil
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "#match_one!" do
|
239
|
+
it "works when given an unambiguous substring" do
|
240
|
+
@collection.match_one!("prod").name.should == "app_production"
|
241
|
+
end
|
242
|
+
|
243
|
+
it "raises an error when given an ambiguous substring" do
|
244
|
+
lambda {
|
245
|
+
@collection.match_one!("staging")
|
246
|
+
}.should raise_error(@collection_class.ambiguous_error)
|
247
|
+
end
|
248
|
+
|
249
|
+
it "returns an exact match if one exists" do
|
250
|
+
@collection.match_one!("app_staging").name.should == "app_staging"
|
251
|
+
end
|
252
|
+
|
253
|
+
it "raises an error when given an ambiguous exact string" do
|
254
|
+
lambda {
|
255
|
+
@collection.match_one!("app_duplicate")
|
256
|
+
}.should raise_error(@collection_class.ambiguous_error)
|
257
|
+
end
|
258
|
+
|
259
|
+
it "raises an error when it can't find anything" do
|
260
|
+
lambda {
|
261
|
+
@collection.match_one!("dev-and-production")
|
262
|
+
}.should raise_error(@collection_class.invalid_error)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
describe "#named" do
|
267
|
+
it "finds matching by name" do
|
268
|
+
@collection.named("app_staging").name.should == "app_staging"
|
269
|
+
end
|
270
|
+
|
271
|
+
it "returns nil when no name matches" do
|
272
|
+
@collection.named("something else").should be_nil
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|