bosh_openstack_cpi 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +24 -4
- data/USAGE.md +103 -0
- data/bosh_cpi.md +82 -0
- data/lib/cloud/openstack/cloud.rb +60 -16
- data/lib/cloud/openstack/version.rb +1 -1
- data/spec/spec_helper.rb +3 -0
- data/spec/unit/cloud_spec.rb +35 -1
- data/spec/unit/create_stemcell_spec.rb +115 -1
- data/spec/unit/create_vm_spec.rb +46 -0
- data/spec/unit/set_vm_metadata_spec.rb +34 -0
- metadata +6 -2
data/Rakefile
CHANGED
@@ -14,6 +14,16 @@ begin
|
|
14
14
|
rescue LoadError
|
15
15
|
end
|
16
16
|
|
17
|
+
begin
|
18
|
+
require "bundler_task"
|
19
|
+
rescue LoadError
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
require "ci_task"
|
24
|
+
rescue LoadError
|
25
|
+
end
|
26
|
+
|
17
27
|
gem_helper = Bundler::GemHelper.new(Dir.pwd)
|
18
28
|
|
19
29
|
desc "Build CPI gem into the pkg directory"
|
@@ -21,10 +31,14 @@ task "build" do
|
|
21
31
|
gem_helper.build_gem
|
22
32
|
end
|
23
33
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
34
|
+
if defined?(BundlerTask)
|
35
|
+
BundlerTask.new
|
36
|
+
|
37
|
+
desc "Build and install CPI into system gems"
|
38
|
+
task "install" do
|
39
|
+
Rake::Task["bundler:install"].invoke
|
40
|
+
gem_helper.install_gem
|
41
|
+
end
|
28
42
|
end
|
29
43
|
|
30
44
|
if defined?(RSpec)
|
@@ -34,6 +48,12 @@ if defined?(RSpec)
|
|
34
48
|
t.pattern = "spec/unit/**/*_spec.rb"
|
35
49
|
t.rspec_opts = %w(--format progress --colour)
|
36
50
|
end
|
51
|
+
|
52
|
+
if defined?(CiTask)
|
53
|
+
CiTask.new do |task|
|
54
|
+
task.rspec_task = rspec_task
|
55
|
+
end
|
56
|
+
end
|
37
57
|
end
|
38
58
|
|
39
59
|
desc "Run tests"
|
data/USAGE.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# BOSH OpenStack Cloud Provider Interface
|
2
|
+
# Copyright (c) 2012 Piston Cloud Computing, Inc.
|
3
|
+
|
4
|
+
For online documentation see: http://rubydoc.info/gems/bosh_openstack_cpi/
|
5
|
+
|
6
|
+
## Options
|
7
|
+
|
8
|
+
These options are passed to the OpenStack CPI when it is instantiated.
|
9
|
+
|
10
|
+
### OpenStack options
|
11
|
+
|
12
|
+
* `auth_url` (required)
|
13
|
+
URL of the OpenStack Identity endpoint to connect to
|
14
|
+
* `username` (required)
|
15
|
+
OpenStack user name
|
16
|
+
* `api_key` (required)
|
17
|
+
OpenStack API key
|
18
|
+
* `tenant` (required)
|
19
|
+
OpenStack tenant name
|
20
|
+
* `region` (optional)
|
21
|
+
OpenStack region
|
22
|
+
* `default_key_name` (required)
|
23
|
+
default OpenStack ssh key name to assign to created virtual machines
|
24
|
+
* `default_security_group` (required)
|
25
|
+
default OpenStack security group to assign to created virtual machines
|
26
|
+
* `private_key` (required)
|
27
|
+
local path to the ssh private key, must match `default_key_name`
|
28
|
+
|
29
|
+
### Registry options
|
30
|
+
|
31
|
+
The registry options are passed to the Openstack CPI by the BOSH director based on the settings in `director.yml`, but can be overridden if needed.
|
32
|
+
|
33
|
+
* `endpoint` (required)
|
34
|
+
OpenStack registry URL
|
35
|
+
* `user` (required)
|
36
|
+
OpenStack registry user
|
37
|
+
* `password` (required)
|
38
|
+
rOpenStack egistry password
|
39
|
+
|
40
|
+
### Agent options
|
41
|
+
|
42
|
+
Agent options are passed to the OpenStack CPI by the BOSH director based on the settings in `director.yml`, but can be overridden if needed.
|
43
|
+
|
44
|
+
### Resource pool options
|
45
|
+
|
46
|
+
These options are specified under `cloud_options` in the `resource_pools` section of a BOSH deployment manifest.
|
47
|
+
|
48
|
+
* `instance_type` (required)
|
49
|
+
which type of instance (OpenStack flavor) the VMs should belong to
|
50
|
+
* `availability_zone` (optional)
|
51
|
+
the OpenStack availability zone the VMs should be created in
|
52
|
+
|
53
|
+
### Network options
|
54
|
+
|
55
|
+
These options are specified under `cloud_options` in the `networks` section of a BOSH deployment manifest.
|
56
|
+
|
57
|
+
* `type` (required)
|
58
|
+
can be either `dynamic` for a DHCP assigned IP by OpenStack, or `vip` to use a Floating IP (which needs to be already allocated)
|
59
|
+
|
60
|
+
## Example
|
61
|
+
|
62
|
+
This is a sample of how OpenStack specific properties are used in a BOSH deployment manifest:
|
63
|
+
|
64
|
+
---
|
65
|
+
name: sample
|
66
|
+
director_uuid: 38ce80c3-e9e9-4aac-ba61-97c676631b91
|
67
|
+
|
68
|
+
...
|
69
|
+
|
70
|
+
networks:
|
71
|
+
- name: nginx_network
|
72
|
+
type: vip
|
73
|
+
cloud_properties: {}
|
74
|
+
- name: default
|
75
|
+
type: dynamic
|
76
|
+
cloud_properties:
|
77
|
+
security_groups:
|
78
|
+
- default
|
79
|
+
|
80
|
+
...
|
81
|
+
|
82
|
+
resource_pools:
|
83
|
+
- name: common
|
84
|
+
network: default
|
85
|
+
size: 3
|
86
|
+
stemcell:
|
87
|
+
name: bosh-stemcell
|
88
|
+
version: 0.6.7
|
89
|
+
cloud_properties:
|
90
|
+
instance_type: m1.small
|
91
|
+
|
92
|
+
...
|
93
|
+
|
94
|
+
properties:
|
95
|
+
openstack:
|
96
|
+
auth_url: http://pistoncloud.com/:5000/v2.0/tokens
|
97
|
+
username: christopher
|
98
|
+
api_key: QRoqsenPsNGX6
|
99
|
+
tenant: Bosh
|
100
|
+
region: us-west
|
101
|
+
default_key_name: bosh
|
102
|
+
default_security_groups: ["bosh"]
|
103
|
+
private_key: /home/bosh/.ssh/bosh.pem
|
data/bosh_cpi.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
#OpenStack CPI Implementation #
|
2
|
+
OpenStack CPI is an implementation of BOSH CPI. It allows BOSH to interface with various services in OpenStack like glance, controller and registry. In the sections below we outline the implementation details for each of the method in CPI interface.
|
3
|
+
|
4
|
+
##Initialize ##
|
5
|
+
|
6
|
+
Implementation of `def initialize(options)` method.
|
7
|
+
|
8
|
+
1. Validate the `options` passed to this method
|
9
|
+
2. In the second step the parameters are extracted from `options` object to populate the following properties
|
10
|
+
+ `@agent_properties`
|
11
|
+
+ `@openstack_properties`
|
12
|
+
+ `@registry_propertiess`
|
13
|
+
3. Populate the `openstack_params` and connect to remove Nova Service
|
14
|
+
1. Instantiate `Fog::Compute` instance
|
15
|
+
2. `Fog::Compute::OpenStack` instance is created
|
16
|
+
3. A New `Fog::Connection` object connects with the remove Nova Compute Service
|
17
|
+
4. Populate the `glance_params`and connect to remove Glance service
|
18
|
+
1. Instantiate `Fog::Image` instance
|
19
|
+
2. `Fog::Image::OpenStack` instance is created
|
20
|
+
3. A New `Fog::Connection` object connects with the remove Glance Service
|
21
|
+
5. Instantiate `Registry_Client`.
|
22
|
+
|
23
|
+
Figure below shows the flow of control.
|
24
|
+
|
25
|
+
![openstack_cpi_initialize](https://raw.github.com/piston/openstack-bosh-cpi/master/images/openstack_cpi_initialize.png)
|
26
|
+
|
27
|
+
##Create Stemcell ##
|
28
|
+
|
29
|
+
Implementation of method `create_stemcell(image_path, cloud_properties)`
|
30
|
+
Steps outlined below are the flow control implemented to extract and upload kernel image, ramdisk and stem cell image.
|
31
|
+
|
32
|
+
1. Extract parameters from the `cloud_properties`. Check if `kernel_file` parameter exists, instantiate `kernel_image` object
|
33
|
+
2. Construct `kernel_params`
|
34
|
+
3. Upload `kernel_image` to glance service by calling the method `upload_image(kernel_params)`
|
35
|
+
4. If params contain `ramdisk_file`
|
36
|
+
5. Instantiate ramdisk_image object and populate `ramdisk_parama`
|
37
|
+
6. Upload the `ramdisk_image` to glance service by calling `upload(ramdisk_params)`
|
38
|
+
7. Populate `image_params` for the stem cell to be uploaded to glance service
|
39
|
+
8. Call the method `upload_image(image_params)`
|
40
|
+
|
41
|
+
Figure below shows the flow control for the method `create_stemcell(image_path, cloud_properties)`
|
42
|
+
|
43
|
+
![openstack_cpi_createstemcell](https://raw.github.com/piston/openstack-bosh-cpi/master/images/openstack_cpi_createstemcell.png)
|
44
|
+
|
45
|
+
##Delete Stemcell
|
46
|
+
|
47
|
+
![openstack_cpi_deletestemcell](https://raw.github.com/piston/openstack-bosh-cpi/master/images/openstack_cpi_deletestemcell.png)
|
48
|
+
|
49
|
+
##Create VM ##
|
50
|
+
|
51
|
+
![openstack_cpi_create_vm](https://raw.github.com/piston/openstack-bosh-cpi/master/images/openstack_cpi_create_vm.png)
|
52
|
+
|
53
|
+
##Delete VM ##
|
54
|
+
|
55
|
+
Implementation of `delete_vm(server_id)`. This method deletes the VM created in Nova Compute.
|
56
|
+
|
57
|
+
1. Get the `server_id` of the VM to be deleted
|
58
|
+
* 1.1, 1.2 : Send the request `get_server_details` to Compute API Server through `Fog::Connection`
|
59
|
+
2. If `server` object returned is not null call `server.destroy`. This will send `delete_server` request to Nova Compute.
|
60
|
+
* 2.1, 2.2 : Create and send the `delete_server` request through `Fog::Connection`
|
61
|
+
3. Delete the settings from Registry by calling `delete_settings` method.
|
62
|
+
|
63
|
+
Figure below shows the flow control for `delete_vm` method
|
64
|
+
|
65
|
+
![openstack_cpi_delete_vm](https://raw.github.com/piston/openstack-bosh-cpi/master/images/openstack_cpi_delete_vm.png)
|
66
|
+
|
67
|
+
##Create Disk ##
|
68
|
+
|
69
|
+
1. Check if size passed is integer, is greater than 1024 and less than 1024*1000, else throw an error
|
70
|
+
2. Create `volume_params`
|
71
|
+
3. Call `create()volume_params)` on `Fog::Compute` service
|
72
|
+
1. `create_volume` request on `Fog::Volume::OpenStack`
|
73
|
+
2. Opens a `Fog::Connection` request to access the remote service and create a volume.
|
74
|
+
|
75
|
+
Figure below shows the flow control of `create_disk` method
|
76
|
+
|
77
|
+
![openstack_cpi_create_disk](https://raw.github.com/piston/openstack-bosh-cpi/master/images/openstack_cpi_create_disk.png)
|
78
|
+
|
79
|
+
##Delete Disk##
|
80
|
+
|
81
|
+
This method deletes the volume created in OpenStack Nova Volume
|
82
|
+
![openstack_cpi_delete_disk](https://raw.github.com/piston/openstack-bosh-cpi/master/images/openstack_cpi_delete_disk.png)
|
@@ -91,7 +91,7 @@ module Bosh::OpenStackCloud
|
|
91
91
|
# 1. Unpack image to temp directory
|
92
92
|
unpack_image(tmp_dir, image_path)
|
93
93
|
root_image = File.join(tmp_dir, "root.img")
|
94
|
-
|
94
|
+
|
95
95
|
# 2. If image contains a kernel file, upload it to glance service
|
96
96
|
kernel_id = nil
|
97
97
|
if cloud_properties["kernel_id"]
|
@@ -122,7 +122,7 @@ module Bosh::OpenStackCloud
|
|
122
122
|
ramdisk_id = cloud_properties["ramdisk_id"]
|
123
123
|
elsif cloud_properties["ramdisk_file"]
|
124
124
|
ramdisk_image = File.join(tmp_dir, cloud_properties["ramdisk_file"])
|
125
|
-
unless File.exists?(
|
125
|
+
unless File.exists?(ramdisk_image)
|
126
126
|
cloud_error("Ramdisk image " \
|
127
127
|
"#{cloud_properties['ramdisk_file']} " \
|
128
128
|
"is missing from stemcell archive")
|
@@ -234,18 +234,9 @@ module Bosh::OpenStackCloud
|
|
234
234
|
network_spec = nil, disk_locality = nil, environment = nil)
|
235
235
|
with_thread_name("create_vm(#{agent_id}, ...)") do
|
236
236
|
@logger.info("Creating new server...")
|
237
|
-
network_configurator = NetworkConfigurator.new(network_spec)
|
238
|
-
|
239
237
|
server_name = "vm-#{generate_unique_name}"
|
240
|
-
user_data = {
|
241
|
-
"registry" => {
|
242
|
-
"endpoint" => @registry.endpoint
|
243
|
-
},
|
244
|
-
"server" => {
|
245
|
-
"name" => server_name
|
246
|
-
}
|
247
|
-
}
|
248
238
|
|
239
|
+
network_configurator = NetworkConfigurator.new(network_spec)
|
249
240
|
security_groups =
|
250
241
|
network_configurator.security_groups(@default_security_groups)
|
251
242
|
@logger.debug("Using security groups: `#{security_groups.join(', ')}'")
|
@@ -269,7 +260,8 @@ module Bosh::OpenStackCloud
|
|
269
260
|
:flavor_ref => flavor.id,
|
270
261
|
:key_name => resource_pool["key_name"] || @default_key_name,
|
271
262
|
:security_groups => security_groups,
|
272
|
-
:user_data => Yajl::Encoder.encode(user_data
|
263
|
+
:user_data => Yajl::Encoder.encode(user_data(server_name,
|
264
|
+
network_spec))
|
273
265
|
}
|
274
266
|
|
275
267
|
availability_zone = select_availability_zone(disk_locality,
|
@@ -489,6 +481,26 @@ module Bosh::OpenStackCloud
|
|
489
481
|
end
|
490
482
|
end
|
491
483
|
|
484
|
+
##
|
485
|
+
# Set metadata for an OpenStack server
|
486
|
+
#
|
487
|
+
# @param [String] server_id OpenStack server UUID
|
488
|
+
# @param [Hash] metadata Metadata key/value pairs
|
489
|
+
# @return [void]
|
490
|
+
def set_vm_metadata(server_id, metadata)
|
491
|
+
with_thread_name("set_vm_metadata(#{server_id}, ...)") do
|
492
|
+
server = @openstack.servers.get(server_id)
|
493
|
+
unless server
|
494
|
+
cloud_error("Server `#{server_id}' not found")
|
495
|
+
end
|
496
|
+
|
497
|
+
metadata.each do |name, value|
|
498
|
+
value = "" if value.nil? # value is required
|
499
|
+
server.metadata.update(name => value)
|
500
|
+
end
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
492
504
|
##
|
493
505
|
# Validates the deployment
|
494
506
|
#
|
@@ -543,6 +555,39 @@ module Bosh::OpenStackCloud
|
|
543
555
|
UUIDTools::UUID.random_create.to_s
|
544
556
|
end
|
545
557
|
|
558
|
+
##
|
559
|
+
# Prepare server user data
|
560
|
+
#
|
561
|
+
# @param [String] server_name server name
|
562
|
+
# @param [Hash] network_spec network specification
|
563
|
+
# @return [Hash] server user data
|
564
|
+
def user_data(server_name, network_spec)
|
565
|
+
data = {}
|
566
|
+
|
567
|
+
data["registry"] = { "endpoint" => @registry.endpoint }
|
568
|
+
data["server"] = { "name" => server_name }
|
569
|
+
|
570
|
+
with_dns(network_spec) do |servers|
|
571
|
+
data["dns"] = { "nameserver" => servers }
|
572
|
+
end
|
573
|
+
|
574
|
+
data
|
575
|
+
end
|
576
|
+
|
577
|
+
##
|
578
|
+
# Extract dns server list from network spec and yield the the list
|
579
|
+
#
|
580
|
+
# @param [Hash] network_spec network specification for instance
|
581
|
+
# @yield [Array]
|
582
|
+
def with_dns(network_spec)
|
583
|
+
network_spec.each_value do |properties|
|
584
|
+
if properties.has_key?("dns") && !properties["dns"].nil?
|
585
|
+
yield properties["dns"]
|
586
|
+
return
|
587
|
+
end
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
546
591
|
##
|
547
592
|
# Generates initial agent settings. These settings will be read by agent
|
548
593
|
# from OpenStack registry (also a BOSH component) on a target server. Disk
|
@@ -696,7 +741,6 @@ module Bosh::OpenStackCloud
|
|
696
741
|
cloud_error("Failed to unpack stemcell root image" \
|
697
742
|
"tar exit status #{$?.exitstatus}: #{output}")
|
698
743
|
end
|
699
|
-
|
700
744
|
root_image = File.join(tmp_dir, "root.img")
|
701
745
|
unless File.exists?(root_image)
|
702
746
|
cloud_error("Root image is missing from stemcell archive")
|
@@ -710,8 +754,8 @@ module Bosh::OpenStackCloud
|
|
710
754
|
# @return [void]
|
711
755
|
# @raise [ArgumentError] if options are not valid
|
712
756
|
def validate_options
|
713
|
-
unless @options.
|
714
|
-
@options
|
757
|
+
unless @options["openstack"].is_a?(Hash) &&
|
758
|
+
@options.has_key?("openstack") &&
|
715
759
|
@options["openstack"]["auth_url"] &&
|
716
760
|
@options["openstack"]["username"] &&
|
717
761
|
@options["openstack"]["api_key"] &&
|
data/spec/spec_helper.rb
CHANGED
data/spec/unit/cloud_spec.rb
CHANGED
@@ -13,6 +13,40 @@ describe Bosh::OpenStackCloud::Cloud do
|
|
13
13
|
cloud.should be_an_instance_of(Bosh::OpenStackCloud::Cloud)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
it "raises ArgumentError on initializing with blank options" do
|
17
|
+
options = Hash.new("options")
|
18
|
+
expect {
|
19
|
+
Bosh::OpenStackCloud::Cloud.new(options)
|
20
|
+
}.to raise_error(ArgumentError)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "raises ArgumentError on initializing with non Hashoptions" do
|
24
|
+
options = "this is a string"
|
25
|
+
expect {
|
26
|
+
Bosh::OpenStackCloud::Cloud.new(options)
|
27
|
+
}.to raise_error(ArgumentError)
|
28
|
+
end
|
17
29
|
|
30
|
+
it "should create a Cloud Instance on giving valid params" do
|
31
|
+
openstack = { "auth_url" => "http://localhost/",
|
32
|
+
"username" =>"testuser",
|
33
|
+
"api_key" => "test_api_key",
|
34
|
+
"tenant" => "test_tenant"
|
35
|
+
}
|
36
|
+
registry = { "endpoint" => "http://0.0.0.0",
|
37
|
+
"user" => "testuser",
|
38
|
+
"password" => "password"
|
39
|
+
}
|
40
|
+
options = { "openstack" => openstack,
|
41
|
+
"registry" => registry
|
42
|
+
}
|
43
|
+
socket_error = false
|
44
|
+
begin
|
45
|
+
cloud = Bosh::OpenStackCloud::Cloud.new(options)
|
46
|
+
rescue Excon::Errors::SocketError => e
|
47
|
+
socket_error = true
|
48
|
+
end
|
49
|
+
socket_error.should be_true
|
50
|
+
end
|
51
|
+
end
|
18
52
|
end
|
@@ -196,6 +196,120 @@ describe Bosh::OpenStackCloud::Cloud do
|
|
196
196
|
sc_id.should == "i-bar"
|
197
197
|
end
|
198
198
|
|
199
|
-
|
199
|
+
it "should throw an error for non existent root image in stemcell archive" do
|
200
|
+
begin
|
201
|
+
dir = Dir.mkdir("tmp")
|
202
|
+
Dir.chdir 'tmp'
|
203
|
+
|
204
|
+
kernel_img = File.new('kernel.img', 'w')
|
205
|
+
ramdisk_img = File.new('initrd.img', 'w')
|
206
|
+
|
207
|
+
tgz = Zlib::GzipWriter.new(File.open('stemcell.tgz', 'wb'))
|
208
|
+
array = ['kernel.img']
|
209
|
+
|
210
|
+
Minitar.pack(array, tgz)
|
211
|
+
|
212
|
+
cloud = mock_glance
|
213
|
+
error_expected = "Root image is missing from stemcell archive"
|
214
|
+
error_actual = ""
|
215
|
+
begin
|
216
|
+
cloud.create_stemcell("./stemcell.tgz", {
|
217
|
+
"name" => "bosh-stemcell",
|
218
|
+
"version" => "x.y.z",
|
219
|
+
"container_format" => "ami",
|
220
|
+
"disk_format" => "ami",
|
221
|
+
"kernel_file" => "kernel.img",
|
222
|
+
"ramdisk_file" => "initrd.img"
|
223
|
+
})
|
224
|
+
rescue Bosh::Clouds::CloudError => e
|
225
|
+
error_actual = e.to_s
|
226
|
+
end
|
227
|
+
error_actual.should eq(error_expected)
|
228
|
+
ensure
|
229
|
+
File.delete('kernel.img')
|
230
|
+
File.delete('initrd.img')
|
231
|
+
File.delete('stemcell.tgz')
|
232
|
+
Dir.chdir '..'
|
233
|
+
Dir.delete('tmp')
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should throw an error for non existent kernel image in stemcell archive" do
|
238
|
+
begin
|
239
|
+
dir = Dir.mkdir("tmp")
|
240
|
+
Dir.chdir 'tmp'
|
241
|
+
root_img = File.new('root.img','w')
|
242
|
+
if root_img
|
243
|
+
root_img.syswrite("ABCDEF")
|
244
|
+
end
|
245
|
+
ramdisk_img = File.new('initrd.img', 'w')
|
246
|
+
|
247
|
+
tgz = Zlib::GzipWriter.new(File.open('stemcell.tgz', 'wb'))
|
248
|
+
array = ['root.img']
|
249
|
+
|
250
|
+
Minitar.pack(array, tgz)
|
251
|
+
|
252
|
+
cloud = mock_glance
|
253
|
+
error_expected = "Kernel image kernel.img is missing from stemcell archive"
|
254
|
+
error_actual = ""
|
255
|
+
begin
|
256
|
+
cloud.create_stemcell("./stemcell.tgz", {
|
257
|
+
"name" => "bosh-stemcell",
|
258
|
+
"version" => "x.y.z",
|
259
|
+
"container_format" => "ami",
|
260
|
+
"disk_format" => "ami",
|
261
|
+
"kernel_file" => "kernel.img",
|
262
|
+
"ramdisk_file" => "initrd.img"
|
263
|
+
})
|
264
|
+
rescue Bosh::Clouds::CloudError => e
|
265
|
+
error_actual = e.to_s
|
266
|
+
end
|
267
|
+
error_actual.should eq(error_expected)
|
268
|
+
ensure
|
269
|
+
File.delete('root.img')
|
270
|
+
File.delete('initrd.img')
|
271
|
+
File.delete('stemcell.tgz')
|
272
|
+
Dir.chdir '..'
|
273
|
+
Dir.delete('tmp')
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should throw an error for non existent ramdisk image in stemcell archive" do
|
278
|
+
begin
|
279
|
+
dir = Dir.mkdir("tmp")
|
280
|
+
Dir.chdir 'tmp'
|
281
|
+
root_img = File.new('root.img','w')
|
282
|
+
if root_img
|
283
|
+
root_img.syswrite("ABCDEF")
|
284
|
+
end
|
200
285
|
|
286
|
+
tgz = Zlib::GzipWriter.new(File.open('stemcell.tgz', 'wb'))
|
287
|
+
array = ['root.img']
|
288
|
+
|
289
|
+
Minitar.pack(array, tgz)
|
290
|
+
|
291
|
+
cloud = mock_glance
|
292
|
+
error_expected = "Ramdisk image initrd.img is missing from stemcell archive"
|
293
|
+
error_actual = ""
|
294
|
+
begin
|
295
|
+
cloud.create_stemcell("./stemcell.tgz", {
|
296
|
+
"name" => "bosh-stemcell",
|
297
|
+
"version" => "x.y.z",
|
298
|
+
"container_format" => "ami",
|
299
|
+
"disk_format" => "ami",
|
300
|
+
#"kernel_file" => "kernel.img",
|
301
|
+
"ramdisk_file" => "initrd.img"
|
302
|
+
})
|
303
|
+
rescue Bosh::Clouds::CloudError => e
|
304
|
+
error_actual = e.to_s
|
305
|
+
end
|
306
|
+
error_actual.should eq(error_expected)
|
307
|
+
ensure
|
308
|
+
File.delete('root.img')
|
309
|
+
File.delete('stemcell.tgz')
|
310
|
+
Dir.chdir '..'
|
311
|
+
Dir.delete('tmp')
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
201
315
|
end
|
data/spec/unit/create_vm_spec.rb
CHANGED
@@ -79,6 +79,52 @@ describe Bosh::OpenStackCloud::Cloud, "create_vm" do
|
|
79
79
|
vm_id.should == "i-test"
|
80
80
|
end
|
81
81
|
|
82
|
+
it "passes dns servers in server user data when present" do
|
83
|
+
unique_name = UUIDTools::UUID.random_create.to_s
|
84
|
+
|
85
|
+
user_data = {
|
86
|
+
"registry" => {
|
87
|
+
"endpoint" => "http://registry:3333"
|
88
|
+
},
|
89
|
+
"server" => {
|
90
|
+
"name" => "vm-#{unique_name}"
|
91
|
+
},
|
92
|
+
"dns" => {
|
93
|
+
"nameserver" => ["1.2.3.4"]
|
94
|
+
}
|
95
|
+
}
|
96
|
+
server = double("server", :id => "i-test", :name => "i-test")
|
97
|
+
image = double("image", :id => "sc-id", :name => "sc-id")
|
98
|
+
flavor = double("flavor", :id => "f-test", :name => "m1.tiny")
|
99
|
+
address = double("address", :id => "a-test", :ip => "10.0.0.1",
|
100
|
+
:instance_id => "i-test")
|
101
|
+
network_spec = dynamic_network_spec
|
102
|
+
network_spec["dns"] = ["1.2.3.4"]
|
103
|
+
|
104
|
+
cloud = mock_cloud do |openstack|
|
105
|
+
openstack.servers.should_receive(:create).
|
106
|
+
with(openstack_params(unique_name, user_data, %w[default])).
|
107
|
+
and_return(server)
|
108
|
+
openstack.images.should_receive(:find).and_return(image)
|
109
|
+
openstack.flavors.should_receive(:find).and_return(flavor)
|
110
|
+
openstack.addresses.should_receive(:each).and_yield(address)
|
111
|
+
end
|
112
|
+
|
113
|
+
cloud.should_receive(:generate_unique_name).and_return(unique_name)
|
114
|
+
address.should_receive(:server=).with(nil)
|
115
|
+
cloud.should_receive(:wait_resource).with(server, :active, :state)
|
116
|
+
|
117
|
+
@registry.should_receive(:update_settings).
|
118
|
+
with("i-test", agent_settings(unique_name, network_spec))
|
119
|
+
|
120
|
+
vm_id = cloud.create_vm("agent-id", "sc-id",
|
121
|
+
resource_pool_spec,
|
122
|
+
{ "network_a" => network_spec },
|
123
|
+
nil, { "test_env" => "value" })
|
124
|
+
vm_id.should == "i-test"
|
125
|
+
end
|
126
|
+
|
127
|
+
|
82
128
|
it "creates an OpenStack server with security group" do
|
83
129
|
unique_name = UUIDTools::UUID.random_create.to_s
|
84
130
|
user_data = {
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Copyright (c) 2009-2012 VMware, Inc.
|
2
|
+
|
3
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
4
|
+
|
5
|
+
describe Bosh::OpenStackCloud::Cloud do
|
6
|
+
before :each do
|
7
|
+
@server = double("server", :id => "i-foobar")
|
8
|
+
@metadata = double("metadata")
|
9
|
+
|
10
|
+
@cloud = mock_cloud do |openstack|
|
11
|
+
openstack.servers.should_receive(:get).
|
12
|
+
with("i-foobar").and_return(@server)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should set metadata" do
|
17
|
+
metadata = {:job => "job", :index => "index"}
|
18
|
+
|
19
|
+
@server.should_receive(:metadata).and_return(@metadata, @metadata)
|
20
|
+
@metadata.should_receive(:update).with(:job => "job")
|
21
|
+
@metadata.should_receive(:update).with(:index => "index")
|
22
|
+
|
23
|
+
@cloud.set_vm_metadata("i-foobar", metadata)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should set metadata with a nil value" do
|
27
|
+
metadata = {:deployment => nil}
|
28
|
+
|
29
|
+
@server.should_receive(:metadata).and_return(@metadata)
|
30
|
+
@metadata.should_receive(:update).with(:deployment => "")
|
31
|
+
|
32
|
+
@cloud.set_vm_metadata("i-foobar", metadata)
|
33
|
+
end
|
34
|
+
end
|
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.6
|
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:
|
12
|
+
date: 2013-01-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fog
|
@@ -126,6 +126,8 @@ files:
|
|
126
126
|
- lib/cloud/openstack/version.rb
|
127
127
|
- lib/cloud/openstack/vip_network.rb
|
128
128
|
- README.md
|
129
|
+
- USAGE.md
|
130
|
+
- bosh_cpi.md
|
129
131
|
- Rakefile
|
130
132
|
- spec/assets/sample_config.yml
|
131
133
|
- spec/integration/cpi_test.rb
|
@@ -143,6 +145,7 @@ files:
|
|
143
145
|
- spec/unit/helpers_spec.rb
|
144
146
|
- spec/unit/network_configurator_spec.rb
|
145
147
|
- spec/unit/reboot_vm_spec.rb
|
148
|
+
- spec/unit/set_vm_metadata_spec.rb
|
146
149
|
- spec/unit/validate_deployment_spec.rb
|
147
150
|
homepage: http://www.pistoncloud.com
|
148
151
|
licenses: []
|
@@ -185,5 +188,6 @@ test_files:
|
|
185
188
|
- spec/unit/helpers_spec.rb
|
186
189
|
- spec/unit/network_configurator_spec.rb
|
187
190
|
- spec/unit/reboot_vm_spec.rb
|
191
|
+
- spec/unit/set_vm_metadata_spec.rb
|
188
192
|
- spec/unit/validate_deployment_spec.rb
|
189
193
|
has_rdoc:
|