<commit_before>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"cloud.google.com/go/pubsub"
	"github.com/hpcloud/tail"
	log "github.com/sirupsen/logrus"
	"google.golang.org/api/option"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	configFile = kingpin.Flag("config", "Configuration file").Required().Short('c').String()
	version    = "master" //overridden by build system, master as default
)

/*
Todo:
- See if I can get hpcloud/tail to use logrus?
- lots of error handling
- config param defaults
- add signal handler support
*/

//FlingConfig - top level structure of json config file
type FlingConfig struct {
	Input     FlingInput      `json:"input"`
	Files     []FlingInFile   `json:"files"`
	Rotations []FlingRotation `json:"rotations"`
	Output    FlingOutput     `json:"output"`
}

//FlingInput - map of input type arrays
type FlingInput struct {
	PubSubs []FlingInPubSub `json:"pubsub"`
	Files   []FlingInFile   `json:"files"`
}

//FlingInPubSub - pub/sub input type
type FlingInPubSub struct {
	AuthFile     string           `json:"auth_file"`
	Project      string           `json:"project"`
	Subscription string           `json:"subscription"`
	Outputs      []string         `json:"outputs"`
	Injections   []FlingInjection `json:"injections"`
}

// FlingRotation - sets of files to rotate and the commands to run afterwards
type FlingRotation struct {
	Files          []string `json:"files"`
	RotateCommand  string   `json:"rotate_command"`
	RotateInterval int      `json:"rotate_interval"`
}

//FlingOutput - map of output types
type FlingOutput struct {
	PubSubs []FlingOutPubSub `json:"pubsub"`
	Loggers []FlingOutLogger `json:"logger"`
}

//FlingOutPubSub - A log output destination
type FlingOutPubSub struct {
	Name     string `json:"name"`
	Project  string `json:"project"`
	Topic    string `json:"topic"`
	AuthFile string `json:"auth_file"`
}

//FlingOutLogger - Send messages to the logger library
//FIXME add level and injections
type FlingOutLogger struct {
	Name      string `json:"name"`
	IsEnabled bool   `json:"is_enabled"`
}

//FlingInFile - instance of a file to monitor
type FlingInFile struct {
	Path       string           `json:"path"`
	IsJSON     bool             `json:"is_json"`
	IsGlob     bool             `json:"is_glob"`
	Outputs    []string         `json:"outputs"`
	Injections []FlingInjection `json:"injections"`
}

//FlingInjection - fields to add to the log line
type FlingInjection struct {
	Field    string `json:"field"`
	Value    string `json:"value"`
	ENVValue string `json:"env_value"`
	Hostname bool   `json:"hostname"`
}

func init() {
	log.SetFormatter(&log.JSONFormatter{})
	log.SetOutput(os.Stdout)
	log.SetLevel(log.DebugLevel)
}

func main() {
	log.Info("Initalizing")
	//Parse command line params
	kingpin.Version(version)
	kingpin.Parse()

	var config, err = loadConfig(*configFile)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Couldn't load config")
		os.Exit(-1)
	}

	//var outputs map[string]interface{}
	//start up go routines for any outputs
	outputChannels := handleOutputs(config.Output)

	//start up go routines for any rotations requested
	handleRotations(config.Rotations)

	//setup handlers for all of the files to be watched
	handleInputs(config.Input, outputChannels)

	select {} //Take a big nap FIXME: add signal handlers down the road
}

func loadConfig(path string) (FlingConfig, error) {
	var config FlingConfig
	configString, readError := ioutil.ReadFile(path)

	if readError != nil {
		return config, readError
	}

	parseError := json.Unmarshal(configString, &config)

	return config, parseError
}

func handleInputs(input FlingInput, outputChannels map[string]interface{}) {
	handleInFiles(input.Files, outputChannels)
}

func handleOutputs(outputs FlingOutput) map[string]interface{} {
	var channels map[string]interface{}
	channels = make(map[string]interface{})

	for k, v := range handleOutPubSubs(outputs.PubSubs) {
		channels[k] = v
	}

	for k, v := range handleOutLoggers(outputs.Loggers) {
		channels[k] = v
	}

	return channels
}

func handleOutLoggers(outputs []FlingOutLogger) map[string]interface{} {
	var channels map[string]interface{}
	channels = make(map[string]interface{})

	for _, output := range outputs {
		channels[output.Name] = make(chan []byte, 1000)
		go outputLoggerWorker(output.Name, output.IsEnabled, channels[output.Name].(chan []byte))
	}

	return channels
}

func outputLoggerWorker(name string, isEnabled bool, channel chan []byte) {
	for {
		message := <-channel

		if isEnabled {
			log.WithFields(log.Fields{
				"OutputName": name,
			}).Debug(fmt.Sprintf("%s", message))
		}
	}
}

func handleOutPubSubs(outputs []FlingOutPubSub) map[string]interface{} {
	var channels map[string]interface{}
	channels = make(map[string]interface{})

	for _, output := range outputs {
		channels[output.Name] = make(chan []byte, 1000)
		go outputPubSubWorker(output.Project, output.Topic, output.AuthFile, channels[output.Name].(chan []byte))
	}

	return channels
}

func outputPubSubWorker(project string, topicName string, authfile string, channel chan []byte) {
	ctx := context.Background()
	pubSubClient, err := pubsub.NewClient(ctx, project, option.WithServiceAccountFile(authfile))
	if err != nil {

	}

	topic := pubSubClient.Topic(topicName)
	defer topic.Stop()

	//send hello message to topic to keep track of what clients, versions etc.. are sending in data
	createPubSubInitMsg(topicName, channel)

	for {
		message := <-channel
		result := topic.Publish(ctx, &pubsub.Message{
			Data: message,
		})

		id, err := result.Get(ctx)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Error("Failed to publish message")
		} else {
			log.WithFields(log.Fields{
				"id": id,
			}).Debug("Published Message")
		}

	}
}

func createPubSubInitMsg(topicName string, channel chan []byte) {
	var logEntry map[string]interface{}
	logEntry = make(map[string]interface{})
	hostname, _ := os.Hostname()

	logEntry["pubsub_topic"] = topicName
	logEntry["fling_version"] = version
	logEntry["hostname"] = hostname
	logEntry["@timestamp"] = get3339Time()
	logEntry["message"] = "Starting up Fling PubSub Output"

	eventJSON, marshalErr := json.Marshal(logEntry)
	if marshalErr != nil {
		log.WithFields(log.Fields{}).Error("PubSub Init message creation failed")
		return
	}

	channel <- eventJSON
	log.WithFields(log.Fields{"topic": topicName}).Info("PubSub Init message queued")
}

func handleInFiles(files []FlingInFile, outputs map[string]interface{}) {
	for _, file := range files {
		if file.IsGlob {
			paths, _ := filepath.Glob(file.Path)
			for _, path := range paths {
				file.Path = path
				startFileWorker(file, outputs)
			}
		} else {
			startFileWorker(file, outputs)
		}
	}
}

func startFileWorker(file FlingInFile, outputs map[string]interface{}) {
	log.WithFields(log.Fields{
		"path": file.Path,
	}).Info("Adding tail for file")
	go fileWorker(file, outputs)
}

func fileWorker(file FlingInFile, outputs map[string]interface{}) {
	t, tailErr := tail.TailFile(file.Path, tail.Config{Follow: true, ReOpen: true, Poll: true})

	if tailErr != nil {
		log.WithFields(log.Fields{
			"path":  file.Path,
			"error": tailErr,
		}).Error("Couldn't tail file")
	}

	for line := range t.Lines {
		var logEntry map[string]interface{}

		log.WithFields(log.Fields{
			"path": file.Path,
			"line": line.Text,
		}).Debug("Processing log line")

		if file.IsJSON {
			unmarshalErr := json.Unmarshal([]byte(line.Text), &logEntry)
			if unmarshalErr != nil {
				log.WithFields(log.Fields{
					"message": line.Text,
					"error":   unmarshalErr,
				}).Error("Couldn't parse JSON log line")

				continue
			}
		} else {
			logEntry = make(map[string]interface{})
			logEntry["message"] = line.Text
		}

		//FIXME: Inject other pertinent context info
		logEntry["fling.source"] = file.Path

		if _, ok := logEntry["@timestamp"]; !ok {
			logEntry["@timestamp"] = get3339Time()
		}

		handleInjections(&logEntry, file.Injections)

		eventJSON, marshalErr := json.Marshal(logEntry)
		if marshalErr != nil {
			log.WithFields(log.Fields{
				"error": marshalErr,
			}).Error("Couldn't create JSON")

			continue
		}

		dispatchEntry(eventJSON, file.Outputs, outputs)
	}
}

func handleInjections(logEntry *map[string]interface{}, injections []FlingInjection) {
	for _, injection := range injections {
		if injection.ENVValue != "" {
			(*logEntry)[injection.Field] = os.Getenv(injection.ENVValue)
		} else if injection.Value != "" {
			(*logEntry)[injection.Field] = injection.Value
		} else if injection.Hostname {
			hostname, _ := os.Hostname()
			(*logEntry)[injection.Field] = hostname
		}
	}
}

func dispatchEntry(message []byte, outputs []string, channels map[string]interface{}) {
	for _, output := range outputs {
		channels[output].(chan []byte) <- message
	}
}

func handleRotations(rotations []FlingRotation) {
	for _, rotation := range rotations {
		go rotateWorker(rotation)
	}
}

func rotateWorker(rotation FlingRotation) {
	for {
		log.WithFields(log.Fields{
			"seconds": rotation.RotateInterval,
		}).Info("Sleeping before rotate")

		time.Sleep(time.Duration(rotation.RotateInterval) * time.Second)

		rotate(rotation)
	}
}

func rotate(rotation FlingRotation) {
	//Handle the files first
	for _, path := range rotation.Files {
		//FIXME add file size check

		renameErr := os.Rename(path, path+".old")
		if renameErr != nil {
			log.WithFields(log.Fields{
				"path": path,
			}).Error("Unable to move log file in rotation")

			continue
		} else {
			log.WithFields(log.Fields{
				"path": path,
			}).Info("Moved log file")
		}
	}

	// Perform rotation command
	if rotation.RotateCommand != "" {
		_, cmdError := exec.Command("sh", "-c", rotation.RotateCommand).Output()
		if cmdError != nil {
			log.WithFields(log.Fields{
				"error":   cmdError,
				"command": rotation.RotateCommand,
			}).Error("Rotate command failed")
		} else {
			log.WithFields(log.Fields{
				"command": rotation.RotateCommand,
			}).Info("Rotation command successful")
		}
	}
}

//Get an RFC 3339 Nano Time for use in log timestamps
func get3339Time() string {
	return time.Now().UTC().Format(time.RFC3339Nano)
}
<commit_msg>Moving channel comms to json, inputs / outputs should marshal / unmarshal as needed<commit_after>package main

import (
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"time"

	"cloud.google.com/go/pubsub"
	"github.com/hpcloud/tail"
	log "github.com/sirupsen/logrus"
	"google.golang.org/api/option"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	configFile = kingpin.Flag("config", "Configuration file").Required().Short('c').String()
	version    = "master" //overridden by build system, master as default
)

/*
Todo:
- See if I can get hpcloud/tail to use logrus?
- lots of error handling
- config param defaults
- add signal handler support
*/

//FlingConfig - top level structure of json config file
type FlingConfig struct {
	Input     FlingInput      `json:"input"`
	Files     []FlingInFile   `json:"files"`
	Rotations []FlingRotation `json:"rotations"`
	Output    FlingOutput     `json:"output"`
}

//FlingInput - map of input type arrays
type FlingInput struct {
	PubSubs []FlingInPubSub `json:"pubsub"`
	Files   []FlingInFile   `json:"files"`
}

//FlingInPubSub - pub/sub input type
type FlingInPubSub struct {
	AuthFile     string           `json:"auth_file"`
	Project      string           `json:"project"`
	Subscription string           `json:"subscription"`
	Outputs      []string         `json:"outputs"`
	Injections   []FlingInjection `json:"injections"`
}

// FlingRotation - sets of files to rotate and the commands to run afterwards
type FlingRotation struct {
	Files          []string `json:"files"`
	RotateCommand  string   `json:"rotate_command"`
	RotateInterval int      `json:"rotate_interval"`
}

//FlingOutput - map of output types
type FlingOutput struct {
	PubSubs []FlingOutPubSub `json:"pubsub"`
	Loggers []FlingOutLogger `json:"logger"`
}

//FlingOutPubSub - A log output destination
type FlingOutPubSub struct {
	Name     string `json:"name"`
	Project  string `json:"project"`
	Topic    string `json:"topic"`
	AuthFile string `json:"auth_file"`
}

//FlingOutLogger - Send messages to the logger library
//FIXME add level and injections
type FlingOutLogger struct {
	Name      string `json:"name"`
	IsEnabled bool   `json:"is_enabled"`
}

//FlingInFile - instance of a file to monitor
type FlingInFile struct {
	Path       string           `json:"path"`
	IsJSON     bool             `json:"is_json"`
	IsGlob     bool             `json:"is_glob"`
	Outputs    []string         `json:"outputs"`
	Injections []FlingInjection `json:"injections"`
}

//FlingInjection - fields to add to the log line
type FlingInjection struct {
	Field    string `json:"field"`
	Value    string `json:"value"`
	ENVValue string `json:"env_value"`
	Hostname bool   `json:"hostname"`
}

func init() {
	log.SetFormatter(&log.JSONFormatter{})
	log.SetOutput(os.Stdout)
	log.SetLevel(log.DebugLevel)
}

func main() {
	log.Info("Initalizing")
	//Parse command line params
	kingpin.Version(version)
	kingpin.Parse()

	var config, err = loadConfig(*configFile)
	if err != nil {
		log.WithFields(log.Fields{
			"error": err,
		}).Fatal("Couldn't load config")
		os.Exit(-1)
	}

	//var outputs map[string]interface{}
	//start up go routines for any outputs
	outputChannels := handleOutputs(config.Output)

	//start up go routines for any rotations requested
	handleRotations(config.Rotations)

	//setup handlers for all of the files to be watched
	handleInputs(config.Input, outputChannels)

	select {} //Take a big nap FIXME: add signal handlers down the road
}

func loadConfig(path string) (FlingConfig, error) {
	var config FlingConfig
	configString, readError := ioutil.ReadFile(path)

	if readError != nil {
		return config, readError
	}

	parseError := json.Unmarshal(configString, &config)

	return config, parseError
}

func handleInputs(input FlingInput, outputChannels map[string]interface{}) {
	handleInFiles(input.Files, outputChannels)
}

func handleOutputs(outputs FlingOutput) map[string]interface{} {
	var channels map[string]interface{}
	channels = make(map[string]interface{})

	for k, v := range handleOutPubSubs(outputs.PubSubs) {
		channels[k] = v
	}

	for k, v := range handleOutLoggers(outputs.Loggers) {
		channels[k] = v
	}

	return channels
}

func handleOutLoggers(outputs []FlingOutLogger) map[string]interface{} {
	var channels map[string]interface{}
	channels = make(map[string]interface{})

	for _, output := range outputs {
		channels[output.Name] = make(chan map[string]interface{}, 1000)
		go outputLoggerWorker(output.Name, output.IsEnabled, channels[output.Name].(chan map[string]interface{}))
	}

	return channels
}

func outputLoggerWorker(name string, isEnabled bool, channel chan map[string]interface{}) {
	for {
		message := <-channel

		if isEnabled {
			log.WithFields(log.Fields{
				"OutputName": name,
			}).Debug(fmt.Sprintf("%s", message))
		}
	}
}

func handleOutPubSubs(outputs []FlingOutPubSub) map[string]interface{} {
	var channels map[string]interface{}
	channels = make(map[string]interface{})

	for _, output := range outputs {
		channels[output.Name] = make(chan map[string]interface{}, 1000)
		go outputPubSubWorker(output.Project, output.Topic, output.AuthFile, channels[output.Name].(chan map[string]interface{}))
	}

	return channels
}

func outputPubSubWorker(project string, topicName string, authfile string, channel chan map[string]interface{}) {
	ctx := context.Background()
	pubSubClient, err := pubsub.NewClient(ctx, project, option.WithServiceAccountFile(authfile))
	if err != nil {

	}

	topic := pubSubClient.Topic(topicName)
	defer topic.Stop()

	//send hello message to topic to keep track of what clients, versions etc.. are sending in data
	createPubSubInitMsg(topicName, channel)

	for {
		eventJSON := <-channel

		message, marshalErr := json.Marshal(eventJSON)
		if marshalErr != nil {
			log.WithFields(log.Fields{}).Error("Event Marshalling for pub/sub submission failed")
			return
		}
		result := topic.Publish(ctx, &pubsub.Message{
			Data: message,
		})

		id, err := result.Get(ctx)
		if err != nil {
			log.WithFields(log.Fields{
				"error": err,
			}).Error("Failed to publish message")
		} else {
			log.WithFields(log.Fields{
				"id": id,
			}).Debug("Published Message")
		}

	}
}

func createPubSubInitMsg(topicName string, channel chan map[string]interface{}) {
	var logEntry map[string]interface{}
	logEntry = make(map[string]interface{})
	hostname, _ := os.Hostname()

	logEntry["pubsub_topic"] = topicName
	logEntry["fling_version"] = version
	logEntry["hostname"] = hostname
	logEntry["@timestamp"] = get3339Time()
	logEntry["message"] = "Starting up Fling PubSub Output"

	channel <- logEntry
	log.WithFields(log.Fields{"topic": topicName}).Info("PubSub Init message queued")
}

func handleInFiles(files []FlingInFile, outputs map[string]interface{}) {
	for _, file := range files {
		if file.IsGlob {
			paths, _ := filepath.Glob(file.Path)
			for _, path := range paths {
				file.Path = path
				startFileWorker(file, outputs)
			}
		} else {
			startFileWorker(file, outputs)
		}
	}
}

func startFileWorker(file FlingInFile, outputs map[string]interface{}) {
	log.WithFields(log.Fields{
		"path": file.Path,
	}).Info("Adding tail for file")
	go fileWorker(file, outputs)
}

func fileWorker(file FlingInFile, outputs map[string]interface{}) {
	t, tailErr := tail.TailFile(file.Path, tail.Config{Follow: true, ReOpen: true, Poll: true})

	if tailErr != nil {
		log.WithFields(log.Fields{
			"path":  file.Path,
			"error": tailErr,
		}).Error("Couldn't tail file")
	}

	for line := range t.Lines {
		var logEntry map[string]interface{}

		log.WithFields(log.Fields{
			"path": file.Path,
			"line": line.Text,
		}).Debug("Processing log line")

		if file.IsJSON {
			unmarshalErr := json.Unmarshal([]byte(line.Text), &logEntry)
			if unmarshalErr != nil {
				log.WithFields(log.Fields{
					"message": line.Text,
					"error":   unmarshalErr,
				}).Error("Couldn't parse JSON log line")

				continue
			}
		} else {
			logEntry = make(map[string]interface{})
			logEntry["message"] = line.Text
		}

		//FIXME: Inject other pertinent context info
		logEntry["fling.source"] = file.Path

		if _, ok := logEntry["@timestamp"]; !ok {
			logEntry["@timestamp"] = get3339Time()
		}

		handleInjections(&logEntry, file.Injections)

		dispatchEntry(logEntry, file.Outputs, outputs)
	}
}

func handleInjections(logEntry *map[string]interface{}, injections []FlingInjection) {
	for _, injection := range injections {
		if injection.ENVValue != "" {
			(*logEntry)[injection.Field] = os.Getenv(injection.ENVValue)
		} else if injection.Value != "" {
			(*logEntry)[injection.Field] = injection.Value
		} else if injection.Hostname {
			hostname, _ := os.Hostname()
			(*logEntry)[injection.Field] = hostname
		}
	}
}

func dispatchEntry(eventJSON map[string]interface{}, outputs []string, channels map[string]interface{}) {
	for _, output := range outputs {
		channels[output].(chan map[string]interface{}) <- eventJSON
	}
}

func handleRotations(rotations []FlingRotation) {
	for _, rotation := range rotations {
		go rotateWorker(rotation)
	}
}

func rotateWorker(rotation FlingRotation) {
	for {
		log.WithFields(log.Fields{
			"seconds": rotation.RotateInterval,
		}).Info("Sleeping before rotate")

		time.Sleep(time.Duration(rotation.RotateInterval) * time.Second)

		rotate(rotation)
	}
}

func rotate(rotation FlingRotation) {
	//Handle the files first
	for _, path := range rotation.Files {
		//FIXME add file size check

		renameErr := os.Rename(path, path+".old")
		if renameErr != nil {
			log.WithFields(log.Fields{
				"path": path,
			}).Error("Unable to move log file in rotation")

			continue
		} else {
			log.WithFields(log.Fields{
				"path": path,
			}).Info("Moved log file")
		}
	}

	// Perform rotation command
	if rotation.RotateCommand != "" {
		_, cmdError := exec.Command("sh", "-c", rotation.RotateCommand).Output()
		if cmdError != nil {
			log.WithFields(log.Fields{
				"error":   cmdError,
				"command": rotation.RotateCommand,
			}).Error("Rotate command failed")
		} else {
			log.WithFields(log.Fields{
				"command": rotation.RotateCommand,
			}).Info("Rotation command successful")
		}
	}
}

//Get an RFC 3339 Nano Time for use in log timestamps
func get3339Time() string {
	return time.Now().UTC().Format(time.RFC3339Nano)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-cli/aws-cli"
	"github.com/enaml-ops/omg-cli/azure-cli"
	"github.com/enaml-ops/omg-cli/plugin/registry"
	"github.com/enaml-ops/omg-cli/utils/boshapi"
	"github.com/pivotalservices/gtils/osutils"
	"github.com/xchapter7x/lo"
)

var Version string
var CloudConfigPluginsDir = "./.plugins/cloudconfig"
var ProductPluginsDir = "./.plugins/product"
var cloudConfigCommands []cli.Command
var productCommands []cli.Command
var productList []string
var cloudconfigList []string

func main() {
	app := cli.NewApp()
	app.Version = Version
	app.Commands = []cli.Command{
		{
			Name:   "azure",
			Usage:  "azure [--flags] - deploy a bosh to azure",
			Action: azurecli.GetAction(BoshInitDeploy),
			Flags:  azurecli.GetFlags(),
		},
		{
			Name:   "aws",
			Usage:  "aws [--flags] - deploy a bosh to aws",
			Action: awscli.GetAction(BoshInitDeploy),
			Flags:  awscli.GetFlags(),
		},
		{
			Name: "list-cloudconfigs",
			Action: func(c *cli.Context) error {
				fmt.Println("Cloud Configs:")
				for _, plgn := range registry.ListCloudConfigs() {
					fmt.Println(plgn.Name, " - ", plgn.Path, " - ", plgn.Properties)
				}
				return nil
			},
		},
		{
			Name: "list-products",
			Action: func(c *cli.Context) error {
				fmt.Println("Products:")
				return nil
			},
		},

		{
			Name:  "register-plugin",
			Usage: "register-plugin -type [cloudconfig, product] -pluginpath <plugin-binary>",
			Action: func(c *cli.Context) (err error) {

				if c.String("type") != "" && c.String("pluginpath") != "" {
					err = registerPlugin(c.String("type"), c.String("pluginpath"))
				}
				return
			},
			Flags: []cli.Flag{
				cli.StringFlag{Name: "type", Value: "product", Usage: "define if the plugin to be registered is a cloud-config or a product"},
				cli.StringFlag{Name: "pluginpath", Value: "", Usage: "the path to the plugin you wish to register"},
			},
		},
		{
			Name:        "deploy-cloudconfig",
			Usage:       "deploy-cloudconfig <cloudconfig-name> [--flags] - deploy a cloudconfig to bosh",
			Flags:       getBoshAuthFlags(),
			Subcommands: cloudConfigCommands,
		},
		{
			Name:        "deploy-product",
			Usage:       "deploy-product <prod-name> [--flags] - deploy a product via bosh",
			Flags:       getBoshAuthFlags(),
			Subcommands: productCommands,
		},
	}
	app.Run(os.Args)
}

func init() {

	if strings.ToLower(os.Getenv("LOG_LEVEL")) != "debug" {
		log.SetOutput(ioutil.Discard)
	}
	registerCloudConfig()
}

func registerPlugin(typename, pluginpath string) (err error) {
	var srcPlugin *os.File

	if srcPlugin, err = os.Open(pluginpath); err == nil {
		defer srcPlugin.Close()

		switch typename {
		case "cloudconfig":
			dstFilepath := path.Join(CloudConfigPluginsDir, path.Base(pluginpath))
			err = copyPlugin(srcPlugin, dstFilepath)

		case "product":
			dstFilepath := path.Join(ProductPluginsDir, path.Base(pluginpath))
			err = copyPlugin(srcPlugin, dstFilepath)

		default:
			err = errors.New("invalid type selected")
			lo.G.Error("error: ", err)
		}
	}
	return
}

func copyPlugin(src io.Reader, dst string) (err error) {
	var dstPlugin *os.File
	if dstPlugin, err = osutils.SafeCreate(dst); err == nil {
		defer dstPlugin.Close()
		_, err = io.Copy(dstPlugin, src)
		os.Chmod(dst, 755)
	}
	return
}

func registerCloudConfig() {
	files, _ := ioutil.ReadDir(CloudConfigPluginsDir)
	for _, f := range files {
		lo.G.Debug("registering: ", f.Name())
		pluginPath := path.Join(CloudConfigPluginsDir, f.Name())
		flags, _ := registry.RegisterCloudConfig(pluginPath)

		cloudConfigCommands = append(cloudConfigCommands, cli.Command{
			Name:  f.Name(),
			Usage: "deploy the " + f.Name() + " cloud config",
			Flags: flags,
			Action: func(c *cli.Context) error {
				lo.G.Debug("running the cloud config plugin")
				client, cc := registry.GetCloudConfigReference(pluginPath)
				defer client.Kill()
				lo.G.Debug("we found client and cloud config: ", client, cc)
				lo.G.Debug("meta", cc.GetMeta())
				lo.G.Debug("args: ", c.Parent().Args())
				manifest := cc.GetCloudConfig(c.Parent().Args())
				lo.G.Debug("we found a manifest and context: ", manifest, c)
				processManifest(c, manifest)
				return nil
			},
		})
	}
	lo.G.Debug("registered cloud configs: ", registry.ListCloudConfigs())
}

func getBoshAuthFlags() []cli.Flag {
	return []cli.Flag{
		cli.StringFlag{Name: "bosh-url", Value: "https://mybosh.com", Usage: "this is the url or ip of your bosh director"},
		cli.IntFlag{Name: "bosh-port", Value: 25555, Usage: "this is the port of your bosh director"},
		cli.StringFlag{Name: "bosh-user", Value: "bosh", Usage: "this is the username for your bosh director"},
		cli.StringFlag{Name: "bosh-pass", Value: "", Usage: "this is the pasword for your bosh director"},
		cli.BoolFlag{Name: "print-manifest", Usage: "if you would simply like to output a manifest the set this flag as true."},
	}
}

func processManifest(c *cli.Context, manifest []byte) (e error) {

	if c.Parent().Bool("print-manifest") {
		yamlString := string(manifest)
		fmt.Println(yamlString)

	} else {
		ccm := enaml.NewCloudConfigManifest(manifest)
		boshclient := boshapi.NewClient(c.Parent().String("bosh-user"), c.Parent().String("bosh-pass"), c.Parent().String("bosh-url"), c.Parent().Int("bosh-port"))
		if req, err := boshclient.NewCloudConfigRequest(*ccm); err == nil {
			tr := &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
			}
			httpClient := &http.Client{Transport: tr}

			if res, err := httpClient.Do(req); err != nil {
				lo.G.Error("res: ", res)
				lo.G.Error("error: ", err)
				e = err
			}
		} else {
			e = err
		}
	}
	return
}
<commit_msg>[#119868047] adding configurable ssl-ignore flag<commit_after>package main

import (
	"crypto/tls"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/enaml-ops/enaml"
	"github.com/enaml-ops/omg-cli/aws-cli"
	"github.com/enaml-ops/omg-cli/azure-cli"
	"github.com/enaml-ops/omg-cli/plugin/registry"
	"github.com/enaml-ops/omg-cli/utils/boshapi"
	"github.com/pivotalservices/gtils/osutils"
	"github.com/xchapter7x/lo"
)

var Version string
var CloudConfigPluginsDir = "./.plugins/cloudconfig"
var ProductPluginsDir = "./.plugins/product"
var cloudConfigCommands []cli.Command
var productCommands []cli.Command
var productList []string
var cloudconfigList []string

func main() {
	app := cli.NewApp()
	app.Version = Version
	app.Commands = []cli.Command{
		{
			Name:   "azure",
			Usage:  "azure [--flags] - deploy a bosh to azure",
			Action: azurecli.GetAction(BoshInitDeploy),
			Flags:  azurecli.GetFlags(),
		},
		{
			Name:   "aws",
			Usage:  "aws [--flags] - deploy a bosh to aws",
			Action: awscli.GetAction(BoshInitDeploy),
			Flags:  awscli.GetFlags(),
		},
		{
			Name: "list-cloudconfigs",
			Action: func(c *cli.Context) error {
				fmt.Println("Cloud Configs:")
				for _, plgn := range registry.ListCloudConfigs() {
					fmt.Println(plgn.Name, " - ", plgn.Path, " - ", plgn.Properties)
				}
				return nil
			},
		},
		{
			Name: "list-products",
			Action: func(c *cli.Context) error {
				fmt.Println("Products:")
				return nil
			},
		},

		{
			Name:  "register-plugin",
			Usage: "register-plugin -type [cloudconfig, product] -pluginpath <plugin-binary>",
			Action: func(c *cli.Context) (err error) {

				if c.String("type") != "" && c.String("pluginpath") != "" {
					err = registerPlugin(c.String("type"), c.String("pluginpath"))
				}
				return
			},
			Flags: []cli.Flag{
				cli.StringFlag{Name: "type", Value: "product", Usage: "define if the plugin to be registered is a cloud-config or a product"},
				cli.StringFlag{Name: "pluginpath", Value: "", Usage: "the path to the plugin you wish to register"},
			},
		},
		{
			Name:        "deploy-cloudconfig",
			Usage:       "deploy-cloudconfig <cloudconfig-name> [--flags] - deploy a cloudconfig to bosh",
			Flags:       getBoshAuthFlags(),
			Subcommands: cloudConfigCommands,
		},
		{
			Name:        "deploy-product",
			Usage:       "deploy-product <prod-name> [--flags] - deploy a product via bosh",
			Flags:       getBoshAuthFlags(),
			Subcommands: productCommands,
		},
	}
	app.Run(os.Args)
}

func init() {

	if strings.ToLower(os.Getenv("LOG_LEVEL")) != "debug" {
		log.SetOutput(ioutil.Discard)
	}
	registerCloudConfig()
}

func registerPlugin(typename, pluginpath string) (err error) {
	var srcPlugin *os.File

	if srcPlugin, err = os.Open(pluginpath); err == nil {
		defer srcPlugin.Close()

		switch typename {
		case "cloudconfig":
			dstFilepath := path.Join(CloudConfigPluginsDir, path.Base(pluginpath))
			err = copyPlugin(srcPlugin, dstFilepath)

		case "product":
			dstFilepath := path.Join(ProductPluginsDir, path.Base(pluginpath))
			err = copyPlugin(srcPlugin, dstFilepath)

		default:
			err = errors.New("invalid type selected")
			lo.G.Error("error: ", err)
		}
	}
	return
}

func copyPlugin(src io.Reader, dst string) (err error) {
	var dstPlugin *os.File
	if dstPlugin, err = osutils.SafeCreate(dst); err == nil {
		defer dstPlugin.Close()
		_, err = io.Copy(dstPlugin, src)
		os.Chmod(dst, 755)
	}
	return
}

func registerCloudConfig() {
	files, _ := ioutil.ReadDir(CloudConfigPluginsDir)
	for _, f := range files {
		lo.G.Debug("registering: ", f.Name())
		pluginPath := path.Join(CloudConfigPluginsDir, f.Name())
		flags, _ := registry.RegisterCloudConfig(pluginPath)

		cloudConfigCommands = append(cloudConfigCommands, cli.Command{
			Name:  f.Name(),
			Usage: "deploy the " + f.Name() + " cloud config",
			Flags: flags,
			Action: func(c *cli.Context) error {
				lo.G.Debug("running the cloud config plugin")
				client, cc := registry.GetCloudConfigReference(pluginPath)
				defer client.Kill()
				lo.G.Debug("we found client and cloud config: ", client, cc)
				lo.G.Debug("meta", cc.GetMeta())
				lo.G.Debug("args: ", c.Parent().Args())
				manifest := cc.GetCloudConfig(c.Parent().Args())
				lo.G.Debug("we found a manifest and context: ", manifest, c)
				processManifest(c, manifest)
				return nil
			},
		})
	}
	lo.G.Debug("registered cloud configs: ", registry.ListCloudConfigs())
}

func getBoshAuthFlags() []cli.Flag {
	return []cli.Flag{
		cli.StringFlag{Name: "bosh-url", Value: "https://mybosh.com", Usage: "this is the url or ip of your bosh director"},
		cli.IntFlag{Name: "bosh-port", Value: 25555, Usage: "this is the port of your bosh director"},
		cli.StringFlag{Name: "bosh-user", Value: "bosh", Usage: "this is the username for your bosh director"},
		cli.StringFlag{Name: "bosh-pass", Value: "", Usage: "this is the pasword for your bosh director"},
		cli.BoolFlag{Name: "ssl-ignore", Usage: "ingore ssl self signed cert warnings"},
		cli.BoolFlag{Name: "print-manifest", Usage: "if you would simply like to output a manifest the set this flag as true."},
	}
}

func processManifest(c *cli.Context, manifest []byte) (e error) {

	if c.Parent().Bool("print-manifest") {
		yamlString := string(manifest)
		fmt.Println(yamlString)

	} else {
		ccm := enaml.NewCloudConfigManifest(manifest)
		boshclient := boshapi.NewClient(c.Parent().String("bosh-user"), c.Parent().String("bosh-pass"), c.Parent().String("bosh-url"), c.Parent().Int("bosh-port"))
		if req, err := boshclient.NewCloudConfigRequest(*ccm); err == nil {
			tr := &http.Transport{
				TLSClientConfig: &tls.Config{InsecureSkipVerify: c.Parent().Bool("ssl-ignore")},
			}
			httpClient := &http.Client{Transport: tr}

			if res, err := httpClient.Do(req); err != nil {
				lo.G.Error("res: ", res)
				lo.G.Error("error: ", err)
				e = err
			}
		} else {
			e = err
		}
	}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"os"
	"strconv"

	"github.com/codegangsta/cli"
)

const (
	dirMode os.FileMode = 0755 // Default mode for directories
)

var (
	logger  = log.New(os.Stderr, "", 0)
	verbose = false

	CachePath = os.Getenv("HACHER_PATH")
	CacheKeep = 3
)

func initClient() {
	if len(CachePath) < 1 {
		printFatal("Env variable HACHER_PATH is not set. Point it to the cache directory.")
	}
	if len(os.Getenv("HACHER_KEEP")) > 0 {
		if i, err := strconv.Atoi(os.Getenv("HACHER_KEEP")); err == nil {
			CacheKeep = i
		}
	}
}

func main() {

	initClient()

	app := cli.NewApp()

	app.Name = "Hacher"
	app.Usage = "A simple CLI tool to cache project artifacts."
	app.Author = "The Dockbit Team"
	app.Email = "hello@dockbit.com"
	app.Version = "0.1.0"

	// Alphabetically ordered list of commands
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, x",
			Usage: "Verbose mode",
		},
	}

	app.Commands = []cli.Command{

		{
			Name:   "get",
			Usage:  "Gets cache content by a given key.",
			Action: cmdGet,
			Flags: []cli.Flag{

				cli.StringFlag{
					Name:  "k, key",
					Usage: "Cache key",
				},

				cli.StringFlag{
					Name:  "f, file",
					Usage: "Path to depdendency file to track for changes.",
				},
			},
		},
		{
			Name:   "set",
			Usage:  "Saves cache content for a given key.",
			Action: cmdSet,
			Flags: []cli.Flag{

				cli.StringFlag{
					Name:  "k, key",
					Usage: "Cache key",
				},

				cli.StringFlag{
					Name:  "f, file",
					Usage: "Path to depdendency file to track for changes.",
				},
			},
		},
	}

	app.Run(os.Args)
}
<commit_msg>Update Dockbit team email<commit_after>package main

import (
	"log"
	"os"
	"strconv"

	"github.com/codegangsta/cli"
)

const (
	dirMode os.FileMode = 0755 // Default mode for directories
)

var (
	logger  = log.New(os.Stderr, "", 0)
	verbose = false

	CachePath = os.Getenv("HACHER_PATH")
	CacheKeep = 3
)

func initClient() {
	if len(CachePath) < 1 {
		printFatal("Env variable HACHER_PATH is not set. Point it to the cache directory.")
	}
	if len(os.Getenv("HACHER_KEEP")) > 0 {
		if i, err := strconv.Atoi(os.Getenv("HACHER_KEEP")); err == nil {
			CacheKeep = i
		}
	}
}

func main() {

	initClient()

	app := cli.NewApp()

	app.Name = "Hacher"
	app.Usage = "A simple CLI tool to cache project artifacts."
	app.Author = "The Dockbit Team"
	app.Email = "team@dockbit.com"
	app.Version = "0.1.0"

	// Alphabetically ordered list of commands
	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:  "verbose, x",
			Usage: "Verbose mode",
		},
	}

	app.Commands = []cli.Command{

		{
			Name:   "get",
			Usage:  "Gets cache content by a given key.",
			Action: cmdGet,
			Flags: []cli.Flag{

				cli.StringFlag{
					Name:  "k, key",
					Usage: "Cache key",
				},

				cli.StringFlag{
					Name:  "f, file",
					Usage: "Path to depdendency file to track for changes.",
				},
			},
		},
		{
			Name:   "set",
			Usage:  "Saves cache content for a given key.",
			Action: cmdSet,
			Flags: []cli.Flag{

				cli.StringFlag{
					Name:  "k, key",
					Usage: "Cache key",
				},

				cli.StringFlag{
					Name:  "f, file",
					Usage: "Path to depdendency file to track for changes.",
				},
			},
		},
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/orchardup/orchard/cli"
	"github.com/orchardup/orchard/proxy"
	"github.com/orchardup/orchard/tlsconfig"
	"github.com/orchardup/orchard/vendor/github.com/docopt/docopt.go"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"strings"
	"syscall"
	"text/tabwriter"
)

func main() {
	usage := `Orchard.

Usage:
  orchard hosts
  orchard start [NAME]
  orchard stop [NAME]
  orchard [options] docker [COMMAND...]
  orchard [options] proxy

Options:
  -h --help               Show this screen.
  --version               Show version.
  -H NAME, --host=NAME    Name of host to connect to (instead of 'default')`

	args, err := docopt.Parse(usage, nil, true, "Orchard 2.0.0", true)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error parsing arguments: %s\n", err)
		return
	}

	var cmdErr error = nil

	if args["hosts"] == true {
		cmdErr = Hosts(args)
	} else if args["start"] == true {
		cmdErr = Start(args)
	} else if args["stop"] == true {
		cmdErr = Stop(args)
	} else if args["docker"] == true || args["proxy"] == true {
		cmdErr = Docker(args)
	}

	if cmdErr != nil {
		fmt.Fprintln(os.Stderr, cmdErr)
		os.Exit(1)
	}
}

func Docker(args map[string]interface{}) error {
	hostName := "default"
	if args["--host"] != nil {
		hostName = args["--host"].(string)
	}

	dirname, err := ioutil.TempDir("/tmp", "orchard-")
	if err != nil {
		return fmt.Errorf("Error creating temporary directory: %s\n", err)
	}
	defer os.RemoveAll(dirname)
	socketPath := path.Join(dirname, "orchard.sock")

	p, err := MakeProxy(socketPath, hostName)
	if err != nil {
		return fmt.Errorf("Error starting proxy: %v\n", err)
	}

	go p.Start()
	defer p.Stop()

	if err := <-p.ErrorChannel; err != nil {
		return fmt.Errorf("Error starting proxy: %v\n", err)
	}

	if args["docker"] == true {
		err := CallDocker(args["COMMAND"].([]string), []string{"DOCKER_HOST=unix://" + socketPath})
		if err != nil {
			return fmt.Errorf("Docker exited with error")
		}
	} else {
		fmt.Fprintln(os.Stderr, "Started proxy at unix://"+socketPath)

		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGKILL)
		<-c

		fmt.Fprintln(os.Stderr, "\nStopping proxy")
	}

	return nil
}

func MakeProxy(socketPath string, hostName string) (*proxy.Proxy, error) {
	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return nil, err
	}

	host, err := httpClient.GetHost(hostName)
	if err != nil {
		return nil, err
	}
	destination := host.IPAddress + ":4243"

	certData := []byte(host.ClientCert)
	keyData := []byte(host.ClientKey)
	config, err := tlsconfig.GetTLSConfig(certData, keyData)
	if err != nil {
		return nil, err
	}

	return proxy.New(
		func() (net.Listener, error) { return net.Listen("unix", socketPath) },
		func() (net.Conn, error) { return tls.Dial("tcp", destination, config) },
	), nil
}

func CallDocker(args []string, env []string) error {
	dockerPath := GetDockerPath()
	if dockerPath == "" {
		return errors.New("Can't find `docker` executable in $PATH.\nYou might need to install it: http://docs.docker.io/en/latest/installation/#installation-list")
	}

	cmd := exec.Command(dockerPath, args...)
	cmd.Env = env
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func GetDockerPath() string {
	for _, dir := range strings.Split(os.Getenv("PATH"), ":") {
		dockerPath := path.Join(dir, "docker")
		_, err := os.Stat(dockerPath)
		if err == nil {
			return dockerPath
		}
	}
	return ""
}

func Start(args map[string]interface{}) error {
	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	hostName, humanName := GetHostName(args)
	humanName = strings.ToUpper(humanName[0:1]) + humanName[1:]

	host, err := httpClient.CreateHost(hostName)
	if err != nil {
		// HACK. api.go should decode JSON and return a specific type of error for this case.
		if strings.Contains(err.Error(), "already exists") {
			fmt.Fprintf(os.Stderr, "%s is already running.\nYou can create additional hosts with `orchard start NAME`.\n", humanName)
			return nil
		}

		return err
	}
	fmt.Fprintf(os.Stderr, "%s running at %s\n", humanName, host.IPAddress)

	return nil
}

func Stop(args map[string]interface{}) error {
	hostName, humanName := GetHostName(args)

	var confirm string
	fmt.Printf("Going to stop and delete %s. All data on it will be lost.\n", humanName)
	fmt.Print("Are you sure you're ready? [yN] ")
	fmt.Scanln(&confirm)

	if strings.ToLower(confirm) != "y" {
		return nil
	}

	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	err = httpClient.DeleteHost(hostName)
	if err != nil {
		return err
	}
	fmt.Fprintf(os.Stderr, "Stopped %s\n", humanName)

	return nil
}

func GetHostName(args map[string]interface{}) (string, string) {
	hostName := "default"
	humanName := "default host"

	if args["NAME"] != nil {
		hostName = args["NAME"].(string)
		humanName = fmt.Sprintf("host '%s'", hostName)
	}

	return hostName, humanName
}

func Hosts(args map[string]interface{}) error {
	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	hosts, err := httpClient.GetHosts()
	if err != nil {
		return err
	}

	writer := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
	fmt.Fprintln(writer, "NAME\tIP")
	for _, host := range hosts {
		fmt.Fprintf(writer, "%s\t%s\n", host.Name, host.IPAddress)
	}
	writer.Flush()

	return nil
}
<commit_msg>Catch invalid-name case<commit_after>package main

import (
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/orchardup/orchard/cli"
	"github.com/orchardup/orchard/proxy"
	"github.com/orchardup/orchard/tlsconfig"
	"github.com/orchardup/orchard/vendor/github.com/docopt/docopt.go"
	"io/ioutil"
	"net"
	"os"
	"os/exec"
	"os/signal"
	"path"
	"strings"
	"syscall"
	"text/tabwriter"
)

func main() {
	usage := `Orchard.

Usage:
  orchard hosts
  orchard start [NAME]
  orchard stop [NAME]
  orchard [options] docker [COMMAND...]
  orchard [options] proxy

Options:
  -h --help               Show this screen.
  --version               Show version.
  -H NAME, --host=NAME    Name of host to connect to (instead of 'default')`

	args, err := docopt.Parse(usage, nil, true, "Orchard 2.0.0", true)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error parsing arguments: %s\n", err)
		return
	}

	var cmdErr error = nil

	if args["hosts"] == true {
		cmdErr = Hosts(args)
	} else if args["start"] == true {
		cmdErr = Start(args)
	} else if args["stop"] == true {
		cmdErr = Stop(args)
	} else if args["docker"] == true || args["proxy"] == true {
		cmdErr = Docker(args)
	}

	if cmdErr != nil {
		fmt.Fprintln(os.Stderr, cmdErr)
		os.Exit(1)
	}
}

func Docker(args map[string]interface{}) error {
	hostName := "default"
	if args["--host"] != nil {
		hostName = args["--host"].(string)
	}

	dirname, err := ioutil.TempDir("/tmp", "orchard-")
	if err != nil {
		return fmt.Errorf("Error creating temporary directory: %s\n", err)
	}
	defer os.RemoveAll(dirname)
	socketPath := path.Join(dirname, "orchard.sock")

	p, err := MakeProxy(socketPath, hostName)
	if err != nil {
		return fmt.Errorf("Error starting proxy: %v\n", err)
	}

	go p.Start()
	defer p.Stop()

	if err := <-p.ErrorChannel; err != nil {
		return fmt.Errorf("Error starting proxy: %v\n", err)
	}

	if args["docker"] == true {
		err := CallDocker(args["COMMAND"].([]string), []string{"DOCKER_HOST=unix://" + socketPath})
		if err != nil {
			return fmt.Errorf("Docker exited with error")
		}
	} else {
		fmt.Fprintln(os.Stderr, "Started proxy at unix://"+socketPath)

		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGKILL)
		<-c

		fmt.Fprintln(os.Stderr, "\nStopping proxy")
	}

	return nil
}

func MakeProxy(socketPath string, hostName string) (*proxy.Proxy, error) {
	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return nil, err
	}

	host, err := httpClient.GetHost(hostName)
	if err != nil {
		return nil, err
	}
	destination := host.IPAddress + ":4243"

	certData := []byte(host.ClientCert)
	keyData := []byte(host.ClientKey)
	config, err := tlsconfig.GetTLSConfig(certData, keyData)
	if err != nil {
		return nil, err
	}

	return proxy.New(
		func() (net.Listener, error) { return net.Listen("unix", socketPath) },
		func() (net.Conn, error) { return tls.Dial("tcp", destination, config) },
	), nil
}

func CallDocker(args []string, env []string) error {
	dockerPath := GetDockerPath()
	if dockerPath == "" {
		return errors.New("Can't find `docker` executable in $PATH.\nYou might need to install it: http://docs.docker.io/en/latest/installation/#installation-list")
	}

	cmd := exec.Command(dockerPath, args...)
	cmd.Env = env
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

func GetDockerPath() string {
	for _, dir := range strings.Split(os.Getenv("PATH"), ":") {
		dockerPath := path.Join(dir, "docker")
		_, err := os.Stat(dockerPath)
		if err == nil {
			return dockerPath
		}
	}
	return ""
}

func Start(args map[string]interface{}) error {
	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	hostName, humanName := GetHostName(args)
	humanName = strings.ToUpper(humanName[0:1]) + humanName[1:]

	host, err := httpClient.CreateHost(hostName)
	if err != nil {
		// HACK. api.go should decode JSON and return a specific type of error for this case.
		if strings.Contains(err.Error(), "already exists") {
			fmt.Fprintf(os.Stderr, "%s is already running.\nYou can create additional hosts with `orchard start NAME`.\n", humanName)
			return nil
		}
		if strings.Contains(err.Error(), "Invalid value") {
			fmt.Fprintf(os.Stderr, "Sorry, '%s' isn't a valid host name.\nHost names can only contain lowercase letters, numbers and underscores.\n", hostName)
			return nil
		}

		return err
	}
	fmt.Fprintf(os.Stderr, "%s running at %s\n", humanName, host.IPAddress)

	return nil
}

func Stop(args map[string]interface{}) error {
	hostName, humanName := GetHostName(args)

	var confirm string
	fmt.Printf("Going to stop and delete %s. All data on it will be lost.\n", humanName)
	fmt.Print("Are you sure you're ready? [yN] ")
	fmt.Scanln(&confirm)

	if strings.ToLower(confirm) != "y" {
		return nil
	}

	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	err = httpClient.DeleteHost(hostName)
	if err != nil {
		return err
	}
	fmt.Fprintf(os.Stderr, "Stopped %s\n", humanName)

	return nil
}

func GetHostName(args map[string]interface{}) (string, string) {
	hostName := "default"
	humanName := "default host"

	if args["NAME"] != nil {
		hostName = args["NAME"].(string)
		humanName = fmt.Sprintf("host '%s'", hostName)
	}

	return hostName, humanName
}

func Hosts(args map[string]interface{}) error {
	httpClient, err := authenticator.Authenticate()
	if err != nil {
		return err
	}

	hosts, err := httpClient.GetHosts()
	if err != nil {
		return err
	}

	writer := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0)
	fmt.Fprintln(writer, "NAME\tIP")
	for _, host := range hosts {
		fmt.Fprintf(writer, "%s\t%s\n", host.Name, host.IPAddress)
	}
	writer.Flush()

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"net/http"
	"os"
	"runtime"
	"time"

	"github.com/gorilla/mux"
	"github.com/phyber/negroni-gzip/gzip"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/sirupsen/logrus"
	"github.com/urfave/negroni"

	"github.com/ivan1993spb/snake-server/client"
	"github.com/ivan1993spb/snake-server/connections"
	"github.com/ivan1993spb/snake-server/handlers"
	"github.com/ivan1993spb/snake-server/middlewares"
)

const ServerName = "Snake-Server"

const (
	defaultAddress     = ":8080"
	defaultGroupsLimit = 100
	defaultConnsLimit  = 1000
)

var (
	Version = "dev"
	Build   = "dev"
	Author  = "Ivan Pushkin"
	License = "MIT"
)

var (
	address string

	flagEnableTLS bool
	certFile      string
	keyFile       string

	groupsLimit int
	connsLimit  int
	seed        int64

	flagJSONLog bool
	logLevel    string

	enableBroadcast bool

	enableWeb bool
)

const logName = "api"

func usage() {
	fmt.Fprint(os.Stderr, "Welcome to snake-server!\n\n")
	fmt.Fprintf(os.Stderr, "Server version %s, build %s\n\n", Version, Build)
	fmt.Fprintf(os.Stderr, "Usage: %s [options]\n\n", os.Args[0])
	flag.PrintDefaults()
}

func init() {
	flag.StringVar(&address, "address", defaultAddress, "address to serve")
	flag.BoolVar(&flagEnableTLS, "tls-enable", false, "enable TLS")
	flag.StringVar(&certFile, "tls-cert", "", "path to certificate file")
	flag.StringVar(&keyFile, "tls-key", "", "path to key file")
	flag.IntVar(&groupsLimit, "groups-limit", defaultGroupsLimit, "game groups limit")
	flag.IntVar(&connsLimit, "conns-limit", defaultConnsLimit, "web-socket connections limit")
	flag.Int64Var(&seed, "seed", time.Now().UnixNano(), "random seed")
	flag.BoolVar(&flagJSONLog, "log-json", false, "use json format for logger")
	flag.StringVar(&logLevel, "log-level", "info", "set log level: panic, fatal, error, warning (warn), info or debug")
	flag.BoolVar(&enableBroadcast, "enable-broadcast", false, "enable broadcasting API method")
	flag.BoolVar(&enableWeb, "enable-web", false, "enable web client")
	flag.Usage = usage
	flag.Parse()
}

func logger() *logrus.Logger {
	logger := logrus.New()
	if flagJSONLog {
		logger.Formatter = &logrus.JSONFormatter{}
	} else if runtime.GOOS == "windows" {
		// Log Output on Windows shows Bash format
		// See: https://gitlab.com/gitlab-org/gitlab-runner/issues/6
		// See: https://github.com/sirupsen/logrus/issues/172
		logger.Formatter = &logrus.TextFormatter{
			DisableColors: true,
		}
	}
	if level, err := logrus.ParseLevel(logLevel); err != nil {
		logger.SetLevel(logrus.InfoLevel)
	} else {
		logger.SetLevel(level)
	}
	return logger
}

func serve(h http.Handler) error {
	if flagEnableTLS {
		return http.ListenAndServeTLS(address, certFile, keyFile, h)
	}
	return http.ListenAndServe(address, h)
}

func main() {
	logger := logger()

	logger.WithFields(logrus.Fields{
		"author":  Author,
		"license": License,
		"version": Version,
		"build":   Build,
	}).Info("welcome to snake-server!")

	logger.WithFields(logrus.Fields{
		"go_version": runtime.Version(),
		"go_os":      runtime.GOOS,
		"go_arch":    runtime.GOARCH,
	}).Info("golang info")

	logger.WithFields(logrus.Fields{
		"conns_limit":  connsLimit,
		"groups_limit": groupsLimit,
		"seed":         seed,
		"log_level":    logLevel,
		"broadcast":    enableBroadcast,
		"web":          enableWeb,
	}).Info("preparing to start server")

	if enableBroadcast {
		logger.Warning("broadcasting API method is enabled!")
	}

	rand.Seed(seed)

	groupManager, err := connections.NewConnectionGroupManager(logger, groupsLimit, connsLimit)
	if err != nil {
		logger.Fatalln("cannot create connections group manager:", err)
	}

	rootRouter := mux.NewRouter().StrictSlash(true)
	rootRouter.Path("/metrics").Handler(promhttp.Handler())
	if enableWeb {
		rootRouter.Path(client.URLRouteServerEndpoint).Handler(http.RedirectHandler(client.URLRouteClient, http.StatusFound))
		rootRouter.PathPrefix(client.URLRouteClient).Handler(negroni.New(gzip.Gzip(gzip.DefaultCompression), negroni.Wrap(client.NewHandler())))
	} else {
		rootRouter.Path(handlers.URLRouteWelcome).Methods(handlers.MethodWelcome).Handler(handlers.NewWelcomeHandler(logger))
	}
	rootRouter.NotFoundHandler = handlers.NewNotFoundHandler(logger)

	// Web-Socket routes
	wsRouter := rootRouter.PathPrefix("/ws").Subrouter()
	wsRouter.Path(handlers.URLRouteGameWebSocketByID).Methods(handlers.MethodGame).Handler(handlers.NewGameWebSocketHandler(logger, groupManager))

	// API routes
	apiRouter := rootRouter.PathPrefix("/api").Subrouter()
	apiRouter.Path(handlers.URLRouteGetInfo).Methods(handlers.MethodGetInfo).Handler(handlers.NewGetInfoHandler(logger, Author, License, Version, Build))
	apiRouter.Path(handlers.URLRouteGetCapacity).Methods(handlers.MethodGetCapacity).Handler(handlers.NewGetCapacityHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRouteCreateGame).Methods(handlers.MethodCreateGame).Handler(handlers.NewCreateGameHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRouteGetGameByID).Methods(handlers.MethodGetGame).Handler(handlers.NewGetGameHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRouteDeleteGameByID).Methods(handlers.MethodDeleteGame).Handler(handlers.NewDeleteGameHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRouteGetGames).Methods(handlers.MethodGetGames).Handler(handlers.NewGetGamesHandler(logger, groupManager))
	if enableBroadcast {
		apiRouter.Path(handlers.URLRouteBroadcast).Methods(handlers.MethodBroadcast).Handler(handlers.NewBroadcastHandler(logger, groupManager))
	}
	apiRouter.Path(handlers.URLRouteGetObjects).Methods(handlers.MethodGetObjects).Handler(handlers.NewGetObjectsHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRoutePing).Methods(handlers.MethodPing).Handler(handlers.NewPingHandler(logger))

	httpMux := http.NewServeMux()

	httpMux.Handle("/", rootRouter)

	// Use middlewares for API routes
	httpMux.Handle("/api/", negroni.New(
		middlewares.NewRecovery(logger),
		middlewares.NewLogger(logger, logName),
		middlewares.NewCORS(),
		negroni.Wrap(rootRouter),
	))

	n := negroni.New()
	n.Use(middlewares.NewServerInfo(ServerName, Version, Build))
	n.UseHandler(httpMux)

	logger.WithFields(logrus.Fields{
		"address": address,
		"tls":     flagEnableTLS,
	}).Info("starting server")

	if err := serve(n); err != nil {
		logger.Fatalf("server error: %s", err)
	}
}
<commit_msg>issue #61 Include openapi.yaml route<commit_after>package main

import (
	"flag"
	"fmt"
	"math/rand"
	"net/http"
	"os"
	"runtime"
	"time"

	"github.com/gorilla/mux"
	"github.com/phyber/negroni-gzip/gzip"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/sirupsen/logrus"
	"github.com/urfave/negroni"

	"github.com/ivan1993spb/snake-server/client"
	"github.com/ivan1993spb/snake-server/connections"
	"github.com/ivan1993spb/snake-server/handlers"
	"github.com/ivan1993spb/snake-server/middlewares"
)

const ServerName = "Snake-Server"

const (
	defaultAddress     = ":8080"
	defaultGroupsLimit = 100
	defaultConnsLimit  = 1000
)

var (
	Version = "dev"
	Build   = "dev"
	Author  = "Ivan Pushkin"
	License = "MIT"
)

var (
	address string

	flagEnableTLS bool
	certFile      string
	keyFile       string

	groupsLimit int
	connsLimit  int
	seed        int64

	flagJSONLog bool
	logLevel    string

	enableBroadcast bool

	enableWeb bool
)

const logName = "api"

func usage() {
	fmt.Fprint(os.Stderr, "Welcome to snake-server!\n\n")
	fmt.Fprintf(os.Stderr, "Server version %s, build %s\n\n", Version, Build)
	fmt.Fprintf(os.Stderr, "Usage: %s [options]\n\n", os.Args[0])
	flag.PrintDefaults()
}

func init() {
	flag.StringVar(&address, "address", defaultAddress, "address to serve")
	flag.BoolVar(&flagEnableTLS, "tls-enable", false, "enable TLS")
	flag.StringVar(&certFile, "tls-cert", "", "path to certificate file")
	flag.StringVar(&keyFile, "tls-key", "", "path to key file")
	flag.IntVar(&groupsLimit, "groups-limit", defaultGroupsLimit, "game groups limit")
	flag.IntVar(&connsLimit, "conns-limit", defaultConnsLimit, "web-socket connections limit")
	flag.Int64Var(&seed, "seed", time.Now().UnixNano(), "random seed")
	flag.BoolVar(&flagJSONLog, "log-json", false, "use json format for logger")
	flag.StringVar(&logLevel, "log-level", "info", "set log level: panic, fatal, error, warning (warn), info or debug")
	flag.BoolVar(&enableBroadcast, "enable-broadcast", false, "enable broadcasting API method")
	flag.BoolVar(&enableWeb, "enable-web", false, "enable web client")
	flag.Usage = usage
	flag.Parse()
}

func logger() *logrus.Logger {
	logger := logrus.New()
	if flagJSONLog {
		logger.Formatter = &logrus.JSONFormatter{}
	} else if runtime.GOOS == "windows" {
		// Log Output on Windows shows Bash format
		// See: https://gitlab.com/gitlab-org/gitlab-runner/issues/6
		// See: https://github.com/sirupsen/logrus/issues/172
		logger.Formatter = &logrus.TextFormatter{
			DisableColors: true,
		}
	}
	if level, err := logrus.ParseLevel(logLevel); err != nil {
		logger.SetLevel(logrus.InfoLevel)
	} else {
		logger.SetLevel(level)
	}
	return logger
}

func serve(h http.Handler) error {
	if flagEnableTLS {
		return http.ListenAndServeTLS(address, certFile, keyFile, h)
	}
	return http.ListenAndServe(address, h)
}

func main() {
	logger := logger()

	logger.WithFields(logrus.Fields{
		"author":  Author,
		"license": License,
		"version": Version,
		"build":   Build,
	}).Info("welcome to snake-server!")

	logger.WithFields(logrus.Fields{
		"go_version": runtime.Version(),
		"go_os":      runtime.GOOS,
		"go_arch":    runtime.GOARCH,
	}).Info("golang info")

	logger.WithFields(logrus.Fields{
		"conns_limit":  connsLimit,
		"groups_limit": groupsLimit,
		"seed":         seed,
		"log_level":    logLevel,
		"broadcast":    enableBroadcast,
		"web":          enableWeb,
	}).Info("preparing to start server")

	if enableBroadcast {
		logger.Warning("broadcasting API method is enabled!")
	}

	rand.Seed(seed)

	groupManager, err := connections.NewConnectionGroupManager(logger, groupsLimit, connsLimit)
	if err != nil {
		logger.Fatalln("cannot create connections group manager:", err)
	}

	rootRouter := mux.NewRouter().StrictSlash(true)
	rootRouter.Path("/metrics").Handler(promhttp.Handler())
	rootRouter.Path(handlers.URLRouteOpenAPI).Handler(handlers.NewOpenAPIHandler())
	if enableWeb {
		rootRouter.Path(client.URLRouteServerEndpoint).Handler(http.RedirectHandler(client.URLRouteClient, http.StatusFound))
		rootRouter.PathPrefix(client.URLRouteClient).Handler(negroni.New(gzip.Gzip(gzip.DefaultCompression), negroni.Wrap(client.NewHandler())))
	} else {
		rootRouter.Path(handlers.URLRouteWelcome).Methods(handlers.MethodWelcome).Handler(handlers.NewWelcomeHandler(logger))
	}
	rootRouter.NotFoundHandler = handlers.NewNotFoundHandler(logger)

	// Web-Socket routes
	wsRouter := rootRouter.PathPrefix("/ws").Subrouter()
	wsRouter.Path(handlers.URLRouteGameWebSocketByID).Methods(handlers.MethodGame).Handler(handlers.NewGameWebSocketHandler(logger, groupManager))

	// API routes
	apiRouter := rootRouter.PathPrefix("/api").Subrouter()
	apiRouter.Path(handlers.URLRouteGetInfo).Methods(handlers.MethodGetInfo).Handler(handlers.NewGetInfoHandler(logger, Author, License, Version, Build))
	apiRouter.Path(handlers.URLRouteGetCapacity).Methods(handlers.MethodGetCapacity).Handler(handlers.NewGetCapacityHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRouteCreateGame).Methods(handlers.MethodCreateGame).Handler(handlers.NewCreateGameHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRouteGetGameByID).Methods(handlers.MethodGetGame).Handler(handlers.NewGetGameHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRouteDeleteGameByID).Methods(handlers.MethodDeleteGame).Handler(handlers.NewDeleteGameHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRouteGetGames).Methods(handlers.MethodGetGames).Handler(handlers.NewGetGamesHandler(logger, groupManager))
	if enableBroadcast {
		apiRouter.Path(handlers.URLRouteBroadcast).Methods(handlers.MethodBroadcast).Handler(handlers.NewBroadcastHandler(logger, groupManager))
	}
	apiRouter.Path(handlers.URLRouteGetObjects).Methods(handlers.MethodGetObjects).Handler(handlers.NewGetObjectsHandler(logger, groupManager))
	apiRouter.Path(handlers.URLRoutePing).Methods(handlers.MethodPing).Handler(handlers.NewPingHandler(logger))

	httpMux := http.NewServeMux()

	httpMux.Handle("/", rootRouter)

	// Use middlewares for API routes
	httpMux.Handle("/api/", negroni.New(
		middlewares.NewRecovery(logger),
		middlewares.NewLogger(logger, logName),
		middlewares.NewCORS(),
		negroni.Wrap(rootRouter),
	))

	n := negroni.New()
	n.Use(middlewares.NewServerInfo(ServerName, Version, Build))
	n.UseHandler(httpMux)

	logger.WithFields(logrus.Fields{
		"address": address,
		"tls":     flagEnableTLS,
	}).Info("starting server")

	if err := serve(n); err != nil {
		logger.Fatalf("server error: %s", err)
	}
}
<|endoftext|>


<commit_before>package core

import (
	"github.com/tinzenite/channel"
	"github.com/tinzenite/model"
	"github.com/tinzenite/shared"
)

/*
CreateTinzenite makes a directory a new Tinzenite directory. Will return error
if already so.
*/
func CreateTinzenite(dirname, dirpath, peername, username, password string) (*Tinzenite, error) {
	if shared.IsTinzenite(dirpath) {
		return nil, shared.ErrIsTinzenite
	}
	// flag whether we have to clean up after us
	var failed bool
	// make .tinzenite
	err := shared.MakeDotTinzenite(dirpath)
	if err != nil {
		return nil, err
	}
	// if failed was set --> clean up by removing everything
	defer func() {
		if failed {
			shared.RemoveDotTinzenite(dirpath)
		}
	}()
	// get auth data
	auth, err := createAuthentication(dirpath, dirname, username, password)
	if err != nil {
		failed = true
		return nil, err
	}
	// Build
	tinzenite := &Tinzenite{
		Path: dirpath,
		auth: auth}
	// prepare chaninterface
	tinzenite.cInterface = createChannelInterface(tinzenite)
	// build channel
	channel, err := channel.Create(peername, nil, tinzenite.cInterface)
	if err != nil {
		failed = true
		return nil, err
	}
	tinzenite.channel = channel
	// build self peer
	address, err := channel.Address()
	if err != nil {
		failed = true
		return nil, err
	}
	peer, err := shared.CreatePeer(peername, address, false)
	if err != nil {
		failed = true
		return nil, err
	}
	tinzenite.selfpeer = peer
	tinzenite.allPeers = []*shared.Peer{peer}
	// build model (can block for long!)
	m, err := model.Create(dirpath, peer.Identification, dirpath+"/"+shared.STOREMODELDIR)
	if err != nil {
		failed = true
		return nil, err
	}
	tinzenite.model = m
	// store initial copy
	err = tinzenite.Store()
	if err != nil {
		failed = true
		return nil, err
	}
	// save that this directory is now a tinzenite dir
	err = shared.WriteDirectoryList(tinzenite.Path)
	if err != nil {
		failed = true
		return nil, err
	}
	tinzenite.initialize()
	return tinzenite, nil
}

/*
LoadTinzenite will try to load the given directory path as a Tinzenite directory.
If not one it won't work: use CreateTinzenite to create a new peer.
*/
func LoadTinzenite(dirpath, password string) (*Tinzenite, error) {
	if !shared.IsTinzenite(dirpath) {
		return nil, shared.ErrNotTinzenite
	}
	t := &Tinzenite{Path: dirpath}
	// load auth
	auth, err := loadAuthenticationFrom(dirpath+"/"+shared.STOREAUTHDIR, password)
	if err != nil {
		return nil, err
	}
	t.auth = auth
	// load model
	model, err := model.Load(dirpath + "/" + shared.STOREMODELDIR)
	if err != nil {
		return nil, err
	}
	t.model = model
	// load peer list (don't use t.applyPeers – channel not running yet!)
	peers, err := shared.LoadPeers(dirpath)
	if err != nil {
		return nil, err
	}
	t.allPeers = peers
	// load tox dump
	selfToxDump, err := shared.LoadToxDumpFrom(dirpath + "/" + shared.STORETOXDUMPDIR)
	if err != nil {
		return nil, err
	}
	t.selfpeer = selfToxDump.SelfPeer
	// prepare chaninterface
	t.cInterface = createChannelInterface(t)
	// prepare channel
	channel, err := channel.Create(t.selfpeer.Name, selfToxDump.ToxData, t.cInterface)
	if err != nil {
		return nil, err
	}
	t.channel = channel
	t.initialize()
	// empty temp folder to remove orphaned files (ignore error because we don't care if it works)
	_ = shared.RemoveDirContents(t.Path + "/" + shared.TINZENITEDIR + "/" + shared.TEMPDIR)
	return t, nil
}
<commit_msg>applied small refactor<commit_after>package core

import (
	"github.com/tinzenite/channel"
	"github.com/tinzenite/model"
	"github.com/tinzenite/shared"
)

/*
CreateTinzenite makes a directory a new Tinzenite directory. Will return error
if already so.
*/
func CreateTinzenite(dirname, dirpath, peername, username, password string) (*Tinzenite, error) {
	if shared.IsTinzenite(dirpath) {
		return nil, shared.ErrIsTinzenite
	}
	// flag whether we have to clean up after us
	var failed bool
	// make .tinzenite
	err := shared.MakeDotTinzenite(dirpath)
	if err != nil {
		return nil, err
	}
	// if failed was set --> clean up by removing everything
	defer func() {
		if failed {
			shared.RemoveDotTinzenite(dirpath)
		}
	}()
	// get auth data
	auth, err := createAuthentication(dirpath, dirname, username, password)
	if err != nil {
		failed = true
		return nil, err
	}
	// Build
	tinzenite := &Tinzenite{
		Path: dirpath,
		auth: auth}
	// prepare chaninterface
	tinzenite.cInterface = createChannelInterface(tinzenite)
	// build channel
	channel, err := channel.Create(peername, nil, tinzenite.cInterface)
	if err != nil {
		failed = true
		return nil, err
	}
	tinzenite.channel = channel
	// build self peer
	address, err := channel.Address()
	if err != nil {
		failed = true
		return nil, err
	}
	peer, err := shared.CreatePeer(peername, address, false)
	if err != nil {
		failed = true
		return nil, err
	}
	tinzenite.selfpeer = peer
	tinzenite.allPeers = []*shared.Peer{peer}
	// build model (can block for long!)
	m, err := model.Create(dirpath, peer.Identification, dirpath+"/"+shared.STOREMODELDIR)
	if err != nil {
		failed = true
		return nil, err
	}
	tinzenite.model = m
	// store initial copy
	err = tinzenite.Store()
	if err != nil {
		failed = true
		return nil, err
	}
	// save that this directory is now a tinzenite dir
	err = shared.WriteDirectoryList(tinzenite.Path)
	if err != nil {
		failed = true
		return nil, err
	}
	tinzenite.initialize()
	return tinzenite, nil
}

/*
LoadTinzenite will try to load the given directory path as a Tinzenite directory.
If not one it won't work: use CreateTinzenite to create a new peer.
*/
func LoadTinzenite(dirpath, password string) (*Tinzenite, error) {
	if !shared.IsTinzenite(dirpath) {
		return nil, shared.ErrNotTinzenite
	}
	t := &Tinzenite{Path: dirpath}
	// load auth
	auth, err := loadAuthenticationFrom(dirpath+"/"+shared.STOREAUTHDIR, password)
	if err != nil {
		return nil, err
	}
	t.auth = auth
	// load model
	model, err := model.LoadFrom(dirpath + "/" + shared.STOREMODELDIR)
	if err != nil {
		return nil, err
	}
	t.model = model
	// load peer list (don't use t.applyPeers – channel not running yet!)
	peers, err := shared.LoadPeers(dirpath)
	if err != nil {
		return nil, err
	}
	t.allPeers = peers
	// load tox dump
	selfToxDump, err := shared.LoadToxDumpFrom(dirpath + "/" + shared.STORETOXDUMPDIR)
	if err != nil {
		return nil, err
	}
	t.selfpeer = selfToxDump.SelfPeer
	// prepare chaninterface
	t.cInterface = createChannelInterface(t)
	// prepare channel
	channel, err := channel.Create(t.selfpeer.Name, selfToxDump.ToxData, t.cInterface)
	if err != nil {
		return nil, err
	}
	t.channel = channel
	t.initialize()
	// empty temp folder to remove orphaned files (ignore error because we don't care if it works)
	_ = shared.RemoveDirContents(t.Path + "/" + shared.TINZENITEDIR + "/" + shared.TEMPDIR)
	return t, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"golang.org/x/build/kubernetes/api"
	"log"
	"net/http"
	"os"
	"time"
)

type Stream struct {
	Type  string    `json:"type,omitempty"`
	Event api.Event `json:"object"`
}

func main() {
	apiAddr := os.Getenv("OPENSHIFT_API_URL")
	apiToken := os.Getenv("OPENSHIFT_TOKEN")

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	req, err := http.NewRequest("GET", apiAddr+"/api/v1/events?watch=true", nil)
	if err != nil {
		log.Fatal("## Error while opening connection to openshift api", err)
	}
	req.Header.Add("Authorization", "Bearer "+apiToken)

	for {
		resp, err := client.Do(req)

		if err != nil {
			log.Println("## Error while connecting to:", apiAddr, err)
			time.Sleep(5 * time.Second)
			continue
		}

		reader := bufio.NewReader(resp.Body)

		for {
			line, err := reader.ReadBytes('\n')
			if err != nil {
				log.Println("## Error reading from response stream.", err)
				continue
			}

			event := Stream{}
			decErr := json.Unmarshal(line, &event)
			if decErr != nil {
				log.Println("## Error decoding json", err)
				continue
			}

			fmt.Printf("%v | Project: %v | Name: %v | Kind: %v | Reason: %v | Message: %v\n",
				event.Event.LastTimestamp,
				event.Event.Namespace, event.Event.Name,
				event.Event.Kind, event.Event.Reason, event.Event.Message)
		}
	}
}

<commit_msg>Fixed break > continue<commit_after>package main

import (
	"bufio"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"golang.org/x/build/kubernetes/api"
	"log"
	"net/http"
	"os"
	"time"
)

type Stream struct {
	Type  string    `json:"type,omitempty"`
	Event api.Event `json:"object"`
}

func main() {
	apiAddr := os.Getenv("OPENSHIFT_API_URL")
	apiToken := os.Getenv("OPENSHIFT_TOKEN")

	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	req, err := http.NewRequest("GET", apiAddr+"/api/v1/events?watch=true", nil)
	if err != nil {
		log.Fatal("## Error while opening connection to openshift api", err)
	}
	req.Header.Add("Authorization", "Bearer "+apiToken)

	for {
		resp, err := client.Do(req)

		if err != nil {
			log.Println("## Error while connecting to:", apiAddr, err)
			time.Sleep(5 * time.Second)
			continue
		}

		reader := bufio.NewReader(resp.Body)

		for {
			line, err := reader.ReadBytes('\n')
			if err != nil {
				log.Println("## Error reading from response stream.", err)
				resp.Body.Close()
				break
			}

			event := Stream{}
			decErr := json.Unmarshal(line, &event)
			if decErr != nil {
				log.Println("## Error decoding json", err)
				resp.Body.Close()
				break
			}

			fmt.Printf("%v | Project: %v | Name: %v | Kind: %v | Reason: %v | Message: %v\n",
				event.Event.LastTimestamp,
				event.Event.Namespace, event.Event.Name,
				event.Event.Kind, event.Event.Reason, event.Event.Message)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/cipher"
	"crypto/des"
	"crypto/sha1"
	"flag"
	"log"
	"net"
	"sync"

	"code.google.com/p/go.crypto/pbkdf2"
)

var (
	flagRemote  = flag.String("remote", "localhost:1194", "Remote addr to connect to.")
	flagLocal   = flag.String("local", ":11194", "Local addr to listen to.")
	flagKey     = flag.String("key", "20121221", "Key to obfuscate the packet.")
	flagServer  = flag.Bool("server", false, "Server or client.")
	flagVerbose = flag.Bool("verbose", false, "Enable debug messages.")

	obfuscator cipher.Block
)

const udpMaxPacketSize = 65535

type connPair struct {
	IncomingAddr *net.UDPAddr
	OutgoingConn *net.UDPConn
}

func initCipher() {
	key := pbkdf2.Key([]byte(*flagKey), []byte("go-udpforward"), 4096, 24, sha1.New)
	var err error
	obfuscator, err = des.NewTripleDESCipher(key)
	check(err)
}

func main() {
	flag.Parse()
	initCipher()

	laddr, err := net.ResolveUDPAddr("udp", *flagLocal)
	check(err)
	raddr, err := net.ResolveUDPAddr("udp", *flagRemote)
	check(err)

	listener, err := net.ListenUDP("udp", laddr)
	check(err)
	buf := make([]byte, udpMaxPacketSize)
	connmap := make(map[string]connPair)
	mu := sync.Mutex{}
	for {
		n, local, err := listener.ReadFromUDP(buf)
		check(err)
		_, ok := connmap[local.String()]
		if !ok {
			outgoing, err := net.DialUDP("udp", nil, raddr)
			check(err)
			log.Println("Incoming connection from ", local.String())
			log.Println("Outgoing connection from ", outgoing.LocalAddr(), "to", outgoing.RemoteAddr())
			go func(laddr *net.UDPAddr, outgoing *net.UDPConn) {
				buf := make([]byte, udpMaxPacketSize)
				for {
					n, err := outgoing.Read(buf)
					if err != nil {
						break
					}
					if *flagVerbose {
						log.Println("Message from remote, writing to", laddr)
					}
					if *flagServer {
						obfuscator.Encrypt(buf[:n], buf[:n])
					} else {
						obfuscator.Decrypt(buf[:n], buf[:n])
					}
					_, err = listener.WriteToUDP(buf[:n], laddr)
					if err != nil {
						continue
					}
				}
				log.Println("Releasing connection for", local)
				mu.Lock()
				delete(connmap, local.String())
				mu.Unlock()
			}(local, outgoing)
			mu.Lock()
			connmap[local.String()] = connPair{local, outgoing}
			mu.Unlock()
		}
		outgoing := connmap[local.String()].OutgoingConn
		if *flagVerbose {
			log.Println("Forwarding packet to", outgoing.RemoteAddr())
		}
		if *flagServer {
			obfuscator.Decrypt(buf[:n], buf[:n])
		} else {
			obfuscator.Encrypt(buf[:n], buf[:n])
		}
		_, err = outgoing.Write(buf[:n])
		check(err)
	}
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>no panic on dail fail<commit_after>package main

import (
	"crypto/cipher"
	"crypto/des"
	"crypto/sha1"
	"flag"
	"log"
	"net"
	"sync"

	"code.google.com/p/go.crypto/pbkdf2"
)

var (
	flagRemote  = flag.String("remote", "localhost:1194", "Remote addr to connect to.")
	flagLocal   = flag.String("local", ":11194", "Local addr to listen to.")
	flagKey     = flag.String("key", "20121221", "Key to obfuscate the packet.")
	flagServer  = flag.Bool("server", false, "Server or client.")
	flagVerbose = flag.Bool("verbose", false, "Enable debug messages.")

	obfuscator cipher.Block
)

const udpMaxPacketSize = 65535

type connPair struct {
	IncomingAddr *net.UDPAddr
	OutgoingConn *net.UDPConn
}

func initCipher() {
	key := pbkdf2.Key([]byte(*flagKey), []byte("go-udpforward"), 4096, 24, sha1.New)
	var err error
	obfuscator, err = des.NewTripleDESCipher(key)
	check(err)
}

func main() {
	flag.Parse()
	initCipher()

	laddr, err := net.ResolveUDPAddr("udp", *flagLocal)
	check(err)
	raddr, err := net.ResolveUDPAddr("udp", *flagRemote)
	check(err)

	listener, err := net.ListenUDP("udp", laddr)
	check(err)
	buf := make([]byte, udpMaxPacketSize)
	connmap := make(map[string]connPair)
	mu := sync.Mutex{}
readloop:
	for {
		n, local, err := listener.ReadFromUDP(buf)
		check(err)
		_, ok := connmap[local.String()]
		if !ok {
			outgoing, err := net.DialUDP("udp", nil, raddr)
			if err != nil {
				log.Println("ERROR", err)
				continue readloop
			}
			log.Println("Incoming connection from ", local.String())
			log.Println("Outgoing connection from ", outgoing.LocalAddr(), "to", outgoing.RemoteAddr())
			go func(laddr *net.UDPAddr, outgoing *net.UDPConn) {
				buf := make([]byte, udpMaxPacketSize)
				for {
					n, err := outgoing.Read(buf)
					if err != nil {
						break
					}
					if *flagVerbose {
						log.Println("Message from remote, writing to", laddr)
					}
					if *flagServer {
						obfuscator.Encrypt(buf[:n], buf[:n])
					} else {
						obfuscator.Decrypt(buf[:n], buf[:n])
					}
					_, err = listener.WriteToUDP(buf[:n], laddr)
					if err != nil {
						continue
					}
				}
				log.Println("Releasing connection for", local)
				mu.Lock()
				delete(connmap, local.String())
				mu.Unlock()
			}(local, outgoing)
			mu.Lock()
			connmap[local.String()] = connPair{local, outgoing}
			mu.Unlock()
		}
		outgoing := connmap[local.String()].OutgoingConn
		if *flagVerbose {
			log.Println("Forwarding packet to", outgoing.RemoteAddr())
		}
		if *flagServer {
			obfuscator.Decrypt(buf[:n], buf[:n])
		} else {
			obfuscator.Encrypt(buf[:n], buf[:n])
		}
		_, err = outgoing.Write(buf[:n])
		check(err)
	}
}

func check(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package cache

import (
	"container/list"
	"sync"
	"time"
)

type CacheStrategy int

const (
	CacheStrategyRandom    = CacheStrategy(1)
	CacheStrategyOldest    = CacheStrategy(2)
	CacheStrategyOldestLRU = CacheStrategy(3)
)

type Cache struct {
	l        *list.List
	contents map[string]*list.Element
	mutex    *sync.Mutex
	dead     bool
	hits     int64
	misses   int64
	options  CacheOptions
}

type CachedItem struct {
	key     string
	value   interface{}
	running bool
}

type CacheOptions struct {
	MaxEntries     int //If this is set to 0, you must have an expiration time set.
	Upper          int
	CacheStrategy  CacheStrategy
	ExpirationTime time.Duration
	JobInvertal    time.Duration
	SafeRange      int
}

func NewCache(c CacheOptions) *Cache {
	newc := &Cache{}
	newc.options = c
	newc.contents = make(map[string]*list.Element)
	newc.mutex = &sync.Mutex{}
	newc.l = list.New()
	newc.dead = true
	if newc.options.MaxEntries > newc.options.Upper && newc.options.Upper > 0 {
		newc.options.Upper = newc.options.MaxEntries
	}
	return newc
}

func (c *Cache) Set(key string, value interface{}) {
	c.lock()
	defer c.unlock()
	if value == nil {
		c.deleteItem(c.contents[key])
		return
	}
	if c.l.Len()+1 >= c.options.Upper && c.options.Upper > 0 {
		c.burnEntryByStrategy()
	}
	newitem := &CachedItem{}
	newitem.value = value
	newitem.key = key
	e := c.l.PushFront(newitem)
	c.contents[key] = e
	if c.options.ExpirationTime > 0 && !c.dead {
		go c.expireIn(c.options.ExpirationTime, e)
	}
}

func (c *Cache) Get(key string) interface{} {
	c.lock()
	defer c.unlock()
	k, ok := c.contents[key]
	if ok {
		c.hits++
		if c.options.CacheStrategy == CacheStrategyOldestLRU {
			c.l.MoveToFront(k)
		}
		return k.Value.(*CachedItem).value
	} else {
		c.misses++
		return nil
	}
}

func (c *Cache) Start() {
	c.dead = false
	if c.options.JobInvertal > 0 {
		go c.runner()
	}
	for _, b := range c.contents {
		if !b.Value.(*CachedItem).running && c.options.ExpirationTime > 0 {
			go c.expireIn(c.options.ExpirationTime, b)
		}
	}
}

func (c *Cache) Stop() {
	c.dead = true
}

func (c *Cache) Hits() int64 {
	return c.hits
}

func (c *Cache) Misses() int64 {
	return c.misses
}

func (c *Cache) RemoveItem(key string) {
	c.lock()
	defer c.unlock()
	c.deleteItem(c.contents[key])
}

func (c *Cache) Trim(num int) {
	c.lock()
	defer c.unlock()
	for num > 0 && c.l.Len() > 0 {
		num--
		c.burnEntryByStrategy()
	}
}

func (c *Cache) Bump(key string) {
	k, ok := c.contents[key]
	if ok {
		c.l.MoveToFront(k)
	}
}

//For now we, can't use this internally since it is mutex'd
func (c *Cache) Len() int {
	c.lock()
	defer c.unlock()
	return c.l.Len()
}

//private functions
func (c *Cache) burnEntryByStrategy() {
	if c.options.CacheStrategy == CacheStrategyOldest || c.options.CacheStrategy == CacheStrategyOldestLRU {
		c.burnEntryByOldest()
	} else {
		c.burnEntryByRandom()
	}
}

func (c *Cache) burnEntryByRandom() {
	for _, a := range c.contents {
		c.deleteItem(a)
		break
	}
}

func (c *Cache) burnEntryByOldest() {
	i := c.l.Back()
	if i != nil {
		c.deleteItem(i)
	}
}

func (c *Cache) lock() {
	c.mutex.Lock()
}

func (c *Cache) unlock() {
	c.mutex.Unlock()
}

func (c *Cache) runner() {
	for {
		time.Sleep(c.options.JobInvertal)
		if c.dead {
			break
		}
		c.lock()
		if c.options.MaxEntries > 0 {
			for len(c.contents) > c.options.MaxEntries-c.options.SafeRange {
				c.burnEntryByStrategy()
			}
		}
		c.unlock()
	}
}

func (c *Cache) expireIn(t time.Duration, i *list.Element) {
	i.Value.(*CachedItem).running = true
	time.Sleep(t)
	if c.dead {
		i.Value.(*CachedItem).running = false
		return
	}
	c.lock()
	defer c.unlock()
	c.deleteItem(i)
}

func (c *Cache) deleteItem(i *list.Element) {
	c.l.Remove(i)
	delete(c.contents, i.Value.(*CachedItem).key)
}
<commit_msg>Implement simple LFU<commit_after>package cache

import (
	"container/list"
	"sync"
	"time"
)

type CacheStrategy int

const (
	CacheStrategyRandom    = CacheStrategy(1)
	CacheStrategyOldest    = CacheStrategy(2)
	CacheStrategyOldestLRU = CacheStrategy(3)
	CacheStrategyLFU       = CacheStrategy(4)
)

type Cache struct {
	l        *list.List
	contents map[string]*list.Element
	mutex    *sync.Mutex
	dead     bool
	hits     int64
	misses   int64
	options  CacheOptions
}

type CachedItem struct {
	key     string
	value   interface{}
	running bool
	used    int
}

type CacheOptions struct {
	MaxEntries     int //If this is set to 0, you must have an expiration time set.
	Upper          int
	CacheStrategy  CacheStrategy
	ExpirationTime time.Duration
	JobInvertal    time.Duration
	SafeRange      int
}

func NewCache(c CacheOptions) *Cache {
	newc := &Cache{}
	newc.options = c
	newc.contents = make(map[string]*list.Element)
	newc.mutex = &sync.Mutex{}
	newc.l = list.New()
	newc.dead = true
	if newc.options.MaxEntries > newc.options.Upper && newc.options.Upper > 0 {
		newc.options.Upper = newc.options.MaxEntries
	}
	return newc
}

func (c *Cache) Set(key string, value interface{}) {
	c.lock()
	defer c.unlock()
	if value == nil {
		c.deleteItem(c.contents[key])
		return
	}
	if c.l.Len()+1 >= c.options.Upper && c.options.Upper > 0 {
		c.burnEntryByStrategy()
	}
	newitem := &CachedItem{}
	newitem.value = value
	newitem.key = key
	e := c.l.PushFront(newitem)
	c.contents[key] = e
	if c.options.ExpirationTime > 0 && !c.dead {
		go c.expireIn(c.options.ExpirationTime, e)
	}
}

func (c *Cache) Get(key string) interface{} {
	c.lock()
	defer c.unlock()
	k, ok := c.contents[key]
	if ok {
		c.hits++
		if c.options.CacheStrategy == CacheStrategyOldestLRU || c.options.CacheStrategy == CacheStrategyLFU {
			c.l.MoveToFront(k)
			k.Value.(*CachedItem).used++
		}
		return k.Value.(*CachedItem).value
	} else {
		c.misses++
		return nil
	}
}

func (c *Cache) Start() {
	c.dead = false
	if c.options.JobInvertal > 0 {
		go c.runner()
	}
	for _, b := range c.contents {
		if !b.Value.(*CachedItem).running && c.options.ExpirationTime > 0 {
			go c.expireIn(c.options.ExpirationTime, b)
		}
	}
}

func (c *Cache) Stop() {
	c.dead = true
}

func (c *Cache) Hits() int64 {
	return c.hits
}

func (c *Cache) Misses() int64 {
	return c.misses
}

func (c *Cache) RemoveItem(key string) {
	c.lock()
	defer c.unlock()
	c.deleteItem(c.contents[key])
}

func (c *Cache) Trim(num int) {
	c.lock()
	defer c.unlock()
	for num > 0 && c.l.Len() > 0 {
		num--
		c.burnEntryByStrategy()
	}
}

func (c *Cache) Bump(key string) {
	k, ok := c.contents[key]
	if ok {
		c.l.MoveToFront(k)
	}
}

//For now we, can't use this internally since it is mutex'd
func (c *Cache) Len() int {
	c.lock()
	defer c.unlock()
	return c.l.Len()
}

//private functions
func (c *Cache) burnEntryByStrategy() {
	if c.options.CacheStrategy == CacheStrategyOldest || c.options.CacheStrategy == CacheStrategyOldestLRU {
		c.burnEntryByOldest()
	} else if c.options.CacheStrategy == CacheStrategyLFU {
		c.burnEntryByLFU()
	} else {
		c.burnEntryByRandom()
	}
}

func (c *Cache) burnEntryByRandom() {
	for _, a := range c.contents {
		c.deleteItem(a)
		break
	}
}

func (c *Cache) burnEntryByOldest() {
	i := c.l.Back()
	if i != nil {
		c.deleteItem(i)
	}
}

func (c *Cache) burnEntryByLFU() {
	counter := 0
	for e := c.l.Back(); e != nil; e = e.Prev() {
		if e.Value.(*CachedItem).used == counter {
			c.deleteItem(e)
			break
		}
		counter++
	}
}

func (c *Cache) lock() {
	c.mutex.Lock()
}

func (c *Cache) unlock() {
	c.mutex.Unlock()
}

func (c *Cache) runner() {
	for {
		time.Sleep(c.options.JobInvertal)
		if c.dead {
			break
		}
		c.lock()
		if c.options.MaxEntries > 0 {
			for len(c.contents) > c.options.MaxEntries-c.options.SafeRange {
				c.burnEntryByStrategy()
			}
		}
		c.unlock()
	}
}

func (c *Cache) expireIn(t time.Duration, i *list.Element) {
	i.Value.(*CachedItem).running = true
	time.Sleep(t)
	if c.dead {
		i.Value.(*CachedItem).running = false
		return
	}
	c.lock()
	defer c.unlock()
	c.deleteItem(i)
}

func (c *Cache) deleteItem(i *list.Element) {
	c.l.Remove(i)
	delete(c.contents, i.Value.(*CachedItem).key)
}
<|endoftext|>


<commit_before>/* CLI utility for stress testing of HTTP servers with many concurrent connections

https://github.com/chillum/httpstress-go

Usage:
 httpstress-go [options] <URL list>

Options:
 * `URL list` – URLs to fetch (required)
 * `-c NUM` – concurrent connections number (defaults to 1)
 * `-n NUM` – total connections number (optional)
 * `-v` – print version to stdout and exit

Example:
 httpstress-go -c 1000 http://localhost https://google.com

Returns 0 if no errors, 1 if some failed (see stdout), 2 on kill and 3 in case of invalid options.

Prints error count for each URL to stdout (does not count successful attempts).
Errors and debugging information go to stderr.

Error output is YAML-formatted. Example:
 errors:
   - location: http://localhost
     count:    334
   - location: http://127.0.0.1
     count:    333

Please note that this utility uses GOMAXPROCS environment variable if it's present.
If not, this defaults to CPU count + 1. */
package main

/* Copyright 2014 Vasily Korytov

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. */

import (
	"flag"
	"fmt"
	"github.com/chillum/httpstress"
	"os"
	"runtime"
)

// Application version
const Version = "2.1.1"

func main() {
	var conn, max int
	flag.IntVar(&conn, "c", 1, "concurrent connections count")
	flag.IntVar(&max, "n", 0, "total connections (optional)")
	version := flag.Bool("v", false, "print version to stdout and exit")
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[options] <URL list>")
		fmt.Fprintln(os.Stderr, "  <URL list>: URLs to fetch (required)")
		flag.PrintDefaults()
		fmt.Fprintln(os.Stderr, "Docs:\n  https://godoc.org/github.com/chillum/httpstress-go")
		fmt.Fprintln(os.Stderr, "Example:\n  httpstress-go -c 1000 http://localhost https://google.com")
		os.Exit(3)
	}
	flag.Parse()

	if *version {
		fmt.Println("httpstress-go", Version)
		fmt.Println("httpstress", httpstress.Version)
		fmt.Println(runtime.Version(), runtime.GOOS, runtime.GOARCH)
		os.Exit(0)
	}

	urls := flag.Args()
	if len(urls) < 1 {
		flag.Usage()
	}

	if os.Getenv("GOMAXPROCS") == "" {
		runtime.GOMAXPROCS(runtime.NumCPU() + 1)
	}

	setlimits(&conn) // Platform-specific code: see unix.go and windows.go for details.

	out, err := httpstress.Test(conn, max, urls)
	if err != nil {
		fmt.Fprintln(os.Stderr, "ERROR:", err)
		flag.Usage()
	}

	if len(out) > 0 {
		fmt.Println("errors:")
		for url, num := range out {
			fmt.Println("  - location: ", url, "\n    count:    ", num)
		}
		os.Exit(1)
	} else {
		fmt.Fprintln(os.Stderr, "Test finished. No failed requests.")
	}
}
<commit_msg>More docs updates<commit_after>/* CLI utility for stress testing of HTTP servers with many concurrent connections

Usage:
 httpstress-go [options] <URL list>

Options:
 * `URL list` – URLs to fetch (required)
 * `-c NUM` – concurrent connections number (defaults to 1)
 * `-n NUM` – total connections number (optional)
 * `-v` – print version to stdout and exit

Example:
 httpstress-go -c 1000 http://localhost https://google.com

Returns 0 if no errors, 1 if some failed (see stdout), 2 on kill and 3 in case of invalid options.

Prints error count for each URL to stdout (does not count successful attempts).
Errors and debugging information go to stderr.

Error output is YAML-formatted. Example:
 errors:
   - location: http://localhost
     count:    334
   - location: http://127.0.0.1
     count:    333

Please note that this utility uses GOMAXPROCS environment variable if it's present.
If not, this defaults to CPU count + 1. */
package main

/* Copyright 2014 Vasily Korytov

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. */

import (
	"flag"
	"fmt"
	"github.com/chillum/httpstress"
	"os"
	"runtime"
)

// Application version
const Version = "2.1.1"

func main() {
	var conn, max int
	flag.IntVar(&conn, "c", 1, "concurrent connections count")
	flag.IntVar(&max, "n", 0, "total connections (optional)")
	version := flag.Bool("v", false, "print version to stdout and exit")
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[options] <URL list>")
		fmt.Fprintln(os.Stderr, "  <URL list>: URLs to fetch (required)")
		flag.PrintDefaults()
		fmt.Fprintln(os.Stderr, "Docs:\n  https://github.com/chillum/httpstress-go")
		fmt.Fprintln(os.Stderr, "Example:\n  httpstress-go -c 1000 http://localhost https://google.com")
		os.Exit(3)
	}
	flag.Parse()

	if *version {
		fmt.Println("httpstress-go", Version)
		fmt.Println("httpstress", httpstress.Version)
		fmt.Println(runtime.Version(), runtime.GOOS, runtime.GOARCH)
		os.Exit(0)
	}

	urls := flag.Args()
	if len(urls) < 1 {
		flag.Usage()
	}

	if os.Getenv("GOMAXPROCS") == "" {
		runtime.GOMAXPROCS(runtime.NumCPU() + 1)
	}

	setlimits(&conn) // Platform-specific code: see unix.go and windows.go for details.

	out, err := httpstress.Test(conn, max, urls)
	if err != nil {
		fmt.Fprintln(os.Stderr, "ERROR:", err)
		flag.Usage()
	}

	if len(out) > 0 {
		fmt.Println("errors:")
		for url, num := range out {
			fmt.Println("  - location: ", url, "\n    count:    ", num)
		}
		os.Exit(1)
	} else {
		fmt.Fprintln(os.Stderr, "Test finished. No failed requests.")
	}
}
<|endoftext|>


<commit_before>/*cloud-proxy is a utility for creating multiple DO droplets
and starting socks proxies via SSH after creation.*/
package main

import (
	"flag"
	"fmt"
	"os"
	"os/signal"
	"strconv"
	"time"

	"github.com/iamthemuffinman/logsip"
)

var (
	token       = flag.String("token", "", "DO API key")
	sshLocation = flag.String("key-location", "~/.ssh/id_rsa", "SSH key location")
	keyID       = flag.String("key", "", "SSH key fingerprint")
	count       = flag.Int("count", 5, "Amount of droplets to deploy")
	name        = flag.String("name", "cloud-proxy", "Droplet name prefix")
	region      = flag.String("region", "nyc3", "Region to deploy droplets to")
	force       = flag.Bool("force", false, "Bypass built-in protections that prevent you from deploying more than 50 droplets")
	startPort   = flag.Int("start-tcp", 55555, "TCP port to start first proxy on and increment from")
	showversion = flag.Bool("v", false, "Print version and exit")
	version     = "1.1.0"
)

func main() {
	flag.Parse()
	if *showversion {
		fmt.Println(version)
		os.Exit(0)
	}
	log := logsip.Default()

	if *token == "" {
		log.Fatalln("-token required")
	}
	if *keyID == "" {
		log.Fatalln("-key required")
	}
	if *count > 50 && !*force {
		log.Fatalln("-count greater than 50")
	}

	client := newDOClient(*token)
	droplets, _, err := client.Droplets.CreateMultiple(newDropLetMultiCreateReqeust(*name, *region, *keyID, *count))
	if err != nil {
		log.Fatalf("There was an error creating the droplets:\nError: %s\n", err.Error())
	}
	log.Infoln("Droplets deployed. Waiting 100 seconds...")
	time.Sleep(100 * time.Second)

	// For each droplet, poll it once, start SSH proxy, and then track it.
	machines := dropletsToMachines(droplets)
	for i := range machines {
		m := &machines[i]
		if err := m.GetIPs(client); err != nil {
			log.Warnf("There was an error getting the IPv4 address of droplet name: %s\nError: %s\n", m.Name, err.Error())
		}
		if m.IsReady() {
			if err := m.StartSSHProxy(strconv.Itoa(*startPort), *sshLocation); err != nil {
				log.Warnf("Could not start SSH proxy on droplet name: %s\nError: %s\n", m.Name, err.Error())
			} else {
				log.Infof("SSH proxy started on port %d on droplet name: %s IP: %s\n", *startPort, m.Name, m.IPv4)
				go m.PrintStdError()
			}
			*startPort++
		} else {
			log.Warnf("Droplet name: %s is not ready yet. Skipping...\n", m.Name)
		}
	}

	log.Infoln("proxychains config")
	printProxyChains(machines)
	log.Infoln("socksd config")
	printSocksd(machines)

	log.Infoln("Please CTRL-C to destroy droplets")

	// Catch CTRL-C and delete droplets.
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	<-c
	for _, m := range machines {
		if err := m.Destroy(client); err != nil {
			log.Warnf("Could not delete droplet name: %s\n", m.Name)
		} else {
			log.Infof("Deleted droplet name: %s", m.Name)
		}
	}
}
<commit_msg>Replace logsip<commit_after>/*cloud-proxy is a utility for creating multiple DO droplets
and starting socks proxies via SSH after creation.*/
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strconv"
	"time"
)

var (
	token       = flag.String("token", "", "DO API key")
	sshLocation = flag.String("key-location", "~/.ssh/id_rsa", "SSH key location")
	keyID       = flag.String("key", "", "SSH key fingerprint")
	count       = flag.Int("count", 5, "Amount of droplets to deploy")
	name        = flag.String("name", "cloud-proxy", "Droplet name prefix")
	region      = flag.String("region", "nyc3", "Region to deploy droplets to")
	force       = flag.Bool("force", false, "Bypass built-in protections that prevent you from deploying more than 50 droplets")
	startPort   = flag.Int("start-tcp", 55555, "TCP port to start first proxy on and increment from")
	showversion = flag.Bool("v", false, "Print version and exit")
	version     = "1.1.0"
)

func main() {
	flag.Parse()
	if *showversion {
		fmt.Println(version)
		os.Exit(0)
	}
	if *token == "" {
		log.Fatalln("-token required")
	}

	if *keyID == "" {
		log.Fatalln("-key required")
	}
	if *count > 50 && !*force {
		log.Fatalln("-count greater than 50")
	}

	client := newDOClient(*token)
	droplets, _, err := client.Droplets.CreateMultiple(newDropLetMultiCreateReqeust(*name, *region, *keyID, *count))
	if err != nil {
		log.Fatalf("There was an error creating the droplets:\nError: %s\n", err.Error())
	}
	log.Println("Droplets deployed. Waiting 100 seconds...")
	time.Sleep(100 * time.Second)

	// For each droplet, poll it once, start SSH proxy, and then track it.
	machines := dropletsToMachines(droplets)
	for i := range machines {
		m := &machines[i]
		if err := m.GetIPs(client); err != nil {
			log.Println("There was an error getting the IPv4 address of droplet name: %s\nError: %s\n", m.Name, err.Error())
		}
		if m.IsReady() {
			if err := m.StartSSHProxy(strconv.Itoa(*startPort), *sshLocation); err != nil {
				log.Println("Could not start SSH proxy on droplet name: %s\nError: %s\n", m.Name, err.Error())
			} else {
				log.Println("SSH proxy started on port %d on droplet name: %s IP: %s\n", *startPort, m.Name, m.IPv4)
				go m.PrintStdError()
			}
			*startPort++
		} else {
			log.Println("Droplet name: %s is not ready yet. Skipping...\n", m.Name)
		}
	}

	log.Println("proxychains config")
	printProxyChains(machines)
	log.Println("socksd config")
	printSocksd(machines)

	log.Println("Please CTRL-C to destroy droplets")

	// Catch CTRL-C and delete droplets.
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	<-c
	for _, m := range machines {
		if err := m.Destroy(client); err != nil {
			log.Println("Could not delete droplet name: %s\n", m.Name)
		} else {
			log.Println("Deleted droplet name: %s", m.Name)
		}
	}
}
<|endoftext|>