예제 #1
0
func (s *DSNTestSuite) TestHideDSNPassword(t *C) {
	dsn := "user:pass@tcp/"
	t.Check(mysql.HideDSNPassword(dsn), Equals, "user:"******"@tcp/")
	dsn = "percona-agent:0xabd123def@tcp(host.example.com:3306)/?parseTime=true"
	t.Check(mysql.HideDSNPassword(dsn), Equals, "percona-agent:"+mysql.HiddenPassword+"@tcp(host.example.com:3306)/?parseTime=true")
	dsn = ""
	t.Check(mysql.HideDSNPassword(dsn), Equals, ":"+mysql.HiddenPassword+"@")
}
예제 #2
0
func (m *Monitor) createMysqlInstance(dsn string) (mi *MysqlInstance, err error) {
	m.logger.Debug("createMysqlInstance:call:" + mysql.HideDSNPassword(dsn))
	defer m.logger.Debug("createMysqlInstance:return:" + mysql.HideDSNPassword(dsn))

	mysqlConn := m.mysqlConnFactory.Make(dsn)
	// todo: fix
	logger := pct.NewLogger(m.logger.LogChan(), "mrms-monitor-mysql")
	subscribers := NewSubscribers(logger)
	return NewMysqlInstance(logger, mysqlConn, subscribers)
}
예제 #3
0
func (m *Monitor) Remove(dsn string, c <-chan bool) {
	m.logger.Debug("Remove:call:" + mysql.HideDSNPassword(dsn))
	defer m.logger.Debug("Remove:return:" + mysql.HideDSNPassword(dsn))

	m.Lock()
	defer m.Unlock()

	if mysqlInstance, ok := m.mysqlInstances[dsn]; ok {
		mysqlInstance.Subscribers.Remove(c)
		if mysqlInstance.Subscribers.Empty() {
			delete(m.mysqlInstances, dsn)
		}
		mysqlInstance.Subscribers.GlobalRemove(dsn)
	}
}
예제 #4
0
// @goroutine[0]
func (m *Manager) Start() error {
	m.status.Update("instance", "Starting")
	if err := m.repo.Init(); err != nil {
		return err
	}
	m.logger.Info("Started")
	m.status.Update("instance", "Running")

	mrmsGlobalChan, err := m.mrm.GlobalSubscribe()
	if err != nil {
		return err
	}

	for _, instance := range m.GetMySQLInstances() {
		ch, err := m.mrm.Add(instance.DSN)
		if err != nil {
			m.logger.Error("Cannot add instance to the monitor:", err)
			continue
		}
		safeDSN := mysql.HideDSNPassword(instance.DSN)
		m.status.Update("instance", "Getting info "+safeDSN)
		if err := GetMySQLInfo(instance); err != nil {
			m.logger.Warn(fmt.Sprintf("Failed to get MySQL info %s: %s", safeDSN, err))
			continue
		}
		m.status.Update("instance", "Updating info "+safeDSN)
		m.pushInstanceInfo(instance)
		// Store the channel to be able to remove it from mrms
		m.mrmChans[instance.DSN] = ch
	}
	go m.monitorInstancesRestart(mrmsGlobalChan)
	return nil
}
예제 #5
0
func (m *Monitor) Add(dsn string) (c <-chan bool, err error) {
	m.logger.Debug("Add:call:" + mysql.HideDSNPassword(dsn))
	defer m.logger.Debug("Add:return:" + mysql.HideDSNPassword(dsn))

	m.Lock()
	defer m.Unlock()

	mysqlInstance, ok := m.mysqlInstances[dsn]
	if !ok {
		mysqlInstance, err = m.createMysqlInstance(dsn)
		if err != nil {
			return nil, err
		}
		m.mysqlInstances[dsn] = mysqlInstance
	}

	c = mysqlInstance.Subscribers.Add()
	return c, nil
}
예제 #6
0
func (m *Manager) monitorInstancesRestart(ch chan string) {
	m.logger.Debug("monitorInstancesRestart:call")
	defer func() {
		if err := recover(); err != nil {
			m.logger.Error("MySQL connection crashed: ", err)
			m.status.Update("instance-mrms", "Crashed")
		} else {
			m.status.Update("instance-mrms", "Stopped")
		}
		m.logger.Debug("monitorInstancesRestart:return")
	}()

	ch, err := m.mrm.GlobalSubscribe()
	if err != nil {
		m.logger.Error(fmt.Sprintf("Failed to get MySQL restart monitor global channel: %s", err))
		return
	}

	for {
		m.status.Update("instance-mrms", "Idle")
		select {
		case dsn := <-ch:
			safeDSN := mysql.HideDSNPassword(dsn)
			m.logger.Debug("mrms:restart:" + safeDSN)
			m.status.Update("instance-mrms", "Updating "+safeDSN)

			// Get the updated instances list. It should be updated every time since
			// the Add method can add new instances to the list.
			for _, instance := range m.GetMySQLInstances() {
				if instance.DSN != dsn {
					continue
				}
				m.status.Update("instance-mrms", "Getting info "+safeDSN)
				if err := GetMySQLInfo(instance); err != nil {
					m.logger.Warn(fmt.Sprintf("Failed to get MySQL info %s: %s", safeDSN, err))
					break
				}
				m.status.Update("instance-mrms", "Updating info "+safeDSN)
				err := m.pushInstanceInfo(instance)
				if err != nil {
					m.logger.Warn(err)
				}
				break
			}
		}
	}
}
예제 #7
0
func (m *Monitor) Check() {
	m.logger.Debug("Check:call")
	defer m.logger.Debug("Check:return")

	m.RLock()
	defer m.RUnlock()

	for _, mysqlInstance := range m.mysqlInstances {
		wasRestarted, err := mysqlInstance.CheckIfMysqlRestarted()
		if err != nil {
			m.logger.Error(err)
			continue
		}
		if wasRestarted {
			m.logger.Debug("Check:restarted:" + mysql.HideDSNPassword(mysqlInstance.DSN()))
			mysqlInstance.Subscribers.Notify()
		}
	}
}
예제 #8
0
// @goroutine[0]
func (m *Manager) Handle(cmd *proto.Cmd) *proto.Reply {
	m.status.UpdateRe("instance", "Handling", cmd)
	defer m.status.Update("instance", "Running")

	it := &proto.ServiceInstance{}
	if err := json.Unmarshal(cmd.Data, it); err != nil {
		return cmd.Reply(nil, err)
	}

	switch cmd.Cmd {
	case "Add":
		err := m.repo.Add(it.Service, it.InstanceId, it.Instance, true) // true = write to disk
		if err != nil {
			return cmd.Reply(nil, err)
		}
		if it.Service == "mysql" {
			// Get the instance as type proto.MySQLInstance instead of proto.ServiceInstance
			// because we need the dsn field
			// We only return errors for repo.Add, not for mrm so all returns within this block
			// will return nil, nil
			iit := &proto.MySQLInstance{}
			err := m.repo.Get(it.Service, it.InstanceId, iit)
			if err != nil {
				m.logger.Error(err)
				return cmd.Reply(nil, nil)
			}
			ch, err := m.mrm.Add(iit.DSN)
			if err != nil {
				m.logger.Error(err)
				return cmd.Reply(nil, nil)
			}
			m.mrmChans[iit.DSN] = ch

			safeDSN := mysql.HideDSNPassword(iit.DSN)
			m.status.Update("instance", "Getting info "+safeDSN)
			if err := GetMySQLInfo(iit); err != nil {
				m.logger.Warn(fmt.Sprintf("Failed to get MySQL info %s: %s", safeDSN, err))
				return cmd.Reply(nil, nil)
			}

			m.status.Update("instance", "Updating info "+safeDSN)
			err = m.pushInstanceInfo(iit)
			if err != nil {
				m.logger.Error(err)
				return cmd.Reply(nil, nil)
			}
		}
		return cmd.Reply(nil, nil)
	case "Remove":
		if it.Service == "mysql" {
			// Get the instance as type proto.MySQLInstance instead of proto.ServiceInstance
			// because we need the dsn field
			iit := &proto.MySQLInstance{}
			err := m.repo.Get(it.Service, it.InstanceId, iit)
			// Don't return an error. This is just a remove from mrms
			if err != nil {
				m.logger.Error(err)
			} else {
				m.mrm.Remove(iit.DSN, m.mrmChans[iit.DSN])
			}
		}
		err := m.repo.Remove(it.Service, it.InstanceId)
		return cmd.Reply(nil, err)
	case "GetInfo":
		info, err := m.handleGetInfo(it.Service, it.Instance)
		return cmd.Reply(info, err)
	default:
		return cmd.Reply(nil, pct.UnknownCmdError{Cmd: cmd.Cmd})
	}
}