Skip to end of metadata
Go to start of metadata

Overview


A role provides a means of grouping similar features of similar nodes, providing a mechanism for easily composing sets of functionality. At web scale, you almost never have just one of something, so you use roles to express the parts of the configuration that are shared by a group of Nodes节点. Roles consist of the same parts as a node: Attributes and a Run List. Nodes can have multiple roles applied, and they will be expanded in place, providing for a complete recipe list for that node. When the Chef client runs, it merges its own attributes and run list with those of any roles it has been assigned.

For example, let's say I have a list of Recipes that should be applied on all my Ubuntu servers, and a list that is specific to machines that are Web Servers. This would map cleanly to two roles: 'ubuntu' and 'web_server'. Each role would specify the list of recipes it requires, in the order they should be applied. Where there is overlap (i.e., a recipe appears twice) it will be run when the first role is expanded (not run twice.)

You can create roles in Chef in 4 different ways:

  1. through the creation of role files in your chef repository (that utilize a ruby DSL, which gets compiled to JSON,)
  2. the creation of the JSON files directly in your chef repository,
  3. through the Management Console,
  4. or through the REST API.

We will cover each option here. Once you have created a role, you can add it to a node through the Management Console by dragging it from the Roles list to the client's "run list", or you can add it with a JSON file.

Roles work with chef-solo too!

You can use Roles with Chef Solo as well as the Client/Server. See the Chef Solo documentation.


Choose Your Workflow


There are two workflows you can use to manage your roles: you can either write your roles as ruby or JSON files and push them to the server, or you can create roles with Knife or the Management Console and edit them as you go along.

If you manage roles with files:

  • You can use the ruby DSL or JSON
  • Your roles will be useable with chef-solo
  • You can dynamically generate role data using the ruby DSL
  • You can keep your roles in your version control system and have a history of who changed what and when.
  • You should not edit roles with the Management Console, as your edits will be overwritten next time you upload from the file.

If you manage roles with knife and the Management Console:

  • You can edit a role's run list visually with the Management Console
  • You can make changes to a role "on the fly"
  • The canonical source of a role's data will be the Chef Server, which makes it difficult to keep in version control
  • You cannot use the ruby DSL.
  • You cannot use your roles with chef-solo

These workflows are mutually exclusive: if you upload a role to your Chef server from a file, then edit it with the Management Console, and then edit the file and upload again, the changes you made with the Management Console will be lost.

The Ruby DSL


Roles created through this mechanism get compiled to JSON, and then are loaded in to the Chef Server. (We never execute ruby code directly on the chef server!) Each time you rake install your Chef Repository, we will re-compile the corresponding JSON and store it in the chef server.

You should create these files in the 'roles' subdirectory of your chef repository - if you are using the opscode canonical Chef Repository as a baseline, the latest version includes this directory and rake tasks to manipulate roles as documented on the repository page. If your repository doesn't have this directory, create it now. Each DSL file should have a .rb suffix.

A complete role file looks like this:

A Very Simple Web Server Role
Work in progress

The env_run_lists feature is only going to be available in Chef 0.10.0 or above.

The Web Server Role

We'll go over each section below.

name

Each role must have a unique name, which is made up of [A-Z][a-z][0-9] and [_-]. Spaces are not allowed.

name field

description

A short description of what functionality is covered by this role.

description field

run_list

In Chef 0.8.x, the recipes attribute is replaced with a run_list, which is identical to the one you specify for Node.

This is the list of recipes or roles to apply for this role, in the order they should be applied.

recipes

Would apply the "apache2" recipe, the "apache2::mod_ssl" recipe, and then anything required by the role "monitor".

Note: You may also see recipes used in place of run_list. These are equivalent in function, though recipes is deprecated. Use run_list instead.

env_run_lists

Work in progress

The env_run_lists feature is only going to be available in Chef 0.10.0 or above.

In Chef 0.10.0, per environment run lists in a role allow you to specify a different run list for a role if the role is in the run list of the node in a specific environment. Before the existence of environments, each role has only one run list and it will be expanded and applied to the node when chef-client runs. With environments, in the role you can specify one run list for each environment, such as:

per environment run lists

If you do not specify a per environment run list for a certain environment, such as "production" and "preprod" in the above example, chef will use the default run list (like before).

default_attributes

An optional set of attributes that should be applied to all nodes with this role, assuming the node does not already have a value for that attribute. Use this to set site-wide defaults that can be overridden on a node-specific basis. The merge is 'deep', meaning that we will preserve nested attributes properly.

default_attributes

In the above example, all nodes with this role would have node[:apache2][:listen_ports] set to '80' and '443', assuming they do not already have a value.

If more than one role attempts to set a default value for the same attribute, the last role applied will win.

override_attributes

An optional set of attributes that should be applied to all nodes with this role, regardless of whether a node already has a value for that attribute. Useful for setting site-wide values that will always be set. The merge is 'deep', meaning that we will preserve nested attributes properly.

override_attributes

In the example above, node[:apache2][:max_children] will always be set to '50'.

If more than one role attempts to set an override value for the same attribute, the last role applied will win.

The parameters in role .rb files are actually Ruby method calls, so you can add parentheses and provide the attribute hashes on separate lines for clarity if specifying numerous or deeply-nested attributes:

Overriding Nested Attributes

Multiple attributes can be overridden like this:

Overriding Multiple Attributes

As JSON


The JSON format for roles maps directly to the Ruby DSL above. For the role we describe in that section, the corresponding JSON is:

The two additional fields are described below.

json_class

This should always be set to Chef::Role. This is used internally by Chef to auto-inflate this type of object. It should be ignored if you are re-building objects outside of Ruby, and its value may change in the future.

chef_type

This should always be set to role. This is the field you should rely on if you are building a system to consume Roles outside of Ruby.

Managing Roles through Knife


Knife is Chef's command line tool. Roles can be managed through Knife.

Creating a role with Knife

1. set EDITOR environment variable, for example:

2. create a new role, for example:

3. enter the data of the role in JSON, for example:

4. Save it. If there isn't an existing role with the same name, you will see a warning message about that, which is normal. For example:

Editing a role with Knife

1. set EDITOR environment variable, for example:

2. edit a role, for example:

3. Update the JSON in the editor.
4. Save it.

Viewing a role with Knife

Listing roles with Knife

Deleting a role with Knife

Adding a role to a node with Knife

Note that you need to put the role in quotes when using the knife node run_list add subcommand.

Managing Roles through the Management Console


You can create and manage roles through the Management Console. Please refer to the Managing Roles through the Management Console articles for information about this topic.

The REST API


You can also create and manage roles directly in a running Chef Server via the REST API. Please refer to the Server API article for information.

Labels
  • None
  1. Jun 08, 2009

    I like the idea of roles, but I can't quite wrap my mind around some of the implementation here. There seems to be a global roles namespace (actually "global" isn't really defined either). Also, why do you put a role spec into a cookbook? I'd expect most roles to straddle cookbooks (else might as well create a recipe). In the end, which roles exist in the role namespace when a node starts? All this seems very ill-defined.

    On implementing roles, how would the following differ from what you describe? Create a "roles" cookbook. Create a recipe for each role. The recipe munges the attributes (to implement the default/override) and then includes each recipe used for the role in turn. Is what you propose different? Is is syntactic sugar? Does it have different semantics?

    1. Jun 08, 2009

      The roles are not tied to cookbooks - they are totally separate entities (and have their own namespace entirely.) Roles definitely straddle cookbooks. The 'roles' directory we talk about above is a top-level item in the chef-repo:

      /roles
      /cookbooks
      /site-cookbooks

      And so on.

      You could get similar functionality from using a 'roles' cookbook, in that you can have a recipe that performs an 'include_recipe' for each, and attribute files that implement something akin to default/override. The role concept is a higher-level abstraction, in that it exists outside of a given cookbook, can be distributed on it's own, and can be used to reason about the set of included recipes that will be run on the node (we'll still miss things that are dynamically included, but the final recipe list is still easier to grok if you compose it via roles.)

      1. Jun 08, 2009

        Ah, I missed that the roles dir is at the top of the repo, not the cookbook. Thanks for clarifying. I'm still not entirely clear on the roles namespace. The cookbook namespace is defined by the search path through repos (or directories). Is the roles namespace similarly defined?

  2. Jun 08, 2009

    Another question your role ruby DSL brought up is what "rake install" does. I haven't looked into it, but it seems to actively push data to a specific chef server. That seems to conteract the ability to publish cookbook libraries on github or similar public access repositories. It seems to me that a chef server should always extract information from files in the cookbook, and if a cookbook is updated, we may want to have ways to ping a chef server (or multiple) but that they should then come back and actively fetch the updated content. At least that's the way we've been planning to operate.

    1. Jun 08, 2009

      See above for your question about roles/cookbooks. When you run 'rake install', we create JSON representations of the role, and then load that in to the chef-server (in the same way you would by using the REST API, basically.) You can absolutely bring in the role data from external sources (eventually, this would be one of the things you can do with a shared community website.)

  3. Feb 15, 2010

    This may seem obvious to most, but it just bit me now, and error logs weren't immediately obvious to me, simply returning a "Failed loading ChefServerSlice (409 "Conflict")" error.

    When loading in roles from the filesystem, a role's filename (without the filetype extension) and the role name inside the file must be the same, so example_server.json must have the name value listed like so: "name": "example_server".

    The first role with a mismatching name/filename combo will stop the subsequent roles being loaded, even if their names do match up as required.

  4. Jul 29, 2010

    A syntax comment - It was unclear to me how to override multiple attributes using the Ruby DSL. After a bit of experimentation, I updated the docs above with an example. It works but seems a bit weird to me - you're making a hash without the open and close braces where the first key needs to be on the same line as the "override_attributes" method (I assume it's the same with default_attributes).

    Has there been any though on changing the syntax to match that in the attributes files?
    e.g. overrideapache2max_children = "2"

    1. Dec 02, 2010

      This is just plain Ruby, but Ruby's flexibility makes it a little confusing if you're not used to it. override_attributes is a method call, and Ruby allows you to omit parentheses and also pass a hash as the final parameter to a method without surrounding it in braces if it's not ambiguous to the parser. In other words, you could add parens and write your example something like this if you find it clearer (I do):

      I'll update your example in the wiki, since it seems like the next commenter has a similar question.

  5. Dec 02, 2010

    I agree with Michael Leinartas. I find that I have to create a superfluous cookbook to go with some roles just so I can use the cookbook style attribute. In many cases I want to have one attribute combine earlier attributes, like building paths, or like:
    setuserssudoers=%w(foo bar)
    setuserslogin_names = userssudoers + %w(buz joe)

    (Noticed that my markup was wrong and my intent wasn't being shown. Fixed now)

    1. Dec 02, 2010

      I've just updated the text and examples following my comment to Michael above – see if that helps for your desired use case (smile)

      1. Dec 02, 2010

        Ches, that clarifies some things, but not as far as I can tell, my question which is can I avoid having to create a matching cookbook/recipe to be able to build up attributes in a role from elements of other attributes that are also part of the override_attributes method.

        I presume I can not say:

        Is there a way to accomplish something like that (use an attibute tha was defined earlier in the same override_attributes method) within a role file?

  6. Feb 21, 2011

    Good Afternoon,

    I create a Role and have few attributes overrides.

    The problem that I have is how to obtain the new values from the overrides attributes of role in a recipe? I create a default recipe and when I try to obtain a result, obtain the value of the attribute/default.rb not for the role. I've done: echo "The file is: #

    Unknown macro: {node[}

    " > /tmp/test.txt. The default attribute is:/dev/dm-1 but the override attribute is: /dev/sda.

    Best Regards,
    javier