bosh_openstack_cpi 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,95 @@
1
+ # Copyright (c) 2012 Piston Cloud Computing, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::OpenStackCloud::Cloud do
6
+
7
+ before(:each) do
8
+ @registry = mock_registry
9
+ end
10
+
11
+ it "attaches an OpenStack volume to a server" do
12
+ server = double("server", :id => "i-test", :name => "i-test")
13
+ volume = double("volume", :id => "v-foobar")
14
+ volume_attachments = double("body", :body => {"volumeAttachments" => []})
15
+ attachment = double("attachment", :device => "/dev/vdc")
16
+
17
+ cloud = mock_cloud do |openstack|
18
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
19
+ openstack.volumes.should_receive(:get).with("v-foobar").and_return(volume)
20
+ openstack.should_receive(:get_server_volumes).and_return(volume_attachments)
21
+ end
22
+
23
+ volume.should_receive(:attach).with(server.id, "/dev/vdc").and_return(attachment)
24
+ volume.should_receive(:status).and_return(:available)
25
+ cloud.should_receive(:wait_resource).with(volume, :available, :"in-use")
26
+
27
+ old_settings = { "foo" => "bar" }
28
+ new_settings = {
29
+ "foo" => "bar",
30
+ "disks" => {
31
+ "persistent" => {
32
+ "v-foobar" => "/dev/vdc"
33
+ }
34
+ }
35
+ }
36
+
37
+ @registry.should_receive(:read_settings).with("i-test").and_return(old_settings)
38
+ @registry.should_receive(:update_settings).with("i-test", new_settings)
39
+
40
+ cloud.attach_disk("i-test", "v-foobar")
41
+ end
42
+
43
+ it "picks available device name" do
44
+ server = double("server", :id => "i-test", :name => "i-test")
45
+ volume = double("volume", :id => "v-foobar")
46
+ volume_attachments = double("body", :body => {"volumeAttachments" => [{"device" => "/dev/vdc"}, {"device" => "/dev/vdd"}]})
47
+ attachment = double("attachment", :device => "/dev/vdd")
48
+
49
+ cloud = mock_cloud do |openstack|
50
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
51
+ openstack.volumes.should_receive(:get).with("v-foobar").and_return(volume)
52
+ openstack.should_receive(:get_server_volumes).and_return(volume_attachments)
53
+ end
54
+
55
+ volume.should_receive(:attach).with(server.id, "/dev/vde").and_return(attachment)
56
+ volume.should_receive(:status).and_return(:available)
57
+ cloud.should_receive(:wait_resource).with(volume, :available, :"in-use")
58
+
59
+ old_settings = { "foo" => "bar" }
60
+ new_settings = {
61
+ "foo" => "bar",
62
+ "disks" => {
63
+ "persistent" => {
64
+ "v-foobar" => "/dev/vde"
65
+ }
66
+ }
67
+ }
68
+
69
+ @registry.should_receive(:read_settings).with("i-test").and_return(old_settings)
70
+ @registry.should_receive(:update_settings).with("i-test", new_settings)
71
+
72
+ cloud.attach_disk("i-test", "v-foobar")
73
+ end
74
+
75
+ it "raises an error when vdc..vdz are all reserved" do
76
+ server = double("server", :id => "i-test", :name => "i-test")
77
+ volume = double("volume", :id => "v-foobar")
78
+ all_mappings = ("c".."z").inject([]) do |array, char|
79
+ array << {"device" => "/dev/vd#{char}"}
80
+ array
81
+ end
82
+ volume_attachments = double("body", :body => {"volumeAttachments" => all_mappings})
83
+
84
+ cloud = mock_cloud do |openstack|
85
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
86
+ openstack.volumes.should_receive(:get).with("v-foobar").and_return(volume)
87
+ openstack.should_receive(:get_server_volumes).and_return(volume_attachments)
88
+ end
89
+
90
+ expect {
91
+ cloud.attach_disk("i-test", "v-foobar")
92
+ }.to raise_error(Bosh::Clouds::CloudError, /too many disks attached/)
93
+ end
94
+
95
+ end
@@ -0,0 +1,18 @@
1
+ # Copyright (c) 2012 Piston Cloud Computing, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::OpenStackCloud::Cloud do
6
+
7
+ describe "creating via provider" do
8
+
9
+ it "can be created using Bosh::Cloud::Provider" do
10
+ Fog::Compute.stub(:new)
11
+ Fog::Image.stub(:new)
12
+ cloud = Bosh::Clouds::Provider.create(:openstack, mock_cloud_options)
13
+ cloud.should be_an_instance_of(Bosh::OpenStackCloud::Cloud)
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,83 @@
1
+ # Copyright (c) 2012 Piston Cloud Computing, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::OpenStackCloud::Cloud do
6
+
7
+ before(:each) do
8
+ @registry = mock_registry
9
+ end
10
+
11
+ it "adds floating ip to the server for vip network" do
12
+ server = double("server", :id => "i-test", :name => "i-test")
13
+ address = double("address", :id => "a-test", :ip => "10.0.0.1", :instance_id => nil)
14
+
15
+ cloud = mock_cloud do |openstack|
16
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
17
+ openstack.addresses.should_receive(:each).and_yield(address)
18
+ end
19
+
20
+ address.should_receive(:server=).with(server)
21
+
22
+ old_settings = { "foo" => "bar", "networks" => "baz" }
23
+ new_settings = { "foo" => "bar", "networks" => combined_network_spec }
24
+
25
+ @registry.should_receive(:read_settings).with("i-test").and_return(old_settings)
26
+ @registry.should_receive(:update_settings).with("i-test", new_settings)
27
+
28
+ cloud.configure_networks("i-test", combined_network_spec)
29
+ end
30
+
31
+ it "removes floating ip from the server if vip network is gone" do
32
+ server = double("server", :id => "i-test", :name => "i-test")
33
+ address = double("address", :id => "a-test", :ip => "10.0.0.1", :instance_id => "i-test")
34
+
35
+ cloud = mock_cloud do |openstack|
36
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
37
+ openstack.addresses.should_receive(:each).and_yield(address)
38
+ end
39
+
40
+ address.should_receive(:server=).with(nil)
41
+
42
+ old_settings = { "foo" => "bar", "networks" => combined_network_spec }
43
+ new_settings = { "foo" => "bar", "networks" => { "net_a" => dynamic_network_spec } }
44
+
45
+ @registry.should_receive(:read_settings).with("i-test").and_return(old_settings)
46
+ @registry.should_receive(:update_settings).with("i-test", new_settings)
47
+
48
+ cloud.configure_networks("i-test", "net_a" => dynamic_network_spec)
49
+ end
50
+
51
+ it "performs network sanity check" do
52
+ server = double("server", :id => "i-test", :name => "i-test")
53
+
54
+ expect {
55
+ cloud = mock_cloud do |openstack|
56
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
57
+ end
58
+ cloud.configure_networks("i-test", "net_a" => vip_network_spec)
59
+ }.to raise_error(Bosh::Clouds::CloudError, "At least one dynamic network should be defined")
60
+
61
+ expect {
62
+ cloud = mock_cloud do |openstack|
63
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
64
+ end
65
+ cloud.configure_networks("i-test", "net_a" => vip_network_spec, "net_b" => vip_network_spec)
66
+ }.to raise_error(Bosh::Clouds::CloudError, /More than one vip network/)
67
+
68
+ expect {
69
+ cloud = mock_cloud do |openstack|
70
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
71
+ end
72
+ cloud.configure_networks("i-test", "net_a" => dynamic_network_spec, "net_b" => dynamic_network_spec)
73
+ }.to raise_error(Bosh::Clouds::CloudError, /More than one dynamic network/)
74
+
75
+ expect {
76
+ cloud = mock_cloud do |openstack|
77
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
78
+ end
79
+ cloud.configure_networks("i-test", "net_a" => { "type" => "foo" })
80
+ }.to raise_error(Bosh::Clouds::CloudError, /Invalid network type `foo'/)
81
+ end
82
+
83
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright (c) 2012 Piston Cloud Computing, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::OpenStackCloud::Cloud do
6
+
7
+ it "creates an OpenStack volume" do
8
+ unique_name = UUIDTools::UUID.random_create.to_s
9
+ disk_params = {
10
+ :name => "volume-#{unique_name}",
11
+ :description => "",
12
+ :size => 2,
13
+ :availability_zone => "nova"
14
+ }
15
+ volume = double("volume", :id => "v-foobar")
16
+
17
+ cloud = mock_cloud do |openstack|
18
+ openstack.volumes.should_receive(:create).with(disk_params).and_return(volume)
19
+ end
20
+
21
+ cloud.should_receive(:generate_unique_name).and_return(unique_name)
22
+ volume.should_receive(:status).and_return(:creating)
23
+ cloud.should_receive(:wait_resource).with(volume, :creating, :available)
24
+
25
+ cloud.create_disk(2048).should == "v-foobar"
26
+ end
27
+
28
+ it "rounds up disk size" do
29
+ unique_name = UUIDTools::UUID.random_create.to_s
30
+ disk_params = {
31
+ :name => "volume-#{unique_name}",
32
+ :description => "",
33
+ :size => 3,
34
+ :availability_zone => "nova"
35
+ }
36
+ volume = double("volume", :id => "v-foobar")
37
+
38
+ cloud = mock_cloud do |openstack|
39
+ openstack.volumes.should_receive(:create).with(disk_params).and_return(volume)
40
+ end
41
+
42
+ cloud.should_receive(:generate_unique_name).and_return(unique_name)
43
+ volume.should_receive(:status).and_return(:creating)
44
+ cloud.should_receive(:wait_resource).with(volume, :creating, :available)
45
+
46
+ cloud.create_disk(2049)
47
+ end
48
+
49
+ it "check min and max disk size" do
50
+ expect {
51
+ mock_cloud.create_disk(100)
52
+ }.to raise_error(Bosh::Clouds::CloudError, /minimum disk size is 1 GiB/)
53
+
54
+ expect {
55
+ mock_cloud.create_disk(2000 * 1024)
56
+ }.to raise_error(Bosh::Clouds::CloudError, /maximum disk size is 1 TiB/)
57
+ end
58
+
59
+ it "puts disk in the same AZ as a server" do
60
+ unique_name = UUIDTools::UUID.random_create.to_s
61
+ disk_params = {
62
+ :name => "volume-#{unique_name}",
63
+ :description => "",
64
+ :size => 1,
65
+ :availability_zone => "foobar-land"
66
+ }
67
+ server = double("server", :id => "i-test", :availability_zone => "foobar-land")
68
+ volume = double("volume", :id => "v-foobar")
69
+
70
+ cloud = mock_cloud do |openstack|
71
+ openstack.servers.should_receive(:get).with("i-test").and_return(server)
72
+ openstack.volumes.should_receive(:create).with(disk_params).and_return(volume)
73
+ end
74
+
75
+ cloud.should_receive(:generate_unique_name).and_return(unique_name)
76
+ volume.should_receive(:status).and_return(:creating)
77
+ cloud.should_receive(:wait_resource).with(volume, :creating, :available)
78
+
79
+ cloud.create_disk(1024, "i-test")
80
+ end
81
+
82
+ end
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2012 Piston Cloud Computing, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::OpenStackCloud::Cloud do
6
+
7
+ before :each do
8
+ @tmp_dir = Dir.mktmpdir
9
+ end
10
+
11
+ describe "Image upload based flow" do
12
+
13
+ it "creates stemcell by uploading an image via Glance" do
14
+ image = double("image", :id => "i-bar", :name => "i-bar")
15
+ unique_name = UUIDTools::UUID.random_create.to_s
16
+ image_params = {
17
+ :name => "BOSH-#{unique_name}",
18
+ :disk_format => "ami",
19
+ :container_format => "ami",
20
+ :location => "#{@tmp_dir}/root.img",
21
+ :is_public => true,
22
+ :properties => {
23
+ :kernel_id => "k-id",
24
+ :ramdisk_id => "r-id",
25
+ }
26
+ }
27
+
28
+ cloud = mock_glance do |glance|
29
+ glance.images.should_receive(:create).with(image_params).and_return(image)
30
+ end
31
+
32
+ Dir.should_receive(:mktmpdir).and_yield(@tmp_dir)
33
+ cloud.should_receive(:unpack_image).with(@tmp_dir, "/tmp/foo")
34
+ cloud.should_receive(:generate_unique_name).and_return(unique_name)
35
+ image.should_receive(:status).and_return(:queued)
36
+ cloud.should_receive(:wait_resource).with(image, :queued, :active)
37
+
38
+ sc_id = cloud.create_stemcell("/tmp/foo", {
39
+ "container_format" => "ami",
40
+ "disk_format" => "ami",
41
+ "kernel_id" => "k-id",
42
+ "ramdisk_id" => "r-id"
43
+ })
44
+
45
+ sc_id.should == "i-bar"
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,142 @@
1
+ # Copyright (c) 2012 Piston Cloud Computing, Inc.
2
+
3
+ require File.expand_path("../../spec_helper", __FILE__)
4
+
5
+ describe Bosh::OpenStackCloud::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/vda",
16
+ "ephemeral" => "/dev/vdb",
17
+ "persistent" => {}
18
+ },
19
+ "env" => {
20
+ "test_env" => "value"
21
+ },
22
+ "foo" => "bar", # Agent env
23
+ "baz" => "zaz"
24
+ }
25
+ end
26
+
27
+ def openstack_params(unique_name, user_data, security_groups=[])
28
+ {
29
+ :name=>"vm-#{unique_name}",
30
+ :image_ref => "sc-id",
31
+ :flavor_ref => "f-test",
32
+ :key_name => "test_key",
33
+ :security_groups => security_groups.map { |secgrp| {:name => secgrp} },
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 an OpenStack server and polls until it's ready" do
44
+ unique_name = UUIDTools::UUID.random_create.to_s
45
+ user_data = {
46
+ "registry" => {
47
+ "endpoint" => "http://registry:3333"
48
+ },
49
+ "server" => {
50
+ "name" => "vm-#{unique_name}"
51
+ }
52
+ }
53
+ server = double("server", :id => "i-test", :name => "i-test")
54
+ image = double("image", :id => "sc-id", :name => "sc-id")
55
+ flavor = double("flavor", :id => "f-test", :name => "m1.tiny")
56
+ address = double("address", :id => "a-test", :ip => "10.0.0.1", :instance_id => "i-test")
57
+
58
+ cloud = mock_cloud do |openstack|
59
+ openstack.servers.should_receive(:create).with(openstack_params(unique_name, user_data)).and_return(server)
60
+ openstack.images.should_receive(:find).and_return(image)
61
+ openstack.flavors.should_receive(:find).and_return(flavor)
62
+ openstack.addresses.should_receive(:each).and_yield(address)
63
+ end
64
+
65
+ cloud.should_receive(:generate_unique_name).and_return(unique_name)
66
+ address.should_receive(:server=).with(nil)
67
+ server.should_receive(:state).and_return(:build)
68
+ cloud.should_receive(:wait_resource).with(server, :build, :active, :state)
69
+
70
+ @registry.should_receive(:update_settings).with("i-test", agent_settings(unique_name))
71
+
72
+ vm_id = cloud.create_vm("agent-id", "sc-id",
73
+ resource_pool_spec,
74
+ { "network_a" => dynamic_network_spec },
75
+ nil, { "test_env" => "value" })
76
+ vm_id.should == "i-test"
77
+ end
78
+
79
+ it "creates an OpenStack server with security group" do
80
+ unique_name = UUIDTools::UUID.random_create.to_s
81
+ user_data = {
82
+ "registry" => {
83
+ "endpoint" => "http://registry:3333"
84
+ },
85
+ "server" => {
86
+ "name" => "vm-#{unique_name}"
87
+ }
88
+ }
89
+ security_groups = %w[foo bar]
90
+ network_spec = dynamic_network_spec
91
+ network_spec["cloud_properties"] = { "security_groups" => security_groups }
92
+ server = double("server", :id => "i-test", :name => "i-test")
93
+ image = double("image", :id => "sc-id", :name => "sc-id")
94
+ flavor = double("flavor", :id => "f-test", :name => "m1.tiny")
95
+ address = double("address", :id => "a-test", :ip => "10.0.0.1", :instance_id => nil)
96
+
97
+ cloud = mock_cloud do |openstack|
98
+ openstack.servers.should_receive(:create).with(openstack_params(unique_name, user_data, security_groups)).and_return(server)
99
+ openstack.images.should_receive(:find).and_return(image)
100
+ openstack.flavors.should_receive(:find).and_return(flavor)
101
+ openstack.addresses.should_receive(:each).and_yield(address)
102
+ end
103
+
104
+ cloud.should_receive(:generate_unique_name).and_return(unique_name)
105
+ server.should_receive(:state).and_return(:build)
106
+ cloud.should_receive(:wait_resource).with(server, :build, :active, :state)
107
+
108
+ @registry.should_receive(:update_settings).with("i-test", agent_settings(unique_name, network_spec))
109
+
110
+ vm_id = cloud.create_vm("agent-id", "sc-id",
111
+ resource_pool_spec,
112
+ { "network_a" => network_spec },
113
+ nil, { "test_env" => "value" })
114
+ vm_id.should == "i-test"
115
+ end
116
+
117
+ it "associates server with floating ip if vip network is provided" do
118
+ server = double("server", :id => "i-test", :name => "i-test")
119
+ image = double("image", :id => "sc-id", :name => "sc-id")
120
+ flavor = double("flavor", :id => "f-test", :name => "m1.tiny")
121
+ address = double("address", :id => "a-test", :ip => "10.0.0.1", :instance_id => "i-test")
122
+
123
+ cloud = mock_cloud do |openstack|
124
+ openstack.servers.should_receive(:create).and_return(server)
125
+ openstack.images.should_receive(:find).and_return(image)
126
+ openstack.flavors.should_receive(:find).and_return(flavor)
127
+ openstack.addresses.should_receive(:each).and_yield(address)
128
+ end
129
+
130
+ address.should_receive(:server=).with(nil)
131
+ address.should_receive(:server=).with(server)
132
+ server.should_receive(:state).and_return(:build)
133
+ cloud.should_receive(:wait_resource).with(server, :build, :active, :state)
134
+
135
+ @registry.should_receive(:update_settings)
136
+
137
+ vm_id = cloud.create_vm("agent-id", "sc-id",
138
+ resource_pool_spec,
139
+ combined_network_spec)
140
+ end
141
+
142
+ end