aws-ec2 1.0.0 → 1.1.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/CHANGELOG.md +10 -0
  4. data/README.md +19 -15
  5. data/docs/example/app/user-data/bootstrap.sh +0 -12
  6. data/lib/aws_ec2/cli.rb +8 -3
  7. data/lib/aws_ec2/core.rb +25 -4
  8. data/lib/aws_ec2/create.rb +19 -9
  9. data/lib/aws_ec2/help/upload.md +3 -2
  10. data/lib/aws_ec2/profile.rb +10 -1
  11. data/lib/aws_ec2/script.rb +19 -3
  12. data/lib/aws_ec2/script/compile.rb +2 -2
  13. data/lib/aws_ec2/script/compress.rb +1 -1
  14. data/lib/aws_ec2/script/templates/ami_creation.sh +12 -0
  15. data/lib/aws_ec2/script/templates/auto_terminate.sh +11 -0
  16. data/lib/aws_ec2/script/templates/auto_terminate_after_timeout.sh +5 -0
  17. data/lib/aws_ec2/script/templates/cloudwatch.sh +3 -0
  18. data/lib/aws_ec2/script/templates/extract_aws_ec2_scripts.sh +48 -0
  19. data/lib/aws_ec2/script/upload.rb +1 -1
  20. data/lib/aws_ec2/scripts/auto_terminate.sh +10 -91
  21. data/lib/aws_ec2/scripts/auto_terminate/after_timeout.sh +18 -0
  22. data/lib/aws_ec2/scripts/auto_terminate/functions.sh +128 -0
  23. data/lib/aws_ec2/scripts/auto_terminate/functions/amazonlinux2.sh +10 -0
  24. data/lib/aws_ec2/scripts/auto_terminate/functions/ubuntu.sh +11 -0
  25. data/lib/aws_ec2/scripts/auto_terminate/setup.sh +31 -0
  26. data/lib/aws_ec2/scripts/cloudwatch.sh +22 -0
  27. data/lib/aws_ec2/scripts/cloudwatch/configure.sh +74 -0
  28. data/lib/aws_ec2/scripts/cloudwatch/install.sh +4 -0
  29. data/lib/aws_ec2/scripts/cloudwatch/service.sh +19 -0
  30. data/lib/aws_ec2/scripts/shared/functions.sh +44 -0
  31. data/lib/aws_ec2/setting.rb +15 -4
  32. data/lib/aws_ec2/template/helper/core_helper.rb +46 -7
  33. data/lib/aws_ec2/template/helper/ssh_key_helper.rb +1 -1
  34. data/lib/aws_ec2/version.rb +1 -1
  35. data/spec/fixtures/demo_project/config/settings.yml +22 -0
  36. data/spec/lib/cli_spec.rb +0 -7
  37. data/spec/lib/params_spec.rb +71 -0
  38. metadata +21 -3
  39. data/lib/aws_ec2/scripts/ami_creation.sh +0 -35
@@ -1,95 +1,14 @@
1
1
  #!/bin/bash -exu
2
- # The shebang line is here in case there's is currently an empty user-data script.
3
- # It wont hurt if already there.
4
- ##################
5
- # auto_terminate.sh script
6
- # When creating an AMI, a aws ec2 create-image command is added to the end of
7
- # the user-data script. Creating AMIs prevent the script going any further.
8
- #
9
- # To get around this the this is script is added before that happens.
10
- #
11
- # https://stackoverflow.com/questions/27920806/how-to-avoid-heredoc-expanding-variables
12
- cat >/root/terminate-myself.sh << 'EOL'
13
- #!/bin/bash -exu
14
-
15
- # install jq dependencies
16
- function install_jq() {
17
- if ! type jq > /dev/null ; then
18
- wget "https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64"
19
- mv jq-linux64 /usr/local/bin/jq
20
- chmod a+x /usr/local/bin/jq
21
- fi
22
- }
23
-
24
- function configure_aws_cli() {
25
- local home_dir=$1
26
- # Configure aws cli in case it is not yet configured
27
- mkdir -p $home_dir/.aws
28
- if [ ! -f $home_dir/.aws/config ]; then
29
- EC2_AVAIL_ZONE=`curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone`
30
- EC2_REGION="`echo \"$EC2_AVAIL_ZONE\" | sed -e 's:\([0-9][0-9]*\)[a-z]*\$:\\1:'`"
31
- cat >$home_dir/.aws/config <<CONFIGURE_AWS_CLI
32
- [default]
33
- region = $EC2_REGION
34
- output = json
35
- CONFIGURE_AWS_CLI
36
- fi
37
- }
38
-
39
- function terminate_instance() {
40
- aws ec2 terminate-instances --instance-ids $INSTANCE_ID
41
- }
42
-
43
- # on-demand instance example:
44
- # $ aws ec2 describe-instances --instance-ids i-09482b1a6e330fbf7 | jq '.Reservations[].Instances[].SpotInstanceRequestId'
45
- # null
46
- # spot instance example:
47
- # $ aws ec2 describe-instances --instance-ids i-08318bb7f33c216bd | jq '.Reservations[].Instances[].SpotInstanceRequestId'
48
- # "sir-dzci5wsh"
49
- function cancel_spot_request() {
50
- aws ec2 cancel-spot-instance-requests --spot-instance-request-ids $SPOT_INSTANCE_REQUEST_ID
51
- }
52
-
53
- ###
54
- # program starts here
55
- ###
56
- export PATH=/usr/local/bin:$PATH
57
- install_jq
58
- configure_aws_cli /root
59
-
60
- AMI_NAME=$1
61
- if [ $AMI_NAME != "NO-WAIT" ]; then
62
- # wait for the ami to be successfully created before terminating the instance
63
- # https://docs.aws.amazon.com/cli/latest/reference/ec2/wait/image-available.html
64
- # 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.
65
- # so it'll wait for 10 mins max
66
- aws ec2 wait image-available --filters "Name=name,Values=$AMI_NAME" --owners self
67
- fi
68
-
69
-
70
- INSTANCE_ID=$(wget -q -O - http://169.254.169.254/latest/meta-data/instance-id)
71
- SPOT_INSTANCE_REQUEST_ID=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID | jq -r '.Reservations[].Instances[].SpotInstanceRequestId')
72
-
73
- # Remove this script so it is only allowed to be ran once ever
74
- # Or else whenenver we launch the AMI, it will kill itself
75
- rm -f /root/terminate-myself.sh
76
- grep -v terminate-myself /etc/rc.d/rc.local > /etc/rc.d/rc.local.tmp
77
- mv /etc/rc.d/rc.local.tmp /etc/rc.d/rc.local
78
2
 
79
- if [ -n "$SPOT_INSTANCE_REQUEST_ID" ]; then
80
- cancel_spot_request
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
81
10
  fi
82
- terminate_instance
83
- EOL
84
- chmod a+x /root/terminate-myself.sh
11
+ WHEN=$1 # now or later
85
12
 
86
- <% if @options[:auto_terminate] %>
87
- <% if @options[:ami_name] %>
88
- # schedule termination upon reboot
89
- chmod +x /etc/rc.d/rc.local
90
- echo "/root/terminate-myself.sh <%= @options[:ami_name] %> >> /var/log/terminate-myself.log 2>&1" >> /etc/rc.d/rc.local
91
- <% else %>
92
- # terminate immediately
93
- /root/terminate-myself.sh NO-WAIT >> /var/log/terminate-myself.log 2>&1
94
- <% end %>
95
- <% end %>
13
+ source /opt/aws-ec2/auto_terminate/functions.sh
14
+ terminate "$WHEN"
@@ -0,0 +1,18 @@
1
+ #!/bin/bash -exu
2
+
3
+ # This is another copy the /opt/aws-ec2/auto_terminate.sh script because the
4
+ # /opt/aws-ec2/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/aws-ec2/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/aws-ec2/auto_terminate/after_timeout.sh
18
+ terminate now # hard code to now since only gets called via an at job
@@ -0,0 +1,128 @@
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/aws-ec2/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!"
14
+ return
15
+ fi
16
+
17
+ INSTANCE_ID=$(wget -q -O - http://169.254.169.254/latest/meta-data/instance-id)
18
+ SPOT_INSTANCE_REQUEST_ID=$(aws ec2 describe-instances --instance-ids "$INSTANCE_ID" | jq -r '.Reservations[].Instances[].SpotInstanceRequestId')
19
+
20
+ if [ -n "$SPOT_INSTANCE_REQUEST_ID" ]; then
21
+ cancel_spot_request
22
+ fi
23
+ aws ec2 terminate-instances --instance-ids "$INSTANCE_ID"
24
+ }
25
+
26
+ # on-demand instance example:
27
+ # $ aws ec2 describe-instances --instance-ids i-09482b1a6e330fbf7 | jq '.Reservations[].Instances[].SpotInstanceRequestId'
28
+ # null
29
+ # spot instance example:
30
+ # $ aws ec2 describe-instances --instance-ids i-08318bb7f33c216bd | jq '.Reservations[].Instances[].SpotInstanceRequestId'
31
+ # "sir-dzci5wsh"
32
+ function cancel_spot_request() {
33
+ aws ec2 cancel-spot-instance-requests --spot-instance-request-ids "$SPOT_INSTANCE_REQUEST_ID"
34
+ }
35
+
36
+ # When image doesnt exist at all, an empty string is returned.
37
+ function ami_state() {
38
+ local ami_id
39
+ ami_id=$1
40
+ aws ec2 describe-images --image-ids "$ami_id" --owners self | jq -r '.Images[].State'
41
+ }
42
+
43
+ function wait_for_ami() {
44
+ local name
45
+ name=$1
46
+
47
+ local x
48
+ local state
49
+ x=0
50
+
51
+ state=$(ami_state "$name")
52
+ while [ "$x" -lt 10 ] && [ "$state" != "available" ]; do
53
+ x=$((x+1))
54
+
55
+ state=$(ami_state "$name")
56
+ echo "state $state"
57
+ echo "sleeping for 60 seconds... times out at 10 minutes total"
58
+
59
+ type sleep
60
+ sleep 60
61
+ done
62
+
63
+ echo "final state $state"
64
+ }
65
+
66
+ function terminate() {
67
+ local when
68
+ when=$1
69
+
70
+ export PATH=/usr/local/bin:$PATH # for jq
71
+
72
+ if [ "$when" == "later" ]; then
73
+ terminate_later
74
+ elif [ "$when" == "after_ami" ]; then
75
+ terminate_after_ami
76
+ elif [ "$when" == "after_timeout" ]; then
77
+ terminate_after_timeout
78
+ else
79
+ terminate_now
80
+ fi
81
+ }
82
+
83
+ function terminate_later() {
84
+ schedule_termination
85
+ }
86
+
87
+ # This gets set up at the very beginning of the user_data script. This ensures
88
+ # that after a 45 minute timeout the instance will get cleaned up and terminated.
89
+ function terminate_after_timeout() {
90
+ rm -f /opt/aws-ec2/data/ami-id.txt # rm file possible stale file from previous ami
91
+
92
+ # Remove all old at jobs.
93
+ # Assume all at job are previous after_timeout.sh job from previous AMI.
94
+ # Note: Each new at job increments the id by 1. So each AMI will have a different
95
+ # at job number.
96
+ for i in $(atq | awk '{print $1}') ; do
97
+ at -r $i
98
+ done
99
+ echo "/opt/aws-ec2/auto_terminate/after_timeout.sh now" | at now + 45 minutes
100
+ }
101
+
102
+ function terminate_after_ami() {
103
+ local AMI_ID
104
+
105
+ unschedule_termination
106
+ AMI_ID=$(cat /opt/aws-ec2/data/ami-id.txt | jq -r '.ImageId')
107
+ if [ -n "$AMI_ID" ]; then
108
+ # wait for the ami to be successfully created before terminating the instance
109
+ # https://docs.aws.amazon.com/cli/latest/reference/ec2/wait/image-available.html
110
+ # 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.
111
+ # so it'll wait for 10 mins max
112
+ # aws ec2 wait image-available --image-ids "$AMI_ID" --owners self
113
+
114
+ # For some reason aws ec2 wait image-available didnt work for amazonlinux2
115
+ # so using a custom version
116
+ wait_for_ami "$AMI_ID"
117
+ fi
118
+
119
+ terminate_instance
120
+ }
121
+
122
+ function terminate_now() {
123
+ terminate_instance
124
+ }
125
+
126
+ source "/opt/aws-ec2/shared/functions.sh"
127
+ os=$(os_name)
128
+ source "/opt/aws-ec2/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/aws-ec2/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/aws-ec2/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
@@ -0,0 +1,22 @@
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 aws-ec2"
8
+ echo " $command ec2"
9
+ exit 1
10
+ fi
11
+ LOG_GROUP_NAME=$1
12
+
13
+ source "/opt/aws-ec2/shared/functions.sh"
14
+ os=$(os_name)
15
+ if [ "$os" != "amazonlinux2" ]; then
16
+ echo "Sorry, enable cloudwatch logging with the aws-ec2 tool is only supported for amazonlinux2 currently"
17
+ exit
18
+ fi
19
+
20
+ /opt/aws-ec2/cloudwatch/install.sh
21
+ /opt/aws-ec2/cloudwatch/configure.sh "$LOG_GROUP_NAME"
22
+ /opt/aws-ec2/cloudwatch/service.sh
@@ -0,0 +1,74 @@
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 aws-ec2"
8
+ echo " $command ec2"
9
+ exit 1
10
+ fi
11
+ LOG_GROUP_NAME=$1
12
+
13
+ # Inject the CloudWatch Logs configuration file contents
14
+ cat > /etc/awslogs/awslogs.conf <<- EOF
15
+ [general]
16
+ state_file = /var/lib/awslogs/agent-state
17
+
18
+ [/var/log/dmesg]
19
+ file = /var/log/dmesg
20
+ log_group_name = ${LOG_GROUP_NAME}
21
+ log_stream_name = {instance_id}/var/log/dmesg
22
+
23
+ [/var/log/messages]
24
+ file = /var/log/messages
25
+ log_group_name = ${LOG_GROUP_NAME}
26
+ log_stream_name = {instance_id}/var/log/messages
27
+ datetime_format = %b %d %H:%M:%S
28
+
29
+ [/var/log/cloud-init.log]
30
+ file = /var/log/cloud-init.log
31
+ log_group_name = ${LOG_GROUP_NAME}
32
+ log_stream_name = {instance_id}/var/log/cloud-init.log
33
+ datetime_format =
34
+
35
+ [/var/log/cloud-init-output.log]
36
+ file = /var/log/cloud-init-output.log
37
+ log_group_name = ${LOG_GROUP_NAME}
38
+ log_stream_name = {instance_id}/var/log/cloud-init-output.log
39
+ datetime_format =
40
+
41
+ [/var/log/secure]
42
+ file = /var/log/secure
43
+ log_group_name = ${LOG_GROUP_NAME}
44
+ log_stream_name = {instance_id}/var/log/secure
45
+ datetime_format =
46
+
47
+ [/var/log/audit/audit.log]
48
+ file = /var/log/audit/audit.log
49
+ log_group_name = ${LOG_GROUP_NAME}
50
+ log_stream_name = {instance_id}/var/log/audit/audit.log
51
+ datetime_format =
52
+
53
+ [/var/lib/cloud/instance/user-data.txt]
54
+ file = /var/lib/cloud/instance/user-data.txt
55
+ log_group_name = ${LOG_GROUP_NAME}
56
+ log_stream_name = {instance_id}/var/lib/cloud/instance/user-data.txt
57
+ datetime_format =
58
+
59
+ [/var/log/messages]
60
+ file = /var/log/messages
61
+ log_group_name = ${LOG_GROUP_NAME}
62
+ log_stream_name = {instance_id}/var/log/messages
63
+ datetime_format =
64
+
65
+ [/var/log/auto-terminate.log]
66
+ file = /var/log/auto-terminate.log
67
+ log_group_name = ${LOG_GROUP_NAME}
68
+ log_stream_name = {instance_id}/var/log/auto-terminate.log
69
+ datetime_format =
70
+
71
+ EOF
72
+
73
+ region=$(curl 169.254.169.254/latest/meta-data/placement/availability-zone | sed s'/.$//')
74
+ sed -i -e "s/region = us-east-1/region = $region/g" /etc/awslogs/awscli.conf
@@ -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,19 @@
1
+ cat > /etc/init/awslogs.conf <<- EOL
2
+ #upstart-job
3
+ description "Configure and start CloudWatch Logs agent EC2 instance"
4
+ author "Tung Nguyen"
5
+ start on startup
6
+
7
+ script
8
+ exec 2>>/var/log/cloudwatch-logs-start.log
9
+ set -x
10
+
11
+ service awslogs start
12
+ chkconfig awslogs on
13
+ end script
14
+ EOL
15
+
16
+ initctl list
17
+ initctl reload-configuration
18
+ initctl start awslogs
19
+ initctl list
@@ -0,0 +1,44 @@
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
+ # Example OS values at this point:
20
+ # Ubuntu
21
+ # Amazon Linux AMI
22
+ function os_name() {
23
+ # https://askubuntu.com/questions/459402/how-to-know-if-the-running-platform-is-ubuntu-or-centos-with-help-of-a-bash-scri
24
+ # Method 1 works for amazonlinux2 and ubuntu
25
+ # Method 3 the complex script, did not work for amazonlinux2
26
+ local OS
27
+ OS=$(gawk -F= '/^NAME/{print $2}' /etc/os-release) # text surrounded by double quotes
28
+ # strip surrounding quotes: https://stackoverflow.com/questions/9733338/shell-script-remove-first-and-last-quote-from-a-variable
29
+ OS="${OS%\"}"
30
+ OS="${OS#\"}"
31
+ # Example OS values at this point:
32
+ # Ubuntu
33
+ # Amazon Linux AMI
34
+
35
+ # normalize values
36
+ case "$OS" in
37
+ Ubuntu)
38
+ echo "ubuntu"
39
+ ;;
40
+ *)
41
+ echo "amazonlinux2" # default
42
+ ;;
43
+ esac
44
+ }