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,24 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
|
3
|
+
if [ $# -eq 0 ]; then
|
4
|
+
command=$(basename "$0")
|
5
|
+
echo "Usage: $command LOG_GROUP_NAME"
|
6
|
+
echo "Examples:"
|
7
|
+
echo " $command forger"
|
8
|
+
echo " $command ec2"
|
9
|
+
exit 1
|
10
|
+
fi
|
11
|
+
LOG_GROUP_NAME=$1
|
12
|
+
|
13
|
+
# shellcheck disable=SC1091
|
14
|
+
source "/opt/forger/shared/functions.sh"
|
15
|
+
OS=$(os_name)
|
16
|
+
if [ "$OS" != "amazonlinux2" ] && [ "$OS" != "ubuntu" ] ; then
|
17
|
+
echo "Sorry, cloudwatch logging with the forger tool is supported for amazonlinux2 and ubuntu only"
|
18
|
+
exit
|
19
|
+
fi
|
20
|
+
|
21
|
+
export OS # used by the scripts to delegate to the right OS script
|
22
|
+
/opt/forger/cloudwatch/install.sh
|
23
|
+
/opt/forger/cloudwatch/configure.sh "$LOG_GROUP_NAME"
|
24
|
+
/opt/forger/cloudwatch/service.sh
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
|
3
|
+
if [ $# -eq 0 ]; then
|
4
|
+
command=$(basename "$0")
|
5
|
+
echo "Usage: $command LOG_GROUP_NAME"
|
6
|
+
echo "Examples:"
|
7
|
+
echo " $command forger"
|
8
|
+
echo " $command ec2"
|
9
|
+
exit 1
|
10
|
+
fi
|
11
|
+
LOG_GROUP_NAME=$1
|
12
|
+
|
13
|
+
if [ "$OS" == "ubuntu" ]; then
|
14
|
+
CONFIG_FILE=/var/awslogs/etc/awslogs.conf
|
15
|
+
STATE_FILE=/var/awslogs/state/agent-state
|
16
|
+
else # amazonlinux2
|
17
|
+
CONFIG_FILE=/etc/awslogs/awslogs.conf
|
18
|
+
STATE_FILE=/var/lib/awslogs/agent-state
|
19
|
+
fi
|
20
|
+
|
21
|
+
# Inject the CloudWatch Logs configuration file contents
|
22
|
+
cat > $CONFIG_FILE <<- EOF
|
23
|
+
[general]
|
24
|
+
state_file = $STATE_FILE
|
25
|
+
|
26
|
+
[/var/log/dmesg]
|
27
|
+
file = /var/log/dmesg
|
28
|
+
log_group_name = ${LOG_GROUP_NAME}
|
29
|
+
log_stream_name = {instance_id}/var/log/dmesg
|
30
|
+
|
31
|
+
[/var/log/messages]
|
32
|
+
file = /var/log/messages
|
33
|
+
log_group_name = ${LOG_GROUP_NAME}
|
34
|
+
log_stream_name = {instance_id}/var/log/messages
|
35
|
+
datetime_format = %b %d %H:%M:%S
|
36
|
+
|
37
|
+
[/var/log/cloud-init.log]
|
38
|
+
file = /var/log/cloud-init.log
|
39
|
+
log_group_name = ${LOG_GROUP_NAME}
|
40
|
+
log_stream_name = {instance_id}/var/log/cloud-init.log
|
41
|
+
datetime_format =
|
42
|
+
|
43
|
+
[/var/log/cloud-init-output.log]
|
44
|
+
file = /var/log/cloud-init-output.log
|
45
|
+
log_group_name = ${LOG_GROUP_NAME}
|
46
|
+
log_stream_name = {instance_id}/var/log/cloud-init-output.log
|
47
|
+
datetime_format =
|
48
|
+
|
49
|
+
[/var/log/secure]
|
50
|
+
file = /var/log/secure
|
51
|
+
log_group_name = ${LOG_GROUP_NAME}
|
52
|
+
log_stream_name = {instance_id}/var/log/secure
|
53
|
+
datetime_format =
|
54
|
+
|
55
|
+
[/var/log/audit/audit.log]
|
56
|
+
file = /var/log/audit/audit.log
|
57
|
+
log_group_name = ${LOG_GROUP_NAME}
|
58
|
+
log_stream_name = {instance_id}/var/log/audit/audit.log
|
59
|
+
datetime_format =
|
60
|
+
|
61
|
+
[/var/lib/cloud/instance/user-data.txt]
|
62
|
+
file = /var/lib/cloud/instance/user-data.txt
|
63
|
+
log_group_name = ${LOG_GROUP_NAME}
|
64
|
+
log_stream_name = {instance_id}/var/lib/cloud/instance/user-data.txt
|
65
|
+
datetime_format =
|
66
|
+
|
67
|
+
[/var/log/messages]
|
68
|
+
file = /var/log/messages
|
69
|
+
log_group_name = ${LOG_GROUP_NAME}
|
70
|
+
log_stream_name = {instance_id}/var/log/messages
|
71
|
+
datetime_format =
|
72
|
+
|
73
|
+
[/var/log/auto-terminate.log]
|
74
|
+
file = /var/log/auto-terminate.log
|
75
|
+
log_group_name = ${LOG_GROUP_NAME}
|
76
|
+
log_stream_name = {instance_id}/var/log/auto-terminate.log
|
77
|
+
datetime_format =
|
78
|
+
|
79
|
+
EOF
|
80
|
+
|
81
|
+
if [ -f /etc/awslogs/awscli.conf ]; then
|
82
|
+
region=$(curl -s 169.254.169.254/latest/meta-data/placement/availability-zone | sed s'/.$//')
|
83
|
+
sed -i -e "s/region = us-east-1/region = $region/g" /etc/awslogs/awscli.conf
|
84
|
+
fi
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
|
3
|
+
# https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/QuickStartEC2Instance.html
|
4
|
+
|
5
|
+
REGION=$(curl -s 169.254.169.254/latest/meta-data/placement/availability-zone | sed s'/.$//')
|
6
|
+
|
7
|
+
if ! type python ; then
|
8
|
+
apt-get update
|
9
|
+
apt-get install -y python-pip
|
10
|
+
fi
|
11
|
+
|
12
|
+
# Install awslogs and the jq JSON parser
|
13
|
+
curl -s https://s3.amazonaws.com/aws-cloudwatch/downloads/latest/awslogs-agent-setup.py -O
|
14
|
+
|
15
|
+
# in order to install awslogs non-interactively we need a filler configfile
|
16
|
+
mkdir -p /etc/awslogs
|
17
|
+
cat > /etc/awslogs/awslogs.conf <<- EOL
|
18
|
+
[general]
|
19
|
+
state_file = /var/awslogs/state/agent-state
|
20
|
+
## filler config file, will get replaced by configure.sh script
|
21
|
+
EOL
|
22
|
+
|
23
|
+
python ./awslogs-agent-setup.py --region "$REGION" --non-interactive --configfile=/etc/awslogs/awslogs.conf
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/bin/bash -exu
|
2
|
+
|
3
|
+
# yum install already has configured
|
4
|
+
# /usr/lib/systemd/system/awslogsd.service
|
5
|
+
# Restart because we adjust the config with configure.sh
|
6
|
+
# The yum awslogs package creates a systemd unit called awslogsd.
|
7
|
+
systemctl daemon-reload
|
8
|
+
systemctl restart awslogsd
|
9
|
+
systemctl enable awslogsd
|
10
|
+
# systemctl status awslogsd
|
11
|
+
# systemctl is-enabled awslogsd
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/bin/bash -eux
|
2
|
+
|
3
|
+
function configure_aws_cli() {
|
4
|
+
local home_dir
|
5
|
+
home_dir=${1:-/root} # default to /root
|
6
|
+
# Configure aws cli in case it is not yet configured
|
7
|
+
mkdir -p "$home_dir/.aws"
|
8
|
+
if [ ! -f "$home_dir/.aws/config" ]; then
|
9
|
+
EC2_AVAIL_ZONE=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)
|
10
|
+
EC2_REGION=${EC2_AVAIL_ZONE::-1}
|
11
|
+
cat >"$home_dir/.aws/config" <<CONFIGURE_AWS_CLI
|
12
|
+
[default]
|
13
|
+
region = $EC2_REGION
|
14
|
+
output = json
|
15
|
+
CONFIGURE_AWS_CLI
|
16
|
+
fi
|
17
|
+
}
|
18
|
+
|
19
|
+
# Normalize os name so we can delegate out to os specific scripts.
|
20
|
+
#
|
21
|
+
# Amazon Linux 2
|
22
|
+
# $ cat /etc/os-release
|
23
|
+
# NAME="Amazon Linux"
|
24
|
+
# VERSION="2 (2017.12)"
|
25
|
+
# ID="amzn"
|
26
|
+
# ID_LIKE="centos rhel fedora"
|
27
|
+
# VERSION_ID="2"
|
28
|
+
# PRETTY_NAME="Amazon Linux 2 (2017.12) LTS Release Candidate"
|
29
|
+
# ANSI_COLOR="0;33"
|
30
|
+
# CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
|
31
|
+
# HOME_URL="https://amazonlinux.com/"
|
32
|
+
#
|
33
|
+
# Ubuntu
|
34
|
+
# ubuntu@ip-172-31-6-8:~$ cat /etc/os-release
|
35
|
+
# NAME="Ubuntu"
|
36
|
+
# VERSION="16.04.3 LTS (Xenial Xerus)"
|
37
|
+
# ID=ubuntu
|
38
|
+
# ID_LIKE=debian
|
39
|
+
# PRETTY_NAME="Ubuntu 16.04.3 LTS"
|
40
|
+
# VERSION_ID="16.04"
|
41
|
+
# HOME_URL="http://www.ubuntu.com/"
|
42
|
+
# SUPPORT_URL="http://help.ubuntu.com/"
|
43
|
+
# BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
|
44
|
+
# VERSION_CODENAME=xenial
|
45
|
+
# UBUNTU_CODENAME=xenial
|
46
|
+
#
|
47
|
+
# Note: Amazon Linux and Amazon Linux 2 have the same name
|
48
|
+
#
|
49
|
+
function os_name() {
|
50
|
+
local OS
|
51
|
+
local VERSION
|
52
|
+
|
53
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
54
|
+
OS="macosx" # gawk not available on macosx usually
|
55
|
+
else
|
56
|
+
# https://askubuntu.com/questions/459402/how-to-know-if-the-running-platform-is-ubuntu-or-centos-with-help-of-a-bash-scri
|
57
|
+
# Method 1 works for amazonlinux and ubuntu
|
58
|
+
# Method 3 the complex script, did not work for amazonlinux
|
59
|
+
OS=$(gawk -F= '/^NAME/{print $2}' /etc/os-release)
|
60
|
+
fi
|
61
|
+
|
62
|
+
OS="${OS// /}" # remove spaces
|
63
|
+
OS=$(echo "$OS" | tr '[:upper:]' '[:lower:]')
|
64
|
+
# https://stackoverflow.com/questions/9733338/shell-script-remove-first-and-last-quote-from-a-variable
|
65
|
+
OS="${OS#\"}" # remove leading "
|
66
|
+
OS="${OS%\"}" # remove trailing "
|
67
|
+
|
68
|
+
if [ "$OS" == "amazonlinux" ]; then
|
69
|
+
VERSION=$(gawk -F= '/^VERSION/{print $2}' /etc/os-release)
|
70
|
+
VERSION="${VERSION#\"}" # remove leading "
|
71
|
+
if [[ "$VERSION" =~ ^2 ]] ; then
|
72
|
+
OS="${OS}2"
|
73
|
+
fi
|
74
|
+
fi
|
75
|
+
|
76
|
+
echo "$OS"
|
77
|
+
}
|
78
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Forger
|
4
|
+
class Setting
|
5
|
+
def initialize(check_project=true)
|
6
|
+
@check_project = check_project
|
7
|
+
end
|
8
|
+
|
9
|
+
# data contains the settings.yml config. The order or precedence for settings
|
10
|
+
# is the project lono/settings.yml and then the ~/.lono/settings.yml.
|
11
|
+
@@data = nil
|
12
|
+
def data
|
13
|
+
return @@data if @@data
|
14
|
+
|
15
|
+
if @check_project && !File.exist?(project_settings_path)
|
16
|
+
puts "ERROR: No settings file at #{project_settings_path}. Are you sure you are in a forger project?".colorize(:red)
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
all_envs = load_file(project_settings_path)
|
21
|
+
all_envs = merge_base(all_envs)
|
22
|
+
@@data = all_envs[Forger.env] || all_envs["base"] || {}
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def load_file(path)
|
27
|
+
return Hash.new({}) unless File.exist?(path)
|
28
|
+
|
29
|
+
content = RenderMePretty.result(path)
|
30
|
+
data = YAML.load(content)
|
31
|
+
# If key is is accidentally set to nil it screws up the merge_base later.
|
32
|
+
# So ensure that all keys with nil value are set to {}
|
33
|
+
data.each do |env, _setting|
|
34
|
+
data[env] ||= {}
|
35
|
+
end
|
36
|
+
data
|
37
|
+
end
|
38
|
+
|
39
|
+
# automatically add base settings to the rest of the environments
|
40
|
+
def merge_base(all_envs)
|
41
|
+
base = all_envs["base"] || {}
|
42
|
+
all_envs.each do |env, settings|
|
43
|
+
all_envs[env] = base.merge(settings) unless env == "base"
|
44
|
+
end
|
45
|
+
all_envs
|
46
|
+
end
|
47
|
+
|
48
|
+
def project_settings_path
|
49
|
+
"#{Forger.root}/config/settings.yml"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "active_support" # for autoload
|
2
|
+
require "active_support/core_ext/string"
|
3
|
+
|
4
|
+
module Forger
|
5
|
+
module Template
|
6
|
+
autoload :Context, "forger/template/context"
|
7
|
+
autoload :Helper, "forger/template/helper"
|
8
|
+
|
9
|
+
def context
|
10
|
+
@context ||= Forger::Template::Context.new(@options)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "active_support/core_ext/string"
|
2
|
+
|
3
|
+
# Encapsulates helper methods and instance variables to be rendered in the ERB
|
4
|
+
# templates.
|
5
|
+
module Forger::Template
|
6
|
+
class Context
|
7
|
+
include Forger::Template::Helper
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
@options = options
|
11
|
+
load_custom_helpers
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
# Load custom helper methods from project
|
16
|
+
def load_custom_helpers
|
17
|
+
Dir.glob("#{Forger.root}/app/helpers/**/*_helper.rb").each do |path|
|
18
|
+
filename = path.sub(%r{.*/},'').sub('.rb','')
|
19
|
+
module_name = filename.classify
|
20
|
+
|
21
|
+
# Prepend a period so require works AWS_EC2_ROOT is set to a relative path
|
22
|
+
# without a period.
|
23
|
+
#
|
24
|
+
# Example: AWS_EC2_ROOT=tmp/project
|
25
|
+
first_char = path[0..0]
|
26
|
+
path = "./#{path}" unless %w[. /].include?(first_char)
|
27
|
+
require path
|
28
|
+
self.class.send :include, module_name.constantize
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "active_support/core_ext/string"
|
2
|
+
|
3
|
+
module Forger::Template
|
4
|
+
module Helper
|
5
|
+
def autoinclude(klass)
|
6
|
+
autoload klass, "forger/template/helper/#{klass.to_s.underscore}"
|
7
|
+
include const_get(klass)
|
8
|
+
end
|
9
|
+
extend self
|
10
|
+
|
11
|
+
autoinclude :AmiHelper
|
12
|
+
autoinclude :CoreHelper
|
13
|
+
autoinclude :PartialHelper
|
14
|
+
autoinclude :ScriptHelper
|
15
|
+
autoinclude :SshKeyHelper
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Forger::Template::Helper::AmiHelper
|
2
|
+
include Forger::AwsService
|
3
|
+
|
4
|
+
# Example:
|
5
|
+
#
|
6
|
+
# latest_ami("ruby-2.5.0_*") => ami-122
|
7
|
+
#
|
8
|
+
# Equivalent aws cli test command:
|
9
|
+
#
|
10
|
+
# $ aws ec2 describe-images --owners self --filters="Name=name,Values=ruby-2.5.0_*" | jq '.Images | length'
|
11
|
+
#
|
12
|
+
# Returns latest ami ami
|
13
|
+
def latest_ami(query, owners=["self"])
|
14
|
+
images = search_ami(query, owners)
|
15
|
+
image = images.sort_by(&:name).reverse.first
|
16
|
+
if image
|
17
|
+
image.image_id
|
18
|
+
else
|
19
|
+
puts "latest_ami helper method could not find an AMI with the query of: #{query.inspect}".colorize(:red)
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def search_ami(query, owners=["self"])
|
25
|
+
ec2.describe_images(
|
26
|
+
owners: owners,
|
27
|
+
filters: [
|
28
|
+
{name: "name", values: [query]},
|
29
|
+
{name: "state", values: ["available"]}
|
30
|
+
]
|
31
|
+
).images
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require "base64"
|
2
|
+
require "erb"
|
3
|
+
|
4
|
+
module Forger::Template::Helper::CoreHelper
|
5
|
+
# assuming user-data script is a bash script for simplicity for now
|
6
|
+
def user_data(name, base64:true, layout:"default")
|
7
|
+
# allow user to specify the path also
|
8
|
+
if File.exist?(name)
|
9
|
+
name = File.basename(name) # normalize name, change path to name
|
10
|
+
end
|
11
|
+
name = File.basename(name, '.sh')
|
12
|
+
|
13
|
+
layout_path = layout_path(layout)
|
14
|
+
path = "#{Forger.root}/app/user-data/#{name}.sh"
|
15
|
+
result = RenderMePretty.result(path, context: self, layout: layout_path)
|
16
|
+
# Must prepend and append scripts in user_data here because we need to
|
17
|
+
# encode the user_data script for valid yaml to load in the profile.
|
18
|
+
# Tried moving this logic to the params but that is too late and produces
|
19
|
+
# invalid yaml. Unless we want to encode and dedode twice.
|
20
|
+
scripts = [result]
|
21
|
+
scripts = prepend_scripts(scripts)
|
22
|
+
scripts = append_scripts(scripts)
|
23
|
+
divider = "\n############################## DIVIDER ##############################\n"
|
24
|
+
result = scripts.join(divider)
|
25
|
+
|
26
|
+
# save the unencoded user-data script for easy debugging
|
27
|
+
temp_path = "#{Forger.root}/tmp/user-data.txt"
|
28
|
+
FileUtils.mkdir_p(File.dirname(temp_path))
|
29
|
+
IO.write(temp_path, result)
|
30
|
+
|
31
|
+
base64 ? Base64.encode64(result).strip : result
|
32
|
+
end
|
33
|
+
|
34
|
+
# Get full path of layout from layout name
|
35
|
+
#
|
36
|
+
# layout_name=false - dont use layout at all
|
37
|
+
# layout_name=nil - default to default.sh layout if available
|
38
|
+
def layout_path(name="default")
|
39
|
+
return false if name == false # disable layout
|
40
|
+
name = "default" if name.nil? # in case user passes in nil
|
41
|
+
|
42
|
+
ext = File.extname(name)
|
43
|
+
name += ".sh" if ext.empty?
|
44
|
+
layout_path = "#{Forger.root}/app/user-data/layouts/#{name}"
|
45
|
+
|
46
|
+
# special rule for default in case there's no default layout
|
47
|
+
if name.include?("default") and !File.exist?(layout_path)
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
|
51
|
+
# other named layouts should error if it doesnt exit
|
52
|
+
unless File.exist?(layout_path)
|
53
|
+
puts "ERROR: Layout #{layout_path} does not exist. Are you sure it exists? Exiting".colorize(:red)
|
54
|
+
exit 1
|
55
|
+
end
|
56
|
+
|
57
|
+
layout_path
|
58
|
+
end
|
59
|
+
|
60
|
+
# provides access to config/* settings as variables
|
61
|
+
# AWS_EC2_ENV=development => config/development.yml
|
62
|
+
# AWS_EC2_ENV=production => config/production.yml
|
63
|
+
def config
|
64
|
+
Forger.config
|
65
|
+
end
|
66
|
+
|
67
|
+
# provides access to config/settings.yml as variables
|
68
|
+
def settings
|
69
|
+
Forger.settings
|
70
|
+
end
|
71
|
+
|
72
|
+
# pretty timestamp that is useful for ami ids.
|
73
|
+
# the timestamp is generated once and cached.
|
74
|
+
def timestamp
|
75
|
+
@timestamp ||= Time.now.strftime("%Y-%m-%d-%H-%M-%S")
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
# TODO: move script combining logic into class
|
80
|
+
def prepend_scripts(scripts)
|
81
|
+
scripts.unshift(script.cloudwatch) if @options[:cloudwatch]
|
82
|
+
scripts.unshift(script.auto_terminate_after_timeout) if @options[:auto_terminate]
|
83
|
+
add_setup_script(scripts, :prepend)
|
84
|
+
scripts
|
85
|
+
end
|
86
|
+
|
87
|
+
def append_scripts(scripts)
|
88
|
+
add_setup_script(scripts, :append)
|
89
|
+
scripts << script.auto_terminate if @options[:auto_terminate]
|
90
|
+
scripts << script.create_ami if @options[:ami_name]
|
91
|
+
scripts
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_setup_script(scripts, how)
|
95
|
+
return if @already_setup
|
96
|
+
@already_setup = true
|
97
|
+
|
98
|
+
requires_setup = @options[:cloudwatch] ||
|
99
|
+
@options[:auto_terminate] ||
|
100
|
+
@options[:ami_name]
|
101
|
+
|
102
|
+
return unless requires_setup
|
103
|
+
|
104
|
+
if how == :prepend
|
105
|
+
scripts.unshift(script.extract_forger_scripts)
|
106
|
+
else
|
107
|
+
scripts << script.extract_forger_scripts
|
108
|
+
end
|
109
|
+
|
110
|
+
scripts
|
111
|
+
end
|
112
|
+
|
113
|
+
def script
|
114
|
+
@script ||= Forger::Script.new(@options)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Load custom helper methods from the project repo
|
118
|
+
def load_custom_helpers
|
119
|
+
Dir.glob("#{Forger.root}/app/helpers/**/*_helper.rb").each do |path|
|
120
|
+
filename = path.sub(%r{.*/},'').sub('.rb','')
|
121
|
+
module_name = filename.classify
|
122
|
+
|
123
|
+
require path
|
124
|
+
self.class.send :include, module_name.constantize
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|