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