<commit_before>package extensions

import (
	"encoding/json"
	"fmt"
	"github.com/pawelszydlo/papa-bot"
	"net/url"
	"strings"
	"github.com/pawelszydlo/papa-bot/events"
)

/*
ExtensionAqicn - query Aqicn.org for air quality data.

Used custom variables:
- AqicnToken- Your Aqicn token.
*/
type ExtensionAqicn struct {
	bot *papaBot.Bot
	resultCache     map[string]string
}

// Structs for Aqicn responses.
type aqiSearchResult struct {
	Status string
	Data   []aqiSearchData
}
type aqiSearchData struct {
	Uid int
}

type aqiQueryResult struct {
	Status string
	Data   aqiData
}
type aqiData struct {
	Aqi  int
	City aqiCity
	Iaqi aqiIaqi
}
type aqiCity struct {
	Name string
}
type aqiIaqi struct {
	No2  aqiValue
	O3   aqiValue
	Pm10 aqiValue
	Pm25 aqiValue
}
type aqiValue struct {
	V float64
}

// Init inits the extension.
func (ext *ExtensionAqicn) Init(bot *papaBot.Bot) error {
	ext.resultCache = map[string]string{}
	// Register new command.
	bot.RegisterCommand(&papaBot.BotCommand{
		[]string{"aq"},
		false, false, false,
		"<station>", "Show air quality for <station>.",
		ext.commandAqicn})
	ext.bot = bot
	bot.EventDispatcher.RegisterListener(events.EventTick, ext.TickListener)
	return nil
}

//qualityIndex shows how the value qualifies.
func (ext *ExtensionAqicn) qualityIndexLevel(stat string, value float64) int {
	norms := map[string][]int{
		"pm25": {15, 30, 55, 110},
		"pm10": {25, 50, 90, 180},
		"o3":   {60, 120, 180, 240},
		"no2":  {50, 100, 200, 400},
		"aqi": {50, 100, 150, 200},
	}
	for i, normValue := range norms[stat] {
		if int(value) < normValue {
			return i
		}
	}
	return 4
}

// interpretQualityIndex will put the quality index into human readable form.
func (ext *ExtensionAqicn) interpretQualityIndex(stat string, value float64) string {
	level := ext.qualityIndexLevel(stat, value)
	levels := map[int]string{
		0: ":smile:",
		1: ":slightly_smiling_face:",
		2: ":confused:",
		3: ":weary:",
		4: ":skull_and_crossbones:",
	}
	return levels[level]
}

// format is a helper function that will prepare a markdown value.
func (ext *ExtensionAqicn) format(stat string, value float64) string {
	if value == 0 { // no readout.
		return "- |"
	}
	return fmt.Sprintf("%.f %s |",value, ext.interpretQualityIndex(stat, value))
}

// queryAqicn will query aqicn.org first for stations matching "city", then for results for those stations.
func (ext *ExtensionAqicn) queryAqicn(city, transport string) string {
	token := ext.bot.GetVar("aqicnToken")
	if token == "" {
		ext.bot.Log.Errorf("Aqicn.org Token key not set! Set the 'aqicnToken' variable in the bot.")
	}

	// Check if we have this cached.
	cacheKey := transport + city
	if cached, exists := ext.resultCache[cacheKey]; exists {
		return cached
	}

	err, _, body := ext.bot.GetPageBody(
		fmt.Sprintf(
			"https://api.waqi.info/search/?token=%s&keyword=%s",
			token, strings.Replace(url.QueryEscape(city), "+", "%20", -1),
		), nil)
	if err != nil {
		ext.bot.Log.Errorf("Error getting Aqicn data: %s", err)
		return ""
	}

	searchResult := aqiSearchResult{Status: "", Data: []aqiSearchData{}}
	// Decode JSON.
	if err := json.Unmarshal(body, &searchResult); err != nil {
		ext.bot.Log.Errorf("Error loading Aqicn.org data for %s: %s", city, err)
		return ""
	}

	// Check response.
	if len(searchResult.Data) == 0 {
		return ext.bot.Texts.SearchNoResults
	} else {
		ext.bot.Log.Infof("Found %d stations for city '%s'.", len(searchResult.Data), city)
	}
	// Limit number of stations to five.
	if len(searchResult.Data) > 5 {
		searchResult.Data = searchResult.Data[:5]
	}

	// Gather data for each station.
	result := []string{}
	if transport == "mattermost" {
		result = append(result, "\n\n| Station | AQI | PM2.5 | PM10 | O3 | NO2 |")
		result = append(result, "| -----: | :----: | :----: | :----:| :----: | :----: | :----: |")
	}
	for _, station := range searchResult.Data {
		url := fmt.Sprintf("http://api.waqi.info/feed/@%d/?token=%s", station.Uid, token)
		ext.bot.Log.Warnf(url)
		err, _, body := ext.bot.GetPageBody(
			fmt.Sprintf("http://api.waqi.info/feed/@%d/?token=%s", station.Uid, token), nil)
		if err != nil {
			ext.bot.Log.Errorf("Error getting Aqicn data: %s", err)
			continue
		}
		queryResult := aqiQueryResult{"", aqiData{City: aqiCity{}, Iaqi: aqiIaqi{}}}
		// Decode JSON.
		if err := json.Unmarshal(body, &queryResult); err != nil {
			ext.bot.Log.Errorf("Error loading Aqicn.org data for %d: %s", station.Uid, err)
		} else {
			if transport == "mattermost" {
				line := fmt.Sprintf("| %s | ", queryResult.Data.City.Name)
				line += ext.format("aqi", float64(queryResult.Data.Aqi))
				line += ext.format("pm25", float64(queryResult.Data.Iaqi.Pm25.V))
				line += ext.format("pm10", float64(queryResult.Data.Iaqi.Pm10.V))
				line += ext.format("o3", float64(queryResult.Data.Iaqi.O3.V))
				line += ext.format("no2", float64(queryResult.Data.Iaqi.No2.V))
				result = append(result, line)
			} else {
				result = append(result, fmt.Sprintf(
					"%s - AQI: %d, PM10: %.f, PM25: %.f",
					queryResult.Data.City.Name, queryResult.Data.Aqi,
					queryResult.Data.Iaqi.Pm10.V, queryResult.Data.Iaqi.Pm25.V),
				)
			}
		}
	}
	finalResult := ""
	if transport == "mattermost" {
		finalResult = strings.Join(result, "\n")
	} else {
		finalResult = strings.Join(result, " | ")
	}
	ext.resultCache[cacheKey] = finalResult
	return finalResult
}

// TickListener will clear announce cache.
func (ext *ExtensionAqicn) TickListener(message events.EventMessage) {
	// Clear the announcement cache.
	ext.resultCache = map[string]string{}
}

// commandMovie is a command for manually searching for movies.
func (ext *ExtensionAqicn) commandAqicn(bot *papaBot.Bot, nick, user, channel, transport, context string, priv bool, params []string) {
	if len(params) < 1 {
		return
	}
	search := strings.Join(params, " ")
	result := ext.queryAqicn(search, transport)

	bot.SendAutoMessage(priv, transport, nick, channel, result, context)
}
<commit_msg>Aqicn better formatting and links.<commit_after>package extensions

import (
	"encoding/json"
	"fmt"
	"github.com/pawelszydlo/papa-bot"
	"net/url"
	"strings"
	"github.com/pawelszydlo/papa-bot/events"
)

/*
ExtensionAqicn - query Aqicn.org for air quality data.

Used custom variables:
- AqicnToken- Your Aqicn token.
*/
type ExtensionAqicn struct {
	bot *papaBot.Bot
	resultCache     map[string]string
}

// Structs for Aqicn responses.
type aqiSearchResult struct {
	Status string
	Data   []aqiSearchData
}
type aqiSearchData struct {
	Uid int
}

type aqiQueryResult struct {
	Status string
	Data   aqiData
}
type aqiData struct {
	Aqi  int
	City aqiCity
	Iaqi aqiIaqi
}
type aqiCity struct {
	Name string
}
type aqiIaqi struct {
	No2  aqiValue
	O3   aqiValue
	Pm10 aqiValue
	Pm25 aqiValue
}
type aqiValue struct {
	V float64
}

// Init inits the extension.
func (ext *ExtensionAqicn) Init(bot *papaBot.Bot) error {
	ext.resultCache = map[string]string{}
	// Register new command.
	bot.RegisterCommand(&papaBot.BotCommand{
		[]string{"aq"},
		false, false, false,
		"<station>", "Show air quality for <station>.",
		ext.commandAqicn})
	ext.bot = bot
	bot.EventDispatcher.RegisterListener(events.EventTick, ext.TickListener)
	return nil
}

//qualityIndex shows how the value qualifies.
func (ext *ExtensionAqicn) qualityIndexLevel(stat string, value float64) int {
	norms := map[string][]int{
		"pm25": {15, 30, 55, 110},
		"pm10": {25, 50, 90, 180},
		"o3":   {60, 120, 180, 240},
		"no2":  {50, 100, 200, 400},
		"aqi": {50, 100, 150, 200},
	}
	for i, normValue := range norms[stat] {
		if int(value) < normValue {
			return i
		}
	}
	return 4
}

// interpretQualityIndex will put the quality index into human readable form.
func (ext *ExtensionAqicn) interpretQualityIndex(stat string, value float64) string {
	level := ext.qualityIndexLevel(stat, value)
	levels := map[int]string{
		0: ":smile:",
		1: ":slightly_smiling_face:",
		2: ":confused:",
		3: ":weary:",
		4: ":skull_and_crossbones:",
	}
	return levels[level]
}

// format is a helper function that will prepare a markdown value.
func (ext *ExtensionAqicn) format(stat string, value float64) string {
	if value == 0 { // no readout.
		return "- |"
	}
	return fmt.Sprintf("%.f %s |",value, ext.interpretQualityIndex(stat, value))
}

// queryAqicn will query aqicn.org first for stations matching "city", then for results for those stations.
func (ext *ExtensionAqicn) queryAqicn(city, transport string) string {
	token := ext.bot.GetVar("aqicnToken")
	if token == "" {
		ext.bot.Log.Errorf("Aqicn.org Token key not set! Set the 'aqicnToken' variable in the bot.")
	}

	// Check if we have this cached.
	cacheKey := transport + city
	if cached, exists := ext.resultCache[cacheKey]; exists {
		return cached
	}

	err, _, body := ext.bot.GetPageBody(
		fmt.Sprintf(
			"https://api.waqi.info/search/?token=%s&keyword=%s",
			token, strings.Replace(url.QueryEscape(city), "+", "%20", -1),
		), nil)
	if err != nil {
		ext.bot.Log.Errorf("Error getting Aqicn data: %s", err)
		return ""
	}

	searchResult := aqiSearchResult{Status: "", Data: []aqiSearchData{}}
	// Decode JSON.
	if err := json.Unmarshal(body, &searchResult); err != nil {
		ext.bot.Log.Errorf("Error loading Aqicn.org data for %s: %s", city, err)
		return ""
	}

	// Check response.
	if len(searchResult.Data) == 0 {
		return ext.bot.Texts.SearchNoResults
	} else {
		ext.bot.Log.Infof("Found %d stations for city '%s'.", len(searchResult.Data), city)
	}
	// Limit number of stations to five.
	if len(searchResult.Data) > 5 {
		searchResult.Data = searchResult.Data[:5]
	}

	// Gather data for each station.
	result := []string{}
	if transport == "mattermost" {
		result = append(result, "\n\n| Station | AQI | PM₂₅| PM₁₀ | O₃ | NO₂ |")
		result = append(result, "| -----: | :----: | :----: | :----:| :----: | :----: | :----: |")
	}
	for _, station := range searchResult.Data {
		url := fmt.Sprintf("http://api.waqi.info/feed/@%d/?token=%s", station.Uid, token)
		ext.bot.Log.Warnf(url)
		err, _, body := ext.bot.GetPageBody(
			fmt.Sprintf("http://api.waqi.info/feed/@%d/?token=%s", station.Uid, token), nil)
		if err != nil {
			ext.bot.Log.Errorf("Error getting Aqicn data: %s", err)
			continue
		}
		queryResult := aqiQueryResult{"", aqiData{City: aqiCity{}, Iaqi: aqiIaqi{}}}
		// Decode JSON.
		if err := json.Unmarshal(body, &queryResult); err != nil {
			ext.bot.Log.Errorf("Error loading Aqicn.org data for %d: %s", station.Uid, err)
		} else {
			if transport == "mattermost" {
				line := fmt.Sprintf("| [%s](http://aqicn.org/city/@%d) | ", queryResult.Data.City.Name, station.Uid)
				line += ext.format("aqi", float64(queryResult.Data.Aqi))
				line += ext.format("pm25", float64(queryResult.Data.Iaqi.Pm25.V))
				line += ext.format("pm10", float64(queryResult.Data.Iaqi.Pm10.V))
				line += ext.format("o3", float64(queryResult.Data.Iaqi.O3.V))
				line += ext.format("no2", float64(queryResult.Data.Iaqi.No2.V))
				result = append(result, line)
			} else {
				result = append(result, fmt.Sprintf(
					"%s - AQI: %d, PM10: %.f, PM25: %.f",
					queryResult.Data.City.Name, queryResult.Data.Aqi,
					queryResult.Data.Iaqi.Pm10.V, queryResult.Data.Iaqi.Pm25.V),
				)
			}
		}
	}
	finalResult := ""
	if transport == "mattermost" {
		finalResult = strings.Join(result, "\n")
	} else {
		finalResult = strings.Join(result, " | ")
	}
	ext.resultCache[cacheKey] = finalResult
	return finalResult
}

// TickListener will clear announce cache.
func (ext *ExtensionAqicn) TickListener(message events.EventMessage) {
	// Clear the announcement cache.
	ext.resultCache = map[string]string{}
}

// commandMovie is a command for manually searching for movies.
func (ext *ExtensionAqicn) commandAqicn(bot *papaBot.Bot, nick, user, channel, transport, context string, priv bool, params []string) {
	if len(params) < 1 {
		return
	}
	search := strings.Join(params, " ")
	result := ext.queryAqicn(search, transport)

	bot.SendAutoMessage(priv, transport, nick, channel, result, context)
}
<|endoftext|>


<commit_before>package common

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// ErrWithExitCode wraps error and exposes an ExitCode method
type ErrWithExitCode interface {
	ExitCode() int
}

// LogFail is the failure log formatter
// prints text to stderr and exits with status 1
func LogFail(text string) {
	fmt.Fprintln(os.Stderr, fmt.Sprintf(" !     %s", text))
	os.Exit(1)
}

// LogFailWithError is the failure log formatter
// prints text to stderr and exits with the specified exit code
func LogFailWithError(err error) {
	fmt.Fprintln(os.Stderr, fmt.Sprintf(" !     %s", err.Error()))
	if errExit, ok := err.(ErrWithExitCode); ok {
		os.Exit(errExit.ExitCode())
	}
	os.Exit(1)
}

// LogFailQuiet is the failure log formatter (with quiet option)
// prints text to stderr and exits with status 1
func LogFailQuiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		fmt.Fprintln(os.Stderr, fmt.Sprintf(" !     %s", text))
	}
	os.Exit(1)
}

// Log is the log formatter
func Log(text string) {
	fmt.Println(text)
}

// LogQuiet is the log formatter (with quiet option)
func LogQuiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		fmt.Println(text)
	}
}

// LogInfo1 is the info1 header formatter
func LogInfo1(text string) {
	fmt.Println(fmt.Sprintf("-----> %s", text))
}

// LogInfo1Quiet is the info1 header formatter (with quiet option)
func LogInfo1Quiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		LogInfo1(text)
	}
}

// LogInfo2 is the info2 header formatter
func LogInfo2(text string) {
	fmt.Println(fmt.Sprintf("=====> %s", text))
}

// LogInfo2Quiet is the info2 header formatter (with quiet option)
func LogInfo2Quiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		LogInfo2(text)
	}
}

// LogVerbose is the verbose log formatter
// prints indented text to stdout
func LogVerbose(text string) {
	fmt.Println(fmt.Sprintf("       %s", text))
}

// LogVerboseQuiet is the verbose log formatter
// prints indented text to stdout (with quiet option)
func LogVerboseQuiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		LogVerbose(text)
	}
}

// LogVerboseQuietContainerLogs is the verbose log formatter for container logs
func LogVerboseQuietContainerLogs(containerID string) {
	sc := NewShellCmdWithArgs(DockerBin(), "container", "logs", containerID)
	sc.ShowOutput = false
	b, err := sc.CombinedOutput()
	if err != nil {
		LogExclaim(fmt.Sprintf("Failed to fetch container logs: %s", containerID))
	}

	output := strings.TrimSpace(string(b))
	if len(output) == 0 {
		return
	}

	for _, line := range strings.Split(output, "\n") {
		if line != "" {
			LogVerboseQuiet(line)
		}
	}
}

// LogVerboseQuietContainerLogsTail is the verbose log formatter for container logs with tail mode enabled
func LogVerboseQuietContainerLogsTail(containerID string, lines int, tail bool) {
	args := []string{"container", "logs", containerID}
	if lines > 0 {
		args = append(args, "--tail", strconv.Itoa(lines))
	}
	if tail {
		args = append(args, "--follow")
	}
	sc := NewShellCmdWithArgs(DockerBin(), args...)
	stdout, _ := sc.Command.StdoutPipe()
	sc.Command.Start()

	scanner := bufio.NewScanner(stdout)
	scanner.Split(bufio.ScanLines)
	for scanner.Scan() {
		m := scanner.Text()
		LogVerboseQuiet(m)
	}
	sc.Command.Wait()
}

// LogWarn is the warning log formatter
func LogWarn(text string) {
	fmt.Fprintln(os.Stderr, fmt.Sprintf(" !     %s", text))
}

// LogExclaim is the log exclaim formatter
func LogExclaim(text string) {
	fmt.Println(fmt.Sprintf(" !     %s", text))
}

// LogStderr is the stderr log formatter
func LogStderr(text string) {
	fmt.Fprintln(os.Stderr, text)
}

// LogDebug is the debug log formatter
func LogDebug(text string) {
	if os.Getenv("DOKKU_TRACE") == "1" {
		fmt.Fprintln(os.Stderr, fmt.Sprintf(" ?     %s", strings.TrimPrefix(text, " ?     ")))
	}
}
<commit_msg>fix: handle both stderr and stdout when tailing container logs<commit_after>package common

import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"sync"
)

// ErrWithExitCode wraps error and exposes an ExitCode method
type ErrWithExitCode interface {
	ExitCode() int
}

type writer struct {
	mu     *sync.Mutex
	source string
}

// Write prints the data to either stdout or stderr using the log helper functions
func (w *writer) Write(bytes []byte) (int, error) {
	w.mu.Lock()
	defer w.mu.Unlock()

	if w.source == "stdout" {
		for _, line := range strings.Split(string(bytes), "\n") {
			if line == "" {
				continue
			}

			LogVerboseQuiet(line)
		}
	} else {
		for _, line := range strings.Split(string(bytes), "\n") {
			if line == "" {
				continue
			}

			LogVerboseStderrQuiet(line)
		}
	}

	return len(bytes), nil
}

// LogFail is the failure log formatter
// prints text to stderr and exits with status 1
func LogFail(text string) {
	fmt.Fprintln(os.Stderr, fmt.Sprintf(" !     %s", text))
	os.Exit(1)
}

// LogFailWithError is the failure log formatter
// prints text to stderr and exits with the specified exit code
func LogFailWithError(err error) {
	fmt.Fprintln(os.Stderr, fmt.Sprintf(" !     %s", err.Error()))
	if errExit, ok := err.(ErrWithExitCode); ok {
		os.Exit(errExit.ExitCode())
	}
	os.Exit(1)
}

// LogFailQuiet is the failure log formatter (with quiet option)
// prints text to stderr and exits with status 1
func LogFailQuiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		fmt.Fprintln(os.Stderr, fmt.Sprintf(" !     %s", text))
	}
	os.Exit(1)
}

// Log is the log formatter
func Log(text string) {
	fmt.Println(text)
}

// LogQuiet is the log formatter (with quiet option)
func LogQuiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		fmt.Println(text)
	}
}

// LogInfo1 is the info1 header formatter
func LogInfo1(text string) {
	fmt.Println(fmt.Sprintf("-----> %s", text))
}

// LogInfo1Quiet is the info1 header formatter (with quiet option)
func LogInfo1Quiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		LogInfo1(text)
	}
}

// LogInfo2 is the info2 header formatter
func LogInfo2(text string) {
	fmt.Println(fmt.Sprintf("=====> %s", text))
}

// LogInfo2Quiet is the info2 header formatter (with quiet option)
func LogInfo2Quiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		LogInfo2(text)
	}
}

// LogVerbose is the verbose log formatter
// prints indented text to stdout
func LogVerbose(text string) {
	fmt.Println(fmt.Sprintf("       %s", text))
}

// LogVerboseStderr is the verbose log formatter
// prints indented text to stderr
func LogVerboseStderr(text string) {
	fmt.Fprintln(os.Stderr, fmt.Sprintf(" !     %s", text))
}

// LogVerboseQuiet is the verbose log formatter
// prints indented text to stdout (with quiet option)
func LogVerboseQuiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		LogVerbose(text)
	}
}

// LogVerboseStderrQuiet is the verbose log formatter
// prints indented text to stderr (with quiet option)
func LogVerboseStderrQuiet(text string) {
	if os.Getenv("DOKKU_QUIET_OUTPUT") == "" {
		LogVerboseStderr(text)
	}
}

// LogVerboseQuietContainerLogs is the verbose log formatter for container logs
func LogVerboseQuietContainerLogs(containerID string) {
	LogVerboseQuietContainerLogsTail(containerID, 0, false)
}

// LogVerboseQuietContainerLogsTail is the verbose log formatter for container logs with tail mode enabled
func LogVerboseQuietContainerLogsTail(containerID string, lines int, tail bool) {
	args := []string{"container", "logs", containerID}
	if lines > 0 {
		args = append(args, "--tail", strconv.Itoa(lines))
	}
	if tail {
		args = append(args, "--follow")
	}

	sc := NewShellCmdWithArgs(DockerBin(), args...)
	var mu sync.Mutex
	sc.Command.Stdout = &writer{
		mu:     &mu,
		source: "stdout",
	}
	sc.Command.Stderr = &writer{
		mu:     &mu,
		source: "stderr",
	}

	if err := sc.Command.Start(); err != nil {
		LogExclaim(fmt.Sprintf("Failed to fetch container logs: %s", containerID))
	}

	if err := sc.Command.Wait(); err != nil {
		LogExclaim(fmt.Sprintf("Failed to fetch container logs: %s", containerID))
	}
}

// LogWarn is the warning log formatter
func LogWarn(text string) {
	fmt.Fprintln(os.Stderr, fmt.Sprintf(" !     %s", text))
}

// LogExclaim is the log exclaim formatter
func LogExclaim(text string) {
	fmt.Println(fmt.Sprintf(" !     %s", text))
}

// LogStderr is the stderr log formatter
func LogStderr(text string) {
	fmt.Fprintln(os.Stderr, text)
}

// LogDebug is the debug log formatter
func LogDebug(text string) {
	if os.Getenv("DOKKU_TRACE") == "1" {
		fmt.Fprintln(os.Stderr, fmt.Sprintf(" ?     %s", strings.TrimPrefix(text, " ?     ")))
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/mpl/gocron"
)

func skipToday() (bool, error) {
	doneFile := filepath.Join(os.Getenv("$HOME"), ".done")
	fi, err := os.Stat(doneFile)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}
	// if .done file was not created today, we ignore it and remove it
	// this breaks if it was created the same day of another month, but I don't
	// really care
	today := time.Now().Day()
	doneDay := fi.ModTime().Day()
	if doneDay != today {
		if err := os.Remove(doneFile); err != nil {
			return false, err
		}
		return false, nil
	}
	return true, nil
}

func main() {
	notToday, err := skipToday()
	if err != nil {
		log.Fatal(err)
	}
	if notToday {
		return
	}
	job := func() error {
		return errors.New("syncblobs -interval=0 -askauth=true -debug=true")
	}
	cron := gocron.Cron{
		Interval: 1 * time.Minute,
		LifeTime: 30 * time.Second, // so it will actually die before the next run
		Job:      job,
		Notif: &gocron.Notification{
			Host:    "localhost:8082",
			Msg:     "Syncblobs reminder",
			Timeout: 5 * time.Minute, // how long the browser tab will remain open
		},
	}
	cron.Run()
}
<commit_msg>daily: print command if any argument<commit_after>package main

import (
	"errors"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/mpl/gocron"
)

func skipToday() (bool, error) {
	doneFile := filepath.Join(os.Getenv("$HOME"), ".done")
	fi, err := os.Stat(doneFile)
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	}
	// if .done file was not created today, we ignore it and remove it
	// this breaks if it was created the same day of another month, but I don't
	// really care
	today := time.Now().Day()
	doneDay := fi.ModTime().Day()
	if doneDay != today {
		if err := os.Remove(doneFile); err != nil {
			return false, err
		}
		return false, nil
	}
	return true, nil
}

func main() {
	if len(os.Args) > 1 {
		println("syncblobs -interval=0 -askauth=true -debug=true")
		os.Exit(1)
	}
	notToday, err := skipToday()
	if err != nil {
		log.Fatal(err)
	}
	if notToday {
		return
	}
	job := func() error {
		return errors.New("syncblobs -interval=0 -askauth=true -debug=true")
	}
	cron := gocron.Cron{
		Interval: 1 * time.Minute,
		LifeTime: 30 * time.Second, // so it will actually die before the next run
		Job:      job,
		Notif: &gocron.Notification{
			Host:    "localhost:8082",
			Msg:     "Syncblobs reminder",
			Timeout: 5 * time.Minute, // how long the browser tab will remain open
		},
	}
	cron.Run()
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package contiv implements plugin providing GRPC-server that accepts requests from CNI plugin.
//
// 1. VETH-based pod-VPP connectivity
//
// +-------------------------------------------------+
// |   vSwitch VPP                                 host.go
// |                             +--------------+    |       +--------------+
// |                             |     vethVPP  |____________|   veth Host  |
// |          routing            |              |    |       |              |
// |                             +--------------+    |       +--------------+
// |    +------+       +------+                      |
// |    |  AF1 |       | AFn  |                      |
// |    |      |  ...  |      |                      |
// |    +------+       +------+                      |
// |      ^                                          |
// |      |                                          |
// +------|------------------------------------------+
//        v
// +------------+
// |            |
// | Veth2      |
// |            |
// +------------+
//        ^
//        |              pod.go
// +------|------------+
// |  NS1 v            |
// |  +------------+   |
// |  |            |   |
// |  | Veth1      |   |
// |  |            |   |
// |  +------------+   |
// |                   |
// +-------------------+
//
//
// 2. TAP-based pod-VPP connectivity
//
// +-------------------------------------------------+
// |   vSwitch VPP                                 host.go
// |                             +--------------+    |       +--------------+
// |                             |     vethVPP  |____________|   veth Host  |
// |          routing            |              |    |       |              |
// |                             +--------------+    |       +--------------+
// |    +-------+       +-------+                    |
// |    |  TAP1 |       | TAPn  |                    |
// |    |       |  ...  |       |                    |
// |    +-------+       +-------+                    |
// |      ^                                          |
// |      |                                          |
// +------|------------------------------------------+
//        |
//        |              pod.go
// +------|------------+
// |  NS1 v            |
// |  +------------+   |
// |  |            |   |
// |  | Linux-TAP1 |   |
// |  |            |   |
// |  +------------+   |
// |                   |
// +-------------------+
//
//
// 3. VPP TCP stack based pod-VPP connectivity
//
// +-------------------------------------------------+
// |   vSwitch VPP                                 host.go
// |                             +--------------+    |       +--------------+
// |                             |     vethVPP  |____________|   veth Host  |
// |          routing            |              |    |       |              |
// |                             +--------------+    |       +--------------+
// |    +-------+       +-------+                    |
// |    | LOOP1 |       | LOOPn |                    |
// |    |       |  ...  |       |                    |
// |    +-------+       +-------+                    |
// |      ^                 ^                        |
// |      |                 |                        |
// |      v                 v                        |
// |    +-----------------------+                    |
// |    |    VPP TCP Stack      |                    |
// |    +-----------------------+                    |
// |      ^                                          |
// |      |                                          |
// +------|------------------------------------------+
//        |
//        |                 pod.go
// +------|---------------+
// |  NS1 v               |
// |  +-----------------+ |
// |  |  VCL            | |
// |  | (LD_PRELOAD-ed) | |
// |  +-----------------+ |
// |          ^           |
// |          |           |
// |          v           |
// |       +------+       |
// |       | App  |       |
// |       +------+       |
// +----------------------+

package contiv
<commit_msg>Fix golint.<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package contiv implements plugin providing GRPC-server that accepts requests from CNI plugin.
//
// 1. VETH-based pod-VPP connectivity
//
// +-------------------------------------------------+
// |   vSwitch VPP                                 host.go
// |                             +--------------+    |       +--------------+
// |                             |     vethVPP  |____________|   veth Host  |
// |          routing            |              |    |       |              |
// |                             +--------------+    |       +--------------+
// |    +------+       +------+                      |
// |    |  AF1 |       | AFn  |                      |
// |    |      |  ...  |      |                      |
// |    +------+       +------+                      |
// |      ^                                          |
// |      |                                          |
// +------|------------------------------------------+
//        v
// +------------+
// |            |
// | Veth2      |
// |            |
// +------------+
//        ^
//        |              pod.go
// +------|------------+
// |  NS1 v            |
// |  +------------+   |
// |  |            |   |
// |  | Veth1      |   |
// |  |            |   |
// |  +------------+   |
// |                   |
// +-------------------+
//
//
// 2. TAP-based pod-VPP connectivity
//
// +-------------------------------------------------+
// |   vSwitch VPP                                 host.go
// |                             +--------------+    |       +--------------+
// |                             |     vethVPP  |____________|   veth Host  |
// |          routing            |              |    |       |              |
// |                             +--------------+    |       +--------------+
// |    +-------+       +-------+                    |
// |    |  TAP1 |       | TAPn  |                    |
// |    |       |  ...  |       |                    |
// |    +-------+       +-------+                    |
// |      ^                                          |
// |      |                                          |
// +------|------------------------------------------+
//        |
//        |              pod.go
// +------|------------+
// |  NS1 v            |
// |  +------------+   |
// |  |            |   |
// |  | Linux-TAP1 |   |
// |  |            |   |
// |  +------------+   |
// |                   |
// +-------------------+
//
//
// 3. VPP TCP stack based pod-VPP connectivity
//
// +-------------------------------------------------+
// |   vSwitch VPP                                 host.go
// |                             +--------------+    |       +--------------+
// |                             |     vethVPP  |____________|   veth Host  |
// |          routing            |              |    |       |              |
// |                             +--------------+    |       +--------------+
// |    +-------+       +-------+                    |
// |    | LOOP1 |       | LOOPn |                    |
// |    |       |  ...  |       |                    |
// |    +-------+       +-------+                    |
// |      ^                 ^                        |
// |      |                 |                        |
// |      v                 v                        |
// |    +-----------------------+                    |
// |    |    VPP TCP Stack      |                    |
// |    +-----------------------+                    |
// |      ^                                          |
// |      |                                          |
// +------|------------------------------------------+
//        |
//        |                 pod.go
// +------|---------------+
// |  NS1 v               |
// |  +-----------------+ |
// |  |  VCL            | |
// |  | (LD_PRELOAD-ed) | |
// |  +-----------------+ |
// |          ^           |
// |          |           |
// |          v           |
// |       +------+       |
// |       | App  |       |
// |       +------+       |
// +----------------------+
package contiv
<|endoftext|>


<commit_before>package feature

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/HouzuoGuo/laitos/env"
	"github.com/HouzuoGuo/laitos/global"
	"runtime"
	"runtime/pprof"
	"strings"
	"time"
)

var ErrBadEnvInfoChoice = errors.New(`elock | estop | log | runtime | stack`)

// Retrieve environment information and trigger emergency stop upon request.
type EnvControl struct {
}

func (info *EnvControl) IsConfigured() bool {
	return true
}

func (info *EnvControl) SelfTest() error {
	return nil
}

func (info *EnvControl) Initialise() error {
	return nil
}

func (info *EnvControl) Trigger() Trigger {
	return ".e"
}

func (info *EnvControl) Execute(cmd Command) *Result {
	if errResult := cmd.Trim(); errResult != nil {
		return errResult
	}
	switch strings.ToLower(cmd.Content) {
	case "elock":
		global.TriggerEmergencyLockDown()
		return &Result{Output: "successfully triggered EmergencyLockDown"}
	case "estop":
		global.TriggerEmergencyStop()
		return &Result{Output: "successfully triggered EmergencyStop"}
	case "runtime":
		return &Result{Output: GetRuntimeInfo()}
	case "log":
		return &Result{Output: GetLatestGlobalLog()}
	case "stack":
		return &Result{Output: GetGoroutineStacktraces()}
	default:
		return &Result{Error: ErrBadEnvInfoChoice}
	}
}

// Return runtime information (uptime, CPUs, goroutines, memory usage) in a multi-line text.
func GetRuntimeInfo() string {
	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)
	return fmt.Sprintf(`Public IP: %s
Uptime: %s
Number of CPUs: %d
Number of Goroutines: %d
GOMAXPROCS: %d
System memory usage: %d MBytes
`,
		env.GetPublicIP(),
		time.Now().Sub(global.StartupTime).String(),
		runtime.NumCPU(),
		runtime.NumGoroutine(),
		runtime.GOMAXPROCS(0),
		memStats.Sys/1024/1024)
}

// Return latest log entries in a multi-line text, one log entry per line. Latest log entry comes first.
func GetLatestGlobalLog() string {
	buf := new(bytes.Buffer)
	global.LatestLogEntries.Iterate(func(entry string) bool {
		buf.WriteString(entry)
		buf.WriteRune('\n')
		return true
	})
	return buf.String()
}

// Return stack traces of all currently running goroutines.
func GetGoroutineStacktraces() string {
	buf := new(bytes.Buffer)
	pprof.Lookup("goroutine").WriteTo(buf, 1)
	return buf.String()
}
<commit_msg>display time in runtime environment info<commit_after>package feature

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/HouzuoGuo/laitos/env"
	"github.com/HouzuoGuo/laitos/global"
	"runtime"
	"runtime/pprof"
	"strings"
	"time"
)

var ErrBadEnvInfoChoice = errors.New(`elock | estop | log | runtime | stack`)

// Retrieve environment information and trigger emergency stop upon request.
type EnvControl struct {
}

func (info *EnvControl) IsConfigured() bool {
	return true
}

func (info *EnvControl) SelfTest() error {
	return nil
}

func (info *EnvControl) Initialise() error {
	return nil
}

func (info *EnvControl) Trigger() Trigger {
	return ".e"
}

func (info *EnvControl) Execute(cmd Command) *Result {
	if errResult := cmd.Trim(); errResult != nil {
		return errResult
	}
	switch strings.ToLower(cmd.Content) {
	case "elock":
		global.TriggerEmergencyLockDown()
		return &Result{Output: "successfully triggered EmergencyLockDown"}
	case "estop":
		global.TriggerEmergencyStop()
		return &Result{Output: "successfully triggered EmergencyStop"}
	case "runtime":
		return &Result{Output: GetRuntimeInfo()}
	case "log":
		return &Result{Output: GetLatestGlobalLog()}
	case "stack":
		return &Result{Output: GetGoroutineStacktraces()}
	default:
		return &Result{Error: ErrBadEnvInfoChoice}
	}
}

// Return runtime information (uptime, CPUs, goroutines, memory usage) in a multi-line text.
func GetRuntimeInfo() string {
	var memStats runtime.MemStats
	runtime.ReadMemStats(&memStats)
	return fmt.Sprintf(`Public IP: %s
System time: %s
Uptime: %s
Number of CPUs: %d
Number of Goroutines: %d
GOMAXPROCS: %d
System memory usage: %d MBytes
`,
		env.GetPublicIP(),
		time.Now().String(),
		time.Now().Sub(global.StartupTime).String(),
		runtime.NumCPU(),
		runtime.NumGoroutine(),
		runtime.GOMAXPROCS(0),
		memStats.Sys/1024/1024)
}

// Return latest log entries in a multi-line text, one log entry per line. Latest log entry comes first.
func GetLatestGlobalLog() string {
	buf := new(bytes.Buffer)
	global.LatestLogEntries.Iterate(func(entry string) bool {
		buf.WriteString(entry)
		buf.WriteRune('\n')
		return true
	})
	return buf.String()
}

// Return stack traces of all currently running goroutines.
func GetGoroutineStacktraces() string {
	buf := new(bytes.Buffer)
	pprof.Lookup("goroutine").WriteTo(buf, 1)
	return buf.String()
}
<|endoftext|>


<commit_before>package collector

import "github.com/prometheus/client_golang/prometheus"

const namespace = "ipmi"

var (
	temperatures = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "temperatures"),
		"Contains the collected temperatures from IPMI",
		[]string{"sensor"},
		nil,
	)

	fanspeed = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "fan_speed"),
		"Fan Speed in RPM",
		[]string{"fan"},
		nil,
	)

	voltages = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "voltages"),
		"Contains the voltages from IPMI",
		[]string{"sensor"},
		nil,
	)

        current = prometheus.NewDesc(
                prometheus.BuildFQName(namespace, "", "current"),
                "Contains the current from IPMI",
                []string{"sensor"},
                nil,
        )

	intrusion = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "intrusion_status"),
		"Indicates if a chassis is open",
		nil,
		nil,
	)

	powersupply = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "power_supply_status"),
		"Indicates if a power supply is operational",
		[]string{"PSU"},
		nil,
	)
)
<commit_msg>Fix go format with go fmt<commit_after>package collector

import "github.com/prometheus/client_golang/prometheus"

const namespace = "ipmi"

var (
	temperatures = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "temperatures"),
		"Contains the collected temperatures from IPMI",
		[]string{"sensor"},
		nil,
	)

	fanspeed = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "fan_speed"),
		"Fan Speed in RPM",
		[]string{"fan"},
		nil,
	)

	voltages = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "voltages"),
		"Contains the voltages from IPMI",
		[]string{"sensor"},
		nil,
	)

	current = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "current"),
		"Contains the current from IPMI",
		[]string{"sensor"},
		nil,
	)

	intrusion = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "intrusion_status"),
		"Indicates if a chassis is open",
		nil,
		nil,
	)

	powersupply = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "", "power_supply_status"),
		"Indicates if a power supply is operational",
		[]string{"PSU"},
		nil,
	)
)
<|endoftext|>


<commit_before>package test

// This file handles the consul service.
// 1) We generate a config file with the port generated dynamically with BookPorts().
//    The reason is that the ports cannot be setup through the command line only.
//    It needs to be setup with a config file.
// 2) It guarantees that both the service port is listening and the leader is elected.

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	consul "github.com/hashicorp/consul/api"
)

const (
	consulChkTimesListen = 20                    // consulChkTimesListen is the number of times to retry for port listening.
	consulChkDelayListen = 50 * time.Millisecond // consulChkDelayListen is the waiting time for next retry for port listening.

	// Constants to check leader election mechanism, which usually takes 1-2 seconds.
	// Thus, we use 5 seconds as the time limit for the checking.
	consulChkTimesLeader = 10                     // consulChkTimesLeader is the number of times to retry for leader election.
	consulChkDelayLeader = 500 * time.Millisecond // consulChkDelayLeader is the waiting time for next retry for leader election.
)

func init() {
	RegisterService(Consul, func() Service {
		return &consulService{}
	})
}

// consulConfig is the config for consul service.
// It is basically a clone of the original config.
// Ref: https://github.com/hashicorp/consul/blob/master/command/agent/config.go#L96
//      https://www.consul.io/docs/agent/options.html
type consulConfig struct {
	BootstrapExpect int                `json:"bootstrap_expect"`
	Server          bool               `json:"server"`
	DataDir         string             `json:"data_dir"`
	Ports           *consulPortsConfig `json:"ports"`
}

// consulPortsConfig is the config for ports of consul service.
// It is basically a clone of the original Ports config.
// Ref: https://github.com/hashicorp/consul/blob/master/command/agent/config.go#L23
//      https://www.consul.io/docs/agent/options.html#ports
type consulPortsConfig struct {
	DNS     int `json:"dns"`      // DNS Query interface
	HTTP    int `json:"http"`     // HTTP API
	HTTPS   int `json:"https"`    // HTTPS API
	RPC     int `json:"rpc" `     // CLI RPC
	SerfLan int `json:"serf_lan"` // LAN gossip (Client + Server)
	SerfWan int `json:"serf_wan"` // WAN gossip (Server only)
	Server  int `json:"server"`   // Server internal RPC
}

// consulService is the consul service.
type consulService struct {
	// cmd is the command to run consul.
	cmd *exec.Cmd

	// port is the http port for consul service.
	port int
}

// Start runs the consul service and returns its port.
func (s *consulService) Start() (port int, err error) {
	if err := CheckExecutable("consul"); err != nil {
		return 0, fmt.Errorf("Consul is not installed: %v", err)
	}
	workDir, err := ioutil.TempDir("", "consul")
	if err != nil {
		return 0, fmt.Errorf("Fail to generate work dir: %v", err)
	}
	ports, err := BookPorts(5)
	if err != nil {
		return 0, fmt.Errorf("Fail to book ports for consul: %v", err)
	}
	config := &consulConfig{
		BootstrapExpect: 1,
		Server:          true,
		DataDir:         filepath.Join(workDir, "data"),
		Ports: &consulPortsConfig{
			DNS:     -1,
			HTTP:    ports[0],
			HTTPS:   -1,
			RPC:     ports[1],
			SerfLan: ports[2],
			SerfWan: ports[3],
			Server:  ports[4],
		},
	}
	b, err := json.Marshal(config)
	if err != nil {
		return 0, fmt.Errorf("Fail to json marshal consul config: %v", err)
	}
	configFile := filepath.Join(workDir, "consul.conf")
	if err := ioutil.WriteFile(configFile, b, os.ModePerm); err != nil {
		return 0, fmt.Errorf("Fail to write config file(path: %v): %v", configFile, err)
	}
	s.cmd = exec.Command(
		"consul", "agent", "-config-file", configFile,
	)
	if err := s.cmd.Start(); err != nil {
		return 0, fmt.Errorf("Fail to start consul: %v", err)
	}
	s.port = config.Ports.HTTP

	// Make sure that the server is running.
	if err := checkPortListening(s.port, consulChkTimesListen, consulChkDelayListen); err != nil {
		return 0, fmt.Errorf("Port is not listening: %v", err)
	}
	if err := checkLeaderElected(s.port, consulChkTimesLeader, consulChkDelayLeader); err != nil {
		return 0, fmt.Errorf("Leader election mechanism fails: %v", err)
	}
	return s.port, nil
}

// checkPortListening checks whether the port is listening or not.
// - port : The port to check.
// - times: Total number of checks.
// - delay: Time delay between checks.
func checkPortListening(port, times int, delay time.Duration) error {
	for i := 0; i < times; i++ {
		time.Sleep(delay)
		if CheckListening(port) {
			return nil
		}
	}
	return fmt.Errorf("Port(%v) is not listening within time: %v",
		port, time.Duration(int64(times))*delay)
}

// checkLeaderElected checks whether the leader is elected for the consul service or not.
// - port : The port to check.
// - times: Total number of checks.
// - delay: Time delay between checks.
func checkLeaderElected(port, times int, delay time.Duration) error {
	config := consul.DefaultConfig()
	config.Address = fmt.Sprintf("127.0.0.1:%d", port)
	client, err := consul.NewClient(config)
	if err != nil {
		return fmt.Errorf("Fail to build connection with consul agent: %v", err)
	}
	for i := 0; i < times; i++ {
		time.Sleep(delay)
		if leader, _ := client.Status().Leader(); leader != "" {
			return nil
		}
	}
	return fmt.Errorf("Fail to find the leader within time: %v", time.Duration(int64(times))*delay)
}

// Stop stops the consul service.
func (s *consulService) Stop() error {
	if err := s.cmd.Process.Signal(os.Interrupt); err != nil {
		return fmt.Errorf("Fail to stop consul service with INT: %v", err)
	}
	for i := 0; i < consulChkTimesListen; i++ {
		time.Sleep(consulChkDelayListen)
		if !CheckListening(s.port) {
			return nil
		}
	}
	return fmt.Errorf("Fail to stop consul service within time limit: %v",
		consulChkTimesListen*consulChkDelayListen)
}
<commit_msg>fix consul bind multiple IPs issue in Mac OSX<commit_after>package test

// This file handles the consul service.
// 1) We generate a config file with the port generated dynamically with BookPorts().
//    The reason is that the ports cannot be setup through the command line only.
//    It needs to be setup with a config file.
// 2) It guarantees that both the service port is listening and the leader is elected.

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	consul "github.com/hashicorp/consul/api"
)

const (
	consulChkTimesListen = 20                    // consulChkTimesListen is the number of times to retry for port listening.
	consulChkDelayListen = 50 * time.Millisecond // consulChkDelayListen is the waiting time for next retry for port listening.

	// Constants to check leader election mechanism, which usually takes 1-2 seconds.
	// Thus, we use 5 seconds as the time limit for the checking.
	consulChkTimesLeader = 10                     // consulChkTimesLeader is the number of times to retry for leader election.
	consulChkDelayLeader = 500 * time.Millisecond // consulChkDelayLeader is the waiting time for next retry for leader election.
)

func init() {
	RegisterService(Consul, func() Service {
		return &consulService{}
	})
}

// consulConfig is the config for consul service.
// It is basically a clone of the original config.
// Ref: https://github.com/hashicorp/consul/blob/master/command/agent/config.go#L96
//      https://www.consul.io/docs/agent/options.html
type consulConfig struct {
	BootstrapExpect int                `json:"bootstrap_expect"`
	Server          bool               `json:"server"`
	DataDir         string             `json:"data_dir"`
	Ports           *consulPortsConfig `json:"ports"`
}

// consulPortsConfig is the config for ports of consul service.
// It is basically a clone of the original Ports config.
// Ref: https://github.com/hashicorp/consul/blob/master/command/agent/config.go#L23
//      https://www.consul.io/docs/agent/options.html#ports
type consulPortsConfig struct {
	DNS     int `json:"dns"`      // DNS Query interface
	HTTP    int `json:"http"`     // HTTP API
	HTTPS   int `json:"https"`    // HTTPS API
	RPC     int `json:"rpc" `     // CLI RPC
	SerfLan int `json:"serf_lan"` // LAN gossip (Client + Server)
	SerfWan int `json:"serf_wan"` // WAN gossip (Server only)
	Server  int `json:"server"`   // Server internal RPC
}

// consulService is the consul service.
type consulService struct {
	// cmd is the command to run consul.
	cmd *exec.Cmd

	// port is the http port for consul service.
	port int
}

// Start runs the consul service and returns its port.
func (s *consulService) Start() (port int, err error) {
	if err := CheckExecutable("consul"); err != nil {
		return 0, fmt.Errorf("Consul is not installed: %v", err)
	}
	workDir, err := ioutil.TempDir("", "consul")
	if err != nil {
		return 0, fmt.Errorf("Fail to generate work dir: %v", err)
	}
	ports, err := BookPorts(5)
	if err != nil {
		return 0, fmt.Errorf("Fail to book ports for consul: %v", err)
	}
	config := &consulConfig{
		BootstrapExpect: 1,
		Server:          true,
		DataDir:         filepath.Join(workDir, "data"),
		Ports: &consulPortsConfig{
			DNS:     -1,
			HTTP:    ports[0],
			HTTPS:   -1,
			RPC:     ports[1],
			SerfLan: ports[2],
			SerfWan: ports[3],
			Server:  ports[4],
		},
	}
	b, err := json.Marshal(config)
	if err != nil {
		return 0, fmt.Errorf("Fail to json marshal consul config: %v", err)
	}
	configFile := filepath.Join(workDir, "consul.conf")
	if err := ioutil.WriteFile(configFile, b, os.ModePerm); err != nil {
		return 0, fmt.Errorf("Fail to write config file(path: %v): %v", configFile, err)
	}
	s.cmd = exec.Command(
		"consul", "agent", "-bind", "127.0.0.1", "-config-file", configFile,
	)
	if err := s.cmd.Start(); err != nil {
		return 0, fmt.Errorf("Fail to start consul: %v", err)
	}
	s.port = config.Ports.HTTP

	// Make sure that the server is running.
	if err := checkPortListening(s.port, consulChkTimesListen, consulChkDelayListen); err != nil {
		return 0, fmt.Errorf("Port is not listening: %v", err)
	}
	if err := checkLeaderElected(s.port, consulChkTimesLeader, consulChkDelayLeader); err != nil {
		return 0, fmt.Errorf("Leader election mechanism fails: %v", err)
	}
	return s.port, nil
}

// checkPortListening checks whether the port is listening or not.
// - port : The port to check.
// - times: Total number of checks.
// - delay: Time delay between checks.
func checkPortListening(port, times int, delay time.Duration) error {
	for i := 0; i < times; i++ {
		time.Sleep(delay)
		if CheckListening(port) {
			return nil
		}
	}
	return fmt.Errorf("Port(%v) is not listening within time: %v",
		port, time.Duration(int64(times))*delay)
}

// checkLeaderElected checks whether the leader is elected for the consul service or not.
// - port : The port to check.
// - times: Total number of checks.
// - delay: Time delay between checks.
func checkLeaderElected(port, times int, delay time.Duration) error {
	config := consul.DefaultConfig()
	config.Address = fmt.Sprintf("127.0.0.1:%d", port)
	client, err := consul.NewClient(config)
	if err != nil {
		return fmt.Errorf("Fail to build connection with consul agent: %v", err)
	}
	for i := 0; i < times; i++ {
		time.Sleep(delay)
		if leader, _ := client.Status().Leader(); leader != "" {
			return nil
		}
	}
	return fmt.Errorf("Fail to find the leader within time: %v", time.Duration(int64(times))*delay)
}

// Stop stops the consul service.
func (s *consulService) Stop() error {
	if err := s.cmd.Process.Signal(os.Interrupt); err != nil {
		return fmt.Errorf("Fail to stop consul service with INT: %v", err)
	}
	for i := 0; i < consulChkTimesListen; i++ {
		time.Sleep(consulChkDelayListen)
		if !CheckListening(s.port) {
			return nil
		}
	}
	return fmt.Errorf("Fail to stop consul service within time limit: %v",
		consulChkTimesListen*consulChkDelayListen)
}
<|endoftext|>


<commit_before>package comb

import (
	"math/big"
)

var (
	ONE = big.NewInt(1)
	TWO = big.NewInt(2)
)

// Comb takes a slice and a number of elements to choose from that slice and
// returns a function that given a slice will fill it in with a combination
// until none are left, at which point it will return false.
//
// This algorithm is based on one from TAOCP Vol. 4 by Donald Knuth.
func Generator(a []uint32, k uint32) func([]uint32) bool {
	// There is one way to choose 0 -- the empty set.
	if k == 0 {
		return func(_ []uint32) bool {
			return false
		}
	}
	var i, j, x uint32
	c := make([]uint32, k+3, k+3)
	for i = 1; i <= k; i++ {
		c[i] = i
	}
	c[k+1] = uint32(len(a)) + 1
	c[k+2] = 0
	j = k
	return func(v []uint32) bool {
		for i = k; i > 0; i-- {
			v[k-i] = a[c[i]-1]
		}

		if j > 0 {
			x = j + 1
			goto incr
		}
		if c[1]+1 < c[2] {
			c[1] += 1
			return true
		}
		j = 2
do_more:
		c[j-1] = j - 1
		x = c[j] + 1
		if x == c[j+1] {
			j++
			goto do_more
		}
		// If true, the algorithm is done.
		if j > k {
			return false
		}
incr:
		c[j] = x
		j--
		return true
	}
}

// Fact returns n! (factorial).
// Returns 1 for negative values.
func Fact(n *big.Int) *big.Int {
	if n.Cmp(TWO) == -1 {
		return ONE
	}

	sum := big.NewInt(1)
	n0 := new(big.Int).Set(n)
	for n0.Cmp(ONE) != -1 {
		sum.Mul(sum, n0)
		n0.Sub(n0, ONE)
	}
	return sum
}

// div returns m! / n!.
// This is an optimization to avoid calculating large factorials.
// Note: n must be less than m.
func div(m, n *big.Int) *big.Int {
	n0 := new(big.Int).Set(n)
	sum := new(big.Int).Add(n0, ONE)
	n0.Add(n0, TWO)
	for n0.Cmp(m) != 1  {
		sum.Mul(sum, n0)
		n0.Add(n0, ONE)
	}
	return sum
}

// Choose returns the number of combinations for n choose k.
func Count(n, k *big.Int) *big.Int {
	if n.Cmp(k) == 0 {
		return ONE
	}
	s := new(big.Int).Sub(n, k)
	if k.Cmp(s) == 1 {
		return s.Quo(div(n, k), Fact(s))
	}
	return s.Quo(div(n, s), Fact(k))
}
<commit_msg>Removed mutable global vars from comb.<commit_after>package comb

import (
	"math/big"
)

// Comb takes a slice and a number of elements to choose from that slice and
// returns a function that given a slice will fill it in with a combination
// until none are left, at which point it will return false.
//
// This algorithm is based on one from TAOCP Vol. 4 by Donald Knuth.
func Generator(a []uint32, k uint32) func([]uint32) bool {
	// There is one way to choose 0 -- the empty set.
	if k == 0 {
		return func(_ []uint32) bool {
			return false
		}
	}
	var i, j, x uint32
	c := make([]uint32, k+3, k+3)
	for i = 1; i <= k; i++ {
		c[i] = i
	}
	c[k+1] = uint32(len(a)) + 1
	c[k+2] = 0
	j = k
	return func(v []uint32) bool {
		for i = k; i > 0; i-- {
			v[k-i] = a[c[i]-1]
		}

		if j > 0 {
			x = j + 1
			goto incr
		}
		if c[1]+1 < c[2] {
			c[1] += 1
			return true
		}
		j = 2
do_more:
		c[j-1] = j - 1
		x = c[j] + 1
		if x == c[j+1] {
			j++
			goto do_more
		}
		// If true, the algorithm is done.
		if j > k {
			return false
		}
incr:
		c[j] = x
		j--
		return true
	}
}

// Fact returns n! (factorial).
// Returns 1 for negative values.
func Fact(n *big.Int) *big.Int {
	if n.Cmp(big.NewInt(2)) == -1 {
		return big.NewInt(1)
	}

	sum := big.NewInt(1)
	n0 := new(big.Int).Set(n)
	for n0.Cmp(big.NewInt(1)) != -1 {
		sum.Mul(sum, n0)
		n0.Sub(n0, big.NewInt(1))
	}
	return sum
}

// div returns m! / n!.
// This is an optimization to avoid calculating large factorials.
// Note: n must be less than m.
func div(m, n *big.Int) *big.Int {
	n0 := new(big.Int).Set(n)
	sum := new(big.Int).Add(n0, big.NewInt(1))
	n0.Add(n0, big.NewInt(2))
	for n0.Cmp(m) != 1  {
		sum.Mul(sum, n0)
		n0.Add(n0, big.NewInt(1))
	}
	return sum
}

// Choose returns the number of combinations for n choose k.
func Count(n, k *big.Int) *big.Int {
	if n.Cmp(k) == 0 {
		return big.NewInt(1)
	}
	s := new(big.Int).Sub(n, k)
	if k.Cmp(s) == 1 {
		return s.Quo(div(n, k), Fact(s))
	}
	return s.Quo(div(n, s), Fact(k))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/montanaflynn/stats"
)

func main() {
	a, _ := stats.Min([]float64{1.1, 2, 3, 4, 5})
	fmt.Println(a) // 1.1

	a, _ = stats.Max([]float64{1.1, 2, 3, 4, 5})
	fmt.Println(a) // 5

	a, _ = stats.Sum([]float64{1.1, 2.2, 3.3})
	fmt.Println(a) // 6.6

	a, _ = stats.Mean([]float64{1, 2, 3, 4, 5})
	fmt.Println(a) // 3

	a, _ = stats.Median([]float64{1, 2, 3, 4, 5, 6, 7})
	fmt.Println(a) // 4

	m, _ := stats.Mode([]float64{5, 5, 3, 3, 4, 2, 1})
	fmt.Println(m) // [5 3]

	a, _ = stats.VarP([]float64{1,2,3,4,5})
	fmt.Println(a) // 2

	a, _ = stats.VarS([]float64{1,2,3,4,5})
	fmt.Println(a) // 2.5

	a, _ = stats.StdDevP([]float64{1, 2, 3})
	fmt.Println(a) // 0.816496580927726

	a, _ = stats.StdDevS([]float64{1, 2, 3})
	fmt.Println(a) // 1

	a, _ = stats.Percentile([]float64{1, 2, 3, 4, 5}, 75)
	fmt.Println(a) // 4

	a, _ = stats.PercentileNearestRank([]float64{35, 20, 15, 40, 50}, 75)
	fmt.Println(a) // 40

	a, _ = stats.Round(5.3253543, 3)
	fmt.Println(a) // 5.325

	c := []stats.Coordinate{
		{1, 2.3},
		{2, 3.3},
		{3, 3.7},
		{4, 4.3},
		{5, 5.3},
	}

	r, _ := stats.LinReg(c)
	fmt.Println(r) // [{1 2.3800000000000026} {2 3.0800000000000014} {3 3.7800000000000002} {4 4.479999999999999} {5 5.179999999999998}]

	r, _ = stats.ExpReg(c)
	fmt.Println(r) // [{1 2.5150181024736638} {2 3.032084111136781} {3 3.6554544271334493} {4 4.406984298281804} {5 5.313022222665875}]

	r, _ = stats.LogReg(c)
	fmt.Println(r) // [{1 2.1520822363811702} {2 3.3305559222492214} {3 4.019918836568674} {4 4.509029608117273} {5 4.888413396683663}]

	s, _ := stats.Sample([]float64{0.1,0.2,0.3,0.4}, 3, false)
	fmt.Println(s) // [0.2,0.4,0.3]

	s, _ = stats.Sample([]float64{0.1,0.2,0.3,0.4}, 10, true)
	fmt.Println(s) // [0.2,0.2,0.4,0.1,0.2,0.4,0.3,0.2,0.2,0.1]

	q, _ := stats.Quartile([]float64{7, 15, 36, 39, 40, 41})
	fmt.Println(q) // {15 37.5 40}

	iqr, _ := stats.InterQuartileRange([]float64{102, 104, 105, 107, 108, 109, 110, 112, 115, 116, 118})
	fmt.Println(iqr) // 10

	mh, _ := stats.Midhinge( []float64{1, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13})
	fmt.Println(mh) // 7.5

	tr, _ := stats.Trimean( []float64{1, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13})
	fmt.Println(tr) // 7.25

	o, _ := stats.QuartileOutliers([]float64{-1000, 1, 3, 4, 4, 6, 6, 6, 6, 7, 8, 15, 18, 100})
	fmt.Printf("%+v\n", o) //  {Mild:[15 18] Extreme:[-1000 100]}
}<commit_msg>Run go fmt to clean up formatting<commit_after>package main

import (
	"fmt"
	"github.com/montanaflynn/stats"
)

func main() {
	a, _ := stats.Min([]float64{1.1, 2, 3, 4, 5})
	fmt.Println(a) // 1.1

	a, _ = stats.Max([]float64{1.1, 2, 3, 4, 5})
	fmt.Println(a) // 5

	a, _ = stats.Sum([]float64{1.1, 2.2, 3.3})
	fmt.Println(a) // 6.6

	a, _ = stats.Mean([]float64{1, 2, 3, 4, 5})
	fmt.Println(a) // 3

	a, _ = stats.Median([]float64{1, 2, 3, 4, 5, 6, 7})
	fmt.Println(a) // 4

	m, _ := stats.Mode([]float64{5, 5, 3, 3, 4, 2, 1})
	fmt.Println(m) // [5 3]

	a, _ = stats.VarP([]float64{1, 2, 3, 4, 5})
	fmt.Println(a) // 2

	a, _ = stats.VarS([]float64{1, 2, 3, 4, 5})
	fmt.Println(a) // 2.5

	a, _ = stats.StdDevP([]float64{1, 2, 3})
	fmt.Println(a) // 0.816496580927726

	a, _ = stats.StdDevS([]float64{1, 2, 3})
	fmt.Println(a) // 1

	a, _ = stats.Percentile([]float64{1, 2, 3, 4, 5}, 75)
	fmt.Println(a) // 4

	a, _ = stats.PercentileNearestRank([]float64{35, 20, 15, 40, 50}, 75)
	fmt.Println(a) // 40

	a, _ = stats.Round(5.3253543, 3)
	fmt.Println(a) // 5.325

	c := []stats.Coordinate{
		{1, 2.3},
		{2, 3.3},
		{3, 3.7},
		{4, 4.3},
		{5, 5.3},
	}

	r, _ := stats.LinReg(c)
	fmt.Println(r) // [{1 2.3800000000000026} {2 3.0800000000000014} {3 3.7800000000000002} {4 4.479999999999999} {5 5.179999999999998}]

	r, _ = stats.ExpReg(c)
	fmt.Println(r) // [{1 2.5150181024736638} {2 3.032084111136781} {3 3.6554544271334493} {4 4.406984298281804} {5 5.313022222665875}]

	r, _ = stats.LogReg(c)
	fmt.Println(r) // [{1 2.1520822363811702} {2 3.3305559222492214} {3 4.019918836568674} {4 4.509029608117273} {5 4.888413396683663}]

	s, _ := stats.Sample([]float64{0.1, 0.2, 0.3, 0.4}, 3, false)
	fmt.Println(s) // [0.2,0.4,0.3]

	s, _ = stats.Sample([]float64{0.1, 0.2, 0.3, 0.4}, 10, true)
	fmt.Println(s) // [0.2,0.2,0.4,0.1,0.2,0.4,0.3,0.2,0.2,0.1]

	q, _ := stats.Quartile([]float64{7, 15, 36, 39, 40, 41})
	fmt.Println(q) // {15 37.5 40}

	iqr, _ := stats.InterQuartileRange([]float64{102, 104, 105, 107, 108, 109, 110, 112, 115, 116, 118})
	fmt.Println(iqr) // 10

	mh, _ := stats.Midhinge([]float64{1, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13})
	fmt.Println(mh) // 7.5

	tr, _ := stats.Trimean([]float64{1, 3, 4, 4, 6, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 11, 12, 13})
	fmt.Println(tr) // 7.25

	o, _ := stats.QuartileOutliers([]float64{-1000, 1, 3, 4, 4, 6, 6, 6, 6, 7, 8, 15, 18, 100})
	fmt.Printf("%+v\n", o) //  {Mild:[15 18] Extreme:[-1000 100]}
}<|endoftext|>


<commit_before>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package examples_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"testing"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	"github.com/golang/glog"
)

func validateObject(obj runtime.Object) (errors []error) {
	switch t := obj.(type) {
	case *api.ReplicationController:
		errors = validation.ValidateManifest(&t.DesiredState.PodTemplate.DesiredState.Manifest)
	case *api.ReplicationControllerList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	case *api.Service:
		errors = validation.ValidateService(t)
	case *api.ServiceList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	case *api.Pod:
		errors = validation.ValidateManifest(&t.DesiredState.Manifest)
	case *api.PodList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	default:
		return []error{fmt.Errorf("no validation defined for %#v", obj)}
	}
	return errors
}

func walkJSONFiles(inDir string, fn func(name, path string, data []byte)) error {
	err := filepath.Walk(inDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() && path != inDir {
			return filepath.SkipDir
		}
		name := filepath.Base(path)
		ext := filepath.Ext(name)
		if ext != "" {
			name = name[:len(name)-len(ext)]
		}
		if !(ext == ".json" || ext == ".yaml") {
			return nil
		}
		glog.Infof("Testing %s", path)
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}
		fn(name, path, data)
		return nil
	})
	return err
}

func TestExampleObjectSchemas(t *testing.T) {
	cases := map[string]map[string]runtime.Object{
		"../api/examples": {
			"controller":       &api.ReplicationController{},
			"controller-list":  &api.ReplicationControllerList{},
			"pod":              &api.Pod{},
			"pod-list":         &api.PodList{},
			"service":          &api.Service{},
			"external-service": &api.Service{},
			"service-list":     &api.ServiceList{},
		},
		"../examples/guestbook": {
			"frontend-controller":    &api.ReplicationController{},
			"redis-slave-controller": &api.ReplicationController{},
			"redis-master":           &api.Pod{},
			"frontend-service":       &api.Service{},
			"redis-master-service":   &api.Service{},
			"redis-slave-service":    &api.Service{},
		},
		"../examples/walkthrough": {
			"pod1": &api.Pod{},
			"pod2": &api.Pod{},
		},
	}

	for path, expected := range cases {
		tested := 0
		err := walkJSONFiles(path, func(name, path string, data []byte) {
			expectedType, found := expected[name]
			if !found {
				t.Errorf("%s does not have a test case defined", path)
				return
			}
			tested += 1
			if err := latest.Codec.DecodeInto(data, expectedType); err != nil {
				t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data))
				return
			}
			if errors := validateObject(expectedType); len(errors) > 0 {
				t.Errorf("%s did not validate correctly: %v", path, errors)
			}
		})
		if err != nil {
			t.Errorf("Expected no error, Got %v", err)
		}
		if tested != len(expected) {
			t.Errorf("Expected %d examples, Got %d", len(expected), tested)
		}
	}
}

var sampleRegexp = regexp.MustCompile("(?ms)^```(?:(?P<type>yaml)\\w*\\n(?P<content>.+?)|\\w*\\n(?P<content>\\{.+?\\}))\\w*\\n^```")
var subsetRegexp = regexp.MustCompile("(?ms)\\.{3}")

func TestReadme(t *testing.T) {
	paths := []string{
		"../README.md",
		"../examples/walkthrough/README.md",
	}

	for _, path := range paths {
		data, err := ioutil.ReadFile(path)
		if err != nil {
			t.Errorf("Unable to read file %s: %v", path, err)
			continue
		}

		matches := sampleRegexp.FindAllStringSubmatch(string(data), -1)
		if matches == nil {
			continue
		}
		for _, match := range matches {
			var content, subtype string
			for i, name := range sampleRegexp.SubexpNames() {
				if name == "type" {
					subtype = match[i]
				}
				if name == "content" && match[i] != "" {
					content = match[i]
				}
			}
			if subtype == "yaml" && subsetRegexp.FindString(content) != "" {
				t.Logf("skipping (%s): \n%s", subtype, content)
				continue
			}

			//t.Logf("testing (%s): \n%s", subtype, content)
			expectedType := &api.Pod{}
			if err := latest.Codec.DecodeInto([]byte(content), expectedType); err != nil {
				t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(content))
				continue
			}
			if errors := validateObject(expectedType); len(errors) > 0 {
				t.Errorf("%s did not validate correctly: %v", path, errors)
			}
			_, err := latest.Codec.Encode(expectedType)
			if err != nil {
				t.Errorf("Could not encode object: %v", err)
				continue
			}
		}
	}
}
<commit_msg>Fix examples test by setting a context prior to validation<commit_after>/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package examples_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"testing"

	"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/api/validation"
	"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
	"github.com/golang/glog"
)

func validateObject(obj runtime.Object) (errors []error) {
	ctx := api.NewDefaultContext()
	switch t := obj.(type) {
	case *api.ReplicationController:
		errors = validation.ValidateManifest(&t.DesiredState.PodTemplate.DesiredState.Manifest)
	case *api.ReplicationControllerList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	case *api.Service:
		api.ValidNamespaceOnCreateOrUpdate(ctx, &t.JSONBase)
		errors = validation.ValidateService(t)
	case *api.ServiceList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	case *api.Pod:
		api.ValidNamespaceOnCreateOrUpdate(ctx, &t.JSONBase)
		errors = validation.ValidateManifest(&t.DesiredState.Manifest)
	case *api.PodList:
		for i := range t.Items {
			errors = append(errors, validateObject(&t.Items[i])...)
		}
	default:
		return []error{fmt.Errorf("no validation defined for %#v", obj)}
	}
	return errors
}

func walkJSONFiles(inDir string, fn func(name, path string, data []byte)) error {
	err := filepath.Walk(inDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if info.IsDir() && path != inDir {
			return filepath.SkipDir
		}
		name := filepath.Base(path)
		ext := filepath.Ext(name)
		if ext != "" {
			name = name[:len(name)-len(ext)]
		}
		if !(ext == ".json" || ext == ".yaml") {
			return nil
		}
		glog.Infof("Testing %s", path)
		data, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}
		fn(name, path, data)
		return nil
	})
	return err
}

func TestExampleObjectSchemas(t *testing.T) {
	cases := map[string]map[string]runtime.Object{
		"../api/examples": {
			"controller":       &api.ReplicationController{},
			"controller-list":  &api.ReplicationControllerList{},
			"pod":              &api.Pod{},
			"pod-list":         &api.PodList{},
			"service":          &api.Service{},
			"external-service": &api.Service{},
			"service-list":     &api.ServiceList{},
		},
		"../examples/guestbook": {
			"frontend-controller":    &api.ReplicationController{},
			"redis-slave-controller": &api.ReplicationController{},
			"redis-master":           &api.Pod{},
			"frontend-service":       &api.Service{},
			"redis-master-service":   &api.Service{},
			"redis-slave-service":    &api.Service{},
		},
		"../examples/walkthrough": {
			"pod1": &api.Pod{},
			"pod2": &api.Pod{},
		},
	}

	for path, expected := range cases {
		tested := 0
		err := walkJSONFiles(path, func(name, path string, data []byte) {
			expectedType, found := expected[name]
			if !found {
				t.Errorf("%s does not have a test case defined", path)
				return
			}
			tested += 1
			if err := latest.Codec.DecodeInto(data, expectedType); err != nil {
				t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data))
				return
			}
			if errors := validateObject(expectedType); len(errors) > 0 {
				t.Errorf("%s did not validate correctly: %v", path, errors)
			}
		})
		if err != nil {
			t.Errorf("Expected no error, Got %v", err)
		}
		if tested != len(expected) {
			t.Errorf("Expected %d examples, Got %d", len(expected), tested)
		}
	}
}

var sampleRegexp = regexp.MustCompile("(?ms)^```(?:(?P<type>yaml)\\w*\\n(?P<content>.+?)|\\w*\\n(?P<content>\\{.+?\\}))\\w*\\n^```")
var subsetRegexp = regexp.MustCompile("(?ms)\\.{3}")

func TestReadme(t *testing.T) {
	paths := []string{
		"../README.md",
		"../examples/walkthrough/README.md",
	}

	for _, path := range paths {
		data, err := ioutil.ReadFile(path)
		if err != nil {
			t.Errorf("Unable to read file %s: %v", path, err)
			continue
		}

		matches := sampleRegexp.FindAllStringSubmatch(string(data), -1)
		if matches == nil {
			continue
		}
		for _, match := range matches {
			var content, subtype string
			for i, name := range sampleRegexp.SubexpNames() {
				if name == "type" {
					subtype = match[i]
				}
				if name == "content" && match[i] != "" {
					content = match[i]
				}
			}
			if subtype == "yaml" && subsetRegexp.FindString(content) != "" {
				t.Logf("skipping (%s): \n%s", subtype, content)
				continue
			}

			//t.Logf("testing (%s): \n%s", subtype, content)
			expectedType := &api.Pod{}
			if err := latest.Codec.DecodeInto([]byte(content), expectedType); err != nil {
				t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(content))
				continue
			}
			if errors := validateObject(expectedType); len(errors) > 0 {
				t.Errorf("%s did not validate correctly: %v", path, errors)
			}
			_, err := latest.Codec.Encode(expectedType)
			if err != nil {
				t.Errorf("Could not encode object: %v", err)
				continue
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	pbs "github.com/brotherlogic/goserver/proto"
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	runner *Runner
	disk   diskChecker
}

func getIP(name string, server string) (string, int) {
	conn, _ := grpc.Dial("192.168.86.34:50055", grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	entry := pbd.RegistryEntry{Name: name, Identifier: server}
	r, err := registry.Discover(context.Background(), &entry)

	if err != nil {
		log.Printf("Lookup failed for %v,%v -> %v", name, server, err)
		return "", -1
	}

	return r.Ip, int(r.Port)
}

// updateState of the runner command
func updateState(com *runnerCommand) {
	elems := strings.Split(com.details.Spec.Name, "/")
	dServer, dPort := getIP(elems[len(elems)-1], com.details.Spec.Server)

	if dPort > 0 {
		dConn, err := grpc.Dial(dServer+":"+strconv.Itoa(dPort), grpc.WithInsecure())
		if err != nil {
			panic(err)
		}
		defer dConn.Close()

		c := pbs.NewGoserverServiceClient(dConn)
		_, err = c.IsAlive(context.Background(), &pbs.Alive{})
		com.details.Running = (err == nil)
	} else {
		//Mark as false if we can't locate the job
		com.details.Running = false
	}
}

// BuildJob builds out a job
func (s *Server) BuildJob(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.Checkout(in.Name)
	return &pb.Empty{}, nil
}

// List lists all running jobs
func (s *Server) List(ctx context.Context, in *pb.Empty) (*pb.JobList, error) {
	details := &pb.JobList{}
	for _, job := range s.runner.backgroundTasks {
		updateState(job)
		details.Details = append(details.Details, job.details)
	}

	return details, nil
}

// Run runs a background task
func (s *Server) Run(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.Run(in)
	return &pb.Empty{}, nil
}

// Kill a background task
func (s *Server) Kill(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.kill(in)
	return &pb.Empty{}, nil
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildSlaveServer(server, &s)
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

//Init builds the default runner framework
func Init() *Runner {
	r := &Runner{gopath: "goautobuild"}
	r.runner = runCommand
	go r.run()
	return r
}

func runCommand(c *runnerCommand) {
	log.Printf("RUNNING COMMAND: %v", c)
	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	if len(home) == 0 {

	}
	gpath := home + "/gobuild"
	c.command.Path = strings.Replace(c.command.Path, "$GOPATH", gpath, -1)
	for i := range c.command.Args {
		c.command.Args[i] = strings.Replace(c.command.Args[i], "$GOPATH", gpath, -1)
	}

	path := fmt.Sprintf("GOPATH=" + home + "/gobuild")
	found := false
	log.Printf("HERE = %v", c.command.Env)
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	log.Printf("ENV = %v", envl)
	c.command.Env = envl

	out, err := c.command.StdoutPipe()
	out2, err2 := c.command.StderrPipe()
	if err != nil {
		log.Printf("Blah: %v", err)
	}

	if err2 != nil {
		log.Printf("Blah2: %v", err)
	}

	log.Printf("%v, %v and %v", c.command.Path, c.command.Args, c.command.Env)
	c.command.Start()

	if !c.background {
		buf := new(bytes.Buffer)
		buf.ReadFrom(out)
		str := buf.String()

		buf2 := new(bytes.Buffer)
		buf2.ReadFrom(out2)
		str2 := buf2.String()
		log.Printf("%v and %v", str, str2)

		c.command.Wait()
		c.output = str
		c.complete = true
	}
	log.Printf("DONE")
}

func (diskChecker prodDiskChecker) diskUsage(path string) int64 {
	return diskUsage(path)
}

func (s *Server) rebuildLoop() {
	for true {
		time.Sleep(time.Minute)

		var rebuildList []*pb.JobSpec
		for _, job := range s.runner.backgroundTasks {
			if time.Since(job.started) > time.Hour {
				rebuildList = append(rebuildList, job.details.Spec)
			}
		}

		for _, job := range rebuildList {
			s.runner.Rebuild(job)
		}
	}
}

func main() {
	s := Server{&goserver.GoServer{}, Init(), prodDiskChecker{}}
	s.Register = s
	s.PrepServer()
	s.RegisterServingTask(s.rebuildLoop)
	s.RegisterServer("gobuildslave", false)
	s.Serve()
}
<commit_msg>Added logging to rebuild loop<commit_after>package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pb "github.com/brotherlogic/gobuildslave/proto"
	pbs "github.com/brotherlogic/goserver/proto"
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	runner *Runner
	disk   diskChecker
}

func getIP(name string, server string) (string, int) {
	conn, _ := grpc.Dial("192.168.86.34:50055", grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	entry := pbd.RegistryEntry{Name: name, Identifier: server}
	r, err := registry.Discover(context.Background(), &entry)

	if err != nil {
		log.Printf("Lookup failed for %v,%v -> %v", name, server, err)
		return "", -1
	}

	return r.Ip, int(r.Port)
}

// updateState of the runner command
func updateState(com *runnerCommand) {
	elems := strings.Split(com.details.Spec.Name, "/")
	dServer, dPort := getIP(elems[len(elems)-1], com.details.Spec.Server)

	if dPort > 0 {
		dConn, err := grpc.Dial(dServer+":"+strconv.Itoa(dPort), grpc.WithInsecure())
		if err != nil {
			panic(err)
		}
		defer dConn.Close()

		c := pbs.NewGoserverServiceClient(dConn)
		_, err = c.IsAlive(context.Background(), &pbs.Alive{})
		com.details.Running = (err == nil)
	} else {
		//Mark as false if we can't locate the job
		com.details.Running = false
	}
}

// BuildJob builds out a job
func (s *Server) BuildJob(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.Checkout(in.Name)
	return &pb.Empty{}, nil
}

// List lists all running jobs
func (s *Server) List(ctx context.Context, in *pb.Empty) (*pb.JobList, error) {
	details := &pb.JobList{}
	for _, job := range s.runner.backgroundTasks {
		updateState(job)
		details.Details = append(details.Details, job.details)
	}

	return details, nil
}

// Run runs a background task
func (s *Server) Run(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.Run(in)
	return &pb.Empty{}, nil
}

// Kill a background task
func (s *Server) Kill(ctx context.Context, in *pb.JobSpec) (*pb.Empty, error) {
	s.runner.kill(in)
	return &pb.Empty{}, nil
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildSlaveServer(server, &s)
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

//Init builds the default runner framework
func Init() *Runner {
	r := &Runner{gopath: "goautobuild"}
	r.runner = runCommand
	go r.run()
	return r
}

func runCommand(c *runnerCommand) {
	log.Printf("RUNNING COMMAND: %v", c)
	env := os.Environ()
	home := ""
	for _, s := range env {
		if strings.HasPrefix(s, "HOME=") {
			home = s[5:]
		}
	}

	if len(home) == 0 {

	}
	gpath := home + "/gobuild"
	c.command.Path = strings.Replace(c.command.Path, "$GOPATH", gpath, -1)
	for i := range c.command.Args {
		c.command.Args[i] = strings.Replace(c.command.Args[i], "$GOPATH", gpath, -1)
	}

	path := fmt.Sprintf("GOPATH=" + home + "/gobuild")
	found := false
	log.Printf("HERE = %v", c.command.Env)
	envl := os.Environ()
	for i, blah := range envl {
		if strings.HasPrefix(blah, "GOPATH") {
			envl[i] = path
			found = true
		}
	}
	if !found {
		envl = append(envl, path)
	}
	log.Printf("ENV = %v", envl)
	c.command.Env = envl

	out, err := c.command.StdoutPipe()
	out2, err2 := c.command.StderrPipe()
	if err != nil {
		log.Printf("Blah: %v", err)
	}

	if err2 != nil {
		log.Printf("Blah2: %v", err)
	}

	log.Printf("%v, %v and %v", c.command.Path, c.command.Args, c.command.Env)
	c.command.Start()

	if !c.background {
		buf := new(bytes.Buffer)
		buf.ReadFrom(out)
		str := buf.String()

		buf2 := new(bytes.Buffer)
		buf2.ReadFrom(out2)
		str2 := buf2.String()
		log.Printf("%v and %v", str, str2)

		c.command.Wait()
		c.output = str
		c.complete = true
	}
	log.Printf("DONE")
}

func (diskChecker prodDiskChecker) diskUsage(path string) int64 {
	return diskUsage(path)
}

func (s *Server) rebuildLoop() {
	for true {
		time.Sleep(time.Minute)

		var rebuildList []*pb.JobSpec
		for _, job := range s.runner.backgroundTasks {
			log.Printf("Job %v", job)
			if time.Since(job.started) > time.Hour {
				log.Printf("Added to rebuild list (%v)", job)
				rebuildList = append(rebuildList, job.details.Spec)
			}
		}

		log.Printf("Rebuilding %v", rebuildList)
		for _, job := range rebuildList {
			s.runner.Rebuild(job)
		}
	}
}

func main() {
	s := Server{&goserver.GoServer{}, Init(), prodDiskChecker{}}
	s.Register = s
	s.PrepServer()
	s.RegisterServingTask(s.rebuildLoop)
	s.RegisterServer("gobuildslave", false)
	s.Serve()
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Waiting for FDs via kqueue/kevent.

package net

import (
	"os"
	"syscall"
)

type pollster struct {
	kq       int
	eventbuf [10]syscall.Kevent_t
	events   []syscall.Kevent_t
}

func newpollster() (p *pollster, err os.Error) {
	p = new(pollster)
	var e int
	if p.kq, e = syscall.Kqueue(); e != 0 {
		return nil, os.NewSyscallError("kqueue", e)
	}
	p.events = p.eventbuf[0:0]
	return p, nil
}

func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_ADD - add event to kqueue list
	// EV_ONESHOT - delete the event the first time it triggers
	flags := syscall.EV_ADD
	if !repeat {
		flags |= syscall.EV_ONESHOT
	}
	syscall.SetKevent(ev, fd, kmode, flags)

	n, e := syscall.Kevent(p.kq, &events, nil, nil)
	if e != 0 {
		return os.NewSyscallError("kevent", e)
	}
	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
		return os.NewSyscallError("kqueue phase error", e)
	}
	if ev.Data != 0 {
		return os.Errno(int(ev.Data))
	}
	return nil
}

func (p *pollster) DelFD(fd int, mode int) {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_DELETE - delete event from kqueue list
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
	syscall.Kevent(p.kq, &events, nil, nil)
}

func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
	var t *syscall.Timespec
	for len(p.events) == 0 {
		if nsec > 0 {
			if t == nil {
				t = new(syscall.Timespec)
			}
			*t = syscall.NsecToTimespec(nsec)
		}
		nn, e := syscall.Kevent(p.kq, nil, &p.eventbuf, t)
		if e != 0 {
			if e == syscall.EINTR {
				continue
			}
			return -1, 0, os.NewSyscallError("kevent", e)
		}
		if nn == 0 {
			return -1, 0, nil
		}
		p.events = p.eventbuf[0:nn]
	}
	ev := &p.events[0]
	p.events = p.events[1:]
	fd = int(ev.Ident)
	if ev.Filter == syscall.EVFILT_READ {
		mode = 'r'
	} else {
		mode = 'w'
	}
	return fd, mode, nil
}

func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
<commit_msg>net: fix freebsd build<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Waiting for FDs via kqueue/kevent.

package net

import (
	"os"
	"syscall"
)

type pollster struct {
	kq       int
	eventbuf [10]syscall.Kevent_t
	events   []syscall.Kevent_t
}

func newpollster() (p *pollster, err os.Error) {
	p = new(pollster)
	var e int
	if p.kq, e = syscall.Kqueue(); e != 0 {
		return nil, os.NewSyscallError("kqueue", e)
	}
	p.events = p.eventbuf[0:0]
	return p, nil
}

func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_ADD - add event to kqueue list
	// EV_ONESHOT - delete the event the first time it triggers
	flags := syscall.EV_ADD
	if !repeat {
		flags |= syscall.EV_ONESHOT
	}
	syscall.SetKevent(ev, fd, kmode, flags)

	n, e := syscall.Kevent(p.kq, events[:], nil, nil)
	if e != 0 {
		return os.NewSyscallError("kevent", e)
	}
	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
		return os.NewSyscallError("kqueue phase error", e)
	}
	if ev.Data != 0 {
		return os.Errno(int(ev.Data))
	}
	return nil
}

func (p *pollster) DelFD(fd int, mode int) {
	var kmode int
	if mode == 'r' {
		kmode = syscall.EVFILT_READ
	} else {
		kmode = syscall.EVFILT_WRITE
	}
	var events [1]syscall.Kevent_t
	ev := &events[0]
	// EV_DELETE - delete event from kqueue list
	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
	syscall.Kevent(p.kq, events[:], nil, nil)
}

func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
	var t *syscall.Timespec
	for len(p.events) == 0 {
		if nsec > 0 {
			if t == nil {
				t = new(syscall.Timespec)
			}
			*t = syscall.NsecToTimespec(nsec)
		}
		nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
		if e != 0 {
			if e == syscall.EINTR {
				continue
			}
			return -1, 0, os.NewSyscallError("kevent", e)
		}
		if nn == 0 {
			return -1, 0, nil
		}
		p.events = p.eventbuf[0:nn]
	}
	ev := &p.events[0]
	p.events = p.events[1:]
	fd = int(ev.Ident)
	if ev.Filter == syscall.EVFILT_READ {
		mode = 'r'
	} else {
		mode = 'w'
	}
	return fd, mode, nil
}

func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// TODO(cw): ListenPacket test, Read() test, ipv6 test &
// Dial()/Listen() level tests

package net

import (
	"bytes"
	"flag"
	"os"
	"testing"
)

const ICMP_ECHO_REQUEST = 8
const ICMP_ECHO_REPLY = 0

// returns a suitable 'ping request' packet, with id & seq and a
// payload length of pktlen
func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
	p := make([]byte, pktlen)
	copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))

	p[0] = ICMP_ECHO_REQUEST // type
	p[1] = 0                 // code
	p[2] = 0                 // cksum
	p[3] = 0                 // cksum
	p[4] = uint8(id >> 8)    // id
	p[5] = uint8(id & 0xff)  // id
	p[6] = uint8(seq >> 8)   // sequence
	p[7] = uint8(seq & 0xff) // sequence

	// calculate icmp checksum
	cklen := len(p)
	s := uint32(0)
	for i := 0; i < (cklen - 1); i += 2 {
		s += uint32(p[i+1])<<8 | uint32(p[i])
	}
	if cklen&1 == 1 {
		s += uint32(p[cklen-1])
	}
	s = (s >> 16) + (s & 0xffff)
	s = s + (s >> 16)

	// place checksum back in header; using ^= avoids the
	// assumption the checksum bytes are zero
	p[2] ^= uint8(^s & 0xff)
	p[3] ^= uint8(^s >> 8)

	return p
}

func parsePingReply(p []byte) (id, seq int) {
	id = int(p[4])<<8 | int(p[5])
	seq = int(p[6])<<8 | int(p[7])
	return
}

var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
var dsthost = flag.String("dsthost", "localhost", "Destination for the ICMP ECHO request")

// test (raw) IP socket using ICMP
func TestICMP(t *testing.T) {
	if os.Getuid() != 0 {
		t.Logf("test disabled; must be root")
		return
	}

	var laddr *IPAddr
	if *srchost != "" {
		laddr, err := ResolveIPAddr(*srchost)
		if err != nil {
			t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *srchost, laddr, err)
		}
	}

	raddr, err := ResolveIPAddr(*dsthost)
	if err != nil {
		t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *dsthost, raddr, err)
	}

	c, err := ListenIP("ip4:icmp", laddr)
	if err != nil {
		t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
	}

	sendid := os.Getpid() & 0xffff
	const sendseq = 61455
	const pingpktlen = 128
	sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))

	n, err := c.WriteToIP(sendpkt, raddr)
	if err != nil || n != pingpktlen {
		t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
	}

	c.SetTimeout(100e6)
	resp := make([]byte, 1024)
	for {
		n, from, err := c.ReadFrom(resp)
		if err != nil {
			t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
		}
		if resp[0] != ICMP_ECHO_REPLY {
			continue
		}
		rcvid, rcvseq := parsePingReply(resp)
		if rcvid != sendid || rcvseq != sendseq {
			t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
		}
		return
	}
	t.Fatalf("saw no ping return")
}
<commit_msg>net: fix laddr typo in test code.<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// TODO(cw): ListenPacket test, Read() test, ipv6 test &
// Dial()/Listen() level tests

package net

import (
	"bytes"
	"flag"
	"os"
	"testing"
)

const ICMP_ECHO_REQUEST = 8
const ICMP_ECHO_REPLY = 0

// returns a suitable 'ping request' packet, with id & seq and a
// payload length of pktlen
func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
	p := make([]byte, pktlen)
	copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))

	p[0] = ICMP_ECHO_REQUEST // type
	p[1] = 0                 // code
	p[2] = 0                 // cksum
	p[3] = 0                 // cksum
	p[4] = uint8(id >> 8)    // id
	p[5] = uint8(id & 0xff)  // id
	p[6] = uint8(seq >> 8)   // sequence
	p[7] = uint8(seq & 0xff) // sequence

	// calculate icmp checksum
	cklen := len(p)
	s := uint32(0)
	for i := 0; i < (cklen - 1); i += 2 {
		s += uint32(p[i+1])<<8 | uint32(p[i])
	}
	if cklen&1 == 1 {
		s += uint32(p[cklen-1])
	}
	s = (s >> 16) + (s & 0xffff)
	s = s + (s >> 16)

	// place checksum back in header; using ^= avoids the
	// assumption the checksum bytes are zero
	p[2] ^= uint8(^s & 0xff)
	p[3] ^= uint8(^s >> 8)

	return p
}

func parsePingReply(p []byte) (id, seq int) {
	id = int(p[4])<<8 | int(p[5])
	seq = int(p[6])<<8 | int(p[7])
	return
}

var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
var dsthost = flag.String("dsthost", "localhost", "Destination for the ICMP ECHO request")

// test (raw) IP socket using ICMP
func TestICMP(t *testing.T) {
	if os.Getuid() != 0 {
		t.Logf("test disabled; must be root")
		return
	}

	var (
		laddr *IPAddr
		err   os.Error
	)
	if *srchost != "" {
		laddr, err = ResolveIPAddr(*srchost)
		if err != nil {
			t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *srchost, laddr, err)
		}
	}

	raddr, err := ResolveIPAddr(*dsthost)
	if err != nil {
		t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *dsthost, raddr, err)
	}

	c, err := ListenIP("ip4:icmp", laddr)
	if err != nil {
		t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
	}

	sendid := os.Getpid() & 0xffff
	const sendseq = 61455
	const pingpktlen = 128
	sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))

	n, err := c.WriteToIP(sendpkt, raddr)
	if err != nil || n != pingpktlen {
		t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
	}

	c.SetTimeout(100e6)
	resp := make([]byte, 1024)
	for {
		n, from, err := c.ReadFrom(resp)
		if err != nil {
			t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
		}
		if resp[0] != ICMP_ECHO_REPLY {
			continue
		}
		rcvid, rcvseq := parsePingReply(resp)
		if rcvid != sendid || rcvseq != sendseq {
			t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
		}
		return
	}
	t.Fatalf("saw no ping return")
}
<|endoftext|>