Created
June 7, 2013 02:27
-
-
Save tily/5726678 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
OPSWORKS_USERDATA_LOG_FILE='/var/log/aws/opsworks/user-data.log' | |
export OPSWORKS_USERDATA_LOG_FILE | |
mkdir -p $(dirname ${OPSWORKS_USERDATA_LOG_FILE}) | |
touch ${OPSWORKS_USERDATA_LOG_FILE} && chmod 0600 ${OPSWORKS_USERDATA_LOG_FILE} | |
exec &> >(tee -a ${OPSWORKS_USERDATA_LOG_FILE}) 2>&1 | |
conslog () { | |
echo "[$(date --rfc-2822)] opsworks-init: $1" | tee -a ${OPSWORKS_USERDATA_LOG_FILE} > /dev/console | |
} | |
execute () { | |
conslog "Executing: $1" | |
eval "$1" | |
if (($? > 0)) | |
then | |
conslog "Bailing out, failed to execute: $1" | |
exit | |
fi | |
} | |
set -e | |
conslog 'Initiallizing AWS OpsWorks environment' | |
conslog 'Installing system packages' | |
execute 'yum -y update' | |
execute 'yum -y install ruby ruby-devel rubygems libicu-devel openssl-devel libxml2-devel libxslt-devel' | |
conslog 'Setup motd' | |
release_name=`head -1 /etc/issue |sed -e 's/ \\\\.*//'` | |
cat <<EOM > /etc/motd.opsworks-static | |
This instance is managed with AWS OpsWorks. | |
###### OpsWorks Summary ###### | |
Operating System: $release_name | |
OpsWorks Instance: pantherinae | |
OpsWorks Instance ID: bbad6b41-6787-4276-9c15-7ca11ad81db7 | |
OpsWorks Layers: rails-app | |
OpsWorks Stack: tily001 | |
EC2 Region: us-east-1 | |
EC2 Availability Zone: us-east-1d | |
Visit http://aws.amazon.com/opsworks for more information. | |
EOM | |
execute 'rm /etc/motd && ln -s /etc/motd.opsworks-static /etc/motd' | |
conslog 'Creating agent pre-install script' | |
umask 0077 | |
WORKDIR='/var/lib/aws/opsworks' | |
mkdir -p ${WORKDIR} | |
chmod 0750 ${WORKDIR} | |
# download the agent and initiate installation | |
DOWNLOAD_AND_INITIATE="${WORKDIR}/spark.rb" | |
cat <<"EOM" > $DOWNLOAD_AND_INITIATE | |
#!/usr/bin/env ruby | |
# | |
# This downloads the opsworks instance agent and initiates its installation | |
require 'fileutils' | |
require 'yaml' | |
LOG_FILE = ENV['OPSWORKS_USERDATA_LOG_FILE'] || '/dev/null' | |
OPSWORKS_AGENT_INSTALLER_URL='https://opsworks-instance-agent.s3.amazonaws.com:443/103/opsworks-agent-installer.tgz' | |
OPSWORKS_AGENT_INSTALLER_TGZ='opsworks-agent-installer.tgz' | |
OPSWORKS_AGENT_INSTALLER_DIR='opsworks-agent-installer' | |
# encoding: UTF-8 | |
require 'digest/sha1' | |
module OpsWorks | |
module Instance | |
class Downloader | |
attr_accessor :url, :log_file, :checksum_url | |
def initialize(url, log_file = nil, checksum_url = nil) | |
raise ArgumentError, 'need URL' if url.nil? | |
@url = url | |
@log_file = log_file | |
@checksum_url = checksum_url || url + '-checksum' | |
end | |
def download | |
ensure_wget_installed | |
fetch_with_checksum | |
end | |
protected | |
def log(msg) | |
`echo "\n#{msg}\n" >> #{log_file}` if log_file | |
end | |
def ensure_wget_installed | |
unless system('which wget > /dev/null') | |
log "wget not installed - aborting download" | |
raise "wget is not installed or not in $PATH" | |
end | |
end | |
def fetch(path, retried_count = 0) | |
raise "failed to download #{path} after #{retried_count} attempts" if retried_count > 4 | |
if log_file | |
downloaded = system("wget -nv -T 30 -O /tmp/#{File.basename(path)} #{path} >> #{log_file} 2>&1") | |
else | |
downloaded = system("wget -nv -T 30 -O /tmp/#{File.basename(path)} #{path}") | |
end | |
unless downloaded | |
retried_count += 1 | |
log "download of #{path} failed - sleeping #{retried_count * 15}" | |
sleep retried_count * 15 | |
fetch(path, retried_count) | |
end | |
end | |
def fetch_with_checksum(retried_count = 0) | |
raise "failed to match checkum of #{url} after #{retried_count} attempts" if retried_count > 4 | |
fetch(url) | |
fetch(checksum_url) | |
content_path = "/tmp/#{File.basename(url)}" | |
checksum_path = "/tmp/#{File.basename(checksum_url)}" | |
unless content_verified?(content_path, checksum_path) | |
retried_count += 1 | |
log "checksum mismatch - re-downloading after #{retried_count * 15} seconds" | |
FileUtils.rm(content_path) if File.exists?(content_path) | |
FileUtils.rm(checksum_path) if File.exists?(checksum_path) | |
sleep retried_count * 15 | |
fetch_with_checksum(retried_count) | |
end | |
log "Download of #{url} finished and checksum verified" | |
end | |
def content_verified?(content_path, checksum_path) | |
size_ok?(content_path, checksum_path) && checksum_ok?(content_path, checksum_path) | |
end | |
def size_ok?(content_path, checksum_path) | |
log "verifying size of #{content_path}" | |
original_size = nil | |
File.readlines( checksum_path ).each do |line| | |
next unless line.match(/\ASIZE/) | |
original_size = line.chomp.sub(/\ASIZE\ /,'').to_i | |
end | |
return original_size == File.size(content_path) | |
end | |
def checksum_ok?(content_path, checksum_path) | |
log "verifying checksum of #{content_path}" | |
original_checksum = nil | |
File.readlines( checksum_path ).each do |line| | |
next unless line.match(/\ASHA-1/) | |
original_checksum = line.chomp.sub(/\ASHA-1\ /,'') | |
end | |
return original_checksum == checksum(content_path) | |
end | |
def checksum(file) | |
now = Time.now.to_i | |
case checksum_cmd | |
when :shasum | |
check = `shasum #{file}`.match(/([a-zA-Z0-9]+)\s+/)[1] | |
when :ruby | |
check = Digest::SHA1.hexdigest(File.read(file)) | |
else | |
raise "No known checksum CMD? #{checksum_cmd.inspect}" | |
end | |
log "Took #{Time.now.to_i - now} seconds to compute checksum of #{file}" | |
check | |
end | |
def checksum_cmd | |
@_checksum_cmd ||= if system('which shasum > /dev/null') | |
log "using shasum as the checksum method" | |
:shasum | |
else | |
log "using Ruby's Digest::SHA1 as the checksum method" | |
:ruby | |
end | |
end | |
end | |
end | |
end | |
def generate_agent_pre_config | |
File.umask 0077 | |
pre_config_file = '/var/lib/aws/opsworks/pre_config.yml' | |
FileUtils.mkdir_p File.dirname(pre_config_file) | |
File.open(pre_config_file, 'w') do |f| | |
f.print YAML.dump( | |
:hostname => 'pantherinae', | |
:identity => 'bbad6b41-6787-4276-9c15-7ca11ad81db7', | |
:agent_installer_base_url => 'opsworks-instance-agent.s3.amazonaws.com', | |
:agent_installer_tgz => 'opsworks-agent-installer.tgz', | |
:verbose => false, | |
:instance_service_region => 'us-east-1', | |
:instance_service_endpoint => 'opsworks-instance-service.us-east-1.amazonaws.com', | |
:instance_service_port => '443', | |
:instance_public_key => '-----BEGIN PUBLIC KEY----- | |
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuTv2vHNXd2Fk6vfNq6s2 | |
ChAVVcshrHWYnnGBPuaA3/lS7uyPN/o2R57q9b3k8RWprKDQMErinazBSqwq/aAa | |
B94ZkCFlCtjcapV7M6a9/uPt42TW8jx2ysWz3zAttUKQ6hWV9qCwxEtusM9vaRlJ | |
DAJ9MINeegm6yf64b7aj7Wu7T8JBMOvpwvjgWZFU2bVS2UuS6AvVR4gfOxDupKpJ | |
LDWghADR37RNrcJND2ei5x6lHMDPV2ZaDJ9OG22JoeQltDR47SkBOHgnlvYVVOCB | |
uMyQoeyeuygkmPp+JFBJxz0K3xepgLLlSuTh6hkK7NpO6lJjEnbf6GvyGgYOBd23 | |
9wIDAQAB | |
-----END PUBLIC KEY----- | |
', | |
:instance_private_key => '-----BEGIN RSA PRIVATE KEY----- | |
MIIEpAIBAAKCAQEAuTv2vHNXd2Fk6vfNq6s2ChAVVcshrHWYnnGBPuaA3/lS7uyP | |
N/o2R57q9b3k8RWprKDQMErinazBSqwq/aAaB94ZkCFlCtjcapV7M6a9/uPt42TW | |
8jx2ysWz3zAttUKQ6hWV9qCwxEtusM9vaRlJDAJ9MINeegm6yf64b7aj7Wu7T8JB | |
MOvpwvjgWZFU2bVS2UuS6AvVR4gfOxDupKpJLDWghADR37RNrcJND2ei5x6lHMDP | |
V2ZaDJ9OG22JoeQltDR47SkBOHgnlvYVVOCBuMyQoeyeuygkmPp+JFBJxz0K3xep | |
gLLlSuTh6hkK7NpO6lJjEnbf6GvyGgYOBd239wIDAQABAoIBADdUagcwjNfkB7kH | |
/C9jHOk0lKrj2lMhbU0mqmyXfbdpShSEJOObocsS9SwiZNh+mAgwoP9L3xUqHTKo | |
6s6HnD7tYMVktEHhNTXBIOP00pvoiY56+Jmy5ej71Ra91WlnUNIbUIgyx5pazd2S | |
mLzUCLXFqI9tLjNV5K2hoIX+EElCelSXV4BrmPk4K75PyfZ08D++jouopyVCf6DV | |
5MA81iYqradx4amaqXY8EU5FN8iEuBiiyWlx4kfYCPSL1rORJHVCjAsYoWKN6qPD | |
QDWvfwwJ3hajJJ3qLjp4Ttf2tYBI9ghMqT5+JYRgulVvW0utCpnz1+BiDASCvhir | |
elRutEECgYEA7BEvCZ72zZNvN8UW9ipmpATc1qhIx4B1VcWmkMxB8wJ31j0DoH1/ | |
VGYcqNGluGLlWLYDctmgXQ/KWiWEvlJ4P2+j/8tvJ0zBCKinOTrqj91ijginZyw4 | |
cbf4k1a48CLm0gxlkC0lGUWydicAYVyrL4QnWC+or/LHuu70tsXRQYMCgYEAyN/6 | |
hqoVaza9zEZIQRnSn36Oj8HqxZ5bA5UlqggXsoBaqsJxuQcHNzOyg/0EsBCP6f2P | |
ndJ4hbNcG91dturivr4/e1wKqYuvanFr/wgTLQZLpKUuQ13IGVf6KIYrUCKGrps2 | |
hmbPwic4gXEojgJRWvCZE55cM25IOObw3rtGaX0CgYEAzh6m6oihSJiOCK0PQnt9 | |
SYNxbABeI8v3J6A/sriWcN/b0PVPYGeTsRbDuWfsghXf2Vh7pGF/EyLBdXrC8AdE | |
NWd+U8/GSxNKjQvtjxvxSRJthkTqHjzPQAP5iHS1X/+peQgX+g5hETL5Aw9E1r46 | |
Pm/uhqJ+cLrUSFVy2M/ayY8CgYEAhI4A9UJhlflur9ElNwiCS8uo6caOVVAVQTz3 | |
uMdUU++NZSehAfdYVJ4hzCV4JXMYdNFlJ0FPVPMx8hVXFTDU5ggHPjFTu+Q4omYs | |
XQQIG2sPGZwC9mN5evfqVTmMdXoDJE+6YGCR8s4M5KY2m9d9tiQU77RNpYa91AbZ | |
pjEw2sUCgYBWieKBYwWwjRiEMas0eU4HjykwqDG48TE2A2UGNyHQgc44pATj0Fs1 | |
Orbb0d3DZt1uV97bOxWtmh26ewGp7t1mC3qZTsUbtGqQDzTPbpuSULGCyeBSjEgS | |
ve8DvwA73DAm21Qn3BKsHczOKAR8KwmKpYDkH5fQ5epXYyEuBUhaTg== | |
-----END RSA PRIVATE KEY----- | |
', | |
:charlie_public_key => '-----BEGIN PUBLIC KEY----- | |
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAni7eKdm34oaCvGiw96Fk | |
lyLX+aPfInYzilkk+AY3pXF6nijpQ2cm3ZeM2EoqZFTv3a/meosNBAs3Q3Sy1e4G | |
7Ibn/xwMof+iSBvimx3PGKFzNP0BhY9yS6AMEMxtmqksHb0glwmFeJcomdhxZV1F | |
ziWTtL6ZEyvCg0I7rxGm1ceQmD25eK90VcZVh4LJtNfnwcZRM4eC+KK9Qllxw5hW | |
vB4Z52JMMZbEG9MYCLydWSY9rnVkAyQ0ngJUaJ3q7JsbkBV/J5BcrGgcbioR1k+h | |
INRoHwBQU9WnT/x8W+N6vwJb4o6v2hBR1H2GSDLwyZ7wC8EVH+XafWYpU1g/nSEe | |
aQIDAQAB | |
-----END PUBLIC KEY----- | |
', | |
:wait_between_runs => '60' | |
) | |
end | |
end | |
def log(msg) | |
puts msg | |
`echo "#{msg}" >> #{LOG_FILE}` | |
end | |
def measure(description) | |
now = Time.now.to_i | |
log("#{Time.now.strftime("%Y-%m-%d %H:%M:%S")} - Starting: #{description}") | |
yield | |
log("#{Time.now.strftime("%Y-%m-%d %H:%M:%S")} - Finished: #{description} in #{Time.now.to_i - now} sec") | |
end | |
def download_installer | |
`rm -rf /tmp/#{File.basename(OPSWORKS_AGENT_INSTALLER_URL)}` | |
`rm -rf /tmp/#{File.basename(OPSWORKS_AGENT_INSTALLER_URL, '.tgz')}*` | |
OpsWorks::Instance::Downloader.new(OPSWORKS_AGENT_INSTALLER_URL, LOG_FILE).download | |
end | |
def unpack_agent | |
`cd /tmp && tar -xvzpof #{OPSWORKS_AGENT_INSTALLER_TGZ}` | |
end | |
def run_installer | |
`cd /tmp && ruby #{OPSWORKS_AGENT_INSTALLER_DIR}/boot.rb && cd /tmp && rm -rf #{OPSWORKS_AGENT_INSTALLER_DIR}*` | |
end | |
measure 'Running all Userdata' do | |
measure('Download Installer') { download_installer } | |
measure('Unpack Agent Package') { unpack_agent } | |
measure('Create pre configuration file') { generate_agent_pre_config } | |
measure('Run Installer') { run_installer } | |
end | |
EOM | |
conslog 'Running agent pre-install script' | |
execute "/usr/bin/ruby ${DOWNLOAD_AND_INITIATE}" | |
if (($? == 0)) | |
then | |
execute "rm ${DOWNLOAD_AND_INITIATE}" | |
conslog 'Succesfully installed the AWS OpsWorks agent' | |
conslog 'Rebooting instance' | |
execute 'reboot' | |
else | |
conslog 'Agent Installation failed.' | |
conslog 'Please verify the log files found under /var/log/aws/opsworks and submmit findings to AWS Support.' | |
conslog 'You can also verify the instace system console on the AWS EC2 Console' | |
conslog 'This instance will be shutdown 30 minutes after this failure' | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment