aws-ec2 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }