示例#1
0
文件: alerts.go 项目: y-kuno/mkr
func joinMonitorsAndHosts(client *mkr.Client, alerts []*mkr.Alert) []*alertSet {
	hostsJSON, err := client.FindHosts(&mkr.FindHostsParam{
		Statuses: []string{"working", "standby", "poweroff", "maintenance"},
	})
	logger.DieIf(err)

	hosts := map[string]*mkr.Host{}
	for _, host := range hostsJSON {
		hosts[host.ID] = host
	}

	monitorsJSON, err := client.FindMonitors()
	logger.DieIf(err)

	monitors := map[string]*mkr.Monitor{}
	for _, monitor := range monitorsJSON {
		monitors[monitor.ID] = monitor
	}

	alertSets := []*alertSet{}
	for _, alert := range alerts {
		alertSets = append(
			alertSets,
			&alertSet{Alert: alert, Host: hosts[alert.HostID], Monitor: monitors[alert.MonitorID]},
		)
	}
	return alertSets
}
示例#2
0
文件: commands.go 项目: syohex/mkr
func doCreate(c *cli.Context) {
	conffile := c.GlobalString("conf")
	argHostName := c.Args().Get(0)
	optRoleFullnames := c.StringSlice("roleFullname")
	optStatus := c.String("status")

	if argHostName == "" {
		cli.ShowCommandHelp(c, "create")
		os.Exit(1)
	}

	client := newMackerel(conffile)

	hostID, err := client.CreateHost(&mkr.CreateHostParam{
		Name:          argHostName,
		RoleFullnames: optRoleFullnames,
	})
	logger.DieIf(err)

	logger.Log("created", hostID)

	if optStatus != "" {
		err := client.UpdateHostStatus(hostID, optStatus)
		logger.DieIf(err)
		logger.Log("updated", fmt.Sprintf("%s %s", hostID, optStatus))
	}
}
示例#3
0
文件: commands.go 项目: y-kuno/mkr
func doThrow(c *cli.Context) error {
	conffile := c.GlobalString("conf")
	optHostID := c.String("host")
	optService := c.String("service")

	var metricValues []*(mkr.MetricValue)

	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		line := scanner.Text()

		// name, value, timestamp
		// ex.) tcp.CLOSING 0 1397031808
		items := strings.Fields(line)
		if len(items) != 3 {
			continue
		}
		value, err := strconv.ParseFloat(items[1], 64)
		if err != nil {
			logger.Log("warning", fmt.Sprintf("Failed to parse values: %s", err))
			continue
		}
		time, err := strconv.ParseInt(items[2], 10, 64)
		if err != nil {
			logger.Log("warning", fmt.Sprintf("Failed to parse values: %s", err))
			continue
		}

		metricValue := &mkr.MetricValue{
			Name:  items[0],
			Value: value,
			Time:  time,
		}

		metricValues = append(metricValues, metricValue)
	}
	logger.ErrorIf(scanner.Err())

	client := newMackerel(conffile)

	if optHostID != "" {
		err := client.PostHostMetricValuesByHostID(optHostID, metricValues)
		logger.DieIf(err)

		for _, metric := range metricValues {
			logger.Log("thrown", fmt.Sprintf("%s '%s\t%f\t%d'", optHostID, metric.Name, metric.Value, metric.Time))
		}
	} else if optService != "" {
		err := client.PostServiceMetricValues(optService, metricValues)
		logger.DieIf(err)

		for _, metric := range metricValues {
			logger.Log("thrown", fmt.Sprintf("%s '%s\t%f\t%d'", optService, metric.Name, metric.Value, metric.Time))
		}
	} else {
		cli.ShowCommandHelp(c, "throw")
		os.Exit(1)
	}
	return nil
}
示例#4
0
文件: commands.go 项目: syohex/mkr
func doUpdate(c *cli.Context) {
	conffile := c.GlobalString("conf")
	argHostIDs := c.Args()
	optName := c.String("name")
	optStatus := c.String("status")
	optRoleFullnames := c.StringSlice("roleFullname")

	if len(argHostIDs) < 1 {
		argHostIDs = make([]string, 1)
		if argHostIDs[0] = LoadHostIDFromConfig(conffile); argHostIDs[0] == "" {
			cli.ShowCommandHelp(c, "update")
			os.Exit(1)
		}
	}

	needUpdateHostStatus := optStatus != ""
	needUpdateHost := (optName != "" || len(optRoleFullnames) > 0)

	if !needUpdateHostStatus && !needUpdateHost {
		cli.ShowCommandHelp(c, "update")
		os.Exit(1)
	}

	client := newMackerel(conffile)

	var wg sync.WaitGroup
	for _, hostID := range argHostIDs {
		wg.Add(1)
		go func(hostID string) {
			defer wg.Done()

			if needUpdateHostStatus {
				err := client.UpdateHostStatus(hostID, optStatus)
				logger.DieIf(err)
			}

			if needUpdateHost {
				_, err := client.UpdateHost(hostID, &mkr.UpdateHostParam{
					Name:          optName,
					RoleFullnames: optRoleFullnames,
				})
				logger.DieIf(err)
			}

			logger.Log("updated", hostID)
		}(hostID)
	}

	wg.Wait()
}
示例#5
0
文件: commands.go 项目: syohex/mkr
func doStatus(c *cli.Context) {
	conffile := c.GlobalString("conf")
	argHostID := c.Args().Get(0)
	isVerbose := c.Bool("verbose")

	if argHostID == "" {
		if argHostID = LoadHostIDFromConfig(conffile); argHostID == "" {
			cli.ShowCommandHelp(c, "status")
			os.Exit(1)
		}
	}

	host, err := newMackerel(conffile).FindHost(argHostID)
	logger.DieIf(err)

	if isVerbose {
		PrettyPrintJSON(host)
	} else {
		format := &HostFormat{
			ID:            host.ID,
			Name:          host.Name,
			Status:        host.Status,
			RoleFullnames: host.GetRoleFullnames(),
			IsRetired:     host.IsRetired,
			CreatedAt:     host.DateStringFromCreatedAt(),
			IPAddresses:   host.IPAddresses(),
		}

		PrettyPrintJSON(format)
	}
}
示例#6
0
文件: commands.go 项目: syohex/mkr
func doRetire(c *cli.Context) {
	conffile := c.GlobalString("conf")
	argHostIDs := c.Args()

	if len(argHostIDs) < 1 {
		argHostIDs = make([]string, 1)
		if argHostIDs[0] = LoadHostIDFromConfig(conffile); argHostIDs[0] == "" {
			cli.ShowCommandHelp(c, "retire")
			os.Exit(1)
		}
	}

	client := newMackerel(conffile)

	var wg sync.WaitGroup
	for _, hostID := range argHostIDs {
		wg.Add(1)
		go func(hostID string) {
			defer wg.Done()

			err := client.RetireHost(hostID)
			logger.DieIf(err)

			logger.Log("retired", hostID)
		}(hostID)
	}

	wg.Wait()
}
示例#7
0
文件: commands.go 项目: y-kuno/mkr
func doRetire(c *cli.Context) error {
	conffile := c.GlobalString("conf")
	force := c.Bool("force")
	argHostIDs := c.Args()

	if len(argHostIDs) < 1 {
		argHostIDs = make([]string, 1)
		if argHostIDs[0] = LoadHostIDFromConfig(conffile); argHostIDs[0] == "" {
			cli.ShowCommandHelp(c, "retire")
			os.Exit(1)
		}
	}

	if !force && !prompter.YN("Retire following hosts.\n  "+strings.Join(argHostIDs, "\n  ")+"\nAre you sure?", true) {
		logger.Log("", "retirement is canceled.")
		return nil
	}

	client := newMackerel(conffile)

	for _, hostID := range argHostIDs {
		err := client.RetireHost(hostID)
		logger.DieIf(err)

		logger.Log("retired", hostID)
	}
	return nil
}
示例#8
0
文件: alerts.go 项目: y-kuno/mkr
func doAlertsRetrieve(c *cli.Context) error {
	conffile := c.GlobalString("conf")
	client := newMackerel(conffile)

	alerts, err := client.FindAlerts()
	logger.DieIf(err)
	PrettyPrintJSON(alerts)
	return nil
}
示例#9
0
文件: monitors.go 项目: y-kuno/mkr
func doMonitorsList(c *cli.Context) error {
	conffile := c.GlobalString("conf")

	monitors, err := newMackerel(conffile).FindMonitors()
	logger.DieIf(err)

	PrettyPrintJSON(monitors)
	return nil
}
示例#10
0
文件: monitors.go 项目: y-kuno/mkr
func checkMonitorsDiff(c *cli.Context) monitorDiff {
	conffile := c.GlobalString("conf")
	filePath := c.String("file-path")

	var monitorDiff monitorDiff

	monitorsRemote, err := newMackerel(conffile).FindMonitors()
	logger.DieIf(err)
	flagNameUniquenessRemote, err := validateRules(monitorsRemote, "remote rules")
	logger.DieIf(err)

	monitorsLocal, err := monitorLoadRules(filePath)
	logger.DieIf(err)
	flagNameUniquenessLocal, err := validateRules(monitorsLocal, "local rules")
	logger.DieIf(err)

	flagNameUniqueness := flagNameUniquenessLocal && flagNameUniquenessRemote

	for _, remote := range monitorsRemote {
		found := false
		for i, local := range monitorsLocal {
			diff, isSame := isSameMonitor(remote, local, flagNameUniqueness)
			if isSame || diff != "" {
				monitorsLocal[i] = nil
				found = true
				if diff != "" {
					monitorDiff.diff = append(monitorDiff.diff, &monitorDiffPair{remote, local})
				}
				break
			}
		}
		if found == false {
			monitorDiff.onlyRemote = append(monitorDiff.onlyRemote, remote)
		}
	}
	for _, local := range monitorsLocal {
		if local != nil {
			monitorDiff.onlyLocal = append(monitorDiff.onlyLocal, local)
		}
	}

	return monitorDiff
}
示例#11
0
文件: commands.go 项目: y-kuno/mkr
func doHosts(c *cli.Context) error {
	conffile := c.GlobalString("conf")
	isVerbose := c.Bool("verbose")

	hosts, err := newMackerel(conffile).FindHosts(&mkr.FindHostsParam{
		Name:     c.String("name"),
		Service:  c.String("service"),
		Roles:    c.StringSlice("role"),
		Statuses: c.StringSlice("status"),
	})
	logger.DieIf(err)

	format := c.String("format")
	if format != "" {
		t := template.Must(template.New("format").Parse(format))
		err := t.Execute(os.Stdout, hosts)
		logger.DieIf(err)
	} else if isVerbose {
		PrettyPrintJSON(hosts)
	} else {
		var hostsFormat []*HostFormat
		for _, host := range hosts {
			format := &HostFormat{
				ID:            host.ID,
				Name:          host.Name,
				DisplayName:   host.DisplayName,
				Status:        host.Status,
				RoleFullnames: host.GetRoleFullnames(),
				IsRetired:     host.IsRetired,
				CreatedAt:     host.DateStringFromCreatedAt(),
				IPAddresses:   host.IPAddresses(),
			}
			hostsFormat = append(hostsFormat, format)
		}

		PrettyPrintJSON(hostsFormat)
	}
	return nil
}
示例#12
0
文件: monitors.go 项目: y-kuno/mkr
func doMonitorsPush(c *cli.Context) error {
	monitorDiff := checkMonitorsDiff(c)
	isDryRun := c.Bool("dry-run")
	isVerbose := c.Bool("verbose")

	conffile := c.GlobalString("conf")
	client := newMackerel(conffile)
	if isVerbose {
		client.Verbose = true
	}

	for _, m := range monitorDiff.onlyLocal {
		logger.Log("info", "Create a new rule.")
		fmt.Println(stringifyMonitor(m, ""))
		if !isDryRun {
			_, err := client.CreateMonitor(m)
			logger.DieIf(err)
		}
	}
	for _, m := range monitorDiff.onlyRemote {
		logger.Log("info", "Delete a rule.")
		fmt.Println(stringifyMonitor(m, ""))
		if !isDryRun {
			_, err := client.DeleteMonitor(m.ID)
			logger.DieIf(err)
		}
	}
	for _, d := range monitorDiff.diff {
		logger.Log("info", "Update a rule.")
		fmt.Println(stringifyMonitor(d.local, ""))
		if !isDryRun {
			_, err := client.UpdateMonitor(d.remote.ID, d.local)
			logger.DieIf(err)
		}
	}
	return nil
}
示例#13
0
文件: commands.go 项目: syohex/mkr
func doFetch(c *cli.Context) {
	conffile := c.GlobalString("conf")
	argHostIDs := c.Args()
	optMetricNames := c.StringSlice("name")

	if len(argHostIDs) < 1 || len(optMetricNames) < 1 {
		cli.ShowCommandHelp(c, "fetch")
		os.Exit(1)
	}

	metricValues, err := newMackerel(conffile).FetchLatestMetricValues(argHostIDs, optMetricNames)
	logger.DieIf(err)

	PrettyPrintJSON(metricValues)
}
示例#14
0
文件: commands.go 项目: syohex/mkr
func newMackerel(conffile string) *mkr.Client {
	apiKey := LoadApikeyFromEnvOrConfig(conffile)
	if apiKey == "" {
		logger.Log("error", `
    Not set MACKEREL_APIKEY environment variable. (Try "export MACKEREL_APIKEY='<Your apikey>'")
`)
		os.Exit(1)
	}

	if os.Getenv("DEBUG") != "" {
		mackerel, err := mkr.NewClientWithOptions(apiKey, "https://mackerel.io/api/v0", true)
		logger.DieIf(err)

		return mackerel
	}

	return mkr.NewClient(apiKey)
}
示例#15
0
文件: monitors.go 项目: y-kuno/mkr
func doMonitorsPull(c *cli.Context) error {
	conffile := c.GlobalString("conf")
	isVerbose := c.Bool("verbose")
	filePath := c.String("file-path")

	monitors, err := newMackerel(conffile).FindMonitors()
	logger.DieIf(err)

	monitorSaveRules(monitors, filePath)

	if isVerbose {
		PrettyPrintJSON(monitors)
	}

	if filePath == "" {
		filePath = "monitors.json"
	}
	logger.Log("info", fmt.Sprintf("Monitor rules are saved to '%s' (%d rules).", filePath, len(monitors)))
	return nil
}
示例#16
0
文件: alerts.go 项目: y-kuno/mkr
func doAlertsList(c *cli.Context) error {
	conffile := c.GlobalString("conf")
	filterServices := c.StringSlice("service")
	filterStatuses := c.StringSlice("host-status")
	client := newMackerel(conffile)

	alerts, err := client.FindAlerts()
	logger.DieIf(err)
	joinedAlerts := joinMonitorsAndHosts(client, alerts)

	for _, joinAlert := range joinedAlerts {
		if len(filterServices) > 0 {
			found := false
			for _, filterService := range filterServices {
				if joinAlert.Host != nil {
					if _, ok := joinAlert.Host.Roles[filterService]; ok {
						found = true
					}
				} else if joinAlert.Monitor.Service == filterService {
					found = true
				}
			}
			if !found {
				continue
			}
		}
		if len(filterStatuses) > 0 {
			found := false
			for _, filterStatus := range filterStatuses {
				if joinAlert.Host != nil && joinAlert.Host.Status == filterStatus {
					found = true
				}
			}
			if !found {
				continue
			}
		}
		fmt.Println(formatJoinedAlert(joinAlert, c.BoolT("color")))
	}
	return nil
}
示例#17
0
文件: alerts.go 项目: y-kuno/mkr
func doAlertsClose(c *cli.Context) error {
	conffile := c.GlobalString("conf")
	isVerbose := c.Bool("verbose")
	argAlertIDs := c.Args()
	reason := c.String("reason")

	if len(argAlertIDs) < 1 {
		cli.ShowCommandHelp(c, "alerts")
		os.Exit(1)
	}

	client := newMackerel(conffile)
	for _, alertID := range argAlertIDs {
		alert, err := client.CloseAlert(alertID, reason)
		logger.DieIf(err)

		logger.Log("Alert closed", alertID)
		if isVerbose == true {
			PrettyPrintJSON(alert)
		}
	}
	return nil
}
示例#18
0
文件: format.go 项目: syohex/mkr
// PrettyPrintJSON output indented json via stdout.
func PrettyPrintJSON(src interface{}) {
	data, err := json.MarshalIndent(src, "", "    ")
	logger.DieIf(err)
	fmt.Fprintln(os.Stdout, string(data))
}
示例#19
0
文件: dashboards.go 项目: y-kuno/mkr
func doGenerateDashboards(c *cli.Context) error {
	conffile := c.GlobalString("conf")

	isStdout := c.Bool("print")

	argFilePath := c.Args()
	if len(argFilePath) < 1 {
		cli.ShowCommandHelp(c, "generate")
		return cli.NewExitError("specify a yaml file.", 1)
	}

	buf, err := ioutil.ReadFile(argFilePath[0])
	logger.DieIf(err)

	yml := graphsConfig{}
	err = yaml.Unmarshal(buf, &yml)
	logger.DieIf(err)

	client := newMackerel(conffile)

	org, err := client.GetOrg()
	logger.DieIf(err)

	if yml.ConfigVersion == "" {
		return cli.NewExitError("config_version is required in yaml.", 1)
	}
	if yml.ConfigVersion != "0.9" {
		return cli.NewExitError(fmt.Sprintf("config_version %s is not suport.", yml.ConfigVersion), 1)
	}
	if yml.Title == "" {
		return cli.NewExitError("title is required in yaml.", 1)
	}
	if yml.URLPath == "" {
		return cli.NewExitError("url_path is required in yaml.", 1)
	}
	if yml.Format == "" {
		yml.Format = "iframe"
	}
	if yml.Format != "iframe" && yml.Format != "image" {
		return cli.NewExitError("graph_type should be 'iframe' or 'image'.", 1)
	}
	if yml.Height == 0 {
		yml.Height = 200
	}
	if yml.Width == 0 {
		yml.Width = 400
	}

	if yml.HostGraphFormat != nil && yml.GraphFormat != nil {
		return cli.NewExitError("you cannot specify both 'graphs' and host_graphs'.", 1)
	}

	var markdown string
	for _, h := range yml.HostGraphFormat {
		mdf := generateHostGraphsMarkdownFactory(h, yml.Format, yml.Height, yml.Width)
		markdown += mdf.generate(org.Name)
	}
	for _, g := range yml.GraphFormat {
		mdf, err := generateGraphsMarkdownFactory(g, yml.Format, yml.Height, yml.Width)
		if err != nil {
			return err
		}
		markdown += mdf.generate(org.Name)
	}

	if isStdout {
		fmt.Println(markdown)
	} else {
		updateDashboard := &mackerel.Dashboard{
			Title:        yml.Title,
			BodyMarkDown: markdown,
			URLPath:      yml.URLPath,
		}

		dashboards, fetchError := client.FindDashboards()
		logger.DieIf(fetchError)

		dashboardID := ""
		for _, ds := range dashboards {
			if ds.URLPath == yml.URLPath {
				dashboardID = ds.ID
			}
		}

		if dashboardID == "" {
			_, createError := client.CreateDashboard(updateDashboard)
			logger.DieIf(createError)
		} else {
			_, updateError := client.UpdateDashboard(dashboardID, updateDashboard)
			logger.DieIf(updateError)
		}
	}

	return nil
}
示例#20
0
文件: format.go 项目: y-kuno/mkr
// JSONMarshalIndent call json.MarshalIndent and replace encoded angle brackets
func JSONMarshalIndent(src interface{}, prefix, indent string) string {
	dataRaw, err := json.MarshalIndent(src, prefix, indent)
	logger.DieIf(err)
	return replaceAngleBrackets(string(dataRaw))
}
示例#21
0
文件: commands.go 项目: y-kuno/mkr
func doUpdate(c *cli.Context) error {
	conffile := c.GlobalString("conf")
	argHostIDs := c.Args()
	optName := c.String("name")
	optDisplayName := c.String("displayName")
	optStatus := c.String("status")
	optRoleFullnames := c.StringSlice("roleFullname")
	overwriteRoles := c.Bool("overwriteRoles")

	if len(argHostIDs) < 1 {
		argHostIDs = make([]string, 1)
		if argHostIDs[0] = LoadHostIDFromConfig(conffile); argHostIDs[0] == "" {
			cli.ShowCommandHelp(c, "update")
			os.Exit(1)
		}
	}

	needUpdateHostStatus := optStatus != ""
	needUpdateRolesInHostUpdate := !overwriteRoles && len(optRoleFullnames) > 0
	needUpdateHost := (optName != "" || optDisplayName != "" || overwriteRoles || needUpdateRolesInHostUpdate)

	if !needUpdateHostStatus && !needUpdateHost {
		logger.Log("update", "at least one argumet is required.")
		cli.ShowCommandHelp(c, "update")
		os.Exit(1)
	}

	client := newMackerel(conffile)

	for _, hostID := range argHostIDs {
		if needUpdateHostStatus {
			err := client.UpdateHostStatus(hostID, optStatus)
			logger.DieIf(err)
		}

		if overwriteRoles {
			err := client.UpdateHostRoleFullnames(hostID, optRoleFullnames)
			logger.DieIf(err)
		}

		if needUpdateHost {
			host, err := client.FindHost(hostID)
			logger.DieIf(err)
			meta := host.Meta
			name := ""
			if optName == "" {
				name = host.Name
			} else {
				name = optName
			}
			displayname := ""
			if optDisplayName == "" {
				displayname = host.DisplayName
			} else {
				displayname = optDisplayName
			}
			param := &mkr.UpdateHostParam{
				Name:        name,
				DisplayName: displayname,
				Meta:        meta,
			}
			if needUpdateRolesInHostUpdate {
				param.RoleFullnames = optRoleFullnames
			}
			_, err = client.UpdateHost(hostID, param)
			logger.DieIf(err)
		}

		logger.Log("updated", hostID)
	}
	return nil
}