bosh_openstack_cpi 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/bosh_openstack_console +5 -0
- data/lib/cloud/openstack/cloud.rb +88 -16
- data/lib/cloud/openstack/version.rb +1 -1
- data/spec/unit/create_stemcell_spec.rb +95 -2
- data/spec/unit/delete_stemcell_spec.rb +58 -4
- metadata +10 -10
data/bin/bosh_openstack_console
CHANGED
@@ -49,6 +49,10 @@ module ConsoleHelpers
|
|
49
49
|
cpi.openstack
|
50
50
|
end
|
51
51
|
|
52
|
+
def glance
|
53
|
+
cpi.glance
|
54
|
+
end
|
55
|
+
|
52
56
|
def registry
|
53
57
|
cpi.registry
|
54
58
|
end
|
@@ -70,5 +74,6 @@ end
|
|
70
74
|
puts "=> Welcome to BOSH OpenStack CPI console"
|
71
75
|
puts "You can use 'cpi' to access CPI methods"
|
72
76
|
puts "You can use 'openstack' to access Fog::Compute::OpenStack methods"
|
77
|
+
puts "You can use 'glance' to access Fog::Image::OpenStack methods"
|
73
78
|
|
74
79
|
IRB.start
|
@@ -56,37 +56,72 @@ module Bosh::OpenStackCloud
|
|
56
56
|
# @param [String] image_path local filesystem path to a stemcell image
|
57
57
|
# @param [Hash] cloud_properties CPI-specific properties
|
58
58
|
def create_stemcell(image_path, cloud_properties)
|
59
|
-
# TODO: refactor into several smaller methods
|
60
59
|
with_thread_name("create_stemcell(#{image_path}...)") do
|
61
60
|
begin
|
62
61
|
Dir.mktmpdir do |tmp_dir|
|
63
62
|
@logger.info("Extracting stemcell to `#{tmp_dir}'")
|
63
|
+
image_name = "BOSH-#{generate_unique_name}"
|
64
64
|
|
65
65
|
# 1. Unpack image to temp directory
|
66
66
|
unpack_image(tmp_dir, image_path)
|
67
67
|
root_image = File.join(tmp_dir, "root.img")
|
68
68
|
|
69
|
-
# 2.
|
69
|
+
# 2. If image contains a kernel file, upload it
|
70
|
+
kernel_id = nil
|
71
|
+
if cloud_properties["kernel_id"]
|
72
|
+
kernel_id = cloud_properties["kernel_id"]
|
73
|
+
elsif cloud_properties["kernel_file"]
|
74
|
+
kernel_image = File.join(tmp_dir, cloud_properties["kernel_file"])
|
75
|
+
unless File.exists?(kernel_image)
|
76
|
+
cloud_error("Kernel image is missing from stemcell archive")
|
77
|
+
end
|
78
|
+
kernel_params = {
|
79
|
+
:name => "AKI-#{image_name}",
|
80
|
+
:disk_format => "aki",
|
81
|
+
:container_format => "aki",
|
82
|
+
:location => kernel_image,
|
83
|
+
:properties => {
|
84
|
+
:stemcell => image_name
|
85
|
+
}
|
86
|
+
}
|
87
|
+
kernel_id = upload_image(kernel_params)
|
88
|
+
end
|
89
|
+
|
90
|
+
# 3. If image contains a ramdisk file, upload it
|
91
|
+
ramdisk_id = nil
|
92
|
+
if cloud_properties["ramdisk_id"]
|
93
|
+
ramdisk_id = cloud_properties["ramdisk_id"]
|
94
|
+
elsif cloud_properties["ramdisk_file"]
|
95
|
+
ramdisk_image = File.join(tmp_dir, cloud_properties["ramdisk_file"])
|
96
|
+
unless File.exists?(kernel_image)
|
97
|
+
cloud_error("Ramdisk image is missing from stemcell archive")
|
98
|
+
end
|
99
|
+
ramdisk_params = {
|
100
|
+
:name => "ARI-#{image_name}",
|
101
|
+
:disk_format => "ari",
|
102
|
+
:container_format => "ari",
|
103
|
+
:location => ramdisk_image,
|
104
|
+
:properties => {
|
105
|
+
:stemcell => image_name
|
106
|
+
}
|
107
|
+
}
|
108
|
+
ramdisk_id = upload_image(ramdisk_params)
|
109
|
+
end
|
110
|
+
|
111
|
+
# 4. Upload image using Glance service
|
70
112
|
image_params = {
|
71
|
-
:name =>
|
113
|
+
:name => image_name,
|
72
114
|
:disk_format => cloud_properties["disk_format"],
|
73
115
|
:container_format => cloud_properties["container_format"],
|
74
|
-
:properties => {
|
75
|
-
:kernel_id => cloud_properties["kernel_id"],
|
76
|
-
:ramdisk_id => cloud_properties["ramdisk_id"],
|
77
|
-
},
|
78
116
|
:location => root_image,
|
79
117
|
:is_public => true
|
80
118
|
}
|
119
|
+
image_properties = {}
|
120
|
+
image_properties[:kernel_id] = kernel_id if kernel_id
|
121
|
+
image_properties[:ramdisk_id] = ramdisk_id if ramdisk_id
|
122
|
+
image_params[:properties] = image_properties unless image_properties.empty?
|
81
123
|
|
82
|
-
|
83
|
-
image = @glance.images.create(image_params)
|
84
|
-
state = image.status
|
85
|
-
|
86
|
-
@logger.info("Creating new image `#{image.id}', state is `#{state}'")
|
87
|
-
wait_resource(image, state, :active)
|
88
|
-
|
89
|
-
image.id.to_s
|
124
|
+
upload_image(image_params)
|
90
125
|
end
|
91
126
|
rescue => e
|
92
127
|
@logger.error(e)
|
@@ -101,7 +136,30 @@ module Bosh::OpenStackCloud
|
|
101
136
|
def delete_stemcell(stemcell_id)
|
102
137
|
with_thread_name("delete_stemcell(#{stemcell_id})") do
|
103
138
|
@logger.info("Deleting `#{stemcell_id}' stemcell")
|
104
|
-
image = @
|
139
|
+
image = @glance.images.find_by_id(stemcell_id)
|
140
|
+
|
141
|
+
kernel_id = image.properties["kernel_id"]
|
142
|
+
if kernel_id
|
143
|
+
kernel = @glance.images.find_by_id(kernel_id)
|
144
|
+
if kernel.properties["stemcell"]
|
145
|
+
if kernel.properties["stemcell"] == image.name
|
146
|
+
@logger.info("Deleting `#{stemcell_id}' stemcell kernel")
|
147
|
+
kernel.destroy
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
ramdisk_id = image.properties["ramdisk_id"]
|
153
|
+
if ramdisk_id
|
154
|
+
ramdisk = @glance.images.find_by_id(ramdisk_id)
|
155
|
+
if ramdisk.properties["stemcell"]
|
156
|
+
if ramdisk.properties["stemcell"] == image.name
|
157
|
+
@logger.info("Deleting `#{stemcell_id}' stemcell ramdisk")
|
158
|
+
ramdisk.destroy
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
105
163
|
image.destroy
|
106
164
|
end
|
107
165
|
end
|
@@ -456,6 +514,20 @@ module Bosh::OpenStackCloud
|
|
456
514
|
wait_resource(volume, state, :available)
|
457
515
|
end
|
458
516
|
|
517
|
+
##
|
518
|
+
# Uploads a new image to OpenStack via Glance
|
519
|
+
# @param [Hash] image_params Image params
|
520
|
+
def upload_image(image_params)
|
521
|
+
@logger.info("Creating new image...")
|
522
|
+
image = @glance.images.create(image_params)
|
523
|
+
state = image.status
|
524
|
+
|
525
|
+
@logger.info("Creating new image `#{image.id}', state is `#{state}'")
|
526
|
+
wait_resource(image, state, :active)
|
527
|
+
|
528
|
+
image.id.to_s
|
529
|
+
end
|
530
|
+
|
459
531
|
##
|
460
532
|
# Reads current server id from OpenStack metadata. We are assuming
|
461
533
|
# server id cannot change while current process is running
|
@@ -10,7 +10,36 @@ describe Bosh::OpenStackCloud::Cloud do
|
|
10
10
|
|
11
11
|
describe "Image upload based flow" do
|
12
12
|
|
13
|
-
it "creates stemcell by uploading an image
|
13
|
+
it "creates stemcell by uploading an image without kernel nor ramdisk" 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
|
+
}
|
23
|
+
|
24
|
+
cloud = mock_glance do |glance|
|
25
|
+
glance.images.should_receive(:create).with(image_params).and_return(image)
|
26
|
+
end
|
27
|
+
|
28
|
+
Dir.should_receive(:mktmpdir).and_yield(@tmp_dir)
|
29
|
+
cloud.should_receive(:unpack_image).with(@tmp_dir, "/tmp/foo")
|
30
|
+
cloud.should_receive(:generate_unique_name).and_return(unique_name)
|
31
|
+
image.should_receive(:status).and_return(:queued)
|
32
|
+
cloud.should_receive(:wait_resource).with(image, :queued, :active)
|
33
|
+
|
34
|
+
sc_id = cloud.create_stemcell("/tmp/foo", {
|
35
|
+
"container_format" => "ami",
|
36
|
+
"disk_format" => "ami"
|
37
|
+
})
|
38
|
+
|
39
|
+
sc_id.should == "i-bar"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "creates stemcell by uploading an image using kernel and ramdisk id's" do
|
14
43
|
image = double("image", :id => "i-bar", :name => "i-bar")
|
15
44
|
unique_name = UUIDTools::UUID.random_create.to_s
|
16
45
|
image_params = {
|
@@ -39,7 +68,71 @@ describe Bosh::OpenStackCloud::Cloud do
|
|
39
68
|
"container_format" => "ami",
|
40
69
|
"disk_format" => "ami",
|
41
70
|
"kernel_id" => "k-id",
|
42
|
-
"ramdisk_id" => "r-id"
|
71
|
+
"ramdisk_id" => "r-id",
|
72
|
+
"kernel_file" => "kernel.img",
|
73
|
+
"ramdisk_file" => "initrd.img"
|
74
|
+
})
|
75
|
+
|
76
|
+
sc_id.should == "i-bar"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "creates stemcell by uploading image, kernel and ramdisk" do
|
80
|
+
image = double("image", :id => "i-bar", :name => "i-bar")
|
81
|
+
kernel = double("image", :id => "k-img-id", :name => "k-img-id")
|
82
|
+
ramdisk = double("image", :id => "r-img-id", :name => "r-img-id")
|
83
|
+
unique_name = UUIDTools::UUID.random_create.to_s
|
84
|
+
kernel_params = {
|
85
|
+
:name => "AKI-BOSH-#{unique_name}",
|
86
|
+
:disk_format => "aki",
|
87
|
+
:container_format => "aki",
|
88
|
+
:location => "#{@tmp_dir}/kernel.img",
|
89
|
+
:properties => {
|
90
|
+
:stemcell => "BOSH-#{unique_name}",
|
91
|
+
}
|
92
|
+
}
|
93
|
+
ramdisk_params = {
|
94
|
+
:name => "ARI-BOSH-#{unique_name}",
|
95
|
+
:disk_format => "ari",
|
96
|
+
:container_format => "ari",
|
97
|
+
:location => "#{@tmp_dir}/initrd.img",
|
98
|
+
:properties => {
|
99
|
+
:stemcell => "BOSH-#{unique_name}",
|
100
|
+
}
|
101
|
+
}
|
102
|
+
image_params = {
|
103
|
+
:name => "BOSH-#{unique_name}",
|
104
|
+
:disk_format => "ami",
|
105
|
+
:container_format => "ami",
|
106
|
+
:location => "#{@tmp_dir}/root.img",
|
107
|
+
:is_public => true,
|
108
|
+
:properties => {
|
109
|
+
:kernel_id => "k-img-id",
|
110
|
+
:ramdisk_id => "r-img-id",
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
cloud = mock_glance do |glance|
|
115
|
+
glance.images.should_receive(:create).with(kernel_params).and_return(kernel)
|
116
|
+
glance.images.should_receive(:create).with(ramdisk_params).and_return(ramdisk)
|
117
|
+
glance.images.should_receive(:create).with(image_params).and_return(image)
|
118
|
+
end
|
119
|
+
|
120
|
+
Dir.should_receive(:mktmpdir).and_yield(@tmp_dir)
|
121
|
+
cloud.should_receive(:unpack_image).with(@tmp_dir, "/tmp/foo")
|
122
|
+
File.stub(:exists?).and_return(true)
|
123
|
+
cloud.should_receive(:generate_unique_name).and_return(unique_name)
|
124
|
+
kernel.should_receive(:status).and_return(:queued)
|
125
|
+
cloud.should_receive(:wait_resource).with(kernel, :queued, :active)
|
126
|
+
ramdisk.should_receive(:status).and_return(:queued)
|
127
|
+
cloud.should_receive(:wait_resource).with(ramdisk, :queued, :active)
|
128
|
+
image.should_receive(:status).and_return(:queued)
|
129
|
+
cloud.should_receive(:wait_resource).with(image, :queued, :active)
|
130
|
+
|
131
|
+
sc_id = cloud.create_stemcell("/tmp/foo", {
|
132
|
+
"container_format" => "ami",
|
133
|
+
"disk_format" => "ami",
|
134
|
+
"kernel_file" => "kernel.img",
|
135
|
+
"ramdisk_file" => "initrd.img"
|
43
136
|
})
|
44
137
|
|
45
138
|
sc_id.should == "i-bar"
|
@@ -4,11 +4,65 @@ require File.expand_path("../../spec_helper", __FILE__)
|
|
4
4
|
|
5
5
|
describe Bosh::OpenStackCloud::Cloud do
|
6
6
|
|
7
|
-
it "deregisters OpenStack image" do
|
8
|
-
image = double("image", :id => "i-foo"
|
7
|
+
it "deregisters OpenStack image with no kernel nor ramdisk associated" do
|
8
|
+
image = double("image", :id => "i-foo", :name => "i-foo",
|
9
|
+
:properties => {})
|
9
10
|
|
10
|
-
cloud =
|
11
|
-
|
11
|
+
cloud = mock_glance do |glance|
|
12
|
+
glance.images.stub(:find_by_id).with("i-foo").and_return(image)
|
13
|
+
end
|
14
|
+
|
15
|
+
image.should_receive(:destroy)
|
16
|
+
|
17
|
+
cloud.delete_stemcell("i-foo")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "deregisters OpenStack image, kernel and ramdisk" do
|
21
|
+
image = double("image", :id => "i-foo", :name => "i-foo",
|
22
|
+
:properties => {"kernel_id" => "k-id", "ramdisk_id" => "r-id"})
|
23
|
+
kernel = double("image", :id => "k-id", :properties => {"stemcell" => "i-foo"})
|
24
|
+
ramdisk = double("image", :id => "r-id", :properties => {"stemcell" => "i-foo"})
|
25
|
+
|
26
|
+
cloud = mock_glance do |glance|
|
27
|
+
glance.images.stub(:find_by_id).with("i-foo").and_return(image)
|
28
|
+
glance.images.stub(:find_by_id).with("k-id").and_return(kernel)
|
29
|
+
glance.images.stub(:find_by_id).with("r-id").and_return(ramdisk)
|
30
|
+
end
|
31
|
+
|
32
|
+
kernel.should_receive(:destroy)
|
33
|
+
ramdisk.should_receive(:destroy)
|
34
|
+
image.should_receive(:destroy)
|
35
|
+
|
36
|
+
cloud.delete_stemcell("i-foo")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "deregisters OpenStack image with kernel and ramdisk not uploaded by the CPI" do
|
40
|
+
image = double("image", :id => "i-foo", :name => "i-foo",
|
41
|
+
:properties => {"kernel_id" => "k-id", "ramdisk_id" => "r-id"})
|
42
|
+
kernel = double("image", :id => "k-id", :properties => {})
|
43
|
+
ramdisk = double("image", :id => "r-id", :properties => {})
|
44
|
+
|
45
|
+
cloud = mock_glance do |glance|
|
46
|
+
glance.images.stub(:find_by_id).with("i-foo").and_return(image)
|
47
|
+
glance.images.stub(:find_by_id).with("k-id").and_return(kernel)
|
48
|
+
glance.images.stub(:find_by_id).with("r-id").and_return(ramdisk)
|
49
|
+
end
|
50
|
+
|
51
|
+
image.should_receive(:destroy)
|
52
|
+
|
53
|
+
cloud.delete_stemcell("i-foo")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "deregisters OpenStack image with kernel and ramdisk that belongs to other stemcell" do
|
57
|
+
image = double("image", :id => "i-foo", :name => "i-foo",
|
58
|
+
:properties => {"kernel_id" => "k-id", "ramdisk_id" => "r-id"})
|
59
|
+
kernel = double("image", :id => "k-id", :properties => {"stemcell" => "i-bar"})
|
60
|
+
ramdisk = double("image", :id => "r-id", :properties => {"stemcell" => "i-bar"})
|
61
|
+
|
62
|
+
cloud = mock_glance do |glance|
|
63
|
+
glance.images.stub(:find_by_id).with("i-foo").and_return(image)
|
64
|
+
glance.images.stub(:find_by_id).with("k-id").and_return(kernel)
|
65
|
+
glance.images.stub(:find_by_id).with("r-id").and_return(ramdisk)
|
12
66
|
end
|
13
67
|
|
14
68
|
image.should_receive(:destroy)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bosh_openstack_cpi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fog
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 1.
|
21
|
+
version: 1.5.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 1.
|
29
|
+
version: 1.5.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: bosh_common
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - ! '>='
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: 0.
|
37
|
+
version: 0.5.0
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 0.
|
45
|
+
version: 0.5.0
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: bosh_cpi
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -50,7 +50,7 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - ! '>='
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.4.
|
53
|
+
version: 0.4.4
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.4.
|
61
|
+
version: 0.4.4
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: httpclient
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -156,7 +156,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
156
|
version: '0'
|
157
157
|
segments:
|
158
158
|
- 0
|
159
|
-
hash:
|
159
|
+
hash: 4125051121174364727
|
160
160
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
161
|
none: false
|
162
162
|
requirements:
|
@@ -165,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
165
|
version: '0'
|
166
166
|
segments:
|
167
167
|
- 0
|
168
|
-
hash:
|
168
|
+
hash: 4125051121174364727
|
169
169
|
requirements: []
|
170
170
|
rubyforge_project:
|
171
171
|
rubygems_version: 1.8.24
|