forger 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.gitmodules +0 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +147 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +136 -0
- data/Guardfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +249 -0
- data/Rakefile +6 -0
- data/docs/example/.env +2 -0
- data/docs/example/.env.development +2 -0
- data/docs/example/.env.production +3 -0
- data/docs/example/app/scripts/hello.sh +3 -0
- data/docs/example/app/user-data/bootstrap.sh +35 -0
- data/docs/example/config/development.yml +8 -0
- data/docs/example/profiles/default.yml +11 -0
- data/docs/example/profiles/spot.yml +20 -0
- data/exe/forger +14 -0
- data/forger.gemspec +38 -0
- data/lib/forger.rb +29 -0
- data/lib/forger/ami.rb +10 -0
- data/lib/forger/aws_service.rb +7 -0
- data/lib/forger/base.rb +42 -0
- data/lib/forger/clean.rb +13 -0
- data/lib/forger/cleaner.rb +5 -0
- data/lib/forger/cleaner/ami.rb +45 -0
- data/lib/forger/cli.rb +67 -0
- data/lib/forger/command.rb +67 -0
- data/lib/forger/completer.rb +161 -0
- data/lib/forger/completer/script.rb +6 -0
- data/lib/forger/completer/script.sh +10 -0
- data/lib/forger/config.rb +20 -0
- data/lib/forger/core.rb +51 -0
- data/lib/forger/create.rb +155 -0
- data/lib/forger/create/error_messages.rb +58 -0
- data/lib/forger/create/params.rb +106 -0
- data/lib/forger/dotenv.rb +30 -0
- data/lib/forger/help.rb +9 -0
- data/lib/forger/help/ami.md +13 -0
- data/lib/forger/help/clean/ami.md +22 -0
- data/lib/forger/help/compile.md +5 -0
- data/lib/forger/help/completion.md +22 -0
- data/lib/forger/help/completion_script.md +3 -0
- data/lib/forger/help/create.md +7 -0
- data/lib/forger/help/upload.md +10 -0
- data/lib/forger/help/wait/ami.md +12 -0
- data/lib/forger/hook.rb +33 -0
- data/lib/forger/profile.rb +64 -0
- data/lib/forger/script.rb +46 -0
- data/lib/forger/script/compile.rb +40 -0
- data/lib/forger/script/compress.rb +62 -0
- data/lib/forger/script/templates/ami_creation.sh +12 -0
- data/lib/forger/script/templates/auto_terminate.sh +11 -0
- data/lib/forger/script/templates/auto_terminate_after_timeout.sh +5 -0
- data/lib/forger/script/templates/cloudwatch.sh +3 -0
- data/lib/forger/script/templates/extract_aws_ec2_scripts.sh +48 -0
- data/lib/forger/script/upload.rb +99 -0
- data/lib/forger/scripts/auto_terminate.sh +14 -0
- data/lib/forger/scripts/auto_terminate/after_timeout.sh +18 -0
- data/lib/forger/scripts/auto_terminate/functions.sh +130 -0
- data/lib/forger/scripts/auto_terminate/functions/amazonlinux2.sh +10 -0
- data/lib/forger/scripts/auto_terminate/functions/ubuntu.sh +11 -0
- data/lib/forger/scripts/auto_terminate/setup.sh +31 -0
- data/lib/forger/scripts/cloudwatch.sh +24 -0
- data/lib/forger/scripts/cloudwatch/configure.sh +84 -0
- data/lib/forger/scripts/cloudwatch/install.sh +3 -0
- data/lib/forger/scripts/cloudwatch/install/amazonlinux2.sh +4 -0
- data/lib/forger/scripts/cloudwatch/install/ubuntu.sh +23 -0
- data/lib/forger/scripts/cloudwatch/service.sh +3 -0
- data/lib/forger/scripts/cloudwatch/service/amazonlinux2.sh +11 -0
- data/lib/forger/scripts/cloudwatch/service/ubuntu.sh +8 -0
- data/lib/forger/scripts/shared/functions.sh +78 -0
- data/lib/forger/setting.rb +52 -0
- data/lib/forger/template.rb +13 -0
- data/lib/forger/template/context.rb +32 -0
- data/lib/forger/template/helper.rb +17 -0
- data/lib/forger/template/helper/ami_helper.rb +33 -0
- data/lib/forger/template/helper/core_helper.rb +127 -0
- data/lib/forger/template/helper/partial_helper.rb +71 -0
- data/lib/forger/template/helper/script_helper.rb +53 -0
- data/lib/forger/template/helper/ssh_key_helper.rb +21 -0
- data/lib/forger/version.rb +3 -0
- data/lib/forger/wait.rb +12 -0
- data/lib/forger/waiter.rb +5 -0
- data/lib/forger/waiter/ami.rb +61 -0
- data/spec/fixtures/demo_project/config/settings.yml +22 -0
- data/spec/fixtures/demo_project/config/test.yml +9 -0
- data/spec/fixtures/demo_project/profiles/default.yml +33 -0
- data/spec/lib/cli_spec.rb +41 -0
- data/spec/lib/params_spec.rb +71 -0
- data/spec/spec_helper.rb +33 -0
- metadata +354 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
class Forger::Script
|
4
|
+
class Compress < Forger::Base
|
5
|
+
def compress
|
6
|
+
reset
|
7
|
+
puts "Tarballing #{BUILD_ROOT}/app/scripts folder to scripts.tgz".colorize(:green)
|
8
|
+
tarball_path = create_tarball
|
9
|
+
save_scripts_info(tarball_path)
|
10
|
+
puts "Tarball created at #{tarball_path}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_tarball
|
14
|
+
# https://apple.stackexchange.com/questions/14980/why-are-dot-underscore-files-created-and-how-can-i-avoid-them
|
15
|
+
sh "cd #{BUILD_ROOT}/app && dot_clean ." if system("type dot_clean > /dev/null")
|
16
|
+
|
17
|
+
# https://serverfault.com/questions/110208/different-md5sums-for-same-tar-contents
|
18
|
+
# Using tar czf directly results in a new m5sum each time because the gzip
|
19
|
+
# timestamp is included. So using: tar -c ... | gzip -n
|
20
|
+
sh "cd #{BUILD_ROOT}/app && tar -c scripts | gzip -n > scripts.tgz" # temporary app/scripts.tgz file
|
21
|
+
|
22
|
+
rename_with_md5!
|
23
|
+
end
|
24
|
+
|
25
|
+
def clean
|
26
|
+
FileUtils.rm_f("#{BUILD_ROOT}/scripts/scripts-#{md5sum}.tgz")
|
27
|
+
end
|
28
|
+
|
29
|
+
# Apppend a md5 to file after it's been created and moves it to
|
30
|
+
# output/scripts/scripts-[MD5].tgz
|
31
|
+
def rename_with_md5!
|
32
|
+
md5_path = "#{BUILD_ROOT}/scripts/scripts-#{md5sum}.tgz"
|
33
|
+
FileUtils.mkdir_p(File.dirname(md5_path))
|
34
|
+
FileUtils.mv("#{BUILD_ROOT}/app/scripts.tgz", md5_path)
|
35
|
+
md5_path
|
36
|
+
end
|
37
|
+
|
38
|
+
def save_scripts_info(scripts_name)
|
39
|
+
FileUtils.mkdir_p(File.dirname(SCRIPTS_INFO_PATH))
|
40
|
+
IO.write(SCRIPTS_INFO_PATH, scripts_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
# cache this because the file will get removed
|
44
|
+
def md5sum
|
45
|
+
@md5sum ||= Digest::MD5.file("#{BUILD_ROOT}/app/scripts.tgz").to_s[0..7]
|
46
|
+
end
|
47
|
+
|
48
|
+
def sh(command)
|
49
|
+
puts "=> #{command}"
|
50
|
+
system command
|
51
|
+
end
|
52
|
+
|
53
|
+
# Only avaialble after script has been built.
|
54
|
+
def scripts_name
|
55
|
+
IO.read(SCRIPTS_INFO_PATH).strip
|
56
|
+
end
|
57
|
+
|
58
|
+
def reset
|
59
|
+
FileUtils.rm_f(SCRIPTS_INFO_PATH)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
|
3
|
+
# Create AMI Bundle
|
4
|
+
AMI_NAME="<%= @ami_name %>"
|
5
|
+
INSTANCE_ID=$(wget -q -O - http://169.254.169.254/latest/meta-data/instance-id)
|
6
|
+
REGION=$(aws configure get region)
|
7
|
+
# Note this will cause the instance to reboot. Not using the --no-reboot flag
|
8
|
+
# to ensure consistent AMI creation.
|
9
|
+
SOURCE_AMI_ID=$(wget -q -O - http://169.254.169.254/latest/meta-data/ami-id)
|
10
|
+
echo "$SOURCE_AMI_ID" > /var/log/source-ami-id.txt
|
11
|
+
mkdir -p /opt/forger/data
|
12
|
+
aws ec2 create-image --name "$AMI_NAME" --instance-id "$INSTANCE_ID" --region "$REGION" > /opt/forger/data/ami-id.txt
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
|
3
|
+
/opt/forger/auto_terminate/setup.sh
|
4
|
+
|
5
|
+
<% if @options[:auto_terminate] -%>
|
6
|
+
<% if @options[:ami_name] %>
|
7
|
+
/opt/forger/auto_terminate.sh later
|
8
|
+
<% else %>
|
9
|
+
/opt/forger/auto_terminate.sh now # terminate immediately
|
10
|
+
<% end -%>
|
11
|
+
<% end -%>
|
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
|
3
|
+
# Downloads and extract the scripts.
|
4
|
+
# The extracted folder from github looks like this:
|
5
|
+
# branch-name.tar.gz => forger-branch-name
|
6
|
+
# master.tar.gz => forger-master
|
7
|
+
# v1.0.0.tar.gz => forger-1.0.0
|
8
|
+
function extract_forger_scripts() {
|
9
|
+
local temp_folder
|
10
|
+
local url
|
11
|
+
local filename
|
12
|
+
|
13
|
+
rm -rf /opt/forger # clean start
|
14
|
+
|
15
|
+
temp_folder="/opt/forger-temp"
|
16
|
+
rm -rf "$temp_folder"
|
17
|
+
mkdir -p "$temp_folder"
|
18
|
+
|
19
|
+
(
|
20
|
+
cd "$temp_folder"
|
21
|
+
|
22
|
+
<%
|
23
|
+
# Examples:
|
24
|
+
# AWS_EC2_CODE=v1.0.0
|
25
|
+
# AWS_EC2_CODE=master
|
26
|
+
# AWS_EC2_CODE=branch-name
|
27
|
+
#
|
28
|
+
# https://github.com/tongueroo/forger/archive/v1.0.0.tar.gz
|
29
|
+
# https://github.com/tongueroo/forger/archive/master.tar.gz
|
30
|
+
code_version = ENV['AWS_EC2_CODE']
|
31
|
+
code_version ||= "v#{Forger::VERSION}"
|
32
|
+
%>
|
33
|
+
url="https://github.com/tongueroo/forger/archive/<%= code_version %>.tar.gz"
|
34
|
+
filename=$(basename "$url")
|
35
|
+
folder="${filename%.tar.gz}" # remove extension
|
36
|
+
folder="${folder#v}" # remove leading v character
|
37
|
+
folder="forger-$folder" # IE: forger-1.0.0
|
38
|
+
|
39
|
+
wget "$url"
|
40
|
+
tar zxf "$filename"
|
41
|
+
|
42
|
+
mv "$temp_folder/$folder/lib/forger/scripts" /opt/forger
|
43
|
+
rm -rf "$temp_folder"
|
44
|
+
chmod a+x -R /opt/forger
|
45
|
+
)
|
46
|
+
}
|
47
|
+
|
48
|
+
extract_forger_scripts
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'filesize'
|
2
|
+
require 'aws-sdk-s3'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
# Class for forger upload command
|
6
|
+
class Forger::Script
|
7
|
+
class Upload < Forger::Base
|
8
|
+
def initialize(options={})
|
9
|
+
@options = options
|
10
|
+
@compile = @options[:compile] ? @options[:compile] : true
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
compiler.compile_scripts if @compile
|
15
|
+
compressor.compress
|
16
|
+
upload(tarball_path)
|
17
|
+
compressor.clean
|
18
|
+
compiler.clean if @compile and Forger.settings["compile_clean"]
|
19
|
+
end
|
20
|
+
|
21
|
+
def upload(tarball_path)
|
22
|
+
puts "Uploading scripts.tgz (#{filesize}) to #{s3_dest}".colorize(:green)
|
23
|
+
obj = s3_resource.bucket(bucket_name).object(key)
|
24
|
+
start_time = Time.now
|
25
|
+
if @options[:noop]
|
26
|
+
puts "NOOP: Not uploading file to s3"
|
27
|
+
else
|
28
|
+
obj.upload_file(tarball_path)
|
29
|
+
end
|
30
|
+
time_took = pretty_time(Time.now-start_time).colorize(:green)
|
31
|
+
puts "Time to upload code to s3: #{time_took}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def tarball_path
|
35
|
+
IO.read(SCRIPTS_INFO_PATH).strip
|
36
|
+
end
|
37
|
+
|
38
|
+
def filesize
|
39
|
+
Filesize.from(File.size(tarball_path).to_s + " B").pretty
|
40
|
+
end
|
41
|
+
|
42
|
+
def s3_dest
|
43
|
+
"s3://#{bucket_name}/#{key}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def key
|
47
|
+
# Example key: ec2/development/scripts/scripts-md5
|
48
|
+
"#{dest_folder}/#{File.basename(tarball_path)}"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Example:
|
52
|
+
# s3_folder: s3://infra-bucket/ec2
|
53
|
+
# bucket_name: infra-bucket
|
54
|
+
def bucket_name
|
55
|
+
s3_folder.sub('s3://','').split('/').first
|
56
|
+
end
|
57
|
+
|
58
|
+
# Removes s3://bucket-name and adds Forger.env. Example:
|
59
|
+
# s3_folder: s3://infra-bucket/ec2
|
60
|
+
# bucket_name: ec2/development/scripts
|
61
|
+
def dest_folder
|
62
|
+
folder = s3_folder.sub('s3://','').split('/')[1..-1].join('/')
|
63
|
+
"#{folder}/#{Forger.env}/scripts"
|
64
|
+
end
|
65
|
+
|
66
|
+
# s3_folder example:
|
67
|
+
def s3_folder
|
68
|
+
Forger.settings["s3_folder"]
|
69
|
+
end
|
70
|
+
|
71
|
+
def s3_resource
|
72
|
+
@s3_resource ||= Aws::S3::Resource.new
|
73
|
+
end
|
74
|
+
|
75
|
+
# http://stackoverflow.com/questions/4175733/convert-duration-to-hoursminutesseconds-or-similar-in-rails-3-or-ruby
|
76
|
+
def pretty_time(total_seconds)
|
77
|
+
minutes = (total_seconds / 60) % 60
|
78
|
+
seconds = total_seconds % 60
|
79
|
+
if total_seconds < 60
|
80
|
+
"#{seconds.to_i}s"
|
81
|
+
else
|
82
|
+
"#{minutes.to_i}m #{seconds.to_i}s"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def sh(command)
|
87
|
+
puts "=> #{command}"
|
88
|
+
system command
|
89
|
+
end
|
90
|
+
|
91
|
+
def compiler
|
92
|
+
@compiler ||= Compile.new(@options)
|
93
|
+
end
|
94
|
+
|
95
|
+
def compressor
|
96
|
+
@compressor ||= Compress.new(@options)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/bin/bash -exu
|
2
|
+
|
3
|
+
if [ $# -eq 0 ]; then
|
4
|
+
command=$(basename "$0")
|
5
|
+
echo "Usage: $command WHEN"
|
6
|
+
echo "Examples:"
|
7
|
+
echo " $command now"
|
8
|
+
echo " $command later"
|
9
|
+
exit 1
|
10
|
+
fi
|
11
|
+
WHEN=$1 # now or later
|
12
|
+
|
13
|
+
source /opt/forger/auto_terminate/functions.sh
|
14
|
+
terminate "$WHEN"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/bin/bash -exu
|
2
|
+
|
3
|
+
# This is another copy the /opt/forger/auto_terminate.sh script because the
|
4
|
+
# /opt/forger/auto_terminate.sh also gets removed when it gets called. Specifically,
|
5
|
+
# it gets gets removed when "terminate after_ami" is called.
|
6
|
+
|
7
|
+
# There's this extra script that terminates after a timeout because sometimes:
|
8
|
+
# 1. the script stalls: IE: aws ec2 wait image-available and a custom wait_ami
|
9
|
+
# does this.
|
10
|
+
# 2. the user_data script breaks and stops before finishing, never reaching
|
11
|
+
# the terminate_later or terminate_now functions.
|
12
|
+
#
|
13
|
+
|
14
|
+
source /opt/forger/auto_terminate/functions.sh
|
15
|
+
# remove itself since at jobs survive reboots and if the ami gets created
|
16
|
+
# successfully we do not want this to be captured as part of the ami
|
17
|
+
rm -f /opt/forger/auto_terminate/after_timeout.sh
|
18
|
+
terminate now # hard code to now since only gets called via an at job
|
@@ -0,0 +1,130 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
|
3
|
+
# Key is that instance will not be terminated if source image is the same as the
|
4
|
+
# original image id.
|
5
|
+
function terminate_instance() {
|
6
|
+
local SOURCE_AMI_ID
|
7
|
+
local AMI_ID
|
8
|
+
|
9
|
+
SOURCE_AMI_ID=$(curl -s http://169.254.169.254/latest/meta-data/ami-id)
|
10
|
+
AMI_ID=$(cat /opt/forger/data/ami-id.txt | jq -r '.ImageId')
|
11
|
+
if [ "$SOURCE_AMI_ID" = "$AMI_ID" ]; then
|
12
|
+
echo "The source ami and ami_id are the same: $AMI_ID"
|
13
|
+
echo "Will not terminate the instance for this case."
|
14
|
+
echo "This case can happen when an /etc/rc.local script to auto-terminate the "
|
15
|
+
echo "instance was capture from a previous AMI build."
|
16
|
+
return
|
17
|
+
fi
|
18
|
+
|
19
|
+
INSTANCE_ID=$(wget -q -O - http://169.254.169.254/latest/meta-data/instance-id)
|
20
|
+
SPOT_INSTANCE_REQUEST_ID=$(aws ec2 describe-instances --instance-ids "$INSTANCE_ID" | jq -r '.Reservations[].Instances[].SpotInstanceRequestId')
|
21
|
+
|
22
|
+
if [ -n "$SPOT_INSTANCE_REQUEST_ID" ]; then
|
23
|
+
cancel_spot_request
|
24
|
+
fi
|
25
|
+
aws ec2 terminate-instances --instance-ids "$INSTANCE_ID"
|
26
|
+
}
|
27
|
+
|
28
|
+
# on-demand instance example:
|
29
|
+
# $ aws ec2 describe-instances --instance-ids i-09482b1a6e330fbf7 | jq '.Reservations[].Instances[].SpotInstanceRequestId'
|
30
|
+
# null
|
31
|
+
# spot instance example:
|
32
|
+
# $ aws ec2 describe-instances --instance-ids i-08318bb7f33c216bd | jq '.Reservations[].Instances[].SpotInstanceRequestId'
|
33
|
+
# "sir-dzci5wsh"
|
34
|
+
function cancel_spot_request() {
|
35
|
+
aws ec2 cancel-spot-instance-requests --spot-instance-request-ids "$SPOT_INSTANCE_REQUEST_ID"
|
36
|
+
}
|
37
|
+
|
38
|
+
# When image doesnt exist at all, an empty string is returned.
|
39
|
+
function ami_state() {
|
40
|
+
local ami_id
|
41
|
+
ami_id=$1
|
42
|
+
aws ec2 describe-images --image-ids "$ami_id" --owners self | jq -r '.Images[].State'
|
43
|
+
}
|
44
|
+
|
45
|
+
function wait_for_ami() {
|
46
|
+
local name
|
47
|
+
name=$1
|
48
|
+
|
49
|
+
local x
|
50
|
+
local state
|
51
|
+
x=0
|
52
|
+
|
53
|
+
state=$(ami_state "$name")
|
54
|
+
while [ "$x" -lt 10 ] && [ "$state" != "available" ]; do
|
55
|
+
x=$((x+1))
|
56
|
+
|
57
|
+
state=$(ami_state "$name")
|
58
|
+
echo "state $state"
|
59
|
+
echo "sleeping for 60 seconds... times out at 10 minutes total"
|
60
|
+
|
61
|
+
type sleep
|
62
|
+
sleep 60
|
63
|
+
done
|
64
|
+
|
65
|
+
echo "final state $state"
|
66
|
+
}
|
67
|
+
|
68
|
+
function terminate() {
|
69
|
+
local when
|
70
|
+
when=$1
|
71
|
+
|
72
|
+
export PATH=/usr/local/bin:$PATH # for jq
|
73
|
+
|
74
|
+
if [ "$when" == "later" ]; then
|
75
|
+
terminate_later
|
76
|
+
elif [ "$when" == "after_ami" ]; then
|
77
|
+
terminate_after_ami
|
78
|
+
elif [ "$when" == "after_timeout" ]; then
|
79
|
+
terminate_after_timeout
|
80
|
+
else
|
81
|
+
terminate_now
|
82
|
+
fi
|
83
|
+
}
|
84
|
+
|
85
|
+
function terminate_later() {
|
86
|
+
schedule_termination
|
87
|
+
}
|
88
|
+
|
89
|
+
# This gets set up at the very beginning of the user_data script. This ensures
|
90
|
+
# that after a 45 minute timeout the instance will get cleaned up and terminated.
|
91
|
+
function terminate_after_timeout() {
|
92
|
+
rm -f /opt/forger/data/ami-id.txt # rm file possible stale file from previous ami
|
93
|
+
|
94
|
+
# Remove all old at jobs.
|
95
|
+
# Assume all at job are previous after_timeout.sh job from previous AMI.
|
96
|
+
# Note: Each new at job increments the id by 1. So each AMI will have a different
|
97
|
+
# at job number.
|
98
|
+
for i in $(atq | awk '{print $1}') ; do
|
99
|
+
at -r $i
|
100
|
+
done
|
101
|
+
echo "/opt/forger/auto_terminate/after_timeout.sh now" | at now + 45 minutes
|
102
|
+
}
|
103
|
+
|
104
|
+
function terminate_after_ami() {
|
105
|
+
local AMI_ID
|
106
|
+
|
107
|
+
unschedule_termination
|
108
|
+
AMI_ID=$(cat /opt/forger/data/ami-id.txt | jq -r '.ImageId')
|
109
|
+
if [ -n "$AMI_ID" ]; then
|
110
|
+
# wait for the ami to be successfully created before terminating the instance
|
111
|
+
# https://docs.aws.amazon.com/cli/latest/reference/ec2/wait/image-available.html
|
112
|
+
# It will poll every 15 seconds until a successful state has been reached. This will exit with a return code of 255 after 40 failed checks.
|
113
|
+
# so it'll wait for 10 mins max
|
114
|
+
# aws ec2 wait image-available --image-ids "$AMI_ID" --owners self
|
115
|
+
|
116
|
+
# For some reason aws ec2 wait image-available didnt work for amazonlinux2
|
117
|
+
# so using a custom version
|
118
|
+
wait_for_ami "$AMI_ID"
|
119
|
+
fi
|
120
|
+
|
121
|
+
terminate_instance
|
122
|
+
}
|
123
|
+
|
124
|
+
function terminate_now() {
|
125
|
+
terminate_instance
|
126
|
+
}
|
127
|
+
|
128
|
+
source "/opt/forger/shared/functions.sh"
|
129
|
+
os=$(os_name)
|
130
|
+
source "/opt/forger/auto_terminate/functions/${os}.sh"
|
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
function schedule_termination() {
|
3
|
+
chmod +x /etc/rc.d/rc.local
|
4
|
+
echo "/opt/forger/auto_terminate.sh after_ami >> /var/log/auto-terminate.log 2>&1" >> /etc/rc.d/rc.local
|
5
|
+
}
|
6
|
+
|
7
|
+
function unschedule_termination() {
|
8
|
+
grep -v auto_terminate.sh /etc/rc.d/rc.local > /etc/rc.d/rc.local.tmp
|
9
|
+
mv /etc/rc.d/rc.local.tmp /etc/rc.d/rc.local
|
10
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
function schedule_termination() {
|
3
|
+
chmod +x /etc/rc.local
|
4
|
+
sed -i 's/exit 0//' /etc/rc.local
|
5
|
+
echo "/opt/forger/auto_terminate.sh after_ami >> /var/log/auto-terminate.log 2>&1" >> /etc/rc.local
|
6
|
+
}
|
7
|
+
|
8
|
+
function unschedule_termination() {
|
9
|
+
grep -v terminate-myself /etc/rc.local > /etc/rc.local.tmp
|
10
|
+
mv /etc/rc.local{.tmp,}
|
11
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
function install_jq() {
|
3
|
+
if ! type jq > /dev/null ; then
|
4
|
+
wget "https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64"
|
5
|
+
mv jq-linux64 /usr/local/bin/jq
|
6
|
+
chmod a+x /usr/local/bin/jq
|
7
|
+
fi
|
8
|
+
}
|
9
|
+
|
10
|
+
function configure_aws_cli() {
|
11
|
+
local home_dir
|
12
|
+
home_dir=${1:-/root} # default to /root
|
13
|
+
# Configure aws cli in case it is not yet configured
|
14
|
+
mkdir -p "$home_dir/.aws"
|
15
|
+
if [ ! -f "$home_dir/.aws/config" ]; then
|
16
|
+
EC2_AVAIL_ZONE=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)
|
17
|
+
EC2_REGION=${EC2_AVAIL_ZONE::-1}
|
18
|
+
cat >"$home_dir/.aws/config" <<CONFIGURE_AWS_CLI
|
19
|
+
[default]
|
20
|
+
region = $EC2_REGION
|
21
|
+
output = json
|
22
|
+
CONFIGURE_AWS_CLI
|
23
|
+
fi
|
24
|
+
}
|
25
|
+
|
26
|
+
function setup() {
|
27
|
+
install_jq
|
28
|
+
configure_aws_cli /root
|
29
|
+
}
|
30
|
+
|
31
|
+
setup
|