<commit_before>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package commands

import (
	"fmt"
	"io"
	"strings"

	"github.com/spf13/cobra"

	"sigs.k8s.io/kustomize/kyaml/errors"
	"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
	"sigs.k8s.io/kustomize/kyaml/runfn"
	"sigs.k8s.io/kustomize/kyaml/yaml"

	"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
)

// GetCatRunner returns a RunFnRunner.
func GetRunFnRunner(name string) *RunFnRunner {
	r := &RunFnRunner{}
	c := &cobra.Command{
		Use:     "run [DIR]",
		Short:   commands.RunFnsShort,
		Long:    commands.RunFnsLong,
		Example: commands.RunFnsExamples,
		RunE:    r.runE,
		PreRunE: r.preRunE,
	}
	fixDocs(name, c)
	c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
		"also print resources from subpackages.")
	r.Command = c
	r.Command.Flags().BoolVar(
		&r.DryRun, "dry-run", false, "print results to stdout")
	r.Command.Flags().BoolVar(
		&r.GlobalScope, "global-scope", false, "set global scope for functions.")
	r.Command.Flags().StringSliceVar(
		&r.FnPaths, "fn-path", []string{},
		"read functions from these directories instead of the configuration directory.")
	r.Command.Flags().StringVar(
		&r.Image, "image", "",
		"run this image as a function instead of discovering them.")
	// NOTE: exec plugins execute arbitrary code -- never change the default value of this flag!!!
	r.Command.Flags().BoolVar(
		&r.EnableExec, "enable-exec", false /*do not change!*/, "enable support for exec functions -- note: exec functions run arbitrary code -- do not use for untrusted configs!!! (Alpha)")
	r.Command.Flags().StringVar(
		&r.ExecPath, "exec-path", "", "run an executable as a function. (Alpha)")
	r.Command.Flags().BoolVar(
		&r.EnableStar, "enable-star", false, "enable support for starlark functions. (Alpha)")
	r.Command.Flags().StringVar(
		&r.StarPath, "star-path", "", "run a starlark script as a function. (Alpha)")
	r.Command.Flags().StringVar(
		&r.StarURL, "star-url", "", "run a starlark script as a function. (Alpha)")
	r.Command.Flags().StringVar(
		&r.StarName, "star-name", "", "name of starlark program. (Alpha)")

	r.Command.Flags().StringVar(
		&r.ResultsDir, "results-dir", "", "write function results to this dir")

	r.Command.Flags().BoolVar(
		&r.Network, "network", false, "enable network access for functions that declare it")
	r.Command.Flags().StringVar(
		&r.NetworkName, "network-name", "bridge", "the docker network to run the container in")
	r.Command.Flags().StringArrayVar(
		&r.Mounts, "mount", []string{},
		"a list of storage options read from the filesystem")
	r.Command.Flags().BoolVar(
		&r.LogSteps, "log-steps", false, "log steps to stderr")
	return r
}

func RunCommand(name string) *cobra.Command {
	return GetRunFnRunner(name).Command
}

// RunFnRunner contains the run function
type RunFnRunner struct {
	IncludeSubpackages bool
	Command            *cobra.Command
	DryRun             bool
	GlobalScope        bool
	FnPaths            []string
	Image              string
	EnableStar         bool
	StarPath           string
	StarURL            string
	StarName           string
	EnableExec         bool
	ExecPath           string
	RunFns             runfn.RunFns
	ResultsDir         string
	Network            bool
	NetworkName        string
	Mounts             []string
	LogSteps           bool
}

func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
	return handleError(c, r.RunFns.Execute())
}

// getContainerFunctions parses the commandline flags and arguments into explicit
// Functions to run.
func (r *RunFnRunner) getContainerFunctions(c *cobra.Command, args, dataItems []string) (
	[]*yaml.RNode, error) {

	if r.Image == "" && r.StarPath == "" && r.ExecPath == "" && r.StarURL == "" {
		return nil, nil
	}

	var fn *yaml.RNode
	var err error

	if r.Image != "" {
		// create the function spec to set as an annotation
		fn, err = yaml.Parse(`container: {}`)
		if err != nil {
			return nil, err
		}
		// TODO: add support network, volumes, etc based on flag values
		err = fn.PipeE(
			yaml.Lookup("container"),
			yaml.SetField("image", yaml.NewScalarRNode(r.Image)))
		if err != nil {
			return nil, err
		}
		if r.Network {
			err = fn.PipeE(
				yaml.LookupCreate(yaml.MappingNode, "container", "network"),
				yaml.SetField("required", yaml.NewScalarRNode("true")))
			if err != nil {
				return nil, err
			}
		}
	} else if r.EnableStar && (r.StarPath != "" || r.StarURL != "") {
		// create the function spec to set as an annotation
		fn, err = yaml.Parse(`starlark: {}`)
		if err != nil {
			return nil, err
		}

		if r.StarPath != "" {
			err = fn.PipeE(
				yaml.Lookup("starlark"),
				yaml.SetField("path", yaml.NewScalarRNode(r.StarPath)))
			if err != nil {
				return nil, err
			}
		}
		if r.StarURL != "" {
			err = fn.PipeE(
				yaml.Lookup("starlark"),
				yaml.SetField("url", yaml.NewScalarRNode(r.StarURL)))
			if err != nil {
				return nil, err
			}
		}
		err = fn.PipeE(
			yaml.Lookup("starlark"),
			yaml.SetField("name", yaml.NewScalarRNode(r.StarName)))
		if err != nil {
			return nil, err
		}

	} else if r.EnableExec && r.ExecPath != "" {
		// create the function spec to set as an annotation
		fn, err = yaml.Parse(`exec: {}`)
		if err != nil {
			return nil, err
		}

		err = fn.PipeE(
			yaml.Lookup("exec"),
			yaml.SetField("path", yaml.NewScalarRNode(r.ExecPath)))
		if err != nil {
			return nil, err
		}
	}

	// create the function config
	rc, err := yaml.Parse(`
metadata:
  name: function-input
data: {}
`)
	if err != nil {
		return nil, err
	}

	// set the function annotation on the function config so it
	// is parsed by RunFns
	value, err := fn.String()
	if err != nil {
		return nil, err
	}
	err = rc.PipeE(
		yaml.LookupCreate(yaml.MappingNode, "metadata", "annotations"),
		yaml.SetField("config.kubernetes.io/function", yaml.NewScalarRNode(value)))
	if err != nil {
		return nil, err
	}

	// default the function config kind to ConfigMap, this may be overridden
	var kind = "ConfigMap"
	var version = "v1"

	// populate the function config with data.  this is a convention for functions
	// to be more commandline friendly
	if len(dataItems) > 0 {
		dataField, err := rc.Pipe(yaml.Lookup("data"))
		if err != nil {
			return nil, err
		}
		for i, s := range dataItems {
			kv := strings.SplitN(s, "=", 2)
			if i == 0 && len(kv) == 1 {
				// first argument may be the kind
				kind = s
				continue
			}
			if len(kv) != 2 {
				return nil, fmt.Errorf("args must have keys and values separated by =")
			}
			err := dataField.PipeE(yaml.SetField(kv[0], yaml.NewScalarRNode(kv[1])))
			if err != nil {
				return nil, err
			}
		}
	}
	err = rc.PipeE(yaml.SetField("kind", yaml.NewScalarRNode(kind)))
	if err != nil {
		return nil, err
	}
	err = rc.PipeE(yaml.SetField("apiVersion", yaml.NewScalarRNode(version)))
	if err != nil {
		return nil, err
	}
	return []*yaml.RNode{rc}, nil
}

func toStorageMounts(mounts []string) []runtimeutil.StorageMount {
	var sms []runtimeutil.StorageMount
	for _, mount := range mounts {
		sms = append(sms, runtimeutil.StringToStorageMount(mount))
	}
	return sms
}

func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
	if !r.EnableStar && (r.StarPath != "" || r.StarURL != "") {
		return errors.Errorf("must specify --enable-star with --star-path and --star-url")
	}

	if !r.EnableExec && r.ExecPath != "" {
		return errors.Errorf("must specify --enable-exec with --exec-path")
	}

	if c.ArgsLenAtDash() >= 0 && r.Image == "" &&
		!(r.EnableStar && (r.StarPath != "" || r.StarURL != "")) && !(r.EnableExec && r.ExecPath != "") {
		return errors.Errorf("must specify --image")
	}

	var dataItems []string
	if c.ArgsLenAtDash() >= 0 {
		dataItems = args[c.ArgsLenAtDash():]
		args = args[:c.ArgsLenAtDash()]
	}
	if len(args) > 1 {
		return errors.Errorf("0 or 1 arguments supported, function arguments go after '--'")
	}

	fns, err := r.getContainerFunctions(c, args, dataItems)
	if err != nil {
		return err
	}

	// set the output to stdout if in dry-run mode or no arguments are specified
	var output io.Writer
	var input io.Reader
	if len(args) == 0 {
		output = c.OutOrStdout()
		input = c.InOrStdin()
	} else if r.DryRun {
		output = c.OutOrStdout()
	}

	// set the path if specified as an argument
	var path string
	if len(args) == 1 {
		// argument is the directory
		path = args[0]
	}

	// parse mounts to set storageMounts
	storageMounts := toStorageMounts(r.Mounts)

	r.RunFns = runfn.RunFns{
		FunctionPaths:  r.FnPaths,
		GlobalScope:    r.GlobalScope,
		Functions:      fns,
		Output:         output,
		Input:          input,
		Path:           path,
		Network:        r.Network,
		NetworkName:    r.NetworkName,
		EnableStarlark: r.EnableStar,
		EnableExec:     r.EnableExec,
		StorageMounts:  storageMounts,
		ResultsDir:     r.ResultsDir,
		LogSteps:       r.LogSteps,
	}

	// don't consider args for the function
	return nil
}
<commit_msg>remove not used args<commit_after>// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package commands

import (
	"fmt"
	"io"
	"strings"

	"github.com/spf13/cobra"

	"sigs.k8s.io/kustomize/kyaml/errors"
	"sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil"
	"sigs.k8s.io/kustomize/kyaml/runfn"
	"sigs.k8s.io/kustomize/kyaml/yaml"

	"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
)

// GetCatRunner returns a RunFnRunner.
func GetRunFnRunner(name string) *RunFnRunner {
	r := &RunFnRunner{}
	c := &cobra.Command{
		Use:     "run [DIR]",
		Short:   commands.RunFnsShort,
		Long:    commands.RunFnsLong,
		Example: commands.RunFnsExamples,
		RunE:    r.runE,
		PreRunE: r.preRunE,
	}
	fixDocs(name, c)
	c.Flags().BoolVar(&r.IncludeSubpackages, "include-subpackages", true,
		"also print resources from subpackages.")
	r.Command = c
	r.Command.Flags().BoolVar(
		&r.DryRun, "dry-run", false, "print results to stdout")
	r.Command.Flags().BoolVar(
		&r.GlobalScope, "global-scope", false, "set global scope for functions.")
	r.Command.Flags().StringSliceVar(
		&r.FnPaths, "fn-path", []string{},
		"read functions from these directories instead of the configuration directory.")
	r.Command.Flags().StringVar(
		&r.Image, "image", "",
		"run this image as a function instead of discovering them.")
	// NOTE: exec plugins execute arbitrary code -- never change the default value of this flag!!!
	r.Command.Flags().BoolVar(
		&r.EnableExec, "enable-exec", false /*do not change!*/, "enable support for exec functions -- note: exec functions run arbitrary code -- do not use for untrusted configs!!! (Alpha)")
	r.Command.Flags().StringVar(
		&r.ExecPath, "exec-path", "", "run an executable as a function. (Alpha)")
	r.Command.Flags().BoolVar(
		&r.EnableStar, "enable-star", false, "enable support for starlark functions. (Alpha)")
	r.Command.Flags().StringVar(
		&r.StarPath, "star-path", "", "run a starlark script as a function. (Alpha)")
	r.Command.Flags().StringVar(
		&r.StarURL, "star-url", "", "run a starlark script as a function. (Alpha)")
	r.Command.Flags().StringVar(
		&r.StarName, "star-name", "", "name of starlark program. (Alpha)")

	r.Command.Flags().StringVar(
		&r.ResultsDir, "results-dir", "", "write function results to this dir")

	r.Command.Flags().BoolVar(
		&r.Network, "network", false, "enable network access for functions that declare it")
	r.Command.Flags().StringVar(
		&r.NetworkName, "network-name", "bridge", "the docker network to run the container in")
	r.Command.Flags().StringArrayVar(
		&r.Mounts, "mount", []string{},
		"a list of storage options read from the filesystem")
	r.Command.Flags().BoolVar(
		&r.LogSteps, "log-steps", false, "log steps to stderr")
	return r
}

func RunCommand(name string) *cobra.Command {
	return GetRunFnRunner(name).Command
}

// RunFnRunner contains the run function
type RunFnRunner struct {
	IncludeSubpackages bool
	Command            *cobra.Command
	DryRun             bool
	GlobalScope        bool
	FnPaths            []string
	Image              string
	EnableStar         bool
	StarPath           string
	StarURL            string
	StarName           string
	EnableExec         bool
	ExecPath           string
	RunFns             runfn.RunFns
	ResultsDir         string
	Network            bool
	NetworkName        string
	Mounts             []string
	LogSteps           bool
}

func (r *RunFnRunner) runE(c *cobra.Command, args []string) error {
	return handleError(c, r.RunFns.Execute())
}

// getContainerFunctions parses the commandline flags and arguments into explicit
// Functions to run.
func (r *RunFnRunner) getContainerFunctions(c *cobra.Command, dataItems []string) (
	[]*yaml.RNode, error) {

	if r.Image == "" && r.StarPath == "" && r.ExecPath == "" && r.StarURL == "" {
		return nil, nil
	}

	var fn *yaml.RNode
	var err error

	if r.Image != "" {
		// create the function spec to set as an annotation
		fn, err = yaml.Parse(`container: {}`)
		if err != nil {
			return nil, err
		}
		// TODO: add support network, volumes, etc based on flag values
		err = fn.PipeE(
			yaml.Lookup("container"),
			yaml.SetField("image", yaml.NewScalarRNode(r.Image)))
		if err != nil {
			return nil, err
		}
		if r.Network {
			err = fn.PipeE(
				yaml.LookupCreate(yaml.MappingNode, "container", "network"),
				yaml.SetField("required", yaml.NewScalarRNode("true")))
			if err != nil {
				return nil, err
			}
		}
	} else if r.EnableStar && (r.StarPath != "" || r.StarURL != "") {
		// create the function spec to set as an annotation
		fn, err = yaml.Parse(`starlark: {}`)
		if err != nil {
			return nil, err
		}

		if r.StarPath != "" {
			err = fn.PipeE(
				yaml.Lookup("starlark"),
				yaml.SetField("path", yaml.NewScalarRNode(r.StarPath)))
			if err != nil {
				return nil, err
			}
		}
		if r.StarURL != "" {
			err = fn.PipeE(
				yaml.Lookup("starlark"),
				yaml.SetField("url", yaml.NewScalarRNode(r.StarURL)))
			if err != nil {
				return nil, err
			}
		}
		err = fn.PipeE(
			yaml.Lookup("starlark"),
			yaml.SetField("name", yaml.NewScalarRNode(r.StarName)))
		if err != nil {
			return nil, err
		}

	} else if r.EnableExec && r.ExecPath != "" {
		// create the function spec to set as an annotation
		fn, err = yaml.Parse(`exec: {}`)
		if err != nil {
			return nil, err
		}

		err = fn.PipeE(
			yaml.Lookup("exec"),
			yaml.SetField("path", yaml.NewScalarRNode(r.ExecPath)))
		if err != nil {
			return nil, err
		}
	}

	// create the function config
	rc, err := yaml.Parse(`
metadata:
  name: function-input
data: {}
`)
	if err != nil {
		return nil, err
	}

	// set the function annotation on the function config so it
	// is parsed by RunFns
	value, err := fn.String()
	if err != nil {
		return nil, err
	}
	err = rc.PipeE(
		yaml.LookupCreate(yaml.MappingNode, "metadata", "annotations"),
		yaml.SetField(runtimeutil.FunctionAnnotationKey, yaml.NewScalarRNode(value)))
	if err != nil {
		return nil, err
	}

	// default the function config kind to ConfigMap, this may be overridden
	var kind = "ConfigMap"
	var version = "v1"

	// populate the function config with data.  this is a convention for functions
	// to be more commandline friendly
	if len(dataItems) > 0 {
		dataField, err := rc.Pipe(yaml.Lookup("data"))
		if err != nil {
			return nil, err
		}
		for i, s := range dataItems {
			kv := strings.SplitN(s, "=", 2)
			if i == 0 && len(kv) == 1 {
				// first argument may be the kind
				kind = s
				continue
			}
			if len(kv) != 2 {
				return nil, fmt.Errorf("args must have keys and values separated by =")
			}
			err := dataField.PipeE(yaml.SetField(kv[0], yaml.NewScalarRNode(kv[1])))
			if err != nil {
				return nil, err
			}
		}
	}
	err = rc.PipeE(yaml.SetField("kind", yaml.NewScalarRNode(kind)))
	if err != nil {
		return nil, err
	}
	err = rc.PipeE(yaml.SetField("apiVersion", yaml.NewScalarRNode(version)))
	if err != nil {
		return nil, err
	}
	return []*yaml.RNode{rc}, nil
}

func toStorageMounts(mounts []string) []runtimeutil.StorageMount {
	var sms []runtimeutil.StorageMount
	for _, mount := range mounts {
		sms = append(sms, runtimeutil.StringToStorageMount(mount))
	}
	return sms
}

func (r *RunFnRunner) preRunE(c *cobra.Command, args []string) error {
	if !r.EnableStar && (r.StarPath != "" || r.StarURL != "") {
		return errors.Errorf("must specify --enable-star with --star-path and --star-url")
	}

	if !r.EnableExec && r.ExecPath != "" {
		return errors.Errorf("must specify --enable-exec with --exec-path")
	}

	if c.ArgsLenAtDash() >= 0 && r.Image == "" &&
		!(r.EnableStar && (r.StarPath != "" || r.StarURL != "")) && !(r.EnableExec && r.ExecPath != "") {
		return errors.Errorf("must specify --image")
	}

	var dataItems []string
	if c.ArgsLenAtDash() >= 0 {
		dataItems = args[c.ArgsLenAtDash():]
		args = args[:c.ArgsLenAtDash()]
	}
	if len(args) > 1 {
		return errors.Errorf("0 or 1 arguments supported, function arguments go after '--'")
	}

	fns, err := r.getContainerFunctions(c, dataItems)
	if err != nil {
		return err
	}

	// set the output to stdout if in dry-run mode or no arguments are specified
	var output io.Writer
	var input io.Reader
	if len(args) == 0 {
		output = c.OutOrStdout()
		input = c.InOrStdin()
	} else if r.DryRun {
		output = c.OutOrStdout()
	}

	// set the path if specified as an argument
	var path string
	if len(args) == 1 {
		// argument is the directory
		path = args[0]
	}

	// parse mounts to set storageMounts
	storageMounts := toStorageMounts(r.Mounts)

	r.RunFns = runfn.RunFns{
		FunctionPaths:  r.FnPaths,
		GlobalScope:    r.GlobalScope,
		Functions:      fns,
		Output:         output,
		Input:          input,
		Path:           path,
		Network:        r.Network,
		NetworkName:    r.NetworkName,
		EnableStarlark: r.EnableStar,
		EnableExec:     r.EnableExec,
		StorageMounts:  storageMounts,
		ResultsDir:     r.ResultsDir,
		LogSteps:       r.LogSteps,
	}

	// don't consider args for the function
	return nil
}
<|endoftext|>


<commit_before>// +build darwin linux
// note: this collector only works on hbase 1.0+

package collectors

import (
	"encoding/json"
	"math"
	"net/http"
	"regexp"
	"strings"

	"bosun.org/cmd/scollector/conf"
	"bosun.org/metadata"
	"bosun.org/opentsdb"
)

var (
	hbURL    = "/jmx?qry=Hadoop:service=HBase,name=RegionServer,sub=Server"
	hbRegURL = "/jmx?qry=Hadoop:service=HBase,name=RegionServer,sub=Regions"
	hbRepURL = "/jmx?qry=Hadoop:service=HBase,name=RegionServer,sub=Replication"
	hbGCURL  = "/jmx?qry=java.lang:type=GarbageCollector,name=*"
)

func init() {
	registerInit(func(c *conf.Conf) {
		host := ""
		if c.HadoopHost != "" {
			host = "http://" + c.HadoopHost
		} else {
			host = "http://localhost:60030"
		}
		hbURL = host + hbURL
		hbRegURL = host + hbRegURL
		hbRepURL = host + hbRepURL
		hbGCURL = host + hbGCURL
		collectors = append(collectors, &IntervalCollector{F: c_hbase_region, Enable: enableURL(hbURL)})
		if c.HbaseRegions {
			collectors = append(collectors, &IntervalCollector{F: c_hbase_regions, Enable: enableURL(hbRegURL)})
		}
		collectors = append(collectors, &IntervalCollector{F: c_hbase_replication, Enable: enableURL(hbRepURL)})
		collectors = append(collectors, &IntervalCollector{F: c_hbase_gc, Enable: enableURL(hbGCURL)})
	})
}

type jmx struct {
	Beans []map[string]interface{} `json:"beans"`
}

func getBeans(url string, jmx *jmx) error {
	res, err := http.Get(url)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if err := json.NewDecoder(res.Body).Decode(&jmx); err != nil {
		return err
	}
	return nil
}

func c_hbase_region() (opentsdb.MultiDataPoint, error) {
	var j jmx
	if err := getBeans(hbURL, &j); err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	if len(j.Beans) > 0 && len(j.Beans[0]) > 0 {
		for k, v := range j.Beans[0] {
			if vv, ok := v.(float64); ok {
				if vv < math.MaxInt64 {
					Add(&md, "hbase.region."+k, v, nil, metadata.Unknown, metadata.None, "")
				}
			}
		}
	}
	return md, nil
}

func c_hbase_regions() (opentsdb.MultiDataPoint, error) {
	var j jmx
	if err := getBeans(hbRegURL, &j); err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	if len(j.Beans) > 0 && len(j.Beans[0]) > 0 {
		for k, v := range j.Beans[0] {
			if vv, ok := v.(float64); ok {
				if vv > math.MaxInt64 {
					continue
				}
				kParts := strings.Split(k, "_")
				t := make(opentsdb.TagSet)
				var m string
				for i := 0; i+1 < len(kParts); i += 2 {
					if kParts[i] == "metric" {
						m = strings.Join(kParts[i+1:], "_")
						break
					}
					t[kParts[i]] = kParts[i+1]
				}
				if m == "" {
					continue
				}
				Add(&md, "hbase.regions."+m, v, t, metadata.Unknown, metadata.None, "")
			}
		}
	}
	return md, nil
}

func c_hbase_gc() (opentsdb.MultiDataPoint, error) {
	var j jmx
	if err := getBeans(hbGCURL, &j); err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	const metric = "hbase.region.gc."
	for _, bean := range j.Beans {
		if name, ok := bean["Name"].(string); ok && name != "" {
			ts := opentsdb.TagSet{"name": name}
			for k, v := range bean {
				if vv, ok := v.(float64); ok {
					if vv < math.MaxInt64 {
						switch k {
						case "CollectionCount":
							Add(&md, metric+k, v, ts, metadata.Counter, metadata.Count, "A counter for the number of times that garbage collection has been called.")
						case "CollectionTime":
							Add(&md, metric+k, v, ts, metadata.Counter, metadata.None, "The total amount of time spent in garbage collection.")
						}
					}
				}
			}
		}
	}
	return md, nil
}

func c_hbase_replication() (opentsdb.MultiDataPoint, error) {
	var j jmx
	if err := getBeans(hbRepURL, &j); err != nil {
		return nil, err
	}
	excludeReg, err := regexp.Compile("source.\\d")
	if err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	for _, section := range j.Beans {
		for k, v := range section {
			// source.[0-9] entries are for other hosts in the cluster
			if excludeReg.MatchString(k) {
				continue
			}
			// Strip "source." and "sink." from the metric names.
			shortName := strings.TrimPrefix(k, "source.")
			shortName = strings.TrimPrefix(shortName, "sink.")
			metric := "hbase.region." + shortName
			if vv, ok := v.(float64); ok {
				if vv < math.MaxInt64 {
					Add(&md, metric, v, nil, metadata.Unknown, metadata.None, "")
				}
			}
		}
	}
	return md, nil
}
<commit_msg>cmd/scollector: hbase - collect IPC stats (#2405)<commit_after>// +build darwin linux
// note: this collector only works on hbase 1.0+

package collectors

import (
	"encoding/json"
	"math"
	"net/http"
	"regexp"
	"strings"

	"bosun.org/cmd/scollector/conf"
	"bosun.org/metadata"
	"bosun.org/opentsdb"
)

var (
	hbURL    = "/jmx?qry=Hadoop:service=HBase,name=RegionServer,sub=Server"
	hbRegURL = "/jmx?qry=Hadoop:service=HBase,name=RegionServer,sub=Regions"
	hbRepURL = "/jmx?qry=Hadoop:service=HBase,name=RegionServer,sub=Replication"
	hbICPURL = "/jmx?qry=Hadoop:service=HBase,name=RegionServer,sub=IPC"
	hbGCURL  = "/jmx?qry=java.lang:type=GarbageCollector,name=*"
)

func init() {
	registerInit(func(c *conf.Conf) {
		host := ""
		if c.HadoopHost != "" {
			host = "http://" + c.HadoopHost
		} else {
			host = "http://localhost:60030"
		}
		hbURL = host + hbURL
		hbRegURL = host + hbRegURL
		hbRepURL = host + hbRepURL
		hbGCURL = host + hbGCURL
		hbICPURL = host + hbICPURL
		collectors = append(collectors, &IntervalCollector{F: c_hbase_region, Enable: enableURL(hbURL)})
		if c.HbaseRegions {
			collectors = append(collectors, &IntervalCollector{F: c_hbase_regions, Enable: enableURL(hbRegURL)})
		}
		collectors = append(collectors, &IntervalCollector{F: c_hbase_replication, Enable: enableURL(hbRepURL)})
		collectors = append(collectors, &IntervalCollector{F: c_hbase_gc, Enable: enableURL(hbGCURL)})
		collectors = append(collectors, &IntervalCollector{F: c_hbase_ipc, Enable: enableURL(hbICPURL)})
	})
}

type jmx struct {
	Beans []map[string]interface{} `json:"beans"`
}

func getBeans(url string, jmx *jmx) error {
	res, err := http.Get(url)
	if err != nil {
		return err
	}
	defer res.Body.Close()
	if err := json.NewDecoder(res.Body).Decode(&jmx); err != nil {
		return err
	}
	return nil
}

func c_hbase_region() (opentsdb.MultiDataPoint, error) {
	var j jmx
	if err := getBeans(hbURL, &j); err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	if len(j.Beans) > 0 && len(j.Beans[0]) > 0 {
		for k, v := range j.Beans[0] {
			if vv, ok := v.(float64); ok {
				if vv < math.MaxInt64 {
					Add(&md, "hbase.region."+k, v, nil, metadata.Unknown, metadata.None, "")
				}
			}
		}
	}
	return md, nil
}

func c_hbase_ipc() (opentsdb.MultiDataPoint, error) {
	var j jmx
	if err := getBeans(hbICPURL, &j); err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	if len(j.Beans) > 0 {
		for k, v := range j.Beans[0] {
			if vv, ok := v.(float64); ok {
				if vv < math.MaxInt64 {
					Add(&md, "hbase.ipc."+k, v, nil, metadata.Unknown, metadata.None, "")
				}
			}
		}
	}
	return md, nil
}

func c_hbase_regions() (opentsdb.MultiDataPoint, error) {
	var j jmx
	if err := getBeans(hbRegURL, &j); err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	if len(j.Beans) > 0 && len(j.Beans[0]) > 0 {
		for k, v := range j.Beans[0] {
			if vv, ok := v.(float64); ok {
				if vv > math.MaxInt64 {
					continue
				}
				kParts := strings.Split(k, "_")
				t := make(opentsdb.TagSet)
				var m string
				for i := 0; i+1 < len(kParts); i += 2 {
					if kParts[i] == "metric" {
						m = strings.Join(kParts[i+1:], "_")
						break
					}
					t[kParts[i]] = kParts[i+1]
				}
				if m == "" {
					continue
				}
				Add(&md, "hbase.regions."+m, v, t, metadata.Unknown, metadata.None, "")
			}
		}
	}
	return md, nil
}

func c_hbase_gc() (opentsdb.MultiDataPoint, error) {
	var j jmx
	if err := getBeans(hbGCURL, &j); err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	const metric = "hbase.region.gc."
	for _, bean := range j.Beans {
		if name, ok := bean["Name"].(string); ok && name != "" {
			ts := opentsdb.TagSet{"name": name}
			for k, v := range bean {
				if vv, ok := v.(float64); ok {
					if vv < math.MaxInt64 {
						switch k {
						case "CollectionCount":
							Add(&md, metric+k, v, ts, metadata.Counter, metadata.Count, "A counter for the number of times that garbage collection has been called.")
						case "CollectionTime":
							Add(&md, metric+k, v, ts, metadata.Counter, metadata.None, "The total amount of time spent in garbage collection.")
						}
					}
				}
			}
		}
	}
	return md, nil
}

func c_hbase_replication() (opentsdb.MultiDataPoint, error) {
	var j jmx
	if err := getBeans(hbRepURL, &j); err != nil {
		return nil, err
	}
	excludeReg, err := regexp.Compile("source.\\d")
	if err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	for _, section := range j.Beans {
		for k, v := range section {
			// source.[0-9] entries are for other hosts in the cluster
			if excludeReg.MatchString(k) {
				continue
			}
			// Strip "source." and "sink." from the metric names.
			shortName := strings.TrimPrefix(k, "source.")
			shortName = strings.TrimPrefix(shortName, "sink.")
			metric := "hbase.region." + shortName
			if vv, ok := v.(float64); ok {
				if vv < math.MaxInt64 {
					Add(&md, metric, v, nil, metadata.Unknown, metadata.None, "")
				}
			}
		}
	}
	return md, nil
}
<|endoftext|>


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

// The Upspin-setupstorage comamnd is an external upspin subcommand that
// executes the second step in establishing an upspinserver.
// Run upspin setupstorage -help for more information.
package main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"

	"golang.org/x/oauth2/google"
	"google.golang.org/api/googleapi"
	iam "google.golang.org/api/iam/v1"
	storage "google.golang.org/api/storage/v1"

	"upspin.io/flags"
	"upspin.io/subcmd"
)

type state struct {
	*subcmd.State
}

const help = `
Setupstorage is the second step in establishing an upspinserver,
It sets up cloud storage for your Upspin installation. You may skip this step
if you wish to store Upspin data on your server's local disk.
The first step is 'setupdomain' and the final step is 'setupserver'.

Setupstorage creates a Google Cloud Storage bucket and a service account for
accessing that bucket. It then writes the service account private key to
$where/$domain/serviceaccount.json and updates the server configuration files
in that directory to use the specified bucket.

Before running this command, you must create a Google Cloud Project and
associated Billing Account using the Cloud Console:
	https://cloud.google.com/console
The project ID can be any available string, but for clarity it's helpful to
pick something that resembles your domain name.

You must also install the Google Cloud SDK:
	https://cloud.google.com/sdk/downloads
Authenticate and enable the necessary APIs:
	$ gcloud auth login
	$ gcloud --project <project> beta service-management enable iam.googleapis.com storage_api
And, finally, authenticate again in a different way:
	$ gcloud auth application-default login

Running this command when the service account or bucket exists is a no-op.
`

func main() {
	const name = "setupstorage"

	log.SetFlags(0)
	log.SetPrefix("upspin setupstorage: ")

	s := &state{
		State: subcmd.NewState(name),
	}

	where := flag.String("where", filepath.Join(os.Getenv("HOME"), "upspin", "deploy"), "`directory` to store private configuration files")
	domain := flag.String("domain", "", "domain `name` for this Upspin installation")

	flags.Register("project")

	s.ParseFlags(flag.CommandLine, os.Args[1:], help,
		"-project=<gcp_project_name> setupstorage -domain=<name> <bucket_name>")
	if flag.NArg() != 1 {
		s.Exitf("a single bucket name must be provided")
	}
	if *domain == "" || flags.Project == "" {
		s.Exitf("the -domain and -project flags must be provided")
	}

	bucket := flag.Arg(0)

	cfgPath := filepath.Join(*where, *domain)
	cfg := s.ReadServerConfig(cfgPath)

	email, privateKeyData := s.createServiceAccount(cfgPath)

	s.createBucket(email, bucket)

	cfg.StoreConfig = []string{
		"backend=GCS",
		"defaultACL=publicRead",
		"gcpBucketName=" + bucket,
		"privateKeyData=" + privateKeyData,
	}
	s.WriteServerConfig(cfgPath, cfg)

	fmt.Fprintf(os.Stderr, "You should now deploy the upspinserver binary and run 'upspin setupserver'.\n")

	s.ExitNow()
}

func (s *state) createServiceAccount(cfgPath string) (email, privateKeyData string) {
	client, err := google.DefaultClient(context.Background(), iam.CloudPlatformScope)
	if err != nil {
		// TODO: ask the user to run 'gcloud auth application-default login'
		s.Exit(err)
	}
	svc, err := iam.New(client)
	if err != nil {
		s.Exit(err)
	}

	name := "projects/" + flags.Project
	req := &iam.CreateServiceAccountRequest{
		AccountId: "upspinstorage", // TODO(adg): flag?
		ServiceAccount: &iam.ServiceAccount{
			DisplayName: "Upspin Storage",
		},
	}
	created := true
	acct, err := svc.Projects.ServiceAccounts.Create(name, req).Do()
	if isExists(err) {
		// This should be the name we need to get.
		// TODO(adg): make this more robust by listing instead.
		guess := name + "/serviceAccounts/upspinstorage@" + flags.Project + ".iam.gserviceaccount.com"
		acct, err = svc.Projects.ServiceAccounts.Get(guess).Do()
		if err != nil {
			s.Exit(err)
		}
		created = false
	} else if err != nil {
		s.Exit(err)
	}

	name += "/serviceAccounts/" + acct.Email
	req2 := &iam.CreateServiceAccountKeyRequest{}
	key, err := svc.Projects.ServiceAccounts.Keys.Create(name, req2).Do()
	if err != nil {
		s.Exit(err)
	}
	if created {
		fmt.Fprintf(os.Stderr, "Service account %q created.\n", acct.Email)
	} else {
		fmt.Fprintf(os.Stderr, "A new key for the service account %q was created.\n", acct.Email)
	}

	return acct.Email, key.PrivateKeyData
}

func (s *state) createBucket(email, bucket string) {
	client, err := google.DefaultClient(context.Background(), storage.DevstorageFullControlScope)
	if err != nil {
		// TODO: ask the user to run 'gcloud auth application-default login'
		s.Exit(err)
	}
	svc, err := storage.New(client)
	if err != nil {
		s.Exit(err)
	}

	_, err = svc.Buckets.Insert(flags.Project, &storage.Bucket{
		Acl: []*storage.BucketAccessControl{{
			Bucket: bucket,
			Entity: "user-" + email,
			Email:  email,
			Role:   "OWNER",
		}},
		Name: bucket,
		// TODO(adg): flag for location
	}).Do()
	if isExists(err) {
		// TODO(adg): update bucket ACL to make sure the service
		// account has access. (For now, we assume that the user
		// created the bucket using this command and that the bucket
		// has the correct permissions.)
		fmt.Fprintf(os.Stderr, "Bucket %q already exists; re-using it.\n", bucket)
	} else if err != nil {
		s.Exit(err)
	} else {
		fmt.Fprintf(os.Stderr, "Bucket %q created.\n", bucket)
	}
}

func isExists(err error) bool {
	if e, ok := err.(*googleapi.Error); ok && len(e.Errors) > 0 {
		for _, e := range e.Errors {
			if e.Reason != "alreadyExists" && e.Reason != "conflict" {
				return false
			}
		}
		return true
	}
	return false
}
<commit_msg>cmd/upspin-setupstorage: replace GCP bucket setup with local disk setup<commit_after>// Copyright 2017 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The Upspin-setupstorage comamnd is an external upspin subcommand that
// executes the second step in establishing an upspinserver.
// Run upspin setupstorage -help for more information.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"

	"upspin.io/subcmd"
)

type state struct {
	*subcmd.State
}

const help = `
Setupstorage is the second step in establishing an upspinserver,
It sets up storage for your Upspin installation.
The first step is 'setupdomain' and the final step is 'setupserver'.

This version of setupstorage configures local disk storage.
Read the documentation at
	https://upspin.io/doc/server_setup.md
for information on configuring upspinserver to use cloud storage services.
`

func main() {
	const name = "setupstorage"

	log.SetFlags(0)
	log.SetPrefix("upspin setupstorage: ")

	s := &state{
		State: subcmd.NewState(name),
	}

	where := flag.String("where", filepath.Join(os.Getenv("HOME"), "upspin", "deploy"), "`directory` to store private configuration files")
	domain := flag.String("domain", "", "domain `name` for this Upspin installation")
	storagePath := flag.String("path", "", "`directory` on the server in which to keep Upspin storage (default is $HOME/upspin/server/storage)")

	s.ParseFlags(flag.CommandLine, os.Args[1:], help,
		"setupstorage -domain=<name> -path=<storage_dir>")
	if flag.NArg() != 1 {
		s.Exitf("a single bucket name must be provided")
	}
	if *domain == "" {
		s.Exitf("the -domain flag must be provided")
	}

	cfgPath := filepath.Join(*where, *domain)
	cfg := s.ReadServerConfig(cfgPath)

	if *storagePath != "" {
		cfg.StoreConfig = []string{
			"backend=Disk",
			"basePath=" + *storagePath,
		}
	}
	s.WriteServerConfig(cfgPath, cfg)

	fmt.Fprintf(os.Stderr, "You should now deploy the upspinserver binary and run 'upspin setupserver'.\n")

	s.ExitNow()
}
<|endoftext|>


<commit_before>// Obdi - a REST interface and GUI for deploying software
// Copyright (C) 2014  Mark Clarkson
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"syscall"
	"time"
	//"encoding/json"
	//"strings"
)

func (api *Api) execCmd(job JobIn) {

	// TODO :: Put this logic in login/logout and reference count
	//defer api.Logout( )

	// Need to set the PATH to run the script from the script dir
	os.Setenv("PATH", config.ScriptDir)

	scriptfile := ""

	// Write ScriptSource to disk
	if file, err := ioutil.TempFile(os.TempDir(), "smworker_"); err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("TempFile error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	} else {
		if _, err := file.Write(job.ScriptSource); err != nil {
			if err := api.sendStatus(job, JobOut{
				Status:        STATUS_SYSCANCELLED,
				StatusReason:  fmt.Sprintf("Write error ('%s')", err.Error()),
				StatusPercent: 0,
				Errors:        0,
			}); err != nil {
				logit(fmt.Sprintf("Error: %s", err.Error()))
			}
			return
		}
		file.Close()
		os.Chmod(file.Name(), 0755)
		scriptfile = file.Name()
	}
	defer os.Remove(scriptfile)

	// Set up command, split on spaces but preserve quoted strings
	head := scriptfile
	r := regexp.MustCompile("'.+'|\".+\"|\\S+")
	parts := r.FindAllString(job.Args, -1)
	cmd := &exec.Cmd{}
	cmd = exec.Command(head, parts...)

	// Apply the sent environment variables, split on spaces
	// but preserve quoted strings
	if len(job.EnvVars) > 0 {
		r = regexp.MustCompile("[^ ]*='[^']+'|[^ ]*=\"[^']+\"|\\S+")
		cmd.Env = r.FindAllString(job.EnvVars, -1)
		// Remove speech marks around the value of quoted strings. Matches, for
		// example, `var="val val"`, and changes to `var=val val`
		for i, j := range Env {
			r := regexp.MustCompile(`([^ ]+=)"(.*)"`)
			if r.Match([]byte(j)) {
				k := r.ReplaceAll([]byte(j), []byte(`$1$2`))
				Env[i] = string(k)
			}
		}
	} else {
		cmd.Env = []string{}
	}

	// Add the system scripts directory to Env.SYSSCRIPTDIR
	cmd.Env = append(cmd.Env, "SYSSCRIPTDIR="+config.SysScriptDir)

	cmd.Dir = os.TempDir()

	// Set up buffer for stdout
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Pipe error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}
	rdr := bufio.NewReader(stdout)
	stderr, err := cmd.StderrPipe()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Pipe error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}
	rdr_stderr := bufio.NewReader(stderr)

	/*
	   data := JobOut{}
	   jsondata, err := json.Marshal(data)
	*/

	// Get child processes to run in a process group so they
	// can all be killed as a group.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}

	// Run command in the background (fork)
	err = cmd.Start()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Fork error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}

	if err := api.sendStatus(job, JobOut{
		Status:        STATUS_INPROGRESS,
		StatusReason:  "Script started",
		StatusPercent: 0,
		Errors:        0,
	}); err != nil {
		logit(fmt.Sprintf("Error: %s", err.Error()))
	}

	// Save the pid so it can be killed
	api.SetPid(job.JobID, int64(cmd.Process.Pid))

	// Process the output
	serial := int64(1)
	line := ""
	if job.Type != 2 {
		// A user job (the default, should be type=1)
		line, err = rdr.ReadString('\n')
		api.sendOutputLine(job, line, serial)
		for err == nil {
			serial++
			a := ""
			starttime := time.Now()
			// Up to 50 lines can be read in one hit
			for i := 0; i < 50; i++ {
				if time.Duration(time.Since(starttime)) > time.Second {
					break
				}
				line, err = rdr.ReadString('\n')
				a = a + line
			}
			api.sendOutputLine(job, a, serial)
		}
	} else {
		// A system job. Send all output in a single output line
		a := ""
		for err == nil {
			line, err = rdr.ReadString('\n')
			a = a + line
		}
		api.sendOutputLine(job, a, 1)
	}

	serial++

	// Read anything in stderr, but don't send it.
	// It will be sent later if the script has non-zero exit status
	error_output := ""
	err = nil
	for err == nil {
		line, err = rdr_stderr.ReadString('\n')
		error_output = error_output + line
	}

	// Process exit status
	err = cmd.Wait()
	if err != nil {
		api.sendOutputLine(job, error_output, serial)
		status := int64(0)
		if api.UserCancel(job.JobID) == true {
			status = STATUS_USERCANCELLED
		} else {
			status = STATUS_ERROR
		}
		if err := api.sendStatus(job, JobOut{
			Status: status,
			StatusReason: fmt.Sprintf("Script, '%s', exited with error status ('%s')",
				job.ScriptName, err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: (Script: '%s') %s", job.ScriptName,
				err.Error()))
		}
		api.RemoveJob(job.JobID)
		return
	}

	status := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
	if status == 0 {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_OK,
			StatusReason:  "Script finished successfully",
			StatusPercent: 100,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
	} else {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_ERROR,
			StatusReason:  "Non-zero exit status. Check the log.",
			StatusPercent: 100,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
	}

	api.RemoveJob(int64(job.JobID))

	// logout
}

/*
func main() {
    exec_cmd ( os.Args[1:]... )
}
*/
<commit_msg>Remove outer quotes from env vars<commit_after>// Obdi - a REST interface and GUI for deploying software
// Copyright (C) 2014  Mark Clarkson
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"syscall"
	"time"
	//"encoding/json"
	//"strings"
)

func (api *Api) execCmd(job JobIn) {

	// TODO :: Put this logic in login/logout and reference count
	//defer api.Logout( )

	// Need to set the PATH to run the script from the script dir
	os.Setenv("PATH", config.ScriptDir)

	scriptfile := ""

	// Write ScriptSource to disk
	if file, err := ioutil.TempFile(os.TempDir(), "smworker_"); err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("TempFile error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	} else {
		if _, err := file.Write(job.ScriptSource); err != nil {
			if err := api.sendStatus(job, JobOut{
				Status:        STATUS_SYSCANCELLED,
				StatusReason:  fmt.Sprintf("Write error ('%s')", err.Error()),
				StatusPercent: 0,
				Errors:        0,
			}); err != nil {
				logit(fmt.Sprintf("Error: %s", err.Error()))
			}
			return
		}
		file.Close()
		os.Chmod(file.Name(), 0755)
		scriptfile = file.Name()
	}
	defer os.Remove(scriptfile)

	// Set up command, split on spaces but preserve quoted strings
	head := scriptfile
	r := regexp.MustCompile("'.+'|\".+\"|\\S+")
	parts := r.FindAllString(job.Args, -1)
	cmd := &exec.Cmd{}
	cmd = exec.Command(head, parts...)

	// Apply the sent environment variables, split on spaces
	// but preserve quoted strings
	if len(job.EnvVars) > 0 {
		r = regexp.MustCompile("[^ ]*='[^']+'|[^ ]*=\"[^']+\"|\\S+")
		cmd.Env = r.FindAllString(job.EnvVars, -1)
		// Remove speech marks around the value of quoted strings. Matches, for
		// example, `var="val val"`, and changes to `var=val val`
		for i, j := range cmd.Env {
			r := regexp.MustCompile(`([^ ]+=)"(.*)"`)
			if r.Match([]byte(j)) {
				k := r.ReplaceAll([]byte(j), []byte(`$1$2`))
				cmd.Env[i] = string(k)
			}
		}
	} else {
		cmd.Env = []string{}
	}

	// Add the system scripts directory to Env.SYSSCRIPTDIR
	cmd.Env = append(cmd.Env, "SYSSCRIPTDIR="+config.SysScriptDir)

	cmd.Dir = os.TempDir()

	// Set up buffer for stdout
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Pipe error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}
	rdr := bufio.NewReader(stdout)
	stderr, err := cmd.StderrPipe()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Pipe error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}
	rdr_stderr := bufio.NewReader(stderr)

	/*
	   data := JobOut{}
	   jsondata, err := json.Marshal(data)
	*/

	// Get child processes to run in a process group so they
	// can all be killed as a group.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}

	// Run command in the background (fork)
	err = cmd.Start()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Fork error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}

	if err := api.sendStatus(job, JobOut{
		Status:        STATUS_INPROGRESS,
		StatusReason:  "Script started",
		StatusPercent: 0,
		Errors:        0,
	}); err != nil {
		logit(fmt.Sprintf("Error: %s", err.Error()))
	}

	// Save the pid so it can be killed
	api.SetPid(job.JobID, int64(cmd.Process.Pid))

	// Process the output
	serial := int64(1)
	line := ""
	if job.Type != 2 {
		// A user job (the default, should be type=1)
		line, err = rdr.ReadString('\n')
		api.sendOutputLine(job, line, serial)
		for err == nil {
			serial++
			a := ""
			starttime := time.Now()
			// Up to 50 lines can be read in one hit
			for i := 0; i < 50; i++ {
				if time.Duration(time.Since(starttime)) > time.Second {
					break
				}
				line, err = rdr.ReadString('\n')
				a = a + line
			}
			api.sendOutputLine(job, a, serial)
		}
	} else {
		// A system job. Send all output in a single output line
		a := ""
		for err == nil {
			line, err = rdr.ReadString('\n')
			a = a + line
		}
		api.sendOutputLine(job, a, 1)
	}

	serial++

	// Read anything in stderr, but don't send it.
	// It will be sent later if the script has non-zero exit status
	error_output := ""
	err = nil
	for err == nil {
		line, err = rdr_stderr.ReadString('\n')
		error_output = error_output + line
	}

	// Process exit status
	err = cmd.Wait()
	if err != nil {
		api.sendOutputLine(job, error_output, serial)
		status := int64(0)
		if api.UserCancel(job.JobID) == true {
			status = STATUS_USERCANCELLED
		} else {
			status = STATUS_ERROR
		}
		if err := api.sendStatus(job, JobOut{
			Status: status,
			StatusReason: fmt.Sprintf("Script, '%s', exited with error status ('%s')",
				job.ScriptName, err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: (Script: '%s') %s", job.ScriptName,
				err.Error()))
		}
		api.RemoveJob(job.JobID)
		return
	}

	status := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
	if status == 0 {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_OK,
			StatusReason:  "Script finished successfully",
			StatusPercent: 100,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
	} else {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_ERROR,
			StatusReason:  "Non-zero exit status. Check the log.",
			StatusPercent: 100,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
	}

	api.RemoveJob(int64(job.JobID))

	// logout
}

/*
func main() {
    exec_cmd ( os.Args[1:]... )
}
*/
<|endoftext|>


<commit_before>// Obdi - a REST interface and GUI for deploying software
// Copyright (C) 2014  Mark Clarkson
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"syscall"
	"time"
	//"encoding/json"
	//"strings"
)

func (api *Api) execCmd(job JobIn) {

	// TODO :: Put this logic in login/logout and reference count
	//defer api.Logout( )

	// Need to set the PATH to run the script from the script dir
	os.Setenv("PATH", config.ScriptDir)

	scriptfile := ""

	// Write ScriptSource to disk
	if file, err := ioutil.TempFile(os.TempDir(), "smworker_"); err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("TempFile error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	} else {
		if _, err := file.Write(job.ScriptSource); err != nil {
			if err := api.sendStatus(job, JobOut{
				Status:        STATUS_SYSCANCELLED,
				StatusReason:  fmt.Sprintf("Write error ('%s')", err.Error()),
				StatusPercent: 0,
				Errors:        0,
			}); err != nil {
				logit(fmt.Sprintf("Error: %s", err.Error()))
			}
			return
		}
		file.Close()
		os.Chmod(file.Name(), 0755)
		scriptfile = file.Name()
	}
	defer os.Remove(scriptfile)

	// Set up command, split on spaces but preserve quoted strings
	head := scriptfile
	r := regexp.MustCompile("'.+'|\".+\"|\\S+")
	parts := r.FindAllString(job.Args, -1)
	cmd := &exec.Cmd{}
	cmd = exec.Command(head, parts...)

	// Apply the sent environment variables, split on spaces
	// but preserve quoted strings
	if len(job.EnvVars) > 0 {
		r = regexp.MustCompile("[^ ]*='[^']+'|[^ ]*=\"[^']+\"|\\S+")
		cmd.Env = r.FindAllString(job.EnvVars, -1)
		// Remove speech marks around the value of quoted strings. Matches, for
		// example, `var="val val"`, and changes to `var=val val`
		for i, j := range cmd.Env {
			r := regexp.MustCompile(`([^ ]+=)["'](.*)["']`)
			if r.Match([]byte(j)) {
				k := r.ReplaceAll([]byte(j), []byte(`$1$2`))
				cmd.Env[i] = string(k)
			}
		}
	} else {
		cmd.Env = []string{}
	}

	// Add the system scripts directory to Env.SYSSCRIPTDIR
	cmd.Env = append(cmd.Env, "SYSSCRIPTDIR="+config.SysScriptDir)

	cmd.Dir = os.TempDir()

	// Set up buffer for stdout
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Pipe error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}
	rdr := bufio.NewReader(stdout)
	stderr, err := cmd.StderrPipe()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Pipe error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}
	rdr_stderr := bufio.NewReader(stderr)

	/*
	   data := JobOut{}
	   jsondata, err := json.Marshal(data)
	*/

	// Get child processes to run in a process group so they
	// can all be killed as a group.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}

	// Run command in the background (fork)
	err = cmd.Start()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Fork error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}

	if err := api.sendStatus(job, JobOut{
		Status:        STATUS_INPROGRESS,
		StatusReason:  "Script started",
		StatusPercent: 0,
		Errors:        0,
	}); err != nil {
		logit(fmt.Sprintf("Error: %s", err.Error()))
	}

	// Save the pid so it can be killed
	api.SetPid(job.JobID, int64(cmd.Process.Pid))

	// Process the output
	serial := int64(1)
	line := ""
	if job.Type != 2 {
		// A user job (the default, should be type=1)
		line, err = rdr.ReadString('\n')
		api.sendOutputLine(job, line, serial)
		for err == nil {
			serial++
			a := ""
			starttime := time.Now()
			// Up to 50 lines can be read in one hit
			for i := 0; i < 50; i++ {
				if time.Duration(time.Since(starttime)) > time.Second {
					break
				}
				line, err = rdr.ReadString('\n')
				a = a + line
			}
			api.sendOutputLine(job, a, serial)
		}
	} else {
		// A system job. Send all output in a single output line
		a := ""
		for err == nil {
			line, err = rdr.ReadString('\n')
			a = a + line
		}
		api.sendOutputLine(job, a, 1)
	}

	serial++

	// Read anything in stderr, but don't send it.
	// It will be sent later if the script has non-zero exit status
	error_output := ""
	err = nil
	for err == nil {
		line, err = rdr_stderr.ReadString('\n')
		error_output = error_output + line
	}

	// Process exit status
	err = cmd.Wait()
	if err != nil {
		api.sendOutputLine(job, error_output, serial)
		status := int64(0)
		if api.UserCancel(job.JobID) == true {
			status = STATUS_USERCANCELLED
		} else {
			status = STATUS_ERROR
		}
		if err := api.sendStatus(job, JobOut{
			Status: status,
			StatusReason: fmt.Sprintf("Script, '%s', exited with error status ('%s')",
				job.ScriptName, err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: (Script: '%s') %s", job.ScriptName,
				err.Error()))
		}
		api.RemoveJob(job.JobID)
		return
	}

	status := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
	if status == 0 {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_OK,
			StatusReason:  "Script finished successfully",
			StatusPercent: 100,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
	} else {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_ERROR,
			StatusReason:  "Non-zero exit status. Check the log.",
			StatusPercent: 100,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
	}

	api.RemoveJob(int64(job.JobID))

	// logout
}

/*
func main() {
    exec_cmd ( os.Args[1:]... )
}
*/
<commit_msg>in progress<commit_after>// Obdi - a REST interface and GUI for deploying software
// Copyright (C) 2014  Mark Clarkson
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"syscall"
	"time"
	//"encoding/json"
	//"strings"
)

func (api *Api) execCmd(job JobIn) {

	// TODO :: Put this logic in login/logout and reference count
	//defer api.Logout( )

	// Need to set the PATH to run the script from the script dir
	os.Setenv("PATH", config.ScriptDir)

	scriptfile := ""

	// Write ScriptSource to disk
	if file, err := ioutil.TempFile(os.TempDir(), "smworker_"); err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("TempFile error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	} else {
		if _, err := file.Write(job.ScriptSource); err != nil {
			if err := api.sendStatus(job, JobOut{
				Status:        STATUS_SYSCANCELLED,
				StatusReason:  fmt.Sprintf("Write error ('%s')", err.Error()),
				StatusPercent: 0,
				Errors:        0,
			}); err != nil {
				logit(fmt.Sprintf("Error: %s", err.Error()))
			}
			return
		}
		file.Close()
		os.Chmod(file.Name(), 0755)
		scriptfile = file.Name()
	}
	defer os.Remove(scriptfile)

	// Set up command, split on spaces but preserve quoted strings
	head := scriptfile
	r := regexp.MustCompile("'.+'|\".+\"|\\S+")
	parts := r.FindAllString(job.Args, -1)
	cmd := &exec.Cmd{}
	cmd = exec.Command(head, parts...)

	// Apply the sent environment variables, split on spaces
	// but preserve quoted strings
	if len(job.EnvVars) > 0 {
		r = regexp.MustCompile("[^ ]*='[^']+'|[^ ]*=\"[^']+\"|\\S+")
		cmd.Env = r.FindAllString(job.EnvVars, -1)
		// Remove speech marks around the value of quoted strings. Matches, for
		// example, `var="val val"`, and changes to `var=val val`
		for i, j := range cmd.Env {
			r := regexp.MustCompile(`(?s)([^ ]+=)["'](.*)["']`)
			if r.Match([]byte(j)) {
				k := r.ReplaceAll([]byte(j), []byte(`$1$2`))
				cmd.Env[i] = string(k)
			}
		}
	} else {
		cmd.Env = []string{}
	}

	// Add the system scripts directory to Env.SYSSCRIPTDIR
	cmd.Env = append(cmd.Env, "SYSSCRIPTDIR="+config.SysScriptDir)

	cmd.Dir = os.TempDir()

	// Set up buffer for stdout
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Pipe error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}
	rdr := bufio.NewReader(stdout)
	stderr, err := cmd.StderrPipe()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Pipe error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}
	rdr_stderr := bufio.NewReader(stderr)

	/*
	   data := JobOut{}
	   jsondata, err := json.Marshal(data)
	*/

	// Get child processes to run in a process group so they
	// can all be killed as a group.
	cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}

	// Run command in the background (fork)
	err = cmd.Start()
	if err != nil {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_SYSCANCELLED,
			StatusReason:  fmt.Sprintf("Fork error ('%s')", err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
		return
	}

	if err := api.sendStatus(job, JobOut{
		Status:        STATUS_INPROGRESS,
		StatusReason:  "Script started",
		StatusPercent: 0,
		Errors:        0,
	}); err != nil {
		logit(fmt.Sprintf("Error: %s", err.Error()))
	}

	// Save the pid so it can be killed
	api.SetPid(job.JobID, int64(cmd.Process.Pid))

	// Process the output
	serial := int64(1)
	line := ""
	if job.Type != 2 {
		// A user job (the default, should be type=1)
		line, err = rdr.ReadString('\n')
		api.sendOutputLine(job, line, serial)
		for err == nil {
			serial++
			a := ""
			starttime := time.Now()
			// Up to 50 lines can be read in one hit
			for i := 0; i < 50; i++ {
				if time.Duration(time.Since(starttime)) > time.Second {
					break
				}
				line, err = rdr.ReadString('\n')
				a = a + line
			}
			api.sendOutputLine(job, a, serial)
		}
	} else {
		// A system job. Send all output in a single output line
		a := ""
		for err == nil {
			line, err = rdr.ReadString('\n')
			a = a + line
		}
		api.sendOutputLine(job, a, 1)
	}

	serial++

	// Read anything in stderr, but don't send it.
	// It will be sent later if the script has non-zero exit status
	error_output := ""
	err = nil
	for err == nil {
		line, err = rdr_stderr.ReadString('\n')
		error_output = error_output + line
	}

	// Process exit status
	err = cmd.Wait()
	if err != nil {
		api.sendOutputLine(job, error_output, serial)
		status := int64(0)
		if api.UserCancel(job.JobID) == true {
			status = STATUS_USERCANCELLED
		} else {
			status = STATUS_ERROR
		}
		if err := api.sendStatus(job, JobOut{
			Status: status,
			StatusReason: fmt.Sprintf("Script, '%s', exited with error status ('%s')",
				job.ScriptName, err.Error()),
			StatusPercent: 0,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: (Script: '%s') %s", job.ScriptName,
				err.Error()))
		}
		api.RemoveJob(job.JobID)
		return
	}

	status := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
	if status == 0 {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_OK,
			StatusReason:  "Script finished successfully",
			StatusPercent: 100,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
	} else {
		if err := api.sendStatus(job, JobOut{
			Status:        STATUS_ERROR,
			StatusReason:  "Non-zero exit status. Check the log.",
			StatusPercent: 100,
			Errors:        0,
		}); err != nil {
			logit(fmt.Sprintf("Error: %s", err.Error()))
		}
	}

	api.RemoveJob(int64(job.JobID))

	// logout
}

/*
func main() {
    exec_cmd ( os.Args[1:]... )
}
*/
<|endoftext|>


<commit_before>// Copyright © 2017 Circonus, Inc. <support@circonus.com>
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package defaults

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"

	"github.com/circonus-labs/circonus-agent/internal/release"
)

const (
	// ListenPort is the default agent tcp listening port
	ListenPort = 2609

	// APIURL for circonus
	APIURL = "https://api.circonus.com/v2/"

	// APIApp defines the api app name associated with the api token key
	APIApp = release.NAME

	// Reverse is false by default
	Reverse = false

	// SSLVerify enabled by default
	SSLVerify = true

	// NoStatsd enabled by default
	NoStatsd = false

	// Debug is false by default
	Debug = false

	// LogLevel set to info by default
	LogLevel = "info"

	// LogPretty colored/formatted output to stderr
	LogPretty = false

	// UID to drop privileges to on start
	UID = "nobody"

	// Watch plugins for changes
	Watch = false

	// ReverseMaxConnRetry - how many times to retry persistently failing broker connection
	ReverseMaxConnRetry = -1

	// StatsdPort to listen, NOTE address is always localhost
	StatsdPort = "8125"

	// StatsdHostPrefix defines that metrics received through StatsD inteface
	// which are prefixed with this string plus a period go to the host check
	StatsdHostPrefix = "" //"host."

	// StatsdHostCategory defines the "plugin" in which the host metrics will be namepspaced
	StatsdHostCategory = "statsd"

	// StatsdGroupPrefix defines that metrics received through StatsD inteface
	// which are prefixed with this string plus a period go to the group check, if enabled
	StatsdGroupPrefix = "group."

	// StatsdGroupCounters defines how group counter metrics will be handled (average or sum)
	StatsdGroupCounters = "sum"

	// StatsdGroupGauges defines how group counter metrics will be handled (average or sum)
	StatsdGroupGauges = "average"

	// StatsdGroupSets defines how group counter metrics will be handled (average or sum)
	StatsdGroupSets = "sum"

	// MetricNameSeparator defines character used to delimit metric name parts
	MetricNameSeparator = "`"

	// PluginTTLUnits defines the default TTL units for plugins with TTLs
	// e.g. plugin_ttl30s.sh (30s ttl) plugin_ttl45.sh (would get default ttl units, e.g. 45s)
	PluginTTLUnits = "s" // seconds

	// DisableGzip disables gzip compression on responses
	DisableGzip = false

	// CheckEnableNewMetrics toggles enabling new metrics
	CheckEnableNewMetrics = false
	// CheckMetricRefreshTTL determines how often to refresh check bundle metrics from API
	CheckMetricRefreshTTL = "5m"

	// CheckCreate toggles creating a check if a check bundle id is not supplied
	CheckCreate = false

	// CheckBroker to use if creating a check, 'select' or '' will
	// result in the first broker which meets some basic criteria being selected.
	// 1. Active status
	// 2. Supports the required check type
	// 3. Responds within reverse.brokerMaxResponseTime
	CheckBroker = "select"

	// CheckTags to use if creating a check (comma separated list)
	CheckTags = ""
)

var (
	// Listen defaults to all interfaces on the default ListenPort
	// valid formats:
	//      ip:port (e.g. 127.0.0.1:12345 - listen address 127.0.0.1, port 12345)
	//      ip (e.g. 127.0.0.1 - listen address 127.0.0.1, port ListenPort)
	//      port (e.g. 12345 (or :12345) - listen address all, port 12345)
	//
	Listen = fmt.Sprintf(":%d", ListenPort)

	// BasePath is the "base" directory
	//
	// expected installation structure:
	// base        (e.g. /opt/circonus/agent)
	//   /bin      (e.g. /opt/circonus/agent/bin)
	//   /etc      (e.g. /opt/circonus/agent/etc)
	//   /plugins  (e.g. /opt/circonus/agent/plugins)
	//   /sbin     (e.g. /opt/circonus/agent/sbin)
	BasePath = ""

	// Collectors defines the default builtin collectors to enable
	// OS specific - see init() below
	Collectors = []string{}

	// EtcPath returns the default etc directory within base directory
	EtcPath = "" // (e.g. /opt/circonus/agent/etc)

	// PluginPath returns the default plugin path
	PluginPath = "" // (e.g. /opt/circonus/agent/plugins)

	// CheckTarget defaults to return from os.Hostname()
	CheckTarget = ""

	// CheckTitle defaults to '<CheckTarget> /agent'
	CheckTitle = ""

	// CheckMetricStatePath returns the default state directory. In order for
	// automatic new metric enabling to work the state path must exist
	// and be owned by the user running circonus-agentd (i.e. 'nobody').
	CheckMetricStatePath = "" // (e.g. /opt/circonus/agent/state)

	// CheckMetricFilters defines default filter to be used with new check creation
	CheckMetricFilters = [][]string{[]string{"deny", "^$", ""}, []string{"allow", "^.+$", ""}}

	// SSLCertFile returns the deefault ssl cert file name
	SSLCertFile = "" // (e.g. /opt/circonus/agent/etc/agent.pem)

	// SSLKeyFile returns the deefault ssl key file name
	SSLKeyFile = "" // (e.g. /opt/circonus/agent/etc/agent.key)

	// StatsdConf returns the default statsd config file
	StatsdConf = "" // (e.g. /opt/circonus/agent/etc/statsd.json)
)

func init() {
	var exePath string
	var resolvedExePath string
	var err error

	exePath, err = os.Executable()
	if err == nil {
		resolvedExePath, err = filepath.EvalSymlinks(exePath)
		if err == nil {
			BasePath = filepath.Clean(filepath.Join(filepath.Dir(resolvedExePath), "..")) // e.g. /opt/circonus/agent
		}
	}

	if err != nil {
		fmt.Printf("Unable to determine path to binary %v\n", err)
		os.Exit(1)
	}

	EtcPath = filepath.Join(BasePath, "etc")
	CheckMetricStatePath = filepath.Join(BasePath, "state")
	PluginPath = filepath.Join(BasePath, "plugins")
	SSLCertFile = filepath.Join(EtcPath, release.NAME+".pem")
	SSLKeyFile = filepath.Join(EtcPath, release.NAME+".key")

	CheckTarget, err = os.Hostname()
	if err != nil {
		fmt.Printf("Unable to determine hostname for target %v\n", err)
		os.Exit(1)
	}
	CheckTitle = CheckTarget + " /agent"

	switch runtime.GOOS {
	case "linux":
		Collectors = []string{
			"procfs/cpu",
			"procfs/diskstats",
			"procfs/if",
			"procfs/loadavg",
			"procfs/vm",
		}
	case "windows":
		Collectors = []string{
			"wmi/cache",
			"wmi/disk", // logical and physical
			"wmi/interface",
			"wmi/ip", // ipv4 and ipv6
			"wmi/memory",
			"wmi/objects",
			"wmi/paging_file",
			// "wmi/processes",
			"wmi/processor",
			"wmi/tcp", // ipv4 and ipv6
			"wmi/udp", // ipv4 and ipv6
		}
	default:
		Collectors = []string{
			"generic/cpu",
			"generic/disk",
			"generic/fs",
			"generic/load",
			"generic/if",
			"generic/proto",
			"generic/vm",
		}
	}
}
<commit_msg>upd: default procfs and generic to same (sans generic/fs)<commit_after>// Copyright © 2017 Circonus, Inc. <support@circonus.com>
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//

package defaults

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"

	"github.com/circonus-labs/circonus-agent/internal/release"
)

const (
	// ListenPort is the default agent tcp listening port
	ListenPort = 2609

	// APIURL for circonus
	APIURL = "https://api.circonus.com/v2/"

	// APIApp defines the api app name associated with the api token key
	APIApp = release.NAME

	// Reverse is false by default
	Reverse = false

	// SSLVerify enabled by default
	SSLVerify = true

	// NoStatsd enabled by default
	NoStatsd = false

	// Debug is false by default
	Debug = false

	// LogLevel set to info by default
	LogLevel = "info"

	// LogPretty colored/formatted output to stderr
	LogPretty = false

	// UID to drop privileges to on start
	UID = "nobody"

	// Watch plugins for changes
	Watch = false

	// ReverseMaxConnRetry - how many times to retry persistently failing broker connection
	ReverseMaxConnRetry = -1

	// StatsdPort to listen, NOTE address is always localhost
	StatsdPort = "8125"

	// StatsdHostPrefix defines that metrics received through StatsD inteface
	// which are prefixed with this string plus a period go to the host check
	StatsdHostPrefix = "" //"host."

	// StatsdHostCategory defines the "plugin" in which the host metrics will be namepspaced
	StatsdHostCategory = "statsd"

	// StatsdGroupPrefix defines that metrics received through StatsD inteface
	// which are prefixed with this string plus a period go to the group check, if enabled
	StatsdGroupPrefix = "group."

	// StatsdGroupCounters defines how group counter metrics will be handled (average or sum)
	StatsdGroupCounters = "sum"

	// StatsdGroupGauges defines how group counter metrics will be handled (average or sum)
	StatsdGroupGauges = "average"

	// StatsdGroupSets defines how group counter metrics will be handled (average or sum)
	StatsdGroupSets = "sum"

	// MetricNameSeparator defines character used to delimit metric name parts
	MetricNameSeparator = "`"

	// PluginTTLUnits defines the default TTL units for plugins with TTLs
	// e.g. plugin_ttl30s.sh (30s ttl) plugin_ttl45.sh (would get default ttl units, e.g. 45s)
	PluginTTLUnits = "s" // seconds

	// DisableGzip disables gzip compression on responses
	DisableGzip = false

	// CheckEnableNewMetrics toggles enabling new metrics
	CheckEnableNewMetrics = false
	// CheckMetricRefreshTTL determines how often to refresh check bundle metrics from API
	CheckMetricRefreshTTL = "5m"

	// CheckCreate toggles creating a check if a check bundle id is not supplied
	CheckCreate = false

	// CheckBroker to use if creating a check, 'select' or '' will
	// result in the first broker which meets some basic criteria being selected.
	// 1. Active status
	// 2. Supports the required check type
	// 3. Responds within reverse.brokerMaxResponseTime
	CheckBroker = "select"

	// CheckTags to use if creating a check (comma separated list)
	CheckTags = ""
)

var (
	// Listen defaults to all interfaces on the default ListenPort
	// valid formats:
	//      ip:port (e.g. 127.0.0.1:12345 - listen address 127.0.0.1, port 12345)
	//      ip (e.g. 127.0.0.1 - listen address 127.0.0.1, port ListenPort)
	//      port (e.g. 12345 (or :12345) - listen address all, port 12345)
	//
	Listen = fmt.Sprintf(":%d", ListenPort)

	// BasePath is the "base" directory
	//
	// expected installation structure:
	// base        (e.g. /opt/circonus/agent)
	//   /bin      (e.g. /opt/circonus/agent/bin)
	//   /etc      (e.g. /opt/circonus/agent/etc)
	//   /plugins  (e.g. /opt/circonus/agent/plugins)
	//   /sbin     (e.g. /opt/circonus/agent/sbin)
	BasePath = ""

	// Collectors defines the default builtin collectors to enable
	// OS specific - see init() below
	Collectors = []string{}

	// EtcPath returns the default etc directory within base directory
	EtcPath = "" // (e.g. /opt/circonus/agent/etc)

	// PluginPath returns the default plugin path
	PluginPath = "" // (e.g. /opt/circonus/agent/plugins)

	// CheckTarget defaults to return from os.Hostname()
	CheckTarget = ""

	// CheckTitle defaults to '<CheckTarget> /agent'
	CheckTitle = ""

	// CheckMetricStatePath returns the default state directory. In order for
	// automatic new metric enabling to work the state path must exist
	// and be owned by the user running circonus-agentd (i.e. 'nobody').
	CheckMetricStatePath = "" // (e.g. /opt/circonus/agent/state)

	// CheckMetricFilters defines default filter to be used with new check creation
	CheckMetricFilters = [][]string{[]string{"deny", "^$", ""}, []string{"allow", "^.+$", ""}}

	// SSLCertFile returns the deefault ssl cert file name
	SSLCertFile = "" // (e.g. /opt/circonus/agent/etc/agent.pem)

	// SSLKeyFile returns the deefault ssl key file name
	SSLKeyFile = "" // (e.g. /opt/circonus/agent/etc/agent.key)

	// StatsdConf returns the default statsd config file
	StatsdConf = "" // (e.g. /opt/circonus/agent/etc/statsd.json)
)

func init() {
	var exePath string
	var resolvedExePath string
	var err error

	exePath, err = os.Executable()
	if err == nil {
		resolvedExePath, err = filepath.EvalSymlinks(exePath)
		if err == nil {
			BasePath = filepath.Clean(filepath.Join(filepath.Dir(resolvedExePath), "..")) // e.g. /opt/circonus/agent
		}
	}

	if err != nil {
		fmt.Printf("Unable to determine path to binary %v\n", err)
		os.Exit(1)
	}

	EtcPath = filepath.Join(BasePath, "etc")
	CheckMetricStatePath = filepath.Join(BasePath, "state")
	PluginPath = filepath.Join(BasePath, "plugins")
	SSLCertFile = filepath.Join(EtcPath, release.NAME+".pem")
	SSLKeyFile = filepath.Join(EtcPath, release.NAME+".key")

	CheckTarget, err = os.Hostname()
	if err != nil {
		fmt.Printf("Unable to determine hostname for target %v\n", err)
		os.Exit(1)
	}
	CheckTitle = CheckTarget + " /agent"

	switch runtime.GOOS {
	case "linux":
		Collectors = []string{
			"procfs/cpu",
			"procfs/disk",
			"procfs/if",
			"procfs/load",
			"procfs/proto",
			"procfs/vm",
		}
	case "windows":
		Collectors = []string{
			"wmi/cache",
			"wmi/disk", // logical and physical
			"wmi/interface",
			"wmi/ip", // ipv4 and ipv6
			"wmi/memory",
			"wmi/objects",
			"wmi/paging_file",
			// "wmi/processes",
			"wmi/processor",
			"wmi/tcp", // ipv4 and ipv6
			"wmi/udp", // ipv4 and ipv6
		}
	default:
		Collectors = []string{
			"generic/cpu",
			"generic/disk",
			"generic/fs",
			"generic/if",
			"generic/load",
			"generic/proto",
			"generic/vm",
		}
	}
}
<|endoftext|>


<commit_before>package handlers_test

import (
	"database/sql"
	"encoding/json"
	"github.com/aclindsa/moneygo/internal/config"
	"github.com/aclindsa/moneygo/internal/db"
	"github.com/aclindsa/moneygo/internal/handlers"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"path"
	"strings"
	"testing"
)

var server *httptest.Server

func Delete(client *http.Client, url string) (*http.Response, error) {
	request, err := http.NewRequest(http.MethodDelete, url, nil)
	if err != nil {
		return nil, err
	}
	return client.Do(request)
}

func PutForm(client *http.Client, url string, data url.Values) (*http.Response, error) {
	request, err := http.NewRequest(http.MethodPut, url, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	return client.Do(request)
}

type TransactType interface {
	Read(string) error
}

func create(client *http.Client, input, output TransactType, urlsuffix, key string) error {
	bytes, err := json.Marshal(input)
	if err != nil {
		return err
	}
	response, err := client.PostForm(server.URL+urlsuffix, url.Values{key: {string(bytes)}})
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func read(client *http.Client, output TransactType, urlsuffix, key string) error {
	response, err := client.Get(server.URL + urlsuffix)
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func update(client *http.Client, input, output TransactType, urlsuffix, key string) error {
	bytes, err := json.Marshal(input)
	if err != nil {
		return err
	}
	response, err := PutForm(client, server.URL+urlsuffix, url.Values{key: {string(bytes)}})
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func remove(client *http.Client, urlsuffix, key string) error {
	response, err := Delete(client, server.URL+urlsuffix)
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	return nil
}

func RunWith(t *testing.T, d *TestData, fn TestDataFunc) {
	testdata, err := d.Initialize()
	if err != nil {
		t.Fatalf("Failed to initialize test data: %s", err)
	}
	defer func() {
		err := testdata.Teardown()
		if err != nil {
			t.Fatal(err)
		}
	}()

	fn(t, testdata)
}

func RunTests(m *testing.M) int {
	tmpdir, err := ioutil.TempDir("./", "handlertest")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(tmpdir)

	dbpath := path.Join(tmpdir, "moneygo.sqlite")
	dsn := db.GetDSN(config.SQLite, "file:"+dbpath+"?cache=shared&mode=rwc")
	database, err := sql.Open("sqlite3", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer database.Close()

	dbmap, err := db.GetDbMap(database, config.SQLite)
	if err != nil {
		log.Fatal(err)
	}

	servemux := handlers.GetHandler(dbmap)
	server = httptest.NewTLSServer(servemux)
	defer server.Close()

	return m.Run()
}

func TestMain(m *testing.M) {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	os.Exit(RunTests(m))
}
<commit_msg>testing: Use an in-memory sqlite3 database<commit_after>package handlers_test

import (
	"database/sql"
	"encoding/json"
	"github.com/aclindsa/moneygo/internal/config"
	"github.com/aclindsa/moneygo/internal/db"
	"github.com/aclindsa/moneygo/internal/handlers"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"strings"
	"testing"
)

var server *httptest.Server

func Delete(client *http.Client, url string) (*http.Response, error) {
	request, err := http.NewRequest(http.MethodDelete, url, nil)
	if err != nil {
		return nil, err
	}
	return client.Do(request)
}

func PutForm(client *http.Client, url string, data url.Values) (*http.Response, error) {
	request, err := http.NewRequest(http.MethodPut, url, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	return client.Do(request)
}

type TransactType interface {
	Read(string) error
}

func create(client *http.Client, input, output TransactType, urlsuffix, key string) error {
	bytes, err := json.Marshal(input)
	if err != nil {
		return err
	}
	response, err := client.PostForm(server.URL+urlsuffix, url.Values{key: {string(bytes)}})
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func read(client *http.Client, output TransactType, urlsuffix, key string) error {
	response, err := client.Get(server.URL + urlsuffix)
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func update(client *http.Client, input, output TransactType, urlsuffix, key string) error {
	bytes, err := json.Marshal(input)
	if err != nil {
		return err
	}
	response, err := PutForm(client, server.URL+urlsuffix, url.Values{key: {string(bytes)}})
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func remove(client *http.Client, urlsuffix, key string) error {
	response, err := Delete(client, server.URL+urlsuffix)
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	return nil
}

func RunWith(t *testing.T, d *TestData, fn TestDataFunc) {
	testdata, err := d.Initialize()
	if err != nil {
		t.Fatalf("Failed to initialize test data: %s", err)
	}
	defer func() {
		err := testdata.Teardown()
		if err != nil {
			t.Fatal(err)
		}
	}()

	fn(t, testdata)
}

func RunTests(m *testing.M) int {
	dsn := db.GetDSN(config.SQLite, ":memory:")
	database, err := sql.Open("sqlite3", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer database.Close()

	dbmap, err := db.GetDbMap(database, config.SQLite)
	if err != nil {
		log.Fatal(err)
	}

	servemux := handlers.GetHandler(dbmap)
	server = httptest.NewTLSServer(servemux)
	defer server.Close()

	return m.Run()
}

func TestMain(m *testing.M) {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	os.Exit(RunTests(m))
}
<|endoftext|>


<commit_before>package handlers_test

import (
	"database/sql"
	"encoding/json"
	"github.com/aclindsa/moneygo/internal/config"
	"github.com/aclindsa/moneygo/internal/db"
	"github.com/aclindsa/moneygo/internal/handlers"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"path"
	"strings"
	"testing"
)

var server *httptest.Server

func Delete(client *http.Client, url string) (*http.Response, error) {
	request, err := http.NewRequest(http.MethodDelete, url, nil)
	if err != nil {
		return nil, err
	}
	return client.Do(request)
}

func PutForm(client *http.Client, url string, data url.Values) (*http.Response, error) {
	request, err := http.NewRequest(http.MethodPut, url, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	return client.Do(request)
}

type TransactType interface {
	Read(string) error
}

func create(client *http.Client, input, output TransactType, urlsuffix, key string) error {
	bytes, err := json.Marshal(input)
	if err != nil {
		return err
	}
	response, err := client.PostForm(server.URL+urlsuffix, url.Values{key: {string(bytes)}})
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func read(client *http.Client, output TransactType, urlsuffix, key string) error {
	response, err := client.Get(server.URL + urlsuffix)
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func update(client *http.Client, input, output TransactType, urlsuffix, key string) error {
	bytes, err := json.Marshal(input)
	if err != nil {
		return err
	}
	response, err := PutForm(client, server.URL+urlsuffix, url.Values{key: {string(bytes)}})
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func remove(client *http.Client, urlsuffix, key string) error {
	response, err := Delete(client, server.URL+urlsuffix)
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	return nil
}

func RunWith(t *testing.T, d *TestData, fn TestDataFunc) {
	testdata, err := d.Initialize()
	if err != nil {
		t.Fatalf("Failed to initialize test data: %s", err)
	}
	defer func() {
		err := testdata.Teardown()
		if err != nil {
			t.Fatal(err)
		}
	}()

	fn(t, testdata)
}

func RunTests(m *testing.M) int {
	tmpdir, err := ioutil.TempDir("./", "handlertest")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(tmpdir)

	dbpath := path.Join(tmpdir, "moneygo.sqlite")
	dsn := db.GetDSN(config.SQLite, "file:"+dbpath+"?cache=shared&mode=rwc")
	database, err := sql.Open("sqlite3", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer database.Close()

	dbmap, err := db.GetDbMap(database, config.SQLite)
	if err != nil {
		log.Fatal(err)
	}

	servemux := handlers.GetHandler(dbmap)
	server = httptest.NewTLSServer(servemux)
	defer server.Close()

	return m.Run()
}

func TestMain(m *testing.M) {
	os.Exit(RunTests(m))
}
<commit_msg>testing: Add files and line numbers to logging output<commit_after>package handlers_test

import (
	"database/sql"
	"encoding/json"
	"github.com/aclindsa/moneygo/internal/config"
	"github.com/aclindsa/moneygo/internal/db"
	"github.com/aclindsa/moneygo/internal/handlers"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/url"
	"os"
	"path"
	"strings"
	"testing"
)

var server *httptest.Server

func Delete(client *http.Client, url string) (*http.Response, error) {
	request, err := http.NewRequest(http.MethodDelete, url, nil)
	if err != nil {
		return nil, err
	}
	return client.Do(request)
}

func PutForm(client *http.Client, url string, data url.Values) (*http.Response, error) {
	request, err := http.NewRequest(http.MethodPut, url, strings.NewReader(data.Encode()))
	if err != nil {
		return nil, err
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	return client.Do(request)
}

type TransactType interface {
	Read(string) error
}

func create(client *http.Client, input, output TransactType, urlsuffix, key string) error {
	bytes, err := json.Marshal(input)
	if err != nil {
		return err
	}
	response, err := client.PostForm(server.URL+urlsuffix, url.Values{key: {string(bytes)}})
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func read(client *http.Client, output TransactType, urlsuffix, key string) error {
	response, err := client.Get(server.URL + urlsuffix)
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func update(client *http.Client, input, output TransactType, urlsuffix, key string) error {
	bytes, err := json.Marshal(input)
	if err != nil {
		return err
	}
	response, err := PutForm(client, server.URL+urlsuffix, url.Values{key: {string(bytes)}})
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	err = output.Read(string(body))
	if err != nil {
		return err
	}

	return nil
}

func remove(client *http.Client, urlsuffix, key string) error {
	response, err := Delete(client, server.URL+urlsuffix)
	if err != nil {
		return err
	}

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

	var e handlers.Error
	err = (&e).Read(string(body))
	if err != nil {
		return err
	}
	if e.ErrorId != 0 || len(e.ErrorString) != 0 {
		return &e
	}

	return nil
}

func RunWith(t *testing.T, d *TestData, fn TestDataFunc) {
	testdata, err := d.Initialize()
	if err != nil {
		t.Fatalf("Failed to initialize test data: %s", err)
	}
	defer func() {
		err := testdata.Teardown()
		if err != nil {
			t.Fatal(err)
		}
	}()

	fn(t, testdata)
}

func RunTests(m *testing.M) int {
	tmpdir, err := ioutil.TempDir("./", "handlertest")
	if err != nil {
		log.Fatal(err)
	}
	defer os.RemoveAll(tmpdir)

	dbpath := path.Join(tmpdir, "moneygo.sqlite")
	dsn := db.GetDSN(config.SQLite, "file:"+dbpath+"?cache=shared&mode=rwc")
	database, err := sql.Open("sqlite3", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer database.Close()

	dbmap, err := db.GetDbMap(database, config.SQLite)
	if err != nil {
		log.Fatal(err)
	}

	servemux := handlers.GetHandler(dbmap)
	server = httptest.NewTLSServer(servemux)
	defer server.Close()

	return m.Run()
}

func TestMain(m *testing.M) {
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
	os.Exit(RunTests(m))
}
<|endoftext|>


<commit_before>package status

import (
	"github.com/byuoitav/configuration-database-microservice/accessors"
)

type PowerStatus struct {
	Power string `json:"power"`
}

type BlankedStatus struct {
	Blanked bool `json:"blanked"`
}

type MuteStatus struct {
	Muted bool `json:"muted"`
}

type VideoInput struct {
	Input string `json:"input"`
}

type AudioInput struct {
	Input string `json:"input"`
}

type AudioList struct {
	Inputs []AudioInput `json"inputs"`
}

type VideoList struct {
	Inputs []VideoInput `json:"inputs"`
}

type Volume struct {
	Volume int `json:"volume"`
}

//represents output from a device, use Error field to flag errors
type Status struct {
	DestinationDevice DestinationDevice      `json:"device"`
	Responses         []StatusResponse       `json:"responses"`
	Status            map[string]interface{} `json:"status"`
	ErrorMessage      *string                `json:"error"`
}

//represents a status response, including the generator that created the command that returned the status
type StatusResponse struct {
	Generator string                 `json:"generator"`
	Status    map[string]interface{} `json:"status"`
}

//StatusCommand contains information to issue a status command against a device
type StatusCommand struct {
	Action            accessors.Command `json:"action"`
	Device            accessors.Device  `json:"device"`
	Generator         string            `json:"generator"`
	DestinationDevice DestinationDevice `json:"destination"`
	Parameters        map[string]string `json:"parameters"`
}

//DestinationDevice represents the device a status command is issued to
type DestinationDevice struct {
	accessors.Device
	AudioDevice bool `json:"audio"`
	Display     bool `json:"video"`
}

type StatusEvaluator interface {

	//Identifies relevant devices
	GetDevices(room accessors.Room) ([]accessors.Device, error)

	//Generates action list
	GenerateCommands(devices []accessors.Device) ([]StatusCommand, error)

	//Evaluate Response
	EvaluateResponse(label string, value interface{}) (string, interface{}, error)
}

const FLAG = "STATUS"

var DEFAULT_MAP = map[string]StatusEvaluator{
	"STATUS_PowerDefault":   &PowerDefault{},
	"STATUS_BlankedDefault": &BlankedDefault{},
	"STATUS_MutedDefault":   &MutedDefault{},
	"STATUS_InputDefault":   &InputDefault{},
	"STATUS_VolumeDefault":  &VolumeDefault{},
}
<commit_msg>Consolidating inputs<commit_after>package status

import (
	"github.com/byuoitav/configuration-database-microservice/accessors"
)

type PowerStatus struct {
	Power string `json:"power"`
}

type BlankedStatus struct {
	Blanked bool `json:"blanked"`
}

type MuteStatus struct {
	Muted bool `json:"muted"`
}

type Input struct {
	Input string `json:"input"`
}

type AudioList struct {
	Inputs []Input `json"inputs"`
}

type VideoList struct {
	Inputs []Input `json:"inputs"`
}

type Volume struct {
	Volume int `json:"volume"`
}

//represents output from a device, use Error field to flag errors
type Status struct {
	DestinationDevice DestinationDevice      `json:"device"`
	Responses         []StatusResponse       `json:"responses"`
	Status            map[string]interface{} `json:"status"`
	ErrorMessage      *string                `json:"error"`
}

//represents a status response, including the generator that created the command that returned the status
type StatusResponse struct {
	Generator string                 `json:"generator"`
	Status    map[string]interface{} `json:"status"`
}

//StatusCommand contains information to issue a status command against a device
type StatusCommand struct {
	Action            accessors.Command `json:"action"`
	Device            accessors.Device  `json:"device"`
	Generator         string            `json:"generator"`
	DestinationDevice DestinationDevice `json:"destination"`
	Parameters        map[string]string `json:"parameters"`
}

//DestinationDevice represents the device a status command is issued to
type DestinationDevice struct {
	accessors.Device
	AudioDevice bool `json:"audio"`
	Display     bool `json:"video"`
}

type StatusEvaluator interface {

	//Identifies relevant devices
	GetDevices(room accessors.Room) ([]accessors.Device, error)

	//Generates action list
	GenerateCommands(devices []accessors.Device) ([]StatusCommand, error)

	//Evaluate Response
	EvaluateResponse(label string, value interface{}) (string, interface{}, error)
}

const FLAG = "STATUS"

var DEFAULT_MAP = map[string]StatusEvaluator{
	"STATUS_PowerDefault":   &PowerDefault{},
	"STATUS_BlankedDefault": &BlankedDefault{},
	"STATUS_MutedDefault":   &MutedDefault{},
	"STATUS_InputDefault":   &InputDefault{},
	"STATUS_VolumeDefault":  &VolumeDefault{},
}
<|endoftext|>