airzinger1
airzinger1

Reputation: 161

How can I set the value of an attribute based on the environment I am in in Chef?

When I push my updates to the chef server, my updates first get pushed to our development node and then I eventually merge them to the production node.

I have two attributes that set to a URL for a database, however, the value of the attributes are different based on whether I am on the development node or the production node.

How can set my attributes so it sets the value of the attribute based on what environment it is in?

Here is what I have:

default['test_cookbook']['Development']['URL]='jdbc:mysql://exampleDB1.com'
default['test_cookbook']['Production']['URL]='jdbc:mysql://exampleDB2.com'

Ideally instead of "Production" and Development, I would want some chef resource like "node.chef_environment" that will check the environment and decide what URL to use based on the environment.

Upvotes: 0

Views: 1081

Answers (2)

lamont
lamont

Reputation: 3974

You can do this in your attributes file:

default['test_cookbook']['Development']['URL']='jdbc:mysql://exampleDB1.com'
default['test_cookbook']['Production']['URL']='jdbc:mysql://exampleDB2.com'

Then at the top of your recipe pull the node attributes for the cookbook into a ruby variable and use that:

attributes = node['test_cookbook'][node.chef_environment]

remote_file attributes['download_location'] do
  source attributes['URL']
end

template attributes['config_file'] do
  source "myapp.conf.erb"
  variables({ attributes: attributes })
end

There's also an elegant way to do this via PolicyFiles using 'hoisting' where policy_group replaces chef_environment and is the recommended way going forwards:

https://docs.chef.io/release_notes_client/#policyfile-hoisting

Upvotes: 1

seshadri_c
seshadri_c

Reputation: 7350

Ideally, Chef attributes should not be named after the environment in which they will be used. Environment agnostic attribute like below is preferred:

default['test_cookbook']['jdbc_url']

TL;DR

You could achieve what you want through an attributes file. The idea is to set the attributes based on the node.chef_environment.

Example test_cookbook/attributes/default.rb:

default['test_cookbook']['jdbc_url'] = case node.chef_environment
  when 'development'
    'jdbc:mysql://exampleDB1.com'
  when 'production'
    'jdbc:mysql://exampleDB2.com'
  end

However...

The value of this variable can be set per Chef Environment by editing the environment with knife environment edit or by editing the .json file for that environment.

This method should be preferred as the JDBC URL can be changed per environment without having to modify the cookbook. Cookbook modifications are like code change - involving branching, version bumping and associated README.md and CHANGELOG.md updates, code reviews and merging. This will then cascade down to using the "new" cookbook versions during deployments.

All this for a value change! Not preferred.

Example development Chef environment:

  "default_attributes": {
    "test_cookbook": {
      "jdbc_url": "jdbc:mysql://exampleDB1.com"
    }
  },

Example production Chef environment:

  "default_attributes": {
    "test_cookbook": {
      "jdbc_url": "jdbc:mysql://exampleDB2.com"
    }
  },

Upvotes: 0

Related Questions