beaker-openstack 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
3
+ require 'beaker-openstack/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "beaker-openstack"
7
+ s.version = BeakerOpenstack::VERSION
8
+ s.authors = ["Rishi Javia, Kevin Imber, Tony Vu"]
9
+ s.email = ["rishi.javia@puppet.com, kevin.imber@puppet.com, tony.vu@puppet.com"]
10
+ s.homepage = "https://github.com/puppetlabs/beaker-openstack"
11
+ s.summary = %q{Beaker DSL Extension Helpers!}
12
+ s.description = %q{For use for the Beaker acceptance testing tool}
13
+ s.license = 'Apache2'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ # Testing dependencies
21
+ s.add_development_dependency 'rspec', '~> 3.0'
22
+ s.add_development_dependency 'rspec-its'
23
+ s.add_development_dependency 'fakefs', '~> 0.6'
24
+ s.add_development_dependency 'rake', '~> 10.1'
25
+ s.add_development_dependency 'simplecov'
26
+ s.add_development_dependency 'pry', '~> 0.10'
27
+
28
+ # Documentation dependencies
29
+ s.add_development_dependency 'yard'
30
+ s.add_development_dependency 'markdown'
31
+ s.add_development_dependency 'thin'
32
+
33
+ # Run time dependencies
34
+ s.add_runtime_dependency 'stringify-hash', '~> 0.0.0'
35
+ s.add_runtime_dependency 'fog', '~> 1.38'
36
+
37
+ end
38
+
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems' unless defined?(Gem)
4
+ require 'beaker-openstack'
5
+
6
+ VERSION_STRING =
7
+ "
8
+ _ .--.
9
+ ( ` )
10
+ beaker-openstack .-' `--,
11
+ _..----.. ( )`-.
12
+ .'_|` _|` _|( .__, )
13
+ /_| _| _| _( (_, .-'
14
+ ;| _| _| _| '-'__,--'`--'
15
+ | _| _| _| _| |
16
+ _ || _| _| _| _| %s
17
+ _( `--.\\_| _| _| _|/
18
+ .-' )--,| _| _|.`
19
+ (__, (_ ) )_| _| /
20
+ `-.__.\\ _,--'\\|__|__/
21
+ ;____;
22
+ \\YT/
23
+ ||
24
+ |\"\"|
25
+ '=='
26
+ "
27
+
28
+
29
+
30
+ puts BeakerOpenstack::VERSION
31
+
32
+ exit 0
@@ -0,0 +1,3 @@
1
+ module BeakerOpenstack
2
+ VERSION = '0.1.0'
3
+ end
@@ -0,0 +1,363 @@
1
+ module Beaker
2
+ #Beaker support for OpenStack
3
+ #This code is EXPERIMENTAL!
4
+ #Please file any issues/concerns at https://github.com/puppetlabs/beaker/issues
5
+ class Openstack < Beaker::Hypervisor
6
+
7
+ SLEEPWAIT = 5
8
+
9
+ #Create a new instance of the OpenStack hypervisor object
10
+ #@param [<Host>] openstack_hosts The array of OpenStack hosts to provision
11
+ #@param [Hash{Symbol=>String}] options The options hash containing configuration values
12
+ #@option options [String] :openstack_api_key The key to access the OpenStack instance with (required)
13
+ #@option options [String] :openstack_username The username to access the OpenStack instance with (required)
14
+ #@option options [String] :openstack_auth_url The URL to access the OpenStack instance with (required)
15
+ #@option options [String] :openstack_tenant The tenant to access the OpenStack instance with (required)
16
+ #@option options [String] :openstack_region The region that each OpenStack instance should be provisioned on (optional)
17
+ #@option options [String] :openstack_network The network that each OpenStack instance should be contacted through (required)
18
+ #@option options [String] :openstack_keyname The name of an existing key pair that should be auto-loaded onto each
19
+ #@option options [Hash] :security_group An array of security groups to associate with the instance
20
+ # OpenStack instance (optional)
21
+ #@option options [String] :jenkins_build_url Added as metadata to each OpenStack instance
22
+ #@option options [String] :department Added as metadata to each OpenStack instance
23
+ #@option options [String] :project Added as metadata to each OpenStack instance
24
+ #@option options [Integer] :timeout The amount of time to attempt execution before quiting and exiting with failure
25
+ def initialize(openstack_hosts, options)
26
+ require 'fog'
27
+ @options = options
28
+ @logger = options[:logger]
29
+ @hosts = openstack_hosts
30
+ @vms = []
31
+
32
+ raise 'You must specify an Openstack API key (:openstack_api_key) for OpenStack instances!' unless @options[:openstack_api_key]
33
+ raise 'You must specify an Openstack username (:openstack_username) for OpenStack instances!' unless @options[:openstack_username]
34
+ raise 'You must specify an Openstack auth URL (:openstack_auth_url) for OpenStack instances!' unless @options[:openstack_auth_url]
35
+ raise 'You must specify an Openstack tenant (:openstack_tenant) for OpenStack instances!' unless @options[:openstack_tenant]
36
+ raise 'You must specify an Openstack network (:openstack_network) for OpenStack instances!' unless @options[:openstack_network]
37
+
38
+ # Common keystone authentication credentials
39
+ @credentials = {
40
+ :provider => :openstack,
41
+ :openstack_auth_url => @options[:openstack_auth_url],
42
+ :openstack_api_key => @options[:openstack_api_key],
43
+ :openstack_username => @options[:openstack_username],
44
+ :openstack_tenant => @options[:openstack_tenant],
45
+ :openstack_region => @options[:openstack_region],
46
+ }
47
+
48
+ # Keystone version 3 requires users and projects to be scoped
49
+ if @credentials[:openstack_auth_url].include?('/v3/')
50
+ @credentials[:openstack_user_domain] = @options[:openstack_user_domain] || 'Default'
51
+ @credentials[:openstack_project_domain] = @options[:openstack_project_domain] || 'Default'
52
+ end
53
+
54
+ @compute_client ||= Fog::Compute.new(@credentials)
55
+
56
+ if not @compute_client
57
+ raise "Unable to create OpenStack Compute instance (api key: #{@options[:openstack_api_key]}, username: #{@options[:openstack_username]}, auth_url: #{@options[:openstack_auth_url]}, tenant: #{@options[:openstack_tenant]})"
58
+ end
59
+
60
+ @network_client ||= Fog::Network.new(@credentials)
61
+
62
+ if not @network_client
63
+ raise "Unable to create OpenStack Network instance (api_key: #{@options[:openstack_api_key]}, username: #{@options[:openstack_username]}, auth_url: #{@options[:openstack_auth_url]}, tenant: #{@options[:openstack_tenant]})"
64
+ end
65
+
66
+ # Validate openstack_volume_support setting value, reset to boolean if passed via ENV value string
67
+ @options[:openstack_volume_support] = true if @options[:openstack_volume_support].to_s.match(/\btrue\b/i)
68
+ @options[:openstack_volume_support] = false if @options[:openstack_volume_support].to_s.match(/\bfalse\b/i)
69
+ [true,false].include? @options[:openstack_volume_support] or raise "Invalid openstack_volume_support setting, current: @options[:openstack_volume_support]"
70
+
71
+ end
72
+
73
+ #Provided a flavor name return the OpenStack id for that flavor
74
+ #@param [String] f The flavor name
75
+ #@return [String] Openstack id for provided flavor name
76
+ def flavor f
77
+ @logger.debug "OpenStack: Looking up flavor '#{f}'"
78
+ @compute_client.flavors.find { |x| x.name == f } || raise("Couldn't find flavor: #{f}")
79
+ end
80
+
81
+ #Provided an image name return the OpenStack id for that image
82
+ #@param [String] i The image name
83
+ #@return [String] Openstack id for provided image name
84
+ def image i
85
+ @logger.debug "OpenStack: Looking up image '#{i}'"
86
+ @compute_client.images.find { |x| x.name == i } || raise("Couldn't find image: #{i}")
87
+ end
88
+
89
+ #Provided a network name return the OpenStack id for that network
90
+ #@param [String] n The network name
91
+ #@return [String] Openstack id for provided network name
92
+ def network n
93
+ @logger.debug "OpenStack: Looking up network '#{n}'"
94
+ @network_client.networks.find { |x| x.name == n } || raise("Couldn't find network: #{n}")
95
+ end
96
+
97
+ #Provided an array of security groups return that array if all
98
+ #security groups are present
99
+ #@param [Array] sgs The array of security group names
100
+ #@return [Array] The array of security group names
101
+ def security_groups sgs
102
+ for sg in sgs
103
+ @logger.debug "Openstack: Looking up security group '#{sg}'"
104
+ @compute_client.security_groups.find { |x| x.name == sg } || raise("Couldn't find security group: #{sg}")
105
+ sgs
106
+ end
107
+ end
108
+
109
+ # Create a volume client on request
110
+ # @return [Fog::OpenStack::Volume] OpenStack volume client
111
+ def volume_client_create
112
+ @volume_client ||= Fog::Volume.new(@credentials)
113
+ unless @volume_client
114
+ raise "Unable to create OpenStack Volume instance"\
115
+ " (api_key: #{@options[:openstack_api_key]},"\
116
+ " username: #{@options[:openstack_username]},"\
117
+ " auth_url: #{@options[:openstack_auth_url]},"\
118
+ " tenant: #{@options[:openstack_tenant]})"
119
+ end
120
+ end
121
+
122
+ # Get a hash of volumes from the host
123
+ def get_volumes host
124
+ return host['volumes'] if host['volumes']
125
+ {}
126
+ end
127
+
128
+ # Get the API version
129
+ def get_volume_api_version
130
+ case @volume_client
131
+ when Fog::Volume::OpenStack::V1
132
+ 1
133
+ else
134
+ -1
135
+ end
136
+ end
137
+
138
+ # Create and attach dynamic volumes
139
+ #
140
+ # Creates an array of volumes and attaches them to the current host.
141
+ # The host bus type is determined by the image type, so by default
142
+ # devices appear as /dev/vdb, /dev/vdc etc. Setting the glance
143
+ # properties hw_disk_bus=scsi, hw_scsi_model=virtio-scsi will present
144
+ # them as /dev/sdb, /dev/sdc (or 2:0:0:1, 2:0:0:2 in SCSI addresses)
145
+ #
146
+ # @param host [Hash] thet current host defined in the nodeset
147
+ # @param vm [Fog::Compute::OpenStack::Server] the server to attach to
148
+ def provision_storage host, vm
149
+ volumes = get_volumes(host)
150
+ if !volumes.empty?
151
+ # Lazily create the volume client if needed
152
+ volume_client_create
153
+ volumes.keys.each_with_index do |volume, index|
154
+ @logger.debug "Creating volume #{volume} for OpenStack host #{host.name}"
155
+
156
+ # The node defintion file defines volume sizes in MB (due to precedent
157
+ # with the vagrant virtualbox implementation) however OpenStack requires
158
+ # this translating into GB
159
+ openstack_size = volumes[volume]['size'].to_i / 1000
160
+
161
+ # Set up the volume creation arguments
162
+ args = {
163
+ :size => openstack_size,
164
+ :description => "Beaker volume: host=#{host.name} volume=#{volume}",
165
+ }
166
+
167
+ # Between version 1 and subsequent versions the API was updated to
168
+ # rename 'display_name' to just 'name' for better consistency
169
+ if get_volume_api_version == 1
170
+ args[:display_name] = volume
171
+ else
172
+ args[:name] = volume
173
+ end
174
+
175
+ # Create the volume and wait for it to become available
176
+ vol = @volume_client.volumes.create(**args)
177
+ vol.wait_for { ready? }
178
+
179
+ # Fog needs a device name to attach as, so invent one. The guest
180
+ # doesn't pay any attention to this
181
+ device = "/dev/vd#{('b'.ord + index).chr}"
182
+ vm.attach_volume(vol.id, device)
183
+ end
184
+ end
185
+ end
186
+
187
+ # Detach and delete guest volumes
188
+ # @param vm [Fog::Compute::OpenStack::Server] the server to detach from
189
+ def cleanup_storage vm
190
+ vm.volumes.each do |vol|
191
+ @logger.debug "Deleting volume #{vol.name} for OpenStack host #{vm.name}"
192
+ vm.detach_volume(vol.id)
193
+ vol.wait_for { ready? }
194
+ vol.destroy
195
+ end
196
+ end
197
+
198
+ # Get a floating IP address to associate with the instance, try
199
+ # to allocate a new one from the specified pool if none are available
200
+ def get_ip
201
+ begin
202
+ @logger.debug "Creating IP"
203
+ ip = @compute_client.addresses.create
204
+ rescue Fog::Compute::OpenStack::NotFound
205
+ # If there are no more floating IP addresses, allocate a
206
+ # new one and try again.
207
+ @compute_client.allocate_address(@options[:floating_ip_pool])
208
+ ip = @compute_client.addresses.find { |ip| ip.instance_id.nil? }
209
+ end
210
+ raise 'Could not find or allocate an address' if not ip
211
+ ip
212
+ end
213
+
214
+ #Create new instances in OpenStack
215
+ def provision
216
+ @logger.notify "Provisioning OpenStack"
217
+
218
+ @hosts.each do |host|
219
+ ip = get_ip
220
+ hostname = ip.ip.gsub('.','-')
221
+ host[:vmhostname] = hostname + '.rfc1918.puppetlabs.net'
222
+ create_or_associate_keypair(host, hostname)
223
+ @logger.debug "Provisioning #{host.name} (#{host[:vmhostname]})"
224
+ options = {
225
+ :flavor_ref => flavor(host[:flavor]).id,
226
+ :image_ref => image(host[:image]).id,
227
+ :nics => [ {'net_id' => network(@options[:openstack_network]).id } ],
228
+ :name => host[:vmhostname],
229
+ :hostname => host[:vmhostname],
230
+ :user_data => host[:user_data] || "#cloud-config\nmanage_etc_hosts: true\n",
231
+ :key_name => host[:keyname],
232
+ }
233
+ options[:security_groups] = security_groups(@options[:security_group]) unless @options[:security_group].nil?
234
+ vm = @compute_client.servers.create(options)
235
+
236
+ #wait for the new instance to start up
237
+ try = 1
238
+ attempts = @options[:timeout].to_i / SLEEPWAIT
239
+
240
+ while try <= attempts
241
+ begin
242
+ vm.wait_for(5) { ready? }
243
+ break
244
+ rescue Fog::Errors::TimeoutError => e
245
+ if try >= attempts
246
+ @logger.debug "Failed to connect to new OpenStack instance #{host.name} (#{host[:vmhostname]})"
247
+ raise e
248
+ end
249
+ @logger.debug "Timeout connecting to instance #{host.name} (#{host[:vmhostname]}), trying again..."
250
+ end
251
+ sleep SLEEPWAIT
252
+ try += 1
253
+ end
254
+
255
+ # Associate a public IP to the server
256
+ ip.server = vm
257
+ host[:ip] = ip.ip
258
+
259
+ @logger.debug "OpenStack host #{host.name} (#{host[:vmhostname]}) assigned ip: #{host[:ip]}"
260
+
261
+ #set metadata
262
+ vm.metadata.update({:jenkins_build_url => @options[:jenkins_build_url].to_s,
263
+ :department => @options[:department].to_s,
264
+ :project => @options[:project].to_s })
265
+ @vms << vm
266
+
267
+ # Wait for the host to accept ssh logins
268
+ host.wait_for_port(22)
269
+
270
+ #enable root if user is not root
271
+ enable_root(host)
272
+
273
+ provision_storage(host, vm) if @options[:openstack_volume_support]
274
+ @logger.notify "OpenStack Volume Support Disabled, can't provision volumes" if not @options[:openstack_volume_support]
275
+ end
276
+
277
+ hack_etc_hosts @hosts, @options
278
+
279
+ end
280
+
281
+ #Destroy any OpenStack instances
282
+ def cleanup
283
+ @logger.notify "Cleaning up OpenStack"
284
+ @vms.each do |vm|
285
+ cleanup_storage(vm) if @options[:openstack_volume_support]
286
+ @logger.debug "Release floating IPs for OpenStack host #{vm.name}"
287
+ floating_ips = vm.all_addresses # fetch and release its floating IPs
288
+ floating_ips.each do |address|
289
+ @compute_client.disassociate_address(vm.id, address['ip'])
290
+ @compute_client.release_address(address['id'])
291
+ end
292
+ @logger.debug "Destroying OpenStack host #{vm.name}"
293
+ vm.destroy
294
+ if @options[:openstack_keyname].nil?
295
+ @logger.debug "Deleting random keypair"
296
+ @compute_client.delete_key_pair vm.key_name
297
+ end
298
+ end
299
+ end
300
+
301
+ # Enables root access for a host when username is not root
302
+ # This method ripped from the aws_sdk implementation and is probably wrong
303
+ # because it iterates on a collection when there's no guarantee the collection
304
+ # has all been brought up in openstack yet and will thus explode
305
+ # @return [void]
306
+ # @api private
307
+ def enable_root_on_hosts
308
+ @hosts.each do |host|
309
+ enable_root(host)
310
+ end
311
+ end
312
+
313
+ # enable root on a single host (the current one presumably) but only
314
+ # if the username isn't 'root'
315
+ def enable_root(host)
316
+ if host['user'] != 'root'
317
+ copy_ssh_to_root(host, @options)
318
+ enable_root_login(host, @options)
319
+ host['user'] = 'root'
320
+ host.close
321
+ end
322
+ end
323
+
324
+ #Get key_name from options or generate a new rsa key and add it to
325
+ #OpenStack keypairs
326
+ #
327
+ #@param [Host] host The OpenStack host to provision
328
+ #@api private
329
+ def create_or_associate_keypair(host, keyname)
330
+ if @options[:openstack_keyname]
331
+ @logger.debug "Adding optional key_name #{@options[:openstack_keyname]} to #{host.name} (#{host[:vmhostname]})"
332
+ keyname = @options[:openstack_keyname]
333
+ else
334
+ @logger.debug "Generate a new rsa key"
335
+
336
+ # There is apparently an error that can occur when generating RSA keys, probably
337
+ # due to some timing issue, probably similar to the issue described here:
338
+ # https://github.com/negativecode/vines/issues/34
339
+ # In order to mitigate this error, we will simply try again up to three times, and
340
+ # then fail if we continue to error out.
341
+ begin
342
+ retries ||= 0
343
+ key = OpenSSL::PKey::RSA.new 2048
344
+ rescue OpenSSL::PKey::RSAError => e
345
+ retries += 1
346
+ if retries > 2
347
+ @logger.notify "error generating RSA key #{retries} times, exiting"
348
+ raise e
349
+ end
350
+ retry
351
+ end
352
+
353
+ type = key.ssh_type
354
+ data = [ key.to_blob ].pack('m0')
355
+ @logger.debug "Creating Openstack keypair '#{keyname}' for public key '#{type} #{data}'"
356
+ @compute_client.create_key_pair keyname, "#{type} #{data}"
357
+ host['ssh'][:key_data] = [ key.to_pem ]
358
+ end
359
+
360
+ host[:keyname] = keyname
361
+ end
362
+ end
363
+ end
@@ -0,0 +1,166 @@
1
+ # Openstack
2
+
3
+ OpenStack is a free and open-source software platform for cloud computing. [Their Site](http://www.openstack.org/).
4
+
5
+ Considered **EXPERIMENTAL**, may break without notice.
6
+
7
+ # Getting Started
8
+
9
+ ### Requirements
10
+
11
+ Get openstack Access & Security credentials:
12
+
13
+ - "openstack_api_key"
14
+ - "openstack_auth_url"
15
+ - "openstack_username"
16
+ - "openstack_tenant"
17
+ - "openstack_network"
18
+ - "openstack_keyname"
19
+
20
+ If you are using [OpenStack Dashboard "Horizon"](https://wiki.openstack.org/wiki/Horizon)
21
+ you can find these keys in next places:
22
+
23
+ 1. login to "Horizon dashboard" -> "project" -> "Compute" -> "Access & Security" -> tab "API Access" -> "Download OpenStack RC File":
24
+ * "openstack_auth_url" == OS_AUTH_URL + "/tokens"
25
+ * "openstack_username" == OS_USERNAME
26
+ * "openstack_tenant" == OS_TENANT_NAME
27
+ 2. "openstack_network": in "project" -> "Networks"
28
+ 3. "openstack_keyname": in "project" -> "Compute" -> "Access & Security" -> tab "Key Pairs"
29
+ 4. "openstack_api_key": Your user Password
30
+
31
+ ### Setup a Openstack Hosts File
32
+
33
+ An Openstack hosts file looks like a typical hosts file,
34
+ except that there are a number of required properties that need to be added to every host
35
+ in order for the Openstack hypervisor to provision hosts properly.
36
+
37
+ **Basic Openstack hosts file**
38
+
39
+ HOSTS:
40
+ centos-6-master:
41
+ roles:
42
+ - master
43
+ - agent
44
+ - database
45
+ - dashboard
46
+ platform: el-6-x86_64
47
+ hypervisor: openstack
48
+ image: centos-6-x86_64-nocm
49
+ flavor: m1.large
50
+
51
+ CONFIG:
52
+ nfs_server: none
53
+ consoleport: 443
54
+ openstack_api_key: Pas$w0rd
55
+ openstack_username: user
56
+ openstack_auth_url: http://10.10.10.10:5000/v2.0/tokens
57
+ openstack_tenant: testing
58
+ openstack_network : testing
59
+ openstack_keyname : nopass
60
+
61
+ The `image` - image name.
62
+
63
+ The `flavor` - templates for VMs, defining sizes for RAM, disk, number of cores, and so on.
64
+
65
+
66
+ # Openstack-Specific Hosts File Settings
67
+
68
+ ### user-data
69
+
70
+ "user data" - a blob of data that the user can specify when they launch an instance.
71
+ The instance can access this data through the metadata service or config drive with one of the next requests:
72
+
73
+ - curl http://169.254.169.254/2009-04-04/user-data
74
+ - curl http://169.254.169.254/openstack/2012-08-10/user_data
75
+
76
+
77
+ Examples of `user_data` you can find here: http://cloudinit.readthedocs.io/en/latest/topics/examples.html
78
+
79
+ Also if you plan use `user-data` make sure that 'cloud-init' package installed in your VM `image` and 'cloud-init' service is running.
80
+
81
+ **Example Openstack hosts file with user_data**
82
+
83
+ HOSTS:
84
+ centos-6-master:
85
+ roles:
86
+ - master
87
+ - agent
88
+ - database
89
+ - dashboard
90
+ platform: el-6-x86_64
91
+ image: centos-6-x86_64-nocm
92
+ flavor: m1.large
93
+ hypervisor: openstack
94
+ user_data: |
95
+ #cloud-config
96
+ bootcmd:
97
+ - echo 123 > /tmp/test.txt
98
+ CONFIG:
99
+ nfs_server: none
100
+ consoleport: 443
101
+ openstack_api_key: P1as$w0rd
102
+ openstack_username: user
103
+ openstack_auth_url: http://10.10.10.10:5000/v2.0/tokens
104
+ openstack_tenant: testing
105
+ openstack_network : testing
106
+ openstack_keyname : nopass
107
+
108
+ ### Security groups
109
+
110
+ A security group is a set of rules for incoming and outgoing traffic to
111
+ an instance. You can associate a host with one or many security groups
112
+ in the `CONFIG` section of your hosts file:
113
+
114
+ security_group: ['my_sg', 'default']
115
+
116
+ This is an optional config parameter.
117
+
118
+ ### Floating IP Pool
119
+
120
+ The name of the floating IP pool that a VM can grab IPs from. This is useful
121
+ if your organization doesn't have a public pool of floating IPs, or give each
122
+ user their own pool. It's used in allocating new IPs. It's an options
123
+ parameter in the CONFIG section of the host file:
124
+
125
+ floating_ip_pool: 'my_pool_name'
126
+
127
+ ### Volumes
128
+
129
+ Attaching volumes to a VM is supported via the Cinder service. All versions are transparently
130
+ supported to cater for differences in the APIs. To create and attach volumes simply add hash
131
+ called 'volumes' to a host in the HOSTS section. Each key is the name given to the volume upon
132
+ resource creation. The value is a hash with a single integer parameter 'size' which defines the
133
+ volume size in MB.
134
+
135
+ **Example OpenStack hosts file with volumes**
136
+
137
+ HOSTS:
138
+ ceph:
139
+ roles:
140
+ - master
141
+ platform: ubuntu-16.04-amd64
142
+ hypervisor: openstack
143
+ flavor: m1.large
144
+ image: xenial-server-cloudimg-amd64-scsi
145
+ user: ubuntu
146
+ volumes:
147
+ osd0:
148
+ size: 10000
149
+ osd1:
150
+ size: 10000
151
+ osd2:
152
+ size: 10000
153
+ journal:
154
+ size: 1000
155
+
156
+
157
+ In the event you're using an OpenStack instance that does not deploy the volume service you can disable that functionality to prevent beaker runs from failing. Either using an ENV variable or setting the following value in the `CONFIG` section of your hosts file(valid values are `true` or `false`):
158
+
159
+ ```
160
+ openstack_volume_support: false
161
+ ```
162
+
163
+ You can also configure this setting via an environment variable:
164
+
165
+ ```
166
+ export OS_VOLUME_SUPPORT=false