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'
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|
r.node.all
end
Resources are accessed 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
ridley.user #=> Ridley::UserResource
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 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 want 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 ...>
]
Notify: You have to send the #reload message to node objects returned from a full listing. Their attributes aren't automatically populated from the initial search.
ridley = Ridley.new(...)
ridley.role.all.first => #<Ridley::RoleObject chef_id:some_chef_id, attributes:#<VariaModel::Attributes chef_type="role" default_attributes=#<Hashie::Mash> description="" env_run_lists=#<VariaModel::Attributes> json_class="Chef::Role" name="some_chef_id" override_attributes=#<Hashie::Mash> run_list=[]>>
ridley.role.all.first.reload => #<Ridley::RoleObject chef_id:some_chef_id, attributes:#<VariaModel::Attributes chef_type="role" default_attributes=#<Hashie::Mash SOME ATTRIBUTES> description="Some description" env_run_lists=#<VariaModel::Attributes> json_class="Chef::Role" name="some_chef_id" override_attributes=#<Hashie::Mash> run_list=[ SOME RUN LIST ]>>
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 expressed 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 = ridley.role.find("motherbrain_srv")
obj.destroy #=> true
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***" ...>
Cookbooks can be created, listed, updated and deleted as shown in the Manipulating Chef Resources section of this README.
To find a cookbook, you must provide both its name and version:
ridley = Ridley.new(...)
ridley.cookbook.find("apache2", "1.6.6")
Cookbooks can be downloaded. If no download path is specified, the chosen cookbook will be downloaded to a tmp folder.
ridley = Ridley.new(...)
ridley.cookbook.download("apache2", "1.6.6", "/path/to/download/cookbook") #=> "/path/to/download/cookbook"
ridley.cookbook.download("apache2", "1.6.6") #=> "/tmp/d20140211-6621-kstalp"
A cookbook's metadata can be accessed using the #metadata
method:
ridley = Ridley.new(...)
apache2 = ridley.cookbook.find("apache2", "1.6.6")
apache2.metadata #=> Hashie::Mash
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.
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">
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
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
ridley = Ridley.new(...)
ridley.search(:node)
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
Works the same way as with a client resource.
ridley = Ridley.new(...)
ridley.user.authenticate('username', 'password')
ridley.user.find('username').authenticate('password')
- Jamie Winsor (jamie@vialstudios.com)
- Kyle Allan (kallan@riotgames.com)
Thank you to all of our Contributors, testers, and users.