Skip to content

Commit

Permalink
Issue #2 - config examples, add better equality checks, support remot…
Browse files Browse the repository at this point in the history
…e with TLS
  • Loading branch information
gondor committed May 9, 2017
1 parent 938b346 commit af3bc31
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 9 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,19 @@ Create a file called `nginx.template`. Refer to the `nginx.template` found in t

### Create the Beethoven Configuration File

Create a file that ends in `.json`. In this example we'll call it `btconf.json`. Refer to the `btconf.json` found in the [examples/](https://github.com/ContainX/beethoven/tree/master/examples) directory in this repo.
Create a file that ends in `.json`. In this example we'll use Marathon as the scheduler and call the file `config-marathon.json`. Refer to the `config-marathon.json` found in the [examples/](https://github.com/ContainX/beethoven/tree/master/examples) directory in this repo.

Add/Modify any options to suit your needs. For a description and all possible configuration options refer to the docs found within the [config.go](https://github.com/ContainX/beethoven/blob/master/config/config.go) file.

#### Create a Dockerfile

Next we will create the `Dockerfile` to package up the `nginx.template` and `btconf.json` files. If you used the filenames in this guide then simply copy the code below into your `Dockerfile`.
Next we will create the `Dockerfile` to package up the `nginx.template` and `config-marathon.json` files. If you used the filenames in this guide then simply copy the code below into your `Dockerfile`.

```
FROM containx/beethoven
ADD nginx.template /etc/nginx/nginx.template
ADD btconf.json /etc/btconf.json
ADD config-marathon.json /etc/config-marathon.json
```

#### Build and Testing your Container
Expand All @@ -62,7 +62,7 @@ Build and Run your Container

```
docker build -t myloadbalancer .
docker run -p 80:80 -d myloadbalancer -c /etc/btconf.json
docker run -p 80:80 -d myloadbalancer -c /etc/config-marathon.json
```

Now open your browser and test paths you created at http://localhost
Expand Down
9 changes: 9 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ type SwarmConfig struct {

// Interval to watch for Swarm topology changes
WatchIntervalSecs int `json:"watch_interval_secs"`

// TLS Certificate file
TLSCert string `json:"tls_cert"`
// TLS Certificate key
TLSKey string `json:"tls_key"`
// TLS CA Certificate
TLSCACert string `json:"tlsca_cert"`
// Verify TLS
TLSVerify bool `json:"tls_verify"`
}

type MarathonConfig struct {
Expand Down
File renamed without changes.
11 changes: 11 additions & 0 deletions examples/config-swarm-manager.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"swarm": {
"endpoint": "unix:///var/run/docker.sock",
"Network": "beethoven"
},
"scheduler_type": 2,
"filter_regex": "",
"port": 7777,
"template": "/etc/nginx/nginx.template",
"nginx_config": "/etc/nginx/nginx.conf"
}
11 changes: 11 additions & 0 deletions examples/config-swarm-remote.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"swarm": {
"endpoint": "1.1.1.1:2375",
"RouteToNode": true
},
"scheduler_type": 2,
"filter_regex": "",
"port": 7777,
"template": "/etc/nginx/nginx.template",
"nginx_config": "/etc/nginx/nginx.conf"
}
86 changes: 81 additions & 5 deletions scheduler/swarm.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package scheduler

import (
"errors"
"github.com/ContainX/beethoven/config"
"github.com/docker/go-connections/nat"
docker "github.com/fsouza/go-dockerclient"
"github.com/moby/moby/api/types/swarm"
"net"
"sort"
"strings"
"sync"
"time"
)
Expand All @@ -18,12 +22,14 @@ type swarmService struct {
*schedulerService
started bool
client *docker.Client
services []serviceData
services Services
shutdown ShutdownChan
watchInterval time.Duration
nodes *swarmNodes
}

type Services []serviceData

type serviceData struct {
ServiceName string
Name string
Expand Down Expand Up @@ -60,7 +66,7 @@ type nodeData struct {

func createSwarmScheduler(ss *schedulerService) Scheduler {
scheduler := &swarmService{schedulerService: ss}
client, err := docker.NewClient(ss.cfg.Swarm.Endpoint)
client, err := newDockerClient(ss.cfg.Swarm)
if err != nil {
panic(err)
}
Expand All @@ -80,13 +86,28 @@ func createSwarmScheduler(ss *schedulerService) Scheduler {
return scheduler
}

func newDockerClient(cfg *config.SwarmConfig) (*docker.Client, error) {
if strings.HasPrefix(cfg.Endpoint, "unix") {
return docker.NewClient(cfg.Endpoint)
} else if cfg.TLSVerify || tlsEnabled(cfg.TLSCert, cfg.TLSCACert, cfg.TLSKey) {
if cfg.TLSVerify {
if e, err := pathExists(cfg.TLSCACert); !e || err != nil {
return nil, errors.New("TLS verification was requested, but CA cert does not exist")
}
}
return docker.NewTLSClient(cfg.Endpoint, cfg.TLSCert, cfg.TLSKey, cfg.TLSCACert)
}
return docker.NewClient(cfg.Endpoint)
}

// Watch for changes using polling and make callbacks to the specified
// handler when apps have been added, removed or health changes.
// Currently docker doesn't support Swarm events (https://github.com/moby/moby/issues/23827)
func (s *swarmService) Watch(reload chan bool) {
log.Info("Starting Swarm Watch...")
s.reload = reload
ticker := time.NewTicker(s.watchInterval)

go func(ticker *time.Ticker, s *swarmService) {
for {
select {
Expand All @@ -100,7 +121,7 @@ func (s *swarmService) Watch(reload chan bool) {
s.services = services

// TODO: better comparison until #23827 is implemented
if len(previous) != len(services) {
if topologyChanged(previous, services) {
s.reload <- true
}
}
Expand Down Expand Up @@ -158,7 +179,7 @@ func (s *swarmService) updateNodeState() {
s.nodes.Unlock()
}

func (s *swarmService) getServices() ([]serviceData, error) {
func (s *swarmService) getServices() (Services, error) {
services, err := s.client.ListServices(docker.ListServicesOptions{})
if err != nil {
return []serviceData{}, err
Expand All @@ -177,13 +198,15 @@ func (s *swarmService) getServices() ([]serviceData, error) {
networkMap[network.ID] = &n
}

serviceDataList := []serviceData{}
serviceDataList := Services{}

for _, service := range services {
sdata := parseService(service, networkMap)
serviceDataList = append(serviceDataList, sdata)
}

sort.Sort(serviceDataList)

return serviceDataList, err
}

Expand Down Expand Up @@ -258,6 +281,59 @@ func (n *swarmNodes) nextNodeAddress() string {
return nodeData.Addr
}

func topologyChanged(a, b []serviceData) bool {
if a == nil && b == nil {
return false
}

if a == nil || b == nil {
return true
}

if len(a) != len(b) {
return true
}

for i := range a {
if a[i].Equal(b[i]) == false {
return true
}
}

return false
}

func (a serviceData) Equal(b serviceData) bool {
if a.Name != b.Name {
return false
}

if a.Health != b.Health {
return false
}

if a.TargetPort != b.TargetPort {
return false
}

if a.Port != b.Port {
return false
}
return true
}

func (s Services) Len() int {
return len(s)
}

func (s Services) Less(i, j int) bool {
return s[i].Name < s[j].Name
}

func (s Services) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}

func (s *swarmService) convertServiceToApp(serviceData []serviceData) map[string]*App {
apps := make(map[string]*App)
for _, service := range serviceData {
Expand Down
24 changes: 24 additions & 0 deletions scheduler/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package scheduler

import "os"

func tlsEnabled(tlsCert, tlsCaCert, tlsKey string) bool {
for _, v := range []string{tlsCert, tlsCaCert, tlsKey} {
if e, err := pathExists(v); e && err == nil {
return true
}
}
return false
}

// pathExists returns whether the given file or directory exists or not
func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}

0 comments on commit af3bc31

Please sign in to comment.