dew 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,16 +2,24 @@ require 'yaml'
2
2
 
3
3
  class Account
4
4
 
5
+ def initialize(yaml)
6
+ @yaml = yaml
7
+ end
8
+
5
9
  def self.read(account_name)
6
- Account.new YAML.load File.read File.join [ ENV['HOME'], '.dew', 'accounts', "#{account_name}.yaml" ]
10
+ Account.new(YAML.load_file(account_path(account_name)))
7
11
  end
8
12
 
9
13
  def self.user_ids
10
- Dir[File.join(ENV['HOME'], '.dew', 'accounts', '*.yaml')].map do |filename|
11
- Account.read(File.basename(filename).gsub(/.yaml$/, '')).aws_user_id
14
+ Dir[account_path('*')].map do |filename|
15
+ read(File.basename(filename, '.yaml')).aws_user_id
12
16
  end
13
17
  end
14
18
 
19
+ def self.account_path(account_name)
20
+ File.join(ENV['HOME'], '.dew', 'accounts', "#{account_name}.yaml")
21
+ end
22
+
15
23
  def aws_access_key_id
16
24
  @yaml['aws']['access_key_id']
17
25
  end
@@ -36,7 +44,4 @@ class Account
36
44
  @yaml['dns']['domain']
37
45
  end
38
46
 
39
- def initialize(yaml)
40
- @yaml = yaml
41
- end
42
47
  end
@@ -5,7 +5,7 @@ class Environment
5
5
 
6
6
  attr_reader :name, :servers, :database
7
7
 
8
- def initialize name, servers=[], database=nil
8
+ def initialize(name, servers=[], database=nil)
9
9
  @name = name
10
10
  @servers = servers
11
11
  @database = database
@@ -34,14 +34,23 @@ class Environment
34
34
  environment.add_database(profile.rds_size, profile.rds_storage_size, password) if profile.has_rds?
35
35
 
36
36
  (1..profile.count).each do
37
- environment.add_server(profile.ami, profile.size, profile.keypair, profile.security_groups, profile.username)
37
+ environment.add_server(
38
+ profile.username,
39
+ :ami => profile.ami,
40
+ :size => profile.size,
41
+ :keypair => profile.keypair,
42
+ :groups => profile.security_groups,
43
+ :disk_size => profile.instance_disk_size
44
+ )
38
45
  end
39
46
 
40
47
  environment.add_elb(profile.elb_listener_ports) if profile.has_elb?
41
48
 
42
49
  environment.wait_until_ready
43
-
50
+
51
+ environment.resize_disks if profile.instance_disk_size?
44
52
  environment.configure_servers_for_database password if profile.has_rds?
53
+
45
54
  Inform.info "Environment %{name} ready!", :name => name
46
55
  environment
47
56
  end
@@ -117,18 +126,17 @@ class Environment
117
126
  end
118
127
  end
119
128
 
120
- def add_server(ami, size, keypair, groups, username)
121
- Inform.info "Adding server using AMI %{ami} of size %{size}, keypair %{keypair} and security groups %{groups}",
122
- :ami => ami, :size => size, :keypair => keypair, :groups => groups.join(',') do
123
- server = Server.create!( ami, size, keypair, groups )
124
- server.add_tag('Environment', name)
125
- server.add_tag('Creator', ENV['USER'])
126
- server_name = "#{name} #{servers.count + 1}"
127
- server.add_tag('Name', server_name)
128
- server.add_tag('Username', username) # Needed for SSH
129
- Inform.debug("%{name} ID: %{id} AZ: %{az}", :name => server_name, :id =>server.id, :az => server.availability_zone)
130
- servers << server
131
- end
129
+ def add_server(username, create_options)
130
+ server_name = "#{name} #{servers.count + 1}"
131
+
132
+ server = Server.create!(create_options)
133
+ server.add_tag('Environment', name)
134
+ server.add_tag('Creator', ENV['USER'])
135
+ server.add_tag('Name', server_name)
136
+ server.add_tag('Username', username) # Needed for SSH
137
+ Inform.debug("%{name} ID: %{id} AZ: %{az}", :name => server_name, :id =>server.id, :az => server.availability_zone)
138
+
139
+ servers << server
132
140
  end
133
141
 
134
142
  def add_server_to_elb server
@@ -185,6 +193,12 @@ class Environment
185
193
  end
186
194
  end
187
195
 
196
+ def resize_disks
197
+ Inform.info "Resizing disks on servers" do
198
+ servers.each { |s| s.resize_disk }
199
+ end
200
+ end
201
+
188
202
  def elb
189
203
  @elb ||= Cloud.elb.load_balancers.detect { |elb| elb.id == name } # XXX - need to refactor
190
204
  end
@@ -5,31 +5,22 @@ class Profile
5
5
  attr_reader :profile_name
6
6
  attr_accessor :ami, :size, :security_groups, :keypair, :count
7
7
  attr_accessor :rds_size, :rds_storage_size, :elb_listener_ports, :username
8
-
9
- AWS_RESOURCES = YAML.load(File.read(File.join(File.dirname(__FILE__), '..', 'aws_resources.yaml')))
8
+ attr_reader :instance_disk_size
9
+
10
+ AWS_RESOURCES = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'aws_resources.yaml'))
10
11
 
11
12
  DEFAULT_RDS_STORAGE_SIZE = 5
12
-
13
+ DEFAULT_USERNAME = 'ubuntu'
14
+
13
15
  def self.read(profile_name)
14
- yaml = YAML.load_file(File.join(ENV['HOME'], '.dew', 'profiles', "#{profile_name}.yaml"))
15
- profile = new(profile_name)
16
- profile.username = 'ubuntu'
17
- if yaml['instances']
18
- profile.ami = yaml['instances']['amis'][Cloud.region]
19
- profile.size = yaml['instances']['size']
20
- profile.security_groups = yaml['instances']['security-groups'] || ['default'] #XXX is this fallback tested?
21
- profile.keypair = yaml['instances']['keypair']
22
- profile.count = yaml['instances']['count'].to_i
23
- profile.username = yaml['instances']['username'] if yaml['instances'].include?('username')
24
- end
25
- if yaml['elb']
26
- profile.elb_listener_ports = yaml['elb']['listener_ports']
27
- end
28
- if yaml['rds']
29
- profile.rds_size = yaml['rds']['size']
30
- profile.rds_storage_size = yaml['rds'].fetch('storage', DEFAULT_RDS_STORAGE_SIZE)
31
- end
32
- profile
16
+ new(
17
+ profile_name,
18
+ YAML.load_file(profile_path(profile_name))
19
+ )
20
+ end
21
+
22
+ def self.profile_path(profile_name)
23
+ File.join(ENV['HOME'], '.dew', 'profiles', "#{profile_name}.yaml")
33
24
  end
34
25
 
35
26
  def has_elb?
@@ -40,18 +31,40 @@ class Profile
40
31
  rds_size != nil
41
32
  end
42
33
 
43
- def initialize(profile_name)
34
+ def initialize(profile_name, init_yaml = nil)
44
35
  @profile_name = profile_name
45
- # :ami, :size, :security_groups, :keypair, :count
46
- # :rds_size, :elb_listener_ports
36
+ populate_from_yaml(Cloud.region, init_yaml) if init_yaml
37
+ end
38
+
39
+ def populate_from_yaml(region, yaml)
40
+ @username = DEFAULT_USERNAME # do we actually need this? There are no instances...
41
+
42
+ if yaml['instances']
43
+ @ami = yaml['instances'].fetch('amis', {})[region]
44
+ @size = yaml['instances']['size']
45
+ @security_groups = yaml['instances'].fetch('security-groups', ['default']) #TODO is this fallback tested?
46
+ @keypair = yaml['instances']['keypair']
47
+ @count = yaml['instances']['count'].to_i
48
+ @username = yaml['instances'].fetch('username', DEFAULT_USERNAME) #TODO is this fallback tested?
49
+ @instance_disk_size = yaml['instances'].fetch('disk-size', nil)
50
+ end
51
+
52
+ if yaml['elb']
53
+ @elb_listener_ports = yaml['elb']['listener_ports']
54
+ end
55
+
56
+ if yaml['rds']
57
+ @rds_size = yaml['rds']['size']
58
+ @rds_storage_size = yaml['rds'].fetch('storage', DEFAULT_RDS_STORAGE_SIZE)
59
+ end
47
60
  end
61
+
62
+ TO_STRING_TEMPLATE = "%{memory} GB memory, %{processor} ECUs processor, %{storage} GB storage, %{platform}-bit platform"
48
63
 
49
64
  def self.size_to_s(size)
50
- #instance_str = "%{memory} memory, %{processor} processor, %{storage} storage, %{platform} platform, %{io_performance} I/O performance"
51
- instance_str = "%{memory} GB memory, %{processor} ECUs processor, %{storage} GB storage, %{platform}-bit platform, %{io_performance} I/O performance"
52
65
  flavor = Cloud.compute.flavors.detect { |f| f.id == size }
53
- instance_hash = { :memory => flavor.ram.to_s, :processor => flavor.cores.to_s, :storage => flavor.disk.to_s, :platform => flavor.bits.to_s, :io_performance => '??' }
54
- instance_hash.inject(instance_str) { |res,(k,v)| res.gsub(/%\{#{k}\}/, v) }
66
+ instance_hash = { :memory => flavor.ram.to_s, :processor => flavor.cores.to_s, :storage => flavor.disk.to_s, :platform => flavor.bits.to_s }
67
+ instance_hash.inject(TO_STRING_TEMPLATE) { |res,(k,v)| res.gsub(/%\{#{k}\}/, v) }
55
68
  end
56
69
 
57
70
  def to_s
@@ -65,4 +78,8 @@ class Profile
65
78
  t << ['keypair', keypair.inspect]
66
79
  }.to_s
67
80
  end
81
+
82
+ def instance_disk_size?
83
+ !!@instance_disk_size
84
+ end
68
85
  end
@@ -1,12 +1,40 @@
1
1
  class Server < FogModel
2
- TEN_SECONDS = 10
3
- SIXTY_SECONDS = 60
4
- TWO_MINUTES = 120
5
- THREE_MINUTES = 180
2
+ TAG_CREATION_TIMEOUT = 60
3
+ AMI_RECOGNITION_TIMEOUT = 60
4
+ DEFAULT_SSH_CONNECTION_TIMEOUT = 180
5
+
6
6
  RUNNING_SERVER_STATES = %w{pending running}
7
7
 
8
- def self.create! ami, size, keypair, groups
9
- new(Cloud.compute.servers.create(:image_id => ami, :flavor_id => size, :key_name => keypair, :groups => groups))
8
+ def self.create!(options)
9
+ ami = options.fetch(:ami)
10
+ size = options.fetch(:size)
11
+ keypair = options.fetch(:keypair)
12
+ groups = options.fetch(:groups)
13
+ disk_size = options.fetch(:disk_size, nil)
14
+
15
+ Inform.info "Creating server using AMI %{ami} of size %{size}, keypair %{keypair} and security groups %{groups}",
16
+ :ami => ami, :size => size, :keypair => keypair, :groups => groups.join(',') do
17
+
18
+ server_options = {
19
+ :image_id => ami,
20
+ :flavor_id => size,
21
+ :key_name => keypair,
22
+ :groups => groups
23
+ }
24
+
25
+ if disk_size
26
+ server_options.merge!(
27
+ :block_device_mapping => [
28
+ {
29
+ 'DeviceName' => '/dev/sda1',
30
+ 'Ebs.VolumeSize' => disk_size.to_s
31
+ }
32
+ ]
33
+ )
34
+ end
35
+
36
+ new(Cloud.compute.servers.create(server_options))
37
+ end
10
38
  end
11
39
 
12
40
  def self.find tag_name, tag_value
@@ -18,15 +46,19 @@ class Server < FogModel
18
46
  end
19
47
 
20
48
  def add_tag key, val
21
- try_for(SIXTY_SECONDS) {
49
+ try_for(TAG_CREATION_TIMEOUT) do
22
50
  Cloud.compute.tags.create(:resource_id => id, :key => key, :value => val)
23
- }
51
+ end
24
52
  end
25
53
 
26
54
  def configure_for_database database, password
27
55
  ssh.write(database.db_environment_file(password), '/tmp/envfile')
28
56
  ssh.run('sudo mv /tmp/envfile /etc/environment')
29
57
  end
58
+
59
+ def resize_disk
60
+ ssh.run('sudo resize2fs -p /dev/sda1')
61
+ end
30
62
 
31
63
  def username
32
64
  fog_object.tags['Username'] || 'ubuntu'
@@ -40,7 +72,7 @@ class Server < FogModel
40
72
  Gofer::Host.new(public_ip_address, username, :port => ssh_port, :key_data => [File.read(Cloud.keyfile_path(key_name))], :paranoid => false, :quiet => true)
41
73
  end
42
74
 
43
- def wait_until_ready ssh_timeout=THREE_MINUTES
75
+ def wait_until_ready ssh_timeout=DEFAULT_SSH_CONNECTION_TIMEOUT
44
76
  super()
45
77
  Inform.debug("%{id} online at %{ip}, waiting for SSH connection...", :id => id, :ip => public_ip_address)
46
78
  wait_for_ssh ssh_timeout
@@ -52,7 +84,7 @@ class Server < FogModel
52
84
 
53
85
  Inform.debug("Created image at %{id}, waiting for AWS to recognize it...", :id => image_id)
54
86
  # Sometimes takes a while for AWS to realise there's a new image...
55
- image = Timeout::timeout(SIXTY_SECONDS) do
87
+ image = Timeout::timeout(AMI_RECOGNITION_TIMEOUT) do
56
88
  image = nil
57
89
  while image == nil
58
90
  image = Cloud.compute.images.get(image_id)
@@ -1,3 +1,3 @@
1
1
  module Dew
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe :Cloud do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe AMIsController do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe DeployController do
4
4
 
@@ -35,4 +35,4 @@ describe DeployController do
35
35
  end
36
36
 
37
37
  end
38
- end
38
+ end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe EnvironmentsController do
4
4
  subject { EnvironmentsController.new }
@@ -1,29 +1,32 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Account do
4
4
 
5
- describe :initialize do
5
+ describe '::read' do
6
6
  it "should look for the named account file in the ~/.dew/accounts dir" do
7
7
  name = 'a_development_name'
8
- File.should_receive(:read).with("#{ENV['HOME']}/.dew/accounts/#{name}.yaml").and_return("---")
8
+ YAML.should_receive(:load_file).with("#{ENV['HOME']}/.dew/accounts/#{name}.yaml").and_return({})
9
9
  Account.read(name)
10
10
  end
11
11
  end
12
12
 
13
13
  describe "parsing yaml" do
14
14
  before :each do
15
- File.stub(:read).and_return(yaml)
15
+ YAML.stub(:load_file).and_return(yaml)
16
16
  end
17
17
 
18
18
  subject { Account.read('foo') }
19
19
 
20
20
  describe "with an aws section" do
21
- let (:yaml) {
22
- "aws:
23
- user_id: 9999-3333-2222
24
- access_key_id: foo
25
- secret_access_key: bar"
26
- }
21
+ let (:yaml) do
22
+ {
23
+ 'aws' => {
24
+ 'user_id' => '9999-3333-2222',
25
+ 'access_key_id' => 'foo',
26
+ 'secret_access_key' => 'bar'
27
+ }
28
+ }
29
+ end
27
30
 
28
31
  it "should have a user_id stripped of dashes" do
29
32
  subject.aws_user_id.should == '999933332222'
@@ -35,16 +38,18 @@ describe Account do
35
38
  end
36
39
 
37
40
  describe "with a DNS section" do
38
- let (:yaml) {
39
- "
40
- dns:
41
- domain: mydomain.com
42
- key: a1b2c3d4e5
43
- "
44
- }
45
- it { subject.has_dns?.should be_true }
46
- it { subject.dns_key.should == 'a1b2c3d4e5' }
47
- it { subject.dns_domain.should == 'mydomain.com' }
41
+ let (:yaml) do
42
+ {
43
+ 'dns' => {
44
+ 'domain' => 'mydomain.com',
45
+ 'key' => 'a1b2c3d4e5'
46
+ }
47
+ }
48
+ end
49
+
50
+ it { subject.should have_dns }
51
+ its(:dns_key) { should == 'a1b2c3d4e5' }
52
+ its(:dns_domain) { should == 'mydomain.com' }
48
53
  end
49
54
  end
50
55
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Database do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../../spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Deploy::Puge do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Deploy::Run do
4
4
 
@@ -35,4 +35,4 @@ describe Deploy::Run do
35
35
  @deploy_run.deploy
36
36
  end
37
37
  end
38
- end
38
+ end
@@ -1,10 +1,9 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '../spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Environment do
4
4
 
5
5
  let (:name) { 'my-environment' }
6
- let (:bad_name) { 'my_environment' }
7
- let (:server) { double('Server', :id => 'i-12345', :add_tag => nil, :wait_until_ready => nil, :availability_zone => 'ap-southeast-1') }
6
+ # let (:server) { double('Server', :id => 'i-12345', :add_tag => nil, :wait_until_ready => nil, :availability_zone => 'ap-southeast-1') }
8
7
  let(:groups) { %w(non_default) }
9
8
  let (:server) { double('Server', :id => 'i-12345', :add_tag => nil, :wait_until_ready => nil, :availability_zone => 'ap-southeast-1', :groups => groups) }
10
9
  let (:servers) { [] }
@@ -13,25 +12,26 @@ describe Environment do
13
12
  let (:database) { double('Database') }
14
13
  let(:keypair_available_in_aws) { true }
15
14
  let(:profile_count) { 2 }
16
- let (:profile) do
17
- double('Profile',
18
- :ami => 'ami-12345', :size => 'm1.large',
19
- :keypair => 'devops', :count => profile_count,
20
- :has_rds? => false, :has_elb? => false
21
- )
22
- end
15
+
16
+ let(:instance_disk_size) { rand(234) }
17
+ let(:database) { mock('Database', :destroy => true, :wait_until_ready => true) }
18
+
19
+ let(:environment) { Environment.new(name, servers, database) }
23
20
 
24
21
  before :each do
25
- @environment = Environment.new(name, servers)
26
22
  Cloud.connect(name, 'development')
27
23
  Cloud.stub(:elb => elb, :keypair_exists? => keypair_available_in_aws)
28
24
  end
29
25
 
30
- it { @environment.name.should == name }
31
- it { @environment.servers.should == [] }
32
- it { @environment.database.should == nil }
26
+ describe "initialization" do
27
+ subject { environment }
33
28
 
34
- describe ".get" do
29
+ its(:name) { should == name }
30
+ its(:servers) { should == [] }
31
+ its(:database) { should == database }
32
+ end
33
+
34
+ describe "::get" do
35
35
  before :each do
36
36
  Server.stub(:find => [])
37
37
  Database.stub(:get => nil)
@@ -49,13 +49,26 @@ describe Environment do
49
49
  end
50
50
  end
51
51
 
52
- describe ".create" do
53
- let (:security_groups) { %w(non_default) }
54
- let(:profile) { double(:profile, :username => 'username', :keypair => 'default', :security_groups => security_groups, :ami => 'i-1234', :has_rds? => false, :has_elb? => false, :count => 2, :size => 'small' ) }
55
-
52
+ describe "::create" do
53
+ let (:profile) do
54
+ double('Profile',
55
+ :username => 'username',
56
+ :security_groups => %w(default),
57
+ :ami => 'ami-12345', :size => 'm1.large',
58
+ :keypair => 'devops', :count => profile_count,
59
+ :has_rds? => false, :has_elb? => false,
60
+ :instance_disk_size => instance_disk_size,
61
+ :instance_disk_size? => !!instance_disk_size
62
+ )
63
+ end
64
+
65
+ subject { Environment.create(name, profile) }
66
+
56
67
  context "when environment name is invalid" do
68
+ let(:name) { 'my_bad_name' }
69
+
57
70
  it "should raise an error" do
58
- lambda { Environment.create(bad_name, profile) }.should raise_error /does not match/
71
+ lambda { subject }.should raise_error(ArgumentError, /does not match/)
59
72
  end
60
73
  end
61
74
 
@@ -63,16 +76,31 @@ describe Environment do
63
76
  let(:keypair_available_in_aws) { false }
64
77
 
65
78
  it "should raise an error" do
66
- lambda { Environment.create(name, profile) }.should raise_error /is not available/
79
+ lambda { subject }.should raise_error /is not available/
80
+ end
81
+ end
82
+
83
+ context "when no instance disk size is specified" do
84
+ let(:instance_disk_size) { nil }
85
+ let(:environment) { mock(:add_server => true, :wait_until_ready => true) }
86
+
87
+ before do
88
+ Environment.stub(:new => environment)
89
+ end
90
+
91
+ it "should not resize_disks on the environment" do
92
+ environment.should_not_receive(:resize_disks)
93
+ subject
67
94
  end
68
95
  end
69
96
 
70
97
  context "when profile keypair is available in AWS" do
71
98
 
72
- before {
73
- @env = double(:environment, :name => name, :add_database => true, :wait_until_ready => true, :add_server => true)
74
- Environment.should_receive(:new).with(name).and_return(@env)
75
- }
99
+ let(:environment) { double(:environment, :name => name, :add_database => true, :wait_until_ready => true, :add_server => true, :resize_disks => true) }
100
+
101
+ before do
102
+ Environment.stub(:new => environment)
103
+ end
76
104
 
77
105
  after { Environment.create(name, profile) }
78
106
 
@@ -80,12 +108,19 @@ describe Environment do
80
108
  let(:profile_count) { 2 }
81
109
 
82
110
  it "should add two instances to that environment with the chosen AMI, size and keypair" do
83
- @env.should_receive(:add_server).with(profile.ami, profile.size, profile.keypair, profile.security_groups, profile.username).twice
111
+ environment.should_receive(:add_server).with(
112
+ profile.username,
113
+ :ami => profile.ami,
114
+ :size => profile.size,
115
+ :keypair => profile.keypair,
116
+ :groups => profile.security_groups,
117
+ :disk_size => profile.instance_disk_size
118
+ ).twice
84
119
  end
85
120
  end
86
121
 
87
122
  it "should wait for our environment to become ready" do
88
- @env.should_receive(:wait_until_ready)
123
+ environment.should_receive(:wait_until_ready)
89
124
  end
90
125
 
91
126
  describe "with an ELB specified in the profile" do
@@ -94,41 +129,41 @@ describe Environment do
94
129
  end
95
130
 
96
131
  it "should add an ELB to the environment with the required ports" do
97
- @env.should_receive(:add_elb).with([80])
132
+ environment.should_receive(:add_elb).with([80])
98
133
  end
99
134
  end
100
135
 
101
136
  describe "with an RDS specified in the profile" do
102
137
  before :each do
103
138
  profile.stub(:has_rds? => true, :rds_size => 'db.m1.small', :rds_storage_size => 5)
104
- @env.stub(:add_database => nil, :configure_servers_for_database => nil)
139
+ environment.stub(:add_database => nil, :configure_servers_for_database => nil)
105
140
  Password.stub(:random => 'abcdef')
106
141
  end
107
142
 
108
143
  it "should add an RDS to the environment with the required size and a random password" do
109
- @env.should_receive(:add_database).with('db.m1.small', 5, 'abcdef')
144
+ environment.should_receive(:add_database).with('db.m1.small', 5, 'abcdef')
110
145
  end
111
146
 
112
147
  it "should ask the environment to update the database configuration on the servers" do
113
- @env.should_receive(:configure_servers_for_database).with('abcdef')
148
+ environment.should_receive(:configure_servers_for_database).with('abcdef')
114
149
  end
115
150
  end
116
151
 
117
152
  end
118
153
  end
119
154
 
120
- describe ".names" do
121
- before {
155
+ describe "::owners" do
156
+ before do
122
157
  Cloud.should_receive(:valid_servers).at_least(1).and_return( [
123
158
  double(:server, :tags => {"Environment" => "test-1", "Creator" => "chris" }),
124
159
  double(:server, :tags => {"Environment" => "test-2", "Creator" => "ash" })
125
160
  ])
126
- }
161
+ end
127
162
 
128
163
  it { Environment.owners.should == [{:name=>"test-1", :owner=>"chris"}, {:name=>"test-2", :owner=>"ash"}] }
129
164
  end
130
165
 
131
- describe ".index" do
166
+ describe "::index" do
132
167
  before {
133
168
  Cloud.should_receive(:valid_servers).at_least(1).and_return( [
134
169
  double(:server, :tags => {"Environment" => "test-1", "Creator" => "chris" }),
@@ -152,119 +187,140 @@ EOF
152
187
  end
153
188
  end
154
189
 
155
- describe :show do
156
- before {
190
+ describe '#show' do
191
+ before do
157
192
  Cloud.stub_chain(:account, :aws_user_id).and_return('12345')
158
- }
159
- after { @environment.show }
193
+ end
194
+
195
+ subject { environment.show }
160
196
 
161
197
  context "with servers" do
162
198
  let(:servers) { [server] }
163
-
164
- before { @environment.stub(:elb => nil) }
199
+ let(:database) { nil }
200
+
201
+ before { environment.stub(:elb => nil) }
165
202
  it "should show the servers" do
166
203
  View.should_receive(:new).with(
167
204
  "SERVERS", [server], %w(id flavor_id public_ip_address state created_at groups key_name availability_zone creator)
168
205
  ).and_return(double(:servers_view, :index => 'servers'))
206
+ subject
169
207
  end
170
208
  end
171
209
 
172
210
  context "with an elb" do
211
+ let(:database) { nil }
212
+
173
213
  it "should show the elb" do
174
214
  elb_view = double(:elb_view)
175
215
  View.should_receive(:new).with(
176
216
  "ELB", [an_elb], %w(created_at dns_name instances availability_zones)
177
217
  ).and_return(elb_view)
178
218
  elb_view.should_receive(:show).and_return('stuff')
219
+ subject
179
220
  end
180
221
  end
181
222
 
182
223
  context "with a database" do
183
- before {
184
- @environment.stub(:database => database)
185
- @environment.stub(:elb => nil)
186
- }
224
+ before { environment.stub(:elb => nil) }
187
225
 
188
226
  it "should show the database" do
189
227
  View.should_receive(:new).with(
190
228
  "DATABASE", [database], %w(flavor_id state created_at availability_zone db_security_groups)
191
- ).and_return(double(:database_view, :index => 'database', :show => "some_ stuff"))
229
+ ).and_return(mock('database_view', :index => 'database', :show => "some_ stuff"))
230
+ subject
192
231
  end
193
232
  end
194
233
 
195
234
  end
196
235
 
197
- describe :destroy do
198
- before :each do
199
- @environment.stub(:has_elb? => false)
236
+ describe '#destroy' do
237
+ subject { environment.destroy }
238
+
239
+ before do
240
+ environment.stub(:has_elb? => false)
200
241
  end
242
+
201
243
  it "should destroy the database if there is one" do
202
- @environment.stub(:database => database)
244
+ environment.stub(:database => database)
203
245
  database.should_receive(:destroy)
204
- @environment.destroy
246
+
247
+ subject
205
248
  end
206
249
  it "should destroy the servers if there are any" do
207
- @environment.stub(:servers => [server])
250
+ environment.stub(:servers => [server])
208
251
  server.should_receive(:destroy)
209
- @environment.destroy
252
+
253
+ subject
210
254
  end
255
+
211
256
  it "should destroy the ELB if there is one" do
212
- @environment.stub(:has_elb? => true)
257
+ environment.stub(:has_elb? => true)
213
258
  elb.should_receive(:delete_load_balancer).with(name)
214
- @environment.destroy
259
+
260
+ subject
215
261
  end
216
262
  end
217
263
 
218
- describe :add_server do
264
+ describe '#add_server' do
265
+ let(:create_options) { mock('create options') }
266
+ let(:username) { 'username' }
267
+
268
+ subject { environment.add_server(username, create_options) }
269
+
219
270
  before :each do
220
- @args = 'ami', 'size', 'keypair', %w(non_default)
221
271
  Server.stub(:create!).and_return(server)
222
272
  end
223
273
 
224
274
  it "should create a Server from the provided ami, size and keypair" do
225
- Server.should_receive(:create!).with(*@args)
226
- @environment.add_server(*@args, 'username')
275
+ Server.should_receive(:create!).with(create_options)
276
+ subject
227
277
  end
228
278
 
229
279
  it "should add the Server to its servers array" do
230
- @environment.add_server(*@args, 'username')
231
- @environment.add_server(*@args, 'username')
232
- @environment.servers.should == [server, server]
280
+ # don't use subject here, is memoized
281
+ environment.add_server(username, create_options)
282
+ environment.add_server(username, create_options)
283
+ environment.servers.should == [server, server]
233
284
  end
234
285
 
235
286
  it "should tag the server with the environment name, creator and username" do
236
287
  server.should_receive(:add_tag).with('Environment', name)
237
288
  server.should_receive(:add_tag).with('Creator', ENV['USER'])
238
289
  server.should_receive(:add_tag).with('Username', 'username')
239
- @environment.add_server(*@args, 'username')
290
+ subject
240
291
  end
241
292
 
242
293
  it "should tag the server with an indexed name" do
243
294
  server.should_receive(:add_tag).with('Name', "#{name} 1")
244
- @environment.add_server(*@args, 'username')
295
+ environment.add_server('username', create_options)
245
296
 
246
297
  server.should_receive(:add_tag).with('Name', "#{name} 2")
247
- @environment.add_server(*@args, 'username')
298
+ environment.add_server('username', create_options)
248
299
  end
249
300
  end
250
301
 
251
- describe :remove_server_from_elb do
302
+ describe '#remove_server_from_elb' do
303
+ subject { environment.remove_server_from_elb(server) }
304
+
252
305
  it "should remove the server from the ELB" do
253
306
  elb.should_receive(:deregister_instances_from_load_balancer).with([server.id], name)
254
- @environment.remove_server_from_elb(server)
307
+ subject
255
308
  end
256
309
  end
257
310
 
258
- describe :add_server_to_elb do
311
+ describe '#add_server_to_elb' do
312
+ subject { environment.add_server_to_elb(server) }
313
+
259
314
  it "should add the server to the ELB" do
260
315
  elb.should_receive(:register_instances_with_load_balancer).with([server.id], name)
261
- @environment.add_server_to_elb(server)
316
+ subject
262
317
  end
263
318
  end
264
319
 
265
320
  context "with one server" do
266
- before :each do
267
- @environment.stub(:servers => [server])
321
+
322
+ before do
323
+ environment.stub(:servers => [server])
268
324
  end
269
325
 
270
326
  describe :add_elb do
@@ -279,17 +335,17 @@ EOF
279
335
  ['ap-southeast-1a'], name,
280
336
  [{'Protocol' => 'TCP', 'LoadBalancerPort' => 80, 'InstancePort' => 80}]
281
337
  )
282
- @environment.add_elb [80]
338
+ environment.add_elb [80]
283
339
  end
284
340
  it "should add the servers to the elb" do
285
341
  elb.should_receive(:register_instances_with_load_balancer).with([server.id], name)
286
- @environment.add_elb [80]
342
+ environment.add_elb [80]
287
343
  end
288
344
 
289
345
  end
290
346
 
291
347
  describe :add_database do
292
- before :each do
348
+ before do
293
349
  Database.stub(:create! => database)
294
350
  end
295
351
 
@@ -297,12 +353,12 @@ EOF
297
353
 
298
354
  it "should create an RDS of the requested size, using the environment name and a random password" do
299
355
  Database.should_receive(:create!).with(name, 'db.m1.small', storage_size, 'password')
300
- @environment.add_database 'db.m1.small', storage_size, 'password'
356
+ environment.add_database 'db.m1.small', storage_size, 'password'
301
357
  end
302
358
 
303
359
  it "should make the database available on the 'database' accessor" do
304
- @environment.add_database 'db.m1.small', storage_size, 'password'
305
- @environment.database.should == database
360
+ environment.add_database 'db.m1.small', storage_size, 'password'
361
+ environment.database.should == database
306
362
  end
307
363
  end
308
364
 
@@ -310,7 +366,7 @@ EOF
310
366
  before {
311
367
  Cloud.stub(:security_groups => { 'non_default' => double(:group, :ip_permissions => ip_permissions) } )
312
368
  }
313
- after { @environment.wait_until_ready }
369
+ after { environment.wait_until_ready }
314
370
 
315
371
  context "with no ip_permissions" do
316
372
  let(:ip_permissions) { [:some_ip_permissions] }
@@ -332,20 +388,20 @@ EOF
332
388
  context "with an RDS" do
333
389
  before :each do
334
390
  Cloud.stub(:security_groups => { 'non_default' => double(:group, :ip_permissions => true) } )
335
- @environment.stub(:database => database)
391
+ environment.stub(:database => database)
336
392
  end
337
393
 
338
394
  describe :wait_until_ready do
339
395
  it "should wait for the database to be ready" do
340
396
  database.should_receive(:wait_until_ready)
341
- @environment.wait_until_ready
397
+ environment.wait_until_ready
342
398
  end
343
399
  end
344
400
 
345
401
  describe :configure_servers_for_database do
346
402
  it "should ask each server to apply credentials from our database" do
347
403
  server.should_receive(:configure_for_database).with(database, 'password')
348
- @environment.configure_servers_for_database 'password'
404
+ environment.configure_servers_for_database 'password'
349
405
  end
350
406
  end
351
407
 
@@ -361,34 +417,43 @@ EOF
361
417
  end
362
418
  end
363
419
 
364
- describe :has_elb? do
420
+ describe '#has_elb?' do
421
+ subject { environment.has_elb? }
422
+
365
423
  it "return true if we have a load balancer" do
366
424
  mock_describe_load_balancers([{'LoadBalancerName' => name}])
367
- @environment.has_elb?.should be_true
425
+ subject.should be_true
368
426
  end
369
427
 
370
428
  it "return false if we don't" do
371
429
  mock_describe_load_balancers([{'LoadBalancerName' => "XXXX"}])
372
- @environment.has_elb?.should be_false
430
+ subject.should be_false
373
431
  end
374
432
 
375
433
  end
376
434
 
377
435
  describe "#show_json" do
378
-
379
436
  let(:servers) { [mock(:dns_name => 'fish.com', :public_ip_address => '1.2.3.4'), mock(:dns_name => 'fish2.com', :public_ip_address => '1.2.3.5')] }
380
437
  let(:output) { servers.map { |s| { 'public_dns' => s.dns_name, 'public_ip' => s.public_ip_address } } }
381
438
 
382
- before do
383
- @environment.stub(:servers => servers)
384
- end
385
-
386
- subject { @environment.show_json }
439
+ subject { environment.show_json }
387
440
 
388
441
  it "should return the correct JSON" do
389
442
  STDOUT.should_receive(:puts).with(JSON.pretty_generate(output))
390
443
  subject
391
444
  end
445
+ end
446
+
447
+ describe '#resize_disks' do
448
+
449
+ let(:servers) { [mock('server1'), mock('server2')] }
450
+
451
+ subject { environment.resize_disks }
452
+
453
+ it "should resize_disk on each server" do
454
+ servers.each { |s| s.should_receive(:resize_disk).with() }
455
+ subject
456
+ end
392
457
 
393
458
  end
394
459