<commit_before>package discordgo

// eventToInterface is a mapping of Discord WSAPI events to their
// DiscordGo event container.
// Each Discord WSAPI event maps to a unique interface.
// Use Session.AddHandler with one of these types to handle that
// type of event.
// eg:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
//     })
//
// or:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
//     })
var eventToInterface = map[string]interface{}{
	"CHANNEL_CREATE":             ChannelCreate{},
	"CHANNEL_UPDATE":             ChannelUpdate{},
	"CHANNEL_DELETE":             ChannelDelete{},
	"GUILD_CREATE":               GuildCreate{},
	"GUILD_UPDATE":               GuildUpdate{},
	"GUILD_DELETE":               GuildDelete{},
	"GUILD_BAN_ADD":              GuildBanAdd{},
	"GUILD_BAN_REMOVE":           GuildBanRemove{},
	"GUILD_MEMBER_ADD":           GuildMemberAdd{},
	"GUILD_MEMBER_UPDATE":        GuildMemberUpdate{},
	"GUILD_MEMBER_REMOVE":        GuildMemberRemove{},
	"GUILD_ROLE_CREATE":          GuildRoleCreate{},
	"GUILD_ROLE_UPDATE":          GuildRoleUpdate{},
	"GUILD_ROLE_DELETE":          GuildRoleDelete{},
	"GUILD_INTEGRATIONS_UPDATE":  GuildIntegrationsUpdate{},
	"GUILD_EMOJIS_UPDATE":        GuildEmojisUpdate{},
	"MESSAGE_ACK":                MessageAck{},
	"MESSAGE_CREATE":             MessageCreate{},
	"MESSAGE_UPDATE":             MessageUpdate{},
	"MESSAGE_DELETE":             MessageDelete{},
	"PRESENCE_UPDATE":            PresenceUpdate{},
	"PRESENCES_REPLACE":          PresencesReplace{},
	"READY":                      Ready{},
	"USER_UPDATE":                UserUpdate{},
	"USER_SETTINGS_UPDATE":       UserSettingsUpdate{},
	"USER_GUILD_SETTINGS_UPDATE": UserGuildSettingsUpdate{},
	"TYPING_START":               TypingStart{},
	"VOICE_SERVER_UPDATE":        VoiceServerUpdate{},
	"VOICE_STATE_UPDATE":         VoiceStateUpdate{},
}

// Connect is an empty struct for an event.
type Connect struct{}

// Disconnect is an empty struct for an event.
type Disconnect struct{}

// MessageCreate is a wrapper struct for an event.
type MessageCreate struct {
	*Message
}

// MessageUpdate is a wrapper struct for an event.
type MessageUpdate struct {
	*Message
}

// MessageDelete is a wrapper struct for an event.
type MessageDelete struct {
	*Message
}

// ChannelCreate is a wrapper struct for an event.
type ChannelCreate struct {
	*Channel
}

// ChannelUpdate is a wrapper struct for an event.
type ChannelUpdate struct {
	*Channel
}

// ChannelDelete is a wrapper struct for an event.
type ChannelDelete struct {
	*Channel
}

// GuildCreate is a wrapper struct for an event.
type GuildCreate struct {
	*Guild
}

// GuildUpdate is a wrapper struct for an event.
type GuildUpdate struct {
	*Guild
}

// GuildDelete is a wrapper struct for an event.
type GuildDelete struct {
	*Guild
}

// GuildBanAdd is a wrapper struct for an event.
type GuildBanAdd struct {
	*GuildBan
}

// GuildBanRemove is a wrapper struct for an event.
type GuildBanRemove struct {
	*GuildBan
}

// GuildMemberAdd is a wrapper struct for an event.
type GuildMemberAdd struct {
	*Member
}

// GuildMemberUpdate is a wrapper struct for an event.
type GuildMemberUpdate struct {
	*Member
}

// GuildMemberRemove is a wrapper struct for an event.
type GuildMemberRemove struct {
	*Member
}

// GuildRoleCreate is a wrapper struct for an event.
type GuildRoleCreate struct {
	*GuildRole
}

// GuildRoleUpdate is a wrapper struct for an event.
type GuildRoleUpdate struct {
	*GuildRole
}

// PresencesReplace is an array of Presences for an event.
type PresencesReplace []*Presence

// VoiceStateUpdate is a wrapper struct for an event.
type VoiceStateUpdate struct {
	*VoiceState
}

// UserUpdate is a wrapper struct for an event.
type UserUpdate struct {
	*UserUpdate
}

// UserSettingsUpdate is a map for an event.
type UserSettingsUpdate map[string]interface{}

// UserGuildSettingsUpdate is a map for an event.
type UserGuildSettingsUpdate struct {
	*UserGuildSettings
}
<commit_msg>Fix user struct embedding in UserUpdate event.<commit_after>package discordgo

// eventToInterface is a mapping of Discord WSAPI events to their
// DiscordGo event container.
// Each Discord WSAPI event maps to a unique interface.
// Use Session.AddHandler with one of these types to handle that
// type of event.
// eg:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.MessageCreate) {
//     })
//
// or:
//     Session.AddHandler(func(s *discordgo.Session, m *discordgo.PresenceUpdate) {
//     })
var eventToInterface = map[string]interface{}{
	"CHANNEL_CREATE":             ChannelCreate{},
	"CHANNEL_UPDATE":             ChannelUpdate{},
	"CHANNEL_DELETE":             ChannelDelete{},
	"GUILD_CREATE":               GuildCreate{},
	"GUILD_UPDATE":               GuildUpdate{},
	"GUILD_DELETE":               GuildDelete{},
	"GUILD_BAN_ADD":              GuildBanAdd{},
	"GUILD_BAN_REMOVE":           GuildBanRemove{},
	"GUILD_MEMBER_ADD":           GuildMemberAdd{},
	"GUILD_MEMBER_UPDATE":        GuildMemberUpdate{},
	"GUILD_MEMBER_REMOVE":        GuildMemberRemove{},
	"GUILD_ROLE_CREATE":          GuildRoleCreate{},
	"GUILD_ROLE_UPDATE":          GuildRoleUpdate{},
	"GUILD_ROLE_DELETE":          GuildRoleDelete{},
	"GUILD_INTEGRATIONS_UPDATE":  GuildIntegrationsUpdate{},
	"GUILD_EMOJIS_UPDATE":        GuildEmojisUpdate{},
	"MESSAGE_ACK":                MessageAck{},
	"MESSAGE_CREATE":             MessageCreate{},
	"MESSAGE_UPDATE":             MessageUpdate{},
	"MESSAGE_DELETE":             MessageDelete{},
	"PRESENCE_UPDATE":            PresenceUpdate{},
	"PRESENCES_REPLACE":          PresencesReplace{},
	"READY":                      Ready{},
	"USER_UPDATE":                UserUpdate{},
	"USER_SETTINGS_UPDATE":       UserSettingsUpdate{},
	"USER_GUILD_SETTINGS_UPDATE": UserGuildSettingsUpdate{},
	"TYPING_START":               TypingStart{},
	"VOICE_SERVER_UPDATE":        VoiceServerUpdate{},
	"VOICE_STATE_UPDATE":         VoiceStateUpdate{},
}

// Connect is an empty struct for an event.
type Connect struct{}

// Disconnect is an empty struct for an event.
type Disconnect struct{}

// MessageCreate is a wrapper struct for an event.
type MessageCreate struct {
	*Message
}

// MessageUpdate is a wrapper struct for an event.
type MessageUpdate struct {
	*Message
}

// MessageDelete is a wrapper struct for an event.
type MessageDelete struct {
	*Message
}

// ChannelCreate is a wrapper struct for an event.
type ChannelCreate struct {
	*Channel
}

// ChannelUpdate is a wrapper struct for an event.
type ChannelUpdate struct {
	*Channel
}

// ChannelDelete is a wrapper struct for an event.
type ChannelDelete struct {
	*Channel
}

// GuildCreate is a wrapper struct for an event.
type GuildCreate struct {
	*Guild
}

// GuildUpdate is a wrapper struct for an event.
type GuildUpdate struct {
	*Guild
}

// GuildDelete is a wrapper struct for an event.
type GuildDelete struct {
	*Guild
}

// GuildBanAdd is a wrapper struct for an event.
type GuildBanAdd struct {
	*GuildBan
}

// GuildBanRemove is a wrapper struct for an event.
type GuildBanRemove struct {
	*GuildBan
}

// GuildMemberAdd is a wrapper struct for an event.
type GuildMemberAdd struct {
	*Member
}

// GuildMemberUpdate is a wrapper struct for an event.
type GuildMemberUpdate struct {
	*Member
}

// GuildMemberRemove is a wrapper struct for an event.
type GuildMemberRemove struct {
	*Member
}

// GuildRoleCreate is a wrapper struct for an event.
type GuildRoleCreate struct {
	*GuildRole
}

// GuildRoleUpdate is a wrapper struct for an event.
type GuildRoleUpdate struct {
	*GuildRole
}

// PresencesReplace is an array of Presences for an event.
type PresencesReplace []*Presence

// VoiceStateUpdate is a wrapper struct for an event.
type VoiceStateUpdate struct {
	*VoiceState
}

// UserUpdate is a wrapper struct for an event.
type UserUpdate struct {
	*User
}

// UserSettingsUpdate is a map for an event.
type UserSettingsUpdate map[string]interface{}

// UserGuildSettingsUpdate is a map for an event.
type UserGuildSettingsUpdate struct {
	*UserGuildSettings
}
<|endoftext|>


<commit_before>package llog

import (
	"context"

	"github.com/levenlabs/golib/errctx"
)

type kvKey int

// ErrWithKV embeds the merging of a set of KVs into an error, returning a new
// error instance. If the error already has a KV embedded in it then the
// returned error will have the merging of them all.
func ErrWithKV(err error, kvs ...KV) error {
	if err == nil {
		return nil
	}
	kv := Merge(kvs...)
	existingKV := errctx.Get(err, kvKey(0))
	if existingKV != nil {
		kv = Merge(existingKV.(KV), kv)
	}
	return errctx.Set(err, kvKey(0), kv)
}

// ErrKV returns a copy of the KV embedded in the error by ErrWithKV. Returns
// empty KV if no KV was previously embedded. Will automatically set the "err"
// field on the returned KV as well.
func ErrKV(err error) KV {
	var kv KV
	if kvi := errctx.Get(err, kvKey(0)); kvi == nil {
		kv = KV{}
	} else {
		kv = kvi.(KV)
	}
	kv["err"] = err.Error()
	return kv
}

// CtxWithKV embeds a KV into a Context, returning a new Context instance. If
// the Context already has a KV embedded in it then the returned error will have
// the merging of the two.
func CtxWithKV(ctx context.Context, kvs ...KV) context.Context {
	kv := Merge(kvs...)
	existingKV := ctx.Value(kvKey(0))
	if existingKV != nil {
		kv = Merge(existingKV.(KV), kv)
	}
	return context.WithValue(ctx, kvKey(0), kv)
}

// CtxKV returns a copy of the KV embedded in the Context by CtxWithKV
func CtxKV(ctx context.Context) KV {
	kv := ctx.Value(kvKey(0))
	if kv == nil {
		return KV{}
	}
	return kv.(KV)
}
<commit_msg>make ErrKV not mutate the existing KV, but make a new one if need be<commit_after>package llog

import (
	"context"

	"github.com/levenlabs/golib/errctx"
)

type kvKey int

// ErrWithKV embeds the merging of a set of KVs into an error, returning a new
// error instance. If the error already has a KV embedded in it then the
// returned error will have the merging of them all.
func ErrWithKV(err error, kvs ...KV) error {
	if err == nil {
		return nil
	}
	kv := Merge(kvs...)
	existingKV := errctx.Get(err, kvKey(0))
	if existingKV != nil {
		kv = Merge(existingKV.(KV), kv)
	}
	return errctx.Set(err, kvKey(0), kv)
}

// ErrKV returns a copy of the KV embedded in the error by ErrWithKV. Returns
// empty KV if no KV was previously embedded. Will automatically set the "err"
// field on the returned KV as well.
func ErrKV(err error) KV {
	var kv KV
	if kvi := errctx.Get(err, kvKey(0)); kvi == nil {
		return KV{"err": err.Error()}
	}
	return kvi.(KV).Set("err", err.Error())
}

// CtxWithKV embeds a KV into a Context, returning a new Context instance. If
// the Context already has a KV embedded in it then the returned error will have
// the merging of the two.
func CtxWithKV(ctx context.Context, kvs ...KV) context.Context {
	kv := Merge(kvs...)
	existingKV := ctx.Value(kvKey(0))
	if existingKV != nil {
		kv = Merge(existingKV.(KV), kv)
	}
	return context.WithValue(ctx, kvKey(0), kv)
}

// CtxKV returns a copy of the KV embedded in the Context by CtxWithKV
func CtxKV(ctx context.Context) KV {
	kv := ctx.Value(kvKey(0))
	if kv == nil {
		return KV{}
	}
	return kv.(KV)
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"io"
	"os"
	"strings"
)

// OsExiter is the function used when the app exits. If not set defaults to os.Exit.
var OsExiter = os.Exit

// ErrWriter is used to write errors to the user. This can be anything
// implementing the io.Writer interface and defaults to os.Stderr.
var ErrWriter io.Writer = os.Stderr

// MultiError is an error that wraps multiple errors.
type MultiError struct {
	Errors []error
}

// NewMultiError creates a new MultiError. Pass in one or more errors.
func NewMultiError(err ...error) MultiError {
	return MultiError{Errors: err}
}

// Error implents the error interface.
func (m MultiError) Error() string {
	errs := make([]string, len(m.Errors))
	for i, err := range m.Errors {
		errs[i] = err.Error()
	}

	return strings.Join(errs, "\n")
}

// ExitCoder is the interface checked by `App` and `Command` for a custom exit
// code
type ExitCoder interface {
	error
	ExitCode() int
}

// ExitError fulfills both the builtin `error` interface and `ExitCoder`
type ExitError struct {
	exitCode int
	message  string
}

// NewExitError makes a new *ExitError
func NewExitError(message string, exitCode int) *ExitError {
	return &ExitError{
		exitCode: exitCode,
		message:  message,
	}
}

// Error returns the string message, fulfilling the interface required by
// `error`
func (ee *ExitError) Error() string {
	return ee.message
}

// ExitCode returns the exit code, fulfilling the interface required by
// `ExitCoder`
func (ee *ExitError) ExitCode() int {
	return ee.exitCode
}

// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if
// so prints the error to stderr (if it is non-empty) and calls OsExiter with the
// given exit code.  If the given error is a MultiError, then this func is
// called on all members of the Errors slice.
func HandleExitCoder(err error) {
	if err == nil {
		return
	}

	if exitErr, ok := err.(ExitCoder); ok {
		if err.Error() != "" {
			fmt.Fprintln(ErrWriter, err)
		}
		OsExiter(exitErr.ExitCode())
		return
	}

	if multiErr, ok := err.(MultiError); ok {
		for _, merr := range multiErr.Errors {
			fmt.Fprintln(ErrWriter, merr)
		}
		OsExiter(1)
		return
	}

	if err.Error() != "" {
		fmt.Fprintln(ErrWriter, err)
	}
	OsExiter(1)
}
<commit_msg>Exit with the code of ExitCoder if exists<commit_after>package cli

import (
	"fmt"
	"io"
	"os"
	"strings"
)

// OsExiter is the function used when the app exits. If not set defaults to os.Exit.
var OsExiter = os.Exit

// ErrWriter is used to write errors to the user. This can be anything
// implementing the io.Writer interface and defaults to os.Stderr.
var ErrWriter io.Writer = os.Stderr

// MultiError is an error that wraps multiple errors.
type MultiError struct {
	Errors []error
}

// NewMultiError creates a new MultiError. Pass in one or more errors.
func NewMultiError(err ...error) MultiError {
	return MultiError{Errors: err}
}

// Error implents the error interface.
func (m MultiError) Error() string {
	errs := make([]string, len(m.Errors))
	for i, err := range m.Errors {
		errs[i] = err.Error()
	}

	return strings.Join(errs, "\n")
}

// ExitCoder is the interface checked by `App` and `Command` for a custom exit
// code
type ExitCoder interface {
	error
	ExitCode() int
}

// ExitError fulfills both the builtin `error` interface and `ExitCoder`
type ExitError struct {
	exitCode int
	message  string
}

// NewExitError makes a new *ExitError
func NewExitError(message string, exitCode int) *ExitError {
	return &ExitError{
		exitCode: exitCode,
		message:  message,
	}
}

// Error returns the string message, fulfilling the interface required by
// `error`
func (ee *ExitError) Error() string {
	return ee.message
}

// ExitCode returns the exit code, fulfilling the interface required by
// `ExitCoder`
func (ee *ExitError) ExitCode() int {
	return ee.exitCode
}

// HandleExitCoder checks if the error fulfills the ExitCoder interface, and if
// so prints the error to stderr (if it is non-empty) and calls OsExiter with the
// given exit code.  If the given error is a MultiError, then this func is
// called on all members of the Errors slice.
func HandleExitCoder(err error) {
	if err == nil {
		return
	}

	if exitErr, ok := err.(ExitCoder); ok {
		if err.Error() != "" {
			fmt.Fprintln(ErrWriter, err)
		}
		OsExiter(exitErr.ExitCode())
		return
	}

	if multiErr, ok := err.(MultiError); ok {
		code := handleMultiError(multiErr)
		OsExiter(code)
		return
	}

	if err.Error() != "" {
		fmt.Fprintln(ErrWriter, err)
	}
	OsExiter(1)
}

func handleMultiError(multiErr MultiError) int {
	code := 1
	for _, merr := range multiErr.Errors {
		if multiErr2, ok := merr.(MultiError); ok {
			code = handleMultiError(multiErr2)
		} else {
			fmt.Fprintln(ErrWriter, merr)
			if exitErr, ok := merr.(ExitCoder); ok {
				code = exitErr.ExitCode()
			}
		}
	}
	return code
}
<|endoftext|>


<commit_before>package common

import (
	"fmt"
)

type StackError struct {
	Err   interface{}
	Stack []byte
}

func (se StackError) String() string {
	return fmt.Sprintf("Error: %v\nStack: %s", se.Err, se.Stack)
}

func (se StackError) Error() string {
	return se.String()
}

//--------------------------------------------------------------------------------------------------
// panic wrappers

// A panic resulting from a sanity check means there is a programmer error
// and some gaurantee is not satisfied.
func PanicSanity(v interface{}) {
	panic(Fmt("Paniced on a Sanity Check: %v", v))
}

// A panic here means something has gone horribly wrong, in the form of data corruption or
// failure of the operating system. In a correct/healthy system, these should never fire.
// If they do, it's indicative of a much more serious problem.
func PanicCrisis(v interface{}) {
	panic(Fmt("Paniced on a Crisis: %v", v))
}

// Indicates a failure of consensus. Someone was malicious or something has
// gone horribly wrong. These should really boot us into an "emergency-recover" mode
func PanicConsensus(v interface{}) {
	panic(Fmt("Paniced on a Consensus Failure: %v", v))
}

// For those times when we're not sure if we should panic
func PanicQ(v interface{}) {
	panic(Fmt("Paniced questionably: %v", v))
}
<commit_msg>Spelling<commit_after>package common

import (
	"fmt"
)

type StackError struct {
	Err   interface{}
	Stack []byte
}

func (se StackError) String() string {
	return fmt.Sprintf("Error: %v\nStack: %s", se.Err, se.Stack)
}

func (se StackError) Error() string {
	return se.String()
}

//--------------------------------------------------------------------------------------------------
// panic wrappers

// A panic resulting from a sanity check means there is a programmer error
// and some gaurantee is not satisfied.
func PanicSanity(v interface{}) {
	panic(Fmt("Panicked on a Sanity Check: %v", v))
}

// A panic here means something has gone horribly wrong, in the form of data corruption or
// failure of the operating system. In a correct/healthy system, these should never fire.
// If they do, it's indicative of a much more serious problem.
func PanicCrisis(v interface{}) {
	panic(Fmt("Panicked on a Crisis: %v", v))
}

// Indicates a failure of consensus. Someone was malicious or something has
// gone horribly wrong. These should really boot us into an "emergency-recover" mode
func PanicConsensus(v interface{}) {
	panic(Fmt("Panicked on a Consensus Failure: %v", v))
}

// For those times when we're not sure if we should panic
func PanicQ(v interface{}) {
	panic(Fmt("Panicked questionably: %v", v))
}
<|endoftext|>


<commit_before>// Copyright 2013 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 docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/repository"
	"io"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"os/user"
	"path"
	"strings"
	"time"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) (string, error) {
	out := bytes.Buffer{}
	err := executor().Execute(cmd, args, nil, &out, &out)
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	return out.String(), err
}

func getSSHCommands() ([]string, error) {
	addKeyCommand, err := config.GetString("docker:ssh:add-key-cmd")
	if err != nil {
		return nil, err
	}
	keyFile, err := config.GetString("docker:ssh:public-key")
	if err != nil {
		if u, err := user.Current(); err == nil {
			keyFile = path.Join(u.HomeDir, ".ssh", "id_rsa.pub")
		} else {
			keyFile = os.ExpandEnv("${HOME}/.ssh/id_rsa.pub")
		}
	}
	f, err := filesystem().Open(keyFile)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	keyContent, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	sshdPath, err := config.GetString("docker:ssh:sshd-path")
	if err != nil {
		sshdPath = "/usr/sbin/sshd"
	}
	return []string{
		fmt.Sprintf("%s %s", addKeyCommand, bytes.TrimSpace(keyContent)),
		sshdPath + " -D",
	}, nil
}

func commandToRun(app provision.App) ([]string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		return nil, err
	}
	port, err := config.GetString("docker:run-cmd:port")
	if err != nil {
		return nil, err
	}
	commands, err := getSSHCommands()
	if err != nil {
		return nil, err
	}
	imageName := fmt.Sprintf("%s/%s", repoNamespace, app.GetPlatform()) // TODO (flaviamissi): should use same algorithm as image.repositoryName
	containerCmd := strings.Join(commands, " && ")
	wholeCmd := []string{docker, "run", "-d", "-t", "-p", port, imageName, "/bin/bash", "-c", containerCmd}
	return wholeCmd, nil
}

func getPort() (string, error) {
	return config.GetString("docker:run-cmd:port")
}

type container struct {
	Id      string `bson:"_id"`
	AppName string
	Type    string
	Ip      string
	Port    string
	Status  string
}

func (c *container) getAddress() string {
	hostAddr, err := config.Get("docker:host-address")
	if err != nil {
		log.Printf("Failed to obtain container address: %s", err.Error())
		return ""
	}
	hostPort, err := c.hostPort()
	if err != nil {
		log.Printf("Failed to obtain container port: %s", err.Error())
		return ""
	}
	return fmt.Sprintf("http://%s:%s", hostAddr, hostPort)
}

// newContainer creates a new container in Docker and stores it in the database.
//
// TODO (flaviamissi): make it atomic
func newContainer(app provision.App) (*container, error) {
	appName := app.GetName()
	c := container{
		AppName: appName,
		Type:    app.GetPlatform(),
	}
	err := c.create(app)
	if err != nil {
		log.Printf("Error creating container %s", appName)
		log.Printf("Error was: %s", err.Error())
		return nil, err
	}
	return &c, nil
}

func (c *container) inspect() (map[string]interface{}, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	out, err := runCmd(docker, "inspect", c.Id)
	if err != nil {
		return nil, err
	}
	var r map[string]interface{}
	err = json.Unmarshal([]byte(out), &r)
	if err != nil {
		return nil, err
	}
	return r, nil
}

// hostPort returns the host port mapped for the container.
func (c *container) hostPort() (string, error) {
	if c.Port == "" {
		return "", errors.New("Container does not contain any mapped port")
	}
	data, err := c.inspect()
	if err != nil {
		return "", err
	}
	mappedPorts := data["NetworkSettings"].(map[string]interface{})["PortMapping"].(map[string]interface{})
	if port, ok := mappedPorts[c.Port]; ok {
		return port.(string), nil
	}
	return "", fmt.Errorf("Container port %s is not mapped to any host port", c.Port)
}

// ip returns the ip for the container.
func (c *container) ip() (string, error) {
	result, err := c.inspect()
	if err != nil {
		msg := fmt.Sprintf("error(%s) parsing json from docker when trying to get ipaddress", err)
		log.Print(msg)
		return "", errors.New(msg)
	}
	if ns, ok := result["NetworkSettings"]; !ok || ns == nil {
		msg := "Error when getting container information. NetworkSettings is missing."
		log.Print(msg)
		return "", errors.New(msg)
	}
	networkSettings := result["NetworkSettings"].(map[string]interface{})
	instanceIp := networkSettings["IpAddress"].(string)
	if instanceIp == "" {
		msg := "error: Can't get ipaddress..."
		log.Print(msg)
		return "", errors.New(msg)
	}
	log.Printf("Instance IpAddress: %s", instanceIp)
	return instanceIp, nil
}

// create creates a docker container, stores it on the database and adds a route to it.
//
// It receives the related application in order to choose the correct
// docker image and the repository to pass to the script that will take
// care of the deploy, and a function to generate the correct command ran by
// docker, which might be to deploy a container or to run and expose a
// container for an application.
func (c *container) create(app provision.App) error {
	cmd, err := commandToRun(app)
	if err != nil {
		return err
	}
	port, err := getPort()
	if err != nil {
		return err
	}
	id, err := runCmd(cmd[0], cmd[1:]...)
	if err != nil {
		return err
	}
	id = strings.TrimSpace(id)
	log.Printf("docker id=%s", id)
	c.Id = strings.TrimSpace(id)
	c.Port = port
	ip, err := c.ip()
	if err != nil {
		return err
	}
	c.Ip = ip
	c.Status = "created"
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.Insert(c); err != nil {
		log.Print(err)
		return err
	}
	r, err := getRouter()
	if err != nil {
		return err
	}
	return r.AddRoute(app.GetName(), c.getAddress())
}

func (c *container) setStatus(status string) error {
	c.Status = status
	coll := collection()
	defer coll.Database.Session.Close()
	return coll.UpdateId(c.Id, c)
}

func (c *container) deploy(w io.Writer) error {
	deployCmd, err := config.GetString("docker:deploy-cmd")
	if err != nil {
		c.setStatus("error")
		return err
	}
	runBin, err := config.GetString("docker:run-cmd:bin")
	if err != nil {
		c.setStatus("error")
		return err
	}
	runArgs, _ := config.GetString("docker:run-cmd:args")
	appRepo := repository.GetReadOnlyUrl(c.AppName)
	filter := filter{w: w, content: []byte("connection refused")}
	for {
		err = c.ssh(w, &filter, deployCmd, appRepo)
		if err == nil {
			break
		}
		if !filter.filtered {
			c.setStatus("error")
			return err
		}
		log.Printf("SSH to the container %q failed. Will retry.", c.Id)
		time.Sleep(100e6)
		filter.filtered = false
	}
	err = c.ssh(w, w, runBin, strings.Fields(runArgs)...)
	if err != nil {
		c.setStatus("error")
	}
	c.setStatus("running")
	return nil
}

// remove removes a docker container.
func (c *container) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	log.Printf("Removing container %s from docker", c.Id)
	address := c.getAddress()
	out, err := runCmd(docker, "rm", c.Id)
	if err != nil {
		log.Printf("Failed to remove container from docker: %s", err.Error())
		log.Printf("Command output: %s", out)
		return err
	}
	log.Printf("Removing container %s from database", c.Id)
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.RemoveId(c.Id); err != nil {
		log.Printf("Failed to remove container from database: %s", err.Error())
		return err
	}
	r, err := getRouter()
	if err != nil {
		log.Printf("Failed to obtain router: %s", err.Error())
		return err
	}
	if err := r.RemoveRoute(c.AppName, address); err != nil {
		log.Printf("Failed to remove route: %s", err.Error())
		return err
	}
	return nil
}

func (c *container) ssh(stdout, stderr io.Writer, cmd string, args ...string) error {
	stderr = &filter{w: stderr, content: []byte("unable to resolve host")}
	user, err := config.GetString("docker:ssh:user")
	if err != nil {
		return err
	}
	sshArgs := []string{c.Ip, "-l", user, "-o", "StrictHostKeyChecking no"}
	if keyFile, err := config.GetString("docker:ssh:private-key"); err == nil {
		sshArgs = append(sshArgs, "-i", keyFile)
	}
	sshArgs = append(sshArgs, "--", cmd)
	sshArgs = append(sshArgs, args...)
	return executor().Execute("ssh", sshArgs, nil, stdout, stderr)
}

// image represents a docker image.
type image struct {
	Name string
	Id   string
}

// repositoryName returns the image repository name for a given image.
//
// Repository is a docker concept, the image actually does not have a name,
// it has a repository, that is a composed name, e.g.: tsuru/base.
// Tsuru will always use a namespace, defined in tsuru.conf.
// Additionally, tsuru will use the application's name to do that composition.
func (img *image) repositoryName() string {
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:repository-namespace config is missing.")
		return ""
	}
	return fmt.Sprintf("%s/%s", repoNamespace, img.Name)
}

// commit commits an image in docker
//
// This is another docker concept, in order to generate an image from a container
// one must commit it.
func (img *image) commit(cId string) (string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return "", err
	}
	log.Printf("attempting to commit image from container %s", cId)
	rName := img.repositoryName()
	id, err := runCmd(docker, "commit", cId, rName)
	if err != nil {
		log.Printf("Could not commit docker image: %s", err.Error())
		return "", err
	}
	img.Id = strings.Replace(id, "\n", "", -1)
	if err := imagesCollection().Insert(&img); err != nil {
		log.Printf("Could not store image information %s", err.Error())
		return "", err
	}
	return img.Id, nil
}

// remove removes an image from docker registry
func (img *image) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return err
	}
	log.Printf("attempting to remove image %s from docker", img.repositoryName())
	_, err = runCmd(docker, "rmi", img.Id)
	if err != nil {
		log.Printf("Could not remove image %s from docker: %s", img.Id, err.Error())
		return err
	}
	err = imagesCollection().Remove(bson.M{"name": img.Name})
	if err != nil {
		log.Printf("Could not remove image %s from mongo: %s", img.Id, err.Error())
		return err
	}
	return nil
}

func getContainer(id string) (*container, error) {
	var c container
	coll := collection()
	defer coll.Database.Session.Close()
	err := coll.Find(bson.M{"_id": id}).One(&c)
	if err != nil {
		return nil, err
	}
	return &c, nil
}

func listAppContainers(appName string) ([]container, error) {
	var containers []container
	err := collection().Find(bson.M{"appname": appName}).All(&containers)
	return containers, err
}
<commit_msg>provision/docker/docker.go: logging removal after getAddress<commit_after>// Copyright 2013 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 docker

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/globocom/config"
	"github.com/globocom/tsuru/fs"
	"github.com/globocom/tsuru/log"
	"github.com/globocom/tsuru/provision"
	"github.com/globocom/tsuru/repository"
	"io"
	"io/ioutil"
	"labix.org/v2/mgo/bson"
	"os"
	"os/user"
	"path"
	"strings"
	"time"
)

var fsystem fs.Fs

func filesystem() fs.Fs {
	if fsystem == nil {
		fsystem = fs.OsFs{}
	}
	return fsystem
}

// runCmd executes commands and log the given stdout and stderror.
func runCmd(cmd string, args ...string) (string, error) {
	out := bytes.Buffer{}
	err := executor().Execute(cmd, args, nil, &out, &out)
	log.Printf("running the cmd: %s with the args: %s", cmd, args)
	return out.String(), err
}

func getSSHCommands() ([]string, error) {
	addKeyCommand, err := config.GetString("docker:ssh:add-key-cmd")
	if err != nil {
		return nil, err
	}
	keyFile, err := config.GetString("docker:ssh:public-key")
	if err != nil {
		if u, err := user.Current(); err == nil {
			keyFile = path.Join(u.HomeDir, ".ssh", "id_rsa.pub")
		} else {
			keyFile = os.ExpandEnv("${HOME}/.ssh/id_rsa.pub")
		}
	}
	f, err := filesystem().Open(keyFile)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	keyContent, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	sshdPath, err := config.GetString("docker:ssh:sshd-path")
	if err != nil {
		sshdPath = "/usr/sbin/sshd"
	}
	return []string{
		fmt.Sprintf("%s %s", addKeyCommand, bytes.TrimSpace(keyContent)),
		sshdPath + " -D",
	}, nil
}

func commandToRun(app provision.App) ([]string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		return nil, err
	}
	port, err := config.GetString("docker:run-cmd:port")
	if err != nil {
		return nil, err
	}
	commands, err := getSSHCommands()
	if err != nil {
		return nil, err
	}
	imageName := fmt.Sprintf("%s/%s", repoNamespace, app.GetPlatform()) // TODO (flaviamissi): should use same algorithm as image.repositoryName
	containerCmd := strings.Join(commands, " && ")
	wholeCmd := []string{docker, "run", "-d", "-t", "-p", port, imageName, "/bin/bash", "-c", containerCmd}
	return wholeCmd, nil
}

func getPort() (string, error) {
	return config.GetString("docker:run-cmd:port")
}

type container struct {
	Id      string `bson:"_id"`
	AppName string
	Type    string
	Ip      string
	Port    string
	Status  string
}

func (c *container) getAddress() string {
	hostAddr, err := config.Get("docker:host-address")
	if err != nil {
		log.Printf("Failed to obtain container address: %s", err.Error())
		return ""
	}
	hostPort, err := c.hostPort()
	if err != nil {
		log.Printf("Failed to obtain container port: %s", err.Error())
		return ""
	}
	return fmt.Sprintf("http://%s:%s", hostAddr, hostPort)
}

// newContainer creates a new container in Docker and stores it in the database.
//
// TODO (flaviamissi): make it atomic
func newContainer(app provision.App) (*container, error) {
	appName := app.GetName()
	c := container{
		AppName: appName,
		Type:    app.GetPlatform(),
	}
	err := c.create(app)
	if err != nil {
		log.Printf("Error creating container %s", appName)
		log.Printf("Error was: %s", err.Error())
		return nil, err
	}
	return &c, nil
}

func (c *container) inspect() (map[string]interface{}, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return nil, err
	}
	out, err := runCmd(docker, "inspect", c.Id)
	if err != nil {
		return nil, err
	}
	log.Printf("docker inspect output: %s", out)
	var r map[string]interface{}
	err = json.Unmarshal([]byte(out), &r)
	if err != nil {
		return nil, err
	}
	return r, nil
}

// hostPort returns the host port mapped for the container.
func (c *container) hostPort() (string, error) {
	if c.Port == "" {
		return "", errors.New("Container does not contain any mapped port")
	}
	data, err := c.inspect()
	if err != nil {
		return "", err
	}
	mappedPorts := data["NetworkSettings"].(map[string]interface{})["PortMapping"].(map[string]interface{})
	if port, ok := mappedPorts[c.Port]; ok {
		return port.(string), nil
	}
	return "", fmt.Errorf("Container port %s is not mapped to any host port", c.Port)
}

// ip returns the ip for the container.
func (c *container) ip() (string, error) {
	result, err := c.inspect()
	if err != nil {
		msg := fmt.Sprintf("error(%s) parsing json from docker when trying to get ipaddress", err)
		log.Print(msg)
		return "", errors.New(msg)
	}
	if ns, ok := result["NetworkSettings"]; !ok || ns == nil {
		msg := "Error when getting container information. NetworkSettings is missing."
		log.Print(msg)
		return "", errors.New(msg)
	}
	networkSettings := result["NetworkSettings"].(map[string]interface{})
	instanceIp := networkSettings["IpAddress"].(string)
	if instanceIp == "" {
		msg := "error: Can't get ipaddress..."
		log.Print(msg)
		return "", errors.New(msg)
	}
	log.Printf("Instance IpAddress: %s", instanceIp)
	return instanceIp, nil
}

// create creates a docker container, stores it on the database and adds a route to it.
//
// It receives the related application in order to choose the correct
// docker image and the repository to pass to the script that will take
// care of the deploy, and a function to generate the correct command ran by
// docker, which might be to deploy a container or to run and expose a
// container for an application.
func (c *container) create(app provision.App) error {
	cmd, err := commandToRun(app)
	if err != nil {
		return err
	}
	port, err := getPort()
	if err != nil {
		return err
	}
	id, err := runCmd(cmd[0], cmd[1:]...)
	if err != nil {
		return err
	}
	id = strings.TrimSpace(id)
	log.Printf("docker id=%s", id)
	c.Id = strings.TrimSpace(id)
	c.Port = port
	ip, err := c.ip()
	if err != nil {
		return err
	}
	c.Ip = ip
	c.Status = "created"
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.Insert(c); err != nil {
		log.Print(err)
		return err
	}
	r, err := getRouter()
	if err != nil {
		return err
	}
	return r.AddRoute(app.GetName(), c.getAddress())
}

func (c *container) setStatus(status string) error {
	c.Status = status
	coll := collection()
	defer coll.Database.Session.Close()
	return coll.UpdateId(c.Id, c)
}

func (c *container) deploy(w io.Writer) error {
	deployCmd, err := config.GetString("docker:deploy-cmd")
	if err != nil {
		c.setStatus("error")
		return err
	}
	runBin, err := config.GetString("docker:run-cmd:bin")
	if err != nil {
		c.setStatus("error")
		return err
	}
	runArgs, _ := config.GetString("docker:run-cmd:args")
	appRepo := repository.GetReadOnlyUrl(c.AppName)
	filter := filter{w: w, content: []byte("connection refused")}
	for {
		err = c.ssh(w, &filter, deployCmd, appRepo)
		if err == nil {
			break
		}
		if !filter.filtered {
			c.setStatus("error")
			return err
		}
		log.Printf("SSH to the container %q failed. Will retry.", c.Id)
		time.Sleep(100e6)
		filter.filtered = false
	}
	err = c.ssh(w, w, runBin, strings.Fields(runArgs)...)
	if err != nil {
		c.setStatus("error")
	}
	c.setStatus("running")
	return nil
}

// remove removes a docker container.
func (c *container) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		return err
	}
	address := c.getAddress()
	log.Printf("Removing container %s from docker", c.Id)
	out, err := runCmd(docker, "rm", c.Id)
	if err != nil {
		log.Printf("Failed to remove container from docker: %s", err.Error())
		log.Printf("Command output: %s", out)
		return err
	}
	log.Printf("Removing container %s from database", c.Id)
	coll := collection()
	defer coll.Database.Session.Close()
	if err := coll.RemoveId(c.Id); err != nil {
		log.Printf("Failed to remove container from database: %s", err.Error())
		return err
	}
	r, err := getRouter()
	if err != nil {
		log.Printf("Failed to obtain router: %s", err.Error())
		return err
	}
	if err := r.RemoveRoute(c.AppName, address); err != nil {
		log.Printf("Failed to remove route: %s", err.Error())
		return err
	}
	return nil
}

func (c *container) ssh(stdout, stderr io.Writer, cmd string, args ...string) error {
	stderr = &filter{w: stderr, content: []byte("unable to resolve host")}
	user, err := config.GetString("docker:ssh:user")
	if err != nil {
		return err
	}
	sshArgs := []string{c.Ip, "-l", user, "-o", "StrictHostKeyChecking no"}
	if keyFile, err := config.GetString("docker:ssh:private-key"); err == nil {
		sshArgs = append(sshArgs, "-i", keyFile)
	}
	sshArgs = append(sshArgs, "--", cmd)
	sshArgs = append(sshArgs, args...)
	return executor().Execute("ssh", sshArgs, nil, stdout, stderr)
}

// image represents a docker image.
type image struct {
	Name string
	Id   string
}

// repositoryName returns the image repository name for a given image.
//
// Repository is a docker concept, the image actually does not have a name,
// it has a repository, that is a composed name, e.g.: tsuru/base.
// Tsuru will always use a namespace, defined in tsuru.conf.
// Additionally, tsuru will use the application's name to do that composition.
func (img *image) repositoryName() string {
	repoNamespace, err := config.GetString("docker:repository-namespace")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:repository-namespace config is missing.")
		return ""
	}
	return fmt.Sprintf("%s/%s", repoNamespace, img.Name)
}

// commit commits an image in docker
//
// This is another docker concept, in order to generate an image from a container
// one must commit it.
func (img *image) commit(cId string) (string, error) {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return "", err
	}
	log.Printf("attempting to commit image from container %s", cId)
	rName := img.repositoryName()
	id, err := runCmd(docker, "commit", cId, rName)
	if err != nil {
		log.Printf("Could not commit docker image: %s", err.Error())
		return "", err
	}
	img.Id = strings.Replace(id, "\n", "", -1)
	if err := imagesCollection().Insert(&img); err != nil {
		log.Printf("Could not store image information %s", err.Error())
		return "", err
	}
	return img.Id, nil
}

// remove removes an image from docker registry
func (img *image) remove() error {
	docker, err := config.GetString("docker:binary")
	if err != nil {
		log.Printf("Tsuru is misconfigured. docker:binary config is missing.")
		return err
	}
	log.Printf("attempting to remove image %s from docker", img.repositoryName())
	_, err = runCmd(docker, "rmi", img.Id)
	if err != nil {
		log.Printf("Could not remove image %s from docker: %s", img.Id, err.Error())
		return err
	}
	err = imagesCollection().Remove(bson.M{"name": img.Name})
	if err != nil {
		log.Printf("Could not remove image %s from mongo: %s", img.Id, err.Error())
		return err
	}
	return nil
}

func getContainer(id string) (*container, error) {
	var c container
	coll := collection()
	defer coll.Database.Session.Close()
	err := coll.Find(bson.M{"_id": id}).One(&c)
	if err != nil {
		return nil, err
	}
	return &c, nil
}

func listAppContainers(appName string) ([]container, error) {
	var containers []container
	err := collection().Find(bson.M{"appname": appName}).All(&containers)
	return containers, err
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	log "github.com/Sirupsen/logrus"
	lab "github.com/fredhsu/aristalabstatus"
	"github.com/fredhsu/eapigo"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"
)

type EosNode struct {
	Hostname      string
	ModelName     string
	MgmtIp        string
	Username      string
	Password      string
	Ssl           bool
	Reachable     bool
	ConfigCorrect bool
	Uptime        float64
	Version       string
	Config        string
	IntfConnected []string
	IpIntf        []string
	Vlans         []string
	LldpNeighbors []eapi.LldpNeighbor
}

type DemoStatus struct {
	Working bool
	Error   string
}

type ChanResponse struct {
	response eapi.JsonRpcResponse
	node     EosNode
}

type Link struct {
	Source   int `json:"source"`
	Target   int `json:"target"`
	Value    int `json:"value"`
	Distance int `json:"distance"`
}

type TopoData struct {
	Nodes []EosNode
	Links []Link
}

func writeConfigFile(path string, n EosNode, config string) {
	filename := path + n.Hostname + ".eos"
	err := ioutil.WriteFile(filename, []byte(config), 0644)
	if err != nil {
		panic(err)
	}
	fmt.Println("wrote to ", filename)
}

func readSwitches(filename string) []EosNode {
	var switches []EosNode

	file, err := os.Open("switches.json")
	if err != nil {
		panic(err)
	}
	decoder := json.NewDecoder(file)
	err = decoder.Decode(&switches)
	if err != nil {
		panic(err)
	}
	return switches
}

func genSwitches(nodes []EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for _, node := range nodes {
			out <- node
		}
		close(out)
	}()
	return out
}

func buildUrl(node EosNode) string {
	prefix := "http"
	if node.Ssl == true {
		prefix = prefix + "s"
	}
	url := prefix + "://" + node.Username + ":" + node.Password + "@" + node.Hostname + "/command-api"
	return url
}

func getConfigs(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			cmds := []string{"enable", "show running-config"}
			url := buildUrl(n)
			response := eapi.Call(url, cmds, "text")
			config := response.Result[1]["output"].(string)
			n.Config = config
			out <- n
		}
		close(out)
	}()
	return out
}

func getVersion(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			cmds := []string{"show version"}
			url := buildUrl(n)
			response := eapi.Call(url, cmds, "json")
			result := response.Result[0]
			n.Version = result["version"].(string)
			n.ModelName = result["modelName"].(string)
			out <- n
		}
		close(out)
	}()
	return out
}

func getIntfConnected(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			cmds := []string{"show interfaces status connected"}
			url := buildUrl(n)
			response := eapi.Call(url, cmds, "json")
			statuses := response.Result[0]["interfaceStatuses"].(map[string]interface{})
			for status := range statuses {
				n.IntfConnected = append(n.IntfConnected, status)
			}
			out <- n
		}
		close(out)
	}()
	return out
}

func getIpInterfaces(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			cmds := []string{"show ip interface"}
			url := buildUrl(n)
			response := eapi.Call(url, cmds, "json")
			intfs := response.Result[0]["interfaces"].(map[string]interface{})
			for intf := range intfs {
				n.IntfConnected = append(n.IntfConnected, intf)
			}
			out <- n
		}
		close(out)
	}()
	return out
}

// Gets LLDP Neighbors and updates the EosNodes with the neighbors
func getLldpNeighbors(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			fmt.Println("getLldpNeighbors" + n.Hostname)
			cmds := []string{"show lldp neighbors"}
			data := eapi.RawCall(buildUrl(n), cmds, "json")
			// data := eapi.Call(buildUrl(n), cmds, "json")
			var jsonresp eapi.RawJsonRpcResponse
			// var jsonresp map[string]interface{}
			err := json.Unmarshal(data, &jsonresp)
			if err != nil {
				fmt.Print("Json error: ")
				fmt.Println(err)
			}
			// v := jsonresp.Result[0].(eapi.ShowLldpNeighbors)
			var v eapi.ShowLldpNeighbors
			// var jsonresp2 []json.RawMessage

			json.Unmarshal(jsonresp.Result[0], &v)
			// v := data.Result[0].(eapi.ShowLldpNeighbors)
			// fmt.Println(jsonresp2)
			// fmt.Println(jsonresp["result"])
			// fmt.Println(v)
			n.LldpNeighbors = v.LldpNeighbors
			// neighbors := (response.Result[0]["lldpNeighbors"]).([]interface{})
			// for _, neigh := range neighbors {
			//     i := neigh.(map[string]interface {})
			//     n.LldpNeighbors = append(n.LldpNeighbors, i["neighborDevice"].(string))
			// }
			out <- n
		}
		close(out)
	}()
	return out
}

// HTTP Handler for /switches
func switchesHandler(w http.ResponseWriter, r *http.Request, switches []EosNode) {
	c1 := genSwitches(switches)
	c2 := getVersion(c1)
	c2 = getLldpNeighbors(c2)
	output := []EosNode{}

	for i := 0; i < len(switches); i++ {
		node := <-c2
		fmt.Println(node)
		output = append(output, node)
	}

	b, err := json.Marshal(output)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Fprintf(w, string(b))
}

// Used to remove the FQDN to make names shorter and consistent
func removeFqdn(host string, domain string) string {
	return strings.TrimSuffix(host, "."+domain)
}

func topoHandler(w http.ResponseWriter, r *http.Request, switches []EosNode) {
	c1 := genSwitches(switches)
	c2 := getLldpNeighbors(c1)
	nodes := []EosNode{}
	sourceIds := map[string]int{}
	var links []Link
	for i := 0; i < len(switches); i++ {
		node := <-c2
		fmt.Println(node)
		nodes = append(nodes, node)
		sourceIds[node.Hostname] = i
		fmt.Println("sourceIds:")
		fmt.Println(sourceIds)
	}
	for i, node := range nodes {
		for _, l := range node.LldpNeighbors {
			target, ok := sourceIds[removeFqdn(l.NeighborDevice, "aristanetworks.com")]
			if !ok {
				fmt.Println("Not a valid neighbor: " + l.NeighborDevice)
			} else {
				fmt.Println("Link from " + node.Hostname + " to " + l.NeighborDevice)
				link := Link{
					Source:   i,
					Target:   target,
					Value:    1,
					Distance: 5,
				}
				// link["source"] = i
				// link["target"] = target
				// link["value"] = 1
				// link["distance"] = 5
				// fmt.Println(removeFqdn(l.NeighborDevice, "aristanetworks.com"))
				links = append(links, link)
			}
		}
	}
	output := TopoData{Nodes: nodes, Links: links}
	b, err := json.Marshal(output)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Fprintf(w, string(b))
}

func panWebHandler(w http.ResponseWriter, r *http.Request, switches []EosNode) {
	svr := "172.22.28.143:8090"
	path := "/showinterfaces"
	url := "http://" + svr + path
	log.WithFields(log.Fields{
		"service": "panWebTest",
		"url":     url,
	}).Info("Testing Service")
	res, err := http.Get(url)
	var webStatus = DemoStatus{}
	if err != nil {
		webStatus.Working = false
		webStatus.Error = err.Error()
	} else {
		webStatus.Working = true
		defer res.Body.Close()
	}
	j, err := json.Marshal([]DemoStatus{webStatus})
	if err != nil {
		fmt.Println(err)
	}
	log.WithFields(log.Fields{
		"service": "panWebTest",
		"url":     url,
	}).Info("Finished Test")
	fmt.Fprintf(w, string(j))
}

func panHandler(w http.ResponseWriter, r *http.Request, switches []EosNode) {
	log.WithFields(log.Fields{
		"service": "panTest",
	}).Info("Starting Test")
	backupHost := "172.22.28.27"
	dosHost := "172.22.28.28"

	lab.PanResume()
	lab.PanClear()
	go lab.PingHost(dosHost)
	go lab.PingHost(backupHost)
	time.Sleep(30 * time.Second)

	// check flow entries
	bypassResult, bypassReason := lab.PanFlowTest("BYPASS")
	dropResult, dropReason := lab.PanFlowTest("DROP")
	// result := bypassResult + "\n" + dropResult
	lab.PanClear()
	// Change this to send a JSON reply instead
	bypassStatus := DemoStatus{Working: bypassResult, Error: bypassReason}
	dropStatus := DemoStatus{Working: dropResult, Error: dropReason}
	j, err := json.Marshal([]DemoStatus{bypassStatus, dropStatus})
	if err != nil {
		fmt.Fprintf(w, "Error encoding PAN demo response")
		return
	}
	log.WithFields(log.Fields{
		"service": "panTest",
	}).Info("Finsihed Test")
	fmt.Fprintf(w, string(j))
}

func makeHandler(fn func(http.ResponseWriter, *http.Request, []EosNode), switches []EosNode) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
		w.Header().Set("Access-Control-Allow-Headers",
			"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
		// Stop here if its Preflighted OPTIONS request
		if r.Method == "OPTIONS" {
			return
		}
		fn(w, r, switches)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {

}

func main() {
	swFilePtr := flag.String("swfile", "switches.json", "A JSON file with switches to fetch")
	flag.Parse() // command-line flag parsing
	switches := readSwitches(*swFilePtr)

	// http.HandleFunc("/switch", func(w http.ResponseWriter, r *http.Request) {
	// 	switchesHandler(w, r, switches)
	// })
	// http.HandleFunc("/topo", func(w http.ResponseWriter, r *http.Request) {
	// 	topoHandler(w, r, switches)
	// })
	// http.HandleFunc("/pan", func(w http.ResponseWriter, r *http.Request) {
	// 	panHandler(w, r, switches)
	// })
	http.HandleFunc("/switches", makeHandler(switchesHandler, switches))
	http.HandleFunc("/status", makeHandler(switchesHandler, switches))
	http.HandleFunc("/topo", makeHandler(topoHandler, switches))
	http.HandleFunc("/pan", makeHandler(panHandler, switches))
	// http.HandleFunc("/panweb", func(w http.ResponseWriter, r *http.Request) {
	// 	panWebHandler(w, r)
	// })
	http.HandleFunc("/panweb", makeHandler(panWebHandler, switches))
	http.Handle("/", http.FileServer(http.Dir(".")))
	http.ListenAndServe(":8081", nil)
}
<commit_msg>Created REST calls for neutron and subnet<commit_after>package main

import (
	"encoding/json"
	// "flag"
	"fmt"
	log "github.com/Sirupsen/logrus"
	lab "github.com/fredhsu/aristalabstatus"
	"github.com/fredhsu/eapigo"
	"github.com/gorilla/mux"
	"io/ioutil"
	"net/http"
	"os"
	"strings"
	"time"
)

type EosNode struct {
	Hostname      string
	ModelName     string
	MgmtIp        string
	Username      string
	Password      string
	Ssl           bool
	Reachable     bool
	ConfigCorrect bool
	Uptime        float64
	Version       string
	Config        string
	IntfConnected []string
	IpIntf        []string
	Vlans         []string
	LldpNeighbors []eapi.LldpNeighbor
}

type DemoStatus struct {
	Working bool
	Error   string
}

type ChanResponse struct {
	response eapi.JsonRpcResponse
	node     EosNode
}

type Link struct {
	Source   int `json:"source"`
	Target   int `json:"target"`
	Value    int `json:"value"`
	Distance int `json:"distance"`
}

type TopoData struct {
	Nodes []EosNode
	Links []Link
}

func writeConfigFile(path string, n EosNode, config string) {
	filename := path + n.Hostname + ".eos"
	err := ioutil.WriteFile(filename, []byte(config), 0644)
	if err != nil {
		panic(err)
	}
	fmt.Println("wrote to ", filename)
}

func readSwitches(filename string) []EosNode {
	var switches []EosNode

	file, err := os.Open("switches.json")
	if err != nil {
		panic(err)
	}
	decoder := json.NewDecoder(file)
	err = decoder.Decode(&switches)
	if err != nil {
		panic(err)
	}
	return switches
}

func genSwitches(nodes []EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for _, node := range nodes {
			out <- node
		}
		close(out)
	}()
	return out
}

func buildUrl(node EosNode) string {
	prefix := "http"
	if node.Ssl == true {
		prefix = prefix + "s"
	}
	url := prefix + "://" + node.Username + ":" + node.Password + "@" + node.Hostname + "/command-api"
	return url
}

func getConfigs(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			cmds := []string{"enable", "show running-config"}
			url := buildUrl(n)
			response := eapi.Call(url, cmds, "text")
			config := response.Result[1]["output"].(string)
			n.Config = config
			out <- n
		}
		close(out)
	}()
	return out
}

func getVersion(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			cmds := []string{"show version"}
			url := buildUrl(n)
			response := eapi.Call(url, cmds, "json")
			result := response.Result[0]
			n.Version = result["version"].(string)
			n.ModelName = result["modelName"].(string)
			out <- n
		}
		close(out)
	}()
	return out
}

func getIntfConnected(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			cmds := []string{"show interfaces status connected"}
			url := buildUrl(n)
			response := eapi.Call(url, cmds, "json")
			statuses := response.Result[0]["interfaceStatuses"].(map[string]interface{})
			for status := range statuses {
				n.IntfConnected = append(n.IntfConnected, status)
			}
			out <- n
		}
		close(out)
	}()
	return out
}

func getIpInterfaces(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			cmds := []string{"show ip interface"}
			url := buildUrl(n)
			response := eapi.Call(url, cmds, "json")
			intfs := response.Result[0]["interfaces"].(map[string]interface{})
			for intf := range intfs {
				n.IntfConnected = append(n.IntfConnected, intf)
			}
			out <- n
		}
		close(out)
	}()
	return out
}

// Gets LLDP Neighbors and updates the EosNodes with the neighbors
func getLldpNeighbors(in <-chan EosNode) <-chan EosNode {
	out := make(chan EosNode)
	go func() {
		for n := range in {
			fmt.Println("getLldpNeighbors" + n.Hostname)
			cmds := []string{"show lldp neighbors"}
			data := eapi.RawCall(buildUrl(n), cmds, "json")
			// data := eapi.Call(buildUrl(n), cmds, "json")
			var jsonresp eapi.RawJsonRpcResponse
			// var jsonresp map[string]interface{}
			err := json.Unmarshal(data, &jsonresp)
			if err != nil {
				fmt.Print("Json error: ")
				fmt.Println(err)
			}
			// v := jsonresp.Result[0].(eapi.ShowLldpNeighbors)
			var v eapi.ShowLldpNeighbors
			// var jsonresp2 []json.RawMessage

			json.Unmarshal(jsonresp.Result[0], &v)
			// v := data.Result[0].(eapi.ShowLldpNeighbors)
			// fmt.Println(jsonresp2)
			// fmt.Println(jsonresp["result"])
			// fmt.Println(v)
			n.LldpNeighbors = v.LldpNeighbors
			// neighbors := (response.Result[0]["lldpNeighbors"]).([]interface{})
			// for _, neigh := range neighbors {
			//     i := neigh.(map[string]interface {})
			//     n.LldpNeighbors = append(n.LldpNeighbors, i["neighborDevice"].(string))
			// }
			out <- n
		}
		close(out)
	}()
	return out
}

// HTTP Handler for /switches
func switchesHandler(w http.ResponseWriter, r *http.Request) {
	switches := readSwitches("switches.json")

	c1 := genSwitches(switches)
	c2 := getVersion(c1)
	c2 = getLldpNeighbors(c2)
	output := []EosNode{}

	for i := 0; i < len(switches); i++ {
		node := <-c2
		fmt.Println(node)
		output = append(output, node)
	}

	b, err := json.Marshal(output)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Fprintf(w, string(b))
}

// Used to remove the FQDN to make names shorter and consistent
func removeFqdn(host string, domain string) string {
	return strings.TrimSuffix(host, "."+domain)
}

func topoHandler(w http.ResponseWriter, r *http.Request) {
	switches := readSwitches("switches.json")

	c1 := genSwitches(switches)
	c2 := getLldpNeighbors(c1)
	nodes := []EosNode{}
	sourceIds := map[string]int{}
	var links []Link
	for i := 0; i < len(switches); i++ {
		node := <-c2
		fmt.Println(node)
		nodes = append(nodes, node)
		sourceIds[node.Hostname] = i
		fmt.Println("sourceIds:")
		fmt.Println(sourceIds)
	}
	for i, node := range nodes {
		for _, l := range node.LldpNeighbors {
			target, ok := sourceIds[removeFqdn(l.NeighborDevice, "aristanetworks.com")]
			if !ok {
				fmt.Println("Not a valid neighbor: " + l.NeighborDevice)
			} else {
				fmt.Println("Link from " + node.Hostname + " to " + l.NeighborDevice)
				link := Link{
					Source:   i,
					Target:   target,
					Value:    1,
					Distance: 5,
				}
				// link["source"] = i
				// link["target"] = target
				// link["value"] = 1
				// link["distance"] = 5
				// fmt.Println(removeFqdn(l.NeighborDevice, "aristanetworks.com"))
				links = append(links, link)
			}
		}
	}
	output := TopoData{Nodes: nodes, Links: links}
	b, err := json.Marshal(output)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Fprintf(w, string(b))
}

func panWebHandler(w http.ResponseWriter, r *http.Request) {
	svr := "172.22.28.143:8090"
	path := "/showinterfaces"
	url := "http://" + svr + path
	log.WithFields(log.Fields{
		"service": "panWebTest",
		"url":     url,
	}).Info("Testing Service")
	res, err := http.Get(url)
	var webStatus = DemoStatus{}
	if err != nil {
		webStatus.Working = false
		webStatus.Error = err.Error()
	} else {
		webStatus.Working = true
		defer res.Body.Close()
	}
	j, err := json.Marshal([]DemoStatus{webStatus})
	if err != nil {
		fmt.Println(err)
	}
	log.WithFields(log.Fields{
		"service": "panWebTest",
		"url":     url,
	}).Info("Finished Test")
	fmt.Fprintf(w, string(j))
}

func panHandler(w http.ResponseWriter, r *http.Request) {
	log.WithFields(log.Fields{
		"service": "panTest",
	}).Info("Starting Test")
	backupHost := "172.22.28.27"
	dosHost := "172.22.28.28"

	lab.PanResume()
	lab.PanClear()
	go lab.PingHost(dosHost)
	go lab.PingHost(backupHost)
	time.Sleep(30 * time.Second)

	// check flow entries
	bypassResult, bypassReason := lab.PanFlowTest("BYPASS")
	dropResult, dropReason := lab.PanFlowTest("DROP")
	// result := bypassResult + "\n" + dropResult
	lab.PanClear()
	// Change this to send a JSON reply instead
	bypassStatus := DemoStatus{Working: bypassResult, Error: bypassReason}
	dropStatus := DemoStatus{Working: dropResult, Error: dropReason}
	j, err := json.Marshal([]DemoStatus{bypassStatus, dropStatus})
	if err != nil {
		fmt.Fprintf(w, "Error encoding PAN demo response")
		return
	}
	log.WithFields(log.Fields{
		"service": "panTest",
	}).Info("Finsihed Test")
	fmt.Fprintf(w, string(j))
}

func openstackHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	method := vars["method"]
	log.WithFields(log.Fields{
		"service": "openstack",
		"method":  method,
	}).Info("Starting Test")
	switch method {
	case "neutron":
		nclient := lab.GetNetworkClient()
		name := "test_network"
		net := lab.CreateNetwork(nclient, name)
		fmt.Fprintf(w, net.Name+" created")
		return
	case "subnet":
		nclient := lab.GetNetworkClient()
		_, net := lab.FindNetwork(nclient, "test_network")
		sn := lab.CreateSubnet(nclient, "test_network_sn", net.ID, "192.168.187.0/24")
		fmt.Fprintf(w, sn.Name+" created")
		return
	case "nova":
		nclient := lab.GetNetworkClient()
		cc := lab.GetComputeClient()
		_, net := lab.FindNetwork(nclient, "test_network")
		s := lab.CreateCompute(cc, "test_vm", net.ID)
		fmt.Fprintf(w, s.Name+" created")
		return
	case "eos":
		// Test Network in EOS
		// Test VM in EOS
		fmt.Fprintf(w, method)

		return
	case "reset":
		// Remove all VMs
		// Remove all networks
		fmt.Fprintf(w, method)

	}

}

// No longer needed since I'm running from Angular the same web server
// No CORS anymore!
func makeHandler(fn func(http.ResponseWriter, *http.Request, []EosNode), switches []EosNode) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
		w.Header().Set("Access-Control-Allow-Headers",
			"Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
		// Stop here if its Preflighted OPTIONS request
		if r.Method == "OPTIONS" {
			return
		}
		fn(w, r, switches)
	}
}

func rootHandler(w http.ResponseWriter, r *http.Request) {

}

func main() {
	// swFilePtr := flag.String("swfile", "switches.json", "A JSON file with switches to fetch")
	// flag.Parse() // command-line flag parsing
	// switches := readSwitches(*swFilePtr)
	// fmt.Println(switches)
	// http.HandleFunc("/switch", func(w http.ResponseWriter, r *http.Request) {
	// 	switchesHandler(w, r, switches)
	// })
	// http.HandleFunc("/topo", func(w http.ResponseWriter, r *http.Request) {
	// 	topoHandler(w, r, switches)
	// })
	// http.HandleFunc("/pan", func(w http.ResponseWriter, r *http.Request) {
	// 	panHandler(w, r, switches)
	// })
	r := mux.NewRouter()
	// http.HandleFunc("/switches", makeHandler(switchesHandler, switches))
	//r.HandleFunc("/status", makeHandler(switchesHandler, switches))
	r.HandleFunc("/topo", topoHandler)
	r.HandleFunc("/status", switchesHandler)
	r.HandleFunc("/pan", panHandler)
	r.HandleFunc("/openstack/{method}", openstackHandler)
	r.HandleFunc("/panweb", panWebHandler)
	// http.HandleFunc("/panweb", func(w http.ResponseWriter, r *http.Request) {
	// 	panWebHandler(w, r)
	// })
	// r.HandleFunc("/panweb", makeHandler(panWebHandler, switches))
	r.PathPrefix("/").Handler(http.FileServer(http.Dir(".")))
	http.Handle("/", r)
	// r.Handle("/", http.FileServer(http.Dir(".")))
	http.ListenAndServe(":8081", r)
}
<|endoftext|>


<commit_before>// Package store ingest monitoring time series data points
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//: All Rights Reserved
//:
//: file:    store.go
//: details: TODO
//: author:  Mehrdad Arshad Rad
//: date:    02/01/2017
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//:     http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//: See the License for the specific language governing permissions and
//: limitations under the License.
//: ----------------------------------------------------------------------------
package store

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

// Monitor is an interface to store system
// and netflow statistics
type Monitor interface {
	System() error
	Netflow() error
}

// IPFIX represents IPFIX metrics
type IPFIX struct {
	UDPQueue       int64
	UDPMirrorQueue int64
	MessageQueue   int64
	UDPCount       int64
	DecodedCount   int64
	MQErrorCount   int64
}

// SFlow represents SFlow metrics
type SFlow struct {
	UDPQueue     int64
	MessageQueue int64
	UDPCount     int64
	DecodedCount int64
	MQErrorCount int64
}

// Flow represents flow (IPFIX+sFlow) metrics
type Flow struct {
	StartTime int64
	Timestamp int64
	IPFIX     IPFIX
	SFlow     SFlow
}

// Sys represents system/go-runtime statistics
type Sys struct {
	MemHeapAlloc    int64
	MemAlloc        int64
	MCacheInuse     int64
	GCNext          int64
	MemTotalAlloc   int64
	GCSys           int64
	MemHeapSys      int64
	NumGoroutine    int64
	NumLogicalCPU   int64
	MemHeapReleased int64
}

// Client represents HTTP client
type Client struct {
	client *http.Client
}

// NewHTTP constructs HTTP client
func NewHTTP() *Client {
	return &Client{
		client: new(http.Client),
	}
}

// Get tries to get metrics through HTTP w/ get method
func (c *Client) Get(url string, s interface{}) error {

	resp, err := c.client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

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

	err = json.Unmarshal(body, &s)
	if err != nil {
		return err
	}

	return nil
}

// Post tries to digest metrics through HTTP w/ post method
func (c *Client) Post(url string, cType, query string) ([]byte, error) {
	resp, err := c.client.Post(url, cType, bytes.NewBufferString(query))
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

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

	return body, nil
}

func getFlow(host string) (*Flow, *Flow, error) {
	lastFlowFile := "/tmp/vflow.mon.lastflow"

	flow := new(Flow)
	lastFlow := new(Flow)

	client := NewHTTP()
	err := client.Get(host+"/flow", flow)
	if err != nil {
		return nil, nil, err
	}

	flow.Timestamp = time.Now().Unix()

	b, err := ioutil.ReadFile(lastFlowFile)
	if err != nil {
		b, _ = json.Marshal(flow)
		ioutil.WriteFile(lastFlowFile, b, 0644)
		return nil, nil, err
	}

	err = json.Unmarshal(b, &lastFlow)
	if err != nil {
		return nil, nil, err
	}

	b, err = json.Marshal(flow)
	if err != nil {
		return nil, nil, err
	}

	ioutil.WriteFile(lastFlowFile, b, 0644)

	// once the vFlow restarted
	if flow.StartTime != lastFlow.StartTime {
		os.Exit(1)
	}

	return flow, lastFlow, err
}
<commit_msg>add workers to sflow<commit_after>// Package store ingest monitoring time series data points
//: ----------------------------------------------------------------------------
//: Copyright (C) 2017 Verizon.  All Rights Reserved.
//: All Rights Reserved
//:
//: file:    store.go
//: details: an interface to other store back-end
//: author:  Mehrdad Arshad Rad
//: date:    02/01/2017
//:
//: Licensed under the Apache License, Version 2.0 (the "License");
//: you may not use this file except in compliance with the License.
//: You may obtain a copy of the License at
//:
//:     http://www.apache.org/licenses/LICENSE-2.0
//:
//: Unless required by applicable law or agreed to in writing, software
//: distributed under the License is distributed on an "AS IS" BASIS,
//: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//: See the License for the specific language governing permissions and
//: limitations under the License.
//: ----------------------------------------------------------------------------
package store

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

// Monitor is an interface to store system
// and netflow statistics
type Monitor interface {
	System() error
	Netflow() error
}

// IPFIX represents IPFIX metrics
type IPFIX struct {
	UDPQueue       int64
	UDPMirrorQueue int64
	MessageQueue   int64
	UDPCount       int64
	DecodedCount   int64
	MQErrorCount   int64
}

// SFlow represents SFlow metrics
type SFlow struct {
	UDPQueue     int64
	MessageQueue int64
	UDPCount     int64
	DecodedCount int64
	MQErrorCount int64
	Workers      int64
}

// Flow represents flow (IPFIX+sFlow) metrics
type Flow struct {
	StartTime int64
	Timestamp int64
	IPFIX     IPFIX
	SFlow     SFlow
}

// Sys represents system/go-runtime statistics
type Sys struct {
	MemHeapAlloc    int64
	MemAlloc        int64
	MCacheInuse     int64
	GCNext          int64
	MemTotalAlloc   int64
	GCSys           int64
	MemHeapSys      int64
	NumGoroutine    int64
	NumLogicalCPU   int64
	MemHeapReleased int64
}

// Client represents HTTP client
type Client struct {
	client *http.Client
}

// NewHTTP constructs HTTP client
func NewHTTP() *Client {
	return &Client{
		client: new(http.Client),
	}
}

// Get tries to get metrics through HTTP w/ get method
func (c *Client) Get(url string, s interface{}) error {

	resp, err := c.client.Get(url)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

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

	err = json.Unmarshal(body, &s)
	if err != nil {
		return err
	}

	return nil
}

// Post tries to digest metrics through HTTP w/ post method
func (c *Client) Post(url string, cType, query string) ([]byte, error) {
	resp, err := c.client.Post(url, cType, bytes.NewBufferString(query))
	if err != nil {
		return nil, err
	}

	defer resp.Body.Close()

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

	return body, nil
}

func getFlow(host string) (*Flow, *Flow, error) {
	lastFlowFile := "/tmp/vflow.mon.lastflow"

	flow := new(Flow)
	lastFlow := new(Flow)

	client := NewHTTP()
	err := client.Get(host+"/flow", flow)
	if err != nil {
		return nil, nil, err
	}

	flow.Timestamp = time.Now().Unix()

	b, err := ioutil.ReadFile(lastFlowFile)
	if err != nil {
		b, _ = json.Marshal(flow)
		ioutil.WriteFile(lastFlowFile, b, 0644)
		return nil, nil, err
	}

	err = json.Unmarshal(b, &lastFlow)
	if err != nil {
		return nil, nil, err
	}

	b, err = json.Marshal(flow)
	if err != nil {
		return nil, nil, err
	}

	ioutil.WriteFile(lastFlowFile, b, 0644)

	// once the vFlow restarted
	if flow.StartTime != lastFlow.StartTime {
		os.Exit(1)
	}

	return flow, lastFlow, err
}
<|endoftext|>


<commit_before>package service

import (
	"context"
	"errors"
	host "gx/ipfs/QmPsRtodRuBUir32nz5v4zuSBTSszrR1d3fA6Ahb6eaejj/go-libp2p-host"
	inet "gx/ipfs/QmQx1dHDDYENugYgqA22BaBrRfuv1coSsuPiM7rYh1wwGH/go-libp2p-net"
	ggio "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/io"
	protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
	ps "gx/ipfs/QmeXj9VAjmYQZxpmVz7VzccbJrpmr8qkCDSjfVNsPTWTYU/go-libp2p-peerstore"
	peer "gx/ipfs/QmfMmLGoKzCHDN7cGgk64PJr4iipzidDRME8HABSJqvmhC/go-libp2p-peer"
	"sync"

	"github.com/OpenBazaar/openbazaar-go/core"
	"github.com/OpenBazaar/openbazaar-go/pb"
	"github.com/OpenBazaar/openbazaar-go/repo"
	"github.com/ipfs/go-ipfs/commands"
	ctxio "github.com/jbenet/go-context/io"
	"github.com/op/go-logging"
)

var log = logging.MustGetLogger("service")

var ProtocolOpenBazaar protocol.ID = "/openbazaar/app/1.0.0"

type OpenBazaarService struct {
	host      host.Host
	self      peer.ID
	peerstore ps.Peerstore
	cmdCtx    commands.Context
	ctx       context.Context
	broadcast chan interface{}
	datastore repo.Datastore
	node      *core.OpenBazaarNode
	sender    map[peer.ID]*messageSender
	senderlk  sync.Mutex
}

func New(node *core.OpenBazaarNode, ctx commands.Context, datastore repo.Datastore) *OpenBazaarService {
	service := &OpenBazaarService{
		host:      node.IpfsNode.PeerHost.(host.Host),
		self:      node.IpfsNode.Identity,
		peerstore: node.IpfsNode.PeerHost.Peerstore(),
		cmdCtx:    ctx,
		ctx:       node.IpfsNode.Context(),
		broadcast: node.Broadcast,
		datastore: datastore,
		node:      node,
	}
	node.IpfsNode.PeerHost.SetStreamHandler(ProtocolOpenBazaar, service.HandleNewStream)
	log.Infof("OpenBazaar service running at %s", ProtocolOpenBazaar)
	return service
}

func (service *OpenBazaarService) HandleNewStream(s inet.Stream) {
	go service.handleNewMessage(s)
}

func (service *OpenBazaarService) handleNewMessage(s inet.Stream) {
	cr := ctxio.NewReader(service.ctx, s)
	cw := ctxio.NewWriter(service.ctx, s)
	r := ggio.NewDelimitedReader(cr, inet.MessageSizeMax)
	w := ggio.NewDelimitedWriter(cw)
	mPeer := s.Conn().RemotePeer()
	// Check if banned
	if service.node.BanManager.IsBanned(mPeer) {
		return
	}

	// ensure the message sender for this peer is updated with this stream, so we reply over it
	service.messageSenderForPeer(mPeer, &s)
	defer s.Close()
	i := 0 // REMOVE
	for {
		log.Info("inbound stream reuse count:", i)
		i++
		// Receive msg
		pmes := new(pb.Message)
		if err := r.ReadMsg(pmes); err != nil {
			log.Errorf("Error unmarshaling data: %s", err)
			return
		}

		// Get handler for this msg type
		handler := service.HandlerForMsgType(pmes.MessageType)
		if handler == nil {
			log.Debug("Got back nil handler from handlerForMsgType")
			return
		}

		// Dispatch handler
		rpmes, err := handler(mPeer, pmes, nil)
		if err != nil {
			log.Debugf("handle message error: %s", err)
			return
		}

		// If nil response, return it before serializing
		if rpmes == nil {
			continue
		}

		// Send out response msg
		if err := w.WriteMsg(rpmes); err != nil {
			log.Debugf("send response error: %s", err)
			return
		}
	}
}

func (service *OpenBazaarService) SendRequest(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Sending %s request to %s", pmes.MessageType.String(), p.Pretty())
	ms := service.messageSenderForPeer(p, nil)

	rpmes, err := ms.SendRequest(ctx, pmes)
	if err != nil {
		log.Debugf("No response from %s", p.Pretty())
		return nil, err
	}

	if rpmes == nil {
		log.Debugf("No response from %s", p.Pretty())
		return nil, errors.New("no response from peer")
	}

	log.Debugf("Received response from %s", p.Pretty())

	return rpmes, nil
}

func (service *OpenBazaarService) SendMessage(ctx context.Context, p peer.ID, pmes *pb.Message) error {
	log.Debugf("Sending %s message to %s", pmes.MessageType.String(), p.Pretty())
	ms := service.messageSenderForPeer(p, nil)

	if err := ms.SendMessage(ctx, pmes); err != nil {
		return err
	}
	return nil
}
<commit_msg>remember to initialise your maps<commit_after>package service

import (
	"context"
	"errors"
	host "gx/ipfs/QmPsRtodRuBUir32nz5v4zuSBTSszrR1d3fA6Ahb6eaejj/go-libp2p-host"
	inet "gx/ipfs/QmQx1dHDDYENugYgqA22BaBrRfuv1coSsuPiM7rYh1wwGH/go-libp2p-net"
	ggio "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/io"
	protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
	ps "gx/ipfs/QmeXj9VAjmYQZxpmVz7VzccbJrpmr8qkCDSjfVNsPTWTYU/go-libp2p-peerstore"
	peer "gx/ipfs/QmfMmLGoKzCHDN7cGgk64PJr4iipzidDRME8HABSJqvmhC/go-libp2p-peer"
	"sync"

	"github.com/OpenBazaar/openbazaar-go/core"
	"github.com/OpenBazaar/openbazaar-go/pb"
	"github.com/OpenBazaar/openbazaar-go/repo"
	"github.com/ipfs/go-ipfs/commands"
	ctxio "github.com/jbenet/go-context/io"
	"github.com/op/go-logging"
)

var log = logging.MustGetLogger("service")

var ProtocolOpenBazaar protocol.ID = "/openbazaar/app/1.0.0"

type OpenBazaarService struct {
	host      host.Host
	self      peer.ID
	peerstore ps.Peerstore
	cmdCtx    commands.Context
	ctx       context.Context
	broadcast chan interface{}
	datastore repo.Datastore
	node      *core.OpenBazaarNode
	sender    map[peer.ID]*messageSender
	senderlk  sync.Mutex
}

func New(node *core.OpenBazaarNode, ctx commands.Context, datastore repo.Datastore) *OpenBazaarService {
	service := &OpenBazaarService{
		host:      node.IpfsNode.PeerHost.(host.Host),
		self:      node.IpfsNode.Identity,
		peerstore: node.IpfsNode.PeerHost.Peerstore(),
		cmdCtx:    ctx,
		ctx:       node.IpfsNode.Context(),
		broadcast: node.Broadcast,
		datastore: datastore,
		node:      node,
		sender:    make(map[peer.ID]*messageSender),
	}
	node.IpfsNode.PeerHost.SetStreamHandler(ProtocolOpenBazaar, service.HandleNewStream)
	log.Infof("OpenBazaar service running at %s", ProtocolOpenBazaar)
	return service
}

func (service *OpenBazaarService) HandleNewStream(s inet.Stream) {
	go service.handleNewMessage(s)
}

func (service *OpenBazaarService) handleNewMessage(s inet.Stream) {
	cr := ctxio.NewReader(service.ctx, s)
	cw := ctxio.NewWriter(service.ctx, s)
	r := ggio.NewDelimitedReader(cr, inet.MessageSizeMax)
	w := ggio.NewDelimitedWriter(cw)
	mPeer := s.Conn().RemotePeer()
	// Check if banned
	if service.node.BanManager.IsBanned(mPeer) {
		return
	}

	// ensure the message sender for this peer is updated with this stream, so we reply over it
	service.messageSenderForPeer(mPeer, &s)
	defer s.Close()
	i := 0 // REMOVE
	for {
		log.Info("inbound stream reuse count:", i)
		i++
		// Receive msg
		pmes := new(pb.Message)
		if err := r.ReadMsg(pmes); err != nil {
			log.Errorf("Error unmarshaling data: %s", err)
			return
		}

		// Get handler for this msg type
		handler := service.HandlerForMsgType(pmes.MessageType)
		if handler == nil {
			log.Debug("Got back nil handler from handlerForMsgType")
			return
		}

		// Dispatch handler
		rpmes, err := handler(mPeer, pmes, nil)
		if err != nil {
			log.Debugf("handle message error: %s", err)
			return
		}

		// If nil response, return it before serializing
		if rpmes == nil {
			continue
		}

		// Send out response msg
		if err := w.WriteMsg(rpmes); err != nil {
			log.Debugf("send response error: %s", err)
			return
		}
	}
}

func (service *OpenBazaarService) SendRequest(ctx context.Context, p peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Sending %s request to %s", pmes.MessageType.String(), p.Pretty())
	ms := service.messageSenderForPeer(p, nil)

	rpmes, err := ms.SendRequest(ctx, pmes)
	if err != nil {
		log.Debugf("No response from %s", p.Pretty())
		return nil, err
	}

	if rpmes == nil {
		log.Debugf("No response from %s", p.Pretty())
		return nil, errors.New("no response from peer")
	}

	log.Debugf("Received response from %s", p.Pretty())

	return rpmes, nil
}

func (service *OpenBazaarService) SendMessage(ctx context.Context, p peer.ID, pmes *pb.Message) error {
	log.Debugf("Sending %s message to %s", pmes.MessageType.String(), p.Pretty())
	ms := service.messageSenderForPeer(p, nil)

	if err := ms.SendMessage(ctx, pmes); err != nil {
		return err
	}
	return nil
}
<|endoftext|>