Current Driver Contract
This page records the current Test Kitchen driver contract. It describes how Kitchen uses drivers today, including behavior that exists because of the Ruby base classes and current implementation details.
This is not a redesign of the driver API. It is a snapshot of the current state so future work can make the contract clearer.
How Kitchen loads drivers
Drivers are Ruby plugins. Kitchen loads a driver by calling
Kitchen::Driver.for_plugin(name, config), which delegates to the shared plugin
loader.
For a driver named example, Kitchen expects to be able to require:
kitchen/driver/example
and find a class under Kitchen::Driver, such as:
module Kitchen
module Driver
class Example < Kitchen::Driver::Base
end
end
end
Kitchen initializes the driver with a config hash:
driver = Kitchen::Driver::Example.new(config)
Kitchen then finalizes it with the instance before actions run:
driver.finalize_config!(instance)
Methods Kitchen calls
The current core lifecycle calls these driver methods:
create(state)
destroy(state)
Kitchen also calls these methods from explicit commands:
package(state)
doctor(state)
Kitchen::Driver::Base provides no-op defaults for destroy, package, and
doctor. Its default create only supports the legacy pre_create_command
behavior.
Although some older code and examples mention driver setup and driver
verify, Kitchen does not currently call driver setup or driver verify.
The instance setup action is empty, and verification is handled by the
verifier.
State
Every driver action receives a mutable state hash:
def create(state)
state[:hostname] = "192.0.2.10"
end
Kitchen reads this hash from the instance state file before the action and writes it back after the action. Drivers commonly use it to persist resource identifiers and connection details that transports later consume.
Kitchen also writes last_action and last_error around lifecycle actions.
What the base class provides
Drivers normally subclass Kitchen::Driver::Base. The base class provides:
- configuration defaults and validation helpers
finalize_config!(instance)- access to
instance - hash-like config lookup with
[] - diagnostics through
diagnoseanddiagnose_plugin - logging helpers such as
debug,info,warn, anderror - shell-out support through
run_command - plugin metadata helpers such as
plugin_versionandkitchen_driver_api_version no_parallel_forsupport for serialized actions
The shared configuration helper expands paths, runs deprecation checks, validates required config, and loads dependencies during finalization.
Failure behavior
Drivers should raise Kitchen::ActionFailed for expected action failures.
When an action raises Kitchen::ActionFailed, Kitchen records the failure in
state, logs the detailed error, preserves the previous successful lifecycle
state, and raises Kitchen::InstanceFailure for the user-facing command.
Unexpected exceptions are wrapped by Kitchen as action failures.
Current rough edges
The current driver contract is broader and less precise than the live lifecycle requires. In particular:
setupandverifyappear in some older driver-oriented behavior but are not called as driver actions today.- Drivers may interact with
instance.transportdirectly, as built-in proxy and exec-style drivers do. - Drivers write arbitrary keys into shared instance state, and those keys may be interpreted later by transports or other plugins.
Future work should make the driver contract explicit, reduce reliance on shared mutable state, and clarify which responsibilities belong to drivers versus transports and other plugin types.