<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/codegangsta/cli"
)

// ErrNotInMount happens when command is run from outside a mount.
var ErrNotInMount = errors.New("command not run on mount")

// RunCommandFactory is the factory method for RunCommand.
func RunCommandFactory(c *cli.Context) int {
	if len(c.Args()) < 1 {
		cli.ShowCommandHelp(c, "run")
		return 1
	}

	// get the path where the command was run
	localPath, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		fmt.Printf("Error running command: '%s'\n", err)
		return 1
	}

	r, err := NewRunCommand()
	if err != nil {
		fmt.Printf("Error running command: '%s'\n", err)
		return 1
	}

	var (
		cmdWithArgs    = os.Args[2:]
		cmdWithArgsStr = strings.Join(cmdWithArgs, " ")
	)

	res, err := r.runOnRemote(localPath, cmdWithArgsStr)
	if err != nil && err != ErrNotInMount {
		fmt.Printf("Error running command: '%s'\n", err)
		return 1
	}

	if err == ErrNotInMount {
		fmt.Println("Running on local:", cmdWithArgsStr)
		return r.runOnLocal(cmdWithArgs)
	}

	fmt.Println("Running on remote:", cmdWithArgsStr)

	// write to standard out stream
	// this stream can contain values even if exit status is not 0.
	if res.Stdout != "" {
		os.Stdout.WriteString(res.Stdout)
	}

	if res.Stderr != "" {
		os.Stderr.WriteString(res.Stderr)
	}

	if res.ExitStatus != 0 {
		return res.ExitStatus
	}

	return 0
}

// RunCommand is the cli command that lets users run a command a remote
// machine. All arguments/flags passed to command are sent to command run on
// remote machine.
//
// It currently only supports running commands from inside a mount. It detects
// if it's inside a mount by parsing the lock files and checking if command path
// is the same as or inside the mount.
type RunCommand struct {
	// Transport is communication layer between this and local klient.
	// This is used to run the command on the remote machine.
	Transport
}

// NewRunCommand is the required initializer for RunCommand.
func NewRunCommand() (*RunCommand, error) {
	klientKite, err := CreateKlientClient(NewKlientOptions())
	if err != nil {
		return nil, err
	}

	if err := klientKite.Dial(); err != nil {
		return nil, err
	}

	return &RunCommand{Transport: klientKite}, nil
}

func (r *RunCommand) runOnRemote(localPath string, cmdWithArgsStr string) (*ExecRes, error) {
	machine, err := GetMachineMountedForPath(localPath)
	if err != nil {
		return nil, err
	}

	fullCmdPath, err := r.getCmdRemotePath(machine, localPath)
	if err != nil {
		return nil, err
	}

	return r.runOnMachine(machine, fullCmdPath, cmdWithArgsStr)
}

func (r *RunCommand) runOnMachine(machine, fullCmdPath string, cmdWithArgsStr string) (*ExecRes, error) {
	req := struct {
		Machine string
		Command string
		Path    string
	}{
		Machine: machine,
		Command: cmdWithArgsStr,
		Path:    fullCmdPath,
	}
	raw, err := r.Tell("remote.exec", req)
	if err != nil {
		return nil, err
	}

	var res ExecRes
	if err := raw.Unmarshal(&res); err != nil {
		return nil, err
	}

	return &res, nil
}

// getCmdRemotePath return the path on remote machine where the command should
// be run.
func (r *RunCommand) getCmdRemotePath(machine, localPath string) (string, error) {
	relativePath, err := GetRelativeMountPath(localPath)
	if err != nil {
		return "", err
	}

	mounts, err := r.getMounts()
	if err != nil {
		return "", err
	}

	for _, m := range mounts {
		if m.MountName == machine {
			// join path in remote machine
			return filepath.Join(m.RemotePath, relativePath), nil
		}
	}

	return "", ErrNotInMount
}

// getMounts returns list of mounts from remote.
func (r *RunCommand) getMounts() ([]kiteMounts, error) {
	res, err := r.Tell("remote.mounts")
	if err != nil {
		return nil, err
	}

	var mounts []kiteMounts
	if err := res.Unmarshal(&mounts); err != nil {
		return nil, err
	}

	return mounts, nil
}

func (r *RunCommand) runOnLocal(cmdWithArgs []string) int {
	cmd := exec.Command(cmdWithArgs[0], cmdWithArgs[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		exitErr, ok := err.(*exec.ExitError)
		if !ok {
			fmt.Printf("Error running command: '%s'\n", err)
			return 1
		}

		return exitErr.Sys().(syscall.WaitStatus).ExitStatus()
	}

	return 0
}
<commit_msg>errors: Logged the run errors (no consolidation needed)<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/codegangsta/cli"
)

// ErrNotInMount happens when command is run from outside a mount.
var ErrNotInMount = errors.New("command not run on mount")

// RunCommandFactory is the factory method for RunCommand.
func RunCommandFactory(c *cli.Context) int {
	if len(c.Args()) < 1 {
		cli.ShowCommandHelp(c, "run")
		return 1
	}

	// get the path where the command was run
	localPath, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Errorf("Failed to create absolute directory. err:%s", err)
		fmt.Println(GenericInternalError)
		return 1
	}

	r, err := NewRunCommand()
	if err != nil {
		log.Errorf("Failed to initialize command. err:%s", err)
		fmt.Println(GenericInternalError)
		return 1
	}

	var (
		cmdWithArgs    = os.Args[2:]
		cmdWithArgsStr = strings.Join(cmdWithArgs, " ")
	)

	res, err := r.runOnRemote(localPath, cmdWithArgsStr)
	if err != nil && err != ErrNotInMount {
		log.Errorf("Error running command. err:%s", err)
		// Note that we're printing the error here to the user. This seems reasonable
		// since their own command may have failed, and that information is meaningful
		// to them.
		//
		// Eg, the binary is not executable, or not formatted for their os, or etc.
		fmt.Println("Error running command: '%s'\n", err)
		return 1
	}

	if err == ErrNotInMount {
		fmt.Println("Running on local:", cmdWithArgsStr)
		return r.runOnLocal(cmdWithArgs)
	}

	fmt.Println("Running on remote:", cmdWithArgsStr)

	// write to standard out stream
	// this stream can contain values even if exit status is not 0.
	if res.Stdout != "" {
		os.Stdout.WriteString(res.Stdout)
	}

	if res.Stderr != "" {
		os.Stderr.WriteString(res.Stderr)
	}

	if res.ExitStatus != 0 {
		return res.ExitStatus
	}

	return 0
}

// RunCommand is the cli command that lets users run a command a remote
// machine. All arguments/flags passed to command are sent to command run on
// remote machine.
//
// It currently only supports running commands from inside a mount. It detects
// if it's inside a mount by parsing the lock files and checking if command path
// is the same as or inside the mount.
type RunCommand struct {
	// Transport is communication layer between this and local klient.
	// This is used to run the command on the remote machine.
	Transport
}

// NewRunCommand is the required initializer for RunCommand.
func NewRunCommand() (*RunCommand, error) {
	klientKite, err := CreateKlientClient(NewKlientOptions())
	if err != nil {
		return nil, err
	}

	if err := klientKite.Dial(); err != nil {
		return nil, err
	}

	return &RunCommand{Transport: klientKite}, nil
}

func (r *RunCommand) runOnRemote(localPath string, cmdWithArgsStr string) (*ExecRes, error) {
	machine, err := GetMachineMountedForPath(localPath)
	if err != nil {
		return nil, err
	}

	fullCmdPath, err := r.getCmdRemotePath(machine, localPath)
	if err != nil {
		return nil, err
	}

	return r.runOnMachine(machine, fullCmdPath, cmdWithArgsStr)
}

func (r *RunCommand) runOnMachine(machine, fullCmdPath string, cmdWithArgsStr string) (*ExecRes, error) {
	req := struct {
		Machine string
		Command string
		Path    string
	}{
		Machine: machine,
		Command: cmdWithArgsStr,
		Path:    fullCmdPath,
	}
	raw, err := r.Tell("remote.exec", req)
	if err != nil {
		return nil, err
	}

	var res ExecRes
	if err := raw.Unmarshal(&res); err != nil {
		return nil, err
	}

	return &res, nil
}

// getCmdRemotePath return the path on remote machine where the command should
// be run.
func (r *RunCommand) getCmdRemotePath(machine, localPath string) (string, error) {
	relativePath, err := GetRelativeMountPath(localPath)
	if err != nil {
		return "", err
	}

	mounts, err := r.getMounts()
	if err != nil {
		return "", err
	}

	for _, m := range mounts {
		if m.MountName == machine {
			// join path in remote machine
			return filepath.Join(m.RemotePath, relativePath), nil
		}
	}

	return "", ErrNotInMount
}

// getMounts returns list of mounts from remote.
func (r *RunCommand) getMounts() ([]kiteMounts, error) {
	res, err := r.Tell("remote.mounts")
	if err != nil {
		return nil, err
	}

	var mounts []kiteMounts
	if err := res.Unmarshal(&mounts); err != nil {
		return nil, err
	}

	return mounts, nil
}

func (r *RunCommand) runOnLocal(cmdWithArgs []string) int {
	cmd := exec.Command(cmdWithArgs[0], cmdWithArgs[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		exitErr, ok := err.(*exec.ExitError)
		if !ok {
			log.Errorf("Error running command: %s", err)
			// Note that we're printing the error here to the user. This seems reasonable
			// since their own command may have failed, and that information is meaningful
			// to them.
			//
			// Eg, the binary is not executable, or not formatted for their os, or etc.
			fmt.Printf("Error running command: '%s'\n", err)
			return 1
		}

		return exitErr.Sys().(syscall.WaitStatus).ExitStatus()
	}

	return 0
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/whitedevops/atexit"
)

var (
	runParams []string
	lastMod   time.Time

	errModifiedApp = errors.New("app has been modified")
)

func run() {
	if !isVolatile() {
		fmt.Println("volatile run: no runnable app detected")
		os.Exit(1)
	}

	appName, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	appName = filepath.Base(appName)

	atexit.Use(func() {
		os.Remove(appName)
	})

	runParams = flag.Args()[1:]
	runBuild(appName)
}

func runBuild(appName string) {
	// Prepare building
	buildCmd := exec.Command("go", "build", "-o", appName)
	buildCmd.Stdout = os.Stdout
	buildCmd.Stderr = os.Stderr

	// Prepare running
	runCmd := exec.Command("./"+appName, runParams...)
	runCmd.Stdout = os.Stdout
	runCmd.Stderr = os.Stderr

	running := false

	// Build and run
	if err := buildCmd.Run(); err == nil {
		runCmd.Start()
		running = true
	}

	// Modification detection
	lastMod = time.Now()
ModDetect:
	for {
		if err := filepath.Walk(".", modDetectWalk); err != nil {
			if err == errModifiedApp {
				break ModDetect
			}
			panic(err)
		}
		time.Sleep(500 * time.Millisecond)
	}

	// Interrupt
	if running {
		if err := runCmd.Process.Signal(os.Interrupt); err != nil {
			runCmd.Process.Kill()
		}
	}

	// Rerun
	log.Print("Rerunning server…\n\n")
	runBuild(appName)
}

func modDetectWalk(path string, fi os.FileInfo, err error) error {
	if err != nil {
		return err
	}
	if fi.ModTime().After(lastMod) {
		return errModifiedApp
	}
	return nil
}
<commit_msg>Fix run without args<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"github.com/whitedevops/atexit"
)

var (
	runParams []string
	lastMod   time.Time

	errModifiedApp = errors.New("app has been modified")
)

func run() {
	if !isVolatile() {
		fmt.Println("volatile run: no runnable app detected")
		os.Exit(1)
	}

	appName, err := os.Getwd()
	if err != nil {
		panic(err)
	}
	appName = filepath.Base(appName)

	atexit.Use(func() {
		os.Remove(appName)
	})

	if len(flag.Args()) > 1 {
		runParams = flag.Args()[1:]
	}
	runBuild(appName)
}

func runBuild(appName string) {
	// Prepare building
	buildCmd := exec.Command("go", "build", "-o", appName)
	buildCmd.Stdout = os.Stdout
	buildCmd.Stderr = os.Stderr

	// Prepare running
	runCmd := exec.Command("./"+appName, runParams...)
	runCmd.Stdout = os.Stdout
	runCmd.Stderr = os.Stderr

	running := false

	// Build and run
	if err := buildCmd.Run(); err == nil {
		runCmd.Start()
		running = true
	}

	// Modification detection
	lastMod = time.Now()
ModDetect:
	for {
		if err := filepath.Walk(".", modDetectWalk); err != nil {
			if err == errModifiedApp {
				break ModDetect
			}
			panic(err)
		}
		time.Sleep(500 * time.Millisecond)
	}

	// Interrupt
	if running {
		if err := runCmd.Process.Signal(os.Interrupt); err != nil {
			runCmd.Process.Kill()
		}
	}

	// Rerun
	log.Print("Rerunning server…\n\n")
	runBuild(appName)
}

func modDetectWalk(path string, fi os.FileInfo, err error) error {
	if err != nil {
		return err
	}
	if fi.ModTime().After(lastMod) {
		return errModifiedApp
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"time"
	"unicode/utf8"
)

var homedir string

func init() {
	usr, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	homedir = usr.HomeDir
}

// Run fillin
func Run(configPath string, args []string, in *bufio.Reader, out *bufio.Writer) (string, error) {
	path := filepath.Join(strings.Split(configPath, "/")...)
	if path[0] == '~' {
		path = homedir + path[1:]
	}
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return "", err
	}
	rfile, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0644)
	if err != nil {
		return "", err
	}
	w := new(bytes.Buffer)
	cmd := escapeJoin(Fillin(args, rfile, w, in, out))
	rfile.Close() // not be defered due to rename
	tmpFileName := fmt.Sprintf("fillin.%d-%d.json", os.Getpid(), rand.Int())
	tmp := filepath.Join(filepath.Dir(path), tmpFileName)
	defer os.Remove(tmp)
	wfile, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return "", err
	}
	if n, err := wfile.Write(w.Bytes()); n != w.Len() || err != nil {
		wfile.Close()
		return "", err
	}
	wfile.Close() // not be defered due to rename
	if err := os.Rename(tmp, path); err != nil {
		return "", err
	}
	histfile := filepath.Join(filepath.Dir(path), ".fillin.histfile")
	hfile, err := os.OpenFile(histfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
	defer hfile.Close()
	if err != nil {
		return "", err
	}
	hfile.WriteString(fmt.Sprintf(": %d:0;%s\n", time.Now().Unix(), cmd))
	return cmd, nil
}

func escapeJoin(args []string) string {
	for i, arg := range args {
		args[i] = escape(arg)
	}
	return strings.Join(args, " ")
}

func escape(arg string) string {
	switch arg {
	case "|", "||", "&&", ">", ">>", "<":
		return arg
	}
quote:
	for _, quote := range []bool{false, true} {
		s := arg
		isHead, afterFd, afterRedirect := true, false, false
		var buf bytes.Buffer
		if quote {
			buf.WriteByte('\'')
		}
		for len(s) > 0 {
			c, l := utf8.DecodeRuneInString(s)
			s = s[l:]
			if (isHead || afterFd) && strings.ContainsRune("<>", c) && !quote {
				buf.WriteRune(c)
				isHead, afterFd, afterRedirect = false, false, true
				continue
			} else if afterRedirect && strings.ContainsRune("<>", c) && !quote {
				buf.WriteRune(c)
			} else if isHead && strings.ContainsRune("12", c) && !quote {
				buf.WriteRune(c)
				isHead, afterFd = false, true
				continue
			} else if afterRedirect && strings.ContainsRune("&", c) && !quote {
				buf.WriteRune(c)
			} else if strings.ContainsRune("\\'\"`${[|&;<>()*?!", c) && !quote {
				buf.WriteByte('\\')
				buf.WriteRune(c)
			} else if c == rune(' ') && !quote {
				continue quote
			} else if c == rune('\t') {
				if quote {
					buf.WriteByte('\\')
					buf.WriteByte('t')
				} else {
					continue quote
				}
			} else {
				buf.WriteRune(c)
			}
			isHead, afterFd, afterRedirect = false, false, false
		}
		if quote {
			buf.WriteByte('\'')
		}
		return buf.String()
	}
	return ""
}
<commit_msg>skip appending to the history file when the command is empty<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"math/rand"
	"os"
	"os/user"
	"path/filepath"
	"strings"
	"time"
	"unicode/utf8"
)

var homedir string

func init() {
	usr, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	homedir = usr.HomeDir
}

// Run fillin
func Run(configPath string, args []string, in *bufio.Reader, out *bufio.Writer) (string, error) {
	path := filepath.Join(strings.Split(configPath, "/")...)
	if path[0] == '~' {
		path = homedir + path[1:]
	}
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return "", err
	}
	rfile, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0644)
	if err != nil {
		return "", err
	}
	w := new(bytes.Buffer)
	cmd := escapeJoin(Fillin(args, rfile, w, in, out))
	rfile.Close() // not be defered due to rename
	tmpFileName := fmt.Sprintf("fillin.%d-%d.json", os.Getpid(), rand.Int())
	tmp := filepath.Join(filepath.Dir(path), tmpFileName)
	defer os.Remove(tmp)
	wfile, err := os.OpenFile(tmp, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return "", err
	}
	if n, err := wfile.Write(w.Bytes()); n != w.Len() || err != nil {
		wfile.Close()
		return "", err
	}
	wfile.Close() // not be defered due to rename
	if err := os.Rename(tmp, path); err != nil {
		return "", err
	}
	if cmd != "" {
		histfile := filepath.Join(filepath.Dir(path), ".fillin.histfile")
		hfile, err := os.OpenFile(histfile, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
		defer hfile.Close()
		if err != nil {
			return "", err
		}
		hfile.WriteString(fmt.Sprintf(": %d:0;%s\n", time.Now().Unix(), cmd))
	}
	return cmd, nil
}

func escapeJoin(args []string) string {
	for i, arg := range args {
		args[i] = escape(arg)
	}
	return strings.Join(args, " ")
}

func escape(arg string) string {
	switch arg {
	case "|", "||", "&&", ">", ">>", "<":
		return arg
	}
quote:
	for _, quote := range []bool{false, true} {
		s := arg
		isHead, afterFd, afterRedirect := true, false, false
		var buf bytes.Buffer
		if quote {
			buf.WriteByte('\'')
		}
		for len(s) > 0 {
			c, l := utf8.DecodeRuneInString(s)
			s = s[l:]
			if (isHead || afterFd) && strings.ContainsRune("<>", c) && !quote {
				buf.WriteRune(c)
				isHead, afterFd, afterRedirect = false, false, true
				continue
			} else if afterRedirect && strings.ContainsRune("<>", c) && !quote {
				buf.WriteRune(c)
			} else if isHead && strings.ContainsRune("12", c) && !quote {
				buf.WriteRune(c)
				isHead, afterFd = false, true
				continue
			} else if afterRedirect && strings.ContainsRune("&", c) && !quote {
				buf.WriteRune(c)
			} else if strings.ContainsRune("\\'\"`${[|&;<>()*?!", c) && !quote {
				buf.WriteByte('\\')
				buf.WriteRune(c)
			} else if c == rune(' ') && !quote {
				continue quote
			} else if c == rune('\t') {
				if quote {
					buf.WriteByte('\\')
					buf.WriteByte('t')
				} else {
					continue quote
				}
			} else {
				buf.WriteRune(c)
			}
			isHead, afterFd, afterRedirect = false, false, false
		}
		if quote {
			buf.WriteByte('\'')
		}
		return buf.String()
	}
	return ""
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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 source

import (
	"net"
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/fake"
	"k8s.io/client-go/pkg/api/v1"

	"github.com/kubernetes-incubator/external-dns/endpoint"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestServiceSource(t *testing.T) {
	t.Run("Interface", testServiceSourceImplementsSource)
	t.Run("NewServiceSource", testServiceSourceNewServiceSource)
	t.Run("Endpoints", testServiceSourceEndpoints)
}

// testServiceSourceImplementsSource tests that serviceSource is a valid Source.
func testServiceSourceImplementsSource(t *testing.T) {
	assert.Implements(t, (*Source)(nil), new(serviceSource))
}

// testServiceSourceNewServiceSource tests that NewServiceSource doesn't return an error.
func testServiceSourceNewServiceSource(t *testing.T) {
	for _, ti := range []struct {
		title        string
		fqdnTemplate string
		expectError  bool
	}{
		{
			title:        "invalid template",
			expectError:  true,
			fqdnTemplate: "{{.Name",
		},
		{
			title:       "valid empty template",
			expectError: false,
		},
		{
			title:        "valid template",
			expectError:  false,
			fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com",
		},
	} {
		t.Run(ti.title, func(t *testing.T) {
			_, err := NewServiceSource(
				fake.NewSimpleClientset(),
				"",
				ti.fqdnTemplate,
				"",
			)

			if ti.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

// testServiceSourceEndpoints tests that various services generate the correct endpoints.
func testServiceSourceEndpoints(t *testing.T) {
	for _, tc := range []struct {
		title           string
		targetNamespace string
		svcNamespace    string
		svcName         string
		compatibility   string
		fqdnTemplate    string
		labels          map[string]string
		annotations     map[string]string
		lbs             []string
		expected        []*endpoint.Endpoint
		expectError     bool
	}{
		{
			"no annotated services return no endpoints",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"annotated services return an endpoint with target IP",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"annotated services return an endpoint with target hostname",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"lb.example.com"}, // Kubernetes omits the trailing dot
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "lb.example.com"},
			},
			false,
		},
		{
			"annotated services can omit trailing dot",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org", // Trailing dot is omitted
			},
			[]string{"1.2.3.4", "lb.example.com"}, // Kubernetes omits the trailing dot
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
				{DNSName: "foo.example.org", Target: "lb.example.com"},
			},
			false,
		},
		{
			"our controller type is dns-controller",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				controllerAnnotationKey: controllerAnnotationValue,
				hostnameAnnotationKey:   "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"different controller types are ignored even (with template specified)",
			"",
			"testing",
			"foo",
			"",
			"{{.Name}}.ext-dns.test.com",
			map[string]string{},
			map[string]string{
				controllerAnnotationKey: "some-other-tool",
				hostnameAnnotationKey:   "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"services are found in target namespace",
			"testing",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"services that are not in target namespace are ignored",
			"testing",
			"other-testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"services are found in all namespaces",
			"",
			"other-testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"no external entrypoints return no endpoints",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"multiple external entrypoints return multiple endpoints",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4", "8.8.8.8"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
				{DNSName: "foo.example.org", Target: "8.8.8.8"},
			},
			false,
		},
		{
			"services annotated with legacy mate annotations are ignored in default mode",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				"zalando.org/dnsname": "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"services annotated with legacy mate annotations return an endpoint in compatibility mode",
			"",
			"testing",
			"foo",
			"mate",
			"",
			map[string]string{},
			map[string]string{
				"zalando.org/dnsname": "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"services annotated with legacy molecule annotations return an endpoint in compatibility mode",
			"",
			"testing",
			"foo",
			"molecule",
			"",
			map[string]string{
				"dns": "route53",
			},
			map[string]string{
				"domainName": "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"not annotated services with set fqdnTemplate return an endpoint with target IP",
			"",
			"testing",
			"foo",
			"",
			"{{.Name}}.bar.example.com",
			map[string]string{},
			map[string]string{},
			[]string{"1.2.3.4", "elb.com"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.bar.example.com", Target: "1.2.3.4"},
				{DNSName: "foo.bar.example.com", Target: "elb.com"},
			},
			false,
		},
		{
			"not annotated services with unknown tmpl field should not return anything",
			"",
			"testing",
			"foo",
			"",
			"{{.Calibre}}.bar.example.com",
			map[string]string{},
			map[string]string{},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			true,
		},
		{
			"compatibility annotated services with tmpl. compatibility takes precedence",
			"",
			"testing",
			"foo",
			"mate",
			"{{.Name}}.bar.example.com",
			map[string]string{},
			map[string]string{
				"zalando.org/dnsname": "mate.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "mate.example.org", Target: "1.2.3.4"},
			},
			false,
		},
	} {
		t.Run(tc.title, func(t *testing.T) {
			// Create a Kubernetes testing client
			kubernetes := fake.NewSimpleClientset()

			// Create a service to test against
			ingresses := []v1.LoadBalancerIngress{}
			for _, lb := range tc.lbs {
				if net.ParseIP(lb) != nil {
					ingresses = append(ingresses, v1.LoadBalancerIngress{IP: lb})
				} else {
					ingresses = append(ingresses, v1.LoadBalancerIngress{Hostname: lb})
				}
			}

			service := &v1.Service{
				ObjectMeta: metav1.ObjectMeta{
					Namespace:   tc.svcNamespace,
					Name:        tc.svcName,
					Labels:      tc.labels,
					Annotations: tc.annotations,
				},
				Status: v1.ServiceStatus{
					LoadBalancer: v1.LoadBalancerStatus{
						Ingress: ingresses,
					},
				},
			}

			_, err := kubernetes.CoreV1().Services(service.Namespace).Create(service)
			require.NoError(t, err)

			// Create our object under test and get the endpoints.
			client, _ := NewServiceSource(
				kubernetes,
				tc.targetNamespace,
				tc.fqdnTemplate,
				tc.compatibility,
			)
			require.NoError(t, err)

			endpoints, err := client.Endpoints()
			if tc.expectError {
				require.Error(t, err)
			} else {
				require.NoError(t, err)
			}

			// Validate returned endpoints against desired endpoints.
			validateEndpoints(t, endpoints, tc.expected)
		})
	}
}

func BenchmarkServiceEndpoints(b *testing.B) {
	kubernetes := fake.NewSimpleClientset()

	service := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "testing",
			Name:      "foo",
			Annotations: map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
		},
		Status: v1.ServiceStatus{
			LoadBalancer: v1.LoadBalancerStatus{
				Ingress: []v1.LoadBalancerIngress{
					{IP: "1.2.3.4"},
					{IP: "8.8.8.8"},
				},
			},
		},
	}

	_, err := kubernetes.CoreV1().Services(service.Namespace).Create(service)
	require.NoError(b, err)

	client, err := NewServiceSource(kubernetes, v1.NamespaceAll, "", "")
	require.NoError(b, err)

	for i := 0; i < b.N; i++ {
		_, err := client.Endpoints()
		require.NoError(b, err)
	}
}
<commit_msg>chore(source): add test for annotation taking precendence over template (#257)<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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 source

import (
	"net"
	"testing"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/fake"
	"k8s.io/client-go/pkg/api/v1"

	"github.com/kubernetes-incubator/external-dns/endpoint"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestServiceSource(t *testing.T) {
	t.Run("Interface", testServiceSourceImplementsSource)
	t.Run("NewServiceSource", testServiceSourceNewServiceSource)
	t.Run("Endpoints", testServiceSourceEndpoints)
}

// testServiceSourceImplementsSource tests that serviceSource is a valid Source.
func testServiceSourceImplementsSource(t *testing.T) {
	assert.Implements(t, (*Source)(nil), new(serviceSource))
}

// testServiceSourceNewServiceSource tests that NewServiceSource doesn't return an error.
func testServiceSourceNewServiceSource(t *testing.T) {
	for _, ti := range []struct {
		title        string
		fqdnTemplate string
		expectError  bool
	}{
		{
			title:        "invalid template",
			expectError:  true,
			fqdnTemplate: "{{.Name",
		},
		{
			title:       "valid empty template",
			expectError: false,
		},
		{
			title:        "valid template",
			expectError:  false,
			fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com",
		},
	} {
		t.Run(ti.title, func(t *testing.T) {
			_, err := NewServiceSource(
				fake.NewSimpleClientset(),
				"",
				ti.fqdnTemplate,
				"",
			)

			if ti.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
			}
		})
	}
}

// testServiceSourceEndpoints tests that various services generate the correct endpoints.
func testServiceSourceEndpoints(t *testing.T) {
	for _, tc := range []struct {
		title           string
		targetNamespace string
		svcNamespace    string
		svcName         string
		compatibility   string
		fqdnTemplate    string
		labels          map[string]string
		annotations     map[string]string
		lbs             []string
		expected        []*endpoint.Endpoint
		expectError     bool
	}{
		{
			"no annotated services return no endpoints",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"annotated services return an endpoint with target IP",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"annotated services return an endpoint with target hostname",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"lb.example.com"}, // Kubernetes omits the trailing dot
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "lb.example.com"},
			},
			false,
		},
		{
			"annotated services can omit trailing dot",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org", // Trailing dot is omitted
			},
			[]string{"1.2.3.4", "lb.example.com"}, // Kubernetes omits the trailing dot
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
				{DNSName: "foo.example.org", Target: "lb.example.com"},
			},
			false,
		},
		{
			"our controller type is dns-controller",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				controllerAnnotationKey: controllerAnnotationValue,
				hostnameAnnotationKey:   "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"different controller types are ignored even (with template specified)",
			"",
			"testing",
			"foo",
			"",
			"{{.Name}}.ext-dns.test.com",
			map[string]string{},
			map[string]string{
				controllerAnnotationKey: "some-other-tool",
				hostnameAnnotationKey:   "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"services are found in target namespace",
			"testing",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"services that are not in target namespace are ignored",
			"testing",
			"other-testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"services are found in all namespaces",
			"",
			"other-testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"no external entrypoints return no endpoints",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"multiple external entrypoints return multiple endpoints",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4", "8.8.8.8"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
				{DNSName: "foo.example.org", Target: "8.8.8.8"},
			},
			false,
		},
		{
			"services annotated with legacy mate annotations are ignored in default mode",
			"",
			"testing",
			"foo",
			"",
			"",
			map[string]string{},
			map[string]string{
				"zalando.org/dnsname": "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			false,
		},
		{
			"services annotated with legacy mate annotations return an endpoint in compatibility mode",
			"",
			"testing",
			"foo",
			"mate",
			"",
			map[string]string{},
			map[string]string{
				"zalando.org/dnsname": "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"services annotated with legacy molecule annotations return an endpoint in compatibility mode",
			"",
			"testing",
			"foo",
			"molecule",
			"",
			map[string]string{
				"dns": "route53",
			},
			map[string]string{
				"domainName": "foo.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"not annotated services with set fqdnTemplate return an endpoint with target IP",
			"",
			"testing",
			"foo",
			"",
			"{{.Name}}.bar.example.com",
			map[string]string{},
			map[string]string{},
			[]string{"1.2.3.4", "elb.com"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.bar.example.com", Target: "1.2.3.4"},
				{DNSName: "foo.bar.example.com", Target: "elb.com"},
			},
			false,
		},
		{
			"annotated services with set fqdnTemplate annotation takes precedence",
			"",
			"testing",
			"foo",
			"",
			"{{.Name}}.bar.example.com",
			map[string]string{},
			map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
			[]string{"1.2.3.4", "elb.com"},
			[]*endpoint.Endpoint{
				{DNSName: "foo.example.org", Target: "1.2.3.4"},
				{DNSName: "foo.example.org", Target: "elb.com"},
			},
			false,
		},
		{
			"compatibility annotated services with tmpl. compatibility takes precedence",
			"",
			"testing",
			"foo",
			"mate",
			"{{.Name}}.bar.example.com",
			map[string]string{},
			map[string]string{
				"zalando.org/dnsname": "mate.example.org.",
			},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{
				{DNSName: "mate.example.org", Target: "1.2.3.4"},
			},
			false,
		},
		{
			"not annotated services with unknown tmpl field should not return anything",
			"",
			"testing",
			"foo",
			"",
			"{{.Calibre}}.bar.example.com",
			map[string]string{},
			map[string]string{},
			[]string{"1.2.3.4"},
			[]*endpoint.Endpoint{},
			true,
		},
	} {
		t.Run(tc.title, func(t *testing.T) {
			// Create a Kubernetes testing client
			kubernetes := fake.NewSimpleClientset()

			// Create a service to test against
			ingresses := []v1.LoadBalancerIngress{}
			for _, lb := range tc.lbs {
				if net.ParseIP(lb) != nil {
					ingresses = append(ingresses, v1.LoadBalancerIngress{IP: lb})
				} else {
					ingresses = append(ingresses, v1.LoadBalancerIngress{Hostname: lb})
				}
			}

			service := &v1.Service{
				ObjectMeta: metav1.ObjectMeta{
					Namespace:   tc.svcNamespace,
					Name:        tc.svcName,
					Labels:      tc.labels,
					Annotations: tc.annotations,
				},
				Status: v1.ServiceStatus{
					LoadBalancer: v1.LoadBalancerStatus{
						Ingress: ingresses,
					},
				},
			}

			_, err := kubernetes.CoreV1().Services(service.Namespace).Create(service)
			require.NoError(t, err)

			// Create our object under test and get the endpoints.
			client, _ := NewServiceSource(
				kubernetes,
				tc.targetNamespace,
				tc.fqdnTemplate,
				tc.compatibility,
			)
			require.NoError(t, err)

			endpoints, err := client.Endpoints()
			if tc.expectError {
				require.Error(t, err)
			} else {
				require.NoError(t, err)
			}

			// Validate returned endpoints against desired endpoints.
			validateEndpoints(t, endpoints, tc.expected)
		})
	}
}

func BenchmarkServiceEndpoints(b *testing.B) {
	kubernetes := fake.NewSimpleClientset()

	service := &v1.Service{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "testing",
			Name:      "foo",
			Annotations: map[string]string{
				hostnameAnnotationKey: "foo.example.org.",
			},
		},
		Status: v1.ServiceStatus{
			LoadBalancer: v1.LoadBalancerStatus{
				Ingress: []v1.LoadBalancerIngress{
					{IP: "1.2.3.4"},
					{IP: "8.8.8.8"},
				},
			},
		},
	}

	_, err := kubernetes.CoreV1().Services(service.Namespace).Create(service)
	require.NoError(b, err)

	client, err := NewServiceSource(kubernetes, v1.NamespaceAll, "", "")
	require.NoError(b, err)

	for i := 0; i < b.N; i++ {
		_, err := client.Endpoints()
		require.NoError(b, err)
	}
}
<|endoftext|>


<commit_before>package mockengine

import (
	t "testing"

	"github.com/taskcluster/taskcluster-worker/engines/enginetest"
)

var provider = enginetest.EngineProvider{
	Engine: "mock",
	Config: "{}",
}

var volumeTestCase = enginetest.VolumeTestCase{
	EngineProvider: provider,
	Mountpoint:     "/mock/volume",
	WriteVolumePayload: `{
    "start": {
      "delay": 10,
      "function": "set-volume",
      "argument": "/mock/volume"
    }
  }`,
	CheckVolumePayload: `{
    "start": {
      "delay": 10,
      "function": "get-volume",
      "argument": "/mock/volume"
    }
  }`,
}

func TestWriteReadVolume(*t.T)       { volumeTestCase.TestWriteReadVolume() }
func TestReadEmptyVolume(*t.T)       { volumeTestCase.TestReadEmptyVolume() }
func TestWriteToReadOnlyVolume(*t.T) { volumeTestCase.TestWriteToReadOnlyVolume() }
func TestReadToReadOnlyVolume(*t.T)  { volumeTestCase.TestReadToReadOnlyVolume() }
func TestVolumeTestCase(t *t.T)      { volumeTestCase.Test() }

var loggingTestCase = enginetest.LoggingTestCase{
	EngineProvider: provider,
	Target:         "Hello World",
	TargetPayload: `{
    "start": {
      "delay": 10,
      "function": "write-log",
      "argument": "Hello World"
    }
  }`,
	FailingPayload: `{
    "start": {
      "delay": 10,
      "function": "write-error-log",
      "argument": "Hello World"
    }
  }`,
	SilentPayload: `{
    "start": {
      "delay": 10,
      "function": "write-log",
      "argument": "Okay, let's try on Danish then: 'Hej Verden'"
    }
  }`,
}

func TestLogTarget(t *t.T)            { loggingTestCase.TestLogTarget() }
func TestLogTargetWhenFailing(t *t.T) { loggingTestCase.TestLogTargetWhenFailing() }
func TestSilentTask(t *t.T)           { loggingTestCase.TestSilentTask() }
func TestLoggingTestCase(t *t.T)      { loggingTestCase.Test() }

var proxyTestCase = enginetest.ProxyTestCase{
	EngineProvider: provider,
	ProxyName:      "proxy.com",
	PingProxyPayload: `{
    "start": {
      "delay": 10,
      "function": "ping-proxy",
      "argument": "http://proxy.com/v1/ping"
    }
  }`,
}

func TestPingProxyPayload(t *t.T)      { proxyTestCase.TestPingProxyPayload() }
func TestPing404IsUnsuccessful(t *t.T) { proxyTestCase.TestPing404IsUnsuccessful() }
func TestLiveLogging(t *t.T)           { proxyTestCase.TestLiveLogging() }
func TestParallelPings(t *t.T)         { proxyTestCase.TestParallelPings() }
func TestProxyTestCase(t *t.T)         { proxyTestCase.Test() }

var envVarTestCase = enginetest.EnvVarTestCase{
	EngineProvider:       provider,
	VariableName:         "HELLO_WORLD",
	InvalidVariableNames: []string{"bad d", "also bad", "can't have space"},
	Payload: `{
    "start": {
      "delay": 10,
      "function": "print-env-var",
      "argument": "HELLO_WORLD"
    }
  }`,
}

func TestPrintVariable(t *t.T)        { envVarTestCase.TestPrintVariable() }
func TestVariableNameConflict(t *t.T) { envVarTestCase.TestVariableNameConflict() }
func TestInvalidVariableNames(t *t.T) { envVarTestCase.TestInvalidVariableNames() }
func TestEnvVarTestCase(t *t.T)       { envVarTestCase.Test() }

var artifactTestCase = enginetest.ArtifactTestCase{
	EngineProvider:     provider,
	Text:               "Hello World",
	TextFilePath:       "/folder/a.txt",
	FileNotFoundPath:   "/not-found.txt",
	FolderNotFoundPath: "/no-folder/",
	NestedFolderFiles:  []string{"/folder/a.txt", "/folder/b.txt", "/folder/c/c.txt"},
	NestedFolderPath:   "/folder/",
	Payload: `{
		"start":{
			"delay": 10,
			"function": "write-files",
			"argument": "/folder/a.txt /folder/b.txt /folder/c/c.txt"
		}
	}`,
}

func TestExtractTextFile(t *t.T)               { artifactTestCase.TestExtractTextFile() }
func TestExtractFileNotFound(t *t.T)           { artifactTestCase.TestExtractFileNotFound() }
func TestExtractFolderNotFound(t *t.T)         { artifactTestCase.TestExtractFolderNotFound() }
func TestExtractNestedFolderPath(t *t.T)       { artifactTestCase.TestExtractNestedFolderPath() }
func TestExtractFolderHandlerInterrupt(t *t.T) { artifactTestCase.TestExtractFolderHandlerInterrupt() }
func TestArtifactTestCase(t *t.T)              { artifactTestCase.Test() }

var shellTestCase = enginetest.ShellTestCase{
	EngineProvider: provider,
	Command:        "print-hello",
	Stdout:         "Hello World",
	Stderr:         "No error!",
	BadCommand:     "exit-false",
	SleepCommand:   "sleep",
	Payload: `{
		"start":{
			"delay": 10,
			"function": "true",
			"argument": ""
		}
	}`,
}

func TestCommand(t *t.T)           { shellTestCase.TestCommand() }
func TestBadCommand(t *t.T)        { shellTestCase.TestBadCommand() }
func TestAbortSleepCommand(t *t.T) { shellTestCase.TestAbortSleepCommand() }
func Test(t *t.T)                  { shellTestCase.Test() }
<commit_msg>Remove some unnecessary delays<commit_after>package mockengine

import (
	t "testing"

	"github.com/taskcluster/taskcluster-worker/engines/enginetest"
)

var provider = enginetest.EngineProvider{
	Engine: "mock",
	Config: "{}",
}

var volumeTestCase = enginetest.VolumeTestCase{
	EngineProvider: provider,
	Mountpoint:     "/mock/volume",
	WriteVolumePayload: `{
    "start": {
      "delay": 0,
      "function": "set-volume",
      "argument": "/mock/volume"
    }
  }`,
	CheckVolumePayload: `{
    "start": {
      "delay": 0,
      "function": "get-volume",
      "argument": "/mock/volume"
    }
  }`,
}

func TestWriteReadVolume(*t.T)       { volumeTestCase.TestWriteReadVolume() }
func TestReadEmptyVolume(*t.T)       { volumeTestCase.TestReadEmptyVolume() }
func TestWriteToReadOnlyVolume(*t.T) { volumeTestCase.TestWriteToReadOnlyVolume() }
func TestReadToReadOnlyVolume(*t.T)  { volumeTestCase.TestReadToReadOnlyVolume() }
func TestVolumeTestCase(t *t.T)      { volumeTestCase.Test() }

var loggingTestCase = enginetest.LoggingTestCase{
	EngineProvider: provider,
	Target:         "Hello World",
	TargetPayload: `{
    "start": {
      "delay": 0,
      "function": "write-log",
      "argument": "Hello World"
    }
  }`,
	FailingPayload: `{
    "start": {
      "delay": 0,
      "function": "write-error-log",
      "argument": "Hello World"
    }
  }`,
	SilentPayload: `{
    "start": {
      "delay": 0,
      "function": "write-log",
      "argument": "Okay, let's try on Danish then: 'Hej Verden'"
    }
  }`,
}

func TestLogTarget(t *t.T)            { loggingTestCase.TestLogTarget() }
func TestLogTargetWhenFailing(t *t.T) { loggingTestCase.TestLogTargetWhenFailing() }
func TestSilentTask(t *t.T)           { loggingTestCase.TestSilentTask() }
func TestLoggingTestCase(t *t.T)      { loggingTestCase.Test() }

var proxyTestCase = enginetest.ProxyTestCase{
	EngineProvider: provider,
	ProxyName:      "proxy.com",
	PingProxyPayload: `{
    "start": {
      "delay": 0,
      "function": "ping-proxy",
      "argument": "http://proxy.com/v1/ping"
    }
  }`,
}

func TestPingProxyPayload(t *t.T)      { proxyTestCase.TestPingProxyPayload() }
func TestPing404IsUnsuccessful(t *t.T) { proxyTestCase.TestPing404IsUnsuccessful() }
func TestLiveLogging(t *t.T)           { proxyTestCase.TestLiveLogging() }
func TestParallelPings(t *t.T)         { proxyTestCase.TestParallelPings() }
func TestProxyTestCase(t *t.T)         { proxyTestCase.Test() }

var envVarTestCase = enginetest.EnvVarTestCase{
	EngineProvider:       provider,
	VariableName:         "HELLO_WORLD",
	InvalidVariableNames: []string{"bad d", "also bad", "can't have space"},
	Payload: `{
    "start": {
      "delay": 0,
      "function": "print-env-var",
      "argument": "HELLO_WORLD"
    }
  }`,
}

func TestPrintVariable(t *t.T)        { envVarTestCase.TestPrintVariable() }
func TestVariableNameConflict(t *t.T) { envVarTestCase.TestVariableNameConflict() }
func TestInvalidVariableNames(t *t.T) { envVarTestCase.TestInvalidVariableNames() }
func TestEnvVarTestCase(t *t.T)       { envVarTestCase.Test() }

var artifactTestCase = enginetest.ArtifactTestCase{
	EngineProvider:     provider,
	Text:               "Hello World",
	TextFilePath:       "/folder/a.txt",
	FileNotFoundPath:   "/not-found.txt",
	FolderNotFoundPath: "/no-folder/",
	NestedFolderFiles:  []string{"/folder/a.txt", "/folder/b.txt", "/folder/c/c.txt"},
	NestedFolderPath:   "/folder/",
	Payload: `{
		"start":{
			"delay": 0,
			"function": "write-files",
			"argument": "/folder/a.txt /folder/b.txt /folder/c/c.txt"
		}
	}`,
}

func TestExtractTextFile(t *t.T)               { artifactTestCase.TestExtractTextFile() }
func TestExtractFileNotFound(t *t.T)           { artifactTestCase.TestExtractFileNotFound() }
func TestExtractFolderNotFound(t *t.T)         { artifactTestCase.TestExtractFolderNotFound() }
func TestExtractNestedFolderPath(t *t.T)       { artifactTestCase.TestExtractNestedFolderPath() }
func TestExtractFolderHandlerInterrupt(t *t.T) { artifactTestCase.TestExtractFolderHandlerInterrupt() }
func TestArtifactTestCase(t *t.T)              { artifactTestCase.Test() }

var shellTestCase = enginetest.ShellTestCase{
	EngineProvider: provider,
	Command:        "print-hello",
	Stdout:         "Hello World",
	Stderr:         "No error!",
	BadCommand:     "exit-false",
	SleepCommand:   "sleep",
	Payload: `{
		"start":{
			"delay": 0,
			"function": "true",
			"argument": ""
		}
	}`,
}

func TestCommand(t *t.T)           { shellTestCase.TestCommand() }
func TestBadCommand(t *t.T)        { shellTestCase.TestBadCommand() }
func TestAbortSleepCommand(t *t.T) { shellTestCase.TestAbortSleepCommand() }
func Test(t *t.T)                  { shellTestCase.Test() }
<|endoftext|>


<commit_before>package mbtiles

import (
	"database/sql"
	"net/http"
	"regexp"
	"strconv"

	_ "github.com/mattn/go-sqlite3"
)

var zxyRegexp = regexp.MustCompile(`\A([0-9]+)/([0-9]+)/([0-9]+)\z`)

type tileServer struct {
	db   *sql.DB
	stmt *sql.Stmt
}

func NewTileServer(dsn string) (*tileServer, error) {
	db, err := sql.Open("sqlite3", dsn)
	if err != nil {
		return nil, err
	}
	stmt, err := db.Prepare("SELECT tile_data FROM tiles WHERE zoom_level = ? AND tile_column = ? AND tile_row = ?;")
	if err != nil {
		db.Close()
		return nil, err
	}
	return &tileServer{db, stmt}, nil
}

func (t *tileServer) Close() error {
	for _, err := range []error{
		t.stmt.Close(),
		t.db.Close(),
	} {
		if err != nil {
			return err
		}
	}
	return nil
}

func (t *tileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	m := zxyRegexp.FindStringSubmatch(r.URL.Path)
	if m == nil {
		http.NotFound(w, r)
		return
	}
	z, _ := strconv.Atoi(m[1])
	x, _ := strconv.Atoi(m[2])
	y, _ := strconv.Atoi(m[3])
	var tileData []byte
	if err := t.stmt.QueryRow(z, x, 1<<uint(z)-y-1).Scan(&tileData); err != nil {
		http.NotFound(w, r)
		return
	}
	w.Write(tileData)
}
<commit_msg>Export TileServer<commit_after>package mbtiles

import (
	"database/sql"
	"net/http"
	"regexp"
	"strconv"

	_ "github.com/mattn/go-sqlite3"
)

var zxyRegexp = regexp.MustCompile(`\A([0-9]+)/([0-9]+)/([0-9]+)\z`)

type TileServer struct {
	db   *sql.DB
	stmt *sql.Stmt
}

func NewTileServer(dsn string) (*TileServer, error) {
	db, err := sql.Open("sqlite3", dsn)
	if err != nil {
		return nil, err
	}
	stmt, err := db.Prepare("SELECT tile_data FROM tiles WHERE zoom_level = ? AND tile_column = ? AND tile_row = ?;")
	if err != nil {
		db.Close()
		return nil, err
	}
	return &TileServer{db, stmt}, nil
}

func (t *TileServer) Close() error {
	for _, err := range []error{
		t.stmt.Close(),
		t.db.Close(),
	} {
		if err != nil {
			return err
		}
	}
	return nil
}

func (t *TileServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	m := zxyRegexp.FindStringSubmatch(r.URL.Path)
	if m == nil {
		http.NotFound(w, r)
		return
	}
	z, _ := strconv.Atoi(m[1])
	x, _ := strconv.Atoi(m[2])
	y, _ := strconv.Atoi(m[3])
	var tileData []byte
	if err := t.stmt.QueryRow(z, x, 1<<uint(z)-y-1).Scan(&tileData); err != nil {
		http.NotFound(w, r)
		return
	}
	w.Write(tileData)
}
<|endoftext|>


<commit_before>package nsq

import (
	"bytes"
	"encoding/binary"
	"io"
	"io/ioutil"
	"time"
)

const (
	MsgIdLength = 16
)

// Message is the fundamental data type containing
// the id, body, and meta-data
type Message struct {
	Id        []byte
	Body      []byte
	Timestamp int64
	Retries   uint16
	UtilChan  chan int
}

// NewMessage creates a Message, initializes some meta-data,
// and returns a pointer
func NewMessage(id []byte, body []byte) *Message {
	return &Message{
		Id:        id,
		Body:      body,
		Timestamp: time.Now().Unix(),
		UtilChan:  make(chan int),
	}
}

// Encode serializes the receiver into []byte
func (m *Message) Encode() ([]byte, error) {
	var buf bytes.Buffer

	err := binary.Write(&buf, binary.BigEndian, &m.Timestamp)
	if err != nil {
		return nil, err
	}

	err = binary.Write(&buf, binary.BigEndian, &m.Retries)
	if err != nil {
		return nil, err
	}

	_, err = buf.Write(m.Id)
	if err != nil {
		return nil, err
	}

	_, err = buf.Write(m.Body)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// DecodeMessage deseralizes data (as []byte) and creates/returns
// a pointer to a new Message
func DecodeMessage(byteBuf []byte) (*Message, error) {
	var timestamp int64
	var retries uint16

	buf := bytes.NewBuffer(byteBuf)

	err := binary.Read(buf, binary.BigEndian, &timestamp)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &retries)
	if err != nil {
		return nil, err
	}

	id := make([]byte, MsgIdLength)
	_, err = io.ReadFull(buf, id)
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(buf)
	if err != nil {
		return nil, err
	}

	msg := NewMessage(id, body)
	msg.Timestamp = timestamp
	msg.Retries = retries

	return msg, nil
}
<commit_msg>refactor message handling to use a deterministic # of goroutines (not 3 per message) and use priority queues to manage the in flight and deferred requeue lists on a nsq channel<commit_after>package nsq

import (
	"bytes"
	"encoding/binary"
	"io"
	"io/ioutil"
	"time"
)

const (
	MsgIdLength = 16
)

// Message is the fundamental data type containing
// the id, body, and meta-data
type Message struct {
	Id        []byte
	Body      []byte
	Timestamp int64
	Retries   uint16
}

// NewMessage creates a Message, initializes some meta-data,
// and returns a pointer
func NewMessage(id []byte, body []byte) *Message {
	return &Message{
		Id:        id,
		Body:      body,
		Timestamp: time.Now().Unix(),
	}
}

// Encode serializes the receiver into []byte
func (m *Message) Encode() ([]byte, error) {
	var buf bytes.Buffer

	err := binary.Write(&buf, binary.BigEndian, &m.Timestamp)
	if err != nil {
		return nil, err
	}

	err = binary.Write(&buf, binary.BigEndian, &m.Retries)
	if err != nil {
		return nil, err
	}

	_, err = buf.Write(m.Id)
	if err != nil {
		return nil, err
	}

	_, err = buf.Write(m.Body)
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// DecodeMessage deseralizes data (as []byte) and creates/returns
// a pointer to a new Message
func DecodeMessage(byteBuf []byte) (*Message, error) {
	var timestamp int64
	var retries uint16

	buf := bytes.NewBuffer(byteBuf)

	err := binary.Read(buf, binary.BigEndian, &timestamp)
	if err != nil {
		return nil, err
	}

	err = binary.Read(buf, binary.BigEndian, &retries)
	if err != nil {
		return nil, err
	}

	id := make([]byte, MsgIdLength)
	_, err = io.ReadFull(buf, id)
	if err != nil {
		return nil, err
	}

	body, err := ioutil.ReadAll(buf)
	if err != nil {
		return nil, err
	}

	msg := NewMessage(id, body)
	msg.Timestamp = timestamp
	msg.Retries = retries

	return msg, nil
}
<|endoftext|>


<commit_before>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to the Message struct

package discordgo

import (
	"io"
	"regexp"
	"strings"
)

// MessageType is the type of Message
// https://discord.com/developers/docs/resources/channel#message-object-message-types
type MessageType int

// Block contains the valid known MessageType values
const (
	MessageTypeDefault MessageType = iota
	MessageTypeRecipientAdd
	MessageTypeRecipientRemove
	MessageTypeCall
	MessageTypeChannelNameChange
	MessageTypeChannelIconChange
	MessageTypeChannelPinnedMessage
	MessageTypeGuildMemberJoin
	MessageTypeUserPremiumGuildSubscription
	MessageTypeUserPremiumGuildSubscriptionTierOne
	MessageTypeUserPremiumGuildSubscriptionTierTwo
	MessageTypeUserPremiumGuildSubscriptionTierThree
	MessageTypeChannelFollowAdd
	MessageTypeGuildDiscoveryDisqualified
	MessageTypeGuildDiscoveryRequalified
)

// A Message stores all data related to a specific Discord message.
type Message struct {
	// The ID of the message.
	ID string `json:"id"`

	// The ID of the channel in which the message was sent.
	ChannelID string `json:"channel_id"`

	// The ID of the guild in which the message was sent.
	GuildID string `json:"guild_id,omitempty"`

	// The content of the message.
	Content string `json:"content"`

	// The time at which the messsage was sent.
	// CAUTION: this field may be removed in a
	// future API version; it is safer to calculate
	// the creation time via the ID.
	Timestamp Timestamp `json:"timestamp"`

	// The time at which the last edit of the message
	// occurred, if it has been edited.
	EditedTimestamp Timestamp `json:"edited_timestamp"`

	// The roles mentioned in the message.
	MentionRoles []string `json:"mention_roles"`

	// Whether the message is text-to-speech.
	TTS bool `json:"tts"`

	// Whether the message mentions everyone.
	MentionEveryone bool `json:"mention_everyone"`

	// The author of the message. This is not guaranteed to be a
	// valid user (webhook-sent messages do not possess a full author).
	Author *User `json:"author"`

	// A list of attachments present in the message.
	Attachments []*MessageAttachment `json:"attachments"`

	// A list of embeds present in the message. Multiple
	// embeds can currently only be sent by webhooks.
	Embeds []*MessageEmbed `json:"embeds"`

	// A list of users mentioned in the message.
	Mentions []*User `json:"mentions"`

	// A list of reactions to the message.
	Reactions []*MessageReactions `json:"reactions"`

	// Whether the message is pinned or not.
	Pinned bool `json:"pinned"`

	// The type of the message.
	Type MessageType `json:"type"`

	// The webhook ID of the message, if it was generated by a webhook
	WebhookID string `json:"webhook_id"`

	// Member properties for this message's author,
	// contains only partial information
	Member *Member `json:"member"`

	// Channels specifically mentioned in this message
	// Not all channel mentions in a message will appear in mention_channels.
	// Only textual channels that are visible to everyone in a lurkable guild will ever be included.
	// Only crossposted messages (via Channel Following) currently include mention_channels at all.
	// If no mentions in the message meet these requirements, this field will not be sent.
	MentionChannels []*Channel `json:"mention_channels"`

	// Is sent with Rich Presence-related chat embeds
	Activity *MessageActivity `json:"activity"`

	// Is sent with Rich Presence-related chat embeds
	Application *MessageApplication `json:"application"`

	// MessageReference contains reference data sent with crossposted messages
	MessageReference *MessageReference `json:"message_reference"`

	// The flags of the message, which describe extra features of a message.
	// This is a combination of bit masks; the presence of a certain permission can
	// be checked by performing a bitwise AND between this int and the flag.
	Flags MessageFlags `json:"flags"`
}

// MessageFlags is the flags of "message" (see MessageFlags* consts)
// https://discord.com/developers/docs/resources/channel#message-object-message-flags
type MessageFlags int

// Valid MessageFlags values
const (
	MessageFlagsCrossPosted MessageFlags = 1 << iota
	MessageFlagsIsCrossPosted
	MessageFlagsSupressEmbeds
	MessageFlagsSourceMessageDeleted
	MessageFlagsUrgent
)

// File stores info about files you e.g. send in messages.
type File struct {
	Name        string
	ContentType string
	Reader      io.Reader
}

// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
type MessageSend struct {
	Content         string                  `json:"content,omitempty"`
	Embed           *MessageEmbed           `json:"embed,omitempty"`
	TTS             bool                    `json:"tts"`
	Files           []*File                 `json:"-"`
	AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
	Reference       *MessageReference       `json:"message_reference,omitempty"`

	// TODO: Remove this when compatibility is not required.
	File *File `json:"-"`
}

// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
// is also where you should get the instance from.
type MessageEdit struct {
	Content         *string                 `json:"content,omitempty"`
	Embed           *MessageEmbed           `json:"embed,omitempty"`
	AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`

	ID      string
	Channel string
}

// NewMessageEdit returns a MessageEdit struct, initialized
// with the Channel and ID.
func NewMessageEdit(channelID string, messageID string) *MessageEdit {
	return &MessageEdit{
		Channel: channelID,
		ID:      messageID,
	}
}

// SetContent is the same as setting the variable Content,
// except it doesn't take a pointer.
func (m *MessageEdit) SetContent(str string) *MessageEdit {
	m.Content = &str
	return m
}

// SetEmbed is a convenience function for setting the embed,
// so you can chain commands.
func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
	m.Embed = embed
	return m
}

// AllowedMentionType describes the types of mentions used
// in the MessageAllowedMentions type.
type AllowedMentionType string

// The types of mentions used in MessageAllowedMentions.
const (
	AllowedMentionTypeRoles    AllowedMentionType = "roles"
	AllowedMentionTypeUsers    AllowedMentionType = "users"
	AllowedMentionTypeEveryone AllowedMentionType = "everyone"
)

// MessageAllowedMentions allows the user to specify which mentions
// Discord is allowed to parse in this message. This is useful when
// sending user input as a message, as it prevents unwanted mentions.
// If this type is used, all mentions must be explicitly whitelisted,
// either by putting an AllowedMentionType in the Parse slice
// (allowing all mentions of that type) or, in the case of roles and
// users, explicitly allowing those mentions on an ID-by-ID basis.
// For more information on this functionality, see:
// https://discordapp.com/developers/docs/resources/channel#allowed-mentions-object-allowed-mentions-reference
type MessageAllowedMentions struct {
	// The mention types that are allowed to be parsed in this message.
	// Please note that this is purposely **not** marked as omitempty,
	// so if a zero-value MessageAllowedMentions object is provided no
	// mentions will be allowed.
	Parse []AllowedMentionType `json:"parse"`

	// A list of role IDs to allow. This cannot be used when specifying
	// AllowedMentionTypeRoles in the Parse slice.
	Roles []string `json:"roles,omitempty"`

	// A list of user IDs to allow. This cannot be used when specifying
	// AllowedMentionTypeUsers in the Parse slice.
	Users []string `json:"users,omitempty"`
}

// A MessageAttachment stores data for message attachments.
type MessageAttachment struct {
	ID       string `json:"id"`
	URL      string `json:"url"`
	ProxyURL string `json:"proxy_url"`
	Filename string `json:"filename"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	Size     int    `json:"size"`
}

// MessageEmbedFooter is a part of a MessageEmbed struct.
type MessageEmbedFooter struct {
	Text         string `json:"text,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedImage is a part of a MessageEmbed struct.
type MessageEmbedImage struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedThumbnail is a part of a MessageEmbed struct.
type MessageEmbedThumbnail struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedVideo is a part of a MessageEmbed struct.
type MessageEmbedVideo struct {
	URL    string `json:"url,omitempty"`
	Width  int    `json:"width,omitempty"`
	Height int    `json:"height,omitempty"`
}

// MessageEmbedProvider is a part of a MessageEmbed struct.
type MessageEmbedProvider struct {
	URL  string `json:"url,omitempty"`
	Name string `json:"name,omitempty"`
}

// MessageEmbedAuthor is a part of a MessageEmbed struct.
type MessageEmbedAuthor struct {
	URL          string `json:"url,omitempty"`
	Name         string `json:"name,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedField is a part of a MessageEmbed struct.
type MessageEmbedField struct {
	Name   string `json:"name,omitempty"`
	Value  string `json:"value,omitempty"`
	Inline bool   `json:"inline,omitempty"`
}

// An MessageEmbed stores data for message embeds.
type MessageEmbed struct {
	URL         string                 `json:"url,omitempty"`
	Type        EmbedType              `json:"type,omitempty"`
	Title       string                 `json:"title,omitempty"`
	Description string                 `json:"description,omitempty"`
	Timestamp   string                 `json:"timestamp,omitempty"`
	Color       int                    `json:"color,omitempty"`
	Footer      *MessageEmbedFooter    `json:"footer,omitempty"`
	Image       *MessageEmbedImage     `json:"image,omitempty"`
	Thumbnail   *MessageEmbedThumbnail `json:"thumbnail,omitempty"`
	Video       *MessageEmbedVideo     `json:"video,omitempty"`
	Provider    *MessageEmbedProvider  `json:"provider,omitempty"`
	Author      *MessageEmbedAuthor    `json:"author,omitempty"`
	Fields      []*MessageEmbedField   `json:"fields,omitempty"`
}

// EmbedType is the type of embed
// https://discord.com/developers/docs/resources/channel#embed-object-embed-types
type EmbedType string

// Block of valid EmbedTypes
const (
	EmbedTypeRich    EmbedType = "rich"
	EmbedTypeImage   EmbedType = "image"
	EmbedTypeVideo   EmbedType = "video"
	EmbedTypeGifv    EmbedType = "gifv"
	EmbedTypeArticle EmbedType = "article"
	EmbedTypeLink    EmbedType = "link"
)

// MessageReactions holds a reactions object for a message.
type MessageReactions struct {
	Count int    `json:"count"`
	Me    bool   `json:"me"`
	Emoji *Emoji `json:"emoji"`
}

// MessageActivity is sent with Rich Presence-related chat embeds
type MessageActivity struct {
	Type    MessageActivityType `json:"type"`
	PartyID string              `json:"party_id"`
}

// MessageActivityType is the type of message activity
type MessageActivityType int

// Constants for the different types of Message Activity
const (
	MessageActivityTypeJoin MessageActivityType = iota + 1
	MessageActivityTypeSpectate
	MessageActivityTypeListen
	MessageActivityTypeJoinRequest
)

// MessageFlag describes an extra feature of the message
type MessageFlag int

// Constants for the different bit offsets of Message Flags
const (
	// This message has been published to subscribed channels (via Channel Following)
	MessageFlagCrossposted MessageFlag = 1 << iota
	// This message originated from a message in another channel (via Channel Following)
	MessageFlagIsCrosspost
	// Do not include any embeds when serializing this message
	MessageFlagSuppressEmbeds
)

// MessageApplication is sent with Rich Presence-related chat embeds
type MessageApplication struct {
	ID          string `json:"id"`
	CoverImage  string `json:"cover_image"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
	Name        string `json:"name"`
}

// MessageReference contains reference data sent with crossposted messages
type MessageReference struct {
	MessageID string `json:"message_id"`
	ChannelID string `json:"channel_id"`
	GuildID   string `json:"guild_id"`
}

// Reference returns MessageReference of given message
func (m *Message) Reference() *MessageReference {
	return &MessageReference{
		GuildID:   m.GuildID,
		ChannelID: m.ChannelID,
		MessageID: m.ID,
	}
}

// ContentWithMentionsReplaced will replace all @<id> mentions with the
// username of the mention.
func (m *Message) ContentWithMentionsReplaced() (content string) {
	content = m.Content

	for _, user := range m.Mentions {
		content = strings.NewReplacer(
			"<@"+user.ID+">", "@"+user.Username,
			"<@!"+user.ID+">", "@"+user.Username,
		).Replace(content)
	}
	return
}

var patternChannels = regexp.MustCompile("<#[^>]*>")

// ContentWithMoreMentionsReplaced will replace all @<id> mentions with the
// username of the mention, but also role IDs and more.
func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) {
	content = m.Content

	if !s.StateEnabled {
		content = m.ContentWithMentionsReplaced()
		return
	}

	channel, err := s.State.Channel(m.ChannelID)
	if err != nil {
		content = m.ContentWithMentionsReplaced()
		return
	}

	for _, user := range m.Mentions {
		nick := user.Username

		member, err := s.State.Member(channel.GuildID, user.ID)
		if err == nil && member.Nick != "" {
			nick = member.Nick
		}

		content = strings.NewReplacer(
			"<@"+user.ID+">", "@"+user.Username,
			"<@!"+user.ID+">", "@"+nick,
		).Replace(content)
	}
	for _, roleID := range m.MentionRoles {
		role, err := s.State.Role(channel.GuildID, roleID)
		if err != nil || !role.Mentionable {
			continue
		}

		content = strings.Replace(content, "<@&"+role.ID+">", "@"+role.Name, -1)
	}

	content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string {
		channel, err := s.State.Channel(mention[2 : len(mention)-1])
		if err != nil || channel.Type == ChannelTypeGuildVoice {
			return mention
		}

		return "#" + channel.Name
	})
	return
}
<commit_msg>Add omitempty to MessageReference's GuildID field<commit_after>// Discordgo - Discord bindings for Go
// Available at https://github.com/bwmarrin/discordgo

// Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains code related to the Message struct

package discordgo

import (
	"io"
	"regexp"
	"strings"
)

// MessageType is the type of Message
// https://discord.com/developers/docs/resources/channel#message-object-message-types
type MessageType int

// Block contains the valid known MessageType values
const (
	MessageTypeDefault MessageType = iota
	MessageTypeRecipientAdd
	MessageTypeRecipientRemove
	MessageTypeCall
	MessageTypeChannelNameChange
	MessageTypeChannelIconChange
	MessageTypeChannelPinnedMessage
	MessageTypeGuildMemberJoin
	MessageTypeUserPremiumGuildSubscription
	MessageTypeUserPremiumGuildSubscriptionTierOne
	MessageTypeUserPremiumGuildSubscriptionTierTwo
	MessageTypeUserPremiumGuildSubscriptionTierThree
	MessageTypeChannelFollowAdd
	MessageTypeGuildDiscoveryDisqualified
	MessageTypeGuildDiscoveryRequalified
)

// A Message stores all data related to a specific Discord message.
type Message struct {
	// The ID of the message.
	ID string `json:"id"`

	// The ID of the channel in which the message was sent.
	ChannelID string `json:"channel_id"`

	// The ID of the guild in which the message was sent.
	GuildID string `json:"guild_id,omitempty"`

	// The content of the message.
	Content string `json:"content"`

	// The time at which the messsage was sent.
	// CAUTION: this field may be removed in a
	// future API version; it is safer to calculate
	// the creation time via the ID.
	Timestamp Timestamp `json:"timestamp"`

	// The time at which the last edit of the message
	// occurred, if it has been edited.
	EditedTimestamp Timestamp `json:"edited_timestamp"`

	// The roles mentioned in the message.
	MentionRoles []string `json:"mention_roles"`

	// Whether the message is text-to-speech.
	TTS bool `json:"tts"`

	// Whether the message mentions everyone.
	MentionEveryone bool `json:"mention_everyone"`

	// The author of the message. This is not guaranteed to be a
	// valid user (webhook-sent messages do not possess a full author).
	Author *User `json:"author"`

	// A list of attachments present in the message.
	Attachments []*MessageAttachment `json:"attachments"`

	// A list of embeds present in the message. Multiple
	// embeds can currently only be sent by webhooks.
	Embeds []*MessageEmbed `json:"embeds"`

	// A list of users mentioned in the message.
	Mentions []*User `json:"mentions"`

	// A list of reactions to the message.
	Reactions []*MessageReactions `json:"reactions"`

	// Whether the message is pinned or not.
	Pinned bool `json:"pinned"`

	// The type of the message.
	Type MessageType `json:"type"`

	// The webhook ID of the message, if it was generated by a webhook
	WebhookID string `json:"webhook_id"`

	// Member properties for this message's author,
	// contains only partial information
	Member *Member `json:"member"`

	// Channels specifically mentioned in this message
	// Not all channel mentions in a message will appear in mention_channels.
	// Only textual channels that are visible to everyone in a lurkable guild will ever be included.
	// Only crossposted messages (via Channel Following) currently include mention_channels at all.
	// If no mentions in the message meet these requirements, this field will not be sent.
	MentionChannels []*Channel `json:"mention_channels"`

	// Is sent with Rich Presence-related chat embeds
	Activity *MessageActivity `json:"activity"`

	// Is sent with Rich Presence-related chat embeds
	Application *MessageApplication `json:"application"`

	// MessageReference contains reference data sent with crossposted messages
	MessageReference *MessageReference `json:"message_reference"`

	// The flags of the message, which describe extra features of a message.
	// This is a combination of bit masks; the presence of a certain permission can
	// be checked by performing a bitwise AND between this int and the flag.
	Flags MessageFlags `json:"flags"`
}

// MessageFlags is the flags of "message" (see MessageFlags* consts)
// https://discord.com/developers/docs/resources/channel#message-object-message-flags
type MessageFlags int

// Valid MessageFlags values
const (
	MessageFlagsCrossPosted MessageFlags = 1 << iota
	MessageFlagsIsCrossPosted
	MessageFlagsSupressEmbeds
	MessageFlagsSourceMessageDeleted
	MessageFlagsUrgent
)

// File stores info about files you e.g. send in messages.
type File struct {
	Name        string
	ContentType string
	Reader      io.Reader
}

// MessageSend stores all parameters you can send with ChannelMessageSendComplex.
type MessageSend struct {
	Content         string                  `json:"content,omitempty"`
	Embed           *MessageEmbed           `json:"embed,omitempty"`
	TTS             bool                    `json:"tts"`
	Files           []*File                 `json:"-"`
	AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`
	Reference       *MessageReference       `json:"message_reference,omitempty"`

	// TODO: Remove this when compatibility is not required.
	File *File `json:"-"`
}

// MessageEdit is used to chain parameters via ChannelMessageEditComplex, which
// is also where you should get the instance from.
type MessageEdit struct {
	Content         *string                 `json:"content,omitempty"`
	Embed           *MessageEmbed           `json:"embed,omitempty"`
	AllowedMentions *MessageAllowedMentions `json:"allowed_mentions,omitempty"`

	ID      string
	Channel string
}

// NewMessageEdit returns a MessageEdit struct, initialized
// with the Channel and ID.
func NewMessageEdit(channelID string, messageID string) *MessageEdit {
	return &MessageEdit{
		Channel: channelID,
		ID:      messageID,
	}
}

// SetContent is the same as setting the variable Content,
// except it doesn't take a pointer.
func (m *MessageEdit) SetContent(str string) *MessageEdit {
	m.Content = &str
	return m
}

// SetEmbed is a convenience function for setting the embed,
// so you can chain commands.
func (m *MessageEdit) SetEmbed(embed *MessageEmbed) *MessageEdit {
	m.Embed = embed
	return m
}

// AllowedMentionType describes the types of mentions used
// in the MessageAllowedMentions type.
type AllowedMentionType string

// The types of mentions used in MessageAllowedMentions.
const (
	AllowedMentionTypeRoles    AllowedMentionType = "roles"
	AllowedMentionTypeUsers    AllowedMentionType = "users"
	AllowedMentionTypeEveryone AllowedMentionType = "everyone"
)

// MessageAllowedMentions allows the user to specify which mentions
// Discord is allowed to parse in this message. This is useful when
// sending user input as a message, as it prevents unwanted mentions.
// If this type is used, all mentions must be explicitly whitelisted,
// either by putting an AllowedMentionType in the Parse slice
// (allowing all mentions of that type) or, in the case of roles and
// users, explicitly allowing those mentions on an ID-by-ID basis.
// For more information on this functionality, see:
// https://discordapp.com/developers/docs/resources/channel#allowed-mentions-object-allowed-mentions-reference
type MessageAllowedMentions struct {
	// The mention types that are allowed to be parsed in this message.
	// Please note that this is purposely **not** marked as omitempty,
	// so if a zero-value MessageAllowedMentions object is provided no
	// mentions will be allowed.
	Parse []AllowedMentionType `json:"parse"`

	// A list of role IDs to allow. This cannot be used when specifying
	// AllowedMentionTypeRoles in the Parse slice.
	Roles []string `json:"roles,omitempty"`

	// A list of user IDs to allow. This cannot be used when specifying
	// AllowedMentionTypeUsers in the Parse slice.
	Users []string `json:"users,omitempty"`
}

// A MessageAttachment stores data for message attachments.
type MessageAttachment struct {
	ID       string `json:"id"`
	URL      string `json:"url"`
	ProxyURL string `json:"proxy_url"`
	Filename string `json:"filename"`
	Width    int    `json:"width"`
	Height   int    `json:"height"`
	Size     int    `json:"size"`
}

// MessageEmbedFooter is a part of a MessageEmbed struct.
type MessageEmbedFooter struct {
	Text         string `json:"text,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedImage is a part of a MessageEmbed struct.
type MessageEmbedImage struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedThumbnail is a part of a MessageEmbed struct.
type MessageEmbedThumbnail struct {
	URL      string `json:"url,omitempty"`
	ProxyURL string `json:"proxy_url,omitempty"`
	Width    int    `json:"width,omitempty"`
	Height   int    `json:"height,omitempty"`
}

// MessageEmbedVideo is a part of a MessageEmbed struct.
type MessageEmbedVideo struct {
	URL    string `json:"url,omitempty"`
	Width  int    `json:"width,omitempty"`
	Height int    `json:"height,omitempty"`
}

// MessageEmbedProvider is a part of a MessageEmbed struct.
type MessageEmbedProvider struct {
	URL  string `json:"url,omitempty"`
	Name string `json:"name,omitempty"`
}

// MessageEmbedAuthor is a part of a MessageEmbed struct.
type MessageEmbedAuthor struct {
	URL          string `json:"url,omitempty"`
	Name         string `json:"name,omitempty"`
	IconURL      string `json:"icon_url,omitempty"`
	ProxyIconURL string `json:"proxy_icon_url,omitempty"`
}

// MessageEmbedField is a part of a MessageEmbed struct.
type MessageEmbedField struct {
	Name   string `json:"name,omitempty"`
	Value  string `json:"value,omitempty"`
	Inline bool   `json:"inline,omitempty"`
}

// An MessageEmbed stores data for message embeds.
type MessageEmbed struct {
	URL         string                 `json:"url,omitempty"`
	Type        EmbedType              `json:"type,omitempty"`
	Title       string                 `json:"title,omitempty"`
	Description string                 `json:"description,omitempty"`
	Timestamp   string                 `json:"timestamp,omitempty"`
	Color       int                    `json:"color,omitempty"`
	Footer      *MessageEmbedFooter    `json:"footer,omitempty"`
	Image       *MessageEmbedImage     `json:"image,omitempty"`
	Thumbnail   *MessageEmbedThumbnail `json:"thumbnail,omitempty"`
	Video       *MessageEmbedVideo     `json:"video,omitempty"`
	Provider    *MessageEmbedProvider  `json:"provider,omitempty"`
	Author      *MessageEmbedAuthor    `json:"author,omitempty"`
	Fields      []*MessageEmbedField   `json:"fields,omitempty"`
}

// EmbedType is the type of embed
// https://discord.com/developers/docs/resources/channel#embed-object-embed-types
type EmbedType string

// Block of valid EmbedTypes
const (
	EmbedTypeRich    EmbedType = "rich"
	EmbedTypeImage   EmbedType = "image"
	EmbedTypeVideo   EmbedType = "video"
	EmbedTypeGifv    EmbedType = "gifv"
	EmbedTypeArticle EmbedType = "article"
	EmbedTypeLink    EmbedType = "link"
)

// MessageReactions holds a reactions object for a message.
type MessageReactions struct {
	Count int    `json:"count"`
	Me    bool   `json:"me"`
	Emoji *Emoji `json:"emoji"`
}

// MessageActivity is sent with Rich Presence-related chat embeds
type MessageActivity struct {
	Type    MessageActivityType `json:"type"`
	PartyID string              `json:"party_id"`
}

// MessageActivityType is the type of message activity
type MessageActivityType int

// Constants for the different types of Message Activity
const (
	MessageActivityTypeJoin MessageActivityType = iota + 1
	MessageActivityTypeSpectate
	MessageActivityTypeListen
	MessageActivityTypeJoinRequest
)

// MessageFlag describes an extra feature of the message
type MessageFlag int

// Constants for the different bit offsets of Message Flags
const (
	// This message has been published to subscribed channels (via Channel Following)
	MessageFlagCrossposted MessageFlag = 1 << iota
	// This message originated from a message in another channel (via Channel Following)
	MessageFlagIsCrosspost
	// Do not include any embeds when serializing this message
	MessageFlagSuppressEmbeds
)

// MessageApplication is sent with Rich Presence-related chat embeds
type MessageApplication struct {
	ID          string `json:"id"`
	CoverImage  string `json:"cover_image"`
	Description string `json:"description"`
	Icon        string `json:"icon"`
	Name        string `json:"name"`
}

// MessageReference contains reference data sent with crossposted messages
type MessageReference struct {
	MessageID string `json:"message_id"`
	ChannelID string `json:"channel_id"`
	GuildID   string `json:"guild_id,omitempty"`
}

// Reference returns MessageReference of given message
func (m *Message) Reference() *MessageReference {
	return &MessageReference{
		GuildID:   m.GuildID,
		ChannelID: m.ChannelID,
		MessageID: m.ID,
	}
}

// ContentWithMentionsReplaced will replace all @<id> mentions with the
// username of the mention.
func (m *Message) ContentWithMentionsReplaced() (content string) {
	content = m.Content

	for _, user := range m.Mentions {
		content = strings.NewReplacer(
			"<@"+user.ID+">", "@"+user.Username,
			"<@!"+user.ID+">", "@"+user.Username,
		).Replace(content)
	}
	return
}

var patternChannels = regexp.MustCompile("<#[^>]*>")

// ContentWithMoreMentionsReplaced will replace all @<id> mentions with the
// username of the mention, but also role IDs and more.
func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) {
	content = m.Content

	if !s.StateEnabled {
		content = m.ContentWithMentionsReplaced()
		return
	}

	channel, err := s.State.Channel(m.ChannelID)
	if err != nil {
		content = m.ContentWithMentionsReplaced()
		return
	}

	for _, user := range m.Mentions {
		nick := user.Username

		member, err := s.State.Member(channel.GuildID, user.ID)
		if err == nil && member.Nick != "" {
			nick = member.Nick
		}

		content = strings.NewReplacer(
			"<@"+user.ID+">", "@"+user.Username,
			"<@!"+user.ID+">", "@"+nick,
		).Replace(content)
	}
	for _, roleID := range m.MentionRoles {
		role, err := s.State.Role(channel.GuildID, roleID)
		if err != nil || !role.Mentionable {
			continue
		}

		content = strings.Replace(content, "<@&"+role.ID+">", "@"+role.Name, -1)
	}

	content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string {
		channel, err := s.State.Channel(mention[2 : len(mention)-1])
		if err != nil || channel.Type == ChannelTypeGuildVoice {
			return mention
		}

		return "#" + channel.Name
	})
	return
}
<|endoftext|>


<commit_before>package serializedcall

type Message struct {
	Error   string
	Message string
	Payload []byte
}
<commit_msg>use string for payload<commit_after>package serializedcall

type Message struct {
	Error   string
	Message string
	Payload string
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"time"

	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/load"
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/net"
)

//Metrics represents a basic struct with systems stats
type Metrics struct {
	//CPU
	CPUStats []cpu.TimesStat `json:"cpustats"`
	//Memory
	MemStats  *mem.VirtualMemoryStat `json:"memstats"`
	SwapStats *mem.SwapMemoryStat    `json:"swapstats"`
	//Disk
	IOStats        map[string]disk.IOCountersStat `json:"iostats"`
	PartitionStats []disk.PartitionStat           `json:"partitionstats"`
	UsageStats     []*disk.UsageStat              `json:"usagestats"`
	//Load Average
	LoadAverage *load.AvgStat  `json:"loadaverage"`
	MiscStats   *load.MiscStat `json:"miscstats"`
	//Network
	InterfaceStats []net.InterfaceStat  `json:"interfacestats"`
	IONetStats     []net.IOCountersStat `json:"ionetstats"`
}

func getNetInfo() ([]net.InterfaceStat, []net.IOCountersStat, error) {
	istats, err := net.Interfaces()
	if err != nil {
		return nil, nil, fmt.Errorf("Error getting network interfaces stats: %v", err)
	}
	ionetstats, err := net.IOCounters(true)
	if err != nil {
		return nil, nil, fmt.Errorf("Error getting network io stats for %v", err)
	}
	return istats, ionetstats, nil
}

func getLoadAverage() (*load.AvgStat, *load.MiscStat, error) {
	lastats, err := load.Avg()
	if err != nil {
		return nil, nil, fmt.Errorf("Error getting load average information: %v", err)
	}
	msstats, err := load.Misc()
	if err != nil {
		return nil, nil, fmt.Errorf("Error getting Misc information: %v", err)
	}
	return lastats, msstats, nil
}

func getDiskInfo() (map[string]disk.IOCountersStat, []disk.PartitionStat, []*disk.UsageStat, error) {
	pstats, err := disk.Partitions(false)
	if err != nil {
		return nil, nil, nil, fmt.Errorf("Error getting partition stats: %v", err)
	}
	iostats, err := disk.IOCounters()
	if err != nil {
		return nil, nil, nil, fmt.Errorf("Error getting io stats for %v", err)
	}
	var usstats []*disk.UsageStat
	for _, partition := range pstats {
		usstat, err := disk.Usage(partition.Device)
		if err != nil {
			return nil, nil, nil, fmt.Errorf("Error getting usage stats for %s: %v", partition.Device, err)
		}
		usstats = append(usstats, usstat)
	}
	return iostats, pstats, usstats, nil
}

func getSWAPInfo() (*mem.SwapMemoryStat, error) {
	swapstats, err := mem.SwapMemory()
	if err != nil {
		return nil, fmt.Errorf("Error getting swap information: %v", err)
	}
	return swapstats, nil
}

func getRAMInfo() (*mem.VirtualMemoryStat, error) {
	memstats, err := mem.VirtualMemory()
	if err != nil {
		return nil, fmt.Errorf("Error getting memory information: %v", err)
	}
	return memstats, nil
}

func getCPUInfo() ([]cpu.TimesStat, error) {
	cpustats, err := cpu.Times(true)
	if err != nil {
		return nil, fmt.Errorf("Error getting cpu information: %v", err)
	}
	return cpustats, nil
}

func (agent *Agent) basicMetrics() {
	for {
		c, err := getCPUInfo()
		if err != nil {
			log.Println(err)
		}
		m, err := getRAMInfo()
		if err != nil {
			log.Println(err)
		}
		s, err := getSWAPInfo()
		if err != nil {
			log.Println(err)
		}
		io, ps, us, err := getDiskInfo()
		if err != nil {
			log.Println(err)
		}
		la, ms, err := getLoadAverage()
		if err != nil {
			log.Println(err)
		}
		ni, ionet, err := getNetInfo()
		if err != nil {
			log.Println(err)
		}
		metrics.CPUStats = c
		metrics.MemStats = m
		metrics.SwapStats = s
		metrics.IOStats = io
		metrics.PartitionStats = ps
		metrics.UsageStats = us
		metrics.LoadAverage = la
		metrics.MiscStats = ms
		metrics.InterfaceStats = ni
		metrics.IONetStats = ionet
		time.Sleep(3 * time.Second)
	}
}
<commit_msg>Add Labels to send for the metrics<commit_after>package main

import (
	"fmt"
	"log"
	"time"

	"github.com/shirou/gopsutil/cpu"
	"github.com/shirou/gopsutil/disk"
	"github.com/shirou/gopsutil/load"
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/net"
)

//Metrics represents a basic struct with systems stats
type Metrics struct {
	//CPU
	CPUStats []cpu.TimesStat `json:"cpustats"`
	//Memory
	MemStats  *mem.VirtualMemoryStat `json:"memstats"`
	SwapStats *mem.SwapMemoryStat    `json:"swapstats"`
	//Disk
	IOStats        map[string]disk.IOCountersStat `json:"iostats"`
	PartitionStats []disk.PartitionStat           `json:"partitionstats"`
	UsageStats     []*disk.UsageStat              `json:"usagestats"`
	//Load Average
	LoadAverage *load.AvgStat  `json:"loadaverage"`
	MiscStats   *load.MiscStat `json:"miscstats"`
	//Network
	InterfaceStats []net.InterfaceStat  `json:"interfacestats"`
	IONetStats     []net.IOCountersStat `json:"ionetstats"`
	//Agent pikacloud
	Labels []string `json:"labels"`
}

func getNetInfo() ([]net.InterfaceStat, []net.IOCountersStat, error) {
	istats, err := net.Interfaces()
	if err != nil {
		return nil, nil, fmt.Errorf("Error getting network interfaces stats: %v", err)
	}
	ionetstats, err := net.IOCounters(true)
	if err != nil {
		return nil, nil, fmt.Errorf("Error getting network io stats for %v", err)
	}
	return istats, ionetstats, nil
}

func getLoadAverage() (*load.AvgStat, *load.MiscStat, error) {
	lastats, err := load.Avg()
	if err != nil {
		return nil, nil, fmt.Errorf("Error getting load average information: %v", err)
	}
	msstats, err := load.Misc()
	if err != nil {
		return nil, nil, fmt.Errorf("Error getting Misc information: %v", err)
	}
	return lastats, msstats, nil
}

func getDiskInfo() (map[string]disk.IOCountersStat, []disk.PartitionStat, []*disk.UsageStat, error) {
	pstats, err := disk.Partitions(false)
	if err != nil {
		return nil, nil, nil, fmt.Errorf("Error getting partition stats: %v", err)
	}
	iostats, err := disk.IOCounters()
	if err != nil {
		return nil, nil, nil, fmt.Errorf("Error getting io stats for %v", err)
	}
	var usstats []*disk.UsageStat
	for _, partition := range pstats {
		usstat, err := disk.Usage(partition.Device)
		if err != nil {
			return nil, nil, nil, fmt.Errorf("Error getting usage stats for %s: %v", partition.Device, err)
		}
		usstats = append(usstats, usstat)
	}
	return iostats, pstats, usstats, nil
}

func getSWAPInfo() (*mem.SwapMemoryStat, error) {
	swapstats, err := mem.SwapMemory()
	if err != nil {
		return nil, fmt.Errorf("Error getting swap information: %v", err)
	}
	return swapstats, nil
}

func getRAMInfo() (*mem.VirtualMemoryStat, error) {
	memstats, err := mem.VirtualMemory()
	if err != nil {
		return nil, fmt.Errorf("Error getting memory information: %v", err)
	}
	return memstats, nil
}

func getCPUInfo() ([]cpu.TimesStat, error) {
	cpustats, err := cpu.Times(true)
	if err != nil {
		return nil, fmt.Errorf("Error getting cpu information: %v", err)
	}
	return cpustats, nil
}

func (agent *Agent) basicMetrics() {
	for {
		c, err := getCPUInfo()
		if err != nil {
			log.Println(err)
		}
		m, err := getRAMInfo()
		if err != nil {
			log.Println(err)
		}
		s, err := getSWAPInfo()
		if err != nil {
			log.Println(err)
		}
		io, ps, us, err := getDiskInfo()
		if err != nil {
			log.Println(err)
		}
		la, ms, err := getLoadAverage()
		if err != nil {
			log.Println(err)
		}
		ni, ionet, err := getNetInfo()
		if err != nil {
			log.Println(err)
		}
		metrics.CPUStats = c
		metrics.MemStats = m
		metrics.SwapStats = s
		metrics.IOStats = io
		metrics.PartitionStats = ps
		metrics.UsageStats = us
		metrics.LoadAverage = la
		metrics.MiscStats = ms
		metrics.InterfaceStats = ni
		metrics.IONetStats = ionet
		metrics.Labels = agent.Labels
		time.Sleep(3 * time.Second)
	}
}
<|endoftext|>


<commit_before>package cfutil

import (
	"github.com/gemnasium/migrate/migrate"
)

// Migrate() starts a database migration for the given
// database specified in `connectString`. It looks in the `path`
// for the migration files.
func Migrate(connectString, path string) ([]error, bool) {
	return migrate.UpSync(connectString, path)
}
<commit_msg>Remove migration<commit_after><|endoftext|>