module Cfer::Provisioning
Constants
- DEFAULT_HUP_INTERVAL_IN_MINUTES
- VERSION
Public Instance Methods
build_write_json_cmd(chef_solo_json_path)
click to toggle source
# File lib/cfer/provisioning/chef.rb, line 66 def build_write_json_cmd(chef_solo_json_path) python_json_dump = [ 'import sys; import json;', 'print json.dumps(json.loads(sys.stdin.read())', '.get("CferExt::Provisioning::Chef", {}), sort_keys=True, indent=2)' ].join('') cmd = <<-BASH.strip_heredoc mkdir -p '#{File.dirname(chef_solo_json_path)}' && cfn-get-metadata --region 'C{AWS.region}' \ -s 'C{AWS.stack_name}' \ -r #{@name} | python -c '#{python_json_dump}' > #{chef_solo_json_path} BASH Cfer.cfize(cmd) end
cfn_auth(name, options = {})
click to toggle source
# File lib/cfer/provisioning/cfn-bootstrap.rb, line 10 def cfn_auth(name, options = {}) cfn_metadata['AWS::CloudFormation::Authentication'] ||= {} cfn_metadata['AWS::CloudFormation::Authentication'][name] = options end
cfn_init_config(name, options = {}, &block)
click to toggle source
# File lib/cfer/provisioning/cfn-bootstrap.rb, line 36 def cfn_init_config(name, options = {}, &block) cfg = ConfigSet.new(cloudformation_init[name]) Docile.dsl_eval(cfg, &block) cloudformation_init[name] = cfg.to_h end
cfn_init_config_set(name, sections)
click to toggle source
# File lib/cfer/provisioning/cfn-bootstrap.rb, line 28 def cfn_init_config_set(name, sections) cfg_sets = cloudformation_init['configSets'] || { 'default' => [] } cfg_set = Set.new(cfg_sets[name] || []) cfg_set.merge sections cfg_sets[name] = cfg_set.to_a cloudformation_init['configSets'] = cfg_sets end
cfn_init_setup(options = {})
click to toggle source
# File lib/cfer/provisioning/cfn-bootstrap.rb, line 15 def cfn_init_setup(options = {}) cfn_metadata['AWS::CloudFormation::Init'] = {} cfn_init_set_cloud_init(options) if options[:cfn_hup_config_set] cfn_hup(options) end end
cfn_metadata()
click to toggle source
# File lib/cfer/provisioning/cfn-bootstrap.rb, line 6 def cfn_metadata self[:Metadata] ||= {} end
chef_client(options = {})
click to toggle source
# File lib/cfer/provisioning/chef.rb, line 84 def chef_client(options = {}) raise "Chef already configured on this resource" if @chef @chef = true raise "must specify chef_server_url" if options[:chef_server_url].nil? raise "must specify validation_client_name" if options[:validation_client_name].nil? options[:config_path] ||= '/etc/chef/client.rb' options[:json_path] ||= '/etc/chef/node.json' options[:cookbook_path] ||= '/var/chef/cookbooks' options[:data_bag_path] ||= '/var/chef/data_bags' options[:log_path] ||= '/var/log/chef-client.log' options[:service_type] ||= :upstart run_set = [] install_chef_with_cloud_init(options) unless options[:no_install] add_write_chef_json(options) run_set << :write_chef_json cfn_init_config :run_chef_client do client_rb = Erubis::Eruby.new(IO.read("#{__dir__}/client.rb.erb")).result(options: options) file options[:config_path], content: Cfer.cfize(options[:client_rb] || client_rb), mode: '000400', owner: 'root', group: 'root' command :'00_run_chef_once', 'chef-client --once' end run_set << :run_chef_client cfn_init_config_set :run_chef_client, run_set end
chef_solo(options = {})
click to toggle source
# File lib/cfer/provisioning/chef.rb, line 119 def chef_solo(options = {}) raise "Chef already configured on this resource" if @chef @chef = true must_install_berkshelf = !options[:berksfile].nil? || options[:force_berkshelf_install] options[:config_path] ||= '/etc/chef/solo.rb' options[:json_path] ||= '/etc/chef/node.json' options[:cookbook_path] ||= '/var/chef/cookbooks' options[:data_bag_path] ||= '/var/chef/data_bags' options[:log_path] ||= '/var/log/chef-solo.log' install_chef_with_cloud_init(options) unless options[:no_install] if must_install_berkshelf install_berkshelf(options) if must_install_berkshelf # places cloud-init runners end run_set = [] unless options[:berksfile].nil? emit_berksfile(options) run_set << :emit_berksfile end unless options[:berksfile].nil? || options[:no_run_berkshelf] run_berkshelf(options) run_set << :run_berkshelf end add_write_chef_json(options) run_set << :write_chef_json cfn_init_config :run_chef_solo do solo_rb = <<-RB.strip_heredoc cookbook_path '#{options[:cookbook_path]}' log_location '#{options[:log_path]}' json_attribs '#{options[:json_path]}' RB file options[:config_path], content: options[:solo_rb] || solo_rb, mode: '000400', owner: 'root', group: 'root' command :run_chef, 'chef-solo' end run_set << :run_chef_solo cfn_init_config_set :run_chef_solo, run_set end
cloud_init()
click to toggle source
# File lib/cfer/provisioning/cloud-init.rb, line 12 def cloud_init unless self.key?(:CloudInit) self[:CloudInit] = { bootcmd: [], runcmd: [], packages: [], ssh_authorized_keys: [], write_files: [ { path: '/etc/cfn-resource-name', permissions: '0444', content: @name.to_s }, { path: '/etc/cfn-stack-name', permissions: '0444', content: 'C{AWS.stack_name}' }, { path: '/etc/cfn-region', permissions: '0444', content: 'C{AWS.region}' } ], output: {} } end self[:CloudInit] end
cloud_init_bootcmds()
click to toggle source
# File lib/cfer/provisioning/cloud-init.rb, line 43 def cloud_init_bootcmds cloud_init[:bootcmd] end
cloud_init_finalize!()
click to toggle source
# File lib/cfer/provisioning/cloud-init.rb, line 67 def cloud_init_finalize! cloud_init_outputs[:all] ||= "| tee -a /var/log/cloud-init-output.log" user_data Fn.base64( cloud_init_to_user_data(self[:CloudInit]) ) self.delete :CloudInit end
cloud_init_outputs()
click to toggle source
# File lib/cfer/provisioning/cloud-init.rb, line 51 def cloud_init_outputs cloud_init[:output] end
cloud_init_packages()
click to toggle source
# File lib/cfer/provisioning/cloud-init.rb, line 55 def cloud_init_packages cloud_init[:packages] end
cloud_init_runcmds()
click to toggle source
# File lib/cfer/provisioning/cloud-init.rb, line 47 def cloud_init_runcmds cloud_init[:runcmd] end
cloud_init_write_files()
click to toggle source
# File lib/cfer/provisioning/cloud-init.rb, line 59 def cloud_init_write_files cloud_init[:write_files] end
config_set(name)
click to toggle source
# File lib/cfer/provisioning/cfn-bootstrap.rb, line 24 def config_set(name) { "ConfigSet" => name } end
emit_berksfile(options)
click to toggle source
# File lib/cfer/provisioning/chef.rb, line 53 def emit_berksfile(options) cfn_init_config :emit_berksfile do file '/var/chef/Berksfile', content: Cfer.cfize(options[:berksfile].strip_heredoc), mode: '000500', owner: 'root', group: 'root' end end
install_berkshelf(options)
click to toggle source
# File lib/cfer/provisioning/chef.rb, line 15 def install_berkshelf(options) cloud_init_packages << 'git' cloud_init_bootcmds << '/opt/chef/embedded/bin/gem install berkshelf --no-ri --no-rdoc' berks_content = <<-EOF.strip_heredoc # may be run before HOME is established (fixes RbReadLine bug) export HOME=/root export BERKSHELF_PATH=/var/chef/berkshelf # Some cookbooks have UTF-8, and cfn-init uses US-ASCII because of reasons export LANG=en_US.UTF-8 export RUBYOPTS="-E utf-8" set -e [ -f /opt/chef/embedded/bin/berks ] || /opt/chef/embedded/bin/gem install berkshelf -v 4.3.5 set +e # Berkshelf seems a bit unreliable, so retry these commands a couple times. if [ -e Berksfile.lock ] then for i in {1..3}; do /opt/chef/embedded/bin/berks update && break || sleep 15 done fi for i in {1..3}; do /opt/chef/embedded/bin/berks vendor '#{options[:cookbook_path]}' \ -b /var/chef/Berksfile && break || sleep 15 done EOF cloud_init_write_files << { path: '/var/chef/berkshelf.sh', content: berks_content, permissions: '0500' } end
install_chef_with_cloud_init(options = {})
click to toggle source
# File lib/cfer/provisioning/chef.rb, line 2 def install_chef_with_cloud_init(options = {}) # we can't use the cloud-init `chef` module because it expects a server/validator. cloud_init_bootcmds << "command -v chef-client || " \ "curl https://www.opscode.com/chef/install.sh | " \ "bash -s -- -v #{options[:version] || 'latest'}" cloud_init_bootcmds << "mkdir -p /etc/chef/ohai/hints" cloud_init_bootcmds << "touch /etc/chef/ohai/hints/ec2.json" cloud_init_bootcmds << "mkdir -p '#{options[:cookbook_path]}'" cloud_init_bootcmds << "mkdir -p '#{options[:data_bag_path]}'" end
run_berkshelf(options)
click to toggle source
# File lib/cfer/provisioning/chef.rb, line 60 def run_berkshelf(options) cfn_init_config :run_berkshelf do command :run_berkshelf, '/var/chef/berkshelf.sh', cwd: '/var/chef' end end
Private Instance Methods
add_write_chef_json(options)
click to toggle source
# File lib/cfer/provisioning/chef.rb, line 171 def add_write_chef_json(options) options[:run_list] ||= [] options[:json] ||= {} cfn_metadata['CferExt::Provisioning::Chef'] = options[:json].merge(run_list: options[:run_list]) cfn_init_config :write_chef_json do command :write_chef_json, build_write_json_cmd(options[:json_path]) end end
cfn_hup(options)
click to toggle source
# File lib/cfer/provisioning/cfn-bootstrap.rb, line 84 def cfn_hup(options) resource_name = @name target_config_set = options[:cfn_hup_config_set] || raise('Please specify a `cfn_hup_config_set`') cfn_init_config_set :cfn_hup, [ :cfn_hup ] cfn_init_config(:cfn_hup) do if options[:access_key] && options[:secret_key] key_content = <<-FILE.strip_heredoc AWSAccessKeyId=#{options[:access_key]} AWSSecretKey=#{options[:secret_key]} FILE file '/etc/cfn/cfn-credentials', content: key_content, mode: '000400', owner: 'root', group: 'root' end hup_conf_content = <<-FILE.strip_heredoc [main] stack=C{AWS.stack_name} region=C{AWS.region} interval=#{options[:hup_interval] || DEFAULT_HUP_INTERVAL_IN_MINUTES} FILE file '/etc/cfn/cfn-hup.conf', content: Cfer.cfize(hup_conf_content), mode: '000400', owner: 'root', group: 'root' cfn_init_reload_content = <<-FILE.strip_heredoc [cfn-auto-reloader-hook] triggers=post.update path=Resources.#{resource_name}.Metadata runas=root action=/usr/local/bin/cfn-init -r #{resource_name} --region C{AWS.region} -s C{AWS.stack_name} -c '#{target_config_set.join(",")}' FILE file '/etc/cfn/hooks.d/cfn-init-reload.conf', content: Cfer.cfize(cfn_init_reload_content), mode: '000400', owner: 'root', group: 'root' end end
cfn_init_set_cloud_init(options)
click to toggle source
# File lib/cfer/provisioning/cfn-bootstrap.rb, line 125 def cfn_init_set_cloud_init(options) cloud_init_bootcmds << "mkdir -p /usr/local/bin" case options[:flavor] when :redhat, :centos, :amazon cloud_init_bootcmds << 'rpm -Uvh https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.amzn1.noarch.rpm' when :debian, :ubuntu, nil [ 'apt-get update --fix-missing', 'apt-get install -y python-pip', 'pip install setuptools', 'easy_install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz' ].each { |line| cloud_init_bootcmds << line } end cfn_script_eruby = Erubis::Eruby.new(IO.read("#{__dir__}/cfn-bootstrap.bash.erb")) cloud_init_write_files << { path: '/usr/local/bin/cfn-bootstrap.bash', content: cfn_script_eruby.evaluate(resource_name: @name, options: options) } cloud_init_runcmds << "bash /usr/local/bin/cfn-bootstrap.bash" end
cloud_init_to_user_data(cloud_init)
click to toggle source
# File lib/cfer/provisioning/cloud-init.rb, line 75 def cloud_init_to_user_data(cloud_init) Cfer.cfize([ '#cloud-config', YAML.dump(cloud_init.to_hash_recursive.deep_stringify_keys).gsub(/^---$/, "") ].join("\n")) end
cloudformation_init(options = {})
click to toggle source
# File lib/cfer/provisioning/cfn-bootstrap.rb, line 79 def cloudformation_init(options = {}) cfn_metadata['AWS::CloudFormation::Init'] ||= {} end