Notes for chef-client Upgrades to Chef 12

[edit on GitHub]

The following sections contain more information about the upgrade process from earlier versions of the chef-client to the chef-client 12 release.

Verify Nodes and Cookbooks

Install the latest version of the chef-client on a small number of test nodes. Download all cookbooks, and then and check the following:

  • Run egrep -L ^name */metadata.rb. Do they all have a metadata.rb file?
  • Does the cookbook name in the metadata.rb file match the name in the run-list? (Some older versions of the chef-client used the cookbook name for the run-list based on the directory name of the cookbook and not the value of the cookbook_name setting in the metadata.rb file.)
  • Do all cookbooks have a metadata.rb file or metadata.json file?
  • Do all cookbooks used in the organization also exist in source control?
  • Do unused cookbooks (or cookbook versions) exist in source control? Run knife cookbook list to view a list of cookbooks, and then for each cookbook run knife cookbook show COOKBOOK_NAME to view its versions. Delete unused cookbook versions with knife cookbook delete -v VERSION_NAME.
  • How large is a cookbook? Most cookbooks are quite small, under ~200 KB. Sometimes cookbooks need to be larger than that. For larger cookbooks, consider why they are that large. Do they contain unnecessary binary files? Do they have a long git history? Mitigate the size of large cookbooks where possible.

Verify the nodes and clients that are in use:

  • Are all nodes and/or clients in use? Clean up any extra nodes and clients. Use the knife node list, knife client list, and knife_status` commands to verify nodes and clients that are in use.
  • Use the knife_client delete command to remove unused clients. Use the knife_node delete command to remove unused nodes.

Run the test nodes against the Chef server. If the server is also being upgraded, first complete that upgrade process (ideally on a fresh operating system), including processes for any highly available, load balanced, or offloaded services, and then verify the test nodes against the upgraded Chef server.

SSL Certificates

Chef server 12 enables SSL verification by default for all requests made to the server, such as those made by knife and the chef-client. The certificate that is generated during the installation of the Chef server is self-signed, which means the certificate is not signed by a trusted certificate authority (CA) that ships with the chef-client. The certificate generated by the Chef server must be downloaded to any machine from which knife and/or the chef-client will make requests to the Chef server.

For example, without downloading the SSL certificate, the following knife command:

$ knife client list

responds with an error similar to:

ERROR: SSL Validation failure connecting to host: chef-server.example.com ...
ERROR: OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 ...

This is by design and will occur until a verifiable certificate is added to the machine from which the request is sent.

See SSL Certificates for more information about how knife and the chef-client use SSL certificates generated by the Chef server.

execute Resource, path Attribute

The path property has been deprecated and will throw an exception in Chef Client 12 or later. We recommend you use the environment property instead.

Chef::Provider Changes

If a custom resource was created in the /libraries directory of a cookbook that also uses a core resource from the chef-client within the custom resource, the base class that is associated with that custom resource must be updated. In previous versions of the chef-client, the Chef::Provider class was all that was necessary because the Recipe DSL was included in the Chef::Provider base class.

For example, the lvm_logical_volume custom resource from the lvm cookbook uses the directory and mount resources:

class Chef
  class Provider
    class LvmLogicalVolume < Chef::Provider
      include Chef::Mixin::ShellOut

      ...
      if new_resource.mount_point
        if new_resource.mount_point.is_a?(String)
          mount_spec = { :location => new_resource.mount_point }
        else
          mount_spec = new_resource.mount_point
        end

        dir_resource = directory mount_spec[:location] do
          mode '0755'
          owner 'root'
          group 'root'
          recursive true
          action :nothing
          not_if { Pathname.new(mount_spec[:location]).mountpoint? }
        end
        dir_resource.run_action(:create)
        updates << dir_resource.updated?

        mount_resource = mount mount_spec[:location] do
          options mount_spec[:options]
          dump mount_spec[:dump]
          pass mount_spec[:pass]
          device device_name
          fstype fs_type
          action :nothing
        end
        mount_resource.run_action(:mount)
        mount_resource.run_action(:enable)
        updates << mount_resource.updated?
      end
      new_resource.updated_by_last_action(updates.any?)
    end

Starting with chef-client 12, the Recipe DSL is removed from the Chef::Provider base class and is only available by using LWRPBase. Cookbooks that contain custom resources authored for the chef-client 11 version should be inspected and updated.

Cookbooks that contain custom resources in the /libraries directory of a cookbook should:

  • Be inspected for instances of a) the Chef::Provider base class, and then b) for the presence of any core resources from the chef-client
  • Be updated to use the LWRPBase base class

For example:

class Chef
  class Provider
    class LvmLogicalVolume < Chef::Provider::LWRPBase
      include Chef::Mixin::ShellOut

      ...
      if new_resource.mount_point
        if new_resource.mount_point.is_a?(String)
          mount_spec = { :location => new_resource.mount_point }
        else
          mount_spec = new_resource.mount_point
        end

        dir_resource = directory mount_spec[:location] do
          mode '0755'
          owner 'root'
          group 'root'
          recursive true
          action :nothing
          not_if { Pathname.new(mount_spec[:location]).mountpoint? }
        end
        dir_resource.run_action(:create)
        updates << dir_resource.updated?

        mount_resource = mount mount_spec[:location] do
          options mount_spec[:options]
          dump mount_spec[:dump]
          pass mount_spec[:pass]
          device device_name
          fstype fs_type
          action :nothing
        end
        mount_resource.run_action(:mount)
        mount_resource.run_action(:enable)
        updates << mount_resource.updated?
      end
      new_resource.updated_by_last_action(updates.any?)
    end

node.default! Changes

In previous versions of the chef-client, node.default! was an alias of node.force_default!. Starting with chef-client 12, node.force_default is changed from an accessor to a setter. Cookbooks that use node.default! must be updated for the correct attribute precedence type and must drop the exclamation point. For example:

node.default![:foo] = 'bar'

must be updated to:

node.force_default[:foo] = 'bar'

node.override! Changes

In previous versions of the chef-client, node.override! was an alias of node.force_override. Starting with chef-client 12, node.force_override is changed from an accessor to a setter. Cookbooks that use node.override! must be updated for the correct attribute precedence type and must drop the exclamation point. For example:

node.override![:foo] = 'bar'

must be updated to:

node.force_override[:foo] = 'bar'