Ejemplo n.º 1
0
//New returns a new instance of the cluster, created using the given Config.
func New(config *Config) (*Cluster, error) {
	c := &Cluster{
		Config: config,
		name:   fmt.Sprintf("%d", config.ID),
	}

	memberlistConfig := memberlist.DefaultLANConfig()
	memberlistConfig.Name = c.name
	memberlistConfig.BindAddr = config.Host
	memberlistConfig.BindPort = config.Port

	//TODO Cosmin temporarily disabling any logging from memberlist, we might want to enable it again using logrus?
	memberlistConfig.LogOutput = ioutil.Discard

	ml, err := memberlist.Create(memberlistConfig)
	if err != nil {
		logger.WithField("error", err).Error("Error when creating the internal memberlist of the cluster")
		return nil, err
	}
	c.memberlist = ml
	memberlistConfig.Delegate = c
	memberlistConfig.Conflict = c
	memberlistConfig.Events = c

	return c, nil
}
Ejemplo n.º 2
0
func main() {
	InitLogger(logrus.DebugLevel.String(), "yws1")

	serfConfig := serf.DefaultConfig()
	serfConfig.NodeName = "yws1"
	serfConfig.MemberlistConfig = memberlist.DefaultLANConfig()

	serfConfig.MemberlistConfig.BindAddr = "127.0.0.1"
	serfConfig.MemberlistConfig.BindPort = 7373
	serfConfig.MemberlistConfig.AdvertiseAddr = "127.0.0.1"
	serfConfig.MemberlistConfig.AdvertisePort = 5000

	eventCh := make(chan serf.Event, 64)
	serfConfig.EventCh = eventCh
	serfConfig.LogOutput = ioutil.Discard
	serfConfig.MemberlistConfig.LogOutput = ioutil.Discard

	s, err := serf.Create(serfConfig)
	if err != nil {
		fmt.Println(err)
	}

	go func() {
		serfShutdownCh := s.ShutdownCh()
		log.Info("agent: Listen for events")
		for {
			select {
			case e := <-eventCh:
				log.WithFields(logrus.Fields{
					"event": e.String(),
				}).Debug("agent: Received event")

				// Log all member events
				if failed, ok := e.(serf.MemberEvent); ok {
					for _, member := range failed.Members {
						log.WithFields(logrus.Fields{
							"node":   "yang",
							"member": member.Name,
							"event":  e.EventType(),
						}).Debug("agent: Member event")
					}
				}

				if e.EventType() == serf.EventQuery {
					query := e.(*serf.Query)
					fmt.Println(query)
				}

			case <-serfShutdownCh:
				log.Warn("agent: Serf shutdown detected, quitting")
				return
			}
		}
	}()

	fmt.Println(s)

	wait := make(chan int)
	<-wait
}
Ejemplo n.º 3
0
func Create() (*Agent, error) {
	conf := serf.DefaultConfig()
	conf.Init()
	conf.NodeName = os.Getenv("HOST")
	conf.Tags["DOCKER_HOST"] = Os.Getenv("DOCKER_HOST")

	logOutput := log.StandardLogger().Out

	// Setup the underlying loggers
	conf.MemberlistConfig.LogOutput = logOutput
	conf.LogOutput = logOutput

	// Create a channel to listen for events from Serf
	eventCh := make(chan serf.Event, 64)
	conf.EventCh = eventCh

	// support only LAN configuration at the moment
	conf.MemberlistConfig = memberlist.DefaultLANConfig()
	conf.MemberlistConfig.BindAddr = "0.0.0.0"
	conf.MemberlistConfig.BindPort = 3388

	// Setup the agent
	agent := &Agent{
		conf:       conf,
		eventCh:    eventCh,
		isManager:  false,
		shutdownCh: make(chan struct{}),
	}

	return agent, nil
}
Ejemplo n.º 4
0
// DefaultConfig returns a Config struct that contains reasonable defaults
// for most of the configurations.
func DefaultConfig() *Config {
	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	return &Config{
		NodeName:                     hostname,
		BroadcastTimeout:             5 * time.Second,
		EventBuffer:                  512,
		QueryBuffer:                  512,
		LogOutput:                    os.Stderr,
		ProtocolVersion:              ProtocolVersionMax,
		ReapInterval:                 15 * time.Second,
		RecentIntentTimeout:          5 * time.Minute,
		ReconnectInterval:            30 * time.Second,
		ReconnectTimeout:             24 * time.Hour,
		QueueDepthWarning:            128,
		MaxQueueDepth:                4096,
		TombstoneTimeout:             24 * time.Hour,
		FlapTimeout:                  60 * time.Second,
		MemberlistConfig:             memberlist.DefaultLANConfig(),
		QueryTimeoutMult:             16,
		QueryResponseSizeLimit:       1024,
		QuerySizeLimit:               1024,
		EnableNameConflictResolution: true,
		DisableCoordinates:           false,
	}
}
Ejemplo n.º 5
0
// setupAgent is used to create the agent we use
func (c *Command) setupAgent(config *Config, logOutput io.Writer) *Agent {
	bindIP, bindPort, err := config.AddrParts(config.BindAddr)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Invalid bind address: %s", err))
		return nil
	}

	var advertiseIP string
	var advertisePort int
	if config.AdvertiseAddr != "" {
		advertiseIP, advertisePort, err = config.AddrParts(config.AdvertiseAddr)
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Invalid advertise address: %s", err))
			return nil
		}
	}

	encryptKey, err := config.EncryptBytes()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Invalid encryption key: %s", err))
		return nil
	}

	serfConfig := serf.DefaultConfig()
	switch config.Profile {
	case "lan":
		serfConfig.MemberlistConfig = memberlist.DefaultLANConfig()
	case "wan":
		serfConfig.MemberlistConfig = memberlist.DefaultWANConfig()
	case "local":
		serfConfig.MemberlistConfig = memberlist.DefaultLocalConfig()
	default:
		c.Ui.Error(fmt.Sprintf("Unknown profile: %s", config.Profile))
		return nil
	}

	serfConfig.MemberlistConfig.BindAddr = bindIP
	serfConfig.MemberlistConfig.BindPort = bindPort
	serfConfig.MemberlistConfig.AdvertiseAddr = advertiseIP
	serfConfig.MemberlistConfig.AdvertisePort = advertisePort
	serfConfig.MemberlistConfig.SecretKey = encryptKey
	serfConfig.NodeName = config.NodeName
	serfConfig.Tags = config.Tags
	serfConfig.SnapshotPath = config.SnapshotPath
	serfConfig.ProtocolVersion = uint8(config.Protocol)
	serfConfig.CoalescePeriod = 3 * time.Second
	serfConfig.QuiescentPeriod = time.Second
	serfConfig.UserCoalescePeriod = 3 * time.Second
	serfConfig.UserQuiescentPeriod = time.Second

	// Start Serf
	c.Ui.Output("Starting Serf agent...")
	agent, err := Create(serfConfig, logOutput)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to start the Serf agent: %v", err))
		return nil
	}
	return agent
}
Ejemplo n.º 6
0
func (nDB *NetworkDB) clusterInit() error {
	config := memberlist.DefaultLANConfig()
	config.Name = nDB.config.NodeName
	config.BindAddr = nDB.config.BindAddr

	if nDB.config.BindPort != 0 {
		config.BindPort = nDB.config.BindPort
	}

	config.ProtocolVersion = memberlist.ProtocolVersionMax
	config.Delegate = &delegate{nDB: nDB}
	config.Events = &eventDelegate{nDB: nDB}
	config.LogOutput = &logWriter{}

	var err error
	if len(nDB.config.Keys) > 0 {
		for i, key := range nDB.config.Keys {
			logrus.Debugf("Encryption key %d: %s", i+1, hex.EncodeToString(key)[0:5])
		}
		nDB.keyring, err = memberlist.NewKeyring(nDB.config.Keys, nDB.config.Keys[0])
		if err != nil {
			return err
		}
		config.Keyring = nDB.keyring
	}

	nDB.networkBroadcasts = &memberlist.TransmitLimitedQueue{
		NumNodes: func() int {
			return len(nDB.nodes)
		},
		RetransmitMult: config.RetransmitMult,
	}

	mlist, err := memberlist.Create(config)
	if err != nil {
		return fmt.Errorf("failed to create memberlist: %v", err)
	}

	nDB.stopCh = make(chan struct{})
	nDB.memberlist = mlist
	nDB.mConfig = config

	for _, trigger := range []struct {
		interval time.Duration
		fn       func()
	}{
		{reapInterval, nDB.reapState},
		{config.GossipInterval, nDB.gossip},
		{config.PushPullInterval, nDB.bulkSyncTables},
	} {
		t := time.NewTicker(trigger.interval)
		go nDB.triggerFunc(trigger.interval, t.C, nDB.stopCh, trigger.fn)
		nDB.tickers = append(nDB.tickers, t)
	}

	return nil
}
Ejemplo n.º 7
0
func DefaultConfig(name, advertiseAddr string, advertisePort int, seed string, restAPIPort int) *config {
	c := &config{
		seed:         seed,
		restAPIPort:  restAPIPort,
		restAPIProto: "http",
	}
	c.MemberlistConfig = memberlist.DefaultLANConfig()
	c.MemberlistConfig.PushPullInterval = 300 * time.Second
	c.MemberlistConfig.Name = name
	c.MemberlistConfig.BindAddr = advertiseAddr
	c.MemberlistConfig.BindPort = advertisePort
	c.MemberlistConfig.GossipNodes = c.MemberlistConfig.GossipNodes * 2
	return c
}
Ejemplo n.º 8
0
func benchmarkCluster(b *testing.B, num int, timeoutForAllJoins time.Duration, lowestPort int) {
	startTime := time.Now()

	var nodes []*memberlist.Memberlist
	eventC := make(chan memberlist.NodeEvent, num)
	addr := "127.0.0.1"
	var firstMemberName string
	for i := 0; i < num; i++ {
		c := memberlist.DefaultLANConfig()
		port := lowestPort + i
		c.Name = fmt.Sprintf("%s:%d", addr, port)
		c.BindAddr = addr
		c.BindPort = port
		c.ProbeInterval = 20 * time.Millisecond
		c.ProbeTimeout = 100 * time.Millisecond
		c.GossipInterval = 20 * time.Millisecond
		c.PushPullInterval = 200 * time.Millisecond

		c.LogOutput = ioutil.Discard

		if i == 0 {
			c.Events = &memberlist.ChannelEventDelegate{eventC}
			firstMemberName = c.Name
		}

		newMember, err := memberlist.Create(c)
		if err != nil {
			log.WithField("error", err).Fatal("Unexpected error when creating the memberlist")
		}
		nodes = append(nodes, newMember)
		defer newMember.Shutdown()

		if i > 0 {
			numContacted, err := newMember.Join([]string{firstMemberName})
			if numContacted == 0 || err != nil {
				log.WithField("error", err).Fatal("Unexpected fatal error when node wanted to join the cluster")
			}
		}
	}

	if convergence(nodes, num, eventC, timeoutForAllJoins) {
		endTime := time.Now()
		log.WithField("durationSeconds", endTime.Sub(startTime).Seconds()).Info("Cluster convergence reached")
	}

	b.StartTimer()
	sendMessagesInCluster(nodes, b.N)
	b.StopTimer()
}
Ejemplo n.º 9
0
// get the default snapd configuration
func GetDefaultConfig() *Config {
	mlCfg := memberlist.DefaultLANConfig()
	mlCfg.PushPullInterval = defaultPushPullInterval
	mlCfg.GossipNodes = mlCfg.GossipNodes * 2
	return &Config{
		Name:                      getHostname(),
		Enable:                    defaultEnable,
		BindAddr:                  netutil.GetIP(),
		BindPort:                  defaultBindPort,
		Seed:                      defaultSeed,
		MemberlistConfig:          mlCfg,
		RestAPIProto:              defaultRestAPIProto,
		RestAPIPassword:           defaultRestAPIPassword,
		RestAPIPort:               defaultRestAPIPort,
		RestAPIInsecureSkipVerify: defaultRestAPIInsecureSkipVerify,
	}
}
Ejemplo n.º 10
0
func (t *Tracker) setupMemberlist() (err error) {

	conf := memberlist.DefaultLANConfig()
	conf.LogOutput = ioutil.Discard

	conf.Name = fmt.Sprintf("%s:%s", t.cfg.UUID().FullString(), t.iface)

	conf.BindAddr = t.iface
	conf.BindPort = t.port

	conf.Delegate = newDelegate(t.adport, t.cfg)
	conf.Events = t.evtHandler

	t.memberlist, err = memberlist.Create(conf)

	return
}
Ejemplo n.º 11
0
func main() {
	fmt.Println("main A")
	config := memberlist.DefaultLANConfig()
	config.BindAddr = "192.168.50.25"
	list, err := memberlist.Create(config)
	n, err := list.Join([]string{"192.168.50.25"})
	if err != nil {
		panic("Failed to join cluster: " + err.Error())
	}
	log.Println("@n:", n)
	if err != nil {
		panic("Failed to create memberlist: " + err.Error())
	}
	for {
		checkCluster(list)
		time.Sleep(time.Second)
	}
}
Ejemplo n.º 12
0
func NewDistributedEventEmitter(cluster []string, bindAddr string) *DistributedEventEmitter {
	dee := DistributedEventEmitter{}
	c := memberlist.DefaultLANConfig()
	c.Name = bindAddr
	c.BindAddr = bindAddr

	ml, err := memberlist.Create(c)
	dee.ml = ml

	if err != nil {
		panic("Failed to create memberlist: " + err.Error())
	}

	_, err = dee.ml.Join(cluster)
	if err != nil {
		panic("Failed to join cluster: " + err.Error())
	}
	h, err := os.Hostname()
	if err != nil {
		panic("Failed to get hostname" + err.Error())
	}

	fmt.Sprintf(dee.nodeId, "%s:%d", h, os.Getpid())

	dee.listeners = make(map[string][]func([]byte))
	a, err := net.ResolveUDPAddr("udp", mcastAddr)

	if err != nil {
		panic("Error converting mcast addr: " + err.Error())
	}

	dee.sub, err = net.ListenMulticastUDP("udp", nil, a)
	dee.sub.SetReadBuffer(maxDGSize)

	if err != nil {
		panic("Failed listen to UDP mcast: " + err.Error())
	}

	go dee.readLoop(dee.sub)

	return &dee
}
Ejemplo n.º 13
0
// DefaultConfig returns a Config struct that contains reasonable defaults
// for most of the configurations.
func DefaultConfig() *Config {
	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	return &Config{
		NodeName:           hostname,
		BroadcastTimeout:   5 * time.Second,
		EventBuffer:        512,
		LogOutput:          os.Stderr,
		ProtocolVersion:    ProtocolVersionMax,
		ReapInterval:       15 * time.Second,
		RecentIntentBuffer: 128,
		ReconnectInterval:  30 * time.Second,
		ReconnectTimeout:   24 * time.Hour,
		QueueDepthWarning:  128,
		MaxQueueDepth:      4096,
		TombstoneTimeout:   24 * time.Hour,
		MemberlistConfig:   memberlist.DefaultLANConfig(),
	}
}
Ejemplo n.º 14
0
func NewAgent(c *Config) (*Agent, error) {
	var err error

	mlConfig := memberlist.DefaultLANConfig()
	mlConfig.Name = c.Name
	mlConfig.BindAddr, mlConfig.BindPort, err = parseHostPort(c.BindAddr)
	if err != nil {
		return nil, err
	}
	if c.AdvertiseAddr != "" {
		mlConfig.AdvertiseAddr, mlConfig.AdvertisePort, err = parseHostPort(c.AdvertiseAddr)
		if err != nil {
			return nil, err
		}
	} else {
		mlConfig.AdvertiseAddr = mlConfig.BindAddr
		mlConfig.AdvertisePort = mlConfig.BindPort
	}

	agent := &Agent{}
	agent.config = mlConfig

	mlConfig.Delegate = &Delegate{agent}
	ml, err := memberlist.Create(mlConfig)
	if err != nil {
		log.Fatalf("create memberlist: %s", err.Error())
	}

	agent.memberlist = ml
	agent.broadcasts = &memberlist.TransmitLimitedQueue{
		NumNodes: func() int {
			return agent.memberlist.NumMembers()
		},
		RetransmitMult: mlConfig.RetransmitMult,
	}

	return agent, nil
}
Ejemplo n.º 15
0
// setupAgent is used to create the agent we use
func (c *Command) setupAgent(config *Config, logOutput io.Writer) *Agent {
	bindIP, bindPort, err := config.AddrParts(config.BindAddr)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Invalid bind address: %s", err))
		return nil
	}

	// Check if we have an interface
	if iface, _ := config.NetworkInterface(); iface != nil {
		addrs, err := iface.Addrs()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Failed to get interface addresses: %s", err))
			return nil
		}
		if len(addrs) == 0 {
			c.Ui.Error(fmt.Sprintf("Interface '%s' has no addresses", config.Interface))
			return nil
		}

		// If there is no bind IP, pick an address
		if bindIP == "0.0.0.0" {
			found := false
			for _, a := range addrs {
				addr, ok := a.(*net.IPNet)
				if !ok {
					continue
				}
				// Skip self-assigned IPs
				if addr.IP.IsLinkLocalUnicast() {
					continue
				}

				// Found an IP
				found = true
				bindIP = addr.IP.String()
				c.Ui.Output(fmt.Sprintf("Using interface '%s' address '%s'",
					config.Interface, bindIP))

				// Update the configuration
				bindAddr := &net.TCPAddr{
					IP:   net.ParseIP(bindIP),
					Port: bindPort,
				}
				config.BindAddr = bindAddr.String()
				break
			}
			if !found {
				c.Ui.Error(fmt.Sprintf("Failed to find usable address for interface '%s'", config.Interface))
				return nil
			}

		} else {
			// If there is a bind IP, ensure it is available
			found := false
			for _, a := range addrs {
				addr, ok := a.(*net.IPNet)
				if !ok {
					continue
				}
				if addr.IP.String() == bindIP {
					found = true
					break
				}
			}
			if !found {
				c.Ui.Error(fmt.Sprintf("Interface '%s' has no '%s' address",
					config.Interface, bindIP))
				return nil
			}
		}
	}

	var advertiseIP string
	var advertisePort int
	if config.AdvertiseAddr != "" {
		advertiseIP, advertisePort, err = config.AddrParts(config.AdvertiseAddr)
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Invalid advertise address: %s", err))
			return nil
		}
	}

	encryptKey, err := config.EncryptBytes()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Invalid encryption key: %s", err))
		return nil
	}

	serfConfig := serf.DefaultConfig()
	switch config.Profile {
	case "lan":
		serfConfig.MemberlistConfig = memberlist.DefaultLANConfig()
	case "wan":
		serfConfig.MemberlistConfig = memberlist.DefaultWANConfig()
	case "local":
		serfConfig.MemberlistConfig = memberlist.DefaultLocalConfig()
	default:
		c.Ui.Error(fmt.Sprintf("Unknown profile: %s", config.Profile))
		return nil
	}

	serfConfig.MemberlistConfig.BindAddr = bindIP
	serfConfig.MemberlistConfig.BindPort = bindPort
	serfConfig.MemberlistConfig.AdvertiseAddr = advertiseIP
	serfConfig.MemberlistConfig.AdvertisePort = advertisePort
	serfConfig.MemberlistConfig.SecretKey = encryptKey
	serfConfig.NodeName = config.NodeName
	serfConfig.Tags = config.Tags
	serfConfig.SnapshotPath = config.SnapshotPath
	serfConfig.ProtocolVersion = uint8(config.Protocol)
	serfConfig.CoalescePeriod = 3 * time.Second
	serfConfig.QuiescentPeriod = time.Second
	serfConfig.UserCoalescePeriod = 3 * time.Second
	serfConfig.UserQuiescentPeriod = time.Second
	if config.ReconnectInterval != 0 {
		serfConfig.ReconnectInterval = config.ReconnectInterval
	}
	if config.ReconnectTimeout != 0 {
		serfConfig.ReconnectTimeout = config.ReconnectTimeout
	}
	if config.TombstoneTimeout != 0 {
		serfConfig.TombstoneTimeout = config.TombstoneTimeout
	}
	serfConfig.EnableNameConflictResolution = !config.DisableNameResolution
	if config.KeyringFile != "" {
		serfConfig.KeyringFile = config.KeyringFile
	}
	serfConfig.RejoinAfterLeave = config.RejoinAfterLeave

	// Start Serf
	c.Ui.Output("Starting Serf agent...")
	agent, err := Create(config, serfConfig, logOutput)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to start the Serf agent: %v", err))
		return nil
	}
	return agent
}
Ejemplo n.º 16
0
func New(cfg *Config) (*tribe, error) {
	cfg.MemberlistConfig.Name = cfg.Name
	cfg.MemberlistConfig.BindAddr = cfg.BindAddr
	cfg.MemberlistConfig.BindPort = cfg.BindPort
	logger := logger.WithFields(log.Fields{
		"port": cfg.MemberlistConfig.BindPort,
		"addr": cfg.MemberlistConfig.BindAddr,
		"name": cfg.MemberlistConfig.Name,
	})

	tribe := &tribe{
		agreements:         map[string]*agreement.Agreement{},
		members:            map[string]*agreement.Member{},
		taskStateResponses: map[string]*taskStateQueryResponse{},
		taskStartStopCache: newCache(),
		msgBuffer:          make([]msg, 512),
		intentBuffer:       []msg{},
		logger:             logger.WithField("_name", cfg.MemberlistConfig.Name),
		tags: map[string]string{
			agreement.RestPort:               strconv.Itoa(cfg.RestAPIPort),
			agreement.RestProtocol:           cfg.RestAPIProto,
			agreement.RestInsecureSkipVerify: cfg.RestAPIInsecureSkipVerify,
		},
		pluginWorkQueue: make(chan worker.PluginRequest, 999),
		taskWorkQueue:   make(chan worker.TaskRequest, 999),
		workerQuitChan:  make(chan struct{}),
		workerWaitGroup: &sync.WaitGroup{},
		config:          cfg,
		EventManager:    gomit.NewEventController(),
	}

	tribe.broadcasts = &memberlist.TransmitLimitedQueue{
		NumNodes: func() int {
			return len(tribe.memberlist.Members())
		},
		RetransmitMult: memberlist.DefaultLANConfig().RetransmitMult,
	}

	//configure delegates
	cfg.MemberlistConfig.Delegate = &delegate{tribe: tribe}
	cfg.MemberlistConfig.Events = &memberDelegate{tribe: tribe}

	ml, err := memberlist.Create(cfg.MemberlistConfig)
	if err != nil {
		logger.Error(err)
		return nil, err
	}
	tribe.memberlist = ml

	if cfg.Seed != "" {
		_, err := ml.Join([]string{cfg.Seed})
		if err != nil {
			logger.WithFields(log.Fields{
				"seed": cfg.Seed,
			}).Error(errMemberlistJoin)
			return nil, errMemberlistJoin
		}
		logger.WithFields(log.Fields{
			"seed": cfg.Seed,
		}).Infoln("tribe started")
		return tribe, nil
	}
	logger.WithFields(log.Fields{
		"seed": "none",
	}).Infoln("tribe started")
	return tribe, nil
}
Ejemplo n.º 17
0
// DefaultConfig provides a basic configuration based on memberlist.DefaultLANConfig()
func DefaultConfig() Config {
	return Config{memberlist.DefaultLANConfig()}
}
Ejemplo n.º 18
0
// setupAgent is used to create the agent we use
func (a *AgentCommand) setupSerf(config *Config) *serf.Serf {
	bindIP, bindPort, err := config.AddrParts(config.BindAddr)
	if err != nil {
		a.Ui.Error(fmt.Sprintf("Invalid bind address: %s", err))
		return nil
	}

	// Check if we have an interface
	if iface, _ := config.NetworkInterface(); iface != nil {
		addrs, err := iface.Addrs()
		if err != nil {
			a.Ui.Error(fmt.Sprintf("Failed to get interface addresses: %s", err))
			return nil
		}
		if len(addrs) == 0 {
			a.Ui.Error(fmt.Sprintf("Interface '%s' has no addresses", config.Interface))
			return nil
		}

		// If there is no bind IP, pick an address
		if bindIP == "0.0.0.0" {
			found := false
			for _, ad := range addrs {
				var addrIP net.IP
				if runtime.GOOS == "windows" {
					// Waiting for https://github.com/golang/go/issues/5395 to use IPNet only
					addr, ok := ad.(*net.IPAddr)
					if !ok {
						continue
					}
					addrIP = addr.IP
				} else {
					addr, ok := ad.(*net.IPNet)
					if !ok {
						continue
					}
					addrIP = addr.IP
				}

				// Skip self-assigned IPs
				if addrIP.IsLinkLocalUnicast() {
					continue
				}

				// Found an IP
				found = true
				bindIP = addrIP.String()
				a.Ui.Output(fmt.Sprintf("Using interface '%s' address '%s'",
					config.Interface, bindIP))

				// Update the configuration
				bindAddr := &net.TCPAddr{
					IP:   net.ParseIP(bindIP),
					Port: bindPort,
				}
				config.BindAddr = bindAddr.String()
				break
			}
			if !found {
				a.Ui.Error(fmt.Sprintf("Failed to find usable address for interface '%s'", config.Interface))
				return nil
			}

		} else {
			// If there is a bind IP, ensure it is available
			found := false
			for _, a := range addrs {
				addr, ok := a.(*net.IPNet)
				if !ok {
					continue
				}
				if addr.IP.String() == bindIP {
					found = true
					break
				}
			}
			if !found {
				a.Ui.Error(fmt.Sprintf("Interface '%s' has no '%s' address",
					config.Interface, bindIP))
				return nil
			}
		}
	}

	var advertiseIP string
	var advertisePort int
	if config.AdvertiseAddr != "" {
		advertiseIP, advertisePort, err = config.AddrParts(config.AdvertiseAddr)
		if err != nil {
			a.Ui.Error(fmt.Sprintf("Invalid advertise address: %s", err))
			return nil
		}
	}

	encryptKey, err := config.EncryptBytes()
	if err != nil {
		a.Ui.Error(fmt.Sprintf("Invalid encryption key: %s", err))
		return nil
	}

	serfConfig := serf.DefaultConfig()
	switch config.Profile {
	case "lan":
		serfConfig.MemberlistConfig = memberlist.DefaultLANConfig()
	case "wan":
		serfConfig.MemberlistConfig = memberlist.DefaultWANConfig()
	case "local":
		serfConfig.MemberlistConfig = memberlist.DefaultLocalConfig()
	default:
		a.Ui.Error(fmt.Sprintf("Unknown profile: %s", config.Profile))
		return nil
	}

	serfConfig.MemberlistConfig.BindAddr = bindIP
	serfConfig.MemberlistConfig.BindPort = bindPort
	serfConfig.MemberlistConfig.AdvertiseAddr = advertiseIP
	serfConfig.MemberlistConfig.AdvertisePort = advertisePort
	serfConfig.MemberlistConfig.SecretKey = encryptKey
	serfConfig.NodeName = config.NodeName
	serfConfig.Tags = config.Tags
	serfConfig.SnapshotPath = config.SnapshotPath
	serfConfig.CoalescePeriod = 3 * time.Second
	serfConfig.QuiescentPeriod = time.Second
	serfConfig.UserCoalescePeriod = 3 * time.Second
	serfConfig.UserQuiescentPeriod = time.Second
	if config.ReconnectInterval != 0 {
		serfConfig.ReconnectInterval = config.ReconnectInterval
	}
	if config.ReconnectTimeout != 0 {
		serfConfig.ReconnectTimeout = config.ReconnectTimeout
	}
	if config.TombstoneTimeout != 0 {
		serfConfig.TombstoneTimeout = config.TombstoneTimeout
	}
	serfConfig.EnableNameConflictResolution = !config.DisableNameResolution
	if config.KeyringFile != "" {
		serfConfig.KeyringFile = config.KeyringFile
	}
	serfConfig.RejoinAfterLeave = config.RejoinAfterLeave

	// Create a channel to listen for events from Serf
	a.eventCh = make(chan serf.Event, 64)
	serfConfig.EventCh = a.eventCh

	// Start Serf
	a.Ui.Output("Starting Serf agent...")
	log.Info("agent: Serf agent starting")

	serfConfig.LogOutput = ioutil.Discard
	serfConfig.MemberlistConfig.LogOutput = ioutil.Discard

	// Create serf first
	serf, err := serf.Create(serfConfig)
	if err != nil {
		a.Ui.Error(err.Error())
		log.Error(err)
		return nil
	}

	return serf
}
Ejemplo n.º 19
0
func main() {
	log.SetFlags(0)
	log.SetPrefix("gossipchat: ")

	port := flag.Int("port", 0, "port on which to listen")
	nick := flag.String("nick", "", "nickname to use on the chat")
	peersCSL := flag.String("peers", "", "comma separated list of addresses where peers can be found")
	flag.Parse()

	if *nick == "" {
		log.Fatal("you need to provice a -nick")
	}

	peers, err := parsePeers(*peersCSL)
	if err != nil {
		log.Fatalf("invalid value for flag -peers. %v", err)
	}

	var (
		msgc    <-chan []message
		memberc <-chan []string

		chatc = make(chan message, 1)
	)
	delegate, msgc := newDelegate(100, chatc)

	conf := memberlist.DefaultLANConfig()
	conf.LogOutput = ioutil.Discard
	conf.BindPort = *port
	conf.Name = *nick
	conf.Delegate = delegate
	conf.Events, memberc = newEvents()
	conf.Conflict = newConflicts()
	conf.PushPullInterval = time.Second
	mlist, err := memberlist.Create(conf)
	if err != nil {
		log.Fatalf("can't create memberlist: %v", err)
	}
	log.SetPrefix(mlist.LocalNode().Name + ": ")
	delegate.queue.NumNodes = mlist.NumMembers

	count, err := mlist.Join(peers)
	if err != nil {
		log.Printf("can't join peers: %v", err)
	}
	log.Printf("joined %d peers", count)

	log.Printf("we are reachable at %q", fmt.Sprintf("%s:%d",
		mlist.LocalNode().Addr, mlist.LocalNode().Port))
	name := mlist.LocalNode().Name

	ctx, cancel := context.WithCancel(context.Background())

	go func() {
		defer cancel()
		uichatc, err := runUI(ctx, name, memberc, msgc)
		if err != nil {
			log.Printf("can't start UI: %v", err)
			return
		}
		for chatmsg := range uichatc {
			select {
			case chatc <- chatmsg:
			case <-ctx.Done():
				return
			}
		}
		log.Printf("stopped UI")
	}()

	<-ctx.Done()

	if err := mlist.Leave(leaveTimeout); err != nil {
		log.Printf("could not announce leave: %v", err)
	}
	if err := mlist.Shutdown(); err != nil {
		log.Printf("could not shutdown cleanly: %v", err)
	}
}
Ejemplo n.º 20
0
func benchmarkCluster(b *testing.B, num int, timeoutForAllJoins time.Duration, lowestPort int) {
	log.WithField("num", b.N).Fatal("Unexpected error when creating the memberlist")

	startTime := time.Now()

	var nodes []*memberlist.Memberlist
	eventC := make(chan memberlist.NodeEvent, num)
	addr := "127.0.0.1"
	var firstMemberName string
	for i := 0; i < num; i++ {
		c := memberlist.DefaultLANConfig()
		port := lowestPort + i
		c.Name = fmt.Sprintf("%s:%d", addr, port)
		c.BindAddr = addr
		c.BindPort = port
		c.ProbeInterval = 20 * time.Millisecond
		c.ProbeTimeout = 100 * time.Millisecond
		c.GossipInterval = 20 * time.Millisecond
		c.PushPullInterval = 200 * time.Millisecond

		c.LogOutput = ioutil.Discard

		if i == 0 {
			c.Events = &memberlist.ChannelEventDelegate{eventC}
			firstMemberName = c.Name
		}

		newMember, err := memberlist.Create(c)
		if err != nil {
			log.WithField("error", err).Fatal("Unexpected error when creating the memberlist")
		}
		nodes = append(nodes, newMember)
		defer newMember.Shutdown()

		if i >= 0 {
			num, err := newMember.Join([]string{firstMemberName})
			if num == 0 || err != nil {
				log.WithField("error", err).Fatal("Unexpected fatal error when node wanted to join the cluster")
			}
		}
	}

	breakTimer := time.After(timeoutForAllJoins)
	numJoins := 0
WAIT:
	for {
		select {
		case e := <-eventC:
			l := log.WithFields(log.Fields{
				"node":       *e.Node,
				"numJoins":   numJoins,
				"numMembers": nodes[0].NumMembers(),
			})
			if e.Event == memberlist.NodeJoin {
				l.Info("Node join")
				numJoins++
				if numJoins == num {
					l.Info("All nodes joined")
					break WAIT
				}
			} else {
				l.Info("Node leave")
			}
		case <-breakTimer:
			break WAIT
		}
	}

	if numJoins != num {
		log.WithFields(log.Fields{
			"joinCounter": numJoins,
			"num":         num,
		}).Error("Timeout before completing all joins")
	}

	convergence := false
	for !convergence {
		convergence = true
		for idx, node := range nodes {
			numSeenByNode := node.NumMembers()
			if numSeenByNode != num {
				log.WithFields(log.Fields{
					"index":    idx,
					"expected": num,
					"actual":   numSeenByNode,
				}).Debug("Wrong number of nodes")
				convergence = false
				break
			}
		}
	}
	endTime := time.Now()
	if numJoins == num {
		log.WithField("durationSeconds", endTime.Sub(startTime).Seconds()).Info("Cluster convergence reached")
	}

	b.StartTimer()

	for senderID, node := range nodes {
		for receiverID, member := range node.Members() {
			for i := 0; i < b.N; i++ {
				message := fmt.Sprintf("Hello from %v to %v !", senderID, receiverID)
				log.WithField("message", message).Debug("SendToTCP")
				node.SendToTCP(member, []byte(message))
			}
		}
	}

	b.StopTimer()
}
Ejemplo n.º 21
0
func (nDB *NetworkDB) clusterInit() error {
	config := memberlist.DefaultLANConfig()
	config.Name = nDB.config.NodeName
	config.BindAddr = nDB.config.BindAddr
	config.AdvertiseAddr = nDB.config.AdvertiseAddr

	if nDB.config.BindPort != 0 {
		config.BindPort = nDB.config.BindPort
	}

	config.ProtocolVersion = memberlist.ProtocolVersionMax
	config.Delegate = &delegate{nDB: nDB}
	config.Events = &eventDelegate{nDB: nDB}
	// custom logger that does not add time or date, so they are not
	// duplicated by logrus
	config.Logger = log.New(&logWriter{}, "", 0)

	var err error
	if len(nDB.config.Keys) > 0 {
		for i, key := range nDB.config.Keys {
			logrus.Debugf("Encryption key %d: %s", i+1, hex.EncodeToString(key)[0:5])
		}
		nDB.keyring, err = memberlist.NewKeyring(nDB.config.Keys, nDB.config.Keys[0])
		if err != nil {
			return err
		}
		config.Keyring = nDB.keyring
	}

	nDB.networkBroadcasts = &memberlist.TransmitLimitedQueue{
		NumNodes: func() int {
			nDB.RLock()
			num := len(nDB.nodes)
			nDB.RUnlock()
			return num
		},
		RetransmitMult: config.RetransmitMult,
	}

	nDB.nodeBroadcasts = &memberlist.TransmitLimitedQueue{
		NumNodes: func() int {
			nDB.RLock()
			num := len(nDB.nodes)
			nDB.RUnlock()
			return num
		},
		RetransmitMult: config.RetransmitMult,
	}

	mlist, err := memberlist.Create(config)
	if err != nil {
		return fmt.Errorf("failed to create memberlist: %v", err)
	}

	nDB.stopCh = make(chan struct{})
	nDB.memberlist = mlist

	for _, trigger := range []struct {
		interval time.Duration
		fn       func()
	}{
		{reapPeriod, nDB.reapState},
		{config.GossipInterval, nDB.gossip},
		{config.PushPullInterval, nDB.bulkSyncTables},
		{retryInterval, nDB.reconnectNode},
		{nodeReapPeriod, nDB.reapDeadNode},
	} {
		t := time.NewTicker(trigger.interval)
		go nDB.triggerFunc(trigger.interval, t.C, nDB.stopCh, trigger.fn)
		nDB.tickers = append(nDB.tickers, t)
	}

	return nil
}
Ejemplo n.º 22
0
// NewClusterBind creates a new Cluster while allowing for
// specification of the address/port to bind to, the address/port to
// advertize to the other nodes (use zero values for default) as well
// as the hostname. (This is useful if your app is running in a Docker
// container where it is impossible to figure out the outside IP
// addresses and the hostname can be the same).
func NewClusterBind(baddr string, bport int, aaddr string, aport int, rpcport int, name string) (*Cluster, error) {
	c := &Cluster{
		rcvChs:    make([]chan *Msg, 0),
		chgNotify: make([]chan bool, 0),
		dds:       make(map[string]*ddEntry),
		copies:    1,
		ncache:    make(map[*memberlist.Node]*Node),
	}
	cfg := memberlist.DefaultLANConfig()
	cfg.TCPTimeout = 30 * time.Second
	cfg.SuspicionMult = 6
	cfg.PushPullInterval = 15 * time.Second

	if baddr != "" {
		cfg.BindAddr = baddr
	}
	if bport != 0 {
		cfg.BindPort = bport
	}
	if aaddr != "" {
		cfg.AdvertiseAddr = aaddr
	}
	if aport != 0 {
		cfg.AdvertisePort = aport
	}
	if name != "" {
		cfg.Name = name
	}
	cfg.LogOutput = &logger{}
	cfg.Delegate, cfg.Events = c, c
	var err error
	if c.Memberlist, err = memberlist.Create(cfg); err != nil {
		return nil, err
	}
	md := &nodeMeta{sortBy: startTime.UnixNano()}
	c.saveMeta(md)
	if err = c.UpdateNode(updateNodeTO); err != nil {
		log.Printf("NewClusterBind(): UpdateNode() failed: %v", err)
		return nil, err
	}

	if rpcport == 0 {
		c.rpcPort = 12354
	} else {
		c.rpcPort = rpcport
	}

	c.snd, c.rcv = c.RegisterMsgType()

	rpc.Register(&ClusterRPC{c})
	if c.rpc, err = net.Listen("tcp", fmt.Sprintf("%s:%d", baddr, c.rpcPort)); err != nil {
		return nil, err
	}

	// Serve RPC Requests
	go func() {
		for {
			rpc.Accept(c.rpc)
		}
	}()

	return c, nil
}