A reliable Chef API client with a clean syntax
Pull request Compare This branch is 270 commits behind berkshelf:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Gem Version Build Status Dependency Status Code Climate

A reliable Chef API client with a clean syntax


Add Ridley to your Gemfile:

gem 'ridley'

And run the bundle command to install. Alternatively, you can install the gem directly:

$ gem install ridley


Before you can use Ridley, you must require it in your application:

require 'ridley'

Creating a new Ridley client

ridley = Ridley.new(
  server_url: "https://api.opscode.com/organizations/ridley",
  client_name: "reset",
  client_key: "/Users/reset/.chef/reset.pem"

Creating a new instance of Ridley requires the following options:

  • server_url
  • client_name
  • client_key

client_key can be either a file path or the client key as a string. You can also optionally supply an encrypted data bag secret for decrypting encrypted data bags. The option is "encrypted_data_bag_secret" This can be a file name or the key itself as a string.

ridley = Ridley.new(
  server_url: "https://api.opscode.com/organizations/ridley",
  client_name: "reset",
  client_key: "some key data",
  encrypted_data_bag_secret: "File path or key as a string"

Ridley exposes a number of functions that return resources which you can use to retrieve or create objects on your Chef server. Here is a simple example of getting a list of all the roles on your Chef server.

ridley = Ridley.new(...)
ridley.role.all #=> [
  #<Ridley::RoleObject chef_id:motherbrain_srv ...>,
  #<Ridley::RoleObject chef_id:motherbrain_proxy ...>

For more information scroll down to the Manipulating Chef Resources section of this README.

You can also tell Ridley to read the values from your Chef config (knife.rb):

ridley = Ridley.from_chef_config('/path/to/knife.rb')
ridley.role.all #=> [
  #<Ridley::RoleObject chef_id:motherbrain_srv ...>,
  #<Ridley::RoleObject chef_id:motherbrain_proxy ...>

The mapping between Chef Config values and Ridley values is:

Ridley Chef
validator_client validation_client_name
validator_path validation_key
client_name node_name
server_url chef_server_url

Additionally, you can leave the path blank and Ridley will perform a "knife.rb search" the same way Chef does:

ridley = Ridley.from_chef_config
ridley.role.all #=> [
  #<Ridley::RoleObject chef_id:motherbrain_srv ...>,
  #<Ridley::RoleObject chef_id:motherbrain_proxy ...>

If you don't want to instantiate and manage a connection object you can use Ridley.open to open a connection, do some work, and it will be closed for you after the block executes.

Ridley.open(server_url: "https://api.opscode.com", ...) do |r|

Manipulating Chef Resources

Resources are access by instance functions on a new instance of Ridley::Client.

ridley = Ridley.new(...)
ridley.client      #=> Ridley::ClientResource
ridley.cookbook    #=> Ridley::CookbookResource
ridley.data_bag    #=> Ridley::DataBagResource
ridley.environment #=> Ridley::EnvironmentResource
ridley.node        #=> Ridley::NodeResource
ridley.role        #=> Ridley::RoleResource
ridley.sandbox     #=> Ridley::SandboxResource
ridley.search      #=> Ridley::SearchResource

DataBagItems are the only exception to this rule. The DataBagItem resource is accessed from a DataBagObject

data_bag = ridley.data_bag.find("my_data")
data_bag.item                 #=> Ridley::DataBagItemResource
data_bag.item.find("my_item") #=> Ridley::DataBagItemObject


Most resources can be listed, retrieved, created, updated, and destroyed. These are commonly referred to as CRUD (Create Read Update Delete) operations.


A new Chef Object can be created in a four ways

With the #create function and an attribute hash

ridley = Ridley.new(...)
ridley.role.create(name: "reset") #=> #<Ridley::RoleObject: chef_id:reset>

With the #create function and an instance of a Chef Object

obj = ridley.role.new
obj.name = "reset"
ridley.role.create(obj) #=> #<Ridley::RoleObject: chef_id:reset>

With the #save function on an instance of a Chef Object

obj = ridley.role.new
obj.name = "reset"
obj.save #=> #<Ridley::RoleObject: chef_id:reset>

With the #save function on an instance of a Chef Object built from serialized json

obj = ridley.role.from_file('/path/to/role.json')
obj.save #=> #<Ridley::RoleObject: chef_id:reset>

Each of these methods produce an identical object on the Chef server. It is up to you on how you'd like to create new resources.


Most resources have two read functions

  • #all for listing all the Chef Objects
  • #find for retrieving a specific Chef Object

If you wanted to get a list of all of the roles on your Chef server

ridley = Ridley.new(...)
ridley.role.all #=> [
  #<Ridley::RoleObject chef_id:motherbrain_srv ...>,
  #<Ridley::RoleObject chef_id:motherbrain_proxy ...>

If you want to retrieve a single role from the Chef server

ridley = Ridley.new(...)
ridley.role.find("motherbrain_srv") #=> #<Ridley::RoleObject: chef_id:motherbrain_srv ...>

If the role does not exist on the Chef server then nil is returned

ridley = Ridley.new(...)
ridley.role.find("not_there") #=> nil


Updating a resource can be expressed in three ways

With the #update function, the ID of the Object to update, and an attributes hash

ridley = Ridley.new(...)
ridley.role.update("motherbrain_srv", description: "testing updates") #=> #<Ridley::RoleObject chef_id:motherbrain_srv, description="testing updates" ...>

With the #update function and an instance of a Chef Object

obj = ridley.role.find("motherbrain_srv")
obj.description = "chef object"

ridley.role.update(obj) #=> #<Ridley::RoleObject: chef_id:motherbrain_srv, description="chef object" ...

With the #save function on an instance of a Chef Object

obj = ridley.role.find("reset")
obj.description = "saving an object"
obj.save #=> #<Ridley::RoleObject: chef_id:motherbrain_srv, description="saving an object" ...>


Destroying a resource can be express in three ways

With the #delete function and the ID of the Object to destroy

ridley = Ridley.new(...)
ridley.role.delete("motherbrain_srv") => #<Ridley::RoleObject: chef_id:motherbrain_srv ...>

With the #delete function and a Chef Object

obj = ridley.role.find("motherbrain_srv")
ridley.role.delete(obj) => #<Ridley::RoleObject: chef_id:motherbrain_srv ...>

With the #destroy function on an instance of a Chef Object

obj = conn.role.find("motherbrain_srv")
obj.destroy #=> true

Client Resource

Regenerating a client's private key

With the #regnerate_key function and the ID of the Client to regenerate

ridley = Ridley.new(...)
ridley.client.regenerate_key("jamie") #=> #<Ridley::ClientObject: chef_id:"jamie", private_key="**HIDDEN***" ...>

With the #regenerate_key function on an instance of a Client Object

obj = ridley.client.find("jamie")
obj.regenerate_key #=> #<Ridley::ClientObject: chef_id:"jamie", private_key="**HIDDEN***" ...>

Cookbook Resource

Data Bag Resource

A data bag is managed exactly the same as any other Chef resource

ridley = Ridley.new(...)
ridley.data_bag.create(name: "ridley-test")

You can create, delete, update, or retrieve a data bag exactly how you would expect if you read through the Manipulating Chef Resources portion of this document.

Unlike a role, node, client, or environment, a data bag is a container for other resources. These other resources are Data Bag Items. Data Bag Items behave slightly different than other resources. Data Bag Items can have an abritrary attribute hash filled with any key values that you would like. The one exception is that every Data Bag Item requires an 'id' key and value. This identifier is the name of the Data Bag Item.

Creating a Data Bag Item

ridley   = Ridley.new(...)
data_bag = ridley.data_bag.create(name: "ridley-test")

data_bag.item.create(id: "appconfig", host: "reset.local", user: "jamie") #=> #<Ridley::DataBagItemObject: chef_id:appconfig, host="reset.local", user="jamie">

Environment Resource

Setting Attributes

Setting a default environment attribute is just like setting a node level default attribute

ridley = Ridley.new(...)
production_env = ridley.environment.find("production")
production_env.set_default_attribute("my_app.proxy.enabled", false)
production_env.save #=> true

And the same goes for setting an environment level override attribute

production_env.set_override_attribute("my_app.proxy.enabled", false)
production_env.save #=> true

Node Resource

Bootstrapping Unix nodes

ridley = Ridley.new(
  server_url: "https://api.opscode.com",
  organization: "vialstudios",
  validator_client: "vialstudios-validator",
  validator_path: "/Users/reset/.chef/vialstudios-validator.pem",
  ssh: {
    user: "vagrant",
    password: "vagrant"

ridley.node.bootstrap("", "")

Bootstrapping Windows Nodes

Windows Nodes are bootstrapped using a combination of WinRM, Batch, and PowerShell. You will probably need to tweak some settings on your Windows servers to ensure the commands are successful.

WinRM Settings

  1. Enable WinRM: winrm quickconfig and say Yes.
  2. Set some WinRM settings to ensure that you don't get 401 Unauthorized responses and 500 Responses because of timeouts.
winrm set winrm/config/service/auth @{Basic="true"}
winrm set winrm/config/service @{AllowUnencrypted="true"}
winrm set winrm/config/service @{EnumerationTimeoutms="600000"}
winrm set winrm/config @{MaxTimeoutms="600000"}
winrm set winrm/config/client @{TrustedHosts="*"}

PowerShell Settings

  1. You should also configure your PowerShell profile, so that PowerShell commands have a more lenient timeout period.
mkdir C:\Users\my_user\Documents\WindowsPowerShell
echo "$PSSessionOption = New-PSSessionOption -OpenTimeout 0 -CancelTimeout 0 -IdleTimeout 0 -OperationTimeout 0" > C:\Users\my_user\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

Verify the PowerShell settings by opening up the PowerShell Console and entering $PSSessionOption and ensure those values are set, and that there are no errors output.

The following links offer some information about configuring a machine's PowerShell settings:

You may also want to tweak your Windows boxes a bit more ex: turning UAC off, turning off the Windows Firewall.

Role Resource

Role Attributes

Setting role attributes is just like setting node and environment attributes

ridley = Ridley.new(...)
my_app_role = ridley.role.find("my_app")
my_app_role.set_default_attribute("my_app.proxy.enabled", false)
my_app_role.save #=> true

And the same goes for setting an environment level override attribute

my_app_role.set_override_attribute("my_app.proxy.enabled", false)
my_app_role.save #=> true

Sandbox Resource

Search Resource

ridley = Ridley.new(...)
ridley.search(:node, "name:ridley-test.local")

Search will return an array of the appropriate Chef Objects if one of the default indices is specified. The indices are

  • node
  • role
  • client
  • environment

Authors and Contributors

Thank you to all of our Contributors, testers, and users.