forked from fujiwara/stretcher
/
stretcher.go
145 lines (130 loc) · 3.07 KB
/
stretcher.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
package stretcher
import (
"bufio"
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"github.com/crowdmob/goamz/aws"
"github.com/crowdmob/goamz/s3"
)
var (
AWSAuth aws.Auth
AWSRegion aws.Region
LogBuffer bytes.Buffer
)
func Init() {
log.SetOutput(io.MultiWriter(os.Stderr, &LogBuffer))
}
func Run() error {
log.Println("Starting up stretcher agent")
profile := os.Getenv("AWS_DEFAULT_PROFILE")
if profile == "" {
profile = AWSDefaultProfileName
}
if file := os.Getenv("AWS_CONFIG_FILE"); file != "" {
err := LoadAWSConfigFile(file, profile)
if err != nil {
return fmt.Errorf("Load AWS_CONFIG_FILE failed: %s", err)
}
}
payload, err := parseEvents()
if err != nil {
return fmt.Errorf("Could not parse event: %s", err)
}
log.Println("Loading manifest:", payload)
m, err := getManifest(payload)
if err != nil {
return fmt.Errorf("Load manifest failed: %s", err)
}
log.Printf("Executing manifest %#v", m)
err = m.Deploy()
if err != nil {
log.Println("Deploy manifest failed:", err)
m.Commands.Failure.InvokePipe(&LogBuffer)
return fmt.Errorf("Deploy manifest failed: %s", err)
}
log.Println("Deploy manifest succeeded.")
m.Commands.Success.InvokePipe(&LogBuffer)
return nil
}
func getS3(u *url.URL) (io.ReadCloser, error) {
if AWSAuth.AccessKey == "" || AWSRegion.Name == "" {
return nil, fmt.Errorf("Invalid AWS Auth or Region. Please check env AWS_CONFIG_FILE.")
}
client := s3.New(AWSAuth, AWSRegion)
bucket := client.Bucket(u.Host)
rc, err := bucket.GetReader(u.Path)
if err != nil {
return nil, err
}
return rc, nil
}
func getFile(u *url.URL) (io.ReadCloser, error) {
file, err := os.Open(u.Path)
if err != nil {
return nil, err
}
return file, nil
}
func getHTTP(u *url.URL) (io.ReadCloser, error) {
resp, err := http.Get(u.String())
if err != nil {
return nil, err
}
return resp.Body, nil
}
func getURL(urlStr string) (io.ReadCloser, error) {
log.Println("Loading URL", urlStr)
u, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
switch u.Scheme {
case "s3":
return getS3(u)
case "http", "https":
return getHTTP(u)
case "file":
return getFile(u)
default:
return nil, fmt.Errorf("manifest URL scheme must be s3 or http(s) or file: %s", urlStr)
}
}
func getManifest(manifestURL string) (*Manifest, error) {
rc, err := getURL(manifestURL)
if err != nil {
return nil, err
}
data, _ := ioutil.ReadAll(rc)
return ParseManifest(data)
}
func parseEvents() (string, error) {
log.Println("Waiting for events from STDIN...")
if os.Getenv("CONSUL_INDEX") != "" {
log.Println("Reading Consul event")
ev, err := ParseConsulEvents(os.Stdin)
if err != nil {
return "", err
}
if ev == nil {
// no event
return "", fmt.Errorf("No Consul events found")
}
return ev.PayloadString(), nil
} else {
if userEvent := os.Getenv("SERF_USER_EVENT"); userEvent != "" {
log.Println("Reading Serf user event:", userEvent)
}
// event passed by stdin (raw string)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
return scanner.Text(), nil
}
return "", scanner.Err()
}
}