-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathha_proxy.go
240 lines (225 loc) · 7.8 KB
/
ha_proxy.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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
package main
import (
"bytes"
"fmt"
"net/http"
"os"
"os/exec"
"strings"
"time"
"./util"
)
const containerStatusRunning = 1
const containerStatusExited = 2
const containerStatusRemoved = 3
const ProxyReconfigureDefaultPort = 8080
const ConsulTemplatesDir = "/consul_templates"
var haProxy Proxy = HaProxy{}
type HaProxy struct{}
var runHaProxyRunCmd = func(cmd *exec.Cmd) error { return cmd.Run() }
var runHaProxyExecCmd = func(cmd *exec.Cmd) error { return cmd.Run() }
var runHaProxyCpCmd = func(cmd *exec.Cmd) error { return cmd.Run() }
var runHaProxyPsCmd = func(cmd *exec.Cmd) error { return cmd.Run() }
var runHaProxyStartCmd = func(cmd *exec.Cmd) error { return cmd.Run() }
var httpGet = http.Get
func (m HaProxy) Provision(dockerHost, reconfPort, certPath, scAddress string) error {
if len(dockerHost) == 0 {
return fmt.Errorf("Proxy docker host is mandatory for the proxy step. Please set the proxy-docker-host argument.")
}
if len(scAddress) == 0 {
return fmt.Errorf("Service Discovery Address is mandatory.")
}
util.SetDockerHost(dockerHost, certPath)
status, err := m.ps()
if err != nil {
return err
}
switch status {
case containerStatusRunning:
return nil
case containerStatusExited:
if err := m.start(); err != nil {
return err
}
util.Sleep(time.Second * 5)
default:
if err := m.run(reconfPort, scAddress); err != nil {
return err
}
util.Sleep(time.Second * 5)
}
return nil
}
// TODO: Change args to struct
func (m HaProxy) Reconfigure(
dockerHost, dockerCertPath, host, reconfPort, serviceName, serviceColor string,
servicePath []string,
consulTemplateFePath string, consulTemplateBePath string,
) error {
if len(consulTemplateFePath) > 0 {
if err := m.sendConsulTemplatesToTheProxy(dockerHost, dockerCertPath, consulTemplateFePath, consulTemplateBePath, serviceName, serviceColor); err != nil {
return err
}
} else if len(servicePath) == 0 {
return fmt.Errorf("It is mandatory to specify servicePath or consulTemplatePath. Please set one of the two.")
}
if len(host) == 0 {
return fmt.Errorf("Proxy host is mandatory for the proxy step. Please set the proxy-host argument.")
}
if len(serviceName) == 0 {
return fmt.Errorf("Service name is mandatory for the proxy step.")
}
if len(reconfPort) == 0 && !strings.Contains(host, ":") {
return fmt.Errorf("Reconfigure port is mandatory.")
}
if err := m.sendReconfigureRequest(host, reconfPort, serviceName, serviceColor, servicePath, consulTemplateFePath, consulTemplateBePath); err != nil {
return err
}
return nil
}
func (m HaProxy) sendReconfigureRequest(
host, reconfPort, serviceName, serviceColor string,
servicePath []string,
consulTemplateFePath, consulTemplateBePath string,
) error {
address := host
if len(reconfPort) > 0 {
address = fmt.Sprintf("%s:%s", host, reconfPort)
}
if !strings.HasPrefix(strings.ToLower(address), "http") {
address = fmt.Sprintf("http://%s", address)
}
proxyUrl := fmt.Sprintf(
"%s/v1/docker-flow-proxy/reconfigure?serviceName=%s",
address,
serviceName,
)
if len(consulTemplateFePath) > 0 {
proxyUrl = fmt.Sprintf("%s&consulTemplateFePath=%s/%s-fe.tmpl&consulTemplateBePath=%s/%s-be.tmpl", proxyUrl, ConsulTemplatesDir, serviceName, ConsulTemplatesDir, serviceName)
} else {
if len(serviceColor) > 0 {
proxyUrl = fmt.Sprintf("%s&serviceColor=%s", proxyUrl, serviceColor)
}
proxyUrl = fmt.Sprintf("%s&servicePath=%s", proxyUrl, strings.Join(servicePath, ","))
}
logPrintf("Sending request to %s to reconfigure the proxy", proxyUrl)
resp, err := httpGet(proxyUrl)
if err != nil {
return fmt.Errorf("The request to reconfigure the proxy failed\n%s\n", err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("The request to the proxy (%s) failed with status code %d\n", proxyUrl, resp.StatusCode)
}
return nil
}
func (m HaProxy) sendConsulTemplatesToTheProxy(dockerHost, dockerCertPath, consulTemplateFePath, consulTemplateBePath, serviceName, color string) error {
if err := m.sendConsulTemplateToTheProxy(dockerHost, dockerCertPath, consulTemplateFePath, serviceName, color, "fe"); err != nil {
return err
}
if err := m.sendConsulTemplateToTheProxy(dockerHost, dockerCertPath, consulTemplateBePath, serviceName, color, "be"); err != nil {
return err
}
return nil
}
func (m HaProxy) sendConsulTemplateToTheProxy(dockerHost, dockerCertPath, consulTemplatePath, serviceName, color, templateType string) error {
if err := m.createTempConsulTemplate(consulTemplatePath, serviceName, color); err != nil {
return err
}
file := fmt.Sprintf("%s-%s.tmpl", serviceName, templateType)
if err := m.copyConsulTemplateToTheProxy(dockerHost, dockerCertPath, consulTemplatePath, file); err != nil {
return err
}
util.RemoveFile(fmt.Sprintf("%s.tmp", consulTemplatePath))
return nil
}
func (m HaProxy) copyConsulTemplateToTheProxy(dockerHost, dockerCertPath, consulTemplatePath, templateName string) error {
util.SetDockerHost(dockerHost, dockerCertPath)
args := []string{"exec", "-i", "docker-flow-proxy", "mkdir", "-p", ConsulTemplatesDir}
execCmd := exec.Command("docker", args...)
execCmd.Stdout = os.Stdout
execCmd.Stderr = os.Stderr
// TODO: Remove. Deprecated since Docker Flow: Proxy has that directory by default.
if err := runHaProxyExecCmd(execCmd); err != nil {
return err
}
args = []string{
"cp",
fmt.Sprintf("%s.tmp", consulTemplatePath),
fmt.Sprintf("docker-flow-proxy:%s/%s", ConsulTemplatesDir, templateName),
}
cpCmd := exec.Command("docker", args...)
cpCmd.Stdout = os.Stdout
cpCmd.Stderr = os.Stderr
if err := runHaProxyCpCmd(cpCmd); err != nil {
return err
}
return nil
}
func (m HaProxy) createTempConsulTemplate(consulTemplatePath, serviceName, color string) error {
fullServiceName := fmt.Sprintf("%s-%s", serviceName, color)
tmpPath := fmt.Sprintf("%s.tmp", consulTemplatePath)
data, err := util.ReadFile(consulTemplatePath)
if err != nil {
return fmt.Errorf("Could not read the Consul template %s\n%s", consulTemplatePath, err.Error())
}
if err := util.WriteFile(
tmpPath,
[]byte(strings.Replace(string(data), "SERVICE_NAME", fullServiceName, -1)),
0644,
); err != nil {
return fmt.Errorf("Could not write temporary Consul template to %s\n%s", tmpPath, err.Error())
}
return nil
}
func (m HaProxy) run(reconfPort, scAddress string) error {
logPrintln("Running the docker-flow-proxy container...")
args := []string{
"run", "-d",
"--name", "docker-flow-proxy",
"-e", fmt.Sprintf("%s=%s", "CONSUL_ADDRESS", scAddress),
"-p", "80:80", "-p", fmt.Sprintf("%s:8080", reconfPort),
"vfarcic/docker-flow-proxy",
}
cmd := exec.Command("docker", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := runHaProxyRunCmd(cmd); err != nil {
return fmt.Errorf("Docker run command failed\n%s\n%s\n", strings.Join(cmd.Args, " "), err.Error())
}
return nil
}
func (m HaProxy) ps() (int, error) {
logPrintln("Checking status of the docker-flow-proxy container...")
args := []string{
"ps", "-a",
"--filter", "name=docker-flow-proxy",
"--format", "{{.Status}}",
}
cmd := exec.Command("docker", args...)
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = os.Stderr
if err := runHaProxyPsCmd(cmd); err != nil {
return 0, fmt.Errorf("Docker ps command failed\n%s\n%s\n", strings.Join(cmd.Args, " "), err.Error())
}
status := string(out.Bytes())
if strings.HasPrefix(status, "Exited") {
return containerStatusExited, nil
}
if len(status) == 0 {
return containerStatusRemoved, nil
}
return containerStatusRunning, nil
}
func (m HaProxy) start() error {
logPrintln("Starting the docker-flow-proxy container...")
args := []string{"start", "docker-flow-proxy"}
cmd := exec.Command("docker", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := runHaProxyStartCmd(cmd); err != nil {
return fmt.Errorf("Docker start command failed\n%s\n%s\n", strings.Join(cmd.Args, " "), err.Error())
}
return nil
}