emilsoman/cloudster

View on GitHub
lib/cloudster/chef_client.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module Cloudster
  #==UserData for Chef Client bootstrap
  class ChefClient

    # Initialize an ChefClient configuration
    #
    # ==== Notes
    # options parameter must include values for :validation_key, :server_url and :node_name
    #
    # ==== Examples
    #   chef_client = Cloudster::ChefClient.new(
    #    :validation_key => 'asd3e33880889098asdnmnnasd8900890a8sdmasdjna9s880808asdnmnasd90-a',
    #    :server_url => 'http://10.50.60.70:4000',
    #    :node_name => 'project.environment.appserver_1',
    #    :validation_client_name => 'chef-validator',
    #    :interval => 1800
    #   )
    #
    # ==== Parameters
    # * options<~Hash> -
    #     * :validation_key: String containing the key used for validating this client with the server. This can be taken from the chef-server validation.pem file. Mandatory field
    #     * :server_url: String containing the fully qualified domain name of the chef-server. Mandatory field
    #     * :node_name: String containing the name for the chef node. It has to be unique across all nodes in the particular chef client-server ecosystem. Mandatory field
    #     * :interval: Integer containing the interval(in seconds) between chef-client runs. Default value : 1800 seconds
    #     * :validation_client_name: String containing the name of the validation client. "ORGNAME-validator" if using hosted chef server. Default: 'chef-validator'
    def initialize(options = {})
      require_options(options, [:validation_key, :server_url, :node_name])
      @validation_key = options[:validation_key]
      @server_url = options[:server_url]
      @node_name = options[:node_name]
      @interval = options[:interval] || 1800
      @validation_client_name = options[:validation_client_name] || 'chef-validator'
    end

    # Merges the required CloudFormation template for installing the Chef Client to the template of the EC2 instance
    #
    #
    # ==== Examples
    #   chef_client = Cloudster::ChefClient.new(
    #    :validation_key => 'asd3e33880889098asdnmnnasd8900890a8sdmasdjna9s880808asdnmnasd90-a',
    #    :server_url => 'http://10.50.60.70:4000',
    #    :node_name => 'project.environment.appserver_1'
    #   )
    #   ec2 = Cloudster::Ec2.new(
    #    :name => 'AppServer',
    #    :key_name => 'mykey',
    #    :image_id => 'ami_image_id',
    #    :instance_type => 't1.micro'
    #   )
    #
    #   chef_client.add_to ec2
    #
    # ==== Parameters
    # * instance of EC2
    def add_to(ec2)
      ec2_template = ec2.template
      @instance_name = ec2.name
      chef_client_template = template
      ec2.template.inner_merge(chef_client_template)
    end

    private
      def template
        return "Resources" => {
          @instance_name => {
            "Metadata" => {
              "AWS::CloudFormation::Init" => {
                "config" => {
                  "packages" => {
                    "rubygems" => {
                      "chef" => [],
                      "ohai" => []
                     },
                    "apt" => {
                       "ruby"            => [],
                       "ruby-dev"        => [],
                       "libopenssl-ruby" => [],
                       "rdoc"            => [],
                       "ri"              => [],
                       "irb"             => [],
                       "build-essential" => [],
                       "wget"            => [],
                       "ssl-cert"        => [],
                       "rubygems"        => []
                    }
                  }
                }
              }
            },
            "Properties"=> {
              "UserData" => { "Fn::Base64" => { "Fn::Join" => ["", [
                "#!/bin/bash -v\n",
                "function error_exit\n",
                "{\n",
                "  exit 1\n",
                "}\n",

                #Install aws sfn scripts to run cfn-init
                "apt-get -y install python-setuptools\n",
                "easy_install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n",
                "cfn-init -v --region ", { "Ref" => "AWS::Region" },
                " -s ", { "Ref" => "AWS::StackId" }, " -r #{@instance_name}",
                " || error_exit 'Failed to run cfn-init'\n",

                # Fixup path and links for the bootstrap script
                "export PATH=$PATH:/var/lib/gems/1.8/bin\n",

                #Bootstrap chef client
                "mkdir /etc/chef\n",
                "cat << EOF > /etc/chef/solo.rb\n",
                "file_cache_path \"/tmp/chef-solo\"\n",
                "cookbook_path \"/tmp/chef-solo/cookbooks\"\n",
                "node_name \"#{@node_name}\"\n",
                "EOF\n",
                "cat << EOF > /etc/chef/chef.json\n",
                "{\n",
                "\"chef_client\": {\n",
                "  \"server_url\": \"#{@server_url}\",\n",
                "  \"validation_client_name\": \"#{@validation_client_name}\",\n",
                "  \"interval\": \"#{@interval}\"\n",
                "},\n",
                "\"run_list\": [\"recipe[chef-client::config]\", \"recipe[chef-client]\"]\n",
                "}\n",
                "EOF\n",
                "echo \"#{@validation_key}\" > /etc/chef/validation.pem\n",
                "# Bootstrap chef\n",
                "chef-solo -c /etc/chef/solo.rb -j /etc/chef/chef.json -r http://s3.amazonaws.com/chef-solo/bootstrap-latest.tar.gz  > /tmp/chef_solo.log 2>&1 || error_exit 'Failed to bootstrap chef client'\n"
            ]]}}
            }
          }
        }
      end

  end
end