func (s *RepoTestSuite) TestInit(t *C) {
	im := instance.NewRepo(s.logger, s.configDir, s.api)
	t.Assert(im, NotNil)

	err := im.Init()
	t.Check(err, IsNil)

	err = test.CopyFile(test.RootDir+"/mm/config/mysql-1.conf", s.configDir)
	t.Assert(err, IsNil)

	err = im.Init()
	t.Assert(err, IsNil)

	mysqlIt := &proto.MySQLInstance{}
	err = im.Get("mysql", 1, mysqlIt)
	t.Assert(err, IsNil)
	expect := &proto.MySQLInstance{
		Id:       1,
		Hostname: "db1",
		DSN:      "user:host@tcp:(127.0.0.1:3306)",
		Distro:   "Percona Server",
		Version:  "5.6.16",
	}

	if same, diff := test.IsDeeply(mysqlIt, expect); !same {
		test.Dump(mysqlIt)
		test.Dump(expect)
		t.Error(diff)
	}
}
Example #2
0
func (s *ManagerTestSuite) SetUpSuite(t *C) {
	s.dsn = os.Getenv("PCT_TEST_MYSQL_DSN")
	if s.dsn == "" {
		t.Fatal("PCT_TEST_MYSQL_DSN is not set")
	}

	s.logChan = make(chan *proto.LogEntry, 10)
	s.logger = pct.NewLogger(s.logChan, query.SERVICE_NAME+"-manager-test")

	var err error
	s.tmpDir, err = ioutil.TempDir("/tmp", "agent-test")
	t.Assert(err, IsNil)

	if err := pct.Basedir.Init(s.tmpDir); err != nil {
		t.Fatal(err)
	}
	s.configDir = pct.Basedir.Dir("config")

	// Real instance repo
	s.repo = instance.NewRepo(pct.NewLogger(s.logChan, "im-test"), s.configDir, s.api)
	data, err := json.Marshal(&proto.MySQLInstance{
		Hostname: "db1",
		DSN:      s.dsn,
	})
	t.Assert(err, IsNil)
	s.repo.Add("mysql", 1, data, false)
	s.mysqlInstance = proto.ServiceInstance{Service: "mysql", InstanceId: 1}

	links := map[string]string{
		"agent":     "http://localhost/agent",
		"instances": "http://localhost/instances",
	}
	s.api = mock.NewAPI("http://localhost", "http://localhost", "123", "abc-123-def", links)
}
Example #3
0
func (i *Installer) writeInstances(si *proto.ServerInstance, mi *proto.MySQLInstance) error {
	// We could write the instance structs directly, but this is the job of an
	// instance repo and it's easy enough to create one, so do the right thing.
	logChan := make(chan *proto.LogEntry, 100)
	logger := pct.NewLogger(logChan, "instance-repo")
	repo := instance.NewRepo(logger, pct.Basedir.Dir("config"), i.api)
	if si != nil {
		bytes, err := json.Marshal(si)
		if err != nil {
			return err
		}
		if err := repo.Add("server", si.Id, bytes, true); err != nil {
			return err
		}
	}
	if mi != nil {
		bytes, err := json.Marshal(mi)
		if err != nil {
			return err
		}
		if err := repo.Add("mysql", mi.Id, bytes, true); err != nil {
			return err
		}
	}
	return nil
}
func (s *ManagerTestSuite) SetUpSuite(t *C) {
	s.logChan = make(chan *proto.LogEntry, 10)
	s.logger = pct.NewLogger(s.logChan, "sysconfig-manager-test")

	s.mockMonitor = mock.NewSysconfigMonitor()
	s.factory = mock.NewSysconfigMonitorFactory([]sysconfig.Monitor{s.mockMonitor})

	s.tickChan = make(chan time.Time)

	s.dataChan = make(chan interface{}, 1)
	s.spool = mock.NewSpooler(s.dataChan)

	var err error
	s.tmpDir, err = ioutil.TempDir("/tmp", "agent-test")
	t.Assert(err, IsNil)

	if err := pct.Basedir.Init(s.tmpDir); err != nil {
		t.Fatal(err)
	}
	s.configDir = pct.Basedir.Dir("config")

	links := map[string]string{
		"agent":     "http://localhost/agent",
		"instances": "http://localhost/instances",
	}
	s.api = mock.NewAPI("http://localhost", "http://localhost", "123", "abc-123-def", links)

	s.im = instance.NewRepo(pct.NewLogger(s.logChan, "im-test"), s.configDir, s.api)
}
func (i *InstallerTestSuite) TestIsSupportedMySQLVersion(t *C) {
	var got bool
	var err error

	agentConfig := &agent.Config{}
	flags := installer.Flags{}

	apiConnector := pct.NewAPI()
	api := api.New(apiConnector, false)
	logChan := make(chan *proto.LogEntry, 100)
	logger := pct.NewLogger(logChan, "instance-repo")
	instanceRepo := instance.NewRepo(logger, pct.Basedir.Dir("config"), apiConnector)
	terminal := term.NewTerminal(os.Stdin, false, true)
	inst := installer.NewInstaller(terminal, "", api, instanceRepo, agentConfig, flags)
	conn := mock.NewNullMySQL()
	errSomethingWentWrong := fmt.Errorf("Something went wrong")

	conn.SetAtLeastVersion(false, errSomethingWentWrong)
	got, err = inst.IsVersionSupported(conn)
	t.Assert(conn.Version, Equals, agent.MIN_SUPPORTED_MYSQL_VERSION)
	t.Assert(err, Equals, errSomethingWentWrong)
	t.Assert(got, Equals, false)

	conn.SetAtLeastVersion(true, nil)
	got, err = inst.IsVersionSupported(conn)
	t.Assert(conn.Version, Equals, agent.MIN_SUPPORTED_MYSQL_VERSION)
	t.Assert(err, IsNil)
	t.Assert(got, Equals, true)

	conn.Close()
}
Example #6
0
func (s *ManagerTestSuite) SetUpSuite(t *C) {
	s.dsn = os.Getenv("PCT_TEST_MYSQL_DSN")
	if s.dsn == "" {
		t.Fatal("PCT_TEST_MYSQL_DSN is not set")
	}
	s.realmysql = mysql.NewConnection(s.dsn)
	if err := s.realmysql.Connect(1); err != nil {
		t.Fatal(err)
	}
	s.reset = []mysql.Query{
		mysql.Query{Set: "SET GLOBAL slow_query_log=OFF"},
		mysql.Query{Set: "SET GLOBAL long_query_time=10"},
	}

	s.nullmysql = mock.NewNullMySQL()

	s.logChan = make(chan *proto.LogEntry, 1000)
	s.logger = pct.NewLogger(s.logChan, "qan-test")

	s.intervalChan = make(chan *qan.Interval, 1)
	s.iter = mock.NewMockIntervalIter(s.intervalChan)
	s.iterFactory = &mock.IntervalIterFactory{
		Iters:     []qan.IntervalIter{s.iter},
		TickChans: make(map[qan.IntervalIter]chan time.Time),
	}

	s.dataChan = make(chan interface{}, 2)
	s.spool = mock.NewSpooler(s.dataChan)
	s.workerFactory = &qan.SlowLogWorkerFactory{}

	var err error
	s.tmpDir, err = ioutil.TempDir("/tmp", "agent-test")
	t.Assert(err, IsNil)

	if err := pct.Basedir.Init(s.tmpDir); err != nil {
		t.Fatal(err)
	}
	s.configDir = pct.Basedir.Dir("config")

	s.im = instance.NewRepo(pct.NewLogger(s.logChan, "im-test"), s.configDir, s.api)
	data, err := json.Marshal(&proto.MySQLInstance{
		Hostname: "db1",
		DSN:      s.dsn,
	})
	t.Assert(err, IsNil)
	s.im.Add("mysql", 1, data, false)
	s.mysqlInstance = proto.ServiceInstance{Service: "mysql", InstanceId: 1}

	links := map[string]string{
		"agent":     "http://localhost/agent",
		"instances": "http://localhost/instances",
	}
	s.api = mock.NewAPI("http://localhost", "http://localhost", "123", "abc-123-def", links)
}
Example #7
0
func (s *ManagerTestSuite) SetUpSuite(t *C) {
	s.logChan = make(chan *proto.LogEntry, 10)
	s.logger = pct.NewLogger(s.logChan, "mm-manager-test")
	s.tickChan = make(chan time.Time)
	s.traceChan = make(chan string, 10)
	s.dataChan = make(chan interface{}, 1)
	s.spool = mock.NewSpooler(s.dataChan)

	var err error
	s.tmpDir, err = ioutil.TempDir("/tmp", "agent-test")
	t.Assert(err, IsNil)

	if err := pct.Basedir.Init(s.tmpDir); err != nil {
		t.Fatal(err)
	}
	s.configDir = pct.Basedir.Dir("config")

	s.im = instance.NewRepo(pct.NewLogger(s.logChan, "im"), s.configDir, s.api)
	data, err := json.Marshal(&proto.MySQLInstance{
		Hostname: "db1",
		DSN:      "user:host@tcp:(127.0.0.1:3306)",
	})
	t.Assert(err, IsNil)
	s.im.Add("mysql", 1, data, false)
	data, err = json.Marshal(&proto.ServerInstance{Hostname: "host1"})
	t.Assert(err, IsNil)
	s.im.Add("server", 1, data, false)

	s.mysqlMonitor = mock.NewMmMonitor()
	s.systemMonitor = mock.NewMmMonitor()
	s.factory = mock.NewMmMonitorFactory(map[string]mm.Monitor{
		"mysql-1":  s.mysqlMonitor,
		"server-1": s.systemMonitor,
	})

	links := map[string]string{
		"agent":     "http://localhost/agent",
		"instances": "http://localhost/instances",
	}
	s.api = mock.NewAPI("http://localhost", "http://localhost", "123", "abc-123-def", links)
}
func (s *RepoTestSuite) TestAddRemove(t *C) {
	im := instance.NewRepo(s.logger, s.configDir, s.api)
	t.Assert(im, NotNil)

	t.Check(test.FileExists(s.configDir+"/mysql-1.conf"), Equals, false)

	mysqlIt := &proto.MySQLInstance{
		Id:       1,
		Hostname: "db1",
		DSN:      "user:host@tcp:(127.0.0.1:3306)",
		Distro:   "Percona Server",
		Version:  "5.6.16",
	}
	data, err := json.Marshal(mysqlIt)
	t.Assert(err, IsNil)
	err = im.Add("mysql", 1, data, true)
	t.Assert(err, IsNil)

	t.Check(test.FileExists(s.configDir+"/mysql-1.conf"), Equals, true)

	got := &proto.MySQLInstance{}
	err = im.Get("mysql", 1, got)
	t.Assert(err, IsNil)
	if same, diff := test.IsDeeply(got, mysqlIt); !same {
		t.Error(diff)
	}

	data, err = ioutil.ReadFile(s.configDir + "/mysql-1.conf")
	t.Assert(err, IsNil)

	got = &proto.MySQLInstance{}
	err = json.Unmarshal(data, got)
	t.Assert(err, IsNil)
	if same, diff := test.IsDeeply(got, mysqlIt); !same {
		t.Error(diff)
	}

	im.Remove("mysql", 1)
	t.Check(test.FileExists(s.configDir+"/mysql-1.conf"), Equals, false)
}
Example #9
0
func (s *AnalyzerTestSuite) SetUpSuite(t *C) {
	s.nullmysql = mock.NewNullMySQL()

	s.logChan = make(chan *proto.LogEntry, 1000)
	s.logger = pct.NewLogger(s.logChan, "qan-test")

	s.intervalChan = make(chan *qan.Interval, 1)

	s.iter = mock.NewIter(s.intervalChan)

	s.dataChan = make(chan interface{}, 1)
	s.spool = mock.NewSpooler(s.dataChan)

	var err error
	s.tmpDir, err = ioutil.TempDir("/tmp", "agent-test")
	t.Assert(err, IsNil)

	if err := pct.Basedir.Init(s.tmpDir); err != nil {
		t.Fatal(err)
	}
	s.configDir = pct.Basedir.Dir("config")

	s.im = instance.NewRepo(pct.NewLogger(s.logChan, "im-test"), s.configDir, s.api)
	data, err := json.Marshal(&proto.MySQLInstance{
		Hostname: "bm-cloud-db01",
		Alias:    "db01",
		DSN:      "user:pass@tcp/",
	})
	t.Assert(err, IsNil)
	s.im.Add("mysql", 1, data, false)
	s.mysqlInstance = proto.ServiceInstance{Service: "mysql", InstanceId: 1}

	links := map[string]string{
		"agent":     "http://localhost/agent",
		"instances": "http://localhost/instances",
	}
	s.api = mock.NewAPI("http://localhost", "http://localhost", "123", "abc-123-def", links)

	s.restartChan = make(chan bool, 1)
}
func (s *RepoTestSuite) TestErrors(t *C) {
	im := instance.NewRepo(s.logger, s.configDir, s.api)
	t.Assert(im, NotNil)

	mysqlIt := &proto.MySQLInstance{
		Id:       0,
		Hostname: "db1",
		DSN:      "user:host@tcp:(127.0.0.1:3306)",
		Distro:   "Percona Server",
		Version:  "5.6.16",
	}
	data, err := json.Marshal(mysqlIt)
	t.Assert(err, IsNil)

	// Instance ID must be > 0.
	err = im.Add("mysql", 0, data, false)
	t.Assert(err, NotNil)

	// Service name must be one of proto.ExternalService.
	err = im.Add("foo", 1, data, false)
	t.Assert(err, NotNil)
}
Example #11
0
func main() {
	// It flag is unknown it exist with os.Exit(10),
	// so exit code=10 is strictly reserved for flags
	// Don't use it anywhere else, as shell script install.sh depends on it
	// NOTE: standard flag.Parse() was using os.Exit(2)
	//       which was the same as returned with ctrl+c
	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
		os.Exit(10)
	}

	agentConfig := &agent.Config{
		ApiHostname: flagApiHostname,
		ApiKey:      flagApiKey,
	}
	// todo: do flags a better way
	if !flagMySQL {
		flagCreateMySQLInstance = false
		flagStartMySQLServices = false
	}

	if flagMySQLSocket != "" && flagMySQLHost != "" {
		log.Println("Options -mysql-socket and -mysql-host are exclusive\n")
		os.Exit(1)
	}

	if flagMySQLSocket != "" && flagMySQLPort != "" {
		log.Println("Options -mysql-socket and -mysql-port are exclusive\n")
		os.Exit(1)
	}

	flags := installer.Flags{
		Bool: map[string]bool{
			"debug":                  flagDebug,
			"create-server-instance": flagCreateServerInstance,
			"start-services":         flagStartServices,
			"create-mysql-instance":  flagCreateMySQLInstance,
			"start-mysql-services":   flagStartMySQLServices,
			"create-agent":           flagCreateAgent,
			"old-passwords":          flagOldPasswords,
			"plain-passwords":        flagPlainPasswords,
			"interactive":            flagInteractive,
			"auto-detect-mysql":      flagAutoDetectMySQL,
			"create-mysql-user":      flagCreateMySQLUser,
			"mysql":                  flagMySQL,
		},
		String: map[string]string{
			"app-host":            DEFAULT_APP_HOSTNAME,
			"mysql-defaults-file": flagMySQLDefaultsFile,
			"agent-mysql-user":    flagAgentMySQLUser,
			"agent-mysql-pass":    flagAgentMySQLPass,
			"mysql-user":          flagMySQLUser,
			"mysql-pass":          flagMySQLPass,
			"mysql-host":          flagMySQLHost,
			"mysql-port":          flagMySQLPort,
			"mysql-socket":        flagMySQLSocket,
		},
		Int64: map[string]int64{
			"mysql-max-user-connections": flagMySQLMaxUserConnections,
		},
	}

	// Agent stores all its files in the basedir.  This must be called first
	// because installer uses pct.Basedir and assumes it's already initialized.
	if err := pct.Basedir.Init(flagBasedir); err != nil {
		log.Printf("Error initializing basedir %s: %s\n", flagBasedir, err)
		os.Exit(1)
	}

	apiConnector := pct.NewAPI()
	api := api.New(apiConnector, flagDebug)
	logChan := make(chan *proto.LogEntry, 100)
	logger := pct.NewLogger(logChan, "instance-repo")
	instanceRepo := instance.NewRepo(logger, pct.Basedir.Dir("config"), apiConnector)
	terminal := term.NewTerminal(os.Stdin, flagInteractive, flagDebug)
	agentInstaller := installer.NewInstaller(terminal, flagBasedir, api, instanceRepo, agentConfig, flags)
	fmt.Println("CTRL-C at any time to quit")
	// todo: catch SIGINT and clean up
	if err := agentInstaller.Run(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	os.Exit(0)
}