-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
168 lines (147 loc) · 3.95 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/morfien101/asg-lifecyle-hook-manager/ec2metadatareader"
"github.com/morfien101/asg-lifecyle-hook-manager/hookmanager"
)
var (
version = "0.0.3"
actionAbandon = "ABANDON"
actionHeartBeat = "HEARTBEAT"
actionContinue = "CONTINUE"
helpBlurb = `
This application is used to interact with AWS Autoscaling Lifecycle hooks.
It can set the hooks to Abandon, Continue or send a heartbeat.
Only a single action can be invoked in a single run.
It will consume credentials from instance roles or ENV vars.
There is no provision for manually feeding in credentials and never will be.
`
versionFlag = flag.Bool("v", false, "Show the version")
helpFlag = flag.Bool("h", false, "Show the help menu")
verboseFlag = flag.Bool("verbose", false, "Will log success statements as well as errors")
asgNameFlag = flag.String("n", "", "Name of the autoscaling group")
hookNameFlag = flag.String("l", "", "Name of the Lifecycle hook")
instanceIDFlag = flag.String("i", "", "instance_id for the EC2 instance. If - is passed the instance ID is determined automatically from the metadata if available")
hookActionFlag = flag.String("a", "", fmt.Sprintf("Set the lifecycle hook action. Valid values: %s, %s, %s", actionAbandon, actionContinue, actionHeartBeat))
)
func main() {
flag.Parse()
// These 2 functions have the ability to exit the app
showStopperFlags()
validateActions()
// Do the work
run()
}
func showStopperFlags() {
if *helpFlag {
fmt.Println(helpBlurb)
flag.PrintDefaults()
os.Exit(0)
}
if *versionFlag {
fmt.Println(version)
os.Exit(0)
}
}
func validateActions() {
errors := []string{}
if err := validateHookAction(*hookActionFlag); err != nil {
errors = append(errors, err.Error())
}
if err := validateRequiredVars(); err != nil {
errors = append(errors, err.Error())
}
if len(errors) != 0 {
fmt.Println(strings.Join(errors, "\n"))
os.Exit(1)
}
}
func validateHookAction(hookAction string) error {
if hookAction == "" {
return fmt.Errorf("-a must to be specified")
}
hookActionValid := false
switch hookAction {
case actionAbandon:
hookActionValid = true
case actionHeartBeat:
hookActionValid = true
case actionContinue:
hookActionValid = true
}
if !hookActionValid {
return fmt.Errorf("Hook action %s is not valid", hookAction)
}
return nil
}
func validateRequiredVars() error {
errors := []string{}
if *asgNameFlag == "" {
errors = append(errors, "-n autoscaling group name must be specified")
}
if *hookNameFlag == "" {
errors = append(errors, "-l lifecycle hook name must be specified")
}
if *instanceIDFlag == "" {
errors = append(errors, "-i instance_id must be specified")
}
if len(errors) != 0 {
return fmt.Errorf("%s", strings.Join(errors, ","))
}
return nil
}
func run() {
instanceID := ""
if *instanceIDFlag == "-" {
localInstanceID, err := ec2metadatareader.InstanceID()
if err != nil {
writeToStdErr(fmt.Sprintf("Could not determine instance id. Error: %s", err))
os.Exit(1)
}
instanceID = localInstanceID
} else {
instanceID = *instanceIDFlag
}
switch *hookActionFlag {
case actionAbandon:
output, err := hookmanager.SetAbandon(*asgNameFlag, *hookNameFlag, instanceID)
if err != nil {
terminate(err.Error(), 1)
return
}
terminate(output, 0)
case actionContinue:
output, err := hookmanager.SetContinue(*asgNameFlag, *hookNameFlag, instanceID)
if err != nil {
terminate(err.Error(), 1)
return
}
terminate(output, 0)
case actionHeartBeat:
output, err := hookmanager.RecordHeartBeat(*asgNameFlag, *hookNameFlag, instanceID)
if err != nil {
terminate(err.Error(), 1)
return
}
terminate(output, 0)
}
}
func terminate(log string, exitCode int) {
if exitCode == 0 {
verboseLog(log)
} else {
writeToStdErr(log)
}
os.Exit(exitCode)
}
func writeToStdErr(s string) {
fmt.Fprintln(os.Stderr, s)
}
func verboseLog(s string) {
if *verboseFlag {
fmt.Println(s)
}
}