Skip to content

Commit

Permalink
Merge pull request #11 from vfarcic/consul-templates
Browse files Browse the repository at this point in the history
Consul templates
  • Loading branch information
vfarcic committed May 22, 2016
2 parents bcd685c + c7cf428 commit b58bed5
Show file tree
Hide file tree
Showing 19 changed files with 618 additions and 203 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
env:
- VERSION=1.0.1-beta
- VERSION=1.0

language: go

Expand Down
145 changes: 94 additions & 51 deletions README.md

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions articles/templates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
```bash
./docker-flow \
-f docker-compose-demo.yml \
--flow deploy --flow proxy
```
1 change: 0 additions & 1 deletion consul.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ func (c Consul) GetScaleCalc(address, serviceName, scale string) (int, error) {
}
}
total := s + inc
fmt.Println(string(total))
if total <= 0 {
return 1, nil
}
Expand Down
22 changes: 21 additions & 1 deletion docker-compose-setup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,29 @@ services:
- 8300:8300
command: -server -bootstrap

consul-server:
container_name: consul
image: consul
network_mode: host
environment:
- 'CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}'
command: agent -server -bind=$HOST_IP -bootstrap-expect=1 -client=$HOST_IP

registrator:
container_name: registrator
image: gliderlabs/registrator
volumes:
- /var/run/docker.sock:/tmp/docker.sock
command: -ip $DOCKER_IP consul://$CONSUL_IP:8500
command: -ip $HOST_IP consul://$CONSUL_IP:8500

proxy:
container_name: docker-flow-proxy
image: vfarcic/docker-flow-proxy
environment:
CONSUL_ADDRESS: $CONSUL_IP:8500
volumes:
- ./test_configs/:/consul_templates/
ports:
- 80:80
- 443:443
- 8080:8080
9 changes: 2 additions & 7 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
version: '2'

services:

app:
image: vfarcic/books-ms${BOOKS_MS_VERSION}
image: vfarcic/go-demo
ports:
- 8080
environment:
- SERVICE_NAME=books-ms
- DB_HOST=books-ms-db

db:
container_name: books-ms-db
image: mongo
environment:
- SERVICE_NAME=books-ms-db
2 changes: 1 addition & 1 deletion docker-flow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ side_targets:
- db
blue_green: true
service_path:
- /api/v1/books
- /demo
3 changes: 3 additions & 0 deletions flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,14 @@ func (m Flow) Proxy(opts Opts, proxy Proxy) error {
color = opts.NextColor
}
if err := proxy.Reconfigure(
opts.ProxyDockerHost,
opts.ProxyDockerCertPath,
opts.ProxyHost,
opts.ProxyReconfPort,
opts.ServiceName,
color,
opts.ServicePath,
opts.ConsulTemplatePath,
); err != nil {
return err
}
Expand Down
9 changes: 9 additions & 0 deletions flow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,11 +502,14 @@ func (s FlowTestSuite) Test_Proxy_InvokesReconfigure_WhenDeploy() {
mockObj.AssertCalled(
s.T(),
"Reconfigure",
s.opts.ProxyDockerHost,
s.opts.ProxyDockerCertPath,
s.opts.ProxyHost,
s.opts.ProxyReconfPort,
s.opts.ServiceName,
s.opts.NextColor,
s.opts.ServicePath,
"",
)
}

Expand All @@ -519,11 +522,14 @@ func (s FlowTestSuite) Test_Proxy_InvokesReconfigure_WhenScale() {
mockObj.AssertCalled(
s.T(),
"Reconfigure",
s.opts.ProxyDockerHost,
s.opts.ProxyDockerCertPath,
s.opts.ProxyHost,
s.opts.ProxyReconfPort,
s.opts.ServiceName,
s.opts.CurrentColor,
s.opts.ServicePath,
"",
)
}

Expand All @@ -537,6 +543,9 @@ func (s FlowTestSuite) Test_Proxy_ReturnsError_WhenReconfigureFails() {
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
mock.Anything,
).Return(fmt.Errorf("This is an error"))

actual := Flow{}.Proxy(s.opts, mockObj)
Expand Down
115 changes: 98 additions & 17 deletions ha_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,27 @@ 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 = runCmd
var runHaProxyExecCmd = runCmd
var runHaProxyCpCmd = runCmd
var runHaProxyPsCmd = runCmd
var runHaProxyStartCmd = runCmd
var httpGet = http.Get

func (m HaProxy) Provision(host, reconfPort, certPath, scAddress string) error {
if len(host) == 0 {
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.")
}
SetDockerHost(host, certPath)
SetDockerHost(dockerHost, certPath)
status, err := m.ps()
if err != nil {
return err
Expand All @@ -53,42 +56,120 @@ func (m HaProxy) Provision(host, reconfPort, certPath, scAddress string) error {
return nil
}

func (m HaProxy) Reconfigure(host, reconfPort, serviceName, serviceColor string, servicePath []string) error {
// TODO: Change args to struct
func (m HaProxy) Reconfigure(
dockerHost, dockerCertPath, host, reconfPort, serviceName, serviceColor string,
servicePath []string,
consulTemplatePath string,
) error {
if len(consulTemplatePath) > 0 {
if err := m.sendConsulTemplateToTheProxy(dockerHost, dockerCertPath, consulTemplatePath, 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(servicePath) == 0 {
return fmt.Errorf("Service path is mandatory.")
}
if len(reconfPort) == 0 {
if len(reconfPort) == 0 && !strings.Contains(host, ":") {
return fmt.Errorf("Reconfigure port is mandatory.")
}
address := fmt.Sprintf("%s:%s", host, reconfPort)
if err := m.sendReconfigureRequest(host, reconfPort, serviceName, serviceColor, servicePath, consulTemplatePath); err != nil {
return err
}
return nil
}

func (m HaProxy) sendReconfigureRequest(
host, reconfPort, serviceName, serviceColor string,
servicePath []string,
consulTemplatePath 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)
}
colorQuery := ""
if len(serviceColor) > 0 {
colorQuery = fmt.Sprintf("&serviceColor=%s", serviceColor)
}
proxyUrl := fmt.Sprintf(
"%s/v1/docker-flow-proxy/reconfigure?serviceName=%s%s&servicePath=%s",
"%s/v1/docker-flow-proxy/reconfigure?serviceName=%s",
address,
serviceName,
colorQuery,
strings.Join(servicePath, ","),
)
if len(consulTemplatePath) > 0 {
proxyUrl = fmt.Sprintf("%s&consulTemplatePath=%s/%s.tmpl", proxyUrl, 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 response from the proxy was incorrect\n%s\n", err.Error())
return fmt.Errorf("The request to the proxy (%s) failed with status code %d\n", proxyUrl, resp.StatusCode)
}
return nil
}

func (m HaProxy) sendConsulTemplateToTheProxy(dockerHost, dockerCertPath, consulTemplatePath, serviceName, color string) error {
if err := m.createTempConsulTemplate(consulTemplatePath, serviceName, color); err != nil {
return err
}
if err := m.copyConsulTemplateToTheProxy(dockerHost, dockerCertPath, consulTemplatePath, serviceName); err != nil {
return err
}
removeFile(fmt.Sprintf("%s.tmp", consulTemplatePath))

return nil
}

func (m HaProxy) copyConsulTemplateToTheProxy(dockerHost, dockerCertPath, consulTemplatePath, serviceName string) error {
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.tmpl", ConsulTemplatesDir, serviceName),
}
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 := readFile(consulTemplatePath)
if err != nil {
return fmt.Errorf("Could not read the Consul template %s\n%s", consulTemplatePath, err.Error())
}
if err := 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
}
Expand Down
Loading

0 comments on commit b58bed5

Please sign in to comment.