<commit_before>package main

import "encoding/json"
import "flag"
import "fmt"
import "os"
import "path/filepath"
import "sort"
import "strconv"
import "strings"
import "text/tabwriter"

import "github.com/appc/spec/schema"
import "github.com/appc/spec/schema/types"
import "github.com/juju/errors"

import "./jetpack"
import "./run"

var Host *jetpack.Host

func die(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, errors.ErrorStack(err))
		os.Exit(1)
	}
}

func show(obj ...interface{}) {
	die(Show("", obj...))
}

func subcommand(def string, args []string) (string, []string) {
	if len(args) == 0 {
		return def, args
	}
	return args[0], args[1:]
}

func image(name string) *jetpack.Image {
	img, err := Host.FindImage(name)
	if err == jetpack.ErrNotFound {
		die(errors.Errorf("No such image: %#v", name))
	}
	die(err)
	return img
}

func getRuntimeApp(name string) (*schema.RuntimeApp, error) {
	if img, err := Host.FindImage(name); err != nil {
		return nil, err
	} else {
		rta := img.RuntimeApp()
		return &rta, nil
	}
}

func main() {
	configPath := jetpack.DefaultConfigPath
	help := false

	if cfg := os.Getenv("JETPACK_CONF"); cfg != "" {
		configPath = cfg
	}

	flag.StringVar(&configPath, "config", configPath, "Configuration file")
	flag.BoolVar(&help, "h", false, "Show help")
	flag.BoolVar(&help, "help", false, "Show help")

	flag.Parse()
	args := flag.Args()

	if help || len(args) == 0 || args[0] == "help" {
		fmt.Fprintf(os.Stderr, `Usage: %s [OPTIONS] COMMAND...
Options:
  -config=PATH  Configuration file (%s)
  -help, -h     Display this help screen
Commands:
  help                                    Display this help screen
  init                                    Initialize host
  info                                    Show global information
  test                                    Run integration tests
  image list [QUERY]                      List images
  image import ARCHIVE [MANIFEST]         Import image from an archive
  image IMAGE build [OPTIONS] COMMAND...  Build new image from an existing one
                    -dir=.                Location on build directory on host
                    -cp=PATH...           Copy additional files from host
  image IMAGE show                        Display image details
  image IMAGE export [PATH]               Export image to an AMI file
                                          Output to stdout if no PATH given
  image IMAGE destroy                     Destroy image
  pod list                                List pods
  pod create [FLAGS] IMAGE [IMAGE FLAGS] [IMAGE [IMAGE FLAGS] ...]
                                          Create new pod from image
             -help                        Show detailed help
  pod POD show                            Display pod details
  pod POD run [APP]                       Run pod's application
  pod POD console [APP]                   Open console inside the pod
  pod POD ps|top|killall [OPTIONS...]
                                          Manage pod's processes
  pod POD kill                            Kill running pod
  pod POD destroy                         Destroy pod
Needs Explanation:
  ARCHIVE, MANIFEST  May be filesystem paths or URLs.
            cp=PATH  This option can be given multiple times
              QUERY  Is an expression that looks like this:
                      - NAME[,LABEL=VALUE[,LABEL=VALUE[,...]]]
                      - NAME:VERSION (alias for NAME:version=VERSION)
              IMAGE  Can be:
                      - an UUID (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX),
                      - a checksum (sha512-...), or
                      - a QUERY (which can't be ambiguous).
          POD  Has to be an UUID for now
Helpful Aliases:
  i|img ... -- image ...
  p ... -- pod ...
  image, images -- image list
  pod, pods -- pod list
  image build|show|export|destroy IMAGE ... -- image IMAGE build|show|... ...
`,
			filepath.Base(os.Args[0]), configPath)
		return
	}

	command := args[0]
	args = args[1:]

	if host, err := jetpack.NewHost(configPath); err != nil {
		die(err)
	} else {
		Host = host
	}

	if command == "init" {
		// Init is special: it doesn't need an initialized host
		die(Host.Initialize())
		show(Host)
		return
	}

	if Host.Dataset == nil {
		die(errors.New("Host is not initialized"))
	}

	switch command {
	case "info":
		show(Host)
	case "test":
		die(run.Command(filepath.Join(jetpack.LibexecPath, "test.integration"),
			append(args, "dataset="+Host.Dataset.Name)...).Run())
	case "images":
		command = "image"
		args = append([]string{"list"}, args...)
		fallthrough
	case "image", "img", "i":
		switch command, args := subcommand("list", args); command {
		case "import":
			var archive, manifest string
			switch len(args) {
			case 2:
				manifest = args[1]
				fallthrough
			case 1:
				archive = args[0]
			default:
				die(errors.New("Usage: import ARCHIVE_URI [MANIFEST_URI]"))
			}
			image, err := Host.ImportImage(archive, manifest)
			die(err)
			show(image)
		case "list":
			var machineFriendly, showHash bool
			fl := flag.NewFlagSet("image list", flag.ExitOnError)
			fl.BoolVar(&machineFriendly, "H", false, "Machine-friendly output")
			fl.BoolVar(&showHash, "hash", false, "Show image hash instead of UUID")
			fl.Parse(args)

			images := Host.Images()

			if len(images) == 0 {
				if !machineFriendly {
					show("No images")
				}
			} else {
				lines := make([]string, len(images))
				for i, img := range images {
					labels := make([]string, len(img.Manifest.Labels))
					for j, label := range img.Manifest.Labels {
						labels[j] = fmt.Sprintf("%v=%#v", label.Name, label.Value)
					}
					sort.Strings(labels)
					first := img.UUID.String()
					if showHash {
						first = img.Hash.String()
					}
					lines[i] = fmt.Sprintf("%v\t%v\t%v",
						first,
						img.Manifest.Name,
						strings.Join(labels, ","))
				}
				sort.Strings(lines)
				output := strings.Join(lines, "\n")

				if machineFriendly {
					fmt.Println(output)
				} else {
					first := "UUID"
					if showHash {
						first = "HASH"
					}
					w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', 0)
					fmt.Fprintf(w, "%v\tNAME\tLABELS\n%v\n", first, output)
					die(w.Flush())
				}
			}
		case "build", "show", "export", "destroy":
			// be nice to people who prefer to type UUID after command
			command, args[0] = args[0], command
			fallthrough
		default:
			img := image(command)

			switch command, args := subcommand("show", args); command {
			case "build":
				var copyFiles sliceFlag
				var buildDir string

				fs := flag.NewFlagSet("build", flag.ExitOnError)
				fs.Var(&copyFiles, "cp", "")
				fs.StringVar(&buildDir, "dir", ".", "")
				die(fs.Parse(args))

				newImage, err := img.Build(buildDir, copyFiles, fs.Args())
				die(err)
				show(newImage)
			case "show":
				show(img)
			case "export":
				path := "-"
				if len(args) > 0 {
					path = args[0]
				}
				if hash, err := img.SaveAMI(path, 0644); err != nil {
					die(err)
				} else {
					fmt.Fprintln(os.Stderr, hash)
				}
			case "destroy":
				die(img.Destroy())
			default:
				die(errors.Errorf("Unknown command %#v", command))
			}
		}
	case "pods":
		command = "pod"
		args = append([]string{"list"}, args...)
		fallthrough
	case "pod", "p":
		switch command, args := subcommand("list", args); command {
		case "create":
			var dryRun, doRun, doDestroy bool
			fl := flag.NewFlagSet("jetpack pod create", flag.ContinueOnError)
			fl.BoolVar(&dryRun, "n", false, "Dry run (don't actually create pod, just show manifest)")
			fl.BoolVar(&doRun, "run", false, "Run pod immediately")
			fl.BoolVar(&doDestroy, "destroy", false, "Destroy pod after running (meaningless without -run)")

			if pm, err := ConstructPod(args, fl, getRuntimeApp); err == flag.ErrHelp {
				// It's all right. Help has been shown.
			} else if err != nil {
				panic(err)
			} else if dryRun {
				if jb, err := json.MarshalIndent(pm, "", "  "); err != nil {
					panic(err)
				} else {
					fmt.Println(string(jb))
				}
			} else {
				pod, err := Host.CreatePod(pm)
				die(err)
				if doRun {
					if len(pod.Manifest.Apps) > 1 {
						die(errors.New("Pod has multiple apps, cannot run"))
					}
					die(pod.RunApp(pod.Manifest.Apps[0].Name))
				} else {
					show(pod)
				}
			}
		case "list":
			var machineFriendly bool
			fl := flag.NewFlagSet("pod list", flag.ExitOnError)
			fl.BoolVar(&machineFriendly, "H", false, "Machine-friendly output")
			fl.Parse(args)

			pods := Host.Pods()

			if len(pods) == 0 {
				if !machineFriendly {
					show("No pods")
				}
			} else {
				lines := make([]string, len(pods))
				for i, pod := range pods {
					apps := make([]string, len(pod.Manifest.Apps))
					for j, app := range pod.Manifest.Apps {
						apps[j] = app.Name.String()
					}
					ipAddress, _ := pod.Manifest.Annotations.Get("ip-address")
					lines[i] = fmt.Sprintf("%v\t%v\t%v\t%v",
						pod.UUID,
						pod.Status().String(),
						ipAddress,
						strings.Join(apps, " "))
				}
				sort.Strings(lines)
				output := strings.Join(lines, "\n")

				if machineFriendly {
					fmt.Println(output)
				} else {
					w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', 0)
					fmt.Fprintf(w, "UUID\tSTATUS\tIP\tAPPS\n%v\n", output)
					die(w.Flush())
				}
			}
		case "show", "run", "ps", "top", "killall", "kill", "destroy":
			// be nice to people who prefer to type UUID after command
			command, args[0] = args[0], command
			fallthrough
		default:
			pod, err := Host.FindPod(command)
			if err == jetpack.ErrNotFound {
				die(errors.Errorf("No such pod: %#v", command))
			}
			die(err)
			switch command, args := subcommand("show", args); command {
			case "show":
				show(pod)
			case "run":
				switch len(args) {
				case 0:
					if len(pod.Manifest.Apps) > 1 {
						die(errors.New("Pod has multiple apps, you need to specify one"))
					}
					die(pod.RunApp(pod.Manifest.Apps[0].Name))
				case 1:
					die(pod.RunApp(types.ACName(args[0])))
				default:
					die(errors.New("Command `run' takes at most one argument"))
				}
			case "console":
				switch len(args) {
				case 0:
					if len(pod.Manifest.Apps) > 1 {
						die(errors.New("Pod has multiple apps, you need to specify one"))
					}
					die(pod.Console(pod.Manifest.Apps[0].Name, "root"))
				case 1:
					die(pod.Console(types.ACName(args[0]), "root"))
				default:
					die(errors.New("Command `console' takes at most one argument"))
				}
			case "ps", "top", "killall":
				jid := pod.Jid()
				if jid == 0 {
					die(errors.New("Pod is not running"))
				}

				flag := "-J"
				if command == "killall" {
					flag = "-j"
				}

				die(run.Command(command, append([]string{flag, strconv.Itoa(jid)}, args...)...).Run())
			case "kill":
				die(pod.Kill())
			case "destroy":
				die(pod.Destroy())
			default:
				die(errors.Errorf("Unknown command %#v", command))
			}
		}
	default:
		die(errors.Errorf("Unknown command %#v", command))
	}
}
<commit_msg>Add `-q` option to `jetpack pod list` & `jetpack image list`<commit_after>package main

import "encoding/json"
import "flag"
import "fmt"
import "os"
import "path/filepath"
import "sort"
import "strconv"
import "strings"
import "text/tabwriter"

import "github.com/appc/spec/schema"
import "github.com/appc/spec/schema/types"
import "github.com/juju/errors"

import "./jetpack"
import "./run"

var Host *jetpack.Host

func die(err error) {
	if err != nil {
		fmt.Fprintln(os.Stderr, errors.ErrorStack(err))
		os.Exit(1)
	}
}

func show(obj ...interface{}) {
	die(Show("", obj...))
}

func subcommand(def string, args []string) (string, []string) {
	if len(args) == 0 {
		return def, args
	}
	return args[0], args[1:]
}

func image(name string) *jetpack.Image {
	img, err := Host.FindImage(name)
	if err == jetpack.ErrNotFound {
		die(errors.Errorf("No such image: %#v", name))
	}
	die(err)
	return img
}

func getRuntimeApp(name string) (*schema.RuntimeApp, error) {
	if img, err := Host.FindImage(name); err != nil {
		return nil, err
	} else {
		rta := img.RuntimeApp()
		return &rta, nil
	}
}

func main() {
	configPath := jetpack.DefaultConfigPath
	help := false

	if cfg := os.Getenv("JETPACK_CONF"); cfg != "" {
		configPath = cfg
	}

	flag.StringVar(&configPath, "config", configPath, "Configuration file")
	flag.BoolVar(&help, "h", false, "Show help")
	flag.BoolVar(&help, "help", false, "Show help")

	flag.Parse()
	args := flag.Args()

	if help || len(args) == 0 || args[0] == "help" {
		fmt.Fprintf(os.Stderr, `Usage: %s [OPTIONS] COMMAND...
Options:
  -config=PATH  Configuration file (%s)
  -help, -h     Display this help screen
Commands:
  help                                    Display this help screen
  init                                    Initialize host
  info                                    Show global information
  test                                    Run integration tests
  image list [QUERY]                      List images
  image import ARCHIVE [MANIFEST]         Import image from an archive
  image IMAGE build [OPTIONS] COMMAND...  Build new image from an existing one
                    -dir=.                Location on build directory on host
                    -cp=PATH...           Copy additional files from host
  image IMAGE show                        Display image details
  image IMAGE export [PATH]               Export image to an AMI file
                                          Output to stdout if no PATH given
  image IMAGE destroy                     Destroy image
  pod list                                List pods
  pod create [FLAGS] IMAGE [IMAGE FLAGS] [IMAGE [IMAGE FLAGS] ...]
                                          Create new pod from image
             -help                        Show detailed help
  pod POD show                            Display pod details
  pod POD run [APP]                       Run pod's application
  pod POD console [APP]                   Open console inside the pod
  pod POD ps|top|killall [OPTIONS...]
                                          Manage pod's processes
  pod POD kill                            Kill running pod
  pod POD destroy                         Destroy pod
Needs Explanation:
  ARCHIVE, MANIFEST  May be filesystem paths or URLs.
            cp=PATH  This option can be given multiple times
              QUERY  Is an expression that looks like this:
                      - NAME[,LABEL=VALUE[,LABEL=VALUE[,...]]]
                      - NAME:VERSION (alias for NAME:version=VERSION)
              IMAGE  Can be:
                      - an UUID (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX),
                      - a checksum (sha512-...), or
                      - a QUERY (which can't be ambiguous).
          POD  Has to be an UUID for now
Helpful Aliases:
  i|img ... -- image ...
  p ... -- pod ...
  image, images -- image list
  pod, pods -- pod list
  image build|show|export|destroy IMAGE ... -- image IMAGE build|show|... ...
`,
			filepath.Base(os.Args[0]), configPath)
		return
	}

	command := args[0]
	args = args[1:]

	if host, err := jetpack.NewHost(configPath); err != nil {
		die(err)
	} else {
		Host = host
	}

	if command == "init" {
		// Init is special: it doesn't need an initialized host
		die(Host.Initialize())
		show(Host)
		return
	}

	if Host.Dataset == nil {
		die(errors.New("Host is not initialized"))
	}

	switch command {
	case "info":
		show(Host)
	case "test":
		die(run.Command(filepath.Join(jetpack.LibexecPath, "test.integration"),
			append(args, "dataset="+Host.Dataset.Name)...).Run())
	case "images":
		command = "image"
		args = append([]string{"list"}, args...)
		fallthrough
	case "image", "img", "i":
		switch command, args := subcommand("list", args); command {
		case "import":
			var archive, manifest string
			switch len(args) {
			case 2:
				manifest = args[1]
				fallthrough
			case 1:
				archive = args[0]
			default:
				die(errors.New("Usage: import ARCHIVE_URI [MANIFEST_URI]"))
			}
			image, err := Host.ImportImage(archive, manifest)
			die(err)
			show(image)
		case "list":
			var machineFriendly, showHash, idOnly bool
			fl := flag.NewFlagSet("image list", flag.ExitOnError)
			fl.BoolVar(&machineFriendly, "H", false, "Machine-friendly output")
			fl.BoolVar(&showHash, "hash", false, "Show image hash instead of UUID")
			fl.BoolVar(&idOnly, "q", false, "Show only ID")
			fl.Parse(args)

			images := Host.Images()

			if idOnly {
				for _, img := range images {
					if showHash {
						fmt.Println(img.Hash)
					} else {
						fmt.Println(img.UUID)
					}
				}
			} else if len(images) == 0 {
				if !machineFriendly {
					show("No images")
				}
			} else {
				lines := make([]string, len(images))
				for i, img := range images {
					labels := make([]string, len(img.Manifest.Labels))
					for j, label := range img.Manifest.Labels {
						labels[j] = fmt.Sprintf("%v=%#v", label.Name, label.Value)
					}
					sort.Strings(labels)
					first := img.UUID.String()
					if showHash {
						first = img.Hash.String()
					}
					lines[i] = fmt.Sprintf("%v\t%v\t%v",
						first,
						img.Manifest.Name,
						strings.Join(labels, ","))
				}
				sort.Strings(lines)
				output := strings.Join(lines, "\n")

				if machineFriendly {
					fmt.Println(output)
				} else {
					first := "UUID"
					if showHash {
						first = "HASH"
					}
					w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', 0)
					fmt.Fprintf(w, "%v\tNAME\tLABELS\n%v\n", first, output)
					die(w.Flush())
				}
			}
		case "build", "show", "export", "destroy":
			// be nice to people who prefer to type UUID after command
			command, args[0] = args[0], command
			fallthrough
		default:
			img := image(command)

			switch command, args := subcommand("show", args); command {
			case "build":
				var copyFiles sliceFlag
				var buildDir string

				fs := flag.NewFlagSet("build", flag.ExitOnError)
				fs.Var(&copyFiles, "cp", "")
				fs.StringVar(&buildDir, "dir", ".", "")
				die(fs.Parse(args))

				newImage, err := img.Build(buildDir, copyFiles, fs.Args())
				die(err)
				show(newImage)
			case "show":
				show(img)
			case "export":
				path := "-"
				if len(args) > 0 {
					path = args[0]
				}
				if hash, err := img.SaveAMI(path, 0644); err != nil {
					die(err)
				} else {
					fmt.Fprintln(os.Stderr, hash)
				}
			case "destroy":
				die(img.Destroy())
			default:
				die(errors.Errorf("Unknown command %#v", command))
			}
		}
	case "pods":
		command = "pod"
		args = append([]string{"list"}, args...)
		fallthrough
	case "pod", "p":
		switch command, args := subcommand("list", args); command {
		case "create":
			var dryRun, doRun, doDestroy bool
			fl := flag.NewFlagSet("jetpack pod create", flag.ContinueOnError)
			fl.BoolVar(&dryRun, "n", false, "Dry run (don't actually create pod, just show manifest)")
			fl.BoolVar(&doRun, "run", false, "Run pod immediately")
			fl.BoolVar(&doDestroy, "destroy", false, "Destroy pod after running (meaningless without -run)")

			if pm, err := ConstructPod(args, fl, getRuntimeApp); err == flag.ErrHelp {
				// It's all right. Help has been shown.
			} else if err != nil {
				panic(err)
			} else if dryRun {
				if jb, err := json.MarshalIndent(pm, "", "  "); err != nil {
					panic(err)
				} else {
					fmt.Println(string(jb))
				}
			} else {
				pod, err := Host.CreatePod(pm)
				die(err)
				if doRun {
					if len(pod.Manifest.Apps) > 1 {
						die(errors.New("Pod has multiple apps, cannot run"))
					}
					die(pod.RunApp(pod.Manifest.Apps[0].Name))
				} else {
					show(pod)
				}
			}
		case "list":
			var machineFriendly, idOnly bool
			fl := flag.NewFlagSet("pod list", flag.ExitOnError)
			fl.BoolVar(&machineFriendly, "H", false, "Machine-friendly output")
			fl.BoolVar(&idOnly, "q", false, "Show only ID")
			fl.Parse(args)

			pods := Host.Pods()

			if idOnly {
				for _, pod := range pods {
					fmt.Println(pod.UUID)
				}
			} else if len(pods) == 0 {
				if !machineFriendly {
					show("No pods")
				}
			} else {
				lines := make([]string, len(pods))
				for i, pod := range pods {
					apps := make([]string, len(pod.Manifest.Apps))
					for j, app := range pod.Manifest.Apps {
						apps[j] = app.Name.String()
					}
					ipAddress, _ := pod.Manifest.Annotations.Get("ip-address")
					lines[i] = fmt.Sprintf("%v\t%v\t%v\t%v",
						pod.UUID,
						pod.Status().String(),
						ipAddress,
						strings.Join(apps, " "))
				}
				sort.Strings(lines)
				output := strings.Join(lines, "\n")

				if machineFriendly {
					fmt.Println(output)
				} else {
					w := tabwriter.NewWriter(os.Stdout, 2, 8, 2, ' ', 0)
					fmt.Fprintf(w, "UUID\tSTATUS\tIP\tAPPS\n%v\n", output)
					die(w.Flush())
				}
			}
		case "show", "run", "ps", "top", "killall", "kill", "destroy":
			// be nice to people who prefer to type UUID after command
			command, args[0] = args[0], command
			fallthrough
		default:
			pod, err := Host.FindPod(command)
			if err == jetpack.ErrNotFound {
				die(errors.Errorf("No such pod: %#v", command))
			}
			die(err)
			switch command, args := subcommand("show", args); command {
			case "show":
				show(pod)
			case "run":
				switch len(args) {
				case 0:
					if len(pod.Manifest.Apps) > 1 {
						die(errors.New("Pod has multiple apps, you need to specify one"))
					}
					die(pod.RunApp(pod.Manifest.Apps[0].Name))
				case 1:
					die(pod.RunApp(types.ACName(args[0])))
				default:
					die(errors.New("Command `run' takes at most one argument"))
				}
			case "console":
				switch len(args) {
				case 0:
					if len(pod.Manifest.Apps) > 1 {
						die(errors.New("Pod has multiple apps, you need to specify one"))
					}
					die(pod.Console(pod.Manifest.Apps[0].Name, "root"))
				case 1:
					die(pod.Console(types.ACName(args[0]), "root"))
				default:
					die(errors.New("Command `console' takes at most one argument"))
				}
			case "ps", "top", "killall":
				jid := pod.Jid()
				if jid == 0 {
					die(errors.New("Pod is not running"))
				}

				flag := "-J"
				if command == "killall" {
					flag = "-j"
				}

				die(run.Command(command, append([]string{flag, strconv.Itoa(jid)}, args...)...).Run())
			case "kill":
				die(pod.Kill())
			case "destroy":
				die(pod.Destroy())
			default:
				die(errors.Errorf("Unknown command %#v", command))
			}
		}
	default:
		die(errors.Errorf("Unknown command %#v", command))
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Prometheus Authors
// 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.

// A minimal example of how to include Prometheus instrumentation.
package main

import (
	"flag"
	"net/http"
	"os/exec"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"bytes"
	"encoding/xml"
	"io/ioutil"
	"time"
	"github.com/prometheus/common/log"
	"strconv"
)

type CliOutput struct {
	XMLName xml.Name  `xml:"cliOutput"`
	OpRet int         `xml:"opRet"`
	OpErrno int       `xml:"opErrno"`
	OpErrstr string   `xml:"opErrstr"`
	VolInfo VolInfo   `xml:"volInfo"`
}

type VolInfo struct {
	XMLName xml.Name  `xml:"volInfo"`
	Volumes Volumes   `xml:"volumes"`
}

type Volumes struct {
	XMLName xml.Name  `xml:"volumes"`
	Volume []Volume   `xml:"volume"`
	Count int         `xml:"count"`
}

type Volume struct {
	XMLName xml.Name  `xml:"volume"`
	Name string       `xml:"name"`
	Id string         `xml:"id"`
	Status int        `xml:"status"`
	StatusStr string  `xml:"statusStr"`
	BrickCount int    `xml:"brickCount"`
	Bricks []Brick    `xml:"bricks"`
	DistCount int     `xml:"distCount"`
}

type Brick struct {
	Uuid string       `xml:"brick>uuid"`
	Name string       `xml:"brick>name"`
	HostUuid string   `xml:"brick>hostUuid"`
	IsArbiter int     `xml:"brick>isArbiter"`
}

var (
	// Error number from GlusterFS
	errno = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name:"glusterfs_errno",
			Help:"Error Number Glusterfs",
		},
		[]string{},
	)

	// creates a gauge of active nodes in glusterfs
	volume_count = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name:"glusterfs_volume_count",
			Help:"Number of active glusterfs nodes",
		},
		[]string{},
	)

	// Count of bricks for gluster volume
	brick_count = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name:"glusterfs_brick_count",
			Help:"Count of bricks for gluster volume",
		},
		[]string{"volume"},
	)

	// distribution count of bricks
	distribution_count = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name:"glusterfs_nodes_active",
			Help:"distribution count of bricks",
		},
		[]string{"volume"},
	)
)

func init() {
	// register metric to prometheus's default registry
	prometheus.MustRegister(errno)
	prometheus.MustRegister(volume_count)
	prometheus.MustRegister(brick_count)
	prometheus.MustRegister(distribution_count)
}

func glusterVolumeInfo(sec_int int) {
	for {
		// Gluster Info
		cmd_profile := exec.Command("/usr/sbin/gluster", "volume", "info", "--xml")
		//cmd_profile := exec.Command("/home/oli/dev/glusterfs_exporter_go/gluster_info")

		stdOutbuff := &bytes.Buffer{}

		cmd_profile.Stdout = stdOutbuff

		err := cmd_profile.Run()

		if err != nil {
			log.Fatal(err)
		}

		var vol CliOutput
		b, err := ioutil.ReadAll(stdOutbuff)
		if err != nil {
			log.Fatal(err)
		}
		xml.Unmarshal(b, &vol)

		// set opErrno
		errno.WithLabelValues().Set(float64(vol.OpErrno))
		log.Debug("opErrno: %v", vol.OpErrno)

		// set volume count
		volume_count.WithLabelValues().Set(float64(vol.VolInfo.Volumes.Count))
		log.Debug("volume_count: %v", vol.VolInfo.Volumes.Count)

		// Volume based values
		for _, v := range vol.VolInfo.Volumes.Volume {
			// brick count with volume label
			brick_count.WithLabelValues(v.Name).Set(float64(v.BrickCount))
			log.Debug("opErrno: %v", vol.OpErrno)

			// distribution count with volume label
			distribution_count.WithLabelValues(v.Name).Set(float64(v.DistCount))
			log.Debug("opErrno: %v", vol.OpErrno)

		}
		time.Sleep(time.Duration(sec_int) * time.Second)
	}
}

func glusterProfile(sec_int int) {
	// Gluster Profile

	// Get gluster volumes, then call gluster profile on every volume

	//  gluster volume profile gv_leoticket info cumulative --xml
	//cmd_profile := exec.Command("/usr/sbin/gluster", "volume", "profile", "gv_leoticket", "info", "cumulative", "--xml")
}

func main() {

	// commandline arguments
	var (
		addr = flag.String("listen-address", ":9189",  "The address to listen on for HTTP requests.")
		sec  = flag.String("scrape-seconds", "2",      "Frequency of scraping glusterfs in seconds")
	)

	flag.Parse()

	// ensure that sec is int
	sec_int, err := strconv.Atoi(*sec)
	if err != nil {
		log.Fatal("Parameter -scrape-seconds is not an int value")
	}

	// gluster volume info
	go glusterVolumeInfo(sec_int)

	http.Handle("/metrics", promhttp.Handler())
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<commit_msg>changed licence information<commit_after>// Copyright 2015 Oliver Fesseler
// 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.

// Glusterfs exorter currently scaping volume info
package main

import (
	"flag"
	"net/http"
	"os/exec"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"bytes"
	"encoding/xml"
	"io/ioutil"
	"time"
	"github.com/prometheus/common/log"
	"strconv"
)

type CliOutput struct {
	XMLName xml.Name  `xml:"cliOutput"`
	OpRet int         `xml:"opRet"`
	OpErrno int       `xml:"opErrno"`
	OpErrstr string   `xml:"opErrstr"`
	VolInfo VolInfo   `xml:"volInfo"`
}

type VolInfo struct {
	XMLName xml.Name  `xml:"volInfo"`
	Volumes Volumes   `xml:"volumes"`
}

type Volumes struct {
	XMLName xml.Name  `xml:"volumes"`
	Volume []Volume   `xml:"volume"`
	Count int         `xml:"count"`
}

type Volume struct {
	XMLName xml.Name  `xml:"volume"`
	Name string       `xml:"name"`
	Id string         `xml:"id"`
	Status int        `xml:"status"`
	StatusStr string  `xml:"statusStr"`
	BrickCount int    `xml:"brickCount"`
	Bricks []Brick    `xml:"bricks"`
	DistCount int     `xml:"distCount"`
}

type Brick struct {
	Uuid string       `xml:"brick>uuid"`
	Name string       `xml:"brick>name"`
	HostUuid string   `xml:"brick>hostUuid"`
	IsArbiter int     `xml:"brick>isArbiter"`
}

var (
	// Error number from GlusterFS
	errno = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name:"glusterfs_errno",
			Help:"Error Number Glusterfs",
		},
		[]string{},
	)

	// creates a gauge of active nodes in glusterfs
	volume_count = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name:"glusterfs_volume_count",
			Help:"Number of active glusterfs nodes",
		},
		[]string{},
	)

	// Count of bricks for gluster volume
	brick_count = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name:"glusterfs_brick_count",
			Help:"Count of bricks for gluster volume",
		},
		[]string{"volume"},
	)

	// distribution count of bricks
	distribution_count = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Name:"glusterfs_nodes_active",
			Help:"distribution count of bricks",
		},
		[]string{"volume"},
	)
)

func init() {
	// register metric to prometheus's default registry
	prometheus.MustRegister(errno)
	prometheus.MustRegister(volume_count)
	prometheus.MustRegister(brick_count)
	prometheus.MustRegister(distribution_count)
}

func glusterVolumeInfo(sec_int int) {
	for {
		// Gluster Info
		cmd_profile := exec.Command("/usr/sbin/gluster", "volume", "info", "--xml")
		//cmd_profile := exec.Command("/home/oli/dev/glusterfs_exporter_go/gluster_info")

		stdOutbuff := &bytes.Buffer{}

		cmd_profile.Stdout = stdOutbuff

		err := cmd_profile.Run()

		if err != nil {
			log.Fatal(err)
		}

		var vol CliOutput
		b, err := ioutil.ReadAll(stdOutbuff)
		if err != nil {
			log.Fatal(err)
		}
		xml.Unmarshal(b, &vol)

		// set opErrno
		errno.WithLabelValues().Set(float64(vol.OpErrno))
		log.Debug("opErrno: %v", vol.OpErrno)

		// set volume count
		volume_count.WithLabelValues().Set(float64(vol.VolInfo.Volumes.Count))
		log.Debug("volume_count: %v", vol.VolInfo.Volumes.Count)

		// Volume based values
		for _, v := range vol.VolInfo.Volumes.Volume {
			// brick count with volume label
			brick_count.WithLabelValues(v.Name).Set(float64(v.BrickCount))
			log.Debug("opErrno: %v", vol.OpErrno)

			// distribution count with volume label
			distribution_count.WithLabelValues(v.Name).Set(float64(v.DistCount))
			log.Debug("opErrno: %v", vol.OpErrno)

		}
		time.Sleep(time.Duration(sec_int) * time.Second)
	}
}

func glusterProfile(sec_int int) {
	// Gluster Profile

	// Get gluster volumes, then call gluster profile on every volume

	//  gluster volume profile gv_leoticket info cumulative --xml
	//cmd_profile := exec.Command("/usr/sbin/gluster", "volume", "profile", "gv_leoticket", "info", "cumulative", "--xml")
}

func main() {

	// commandline arguments
	var (
		addr = flag.String("listen-address", ":9189",  "The address to listen on for HTTP requests.")
		sec  = flag.String("scrape-seconds", "2",      "Frequency of scraping glusterfs in seconds")
	)

	flag.Parse()

	// ensure that sec is int
	sec_int, err := strconv.Atoi(*sec)
	if err != nil {
		log.Fatal("Parameter -scrape-seconds is not an int value")
	}

	// gluster volume info
	go glusterVolumeInfo(sec_int)

	http.Handle("/metrics", promhttp.Handler())
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-chi/chi"
	"github.com/gorilla/handlers"
	"github.com/unrolled/secure"
	"gopkg.in/reportportal/commons-go.v1/commons"
	"gopkg.in/reportportal/commons-go.v1/conf"
	"gopkg.in/reportportal/commons-go.v1/server"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

func main() {

	currDir, e := os.Getwd()
	if nil != e {
		log.Fatalf("Cannot get workdir: %s", e.Error())
	}

	rpConf := struct {
		Cfg         *conf.RpConfig
		StaticsPath string `env:"RP_STATICS_PATH"`
	}{
		Cfg:         conf.EmptyConfig(),
		StaticsPath: currDir,
	}

	err := conf.LoadConfig(&rpConf)
	if nil != err {
		log.Fatalf("Cannot log app config")
	}

	rpConf.Cfg.AppName = "ui"

	info := commons.GetBuildInfo()
	info.Name = "Service UI"

	srv := server.New(rpConf.Cfg, info)
	srv.WithRouter(func(router *chi.Mux) {

		//apply compression
		router.Use(func(next http.Handler) http.Handler {
			return handlers.CompressHandler(next)
		})

		//content security policy
		csp := map[string][]string{
			"default-src": {"'self'", "'unsafe-inline'"},
			"script-src": {
				"'self'",
				"'unsafe-inline'",
				"'unsafe-eval'",
				"status.reportportal.io",
				"www.google-analytics.com",
				"*.uservoice.com",
			},
			"img-src":    {"'self'", "www.google-analytics.com"},
			"object-src": {"'self'"},
		}

		//apply content security policies
		router.Use(func(next http.Handler) http.Handler {
			return secure.New(secure.Options{
				FrameDeny:             true,
				ContentTypeNosniff:    true,
				BrowserXssFilter:      true,
				ContentSecurityPolicy: buildCSP(csp),
			}).Handler(next)
		})

		err := os.Chdir(rpConf.StaticsPath)
		if nil != err {
			log.Fatalf("Dir %s not found", rpConf.StaticsPath)
		}

		router.Handle("/*", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			//trim query params
			ext := filepath.Ext(trimQuery(r.URL.String(), "?"))

			// never cache html
			if "/" == r.URL.String() || ".html" == ext {
				w.Header().Add("Cache-Control", "no-cache")
			}

			http.FileServer(http.Dir(rpConf.StaticsPath)).ServeHTTP(&redirectingRW{ResponseWriter: w, Request: r}, r)
		}))

	})

	srv.StartServer()

}

func trimQuery(s string, sep string) string {
	sepIndex := strings.Index(s, sep)
	if -1 != sepIndex {
		return s[:sepIndex]
	}
	return s
}

func buildCSP(csp map[string][]string) string {
	instr := make([]string, len(csp))
	for k, v := range csp {
		instr = append(instr, k+" "+strings.Join(v, " "))
	}
	return strings.Join(instr, "; ")

}

type redirectingRW struct {
	*http.Request
	http.ResponseWriter
	ignore bool
}

func (hrw *redirectingRW) Header() http.Header {
	return hrw.ResponseWriter.Header()
}

func (hrw *redirectingRW) WriteHeader(status int) {
	if status == 404 {
		hrw.ignore = true
		http.Redirect(hrw.ResponseWriter, hrw.Request, "/ui/404.html", http.StatusTemporaryRedirect)
	} else {
		hrw.ResponseWriter.WriteHeader(status)
	}

}

func (hrw *redirectingRW) Write(p []byte) (int, error) {
	if hrw.ignore {
		return len(p), nil
	}
	return hrw.ResponseWriter.Write(p)
}
<commit_msg>accept epam domain in csp policy<commit_after>package main

import (
	"github.com/go-chi/chi"
	"github.com/gorilla/handlers"
	"github.com/unrolled/secure"
	"gopkg.in/reportportal/commons-go.v1/commons"
	"gopkg.in/reportportal/commons-go.v1/conf"
	"gopkg.in/reportportal/commons-go.v1/server"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

func main() {

	currDir, e := os.Getwd()
	if nil != e {
		log.Fatalf("Cannot get workdir: %s", e.Error())
	}

	rpConf := struct {
		Cfg         *conf.RpConfig
		StaticsPath string `env:"RP_STATICS_PATH"`
	}{
		Cfg:         conf.EmptyConfig(),
		StaticsPath: currDir,
	}

	err := conf.LoadConfig(&rpConf)
	if nil != err {
		log.Fatalf("Cannot log app config")
	}

	rpConf.Cfg.AppName = "ui"

	info := commons.GetBuildInfo()
	info.Name = "Service UI"

	srv := server.New(rpConf.Cfg, info)
	srv.WithRouter(func(router *chi.Mux) {

		//apply compression
		router.Use(func(next http.Handler) http.Handler {
			return handlers.CompressHandler(next)
		})

		//content security policy
		csp := map[string][]string{
			"default-src": {"'self'", "'unsafe-inline'"},
			"script-src": {
				"'self'",
				"'unsafe-inline'",
				"'unsafe-eval'",
				"status.reportportal.io",
				"www.google-analytics.com",
				"*.epam.com",
				"*.uservoice.com",
			},
			"img-src":    {"'self'", "www.google-analytics.com"},
			"object-src": {"'self'"},
		}

		//apply content security policies
		router.Use(func(next http.Handler) http.Handler {
			return secure.New(secure.Options{
				FrameDeny:             true,
				ContentTypeNosniff:    true,
				BrowserXssFilter:      true,
				ContentSecurityPolicy: buildCSP(csp),
			}).Handler(next)
		})

		err := os.Chdir(rpConf.StaticsPath)
		if nil != err {
			log.Fatalf("Dir %s not found", rpConf.StaticsPath)
		}

		router.Handle("/*", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			//trim query params
			ext := filepath.Ext(trimQuery(r.URL.String(), "?"))

			// never cache html
			if "/" == r.URL.String() || ".html" == ext {
				w.Header().Add("Cache-Control", "no-cache")
			}

			http.FileServer(http.Dir(rpConf.StaticsPath)).ServeHTTP(&redirectingRW{ResponseWriter: w, Request: r}, r)
		}))

	})

	srv.StartServer()

}

func trimQuery(s string, sep string) string {
	sepIndex := strings.Index(s, sep)
	if -1 != sepIndex {
		return s[:sepIndex]
	}
	return s
}

func buildCSP(csp map[string][]string) string {
	instr := make([]string, len(csp))
	for k, v := range csp {
		instr = append(instr, k+" "+strings.Join(v, " "))
	}
	return strings.Join(instr, "; ")

}

type redirectingRW struct {
	*http.Request
	http.ResponseWriter
	ignore bool
}

func (hrw *redirectingRW) Header() http.Header {
	return hrw.ResponseWriter.Header()
}

func (hrw *redirectingRW) WriteHeader(status int) {
	if status == 404 {
		hrw.ignore = true
		http.Redirect(hrw.ResponseWriter, hrw.Request, "/ui/404.html", http.StatusTemporaryRedirect)
	} else {
		hrw.ResponseWriter.WriteHeader(status)
	}

}

func (hrw *redirectingRW) Write(p []byte) (int, error) {
	if hrw.ignore {
		return len(p), nil
	}
	return hrw.ResponseWriter.Write(p)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	nurl "net/url"
	"os"
	"strconv"
	"strings"
	// "reflect"

	"github.com/codegangsta/martini"
	"github.com/donovanhide/eventsource"
	"github.com/monnand/goredis"
)

type Message struct {
	Idx           string
	Channel, Html string
}

func (c *Message) Id() string    { return c.Idx }
func (c *Message) Event() string { return c.Channel }
func (c *Message) Data() string {
	return c.Html
}

type Connection struct {
	token   string
	channel string
}

type Hub struct {
	Data       map[string][]string // Key is the channel, value is a slice of token
	Users      map[string]string   // Key is the token, value is a channel
	register   chan Connection
	unregister chan string
	messages   chan goredis.Message
	srv        *eventsource.Server
	client     goredis.Client
}

func (h *Hub) userExists(token string) bool {
	_, ok := h.Users[token]
	return ok
}

func (h *Hub) run() {
	fmt.Println("Start the Hub")
	var payload [3]string
	psub := make(chan string, 0)
	go h.client.Subscribe(nil, nil, psub, nil, h.messages)

	// Listening to all channel updates
	psub <- "channel_update:*"

	for {
		select {
		case conn := <-h.register:
			fmt.Println("register user: ", conn.token)
			// TODO try to get the channel
			h.Users[conn.token] = conn.channel
			//fmt.Println("[DEBUG] After h.Users assignment", h.Users[conn.token])
			h.Data[conn.channel] = append(h.Data[conn.channel], conn.token)
			//fmt.Println("[DEBUG] After h.Data assignment", h.Data[conn.channel])

		case token := <-h.unregister:
			fmt.Println("unregister user: ", token)
			ch, ok := h.Users[token]
			if ok {
				delete(h.Users, token)
				delete(h.Data, ch)
			}

		case msg := <-h.messages:
			err := json.Unmarshal(msg.Message, &payload)
			if err != nil {
				fmt.Println("[Error] An error occured while Unmarshalling the msg: ", msg)
			}
			message := &Message{
				Idx:     payload[2],
				Channel: payload[0],
				Html:    payload[1],
			}
			val, ok := h.Data[msg.Channel]
			if ok && len(val) >= 1 {
				fmt.Println("[DEBUG] msg sent to tokens", val)
				h.srv.Publish(val, message)
			}
		}
	}
}

func NewHub() *Hub {
	redisUrlString := os.Getenv("REDIS_SSEQUEUE_URL")
	if redisUrlString == "" {
		redisUrlString = "redis://localhost:6379/2"
	}
	redisUrl, err := nurl.Parse(redisUrlString)
	if err != nil {
		log.Fatal("Could not read Redis string", err)
	}

	redis_db, err := strconv.Atoi(strings.TrimLeft(redisUrl.Path, "/"))
	if err != nil {
		log.Fatal("Could not read Redis path", err)
	}

	server := eventsource.NewServer()
	server.AllowCORS = true

	h := Hub{
		Data:       make(map[string][]string),
		Users:      make(map[string]string),
		register:   make(chan Connection, 0),
		unregister: make(chan string, 0),
		messages:   make(chan goredis.Message, 0),
		srv:        server,
		client:     goredis.Client{Addr: redisUrl.Host, Db: redis_db},
	}
	// We use the second redis database for the pub/sub
	//h.client.Db = 2
	return &h
}

func main() {
	h := NewHub()
	go h.run()

	m := martini.Classic()

	// eventsource endpoints
	m.Get("/push/:token", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		token := params["token"]

		if h.userExists(token) {
			// TODO proper resonse
			fmt.Fprintf(w, "Not allowed -- User already connected")
		} else {
			fmt.Println("Exchange token against the channel")
			ch, err := h.client.Getset(token, []byte{})
			if err != nil {
				fmt.Fprintf(w, "Not allowed -- Error occured while exchanging the token")
			} else {
				h.register <- Connection{token, string(ch)}
				defer func(u string) {
					h.unregister <- u
				}(token)
				h.srv.Handler(token)(w, req)
			}
		}
	})

	sseString := os.Getenv("SSE_ENDPOINT_URL")
	if sseString == "" {
		log.Fatal("SSE_URL is not set, example: SSE_URL=http://localhost:3000/")
	}
	sseUrl, err := nurl.Parse(sseString)
	if err != nil {
		log.Fatal("Could not read SSE string", err)
	}

	log.Println("listening on " + sseUrl.Host)
	log.Fatalln(http.ListenAndServe(sseUrl.Host, m))
}
<commit_msg>linting of the file.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	nurl "net/url"
	"os"
	"strconv"
	"strings"
	// "reflect"

	"github.com/codegangsta/martini"
	"github.com/donovanhide/eventsource"
	"github.com/monnand/goredis"
)

// Message is the bit of information that is transfered via eventsource
type Message struct {
	Idx           string
	Channel, Html string
}

// Id is required to implement the eventsource.Event interface
func (c *Message) Id() string { return c.Idx }

// Event is required to implement the eventsource.Event interface
func (c *Message) Event() string { return c.Channel }

// Data is required to implement the eventsource.Event interface
func (c *Message) Data() string {
	return c.Html
}

// Connection is use to relate a user token to a channel
type Connection struct {
	token   string
	channel string
}

// Hub maintains the states
type Hub struct {
	Data       map[string][]string // Key is the channel, value is a slice of token
	Users      map[string]string   // Key is the token, value is a channel
	register   chan Connection
	unregister chan string
	messages   chan goredis.Message
	srv        *eventsource.Server
	client     goredis.Client
}

func (h *Hub) userExists(token string) bool {
	_, ok := h.Users[token]
	return ok
}

func (h *Hub) run() {
	fmt.Println("Start the Hub")
	var payload [3]string
	psub := make(chan string, 0)
	go h.client.Subscribe(nil, nil, psub, nil, h.messages)

	// Listening to all channel updates
	psub <- "channel_update:*"

	for {
		select {
		case conn := <-h.register:
			fmt.Println("register user: ", conn.token)
			// TODO try to get the channel
			h.Users[conn.token] = conn.channel
			//fmt.Println("[DEBUG] After h.Users assignment", h.Users[conn.token])
			h.Data[conn.channel] = append(h.Data[conn.channel], conn.token)
			//fmt.Println("[DEBUG] After h.Data assignment", h.Data[conn.channel])

		case token := <-h.unregister:
			fmt.Println("unregister user: ", token)
			ch, ok := h.Users[token]
			if ok {
				delete(h.Users, token)
				delete(h.Data, ch)
			}

		case msg := <-h.messages:
			err := json.Unmarshal(msg.Message, &payload)
			if err != nil {
				fmt.Println("[Error] An error occured while Unmarshalling the msg: ", msg)
			}
			message := &Message{
				Idx:     payload[2],
				Channel: payload[0],
				Html:    payload[1],
			}
			val, ok := h.Data[msg.Channel]
			if ok && len(val) >= 1 {
				fmt.Println("[DEBUG] msg sent to tokens", val)
				h.srv.Publish(val, message)
			}
		}
	}
}

// NewHub a pointer to an initialized Hub
func NewHub() *Hub {
	redisUrlString := os.Getenv("REDIS_SSEQUEUE_URL")
	if redisUrlString == "" {
		redisUrlString = "redis://localhost:6379/2"
	}
	redisUrl, err := nurl.Parse(redisUrlString)
	if err != nil {
		log.Fatal("Could not read Redis string", err)
	}

	redisDb, err := strconv.Atoi(strings.TrimLeft(redisUrl.Path, "/"))
	if err != nil {
		log.Fatal("Could not read Redis path", err)
	}

	server := eventsource.NewServer()
	server.AllowCORS = true

	h := Hub{
		Data:       make(map[string][]string),
		Users:      make(map[string]string),
		register:   make(chan Connection, 0),
		unregister: make(chan string, 0),
		messages:   make(chan goredis.Message, 0),
		srv:        server,
		client:     goredis.Client{Addr: redisUrl.Host, Db: redisDb},
	}
	// We use the second redis database for the pub/sub
	//h.client.Db = 2
	return &h
}

func main() {
	h := NewHub()
	go h.run()

	m := martini.Classic()

	// eventsource endpoints
	m.Get("/push/:token", func(w http.ResponseWriter, req *http.Request, params martini.Params) {
		token := params["token"]

		if h.userExists(token) {
			// TODO proper response
			fmt.Fprintf(w, "Not allowed -- User already connected")
		} else {
			fmt.Println("Exchange token against the channel")
			ch, err := h.client.Getset(token, []byte{})
			if err != nil {
				fmt.Fprintf(w, "Not allowed -- Error occured while exchanging the token")
			} else {
				h.register <- Connection{token, string(ch)}
				defer func(u string) {
					h.unregister <- u
				}(token)
				h.srv.Handler(token)(w, req)
			}
		}
	})

	sseString := os.Getenv("SSE_ENDPOINT_URL")
	if sseString == "" {
		log.Fatal("SSE_URL is not set, example: SSE_URL=http://localhost:3000/")
	}
	sseURL, err := nurl.Parse(sseString)
	if err != nil {
		log.Fatal("Could not read SSE string", err)
	}

	log.Println("listening on " + sseURL.Host)
	log.Fatalln(http.ListenAndServe(sseURL.Host, m))
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"regexp"
	"strings"

	"github.com/rakyll/boom/commands"
)

var (
	flagMethod   = flag.String("m", "GET", "")
	flagHeaders  = flag.String("h", "", "")
	flagD        = flag.String("d", "", "")
	flagType     = flag.String("T", "text/html", "")
	flagAuth     = flag.String("a", "", "")
	flagInsecure = flag.Bool("allow-insecure", false, "")

	flagC = flag.Int("c", 50, "")
	flagN = flag.Int("n", 200, "")
	flagQ = flag.Int("q", 0, "")
	flagT = flag.Int("t", 0, "")
)

var usage = `Usage: boom [options...] <url>

Options:
  -n	Number of requests to run.
  -c	Number of requests to run concurrently. Total number of requests cannot
  	be smaller than the concurency level.
  -q    Rate limit, in seconds (QPS).

  -m	HTTP method, one of GET, POST, PUT, DELETE, HEAD, OPTIONS.
  -h	Custom HTTP headers, name1:value1;name2:value2.
  -d	HTTP request body.
  -T	Content-type, defaults to "text/html".
  -a	Basic authentication, username:password.

  -allow-insecure	Allow bad/expired TLS/SSL certificates.

`

func main() {
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, usage)
	}

	flag.Parse()
	if flag.NArg() < 1 {
		usageAndExit()
	}

	n := *flagN
	c := *flagC
	q := *flagQ
	t := *flagT

	if n <= 0 || c <= 0 {
		usageAndExit()
	}

	// If total number is smaller than concurrency level,
	// make the total number c.
	if c > n {
		n = c
	}

	url := flag.Args()[0]
	method := strings.ToUpper(*flagMethod)
	req, _ := http.NewRequest(method, url, strings.NewReader(*flagD))

	// set content-type
	req.Header.Set("Content-Type", *flagType)

	// set any other additional headers
	if *flagHeaders != "" {
		headers := strings.Split(*flagHeaders, ";")
		for _, h := range headers {
			re := regexp.MustCompile("(\\w+):(\\w+)")
			matches := re.FindAllStringSubmatch(h, -1)
			if len(matches) < 1 {
				usageAndExit()
			}
			req.Header.Set(matches[0][1], matches[0][2])
		}
	}

	// set basic auth if set
	if *flagAuth != "" {
		re := regexp.MustCompile("(\\w+):(\\w+)")
		matches := re.FindAllStringSubmatch(*flagAuth, -1)
		if len(matches) < 1 {
			usageAndExit()
		}
		req.SetBasicAuth(matches[0][1], matches[0][2])
	}

	(&commands.Boom{N: n, C: c, Qps: q, Timeout: t, Req: req, AllowInsecure: *flagInsecure}).Run()
}

func usageAndExit() {
	flag.Usage()
	os.Exit(1)
}
<commit_msg>Handle header values with spaces, allow header keys to contain dashes.<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"net/http"
	"os"
	"regexp"
	"strings"

	"github.com/rakyll/boom/commands"
)

var (
	flagMethod   = flag.String("m", "GET", "")
	flagHeaders  = flag.String("h", "", "")
	flagD        = flag.String("d", "", "")
	flagType     = flag.String("T", "text/html", "")
	flagAuth     = flag.String("a", "", "")
	flagInsecure = flag.Bool("allow-insecure", false, "")

	flagC = flag.Int("c", 50, "")
	flagN = flag.Int("n", 200, "")
	flagQ = flag.Int("q", 0, "")
	flagT = flag.Int("t", 0, "")
)

var usage = `Usage: boom [options...] <url>

Options:
  -n	Number of requests to run.
  -c	Number of requests to run concurrently. Total number of requests cannot
  	be smaller than the concurency level.
  -q    Rate limit, in seconds (QPS).

  -m	HTTP method, one of GET, POST, PUT, DELETE, HEAD, OPTIONS.
  -h	Custom HTTP headers, name1:value1;name2:value2.
  -d	HTTP request body.
  -T	Content-type, defaults to "text/html".
  -a	Basic authentication, username:password.

  -allow-insecure	Allow bad/expired TLS/SSL certificates.

`

func main() {
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, usage)
	}

	flag.Parse()
	if flag.NArg() < 1 {
		usageAndExit()
	}

	n := *flagN
	c := *flagC
	q := *flagQ
	t := *flagT

	if n <= 0 || c <= 0 {
		usageAndExit()
	}

	// If total number is smaller than concurrency level,
	// make the total number c.
	if c > n {
		n = c
	}

	url := flag.Args()[0]
	method := strings.ToUpper(*flagMethod)
	req, _ := http.NewRequest(method, url, strings.NewReader(*flagD))

	// set content-type
	req.Header.Set("Content-Type", *flagType)

	// set any other additional headers
	if *flagHeaders != "" {
		headers := strings.Split(*flagHeaders, ";")
		for _, h := range headers {
			re := regexp.MustCompile("([\\w|-]+):(.+)")
			matches := re.FindAllStringSubmatch(h, -1)
			if len(matches) < 1 {
				usageAndExit()
			}
			req.Header.Set(matches[0][1], matches[0][2])
		}
	}

	// set basic auth if set
	if *flagAuth != "" {
		re := regexp.MustCompile("(\\w+):(\\w+)")
		matches := re.FindAllStringSubmatch(*flagAuth, -1)
		if len(matches) < 1 {
			usageAndExit()
		}
		req.SetBasicAuth(matches[0][1], matches[0][2])
	}

	(&commands.Boom{N: n, C: c, Qps: q, Timeout: t, Req: req, AllowInsecure: *flagInsecure}).Run()
}

func usageAndExit() {
	flag.Usage()
	os.Exit(1)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"runtime"

	"github.com/gorilla/mux"
	"github.com/schimmy/shorty/db"
	"github.com/schimmy/shorty/routes"
)

const (
	pgBackend    = "postgres"
	redisBackend = "redis"
)

var (
	port     = flag.String("port", "80", "port to listen on")
	database = flag.String("db", pgBackend, "datastore option to use, one of: ['postgres', 'redis']")
	readonly = flag.Bool("readonly", true, "set readonly mode (useful for external-facing instance)")
	protocol = flag.String("protocol", "http", "protocol for the short handler - useful to separate for external-facing separate instance")
	domain   = flag.String("domain", "go", "set the domain for the short URL reported to the user")
)

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	flag.Parse()
}

func main() {
	var sdb db.ShortenBackend
	switch *database {
	case pgBackend:
		sdb = db.NewPostgresDB()
	case redisBackend:
		sdb = db.NewRedisDB()
	default:
		log.Fatalf("'%s' backend is not offered", *database)
	}

	// default to ReadOnly mode for POSTs and list of slugs
	deleteHandler := routes.ReadOnlyHandler()
	shortenHandler := routes.ReadOnlyHandler()
	listHandler := routes.ReadOnlyHandler()
	if *readonly == false {
		deleteHandler = routes.DeleteHandler(sdb)
		shortenHandler = routes.ShortenHandler(sdb)
		listHandler = routes.ListHandler(sdb)
	}
	r := mux.NewRouter()
	r.HandleFunc("/delete", deleteHandler).Methods("POST")
	r.HandleFunc("/shorten", shortenHandler).Methods("POST")
	r.HandleFunc("/list", listHandler).Methods("GET")

	// Safe for public consumption no matter what below here
	// Technically someone could scrape the whole slug space to discover
	// all the slugs, but that comes along with the territory
	r.HandleFunc("/meta", routes.MetaHandler(*protocol, *domain)).Methods("GET")
	r.PathPrefix("/Shortener.jsx").Handler(http.FileServer(http.Dir("./static")))
	r.PathPrefix("/favicon.png").Handler(http.FileServer(http.Dir("./static")))
	r.HandleFunc("/{slug}", routes.RedirectHandler(sdb, *domain)).Methods("GET")
	r.HandleFunc("/health/check", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "STATUS OK")
	})

	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		http.ServeFile(w, r, "./static/index.html")
	}).Methods("GET")
	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./static")))
	http.Handle("/", r)

	fmt.Printf("Starting server on port: %s\n", *port)
	log.Fatal(http.ListenAndServe(":"+*port, nil))
}
<commit_msg>default to false for readonly mode for now so we don't break anything<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"runtime"

	"github.com/gorilla/mux"
	"github.com/schimmy/shorty/db"
	"github.com/schimmy/shorty/routes"
)

const (
	pgBackend    = "postgres"
	redisBackend = "redis"
)

var (
	port     = flag.String("port", "80", "port to listen on")
	database = flag.String("db", pgBackend, "datastore option to use, one of: ['postgres', 'redis']")
	readonly = flag.Bool("readonly", false, "set readonly mode (useful for external-facing instance)")
	protocol = flag.String("protocol", "http", "protocol for the short handler - useful to separate for external-facing separate instance")
	domain   = flag.String("domain", "go", "set the domain for the short URL reported to the user")
)

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	flag.Parse()
}

func main() {
	var sdb db.ShortenBackend
	switch *database {
	case pgBackend:
		sdb = db.NewPostgresDB()
	case redisBackend:
		sdb = db.NewRedisDB()
	default:
		log.Fatalf("'%s' backend is not offered", *database)
	}

	// default to ReadOnly mode for POSTs and list of slugs
	deleteHandler := routes.ReadOnlyHandler()
	shortenHandler := routes.ReadOnlyHandler()
	listHandler := routes.ReadOnlyHandler()
	if *readonly == false {
		deleteHandler = routes.DeleteHandler(sdb)
		shortenHandler = routes.ShortenHandler(sdb)
		listHandler = routes.ListHandler(sdb)
	}
	r := mux.NewRouter()
	r.HandleFunc("/delete", deleteHandler).Methods("POST")
	r.HandleFunc("/shorten", shortenHandler).Methods("POST")
	r.HandleFunc("/list", listHandler).Methods("GET")

	// Safe for public consumption no matter what below here
	// Technically someone could scrape the whole slug space to discover
	// all the slugs, but that comes along with the territory
	r.HandleFunc("/meta", routes.MetaHandler(*protocol, *domain)).Methods("GET")
	r.PathPrefix("/Shortener.jsx").Handler(http.FileServer(http.Dir("./static")))
	r.PathPrefix("/favicon.png").Handler(http.FileServer(http.Dir("./static")))
	r.HandleFunc("/{slug}", routes.RedirectHandler(sdb, *domain)).Methods("GET")
	r.HandleFunc("/health/check", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "STATUS OK")
	})

	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		http.ServeFile(w, r, "./static/index.html")
	}).Methods("GET")
	r.PathPrefix("/").Handler(http.FileServer(http.Dir("./static")))
	http.Handle("/", r)

	fmt.Printf("Starting server on port: %s\n", *port)
	log.Fatal(http.ListenAndServe(":"+*port, nil))
}
<|endoftext|>


<commit_before>// main.go is the entry point for the program.
// It sets up all necessary connections for the application.
package main

import (
  "net/http"
  "fmt"
  "io/ioutil"
  "encoding/json"
  "os"
  "github.com/PuerkitoBio/goquery"
)

func main() {
  // urlArr := GetSongsPath()

  // for _, songEndpoint := range urlArr {
    // GetSongLyrics(songEndpoint)
  // }

  // Iterate over tracks
  for _, track := range scrapeTrackList("http://www.azlyrics.com/m/migos.html") {
    fmt.Println(track)
  }
}

// GetSongsPath
// Returns an array of URLs for Migos songs
func GetSongsPath() []string {
  var data interface{}

  accessToken := os.Getenv("GENIUS_ACCESS_TOKEN")
  migosId := "44080" // Genius artist id for Migos

  artistEndpoint := "https://api.genius.com/artists/" + migosId + "/songs?access_token=" + accessToken
  fmt.Println("GET:", artistEndpoint)
  res, err := http.Get(artistEndpoint)
  if err != nil {
    panic(err.Error())
  }

  body, err := ioutil.ReadAll(res.Body)
   if err != nil {
     panic(err.Error())
   }
   err = json.Unmarshal(body, &data)
   if err != nil {
     panic(err.Error())
   }

  songs := data.(map[string]interface{})["response"].(map[string]interface{})["songs"]
  var ret []string
   for _, song := range songs.([]interface{}) {
     ret = append(ret, "https://api.genius.com" + song.(map[string]interface{})["api_path"].(string))
   }
   return ret
}

// Since Genius API is whack, we need to scrape the data from the website
func GetSongLyrics(apiPath string)  {

  var data interface{}
  accessToken := os.Getenv("GENIUS_ACCESS_TOKEN")
  authEndpoint := apiPath + "?access_token=" + accessToken
  fmt.Println("GET:", authEndpoint)
  res, err := http.Get(authEndpoint)
  if err != nil {
    panic(err.Error())
  }

  body, err := ioutil.ReadAll(res.Body)
   if err != nil {
     panic(err.Error())
   }
   err = json.Unmarshal(body, &data)
   if err != nil {
     panic(err.Error())
   }

   song := data.(map[string]interface{})["response"].(map[string]interface{})["song"]
   websiteUrl := "https://genius.com" + song.(map[string]interface{})["path"].(string)
   fmt.Println(" === SCRAPING", websiteUrl, "===")
   scrapeLyrics(websiteUrl)
}

// Scrape Migos songs from http://www.azlyrics.com/m/migos.html
func scrapeTrackList(websiteUrl string) []string {
  doc, err := goquery.NewDocument(websiteUrl)
  if err != nil {
    panic(err.Error())
  }

  var trackList []string
  doc.Find("#listAlbum > a").Each(func (i int, s *goquery.Selection) {
    trackList = append(trackList, s.Text())
  })
  return trackList
}

// Scrape lyrics using goQuery
func scrapeLyrics(websiteUrl string) {
  doc, err := goquery.NewDocument(websiteUrl)
  if err != nil {
    panic(err.Error())
  }

  fmt.Println(doc.Find(".lyrics").Text())
}
<commit_msg>Hook up track names and lyrics<commit_after>// main.go is the entry point for the program.
// It sets up all necessary connections for the application.
package main

import (
  "net/http"
  "fmt"
  "io/ioutil"
  "encoding/json"
  "os"
  "github.com/PuerkitoBio/goquery"
  "strings"
)

func main() {

  // Iterate over tracks
  for _, track := range scrapeTrackList("http://www.azlyrics.com/m/migos.html") {
    if track != "" {
      geniusUrl := "https://genius.com/Migos-" + dasherize(track) + "-lyrics"
      scrapeLyrics(geniusUrl)
    }
  }
}

// GetSongsPath
// Returns an array of URLs for Migos songs
func GetSongsPath() []string {
  var data interface{}

  accessToken := os.Getenv("GENIUS_ACCESS_TOKEN")
  migosId := "44080" // Genius artist id for Migos

  artistEndpoint := "https://api.genius.com/artists/" + migosId + "/songs?access_token=" + accessToken
  fmt.Println("GET:", artistEndpoint)
  res, err := http.Get(artistEndpoint)
  if err != nil {
    panic(err.Error())
  }

  body, err := ioutil.ReadAll(res.Body)
   if err != nil {
     panic(err.Error())
   }
   err = json.Unmarshal(body, &data)
   if err != nil {
     panic(err.Error())
   }

  songs := data.(map[string]interface{})["response"].(map[string]interface{})["songs"]
  var ret []string
   for _, song := range songs.([]interface{}) {
     ret = append(ret, "https://api.genius.com" + song.(map[string]interface{})["api_path"].(string))
   }
   return ret
}

// Since Genius API is whack, we need to scrape the data from the website
func GetSongLyrics(apiPath string)  {
  var data interface{}
  accessToken := os.Getenv("GENIUS_ACCESS_TOKEN")
  authEndpoint := apiPath + "?access_token=" + accessToken
  fmt.Println("GET:", authEndpoint)

  res, err := http.Get(authEndpoint)
  if err != nil {
    panic(err.Error())
  }

  body, err := ioutil.ReadAll(res.Body)
   if err != nil {
     panic(err.Error())
   }
   err = json.Unmarshal(body, &data)
   if err != nil {
     panic(err.Error())
   }

   song := data.(map[string]interface{})["response"].(map[string]interface{})["song"]
   websiteUrl := "https://genius.com" + song.(map[string]interface{})["path"].(string)
   fmt.Println(" === SCRAPING", websiteUrl, "===")
   scrapeLyrics(websiteUrl)
}

// Scrape Migos songs from http://www.azlyrics.com/m/migos.html
func scrapeTrackList(websiteUrl string) []string {
  doc, err := goquery.NewDocument(websiteUrl)
  if err != nil {
    panic(err.Error())
  }

  var trackList []string
  doc.Find("#listAlbum > a").Each(func (i int, s *goquery.Selection) {
    trackList = append(trackList, s.Text())
  })
  return trackList
}

// Scrape lyrics using goQuery
func scrapeLyrics(websiteUrl string) {
  fmt.Println("\n === Scraping from", websiteUrl, "\n")
  doc, err := goquery.NewDocument(websiteUrl)
  if err != nil {
    panic(err.Error())
  }

  fmt.Println(doc.Find(".lyrics").Text())
}

func dasherize(track string) string {
  r := strings.NewReplacer(" ", "-", "(", "", ")", "", "'", "", ".", "", "&", "and")
  return r.Replace(track)
}
<|endoftext|>


<commit_before>// Package main is used as an entry point of
// the framework. It validates user input parameters
// and runs subcommands (aka tools).
package main

import (
	"os"
	"strings"

	"github.com/colegion/goal/internal/command"
	"github.com/colegion/goal/log"
)

// handlers is a stores information about the registered subcommands (aka tools)
// the framework supports.
var handlers = command.NewContext()

func main() {
	// Try to run the command user requested.
	// Ignoring the first argument as it is name of the executable.
	err := handlers.Run(os.Args[1:])
	switch err {
	case nil: // Handler's entry function has been successfully executed.
		// Do nothing.
	case command.ErrIncorrectArgs: // Incorrect command requested.
		log.Warn.Printf(unknownCmd, strings.Join(os.Args, " "))
	default: // Some other error has been received.
		log.Error.Println(err)
	}
}

var unknownCmd = `Unknown command "%s".
Run "goal help" for usage.`
<commit_msg>Included 'create' tool<commit_after>// Package main is used as an entry point of
// the framework. It validates user input parameters
// and runs subcommands (aka tools).
package main

import (
	"os"
	"strings"

	"github.com/colegion/goal/internal/command"
	"github.com/colegion/goal/log"
	"github.com/colegion/goal/tools/create"
)

// handlers is a stores information about the registered subcommands (aka tools)
// the framework supports.
var handlers = command.NewContext(
	create.Handler,
)

func main() {
	// Try to run the command user requested.
	// Ignoring the first argument as it is name of the executable.
	err := handlers.Run(os.Args[1:])
	switch err {
	case nil: // Handler's entry function has been successfully executed.
		// Do nothing.
	case command.ErrIncorrectArgs: // Incorrect command requested.
		log.Warn.Printf(unknownCmd, strings.Join(os.Args, " "))
	default: // Some other error has been received.
		log.Error.Printf(`Error: "%v".`, err)
	}
}

var unknownCmd = `Unknown command "%s".
Run "goal help" for usage.`
<|endoftext|>


<commit_before>package main

import (
	"crypto/tls"
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"sync"
	"time"

	"github.com/google/gops/agent"
	"github.com/nabeken/go-smtp-source/net/smtp"
)

var (
	myDate     = time.Now()
	myPid      = os.Getpid()
	myhostname = "localhost"
)

var (
	defaultSender    = "from@example.com"
	defaultRecipient = "to@example.com"
	defaultSubject   = "from go-smtp-source"
)

var config *Config

type Config struct {
	Host         string
	Sender       string
	Recipient    string
	MessageCount int
	Sessions     int
	MessageSize  int

	// extension
	UseTLS      bool
	ResolveOnce bool

	tlsConfig *tls.Config
}

func usage(m, def string) string {
	return fmt.Sprintf("%s [default: %s]", m, def)
}

func Parse() error {
	var (
		msgcount  = flag.Int("m", 1, usage("specify a number of messages to send.", "1"))
		msgsize   = flag.Int("l", 0, usage("specify the size of the body.", "0"))
		session   = flag.Int("s", 1, usage("specify a number of cocurrent sessions.", "1"))
		sender    = flag.String("f", defaultSender, usage("specify a sender address.", defaultSender))
		recipient = flag.String("t", defaultRecipient, usage("specify a recipient address.", defaultRecipient))

		usetls      = flag.Bool("tls", false, usage("specify if STARTTLS is needed.", "false"))
		resolveOnce = flag.Bool("resolve-once", false, usage("resolve the hostname only once.", "false"))
	)

	flag.Parse()

	host := flag.Arg(0)
	if host == "" {
		return errors.New("host is missing")
	}

	config = &Config{
		Host:         host,
		Sender:       *sender,
		Recipient:    *recipient,
		MessageCount: *msgcount,
		MessageSize:  *msgsize,
		Sessions:     *session,

		UseTLS:      *usetls,
		ResolveOnce: *resolveOnce,

		tlsConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}
	return nil
}

func sendMail(c *smtp.Client) error {
	if config.UseTLS {
		if err := c.StartTLS(config.tlsConfig); err != nil {
			return err
		}
	} else {
		if err := c.Hello(myhostname); err != nil {
			return err
		}
	}
	if err := c.Mail(config.Sender); err != nil {
		return err
	}
	if err := c.Rcpt(config.Recipient); err != nil {
		return err
	}

	wc, err := c.Data()
	if err != nil {
		return err
	}

	fmt.Fprintf(wc, "From: <%s>\n", config.Sender)
	fmt.Fprintf(wc, "To: <%s>\n", config.Recipient)
	fmt.Fprintf(wc, "Date: %s\n", myDate.Format(time.RFC1123))
	fmt.Fprintf(wc, "Subject: %s\n", defaultSubject)
	fmt.Fprintf(wc, "Message-Id: <%04x.%04x@%s>\n", myPid, config.MessageCount, myhostname)
	fmt.Fprintln(wc, "")

	if config.MessageSize == 0 {
		for i := 1; i < 5; i++ {
			fmt.Fprintf(wc, "La de da de da %d.\n", i)
		}
	} else {
		for i := 1; i < config.MessageSize; i++ {
			fmt.Fprint(wc, "X")
			if i%80 == 0 {
				fmt.Fprint(wc, "\n")
			}
		}
	}

	if err := wc.Close(); err != nil {
		return err
	}

	return c.Quit()
}

func main() {
	if err := agent.Listen(nil); err != nil {
		log.Fatal(err)
	}
	if err := Parse(); err != nil {
		log.Fatal(err)
	}

	addr, port, err := net.SplitHostPort(config.Host)
	if err != nil {
		log.Fatal(err)
	}

	if config.ResolveOnce {
		addrs, err := net.LookupHost(addr)
		if err != nil {
			log.Fatal(err)
		}

		// use first one
		addr = addrs[0]
	}

	// semaphore for concurrency
	sem := make(chan struct{}, config.Sessions)
	for i := 0; i < config.Sessions; i++ {
		sem <- struct{}{}
	}

	// response for async dial
	type clientCall struct {
		c   *smtp.Client
		err error
	}
	clientQueue := make(chan *clientCall, config.Sessions)
	go func() {
		for i := 0; i < config.MessageCount; i++ {
			conn, err := net.Dial("tcp", addr+":"+port)
			if err != nil {
				clientQueue <- &clientCall{nil, err}
				continue
			}

			if tcpConn, ok := conn.(*net.TCPConn); ok {
				// smtp-source does this so we just follow it
				if err := tcpConn.SetLinger(0); err != nil {
					clientQueue <- &clientCall{nil, err}
					continue
				}
			}

			c, err := smtp.NewClient(conn, addr)
			clientQueue <- &clientCall{c, err}
		}
	}()

	// wait group for all attempts
	var wg sync.WaitGroup
	wg.Add(config.MessageCount)

	for i := 0; i < config.MessageCount; i++ {
		<-sem
		go func() {
			defer func() {
				sem <- struct{}{}
				wg.Done()
			}()
			cc := <-clientQueue
			if cc.err != nil {
				log.Println("unable to connect to the server:", cc.err)
				return
			}
			if err := sendMail(cc.c); err != nil {
				log.Println("unable to send a mail:", err)
			}
		}()
	}

	wg.Wait()
}
<commit_msg>Add the format strings '%d' for the subject<commit_after>package main

import (
	"crypto/tls"
	"errors"
	"flag"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/google/gops/agent"
	"github.com/nabeken/go-smtp-source/net/smtp"
)

var (
	myDate     = time.Now()
	myPid      = os.Getpid()
	myhostname = "localhost"
)

var (
	defaultSender    = "from@example.com"
	defaultRecipient = "to@example.com"
	defaultSubject   = "from go-smtp-source"
)

var config *Config

type Config struct {
	Host         string
	Sender       string
	Recipient    string
	MessageCount int
	Sessions     int
	MessageSize  int
	Subject      string

	// extension
	UseTLS      bool
	ResolveOnce bool

	tlsConfig *tls.Config
}

func usage(m, def string) string {
	return fmt.Sprintf("%s [default: %s]", m, def)
}

func Parse() error {
	var (
		msgcount  = flag.Int("m", 1, usage("specify a number of messages to send.", "1"))
		msgsize   = flag.Int("l", 0, usage("specify the size of the body.", "0"))
		session   = flag.Int("s", 1, usage("specify a number of cocurrent sessions.", "1"))
		sender    = flag.String("f", defaultSender, usage("specify a sender address.", defaultSender))
		recipient = flag.String("t", defaultRecipient, usage("specify a recipient address.", defaultRecipient))
		subject   = flag.String("S", defaultSubject, usage("specify a subject.", defaultSubject))

		usetls      = flag.Bool("tls", false, usage("specify if STARTTLS is needed.", "false"))
		resolveOnce = flag.Bool("resolve-once", false, usage("resolve the hostname only once.", "false"))
	)

	flag.Parse()

	host := flag.Arg(0)
	if host == "" {
		return errors.New("host is missing")
	}

	config = &Config{
		Host:         host,
		Sender:       *sender,
		Recipient:    *recipient,
		MessageCount: *msgcount,
		MessageSize:  *msgsize,
		Sessions:     *session,
		Subject:      *subject,

		UseTLS:      *usetls,
		ResolveOnce: *resolveOnce,

		tlsConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}
	return nil
}

func sendMail(c *smtp.Client, idx int) error {
	if config.UseTLS {
		if err := c.StartTLS(config.tlsConfig); err != nil {
			return err
		}
	} else {
		if err := c.Hello(myhostname); err != nil {
			return err
		}
	}
	if err := c.Mail(config.Sender); err != nil {
		return err
	}
	if err := c.Rcpt(config.Recipient); err != nil {
		return err
	}

	wc, err := c.Data()
	if err != nil {
		return err
	}

	fmt.Fprintf(wc, "From: <%s>\n", config.Sender)
	fmt.Fprintf(wc, "To: <%s>\n", config.Recipient)
	fmt.Fprintf(wc, "Date: %s\n", myDate.Format(time.RFC1123))

	subject := fmt.Sprintf(config.Subject, idx)
	if subjectIdx := strings.Index(subject, "%!(EXTRA"); subjectIdx >= 0 {
		fmt.Fprintf(wc, "Subject: %s\n", subject[0:subjectIdx])
	} else {
		fmt.Fprintf(wc, "Subject: %s\n", subject)
	}
	fmt.Fprintf(wc, "Message-Id: <%04x.%04x@%s>\n", myPid, config.MessageCount, myhostname)
	fmt.Fprintln(wc, "")

	if config.MessageSize == 0 {
		for i := 1; i < 5; i++ {
			fmt.Fprintf(wc, "La de da de da %d.\n", i)
		}
	} else {
		for i := 1; i < config.MessageSize; i++ {
			fmt.Fprint(wc, "X")
			if i%80 == 0 {
				fmt.Fprint(wc, "\n")
			}
		}
	}

	if err := wc.Close(); err != nil {
		return err
	}

	return c.Quit()
}

func main() {
	if err := agent.Listen(nil); err != nil {
		log.Fatal(err)
	}
	if err := Parse(); err != nil {
		log.Fatal(err)
	}

	addr, port, err := net.SplitHostPort(config.Host)
	if err != nil {
		log.Fatal(err)
	}

	if config.ResolveOnce {
		addrs, err := net.LookupHost(addr)
		if err != nil {
			log.Fatal(err)
		}

		// use first one
		addr = addrs[0]
	}

	// semaphore for concurrency
	sem := make(chan struct{}, config.Sessions)
	for i := 0; i < config.Sessions; i++ {
		sem <- struct{}{}
	}

	// response for async dial
	type clientCall struct {
		c   *smtp.Client
		err error
		idx int
	}
	clientQueue := make(chan *clientCall, config.Sessions)
	go func() {
		for i := 0; i < config.MessageCount; i++ {
			idx := i + 1
			conn, err := net.Dial("tcp", addr+":"+port)
			if err != nil {
				clientQueue <- &clientCall{nil, err, idx}
				continue
			}

			if tcpConn, ok := conn.(*net.TCPConn); ok {
				// smtp-source does this so we just follow it
				if err := tcpConn.SetLinger(0); err != nil {
					clientQueue <- &clientCall{nil, err, idx}
					continue
				}
			}

			c, err := smtp.NewClient(conn, addr)
			clientQueue <- &clientCall{c, err, idx}
		}
	}()

	// wait group for all attempts
	var wg sync.WaitGroup
	wg.Add(config.MessageCount)

	for i := 0; i < config.MessageCount; i++ {
		<-sem
		go func() {
			defer func() {
				sem <- struct{}{}
				wg.Done()
			}()
			cc := <-clientQueue
			if cc.err != nil {
				log.Println("unable to connect to the server:", cc.err)
				return
			}
			if err := sendMail(cc.c, cc.idx); err != nil {
				log.Println("unable to send a mail:", err)
			}
		}()
	}

	wg.Wait()
}
<|endoftext|>


<commit_before>package main

import
(
   "github.com/cloudlibz/gocloud/gocloud"
   "fmt"
)
func main(){

  amazoncloud, _ := gocloud.CloudProvider(gocloud.Amazonprovider)
  fmt.Println(amazoncloud)
}
<commit_msg>main.go removed<commit_after><|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

const (
	version = "0.8.5"
)

func init() {
	flag.Usage = func() {
		h := "Usage:\n"
		h += "  bozr [OPTIONS] (DIR|FILE)\n\n"

		h += "Options:\n"
		h += "  -d, --debug		Enable debug mode\n"
		h += "  -H, --host		Server to test\n"
		h += "  -h, --help		Print usage\n"
		h += "  -i, --info		Enable info mode. Print request and response details.\n"
		h += "      --junit		Enable junit xml reporter\n"
		h += "  -v, --version		Print version information and quit\n\n"

		h += "Examples:\n"
		h += "  bozr ./examples\n"
		h += "  bozr -H http://example.com ./examples \n"

		fmt.Fprintf(os.Stderr, h)
	}
}

var (
	suiteDir    string
	hostFlag    string
	infoFlag    bool
	debugFlag   bool
	helpFlag    bool
	versionFlag bool
	junitFlag   bool

	info  *log.Logger
	debug *log.Logger
)

func initLogger() {
	infoHandler := ioutil.Discard
	debugHandler := ioutil.Discard

	if infoFlag {
		infoHandler = os.Stdout
	}

	if debugFlag {
		debugHandler = os.Stdout
	}

	info = log.New(infoHandler, "", 0)
	debug = log.New(debugHandler, "DEBUG: ", log.Ltime|log.Lshortfile)
}

func main() {
	flag.BoolVar(&debugFlag, "d", false, "Enable debug mode.")
	flag.BoolVar(&debugFlag, "debug", false, "Enable debug mode")

	flag.BoolVar(&infoFlag, "i", false, "Enable info mode. Print request and response details.")
	flag.BoolVar(&infoFlag, "info", false, "Enable info mode. Print request and response details.")

	flag.StringVar(&hostFlag, "H", "", "Test server address. Example: http://example.com/api.")

	flag.BoolVar(&helpFlag, "h", false, "Print usage")
	flag.BoolVar(&helpFlag, "help", false, "Print usage")

	flag.BoolVar(&versionFlag, "v", false, "Print version information and quit")
	flag.BoolVar(&versionFlag, "version", false, "Print version information and quit")

	flag.BoolVar(&junitFlag, "junit", false, "Enable junit xml reporter")

	flag.Parse()

	initLogger()

	if versionFlag {
		fmt.Println("bozr version " + version)
		return
	}

	if helpFlag {
		flag.Usage()
		return
	}

	if len(hostFlag) > 0 {
		_, err := url.ParseRequestURI(hostFlag)
		if err != nil {
			fmt.Println("Invalid host is specified.")
			os.Exit(1)
			return
		}
	}

	src := flag.Arg(0)

	if src == "" {
		fmt.Print("You must specify a directory or file with tests.\n\n")
		flag.Usage()
		os.Exit(1)
		return
	}

	// check specified source dir/file exists
	_, err := os.Lstat(src)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
		return
	}

	var ch <-chan TestSuite
	if filepath.Ext(src) == "" {
		debug.Print("Loading from directory")
		suiteDir = src
		ch = NewDirLoader(suiteDir)
	} else {
		debug.Print("Loading from file")
		suiteDir = filepath.Dir(src)
		ch = NewFileLoader(src)
	}

	reporters := []Reporter{NewConsoleReporter()}
	if junitFlag {
		path, _ := filepath.Abs("./report")
		reporters = append(reporters, NewJUnitReporter(path))
	}
	reporter := NewMultiReporter(reporters...)

	// test case runner?
	for suite := range ch {
		for _, testCase := range suite.Cases {

			result := TestResult{
				Suite: suite,
				Case:  testCase,
			}

			rememberedMap := make(map[string]interface{})
			start := time.Now()
			for _, c := range testCase.Calls {
				addAll(c.Args, rememberedMap)
				terr := call(suite, testCase, c, rememberedMap)
				if terr != nil {
					result.Error = terr
					break
				}
			}

			result.Duration = time.Since(start)

			reporter.Report(result)
		}
	}

	reporter.Flush()
}

func addAll(src, target map[string]interface{}) {
	for key, val := range src {
		target[key] = val
	}
}

func call(testSuite TestSuite, testCase TestCase, call Call, rememberMap map[string]interface{}) *TError {
	debug.Printf("Starting call: %s - %s", testSuite.Name, testCase.Name)
	terr := &TError{}

	on := call.On

	dat := []byte(on.Body)
	if on.BodyFile != "" {
		uri, err := toAbsPath(testSuite.Dir, on.BodyFile)
		if err != nil {
			terr.Cause = err
			return terr
		}

		if d, err := ioutil.ReadFile(uri); err == nil {
			dat = d
		} else {
			terr.Cause = fmt.Errorf("Can't read body file: %s", err.Error())
			return terr
		}
	}

	req, err := populateRequest(on, string(dat), rememberMap)
	if err != nil {
		terr.Cause = err
		return terr
	}

	printRequestInfo(req, dat)

	client := &http.Client{}

	resp, err := client.Do(req)

	if err != nil {
		debug.Print("Error when sending request", err)
		terr.Cause = err
		return terr
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		debug.Print("Error reading response")
		terr.Cause = err
		return terr
	}

	testResp := Response{http: *resp, body: body}
	terr.Resp = testResp

	info.Println(strings.Repeat("-", 50))
	info.Println(testResp.ToString())
	info.Println("")

	exps, err := expectations(call, testSuite.Dir)
	if err != nil {
		terr.Cause = err
		return terr
	}

	for _, exp := range exps {
		checkErr := exp.check(testResp)
		if checkErr != nil {
			terr.Cause = checkErr
			return terr
		}
	}

	m, err := testResp.parseBody()
	if err != nil {
		debug.Print("Can't parse response body to Map for [remember]")
		terr.Cause = err
		return terr
	}

	err = remember(m, call.Remember, rememberMap)
	debug.Print("Remember: ", rememberMap)
	if err != nil {
		debug.Print("Error remember")
		terr.Cause = err
		return terr
	}

	return nil
}

func populateRequest(on On, body string, rememberMap map[string]interface{}) (*http.Request, error) {

	urlStr, err := urlPrefix(populateRememberedVars(on.URL, rememberMap))
	if err != nil {
		return nil, errors.New("Cannot create request. Invalid url: " + on.URL)
	}

	body = populateRememberedVars(body, rememberMap)
	dat := []byte(body)

	req, err := http.NewRequest(on.Method, urlStr, bytes.NewBuffer(dat))
	if err != nil {
		return nil, err
	}

	for key, value := range on.Headers {
		req.Header.Add(key, populateRememberedVars(value, rememberMap))
	}

	q := req.URL.Query()
	for key, value := range on.Params {
		q.Add(key, populateRememberedVars(value, rememberMap))
	}
	req.URL.RawQuery = q.Encode()

	return req, nil
}

func urlPrefix(p string) (string, error) {
	if strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://") {
		return p, nil
	}

	return concatURL(hostFlag, p)
}

func concatURL(base string, p string) (string, error) {
	baseURL, err := url.ParseRequestURI(base)
	if err != nil {
		return "", err
	}
	return baseURL.Scheme + "://" + baseURL.Host + path.Join(baseURL.Path, p), nil
}

func populateRememberedVars(str string, rememberMap map[string]interface{}) string {
	res := str
	for varName, val := range rememberMap {
		placeholder := "{" + varName + "}"
		res = strings.Replace(res, placeholder, toString(val), -1)
	}
	return res
}

// toString returns value suitable to insert as an argument
// if value if a float where decimal part is zero - convert to int
func toString(rw interface{}) string {
	var sv interface{} = rw
	if fv, ok := rw.(float64); ok {
		_, frac := math.Modf(fv)
		if frac == 0 {
			sv = int(fv)
		}
	}

	return fmt.Sprintf("%v", sv)
}

func expectations(call Call, srcDir string) ([]ResponseExpectation, error) {
	var exps []ResponseExpectation
	if call.Expect.StatusCode != 0 {
		exps = append(exps, StatusCodeExpectation{statusCode: call.Expect.StatusCode})
	}

	if call.Expect.hasSchema() {
		var (
			schemeURI string
			err       error
		)

		if call.Expect.BodySchemaFile != "" {
			schemeURI, err = toAbsPath(srcDir, call.Expect.BodySchemaFile)
			if err != nil {
				return nil, err
			}
			schemeURI = "file:///" + schemeURI
		}

		if call.Expect.BodySchemaURI != "" {
			isHTTP := strings.HasPrefix(call.Expect.BodySchemaURI, "http://")
			isHTTPS := strings.HasPrefix(call.Expect.BodySchemaURI, "https://")
			if !(isHTTP || isHTTPS) {
				schemeURI = hostFlag + call.Expect.BodySchemaURI
			} else {
				schemeURI = call.Expect.BodySchemaURI
			}
		}
		exps = append(exps, BodySchemaExpectation{schemaURI: schemeURI})
	}

	if len(call.Expect.Body) > 0 {
		exps = append(exps, BodyExpectation{pathExpectations: call.Expect.Body})
	}

	if len(call.Expect.Absent) > 0 {
		exps = append(exps, AbsentExpectation{paths: call.Expect.Absent})
	}

	if len(call.Expect.Headers) > 0 {
		for k, v := range call.Expect.Headers {
			exps = append(exps, HeaderExpectation{Name: k, Value: v})
		}
	}

	if call.Expect.ContentType != "" {
		exps = append(exps, ContentTypeExpectation{call.Expect.ContentType})
	}

	// and so on
	return exps, nil
}

func toAbsPath(srcDir string, assetPath string) (string, error) {
	if filepath.IsAbs(assetPath) {
		// ignore srcDir
		return assetPath, nil
	}

	uri, err := filepath.Abs(filepath.Join(suiteDir, srcDir, assetPath))
	if err != nil {
		return "", errors.New("Invalid file path: " + assetPath)
	}

	return filepath.ToSlash(uri), nil
}

func remember(body interface{}, remember map[string]string, rememberedMap map[string]interface{}) (err error) {

	for varName, pathLine := range remember {

		if rememberVar, err := getByPath(body, pathLine); err == nil {
			rememberedMap[varName] = rememberVar
		} else {
			strErr := fmt.Sprintf("Remembered value not found, path: %v", pathLine)
			err = errors.New(strErr)
		}
		//fmt.Printf("v: %v\n", getByPath(bodyMap, b...))
	}

	return err
}

func printRequestInfo(req *http.Request, body []byte) {
	info.Println()
	info.Printf("%s %s %s\n", req.Method, req.URL.String(), req.Proto)

	if len(req.Header) > 0 {
		info.Println()
	}

	for k, v := range req.Header {
		info.Printf("%s: %s", k, strings.Join(v, " "))
	}
	info.Println()

	if len(body) > 0 {
		info.Printf(string(body))
	}
}
<commit_msg>prepare 0.8.6<commit_after>package main

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"
)

const (
	version = "0.8.6"
)

func init() {
	flag.Usage = func() {
		h := "Usage:\n"
		h += "  bozr [OPTIONS] (DIR|FILE)\n\n"

		h += "Options:\n"
		h += "  -d, --debug		Enable debug mode\n"
		h += "  -H, --host		Server to test\n"
		h += "  -h, --help		Print usage\n"
		h += "  -i, --info		Enable info mode. Print request and response details.\n"
		h += "      --junit		Enable junit xml reporter\n"
		h += "  -v, --version		Print version information and quit\n\n"

		h += "Examples:\n"
		h += "  bozr ./examples\n"
		h += "  bozr -H http://example.com ./examples \n"

		fmt.Fprintf(os.Stderr, h)
	}
}

var (
	suiteDir    string
	hostFlag    string
	infoFlag    bool
	debugFlag   bool
	helpFlag    bool
	versionFlag bool
	junitFlag   bool

	info  *log.Logger
	debug *log.Logger
)

func initLogger() {
	infoHandler := ioutil.Discard
	debugHandler := ioutil.Discard

	if infoFlag {
		infoHandler = os.Stdout
	}

	if debugFlag {
		debugHandler = os.Stdout
	}

	info = log.New(infoHandler, "", 0)
	debug = log.New(debugHandler, "DEBUG: ", log.Ltime|log.Lshortfile)
}

func main() {
	flag.BoolVar(&debugFlag, "d", false, "Enable debug mode.")
	flag.BoolVar(&debugFlag, "debug", false, "Enable debug mode")

	flag.BoolVar(&infoFlag, "i", false, "Enable info mode. Print request and response details.")
	flag.BoolVar(&infoFlag, "info", false, "Enable info mode. Print request and response details.")

	flag.StringVar(&hostFlag, "H", "", "Test server address. Example: http://example.com/api.")

	flag.BoolVar(&helpFlag, "h", false, "Print usage")
	flag.BoolVar(&helpFlag, "help", false, "Print usage")

	flag.BoolVar(&versionFlag, "v", false, "Print version information and quit")
	flag.BoolVar(&versionFlag, "version", false, "Print version information and quit")

	flag.BoolVar(&junitFlag, "junit", false, "Enable junit xml reporter")

	flag.Parse()

	initLogger()

	if versionFlag {
		fmt.Println("bozr version " + version)
		return
	}

	if helpFlag {
		flag.Usage()
		return
	}

	if len(hostFlag) > 0 {
		_, err := url.ParseRequestURI(hostFlag)
		if err != nil {
			fmt.Println("Invalid host is specified.")
			os.Exit(1)
			return
		}
	}

	src := flag.Arg(0)

	if src == "" {
		fmt.Print("You must specify a directory or file with tests.\n\n")
		flag.Usage()
		os.Exit(1)
		return
	}

	// check specified source dir/file exists
	_, err := os.Lstat(src)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
		return
	}

	var ch <-chan TestSuite
	if filepath.Ext(src) == "" {
		debug.Print("Loading from directory")
		suiteDir = src
		ch = NewDirLoader(suiteDir)
	} else {
		debug.Print("Loading from file")
		suiteDir = filepath.Dir(src)
		ch = NewFileLoader(src)
	}

	reporters := []Reporter{NewConsoleReporter()}
	if junitFlag {
		path, _ := filepath.Abs("./report")
		reporters = append(reporters, NewJUnitReporter(path))
	}
	reporter := NewMultiReporter(reporters...)

	// test case runner?
	for suite := range ch {
		for _, testCase := range suite.Cases {

			result := TestResult{
				Suite: suite,
				Case:  testCase,
			}

			rememberedMap := make(map[string]interface{})
			start := time.Now()
			for _, c := range testCase.Calls {
				addAll(c.Args, rememberedMap)
				terr := call(suite, testCase, c, rememberedMap)
				if terr != nil {
					result.Error = terr
					break
				}
			}

			result.Duration = time.Since(start)

			reporter.Report(result)
		}
	}

	reporter.Flush()
}

func addAll(src, target map[string]interface{}) {
	for key, val := range src {
		target[key] = val
	}
}

func call(testSuite TestSuite, testCase TestCase, call Call, rememberMap map[string]interface{}) *TError {
	debug.Printf("Starting call: %s - %s", testSuite.Name, testCase.Name)
	terr := &TError{}

	on := call.On

	dat := []byte(on.Body)
	if on.BodyFile != "" {
		uri, err := toAbsPath(testSuite.Dir, on.BodyFile)
		if err != nil {
			terr.Cause = err
			return terr
		}

		if d, err := ioutil.ReadFile(uri); err == nil {
			dat = d
		} else {
			terr.Cause = fmt.Errorf("Can't read body file: %s", err.Error())
			return terr
		}
	}

	req, err := populateRequest(on, string(dat), rememberMap)
	if err != nil {
		terr.Cause = err
		return terr
	}

	printRequestInfo(req, dat)

	client := &http.Client{}

	resp, err := client.Do(req)

	if err != nil {
		debug.Print("Error when sending request", err)
		terr.Cause = err
		return terr
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		debug.Print("Error reading response")
		terr.Cause = err
		return terr
	}

	testResp := Response{http: *resp, body: body}
	terr.Resp = testResp

	info.Println(strings.Repeat("-", 50))
	info.Println(testResp.ToString())
	info.Println("")

	exps, err := expectations(call, testSuite.Dir)
	if err != nil {
		terr.Cause = err
		return terr
	}

	for _, exp := range exps {
		checkErr := exp.check(testResp)
		if checkErr != nil {
			terr.Cause = checkErr
			return terr
		}
	}

	m, err := testResp.parseBody()
	if err != nil {
		debug.Print("Can't parse response body to Map for [remember]")
		terr.Cause = err
		return terr
	}

	err = remember(m, call.Remember, rememberMap)
	debug.Print("Remember: ", rememberMap)
	if err != nil {
		debug.Print("Error remember")
		terr.Cause = err
		return terr
	}

	return nil
}

func populateRequest(on On, body string, rememberMap map[string]interface{}) (*http.Request, error) {

	urlStr, err := urlPrefix(populateRememberedVars(on.URL, rememberMap))
	if err != nil {
		return nil, errors.New("Cannot create request. Invalid url: " + on.URL)
	}

	body = populateRememberedVars(body, rememberMap)
	dat := []byte(body)

	req, err := http.NewRequest(on.Method, urlStr, bytes.NewBuffer(dat))
	if err != nil {
		return nil, err
	}

	for key, value := range on.Headers {
		req.Header.Add(key, populateRememberedVars(value, rememberMap))
	}

	q := req.URL.Query()
	for key, value := range on.Params {
		q.Add(key, populateRememberedVars(value, rememberMap))
	}
	req.URL.RawQuery = q.Encode()

	return req, nil
}

func urlPrefix(p string) (string, error) {
	if strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://") {
		return p, nil
	}

	return concatURL(hostFlag, p)
}

func concatURL(base string, p string) (string, error) {
	baseURL, err := url.ParseRequestURI(base)
	if err != nil {
		return "", err
	}
	return baseURL.Scheme + "://" + baseURL.Host + path.Join(baseURL.Path, p), nil
}

func populateRememberedVars(str string, rememberMap map[string]interface{}) string {
	res := str
	for varName, val := range rememberMap {
		placeholder := "{" + varName + "}"
		res = strings.Replace(res, placeholder, toString(val), -1)
	}
	return res
}

// toString returns value suitable to insert as an argument
// if value if a float where decimal part is zero - convert to int
func toString(rw interface{}) string {
	var sv interface{} = rw
	if fv, ok := rw.(float64); ok {
		_, frac := math.Modf(fv)
		if frac == 0 {
			sv = int(fv)
		}
	}

	return fmt.Sprintf("%v", sv)
}

func expectations(call Call, srcDir string) ([]ResponseExpectation, error) {
	var exps []ResponseExpectation
	if call.Expect.StatusCode != 0 {
		exps = append(exps, StatusCodeExpectation{statusCode: call.Expect.StatusCode})
	}

	if call.Expect.hasSchema() {
		var (
			schemeURI string
			err       error
		)

		if call.Expect.BodySchemaFile != "" {
			schemeURI, err = toAbsPath(srcDir, call.Expect.BodySchemaFile)
			if err != nil {
				return nil, err
			}
			schemeURI = "file:///" + schemeURI
		}

		if call.Expect.BodySchemaURI != "" {
			isHTTP := strings.HasPrefix(call.Expect.BodySchemaURI, "http://")
			isHTTPS := strings.HasPrefix(call.Expect.BodySchemaURI, "https://")
			if !(isHTTP || isHTTPS) {
				schemeURI = hostFlag + call.Expect.BodySchemaURI
			} else {
				schemeURI = call.Expect.BodySchemaURI
			}
		}
		exps = append(exps, BodySchemaExpectation{schemaURI: schemeURI})
	}

	if len(call.Expect.Body) > 0 {
		exps = append(exps, BodyExpectation{pathExpectations: call.Expect.Body})
	}

	if len(call.Expect.Absent) > 0 {
		exps = append(exps, AbsentExpectation{paths: call.Expect.Absent})
	}

	if len(call.Expect.Headers) > 0 {
		for k, v := range call.Expect.Headers {
			exps = append(exps, HeaderExpectation{Name: k, Value: v})
		}
	}

	if call.Expect.ContentType != "" {
		exps = append(exps, ContentTypeExpectation{call.Expect.ContentType})
	}

	// and so on
	return exps, nil
}

func toAbsPath(srcDir string, assetPath string) (string, error) {
	if filepath.IsAbs(assetPath) {
		// ignore srcDir
		return assetPath, nil
	}

	uri, err := filepath.Abs(filepath.Join(suiteDir, srcDir, assetPath))
	if err != nil {
		return "", errors.New("Invalid file path: " + assetPath)
	}

	return filepath.ToSlash(uri), nil
}

func remember(body interface{}, remember map[string]string, rememberedMap map[string]interface{}) (err error) {

	for varName, pathLine := range remember {

		if rememberVar, err := getByPath(body, pathLine); err == nil {
			rememberedMap[varName] = rememberVar
		} else {
			strErr := fmt.Sprintf("Remembered value not found, path: %v", pathLine)
			err = errors.New(strErr)
		}
		//fmt.Printf("v: %v\n", getByPath(bodyMap, b...))
	}

	return err
}

func printRequestInfo(req *http.Request, body []byte) {
	info.Println()
	info.Printf("%s %s %s\n", req.Method, req.URL.String(), req.Proto)

	if len(req.Header) > 0 {
		info.Println()
	}

	for k, v := range req.Header {
		info.Printf("%s: %s", k, strings.Join(v, " "))
	}
	info.Println()

	if len(body) > 0 {
		info.Printf(string(body))
	}
}
<|endoftext|>


<commit_before>// kylin project main.go
package main

import (
	"code.google.com/p/go.net/websocket"
	"fmt"
	"io"
	"kylin/cluster"
	"log"
	"net/http"
	"reflect"
)

// echo back the websocket.
func EchoServer(ws *websocket.Conn) {
	fmt.Println(ws.Request().RemoteAddr)
	fmt.Println(ws.RemoteAddr().String())
	io.Copy(ws, ws)
}

func main() {
	config := cluster.Config{"localhost:12345", []string{"localhost:12346"}}
	http.Handle("/echo", websocket.Handler(EchoServer))
	go func() {
		err := http.ListenAndServe(":12346", nil)
		if err != nil {
			panic(err.Error())
		}

	}()
	{
		ws, err := websocket.Dial("ws://localhost:12346/echo", "", config.Address)
		if err != nil {
			panic(err.Error())
		}
		if _, err := ws.Write([]byte("hello, world!\n")); err != nil {
			log.Fatal(err)
		}
		var msg = make([]byte, 512)
		if _, err := ws.Read(msg); err != nil {
			log.Fatal(err)
		}
		fmt.Println(msg)
	}

}
<commit_msg>delete unused main file<commit_after><|endoftext|>