func (flipper *HAProxyFlipperClient) Orchestrate(switchEvent types.MasterSwitchedEvent) {

	flipper.lock.Lock()
	defer flipper.lock.Unlock()

	logger.NoteWorthy.Printf("Redis cluster {%s} master failover detected from {%s}:{%d} to {%s}:{%d}.", switchEvent.Name, switchEvent.OldMasterIp, switchEvent.OldMasterPort, switchEvent.NewMasterIp, switchEvent.NewMasterPort)
	logger.NoteWorthy.Printf("Master Switched : %s", util.String(switchEvent))

	configuration := flipper.configurationManager.GetCurrentConfiguration()
	logger.Info.Printf("Current Configuration : %s", util.String(configuration.Clusters))

	cluster, err := configuration.FindClusterByName(switchEvent.Name)

	if err != nil {
		logger.Error.Printf("Redis cluster called %s not found in configuration.", switchEvent.Name)
		return
	}

	logger.Info.Printf("Cluster found : %s", util.String(cluster))

	detail := &types.MasterDetails{
		ExternalPort: cluster.ExternalPort,
		Name:         switchEvent.Name,
		Ip:           switchEvent.NewMasterIp,
		Port:         switchEvent.NewMasterPort}

	flipper.state.AddOrReplace(detail)

	flipper.renderAndReload(configuration, flipper.state)
}
func (c *ConsulFlipperClient) InitialiseRunningState(state *types.MasterDetailsCollection) {

	logger.Info.Printf("InitialiseRunningState called : %s", util.String(state.Items()))
	for _, md := range state.Items() {
		c.UpdateConsul(md.Name, md.Ip, md.Port)
	}
}
func TestCanMarkSentinelsDown(t *testing.T) {

	state := NewSentinelState(func(_ types.Sentinel) {})
	sentinel := types.Sentinel{Host: "10.1.1.2", Port: 12345}

	sentinelAddedMessage := &SentinelAdded{Sentinel: sentinel}
	sentinelLostMessage := &SentinelLost{Sentinel: sentinel}

	responseChannel := make(chan SentinelTopology)

	state.Notify(sentinelAddedMessage)
	state.Notify(sentinelLostMessage)

	state.GetState(TopologyRequest{ReplyChannel: responseChannel})
	topologyState := <-responseChannel
	fmt.Print(util.String(topologyState))

	if len(topologyState.Sentinels) != 1 {
		t.Error("Topology count should be 1")
	}

	sen, _ := topologyState.FindSentinelInfo(sentinel)

	if sen.SentinelLocation != sentinel.GetLocation() {
		t.Error("Wrong host found")
	}

	if sen.State != SentinelMarkedDown {
		t.Errorf("Sentinel in wrong state : %d", sen.State)
	}
}
func TestSerialisationOnNewMasterDetailsCollection(t *testing.T) {

	collection := NewMasterDetailsCollection()

	detail1 := &MasterDetails{ExternalPort: 1111, Name: "a", Ip: "1.1.1.1.", Port: 2222}
	detail2 := &MasterDetails{ExternalPort: 2222, Name: "b", Ip: "2.2.2.2.", Port: 3333}
	detail3 := &MasterDetails{ExternalPort: 2222, Name: "c", Ip: "2.2.2.2.", Port: 3333}

	collection.AddOrReplace(detail3)
	collection.AddOrReplace(detail2)
	collection.AddOrReplace(detail1)

	json := util.String(collection.Items())

	if json == "{}" {
		t.Errorf("Json should not be empty : %s", json)
	}
}
func renderTemplate(details *types.MasterDetailsCollection, outputPath string, templatepath string) (bool, error) {

	logger.Info.Printf("Details %s", util.String(details.Items()))
	renderedTemplate, err := template.RenderTemplate(templatepath, details)

	if err != nil {
		logger.Error.Printf("Error rendering tempate at %s.", templatepath)
		return false, err
	}

	if util.FileExists(outputPath) {
		newFileHash := util.HashString(renderedTemplate)
		oldFileHash, err := util.HashFile(outputPath)

		if err != nil {
			logger.Error.Printf("Error hashing existing HAProxy config file at %s.", outputPath)
			return false, err
		}

		if newFileHash == oldFileHash {
			logger.NoteWorthy.Printf("Existing config file up todate. New file hash : %s == Old file hash %s. Nothing to do.", newFileHash, oldFileHash)
			return true, nil
		}

		logger.Info.Printf("Updating config file. New file hash : %s != Old file hash %s", newFileHash, oldFileHash)
	}

	err = util.WriteFile(outputPath, renderedTemplate)

	if err != nil {
		logger.Error.Printf("Error writing file to %s : %s\n", outputPath, err.Error())
		return false, err
	}

	return true, nil
}
func (c *ConsulFlipperClient) Orchestrate(switchEvent types.MasterSwitchedEvent) {

	logger.NoteWorthy.Printf("Redis master changed : %s", util.String(switchEvent))
	c.UpdateConsul(switchEvent.Name, switchEvent.NewMasterIp, switchEvent.NewMasterPort)

}
func (*NoOpFlipperClient) Orchestrate(switchEvent types.MasterSwitchedEvent) {
	logger.NoteWorthy.Printf("Orchestrate called : %s", util.String(switchEvent))
}
func (*NoOpFlipperClient) InitialiseRunningState(state *types.MasterDetailsCollection) {
	logger.NoteWorthy.Printf("InitialiseRunningState called : %s", util.String(state.Items()))
}
func (s SentinelState) updateState(event interface{}) {

	switch e := event.(type) {
	case *SentinelAdded:

		sentinel := e.GetSentinel()
		uid := s.state.createKey(sentinel)

		//if we don't know about the sentinel start monitoring it
		if _, exists := s.state.Sentinels[uid]; !exists {

			info := &SentinelInfo{SentinelLocation: uid,
				LastUpdated: time.Now().UTC(),
				State:       SentinelMarkedUp}

			s.state.Sentinels[uid] = info

			go s.startMonitoringSentinel(sentinel)

			logger.Trace.Printf("Sentinel added : %s", util.String(sentinel))
		}

	case *SentinelLost:

		sentinel := e.GetSentinel()
		uid := s.state.createKey(sentinel)
		currentInfo, ok := s.state.Sentinels[uid]

		if ok {

			currentInfo.LastUpdated = time.Now().UTC()

			if currentInfo.State != SentinelMarkedDown {

				currentInfo.State = SentinelMarkedDown
				util.Schedule(func() { go s.startMonitoringSentinel(sentinel) }, SentinelReconnectionPeriod)
				logger.Trace.Printf("Sentinel lost : %s", util.String(sentinel))
				logger.Trace.Printf("Sentinel state : %s", util.String(s.state))
			}

		} else {
			logger.Trace.Printf("Unknown sentinel lost : %s.", util.String(sentinel))
		}

	case *SentinelPing:
		sentinel := e.GetSentinel()
		uid := s.state.createKey(sentinel)
		currentInfo, exists := s.state.Sentinels[uid]

		if exists {

			if currentInfo.State != SentinelMarkedAlive {
				currentInfo.State = SentinelMarkedAlive
				logger.Trace.Printf("Sentinel ping : %s", util.String(sentinel))
				logger.Trace.Printf("Sentinel state : %s.", util.String(s.state))
			}
			currentInfo.LastUpdated = time.Now().UTC()
		} else {
			logger.Trace.Printf("Unknown sentinel ping : %s.", util.String(sentinel))
		}

	case *SentinelUnknown:

		sentinel := e.GetSentinel()
		uid := s.state.createKey(sentinel)
		currentInfo, exists := s.state.Sentinels[uid]

		if exists {
			currentInfo.State = SentinelMarkedUnknown
			currentInfo.LastUpdated = time.Now().UTC()
		} else {
			logger.Trace.Printf("Unknown sentinel unknown{*} : %s.", util.String(sentinel))
		}

	case *SentinelClustersMonitoredUpdate:
		sentinel := e.GetSentinel()
		uid := s.state.createKey(sentinel)

		if info, exists := s.state.Sentinels[uid]; exists {

			info.Clusters = e.Clusters
		} else {
			logger.Trace.Printf("Unknown sentinel updated state : %s.", util.String(sentinel))
		}

	default:
		logger.Error.Println("Unknown sentinel event : ", util.String(e))
	}
}