github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/pkg/discovery/backends.go (about) 1 package discovery 2 3 import ( 4 "fmt" 5 "net" 6 "strings" 7 "time" 8 9 log "github.com/Sirupsen/logrus" 10 ) 11 12 var ( 13 // Backends is a global map of discovery backends indexed by their 14 // associated scheme. 15 backends map[string]Backend 16 ) 17 18 func init() { 19 backends = make(map[string]Backend) 20 } 21 22 // Register makes a discovery backend available by the provided scheme. 23 // If Register is called twice with the same scheme an error is returned. 24 func Register(scheme string, d Backend) error { 25 if _, exists := backends[scheme]; exists { 26 return fmt.Errorf("scheme already registered %s", scheme) 27 } 28 log.WithField("name", scheme).Debug("Registering discovery service") 29 backends[scheme] = d 30 return nil 31 } 32 33 func parse(rawurl string) (string, string) { 34 parts := strings.SplitN(rawurl, "://", 2) 35 36 // nodes:port,node2:port => nodes://node1:port,node2:port 37 if len(parts) == 1 { 38 return "nodes", parts[0] 39 } 40 return parts[0], parts[1] 41 } 42 43 // ParseAdvertise parses the --cluster-advertise daemon config which accepts 44 // <ip-address>:<port> or <interface-name>:<port> 45 func ParseAdvertise(store, advertise string) (string, error) { 46 var ( 47 iface *net.Interface 48 addrs []net.Addr 49 err error 50 ) 51 52 addr, port, err := net.SplitHostPort(advertise) 53 54 if err != nil { 55 return "", fmt.Errorf("invalid --cluster-advertise configuration: %s: %v", advertise, err) 56 } 57 58 ip := net.ParseIP(addr) 59 // If it is a valid ip-address, use it as is 60 if ip != nil { 61 return advertise, nil 62 } 63 64 // If advertise is a valid interface name, get the valid ipv4 address and use it to advertise 65 ifaceName := addr 66 iface, err = net.InterfaceByName(ifaceName) 67 if err != nil { 68 return "", fmt.Errorf("invalid cluster advertise IP address or interface name (%s) : %v", advertise, err) 69 } 70 71 addrs, err = iface.Addrs() 72 if err != nil { 73 return "", fmt.Errorf("unable to get advertise IP address from interface (%s) : %v", advertise, err) 74 } 75 76 if addrs == nil || len(addrs) == 0 { 77 return "", fmt.Errorf("no available advertise IP address in interface (%s)", advertise) 78 } 79 80 addr = "" 81 for _, a := range addrs { 82 ip, _, err := net.ParseCIDR(a.String()) 83 if err != nil { 84 return "", fmt.Errorf("error deriving advertise ip-address in interface (%s) : %v", advertise, err) 85 } 86 if ip.To4() == nil || ip.IsLoopback() { 87 continue 88 } 89 addr = ip.String() 90 break 91 } 92 if addr == "" { 93 return "", fmt.Errorf("couldnt find a valid ip-address in interface %s", advertise) 94 } 95 96 addr = fmt.Sprintf("%s:%s", addr, port) 97 return addr, nil 98 } 99 100 // New returns a new Discovery given a URL, heartbeat and ttl settings. 101 // Returns an error if the URL scheme is not supported. 102 func New(rawurl string, heartbeat time.Duration, ttl time.Duration, clusterOpts map[string]string) (Backend, error) { 103 scheme, uri := parse(rawurl) 104 if backend, exists := backends[scheme]; exists { 105 log.WithFields(log.Fields{"name": scheme, "uri": uri}).Debug("Initializing discovery service") 106 err := backend.Initialize(uri, heartbeat, ttl, clusterOpts) 107 return backend, err 108 } 109 110 return nil, ErrNotSupported 111 }