<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/googollee/go-socket.io"

	"github.com/jesusrmoreno/toto/domain"
	"github.com/jesusrmoreno/toto/implementations"
	"github.com/jesusrmoreno/toto/utils"

	"github.com/BurntSushi/toml"
	"github.com/jesusrmoreno/sad-squid"

	"github.com/codegangsta/cli"
)

const Version = "No Version Provided"

// Events that are exposed to the client
const (
	groupAssignment = "group-assignment"
	roomMessage     = "room-message"
	leaveGroup      = "leave-group"
	joinGroup       = "join-group"
	joinGame        = "join-game"
	getPeers        = "get-peers"
	makeMove        = "make-move"
	moveMade        = "move-made"
	inQueue         = "in-queue"

	serverError = "server-error"
	clientError = "client-error"
)

// Response ...
type Response struct {
	Kind string                 `json:"kind"`
	Data map[string]interface{} `json:"data"`
}

// Method for creating errors more quickly.
func errorResponse(kind, err string) Response {
	d := map[string]interface{}{}
	d["error"] = err
	r := Response{
		Kind: kind,
		Data: d,
	}
	return r
}

// GamesInfo serves to store the metadata for different games
type GamesInfo struct {
	// These must be thread safe so we use the ConcurrentMap types
	TurnMap *utils.ConcurrentStringIntMap
	// Maps the player id to the room
	RoomMap *utils.ConcurrentStringMap
}

// ReadGameFiles reads the provided directory for files that conform to the
// game struct definition, these must be json files, and loads them into our
// game map.
func ReadGameFiles(gameDir string) (domain.GameMap, error) {
	files, err := filepath.Glob(gameDir + "/*.toml")
	gm := domain.GameMap{}
	if err != nil {
		return nil, err
	}
	for _, f := range files {
		raw, err := os.Open(f)
		defer raw.Close()
		if err != nil {
			return nil, err
		}
		r := io.Reader(raw)
		dummy := domain.Game{}
		if meta, err := toml.DecodeReader(r, &dummy); err != nil {
			log.Println(meta)
			return nil, errors.New("Invalid configuration in file: " + f)
		}
		g := domain.Game{
			Players: dummy.Players,
			Title:   dummy.Title,
			UUID:    dummy.UUID,
			Lobby: impl.Lobby{
				// We implement our lobby as a buffered channel that takes the number of
				// players specified in the config file for the game and makes that the
				// cap.
				Queue: make(chan domain.Player, dummy.Players),
			},
		}
		g.FileName = f
		if _, exists := gm[g.UUID]; exists {
			return nil, errors.New("uniqueKey conflict between: " + f + " and " + gm[g.UUID].FileName)
		}
		gm[g.UUID] = g
	}
	return gm, nil
}

// QueuePlayers adds players to the game's lobby to wait for a partner.
// Players are queued on a first come first serve basis.
func QueuePlayers(g domain.Game, p domain.Player) {
	data := map[string]interface{}{}
	data["message"] = "You are in the queue for game: " + g.Title
	r := Response{
		Kind: inQueue,
		Data: data,
	}
	p.Comm.Emit(inQueue, r)
	pq := g.Lobby
	pq.AddToQueue(p)
}

// GroupPlayers creates groups of players of size PlayerSize as defined in the
// game files.
func GroupPlayers(g domain.Game, server *socketio.Server, gi *GamesInfo) {
	pq := g.Lobby
	n := g.Players
	for {
		select {
		default:
			if g.Lobby.Size() >= n {
				team := []domain.Player{}
				// Generate a room id
				roomName := squid.GenerateSimpleID()
				for i := 0; i < n; i++ {
					p := pq.PopFromQueue()
					pID := p.Comm.Id()
					team = append(team, p)

					// Set the metadata
					gi.RoomMap.Set(pID, roomName)
					gi.TurnMap.Set(roomName+":"+pID, i)

					// Place the player in the created room.
					p.Comm.Join(roomName)

					// Create the response
					data := map[string]interface{}{}
					data["roomName"] = roomName
					data["turnNumber"] = i
					r := Response{
						Kind: inQueue,
						Data: data,
					}
					p.Comm.Emit(groupAssignment, r)
				}

				// Create the response
				data := map[string]interface{}{}
				data["message"] = fmt.Sprintf("Welcome to %s", roomName)
				r := Response{
					Kind: roomMessage,
					Data: data,
				}
				server.BroadcastTo(roomName, roomMessage, r)
			}
		}
	}
}

// StartServer ...
func StartServer(c *cli.Context) {
	games, err := ReadGameFiles("./games")
	for key, game := range games {
		log.Println("Loaded:", key, "from", game.FileName)
	}
	if err != nil {
		log.Fatal(err)
	}

	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	info := GamesInfo{
		RoomMap: utils.NewConcurrentStringMap(),
		TurnMap: utils.NewConcurrentStringIntMap(),
	}
	for key := range games {
		go GroupPlayers(games[key], server, &info)
	}
	server.On("connection", func(so socketio.Socket) {
		// Makes it so that the player joins a room with his/her unique id.
		so.Join(so.Id())
		so.On(joinGame, func(req json.RawMessage) {
			m := map[string]string{}
			if err := json.Unmarshal(req, &m); err != nil {
				so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
			}
			gameID, exists := m["gameId"]
			if !exists {
				so.Emit(clientError, errorResponse(clientError, "Must include GameID"))
			}
			// If the player attempts to connect to a game we first have to make
			// sure that they are joining a game that is registered with our server.
			if g, exists := games[gameID]; exists {
				QueuePlayers(g, domain.Player{
					Comm: so,
				})
			} else {
				so.Emit(clientError, errorResponse(clientError, "Invalid GameID"))
			}
		})
		so.On(makeMove, func(move json.RawMessage) {
			room, exists := info.RoomMap.Get(so.Id())
			if exists {
				m := map[string]interface{}{}
				if err := json.Unmarshal(move, &m); err != nil {
					so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
				}
				turn, exists := info.TurnMap.Get(room + ":" + so.Id())
				if !exists {
					so.Emit(serverError, errorResponse(serverError, "No turn assigned"))
				}
				// Overwrites who's turn it is using the turn map assigned at join.
				m["madeBy"] = turn
				m["madeById"] = so.Id()
				r := Response{
					Kind: moveMade,
					Data: m,
				}
				so.BroadcastTo(room, moveMade, r)
			} else {
				so.Emit(serverError, errorResponse(serverError, "Not in any Room"))
			}
		})
	})

	port := c.String("port")
	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("./asset")))
	log.Println("Serving at localhost:" + port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

func main() {
	app := cli.NewApp()
	app.Name = "Toto"
	app.Usage = "a server for creating quick prototype websocket based games."
	app.Action = StartServer
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "port, p",
			Value: "3000",
			Usage: "The port to run the server on",
		},
	}
	app.Run(os.Args)
}
<commit_msg>Feature: Add cli flags<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"

	"github.com/googollee/go-socket.io"

	"github.com/jesusrmoreno/toto/domain"
	"github.com/jesusrmoreno/toto/implementations"
	"github.com/jesusrmoreno/toto/utils"

	"github.com/BurntSushi/toml"
	"github.com/jesusrmoreno/sad-squid"

	"github.com/codegangsta/cli"
)

// Version ...
var Version = "No Version Provided"

// Events that are exposed to the client
const (
	groupAssignment = "group-assignment"
	roomMessage     = "room-message"
	leaveGroup      = "leave-group"
	joinGroup       = "join-group"
	joinGame        = "join-game"
	getPeers        = "get-peers"
	makeMove        = "make-move"
	moveMade        = "move-made"
	inQueue         = "in-queue"

	serverError = "server-error"
	clientError = "client-error"
)

// Response ...
type Response struct {
	Kind string                 `json:"kind"`
	Data map[string]interface{} `json:"data"`
}

// Method for creating errors more quickly.
func errorResponse(kind, err string) Response {
	d := map[string]interface{}{}
	d["error"] = err
	r := Response{
		Kind: kind,
		Data: d,
	}
	return r
}

// GamesInfo serves to store the metadata for different games
type GamesInfo struct {
	// These must be thread safe so we use the ConcurrentMap types
	TurnMap *utils.ConcurrentStringIntMap
	// Maps the player id to the room
	RoomMap *utils.ConcurrentStringMap
}

// ReadGameFiles reads the provided directory for files that conform to the
// game struct definition, these must be json files, and loads them into our
// game map.
func ReadGameFiles(gameDir string) (domain.GameMap, error) {
	files, err := filepath.Glob(gameDir + "/*.toml")
	gm := domain.GameMap{}
	if err != nil {
		return nil, err
	}
	for _, f := range files {
		raw, err := os.Open(f)
		defer raw.Close()
		if err != nil {
			return nil, err
		}
		r := io.Reader(raw)
		dummy := domain.Game{}
		if meta, err := toml.DecodeReader(r, &dummy); err != nil {
			log.Println(meta)
			return nil, errors.New("Invalid configuration in file: " + f)
		}
		g := domain.Game{
			Players: dummy.Players,
			Title:   dummy.Title,
			UUID:    dummy.UUID,
			Lobby: impl.Lobby{
				// We implement our lobby as a buffered channel that takes the number of
				// players specified in the config file for the game and makes that the
				// cap.
				Queue: make(chan domain.Player, dummy.Players),
			},
		}
		g.FileName = f
		if _, exists := gm[g.UUID]; exists {
			return nil, errors.New("uniqueKey conflict between: " + f + " and " + gm[g.UUID].FileName)
		}
		gm[g.UUID] = g
	}
	return gm, nil
}

// QueuePlayers adds players to the game's lobby to wait for a partner.
// Players are queued on a first come first serve basis.
func QueuePlayers(g domain.Game, p domain.Player) {
	data := map[string]interface{}{}
	data["message"] = "You are in the queue for game: " + g.Title
	r := Response{
		Kind: inQueue,
		Data: data,
	}
	p.Comm.Emit(inQueue, r)
	pq := g.Lobby
	pq.AddToQueue(p)
}

// GroupPlayers creates groups of players of size PlayerSize as defined in the
// game files.
func GroupPlayers(g domain.Game, server *socketio.Server, gi *GamesInfo) {
	pq := g.Lobby
	n := g.Players
	for {
		select {
		default:
			if g.Lobby.Size() >= n {
				team := []domain.Player{}
				// Generate a room id
				roomName := squid.GenerateSimpleID()
				for i := 0; i < n; i++ {
					p := pq.PopFromQueue()
					pID := p.Comm.Id()
					team = append(team, p)

					// Set the metadata
					gi.RoomMap.Set(pID, roomName)
					gi.TurnMap.Set(roomName+":"+pID, i)

					// Place the player in the created room.
					p.Comm.Join(roomName)

					// Create the response
					data := map[string]interface{}{}
					data["roomName"] = roomName
					data["turnNumber"] = i
					r := Response{
						Kind: inQueue,
						Data: data,
					}
					p.Comm.Emit(groupAssignment, r)
				}

				// Create the response
				data := map[string]interface{}{}
				data["message"] = fmt.Sprintf("Welcome to %s", roomName)
				r := Response{
					Kind: roomMessage,
					Data: data,
				}
				server.BroadcastTo(roomName, roomMessage, r)
			}
		}
	}
}

// StartServer ...
func StartServer(c *cli.Context) {
	games, err := ReadGameFiles("./games")
	for key, game := range games {
		log.Println("Loaded:", key, "from", game.FileName)
	}
	if err != nil {
		log.Fatal(err)
	}

	server, err := socketio.NewServer(nil)
	if err != nil {
		log.Fatal(err)
	}

	info := GamesInfo{
		RoomMap: utils.NewConcurrentStringMap(),
		TurnMap: utils.NewConcurrentStringIntMap(),
	}
	for key := range games {
		go GroupPlayers(games[key], server, &info)
	}
	server.On("connection", func(so socketio.Socket) {
		// Makes it so that the player joins a room with his/her unique id.
		so.Join(so.Id())
		so.On(joinGame, func(req json.RawMessage) {
			m := map[string]string{}
			if err := json.Unmarshal(req, &m); err != nil {
				so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
			}
			gameID, exists := m["gameId"]
			if !exists {
				so.Emit(clientError, errorResponse(clientError, "Must include GameID"))
			}
			// If the player attempts to connect to a game we first have to make
			// sure that they are joining a game that is registered with our server.
			if g, exists := games[gameID]; exists {
				QueuePlayers(g, domain.Player{
					Comm: so,
				})
			} else {
				so.Emit(clientError, errorResponse(clientError, "Invalid GameID"))
			}
		})
		so.On(makeMove, func(move json.RawMessage) {
			room, exists := info.RoomMap.Get(so.Id())
			if exists {
				m := map[string]interface{}{}
				if err := json.Unmarshal(move, &m); err != nil {
					so.Emit(clientError, errorResponse(clientError, "Invalid JSON"))
				}
				turn, exists := info.TurnMap.Get(room + ":" + so.Id())
				if !exists {
					so.Emit(serverError, errorResponse(serverError, "No turn assigned"))
				}
				// Overwrites who's turn it is using the turn map assigned at join.
				m["madeBy"] = turn
				m["madeById"] = so.Id()
				r := Response{
					Kind: moveMade,
					Data: m,
				}
				so.BroadcastTo(room, moveMade, r)
			} else {
				so.Emit(serverError, errorResponse(serverError, "Not in any Room"))
			}
		})
	})

	port := c.String("port")
	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("./asset")))
	log.Println("Serving at localhost:" + port)
	log.Fatal(http.ListenAndServe(":"+port, nil))
}

func main() {
	app := cli.NewApp()
	app.Name = "Toto"
	app.Usage = "a server for creating quick prototype websocket based games."
	app.Action = StartServer
	app.Version = Version
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "port, p",
			Value: "3000",
			Usage: "The port to run the server on",
		},
	}
	app.Run(os.Args)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/alistanis/st/flags"
	"github.com/alistanis/st/parse"
)

func run() int {
	flag.Usage = usage
	err := flags.ParseFlags()
	if err != nil {
		fmt.Println(err)
		return -1
	}

	options := &parse.Options{
		Tag:        flags.Tag,
		Case:       flags.Case,
		AppendMode: flags.AppendMode,
		TagMode:    flags.TagMode,
		// this is confusing, I'll fix it later when changing documentation/flags behavior
		DryRun:  !flags.Write,
		Verbose: flags.Verbose}
	parse.SetOptions(options)
	err = parse.ParseAndProcessFiles(flag.Args())
	if err != nil {
		fmt.Println(err)
		return -1
	}
	return 0
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: st [flags] [path ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	os.Exit(run())
}
<commit_msg>start adding test files and test data<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	"github.com/alistanis/st/flags"
	"github.com/alistanis/st/parse"
)

func run() int {
	flag.Usage = usage
	err := flags.ParseFlags()
	if err != nil {
		fmt.Println(err)
		return -1
	}

	options := &parse.Options{
		Tag:        flags.Tag,
		Case:       flags.Case,
		AppendMode: flags.AppendMode,
		TagMode:    flags.TagMode,
		// this is confusing, I'll fix it later when changing documentation/flags behavior
		DryRun:  !flags.Write,
		Verbose: flags.Verbose}
	parse.SetOptions(options)
	err = parse.ParseAndProcessFiles(flag.Args())
	if err != nil {
		fmt.Println(err)
		return -1
	}
	return 0
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: st [flags] [path ...]\n")
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	os.Exit(run())
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/x509"
	"flag"
	"fmt"
	"github.com/rossdylan/sslcheck/sclib"
	"os"
	"strings"
)

var email string
var warning bool

func init() {
	flag.StringVar(&email, "email", "", "Send a full report to the given email")
	flag.BoolVar(&warning, "warning", false, "Send a warning report listing certs close to expiration")
}

//Main function, sets up all the channels needed for communication
//and grabs the uris to parse out of the arguments. We also monitor
//a channel to make sure all our workers die
func main() {
	flag.Parse()
	queue := make(chan *x509.Certificate, 10)
	var numCerts int
	numCerts = 0
	for _, arg := range os.Args[1:] {
		if strings.Contains(arg, ":") {
			go sclib.CertGrabber(arg, queue)
			numCerts += 1
		}
	}
	if numCerts == 0 {
		fmt.Println("Enter at least 1 service")
		return
	}
	var count int
	count = 0
	var certs sclib.Certificates
	certs = make(sclib.Certificates, numCerts)
	for cert := range queue {
		if cert != nil {
			certs[count] = cert
			count++
		}
		if count == numCerts {
			break
		}
	}
	var report string
	report = sclib.GenerateReport(certs, warning)
	if email != "" {
		if report == "" {
			return
		}
		sclib.MailReport(report, email)
	} else {
		fmt.Println(report)
	}
}
<commit_msg>Improve usage output to align with actual options.<commit_after>package main

import (
	"crypto/x509"
	"flag"
	"fmt"
	"github.com/rossdylan/sslcheck/sclib"
	"os"
	"strings"
	"path/filepath"
)

var email string
var warning bool

func init() {
	flag.StringVar(&email, "email", "", "Send a full report to the given email")
	flag.BoolVar(&warning, "warning", false, "Send a warning report listing certs close to expiration")
}

//Main function, sets up all the channels needed for communication
//and grabs the uris to parse out of the arguments. We also monitor
//a channel to make sure all our workers die
func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] [host:port ...]\n", filepath.Base(os.Args[0]))
		fmt.Println("\nOptions:")
		flag.PrintDefaults()
	}
	flag.Parse()
	queue := make(chan *x509.Certificate, 10)
	var numCerts int
	numCerts = 0
	for _, arg := range os.Args[1:] {
		if strings.Contains(arg, ":") {
			go sclib.CertGrabber(arg, queue)
			numCerts += 1
		}
	}
	if numCerts == 0 {
		fmt.Println("Enter at least 1 service")
		return
	}
	var count int
	count = 0
	var certs sclib.Certificates
	certs = make(sclib.Certificates, numCerts)
	for cert := range queue {
		if cert != nil {
			certs[count] = cert
			count++
		}
		if count == numCerts {
			break
		}
	}
	var report string
	report = sclib.GenerateReport(certs, warning)
	if email != "" {
		if report == "" {
			return
		}
		sclib.MailReport(report, email)
	} else {
		fmt.Println(report)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/mbndr/logo"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"time"
)

const (
	VERSION     = "0.1.2"
	minDuration = time.Duration(15) * time.Minute
	maxDuration = time.Duration(36) * time.Hour
)

var (
	listRoles       *bool
	listMfa         *bool
	showExpire      *bool
	sesCreds        *bool
	refresh         *bool
	verbose         *bool
	version         *bool
	makeConf        *bool
	profile         *string
	duration        *time.Duration
	cmd             *[]string
	defaultDuration = time.Duration(12) * time.Hour
	cacheDir        = filepath.Dir(defaults.SharedCredentialsFilename())
	logLevel        = logo.WARN
)

func init() {
	const (
		cmdDesc         = "Create an environment for interacting with the AWS API using an assumed role"
		durationArgDesc = "duration of the retrieved session token"
		listRoleArgDesc = "list role ARNs you are able to assume"
		listMfaArgDesc  = "list the ARN of the MFA device associated with your account"
		showExpArgDesc  = "Show token expiration time"
		sesCredArgDesc  = "print eval()-able session token info, or run command using session token credentials"
		refreshArgDesc  = "force a refresh of the cached credentials"
		verboseArgDesc  = "print verbose/debug messages"
		profileArgDesc  = "name of profile"
		cmdArgDesc      = "command to execute using configured profile"
		makeConfArgDesc = "Build an AWS extended switch-role plugin configuration for all available roles"
	)

	duration = kingpin.Flag("duration", durationArgDesc).Short('d').Default(defaultDuration.String()).Duration()
	listRoles = kingpin.Flag("list-roles", listRoleArgDesc).Short('l').Bool()
	listMfa = kingpin.Flag("list-mfa", listMfaArgDesc).Short('m').Bool()
	showExpire = kingpin.Flag("expiration", showExpArgDesc).Short('e').Bool()
	makeConf = kingpin.Flag("make-conf", makeConfArgDesc).Short('c').Bool()
	sesCreds = kingpin.Flag("session", sesCredArgDesc).Short('s').Bool()
	refresh = kingpin.Flag("refresh", refreshArgDesc).Short('r').Bool()
	verbose = kingpin.Flag("verbose", verboseArgDesc).Short('v').Bool()
	profile = kingpin.Arg("profile", profileArgDesc).Default("default").String()
	cmd = CmdArg(kingpin.Arg("cmd", cmdArgDesc))

	kingpin.Version(VERSION)
	kingpin.CommandLine.VersionFlag.Short('V')
	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.CommandLine.Help = cmdDesc
}

func dedupAndSort(ary *[]string) *[]string {
	m := make(map[string]bool)

	// dedup
	for _, v := range *ary {
		trimV := strings.TrimSpace(v)
		if len(trimV) > 0 {
			m[trimV] = true
		}
	}

	// array-ify
	i := 0
	newAry := make([]string, len(m))
	for k := range m {
		newAry[i] = k
		i++
	}

	// sort & return
	sort.Strings(newAry)
	return &newAry
}

func printCredentials(creds credentials.Value) {
	exportToken := "export"
	switch runtime.GOOS {
	case "windows":
		exportToken = "set"
	}

	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_ACCESS_KEY_ID", creds.AccessKeyID)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SESSION_TOKEN", creds.SessionToken)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SECURITY_TOKEN", creds.SessionToken)
}

func getIamUser(sess *session.Session, log *logo.Logger) *iam.User {
	s := iam.New(sess)

	u, err := s.GetUser(&iam.GetUserInput{})
	if err != nil {
		log.Fatalf("Error getting IAM user info: %v", err)
	}

	log.Debugf("USER: %+v", u)
	return u.User
}

func getRoles(sess *session.Session, userName *string, log *logo.Logger) *[]string {
	s := iam.New(sess)

	// Used to return an array of role ARN's available to the user
	roles := make([]string, 0)

	urg_logger := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.UserRoleGetter", true)
	urg := UserRoleGetter{Client: s, Logger: urg_logger}
	roles = append(roles, *urg.FetchRoles(*userName)...)

	i := iam.ListGroupsForUserInput{UserName: userName}
	grg_logger := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.GroupRoleGetter", true)
	grg := GroupRoleGetter{Client: s, Logger: grg_logger}
	truncated := true
	for truncated {
		g, err := s.ListGroupsForUser(&i)
		if err != nil {
			log.Errorf("Error getting user's IAM group list: %v", err)
			break
		}

		if *verbose {
			for x, grp := range g.Groups {
				log.Debugf("GROUP[%d]: %s", x, *grp.GroupName)
			}
		}
		roles = append(roles, *grg.FetchRoles(g.Groups...)...)

		truncated = *g.IsTruncated
		if truncated {
			i.Marker = g.Marker
		}
	}

	dedupAndSort(&roles)
	return &roles
}

func getAWSSession() *session.Session {
	//  Unset the environment
	env := []string{"AWS_SECRET_ACCESS_KEY", "AWS_ACCESS_KEY_ID", "AWS_SESSION_TOKEN", "AWS_SECURITY_TOKEN"}
	for _, env := range env {
		os.Unsetenv(env)
	}

	// This is how to get the MFA and AssumeRole config for a given profile.
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState:       session.SharedConfigEnable,
		Profile:                 *profile,
		AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
	}))

	return sess
}

func main() {
	kingpin.Parse()

	if *verbose {
		logLevel = logo.DEBUG
	}

	log := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.main", true)

	if *duration < minDuration || *duration > maxDuration {
		log.Warnf("Duration should be between %s and %s, using default of %s",
			minDuration.String(), maxDuration.String(), defaultDuration.String())
		duration = &defaultDuration
	}

	// These are magic words to change AssumeRole credential expiration
	stscreds.DefaultDuration = time.Duration(1) * time.Hour

	log.Debugf("PROFILE: %s", *profile)
	sess := getAWSSession()

	switch {
	case *listMfa:
		log.Debug("List MFA")
		s := iam.New(sess)

		res, err := s.ListMFADevices(&iam.ListMFADevicesInput{})
		if err != nil {
			log.Fatalf("Error listing MFA devices: %v", err)
		}

		fmt.Printf("%s\n", *res.MFADevices[0].SerialNumber)
	case *listRoles, *makeConf:
		u := getIamUser(sess, log)
		userName := *u.UserName

		roles := getRoles(sess, &userName, log)

		if *listRoles {
			log.Debug("List Roles")
			fmt.Printf("Available role ARNs for %s (%s)\n", userName, *u.Arn)
			for _, v := range *roles {
				fmt.Printf("  %s\n", v)
			}
		}

		if *makeConf {
			log.Debug("Make Configuration Files.")
			// TODO create .aws/config formatted output based on result of getRoles()
		}
	default:
		cfgParser := AWSConfigParser{Logger: logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.AWSConfigParser", true)}
		profile_cfg, err := cfgParser.GetProfile(profile)
		if err != nil {
			log.Fatalf("Unable to get configuration for profile '%s': %+v", *profile, err)
		}

		credProvider := CachingSessionTokenProvider{
			Profile:  profile_cfg.SourceProfile,
			Duration: *duration,
			Logger:   logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.CachingSessionTokenProvider", true),
		}

		if len(profile_cfg.MfaSerial) > 0 {
			credProvider.MfaSerial = profile_cfg.MfaSerial
		}

		if *refresh {
			os.Remove(credProvider.CacheFile())
		}

		p := credentials.NewCredentials(&credProvider)
		creds, err := p.Get()
		if err != nil {
			log.Fatalf("Unable to get SessionToken credentials: +%v", err)
		}

		if *showExpire {
			exp_t := credProvider.ExpirationTime()
			fmt.Printf("Session credentials will expire on %s (%s)\n", exp_t, exp_t.Sub(time.Now()).Round(time.Second))
			os.Exit(0)
		}

		if !*sesCreds {
			creds, err = credProvider.AssumeRole(profile_cfg)
			if err != nil {
				log.Fatalf("Error doing AssumeRole: %+v", err)
			}
		}

		if len(*cmd) > 1 {
			os.Setenv("AWS_ACCESS_KEY_ID", creds.AccessKeyID)
			os.Setenv("AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)
			if len(creds.SessionToken) > 0 {
				os.Setenv("AWS_SESSION_TOKEN", creds.SessionToken)
				os.Setenv("AWS_SECURITY_TOKEN", creds.SessionToken)
			}

			c := exec.Command((*cmd)[0], (*cmd)[1:]...)
			c.Stdin = os.Stdin
			c.Stdout = os.Stdout
			c.Stderr = os.Stderr

			err := c.Run()
			if err != nil {
				log.Debug("Error running command")
				log.Fatalf("%v", err)
			}
		} else {
			printCredentials(creds)
		}
	}
}
<commit_msg>version bump for release<commit_after>package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/credentials/stscreds"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/iam"
	"github.com/mbndr/logo"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"sort"
	"strings"
	"time"
)

const (
	VERSION     = "0.1.3"
	minDuration = time.Duration(15) * time.Minute
	maxDuration = time.Duration(36) * time.Hour
)

var (
	listRoles       *bool
	listMfa         *bool
	showExpire      *bool
	sesCreds        *bool
	refresh         *bool
	verbose         *bool
	version         *bool
	makeConf        *bool
	profile         *string
	duration        *time.Duration
	cmd             *[]string
	defaultDuration = time.Duration(12) * time.Hour
	cacheDir        = filepath.Dir(defaults.SharedCredentialsFilename())
	logLevel        = logo.WARN
)

func init() {
	const (
		cmdDesc         = "Create an environment for interacting with the AWS API using an assumed role"
		durationArgDesc = "duration of the retrieved session token"
		listRoleArgDesc = "list role ARNs you are able to assume"
		listMfaArgDesc  = "list the ARN of the MFA device associated with your account"
		showExpArgDesc  = "Show token expiration time"
		sesCredArgDesc  = "print eval()-able session token info, or run command using session token credentials"
		refreshArgDesc  = "force a refresh of the cached credentials"
		verboseArgDesc  = "print verbose/debug messages"
		profileArgDesc  = "name of profile"
		cmdArgDesc      = "command to execute using configured profile"
		makeConfArgDesc = "Build an AWS extended switch-role plugin configuration for all available roles"
	)

	duration = kingpin.Flag("duration", durationArgDesc).Short('d').Default(defaultDuration.String()).Duration()
	listRoles = kingpin.Flag("list-roles", listRoleArgDesc).Short('l').Bool()
	listMfa = kingpin.Flag("list-mfa", listMfaArgDesc).Short('m').Bool()
	showExpire = kingpin.Flag("expiration", showExpArgDesc).Short('e').Bool()
	makeConf = kingpin.Flag("make-conf", makeConfArgDesc).Short('c').Bool()
	sesCreds = kingpin.Flag("session", sesCredArgDesc).Short('s').Bool()
	refresh = kingpin.Flag("refresh", refreshArgDesc).Short('r').Bool()
	verbose = kingpin.Flag("verbose", verboseArgDesc).Short('v').Bool()
	profile = kingpin.Arg("profile", profileArgDesc).Default("default").String()
	cmd = CmdArg(kingpin.Arg("cmd", cmdArgDesc))

	kingpin.Version(VERSION)
	kingpin.CommandLine.VersionFlag.Short('V')
	kingpin.CommandLine.HelpFlag.Short('h')
	kingpin.CommandLine.Help = cmdDesc
}

func dedupAndSort(ary *[]string) *[]string {
	m := make(map[string]bool)

	// dedup
	for _, v := range *ary {
		trimV := strings.TrimSpace(v)
		if len(trimV) > 0 {
			m[trimV] = true
		}
	}

	// array-ify
	i := 0
	newAry := make([]string, len(m))
	for k := range m {
		newAry[i] = k
		i++
	}

	// sort & return
	sort.Strings(newAry)
	return &newAry
}

func printCredentials(creds credentials.Value) {
	exportToken := "export"
	switch runtime.GOOS {
	case "windows":
		exportToken = "set"
	}

	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_ACCESS_KEY_ID", creds.AccessKeyID)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SESSION_TOKEN", creds.SessionToken)
	fmt.Printf("%s %s='%s'\n", exportToken, "AWS_SECURITY_TOKEN", creds.SessionToken)
}

func getIamUser(sess *session.Session, log *logo.Logger) *iam.User {
	s := iam.New(sess)

	u, err := s.GetUser(&iam.GetUserInput{})
	if err != nil {
		log.Fatalf("Error getting IAM user info: %v", err)
	}

	log.Debugf("USER: %+v", u)
	return u.User
}

func getRoles(sess *session.Session, userName *string, log *logo.Logger) *[]string {
	s := iam.New(sess)

	// Used to return an array of role ARN's available to the user
	roles := make([]string, 0)

	urg_logger := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.UserRoleGetter", true)
	urg := UserRoleGetter{Client: s, Logger: urg_logger}
	roles = append(roles, *urg.FetchRoles(*userName)...)

	i := iam.ListGroupsForUserInput{UserName: userName}
	grg_logger := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.GroupRoleGetter", true)
	grg := GroupRoleGetter{Client: s, Logger: grg_logger}
	truncated := true
	for truncated {
		g, err := s.ListGroupsForUser(&i)
		if err != nil {
			log.Errorf("Error getting user's IAM group list: %v", err)
			break
		}

		if *verbose {
			for x, grp := range g.Groups {
				log.Debugf("GROUP[%d]: %s", x, *grp.GroupName)
			}
		}
		roles = append(roles, *grg.FetchRoles(g.Groups...)...)

		truncated = *g.IsTruncated
		if truncated {
			i.Marker = g.Marker
		}
	}

	dedupAndSort(&roles)
	return &roles
}

func getAWSSession() *session.Session {
	//  Unset the environment
	env := []string{"AWS_SECRET_ACCESS_KEY", "AWS_ACCESS_KEY_ID", "AWS_SESSION_TOKEN", "AWS_SECURITY_TOKEN"}
	for _, env := range env {
		os.Unsetenv(env)
	}

	// This is how to get the MFA and AssumeRole config for a given profile.
	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState:       session.SharedConfigEnable,
		Profile:                 *profile,
		AssumeRoleTokenProvider: stscreds.StdinTokenProvider,
	}))

	return sess
}

func main() {
	kingpin.Parse()

	if *verbose {
		logLevel = logo.DEBUG
	}

	log := logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.main", true)

	if *duration < minDuration || *duration > maxDuration {
		log.Warnf("Duration should be between %s and %s, using default of %s",
			minDuration.String(), maxDuration.String(), defaultDuration.String())
		duration = &defaultDuration
	}

	// These are magic words to change AssumeRole credential expiration
	stscreds.DefaultDuration = time.Duration(1) * time.Hour

	log.Debugf("PROFILE: %s", *profile)
	sess := getAWSSession()

	switch {
	case *listMfa:
		log.Debug("List MFA")
		s := iam.New(sess)

		res, err := s.ListMFADevices(&iam.ListMFADevicesInput{})
		if err != nil {
			log.Fatalf("Error listing MFA devices: %v", err)
		}

		fmt.Printf("%s\n", *res.MFADevices[0].SerialNumber)
	case *listRoles, *makeConf:
		u := getIamUser(sess, log)
		userName := *u.UserName

		roles := getRoles(sess, &userName, log)

		if *listRoles {
			log.Debug("List Roles")
			fmt.Printf("Available role ARNs for %s (%s)\n", userName, *u.Arn)
			for _, v := range *roles {
				fmt.Printf("  %s\n", v)
			}
		}

		if *makeConf {
			log.Debug("Make Configuration Files.")
			// TODO create .aws/config formatted output based on result of getRoles()
		}
	default:
		cfgParser := AWSConfigParser{Logger: logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.AWSConfigParser", true)}
		profile_cfg, err := cfgParser.GetProfile(profile)
		if err != nil {
			log.Fatalf("Unable to get configuration for profile '%s': %+v", *profile, err)
		}

		credProvider := CachingSessionTokenProvider{
			Profile:  profile_cfg.SourceProfile,
			Duration: *duration,
			Logger:   logo.NewSimpleLogger(os.Stderr, logLevel, "aws-runas.CachingSessionTokenProvider", true),
		}

		if len(profile_cfg.MfaSerial) > 0 {
			credProvider.MfaSerial = profile_cfg.MfaSerial
		}

		if *refresh {
			os.Remove(credProvider.CacheFile())
		}

		p := credentials.NewCredentials(&credProvider)
		creds, err := p.Get()
		if err != nil {
			log.Fatalf("Unable to get SessionToken credentials: +%v", err)
		}

		if *showExpire {
			exp_t := credProvider.ExpirationTime()
			fmt.Printf("Session credentials will expire on %s (%s)\n", exp_t, exp_t.Sub(time.Now()).Round(time.Second))
			os.Exit(0)
		}

		if !*sesCreds {
			creds, err = credProvider.AssumeRole(profile_cfg)
			if err != nil {
				log.Fatalf("Error doing AssumeRole: %+v", err)
			}
		}

		if len(*cmd) > 1 {
			os.Setenv("AWS_ACCESS_KEY_ID", creds.AccessKeyID)
			os.Setenv("AWS_SECRET_ACCESS_KEY", creds.SecretAccessKey)
			if len(creds.SessionToken) > 0 {
				os.Setenv("AWS_SESSION_TOKEN", creds.SessionToken)
				os.Setenv("AWS_SECURITY_TOKEN", creds.SessionToken)
			}

			c := exec.Command((*cmd)[0], (*cmd)[1:]...)
			c.Stdin = os.Stdin
			c.Stdout = os.Stdout
			c.Stderr = os.Stderr

			err := c.Run()
			if err != nil {
				log.Debug("Error running command")
				log.Fatalf("%v", err)
			}
		} else {
			printCredentials(creds)
		}
	}
}
<|endoftext|>


<commit_before>/*

rtop-vis - ad hoc cluster monitoring over SSH

Copyright (c) 2015 RapidLoop

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"syscall"
	"time"
)

const (
	VERSION          = "0.1"
	DEFAULT_REFRESH  = 5 // default refresh interval in seconds
	DEFAULT_WEB_ADDR = "0.0.0.0:8080"
	HISTORY_LENGTH   = 10 * 60 / DEFAULT_REFRESH // for 10 minutes
)

var (
	currentUser   *user.User
	sshConfigRead bool
	allStats      *HostStats
)

func usage(code int) {
	fmt.Printf(
		`rtop-vis %s - (c) 2015 RapidLoop - MIT Licensed - http://rtop-monitor.org/rtop-vis
rtop-vis monitors system stats for a cluster over SSH

Usage: rtop-vis host [host ...]

    host
        one or more host to monitor, "ssh host" should work without password

After invoking, web UI will be available on http://localhost:8080/. Stats will
be collected every 5 seconds and graphs will refresh every 10 seconds. Graphs
will show 10 minutes of history.
`, VERSION)
	os.Exit(code)
}

func main() {

	if len(os.Args) == 1 {
		usage(1)
	}

	log.SetPrefix("rtop-vis: ")
	log.SetFlags(0)

	// get current user
	var err error
	currentUser, err = user.Current()
	if err != nil {
		log.Print(err)
		return
	}

	// read from ~/.ssh/config if possible
	sshConfig := filepath.Join(currentUser.HomeDir, ".ssh", "config")
	if _, err := os.Stat(sshConfig); err == nil {
		sshConfigRead = parseSshConfig(sshConfig)
	}

	// start connecting
	allStats = NewHostStats(HISTORY_LENGTH)
	for _, host := range os.Args[1:] {
		go doHost(host)
	}

	// start the web server
	go startWeb()

	// wait for ^C
	ch := make(chan os.Signal, 1)
	signal.Notify(ch)
	for s := range ch {
		if s == syscall.SIGTERM || s == os.Interrupt {
			break
		}
	}
	signal.Stop(ch)
	close(ch)
}

func doHost(host string) {

	var (
		port          int
		username, key string
	)

	if sshConfigRead {
		shost, sport, suser, skey := getSshEntry(host)
		if len(shost) > 0 {
			host = shost
		}
		if sport != 0 {
			port = sport
		}
		if len(suser) > 0 {
			username = suser
		}
		if len(skey) > 0 {
			key = skey
		}
	}

	// fill in still-unknown ones with defaults
	if port == 0 {
		port = 22
	}
	if len(username) == 0 {
		username = currentUser.Username
	}
	if len(key) == 0 {
		idrsap := filepath.Join(currentUser.HomeDir, ".ssh", "id_rsa")
		if _, err := os.Stat(idrsap); err == nil {
			key = idrsap
		}
	}

	addr := fmt.Sprintf("%s:%d", host, port)
	client := sshConnect(username, addr, key)
	if client == nil {
		return
	}

	for {
		stats := Stats{At: time.Now()}
		getAllStats(client, &stats)
		allStats.GetRing(stats.Hostname).Add(stats)
		time.Sleep(DEFAULT_REFRESH * time.Second)
	}
}
<commit_msg>assume a sensible default if /bin/hostname is not available, closes PR #7<commit_after>/*

rtop-vis - ad hoc cluster monitoring over SSH

Copyright (c) 2015 RapidLoop

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"syscall"
	"time"
)

const (
	VERSION          = "0.1"
	DEFAULT_REFRESH  = 5 // default refresh interval in seconds
	DEFAULT_WEB_ADDR = "0.0.0.0:8080"
	HISTORY_LENGTH   = 10 * 60 / DEFAULT_REFRESH // for 10 minutes
)

var (
	currentUser   *user.User
	sshConfigRead bool
	allStats      *HostStats
)

func usage(code int) {
	fmt.Printf(
		`rtop-vis %s - (c) 2015 RapidLoop - MIT Licensed - http://rtop-monitor.org/rtop-vis
rtop-vis monitors system stats for a cluster over SSH

Usage: rtop-vis host [host ...]

    host
        one or more host to monitor, "ssh host" should work without password

After invoking, web UI will be available on http://localhost:8080/. Stats will
be collected every 5 seconds and graphs will refresh every 10 seconds. Graphs
will show 10 minutes of history.
`, VERSION)
	os.Exit(code)
}

func main() {

	if len(os.Args) == 1 {
		usage(1)
	}

	log.SetPrefix("rtop-vis: ")
	log.SetFlags(0)

	// get current user
	var err error
	currentUser, err = user.Current()
	if err != nil {
		log.Print(err)
		return
	}

	// read from ~/.ssh/config if possible
	sshConfig := filepath.Join(currentUser.HomeDir, ".ssh", "config")
	if _, err := os.Stat(sshConfig); err == nil {
		sshConfigRead = parseSshConfig(sshConfig)
	}

	// start connecting
	allStats = NewHostStats(HISTORY_LENGTH)
	for _, host := range os.Args[1:] {
		go doHost(host)
	}

	// start the web server
	go startWeb()

	// wait for ^C
	ch := make(chan os.Signal, 1)
	signal.Notify(ch)
	for s := range ch {
		if s == syscall.SIGTERM || s == os.Interrupt {
			break
		}
	}
	signal.Stop(ch)
	close(ch)
}

func doHost(host string) {

	var (
		port          int
		username, key string
	)

	if sshConfigRead {
		shost, sport, suser, skey := getSshEntry(host)
		if len(shost) > 0 {
			host = shost
		}
		if sport != 0 {
			port = sport
		}
		if len(suser) > 0 {
			username = suser
		}
		if len(skey) > 0 {
			key = skey
		}
	}

	// fill in still-unknown ones with defaults
	if port == 0 {
		port = 22
	}
	if len(username) == 0 {
		username = currentUser.Username
	}
	if len(key) == 0 {
		idrsap := filepath.Join(currentUser.HomeDir, ".ssh", "id_rsa")
		if _, err := os.Stat(idrsap); err == nil {
			key = idrsap
		}
	}

	addr := fmt.Sprintf("%s:%d", host, port)
	client := sshConnect(username, addr, key)
	if client == nil {
		return
	}

	for {
		stats := Stats{At: time.Now(), Hostname: host}
		getAllStats(client, &stats)
		allStats.GetRing(stats.Hostname).Add(stats)
		time.Sleep(DEFAULT_REFRESH * time.Second)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/optiopay/klar/clair"
	"github.com/optiopay/klar/docker"
)

type jsonOutput struct {
	LayerCount      int
	Vulnerabilities []clair.Vulnerability
}

var priorities = []string{"Unknown", "Negligible", "Low", "Medium", "High", "Critical", "Defcon1"}
var store = make(map[string][]clair.Vulnerability)

func main() {
	if len(os.Args) != 2 {
		fmt.Printf("Image name must be provided")
		os.Exit(1)
	}

	clairAddr := os.Getenv("CLAIR_ADDR")
	if clairAddr == "" {
		fmt.Printf("Clair address must be provided")
		os.Exit(1)
	}

	clairOutput := priorities[0]
	outputEnv := os.Getenv("CLAIR_OUTPUT")
	if outputEnv != "" {
		output := strings.Title(strings.ToLower(outputEnv))
		correct := false
		for _, sev := range priorities {
			if sev == output {
				clairOutput = sev
				correct = true
				break
			}
		}

		if !correct {
			fmt.Printf("Clair output level %s is not supported, only support %v", outputEnv, priorities)
			os.Exit(1)
		}
	}

	threshold := 0
	thresholdStr := os.Getenv("CLAIR_THRESHOLD")
	if thresholdStr != "" {
		threshold, _ = strconv.Atoi(thresholdStr)
	}

	dockerUser := os.Getenv("DOCKER_USER")
	dockerPassword := os.Getenv("DOCKER_PASSWORD")

	insecureTLS := false
	if envInsecure, err := strconv.ParseBool(os.Getenv("DOCKER_INSECURE")); err == nil {
		insecureTLS = envInsecure
	}

	useJSONOutput := false
	if envJSONOutput, err := strconv.ParseBool(os.Getenv("JSON_OUTPUT")); err == nil {
		useJSONOutput = envJSONOutput
	}

	image, err := docker.NewImage(os.Args[1], dockerUser, dockerPassword, insecureTLS)
	if err != nil {
		fmt.Printf("Can't parse qname: %s", err)
		os.Exit(1)
	}

	err = image.Pull()
	if err != nil {
		fmt.Printf("Can't pull image: %s", err)
		os.Exit(1)
	}

	var output = jsonOutput{}

	if len(image.FsLayers) == 0 {
		fmt.Printf("Can't pull fsLayers")
		os.Exit(1)
	} else {
		if useJSONOutput {
			output.LayerCount = len(image.FsLayers)
		} else {
			fmt.Printf("Analysing %d layers\n", len(image.FsLayers))
		}
	}

	c := clair.NewClair(clairAddr)
	vs := c.Analyse(image)
	groupBySeverity(vs)
	if !useJSONOutput {
		fmt.Printf("Found %d vulnerabilities \n", len(vs))
	}
	highSevNumber := len(store["High"]) + len(store["Critical"]) + len(store["Defcon1"])

	if useJSONOutput {
		output.Vulnerabilities = vs
		enc := json.NewEncoder(os.Stdout)
		enc.Encode(output)
	} else {
		iteratePriorities(clairOutput, func(sev string) {
			for _, v := range store[sev] {
				fmt.Printf("%s: [%s] \n%s\n%s\n", v.Name, v.Severity, v.Description, v.Link)
				fmt.Println("-----------------------------------------")
			}
		})
		iteratePriorities(priorities[0], func(sev string) { fmt.Printf("%s: %d\n", sev, len(store[sev])) })
	}

	if highSevNumber > threshold {
		os.Exit(1)
	}
}

func iteratePriorities(output string, f func(sev string)) {
	filtered := true
	for _, sev := range priorities {
		if filtered {
			if sev != output {
				continue
			} else {
				filtered = false
			}
		}

		if len(store[sev]) != 0 {
			f(sev)
		}
	}

}

func groupBySeverity(vs []clair.Vulnerability) {
	for _, v := range vs {
		sevRow := vulnsBy(v.Severity, store)
		store[v.Severity] = append(sevRow, v)
	}
}

func vulnsBy(sev string, store map[string][]clair.Vulnerability) []clair.Vulnerability {
	items, found := store[sev]
	if !found {
		items = make([]clair.Vulnerability, 0)
		store[sev] = items
	}
	return items
}
<commit_msg>Move "found" line to reduce if count<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/optiopay/klar/clair"
	"github.com/optiopay/klar/docker"
)

type jsonOutput struct {
	LayerCount      int
	Vulnerabilities []clair.Vulnerability
}

var priorities = []string{"Unknown", "Negligible", "Low", "Medium", "High", "Critical", "Defcon1"}
var store = make(map[string][]clair.Vulnerability)

func main() {
	if len(os.Args) != 2 {
		fmt.Printf("Image name must be provided")
		os.Exit(1)
	}

	clairAddr := os.Getenv("CLAIR_ADDR")
	if clairAddr == "" {
		fmt.Printf("Clair address must be provided")
		os.Exit(1)
	}

	clairOutput := priorities[0]
	outputEnv := os.Getenv("CLAIR_OUTPUT")
	if outputEnv != "" {
		output := strings.Title(strings.ToLower(outputEnv))
		correct := false
		for _, sev := range priorities {
			if sev == output {
				clairOutput = sev
				correct = true
				break
			}
		}

		if !correct {
			fmt.Printf("Clair output level %s is not supported, only support %v", outputEnv, priorities)
			os.Exit(1)
		}
	}

	threshold := 0
	thresholdStr := os.Getenv("CLAIR_THRESHOLD")
	if thresholdStr != "" {
		threshold, _ = strconv.Atoi(thresholdStr)
	}

	dockerUser := os.Getenv("DOCKER_USER")
	dockerPassword := os.Getenv("DOCKER_PASSWORD")

	insecureTLS := false
	if envInsecure, err := strconv.ParseBool(os.Getenv("DOCKER_INSECURE")); err == nil {
		insecureTLS = envInsecure
	}

	useJSONOutput := false
	if envJSONOutput, err := strconv.ParseBool(os.Getenv("JSON_OUTPUT")); err == nil {
		useJSONOutput = envJSONOutput
	}

	image, err := docker.NewImage(os.Args[1], dockerUser, dockerPassword, insecureTLS)
	if err != nil {
		fmt.Printf("Can't parse qname: %s", err)
		os.Exit(1)
	}

	err = image.Pull()
	if err != nil {
		fmt.Printf("Can't pull image: %s", err)
		os.Exit(1)
	}

	var output = jsonOutput{}

	if len(image.FsLayers) == 0 {
		fmt.Printf("Can't pull fsLayers")
		os.Exit(1)
	} else {
		if useJSONOutput {
			output.LayerCount = len(image.FsLayers)
		} else {
			fmt.Printf("Analysing %d layers\n", len(image.FsLayers))
		}
	}

	c := clair.NewClair(clairAddr)
	vs := c.Analyse(image)
	groupBySeverity(vs)
	highSevNumber := len(store["High"]) + len(store["Critical"]) + len(store["Defcon1"])

	if useJSONOutput {
		output.Vulnerabilities = vs
		enc := json.NewEncoder(os.Stdout)
		enc.Encode(output)
	} else {
		fmt.Printf("Found %d vulnerabilities \n", len(vs))
		iteratePriorities(clairOutput, func(sev string) {
			for _, v := range store[sev] {
				fmt.Printf("%s: [%s] \n%s\n%s\n", v.Name, v.Severity, v.Description, v.Link)
				fmt.Println("-----------------------------------------")
			}
		})
		iteratePriorities(priorities[0], func(sev string) { fmt.Printf("%s: %d\n", sev, len(store[sev])) })
	}

	if highSevNumber > threshold {
		os.Exit(1)
	}
}

func iteratePriorities(output string, f func(sev string)) {
	filtered := true
	for _, sev := range priorities {
		if filtered {
			if sev != output {
				continue
			} else {
				filtered = false
			}
		}

		if len(store[sev]) != 0 {
			f(sev)
		}
	}

}

func groupBySeverity(vs []clair.Vulnerability) {
	for _, v := range vs {
		sevRow := vulnsBy(v.Severity, store)
		store[v.Severity] = append(sevRow, v)
	}
}

func vulnsBy(sev string, store map[string][]clair.Vulnerability) []clair.Vulnerability {
	items, found := store[sev]
	if !found {
		items = make([]clair.Vulnerability, 0)
		store[sev] = items
	}
	return items
}
<|endoftext|>


<commit_before>// Copyright 2016 Mender Software AS
//
//    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"
	"os"
	"os/exec"
	"strings"

	"github.com/mendersoftware/log"

	"github.com/pkg/errors"
)

type logOptionsType struct {
	debug      *bool
	info       *bool
	logLevel   *string
	logModules *string
	logFile    *string
	noSyslog   *bool
}

type runOptionsType struct {
	version        *bool
	config         *string
	dataStore      *string
	imageFile      *string
	commit         *bool
	bootstrap      *bool
	daemon         *bool
	bootstrapForce *bool
	httpsClientConfig
}

var (
	errMsgNoArgumentsGiven = errors.New("Must give one of -rootfs, " +
		"-commit, -bootstrap or -daemon arguments")
	errMsgAmbiguousArgumentsGiven = errors.New("Ambiguous parameters given " +
		"- must give exactly one from: -rootfs, -commit, -bootstrap, -authorize or -daemon")
	errMsgIncompatibleLogOptions = errors.New("One or more " +
		"incompatible log log options specified.")
)

var defaultConfFile string = "/etc/mender/mender.conf"

var DeploymentLogger *DeploymentLogManager

type Commander interface {
	Command(name string, arg ...string) *exec.Cmd
}

type StatCommander interface {
	Stat(string) (os.FileInfo, error)
	Commander
}

// we need real OS implementation
type osCalls struct {
}

func (osCalls) Command(name string, arg ...string) *exec.Cmd {
	return exec.Command(name, arg...)
}

func (osCalls) Stat(name string) (os.FileInfo, error) {
	return os.Stat(name)
}

func argsParse(args []string) (runOptionsType, error) {
	parsing := flag.NewFlagSet("mender", flag.ContinueOnError)

	// FLAGS ---------------------------------------------------------------

	version := parsing.Bool("version", false, "Show mender agent version and exit.")

	config := parsing.String("config", defaultConfFile,
		"Configuration file location.")

	data := parsing.String("data", defaultDataStore,
		"Mender state data location.")

	commit := parsing.Bool("commit", false, "Commit current update.")

	bootstrap := parsing.Bool("bootstrap", false, "Perform bootstrap and exit.")

	imageFile := parsing.String("rootfs", "",
		"Root filesystem URI to use for update. Can be either a local "+
			"file or a URL.")

	daemon := parsing.Bool("daemon", false, "Run as a daemon.")

	// add bootstrap related command line options
	certFile := parsing.String("certificate", "", "Client certificate")
	certKey := parsing.String("cert-key", "", "Client certificate's private key")
	serverCert := parsing.String("trusted-certs", "", "Trusted server certificates")
	forcebootstrap := parsing.Bool("forcebootstrap", false, "Force bootstrap")
	skipVerify := parsing.Bool("skipverify", false, "Skip certificate verification")

	// add log related command line options
	logFlags := addLogFlags(parsing)

	// PARSING -------------------------------------------------------------

	if err := parsing.Parse(args); err != nil {
		return runOptionsType{}, err
	}

	runOptions := runOptionsType{
		version:        version,
		config:         config,
		dataStore:      data,
		imageFile:      imageFile,
		commit:         commit,
		bootstrap:      bootstrap,
		daemon:         daemon,
		bootstrapForce: forcebootstrap,
		httpsClientConfig: httpsClientConfig{
			certFile:   *certFile,
			certKey:    *certKey,
			serverCert: *serverCert,
			isHttps:    false,
			noVerify:   *skipVerify,
		},
	}

	//runOptions.bootstrap = httpsClientConfig{}

	// FLAG LOGIC ----------------------------------------------------------

	// we just want to see the version string, the rest does not
	// matter
	if *version == true {
		return runOptions, nil
	}

	if err := parseLogFlags(logFlags); err != nil {
		return runOptions, err
	}

	if moreThanOneRunOptionSelected(runOptions) {
		return runOptions, errMsgAmbiguousArgumentsGiven
	}

	return runOptions, nil
}

func moreThanOneRunOptionSelected(runOptions runOptionsType) bool {
	// check if more than one command line action is selected
	var runOptionsCount int

	if *runOptions.imageFile != "" {
		runOptionsCount++
	}
	if *runOptions.commit {
		runOptionsCount++
	}
	if *runOptions.daemon {
		runOptionsCount++
	}

	if runOptionsCount > 1 {
		return true
	}
	return false
}

func addLogFlags(f *flag.FlagSet) logOptionsType {

	var logOptions logOptionsType

	logOptions.debug = f.Bool("debug", false, "Debug log level. This is a "+
		"shorthand for '-l debug'.")

	logOptions.info = f.Bool("info", false, "Info log level. This is a "+
		"shorthand for '-l info'.")

	logOptions.logLevel = f.String("log-level", "", "Log level, which can be "+
		"'debug', 'info', 'warning', 'error', 'fatal' or 'panic'. "+
		"Earlier log levels will also log the subsequent levels (so "+
		"'debug' will log everything). The default log level is "+
		"'info'.")

	logOptions.logModules = f.String("log-modules", "", "Filter logging by "+
		"module. This is a comma separated list of modules to log, "+
		"other modules will be omitted. To see which modules are "+
		"available, take a look at a non-filtered log and select "+
		"the modules appropriate for you.")

	logOptions.noSyslog = f.Bool("no-syslog", false, "Disable logging to "+
		"syslog. Note that debug message are never logged to syslog.")

	logOptions.logFile = f.String("log-file", "", "File to log to.")

	return logOptions

}

func parseLogFlags(args logOptionsType) error {
	var logOptCount int

	// set info as a default log level
	log.SetLevel(log.InfoLevel)

	if *args.logLevel != "" {
		level, err := log.ParseLevel(*args.logLevel)
		if err != nil {
			return err
		}
		log.SetLevel(level)
		logOptCount++
	}

	if *args.info {
		log.SetLevel(log.InfoLevel)
		logOptCount++
	}

	if *args.debug {
		log.SetLevel(log.DebugLevel)
		logOptCount++
	}

	if logOptCount > 1 {
		return errMsgIncompatibleLogOptions
	} else if logOptCount == 0 {
		// Default log level.
		log.SetLevel(log.WarnLevel)
	}

	if *args.logFile != "" {
		fd, err := os.Create(*args.logFile)
		if err != nil {
			return err
		}
		log.SetOutput(fd)
	}

	if *args.logModules != "" {
		modules := strings.Split(*args.logModules, ",")
		log.SetModuleFilter(modules)
	}

	if !*args.noSyslog {
		if err := log.AddSyslogHook(); err != nil {
			log.Warnf("Could not connect to syslog daemon: %s. "+
				"(use -no-syslog to disable completely)",
				err.Error())
		}
	}

	return nil
}

func ShowVersion() {
	v := fmt.Sprintf("%s\n", VersionString())
	os.Stdout.Write([]byte(v))
}

func doBootstrapAuthorize(config *menderConfig, opts *runOptionsType) error {
	store := NewDirStore(*opts.dataStore)

	authmgr := NewAuthManager(store, config.DeviceKey, NewIdentityDataGetter())

	controller, err := NewMender(*config, MenderPieces{
		store:   store,
		authMgr: authmgr,
	})
	if err != nil {
		return errors.Wrap(err, "error initializing mender controller")
	}

	if *opts.bootstrapForce {
		controller.ForceBootstrap()
	}

	if merr := controller.Bootstrap(); merr != nil {
		return merr.Cause()
	}

	if merr := controller.Authorize(); merr != nil {
		return merr.Cause()
	}

	return nil
}

func initDaemon(config *menderConfig, dev *device, env *uBootEnv,
	opts *runOptionsType) (*menderDaemon, error) {

	store := NewDirStore(*opts.dataStore)

	authmgr := NewAuthManager(store, config.DeviceKey, NewIdentityDataGetter())

	controller, err := NewMender(*config, MenderPieces{
		device:  dev,
		env:     env,
		store:   store,
		authMgr: authmgr,
	})

	if controller == nil {
		return nil, errors.Wrap(err, "error initializing mender controller")
	}

	if *opts.bootstrapForce {
		controller.ForceBootstrap()
	}

	daemon := NewDaemon(controller, store)

	// add logging hook; only daemon needs this
	log.AddHook(NewDeploymentLogHook(DeploymentLogger))

	return daemon, nil
}

func doMain(args []string) error {
	runOptions, err := argsParse(args)
	if err != nil {
		return err
	}

	if *runOptions.version {
		ShowVersion()
		return nil
	}

	config, err := LoadConfig(*runOptions.config)
	if err != nil {
		return err
	}

	if runOptions.httpsClientConfig.noVerify {
		config.HttpsClient.SkipVerify = true
	}

	env := NewEnvironment(new(osCalls))
	device := NewDevice(env, new(osCalls), config.GetDeviceConfig())

	DeploymentLogger = NewDeploymentLogManager(*runOptions.dataStore)

	switch {

	case *runOptions.imageFile != "":
		return doRootfs(device, runOptions)

	case *runOptions.commit:
		return device.CommitUpdate()

	case *runOptions.bootstrap:
		return doBootstrapAuthorize(config, &runOptions)

	case *runOptions.daemon:
		d, err := initDaemon(config, device, env, &runOptions)
		if err != nil {
			return err
		}
		return d.Run()

	case *runOptions.imageFile == "" && !*runOptions.commit &&
		!*runOptions.daemon && !*runOptions.bootstrap:
		return errMsgNoArgumentsGiven
	}

	return nil
}

func main() {
	if err := doMain(os.Args[1:]); err != nil && err != flag.ErrHelp {
		log.Errorln(err.Error())
		os.Exit(1)
	}
}
<commit_msg>Fix setting default log level.<commit_after>// Copyright 2016 Mender Software AS
//
//    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"
	"os"
	"os/exec"
	"strings"

	"github.com/mendersoftware/log"

	"github.com/pkg/errors"
)

type logOptionsType struct {
	debug      *bool
	info       *bool
	logLevel   *string
	logModules *string
	logFile    *string
	noSyslog   *bool
}

type runOptionsType struct {
	version        *bool
	config         *string
	dataStore      *string
	imageFile      *string
	commit         *bool
	bootstrap      *bool
	daemon         *bool
	bootstrapForce *bool
	httpsClientConfig
}

var (
	errMsgNoArgumentsGiven = errors.New("Must give one of -rootfs, " +
		"-commit, -bootstrap or -daemon arguments")
	errMsgAmbiguousArgumentsGiven = errors.New("Ambiguous parameters given " +
		"- must give exactly one from: -rootfs, -commit, -bootstrap, -authorize or -daemon")
	errMsgIncompatibleLogOptions = errors.New("One or more " +
		"incompatible log log options specified.")
)

var defaultConfFile string = "/etc/mender/mender.conf"

var DeploymentLogger *DeploymentLogManager

type Commander interface {
	Command(name string, arg ...string) *exec.Cmd
}

type StatCommander interface {
	Stat(string) (os.FileInfo, error)
	Commander
}

// we need real OS implementation
type osCalls struct {
}

func (osCalls) Command(name string, arg ...string) *exec.Cmd {
	return exec.Command(name, arg...)
}

func (osCalls) Stat(name string) (os.FileInfo, error) {
	return os.Stat(name)
}

func argsParse(args []string) (runOptionsType, error) {
	parsing := flag.NewFlagSet("mender", flag.ContinueOnError)

	// FLAGS ---------------------------------------------------------------

	version := parsing.Bool("version", false, "Show mender agent version and exit.")

	config := parsing.String("config", defaultConfFile,
		"Configuration file location.")

	data := parsing.String("data", defaultDataStore,
		"Mender state data location.")

	commit := parsing.Bool("commit", false, "Commit current update.")

	bootstrap := parsing.Bool("bootstrap", false, "Perform bootstrap and exit.")

	imageFile := parsing.String("rootfs", "",
		"Root filesystem URI to use for update. Can be either a local "+
			"file or a URL.")

	daemon := parsing.Bool("daemon", false, "Run as a daemon.")

	// add bootstrap related command line options
	certFile := parsing.String("certificate", "", "Client certificate")
	certKey := parsing.String("cert-key", "", "Client certificate's private key")
	serverCert := parsing.String("trusted-certs", "", "Trusted server certificates")
	forcebootstrap := parsing.Bool("forcebootstrap", false, "Force bootstrap")
	skipVerify := parsing.Bool("skipverify", false, "Skip certificate verification")

	// add log related command line options
	logFlags := addLogFlags(parsing)

	// PARSING -------------------------------------------------------------

	if err := parsing.Parse(args); err != nil {
		return runOptionsType{}, err
	}

	runOptions := runOptionsType{
		version:        version,
		config:         config,
		dataStore:      data,
		imageFile:      imageFile,
		commit:         commit,
		bootstrap:      bootstrap,
		daemon:         daemon,
		bootstrapForce: forcebootstrap,
		httpsClientConfig: httpsClientConfig{
			certFile:   *certFile,
			certKey:    *certKey,
			serverCert: *serverCert,
			isHttps:    false,
			noVerify:   *skipVerify,
		},
	}

	//runOptions.bootstrap = httpsClientConfig{}

	// FLAG LOGIC ----------------------------------------------------------

	// we just want to see the version string, the rest does not
	// matter
	if *version == true {
		return runOptions, nil
	}

	if err := parseLogFlags(logFlags); err != nil {
		return runOptions, err
	}

	if moreThanOneRunOptionSelected(runOptions) {
		return runOptions, errMsgAmbiguousArgumentsGiven
	}

	return runOptions, nil
}

func moreThanOneRunOptionSelected(runOptions runOptionsType) bool {
	// check if more than one command line action is selected
	var runOptionsCount int

	if *runOptions.imageFile != "" {
		runOptionsCount++
	}
	if *runOptions.commit {
		runOptionsCount++
	}
	if *runOptions.daemon {
		runOptionsCount++
	}

	if runOptionsCount > 1 {
		return true
	}
	return false
}

func addLogFlags(f *flag.FlagSet) logOptionsType {

	var logOptions logOptionsType

	logOptions.debug = f.Bool("debug", false, "Debug log level. This is a "+
		"shorthand for '-l debug'.")

	logOptions.info = f.Bool("info", false, "Info log level. This is a "+
		"shorthand for '-l info'.")

	logOptions.logLevel = f.String("log-level", "", "Log level, which can be "+
		"'debug', 'info', 'warning', 'error', 'fatal' or 'panic'. "+
		"Earlier log levels will also log the subsequent levels (so "+
		"'debug' will log everything). The default log level is "+
		"'info'.")

	logOptions.logModules = f.String("log-modules", "", "Filter logging by "+
		"module. This is a comma separated list of modules to log, "+
		"other modules will be omitted. To see which modules are "+
		"available, take a look at a non-filtered log and select "+
		"the modules appropriate for you.")

	logOptions.noSyslog = f.Bool("no-syslog", false, "Disable logging to "+
		"syslog. Note that debug message are never logged to syslog.")

	logOptions.logFile = f.String("log-file", "", "File to log to.")

	return logOptions

}

func parseLogFlags(args logOptionsType) error {
	var logOptCount int

	if *args.logLevel != "" {
		level, err := log.ParseLevel(*args.logLevel)
		if err != nil {
			return err
		}
		log.SetLevel(level)
		logOptCount++
	}

	if *args.info {
		log.SetLevel(log.InfoLevel)
		logOptCount++
	}

	if *args.debug {
		log.SetLevel(log.DebugLevel)
		logOptCount++
	}

	if logOptCount > 1 {
		return errMsgIncompatibleLogOptions
	} else if logOptCount == 0 {
		// set info as a default log level
		log.SetLevel(log.InfoLevel)
	}

	if *args.logFile != "" {
		fd, err := os.Create(*args.logFile)
		if err != nil {
			return err
		}
		log.SetOutput(fd)
	}

	if *args.logModules != "" {
		modules := strings.Split(*args.logModules, ",")
		log.SetModuleFilter(modules)
	}

	if !*args.noSyslog {
		if err := log.AddSyslogHook(); err != nil {
			log.Warnf("Could not connect to syslog daemon: %s. "+
				"(use -no-syslog to disable completely)",
				err.Error())
		}
	}

	return nil
}

func ShowVersion() {
	v := fmt.Sprintf("%s\n", VersionString())
	os.Stdout.Write([]byte(v))
}

func doBootstrapAuthorize(config *menderConfig, opts *runOptionsType) error {
	store := NewDirStore(*opts.dataStore)

	authmgr := NewAuthManager(store, config.DeviceKey, NewIdentityDataGetter())

	controller, err := NewMender(*config, MenderPieces{
		store:   store,
		authMgr: authmgr,
	})
	if err != nil {
		return errors.Wrap(err, "error initializing mender controller")
	}

	if *opts.bootstrapForce {
		controller.ForceBootstrap()
	}

	if merr := controller.Bootstrap(); merr != nil {
		return merr.Cause()
	}

	if merr := controller.Authorize(); merr != nil {
		return merr.Cause()
	}

	return nil
}

func initDaemon(config *menderConfig, dev *device, env *uBootEnv,
	opts *runOptionsType) (*menderDaemon, error) {

	store := NewDirStore(*opts.dataStore)

	authmgr := NewAuthManager(store, config.DeviceKey, NewIdentityDataGetter())

	controller, err := NewMender(*config, MenderPieces{
		device:  dev,
		env:     env,
		store:   store,
		authMgr: authmgr,
	})

	if controller == nil {
		return nil, errors.Wrap(err, "error initializing mender controller")
	}

	if *opts.bootstrapForce {
		controller.ForceBootstrap()
	}

	daemon := NewDaemon(controller, store)

	// add logging hook; only daemon needs this
	log.AddHook(NewDeploymentLogHook(DeploymentLogger))

	return daemon, nil
}

func doMain(args []string) error {
	runOptions, err := argsParse(args)
	if err != nil {
		return err
	}

	if *runOptions.version {
		ShowVersion()
		return nil
	}

	config, err := LoadConfig(*runOptions.config)
	if err != nil {
		return err
	}

	if runOptions.httpsClientConfig.noVerify {
		config.HttpsClient.SkipVerify = true
	}

	env := NewEnvironment(new(osCalls))
	device := NewDevice(env, new(osCalls), config.GetDeviceConfig())

	DeploymentLogger = NewDeploymentLogManager(*runOptions.dataStore)

	switch {

	case *runOptions.imageFile != "":
		return doRootfs(device, runOptions)

	case *runOptions.commit:
		return device.CommitUpdate()

	case *runOptions.bootstrap:
		return doBootstrapAuthorize(config, &runOptions)

	case *runOptions.daemon:
		d, err := initDaemon(config, device, env, &runOptions)
		if err != nil {
			return err
		}
		return d.Run()

	case *runOptions.imageFile == "" && !*runOptions.commit &&
		!*runOptions.daemon && !*runOptions.bootstrap:
		return errMsgNoArgumentsGiven
	}

	return nil
}

func main() {
	if err := doMain(os.Args[1:]); err != nil && err != flag.ErrHelp {
		log.Errorln(err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"math/rand"
	"time"
)

var blockFlag UnicodeBlock

func init() {
	flag.Var(&blockFlag, "r", "codepoint range")
}

func main() {
	rand.Seed(time.Now().UnixNano())

	dump := flag.Bool("d", false, "print all Blocks")
	list := flag.Bool("l", false, "list all Blocks")
	nchars := flag.Int("n", 80, "number of characters to print")
	block := flag.String("b", "", "unicode block by name")
	flag.Parse()

	// If invalid Blocks key specified, use a default instead
	b, valid := Blocks[*block]
	if !valid {
		b = Blocks["geometric"]
	}

	switch {
	case *dump:
		if *block != "" {
			b.Print()
		} else {
			printBlocks(true)
		}
	case *list:
		printBlocks(false)
	case blockFlag.end > 0:
		b.start = blockFlag.start
		b.end = blockFlag.end
		b.PrintRandom(*nchars)
	default:
		b.PrintRandom(*nchars)
	}
}
<commit_msg>Provide example argument in blockFlag comment<commit_after>package main

import (
	"flag"
	"math/rand"
	"time"
)

var blockFlag UnicodeBlock

func init() {
	flag.Var(&blockFlag, "r", "comma separated codepoint range (eg. 0x0000,0x23ff)")
}

func main() {
	rand.Seed(time.Now().UnixNano())

	dump := flag.Bool("d", false, "print all Blocks")
	list := flag.Bool("l", false, "list all Blocks")
	nchars := flag.Int("n", 80, "number of characters to print")
	block := flag.String("b", "", "unicode block by name")
	flag.Parse()

	// If invalid Blocks key specified, use a default instead
	b, valid := Blocks[*block]
	if !valid {
		b = Blocks["geometric"]
	}

	switch {
	case *dump:
		if *block != "" {
			b.Print()
		} else {
			printBlocks(true)
		}
	case *list:
		printBlocks(false)
	case blockFlag.end > 0:
		b.start = blockFlag.start
		b.end = blockFlag.end
		b.PrintRandom(*nchars)
	default:
		b.PrintRandom(*nchars)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"sync"

	"code.google.com/p/go.net/idna"
	"github.com/domainr/go-whois/whois"
)

var (
	v, quick      bool
	concurrency   int
	zones         []string
	prefixes      []string
	_, FILE, _, _ = runtime.Caller(0)
	DIR           = filepath.Dir(FILE)
)

func init() {
	flag.BoolVar(&v, "v", false, "verbose output (to stderr)")
	flag.BoolVar(&quick, "quick", false, "Only work on a subset of zones")
	flag.IntVar(&concurrency, "concurrency", 8, "Set maximum number of concurrent requests")
}

func main() {
	flag.Parse()

	if err := main1(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main1() error {
	var err error
	zones, err = readLines("zones.txt")
	if err != nil {
		return err
	}
	prefixes, err = readLines("prefixes.txt")
	if err != nil {
		return err
	}

	// Quick for debugging?
	if quick {
		fmt.Fprintf(os.Stderr, "Quick mode enabled\n")
		zones = zones[0:50]
	}

	limiter := make(chan struct{}, concurrency) // semaphore to limit concurrency
	var wg sync.WaitGroup

	fmt.Fprintf(os.Stderr, "Querying whois for %d prefixes and %d zones\n", len(prefixes), len(zones))

	for _, zone := range zones {
		for _, prefix := range prefixes {
			wg.Add(1)
			go func(domain string) {
				limiter <- struct{}{} // acquire semaphore
				defer func() {        // release semaphore
					<-limiter
					wg.Done()
				}()

				req, err := whois.Resolve(domain)
				if err != nil {
					return
				}

				err = os.MkdirAll(filepath.Join(DIR, "data", "responses", req.Host), os.ModePerm)
				if err != nil {
					return
				}
			}(fmt.Sprintf("%s.%s", prefix, zone))
		}
	}

	wg.Wait()

	return nil
}

var re = regexp.MustCompile("\\s+|#.+$")

func readLines(fn string) (out []string, err error) {
	fmt.Fprintf(os.Stderr, "Reading %s\n", fn)
	buf, err := ioutil.ReadFile(filepath.Join(DIR, "data", fn))
	if err != nil {
		return
	}
	s := strings.Trim(string(buf), "\n")
	lines := strings.Split(s, "\n")
	for _, line := range lines {
		line = re.ReplaceAllLiteralString(line, "")
		if line != "" {
			line, _ = idna.ToASCII(line)
			out = append(out, line)
		}
	}
	return
}
<commit_msg>Perform whois on whois server names.<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"sync"

	"code.google.com/p/go.net/idna"
	"github.com/domainr/go-whois/whois"
)

var (
	v, quick      bool
	concurrency   int
	zones         []string
	prefixes      []string
	_, FILE, _, _ = runtime.Caller(0)
	DIR           = filepath.Dir(FILE)
)

func init() {
	flag.BoolVar(&v, "v", false, "verbose output (to stderr)")
	flag.BoolVar(&quick, "quick", false, "Only work on a subset of zones")
	flag.IntVar(&concurrency, "concurrency", 8, "Set maximum number of concurrent requests")
}

func main() {
	flag.Parse()

	if err := main1(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}

func main1() error {
	var err error
	zones, err = readLines("zones.txt")
	if err != nil {
		return err
	}
	prefixes, err = readLines("prefixes.txt")
	if err != nil {
		return err
	}

	// Quick for debugging?
	if quick {
		fmt.Fprintf(os.Stderr, "Quick mode enabled\n")
		zones = zones[0:50]
	}

	domains := make(map[string]bool, len(zones)*len(prefixes))
	for _, zone := range zones {
		for _, prefix := range prefixes {
			domain := prefix + "." + zone
			domains[domain] = true
			req, err := whois.Resolve(domain)
			if err == nil {
				domains[req.Host] = true
			}
		}
	}

	fmt.Fprintf(os.Stderr, "Querying whois for %d domains (%d prefixes × %d zones)\n",  len(domains), len(prefixes), len(zones))

	limiter := make(chan struct{}, concurrency) // semaphore to limit concurrency
	var wg sync.WaitGroup
	for domain, _ := range domains {
		wg.Add(1)
		go func(domain string) {
			limiter <- struct{}{} // acquire semaphore
			defer func() {        // release semaphore
				<-limiter
				wg.Done()
			}()

			req, err := whois.Resolve(domain)
			if err != nil {
				return
			}

			err = os.MkdirAll(filepath.Join(DIR, "data", "responses", req.Host), os.ModePerm)
			if err != nil {
				return
			}
		}(domain)
	}
	wg.Wait()

	return nil
}

var re = regexp.MustCompile("\\s+|#.+$")

func readLines(fn string) (out []string, err error) {
	fmt.Fprintf(os.Stderr, "Reading %s\n", fn)
	buf, err := ioutil.ReadFile(filepath.Join(DIR, "data", fn))
	if err != nil {
		return
	}
	s := strings.Trim(string(buf), "\n")
	lines := strings.Split(s, "\n")
	for _, line := range lines {
		line = re.ReplaceAllLiteralString(line, "")
		if line != "" {
			line, _ = idna.ToASCII(line)
			out = append(out, line)
		}
	}
	return
}
<|endoftext|>


<commit_before>package cache

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

const (
	BurnStrategyRandom = 1
	BurnStrategyOldest = 2
)

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

type CachedItem struct {
	key   string
	value interface{}
}

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

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

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

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

func (c *Cache) Start() {
	go c.runner()
}

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

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

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

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

//private functions
func (c *Cache) burnEntryByStrategy() {
	if c.options.BurnStrategy == BurnStrategyOldest {
		c.burnEntryByOldest()
	} else {
		c.burnEntryByRandom()
	}
}

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

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

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

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

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

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

func (c *Cache) deleteItem(i *list.Element) {
	c.l.Remove(i)
	delete(c.contents, i.Value.(*CachedItem).key)
}
<commit_msg>Delete item if set to nil<commit_after>package cache

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

const (
	BurnStrategyRandom = 1
	BurnStrategyOldest = 2
)

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

type CachedItem struct {
	key   string
	value interface{}
}

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

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

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

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

func (c *Cache) Start() {
	go c.runner()
}

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

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

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

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

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

//private functions
func (c *Cache) burnEntryByStrategy() {
	if c.options.BurnStrategy == BurnStrategyOldest {
		c.burnEntryByOldest()
	} else {
		c.burnEntryByRandom()
	}
}

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

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

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

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

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

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

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