forger 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|