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,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
|