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+"@") }
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) }
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) } }
// @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 }
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 }
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 } } } }
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() } } }
// @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}) } }