Skip to content

Instantly share code, notes, and snippets.

@ccooper21
Last active December 10, 2015 13:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ccooper21/4439163 to your computer and use it in GitHub Desktop.
Save ccooper21/4439163 to your computer and use it in GitHub Desktop.
This is a Chef bootstrap script for bootstrapping the Chef client on an Amazon Linux AMI instance. It has been tested with Amazon Linux v2012.09 (AMI ID ami-1624987f). See the first comment below for the detailed background.
bash -c '
<%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
exists() {
if command -v $1 &>/dev/null
then
return 0
else
return 1
fi
}
sudo sed -i "s/\(Defaults[[:space:]]*secure_path[[:space:]]*=[[:space:]]*\)\(.*\)/\1\/usr\/local\/sbin:\/usr\/local\/bin:\2/g" /etc/sudoers
if ! exists gcc; then
sudo yum -y install gcc gcc-c++ make
fi
if ! exists git; then
yum -y install git
fi
install_sh="http://opscode.com/chef/install.sh"
version_string="-v <%= chef_version %>"
if ! exists /usr/bin/chef-client; then
if exists wget; then
bash <(wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> ${install_sh} -O -) ${version_string}
else
if exists curl; then
bash <(curl -L <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> ${install_sh}) ${version_string}
fi
fi
fi
mkdir -p /etc/chef
(
cat <<'EOP'
<%= validation_key %>
EOP
) > /tmp/validation.pem
awk NF /tmp/validation.pem > /etc/chef/validation.pem
rm /tmp/validation.pem
chmod 0600 /etc/chef/validation.pem
<% if @chef_config[:encrypted_data_bag_secret] -%>
(
cat <<'EOP'
<%= encrypted_data_bag_secret %>
EOP
) > /tmp/encrypted_data_bag_secret
awk NF /tmp/encrypted_data_bag_secret > /etc/chef/encrypted_data_bag_secret
rm /tmp/encrypted_data_bag_secret
chmod 0600 /etc/chef/encrypted_data_bag_secret
<% end -%>
<%# Generate Ohai Hints -%>
<% unless @chef_config[:knife][:hints].nil? || @chef_config[:knife][:hints].empty? -%>
mkdir -p /etc/chef/ohai/hints
<% @chef_config[:knife][:hints].each do |name, hash| -%>
(
cat <<'EOP'
<%= hash.to_json %>
EOP
) > /etc/chef/ohai/hints/<%= name %>.json
<% end -%>
<% end -%>
(
cat <<'EOP'
<%= config_content %>
EOP
) > /etc/chef/client.rb
(
cat <<'EOP'
<%= first_boot.to_json %>
EOP
) > /etc/chef/first-boot.json
<%= start_chef %>'
@ccooper21
Copy link
Author

What is this?

This is a Chef bootstrap script for bootstrapping the Chef client on an Amazon Linux AMI instance. It has been tested with Amazon Linux v2012.09 (AMI ID ami-1624987f).

How do I use it?

  1. Assuming your Chef management console is hosted in a Linux based environment, put this file in your ".chef/bootstrap" directory. If this directory does not already exist, you can first create it normally. The directory can either be in your home directory or in the root directory of your "git" repository you use to work with Chef.
  2. When you use the "knife ec2 create" command to instantiate an Amazon Linux AMI instance, include the "-d amazon-linux-omnibus" option. For example:

knife ec2 server create -I ami-1624987f -f t1.micro -G ssh-only -i .chef/aws-master-key.pem -S master-key -x ec2-user -d amazon-linux-omnibus

Why does it exist?

I didn't find Chef to support Amazon Linux well out-of-the-box. Specifically, I encountered several problems:

  • By default, Amazon Linux does not have "gcc" or other traditional development tools installed. While I'm glad Amazon Linux's default configuration includes less rather than more, this apparently creates a disparity with other AMIs. Since I am using some recipes that that build additional tools from source code (e.g. the latest Python v2.7.x interpreter), I need these tools to be installed.
  • The default "sudo" configuration does not include the "/usr/local/bin" directory in the "PATH" environment variable, limiting access via the "sudo" command to tools built from source, assuming they are installed in the "/usr/local/bin" directory.

In addition, while others have posted similar bootstrap scripts, the ones I found all installed Chef as a Ruby gem. Since I am not doing any Ruby development, am not planning to extend Chef beyond the use of recipes and cookbooks, and don't care to build and install Chef's dependencies, I prefer to use the Chef client omnibus installer which bundles together the Chef client and its dependencies.

Contributions

Most of the credit for this bootstrap script goes to others. It was cobbled together based on the "chef-full.erb" and "centos5-gems.erb" scripts included with Chef. It also includes snippets from the Ruby gem based Amazon Linux AMI script found at https://gist.github.com/1571189.

Outstanding Questions and Issues

  • I'm unclear on the best practices with respect to installing "gcc" and the like. On one hand, it seems like "gcc" should be installed using a Chef recipe. On the other hand, it seems like Chef community cookbooks expect that certain base tools are always available. While this appears to include "gcc", I don't know where this is documented.

  • I was expecting this same bootstrap script to work with the RightScale Centos v6.3 AMI (AMI ID ami-3b7bfc52) since Amazon Linux is based on Centos. However, it fails on this statement:

    sudo sed -i "s/(Defaults[[:space:]]secure_path[[:space:]]=[[:space:]])(.)/\1/usr/local/sbin:/usr/local/bin:\2/g" /etc/sudoers

    The failure is a result of a string substitution the "knife ssh" command performs that adds a "-p" option to this occurrence of the "sudo" command. As of Chef v10.16.2, the code that makes this string substitution can be found in the "chef/knife/ssh.rb" file and is as follows:

    command.sub(/^sudo/, 'sudo -p 'knife sudo password: '')

    I have not yet figured out why the resulting behavior is different on Amazon Linux vs. Centos. As a workaround, white space can be inserted before the "sudo" command causing the regular expression for the string substitution to not match.

  • While not a Chef issue, I am wondering what the best practice is around installing tools from packages vs. source code. I specifically ran into this with respect to the Python interpreter as the Amazon Linux AMI includes Python v2.6.x while I am deploying an application built on Python v2.7.x. While I believe the Amazon Linux package repository includes a Python v2.7.x package, installing it breaks "yum" since "yum" expects certain non-default libraries (i.e. eggs) to be installed. Building Python v2.7.x from source and installing it in the "/usr/local/bin" directory allows both versions of Python to co-exist and keeps "yum" working. Is this the right thing to do?

Disclaimer / Feedback

My past experience with Linux has been as a super user running Linux on a few nodes for development purposes as opposed to my current assignment as an administrator managing Linux across many nodes in both pre-production and production environments. I am also new to Chef. Hence, I am especially interested in feedback letting me know where I am on-track and off-track. Details are appreciated.

@ccooper21
Copy link
Author

I stripped down the list of additional packages to install via "yum" to just "gcc", "gcc-g++", and "make". These are sufficient to get the Chef client installed and execute the recipes that I am currently using. I did find this article, http://wiki.opscode.com/display/chef/Installing+Chef+Client+and+Chef+Solo, that suggests the minimal dependencies also include the "autoconf" and "automake" packages. This dependency list is for installing the Chef client as a Ruby gem though instead of via the omnibus installer. Also, I haven't found a reason to install any packages for development libraries, as was the case in the bootstrap script from which I started, so I removed them. The Chef recipes I am using seem to know which libraries on which they depend and hence install the necessary libraries as needed.

@ccooper21
Copy link
Author

Regarding the addition of the "/usr/local/bin" directory to the path used by the "sudo" command, this is no longer necessary with the cookbooks I am using since the v1.2.0 release of the Python cookbook. The addition of this directory to the path was a partial workaround for issue COOK-1866 (see http://tickets.opscode.com/browse/COOK-1866) fixed in this release.

I'm guessing this may still prove necessary for other cookbooks though. In the event that I keep this statement, it really should be split into two statements, one each for the "/usr/local/sbin" and "/usr/local/bin" directories, and each statement should be made idempotent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment