<commit_before>// Copyright 2014 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
)

// Exec is the type representing a `docker exec` instance and containing the
// instance ID
type Exec struct {
	ID string `json:"Id,omitempty" yaml:"Id,omitempty"`
}

// CreateExecOptions specify parameters to the CreateExecContainer function.
//
// See https://goo.gl/60TeBP for more details
type CreateExecOptions struct {
	Env          []string        `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"`
	Cmd          []string        `json:"Cmd,omitempty" yaml:"Cmd,omitempty" toml:"Cmd,omitempty"`
	Container    string          `json:"Container,omitempty" yaml:"Container,omitempty" toml:"Container,omitempty"`
	User         string          `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"`
	WorkingDir   string          `json:"WorkingDir,omitempty" yaml:"WorkingDir,omitempty" toml:"WorkingDir,omitempty"`
	DetachKeys   string          `json:"DetachKeys,omitempty" yaml:"DetachKeys,omitempty" toml:"DetachKeys,omitempty"`
	Context      context.Context `json:"-"`
	AttachStdin  bool            `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty" toml:"AttachStdin,omitempty"`
	AttachStdout bool            `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty" toml:"AttachStdout,omitempty"`
	AttachStderr bool            `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty" toml:"AttachStderr,omitempty"`
	Tty          bool            `json:"Tty,omitempty" yaml:"Tty,omitempty" toml:"Tty,omitempty"`
	Privileged   bool            `json:"Privileged,omitempty" yaml:"Privileged,omitempty" toml:"Privileged,omitempty"`
}

// CreateExec sets up an exec instance in a running container `id`, returning the exec
// instance, or an error in case of failure.
//
// See https://goo.gl/60TeBP for more details
func (c *Client) CreateExec(opts CreateExecOptions) (*Exec, error) {
	if len(opts.Env) > 0 && c.serverAPIVersion.LessThan(apiVersion125) {
		return nil, errors.New("exec configuration Env is only supported in API#1.25 and above")
	}
	if len(opts.WorkingDir) > 0 && c.serverAPIVersion.LessThan(apiVersion135) {
		return nil, errors.New("exec configuration WorkingDir is only supported in API#1.35 and above")
	}
	path := fmt.Sprintf("/containers/%s/exec", opts.Container)
	resp, err := c.do(http.MethodPost, path, doOptions{data: opts, context: opts.Context})
	if err != nil {
		var e *Error
		if errors.As(err, &e) && e.Status == http.StatusNotFound {
			return nil, &NoSuchContainer{ID: opts.Container}
		}
		return nil, err
	}
	defer resp.Body.Close()
	var exec Exec
	if err := json.NewDecoder(resp.Body).Decode(&exec); err != nil {
		return nil, err
	}

	return &exec, nil
}

// StartExecOptions specify parameters to the StartExecContainer function.
//
// See https://goo.gl/1EeDWi for more details
type StartExecOptions struct {
	InputStream  io.Reader `qs:"-"`
	OutputStream io.Writer `qs:"-"`
	ErrorStream  io.Writer `qs:"-"`

	Detach bool `json:"Detach,omitempty" yaml:"Detach,omitempty" toml:"Detach,omitempty"`
	Tty    bool `json:"Tty,omitempty" yaml:"Tty,omitempty" toml:"Tty,omitempty"`

	// Use raw terminal? Usually true when the container contains a TTY.
	RawTerminal bool `qs:"-"`

	// If set, after a successful connect, a sentinel will be sent and then the
	// client will block on receive before continuing.
	//
	// It must be an unbuffered channel. Using a buffered channel can lead
	// to unexpected behavior.
	Success chan struct{} `json:"-"`

	Context context.Context `json:"-"`
}

// StartExec starts a previously set up exec instance id. If opts.Detach is
// true, it returns after starting the exec command. Otherwise, it sets up an
// interactive session with the exec command.
//
// See https://goo.gl/1EeDWi for more details
func (c *Client) StartExec(id string, opts StartExecOptions) error {
	cw, err := c.StartExecNonBlocking(id, opts)
	if err != nil {
		return err
	}
	if cw != nil {
		return cw.Wait()
	}
	return nil
}

// StartExecNonBlocking starts a previously set up exec instance id. If opts.Detach is
// true, it returns after starting the exec command. Otherwise, it sets up an
// interactive session with the exec command.
//
// See https://goo.gl/1EeDWi for more details
func (c *Client) StartExecNonBlocking(id string, opts StartExecOptions) (CloseWaiter, error) {
	if id == "" {
		return nil, &NoSuchExec{ID: id}
	}

	path := fmt.Sprintf("/exec/%s/start", id)

	if opts.Detach {
		resp, err := c.do(http.MethodPost, path, doOptions{data: opts, context: opts.Context})
		if err != nil {
			var e *Error
			if errors.As(err, &e) && e.Status == http.StatusNotFound {
				return nil, &NoSuchExec{ID: id}
			}
			return nil, err
		}
		defer resp.Body.Close()
		return nil, nil
	}

	return c.hijack(http.MethodPost, path, hijackOptions{
		success:        opts.Success,
		setRawTerminal: opts.RawTerminal,
		in:             opts.InputStream,
		stdout:         opts.OutputStream,
		stderr:         opts.ErrorStream,
		data:           opts,
	})
}

// ResizeExecTTY resizes the tty session used by the exec command id. This API
// is valid only if Tty was specified as part of creating and starting the exec
// command.
//
// See https://goo.gl/Mo5bxx for more details
func (c *Client) ResizeExecTTY(id string, height, width int) error {
	params := make(url.Values)
	params.Set("h", strconv.Itoa(height))
	params.Set("w", strconv.Itoa(width))

	path := fmt.Sprintf("/exec/%s/resize?%s", id, params.Encode())
	resp, err := c.do(http.MethodPost, path, doOptions{})
	if err != nil {
		return err
	}
	resp.Body.Close()
	return nil
}

// ExecProcessConfig is a type describing the command associated to a Exec
// instance. It's used in the ExecInspect type.
type ExecProcessConfig struct {
	User       string   `json:"user,omitempty" yaml:"user,omitempty" toml:"user,omitempty"`
	Privileged bool     `json:"privileged,omitempty" yaml:"privileged,omitempty" toml:"privileged,omitempty"`
	Tty        bool     `json:"tty,omitempty" yaml:"tty,omitempty" toml:"tty,omitempty"`
	EntryPoint string   `json:"entrypoint,omitempty" yaml:"entrypoint,omitempty" toml:"entrypoint,omitempty"`
	Arguments  []string `json:"arguments,omitempty" yaml:"arguments,omitempty" toml:"arguments,omitempty"`
}

// ExecInspect is a type with details about a exec instance, including the
// exit code if the command has finished running. It's returned by a api
// call to /exec/(id)/json
//
// See https://goo.gl/ctMUiW for more details
type ExecInspect struct {
	ID            string            `json:"ID,omitempty" yaml:"ID,omitempty" toml:"ID,omitempty"`
	ExitCode      int               `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty" toml:"ExitCode,omitempty"`
	ProcessConfig ExecProcessConfig `json:"ProcessConfig,omitempty" yaml:"ProcessConfig,omitempty" toml:"ProcessConfig,omitempty"`
	ContainerID   string            `json:"ContainerID,omitempty" yaml:"ContainerID,omitempty" toml:"ContainerID,omitempty"`
	DetachKeys    string            `json:"DetachKeys,omitempty" yaml:"DetachKeys,omitempty" toml:"DetachKeys,omitempty"`
	Running       bool              `json:"Running,omitempty" yaml:"Running,omitempty" toml:"Running,omitempty"`
	OpenStdin     bool              `json:"OpenStdin,omitempty" yaml:"OpenStdin,omitempty" toml:"OpenStdin,omitempty"`
	OpenStderr    bool              `json:"OpenStderr,omitempty" yaml:"OpenStderr,omitempty" toml:"OpenStderr,omitempty"`
	OpenStdout    bool              `json:"OpenStdout,omitempty" yaml:"OpenStdout,omitempty" toml:"OpenStdout,omitempty"`
	CanRemove     bool              `json:"CanRemove,omitempty" yaml:"CanRemove,omitempty" toml:"CanRemove,omitempty"`
}

// InspectExec returns low-level information about the exec command id.
//
// See https://goo.gl/ctMUiW for more details
func (c *Client) InspectExec(id string) (*ExecInspect, error) {
	path := fmt.Sprintf("/exec/%s/json", id)
	resp, err := c.do(http.MethodGet, path, doOptions{})
	if err != nil {
		var e *Error
		if errors.As(err, &e) && e.Status == http.StatusNotFound {
			return nil, &NoSuchExec{ID: id}
		}
		return nil, err
	}
	defer resp.Body.Close()
	var exec ExecInspect
	if err := json.NewDecoder(resp.Body).Decode(&exec); err != nil {
		return nil, err
	}
	return &exec, nil
}

// NoSuchExec is the error returned when a given exec instance does not exist.
type NoSuchExec struct {
	ID string
}

func (err *NoSuchExec) Error() string {
	return "No such exec instance: " + err.ID
}
<commit_msg>ServerAPIVersion needs to be set in Client.CreateExec()<commit_after>// Copyright 2014 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strconv"
)

// Exec is the type representing a `docker exec` instance and containing the
// instance ID
type Exec struct {
	ID string `json:"Id,omitempty" yaml:"Id,omitempty"`
}

// CreateExecOptions specify parameters to the CreateExecContainer function.
//
// See https://goo.gl/60TeBP for more details
type CreateExecOptions struct {
	Env          []string        `json:"Env,omitempty" yaml:"Env,omitempty" toml:"Env,omitempty"`
	Cmd          []string        `json:"Cmd,omitempty" yaml:"Cmd,omitempty" toml:"Cmd,omitempty"`
	Container    string          `json:"Container,omitempty" yaml:"Container,omitempty" toml:"Container,omitempty"`
	User         string          `json:"User,omitempty" yaml:"User,omitempty" toml:"User,omitempty"`
	WorkingDir   string          `json:"WorkingDir,omitempty" yaml:"WorkingDir,omitempty" toml:"WorkingDir,omitempty"`
	DetachKeys   string          `json:"DetachKeys,omitempty" yaml:"DetachKeys,omitempty" toml:"DetachKeys,omitempty"`
	Context      context.Context `json:"-"`
	AttachStdin  bool            `json:"AttachStdin,omitempty" yaml:"AttachStdin,omitempty" toml:"AttachStdin,omitempty"`
	AttachStdout bool            `json:"AttachStdout,omitempty" yaml:"AttachStdout,omitempty" toml:"AttachStdout,omitempty"`
	AttachStderr bool            `json:"AttachStderr,omitempty" yaml:"AttachStderr,omitempty" toml:"AttachStderr,omitempty"`
	Tty          bool            `json:"Tty,omitempty" yaml:"Tty,omitempty" toml:"Tty,omitempty"`
	Privileged   bool            `json:"Privileged,omitempty" yaml:"Privileged,omitempty" toml:"Privileged,omitempty"`
}

// CreateExec sets up an exec instance in a running container `id`, returning the exec
// instance, or an error in case of failure.
//
// See https://goo.gl/60TeBP for more details
func (c *Client) CreateExec(opts CreateExecOptions) (*Exec, error) {
	if c.serverAPIVersion == nil {
		c.checkAPIVersion()
	}
	if len(opts.Env) > 0 && c.serverAPIVersion.LessThan(apiVersion125) {
		return nil, errors.New("exec configuration Env is only supported in API#1.25 and above")
	}
	if len(opts.WorkingDir) > 0 && c.serverAPIVersion.LessThan(apiVersion135) {
		return nil, errors.New("exec configuration WorkingDir is only supported in API#1.35 and above")
	}
	path := fmt.Sprintf("/containers/%s/exec", opts.Container)
	resp, err := c.do(http.MethodPost, path, doOptions{data: opts, context: opts.Context})
	if err != nil {
		var e *Error
		if errors.As(err, &e) && e.Status == http.StatusNotFound {
			return nil, &NoSuchContainer{ID: opts.Container}
		}
		return nil, err
	}
	defer resp.Body.Close()
	var exec Exec
	if err := json.NewDecoder(resp.Body).Decode(&exec); err != nil {
		return nil, err
	}

	return &exec, nil
}

// StartExecOptions specify parameters to the StartExecContainer function.
//
// See https://goo.gl/1EeDWi for more details
type StartExecOptions struct {
	InputStream  io.Reader `qs:"-"`
	OutputStream io.Writer `qs:"-"`
	ErrorStream  io.Writer `qs:"-"`

	Detach bool `json:"Detach,omitempty" yaml:"Detach,omitempty" toml:"Detach,omitempty"`
	Tty    bool `json:"Tty,omitempty" yaml:"Tty,omitempty" toml:"Tty,omitempty"`

	// Use raw terminal? Usually true when the container contains a TTY.
	RawTerminal bool `qs:"-"`

	// If set, after a successful connect, a sentinel will be sent and then the
	// client will block on receive before continuing.
	//
	// It must be an unbuffered channel. Using a buffered channel can lead
	// to unexpected behavior.
	Success chan struct{} `json:"-"`

	Context context.Context `json:"-"`
}

// StartExec starts a previously set up exec instance id. If opts.Detach is
// true, it returns after starting the exec command. Otherwise, it sets up an
// interactive session with the exec command.
//
// See https://goo.gl/1EeDWi for more details
func (c *Client) StartExec(id string, opts StartExecOptions) error {
	cw, err := c.StartExecNonBlocking(id, opts)
	if err != nil {
		return err
	}
	if cw != nil {
		return cw.Wait()
	}
	return nil
}

// StartExecNonBlocking starts a previously set up exec instance id. If opts.Detach is
// true, it returns after starting the exec command. Otherwise, it sets up an
// interactive session with the exec command.
//
// See https://goo.gl/1EeDWi for more details
func (c *Client) StartExecNonBlocking(id string, opts StartExecOptions) (CloseWaiter, error) {
	if id == "" {
		return nil, &NoSuchExec{ID: id}
	}

	path := fmt.Sprintf("/exec/%s/start", id)

	if opts.Detach {
		resp, err := c.do(http.MethodPost, path, doOptions{data: opts, context: opts.Context})
		if err != nil {
			var e *Error
			if errors.As(err, &e) && e.Status == http.StatusNotFound {
				return nil, &NoSuchExec{ID: id}
			}
			return nil, err
		}
		defer resp.Body.Close()
		return nil, nil
	}

	return c.hijack(http.MethodPost, path, hijackOptions{
		success:        opts.Success,
		setRawTerminal: opts.RawTerminal,
		in:             opts.InputStream,
		stdout:         opts.OutputStream,
		stderr:         opts.ErrorStream,
		data:           opts,
	})
}

// ResizeExecTTY resizes the tty session used by the exec command id. This API
// is valid only if Tty was specified as part of creating and starting the exec
// command.
//
// See https://goo.gl/Mo5bxx for more details
func (c *Client) ResizeExecTTY(id string, height, width int) error {
	params := make(url.Values)
	params.Set("h", strconv.Itoa(height))
	params.Set("w", strconv.Itoa(width))

	path := fmt.Sprintf("/exec/%s/resize?%s", id, params.Encode())
	resp, err := c.do(http.MethodPost, path, doOptions{})
	if err != nil {
		return err
	}
	resp.Body.Close()
	return nil
}

// ExecProcessConfig is a type describing the command associated to a Exec
// instance. It's used in the ExecInspect type.
type ExecProcessConfig struct {
	User       string   `json:"user,omitempty" yaml:"user,omitempty" toml:"user,omitempty"`
	Privileged bool     `json:"privileged,omitempty" yaml:"privileged,omitempty" toml:"privileged,omitempty"`
	Tty        bool     `json:"tty,omitempty" yaml:"tty,omitempty" toml:"tty,omitempty"`
	EntryPoint string   `json:"entrypoint,omitempty" yaml:"entrypoint,omitempty" toml:"entrypoint,omitempty"`
	Arguments  []string `json:"arguments,omitempty" yaml:"arguments,omitempty" toml:"arguments,omitempty"`
}

// ExecInspect is a type with details about a exec instance, including the
// exit code if the command has finished running. It's returned by a api
// call to /exec/(id)/json
//
// See https://goo.gl/ctMUiW for more details
type ExecInspect struct {
	ID            string            `json:"ID,omitempty" yaml:"ID,omitempty" toml:"ID,omitempty"`
	ExitCode      int               `json:"ExitCode,omitempty" yaml:"ExitCode,omitempty" toml:"ExitCode,omitempty"`
	ProcessConfig ExecProcessConfig `json:"ProcessConfig,omitempty" yaml:"ProcessConfig,omitempty" toml:"ProcessConfig,omitempty"`
	ContainerID   string            `json:"ContainerID,omitempty" yaml:"ContainerID,omitempty" toml:"ContainerID,omitempty"`
	DetachKeys    string            `json:"DetachKeys,omitempty" yaml:"DetachKeys,omitempty" toml:"DetachKeys,omitempty"`
	Running       bool              `json:"Running,omitempty" yaml:"Running,omitempty" toml:"Running,omitempty"`
	OpenStdin     bool              `json:"OpenStdin,omitempty" yaml:"OpenStdin,omitempty" toml:"OpenStdin,omitempty"`
	OpenStderr    bool              `json:"OpenStderr,omitempty" yaml:"OpenStderr,omitempty" toml:"OpenStderr,omitempty"`
	OpenStdout    bool              `json:"OpenStdout,omitempty" yaml:"OpenStdout,omitempty" toml:"OpenStdout,omitempty"`
	CanRemove     bool              `json:"CanRemove,omitempty" yaml:"CanRemove,omitempty" toml:"CanRemove,omitempty"`
}

// InspectExec returns low-level information about the exec command id.
//
// See https://goo.gl/ctMUiW for more details
func (c *Client) InspectExec(id string) (*ExecInspect, error) {
	path := fmt.Sprintf("/exec/%s/json", id)
	resp, err := c.do(http.MethodGet, path, doOptions{})
	if err != nil {
		var e *Error
		if errors.As(err, &e) && e.Status == http.StatusNotFound {
			return nil, &NoSuchExec{ID: id}
		}
		return nil, err
	}
	defer resp.Body.Close()
	var exec ExecInspect
	if err := json.NewDecoder(resp.Body).Decode(&exec); err != nil {
		return nil, err
	}
	return &exec, nil
}

// NoSuchExec is the error returned when a given exec instance does not exist.
type NoSuchExec struct {
	ID string
}

func (err *NoSuchExec) Error() string {
	return "No such exec instance: " + err.ID
}
<|endoftext|>


<commit_before>package events

import (
	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/cloudfoundry-community/firehose-to-syslog/caching"
	log "github.com/cloudfoundry-community/firehose-to-syslog/logging"
	"github.com/cloudfoundry/noaa/events"
	"strings"
)

type Event struct {
	Fields logrus.Fields
	Msg    string
	Type   string
}

var selectedEvents map[string]bool

func RouteEvents(in chan *events.Envelope) {
	for msg := range in {
		routeEvent(msg)
	}
}

func GetSelectedEvents() map[string]bool {
	return selectedEvents
}

func routeEvent(msg *events.Envelope) {

	eventType := msg.GetEventType()

	if selectedEvents[eventType.String()] {
		var event Event
		switch eventType {
		case events.Envelope_Heartbeat:
			event = Heartbeat(msg)
		case events.Envelope_HttpStart:
			event = HttpStart(msg)
		case events.Envelope_HttpStop:
			event = HttpStop(msg)
		case events.Envelope_HttpStartStop:
			event = HttpStartStop(msg)
		case events.Envelope_LogMessage:
			event = LogMessage(msg)
		case events.Envelope_ValueMetric:
			event = ValueMetric(msg)
		case events.Envelope_CounterEvent:
			event = CounterEvent(msg)
		case events.Envelope_Error:
			event = ErrorEvent(msg)
		case events.Envelope_ContainerMetric:
			event = ContainerMetric(msg)
		}

		event.AnnotateWithAppData()
		event.ShipEvent()
	}
}

func SetupEventRouting(wantedEvents string) {
	selectedEvents = make(map[string]bool)
	for _, event := range strings.Split(wantedEvents, ",") {
		if isAuthorizedEvent(event) {
			selectedEvents[event] = true
			log.LogStd(fmt.Sprintf("Event Type [%s] is included in the fireshose!", event), false)
		} else {
			log.LogError(fmt.Sprintf("Rejected Event Name [%s] - See wanted/selected events arg. Check Your Command Line Arguments!", event), "")
		}
	}
	// If any event is not authorize we fallback to the default one
	if len(selectedEvents) < 1 {
		selectedEvents["LogMessage"] = true
	}
}

func isAuthorizedEvent(wantedEvent string) bool {
	for _, authorizeEvent := range events.Envelope_EventType_name {
		if wantedEvent == authorizeEvent {
			return true
		}
	}
	return false
}

func GetListAuthorizedEventEvents() (authorizedEvents string) {
	arrEvents := []string{}
	for _, listEvent := range events.Envelope_EventType_name {
		arrEvents = append(arrEvents, listEvent)
	}
	return strings.Join(arrEvents, ", ")

}

func getAppInfo(appGuid string) caching.App {
	if app := caching.GetAppInfo(appGuid); app.Name != "" {
		return app
	} else {
		caching.GetAppByGuid(appGuid)
	}
	return caching.GetAppInfo(appGuid)
}

func Heartbeat(msg *events.Envelope) Event {
	heartbeat := msg.GetHeartbeat()

	var avail uint64

	if heartbeat.GetSentCount() > 0 {
		avail = heartbeat.GetReceivedCount() / heartbeat.GetSentCount()
	}

	fields := logrus.Fields{
		"ctl_msg_id":     heartbeat.GetControlMessageIdentifier(),
		"error_count":    heartbeat.GetErrorCount(),
		"origin":         msg.GetOrigin(),
		"received_count": heartbeat.GetReceivedCount(),
		"sent_count":     heartbeat.GetSentCount(),
		"availability":   avail,
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func HttpStart(msg *events.Envelope) Event {
	httpStart := msg.GetHttpStart()

	fields := logrus.Fields{
		"origin":            msg.GetOrigin(),
		"cf_app_id":         httpStart.GetApplicationId(),
		"instance_id":       httpStart.GetInstanceId(),
		"instance_index":    httpStart.GetInstanceIndex(),
		"method":            httpStart.GetMethod(),
		"parent_request_id": httpStart.GetParentRequestId(),
		"peer_type":         httpStart.GetPeerType(),
		"request_id":        httpStart.GetRequestId(),
		"remote_addr":       httpStart.GetRemoteAddress(),
		"timestamp":         httpStart.GetTimestamp(),
		"uri":               httpStart.GetUri(),
		"user_agent":        httpStart.GetUserAgent(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func HttpStop(msg *events.Envelope) Event {
	httpStop := msg.GetHttpStop()

	fields := logrus.Fields{
		"origin":         msg.GetOrigin(),
		"cf_app_id":      httpStop.GetApplicationId(),
		"content_length": httpStop.GetContentLength(),
		"peer_type":      httpStop.GetPeerType(),
		"request_id":     httpStop.GetRequestId(),
		"status_code":    httpStop.GetStatusCode(),
		"timestamp":      httpStop.GetTimestamp(),
		"uri":            httpStop.GetUri(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func HttpStartStop(msg *events.Envelope) Event {
	httpStartStop := msg.GetHttpStartStop()

	fields := logrus.Fields{
		"origin":            msg.GetOrigin(),
		"cf_app_id":         httpStartStop.GetApplicationId(),
		"content_length":    httpStartStop.GetContentLength(),
		"instance_id":       httpStartStop.GetInstanceId(),
		"instance_index":    httpStartStop.GetInstanceIndex(),
		"method":            httpStartStop.GetMethod(),
		"parent_request_id": httpStartStop.GetParentRequestId(),
		"peer_type":         httpStartStop.GetPeerType(),
		"remote_addr":       httpStartStop.GetRemoteAddress(),
		"request_id":        httpStartStop.GetRequestId(),
		"start_timestamp":   httpStartStop.GetStartTimestamp(),
		"status_code":       httpStartStop.GetStatusCode(),
		"stop_timestamp":    httpStartStop.GetStopTimestamp(),
		"uri":               httpStartStop.GetUri(),
		"user_agent":        httpStartStop.GetUserAgent(),
		"duration_ms":       (((httpStartStop.GetStopTimestamp() - httpStartStop.GetStartTimestamp()) / 1000) / 1000),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func LogMessage(msg *events.Envelope) Event {
	logMessage := msg.GetLogMessage()

	fields := logrus.Fields{
		"origin":          msg.GetOrigin(),
		"cf_app_id":       logMessage.GetAppId(),
		"timestamp":       logMessage.GetTimestamp(),
		"source_type":     logMessage.GetSourceType(),
		"message_type":    logMessage.GetMessageType().String(),
		"source_instance": logMessage.GetSourceInstance(),
	}

	return Event{
		Fields: fields,
		Msg:    string(logMessage.GetMessage()),
		Type:   msg.GetEventType().String(),
	}
}

func ValueMetric(msg *events.Envelope) Event {
	valMetric := msg.GetValueMetric()

	fields := logrus.Fields{
		"origin": msg.GetOrigin(),
		"name":   valMetric.GetName(),
		"unit":   valMetric.GetUnit(),
		"value":  valMetric.GetValue(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func CounterEvent(msg *events.Envelope) Event {
	counterEvent := msg.GetCounterEvent()

	fields := logrus.Fields{
		"origin": msg.GetOrigin(),
		"name":   counterEvent.GetName(),
		"delta":  counterEvent.GetDelta(),
		"total":  counterEvent.GetTotal(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func ErrorEvent(msg *events.Envelope) Event {
	errorEvent := msg.GetError()

	fields := logrus.Fields{
		"origin": msg.GetOrigin(),
		"code":   errorEvent.GetCode(),
		"delta":  errorEvent.GetSource(),
	}

	return Event{
		Fields: fields,
		Msg:    errorEvent.GetMessage(),
		Type:   msg.GetEventType().String(),
	}
}

func ContainerMetric(msg *events.Envelope) Event {
	containerMetric := msg.GetContainerMetric()

	fields := logrus.Fields{
		"origin":         msg.GetOrigin(),
		"cf_app_id":      containerMetric.GetApplicationId(),
		"cpu_percentage": containerMetric.GetCpuPercentage(),
		"disk_bytes":     containerMetric.GetDiskBytes(),
		"instance_index": containerMetric.GetInstanceIndex(),
		"memory_bytes":   containerMetric.GetMemoryBytes(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func (e *Event) AnnotateWithAppData() {

	cf_app_id := e.Fields["cf_app_id"]
	appGuid := ""
	if cf_app_id != nil {
		appGuid = fmt.Sprintf("%s", cf_app_id)
	}

	if cf_app_id != nil && appGuid != "<nil>" && cf_app_id != "" {
		appInfo := getAppInfo(appGuid)
		cf_app_name := appInfo.Name
		cf_space_id := appInfo.SpaceGuid
		cf_space_name := appInfo.SpaceName
		cf_org_id := appInfo.OrgGuid
		cf_org_name := appInfo.OrgName

		if cf_app_name != "" {
			e.Fields["cf_app_name"] = cf_app_name
		}

		if cf_space_id != "" {
			e.Fields["cf_space_id"] = cf_space_id
		}

		if cf_space_name != "" {
			e.Fields["cf_space_name"] = cf_space_name
		}

		if cf_org_id != "" {
			e.Fields["cf_org_id"] = cf_org_id
		}

		if cf_org_name != "" {
			e.Fields["cf_org_name"] = cf_org_name
		}
		e.Fields["cf_origin"] = "firehose"
		e.Fields["event_type"] = e.Type
	}
}

func (e Event) ShipEvent() {

	defer func() {
		if r := recover(); r != nil {
			log.LogError("Recovered in event.Log()", r)
		}
	}()

	logrus.WithFields(e.Fields).Info(e.Msg)
}
<commit_msg>Annotate the event with non app-data outside of AnnotateWithAppData.<commit_after>package events

import (
	"fmt"
	"github.com/Sirupsen/logrus"
	"github.com/cloudfoundry-community/firehose-to-syslog/caching"
	log "github.com/cloudfoundry-community/firehose-to-syslog/logging"
	"github.com/cloudfoundry/noaa/events"
	"strings"
)

type Event struct {
	Fields logrus.Fields
	Msg    string
	Type   string
}

var selectedEvents map[string]bool

func RouteEvents(in chan *events.Envelope) {
	for msg := range in {
		routeEvent(msg)
	}
}

func GetSelectedEvents() map[string]bool {
	return selectedEvents
}

func routeEvent(msg *events.Envelope) {

	eventType := msg.GetEventType()

	if selectedEvents[eventType.String()] {
		var event Event
		switch eventType {
		case events.Envelope_Heartbeat:
			event = Heartbeat(msg)
		case events.Envelope_HttpStart:
			event = HttpStart(msg)
		case events.Envelope_HttpStop:
			event = HttpStop(msg)
		case events.Envelope_HttpStartStop:
			event = HttpStartStop(msg)
		case events.Envelope_LogMessage:
			event = LogMessage(msg)
		case events.Envelope_ValueMetric:
			event = ValueMetric(msg)
		case events.Envelope_CounterEvent:
			event = CounterEvent(msg)
		case events.Envelope_Error:
			event = ErrorEvent(msg)
		case events.Envelope_ContainerMetric:
			event = ContainerMetric(msg)
		}

		event.AnnotateWithAppData()
		event.AnnotateWithMetaData()
		event.ShipEvent()
	}
}

func SetupEventRouting(wantedEvents string) {
	selectedEvents = make(map[string]bool)
	for _, event := range strings.Split(wantedEvents, ",") {
		if isAuthorizedEvent(event) {
			selectedEvents[event] = true
			log.LogStd(fmt.Sprintf("Event Type [%s] is included in the fireshose!", event), false)
		} else {
			log.LogError(fmt.Sprintf("Rejected Event Name [%s] - See wanted/selected events arg. Check Your Command Line Arguments!", event), "")
		}
	}
	// If any event is not authorize we fallback to the default one
	if len(selectedEvents) < 1 {
		selectedEvents["LogMessage"] = true
	}
}

func isAuthorizedEvent(wantedEvent string) bool {
	for _, authorizeEvent := range events.Envelope_EventType_name {
		if wantedEvent == authorizeEvent {
			return true
		}
	}
	return false
}

func GetListAuthorizedEventEvents() (authorizedEvents string) {
	arrEvents := []string{}
	for _, listEvent := range events.Envelope_EventType_name {
		arrEvents = append(arrEvents, listEvent)
	}
	return strings.Join(arrEvents, ", ")

}

func getAppInfo(appGuid string) caching.App {
	if app := caching.GetAppInfo(appGuid); app.Name != "" {
		return app
	} else {
		caching.GetAppByGuid(appGuid)
	}
	return caching.GetAppInfo(appGuid)
}

func Heartbeat(msg *events.Envelope) Event {
	heartbeat := msg.GetHeartbeat()

	var avail uint64

	if heartbeat.GetSentCount() > 0 {
		avail = heartbeat.GetReceivedCount() / heartbeat.GetSentCount()
	}

	fields := logrus.Fields{
		"ctl_msg_id":     heartbeat.GetControlMessageIdentifier(),
		"error_count":    heartbeat.GetErrorCount(),
		"origin":         msg.GetOrigin(),
		"received_count": heartbeat.GetReceivedCount(),
		"sent_count":     heartbeat.GetSentCount(),
		"availability":   avail,
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func HttpStart(msg *events.Envelope) Event {
	httpStart := msg.GetHttpStart()

	fields := logrus.Fields{
		"origin":            msg.GetOrigin(),
		"cf_app_id":         httpStart.GetApplicationId(),
		"instance_id":       httpStart.GetInstanceId(),
		"instance_index":    httpStart.GetInstanceIndex(),
		"method":            httpStart.GetMethod(),
		"parent_request_id": httpStart.GetParentRequestId(),
		"peer_type":         httpStart.GetPeerType(),
		"request_id":        httpStart.GetRequestId(),
		"remote_addr":       httpStart.GetRemoteAddress(),
		"timestamp":         httpStart.GetTimestamp(),
		"uri":               httpStart.GetUri(),
		"user_agent":        httpStart.GetUserAgent(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func HttpStop(msg *events.Envelope) Event {
	httpStop := msg.GetHttpStop()

	fields := logrus.Fields{
		"origin":         msg.GetOrigin(),
		"cf_app_id":      httpStop.GetApplicationId(),
		"content_length": httpStop.GetContentLength(),
		"peer_type":      httpStop.GetPeerType(),
		"request_id":     httpStop.GetRequestId(),
		"status_code":    httpStop.GetStatusCode(),
		"timestamp":      httpStop.GetTimestamp(),
		"uri":            httpStop.GetUri(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func HttpStartStop(msg *events.Envelope) Event {
	httpStartStop := msg.GetHttpStartStop()

	fields := logrus.Fields{
		"origin":            msg.GetOrigin(),
		"cf_app_id":         httpStartStop.GetApplicationId(),
		"content_length":    httpStartStop.GetContentLength(),
		"instance_id":       httpStartStop.GetInstanceId(),
		"instance_index":    httpStartStop.GetInstanceIndex(),
		"method":            httpStartStop.GetMethod(),
		"parent_request_id": httpStartStop.GetParentRequestId(),
		"peer_type":         httpStartStop.GetPeerType(),
		"remote_addr":       httpStartStop.GetRemoteAddress(),
		"request_id":        httpStartStop.GetRequestId(),
		"start_timestamp":   httpStartStop.GetStartTimestamp(),
		"status_code":       httpStartStop.GetStatusCode(),
		"stop_timestamp":    httpStartStop.GetStopTimestamp(),
		"uri":               httpStartStop.GetUri(),
		"user_agent":        httpStartStop.GetUserAgent(),
		"duration_ms":       (((httpStartStop.GetStopTimestamp() - httpStartStop.GetStartTimestamp()) / 1000) / 1000),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func LogMessage(msg *events.Envelope) Event {
	logMessage := msg.GetLogMessage()

	fields := logrus.Fields{
		"origin":          msg.GetOrigin(),
		"cf_app_id":       logMessage.GetAppId(),
		"timestamp":       logMessage.GetTimestamp(),
		"source_type":     logMessage.GetSourceType(),
		"message_type":    logMessage.GetMessageType().String(),
		"source_instance": logMessage.GetSourceInstance(),
	}

	return Event{
		Fields: fields,
		Msg:    string(logMessage.GetMessage()),
		Type:   msg.GetEventType().String(),
	}
}

func ValueMetric(msg *events.Envelope) Event {
	valMetric := msg.GetValueMetric()

	fields := logrus.Fields{
		"origin": msg.GetOrigin(),
		"name":   valMetric.GetName(),
		"unit":   valMetric.GetUnit(),
		"value":  valMetric.GetValue(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func CounterEvent(msg *events.Envelope) Event {
	counterEvent := msg.GetCounterEvent()

	fields := logrus.Fields{
		"origin": msg.GetOrigin(),
		"name":   counterEvent.GetName(),
		"delta":  counterEvent.GetDelta(),
		"total":  counterEvent.GetTotal(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func ErrorEvent(msg *events.Envelope) Event {
	errorEvent := msg.GetError()

	fields := logrus.Fields{
		"origin": msg.GetOrigin(),
		"code":   errorEvent.GetCode(),
		"delta":  errorEvent.GetSource(),
	}

	return Event{
		Fields: fields,
		Msg:    errorEvent.GetMessage(),
		Type:   msg.GetEventType().String(),
	}
}

func ContainerMetric(msg *events.Envelope) Event {
	containerMetric := msg.GetContainerMetric()

	fields := logrus.Fields{
		"origin":         msg.GetOrigin(),
		"cf_app_id":      containerMetric.GetApplicationId(),
		"cpu_percentage": containerMetric.GetCpuPercentage(),
		"disk_bytes":     containerMetric.GetDiskBytes(),
		"instance_index": containerMetric.GetInstanceIndex(),
		"memory_bytes":   containerMetric.GetMemoryBytes(),
	}

	return Event{
		Fields: fields,
		Msg:    "",
		Type:   msg.GetEventType().String(),
	}
}

func (e *Event) AnnotateWithAppData() {

	cf_app_id := e.Fields["cf_app_id"]
	appGuid := ""
	if cf_app_id != nil {
		appGuid = fmt.Sprintf("%s", cf_app_id)
	}

	if cf_app_id != nil && appGuid != "<nil>" && cf_app_id != "" {
		appInfo := getAppInfo(appGuid)
		cf_app_name := appInfo.Name
		cf_space_id := appInfo.SpaceGuid
		cf_space_name := appInfo.SpaceName
		cf_org_id := appInfo.OrgGuid
		cf_org_name := appInfo.OrgName

		if cf_app_name != "" {
			e.Fields["cf_app_name"] = cf_app_name
		}

		if cf_space_id != "" {
			e.Fields["cf_space_id"] = cf_space_id
		}

		if cf_space_name != "" {
			e.Fields["cf_space_name"] = cf_space_name
		}

		if cf_org_id != "" {
			e.Fields["cf_org_id"] = cf_org_id
		}

		if cf_org_name != "" {
			e.Fields["cf_org_name"] = cf_org_name
		}
	}
}

func (e *Event) AnnotateWithMetaData() {
	e.Fields["cf_origin"] = "firehose"
	e.Fields["event_type"] = e.Type
}

func (e Event) ShipEvent() {

	defer func() {
		if r := recover(); r != nil {
			log.LogError("Recovered in event.Log()", r)
		}
	}()

	logrus.WithFields(e.Fields).Info(e.Msg)
}
<|endoftext|>


<commit_before>package main

import (
	"./ganglia/api"
	"./ganglia/response"
	"fmt"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	node        = kingpin.Flag("node", "Node name to search").String()
	cluster     = kingpin.Flag("cluster", "Cluster name to search").String()
	metric      = kingpin.Flag("metric", "Metric name to search").String()
	threshhold  = kingpin.Flag("threshhold", "Threshhold value").Int()
	condition   = kingpin.Flag("condition", "Condition").Enum("eq", "gt", "ge", "lt", "le")
	listMetric  = kingpin.Flag("list-metrics", "List metrics").Bool()
	listNodes   = kingpin.Flag("list-nodes", "List nodes").Bool()
	lisClusters = kingpin.Flag("list-clusters", "List clusters").Bool()
	localPath   = kingpin.Flag("file", "Read gmeta response from local file").ExistingFile()
	remoteIP    = kingpin.Flag("host", "Read gmeta response from host, default: 127.0.0.1").Default("127.0.0.1").String()
	remotePort  = kingpin.Flag("port", "Read gmeta response from port, default: 8651").Default("8651").Int()
)

func main() {

	kingpin.Parse()

	gResp := response.GMetaResponse{}
	filter := response.MetricFilter{*metric, *node, *cluster, *condition, *threshhold}

	if *localPath != "" {
		gResp = api.ParseFile(*localPath)
	} else {
		gResp = api.ParseSocket(*remoteIP, *remotePort)
	}

	for _, metric := range gResp.Find(&filter) {
		fmt.Println(metric.GCluster)
		fmt.Println(metric.GHost)
		fmt.Println(metric.GMetric)
		fmt.Println()
	}

}
<commit_msg>Simplified cli; Added options: --list-(nodes|clusters|metrics)<commit_after>package main

import (
	"./ganglia/api"
	"./ganglia/response"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	// filters
	node    = kingpin.Flag("node", "Node name to search").String()
	cluster = kingpin.Flag("cluster", "Cluster name to search").String()
	metric  = kingpin.Flag("metric", "Metric name to search").String()
	// conditions
	threshhold = kingpin.Flag("threshhold", "Threshhold value").Int()
	condition  = kingpin.Flag("condition", "Condition").Enum("eq", "gt", "ge", "lt", "le")
	// source of the xml
	localPath  = kingpin.Flag("file", "Read gmeta response from local file").ExistingFile()
	remoteIP   = kingpin.Flag("host", "Read gmeta response from host, default: 127.0.0.1").Default("127.0.0.1").String()
	remotePort = kingpin.Flag("port", "Read gmeta response from port, default: 8651").Default("8651").Int()
	// list objects
	listMetric   = kingpin.Flag("list-metrics", "List metrics").Bool()
	listNodes    = kingpin.Flag("list-nodes", "List nodes").Bool()
	listClusters = kingpin.Flag("list-clusters", "List clusters").Bool()
)

func main() {

	kingpin.Parse()

	gResp := response.GMetaResponse{}
	filter := response.MetricFilter{*metric, *node, *cluster, *condition, *threshhold}

	if *localPath != "" {
		gResp = api.ParseFile(*localPath)
	} else {
		gResp = api.ParseSocket(*remoteIP, *remotePort)
	}

	s := api.NewGSet()
	for _, metric := range gResp.Find(&filter) {
		if *listClusters {
			s.PrintIfNotInSet(metric.GCluster.Name)
		}
		if *listNodes {
			s.PrintIfNotInSet(metric.GHost.Name)
		}
		if *listMetric {
			s.PrintIfNotInSet(metric.GMetric.Name)
		}
	}

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/JustinTulloss/hut"
	"github.com/facebookgo/httpcontrol"
	"github.com/temoto/robotstxt.go"
	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
)

var ogmatcher = regexp.MustCompile("(^(og|airbedandbreakfast|twitter):|^description$)")
var useragent = "Gogetter (https://github.com/JustinTulloss/gogetter) (like GoogleBot and facebookexternalhit)"
var service *hut.Service
var client *http.Client

type HttpError struct {
	msg        string
	StatusCode int
}

func (e *HttpError) Error() string { return e.msg }

func buildRequest(url string) (*http.Request, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("User-Agent", useragent)
	return req, nil
}

func checkRobotsTxt(fullUrl string) (bool, error) {
	parsed, err := url.Parse(fullUrl)
	if err != nil {
		return false, err
	}
	original := parsed.Path
	parsed.Path = "robots.txt"
	parsed.RawQuery = ""
	req, err := buildRequest(parsed.String())
	if err != nil {
		return false, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return false, err
	}
	defer resp.Body.Close()
	robots, err := robotstxt.FromResponse(resp)
	if robots == nil {
		// Assume we can crawl if the robots.txt file doesn't work
		return true, nil
	}
	return robots.TestAgent(original, useragent), nil
}

func parseTags(r io.Reader) (map[string]string, *HttpError) {
	node, err := html.Parse(r)
	if err != nil {
		return nil, &HttpError{err.Error(), 500}
	}
	var findmeta func(*html.Node)
	results := make(map[string]string)
	// Recursively goes through nodes looking for meta nodes that
	// have a property tag that matches the opengraph regex. If it does,
	// Saves the contents to the results map.
	findmeta = func(n *html.Node) {
		if n.Type == html.ElementNode && n.DataAtom == atom.Title {
			results["title"] = n.FirstChild.Data
		}
		if n.Type == html.ElementNode && n.DataAtom == atom.Link {
			var href string
			save := false
			for _, a := range n.Attr {
				if a.Key == "rel" && strings.Contains(a.Val, "icon") {
					save = true
				}
				if a.Key == "href" {
					href = html.UnescapeString(a.Val)
				}
			}
			if save {
				results["favicon"] = href
			}
		}
		if n.Type == html.ElementNode && n.DataAtom == atom.Meta {
			var content, property string
			save := false
			for _, a := range n.Attr {
				if (a.Key == "property" || a.Key == "name") && ogmatcher.FindStringIndex(a.Val) != nil {
					save = true
					property = html.UnescapeString(a.Val)
				}
				if a.Key == "content" {
					content = html.UnescapeString(a.Val)
				}
			}
			if save {
				results[property] = content
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			findmeta(c)
		}
	}
	findmeta(node)
	return results, nil
}

func getTags(url string) (map[string]string, *HttpError) {
	permitted, err := checkRobotsTxt(url)
	if err != nil {
		return nil, &HttpError{err.Error(), 500}
	}
	if !permitted {
		msg := fmt.Sprintf("Not permitted to fetch %s as a robot", url)
		log.Println(msg)
		return nil, &HttpError{msg, 403}
	}
	req, _ := buildRequest(url)
	resp, err := client.Do(req)
	if err != nil {
		return nil, &HttpError{err.Error(), 500}
	}
	log.Printf("Fetched %s\n", url)
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return nil, &HttpError{
			fmt.Sprintf("Could not fetch %s, request was: %v", url, req),
			resp.StatusCode,
		}
	}
	return parseTags(resp.Body)
}

func handler(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		service.ErrorReply(err, w)
		return
	}
	decodedUrl, err := url.QueryUnescape(r.Form.Get("url"))
	if err != nil {
		service.ErrorReply(err, w)
		return
	}
	tags, httpErr := getTags(decodedUrl)
	if httpErr != nil {
		service.HttpErrorReply(w, httpErr.Error(), httpErr.StatusCode)
		return
	}
	service.Reply(tags, w)
}

func main() {
	var err error
	service = hut.NewService(nil)
	jar, err := cookiejar.New(nil)
	if err != nil {
		service.Log.Error().Printf("Could not create cookie jar: %s\n", err)
	}
	service.Router.HandleFunc("/", handler)

	client = &http.Client{
		Transport: &httpcontrol.Transport{
			RequestTimeout: 10 * time.Second,
			MaxTries:       3,
		},
		Jar: jar,
	}

	flag.Parse()
	protocol := service.Env.Get("protocol")
	if protocol == "http" {
		service.Start()
	} else if len(flag.Args()) != 0 {
		tags, err := getTags(flag.Arg(0))
		if err != nil {
			fmt.Printf("Could not fetch: %s\n", err)
			return
		}
		for prop, val := range tags {
			fmt.Printf("%s -- %s\n", prop, val)
		}
	} else {
		panic("Need to use this properly and I need to print usage info!")
	}
}
<commit_msg>Add the option to turn off checking robots.txt<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"regexp"
	"strings"
	"time"

	"github.com/JustinTulloss/hut"
	"github.com/facebookgo/httpcontrol"
	"github.com/temoto/robotstxt.go"
	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
)

var ogmatcher = regexp.MustCompile("(^(og|airbedandbreakfast|twitter):|^description$)")
var useragent = "Gogetter (https://github.com/JustinTulloss/gogetter) (like GoogleBot and facebookexternalhit)"
var service *hut.Service
var client *http.Client

type HttpError struct {
	msg        string
	StatusCode int
}

func (e *HttpError) Error() string { return e.msg }

func buildRequest(url string) (*http.Request, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("User-Agent", useragent)
	return req, nil
}

func checkRobotsTxt(fullUrl string) (bool, error) {
	if service.Env.GetString("CHECK_ROBOTS_TXT") == "false" {
		return true, nil
	}
	parsed, err := url.Parse(fullUrl)
	if err != nil {
		return false, err
	}
	original := parsed.Path
	parsed.Path = "robots.txt"
	parsed.RawQuery = ""
	req, err := buildRequest(parsed.String())
	if err != nil {
		return false, err
	}
	resp, err := client.Do(req)
	if err != nil {
		return false, err
	}
	defer resp.Body.Close()
	robots, err := robotstxt.FromResponse(resp)
	if robots == nil {
		// Assume we can crawl if the robots.txt file doesn't work
		return true, nil
	}
	return robots.TestAgent(original, useragent), nil
}

func parseTags(r io.Reader) (map[string]string, *HttpError) {
	node, err := html.Parse(r)
	if err != nil {
		return nil, &HttpError{err.Error(), 500}
	}
	var findmeta func(*html.Node)
	results := make(map[string]string)
	// Recursively goes through nodes looking for meta nodes that
	// have a property tag that matches the opengraph regex. If it does,
	// Saves the contents to the results map.
	findmeta = func(n *html.Node) {
		if n.Type == html.ElementNode && n.DataAtom == atom.Title {
			results["title"] = n.FirstChild.Data
		}
		if n.Type == html.ElementNode && n.DataAtom == atom.Link {
			var href string
			save := false
			for _, a := range n.Attr {
				if a.Key == "rel" && strings.Contains(a.Val, "icon") {
					save = true
				}
				if a.Key == "href" {
					href = html.UnescapeString(a.Val)
				}
			}
			if save {
				results["favicon"] = href
			}
		}
		if n.Type == html.ElementNode && n.DataAtom == atom.Meta {
			var content, property string
			save := false
			for _, a := range n.Attr {
				if (a.Key == "property" || a.Key == "name") && ogmatcher.FindStringIndex(a.Val) != nil {
					save = true
					property = html.UnescapeString(a.Val)
				}
				if a.Key == "content" {
					content = html.UnescapeString(a.Val)
				}
			}
			if save {
				results[property] = content
			}
		}
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			findmeta(c)
		}
	}
	findmeta(node)
	return results, nil
}

func getTags(url string) (map[string]string, *HttpError) {
	permitted, err := checkRobotsTxt(url)
	if err != nil {
		return nil, &HttpError{err.Error(), 500}
	}
	if !permitted {
		msg := fmt.Sprintf("Not permitted to fetch %s as a robot", url)
		log.Println(msg)
		return nil, &HttpError{msg, 403}
	}
	req, _ := buildRequest(url)
	resp, err := client.Do(req)
	if err != nil {
		return nil, &HttpError{err.Error(), 500}
	}
	log.Printf("Fetched %s\n", url)
	defer resp.Body.Close()
	if resp.StatusCode != 200 {
		return nil, &HttpError{
			fmt.Sprintf("Could not fetch %s, request was: %v", url, req),
			resp.StatusCode,
		}
	}
	return parseTags(resp.Body)
}

func handler(w http.ResponseWriter, r *http.Request) {
	if err := r.ParseForm(); err != nil {
		service.ErrorReply(err, w)
		return
	}
	decodedUrl, err := url.QueryUnescape(r.Form.Get("url"))
	if err != nil {
		service.ErrorReply(err, w)
		return
	}
	tags, httpErr := getTags(decodedUrl)
	if httpErr != nil {
		service.HttpErrorReply(w, httpErr.Error(), httpErr.StatusCode)
		return
	}
	service.Reply(tags, w)
}

func main() {
	var err error
	service = hut.NewService(nil)
	jar, err := cookiejar.New(nil)
	if err != nil {
		service.Log.Error().Printf("Could not create cookie jar: %s\n", err)
	}
	service.Router.HandleFunc("/", handler)

	client = &http.Client{
		Transport: &httpcontrol.Transport{
			RequestTimeout: 10 * time.Second,
			MaxTries:       3,
		},
		Jar: jar,
	}

	flag.Parse()
	protocol := service.Env.Get("protocol")
	if protocol == "http" {
		service.Start()
	} else if len(flag.Args()) != 0 {
		tags, err := getTags(flag.Arg(0))
		if err != nil {
			fmt.Printf("Could not fetch: %s\n", err)
			return
		}
		for prop, val := range tags {
			fmt.Printf("%s -- %s\n", prop, val)
		}
	} else {
		panic("Need to use this properly and I need to print usage info!")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"

	"sync"
)

type peerKind int

const (
	client peerKind = iota
	server
)

type peerInfo struct {
	Kind    peerKind
	Name    string
	ID      string
	Channel chan string
}

const peerIDParamName string = "peer_id"
const toParamName string = "to"

const peerMessageBufferSize int = 100

var peers = make(map[string]peerInfo)

var peerIDCount uint
var peerMutex sync.Mutex

func printReqHandler(res http.ResponseWriter, req *http.Request) {
	reqDump, err := httputil.DumpRequest(req, true)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(reqDump))
}

func registerHandler(path string, handlerFunc func(http.ResponseWriter, *http.Request)) {
	if path != "" {
		fmt.Printf("Registering handler for %s", path)
		fmt.Println()
		http.HandleFunc(path, handlerFunc)
	}
}

func setConnectionHeader(header http.Header, close bool) {
	if close {
		header.Set("Connection", "close")
	} else {
		header.Set("Connection", "keep-alive")
	}
}

func setVersionHeader(header http.Header) {
	header.Set("Server", "PeerConnectionTestServer/0.1g")
}

func setNoCacheHeader(header http.Header) {
	header.Set("Cache-Control", "no-cache")
}

func addCorsHeaders(header http.Header) {
	header.Set("Access-Control-Allow-Origin", "*")
	header.Set("Access-Control-Allow-Credentials", "true")
	header.Set("Access-Control-Allow-Methods", strings.Join([]string{"GET", "POST", "OPTIONS"}, ","))
	header.Set("Access-Control-Allow-Headers", strings.Join([]string{"Content-Type", "Content-Length", "Cache-Control", "Connection"}, ","))
	header.Set("Access-Control-Expose-Headers", strings.Join([]string{"Content-Length", "X-Peer-Id"}, ","))
}

func addPragmaHeader(header http.Header, peerID string) {
	header.Set("Pragma", peerID)
}

func addCommonHeaders(header http.Header, closeConnection bool) {
	setConnectionHeader(header, closeConnection)
	setNoCacheHeader(header)
	setVersionHeader(header)
	addCorsHeaders(header)
}

func signinHandler(res http.ResponseWriter, req *http.Request) {
	addCommonHeaders(res.Header(), true)

	if req.Method != "GET" {
		http.Error(res, "Bad request", http.StatusBadRequest)
		return
	}
	var name string
	// Parse out peer name
	for k, v := range req.URL.Query() {
		if v[0] == "" {
			name = k
			break
		}
	}

	if name == "" {
		http.Error(res, "No name", http.StatusBadRequest)
		return
	}

	var peerInfo peerInfo
	peerInfo.Name = name
	peerInfo.Channel = make(chan string, peerMessageBufferSize)

	// Determine peer type
	if strings.Index(name, "renderingserver_") == 0 {
		peerInfo.Kind = server
	}

	// Generate id
	peerMutex.Lock()
	peerIDCount++
	peerInfo.ID = fmt.Sprintf("%d", peerIDCount)
	peerMutex.Unlock()

	peers[peerInfo.ID] = peerInfo

	addPragmaHeader(res.Header(), peerInfo.ID)

	peerInfoString := fmt.Sprintf("%s,%s,1", peerInfo.Name, peerInfo.ID)
	peerInfoString += fmt.Sprintln()
	responseString := peerInfoString

	// Return above + current peers (filtered for oppositing type)
	for pID, pInfo := range peers {
		if pID != peerInfo.ID && pInfo.Kind != peerInfo.Kind {
			responseString += fmt.Sprintf("%s,%s,1", pInfo.Name, pInfo.ID)
			responseString += fmt.Sprintln()

			// Also notify these peers that the new one exists
			if len(pInfo.Channel) < cap(pInfo.Channel) {
				pInfo.Channel <- peerInfoString
			} else {
				// TODO: Figure out what to do when peeer message buffer fills up
			}
		}
	}
	res.WriteHeader(http.StatusOK)
	fmt.Fprintf(res, responseString)
	// http.Error(res, "Not implemented "+name+" "+uuid.String(), http.statusadd)
}

func signoutHandler(res http.ResponseWriter, req *http.Request) {
	if req.Method != "GET" {
		http.Error(res, "Bad request", http.StatusBadRequest)
		return
	}
	addCommonHeaders(res.Header(), true)
	var peerID string
	// Parse out peers id
	for k, v := range req.URL.Query() {
		if k == peerIDParamName {
			peerID = v[0]
		}
	}
	_, exists := peers[peerID]
	if !exists {
		http.Error(res, "Unknown peer", http.StatusBadRequest)
		return
	}
	addPragmaHeader(res.Header(), peerID)
	delete(peers, peerID)
	res.WriteHeader(http.StatusOK)
}

func messageHandler(res http.ResponseWriter, req *http.Request) {
	if req.Method != "POST" {
		http.Error(res, "Bad request", http.StatusBadRequest)
		return
	}

	// Parse out from id
	// Parse out to id
	peerID, peerExists := req.URL.Query()[peerIDParamName]
	toID, toExists := req.URL.Query()[toParamName]

	if !peerExists || !toExists {
		http.Error(res, "Missing Peer or To ID", http.StatusBadRequest)
		return
	}

	_, peerInfoExists := peers[peerID[0]]
	to, toInfoExists := peers[toID[0]]

	if !peerInfoExists || !toInfoExists {
		http.Error(res, "Invalid Peer or To ID", http.StatusBadRequest)
		return
	}

	addPragmaHeader(res.Header(), peerID[0])

	requestData, err := ioutil.ReadAll(req.Body)
	if err != nil {
		http.Error(res, err.Error(), http.StatusInternalServerError)
	}
	requestString := string(requestData)
	defer req.Body.Close()
	// Look up channel for to id
	if len(to.Channel) == cap(to.Channel) {
		http.Error(res, "Peer is backed up", http.StatusServiceUnavailable)
		return
	}
	to.Channel <- requestString

	// Send message to channel for to id
	res.WriteHeader(http.StatusOK)
}

func waitHandler(res http.ResponseWriter, req *http.Request) {
	addCommonHeaders(res.Header(), true)

	if req.Method != "GET" {
		http.Error(res, "Bad request", http.StatusBadRequest)
		return
	}

	// Parse out peer id
	peerID, peerExists := req.URL.Query()[peerIDParamName]

	if !peerExists {
		http.Error(res, "Missing Peer ID", http.StatusBadRequest)
		return
	}

	peerInfo, peerInfoExists := peers[peerID[0]]

	if !peerInfoExists {
		http.Error(res, "Unknown peer", http.StatusBadRequest)
		return
	}

	addPragmaHeader(res.Header(), peerID[0])

	// Look up message channel for peers id
	// Wait for message to reply
	responseString := <-peerInfo.Channel

	res.WriteHeader(http.StatusOK)
	fmt.Fprint(res, responseString)
}

func main() {

	fmt.Println("gosigsrv starting")
	fmt.Println()

	port := os.Getenv("PORT")
	if port == "" {
		port = "8087"
	}

	fmt.Printf("Will listen on port %s\n\n", port)

	// Register handlers
	registerHandler("/sign_in", signinHandler)
	registerHandler("/sign_out", signoutHandler)
	registerHandler("/message", messageHandler)
	registerHandler("/wait", waitHandler)
	registerHandler("/", printReqHandler)

	// Start listening
	http.ListenAndServe(fmt.Sprintf(":%s", port), nil)
	fmt.Println()
	fmt.Println("gosigsrv exiting")
}
<commit_msg>Set Pragma (peer) header correctly for wait/msg operations<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"

	"sync"
)

type peerKind int

const (
	client peerKind = iota
	server
)

type peerMsg struct {
	FromID  string
	Message string
}

type peerInfo struct {
	Kind    peerKind
	Name    string
	ID      string
	Channel chan peerMsg
}

const peerIDParamName string = "peer_id"
const toParamName string = "to"

const peerMessageBufferSize int = 100

var peers = make(map[string]peerInfo)

var peerIDCount uint
var peerMutex sync.Mutex

func printReqHandler(res http.ResponseWriter, req *http.Request) {
	reqDump, err := httputil.DumpRequest(req, true)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(string(reqDump))
}

func registerHandler(path string, handlerFunc func(http.ResponseWriter, *http.Request)) {
	if path != "" {
		fmt.Printf("Registering handler for %s", path)
		fmt.Println()
		http.HandleFunc(path, handlerFunc)
	}
}

func setConnectionHeader(header http.Header, close bool) {
	if close {
		header.Set("Connection", "close")
	} else {
		header.Set("Connection", "keep-alive")
	}
}

func setVersionHeader(header http.Header) {
	header.Set("Server", "PeerConnectionTestServer/0.1g")
}

func setNoCacheHeader(header http.Header) {
	header.Set("Cache-Control", "no-cache")
}

func addCorsHeaders(header http.Header) {
	header.Set("Access-Control-Allow-Origin", "*")
	header.Set("Access-Control-Allow-Credentials", "true")
	header.Set("Access-Control-Allow-Methods", strings.Join([]string{"GET", "POST", "OPTIONS"}, ","))
	header.Set("Access-Control-Allow-Headers", strings.Join([]string{"Content-Type", "Content-Length", "Cache-Control", "Connection"}, ","))
	header.Set("Access-Control-Expose-Headers", strings.Join([]string{"Content-Length", "X-Peer-Id"}, ","))
}

func addPragmaHeader(header http.Header, peerID string) {
	header.Set("Pragma", peerID)
}

func addCommonHeaders(header http.Header, closeConnection bool) {
	setConnectionHeader(header, closeConnection)
	setNoCacheHeader(header)
	setVersionHeader(header)
	addCorsHeaders(header)
}

func signinHandler(res http.ResponseWriter, req *http.Request) {
	addCommonHeaders(res.Header(), true)

	if req.Method != "GET" {
		http.Error(res, "Bad request", http.StatusBadRequest)
		return
	}
	var name string
	// Parse out peer name
	for k, v := range req.URL.Query() {
		if v[0] == "" {
			name = k
			break
		}
	}

	if name == "" {
		http.Error(res, "No name", http.StatusBadRequest)
		return
	}

	var peerInfo peerInfo
	peerInfo.Name = name
	peerInfo.Channel = make(chan peerMsg, peerMessageBufferSize)

	// Determine peer type
	if strings.Index(name, "renderingserver_") == 0 {
		peerInfo.Kind = server
	}

	// Generate id
	peerMutex.Lock()
	peerIDCount++
	peerInfo.ID = fmt.Sprintf("%d", peerIDCount)
	peerMutex.Unlock()

	peers[peerInfo.ID] = peerInfo

	addPragmaHeader(res.Header(), peerInfo.ID)

	peerInfoString := fmt.Sprintf("%s,%s,1", peerInfo.Name, peerInfo.ID)
	peerInfoString += fmt.Sprintln()
	responseString := peerInfoString

	// Return above + current peers (filtered for oppositing type)
	for pID, pInfo := range peers {
		if pID != peerInfo.ID && pInfo.Kind != peerInfo.Kind {
			responseString += fmt.Sprintf("%s,%s,1", pInfo.Name, pInfo.ID)
			responseString += fmt.Sprintln()

			// Also notify these peers that the new one exists
			if len(pInfo.Channel) < cap(pInfo.Channel) {
				pInfo.Channel <- peerMsg{peerInfo.ID, peerInfoString}
			} else {
				// TODO: Figure out what to do when peeer message buffer fills up
			}
		}
	}
	res.WriteHeader(http.StatusOK)
	fmt.Fprintf(res, responseString)
	// http.Error(res, "Not implemented "+name+" "+uuid.String(), http.statusadd)
}

func signoutHandler(res http.ResponseWriter, req *http.Request) {
	if req.Method != "GET" {
		http.Error(res, "Bad request", http.StatusBadRequest)
		return
	}
	addCommonHeaders(res.Header(), true)
	var peerID string
	// Parse out peers id
	for k, v := range req.URL.Query() {
		if k == peerIDParamName {
			peerID = v[0]
		}
	}
	_, exists := peers[peerID]
	if !exists {
		http.Error(res, "Unknown peer", http.StatusBadRequest)
		return
	}
	addPragmaHeader(res.Header(), peerID)
	delete(peers, peerID)
	res.WriteHeader(http.StatusOK)
}

func messageHandler(res http.ResponseWriter, req *http.Request) {
	if req.Method != "POST" {
		http.Error(res, "Bad request", http.StatusBadRequest)
		return
	}

	// Parse out from id
	// Parse out to id
	peerID, peerExists := req.URL.Query()[peerIDParamName]
	toID, toExists := req.URL.Query()[toParamName]

	if !peerExists || !toExists {
		http.Error(res, "Missing Peer or To ID", http.StatusBadRequest)
		return
	}

	_, peerInfoExists := peers[peerID[0]]
	to, toInfoExists := peers[toID[0]]

	if !peerInfoExists || !toInfoExists {
		http.Error(res, "Invalid Peer or To ID", http.StatusBadRequest)
		return
	}

	addPragmaHeader(res.Header(), peerID[0])

	requestData, err := ioutil.ReadAll(req.Body)
	if err != nil {
		http.Error(res, err.Error(), http.StatusInternalServerError)
	}
	requestString := string(requestData)
	defer req.Body.Close()
	// Look up channel for to id
	if len(to.Channel) == cap(to.Channel) {
		http.Error(res, "Peer is backed up", http.StatusServiceUnavailable)
		return
	}
	to.Channel <- peerMsg{peerID[0], requestString}

	// Send message to channel for to id
	res.WriteHeader(http.StatusOK)
}

func waitHandler(res http.ResponseWriter, req *http.Request) {
	addCommonHeaders(res.Header(), true)

	if req.Method != "GET" {
		http.Error(res, "Bad request", http.StatusBadRequest)
		return
	}

	// Parse out peer id
	peerID, peerExists := req.URL.Query()[peerIDParamName]

	if !peerExists {
		http.Error(res, "Missing Peer ID", http.StatusBadRequest)
		return
	}

	peerInfo, peerInfoExists := peers[peerID[0]]

	if !peerInfoExists {
		http.Error(res, "Unknown peer", http.StatusBadRequest)
		return
	}

	// Look up message channel for peers id
	// Wait for message to reply
	peerMsg := <-peerInfo.Channel
	addPragmaHeader(res.Header(), peerMsg.FromID)
	res.WriteHeader(http.StatusOK)
	fmt.Fprint(res, peerMsg.Message)
}

func main() {

	fmt.Println("gosigsrv starting")
	fmt.Println()

	port := os.Getenv("PORT")
	if port == "" {
		port = "8087"
	}

	fmt.Printf("Will listen on port %s\n\n", port)

	// Register handlers
	registerHandler("/sign_in", signinHandler)
	registerHandler("/sign_out", signoutHandler)
	registerHandler("/message", messageHandler)
	registerHandler("/wait", waitHandler)
	registerHandler("/", printReqHandler)

	// Start listening
	http.ListenAndServe(fmt.Sprintf(":%s", port), nil)
	fmt.Println()
	fmt.Println("gosigsrv exiting")
}
<|endoftext|>


<commit_before>package gouuidv6

import (
	"crypto/rand"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"net"
	"sync/atomic"
	"time"
)

var bigEnd = binary.BigEndian

// "Version 6" UUID.
type UUID [16]byte

// Textual representation per RFC 4122, e.g. "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
func (u UUID) String() string {
	return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", u[:4], u[4:6], u[6:8], u[8:10], u[10:])
}

// Parse text representation
func Parse(us string) (UUID, error) {
	var ret UUID
	var v1, v2, v3, v4, v5 uint64
	_, err := fmt.Sscanf(us, "%08x-%04x-%04x-%04x-%012x", &v1, &v2, &v3, &v4, &v5)
	if err != nil {
		return ret, err
	}
	bigEnd.PutUint64(ret[8:], v5)
	bigEnd.PutUint16(ret[8:10], uint16(v4))
	bigEnd.PutUint16(ret[6:8], uint16(v3))
	bigEnd.PutUint16(ret[4:6], uint16(v2))
	bigEnd.PutUint32(ret[:4], uint32(v1))
	return ret, nil
}

func (u UUID) MarshalText() ([]byte, error)           { return []byte(u.String()), nil }
func (u *UUID) UnmarshalText(text []byte) (err error) { *u, err = Parse(string(text)); return }

func (u UUID) MarshalBinary() ([]byte, error)     { return u[:], nil }
func (u *UUID) UnmarshalBinary(data []byte) error { copy(u[:], data); return nil }

func (u UUID) MarshalJSON() ([]byte, error) { return []byte(`"` + u.String() + `"`), nil }
func (u *UUID) UnmarshalJSON(data []byte) error {
	s := ""
	err := json.Unmarshal(data, &s)
	if err != nil {
		return err
	}
	*u, err = Parse(s)
	return err
}

// Return as byte slice.
func (u UUID) Bytes() []byte { return u[:] }

// Return true if all UUID bytes are zero.
func (u UUID) IsNil() bool { return (bigEnd.Uint64(u[0:8]) | bigEnd.Uint64(u[8:16])) == 0 }

// Extract and return the time from the UUID.
func (u UUID) Time() time.Time {

	hi := uint64(bigEnd.Uint64(u[:8]))

	// chop the version data out and form the number we want
	t := ((hi >> 4) & 0xFFFFFFFFFFFFF000) | (0x0FFF & hi)

	// convert to nanoseconds
	ut := int64(t-tsoff) * 100

	return time.Unix(ut/int64(time.Second), ut%int64(time.Second))
}

// Return a new UUID initialized to a proper value according to "Version 6" rules.
func New() UUID {

	var ret UUID

	// increment and get clock sequence - a simple and fast way of using
	// clock sequence to avoid duplication
	cs := atomic.AddUint32(&clockseq, 1)

	// get timestamp
	tsval := ts()

	// shift up 4 bits, mask back in the relevant lower part and set the version
	hi := uint64(((tsval << 4) & 0xFFFFFFFFFFFF0000) | (tsval & 0x0FFF) | 0x6000)

	// 2 bit variant, 14 bits clock sequence, 48 bits node
	lo := uint64(0x80) | (uint64(cs&0x3fff) << 48) | node

	bigEnd.PutUint64(ret[:8], hi)
	bigEnd.PutUint64(ret[8:], lo)

	return ret

}

// Returns a timestamp appropriate for UUID time
func ts() uint64 { return tsoff + uint64(time.Now().UnixNano()/100) }

// UUID static time offset (see https://play.golang.org/p/pPJd86iZMW)
const tsoff = uint64(122192928000000000)

// clock sequence value (32-bit so we can use sync/atomic)
var clockseq uint32

// the node part - based on interface MAC address or random
var node uint64

func init() {

	b := make([]byte, 8)

	// start with random clock sequence
	rand.Read(b)
	clockseq = bigEnd.Uint32(b[:4])

	// try to get first interface MAC and use that for node
	ifs, _ := net.Interfaces()
	for _, i := range ifs {
		if len(i.HardwareAddr) >= 6 {
			node = uint64(bigEnd.Uint16(i.HardwareAddr[:2]))<<32 | uint64(bigEnd.Uint32(i.HardwareAddr[2:6]))
			break
		}
	}

	// no node yet, make it random
	if node == 0 {
		rand.Read(b)
		// mask out high 2 bytes and set the multicast bit
		node = (bigEnd.Uint64(b[:8]) & 0x0000FFFFFFFFFFFF) | 0x0000010000000000
	}

}
<commit_msg>better clockseq behavior; requires mutex but performs roughly the same as sync/atomic<commit_after>package gouuidv6

import (
	"crypto/rand"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"net"
	"sync"
	"time"
)

var bigEnd = binary.BigEndian

// "Version 6" UUID.
type UUID [16]byte

// Textual representation per RFC 4122, e.g. "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
func (u UUID) String() string {
	return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", u[:4], u[4:6], u[6:8], u[8:10], u[10:])
}

// Parse text representation
func Parse(us string) (UUID, error) {
	var ret UUID
	var v1, v2, v3, v4, v5 uint64
	_, err := fmt.Sscanf(us, "%08x-%04x-%04x-%04x-%012x", &v1, &v2, &v3, &v4, &v5)
	if err != nil {
		return ret, err
	}
	bigEnd.PutUint64(ret[8:], v5)
	bigEnd.PutUint16(ret[8:10], uint16(v4))
	bigEnd.PutUint16(ret[6:8], uint16(v3))
	bigEnd.PutUint16(ret[4:6], uint16(v2))
	bigEnd.PutUint32(ret[:4], uint32(v1))
	return ret, nil
}

func (u UUID) MarshalText() ([]byte, error)           { return []byte(u.String()), nil }
func (u *UUID) UnmarshalText(text []byte) (err error) { *u, err = Parse(string(text)); return }

func (u UUID) MarshalBinary() ([]byte, error)     { return u[:], nil }
func (u *UUID) UnmarshalBinary(data []byte) error { copy(u[:], data); return nil }

func (u UUID) MarshalJSON() ([]byte, error) { return []byte(`"` + u.String() + `"`), nil }
func (u *UUID) UnmarshalJSON(data []byte) error {
	s := ""
	err := json.Unmarshal(data, &s)
	if err != nil {
		return err
	}
	*u, err = Parse(s)
	return err
}

// Return as byte slice.
func (u UUID) Bytes() []byte { return u[:] }

// Return true if all UUID bytes are zero.
func (u UUID) IsNil() bool { return (bigEnd.Uint64(u[0:8]) | bigEnd.Uint64(u[8:16])) == 0 }

// Extract and return the time from the UUID.
func (u UUID) Time() time.Time {

	hi := uint64(bigEnd.Uint64(u[:8]))

	// chop the version data out and form the number we want
	t := ((hi >> 4) & 0xFFFFFFFFFFFFF000) | (0x0FFF & hi)

	// convert to nanoseconds
	ut := int64(t-tsoff) * 100

	return time.Unix(ut/int64(time.Second), ut%int64(time.Second))
}

// Return a new UUID initialized to a proper value according to "Version 6" rules.
func New() UUID {

	// NOTE: We intentionally ignore RFC 4122 section 4.2.1.2. and in the case
	// that UUIDs are requested within the same 100-nanosecond time interval,
	// we just increment the clock sequence - the same thing the RFC advises
	// in the case of the clock moving backward (section 4.1.5).

	// get current timestamp
	tsval := ts()

	newlock.Lock()
	// if clock is the same as last time or moved backward, increment clockseq
	if lastts >= tsval {
		clockseq++
	}
	lastts = tsval
	cs := clockseq
	newlock.Unlock()

	var ret UUID

	// shift up 4 bits, mask back in the relevant lower part and set the version
	hi := uint64(((tsval << 4) & 0xFFFFFFFFFFFF0000) | (tsval & 0x0FFF) | 0x6000)

	// 2 bit variant, 14 bits clock sequence, 48 bits node
	lo := uint64(0x80) | (uint64(cs&0x3fff) << 48) | node

	bigEnd.PutUint64(ret[:8], hi)
	bigEnd.PutUint64(ret[8:], lo)

	return ret

}

// Returns a timestamp appropriate for UUID time
func ts() uint64 { return tsoff + uint64(time.Now().UnixNano()/100) }

// UUID static time offset (see https://play.golang.org/p/pPJd86iZMW)
const tsoff = uint64(122192928000000000)

// lock we use when creating new UUIDs
var newlock sync.Mutex

// last timestamp used
var lastts uint64

// clock sequence value (32-bit so we can use sync/atomic)
var clockseq uint32

// the node part - based on interface MAC address or random
var node uint64

func init() {

	b := make([]byte, 8)

	// start with random clock sequence
	rand.Read(b)
	clockseq = bigEnd.Uint32(b[:4])

	// try to get first interface MAC and use that for node
	ifs, _ := net.Interfaces()
	for _, i := range ifs {
		if len(i.HardwareAddr) >= 6 {
			node = uint64(bigEnd.Uint16(i.HardwareAddr[:2]))<<32 | uint64(bigEnd.Uint32(i.HardwareAddr[2:6]))
			break
		}
	}

	// no node yet, make it random
	if node == 0 {
		rand.Read(b)
		// mask out high 2 bytes and set the multicast bit
		node = (bigEnd.Uint64(b[:8]) & 0x0000FFFFFFFFFFFF) | 0x0000010000000000
	}

}
<|endoftext|>


<commit_before>package main

import "testing"

func TestNewGpx(t *testing.T) {
	gpx := NewGpx()

	if gpx == nil {
		t.Error("Expected Gpx struct.")
	}
}

func TestNewGpxXMLNs(t *testing.T) {
	gpx := NewGpx()

	xmlnsE := "http://www.topografix.com/GPX/1/1"
	xmlnsA := gpx.XMLNs
	if xmlnsE != xmlnsA {
		t.Error("Expected %s XMLNs but got %s", xmlnsE, xmlnsA)
	}
}

func TestNewGpxXMLNsXsi(t *testing.T) {
	gpx := NewGpx()

	xmlnsXsiE := "http://www.w3.org/2001/XMLSchema-instance"
	xmlnsXsiA := gpx.XMLNsXsi
	if xmlnsXsiE != xmlnsXsiA {
		t.Error("Expected %s XMLNsXsi but got %s", xmlnsXsiE, xmlnsXsiA)
	}
}

func TestNewGpxXMLSchemaLoc(t *testing.T) {
	gpx := NewGpx()

	xmlSchemaLocE := "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
	xmlSchemaLocA := gpx.XMLSchemaLoc
	if xmlSchemaLocE != xmlSchemaLocA {
		t.Error("Expected %s XMLSchemaLoc but got %s", xmlSchemaLocE, xmlSchemaLocA)
	}
}

func TestNewGpxVersion(t *testing.T) {
	gpx := NewGpx()

	versionE := "1.1"
	versionA := gpx.Version
	if versionE != versionA {
		t.Error("Expected %s Version but got %s", versionE, versionA)
	}
}

func TestGetWaypoints(t *testing.T) {
	var gpx *Gpx
	gpx, _ = ParseFile("sample/sample.gpx")
	expectedWaypoints := gpx.Tracks[0].Segments[0].Waypoints

	waypoints := gpx.GetWaypoints()

	if len(waypoints) != len(expectedWaypoints) {
		t.Errorf("Expected %d waypoints but got %d waypoints", len(expectedWaypoints), len(waypoints))
	}
}
<commit_msg>t.Error > t.Errorf<commit_after>package main

import "testing"

func TestNewGpx(t *testing.T) {
	gpx := NewGpx()

	if gpx == nil {
		t.Error("Expected Gpx struct.")
	}
}

func TestNewGpxXMLNs(t *testing.T) {
	gpx := NewGpx()

	xmlnsE := "http://www.topografix.com/GPX/1/1"
	xmlnsA := gpx.XMLNs
	if xmlnsE != xmlnsA {
		t.Errorf("Expected %s XMLNs but got %s", xmlnsE, xmlnsA)
	}
}

func TestNewGpxXMLNsXsi(t *testing.T) {
	gpx := NewGpx()

	xmlnsXsiE := "http://www.w3.org/2001/XMLSchema-instance"
	xmlnsXsiA := gpx.XMLNsXsi
	if xmlnsXsiE != xmlnsXsiA {
		t.Errorf("Expected %s XMLNsXsi but got %s", xmlnsXsiE, xmlnsXsiA)
	}
}

func TestNewGpxXMLSchemaLoc(t *testing.T) {
	gpx := NewGpx()

	xmlSchemaLocE := "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
	xmlSchemaLocA := gpx.XMLSchemaLoc
	if xmlSchemaLocE != xmlSchemaLocA {
		t.Errorf("Expected %s XMLSchemaLoc but got %s", xmlSchemaLocE, xmlSchemaLocA)
	}
}

func TestNewGpxVersion(t *testing.T) {
	gpx := NewGpx()

	versionE := "1.1"
	versionA := gpx.Version
	if versionE != versionA {
		t.Errorf("Expected %s Version but got %s", versionE, versionA)
	}
}

func TestGetWaypoints(t *testing.T) {
	var gpx *Gpx
	gpx, _ = ParseFile("sample/sample.gpx")
	expectedWaypoints := gpx.Tracks[0].Segments[0].Waypoints

	waypoints := gpx.GetWaypoints()

	if len(waypoints) != len(expectedWaypoints) {
		t.Errorf("Expected %d waypoints but got %d waypoints", len(expectedWaypoints), len(waypoints))
	}
}
<|endoftext|>


<commit_before>package convertutil

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"

	"github.com/grokify/gotilla/cmd/cmdutil"
)

/*
https://stackoverflow.com/questions/9586048/imagemagick-no-decode-delegate

brew uninstall graphicsmagick jpeg libtiff jasper
brew install imagemagick

*/

const (
	PdfWidth                      = 1950
	KindleWidth                   = 600
	PressDpi                      = 300
	WebDpi                        = 72
	ResolutionPixelsPerInchString = "PixelsPerInch"
	ConvertFormat                 = `convert %s -resize %sX%s %s %s %s`
	//ConvertFormat                 = `convert %s -resize %sx%s -set units %s -density %d %s`
)

type ResolutionUnits int

const (
	ResolutionUndefined           ResolutionUnits = iota // 0 convert cli value
	ResolutionPixelsPerInch                              // 1 convert cli value
	ResolutionPixelsPerCentimeter                        // 2 convert cli value
)

type ConvertParams struct {
	SourcePath        string
	OutputPath        string
	OutputWidth       int
	OutputHeight      int
	ResolutionDensity int
	ResolutionUnits   ResolutionUnits
}

/*
	cmdPDF := convertutil.ConvertCommand(
		filepathOrg, filepathPDF, convertutil.PdfWidth, 0, convertutil.PressDpi,
		convertutil.ResolutionPixelsPerInch)
*/

//func ConvertCommand(srcPath, outPath string, width, height, resolutionDensity, resolutionUnits int) string {

func ConvertCommand(params ConvertParams) string {
	widthStr := ""
	heightStr := ""
	densityStr := ""
	unitsStr := ""
	if params.OutputWidth > 0 {
		widthStr = strconv.Itoa(params.OutputWidth)
	}
	if params.OutputHeight > 0 {
		heightStr = strconv.Itoa(params.OutputHeight)
	}
	if params.ResolutionDensity > 0 {
		densityStr = fmt.Sprintf(" -density %d", params.ResolutionDensity)
	} /*
		if len(resolutionUnits) > 0 {
			unitsStr = fmt.Sprintf(` -set units %s`, resolutionUnits)
		}*/
	if params.ResolutionUnits == ResolutionPixelsPerInch {
		unitsStr = fmt.Sprintf(` -set units %s`, ResolutionPixelsPerInchString)
	}
	if 1 == 0 {
		quote := `"`
		params.SourcePath = quote + strings.TrimSpace(params.SourcePath) + quote
		params.OutputPath = quote + strings.TrimSpace(params.OutputPath) + quote
	}
	cmd := fmt.Sprintf(
		ConvertFormat,
		params.SourcePath,
		widthStr,
		heightStr,
		unitsStr,
		densityStr,
		params.OutputPath)

	return cmd

	//convert input.jpg -resize 1950x -set units PixelsPerInch -density 300 output.jpg
}

func ConvertToKindle(sourcePath, outputPath string) (bytes.Buffer, bytes.Buffer, error) {
	command := ConvertCommand(ConvertParams{
		SourcePath:        sourcePath,
		OutputPath:        outputPath,
		OutputWidth:       KindleWidth,
		OutputHeight:      0,
		ResolutionDensity: PressDpi,
		ResolutionUnits:   ResolutionPixelsPerInch})
	return cmdutil.ExecSimple(command)
}

func ConvertToPDF(sourcePath, outputPath string) (bytes.Buffer, bytes.Buffer, error) {
	command := ConvertCommand(ConvertParams{
		SourcePath:        sourcePath,
		OutputPath:        outputPath,
		OutputWidth:       KindleWidth,
		OutputHeight:      0,
		ResolutionDensity: PressDpi,
		ResolutionUnits:   ResolutionPixelsPerInch})
	fmt.Println(command)
	return cmdutil.ExecSimple(command)
}

const (
	convertErrorStatus = "exit status 1"
	convertError       = "convert: no decode delegate for this image format `'"
)

// CheckError removes the error if ReadImage doesn't work.
// exit status 1: convert: no decode delegate for this image format `' @ error/constitute.c/ReadImage/501.
func CheckError(err error, stderr bytes.Buffer) error {
	if err.Error() == convertErrorStatus &&
		strings.Index(stderr.String(), convertError) > -1 {
		return nil
	}
	return err
}
<commit_msg>fix image/convertutil bug<commit_after>package convertutil

import (
	"bytes"
	"fmt"
	"strconv"
	"strings"

	"github.com/grokify/gotilla/cmd/cmdutil"
)

/*
https://stackoverflow.com/questions/9586048/imagemagick-no-decode-delegate

brew uninstall graphicsmagick jpeg libtiff jasper
brew install imagemagick

*/

const (
	PdfWidth                      = 1950
	KindleWidth                   = 600
	PressDpi                      = 300
	WebDpi                        = 72
	ResolutionPixelsPerInchString = "PixelsPerInch"
	ConvertFormat                 = `convert %s -resize %sX%s %s %s %s`
	//ConvertFormat                 = `convert %s -resize %sx%s -set units %s -density %d %s`
)

type ResolutionUnits int

const (
	ResolutionUndefined           ResolutionUnits = iota // 0 convert cli value
	ResolutionPixelsPerInch                              // 1 convert cli value
	ResolutionPixelsPerCentimeter                        // 2 convert cli value
)

type ConvertParams struct {
	SourcePath        string
	OutputPath        string
	OutputWidth       int
	OutputHeight      int
	ResolutionDensity int
	ResolutionUnits   ResolutionUnits
}

/*
	cmdPDF := convertutil.ConvertCommand(
		filepathOrg, filepathPDF, convertutil.PdfWidth, 0, convertutil.PressDpi,
		convertutil.ResolutionPixelsPerInch)
*/

//func ConvertCommand(srcPath, outPath string, width, height, resolutionDensity, resolutionUnits int) string {

func ConvertCommand(params ConvertParams) string {
	widthStr := ""
	heightStr := ""
	densityStr := ""
	unitsStr := ""
	if params.OutputWidth > 0 {
		widthStr = strconv.Itoa(params.OutputWidth)
	}
	if params.OutputHeight > 0 {
		heightStr = strconv.Itoa(params.OutputHeight)
	}
	if params.ResolutionDensity > 0 {
		densityStr = fmt.Sprintf(" -density %d", params.ResolutionDensity)
	} /*
		if len(resolutionUnits) > 0 {
			unitsStr = fmt.Sprintf(` -set units %s`, resolutionUnits)
		}*/
	if params.ResolutionUnits == ResolutionPixelsPerInch {
		unitsStr = fmt.Sprintf(` -set units %s`, ResolutionPixelsPerInchString)
	}
	if 1 == 0 {
		quote := `"`
		params.SourcePath = quote + strings.TrimSpace(params.SourcePath) + quote
		params.OutputPath = quote + strings.TrimSpace(params.OutputPath) + quote
	}
	cmd := fmt.Sprintf(
		ConvertFormat,
		params.SourcePath,
		widthStr,
		heightStr,
		unitsStr,
		densityStr,
		params.OutputPath)

	return cmd

	//convert input.jpg -resize 1950x -set units PixelsPerInch -density 300 output.jpg
}

func ConvertToKindle(sourcePath, outputPath string) (bytes.Buffer, bytes.Buffer, error) {
	command := ConvertCommand(ConvertParams{
		SourcePath:        sourcePath,
		OutputPath:        outputPath,
		OutputWidth:       KindleWidth,
		OutputHeight:      0,
		ResolutionDensity: PressDpi,
		ResolutionUnits:   ResolutionPixelsPerInch})
	return cmdutil.ExecSimple(command)
}

func ConvertToPDF(sourcePath, outputPath string) (bytes.Buffer, bytes.Buffer, error) {
	command := ConvertCommand(ConvertParams{
		SourcePath:        sourcePath,
		OutputPath:        outputPath,
		OutputWidth:       PdfWidth,
		OutputHeight:      0,
		ResolutionDensity: PressDpi,
		ResolutionUnits:   ResolutionPixelsPerInch})
	fmt.Println(command)
	return cmdutil.ExecSimple(command)
}

const (
	convertErrorStatus = "exit status 1"
	convertError       = "convert: no decode delegate for this image format `'"
)

// CheckError removes the error if ReadImage doesn't work.
// exit status 1: convert: no decode delegate for this image format `' @ error/constitute.c/ReadImage/501.
func CheckError(err error, stderr bytes.Buffer) error {
	if err.Error() == convertErrorStatus &&
		strings.Index(stderr.String(), convertError) > -1 {
		return nil
	}
	return err
}
<|endoftext|>


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

package api

import (
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/ajg/form"
	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/iaas"
	"github.com/tsuru/tsuru/permission"
	"gopkg.in/mgo.v2"
)

// title: machine list
// path: /iaas/machines
// method: GET
// produce: application/json
// responses:
//   200: OK
//   401: Unauthorized
func machinesList(w http.ResponseWriter, r *http.Request, token auth.Token) error {
	machines, err := iaas.ListMachines()
	if err != nil {
		return err
	}
	contexts := permission.ContextsForPermission(token, permission.PermMachineRead)
	allowedIaaS := map[string]struct{}{}
	for _, c := range contexts {
		if c.CtxType == permission.CtxGlobal {
			allowedIaaS = nil
			break
		}
		if c.CtxType == permission.CtxIaaS {
			allowedIaaS[c.Value] = struct{}{}
		}
	}
	for i := 0; allowedIaaS != nil && i < len(machines); i++ {
		if _, ok := allowedIaaS[machines[i].Iaas]; !ok {
			machines = append(machines[:i], machines[i+1:]...)
			i--
		}
	}
	w.Header().Add("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(machines)
}

// title: machine destroy
// path: /iaas/machines/{machine_id}
// method: DELETE
// responses:
//   200: OK
//   400: Invalid data
//   401: Unauthorized
//   404: Not found
func machineDestroy(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	r.ParseForm()
	machineID := r.URL.Query().Get(":machine_id")
	if machineID == "" {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: "machine id is required"}
	}
	m, err := iaas.FindMachineById(machineID)
	if err != nil {
		if err == mgo.ErrNotFound {
			return &errors.HTTP{Code: http.StatusNotFound, Message: "machine not found"}
		}
		return err
	}
	iaasCtx := permission.Context(permission.CtxIaaS, m.Iaas)
	allowed := permission.Check(token, permission.PermMachineDelete, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: m.Iaas},
		Kind:       permission.PermMachineDelete,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	return m.Destroy()
}

// title: machine template list
// path: /iaas/templates
// method: GET
// produce: application/json
// responses:
//   200: OK
//   401: Unauthorized
func templatesList(w http.ResponseWriter, r *http.Request, token auth.Token) error {
	templates, err := iaas.ListTemplates()
	if err != nil {
		return err
	}
	contexts := permission.ContextsForPermission(token, permission.PermMachineTemplateRead)
	allowedIaaS := map[string]struct{}{}
	for _, c := range contexts {
		if c.CtxType == permission.CtxGlobal {
			allowedIaaS = nil
			break
		}
		if c.CtxType == permission.CtxIaaS {
			allowedIaaS[c.Value] = struct{}{}
		}
	}
	for i := 0; allowedIaaS != nil && i < len(templates); i++ {
		if _, ok := allowedIaaS[templates[i].IaaSName]; !ok {
			templates = append(templates[:i], templates[i+1:]...)
			i--
		}
	}
	w.Header().Add("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(templates)
}

// title: template create
// path: /iaas/templates
// method: POST
// consume: application/x-www-form-urlencoded
// responses:
//   201: Template created
//   400: Invalid data
//   401: Unauthorized
func templateCreate(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var paramTemplate iaas.Template
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&paramTemplate, r.Form)
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	iaasCtx := permission.Context(permission.CtxIaaS, paramTemplate.IaaSName)
	allowed := permission.Check(token, permission.PermMachineTemplateCreate, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: paramTemplate.IaaSName},
		Kind:       permission.PermMachineTemplateCreate,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = paramTemplate.Save()
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusCreated)
	return nil
}

// title: template destroy
// path: /iaas/templates/{template_name}
// method: DELETE
// responses:
//   200: OK
//   401: Unauthorized
//   404: Not found
func templateDestroy(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	r.ParseForm()
	templateName := r.URL.Query().Get(":template_name")
	t, err := iaas.FindTemplate(templateName)
	if err != nil {
		if err == mgo.ErrNotFound {
			return &errors.HTTP{Code: http.StatusNotFound, Message: "template not found"}
		}
		return err
	}
	iaasCtx := permission.Context(permission.CtxIaaS, t.IaaSName)
	allowed := permission.Check(token, permission.PermMachineTemplateDelete, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: t.IaaSName},
		Kind:       permission.PermMachineTemplateDelete,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	return iaas.DestroyTemplate(templateName)
}

// title: template update
// path: /iaas/templates/{template_name}
// method: PUT
// consume: application/x-www-form-urlencoded
// responses:
//   200: OK
//   400: Invalid data
//   401: Unauthorized
//   404: Not found
func templateUpdate(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var paramTemplate iaas.Template
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&paramTemplate, r.Form)
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	templateName := r.URL.Query().Get(":template_name")
	iaasName := r.URL.Query().Get(":template_iaasname")
	fmt.Println(iaasName, r.URL)
	dbTpl, err := iaas.FindTemplate(templateName)
	if err != nil {
		if err == mgo.ErrNotFound {
			return &errors.HTTP{Code: http.StatusNotFound, Message: "template not found"}
		}
		return err
	}
	iaasCtx := permission.Context(permission.CtxIaaS, dbTpl.IaaSName)
	allowed := permission.Check(token, permission.PermMachineTemplateUpdate, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: dbTpl.IaaSName},
		Kind:       permission.PermMachineTemplateUpdate,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	return dbTpl.Update(&paramTemplate)
}
<commit_msg>iaas: let's the user update the template IaaS<commit_after>// Copyright 2014 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
	"encoding/json"
	"net/http"

	"github.com/ajg/form"
	"github.com/tsuru/tsuru/auth"
	"github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/iaas"
	"github.com/tsuru/tsuru/permission"
	"gopkg.in/mgo.v2"
)

// title: machine list
// path: /iaas/machines
// method: GET
// produce: application/json
// responses:
//   200: OK
//   401: Unauthorized
func machinesList(w http.ResponseWriter, r *http.Request, token auth.Token) error {
	machines, err := iaas.ListMachines()
	if err != nil {
		return err
	}
	contexts := permission.ContextsForPermission(token, permission.PermMachineRead)
	allowedIaaS := map[string]struct{}{}
	for _, c := range contexts {
		if c.CtxType == permission.CtxGlobal {
			allowedIaaS = nil
			break
		}
		if c.CtxType == permission.CtxIaaS {
			allowedIaaS[c.Value] = struct{}{}
		}
	}
	for i := 0; allowedIaaS != nil && i < len(machines); i++ {
		if _, ok := allowedIaaS[machines[i].Iaas]; !ok {
			machines = append(machines[:i], machines[i+1:]...)
			i--
		}
	}
	w.Header().Add("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(machines)
}

// title: machine destroy
// path: /iaas/machines/{machine_id}
// method: DELETE
// responses:
//   200: OK
//   400: Invalid data
//   401: Unauthorized
//   404: Not found
func machineDestroy(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	r.ParseForm()
	machineID := r.URL.Query().Get(":machine_id")
	if machineID == "" {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: "machine id is required"}
	}
	m, err := iaas.FindMachineById(machineID)
	if err != nil {
		if err == mgo.ErrNotFound {
			return &errors.HTTP{Code: http.StatusNotFound, Message: "machine not found"}
		}
		return err
	}
	iaasCtx := permission.Context(permission.CtxIaaS, m.Iaas)
	allowed := permission.Check(token, permission.PermMachineDelete, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: m.Iaas},
		Kind:       permission.PermMachineDelete,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	return m.Destroy()
}

// title: machine template list
// path: /iaas/templates
// method: GET
// produce: application/json
// responses:
//   200: OK
//   401: Unauthorized
func templatesList(w http.ResponseWriter, r *http.Request, token auth.Token) error {
	templates, err := iaas.ListTemplates()
	if err != nil {
		return err
	}
	contexts := permission.ContextsForPermission(token, permission.PermMachineTemplateRead)
	allowedIaaS := map[string]struct{}{}
	for _, c := range contexts {
		if c.CtxType == permission.CtxGlobal {
			allowedIaaS = nil
			break
		}
		if c.CtxType == permission.CtxIaaS {
			allowedIaaS[c.Value] = struct{}{}
		}
	}
	for i := 0; allowedIaaS != nil && i < len(templates); i++ {
		if _, ok := allowedIaaS[templates[i].IaaSName]; !ok {
			templates = append(templates[:i], templates[i+1:]...)
			i--
		}
	}
	w.Header().Add("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(templates)
}

// title: template create
// path: /iaas/templates
// method: POST
// consume: application/x-www-form-urlencoded
// responses:
//   201: Template created
//   400: Invalid data
//   401: Unauthorized
func templateCreate(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var paramTemplate iaas.Template
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&paramTemplate, r.Form)
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	iaasCtx := permission.Context(permission.CtxIaaS, paramTemplate.IaaSName)
	allowed := permission.Check(token, permission.PermMachineTemplateCreate, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: paramTemplate.IaaSName},
		Kind:       permission.PermMachineTemplateCreate,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = paramTemplate.Save()
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusCreated)
	return nil
}

// title: template destroy
// path: /iaas/templates/{template_name}
// method: DELETE
// responses:
//   200: OK
//   401: Unauthorized
//   404: Not found
func templateDestroy(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	r.ParseForm()
	templateName := r.URL.Query().Get(":template_name")
	t, err := iaas.FindTemplate(templateName)
	if err != nil {
		if err == mgo.ErrNotFound {
			return &errors.HTTP{Code: http.StatusNotFound, Message: "template not found"}
		}
		return err
	}
	iaasCtx := permission.Context(permission.CtxIaaS, t.IaaSName)
	allowed := permission.Check(token, permission.PermMachineTemplateDelete, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: t.IaaSName},
		Kind:       permission.PermMachineTemplateDelete,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	return iaas.DestroyTemplate(templateName)
}

// title: template update
// path: /iaas/templates/{template_name}
// method: PUT
// consume: application/x-www-form-urlencoded
// responses:
//   200: OK
//   400: Invalid data
//   401: Unauthorized
//   404: Not found
func templateUpdate(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var paramTemplate iaas.Template
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&paramTemplate, r.Form)
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	templateName := r.URL.Query().Get(":template_name")
	iaasName := r.Form.Get("IaaSName")
	dbTpl, err := iaas.FindTemplate(templateName)
	if err != nil {
		if err == mgo.ErrNotFound {
			return &errors.HTTP{Code: http.StatusNotFound, Message: "template not found"}
		}
		return err
	}
	if (dbTpl.IaaSName != iaasName) && (iaasName != "") {
		dbTpl.IaaSName = iaasName
	}
	iaasCtx := permission.Context(permission.CtxIaaS, dbTpl.IaaSName)
	allowed := permission.Check(token, permission.PermMachineTemplateUpdate, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: dbTpl.IaaSName},
		Kind:       permission.PermMachineTemplateUpdate,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	return dbTpl.Update(&paramTemplate)
}
<|endoftext|>