Class: Chef::Provisioning::Driver

Inherits:
Object
  • Object
show all
Defined in:
lib/chef/provisioning/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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(driver_url, config) ⇒ Driver

Inflate a driver from a driver URL.

config - a configuration hash. See “config” for a list of known keys.

Returns

A Driver representing the given driver_url.

Parameters:

  • driver_url (String)

    the URL to inflate the driver



48
49
50
51
# File 'lib/chef/provisioning/driver.rb', line 48

def initialize(driver_url, config)
  @driver_url = driver_url
  @config = config
end

Instance Attribute Details

#configObject (readonly)

A configuration hash. These keys may be present:

- :driver_options: a driver-defined object containing driver config.
- :private_keys: a hash of private keys, with a "name" and a "value".  Values are either strings (paths) or PrivateKey objects.
- :private_key_paths: a list of paths to directories containing private keys.
- :write_private_key_path: the path to which we write new keys by default.
- :log_level: :debug/:info/:warn/:error/:fatal
- :chef_server_url: url to chef server
- :node_name: username to talk to chef server
- :client_key: path to key used to talk to chef server


85
86
87
# File 'lib/chef/provisioning/driver.rb', line 85

def config
  @config
end

#driver_urlObject (readonly)

A URL representing the driver and the place where machines come from. This will be stuffed in machine_spec.reference so that the machine can be re-inflated. URLs must have a unique scheme identifying the driver class, and enough information to identify the place where created machines can be found. For AWS, this is the account number; for lxc and vagrant, it is the directory in which VMs and containers are.

For example:

  • fog:AWS:123456789012

  • vagrant:/var/vms

  • lxc:

  • docker:



74
75
76
# File 'lib/chef/provisioning/driver.rb', line 74

def driver_url
  @driver_url
end

Class Method Details

.from_url(driver_url, config) ⇒ Object

Override this on specific driver classes



56
57
58
# File 'lib/chef/provisioning/driver.rb', line 56

def self.from_url(driver_url, config)
  Chef::Provisioning.from_url(driver_url, config)
end

Instance Method Details

#allocate_image(action_handler, image_spec, image_options, machine_spec, machine_options) ⇒ Object

Allocate an image. Returns quickly with an ID that tracks the image.

Parameters:

  • action_handler (Chef::Provisioning::ActionHandler)

    The action_handler object that is calling this method

  • image_spec (Chef::Provisioning::ManagedEntry)

    An image specification representing this image.

  • image_options (Hash)

    A set of options representing the desired state of the image

  • machine_spec (Chef::Provisioning::ManagedEntry)

    A machine specification representing this machine.

  • machine_options (Hash)

    A set of options representing the desired state of the machine used to create the image



173
174
175
# File 'lib/chef/provisioning/driver.rb', line 173

def allocate_image(action_handler, image_spec, image_options, machine_spec, machine_options)
  raise "#{self.class} does not implement create_image"
end

#allocate_load_balancer(action_handler, lb_spec, lb_options, machine_specs) ⇒ Object

Allocate a load balancer

Parameters:



279
280
# File 'lib/chef/provisioning/driver.rb', line 279

def allocate_load_balancer(action_handler, lb_spec, lb_options, machine_specs)
end

#allocate_machine(action_handler, machine_spec, machine_options) ⇒ Chef::Provisioning::ManagedEntry

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.reference 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 :)

constructing the machine

back after allocate_machine completes.

Parameters:

Returns:



112
113
114
# File 'lib/chef/provisioning/driver.rb', line 112

def allocate_machine(action_handler, machine_spec, machine_options)
  raise "#{self.class} does not implement allocate_machine"
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.

Examples:

Example parallelizer

parallelizer.parallelize(specs_and_options) do |machine_spec|
  allocate_machine(action_handler, machine_spec)
end.to_a
# The to_a at the end causes you to wait until the parallelization is done

Passing a block

allocate_machines(action_handler, specs_and_options, parallelizer) do |machine_spec|
  ...
end

Parameters:

  • action_handler (Chef::Provisioning::ActionHandler)

    The action_handler object that is calling this method; this is generally a driver, but could be anything that can support the interface (i.e., in the case of the test kitchen provisioning driver for acquiring and destroying VMs).

  • specs_and_options (Hash)

    A hash of machine_spec -> machine_options representing the machines to allocate.

  • parallelizer (Parallelizer)

    an object with a parallelize() method that works like this:

Returns:

  • (Array<Machine>)

    An array of machine objects created



239
240
241
242
243
244
245
# File 'lib/chef/provisioning/driver.rb', line 239

def allocate_machines(action_handler, specs_and_options, parallelizer)
  parallelizer.parallelize(specs_and_options) do |machine_spec, machine_options|
    allocate_machine(add_prefix(machine_spec, action_handler), machine_spec, machine_options)
    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.

converge, execute, file and directory.

Parameters:

Returns:

  • (Machine)

    A machine object pointing at the machine, allowing useful actions like setup,



142
143
144
# File 'lib/chef/provisioning/driver.rb', line 142

def connect_to_machine(machine_spec, machine_options)
  raise "#{self.class} does not implement connect_to_machine"
end

#destroy_image(action_handler, image_spec, image_options, machine_options = {}) ⇒ Object

Destroy an image using this service.

Parameters:

  • action_handler (Chef::Provisioning::ActionHandler)

    The action_handler object that is calling this method

  • image_spec (Chef::Provisioning::ManagedEntry)

    An image specification representing this image.

  • image_options (Hash)

    A set of options representing the desired state of the image

  • machine_options (Hash) (defaults to: {})

    A set of options representing the desired state of the machine used to create the image



192
193
194
# File 'lib/chef/provisioning/driver.rb', line 192

def destroy_image(action_handler, image_spec, image_options, machine_options={})
  raise "#{self.class} does not implement destroy_image"
end

#destroy_load_balancer(action_handler, lb_spec, lb_options) ⇒ Object

Destroy the load balancer

Parameters:



296
297
# File 'lib/chef/provisioning/driver.rb', line 296

def destroy_load_balancer(action_handler, lb_spec, lb_options)
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.

Parameters:



153
154
155
# File 'lib/chef/provisioning/driver.rb', line 153

def destroy_machine(action_handler, machine_spec, machine_options)
  raise "#{self.class} does not implement destroy_machine"
end

#destroy_machines(action_handler, specs_and_options, parallelizer) ⇒ Object

Delete machines in batch, in parallel if possible.



265
266
267
268
269
270
# File 'lib/chef/provisioning/driver.rb', line 265

def destroy_machines(action_handler, specs_and_options, parallelizer)
  parallelizer.parallelize(specs_and_options) do |machine_spec, machine_options|
    destroy_machine(add_prefix(machine_spec, action_handler), machine_spec, machine_options)
    yield machine_spec if block_given?
  end.to_a
end

#driver_optionsObject

Driver configuration. Equivalent to config || {}



90
91
92
# File 'lib/chef/provisioning/driver.rb', line 90

def driver_options
  config[:driver_options] || {}
end

#ready_image(action_handler, image_spec, image_options) ⇒ Object

Ready an image, waiting till the point where it is ready to be used.

Parameters:



182
183
184
# File 'lib/chef/provisioning/driver.rb', line 182

def ready_image(action_handler, image_spec, image_options)
  raise "#{self.class} does not implement ready_image"
end

#ready_load_balancer(action_handler, lb_spec, lb_options, machine_specs) ⇒ Object

Make the load balancer ready

Parameters:



289
290
# File 'lib/chef/provisioning/driver.rb', line 289

def ready_load_balancer(action_handler, lb_spec, lb_options, machine_specs)
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.

converge, execute, file and directory.

Parameters:

Returns:

  • (Machine)

    A machine object pointing at the machine, allowing useful actions like setup,



130
131
132
# File 'lib/chef/provisioning/driver.rb', line 130

def ready_machine(action_handler, machine_spec, machine_options)
  raise "#{self.class} does not implement ready_machine"
end

#ready_machines(action_handler, specs_and_options, parallelizer) ⇒ Object

Ready machines in batch, in parallel if possible.



248
249
250
251
252
253
254
# File 'lib/chef/provisioning/driver.rb', line 248

def ready_machines(action_handler, specs_and_options, parallelizer)
  parallelizer.parallelize(specs_and_options) do |machine_spec, machine_options|
    machine = ready_machine(add_prefix(machine_spec, action_handler), machine_spec, machine_options)
    yield machine if block_given?
    machine
  end.to_a
end

#stop_machine(action_handler, machine_spec, machine_options) ⇒ Object

Stop the given machine.

Parameters:



162
163
164
# File 'lib/chef/provisioning/driver.rb', line 162

def stop_machine(action_handler, machine_spec, machine_options)
  raise "#{self.class} does not implement stop_machine"
end

#stop_machines(action_handler, specs_and_options, parallelizer) ⇒ Object

Stop machines in batch, in parallel if possible.



257
258
259
260
261
262
# File 'lib/chef/provisioning/driver.rb', line 257

def stop_machines(action_handler, specs_and_options, parallelizer)
  parallelizer.parallelize(specs_and_options) do |machine_spec, machine_options|
    stop_machine(add_prefix(machine_spec, action_handler), machine_spec, machine_options)
    yield machine_spec if block_given?
  end.to_a
end