forger 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.gitmodules +0 -0
  4. data/.rspec +3 -0
  5. data/CHANGELOG.md +147 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.lock +136 -0
  8. data/Guardfile +19 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +249 -0
  11. data/Rakefile +6 -0
  12. data/docs/example/.env +2 -0
  13. data/docs/example/.env.development +2 -0
  14. data/docs/example/.env.production +3 -0
  15. data/docs/example/app/scripts/hello.sh +3 -0
  16. data/docs/example/app/user-data/bootstrap.sh +35 -0
  17. data/docs/example/config/development.yml +8 -0
  18. data/docs/example/profiles/default.yml +11 -0
  19. data/docs/example/profiles/spot.yml +20 -0
  20. data/exe/forger +14 -0
  21. data/forger.gemspec +38 -0
  22. data/lib/forger.rb +29 -0
  23. data/lib/forger/ami.rb +10 -0
  24. data/lib/forger/aws_service.rb +7 -0
  25. data/lib/forger/base.rb +42 -0
  26. data/lib/forger/clean.rb +13 -0
  27. data/lib/forger/cleaner.rb +5 -0
  28. data/lib/forger/cleaner/ami.rb +45 -0
  29. data/lib/forger/cli.rb +67 -0
  30. data/lib/forger/command.rb +67 -0
  31. data/lib/forger/completer.rb +161 -0
  32. data/lib/forger/completer/script.rb +6 -0
  33. data/lib/forger/completer/script.sh +10 -0
  34. data/lib/forger/config.rb +20 -0
  35. data/lib/forger/core.rb +51 -0
  36. data/lib/forger/create.rb +155 -0
  37. data/lib/forger/create/error_messages.rb +58 -0
  38. data/lib/forger/create/params.rb +106 -0
  39. data/lib/forger/dotenv.rb +30 -0
  40. data/lib/forger/help.rb +9 -0
  41. data/lib/forger/help/ami.md +13 -0
  42. data/lib/forger/help/clean/ami.md +22 -0
  43. data/lib/forger/help/compile.md +5 -0
  44. data/lib/forger/help/completion.md +22 -0
  45. data/lib/forger/help/completion_script.md +3 -0
  46. data/lib/forger/help/create.md +7 -0
  47. data/lib/forger/help/upload.md +10 -0
  48. data/lib/forger/help/wait/ami.md +12 -0
  49. data/lib/forger/hook.rb +33 -0
  50. data/lib/forger/profile.rb +64 -0
  51. data/lib/forger/script.rb +46 -0
  52. data/lib/forger/script/compile.rb +40 -0
  53. data/lib/forger/script/compress.rb +62 -0
  54. data/lib/forger/script/templates/ami_creation.sh +12 -0
  55. data/lib/forger/script/templates/auto_terminate.sh +11 -0
  56. data/lib/forger/script/templates/auto_terminate_after_timeout.sh +5 -0
  57. data/lib/forger/script/templates/cloudwatch.sh +3 -0
  58. data/lib/forger/script/templates/extract_aws_ec2_scripts.sh +48 -0
  59. data/lib/forger/script/upload.rb +99 -0
  60. data/lib/forger/scripts/auto_terminate.sh +14 -0
  61. data/lib/forger/scripts/auto_terminate/after_timeout.sh +18 -0
  62. data/lib/forger/scripts/auto_terminate/functions.sh +130 -0
  63. data/lib/forger/scripts/auto_terminate/functions/amazonlinux2.sh +10 -0
  64. data/lib/forger/scripts/auto_terminate/functions/ubuntu.sh +11 -0
  65. data/lib/forger/scripts/auto_terminate/setup.sh +31 -0
  66. data/lib/forger/scripts/cloudwatch.sh +24 -0
  67. data/lib/forger/scripts/cloudwatch/configure.sh +84 -0
  68. data/lib/forger/scripts/cloudwatch/install.sh +3 -0
  69. data/lib/forger/scripts/cloudwatch/install/amazonlinux2.sh +4 -0
  70. data/lib/forger/scripts/cloudwatch/install/ubuntu.sh +23 -0
  71. data/lib/forger/scripts/cloudwatch/service.sh +3 -0
  72. data/lib/forger/scripts/cloudwatch/service/amazonlinux2.sh +11 -0
  73. data/lib/forger/scripts/cloudwatch/service/ubuntu.sh +8 -0
  74. data/lib/forger/scripts/shared/functions.sh +78 -0
  75. data/lib/forger/setting.rb +52 -0
  76. data/lib/forger/template.rb +13 -0
  77. data/lib/forger/template/context.rb +32 -0
  78. data/lib/forger/template/helper.rb +17 -0
  79. data/lib/forger/template/helper/ami_helper.rb +33 -0
  80. data/lib/forger/template/helper/core_helper.rb +127 -0
  81. data/lib/forger/template/helper/partial_helper.rb +71 -0
  82. data/lib/forger/template/helper/script_helper.rb +53 -0
  83. data/lib/forger/template/helper/ssh_key_helper.rb +21 -0
  84. data/lib/forger/version.rb +3 -0
  85. data/lib/forger/wait.rb +12 -0
  86. data/lib/forger/waiter.rb +5 -0
  87. data/lib/forger/waiter/ami.rb +61 -0
  88. data/spec/fixtures/demo_project/config/settings.yml +22 -0
  89. data/spec/fixtures/demo_project/config/test.yml +9 -0
  90. data/spec/fixtures/demo_project/profiles/default.yml +33 -0
  91. data/spec/lib/cli_spec.rb +41 -0
  92. data/spec/lib/params_spec.rb +71 -0
  93. data/spec/spec_helper.rb +33 -0
  94. 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,3 @@
1
+ #!/bin/bash -eux
2
+
3
+ /opt/forger/cloudwatch/install/"$OS".sh
@@ -0,0 +1,4 @@
1
+ #!/bin/bash -eux
2
+
3
+ # Install awslogs and the jq JSON parser
4
+ yum install -y awslogs jq
@@ -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,3 @@
1
+ #!/bin/bash -eux
2
+
3
+ /opt/forger/cloudwatch/service/"$OS".sh
@@ -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,8 @@
1
+ #/bin/bash -exu
2
+
3
+ # The awslogs-agent-setup.py setup creates a systemd unit is called awslogs.
4
+ systemctl daemon-reload
5
+ systemctl restart awslogs
6
+ systemctl enable awslogs
7
+ # systemctl status awslogs
8
+ # systemctl is-enabled awslogs
@@ -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