Merge pull request #509 from vieux/nodes-discovery-gen

Proposal: implement IP generator for nodes and file discoveries by @chanwit
This commit is contained in:
Victor Vieux 2015-03-24 17:00:48 -06:00
commit 45fc0c9272
7 changed files with 142 additions and 8 deletions

View File

@ -149,6 +149,27 @@ $ docker -H <swarm_ip:swarm_port> logs ...
...
```
### Range pattern for IP addresses
The `file` and `nodes` discoveries support a range pattern to specify IP addresses, i.e., `10.0.0.[10:200]` will be a list of nodes starting from `10.0.0.10` to `10.0.0.200`.
For example,
```bash
# file example
$ echo "10.0.0.[11:100]:2375" >> /tmp/my_cluster
$ echo "10.0.1.[15:20]:2375" >> /tmp/my_cluster
$ echo "192.168.1.2:[2:20]375" >> /tmp/my_cluster
# start the manager
$ swarm manage -H tcp://<swarm_ip:swarm_port> file:///tmp/my_cluster
```
```bash
# nodes example
$ swarm manage -H <swarm_ip:swarm_port> "nodes://10.0.0.[10:200]:2375,10.0.1.[2:250]:2375"
```
## Contributing a new discovery backend
Contributing a new discovery backend is easy,

View File

@ -23,13 +23,22 @@ func (s *FileDiscoveryService) Initialize(path string, heartbeat int) error {
return nil
}
func parseFileContent(content []byte) []string {
result := make([]string, 0)
for _, line := range strings.Split(strings.TrimSpace(string(content)), "\n") {
for _, ip := range discovery.Generate(line) {
result = append(result, ip)
}
}
return result
}
func (s *FileDiscoveryService) Fetch() ([]*discovery.Entry, error) {
data, err := ioutil.ReadFile(s.path)
fileContent, err := ioutil.ReadFile(s.path)
if err != nil {
return nil, err
}
return discovery.CreateEntries(strings.Split(string(data), "\n"))
return discovery.CreateEntries(parseFileContent(fileContent))
}
func (s *FileDiscoveryService) Watch(callback discovery.WatchCallback) {

View File

@ -12,6 +12,19 @@ func TestInitialize(t *testing.T) {
assert.Equal(t, discovery.path, "/path/to/file")
}
func TestContent(t *testing.T) {
data := `
1.1.1.[1:2]:1111
2.2.2.[2:4]:2222
`
ips := parseFileContent([]byte(data))
assert.Equal(t, ips[0], "1.1.1.1:1111")
assert.Equal(t, ips[1], "1.1.1.2:1111")
assert.Equal(t, ips[2], "2.2.2.2:2222")
assert.Equal(t, ips[3], "2.2.2.3:2222")
assert.Equal(t, ips[4], "2.2.2.4:2222")
}
func TestRegister(t *testing.T) {
discovery := &FileDiscoveryService{path: "/path/to/file"}
assert.Error(t, discovery.Register("0.0.0.0"))

37
discovery/generator.go Normal file
View File

@ -0,0 +1,37 @@
package discovery
import (
"fmt"
"regexp"
"strconv"
)
//
// IP generator
//
func Generate(pattern string) []string {
re, _ := regexp.Compile(`\[(.+):(.+)\]`)
submatch := re.FindStringSubmatch(pattern)
if submatch == nil {
return []string{pattern}
}
from, err := strconv.Atoi(submatch[1])
if err != nil {
return []string{pattern}
}
to, err := strconv.Atoi(submatch[2])
if err != nil {
return []string{pattern}
}
template := re.ReplaceAllString(pattern, "%d")
result := make([]string, 0)
for val := from; val <= to; val++ {
entry := fmt.Sprintf(template, val)
result = append(result, entry)
}
return result
}

View File

@ -0,0 +1,41 @@
package discovery
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGeneratorNotGenerate(t *testing.T) {
ips := Generate("127.0.0.1")
assert.Equal(t, len(ips), 1)
assert.Equal(t, ips[0], "127.0.0.1")
}
func TestGeneratorWithPortNotGenerate(t *testing.T) {
ips := Generate("127.0.0.1:8080")
assert.Equal(t, len(ips), 1)
assert.Equal(t, ips[0], "127.0.0.1:8080")
}
func TestGeneratorMatchFailedNotGenerate(t *testing.T) {
ips := Generate("127.0.0.[1]")
assert.Equal(t, len(ips), 1)
assert.Equal(t, ips[0], "127.0.0.[1]")
}
func TestGeneratorWithPort(t *testing.T) {
ips := Generate("127.0.0.[1:11]:2375")
assert.Equal(t, len(ips), 11)
assert.Equal(t, ips[0], "127.0.0.1:2375")
assert.Equal(t, ips[1], "127.0.0.2:2375")
assert.Equal(t, ips[2], "127.0.0.3:2375")
assert.Equal(t, ips[3], "127.0.0.4:2375")
assert.Equal(t, ips[4], "127.0.0.5:2375")
assert.Equal(t, ips[5], "127.0.0.6:2375")
assert.Equal(t, ips[6], "127.0.0.7:2375")
assert.Equal(t, ips[7], "127.0.0.8:2375")
assert.Equal(t, ips[8], "127.0.0.9:2375")
assert.Equal(t, ips[9], "127.0.0.10:2375")
assert.Equal(t, ips[10], "127.0.0.11:2375")
}

View File

@ -15,12 +15,14 @@ func init() {
}
func (s *NodesDiscoveryService) Initialize(uris string, _ int) error {
for _, ip := range strings.Split(uris, ",") {
entry, err := discovery.NewEntry(ip)
if err != nil {
return err
for _, input := range strings.Split(uris, ",") {
for _, ip := range discovery.Generate(input) {
entry, err := discovery.NewEntry(ip)
if err != nil {
return err
}
s.entries = append(s.entries, entry)
}
s.entries = append(s.entries, entry)
}
return nil

View File

@ -14,6 +14,17 @@ func TestInitialise(t *testing.T) {
assert.Equal(t, discovery.entries[1].String(), "2.2.2.2:2222")
}
func TestInitialiseWithPattern(t *testing.T) {
discovery := &NodesDiscoveryService{}
discovery.Initialize("1.1.1.[1:2]:1111,2.2.2.[2:4]:2222", 0)
assert.Equal(t, len(discovery.entries), 5)
assert.Equal(t, discovery.entries[0].String(), "1.1.1.1:1111")
assert.Equal(t, discovery.entries[1].String(), "1.1.1.2:1111")
assert.Equal(t, discovery.entries[2].String(), "2.2.2.2:2222")
assert.Equal(t, discovery.entries[3].String(), "2.2.2.3:2222")
assert.Equal(t, discovery.entries[4].String(), "2.2.2.4:2222")
}
func TestRegister(t *testing.T) {
discovery := &NodesDiscoveryService{}
assert.Error(t, discovery.Register("0.0.0.0"))