dew 0.3.0 → 0.4.0

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.
@@ -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