Class: Chef::Provisioning::OpenNebulaDriver::Driver
- Inherits:
-
Driver
- Object
- Driver
- Chef::Provisioning::OpenNebulaDriver::Driver
- Defined in:
- lib/chef/provisioning/opennebula_driver/driver.rb
Overview
A Driver instance represents a place where machines can be created and found, and contains methods to create, delete, start, stop, and find them.
For AWS, a Driver instance corresponds to a single account. For Vagrant, it is a directory where VM files are found.
How to Make a Driver
To implement a Driver, you must implement the following methods:
-
initialize(driver_url) - create a new driver with the given URL
-
driver_url - a URL representing everything unique about your
driver. (NOT credentials)
-
allocate_machine - ask the driver to allocate a machine to you.
-
ready_machine - get the machine “ready” - wait for it to be booted
and accessible (for example, accessible via SSH transport).
-
stop_machine - stop the machine.
-
destroy_machine - delete the machine.
-
connect_to_machine - connect to the given machine.
Optionally, you can also implement:
-
allocate_machines - allocate an entire group of machines.
-
ready_machines - get a group of machines warm and booted.
-
stop_machines - stop a group of machines.
-
destroy_machines - delete a group of machines.
Additionally, you must create a file named ‘chef/provisioning/driver_init/<scheme>.rb`, where <scheme> is the name of the scheme you chose for your driver_url. This file, when required, must call Chef::Provisioning.add_registered_driver(<scheme>, <class>). The given <class>.from_url(url, config) will be called with a driver_url and configuration.
All of these methods must be idempotent - if the work is already done, they just don’t do anything.
Instance Attribute Summary collapse
-
#one ⇒ Object
readonly
Returns the value of attribute one.
Class Method Summary collapse
-
.canonicalize_url(driver_url, config) ⇒ Object
URL must have an endpoint to prevent machine moving, which is not possible today between different endpoints.
- .from_url(driver_url, config) ⇒ Object
Instance Method Summary collapse
-
#allocate_image(action_handler, image_spec, image_options, machine_spec) ⇒ Object
Allocate an image.
-
#allocate_load_balancer(_action_handler, _lb_spec, _lb_options, _machine_specs) ⇒ Object
Allocate a load balancer.
-
#allocate_machine(action_handler, machine_spec, machine_options) ⇒ Chef::Provisioning::MachineSpec
Allocate a machine from the underlying service.
-
#allocate_machines(action_handler, specs_and_options, parallelizer) ⇒ Array<Machine>
Allocate a set of machines.
-
#connect_to_machine(machine_spec, machine_options) ⇒ Machine
Connect to a machine without allocating or readying it.
-
#destroy_image(action_handler, image_spec, _image_options) ⇒ Object
Destroy an image using this service.
-
#destroy_load_balancer(_action_handler, _lb_spec, _lb_options) ⇒ Object
Destroy the load balancer.
-
#destroy_machine(action_handler, machine_spec, machine_options) ⇒ Object
Delete the given machine – destroy the machine, returning things to the state before allocate_machine was called.
-
#destroy_machines(action_handler, specs_and_options, parallelizer) ⇒ Object
Delete machines in batch, in parallel if possible.
-
#initialize(driver_url, config) ⇒ Driver
constructor
OpenNebula by default reads the following information:.
-
#ready_image(action_handler, image_spec, _image_options) ⇒ Object
Ready an image, waiting till the point where it is ready to be used.
-
#ready_load_balancer(_action_handler, _lb_spec, _lb_options, _machine_specs) ⇒ Object
Make the load balancer ready.
-
#ready_machine(action_handler, machine_spec, machine_options) ⇒ Machine
Ready a machine, to the point where it is running and accessible via a transport.
-
#ready_machines(action_handler, specs_and_options, parallelizer) ⇒ Object
Ready machines in batch, in parallel if possible.
-
#stop_machine(action_handler, machine_spec, machine_options) ⇒ Object
Stop the given machine.
-
#stop_machines(action_handler, specs_and_options, parallelizer) ⇒ Object
Stop machines in batch, in parallel if possible.
Constructor Details
#initialize(driver_url, config) ⇒ Driver
OpenNebula by default reads the following information:
username:password from ENV['ONE_AUTH'] or ENV['HOME']/.one/one_auth
endpoint from ENV['ONE_XMLRPC']
driver_url format:
opennebula:<endpoint>:<profile>
where <profile> points to a one_auth file in ENV/.one/<profile>
driver_options:
credentials: bbsl-auto:text_pass credentials has precedence over secret_file
endpoint: opennebula endpoint
options: additional options for OpenNebula::Client
171 172 173 174 175 176 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 171 def initialize(driver_url, config) super @one = Chef::Provisioning::OpenNebulaDriver.get_onelib(:driver_url => driver_url) @driver_url_with_profile = driver_url @driver_url = @one.client.one_endpoint end |
Instance Attribute Details
#one ⇒ Object (readonly)
Returns the value of attribute one.
154 155 156 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 154 def one @one end |
Class Method Details
.canonicalize_url(driver_url, config) ⇒ Object
URL must have an endpoint to prevent machine moving, which is not possible today between different endpoints.
184 185 186 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 184 def self.canonicalize_url(driver_url, config) [driver_url, config] end |
Instance Method Details
#allocate_image(action_handler, image_spec, image_options, machine_spec) ⇒ Object
Allocate an image. Returns quickly with an ID that tracks the image.
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 363 def allocate_image(action_handler, image_spec, , machine_spec) if image_spec.reference # check if image already exists image = @one.get_resource(:image, :id => image_spec.reference['image_id'].to_i) action_handler.report_progress "image #{image_spec.name} (ID: #{image_spec.reference['image_id']}) already exists" unless image.nil? else action_handler.perform_action "create image #{image_spec.name} from machine ID #{machine_spec.reference['instance_id']} with options #{.inspect}" do vm = @one.get_resource(:virtualmachine, :id => machine_spec.reference['instance_id']) fail "allocate_image: VM does not exist" if vm.nil? # set default disk ID disk_id = 1 if .disk_id disk_id = .disk_id.is_a?(Integer) ? .disk_id : @one.get_disk_id(vm, new_resource.disk_id) end new_img = @one.version_ge_4_14 ? vm.disk_saveas(disk_id, image_spec.name) : vm.disk_snapshot(disk_id, image_spec.name, "", true) fail "Failed to create snapshot '#{new_resource.name}': #{new_img.}" if OpenNebula.is_error?(new_img) populate_img_object(image_spec, new_image) end end end |
#allocate_load_balancer(_action_handler, _lb_spec, _lb_options, _machine_specs) ⇒ Object
Allocate a load balancer
512 513 514 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 512 def allocate_load_balancer(_action_handler, _lb_spec, , _machine_specs) fail "'allocate_load_balancer' is not implemented" end |
#allocate_machine(action_handler, machine_spec, machine_options) ⇒ Chef::Provisioning::MachineSpec
Allocate a machine from the underlying service. This method does not need to wait for the machine to boot or have an IP, but it must store enough information in machine_spec.location to find the machine later in ready_machine.
If a machine is powered off or otherwise unusable, this method may start it, but does not need to wait until it is started. The idea is to get the gears moving, but the job doesn’t need to be done :)
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 210 def allocate_machine(action_handler, machine_spec, ) instance = instance_for(machine_spec) return machine_spec unless instance.nil? unless [:bootstrap_options] instance = @one.retry_one("Retrying allocate_machine.instance_for (missing bootstrap options)") do instance_for(machine_spec) end return machine_spec unless instance.nil? fail "'bootstrap_options' must be specified" end check_unique_names(, machine_spec) action_handler.perform_action "created vm '#{machine_spec.name}'" do Chef::Log.debug() tpl = @one.get_template(machine_spec.name, [:bootstrap_options]) vm = @one.allocate_vm(tpl) populate_node_object(machine_spec, , vm) @one.chmod_resource(vm, [:bootstrap_options][:mode]) # This option allows to manipulate how the machine shows up # in the OpenNebula UI and CLI tools. We either set the VM # name to the short hostname of the machine, rename it # to the String passed to us, or leave it alone. if [:vm_name] == :short @one.rename_vm(vm, machine_spec.name.split('.').first) elsif [:vm_name].is_a?(String) @one.rename_vm(vm, [:vm_name]) # else use machine_spec.name for name in OpenNebula end end Chef::Log.debug(machine_spec.reference) machine_spec end |
#allocate_machines(action_handler, specs_and_options, parallelizer) ⇒ Array<Machine>
Allocate a set of machines. This should have the same effect as running allocate_machine on all machine_specs.
Drivers do not need to implement this; the default implementation calls acquire_machine in parallel.
Parallelizing
The parallelizer must implement #parallelize This object is shared among other chef-provisioning actions, ensuring that you do not go over parallelization limits set by the user. Use of the parallelizer to parallelizer machines is not required.
Passing a block
If you pass a block to this function, each machine will be yielded to you as it completes, and then the function will return when all machines are yielded.
473 474 475 476 477 478 479 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 473 def allocate_machines(action_handler, , parallelizer) parallelizer.parallelize() do |machine_spec, | allocate_machine(add_prefix(machine_spec, action_handler), machine_spec, ) yield machine_spec if block_given? machine_spec end.to_a end |
#connect_to_machine(machine_spec, machine_options) ⇒ Machine
Connect to a machine without allocating or readying it. This method will NOT make any changes to anything, or attempt to wait.
292 293 294 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 292 def connect_to_machine(machine_spec, ) machine_for(machine_spec, ) end |
#destroy_image(action_handler, image_spec, _image_options) ⇒ Object
Destroy an image using this service.
411 412 413 414 415 416 417 418 419 420 421 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 411 def destroy_image(action_handler, image_spec, ) img = @one.get_resource(:image, :id => image_spec.location['image_id'].to_i) if img.nil? action_handler.report_progress "image #{image_spec.name} (#{image_spec.location['image_id']}) does not exist - (up to date)" else action_handler.perform_action "deleted image #{image_spec.name} (#{image_spec.location['image_id']})" do rc = img.delete fail "Failed to delete image '#{image_spec.name}' : #{rc.}" if OpenNebula.is_error?(rc) end end end |
#destroy_load_balancer(_action_handler, _lb_spec, _lb_options) ⇒ Object
Destroy the load balancer
528 529 530 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 528 def destroy_load_balancer(_action_handler, _lb_spec, ) fail "'destroy_load_balancer' is not implemented" end |
#destroy_machine(action_handler, machine_spec, machine_options) ⇒ Object
Delete the given machine – destroy the machine, returning things to the state before allocate_machine was called.
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 305 def destroy_machine(action_handler, machine_spec, ) instance = instance_for(machine_spec) if !instance.nil? action_handler.perform_action "destroyed machine #{machine_spec.name} (#{machine_spec.reference['instance_id']})" do instance.delete 1.upto(10) do instance.info break if instance.state_str == 'DONE' Chef::Log.debug("Waiting for VM '#{instance.id}' to be in 'DONE' state: '#{instance.state_str}'") sleep(2) end fail "Failed to destroy '#{instance.name}'. Current state: #{instance.state_str}" if instance.state_str != 'DONE' end elsif machine_spec.reference Chef::Log.info("vm #{machine_spec.name} (#{machine_spec.reference['instance_id']}) does not exist - (up to date)") else Chef::Log.info("vm #{machine_spec.name} does not exist - (up to date)") end begin strategy = convergence_strategy_for(machine_spec, ) strategy.cleanup_convergence(action_handler, machine_spec) rescue Net::HTTPServerException => e raise unless e.response.code == '404' end end |
#destroy_machines(action_handler, specs_and_options, parallelizer) ⇒ Object
Delete machines in batch, in parallel if possible.
499 500 501 502 503 504 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 499 def destroy_machines(action_handler, , parallelizer) parallelizer.parallelize() do |machine_spec, | destroy_machine(add_prefix(machine_spec, action_handler), machine_spec, ) yield machine_spec if block_given? end.to_a end |
#ready_image(action_handler, image_spec, _image_options) ⇒ Object
Ready an image, waiting till the point where it is ready to be used.
393 394 395 396 397 398 399 400 401 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 393 def ready_image(action_handler, image_spec, ) img = @one.get_resource(:image, :id => image_spec.reference['image_id'].to_i) fail "Image #{image_spec.name} (#{image_spec.reference['image_id']}) does not exist" if img.nil? action_handler.perform_action "image #{image_spec.name} is ready" do deployed = @one.wait_for_img(img.name, img.id) image_spec.reference['state'] = deployed.state_str end img end |
#ready_load_balancer(_action_handler, _lb_spec, _lb_options, _machine_specs) ⇒ Object
Make the load balancer ready
520 521 522 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 520 def ready_load_balancer(_action_handler, _lb_spec, , _machine_specs) fail "'ready_load_balancer' is not implemented" end |
#ready_machine(action_handler, machine_spec, machine_options) ⇒ Machine
Ready a machine, to the point where it is running and accessible via a transport. This will NOT allocate a machine, but may kick it if it is down. This method waits for the machine to be usable, returning a Machine object pointing at the machine, allowing useful actions like setup, converge, execute, file and directory.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 263 def ready_machine(action_handler, machine_spec, ) instance = instance_for(machine_spec) fail "Machine '#{machine_spec.name}' does not have an instance associated with it, or instance does not exist." if instance.nil? # TODO: Currently it does not start stopped VMs, it only waits for new VMs to be in RUNNING state machine = nil action_handler.perform_action "vm '#{machine_spec.name}' is ready" do deployed = @one.wait_for_vm(instance.id) machine_spec.reference['name'] = deployed.name machine_spec.reference['state'] = deployed.state_str if deployed.to_hash['VM']['TEMPLATE']['NIC'] ip = [deployed.to_hash['VM']['TEMPLATE']['NIC']].flatten.first['IP'] end fail "Could not get IP from VM '#{deployed.name}'" if ip.nil? || ip.to_s.empty? machine_spec.reference['ip'] = ip machine = machine_for(machine_spec, ) end machine end |
#ready_machines(action_handler, specs_and_options, parallelizer) ⇒ Object
Ready machines in batch, in parallel if possible.
482 483 484 485 486 487 488 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 482 def ready_machines(action_handler, , parallelizer) parallelizer.parallelize() do |machine_spec, | machine = ready_machine(add_prefix(machine_spec, action_handler), machine_spec, ) yield machine if block_given? machine end.to_a end |
#stop_machine(action_handler, machine_spec, machine_options) ⇒ Object
Stop the given machine.
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 339 def stop_machine(action_handler, machine_spec, ) instance = instance_for(machine_spec) if !instance.nil? action_handler.perform_action "powered off machine #{machine_spec.name} (#{machine_spec.reference['instance_id']})" do if machine_spec.reference[:is_shutdown] || ([:bootstrap_options] && [:bootstrap_options][:is_shutdown]) hard = machine_spec.reference[:shutdown_hard] || [:bootstrap_options][:shutdown_hard] || false instance.shutdown(hard) else instance.stop end end else Chef::Log.info("vm #{machine_spec.name} (#{machine_spec.reference['instance_id']}) does not exist - (up to date)") end end |
#stop_machines(action_handler, specs_and_options, parallelizer) ⇒ Object
Stop machines in batch, in parallel if possible.
491 492 493 494 495 496 |
# File 'lib/chef/provisioning/opennebula_driver/driver.rb', line 491 def stop_machines(action_handler, , parallelizer) parallelizer.parallelize() do |machine_spec, | stop_machine(add_prefix(machine_spec, action_handler), machine_spec, ) yield machine_spec if block_given? end.to_a end |