bosh_aws_cpi 0.3.3

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.
@@ -0,0 +1,146 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::AwsCloud::Cloud do
6
+
7
+ before(:each) do
8
+ @registry = mock_registry
9
+ end
10
+
11
+ it "attaches EC2 volume to an instance" do
12
+ instance = double("instance", :id => "i-test")
13
+ volume = double("volume", :id => "v-foobar")
14
+ attachment = double("attachment", :device => "/dev/sdf")
15
+
16
+ cloud = mock_cloud do |ec2|
17
+ ec2.instances.should_receive(:[]).with("i-test").and_return(instance)
18
+ ec2.volumes.should_receive(:[]).with("v-foobar").and_return(volume)
19
+ end
20
+
21
+ volume.should_receive(:attach_to).
22
+ with(instance, "/dev/sdf").and_return(attachment)
23
+
24
+ instance.should_receive(:block_device_mappings).and_return({})
25
+
26
+ attachment.should_receive(:status).and_return(:attaching)
27
+ cloud.should_receive(:wait_resource).with(attachment, :attaching, :attached)
28
+
29
+ old_settings = { "foo" => "bar" }
30
+ new_settings = {
31
+ "foo" => "bar",
32
+ "disks" => {
33
+ "persistent" => {
34
+ "v-foobar" => "/dev/sdf"
35
+ }
36
+ }
37
+ }
38
+
39
+ @registry.should_receive(:read_settings).
40
+ with("i-test").
41
+ and_return(old_settings)
42
+
43
+ @registry.should_receive(:update_settings).with("i-test", new_settings)
44
+
45
+ cloud.attach_disk("i-test", "v-foobar")
46
+ end
47
+
48
+ it "picks available device name" do
49
+ instance = double("instance", :id => "i-test")
50
+ volume = double("volume", :id => "v-foobar")
51
+ attachment = double("attachment", :device => "/dev/sdh")
52
+
53
+ cloud = mock_cloud do |ec2|
54
+ ec2.instances.should_receive(:[]).with("i-test").and_return(instance)
55
+ ec2.volumes.should_receive(:[]).with("v-foobar").and_return(volume)
56
+ end
57
+
58
+ instance.should_receive(:block_device_mappings).
59
+ and_return({ "/dev/sdf" => "foo", "/dev/sdg" => "bar" })
60
+
61
+ volume.should_receive(:attach_to).
62
+ with(instance, "/dev/sdh").and_return(attachment)
63
+
64
+ attachment.should_receive(:status).and_return(:attaching)
65
+ cloud.should_receive(:wait_resource).with(attachment, :attaching, :attached)
66
+
67
+ old_settings = { "foo" => "bar" }
68
+ new_settings = {
69
+ "foo" => "bar",
70
+ "disks" => {
71
+ "persistent" => {
72
+ "v-foobar" => "/dev/sdh"
73
+ }
74
+ }
75
+ }
76
+
77
+ @registry.should_receive(:read_settings).
78
+ with("i-test").
79
+ and_return(old_settings)
80
+
81
+ @registry.should_receive(:update_settings).with("i-test", new_settings)
82
+
83
+ cloud.attach_disk("i-test", "v-foobar")
84
+ end
85
+
86
+ it "picks available device name" do
87
+ instance = double("instance", :id => "i-test")
88
+ volume = double("volume", :id => "v-foobar")
89
+ attachment = double("attachment", :device => "/dev/sdh")
90
+
91
+ cloud = mock_cloud do |ec2|
92
+ ec2.instances.should_receive(:[]).with("i-test").and_return(instance)
93
+ ec2.volumes.should_receive(:[]).with("v-foobar").and_return(volume)
94
+ end
95
+
96
+ instance.should_receive(:block_device_mappings).
97
+ and_return({ "/dev/sdf" => "foo", "/dev/sdg" => "bar" })
98
+
99
+ volume.should_receive(:attach_to).
100
+ with(instance, "/dev/sdh").and_return(attachment)
101
+
102
+ attachment.should_receive(:status).and_return(:attaching)
103
+ cloud.should_receive(:wait_resource).with(attachment, :attaching, :attached)
104
+
105
+ old_settings = { "foo" => "bar" }
106
+ new_settings = {
107
+ "foo" => "bar",
108
+ "disks" => {
109
+ "persistent" => {
110
+ "v-foobar" => "/dev/sdh"
111
+ }
112
+ }
113
+ }
114
+
115
+ @registry.should_receive(:read_settings).
116
+ with("i-test").
117
+ and_return(old_settings)
118
+
119
+ @registry.should_receive(:update_settings).with("i-test", new_settings)
120
+
121
+ cloud.attach_disk("i-test", "v-foobar")
122
+ end
123
+
124
+ it "raises an error when sdf..sdp are all reserved" do
125
+ instance = double("instance", :id => "i-test")
126
+ volume = double("volume", :id => "v-foobar")
127
+
128
+ cloud = mock_cloud do |ec2|
129
+ ec2.instances.should_receive(:[]).with("i-test").and_return(instance)
130
+ ec2.volumes.should_receive(:[]).with("v-foobar").and_return(volume)
131
+ end
132
+
133
+ all_mappings = ("f".."p").inject({}) do |hash, char|
134
+ hash["/dev/sd#{char}"] = "foo"
135
+ hash
136
+ end
137
+
138
+ instance.should_receive(:block_device_mappings).
139
+ and_return(all_mappings)
140
+
141
+ expect {
142
+ cloud.attach_disk("i-test", "v-foobar")
143
+ }.to raise_error(Bosh::Clouds::CloudError, /too many disks attached/)
144
+ end
145
+
146
+ end
@@ -0,0 +1,16 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::AwsCloud::Cloud do
6
+
7
+ describe "creating via provider" do
8
+
9
+ it "can be created using Bosh::Cloud::Provider" do
10
+ cloud = Bosh::Clouds::Provider.create(:aws, mock_cloud_options)
11
+ cloud.should be_an_instance_of(Bosh::AwsCloud::Cloud)
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,92 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::AwsCloud::Cloud do
6
+
7
+ before(:each) do
8
+ @registry = mock_registry
9
+ end
10
+
11
+ it "adds elastic ip from to the instance for vip network" do
12
+ instance = double("instance",
13
+ :id => "i-foobar")
14
+
15
+ cloud = mock_cloud do |ec2|
16
+ ec2.instances.stub(:[]).
17
+ with("i-foobar").
18
+ and_return(instance)
19
+ end
20
+
21
+ old_settings = { "foo" => "bar", "networks" => "baz" }
22
+ new_settings = { "foo" => "bar", "networks" => combined_network_spec }
23
+
24
+ @registry.should_receive(:read_settings).
25
+ with("i-foobar").
26
+ and_return(old_settings)
27
+
28
+ @registry.should_receive(:update_settings).with("i-foobar", new_settings)
29
+
30
+ instance.should_receive(:associate_elastic_ip).with("10.0.0.1")
31
+
32
+ cloud.configure_networks("i-foobar", combined_network_spec)
33
+ end
34
+
35
+ it "removes elastic ip from the instance if vip network is gone" do
36
+ instance = double("instance",
37
+ :id => "i-foobar")
38
+
39
+ cloud = mock_cloud do |ec2|
40
+ ec2.instances.stub(:[]).
41
+ with("i-foobar").
42
+ and_return(instance)
43
+ end
44
+
45
+ instance.should_receive(:elastic_ip).and_return("10.0.0.1")
46
+ instance.should_receive(:disassociate_elastic_ip)
47
+
48
+ old_settings = { "foo" => "bar", "networks" => combined_network_spec }
49
+ new_settings = {
50
+ "foo" => "bar",
51
+ "networks" => {
52
+ "net_a" => dynamic_network_spec
53
+ }
54
+ }
55
+
56
+ @registry.should_receive(:read_settings).
57
+ with("i-foobar").
58
+ and_return(old_settings)
59
+
60
+ @registry.should_receive(:update_settings).with("i-foobar", new_settings)
61
+
62
+ cloud.configure_networks("i-foobar", "net_a" => dynamic_network_spec)
63
+ end
64
+
65
+ it "performs network sanity check" do
66
+ expect {
67
+ mock_cloud.configure_networks("i-foobar", "net_a" => vip_network_spec)
68
+ }.to raise_error(Bosh::Clouds::CloudError,
69
+ "At least one dynamic network should be defined")
70
+
71
+ expect {
72
+ mock_cloud.configure_networks("i-foobar",
73
+ "net_a" => vip_network_spec,
74
+ "net_b" => vip_network_spec)
75
+ }.to raise_error(Bosh::Clouds::CloudError,
76
+ /More than one vip network/)
77
+
78
+ expect {
79
+ mock_cloud.configure_networks("i-foobar",
80
+ "net_a" => dynamic_network_spec,
81
+ "net_b" => dynamic_network_spec)
82
+ }.to raise_error(Bosh::Clouds::CloudError,
83
+ /More than one dynamic network/)
84
+
85
+ expect {
86
+ mock_cloud.configure_networks("i-foobar",
87
+ "net_a" => { "type" => "foo" })
88
+ }.to raise_error(Bosh::Clouds::CloudError,
89
+ /Invalid network type `foo'/)
90
+ end
91
+
92
+ end
@@ -0,0 +1,76 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::AwsCloud::Cloud do
6
+
7
+ it "creates an EC2 volume" do
8
+ disk_params = {
9
+ :size => 2,
10
+ :availability_zone => "us-east-1a"
11
+ }
12
+
13
+ volume = double("volume", :id => "v-foobar")
14
+
15
+ cloud = mock_cloud do |ec2|
16
+ ec2.volumes.should_receive(:create).with(disk_params).and_return(volume)
17
+ end
18
+
19
+ volume.should_receive(:state).and_return(:creating)
20
+ cloud.should_receive(:wait_resource).with(volume, :creating, :available)
21
+
22
+ cloud.create_disk(2048).should == "v-foobar"
23
+ end
24
+
25
+ it "rounds up disk size" do
26
+ disk_params = {
27
+ :size => 3,
28
+ :availability_zone => "us-east-1a"
29
+ }
30
+
31
+ volume = double("volume", :id => "v-foobar")
32
+
33
+ cloud = mock_cloud do |ec2|
34
+ ec2.volumes.should_receive(:create).with(disk_params).and_return(volume)
35
+ end
36
+
37
+ volume.should_receive(:state).and_return(:creating)
38
+ cloud.should_receive(:wait_resource).with(volume, :creating, :available)
39
+
40
+ cloud.create_disk(2049)
41
+ end
42
+
43
+ it "check min and max disk size" do
44
+ expect {
45
+ mock_cloud.create_disk(100)
46
+ }.to raise_error(Bosh::Clouds::CloudError, /minimum disk size is 1 GiB/)
47
+
48
+ expect {
49
+ mock_cloud.create_disk(2000 * 1024)
50
+ }.to raise_error(Bosh::Clouds::CloudError, /maximum disk size is 1 TiB/)
51
+ end
52
+
53
+ it "puts disk in the same AZ as an instance" do
54
+ disk_params = {
55
+ :size => 1,
56
+ :availability_zone => "foobar-land"
57
+ }
58
+
59
+ instance = double("instance",
60
+ :id => "i-test",
61
+ :availability_zone => "foobar-land")
62
+
63
+ volume = double("volume", :id => "v-foobar")
64
+
65
+ cloud = mock_cloud do |ec2|
66
+ ec2.volumes.should_receive(:create).with(disk_params).and_return(volume)
67
+ ec2.instances.stub(:[]).with("i-test").and_return(instance)
68
+ end
69
+
70
+ volume.should_receive(:state).and_return(:creating)
71
+ cloud.should_receive(:wait_resource).with(volume, :creating, :available)
72
+
73
+ cloud.create_disk(1024, "i-test")
74
+ end
75
+
76
+ end
@@ -0,0 +1,107 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::AwsCloud::Cloud do
6
+
7
+ before :each do
8
+ @tmp_dir = Dir.mktmpdir
9
+ end
10
+
11
+ describe "EBS-volume based flow" do
12
+
13
+ it "creates stemcell by copying an image to a new EBS volume" do
14
+ volume = double("volume", :id => "v-foo")
15
+ current_instance = double("instance",
16
+ :id => "i-current",
17
+ :availability_zone => "us-nowhere-2b")
18
+ attachment = double("attachment",
19
+ :device => "/dev/sdh",
20
+ :volume => volume)
21
+
22
+ snapshot = double("snapshot", :id => "s-baz")
23
+ image = double("image", :id => "i-bar")
24
+
25
+ unique_name = UUIDTools::UUID.random_create.to_s
26
+
27
+ image_params = {
28
+ :name => "BOSH-#{unique_name}",
29
+ :architecture => "x86_64",
30
+ :kernel_id => "aki-825ea7eb",
31
+ :root_device_name => "/dev/sda",
32
+ :block_device_mappings => {
33
+ "/dev/sda" => { :snapshot_id => "s-baz" },
34
+ "/dev/sdb" => "ephemeral0"
35
+ }
36
+ }
37
+
38
+ cloud = mock_cloud do |ec2|
39
+ ec2.volumes.stub(:[]).with("v-foo").and_return(volume)
40
+ ec2.instances.stub(:[]).with("i-current").and_return(current_instance)
41
+ ec2.images.should_receive(:create).with(image_params).and_return(image)
42
+ end
43
+
44
+ cloud.stub(:generate_unique_name).and_return(unique_name)
45
+ cloud.stub(:current_instance_id).and_return("i-current")
46
+
47
+ old_mappings = {
48
+ "/dev/sdf" => double("attachment",
49
+ :volume => double("volume",
50
+ :id => "v-zb")),
51
+ "/dev/sdg" => double("attachment",
52
+ :volume => double("volume",
53
+ :id => "v-ppc"))
54
+ }
55
+
56
+ extra_mapping = {
57
+ "/dev/sdh" => attachment
58
+ }
59
+
60
+ new_mappings = old_mappings.merge(extra_mapping)
61
+
62
+ current_instance.stub(:block_device_mappings).
63
+ and_return(old_mappings, new_mappings)
64
+
65
+ cloud.should_receive(:create_disk).with(2048, "i-current").
66
+ and_return("v-foo")
67
+
68
+ volume.should_receive(:attach_to).with(current_instance, "/dev/sdh").
69
+ and_return(attachment)
70
+
71
+ attachment.should_receive(:status).and_return(:attaching)
72
+ cloud.should_receive(:wait_resource).
73
+ with(attachment, :attaching, :attached)
74
+
75
+ cloud.stub(:sleep)
76
+
77
+ File.stub(:blockdev?).with("/dev/sdh").and_return(false, false, false)
78
+ File.stub(:blockdev?).with("/dev/xvdh").and_return(false, false, true)
79
+
80
+ Dir.should_receive(:mktmpdir).and_yield(@tmp_dir)
81
+
82
+ cloud.should_receive(:unpack_image).with(@tmp_dir, "/tmp/foo")
83
+ cloud.should_receive(:copy_root_image).with(@tmp_dir, "/dev/xvdh")
84
+
85
+ volume.should_receive(:create_snapshot).and_return(snapshot)
86
+ snapshot.should_receive(:status).and_return(:in_progress)
87
+ cloud.should_receive(:wait_resource).
88
+ with(snapshot, :in_progress, :completed)
89
+
90
+ image.should_receive(:state).and_return(:creating)
91
+ cloud.should_receive(:wait_resource).with(image,
92
+ :creating, :available, :state)
93
+
94
+ volume.should_receive(:detach_from).with(current_instance, "/dev/sdh").
95
+ and_return(attachment)
96
+
97
+ attachment.should_receive(:status).and_return(:detaching)
98
+ cloud.should_receive(:wait_resource).
99
+ with(attachment, :detaching, :detached)
100
+
101
+ cloud.should_receive(:delete_disk).with("v-foo")
102
+
103
+ cloud.create_stemcell("/tmp/foo", {}).should == "i-bar"
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,134 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::AwsCloud::Cloud, "create_vm" do
6
+
7
+ def agent_settings(unique_name, network_spec=dynamic_network_spec)
8
+ {
9
+ "vm" => {
10
+ "name" => "vm-#{unique_name}"
11
+ },
12
+ "agent_id" => "agent-id",
13
+ "networks" => { "network_a" => network_spec },
14
+ "disks" => {
15
+ "system" => "/dev/sda",
16
+ "ephemeral" => "/dev/sdb",
17
+ "persistent" => {}
18
+ },
19
+ "env" => {
20
+ "test_env" => "value"
21
+ },
22
+ "foo" => "bar", # Agent env
23
+ "baz" => "zaz"
24
+ }
25
+ end
26
+
27
+ def ec2_params(user_data, security_groups=[])
28
+ {
29
+ :image_id => "sc-id",
30
+ :count => 1,
31
+ :key_name => "test_key",
32
+ :security_groups => security_groups,
33
+ :instance_type => "m3.zb",
34
+ :user_data => Yajl::Encoder.encode(user_data),
35
+ :availability_zone => "foobar-1a"
36
+ }
37
+ end
38
+
39
+ before(:each) do
40
+ @registry = mock_registry
41
+ end
42
+
43
+ it "creates EC2 instance and polls until it's ready" do
44
+ unique_name = UUIDTools::UUID.random_create.to_s
45
+
46
+ user_data = {
47
+ "registry" => {
48
+ "endpoint" => "http://registry:3333"
49
+ }
50
+ }
51
+
52
+ instance = double("instance",
53
+ :id => "i-test",
54
+ :elastic_ip => nil)
55
+
56
+ cloud = mock_cloud do |ec2|
57
+ ec2.instances.should_receive(:create).
58
+ with(ec2_params(user_data)).
59
+ and_return(instance)
60
+ end
61
+
62
+ instance.should_receive(:status).and_return(:pending)
63
+ cloud.should_receive(:generate_unique_name).and_return(unique_name)
64
+ cloud.should_receive(:wait_resource).with(instance, :pending, :running)
65
+ @registry.should_receive(:update_settings)
66
+ .with("i-test", agent_settings(unique_name))
67
+
68
+ vm_id = cloud.create_vm("agent-id", "sc-id",
69
+ resource_pool_spec,
70
+ { "network_a" => dynamic_network_spec },
71
+ nil, { "test_env" => "value" })
72
+
73
+ vm_id.should == "i-test"
74
+ end
75
+
76
+ it "creates EC2 instance with security group" do
77
+ unique_name = UUIDTools::UUID.random_create.to_s
78
+
79
+ user_data = {
80
+ "registry" => {
81
+ "endpoint" => "http://registry:3333"
82
+ }
83
+ }
84
+
85
+ instance = double("instance",
86
+ :id => "i-test",
87
+ :elastic_ip => nil)
88
+
89
+ security_groups = %w[foo bar]
90
+ network_spec = dynamic_network_spec
91
+ network_spec["cloud_properties"] = {
92
+ "security_groups" => security_groups
93
+ }
94
+
95
+ cloud = mock_cloud do |ec2|
96
+ ec2.instances.should_receive(:create).
97
+ with(ec2_params(user_data, security_groups)).
98
+ and_return(instance)
99
+ end
100
+
101
+ instance.should_receive(:status).and_return(:pending)
102
+ cloud.should_receive(:generate_unique_name).and_return(unique_name)
103
+ cloud.should_receive(:wait_resource).with(instance, :pending, :running)
104
+ @registry.should_receive(:update_settings)
105
+ .with("i-test", agent_settings(unique_name, network_spec))
106
+
107
+ vm_id = cloud.create_vm("agent-id", "sc-id",
108
+ resource_pool_spec,
109
+ { "network_a" => network_spec },
110
+ nil, { "test_env" => "value" })
111
+
112
+ vm_id.should == "i-test"
113
+ end
114
+
115
+ it "associates instance with elastic ip if vip network is provided" do
116
+ instance = double("instance",
117
+ :id => "i-test",
118
+ :elastic_ip => nil)
119
+
120
+ cloud = mock_cloud do |ec2|
121
+ ec2.instances.should_receive(:create).and_return(instance)
122
+ end
123
+
124
+ instance.should_receive(:status).and_return(:pending)
125
+ instance.should_receive(:associate_elastic_ip).with("10.0.0.1")
126
+ cloud.should_receive(:wait_resource).with(instance, :pending, :running)
127
+ @registry.should_receive(:update_settings)
128
+
129
+ vm_id = cloud.create_vm("agent-id", "sc-id",
130
+ resource_pool_spec,
131
+ combined_network_spec)
132
+ end
133
+
134
+ end