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  }