<commit_before>package gosecco

import (
	"fmt"
	"runtime"
	"strings"
	"syscall"

	"github.com/twtiger/gosecco/checker"
	"github.com/twtiger/gosecco/compiler"
	"github.com/twtiger/gosecco/data"
	"github.com/twtiger/gosecco/native"
	"github.com/twtiger/gosecco/parser"
	"github.com/twtiger/gosecco/precompilation"
	"github.com/twtiger/gosecco/simplifier"
	"github.com/twtiger/gosecco/tree"
	"github.com/twtiger/gosecco/unifier"

	"golang.org/x/sys/unix"
)

// CheckSupport checks for the required seccomp support in the kernel.
func CheckSupport() error {
	if err := native.CheckGetSeccomp(); err != nil {
		return fmt.Errorf("seccomp not available: %v", err)
	}
	if err := native.CheckSetSeccompModeFilter(); err != syscall.EFAULT {
		return fmt.Errorf("seccomp filter not available: %v", err)
	}
	if err := native.CheckSetSeccompModeFilterWithSeccomp(); err != syscall.EFAULT {
		return fmt.Errorf("seccomp syscall not available: %v", err)
	}
	if err := native.CheckSetSeccompModeTsync(); err != syscall.EFAULT {
		return fmt.Errorf("seccomp tsync not available: %v", err)
	}
	return nil
}

// SeccompSettings contains the extra settings necessary to tweak the
// behavior of the compilation process
type SeccompSettings struct {
	// ExtraDefinitions contains paths to files with extra definitions to parse
	// These files should only contain variables/macros - rules will not be picked
	// up.
	// If the path starts with the special marker InlineMarker, the rest of the string will
	// be interpreted as an inline definition, not a path.
	// ExtraDefinitions is softly deprecated - you should probably use parser.CombinedSources instead
	ExtraDefinitions []string
	// DefaultPositiveAction is the action to take when a syscall is matched, and the expression returns a positive result - and the rule
	// doesn't have any specified custom actions.  It can be specified as one of "trap", "kill", "allow" or "trace". It can also be a number
	// - this will be treated as an errno. You can also use the pre- defined classical names for errors instead of the number - such as
	// EACCES.
	DefaultPositiveAction string
	// DefaultNegativeAction is the action to take when a syscall is matched, the expression returns a negative result and the rule doesn't
	// have any custom actions defined. The action can be specified using the same syntax as described for DefaultPositiveAction.
	DefaultNegativeAction string
	// DefaultPolicyAction is the action to take when the syscall is not matched. The action can be specified using the same syntax as
	// described for DefaultPositiveAction.
	DefaultPolicyAction string
	// ActionOnX32 is the action to take if the syscall is a 32-bit ABI compatibility syscall. If no action is specified, this case will not
	// be considered. The actions are specified using the same syntax as described for DefaultPositiveAction.
	ActionOnX32 string
	// ActionOnAuditFailure is the action to take if the policy is running on the wrong architecture compared to what it was compiled
	// for. If not specified, it will default to "kill". The actions are specified using the same syntax as described for
	// DefaultPositiveAction.
	ActionOnAuditFailure string
}

// InlineMarker is the marker a string should start with in order to
// specify it should be parsed as an inline string, not a path.
const InlineMarker = "{inline}"

// PrepareSource will take the given source and settings, parse and compile the given
// data, combined with the settings - and returns the bytecode
func PrepareSource(source parser.Source, s SeccompSettings) ([]unix.SockFilter, error) {
	var e error
	var rp tree.RawPolicy

	// Parsing of extra files with definitions
	extras := make([]map[string]tree.Macro, len(s.ExtraDefinitions))
	for ix, ed := range s.ExtraDefinitions {
		if strings.HasPrefix(ed, InlineMarker) {
			rp, e = parser.ParseString(strings.TrimPrefix(ed, InlineMarker))
		} else {
			rp, e = parser.ParseFile(ed)
		}
		if e != nil {
			return nil, e
		}
		p, e2 := unifier.Unify(rp, nil, "", "", "")
		if e2 != nil {
			return nil, e2
		}
		extras[ix] = p.Macros
	}

	// Parsing
	rp, e = parser.Parse(source)
	if e != nil {
		return nil, e
	}

	// Unifying
	pol, err := unifier.Unify(rp, extras, s.DefaultPositiveAction, s.DefaultNegativeAction, s.DefaultPolicyAction)
	if err != nil {
		return nil, err
	}

	// Type checking
	errors := checker.EnsureValid(pol)
	if len(errors) > 0 {
		return nil, errors[0]
	}

	// Simplification
	simplifier.SimplifyPolicy(&pol)

	// Pre-compilation
	errors = precompilation.EnsureValid(pol)
	if len(errors) > 0 {
		return nil, errors[0]
	}

	// Compilation
	return compiler.Compile(pol)
}

// Prepare will take the given path and settings, parse and compile the given
// data, combined with the settings - and returns the bytecode
// If path starts with the special marker InlineMarker, the rest of the string will
// be interpreted as an inline definition, not a path.
// Prepare is now deprecated, and PrepareSource should be used instead
func Prepare(path string, s SeccompSettings) ([]unix.SockFilter, error) {
	return PrepareSource(&parser.FileSource{path}, s)
}

// Compile provides the compatibility interface for gosecco - it has the same signature as
// Compile from the go-seccomp package and should provide the same behavior.
// However, the modern interface is through the Prepare function
func Compile(path string, enforce bool) ([]unix.SockFilter, error) {

	settings := SeccompSettings{}
	settings.DefaultPositiveAction = "allow"
	settings.ActionOnAuditFailure = "kill"
	if enforce {
		settings.DefaultNegativeAction = "kill"
		settings.DefaultPolicyAction = "kill"
	} else {
		settings.DefaultNegativeAction = "trace"
		settings.DefaultPolicyAction = "trace"
	}

	return Prepare(path, settings)
}

// CompileBlacklist provides the compatibility interface for gosecco, for blacklist mode
// It has the same signature as CompileBlacklist from Subgraphs go-seccomp and should provide the same behavior.
// However, the modern interface is through the Prepare function
func CompileBlacklist(path string, enforce bool) ([]unix.SockFilter, error) {

	settings := SeccompSettings{}
	settings.DefaultNegativeAction = "allow"
	settings.DefaultPolicyAction = "allow"
	settings.ActionOnX32 = "kill"
	settings.ActionOnAuditFailure = "kill"
	if enforce {
		settings.DefaultPositiveAction = "kill"
	} else {
		settings.DefaultPositiveAction = "trace"
	}

	return Prepare(path, settings)
}

// Load makes the seccomp system call to install the bpf filter for
// all threads (with tsync). Most users of this library should use
// Install instead of Load, since Install ensures that prctl(set_no_new_privs, 1)
// has been called
func Load(bpf []unix.SockFilter) error {
	if size, limit := len(bpf), 0xffff; size > limit {
		return fmt.Errorf("filter program too big: %d bpf instructions (limit = %d)", size, limit)
	}

	prog := &data.SockFprog{
		Filter: &bpf[0],
		Len:    uint16(len(bpf)),
	}

	return native.InstallSeccomp(prog)
}

// Install will install the given policy filters into the kernel
func Install(bpf []unix.SockFilter) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	if err := native.NoNewPrivs(); err != nil {
		return err
	}
	return Load(bpf)
}

// InstallBlacklist makes the necessary system calls to install the Seccomp-BPF
// filter for the current process (all threads). Install can be called
// multiple times to install additional filters.
func InstallBlacklist(bpf []unix.SockFilter) error {
	return Install(bpf)
}
<commit_msg>Fix a typo in docs<commit_after>package gosecco

import (
	"fmt"
	"runtime"
	"strings"
	"syscall"

	"github.com/twtiger/gosecco/checker"
	"github.com/twtiger/gosecco/compiler"
	"github.com/twtiger/gosecco/data"
	"github.com/twtiger/gosecco/native"
	"github.com/twtiger/gosecco/parser"
	"github.com/twtiger/gosecco/precompilation"
	"github.com/twtiger/gosecco/simplifier"
	"github.com/twtiger/gosecco/tree"
	"github.com/twtiger/gosecco/unifier"

	"golang.org/x/sys/unix"
)

// CheckSupport checks for the required seccomp support in the kernel.
func CheckSupport() error {
	if err := native.CheckGetSeccomp(); err != nil {
		return fmt.Errorf("seccomp not available: %v", err)
	}
	if err := native.CheckSetSeccompModeFilter(); err != syscall.EFAULT {
		return fmt.Errorf("seccomp filter not available: %v", err)
	}
	if err := native.CheckSetSeccompModeFilterWithSeccomp(); err != syscall.EFAULT {
		return fmt.Errorf("seccomp syscall not available: %v", err)
	}
	if err := native.CheckSetSeccompModeTsync(); err != syscall.EFAULT {
		return fmt.Errorf("seccomp tsync not available: %v", err)
	}
	return nil
}

// SeccompSettings contains the extra settings necessary to tweak the
// behavior of the compilation process
type SeccompSettings struct {
	// ExtraDefinitions contains paths to files with extra definitions to parse
	// These files should only contain variables/macros - rules will not be picked
	// up.
	// If the path starts with the special marker InlineMarker, the rest of the string will
	// be interpreted as an inline definition, not a path.
	// ExtraDefinitions is softly deprecated - you should probably use parser.CombineSources instead
	ExtraDefinitions []string
	// DefaultPositiveAction is the action to take when a syscall is matched, and the expression returns a positive result - and the rule
	// doesn't have any specified custom actions.  It can be specified as one of "trap", "kill", "allow" or "trace". It can also be a number
	// - this will be treated as an errno. You can also use the pre- defined classical names for errors instead of the number - such as
	// EACCES.
	DefaultPositiveAction string
	// DefaultNegativeAction is the action to take when a syscall is matched, the expression returns a negative result and the rule doesn't
	// have any custom actions defined. The action can be specified using the same syntax as described for DefaultPositiveAction.
	DefaultNegativeAction string
	// DefaultPolicyAction is the action to take when the syscall is not matched. The action can be specified using the same syntax as
	// described for DefaultPositiveAction.
	DefaultPolicyAction string
	// ActionOnX32 is the action to take if the syscall is a 32-bit ABI compatibility syscall. If no action is specified, this case will not
	// be considered. The actions are specified using the same syntax as described for DefaultPositiveAction.
	ActionOnX32 string
	// ActionOnAuditFailure is the action to take if the policy is running on the wrong architecture compared to what it was compiled
	// for. If not specified, it will default to "kill". The actions are specified using the same syntax as described for
	// DefaultPositiveAction.
	ActionOnAuditFailure string
}

// InlineMarker is the marker a string should start with in order to
// specify it should be parsed as an inline string, not a path.
const InlineMarker = "{inline}"

// PrepareSource will take the given source and settings, parse and compile the given
// data, combined with the settings - and returns the bytecode
func PrepareSource(source parser.Source, s SeccompSettings) ([]unix.SockFilter, error) {
	var e error
	var rp tree.RawPolicy

	// Parsing of extra files with definitions
	extras := make([]map[string]tree.Macro, len(s.ExtraDefinitions))
	for ix, ed := range s.ExtraDefinitions {
		if strings.HasPrefix(ed, InlineMarker) {
			rp, e = parser.ParseString(strings.TrimPrefix(ed, InlineMarker))
		} else {
			rp, e = parser.ParseFile(ed)
		}
		if e != nil {
			return nil, e
		}
		p, e2 := unifier.Unify(rp, nil, "", "", "")
		if e2 != nil {
			return nil, e2
		}
		extras[ix] = p.Macros
	}

	// Parsing
	rp, e = parser.Parse(source)
	if e != nil {
		return nil, e
	}

	// Unifying
	pol, err := unifier.Unify(rp, extras, s.DefaultPositiveAction, s.DefaultNegativeAction, s.DefaultPolicyAction)
	if err != nil {
		return nil, err
	}

	// Type checking
	errors := checker.EnsureValid(pol)
	if len(errors) > 0 {
		return nil, errors[0]
	}

	// Simplification
	simplifier.SimplifyPolicy(&pol)

	// Pre-compilation
	errors = precompilation.EnsureValid(pol)
	if len(errors) > 0 {
		return nil, errors[0]
	}

	// Compilation
	return compiler.Compile(pol)
}

// Prepare will take the given path and settings, parse and compile the given
// data, combined with the settings - and returns the bytecode
// If path starts with the special marker InlineMarker, the rest of the string will
// be interpreted as an inline definition, not a path.
// Prepare is now deprecated, and PrepareSource should be used instead
func Prepare(path string, s SeccompSettings) ([]unix.SockFilter, error) {
	return PrepareSource(&parser.FileSource{path}, s)
}

// Compile provides the compatibility interface for gosecco - it has the same signature as
// Compile from the go-seccomp package and should provide the same behavior.
// However, the modern interface is through the Prepare function
func Compile(path string, enforce bool) ([]unix.SockFilter, error) {

	settings := SeccompSettings{}
	settings.DefaultPositiveAction = "allow"
	settings.ActionOnAuditFailure = "kill"
	if enforce {
		settings.DefaultNegativeAction = "kill"
		settings.DefaultPolicyAction = "kill"
	} else {
		settings.DefaultNegativeAction = "trace"
		settings.DefaultPolicyAction = "trace"
	}

	return Prepare(path, settings)
}

// CompileBlacklist provides the compatibility interface for gosecco, for blacklist mode
// It has the same signature as CompileBlacklist from Subgraphs go-seccomp and should provide the same behavior.
// However, the modern interface is through the Prepare function
func CompileBlacklist(path string, enforce bool) ([]unix.SockFilter, error) {

	settings := SeccompSettings{}
	settings.DefaultNegativeAction = "allow"
	settings.DefaultPolicyAction = "allow"
	settings.ActionOnX32 = "kill"
	settings.ActionOnAuditFailure = "kill"
	if enforce {
		settings.DefaultPositiveAction = "kill"
	} else {
		settings.DefaultPositiveAction = "trace"
	}

	return Prepare(path, settings)
}

// Load makes the seccomp system call to install the bpf filter for
// all threads (with tsync). Most users of this library should use
// Install instead of Load, since Install ensures that prctl(set_no_new_privs, 1)
// has been called
func Load(bpf []unix.SockFilter) error {
	if size, limit := len(bpf), 0xffff; size > limit {
		return fmt.Errorf("filter program too big: %d bpf instructions (limit = %d)", size, limit)
	}

	prog := &data.SockFprog{
		Filter: &bpf[0],
		Len:    uint16(len(bpf)),
	}

	return native.InstallSeccomp(prog)
}

// Install will install the given policy filters into the kernel
func Install(bpf []unix.SockFilter) error {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	if err := native.NoNewPrivs(); err != nil {
		return err
	}
	return Load(bpf)
}

// InstallBlacklist makes the necessary system calls to install the Seccomp-BPF
// filter for the current process (all threads). Install can be called
// multiple times to install additional filters.
func InstallBlacklist(bpf []unix.SockFilter) error {
	return Install(bpf)
}
<|endoftext|>


<commit_before>package framework

import (
	"net/http"

	"github.com/go-distributed/meritop/framework/frameworkhttp"
	"github.com/go-distributed/meritop/pkg/etcdutil"
	"github.com/go-distributed/meritop/pkg/topoutil"
)

func (f *framework) sendRequest(dr *dataRequest) {
	addr, err := etcdutil.GetAddress(f.etcdClient, f.name, dr.taskID)
	if err != nil {
		// TODO: We should handle network faults later by retrying
		f.log.Fatalf("getAddress(%d) failed: %v", dr.taskID, err)
		return
	}
	d, err := frameworkhttp.RequestData(addr, dr.req, f.taskID, dr.taskID, dr.epoch, f.log)
	if err != nil {
		f.log.Printf("RequestData failed: %v", err)
		return
	}
	f.dataRespChan <- d
}

func (f *framework) GetTaskData(taskID, epoch uint64, req string) ([]byte, error) {
	dataChan := make(chan []byte, 1)
	f.dataReqChan <- &dataRequest{
		taskID:   taskID,
		epoch:    epoch,
		req:      req,
		dataChan: dataChan,
	}

	d, ok := <-dataChan
	if !ok {
		// it assumes that only epoch mismatch will close the channel
		return nil, frameworkhttp.EpochMismatchError
	}
	return d, nil
}

// Framework http server for data request.
// Each request will be in the format: "/datareq?taskID=XXX&req=XXX".
// "taskID" indicates the requesting task. "req" is the meta data for this request.
// On success, it should respond with requested data in http body.
func (f *framework) startHTTP() {
	f.log.Printf("task %d serving http on %s\n", f.taskID, f.ln.Addr())
	// TODO: http server graceful shutdown
	handler := frameworkhttp.NewDataRequestHandler(f.log, f)
	if err := http.Serve(f.ln, handler); err != nil {
		f.log.Fatalf("http.Serve() returns error: %v\n", err)
	}
}

func (f *framework) sendResponse(dr *dataResponse) {
	dr.dataChan <- dr.data
}

func (f *framework) handleDataReq(dr *dataRequest) {
	var data []byte
	switch {
	case topoutil.IsParent(f.topology, dr.epoch, dr.taskID):
		data = f.task.ServeAsChild(dr.taskID, dr.req)
	case topoutil.IsChild(f.topology, dr.epoch, dr.taskID):
		data = f.task.ServeAsParent(dr.taskID, dr.req)
	default:
		f.log.Panic("unexpected")
	}
	// Getting the data from task could take a long time. We need to let
	// the response-to-send go through event loop to check epoch.
	f.dataRespToSendChan <- &dataResponse{
		taskID:   dr.taskID,
		epoch:    dr.epoch,
		req:      dr.req,
		data:     data,
		dataChan: dr.dataChan,
	}
}

func (f *framework) handleDataResp(resp *frameworkhttp.DataResponse) {
	switch {
	case topoutil.IsParent(f.topology, resp.Epoch, resp.TaskID):
		f.task.ParentDataReady(resp.TaskID, resp.Req, resp.Data)
	case topoutil.IsChild(f.topology, resp.Epoch, resp.TaskID):
		f.task.ChildDataReady(resp.TaskID, resp.Req, resp.Data)
	default:
		f.log.Panic("unexpected")
	}
}
<commit_msg>client: logging epoch mismatch error<commit_after>package framework

import (
	"net/http"

	"github.com/go-distributed/meritop/framework/frameworkhttp"
	"github.com/go-distributed/meritop/pkg/etcdutil"
	"github.com/go-distributed/meritop/pkg/topoutil"
)

func (f *framework) sendRequest(dr *dataRequest) {
	addr, err := etcdutil.GetAddress(f.etcdClient, f.name, dr.taskID)
	if err != nil {
		// TODO: We should handle network faults later by retrying
		f.log.Fatalf("getAddress(%d) failed: %v", dr.taskID, err)
		return
	}
	d, err := frameworkhttp.RequestData(addr, dr.req, f.taskID, dr.taskID, dr.epoch, f.log)
	if err != nil {
		if err != frameworkhttp.EpochMismatchError {
			f.log.Printf("Epoch mismatch error from server")
			return
		}
		f.log.Printf("RequestData failed: %v", err)
		return
	}
	f.dataRespChan <- d
}

func (f *framework) GetTaskData(taskID, epoch uint64, req string) ([]byte, error) {
	dataChan := make(chan []byte, 1)
	f.dataReqChan <- &dataRequest{
		taskID:   taskID,
		epoch:    epoch,
		req:      req,
		dataChan: dataChan,
	}

	d, ok := <-dataChan
	if !ok {
		// it assumes that only epoch mismatch will close the channel
		return nil, frameworkhttp.EpochMismatchError
	}
	return d, nil
}

// Framework http server for data request.
// Each request will be in the format: "/datareq?taskID=XXX&req=XXX".
// "taskID" indicates the requesting task. "req" is the meta data for this request.
// On success, it should respond with requested data in http body.
func (f *framework) startHTTP() {
	f.log.Printf("task %d serving http on %s\n", f.taskID, f.ln.Addr())
	// TODO: http server graceful shutdown
	handler := frameworkhttp.NewDataRequestHandler(f.log, f)
	if err := http.Serve(f.ln, handler); err != nil {
		f.log.Fatalf("http.Serve() returns error: %v\n", err)
	}
}

func (f *framework) sendResponse(dr *dataResponse) {
	dr.dataChan <- dr.data
}

func (f *framework) handleDataReq(dr *dataRequest) {
	var data []byte
	switch {
	case topoutil.IsParent(f.topology, dr.epoch, dr.taskID):
		data = f.task.ServeAsChild(dr.taskID, dr.req)
	case topoutil.IsChild(f.topology, dr.epoch, dr.taskID):
		data = f.task.ServeAsParent(dr.taskID, dr.req)
	default:
		f.log.Panic("unexpected")
	}
	// Getting the data from task could take a long time. We need to let
	// the response-to-send go through event loop to check epoch.
	f.dataRespToSendChan <- &dataResponse{
		taskID:   dr.taskID,
		epoch:    dr.epoch,
		req:      dr.req,
		data:     data,
		dataChan: dr.dataChan,
	}
}

func (f *framework) handleDataResp(resp *frameworkhttp.DataResponse) {
	switch {
	case topoutil.IsParent(f.topology, resp.Epoch, resp.TaskID):
		f.task.ParentDataReady(resp.TaskID, resp.Req, resp.Data)
	case topoutil.IsChild(f.topology, resp.Epoch, resp.TaskID):
		f.task.ChildDataReady(resp.TaskID, resp.Req, resp.Data)
	default:
		f.log.Panic("unexpected")
	}
}
<|endoftext|>


<commit_before>package getjob

import (
	"errors"
	"html/template"
	"net/http"
	"strconv"

	"github.com/concourse/atc"
	"github.com/concourse/atc/db"
	"github.com/concourse/atc/web/group"
	"github.com/concourse/atc/web/pagination"
	"github.com/pivotal-golang/lager"
)

type BuildWithInputsOutputs struct {
	Build   db.Build
	Inputs  []db.BuildInput
	Outputs []db.BuildOutput
}

type server struct {
	logger lager.Logger

	db       db.DB
	configDB db.ConfigDB

	template *template.Template
}

func NewServer(logger lager.Logger, template *template.Template) *server {
	return &server{
		logger: logger,

		template: template,
	}
}

type TemplateData struct {
	Job    atc.JobConfig
	DBJob  db.SavedJob
	Builds []BuildWithInputsOutputs

	GroupStates []group.State

	CurrentBuild db.Build
	PipelineName string

	PaginationData pagination.PaginationData
}

//go:generate counterfeiter . JobDB

type JobDB interface {
	GetConfig() (atc.Config, db.ConfigVersion, error)
	GetJob(string) (db.SavedJob, error)
	GetCurrentBuild(job string) (db.Build, error)
	GetPipelineName() string
	GetBuildResources(buildID int) ([]db.BuildInput, []db.BuildOutput, error)
}

//go:generate counterfeiter . JobBuildsPaginator

type JobBuildsPaginator interface {
	PaginateJobBuilds(job string, startingJobBuildID int, newerJobBuilds bool) ([]db.Build, pagination.PaginationData, error)
}

var ErrJobConfigNotFound = errors.New("could not find job")
var Err = errors.New("could not find job")

func FetchTemplateData(jobDB JobDB, paginator JobBuildsPaginator, jobName string, startingJobBuildID int, resultsGreaterThanStartingID bool) (TemplateData, error) {
	config, _, err := jobDB.GetConfig()
	if err != nil {
		return TemplateData{}, err
	}

	job, found := config.Jobs.Lookup(jobName)
	if !found {
		return TemplateData{}, ErrJobConfigNotFound
	}

	bs, paginationData, err := paginator.PaginateJobBuilds(job.Name, startingJobBuildID, resultsGreaterThanStartingID)
	if err != nil {
		return TemplateData{}, err
	}

	var bsr []BuildWithInputsOutputs

	for _, build := range bs {
		inputs, outputs, err := jobDB.GetBuildResources(build.ID)
		if err != nil {
			return TemplateData{}, err
		}

		bsr = append(bsr, BuildWithInputsOutputs{
			Build:   build,
			Inputs:  inputs,
			Outputs: outputs,
		})
	}

	currentBuild, err := jobDB.GetCurrentBuild(job.Name)
	if err != nil {
		currentBuild.Status = db.StatusPending
	}

	dbJob, err := jobDB.GetJob(job.Name)
	if err != nil {
		return TemplateData{}, err
	}

	return TemplateData{
		Job:            job,
		DBJob:          dbJob,
		Builds:         bsr,
		PaginationData: paginationData,

		GroupStates: group.States(config.Groups, func(g atc.GroupConfig) bool {
			for _, groupJob := range g.Jobs {
				if groupJob == job.Name {
					return true
				}
			}

			return false
		}),

		CurrentBuild: currentBuild,
		PipelineName: jobDB.GetPipelineName(),
	}, nil
}

func (server *server) GetJob(pipelineDB db.PipelineDB) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log := server.logger.Session("job")
		jobName := r.FormValue(":job")
		if len(jobName) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		startingID, parseErr := strconv.Atoi(r.FormValue("startingID"))
		if parseErr != nil {
			log.Info("cannot-parse-startingID-to-int", lager.Data{"startingID": r.FormValue("startingID")})
			startingID = 0
		}

		resultsGreaterThanStartingID, parseErr := strconv.ParseBool(r.FormValue("resultsGreaterThanStartingID"))
		if parseErr != nil {
			resultsGreaterThanStartingID = false
			log.Info("cannot-parse-resultsGreaterThanStartingID-to-bool", lager.Data{"resultsGreaterThanStartingID": r.FormValue("resultsGreaterThanStartingID")})
		}

		templateData, err := FetchTemplateData(
			pipelineDB,
			Paginator{
				PaginatorDB: pipelineDB,
			},
			jobName,
			startingID,
			resultsGreaterThanStartingID,
		)
		switch err {
		case ErrJobConfigNotFound:
			log.Error("could-not-find-job-in-config", ErrJobConfigNotFound, lager.Data{
				"job": jobName,
			})
			w.WriteHeader(http.StatusNotFound)
			return
		case nil:
			break
		default:
			log.Error("failed-to-build-template-data", err, lager.Data{
				"job": jobName,
			})
			http.Error(w, "failed to fetch job", http.StatusInternalServerError)
			return
		}

		err = server.template.Execute(w, templateData)
		if err != nil {
			log.Fatal("failed-to-task-template", err, lager.Data{
				"template-data": templateData,
			})
		}
	})
}
<commit_msg>Reduce frequency of errors logged.<commit_after>package getjob

import (
	"errors"
	"html/template"
	"net/http"
	"strconv"

	"github.com/concourse/atc"
	"github.com/concourse/atc/db"
	"github.com/concourse/atc/web/group"
	"github.com/concourse/atc/web/pagination"
	"github.com/pivotal-golang/lager"
)

type BuildWithInputsOutputs struct {
	Build   db.Build
	Inputs  []db.BuildInput
	Outputs []db.BuildOutput
}

type server struct {
	logger lager.Logger

	db       db.DB
	configDB db.ConfigDB

	template *template.Template
}

func NewServer(logger lager.Logger, template *template.Template) *server {
	return &server{
		logger: logger,

		template: template,
	}
}

type TemplateData struct {
	Job    atc.JobConfig
	DBJob  db.SavedJob
	Builds []BuildWithInputsOutputs

	GroupStates []group.State

	CurrentBuild db.Build
	PipelineName string

	PaginationData pagination.PaginationData
}

//go:generate counterfeiter . JobDB

type JobDB interface {
	GetConfig() (atc.Config, db.ConfigVersion, error)
	GetJob(string) (db.SavedJob, error)
	GetCurrentBuild(job string) (db.Build, error)
	GetPipelineName() string
	GetBuildResources(buildID int) ([]db.BuildInput, []db.BuildOutput, error)
}

//go:generate counterfeiter . JobBuildsPaginator

type JobBuildsPaginator interface {
	PaginateJobBuilds(job string, startingJobBuildID int, newerJobBuilds bool) ([]db.Build, pagination.PaginationData, error)
}

var ErrJobConfigNotFound = errors.New("could not find job")
var Err = errors.New("could not find job")

func FetchTemplateData(jobDB JobDB, paginator JobBuildsPaginator, jobName string, startingJobBuildID int, resultsGreaterThanStartingID bool) (TemplateData, error) {
	config, _, err := jobDB.GetConfig()
	if err != nil {
		return TemplateData{}, err
	}

	job, found := config.Jobs.Lookup(jobName)
	if !found {
		return TemplateData{}, ErrJobConfigNotFound
	}

	bs, paginationData, err := paginator.PaginateJobBuilds(job.Name, startingJobBuildID, resultsGreaterThanStartingID)
	if err != nil {
		return TemplateData{}, err
	}

	var bsr []BuildWithInputsOutputs

	for _, build := range bs {
		inputs, outputs, err := jobDB.GetBuildResources(build.ID)
		if err != nil {
			return TemplateData{}, err
		}

		bsr = append(bsr, BuildWithInputsOutputs{
			Build:   build,
			Inputs:  inputs,
			Outputs: outputs,
		})
	}

	currentBuild, err := jobDB.GetCurrentBuild(job.Name)
	if err != nil {
		currentBuild.Status = db.StatusPending
	}

	dbJob, err := jobDB.GetJob(job.Name)
	if err != nil {
		return TemplateData{}, err
	}

	return TemplateData{
		Job:            job,
		DBJob:          dbJob,
		Builds:         bsr,
		PaginationData: paginationData,

		GroupStates: group.States(config.Groups, func(g atc.GroupConfig) bool {
			for _, groupJob := range g.Jobs {
				if groupJob == job.Name {
					return true
				}
			}

			return false
		}),

		CurrentBuild: currentBuild,
		PipelineName: jobDB.GetPipelineName(),
	}, nil
}

func (server *server) GetJob(pipelineDB db.PipelineDB) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log := server.logger.Session("job")
		jobName := r.FormValue(":job")
		if len(jobName) == 0 {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		startingID, parseErr := strconv.Atoi(r.FormValue("startingID"))
		if parseErr != nil {
			log.Info("cannot-parse-startingID-to-int", lager.Data{"startingID": r.FormValue("startingID")})
			startingID = 0
		}

		resultsGreaterThanStartingID, parseErr := strconv.ParseBool(r.FormValue("resultsGreaterThanStartingID"))
		if parseErr != nil {
			resultsGreaterThanStartingID = false
			log.Info("cannot-parse-resultsGreaterThanStartingID-to-bool", lager.Data{"resultsGreaterThanStartingID": r.FormValue("resultsGreaterThanStartingID")})
		}

		templateData, err := FetchTemplateData(
			pipelineDB,
			Paginator{
				PaginatorDB: pipelineDB,
			},
			jobName,
			startingID,
			resultsGreaterThanStartingID,
		)
		switch err {
		case ErrJobConfigNotFound:
			log.Info("could-not-find-job-in-config", lager.Data{
				"job": jobName,
			})
			w.WriteHeader(http.StatusNotFound)
			return
		case nil:
			break
		default:
			log.Error("failed-to-build-template-data", err, lager.Data{
				"job": jobName,
			})
			http.Error(w, "failed to fetch job", http.StatusInternalServerError)
			return
		}

		err = server.template.Execute(w, templateData)
		if err != nil {
			log.Fatal("failed-to-task-template", err, lager.Data{
				"template-data": templateData,
			})
		}
	})
}
<|endoftext|>


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

package x509

import (
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"strings"

	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/types"
)

type Certificate struct {
	Issuer         string
	SerialNumber   string
	Subject        string
	SubjectKeyID   string
	AuthorityKeyID string
	Certificate    *x509.Certificate
}

func DecodeX509Certificate(pemCertificate string) (*Certificate, error) {
	block, _ := pem.Decode([]byte(pemCertificate))
	if block == nil {
		return nil, types.NewErrInvalidCertificate("Could not decode pem certificate")
	}

	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, types.NewErrInvalidCertificate(fmt.Sprintf("Could not parse certificate: %v", err.Error()))
	}

	certificate := Certificate{
		Issuer:         cert.Issuer.String(),
		SerialNumber:   cert.SerialNumber.String(),
		Subject:        cert.Subject.String(),
		SubjectKeyID:   BytesToHex(cert.SubjectKeyId),
		AuthorityKeyID: BytesToHex(cert.AuthorityKeyId),
		Certificate:    cert,
	}

	certificate = PatchCertificate(certificate)

	return &certificate, nil
}

// This function is needed to patch the Issuer/Subject(vid/pid) field of certificate to hex format.
// https://github.com/zigbee-alliance/distributed-compliance-ledger/issues/270
func PatchCertificate(certificate X509Certificate) X509Certificate {
	oldVIDKey := "1.3.6.1.4.1.37244.2.1"
	oldPIDKey := "1.3.6.1.4.1.37244.2.2"

	newVIDKey := "vid"
	newPIDKey := "pid"

	issuer := certificate.Issuer
	issuer = FormatOID(issuer, oldVIDKey, newVIDKey)
	issuer = FormatOID(issuer, oldPIDKey, newPIDKey)

	subject := certificate.Subject
	subject = FormatOID(subject, oldVIDKey, newVIDKey)
	subject = FormatOID(subject, oldPIDKey, newPIDKey)

	certificate.Issuer = issuer
	certificate.Subject = subject

	return certificate
}

func FormatOID(header, oldKey, newKey string) string {
	subjectValues := strings.Split(header, ",")

	// When translating a string number into a hexadecimal number,
	// we must take 8 numbers of this string number from the end so that it needs to fit into an integer number.
	hexStringIntegerLength := 8
	for index, value := range subjectValues {
		if strings.HasPrefix(value, oldKey) {
			// get value from header
			value = value[len(value)-hexStringIntegerLength:]

			decoded, _ := hex.DecodeString(value)

			subjectValues[index] = fmt.Sprintf("%s=0x%s", newKey, decoded)
		}
	}

	return strings.Join(subjectValues, ",")
}

func BytesToHex(bytes []byte) string {
	if bytes == nil {
		return ""
	}

	bytesHex := make([]string, len(bytes))
	for i, b := range bytes {
		bytesHex[i] = fmt.Sprintf("%X", b)
	}

	return strings.Join(bytesHex, ":")
}

func (c Certificate) Verify(parent *Certificate) error {
	roots := x509.NewCertPool()
	roots.AddCert(parent.Certificate)

	opts := x509.VerifyOptions{Roots: roots}

	if _, err := c.Certificate.Verify(opts); err != nil {
		return types.NewErrInvalidCertificate(fmt.Sprintf("Certificate verification failed. Error: %v", err))
	}

	return nil
}

func (c Certificate) IsSelfSigned() bool {
	if len(c.AuthorityKeyID) > 0 {
		return c.Issuer == c.Subject && c.AuthorityKeyID == c.SubjectKeyID
	}

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

package x509

import (
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"strings"

	"github.com/zigbee-alliance/distributed-compliance-ledger/x/pki/types"
)

type Certificate struct {
	Issuer         string
	SerialNumber   string
	Subject        string
	SubjectKeyID   string
	AuthorityKeyID string
	Certificate    *x509.Certificate
}

func DecodeX509Certificate(pemCertificate string) (*Certificate, error) {
	block, _ := pem.Decode([]byte(pemCertificate))
	if block == nil {
		return nil, types.NewErrInvalidCertificate("Could not decode pem certificate")
	}

	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, types.NewErrInvalidCertificate(fmt.Sprintf("Could not parse certificate: %v", err.Error()))
	}

	certificate := Certificate{
		Issuer:         cert.Issuer.String(),
		SerialNumber:   cert.SerialNumber.String(),
		Subject:        cert.Subject.String(),
		SubjectKeyID:   BytesToHex(cert.SubjectKeyId),
		AuthorityKeyID: BytesToHex(cert.AuthorityKeyId),
		Certificate:    cert,
	}

	certificate = PatchCertificate(certificate)

	return &certificate, nil
}

// This function is needed to patch the Issuer/Subject(vid/pid) field of certificate to hex format.
// https://github.com/zigbee-alliance/distributed-compliance-ledger/issues/270
func PatchCertificate(certificate Certificate) Certificate {
	oldVIDKey := "1.3.6.1.4.1.37244.2.1"
	oldPIDKey := "1.3.6.1.4.1.37244.2.2"

	newVIDKey := "vid"
	newPIDKey := "pid"

	issuer := certificate.Issuer
	issuer = FormatOID(issuer, oldVIDKey, newVIDKey)
	issuer = FormatOID(issuer, oldPIDKey, newPIDKey)

	subject := certificate.Subject
	subject = FormatOID(subject, oldVIDKey, newVIDKey)
	subject = FormatOID(subject, oldPIDKey, newPIDKey)

	certificate.Issuer = issuer
	certificate.Subject = subject

	return certificate
}

func FormatOID(header, oldKey, newKey string) string {
	subjectValues := strings.Split(header, ",")

	// When translating a string number into a hexadecimal number,
	// we must take 8 numbers of this string number from the end so that it needs to fit into an integer number.
	hexStringIntegerLength := 8
	for index, value := range subjectValues {
		if strings.HasPrefix(value, oldKey) {
			// get value from header
			value = value[len(value)-hexStringIntegerLength:]

			decoded, _ := hex.DecodeString(value)

			subjectValues[index] = fmt.Sprintf("%s=0x%s", newKey, decoded)
		}
	}

	return strings.Join(subjectValues, ",")
}

func BytesToHex(bytes []byte) string {
	if bytes == nil {
		return ""
	}

	bytesHex := make([]string, len(bytes))
	for i, b := range bytes {
		bytesHex[i] = fmt.Sprintf("%X", b)
	}

	return strings.Join(bytesHex, ":")
}

func (c Certificate) Verify(parent *Certificate) error {
	roots := x509.NewCertPool()
	roots.AddCert(parent.Certificate)

	opts := x509.VerifyOptions{Roots: roots}

	if _, err := c.Certificate.Verify(opts); err != nil {
		return types.NewErrInvalidCertificate(fmt.Sprintf("Certificate verification failed. Error: %v", err))
	}

	return nil
}

func (c Certificate) IsSelfSigned() bool {
	if len(c.AuthorityKeyID) > 0 {
		return c.Issuer == c.Subject && c.AuthorityKeyID == c.SubjectKeyID
	}

	return c.Issuer == c.Subject
}
<|endoftext|>


<commit_before>package index

import (
	"context"
	"database/sql"
	"time"

	"github.com/lib/pq"
	log "github.com/sirupsen/logrus"
)

const UpdateBatchSize = 1000

type FingerprintStore struct {
	db *sql.DB
}

func NewFingerprintStore(db *sql.DB) *FingerprintStore {
	return &FingerprintStore{
		db: db,
	}
}

func (s *FingerprintStore) GetMaxID(ctx context.Context) (int, error) {
	row := s.db.QueryRowContext(ctx, "SELECT max(id) FROM fingerprint")
	var id int
	err := row.Scan(&id)
	if err != nil {
		if err == sql.ErrNoRows {
			return 0, nil
		}
		return 0, err
	}
	return id, nil
}

func (s *FingerprintStore) GetNextFingerprints(ctx context.Context, lastID uint32, limit int) ([]FingerprintInfo, error) {
	rows, err := s.db.QueryContext(ctx, "SELECT id, acoustid_extract_query(fingerprint) FROM fingerprint WHERE id > $1 ORDER BY id LIMIT $2", lastID, limit)
	if err != nil {
		return nil, err
	}
	var fingerprints []FingerprintInfo
	for rows.Next() {
		var id uint32
		var hashes []uint32
		err = rows.Scan(&id, pq.Array(hashes))
		if err != nil {
			return nil, err
		}
		fingerprints = append(fingerprints, FingerprintInfo{ID: id, Hashes: hashes})
	}
	err = rows.Close()
	if err != nil {
		return nil, err
	}
	return fingerprints, nil
}

type UpdaterConfig struct {
	Database *DatabaseConfig
	Index    *IndexConfig
	Debug    bool
}

func NewUpdaterConfig() *UpdaterConfig {
	return &UpdaterConfig{
		Database: NewDatabaseConfig(),
		Index:    NewIndexConfig(),
	}
}

func RunUpdater(cfg *UpdaterConfig) {
	if cfg.Debug {
		log.SetLevel(log.DebugLevel)
	} else {
		log.SetLevel(log.InfoLevel)
	}

	db, err := sql.Open("postgres", cfg.Database.URL().String())
	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}
	defer db.Close()

	err = db.Ping()
	if err != nil {
		log.Fatalf("Can't ping the database: %v", err)
	}

	idx, err := ConnectWithConfig(context.Background(), cfg.Index)
	if err != nil {
		log.Fatalf("Failed to connect to index: %s", err)
	}
	defer idx.Close(context.Background())

	fp := NewFingerprintStore(db)

	var delay time.Duration

	for {
		if delay > 0 {
			log.Debugf("Sleeping for %v", delay)
			time.Sleep(delay)
		}

		ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
		defer cancel()

		lastID, err := GetLastFingerprintID(ctx, idx)
		if err != nil {
			log.Fatalf("Failed to get the last fingerprint ID in index: %s", err)
			delay = 10 * time.Second
			continue
		}

		fingerprints, err := fp.GetNextFingerprints(ctx, lastID, UpdateBatchSize)
		if err != nil {
			log.Fatalf("Failed to get the next fingerprints to import: %s", err)
			delay = 10 * time.Second
			continue
		}

		err = MultiInsert(ctx, idx, fingerprints)
		if err != nil {
			log.Fatalf("Failed to import the fingerprints: %s", err)
			delay = 10 * time.Second
			continue
		}

		fingerprintCount := len(fingerprints)
		if fingerprintCount == 0 {
			log.Infof("Added %d fingerprints", fingerprintCount)
		} else {
			log.Infof("Added %d fingerprints up to ID %d", fingerprintCount, fingerprints[fingerprintCount-1].ID)
		}

		if fingerprintCount == 0 {
			if delay > time.Second {
			    delay = time.Second
			} else {
				delay += 10 * time.Millisecond
			}
		} else {
			delay = 0
		}
	}
}
<commit_msg>Better delay handling<commit_after>package index

import (
	"context"
	"database/sql"
	"time"

	"github.com/lib/pq"
	log "github.com/sirupsen/logrus"
)

const UpdateBatchSize = 1000

type FingerprintStore struct {
	db *sql.DB
}

func NewFingerprintStore(db *sql.DB) *FingerprintStore {
	return &FingerprintStore{
		db: db,
	}
}

func (s *FingerprintStore) GetMaxID(ctx context.Context) (int, error) {
	row := s.db.QueryRowContext(ctx, "SELECT max(id) FROM fingerprint")
	var id int
	err := row.Scan(&id)
	if err != nil {
		if err == sql.ErrNoRows {
			return 0, nil
		}
		return 0, err
	}
	return id, nil
}

func (s *FingerprintStore) GetNextFingerprints(ctx context.Context, lastID uint32, limit int) ([]FingerprintInfo, error) {
	rows, err := s.db.QueryContext(ctx, "SELECT id, acoustid_extract_query(fingerprint) FROM fingerprint WHERE id > $1 ORDER BY id LIMIT $2", lastID, limit)
	if err != nil {
		return nil, err
	}
	var fingerprints []FingerprintInfo
	for rows.Next() {
		var id uint32
		var hashes []uint32
		err = rows.Scan(&id, pq.Array(hashes))
		if err != nil {
			return nil, err
		}
		fingerprints = append(fingerprints, FingerprintInfo{ID: id, Hashes: hashes})
	}
	err = rows.Close()
	if err != nil {
		return nil, err
	}
	return fingerprints, nil
}

type UpdaterConfig struct {
	Database *DatabaseConfig
	Index    *IndexConfig
	Debug    bool
}

func NewUpdaterConfig() *UpdaterConfig {
	return &UpdaterConfig{
		Database: NewDatabaseConfig(),
		Index:    NewIndexConfig(),
	}
}

func RunUpdater(cfg *UpdaterConfig) {
	if cfg.Debug {
		log.SetLevel(log.DebugLevel)
	} else {
		log.SetLevel(log.InfoLevel)
	}

	db, err := sql.Open("postgres", cfg.Database.URL().String())
	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}
	defer db.Close()

	err = db.Ping()
	if err != nil {
		log.Fatalf("Can't ping the database: %v", err)
	}

	idx, err := ConnectWithConfig(context.Background(), cfg.Index)
	if err != nil {
		log.Fatalf("Failed to connect to index: %s", err)
	}
	defer idx.Close(context.Background())

	fp := NewFingerprintStore(db)

	const MaxDelay = time.Minute
	var delay time.Duration

	for {
		if delay > 0 {
			if delay > MaxDelay {
				delay = MaxDelay
			}
			log.Debugf("Sleeping for %v", delay)
			time.Sleep(delay)
		}

		ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
		defer cancel()

		lastID, err := GetLastFingerprintID(ctx, idx)
		if err != nil {
			log.Fatalf("Failed to get the last fingerprint ID in index: %s", err)
			delay = MaxDelay
			continue
		}

		fingerprints, err := fp.GetNextFingerprints(ctx, lastID, UpdateBatchSize)
		if err != nil {
			log.Fatalf("Failed to get the next fingerprints to import: %s", err)
			delay = MaxDelay
			continue
		}

		err = MultiInsert(ctx, idx, fingerprints)
		if err != nil {
			log.Fatalf("Failed to import the fingerprints: %s", err)
			delay = MaxDelay
			continue
		}

		fingerprintCount := len(fingerprints)
		if fingerprintCount == 0 {
			log.Infof("Added %d fingerprints", fingerprintCount)
		} else {
			log.Infof("Added %d fingerprints up to ID %d", fingerprintCount, fingerprints[fingerprintCount-1].ID)
		}

		if fingerprintCount == 0 {
			delay += (delay * 10) / 100
		} else {
			delay = 0
		}
	}
}
<|endoftext|>


<commit_before>package softlayer

import (
	"errors"
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/softlayer/softlayer-go/services"
	"github.com/softlayer/softlayer-go/session"
)

func dataSourceSoftLayerImageTemplate() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceSoftLayerImageTemplateRead,

		// TODO: based on need add properties for visibility, type of image,
		// notes, size, shared on accounts if needed
		Schema: map[string]*schema.Schema{
			"id": {
				Description: "The internal id of the image template",
				Type:        schema.TypeInt,
				Computed:    true,
			},

			"name": {
				Description: "The name of this image template",
				Type:        schema.TypeString,
				Required:    true,
			},
		},
	}
}

func dataSourceSoftLayerImageTemplateRead(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetAccountService(sess)

	name := d.Get("name").(string)

	imageTemplates, err := service.
		Mask("id,name").
		GetBlockDeviceTemplateGroups()

	if err != nil {
		return fmt.Errorf("Error looking up image template [%s]: %s", name, err)
	}

	if len(imageTemplates) == 0 {
		return errors.New("The SoftLayer account has no image templates.")
	}

	for _, imageTemplate := range imageTemplates {
		if imageTemplate.Name != nil && *imageTemplate.Name == name {
			d.SetId(fmt.Sprintf("%d", *imageTemplate.Id))
			return nil
		}
	}

	return fmt.Errorf("Could not find image template with name [%s]", name)
}
<commit_msg>Make data source image template search among public images, too. Closes #28<commit_after>package softlayer

import (
	"errors"
	"fmt"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/softlayer/softlayer-go/filter"
	"github.com/softlayer/softlayer-go/services"
	"github.com/softlayer/softlayer-go/session"
)

func dataSourceSoftLayerImageTemplate() *schema.Resource {
	return &schema.Resource{
		Read: dataSourceSoftLayerImageTemplateRead,

		// TODO: based on need add properties for visibility, type of image,
		// notes, size, shared on accounts if needed
		Schema: map[string]*schema.Schema{
			"id": {
				Description: "The internal id of the image template",
				Type:        schema.TypeInt,
				Computed:    true,
			},

			"name": {
				Description: "The name of this image template",
				Type:        schema.TypeString,
				Required:    true,
			},
		},
	}
}

func dataSourceSoftLayerImageTemplateRead(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(*session.Session)
	service := services.GetAccountService(sess)

	name := d.Get("name").(string)

	imageTemplates, err := service.
		Mask("id,name").
		GetBlockDeviceTemplateGroups()
	if err != nil {
		return fmt.Errorf("Error looking up image template [%s]: %s", name, err)
	}

	if len(imageTemplates) == 0 {
		return errors.New("The SoftLayer account has no image templates.")
	}

	for _, imageTemplate := range imageTemplates {
		if imageTemplate.Name != nil && *imageTemplate.Name == name {
			d.SetId(fmt.Sprintf("%d", *imageTemplate.Id))
			return nil
		}
	}

	// Image not found among private nor shared images in the account.
	// Looking up in the public images
	templateService := services.GetVirtualGuestBlockDeviceTemplateGroupService(sess)
	imageTemplates, err = templateService.
		Mask("id,name").
		Filter(filter.Path("name").Eq(name).Build()).
		GetPublicImages()
	if err != nil {
		return fmt.Errorf("Error looking up image template [%s] among the public images: %s", name, err)
	}

	for _, imageTemplate := range imageTemplates {
		if imageTemplate.Name != nil && *imageTemplate.Name == name {
			d.SetId(fmt.Sprintf("%d", *imageTemplate.Id))
			return nil
		}
	}

	return fmt.Errorf("Could not find image template with name [%s]", name)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/andelf/go-curl"
	"github.com/nu7hatch/gouuid"
)

type Config struct {
	Location        string
	ChecksUrl       string
	MeasurementsUrl string
}

type Check struct {
	Id  string `json:"id"`
	Url string `json:"url"`
}

type Measurement struct {
	Check             Check   `json:"check"`
	Id                string  `json:"id"`
	Location          string  `json:"location"`
	T                 int     `json:"t"`
	ExitStatus        int     `json:"exit_status"`
	ConnectTime       float64 `json:"connect_time,omitempty"`
	StartTransferTime float64 `json:"starttransfer_time,omitempty"`
	LocalIp           string  `json:"local_ip,omitempty"`
	PrimaryIp         string  `json:"primary_ip,omitempty"`
	TotalTime         float64 `json:"total_time,omitempty"`
	HttpStatus        int     `json:"http_status,omitempty"`
	NameLookupTime    float64 `json:"namelookup_time,omitempty"`
}

func GetEnvWithDefault(env string, def string) string {
	tmp := os.Getenv(env)

	if tmp == "" {
		return def
	}

	return tmp
}

func (c *Check) Measure(config Config) Measurement {
	var m Measurement

	id, _ := uuid.NewV4()
	m.Id = id.String()
	m.Check = *c
	m.Location = config.Location

	easy := curl.EasyInit()
	defer easy.Cleanup()

	easy.Setopt(curl.OPT_URL, c.Url)

	// dummy func for curl output
	noOut := func(buf []byte, userdata interface{}) bool {
		return true
	}

	easy.Setopt(curl.OPT_WRITEFUNCTION, noOut)
	easy.Setopt(curl.OPT_CONNECTTIMEOUT, 10)
	easy.Setopt(curl.OPT_TIMEOUT, 10)

	now := time.Now()
	nanos := now.UnixNano()
	millis := nanos / 1000000

	m.T = int(millis)

	if err := easy.Perform(); err != nil {
		if e, ok := err.(curl.CurlError); ok {
			m.ExitStatus = (int(e))
			return m
		}
		os.Exit(1)
	}

	m.ExitStatus = 0
	http_status, _ := easy.Getinfo(curl.INFO_RESPONSE_CODE)
	m.HttpStatus = http_status.(int)

	connect_time, _ := easy.Getinfo(curl.INFO_CONNECT_TIME)
	m.ConnectTime = connect_time.(float64)

	namelookup_time, _ := easy.Getinfo(curl.INFO_NAMELOOKUP_TIME)
	m.NameLookupTime = namelookup_time.(float64)

	starttransfer_time, _ := easy.Getinfo(curl.INFO_STARTTRANSFER_TIME)
	m.StartTransferTime = starttransfer_time.(float64)

	total_time, _ := easy.Getinfo(curl.INFO_TOTAL_TIME)
	m.TotalTime = total_time.(float64)

	local_ip, _ := easy.Getinfo(curl.INFO_LOCAL_IP)
	m.LocalIp = local_ip.(string)

	primary_ip, _ := easy.Getinfo(curl.INFO_PRIMARY_IP)
	m.PrimaryIp = primary_ip.(string)

	return m
}

func MeasureLoop(config Config, checks chan Check, measurements chan Measurement) {
	for {
		c := <-checks
		m := c.Measure(config)

		measurements <- m
	}
}

func RecordLoop(config Config, measurements chan Measurement) {
	payload := make([]Measurement, 0, 100)
	for {
		m := <-measurements
		payload = append(payload, m)

		s, err := json.Marshal(&payload)
		if err != nil {
			panic(err)
		}

		body := bytes.NewBuffer(s)
		req, err := http.NewRequest("POST", config.MeasurementsUrl, body)
		if err != nil {
			panic(err)
		}

		req.Header.Add("Content-Type", "application/json")
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			panic(err)
		}
		resp.Body.Close()
		payload = make([]Measurement, 0, 100)

		fmt.Println(resp)
	}
}

func GetChecks(config Config) []Check {
	url := config.ChecksUrl

	res, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}

	var checks []Check
	err = json.Unmarshal(body, &checks)
	if err != nil {
		panic(err)
	}

	return checks
}

func main() {
	var config Config
	config.Location = GetEnvWithDefault("LOCATION", "undefined")
	config.ChecksUrl = GetEnvWithDefault("CHECKS_URL", "https://s3.amazonaws.com/canary-public-data/data.json")
	config.MeasurementsUrl = GetEnvWithDefault("MEASUREMENTS_URL", "http://localhost:5000/measurements")

	fmt.Printf("%s\n", config.MeasurementsUrl)

	check_list := GetChecks(config)

	checks := make(chan Check)
	measurements := make(chan Measurement)

	go MeasureLoop(config, checks, measurements)
	go RecordLoop(config, measurements)

	for {
		for _, c := range check_list {
			checks <- c
		}

		time.Sleep(1000 * time.Millisecond)
	}
}
<commit_msg>Revert pull request #33<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"time"

	"github.com/andelf/go-curl"
	"github.com/nu7hatch/gouuid"
)

type Config struct {
	Location        string
	ChecksUrl       string
	MeasurementsUrl string
}

type Check struct {
	Id  string `json:"id"`
	Url string `json:"url"`
}

type Measurement struct {
	Check             Check   `json:"check"`
	Id                string  `json:"id"`
	Location          string  `json:"location"`
	T                 int     `json:"t"`
	ExitStatus        int     `json:"exit_status"`
	ConnectTime       float64 `json:"connect_time,omitempty"`
	StartTransferTime float64 `json:"starttransfer_time,omitempty"`
	LocalIp           string  `json:"local_ip,omitempty"`
	PrimaryIp         string  `json:"primary_ip,omitempty"`
	TotalTime         float64 `json:"total_time,omitempty"`
	HttpStatus        int     `json:"http_status,omitempty"`
	NameLookupTime    float64 `json:"namelookup_time,omitempty"`
}

func GetEnvWithDefault(env string, def string) string {
	tmp := os.Getenv(env)

	if tmp == "" {
		return def
	}

	return tmp
}

func (c *Check) Measure(config Config) Measurement {
	var m Measurement

	id, _ := uuid.NewV4()
	m.Id = id.String()
	m.Check = *c
	m.Location = config.Location

	easy := curl.EasyInit()
	defer easy.Cleanup()

	easy.Setopt(curl.OPT_URL, c.Url)

	// dummy func for curl output
	noOut := func(buf []byte, userdata interface{}) bool {
		return true
	}

	easy.Setopt(curl.OPT_WRITEFUNCTION, noOut)
	easy.Setopt(curl.OPT_CONNECTTIMEOUT, 10)
	easy.Setopt(curl.OPT_TIMEOUT, 10)

	now := time.Now()
	m.T = int(now.Unix())

	if err := easy.Perform(); err != nil {
		if e, ok := err.(curl.CurlError); ok {
			m.ExitStatus = (int(e))
			return m
		}
		os.Exit(1)
	}

	m.ExitStatus = 0
	http_status, _ := easy.Getinfo(curl.INFO_RESPONSE_CODE)
	m.HttpStatus = http_status.(int)

	connect_time, _ := easy.Getinfo(curl.INFO_CONNECT_TIME)
	m.ConnectTime = connect_time.(float64)

	namelookup_time, _ := easy.Getinfo(curl.INFO_NAMELOOKUP_TIME)
	m.NameLookupTime = namelookup_time.(float64)

	starttransfer_time, _ := easy.Getinfo(curl.INFO_STARTTRANSFER_TIME)
	m.StartTransferTime = starttransfer_time.(float64)

	total_time, _ := easy.Getinfo(curl.INFO_TOTAL_TIME)
	m.TotalTime = total_time.(float64)

	local_ip, _ := easy.Getinfo(curl.INFO_LOCAL_IP)
	m.LocalIp = local_ip.(string)

	primary_ip, _ := easy.Getinfo(curl.INFO_PRIMARY_IP)
	m.PrimaryIp = primary_ip.(string)

	return m
}

func MeasureLoop(config Config, checks chan Check, measurements chan Measurement) {
	for {
		c := <-checks
		m := c.Measure(config)

		measurements <- m
	}
}

func RecordLoop(config Config, measurements chan Measurement) {
	payload := make([]Measurement, 0, 100)
	for {
		m := <-measurements
		payload = append(payload, m)

		s, err := json.Marshal(&payload)
		if err != nil {
			panic(err)
		}

		body := bytes.NewBuffer(s)
		req, err := http.NewRequest("POST", config.MeasurementsUrl, body)
		if err != nil {
			panic(err)
		}

		req.Header.Add("Content-Type", "application/json")
		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			panic(err)
		}
		resp.Body.Close()
		payload = make([]Measurement, 0, 100)

		fmt.Println(resp)
	}
}

func GetChecks(config Config) []Check {
	url := config.ChecksUrl

	res, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}

	var checks []Check
	err = json.Unmarshal(body, &checks)
	if err != nil {
		panic(err)
	}

	return checks
}

func main() {
	var config Config
	config.Location = GetEnvWithDefault("LOCATION", "undefined")
	config.ChecksUrl = GetEnvWithDefault("CHECKS_URL", "https://s3.amazonaws.com/canary-public-data/data.json")
	config.MeasurementsUrl = GetEnvWithDefault("MEASUREMENTS_URL", "http://localhost:5000/measurements")

	fmt.Printf("%s\n", config.MeasurementsUrl)

	check_list := GetChecks(config)

	checks := make(chan Check)
	measurements := make(chan Measurement)

	go MeasureLoop(config, checks, measurements)
	go RecordLoop(config, measurements)

	for {
		for _, c := range check_list {
			checks <- c
		}

		time.Sleep(1000 * time.Millisecond)
	}
}
<|endoftext|>


<commit_before>// Copyright 2010 Bill Burdick. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
package seq

import "fmt"
import "io"
import "os"
import "container/vector"

type Element interface{}
type SeqChan chan Element
type Sequence func()SeqChan

func IsSeq(s interface{}) bool {
	_, test := s.(Sequence)
	return test
}

// f must behave properly when the channel is closed, so that IsEmpty and First work properly
func Seq(f func(c SeqChan)) Sequence {
	return func() SeqChan {
		c := make(SeqChan)
		go func() {
			defer close(c)
			f(c)
		}()
		return c
	}
}

func From(el... interface{}) Sequence {
	return Seq(func(c SeqChan) {Output(c, el...)})
}

func Output(c SeqChan, el... interface{}) {
	for _, v := range el {
		c <- v
	}
}

func (s Sequence) First() Element {
	c := s()
	defer close(c)
	return <- c
}

func (s Sequence) Rest() Sequence {
	return func()SeqChan{
		c := s()
		<- c
		return c
	}
}

func (s Sequence) AddFirst(els... interface{}) Sequence {
	return Seq(func(c SeqChan){
		for el := range els {
			c <- el
		}
		s.Output(c)
	})
}

func (s Sequence) AddLast(els... interface{}) Sequence {
	return Seq(func(c SeqChan){
		s.Output(c)
		for el := range els {
			c <- el
		}
	})
}

func (s Sequence) IsEmpty() bool {
	c := s()
	<- c
	result := closed(c)
	if !result {defer close(c)}
	return result
}

func (s Sequence) Append(s2 Sequence) Sequence {
	return Seq(func(c SeqChan){
		s.Output(c)
		s2.Output(c)
	})
}

func (s Sequence) Len() int {
	len := 0
	c := s()
	for !closed(c) {
		<- c
		len++
	}
	return len - 1
}

func (s Sequence) Output(c chan Element) {
	for el := range s() {
		c <- el
	}
}

func Upto(limit int) Sequence {
	return Seq(func(c SeqChan) {
		for i := 0; i < limit; i++ {
			c <- i
		}
	})
}

func (s Sequence) Filter(filter func(e Element)bool) Sequence {
	return Seq(func(c SeqChan){
		for el := range s() {
			if filter(el) {
				c <- el
			}
		}
	})
}

func (s Sequence) Do(f func(el Element)) {
	for v := range s() {
		f(v)
	}
}

func (s Sequence) Map(f func(i Element)Element) Sequence {
	return Seq(func(c SeqChan) {
		for v := range s() {
			c <- f(v)
		}
	})
}

func (s Sequence) FlatMap(f func(i Element) Sequence) Sequence {
	return Seq(func(c SeqChan) {
		for v := range s() {
			for sub := range f(v)() {
				c <- sub
			}
		}
	})
}

func (s Sequence) Fold(init Element, f func(acc, el Element)Element) Element {
	for el := range s() {
		init = f(init, el)
	}
	return init
}

//maybe convert this to use an accumulator instead of append?
func (s Sequence) Combinations(number int) Sequence {
	if number == 0 || s.IsEmpty() {return From(From())}
	return s.Rest().Combinations(number - 1).Map(func(el Element)Element{
		return el.(Sequence).AddFirst(s.First())
	}).Append(s.Rest().Combinations(number))
}

//returns the product of the Sequences contained in sequences
func (sequences Sequence) Product() Sequence {
	return sequences.Fold(From(From()), func(acc, el Element)Element{
		return el.(Sequence).peelOnto(acc.(Sequence))
	}).(Sequence)
}

func (s Sequence) peelOnto(seq Sequence) Sequence {
	return seq.FlatMap(func(old Element)Sequence{
		return s.Map(func(i Element) Element {
			return old.(Sequence).Append(From(i))
		})
	})
}

func (s Sequence) Reify() Sequence {
	vec := vector.Vector(make([]interface{}, 0, 128))
	for v := range s() {
		sv, is := v.(Sequence)
		if is {
			vec.Push(sv.Reify())
		} else {
			vec.Push(v)
		}
	}
	return From([]interface{}(vec)...)
}

func (s Sequence) ToVector() Vector {
	vec := vector.Vector(make([]interface{}, 0, 128))
	for v := range s() {
		sv, is := v.(Sequence)
		if is {
			vec.Push(sv.ToVector())
		} else {
			vec.Push(v)
		}
	}
	return vec
}

func (s Sequence) Prettyln(names map[Element]string, writer... io.Writer) {
	if len(writer) == 0 {
		writer = []io.Writer{os.Stdout}
	}
	s.Pretty(names, writer...)
	fmt.Fprintln(writer[0])
}
func (s Sequence) Pretty(names map[Element]string, writer... io.Writer) {
	if len(writer) == 0 {
		writer = []io.Writer{os.Stdout}
	}
	s.prettyLevel(0, names, writer[0])
}

//This is pretty ugly :)
func (s Sequence) prettyLevel(level int, names map[Element]string, w io.Writer) {
	name, hasName := names[s]
	if hasName {
		fmt.Fprint(w, name)
	} else {
		c := s()
		fmt.Fprintf(w, "%*s%s", level, "", "[")
		first := true
		innerSeq := false
		named := false
		for v := range c {
			_, named = names[v]
			_,innerSeq = v.(Sequence)
			if first {
				first = false
				if !named && innerSeq {
					fmt.Fprintln(w)
				}
			} else if !named && innerSeq {
				fmt.Fprintln(w, ",")
			} else {
				fmt.Fprint(w, ", ")
			}
			if innerSeq {
				v.(Sequence).prettyLevel(level + 4, names, w)
			} else {
				fmt.Fprintf(w, "%v", v)
			}
		}
		if innerSeq {
			if !named {
				fmt.Fprintf(w, "\n%*s", level, "")
			}
		}
		fmt.Fprintf(w, "]")
	}
}
<commit_msg>added some defers<commit_after>// Copyright 2010 Bill Burdick. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
package seq

import "fmt"
import "io"
import "os"
import "container/vector"

type Element interface{}
type SeqChan chan Element
type Sequence func()SeqChan

func IsSeq(s interface{}) bool {
	_, test := s.(Sequence)
	return test
}

// f must behave properly when the channel is closed, so that IsEmpty and First work properly
func Seq(f func(c SeqChan)) Sequence {
	return func() SeqChan {
		c := make(SeqChan)
		go func() {
			defer close(c)
			f(c)
		}()
		return c
	}
}

func From(el... interface{}) Sequence {
	return Seq(func(c SeqChan) {Output(c, el...)})
}

func Output(c SeqChan, el... interface{}) {
	for _, v := range el {
		c <- v
	}
}

func (s Sequence) First() Element {
	c := s()
	defer close(c)
	return <- c
}

func (s Sequence) Rest() Sequence {
	return func()SeqChan{
		c := s()
		<- c
		return c
	}
}

func (s Sequence) AddFirst(els... interface{}) Sequence {
	return Seq(func(c SeqChan){
		for el := range els {
			c <- el
		}
		s.Output(c)
	})
}

func (s Sequence) AddLast(els... interface{}) Sequence {
	return Seq(func(c SeqChan){
		s.Output(c)
		for el := range els {
			c <- el
		}
	})
}

func (s Sequence) IsEmpty() bool {
	c := s()
	<- c
	result := closed(c)
	defer close(c)
	return result
}

func (s Sequence) Append(s2 Sequence) Sequence {
	return Seq(func(c SeqChan){
		s.Output(c)
		s2.Output(c)
	})
}

func (s Sequence) Len() int {
	len := 0
	c := s()
	defer close(c)
	for !closed(c) {
		<- c
		len++
	}
	return len - 1
}

func (s Sequence) Output(c chan Element) {
	for el := range s() {
		c <- el
	}
}

func Upto(limit int) Sequence {
	return Seq(func(c SeqChan) {
		for i := 0; i < limit; i++ {
			c <- i
		}
	})
}

func (s Sequence) Filter(filter func(e Element)bool) Sequence {
	return Seq(func(c SeqChan){
		for el := range s() {
			if filter(el) {
				c <- el
			}
		}
	})
}

func (s Sequence) Do(f func(el Element)) {
	for v := range s() {
		f(v)
	}
}

func (s Sequence) Map(f func(i Element)Element) Sequence {
	return Seq(func(c SeqChan) {
		for v := range s() {
			c <- f(v)
		}
	})
}

func (s Sequence) FlatMap(f func(i Element) Sequence) Sequence {
	return Seq(func(c SeqChan) {
		for v := range s() {
			for sub := range f(v)() {
				c <- sub
			}
		}
	})
}

func (s Sequence) Fold(init Element, f func(acc, el Element)Element) Element {
	for el := range s() {
		init = f(init, el)
	}
	return init
}

//maybe convert this to use an accumulator instead of append?
func (s Sequence) Combinations(number int) Sequence {
	if number == 0 || s.IsEmpty() {return From(From())}
	return s.Rest().Combinations(number - 1).Map(func(el Element)Element{
		return el.(Sequence).AddFirst(s.First())
	}).Append(s.Rest().Combinations(number))
}

//returns the product of the Sequences contained in sequences
func (sequences Sequence) Product() Sequence {
	return sequences.Fold(From(From()), func(acc, el Element)Element{
		return el.(Sequence).peelOnto(acc.(Sequence))
	}).(Sequence)
}

func (s Sequence) peelOnto(seq Sequence) Sequence {
	return seq.FlatMap(func(old Element)Sequence{
		return s.Map(func(i Element) Element {
			return old.(Sequence).Append(From(i))
		})
	})
}

func (s Sequence) Reify() Sequence {
	vec := vector.Vector(make([]interface{}, 0, 128))
	for v := range s() {
		sv, is := v.(Sequence)
		if is {
			vec.Push(sv.Reify())
		} else {
			vec.Push(v)
		}
	}
	return From([]interface{}(vec)...)
}

func (s Sequence) ToVector() Vector {
	vec := vector.Vector(make([]interface{}, 0, 128))
	for v := range s() {
		sv, is := v.(Sequence)
		if is {
			vec.Push(sv.ToVector())
		} else {
			vec.Push(v)
		}
	}
	return vec
}

func (s Sequence) Prettyln(names map[Element]string, writer... io.Writer) {
	if len(writer) == 0 {
		writer = []io.Writer{os.Stdout}
	}
	s.Pretty(names, writer...)
	fmt.Fprintln(writer[0])
}
func (s Sequence) Pretty(names map[Element]string, writer... io.Writer) {
	if len(writer) == 0 {
		writer = []io.Writer{os.Stdout}
	}
	s.prettyLevel(0, names, writer[0])
}

//This is pretty ugly :)
func (s Sequence) prettyLevel(level int, names map[Element]string, w io.Writer) {
	name, hasName := names[s]
	if hasName {
		fmt.Fprint(w, name)
	} else {
		c := s()
		fmt.Fprintf(w, "%*s%s", level, "", "[")
		first := true
		innerSeq := false
		named := false
		for v := range c {
			_, named = names[v]
			_,innerSeq = v.(Sequence)
			if first {
				first = false
				if !named && innerSeq {
					fmt.Fprintln(w)
				}
			} else if !named && innerSeq {
				fmt.Fprintln(w, ",")
			} else {
				fmt.Fprint(w, ", ")
			}
			if innerSeq {
				v.(Sequence).prettyLevel(level + 4, names, w)
			} else {
				fmt.Fprintf(w, "%v", v)
			}
		}
		if innerSeq {
			if !named {
				fmt.Fprintf(w, "\n%*s", level, "")
			}
		}
		fmt.Fprintf(w, "]")
	}
}
<|endoftext|>


<commit_before>package service

import (
	"flag"
	"os"

	"github.com/kardianos/service"
	"github.com/mholt/caddy"
)

var (
	logger       service.Logger
	name, action string
)

func init() {
	flag.StringVar(&name, "name", "Caddy", "Caddy's service name")
	flag.StringVar(&action, "service", "", "install, uninstall, start, stop, restart")

	caddy.RegisterEventHook("service", hook)
}

type program struct{}

func (p *program) Start(s service.Service) error {
	// Get Caddyfile input
	caddyfile, err := caddy.LoadCaddyfile(flag.Lookup("type").Value.String())
	if err != nil {
		return err
	}

	// Start your engines
	_, err = caddy.Start(caddyfile)
	if err != nil {
		return err
	}

	return nil
}

func (p *program) Stop(s service.Service) error {
	return caddy.Stop()
}

func hook(event caddy.EventName) error {
	if event != caddy.StartupEvent {
		return nil
	}

	flags := []string{
		"conf",
		"type",
		"log",
		"http2",
		"email",
		"grace",
		"cpu",
	}

	config := &service.Config{
		Name:        name,
		DisplayName: name,
		Description: "Caddy's service",
		Arguments:   []string{},
	}

	for k := range flags {
		f := flag.Lookup(flags[k])
		if f.Value.String() != f.DefValue {
			config.Arguments = append(config.Arguments, "-"+flags[k], f.Value.String())
		}
	}

	s, err := service.New(&program{}, config)
	if err != nil {
		return err
	}

	if action != "" {
		err = service.Control(s, action)
		if err != nil {
			return err
		}
		os.Exit(0)
	}

	err = s.Run()
	if err != nil {
		return err
	}

	os.Exit(0)
	return nil
}
<commit_msg>add all flags. see #1<commit_after>package service

import (
	"flag"
	"os"

	"github.com/kardianos/service"
	"github.com/mholt/caddy"
)

var (
	logger       service.Logger
	name, action string
)

func init() {
	flag.StringVar(&name, "name", "Caddy", "Caddy's service name")
	flag.StringVar(&action, "service", "", "install, uninstall, start, stop, restart")

	caddy.RegisterEventHook("service", hook)
}

type program struct{}

func (p *program) Start(s service.Service) error {
	// Get Caddyfile input
	caddyfile, err := caddy.LoadCaddyfile(flag.Lookup("type").Value.String())
	if err != nil {
		return err
	}

	// Start your engines
	_, err = caddy.Start(caddyfile)
	if err != nil {
		return err
	}

	return nil
}

func (p *program) Stop(s service.Service) error {
	return caddy.Stop()
}

func hook(event caddy.EventName) error {
	if event != caddy.StartupEvent {
		return nil
	}

	config := &service.Config{
		Name:        name,
		DisplayName: name,
		Description: "Caddy's service",
		Arguments:   []string{},
	}

	flag.VisitAll(func(f *flag.Flag) {
		// ignore our own flags
		if f.Name == "service" || f.Name == "name" {
			return
		}

		// ignore flags with default value
		if f.Value.String() == f.DefValue {
			return
		}

		config.Arguments = append(config.Arguments, "-"+f.Name, f.Value.String())
	})

	s, err := service.New(&program{}, config)
	if err != nil {
		return err
	}

	if action != "" {
		err = service.Control(s, action)
		if err != nil {
			return err
		}
		os.Exit(0)
	}

	err = s.Run()
	if err != nil {
		return err
	}

	os.Exit(0)
	return nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package yarpcconfig implements a generic configuration system that may be
// used to build YARPC Dispatchers from configurations specified in different
// markup formats.
//
// Usage
//
// To build a Dispatcher, first create a new Configurator. This object will be
// responsible for loading your configuration. It does not yet know about the
// different transports, peer lists, etc. that you want to use. You can inform
// the Configurator about the different transports, peer lists, etc. by
// registering them using RegisterTransport, RegisterPeerChooser,
// RegisterPeerList, and RegisterPeerListUpdater.
//
// 	cfg := config.New()
// 	cfg.MustRegisterTransport(http.TransportSpec())
// 	cfg.MustRegisterPeerList(roundrobin.Spec())
//
// This object is re-usable and may be stored as a singleton in your
// application. Custom transports, peer lists, and peer list updaters may be
// integrated with the configuration system by registering more
// TransportSpecs, PeerChooserSpecs, PeerListSpecs, and PeerListUpdaterSpecs
// with it.
//
// Use LoadConfigFromYAML to load a yarpc.Config from YAML and pass that to
// yarpc.NewDispatcher.
//
// 	c, err := cfg.LoadConfigFromYAML("myservice", yamlConfig)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
// 	dispatcher := yarpc.NewDispatcher(c)
//
// If you have already parsed your configuration from a different format, pass
// the parsed data to LoadConfig instead.
//
// 	var m map[string]interface{} = ...
// 	c, err := cfg.LoadConfig("myservice", m)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
// 	dispatcher := yarpc.NewDispatcher(c)
//
// NewDispatcher or NewDispatcherFromYAML may be used to get a
// yarpc.Dispatcher directly instead of a yarpc.Config.
//
// 	dispatcher, err := cfg.NewDispatcherFromYAML("myservice", yamlConfig)
//
// Configuration parameters for the different transports, inbounds, and
// outbounds are defined in the TransportSpecs that were registered against
// the Configurator. A TransportSpec uses this information to build the
// corresponding Transport, Inbound and Outbound objects.
//
// Configuration
//
// The configuration may be specified in YAML or as any Go-level
// map[string]interface{}. The examples below use YAML for illustration
// purposes but other markup formats may be parsed into map[string]interface{}
// as long as the information provided is the same.
//
// The configuration accepts the following top-level attributes: transports,
// inbounds, and outbounds.
//
// 	inbounds:
// 	  # ...
// 	outbounds:
// 	  # ...
// 	transports:
// 	  # ...
//
// See the following sections for details on the transports, inbounds, and
// outbounds keys in the configuration.
//
// Inbound Configuration
//
// The 'inbounds' attribute configures the different ways in which the service
// receives requests. It is represented as a mapping between inbound transport
// type and its configuration. For example, the following states that we want
// to receive requests over HTTP.
//
// 	inbounds:
// 	  http:
// 	    address: :8080
//
// (For details on the configuration parameters of individual transport types,
// check the documentation for the corresponding transport package.)
//
// If you want multiple inbounds of the same type, specify a different name
// for it and add a 'type' attribute to its configuration:
//
// 	inbounds:
// 	  http:
// 	    address: :8081
// 	  http-deprecated:
// 	    type: http
// 	    address: :8080
//
// Any inbound can be disabled by adding a 'disabled' attribute.
//
// 	inbounds:
// 	  http:
// 	    address: :8080
// 	  http-deprecated:
// 	    type: http
// 	    disabled: true
// 	    address: :8081
//
// Outbound Configuration
//
// The 'outbounds' attribute configures how this service makes requests to
// other YARPC-compatible services. It is represented as mapping between
// service name and outbound configuration.
//
// 	outbounds:
// 	  keyvalue:
// 	    # ..
// 	  anotherservice:
// 	    # ..
//
// (For details on the configuration parameters of individual transport types,
// check the documentation for the corresponding transport package.)
//
// The outbound configuration for a service has at least one of the following
// keys: unary, oneway. These specify the configurations for the corresponding
// RPC types for that service. For example, the following specifies that we
// make Unary requests to keyvalue service over TChannel and Oneway requests over
// HTTP.
//
// 	keyvalue:
// 	  unary:
// 	    tchannel:
//        peer: 127.0.0.1:4040
// 	  oneway:
// 	    http:
//        url: http://127.0.0.1:8080/
//
// For convenience, if there is only one outbound configuration for a service,
// it may be specified one level higher (without the 'unary' or 'oneway'
// attributes). In this case, that transport will be used to send requests for
// all compatible RPC types. For example, the HTTP transport supports both,
// Unary and Oneway RPC types so the following states that requests for both
// RPC types must be made over HTTP.
//
// 	keyvalue:
// 	  http:
// 	    url: http://127.0.0.1:8080/
//
// Similarly, the following states that we only make Oneway requests to the
// "email" service and those are always made over HTTP.
//
// 	email:
// 	  http:
// 	    url: http://127.0.0.1:8080/
//
// When the name of the target service differs from the outbound name, it may
// be overridden with the 'service' key.
//
// 	keyvalue:
// 	  unary:
// 	    # ...
// 	  oneway:
// 	    # ...
// 	keyvalue-staging:
// 	  service: keyvalue
// 	  unary:
// 	    # ...
// 	  oneway:
// 	    # ...
//
// Peer Configuration
//
// Transports that support peer management and selection through YARPC accept
// some additional keys in their outbound configuration.
//
// An explicit peer may be specified for a supported transport by using the
// `peer` option.
//
// 	keyvalue:
// 	  tchannel:
// 	    peer: 127.0.0.1:4040
//
// All requests made to this outbound will be made through this peer.
//
// If a peer list was registered with the system, the name of the peer list
// may be used to specify a more complex peer selection and load balancing
// strategy.
//
// 	keyvalue:
// 	  http:
// 	    url: https://host/yarpc
// 	    round-robin:
// 	      peers:
// 	        - 127.0.0.1:8080
// 	        - 127.0.0.1:8081
// 	        - 127.0.0.1:8082
//
// In the example above, the system will round-robin the requests between the
// different addresses. In case of the HTTP transport, the URL will be used as
// a template for the HTTP requests made to these hosts.
//
// Finally, the TransportSpec for a Transport may include named presets for
// peer lists in its definition. These may be referenced by name in the config
// using the `with` key.
//
// 	# Given a preset "dev-proxy" that was included in the TransportSpec, the
// 	# following is valid.
// 	keyvalue:
// 	  http:
// 	    url: https://host/yarpc
// 	    with: dev-proxy
//
// Transport Configuration
//
// The 'transports' attribute configures the Transport objects that are shared
// between all inbounds and outbounds of that transport type. It is
// represented as a mapping between the transport name and its configuration.
//
// 	transports:
// 	  http:
// 	    keepAlive: 30s
//
// (For details on the configuration parameters of individual transport types,
// check the documentation for the corresponding transport package.)
//
// Customizing Configuration
//
// When building your own TransportSpec, PeerListSpec, or PeerListUpdaterSpec,
// you will define functions accepting structs or pointers to structs which
// define the different configuration parameters needed to build that entity.
// These configuration parameters will be decoded from the user-specified
// configuration using a case-insensitive match on the field names.
//
// Given the struct,
//
// 	type MyConfig struct {
// 		URL string
// 	}
//
// An object containing a `url`, `URL` or `Url` key with a string value will
// be accepted in place of MyConfig.
//
// Configuration structs can use standard Go primitive types, time.Duration,
// maps, slices, and other similar structs. For example only, an outbound
// might accept a config containing an array of host:port structs (in
// practice, an outbound would use a config.PeerList to build a peer.Chooser).
//
// 	type Peer struct {
// 		Host string
// 		Port int
// 	}
//
// 	type MyOutboundConfig struct{ Peers []Peer }
//
// The above will accept the following YAML:
//
// 	myoutbound:
// 	  peers:
// 	    - host: localhost
// 	      port: 8080
// 	    - host: anotherhost
// 	      port: 8080
//
// Field names can be changed by adding a `config` tag to fields in the
// configuration struct.
//
// 	type MyInboundConfig struct {
// 		Address string `config:"addr"`
// 	}
//
// This struct will accept the `addr` key, not `address`.
//
// In addition to specifying the field name, the `config` tag may also include
// an `interpolate` option to request interpolation of variables in the form
// ${NAME} or ${NAME:default} at the time the value is decoded. By default,
// environment variables are used to fill these variables; this may be changed
// with the InterpolationResolver option.
//
// Interpolation may be requested only for primitive fields and time.Duration.
//
// 	type MyConfig struct {
// 		Address string `config:"addr,interpolate"`
// 		Timeout time.Duration `config:",interpolate"`
// 	}
//
// Note that for the second field, we don't change the name with the tag; we
// only indicate that we want interpolation for that variable.
//
// In the example above, values for both, Address and Timeout may contain
// strings in the form ${NAME} or ${NAME:default} anywhere in the value. These
// will be replaced with the value of the environment variable or the default
// (if specified) if the environment variable was unset.
//
// 	addr: localhost:${PORT}
// 	timeout: ${TIMEOUT_SECONDS:5}s
package yarpcconfig
<commit_msg>config: Add docs for log level customization (#1719)<commit_after>// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package yarpcconfig implements a generic configuration system that may be
// used to build YARPC Dispatchers from configurations specified in different
// markup formats.
//
// Usage
//
// To build a Dispatcher, first create a new Configurator. This object will be
// responsible for loading your configuration. It does not yet know about the
// different transports, peer lists, etc. that you want to use. You can inform
// the Configurator about the different transports, peer lists, etc. by
// registering them using RegisterTransport, RegisterPeerChooser,
// RegisterPeerList, and RegisterPeerListUpdater.
//
// 	cfg := config.New()
// 	cfg.MustRegisterTransport(http.TransportSpec())
// 	cfg.MustRegisterPeerList(roundrobin.Spec())
//
// This object is re-usable and may be stored as a singleton in your
// application. Custom transports, peer lists, and peer list updaters may be
// integrated with the configuration system by registering more
// TransportSpecs, PeerChooserSpecs, PeerListSpecs, and PeerListUpdaterSpecs
// with it.
//
// Use LoadConfigFromYAML to load a yarpc.Config from YAML and pass that to
// yarpc.NewDispatcher.
//
// 	c, err := cfg.LoadConfigFromYAML("myservice", yamlConfig)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
// 	dispatcher := yarpc.NewDispatcher(c)
//
// If you have already parsed your configuration from a different format, pass
// the parsed data to LoadConfig instead.
//
// 	var m map[string]interface{} = ...
// 	c, err := cfg.LoadConfig("myservice", m)
// 	if err != nil {
// 		log.Fatal(err)
// 	}
// 	dispatcher := yarpc.NewDispatcher(c)
//
// NewDispatcher or NewDispatcherFromYAML may be used to get a
// yarpc.Dispatcher directly instead of a yarpc.Config.
//
// 	dispatcher, err := cfg.NewDispatcherFromYAML("myservice", yamlConfig)
//
// Configuration parameters for the different transports, inbounds, and
// outbounds are defined in the TransportSpecs that were registered against
// the Configurator. A TransportSpec uses this information to build the
// corresponding Transport, Inbound and Outbound objects.
//
// Configuration
//
// The configuration may be specified in YAML or as any Go-level
// map[string]interface{}. The examples below use YAML for illustration
// purposes but other markup formats may be parsed into map[string]interface{}
// as long as the information provided is the same.
//
// The configuration accepts the following top-level attributes: transports,
// inbounds, and outbounds.
//
// 	inbounds:
// 	  # ...
// 	outbounds:
// 	  # ...
// 	transports:
// 	  # ...
// 	logging:
// 	  # ...
//
// See the following sections for details on the logging, transports,
// inbounds, and outbounds keys in the configuration.
//
// Inbound Configuration
//
// The 'inbounds' attribute configures the different ways in which the service
// receives requests. It is represented as a mapping between inbound transport
// type and its configuration. For example, the following states that we want
// to receive requests over HTTP.
//
// 	inbounds:
// 	  http:
// 	    address: :8080
//
// (For details on the configuration parameters of individual transport types,
// check the documentation for the corresponding transport package.)
//
// If you want multiple inbounds of the same type, specify a different name
// for it and add a 'type' attribute to its configuration:
//
// 	inbounds:
// 	  http:
// 	    address: :8081
// 	  http-deprecated:
// 	    type: http
// 	    address: :8080
//
// Any inbound can be disabled by adding a 'disabled' attribute.
//
// 	inbounds:
// 	  http:
// 	    address: :8080
// 	  http-deprecated:
// 	    type: http
// 	    disabled: true
// 	    address: :8081
//
// Outbound Configuration
//
// The 'outbounds' attribute configures how this service makes requests to
// other YARPC-compatible services. It is represented as mapping between
// service name and outbound configuration.
//
// 	outbounds:
// 	  keyvalue:
// 	    # ..
// 	  anotherservice:
// 	    # ..
//
// (For details on the configuration parameters of individual transport types,
// check the documentation for the corresponding transport package.)
//
// The outbound configuration for a service has at least one of the following
// keys: unary, oneway. These specify the configurations for the corresponding
// RPC types for that service. For example, the following specifies that we
// make Unary requests to keyvalue service over TChannel and Oneway requests over
// HTTP.
//
// 	keyvalue:
// 	  unary:
// 	    tchannel:
//        peer: 127.0.0.1:4040
// 	  oneway:
// 	    http:
//        url: http://127.0.0.1:8080/
//
// For convenience, if there is only one outbound configuration for a service,
// it may be specified one level higher (without the 'unary' or 'oneway'
// attributes). In this case, that transport will be used to send requests for
// all compatible RPC types. For example, the HTTP transport supports both,
// Unary and Oneway RPC types so the following states that requests for both
// RPC types must be made over HTTP.
//
// 	keyvalue:
// 	  http:
// 	    url: http://127.0.0.1:8080/
//
// Similarly, the following states that we only make Oneway requests to the
// "email" service and those are always made over HTTP.
//
// 	email:
// 	  http:
// 	    url: http://127.0.0.1:8080/
//
// When the name of the target service differs from the outbound name, it may
// be overridden with the 'service' key.
//
// 	keyvalue:
// 	  unary:
// 	    # ...
// 	  oneway:
// 	    # ...
// 	keyvalue-staging:
// 	  service: keyvalue
// 	  unary:
// 	    # ...
// 	  oneway:
// 	    # ...
//
// Peer Configuration
//
// Transports that support peer management and selection through YARPC accept
// some additional keys in their outbound configuration.
//
// An explicit peer may be specified for a supported transport by using the
// `peer` option.
//
// 	keyvalue:
// 	  tchannel:
// 	    peer: 127.0.0.1:4040
//
// All requests made to this outbound will be made through this peer.
//
// If a peer list was registered with the system, the name of the peer list
// may be used to specify a more complex peer selection and load balancing
// strategy.
//
// 	keyvalue:
// 	  http:
// 	    url: https://host/yarpc
// 	    round-robin:
// 	      peers:
// 	        - 127.0.0.1:8080
// 	        - 127.0.0.1:8081
// 	        - 127.0.0.1:8082
//
// In the example above, the system will round-robin the requests between the
// different addresses. In case of the HTTP transport, the URL will be used as
// a template for the HTTP requests made to these hosts.
//
// Finally, the TransportSpec for a Transport may include named presets for
// peer lists in its definition. These may be referenced by name in the config
// using the `with` key.
//
// 	# Given a preset "dev-proxy" that was included in the TransportSpec, the
// 	# following is valid.
// 	keyvalue:
// 	  http:
// 	    url: https://host/yarpc
// 	    with: dev-proxy
//
// Transport Configuration
//
// The 'transports' attribute configures the Transport objects that are shared
// between all inbounds and outbounds of that transport type. It is
// represented as a mapping between the transport name and its configuration.
//
// 	transports:
// 	  http:
// 	    keepAlive: 30s
//
// (For details on the configuration parameters of individual transport types,
// check the documentation for the corresponding transport package.)
//
// Logging Configuration
//
// The 'logging' attribute configures how YARPC's observability middleware
// logs output.
//
// 	logging:
// 	  levels:
// 	    # ...
//
// The following keys are supported under the 'levels' key,
//
// 	applicationError
// 	  Configures the level at which application errors are logged. All Thrift
// 	  exceptions are considered application errors. Defaults to "error".
//
// For example, the following configuration will have the effect of logging
// Thrift exceptions for inbound and outbound calls ("Error handling inbound
// request" and "Error making outbound call") at info level instead of error.
//
// 	logging:
// 	  levels:
// 	    applicationError: info
//
// Customizing Configuration
//
// When building your own TransportSpec, PeerListSpec, or PeerListUpdaterSpec,
// you will define functions accepting structs or pointers to structs which
// define the different configuration parameters needed to build that entity.
// These configuration parameters will be decoded from the user-specified
// configuration using a case-insensitive match on the field names.
//
// Given the struct,
//
// 	type MyConfig struct {
// 		URL string
// 	}
//
// An object containing a `url`, `URL` or `Url` key with a string value will
// be accepted in place of MyConfig.
//
// Configuration structs can use standard Go primitive types, time.Duration,
// maps, slices, and other similar structs. For example only, an outbound
// might accept a config containing an array of host:port structs (in
// practice, an outbound would use a config.PeerList to build a peer.Chooser).
//
// 	type Peer struct {
// 		Host string
// 		Port int
// 	}
//
// 	type MyOutboundConfig struct{ Peers []Peer }
//
// The above will accept the following YAML:
//
// 	myoutbound:
// 	  peers:
// 	    - host: localhost
// 	      port: 8080
// 	    - host: anotherhost
// 	      port: 8080
//
// Field names can be changed by adding a `config` tag to fields in the
// configuration struct.
//
// 	type MyInboundConfig struct {
// 		Address string `config:"addr"`
// 	}
//
// This struct will accept the `addr` key, not `address`.
//
// In addition to specifying the field name, the `config` tag may also include
// an `interpolate` option to request interpolation of variables in the form
// ${NAME} or ${NAME:default} at the time the value is decoded. By default,
// environment variables are used to fill these variables; this may be changed
// with the InterpolationResolver option.
//
// Interpolation may be requested only for primitive fields and time.Duration.
//
// 	type MyConfig struct {
// 		Address string `config:"addr,interpolate"`
// 		Timeout time.Duration `config:",interpolate"`
// 	}
//
// Note that for the second field, we don't change the name with the tag; we
// only indicate that we want interpolation for that variable.
//
// In the example above, values for both, Address and Timeout may contain
// strings in the form ${NAME} or ${NAME:default} anywhere in the value. These
// will be replaced with the value of the environment variable or the default
// (if specified) if the environment variable was unset.
//
// 	addr: localhost:${PORT}
// 	timeout: ${TIMEOUT_SECONDS:5}s
package yarpcconfig
<|endoftext|>


<commit_before>package gorocksdb

// #include "rocksdb/c.h"
import "C"

// EnvOptions represents options for env.
type EnvOptions struct {
	c *C.rocksdb_envoptions_t
}

// NewDefaultEnvOptions creates a default EnvOptions object.
func NewDefaultEnvOptions() *EnvOptions {
	return NewNativeEnvOptions(C.rocksdb_envoptions_create())
}

// NewNativeEnvOptions creates a EnvOptions object.
func NewNativeEnvOptions(c *C.rocksdb_envoptions_t) *EnvOptions {
	return &EnvOptions{c: c}
}
<commit_msg>Add Destroy method for EnvOption<commit_after>package gorocksdb

// #include "rocksdb/c.h"
import "C"

// EnvOptions represents options for env.
type EnvOptions struct {
	c *C.rocksdb_envoptions_t
}

// NewDefaultEnvOptions creates a default EnvOptions object.
func NewDefaultEnvOptions() *EnvOptions {
	return NewNativeEnvOptions(C.rocksdb_envoptions_create())
}

// NewNativeEnvOptions creates a EnvOptions object.
func NewNativeEnvOptions(c *C.rocksdb_envoptions_t) *EnvOptions {
	return &EnvOptions{c: c}
}

// Destroy deallocates the EnvOptions object.
func (opts *EnvOptions) Destroy() {
	C.rocksdb_envoptions_destroy(opts.c)
	opts.c = nil
}
<|endoftext|>


<commit_before>package geotrigger_golang

import (
	"net/http"
	"bytes"
	"fmt"
	"errors"
	"io/ioutil"
	"encoding/json"
	"reflect"
)

// The following are vars so that they can be changed by tests
var (
	GEOTRIGGER_BASE_URL = "https://geotrigger.arcgis.com"
	AGO_BASE_URL = "https://www.arcgis.com"
)

const AGO_TOKEN_ROUTE = "/sharing/oauth2/token"
const AGO_REGISTER_ROUTE = "/sharing/oauth2/registerDevice"

type Session interface {
	RequestAccess() (error)
	GeotriggerAPIRequest(route string, params map[string]interface{}, responseJSON interface{}) (error)
}

type ErrorResponse struct {
	Error ErrorJSON `json:"error"`
}

type ErrorJSON struct {
	Code int `json:"code"`
	Message string `json:"message"`
}

type errorHandler func(*ErrorResponse)(error)

func agoPost(route string, body []byte, responseJSON interface{}) (error) {
	req, err := http.NewRequest("POST", AGO_BASE_URL + route, bytes.NewReader(body))
	if err != nil {
		return errors.New(fmt.Sprintf("Error creating AgoPost for route %s. %s", route, err))
	}

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	return post(req, responseJSON, func(errResponse *ErrorResponse) error {
		return errors.New(fmt.Sprintf("Error from AGO, code: %d. Message: %s", errResponse.Error.Code,
			errResponse.Error.Message))
	})
}

func post(req *http.Request, responseJSON interface{}, errHandler errorHandler) (error) {
	path := req.URL.Path
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return errors.New(fmt.Sprintf("Error while posting to: %s.  Error: %s", path, err))
	}

	if resp.StatusCode != 200 {
		return errors.New(fmt.Sprintf("Received status code %d from %s.", resp.StatusCode, path))
	}

	contents, err := readResponseBody(resp)
	if err != nil {
		return errors.New(fmt.Sprintf("Could not read response body from %s. %s", path, err))
	}

	if errorResponse := errorCheck(contents); errorResponse != nil {
		return errHandler(errorResponse)
	}

	return parseJSONResponse(contents, responseJSON)
}

func readResponseBody(resp *http.Response) (contents []byte, err error) {
	defer resp.Body.Close()
	contents, err = ioutil.ReadAll(resp.Body)
	return
}

func errorCheck(resp []byte) (*ErrorResponse) {
	var errorContainer ErrorResponse
	if err := json.Unmarshal(resp, &errorContainer); err != nil {
		return nil // no recognized error present
	}

	return &errorContainer
}

func parseJSONResponse(resp []byte, responseJSON interface{}) (error) {
	t := reflect.TypeOf(responseJSON)
	if t.Kind() != reflect.Ptr {
		return errors.New(fmt.Sprintf("Provided responseJSON interface should be a pointer (to struct or map)."))
	}

	if err := json.Unmarshal(resp, responseJSON); err != nil {
		return errors.New(fmt.Sprintf("Error parsing response: %s  Error: %s", string(resp), err))
	}

	return nil
}
<commit_msg>geotrigger post session func<commit_after>package geotrigger_golang

import (
	"net/http"
	"bytes"
	"fmt"
	"errors"
	"io/ioutil"
	"encoding/json"
	"reflect"
)

// The following are vars so that they can be changed by tests
var (
	GEOTRIGGER_BASE_URL = "https://geotrigger.arcgis.com"
	AGO_BASE_URL = "https://www.arcgis.com"
)

const AGO_TOKEN_ROUTE = "/sharing/oauth2/token"
const AGO_REGISTER_ROUTE = "/sharing/oauth2/registerDevice"

type Session interface {
	RequestAccess() (error)
	GeotriggerAPIRequest(route string, params map[string]interface{}, responseJSON interface{}) (error)
}

type ErrorResponse struct {
	Error ErrorJSON `json:"error"`
}

type ErrorJSON struct {
	Code int `json:"code"`
	Message string `json:"message"`
}

type errorHandler func(*ErrorResponse)(error)

func agoPost(route string, body []byte, responseJSON interface{}) (error) {
	req, err := http.NewRequest("POST", AGO_BASE_URL + route, bytes.NewReader(body))
	if err != nil {
		return errors.New(fmt.Sprintf("Error creating AgoPost for route %s. %s", route, err))
	}

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	return post(req, responseJSON, func(errResponse *ErrorResponse) error {
		return errors.New(fmt.Sprintf("Error from AGO, code: %d. Message: %s", errResponse.Error.Code,
			errResponse.Error.Message))
	})
}

func geotriggerPost(route string, body []byte, responseJSON interface{}, accessToken string,
	errHandler errorHandler) (error) {
	req, err := http.NewRequest("POST", GEOTRIGGER_BASE_URL + route, bytes.NewReader(body))
	if err != nil {
		return errors.New(fmt.Sprintf("Error creating GeotriggerPost for route %s. %s", route, err))
	}

	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
	req.Header.Set("Content-Type", "application/json")

	return post(req, responseJSON, errHandler)
}

func post(req *http.Request, responseJSON interface{}, errHandler errorHandler) (error) {
	path := req.URL.Path
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return errors.New(fmt.Sprintf("Error while posting to: %s.  Error: %s", path, err))
	}

	if resp.StatusCode != 200 {
		return errors.New(fmt.Sprintf("Received status code %d from %s.", resp.StatusCode, path))
	}

	contents, err := readResponseBody(resp)
	if err != nil {
		return errors.New(fmt.Sprintf("Could not read response body from %s. %s", path, err))
	}

	if errorResponse := errorCheck(contents); errorResponse != nil {
		return errHandler(errorResponse)
	}

	return parseJSONResponse(contents, responseJSON)
}

func readResponseBody(resp *http.Response) (contents []byte, err error) {
	defer resp.Body.Close()
	contents, err = ioutil.ReadAll(resp.Body)
	return
}

func errorCheck(resp []byte) (*ErrorResponse) {
	var errorContainer ErrorResponse
	if err := json.Unmarshal(resp, &errorContainer); err != nil {
		return nil // no recognized error present
	}

	return &errorContainer
}

func parseJSONResponse(resp []byte, responseJSON interface{}) (error) {
	t := reflect.TypeOf(responseJSON)
	if t.Kind() != reflect.Ptr {
		return errors.New(fmt.Sprintf("Provided responseJSON interface should be a pointer (to struct or map)."))
	}

	if err := json.Unmarshal(resp, responseJSON); err != nil {
		return errors.New(fmt.Sprintf("Error parsing response: %s  Error: %s", string(resp), err))
	}

	return nil
}
<|endoftext|>