<commit_before>package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/dt/thile/gen"
	"github.com/foursquare/gohfile"
)

type Collection struct {
	cfg    *hfile.CollectionConfig
	reader *hfile.Reader
}

type CollectionSet struct {
	settings    *Settings
	collections map[string]Collection
}

func LoadCollections(settings *Settings, collections []hfile.CollectionConfig) (*CollectionSet, error) {
	cs := new(CollectionSet)
	cs.settings = settings
	cs.collections = make(map[string]Collection)

	for _, cfg := range collections {
		reader, err := hfile.NewReaderFromConfig(&cfg, settings.debug)
		if err != nil {
			return nil, err
		}

		cs.collections[cfg.Name] = Collection{&cfg, reader}
	}

	return cs, nil
}

func (cs *CollectionSet) readerFor(name string) (*hfile.Reader, error) {
	c, ok := cs.collections[name]
	if !ok {
		return nil, fmt.Errorf("not configured with reader for collection %s", name)
	}
	return c.reader, nil
}

func (cs *CollectionSet) scannerFor(c string) (*hfile.Scanner, error) {
	reader, err := cs.readerFor(c)
	if err != nil {
		return nil, err
	}
	s := hfile.NewScanner(reader)
	return &s, nil
}

func (cs *CollectionSet) GetValuesSingle(req *gen.SingleHFileKeyRequest) (r *gen.SingleHFileKeyResponse, err error) {
	if cs.settings.debug {
		log.Printf("[GetValuesSingle] %s (%d keys)\n", *req.HfileName, len(req.SortedKeys))
	}
	reader, err := cs.scannerFor(*req.HfileName)
	if err != nil {
		return nil, err
	}

	if req.PerKeyValueLimit != nil {
		log.Println("[GetValuesSingle] PerKeyValueLimit. oh well.")
	}

	if req.CountOnly != nil {
		log.Println("[GetValuesSingle] CountOnly. oh well.")
	}

	res := new(gen.SingleHFileKeyResponse)
	res.Values = make(map[int32][]byte)
	found := int32(0)

	for idx, key := range req.SortedKeys {
		if cs.settings.debug {
			log.Printf("[GetValuesSingle] key: %s\n", hex.EncodeToString(key))
		}
		value, err, ok := reader.GetFirst(key)
		if err != nil {
			return nil, err
		}
		if ok {
			found++
			res.Values[int32(idx)] = value
		}
	}

	if cs.settings.debug {
		log.Printf("[GetValuesSingle] %s found %d of %d.\n", *req.HfileName, found, len(req.SortedKeys))
	}
	res.KeyCount = &found
	return res, nil
}

func (cs *CollectionSet) GetValuesMulti(req *gen.SingleHFileKeyRequest) (r *gen.MultiHFileKeyResponse, err error) {
	log.Println("[GetValuesMulti]", len(req.SortedKeys))
	reader, err := cs.scannerFor(*req.HfileName)
	if err != nil {
		return nil, err
	}

	//out := make(map[int32][]byte)
	res := new(gen.MultiHFileKeyResponse)
	found := int32(0)

	for idx, key := range req.SortedKeys {
		values, err := reader.GetAll(key)
		if err != nil {
			return nil, err
		}
		if len(values) > 0 {
			found += int32(len(values))
			res.Values[int32(idx)] = values
		}
	}

	res.KeyCount = &found
	return res, nil

}

func (cs *CollectionSet) GetValuesForPrefixes(req *gen.PrefixRequest) (r *gen.PrefixResponse, err error) {
	return nil, nil
}

func (cs *CollectionSet) GetValuesMultiSplitKeys(req *gen.MultiHFileSplitKeyRequest) (r *gen.KeyToValuesResponse, err error) {
	return nil, nil
}

func (cs *CollectionSet) GetIterator(req *gen.IteratorRequest) (r *gen.IteratorResponse, err error) {
	return nil, nil
}

func (cs *CollectionSet) GetInfo(req *gen.InfoRequest) (r []*gen.HFileInfo, err error) {
	return nil, nil
}

func (cs *CollectionSet) TestTimeout(waitInMillis int32) (r int32, err error) {
	return 0, nil
}
<commit_msg>fix pointer type from upstream change<commit_after>package main

import (
	"encoding/hex"
	"fmt"
	"log"

	"github.com/dt/thile/gen"
	"github.com/foursquare/gohfile"
)

type Collection struct {
	cfg    *hfile.CollectionConfig
	reader *hfile.Reader
}

type CollectionSet struct {
	settings    *Settings
	collections map[string]Collection
}

func LoadCollections(settings *Settings, collections []hfile.CollectionConfig) (*CollectionSet, error) {
	cs := new(CollectionSet)
	cs.settings = settings
	cs.collections = make(map[string]Collection)

	for _, cfg := range collections {
		reader, err := hfile.NewReaderFromConfig(&cfg, settings.debug)
		if err != nil {
			return nil, err
		}

		cs.collections[cfg.Name] = Collection{&cfg, reader}
	}

	return cs, nil
}

func (cs *CollectionSet) readerFor(name string) (*hfile.Reader, error) {
	c, ok := cs.collections[name]
	if !ok {
		return nil, fmt.Errorf("not configured with reader for collection %s", name)
	}
	return c.reader, nil
}

func (cs *CollectionSet) scannerFor(c string) (*hfile.Scanner, error) {
	reader, err := cs.readerFor(c)
	if err != nil {
		return nil, err
	}
	s := hfile.NewScanner(reader)
	return s, nil
}

func (cs *CollectionSet) GetValuesSingle(req *gen.SingleHFileKeyRequest) (r *gen.SingleHFileKeyResponse, err error) {
	if cs.settings.debug {
		log.Printf("[GetValuesSingle] %s (%d keys)\n", *req.HfileName, len(req.SortedKeys))
	}
	reader, err := cs.scannerFor(*req.HfileName)
	if err != nil {
		return nil, err
	}

	if req.PerKeyValueLimit != nil {
		log.Println("[GetValuesSingle] PerKeyValueLimit. oh well.")
	}

	if req.CountOnly != nil {
		log.Println("[GetValuesSingle] CountOnly. oh well.")
	}

	res := new(gen.SingleHFileKeyResponse)
	res.Values = make(map[int32][]byte)
	found := int32(0)

	for idx, key := range req.SortedKeys {
		if cs.settings.debug {
			log.Printf("[GetValuesSingle] key: %s\n", hex.EncodeToString(key))
		}
		value, err, ok := reader.GetFirst(key)
		if err != nil {
			return nil, err
		}
		if ok {
			found++
			res.Values[int32(idx)] = value
		}
	}

	if cs.settings.debug {
		log.Printf("[GetValuesSingle] %s found %d of %d.\n", *req.HfileName, found, len(req.SortedKeys))
	}
	res.KeyCount = &found
	return res, nil
}

func (cs *CollectionSet) GetValuesMulti(req *gen.SingleHFileKeyRequest) (r *gen.MultiHFileKeyResponse, err error) {
	log.Println("[GetValuesMulti]", len(req.SortedKeys))
	reader, err := cs.scannerFor(*req.HfileName)
	if err != nil {
		return nil, err
	}

	//out := make(map[int32][]byte)
	res := new(gen.MultiHFileKeyResponse)
	found := int32(0)

	for idx, key := range req.SortedKeys {
		values, err := reader.GetAll(key)
		if err != nil {
			return nil, err
		}
		if len(values) > 0 {
			found += int32(len(values))
			res.Values[int32(idx)] = values
		}
	}

	res.KeyCount = &found
	return res, nil

}

func (cs *CollectionSet) GetValuesForPrefixes(req *gen.PrefixRequest) (r *gen.PrefixResponse, err error) {
	return nil, nil
}

func (cs *CollectionSet) GetValuesMultiSplitKeys(req *gen.MultiHFileSplitKeyRequest) (r *gen.KeyToValuesResponse, err error) {
	return nil, nil
}

func (cs *CollectionSet) GetIterator(req *gen.IteratorRequest) (r *gen.IteratorResponse, err error) {
	return nil, nil
}

func (cs *CollectionSet) GetInfo(req *gen.InfoRequest) (r []*gen.HFileInfo, err error) {
	return nil, nil
}

func (cs *CollectionSet) TestTimeout(waitInMillis int32) (r int32, err error) {
	return 0, nil
}
<|endoftext|>


<commit_before>package commands

import (
	"errors"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/engine"
	"github.com/docker/machine/libmachine/host"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/persist"
	"github.com/docker/machine/libmachine/state"
	"github.com/docker/machine/libmachine/swarm"
	"github.com/skarademir/naturalsort"
)

const lsDefaultTimeout = 10

var (
	stateTimeoutDuration = lsDefaultTimeout * time.Second
)

// FilterOptions -
type FilterOptions struct {
	SwarmName  []string
	DriverName []string
	State      []string
	Name       []string
	Labels     []string
}

type HostListItem struct {
	Name          string
	Active        bool
	DriverName    string
	State         state.State
	URL           string
	SwarmOptions  *swarm.Options
	EngineOptions *engine.Options
	Error         string
	DockerVersion string
}

func cmdLs(c CommandLine, api libmachine.API) error {
	stateTimeoutDuration = time.Duration(c.Int("timeout")) * time.Second
	log.Debugf("ls timeout set to %s", stateTimeoutDuration)

	quiet := c.Bool("quiet")
	filters, err := parseFilters(c.StringSlice("filter"))
	if err != nil {
		return err
	}

	hostList, hostInError, err := persist.LoadAllHosts(api)
	if err != nil {
		return err
	}

	hostList = filterHosts(hostList, filters)

	// Just print out the names if we're being quiet
	if quiet {
		for _, host := range hostList {
			fmt.Println(host.Name)
		}
		return nil
	}

	swarmMasters := make(map[string]string)
	swarmInfo := make(map[string]string)

	w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
	fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM\tDOCKER\tERRORS")

	for _, host := range hostList {
		swarmOptions := host.HostOptions.SwarmOptions
		if swarmOptions.Master {
			swarmMasters[swarmOptions.Discovery] = host.Name
		}

		if swarmOptions.Discovery != "" {
			swarmInfo[host.Name] = swarmOptions.Discovery
		}
	}

	items := getHostListItems(hostList, hostInError)

	for _, item := range items {
		activeString := "-"
		if item.Active {
			activeString = "*"
		}

		swarmInfo := ""

		if item.SwarmOptions != nil && item.SwarmOptions.Discovery != "" {
			swarmInfo = swarmMasters[item.SwarmOptions.Discovery]
			if item.SwarmOptions.Master {
				swarmInfo = fmt.Sprintf("%s (master)", swarmInfo)
			}
		}
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
			item.Name, activeString, item.DriverName, item.State, item.URL, swarmInfo, item.DockerVersion, item.Error)
	}

	w.Flush()

	return nil
}

func parseFilters(filters []string) (FilterOptions, error) {
	options := FilterOptions{}
	for _, f := range filters {
		kv := strings.SplitN(f, "=", 2)
		if len(kv) != 2 {
			return options, errors.New("Unsupported filter syntax.")
		}
		key, value := strings.ToLower(kv[0]), kv[1]

		switch key {
		case "swarm":
			options.SwarmName = append(options.SwarmName, value)
		case "driver":
			options.DriverName = append(options.DriverName, value)
		case "state":
			options.State = append(options.State, value)
		case "name":
			options.Name = append(options.Name, value)
		case "label":
			options.Labels = append(options.Labels, value)
		default:
			return options, fmt.Errorf("Unsupported filter key '%s'", key)
		}
	}
	return options, nil
}

func filterHosts(hosts []*host.Host, filters FilterOptions) []*host.Host {
	if len(filters.SwarmName) == 0 &&
		len(filters.DriverName) == 0 &&
		len(filters.State) == 0 &&
		len(filters.Name) == 0 &&
		len(filters.Labels) == 0 {
		return hosts
	}

	filteredHosts := []*host.Host{}
	swarmMasters := getSwarmMasters(hosts)

	for _, h := range hosts {
		if filterHost(h, filters, swarmMasters) {
			filteredHosts = append(filteredHosts, h)
		}
	}
	return filteredHosts
}

func getSwarmMasters(hosts []*host.Host) map[string]string {
	swarmMasters := make(map[string]string)
	for _, h := range hosts {
		if h.HostOptions != nil {
			swarmOptions := h.HostOptions.SwarmOptions
			if swarmOptions != nil && swarmOptions.Master {
				swarmMasters[swarmOptions.Discovery] = h.Name
			}
		}
	}
	return swarmMasters
}

func filterHost(host *host.Host, filters FilterOptions, swarmMasters map[string]string) bool {
	swarmMatches := matchesSwarmName(host, filters.SwarmName, swarmMasters)
	driverMatches := matchesDriverName(host, filters.DriverName)
	stateMatches := matchesState(host, filters.State)
	nameMatches := matchesName(host, filters.Name)
	labelMatches := matchesLabel(host, filters.Labels)

	return swarmMatches && driverMatches && stateMatches && nameMatches && labelMatches
}

func matchesSwarmName(host *host.Host, swarmNames []string, swarmMasters map[string]string) bool {
	if len(swarmNames) == 0 {
		return true
	}
	for _, n := range swarmNames {
		if host.HostOptions != nil && host.HostOptions.SwarmOptions != nil {
			if strings.EqualFold(n, swarmMasters[host.HostOptions.SwarmOptions.Discovery]) {
				return true
			}
		}
	}
	return false
}

func matchesDriverName(host *host.Host, driverNames []string) bool {
	if len(driverNames) == 0 {
		return true
	}
	for _, n := range driverNames {
		if strings.EqualFold(host.DriverName, n) {
			return true
		}
	}
	return false
}

func matchesState(host *host.Host, states []string) bool {
	if len(states) == 0 {
		return true
	}
	for _, n := range states {
		s, err := host.Driver.GetState()
		if err != nil {
			log.Warn(err)
		}
		if strings.EqualFold(n, s.String()) {
			return true
		}
	}
	return false
}

func matchesName(host *host.Host, names []string) bool {
	if len(names) == 0 {
		return true
	}
	for _, n := range names {
		r, err := regexp.Compile(n)
		if err != nil {
			// TODO: remove that call to Fatal
			log.Fatal(err)
		}
		if r.MatchString(host.Driver.GetMachineName()) {
			return true
		}
	}
	return false
}

func matchesLabel(host *host.Host, labels []string) bool {
	if len(labels) == 0 {
		return true
	}

	var englabels = make(map[string]string, len(host.HostOptions.EngineOptions.Labels))

	if host.HostOptions != nil && host.HostOptions.EngineOptions.Labels != nil {
		for _, s := range host.HostOptions.EngineOptions.Labels {
			kv := strings.SplitN(s, "=", 2)
			englabels[kv[0]] = kv[1]
		}
	}

	for _, l := range labels {
		kv := strings.SplitN(l, "=", 2)
		if val, exists := englabels[kv[0]]; exists && strings.EqualFold(val, kv[1]) {
			return true
		}
	}
	return false
}

func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) {
	url := ""
	hostError := ""
	dockerVersion := "Unknown"

	currentState, err := h.Driver.GetState()
	if err == nil {
		url, err = h.URL()
	}
	if err == nil {
		dockerVersion, err = h.DockerVersion()
		if err != nil {
			dockerVersion = "Unknown"
		} else {
			dockerVersion = fmt.Sprintf("v%s", dockerVersion)
		}
	}

	if err != nil {
		hostError = err.Error()
	}
	if hostError == drivers.ErrHostIsNotRunning.Error() {
		hostError = ""
	}

	var swarmOptions *swarm.Options
	var engineOptions *engine.Options
	if h.HostOptions != nil {
		swarmOptions = h.HostOptions.SwarmOptions
		engineOptions = h.HostOptions.EngineOptions
	}

	stateQueryChan <- HostListItem{
		Name:          h.Name,
		Active:        isActive(currentState, url),
		DriverName:    h.Driver.DriverName(),
		State:         currentState,
		URL:           url,
		SwarmOptions:  swarmOptions,
		EngineOptions: engineOptions,
		DockerVersion: dockerVersion,
		Error:         hostError,
	}
}

func getHostState(h *host.Host, hostListItemsChan chan<- HostListItem) {
	// This channel is used to communicate the properties we are querying
	// about the host in the case of a successful read.
	stateQueryChan := make(chan HostListItem)

	go attemptGetHostState(h, stateQueryChan)

	select {
	// If we get back useful information, great.  Forward it straight to
	// the original parent channel.
	case hli := <-stateQueryChan:
		hostListItemsChan <- hli

	// Otherwise, give up after a predetermined duration.
	case <-time.After(stateTimeoutDuration):
		hostListItemsChan <- HostListItem{
			Name:       h.Name,
			DriverName: h.Driver.DriverName(),
			State:      state.Timeout,
		}
	}
}

func getHostListItems(hostList []*host.Host, hostsInError map[string]error) []HostListItem {
	hostListItems := []HostListItem{}
	hostListItemsChan := make(chan HostListItem)

	for _, h := range hostList {
		go getHostState(h, hostListItemsChan)
	}

	for range hostList {
		hostListItems = append(hostListItems, <-hostListItemsChan)
	}

	close(hostListItemsChan)

	for name, err := range hostsInError {
		itemInError := HostListItem{}
		itemInError.Name = name
		itemInError.DriverName = "not found"
		itemInError.State = state.Error
		itemInError.Error = err.Error()
		hostListItems = append(hostListItems, itemInError)
	}

	sortHostListItemsByName(hostListItems)
	return hostListItems
}

func sortHostListItemsByName(items []HostListItem) {
	m := make(map[string]HostListItem, len(items))
	s := make([]string, len(items))
	for i, v := range items {
		name := strings.ToLower(v.Name)
		m[name] = v
		s[i] = name
	}
	sort.Sort(naturalsort.NaturalSort(s))
	for i, v := range s {
		items[i] = m[v]
	}
}

// IsActive provides a single function for determining if a host is active
// based on both the url and if the host is stopped.
func isActive(currentState state.State, url string) bool {
	dockerHost := os.Getenv("DOCKER_HOST")

	// TODO: hard-coding the swarm port is a travesty...
	deSwarmedHost := strings.Replace(dockerHost, ":3376", ":2376", 1)
	if dockerHost == url || deSwarmedHost == url {
		return currentState == state.Running
	}

	return false
}
<commit_msg>FIX #2280 prevent nil dereference<commit_after>package commands

import (
	"errors"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"
	"text/tabwriter"
	"time"

	"github.com/docker/machine/libmachine"
	"github.com/docker/machine/libmachine/drivers"
	"github.com/docker/machine/libmachine/engine"
	"github.com/docker/machine/libmachine/host"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/persist"
	"github.com/docker/machine/libmachine/state"
	"github.com/docker/machine/libmachine/swarm"
	"github.com/skarademir/naturalsort"
)

const lsDefaultTimeout = 10

var (
	stateTimeoutDuration = lsDefaultTimeout * time.Second
)

// FilterOptions -
type FilterOptions struct {
	SwarmName  []string
	DriverName []string
	State      []string
	Name       []string
	Labels     []string
}

type HostListItem struct {
	Name          string
	Active        bool
	DriverName    string
	State         state.State
	URL           string
	SwarmOptions  *swarm.Options
	EngineOptions *engine.Options
	Error         string
	DockerVersion string
}

func cmdLs(c CommandLine, api libmachine.API) error {
	stateTimeoutDuration = time.Duration(c.Int("timeout")) * time.Second
	log.Debugf("ls timeout set to %s", stateTimeoutDuration)

	quiet := c.Bool("quiet")
	filters, err := parseFilters(c.StringSlice("filter"))
	if err != nil {
		return err
	}

	hostList, hostInError, err := persist.LoadAllHosts(api)
	if err != nil {
		return err
	}

	hostList = filterHosts(hostList, filters)

	// Just print out the names if we're being quiet
	if quiet {
		for _, host := range hostList {
			fmt.Println(host.Name)
		}
		return nil
	}

	swarmMasters := make(map[string]string)
	swarmInfo := make(map[string]string)

	w := tabwriter.NewWriter(os.Stdout, 5, 1, 3, ' ', 0)
	fmt.Fprintln(w, "NAME\tACTIVE\tDRIVER\tSTATE\tURL\tSWARM\tDOCKER\tERRORS")

	for _, host := range hostList {
		if host.HostOptions != nil {
			swarmOptions := host.HostOptions.SwarmOptions
			if swarmOptions.Master {
				swarmMasters[swarmOptions.Discovery] = host.Name
			}

			if swarmOptions.Discovery != "" {
				swarmInfo[host.Name] = swarmOptions.Discovery
			}
		}
	}

	items := getHostListItems(hostList, hostInError)

	for _, item := range items {
		activeString := "-"
		if item.Active {
			activeString = "*"
		}

		swarmInfo := ""

		if item.SwarmOptions != nil && item.SwarmOptions.Discovery != "" {
			swarmInfo = swarmMasters[item.SwarmOptions.Discovery]
			if item.SwarmOptions.Master {
				swarmInfo = fmt.Sprintf("%s (master)", swarmInfo)
			}
		}
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
			item.Name, activeString, item.DriverName, item.State, item.URL, swarmInfo, item.DockerVersion, item.Error)
	}

	w.Flush()

	return nil
}

func parseFilters(filters []string) (FilterOptions, error) {
	options := FilterOptions{}
	for _, f := range filters {
		kv := strings.SplitN(f, "=", 2)
		if len(kv) != 2 {
			return options, errors.New("Unsupported filter syntax.")
		}
		key, value := strings.ToLower(kv[0]), kv[1]

		switch key {
		case "swarm":
			options.SwarmName = append(options.SwarmName, value)
		case "driver":
			options.DriverName = append(options.DriverName, value)
		case "state":
			options.State = append(options.State, value)
		case "name":
			options.Name = append(options.Name, value)
		case "label":
			options.Labels = append(options.Labels, value)
		default:
			return options, fmt.Errorf("Unsupported filter key '%s'", key)
		}
	}
	return options, nil
}

func filterHosts(hosts []*host.Host, filters FilterOptions) []*host.Host {
	if len(filters.SwarmName) == 0 &&
		len(filters.DriverName) == 0 &&
		len(filters.State) == 0 &&
		len(filters.Name) == 0 &&
		len(filters.Labels) == 0 {
		return hosts
	}

	filteredHosts := []*host.Host{}
	swarmMasters := getSwarmMasters(hosts)

	for _, h := range hosts {
		if filterHost(h, filters, swarmMasters) {
			filteredHosts = append(filteredHosts, h)
		}
	}
	return filteredHosts
}

func getSwarmMasters(hosts []*host.Host) map[string]string {
	swarmMasters := make(map[string]string)
	for _, h := range hosts {
		if h.HostOptions != nil {
			swarmOptions := h.HostOptions.SwarmOptions
			if swarmOptions != nil && swarmOptions.Master {
				swarmMasters[swarmOptions.Discovery] = h.Name
			}
		}
	}
	return swarmMasters
}

func filterHost(host *host.Host, filters FilterOptions, swarmMasters map[string]string) bool {
	swarmMatches := matchesSwarmName(host, filters.SwarmName, swarmMasters)
	driverMatches := matchesDriverName(host, filters.DriverName)
	stateMatches := matchesState(host, filters.State)
	nameMatches := matchesName(host, filters.Name)
	labelMatches := matchesLabel(host, filters.Labels)

	return swarmMatches && driverMatches && stateMatches && nameMatches && labelMatches
}

func matchesSwarmName(host *host.Host, swarmNames []string, swarmMasters map[string]string) bool {
	if len(swarmNames) == 0 {
		return true
	}
	for _, n := range swarmNames {
		if host.HostOptions != nil && host.HostOptions.SwarmOptions != nil {
			if strings.EqualFold(n, swarmMasters[host.HostOptions.SwarmOptions.Discovery]) {
				return true
			}
		}
	}
	return false
}

func matchesDriverName(host *host.Host, driverNames []string) bool {
	if len(driverNames) == 0 {
		return true
	}
	for _, n := range driverNames {
		if strings.EqualFold(host.DriverName, n) {
			return true
		}
	}
	return false
}

func matchesState(host *host.Host, states []string) bool {
	if len(states) == 0 {
		return true
	}
	for _, n := range states {
		s, err := host.Driver.GetState()
		if err != nil {
			log.Warn(err)
		}
		if strings.EqualFold(n, s.String()) {
			return true
		}
	}
	return false
}

func matchesName(host *host.Host, names []string) bool {
	if len(names) == 0 {
		return true
	}
	for _, n := range names {
		r, err := regexp.Compile(n)
		if err != nil {
			// TODO: remove that call to Fatal
			log.Fatal(err)
		}
		if r.MatchString(host.Driver.GetMachineName()) {
			return true
		}
	}
	return false
}

func matchesLabel(host *host.Host, labels []string) bool {
	if len(labels) == 0 {
		return true
	}

	var englabels = make(map[string]string, len(host.HostOptions.EngineOptions.Labels))

	if host.HostOptions != nil && host.HostOptions.EngineOptions.Labels != nil {
		for _, s := range host.HostOptions.EngineOptions.Labels {
			kv := strings.SplitN(s, "=", 2)
			englabels[kv[0]] = kv[1]
		}
	}

	for _, l := range labels {
		kv := strings.SplitN(l, "=", 2)
		if val, exists := englabels[kv[0]]; exists && strings.EqualFold(val, kv[1]) {
			return true
		}
	}
	return false
}

func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) {
	url := ""
	hostError := ""
	dockerVersion := "Unknown"

	currentState, err := h.Driver.GetState()
	if err == nil {
		url, err = h.URL()
	}
	if err == nil {
		dockerVersion, err = h.DockerVersion()
		if err != nil {
			dockerVersion = "Unknown"
		} else {
			dockerVersion = fmt.Sprintf("v%s", dockerVersion)
		}
	}

	if err != nil {
		hostError = err.Error()
	}
	if hostError == drivers.ErrHostIsNotRunning.Error() {
		hostError = ""
	}

	var swarmOptions *swarm.Options
	var engineOptions *engine.Options
	if h.HostOptions != nil {
		swarmOptions = h.HostOptions.SwarmOptions
		engineOptions = h.HostOptions.EngineOptions
	}

	stateQueryChan <- HostListItem{
		Name:          h.Name,
		Active:        isActive(currentState, url),
		DriverName:    h.Driver.DriverName(),
		State:         currentState,
		URL:           url,
		SwarmOptions:  swarmOptions,
		EngineOptions: engineOptions,
		DockerVersion: dockerVersion,
		Error:         hostError,
	}
}

func getHostState(h *host.Host, hostListItemsChan chan<- HostListItem) {
	// This channel is used to communicate the properties we are querying
	// about the host in the case of a successful read.
	stateQueryChan := make(chan HostListItem)

	go attemptGetHostState(h, stateQueryChan)

	select {
	// If we get back useful information, great.  Forward it straight to
	// the original parent channel.
	case hli := <-stateQueryChan:
		hostListItemsChan <- hli

	// Otherwise, give up after a predetermined duration.
	case <-time.After(stateTimeoutDuration):
		hostListItemsChan <- HostListItem{
			Name:       h.Name,
			DriverName: h.Driver.DriverName(),
			State:      state.Timeout,
		}
	}
}

func getHostListItems(hostList []*host.Host, hostsInError map[string]error) []HostListItem {
	hostListItems := []HostListItem{}
	hostListItemsChan := make(chan HostListItem)

	for _, h := range hostList {
		go getHostState(h, hostListItemsChan)
	}

	for range hostList {
		hostListItems = append(hostListItems, <-hostListItemsChan)
	}

	close(hostListItemsChan)

	for name, err := range hostsInError {
		itemInError := HostListItem{}
		itemInError.Name = name
		itemInError.DriverName = "not found"
		itemInError.State = state.Error
		itemInError.Error = err.Error()
		hostListItems = append(hostListItems, itemInError)
	}

	sortHostListItemsByName(hostListItems)
	return hostListItems
}

func sortHostListItemsByName(items []HostListItem) {
	m := make(map[string]HostListItem, len(items))
	s := make([]string, len(items))
	for i, v := range items {
		name := strings.ToLower(v.Name)
		m[name] = v
		s[i] = name
	}
	sort.Sort(naturalsort.NaturalSort(s))
	for i, v := range s {
		items[i] = m[v]
	}
}

// IsActive provides a single function for determining if a host is active
// based on both the url and if the host is stopped.
func isActive(currentState state.State, url string) bool {
	dockerHost := os.Getenv("DOCKER_HOST")

	// TODO: hard-coding the swarm port is a travesty...
	deSwarmedHost := strings.Replace(dockerHost, ":3376", ":2376", 1)
	if dockerHost == url || deSwarmedHost == url {
		return currentState == state.Running
	}

	return false
}
<|endoftext|>


<commit_before>// Copyright 2014 ISRG.  All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package ca

import (
	"crypto"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"time"

	"github.com/letsencrypt/boulder/core"
	blog "github.com/letsencrypt/boulder/log"
	"github.com/letsencrypt/boulder/policy"

	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
	cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp"
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote"
)

type Config struct {
	Server       string
	AuthKey      string
	Profile      string
	TestMode     bool
	DBDriver     string
	DBName       string
	SerialPrefix int
	// A PEM-encoded copy of the issuer certificate.
	IssuerCert string
	// This field is only allowed if TestMode is true, indicating that we are
	// signing with a local key. In production we will use an HSM and this
	// IssuerKey must be empty (and TestMode must be false). PEM-encoded private
	// key used for signing certificates and OCSP responses.
	IssuerKey string
}

// CertificateAuthorityImpl represents a CA that signs certificates, CRLs, and
// OCSP responses.
type CertificateAuthorityImpl struct {
	profile    string
	Signer     signer.Signer
	OCSPSigner ocsp.Signer
	SA         core.StorageAuthority
	PA         core.PolicyAuthority
	DB         core.CertificateAuthorityDatabase
	log        *blog.AuditLogger
	Prefix     int // Prepended to the serial number
}

// NewCertificateAuthorityImpl creates a CA that talks to a remote CFSSL
// instance.  (To use a local signer, simply instantiate CertificateAuthorityImpl
// directly.)  Communications with the CA are authenticated with MACs,
// using CFSSL's authenticated signature scheme.  A CA created in this way
// issues for a single profile on the remote signer, which is indicated
// by name in this constructor.
func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config Config) (*CertificateAuthorityImpl, error) {
	var ca *CertificateAuthorityImpl
	var err error
	logger := blog.GetAuditLogger()
	logger.Notice("Certificate Authority Starting")

	if config.SerialPrefix == 0 {
		err = errors.New("Must have non-zero serial prefix for CA.")
		return nil, err
	}

	// Create the remote signer
	localProfile := cfsslConfig.SigningProfile{
		Expiry:       time.Hour,     // BOGUS: Required by CFSSL, but not used
		RemoteName:   config.Server, // BOGUS: Only used as a flag by CFSSL
		RemoteServer: config.Server,
		UseSerialSeq: true,
	}

	localProfile.Provider, err = auth.New(config.AuthKey, nil)
	if err != nil {
		return nil, err
	}

	signer, err := remote.NewSigner(&cfsslConfig.Signing{Default: &localProfile})
	if err != nil {
		return nil, err
	}

	issuer, err := loadIssuer(config.IssuerCert)
	if err != nil {
		return nil, err
	}

	// In test mode, load a private key from a file. In production, use an HSM.
	if !config.TestMode {
		err = errors.New("OCSP signing with a PKCS#11 key not yet implemented.")
		return nil, err
	}
	issuerKey, err := loadIssuerKey(config.IssuerKey)
	if err != nil {
		return nil, err
	}

	// Set up our OCSP signer. Note this calls for both the issuer cert and the
	// OCSP signing cert, which are the same in our case.
	ocspSigner, err := ocsp.NewSigner(issuer, issuer, issuerKey,
		time.Hour*24*4)

	pa := policy.NewPolicyAuthorityImpl()

	ca = &CertificateAuthorityImpl{
		Signer:     signer,
		OCSPSigner: ocspSigner,
		profile:    config.Profile,
		PA:         pa,
		DB:         cadb,
		Prefix:     config.SerialPrefix,
		log:        logger,
	}
	return ca, err
}

func loadIssuer(filename string) (issuerCert *x509.Certificate, err error) {
	if filename == "" {
		err = errors.New("Issuer certificate was not provided in config.")
		return
	}
	issuerCertPEM, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	issuerCert, err = helpers.ParseCertificatePEM(issuerCertPEM)
	return
}

func loadIssuerKey(filename string) (issuerKey crypto.Signer, err error) {
	if filename == "" {
		err = errors.New("IssuerKey must be provided in test mode.")
		return
	}

	pem, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	issuerKey, err = helpers.ParsePrivateKeyPEM(pem)
	return
}

func (ca *CertificateAuthorityImpl) RevokeCertificate(serial string) (err error) {
	certDER, err := ca.SA.GetCertificate(serial)
	if err != nil {
		return err
	}
	cert, err := x509.ParseCertificate(certDER)
	if err != nil {
		return err
	}

	// Per https://tools.ietf.org/html/rfc5280, CRLReason 0 is "unspecified."
	// TODO: Add support for specifying reason.
	reason := 0

	signRequest := ocsp.SignRequest{
		Certificate: cert,
		Status:      string(core.OCSPStatusRevoked),
		Reason:      reason,
		RevokedAt:   time.Now(),
	}
	ocspResponse, err := ca.OCSPSigner.Sign(signRequest)
	if err != nil {
		return err
	}
	err = ca.SA.MarkCertificateRevoked(serial, ocspResponse, reason)
	return err
}

// IssueCertificate attempts to convert a CSR into a signed Certificate, while
// enforcing all policies.
func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest) (core.Certificate, error) {
	emptyCert := core.Certificate{}
	var err error
	// XXX Take in authorizations and verify that union covers CSR?
	// Pull hostnames from CSR
	hostNames := csr.DNSNames // DNSNames + CN from CSR
	var commonName string
	if len(csr.Subject.CommonName) > 0 {
		commonName = csr.Subject.CommonName
	} else if len(hostNames) > 0 {
		commonName = hostNames[0]
	} else {
		err = errors.New("Cannot issue a certificate without a hostname.")
		ca.log.WarningErr(err)
		return emptyCert, err
	}

	if len(hostNames) == 0 {
		hostNames = []string{commonName}
	}

	identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: commonName}
	if err = ca.PA.WillingToIssue(identifier); err != nil {
		err = errors.New("Policy forbids issuing for name " + commonName)
		ca.log.AuditErr(err)
		return emptyCert, err
	}
	for _, name := range hostNames {
		identifier = core.AcmeIdentifier{Type: core.IdentifierDNS, Value: name}
		if err = ca.PA.WillingToIssue(identifier); err != nil {
			err = errors.New("Policy forbids issuing for name " + name)
			ca.log.AuditErr(err)
			return emptyCert, err
		}
	}

	// Convert the CSR to PEM
	csrPEM := string(pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE REQUEST",
		Bytes: csr.Raw,
	}))

	// Get the next serial number
	ca.DB.Begin()
	serialDec, err := ca.DB.IncrementAndGetSerial()
	if err != nil {
		return emptyCert, err
	}
	serialHex := fmt.Sprintf("%02X%014X", ca.Prefix, serialDec)

	// Send the cert off for signing
	req := signer.SignRequest{
		Request: csrPEM,
		Profile: ca.profile,
		Hosts:   hostNames,
		Subject: &signer.Subject{
			CN: commonName,
		},
		SerialSeq: serialHex,
	}

	certPEM, err := ca.Signer.Sign(req)
	if err != nil {
		ca.DB.Rollback()
		return emptyCert, err
	}

	if len(certPEM) == 0 {
		err = errors.New("No certificate returned by server")
		ca.log.WarningErr(err)
		ca.DB.Rollback()
		return emptyCert, err
	}

	block, _ := pem.Decode(certPEM)
	if block == nil || block.Type != "CERTIFICATE" {
		err = errors.New("Invalid certificate value returned")
		ca.log.WarningErr(err)
		ca.DB.Rollback()
		return emptyCert, err
	}
	certDER := block.Bytes

	cert := core.Certificate{
		DER:    certDER,
		Status: core.StatusValid,
	}
	if err != nil {
		return emptyCert, err
	}

	// Store the cert with the certificate authority, if provided
	_, err = ca.SA.AddCertificate(certDER)
	if err != nil {
		ca.DB.Rollback()
		return emptyCert, err
	}

	ca.DB.Commit()
	return cert, nil
}
<commit_msg>check config serial prefix is less than 256<commit_after>// Copyright 2014 ISRG.  All rights reserved
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package ca

import (
	"crypto"
	"crypto/x509"
	"encoding/pem"
	"errors"
	"fmt"
	"io/ioutil"
	"time"

	"github.com/letsencrypt/boulder/core"
	blog "github.com/letsencrypt/boulder/log"
	"github.com/letsencrypt/boulder/policy"

	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/auth"
	cfsslConfig "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/config"
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/helpers"
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/ocsp"
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer"
	"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cloudflare/cfssl/signer/remote"
)

type Config struct {
	Server       string
	AuthKey      string
	Profile      string
	TestMode     bool
	DBDriver     string
	DBName       string
	SerialPrefix int
	// A PEM-encoded copy of the issuer certificate.
	IssuerCert string
	// This field is only allowed if TestMode is true, indicating that we are
	// signing with a local key. In production we will use an HSM and this
	// IssuerKey must be empty (and TestMode must be false). PEM-encoded private
	// key used for signing certificates and OCSP responses.
	IssuerKey string
}

// CertificateAuthorityImpl represents a CA that signs certificates, CRLs, and
// OCSP responses.
type CertificateAuthorityImpl struct {
	profile    string
	Signer     signer.Signer
	OCSPSigner ocsp.Signer
	SA         core.StorageAuthority
	PA         core.PolicyAuthority
	DB         core.CertificateAuthorityDatabase
	log        *blog.AuditLogger
	Prefix     int // Prepended to the serial number
}

// NewCertificateAuthorityImpl creates a CA that talks to a remote CFSSL
// instance.  (To use a local signer, simply instantiate CertificateAuthorityImpl
// directly.)  Communications with the CA are authenticated with MACs,
// using CFSSL's authenticated signature scheme.  A CA created in this way
// issues for a single profile on the remote signer, which is indicated
// by name in this constructor.
func NewCertificateAuthorityImpl(cadb core.CertificateAuthorityDatabase, config Config) (*CertificateAuthorityImpl, error) {
	var ca *CertificateAuthorityImpl
	var err error
	logger := blog.GetAuditLogger()
	logger.Notice("Certificate Authority Starting")

	if config.SerialPrefix == 0 || config.SerialPrefix >= 256 {
		err = errors.New("Must have non-zero serial prefix less than 256 for CA.")
		return nil, err
	}

	// Create the remote signer
	localProfile := cfsslConfig.SigningProfile{
		Expiry:       time.Hour,     // BOGUS: Required by CFSSL, but not used
		RemoteName:   config.Server, // BOGUS: Only used as a flag by CFSSL
		RemoteServer: config.Server,
		UseSerialSeq: true,
	}

	localProfile.Provider, err = auth.New(config.AuthKey, nil)
	if err != nil {
		return nil, err
	}

	signer, err := remote.NewSigner(&cfsslConfig.Signing{Default: &localProfile})
	if err != nil {
		return nil, err
	}

	issuer, err := loadIssuer(config.IssuerCert)
	if err != nil {
		return nil, err
	}

	// In test mode, load a private key from a file. In production, use an HSM.
	if !config.TestMode {
		err = errors.New("OCSP signing with a PKCS#11 key not yet implemented.")
		return nil, err
	}
	issuerKey, err := loadIssuerKey(config.IssuerKey)
	if err != nil {
		return nil, err
	}

	// Set up our OCSP signer. Note this calls for both the issuer cert and the
	// OCSP signing cert, which are the same in our case.
	ocspSigner, err := ocsp.NewSigner(issuer, issuer, issuerKey,
		time.Hour*24*4)

	pa := policy.NewPolicyAuthorityImpl()

	ca = &CertificateAuthorityImpl{
		Signer:     signer,
		OCSPSigner: ocspSigner,
		profile:    config.Profile,
		PA:         pa,
		DB:         cadb,
		Prefix:     config.SerialPrefix,
		log:        logger,
	}
	return ca, err
}

func loadIssuer(filename string) (issuerCert *x509.Certificate, err error) {
	if filename == "" {
		err = errors.New("Issuer certificate was not provided in config.")
		return
	}
	issuerCertPEM, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	issuerCert, err = helpers.ParseCertificatePEM(issuerCertPEM)
	return
}

func loadIssuerKey(filename string) (issuerKey crypto.Signer, err error) {
	if filename == "" {
		err = errors.New("IssuerKey must be provided in test mode.")
		return
	}

	pem, err := ioutil.ReadFile(filename)
	if err != nil {
		return
	}
	issuerKey, err = helpers.ParsePrivateKeyPEM(pem)
	return
}

func (ca *CertificateAuthorityImpl) RevokeCertificate(serial string) (err error) {
	certDER, err := ca.SA.GetCertificate(serial)
	if err != nil {
		return err
	}
	cert, err := x509.ParseCertificate(certDER)
	if err != nil {
		return err
	}

	// Per https://tools.ietf.org/html/rfc5280, CRLReason 0 is "unspecified."
	// TODO: Add support for specifying reason.
	reason := 0

	signRequest := ocsp.SignRequest{
		Certificate: cert,
		Status:      string(core.OCSPStatusRevoked),
		Reason:      reason,
		RevokedAt:   time.Now(),
	}
	ocspResponse, err := ca.OCSPSigner.Sign(signRequest)
	if err != nil {
		return err
	}
	err = ca.SA.MarkCertificateRevoked(serial, ocspResponse, reason)
	return err
}

// IssueCertificate attempts to convert a CSR into a signed Certificate, while
// enforcing all policies.
func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest) (core.Certificate, error) {
	emptyCert := core.Certificate{}
	var err error
	// XXX Take in authorizations and verify that union covers CSR?
	// Pull hostnames from CSR
	hostNames := csr.DNSNames // DNSNames + CN from CSR
	var commonName string
	if len(csr.Subject.CommonName) > 0 {
		commonName = csr.Subject.CommonName
	} else if len(hostNames) > 0 {
		commonName = hostNames[0]
	} else {
		err = errors.New("Cannot issue a certificate without a hostname.")
		ca.log.WarningErr(err)
		return emptyCert, err
	}

	if len(hostNames) == 0 {
		hostNames = []string{commonName}
	}

	identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: commonName}
	if err = ca.PA.WillingToIssue(identifier); err != nil {
		err = errors.New("Policy forbids issuing for name " + commonName)
		ca.log.AuditErr(err)
		return emptyCert, err
	}
	for _, name := range hostNames {
		identifier = core.AcmeIdentifier{Type: core.IdentifierDNS, Value: name}
		if err = ca.PA.WillingToIssue(identifier); err != nil {
			err = errors.New("Policy forbids issuing for name " + name)
			ca.log.AuditErr(err)
			return emptyCert, err
		}
	}

	// Convert the CSR to PEM
	csrPEM := string(pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE REQUEST",
		Bytes: csr.Raw,
	}))

	// Get the next serial number
	ca.DB.Begin()
	serialDec, err := ca.DB.IncrementAndGetSerial()
	if err != nil {
		return emptyCert, err
	}
	serialHex := fmt.Sprintf("%02X%014X", ca.Prefix, serialDec)

	// Send the cert off for signing
	req := signer.SignRequest{
		Request: csrPEM,
		Profile: ca.profile,
		Hosts:   hostNames,
		Subject: &signer.Subject{
			CN: commonName,
		},
		SerialSeq: serialHex,
	}

	certPEM, err := ca.Signer.Sign(req)
	if err != nil {
		ca.DB.Rollback()
		return emptyCert, err
	}

	if len(certPEM) == 0 {
		err = errors.New("No certificate returned by server")
		ca.log.WarningErr(err)
		ca.DB.Rollback()
		return emptyCert, err
	}

	block, _ := pem.Decode(certPEM)
	if block == nil || block.Type != "CERTIFICATE" {
		err = errors.New("Invalid certificate value returned")
		ca.log.WarningErr(err)
		ca.DB.Rollback()
		return emptyCert, err
	}
	certDER := block.Bytes

	cert := core.Certificate{
		DER:    certDER,
		Status: core.StatusValid,
	}
	if err != nil {
		return emptyCert, err
	}

	// Store the cert with the certificate authority, if provided
	_, err = ca.SA.AddCertificate(certDER)
	if err != nil {
		ca.DB.Rollback()
		return emptyCert, err
	}

	ca.DB.Commit()
	return cert, nil
}
<|endoftext|>


<commit_before>//Package session is used to store user data in token based cache.
//It is normally used as user session or token.
//This package depands github.com/herb-go/herb/cache.
package session

import (
	"crypto/md5"
	"encoding/hex"
	"net/url"
	"time"

	"github.com/herb-go/herb/cache"
)

const (
	//PrefixModeRaw prefix mode which dont convert prefix
	PrefixModeRaw = "raw"
	//PrefixModeMd5 prefix mode which  convert prefix to md5 sum
	PrefixModeMd5     = "md5"
	PrefixModeEmpty   = "empty"
	DefaultPrefixMode = PrefixModeRaw
)

const DefaultTokenLength = 256

var defaultUpdateActiveInterval = 5 * time.Minute

var defaultTokenMaxLifetime = 365 * 24 * time.Hour
var (
	defaultCookieName = "herb-session"
	defaultCookiePath = "/"
)

func defaultTokenGenerater(s *CacheDriver, prefix string) (token string, err error) {
	t, err := cache.RandMaskedBytes(cache.TokenMask, s.Length)
	if err != nil {
		return
	}
	prefixconverted, err := s.ConvertPrefix(prefix)
	if err != nil {
		return
	}
	if prefixconverted != "" {
		token = url.PathEscape(prefix) + "-" + string(t)
	} else {
		token = string(t)
	}
	return
}

//NewCacheDriver create new cache driver
func NewCacheDriver() *CacheDriver {
	return &CacheDriver{
		TokenGenerater: defaultTokenGenerater,
		Length:         DefaultTokenLength,
		PrefixMode:     PrefixModeRaw,
	}
}

// MustCacheStore create new cache store with given token lifetime.
//Return store created.
//Panic if any error raised.
func MustCacheStore(Cache *cache.Cache, TokenLifetime time.Duration) *Store {
	driver := NewCacheDriver()
	oc := NewCacheDriverOptionConfig()
	oc.Cache = Cache
	err := driver.Init(oc)
	if err != nil {
		panic(err)
	}
	store := New()
	soc := NewOptionConfig()
	soc.Driver = driver
	soc.TokenLifetime = TokenLifetime
	err = store.Init(soc)
	if err != nil {
		panic(err)
	}
	return store
}

//CacheDriver CacheDriver is the stuct store token data in cache.
type CacheDriver struct {
	Cache          *cache.Cache //Cache which stores token data
	Length         int
	PrefixMode     string
	TokenGenerater func(s *CacheDriver, prefix string) (token string, err error) //Token name generate func
}

//Init init cache driver with given option
func (s *CacheDriver) Init(option CacheDriverOption) error {
	return option.ApplyTo(s)
}

//Close Close cachestore and return any error if raised
func (s *CacheDriver) Close() error {
	return s.Cache.Close()
}

//GenerateToken generate new token name with given prefix.
//Return the new token name and error.
func (s *CacheDriver) GenerateToken(prefix string) (token string, err error) {
	return s.TokenGenerater(s, prefix)
}

func (s *CacheDriver) ConvertPrefix(prefix string) (output string, err error) {
	switch s.PrefixMode {
	case PrefixModeEmpty:
		return "", nil
	case PrefixModeRaw:
		return prefix, nil
	case PrefixModeMd5:
		o := md5.Sum([]byte(prefix))
		return hex.EncodeToString(o[:]), nil
	}
	return "", nil
}

//Load load a given session with token from store.
func (s *CacheDriver) Load(v *Session) (err error) {
	token := v.token
	bytes, err := s.Cache.GetBytesValue(token)
	if err == cache.ErrNotFound {
		err = ErrDataNotFound
	}
	if err != nil {
		return err
	}

	err = v.Unmarshal(token, bytes)
	if err == nil {
		v.token = token
	}
	return
}

//Save  save given session with given ttl to store.
//Return any error if raised.
func (s *CacheDriver) Save(ts *Session, ttl time.Duration) (err error) {
	bytes, err := ts.Marshal()
	if err != nil {
		return err
	}
	if ts.oldToken == ts.token {
		err = s.Cache.UpdateBytesValue(ts.token, bytes, ttl)
	} else {
		err = s.Cache.SetBytesValue(ts.token, bytes, ttl)
	}
	return
}

//Delete delete the token with given name.
//Return any error if raised.
func (s *CacheDriver) Delete(token string) error {
	return s.Cache.Del(token)
}

//GetSessionToken Get the token string from token data.
//Return token and any error raised.
func (s *CacheDriver) GetSessionToken(ts *Session) (token string, err error) {
	return ts.token, nil
}
<commit_msg>update<commit_after>//Package session is used to store user data in token based cache.
//It is normally used as user session or token.
//This package depands github.com/herb-go/herb/cache.
package session

import (
	"crypto/md5"
	"encoding/hex"
	"net/url"
	"time"

	"github.com/herb-go/herb/cache"
)

const (
	//PrefixModeRaw prefix mode which dont convert prefix
	PrefixModeRaw = "raw"
	//PrefixModeMd5 prefix mode which  convert prefix to md5 sum
	PrefixModeMd5     = "md5"
	PrefixModeEmpty   = "empty"
	DefaultPrefixMode = PrefixModeRaw
)

const DefaultTokenLength = 256

var defaultUpdateActiveInterval = 5 * time.Minute

var defaultTokenMaxLifetime = 365 * 24 * time.Hour
var (
	defaultCookieName = "herb-session"
	defaultCookiePath = "/"
)

func defaultTokenGenerater(s *CacheDriver, prefix string) (token string, err error) {
	t, err := cache.RandMaskedBytes(cache.TokenMask, s.Length)
	if err != nil {
		return
	}
	prefixconverted, err := s.ConvertPrefix(prefix)
	if err != nil {
		return
	}
	if prefixconverted != "" {
		token = url.PathEscape(prefixconverted) + "-" + string(t)
	} else {
		token = string(t)
	}
	return
}

//NewCacheDriver create new cache driver
func NewCacheDriver() *CacheDriver {
	return &CacheDriver{
		TokenGenerater: defaultTokenGenerater,
		Length:         DefaultTokenLength,
		PrefixMode:     PrefixModeRaw,
	}
}

// MustCacheStore create new cache store with given token lifetime.
//Return store created.
//Panic if any error raised.
func MustCacheStore(Cache *cache.Cache, TokenLifetime time.Duration) *Store {
	driver := NewCacheDriver()
	oc := NewCacheDriverOptionConfig()
	oc.Cache = Cache
	err := driver.Init(oc)
	if err != nil {
		panic(err)
	}
	store := New()
	soc := NewOptionConfig()
	soc.Driver = driver
	soc.TokenLifetime = TokenLifetime
	err = store.Init(soc)
	if err != nil {
		panic(err)
	}
	return store
}

//CacheDriver CacheDriver is the stuct store token data in cache.
type CacheDriver struct {
	Cache          *cache.Cache //Cache which stores token data
	Length         int
	PrefixMode     string
	TokenGenerater func(s *CacheDriver, prefix string) (token string, err error) //Token name generate func
}

//Init init cache driver with given option
func (s *CacheDriver) Init(option CacheDriverOption) error {
	return option.ApplyTo(s)
}

//Close Close cachestore and return any error if raised
func (s *CacheDriver) Close() error {
	return s.Cache.Close()
}

//GenerateToken generate new token name with given prefix.
//Return the new token name and error.
func (s *CacheDriver) GenerateToken(prefix string) (token string, err error) {
	return s.TokenGenerater(s, prefix)
}

func (s *CacheDriver) ConvertPrefix(prefix string) (output string, err error) {
	switch s.PrefixMode {
	case PrefixModeEmpty:
		return "", nil
	case PrefixModeRaw:
		return prefix, nil
	case PrefixModeMd5:
		o := md5.Sum([]byte(prefix))
		return hex.EncodeToString(o[:]), nil
	}
	return "", nil
}

//Load load a given session with token from store.
func (s *CacheDriver) Load(v *Session) (err error) {
	token := v.token
	bytes, err := s.Cache.GetBytesValue(token)
	if err == cache.ErrNotFound {
		err = ErrDataNotFound
	}
	if err != nil {
		return err
	}

	err = v.Unmarshal(token, bytes)
	if err == nil {
		v.token = token
	}
	return
}

//Save  save given session with given ttl to store.
//Return any error if raised.
func (s *CacheDriver) Save(ts *Session, ttl time.Duration) (err error) {
	bytes, err := ts.Marshal()
	if err != nil {
		return err
	}
	if ts.oldToken == ts.token {
		err = s.Cache.UpdateBytesValue(ts.token, bytes, ttl)
	} else {
		err = s.Cache.SetBytesValue(ts.token, bytes, ttl)
	}
	return
}

//Delete delete the token with given name.
//Return any error if raised.
func (s *CacheDriver) Delete(token string) error {
	return s.Cache.Del(token)
}

//GetSessionToken Get the token string from token data.
//Return token and any error raised.
func (s *CacheDriver) GetSessionToken(ts *Session) (token string, err error) {
	return ts.token, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"time"
)

type perror string

func (e perror) Error() string { return string(e) }

func git(msg string) (err error) {
	cmd := exec.Command("git", "commit", "-m", msg)
	if err = cmd.Run(); err != nil {
		// not a git repository
		if err.Error() == "exit status 128" {
			return perror("not a git repo")
		}
		// nothing changed
		if err.Error() == "exit status 1" {
			fmt.Fprintf(os.Stdout, "%s: nothing changed\n", os.Args[0])
			return nil
		}
		return err
	}
	return nil
}

func mercurial(msg string) (err error) {
	cmd := exec.Command("hg", "commit", "-m", msg)
	if err = cmd.Run(); err != nil {
		// not a mercurial repository
		if err.Error() == "exit status 255" {
			return perror("not a hg repo")
		}
		// nothing changed
		if err.Error() == "exit status 1" {
			fmt.Fprintf(os.Stdout, "%s: nothing changed\n", os.Args[0])
			return nil
		}
		return err
	}
	return nil
}

func main() {
	if len(os.Args) == 2 && os.Args[1] == "-h" {
		fmt.Fprintf(os.Stderr, "Usage: %s [MESSAGE]\n", os.Args[0])
		os.Exit(2)
	}
	msg := fmt.Sprintf("%d", time.Now().Unix())
	if len(os.Args) == 2 {
		msg = os.Args[1]
	}
	err := mercurial(msg)
	if err != nil {
		if _, ok := err.(perror); ok {
			if err = git(msg); err != nil {
				if _, ok := err.(perror); ok {
					fmt.Fprintf(os.Stderr, "%s: not a hg/git repository\n", os.Args[0])
					os.Exit(0)
				}
				goto Error
			}
			os.Exit(0)
		}
		goto Error
	}
	os.Exit(0)

Error:
	fmt.Fprintf(os.Stderr, "%s: %v\n", os.Args[0], err)
	os.Exit(1)

}
<commit_msg>1428315157<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"time"
)

type perror string

func (e perror) Error() string { return string(e) }

func git(msg string) (err error) {
	cmd := exec.Command("git", "commit", "-m", msg)
	if err = cmd.Run(); err != nil {
		// not a git repository
		if err.Error() == "exit status 128" {
			return perror("not a git repo")
		}
		// nothing changed
		if err.Error() == "exit status 1" {
			fmt.Fprintf(os.Stdout, "%s: nothing changed\n", os.Args[0])
			return nil
		}
		return err
	}
	return nil
}

func mercurial(msg string) (err error) {
	cmd := exec.Command("hg", "commit", "-m", msg)
	if err = cmd.Run(); err != nil {
		// not a mercurial repository
		if err.Error() == "exit status 255" {
			return perror("not a hg repo")
		}
		// nothing changed
		if err.Error() == "exit status 1" {
			fmt.Fprintf(os.Stdout, "%s: nothing changed\n", os.Args[0])
			return nil
		}
		return err
	}
	return nil
}

func main() {
	if len(os.Args) == 2 && os.Args[1] == "-h" {
		fmt.Fprintf(os.Stderr, "Usage: %s [MESSAGE]\n", os.Args[0])
		os.Exit(2)
	}
	msg := fmt.Sprintf("%d", time.Now().Unix())
	if len(os.Args) == 2 {
		msg = os.Args[1]
	}
	err := git(msg)
	if err != nil {
		if _, ok := err.(perror); ok {
			if err = mercurial(msg); err != nil {
				if _, ok := err.(perror); ok {
					fmt.Fprintf(os.Stderr, "%s: not a hg/git repository\n", os.Args[0])
					os.Exit(0)
				}
				goto Error
			}
			os.Exit(0)
		}
		goto Error
	}
	os.Exit(0)

Error:
	fmt.Fprintf(os.Stderr, "%s: %v\n", os.Args[0], err)
	os.Exit(1)

}
<|endoftext|>


<commit_before>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package coldef

import (
	"fmt"
	"strings"

	"github.com/pingcap/tidb/expression"
)

// FloatOpt is used for parsing floating-point type option from SQL.
// TODO: add reference doc.
type FloatOpt struct {
	Flen    int
	Decimal int
}

// CharsetOpt is used for parsing charset option from SQL.
type CharsetOpt struct {
	Chs string
	Col string
}

// String implements fmt.Stringer interface.
func (o *CharsetOpt) String() string {
	var ss []string
	if o.Chs != "" {
		ss = append(ss, "CHARACTER SET = "+o.Chs)
	}
	if o.Col != "" {
		ss = append(ss, "COLLATE = "+o.Col)
	}
	return strings.Join(ss, " ")
}

// ConstraintOpt is used for parsing column constraint info from SQL.
type ConstraintOpt struct {
	Tp     int
	Bvalue bool
	Evalue expression.Expression
}

// String implements fmt.Stringer interface.
func (c *ConstraintOpt) String() string {
	switch c.Tp {
	case ConstrNotNull:
		return "NOT NULL"
	case ConstrNull:
		return "NULL"
	case ConstrAutoIncrement:
		return "AUTO_INCREMENT"
	case ConstrPrimaryKey:
		return "PRIMARY KEY"
	case ConstrUniq:
		return "UNIQUE"
	case ConstrUniqKey:
		return "UNIQUE KEY"
	case ConstrDefaultValue:
		return "DEFAULT " + c.Evalue.String()
	case ConstrOnUpdate:
		return "ON UPDATE " + c.Evalue.String()
	default:
		return ""
	}
}

// DB Options.
const (
	DBOptNone = iota
	DBOptCharset
	DBOptCollate
)

// DatabaseOpt is used for parsing database option from SQL.
type DatabaseOpt struct {
	Tp    int
	Value string
}

// Constraints.
const (
	ConstrNoConstr = iota
	ConstrPrimaryKey
	ConstrForeignKey
	ConstrNotNull
	ConstrAutoIncrement
	ConstrDefaultValue
	ConstrUniq
	ConstrIndex
	ConstrUniqIndex
	ConstrKey
	ConstrUniqKey
	ConstrNull
	ConstrOnUpdate
	ConstrFulltext
	ConstrComment
)

// LockType is select lock type.
type LockType int

// Select Lock Type.
const (
	SelectLockNone LockType = iota
	SelectLockForUpdate
	SelectLockInShareMode
)

// Table Options.
const (
	TblOptNone = iota
	TblOptEngine
	TblOptCharset
	TblOptCollate
	TblOptAutoIncrement
	TblOptComment
	TblOptAvgRowLength
	TblOptCheckSum
	TblOptCompression
	TblOptConnection
	TblOptPassword
	TblOptKeyBlockSize
	TblOptMaxRows
	TblOptMinRows
	// Following table options are just listed here,
	// we may support them one by one later.
	TblOptDataDirectory
	TblOptDelayKeyWrite
	TblOptIndexDirectory
	TblOptInsertMethod
	TblOptPackKeys
	TblOptRowFormat
	TblOptStatsAutoRecalc
	TblOptStatsPersistent
	TblOptStatsSamplePages
	TblOptTableSpace
	TblOptUnion
)

// TableOpt is used for parsing table option from SQL.
type TableOpt struct {
	Tp        int
	StrValue  string
	UintValue uint64
}

// TableOption is the collection of table options.
// TODO: rename TableOpt or TableOption.
type TableOption struct {
	Engine        string
	Charset       string
	Collate       string
	AutoIncrement uint64 // TODO: apply this value to autoid.Allocator.
}

// String implements fmt.Stringer interface.
func (o *TableOption) String() string {
	strs := []string{}
	if o.Engine != "" {
		x := fmt.Sprintf("ENGINE=%s", o.Engine)
		strs = append(strs, x)
	}
	if o.Charset != "" {
		x := fmt.Sprintf("CHARSET=%s", o.Charset)
		strs = append(strs, x)
	}
	if o.Collate != "" {
		x := fmt.Sprintf("COLLATE=%s", o.Collate)
		strs = append(strs, x)
	}

	return strings.Join(strs, " ")
}

// TableConstraint is constraint for table definition.
type TableConstraint struct {
	Tp         int
	ConstrName string

	// Used for PRIMARY KEY, UNIQUE, ......
	Keys []*IndexColName

	// Used for foreign key.
	Refer *ReferenceDef
}

// Clone clones a new TableConstraint from old TableConstraint.
func (tc *TableConstraint) Clone() *TableConstraint {
	keys := make([]*IndexColName, 0, len(tc.Keys))
	for _, k := range tc.Keys {
		keys = append(keys, k)
	}
	ntc := &TableConstraint{
		Tp:         tc.Tp,
		ConstrName: tc.ConstrName,
		Keys:       keys,
	}
	if tc.Refer != nil {
		ntc.Refer = tc.Refer.Clone()
	}
	return ntc
}

// String implements fmt.Stringer interface.
func (tc *TableConstraint) String() string {
	tokens := []string{}
	if tc.Tp == ConstrPrimaryKey {
		tokens = append(tokens, "PRIMARY KEY")
	} else {
		if tc.Tp == ConstrKey {
			tokens = append(tokens, "KEY")
		} else if tc.Tp == ConstrIndex {
			tokens = append(tokens, "INDEX")
		} else if tc.Tp == ConstrUniq {
			tokens = append(tokens, "UNIQUE")
		} else if tc.Tp == ConstrUniqKey {
			tokens = append(tokens, "UNIQUE KEY")
		} else if tc.Tp == ConstrUniqIndex {
			tokens = append(tokens, "UNIQUE INDEX")
		} else if tc.Tp == ConstrForeignKey {
			tokens = append(tokens, "FOREIGN KEY")
		}
		tokens = append(tokens, tc.ConstrName)
	}
	keysStr := make([]string, 0, len(tc.Keys))
	for _, v := range tc.Keys {
		keysStr = append(keysStr, v.String())
	}
	tokens = append(tokens, fmt.Sprintf("(%s)", strings.Join(keysStr, ", ")))
	if tc.Refer != nil {
		tokens = append(tokens, tc.Refer.String())
	}
	return strings.Join(tokens, " ")
}

// AuthOption is used for parsing create use statement.
type AuthOption struct {
	// AuthString/HashString can be empty, so we need to decide which one to use.
	ByAuthString bool
	AuthString   string
	HashString   string
	// TODO: support auth_plugin
}

// UserSpecification is used for parsing create use statement.
type UserSpecification struct {
	User    string
	AuthOpt *AuthOption
}
<commit_msg>coldef: remove unsupported table options<commit_after>// Copyright 2015 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package coldef

import (
	"fmt"
	"strings"

	"github.com/pingcap/tidb/expression"
)

// FloatOpt is used for parsing floating-point type option from SQL.
// TODO: add reference doc.
type FloatOpt struct {
	Flen    int
	Decimal int
}

// CharsetOpt is used for parsing charset option from SQL.
type CharsetOpt struct {
	Chs string
	Col string
}

// String implements fmt.Stringer interface.
func (o *CharsetOpt) String() string {
	var ss []string
	if o.Chs != "" {
		ss = append(ss, "CHARACTER SET = "+o.Chs)
	}
	if o.Col != "" {
		ss = append(ss, "COLLATE = "+o.Col)
	}
	return strings.Join(ss, " ")
}

// ConstraintOpt is used for parsing column constraint info from SQL.
type ConstraintOpt struct {
	Tp     int
	Bvalue bool
	Evalue expression.Expression
}

// String implements fmt.Stringer interface.
func (c *ConstraintOpt) String() string {
	switch c.Tp {
	case ConstrNotNull:
		return "NOT NULL"
	case ConstrNull:
		return "NULL"
	case ConstrAutoIncrement:
		return "AUTO_INCREMENT"
	case ConstrPrimaryKey:
		return "PRIMARY KEY"
	case ConstrUniq:
		return "UNIQUE"
	case ConstrUniqKey:
		return "UNIQUE KEY"
	case ConstrDefaultValue:
		return "DEFAULT " + c.Evalue.String()
	case ConstrOnUpdate:
		return "ON UPDATE " + c.Evalue.String()
	default:
		return ""
	}
}

// DB Options.
const (
	DBOptNone = iota
	DBOptCharset
	DBOptCollate
)

// DatabaseOpt is used for parsing database option from SQL.
type DatabaseOpt struct {
	Tp    int
	Value string
}

// Constraints.
const (
	ConstrNoConstr = iota
	ConstrPrimaryKey
	ConstrForeignKey
	ConstrNotNull
	ConstrAutoIncrement
	ConstrDefaultValue
	ConstrUniq
	ConstrIndex
	ConstrUniqIndex
	ConstrKey
	ConstrUniqKey
	ConstrNull
	ConstrOnUpdate
	ConstrFulltext
	ConstrComment
)

// LockType is select lock type.
type LockType int

// Select Lock Type.
const (
	SelectLockNone LockType = iota
	SelectLockForUpdate
	SelectLockInShareMode
)

// Table Options.
const (
	TblOptNone = iota
	TblOptEngine
	TblOptCharset
	TblOptCollate
	TblOptAutoIncrement
	TblOptComment
	TblOptAvgRowLength
	TblOptCheckSum
	TblOptCompression
	TblOptConnection
	TblOptPassword
	TblOptKeyBlockSize
	TblOptMaxRows
	TblOptMinRows
)

// TableOpt is used for parsing table option from SQL.
type TableOpt struct {
	Tp        int
	StrValue  string
	UintValue uint64
}

// TableOption is the collection of table options.
// TODO: rename TableOpt or TableOption.
type TableOption struct {
	Engine        string
	Charset       string
	Collate       string
	AutoIncrement uint64 // TODO: apply this value to autoid.Allocator.
}

// String implements fmt.Stringer interface.
func (o *TableOption) String() string {
	strs := []string{}
	if o.Engine != "" {
		x := fmt.Sprintf("ENGINE=%s", o.Engine)
		strs = append(strs, x)
	}
	if o.Charset != "" {
		x := fmt.Sprintf("CHARSET=%s", o.Charset)
		strs = append(strs, x)
	}
	if o.Collate != "" {
		x := fmt.Sprintf("COLLATE=%s", o.Collate)
		strs = append(strs, x)
	}

	return strings.Join(strs, " ")
}

// TableConstraint is constraint for table definition.
type TableConstraint struct {
	Tp         int
	ConstrName string

	// Used for PRIMARY KEY, UNIQUE, ......
	Keys []*IndexColName

	// Used for foreign key.
	Refer *ReferenceDef
}

// Clone clones a new TableConstraint from old TableConstraint.
func (tc *TableConstraint) Clone() *TableConstraint {
	keys := make([]*IndexColName, 0, len(tc.Keys))
	for _, k := range tc.Keys {
		keys = append(keys, k)
	}
	ntc := &TableConstraint{
		Tp:         tc.Tp,
		ConstrName: tc.ConstrName,
		Keys:       keys,
	}
	if tc.Refer != nil {
		ntc.Refer = tc.Refer.Clone()
	}
	return ntc
}

// String implements fmt.Stringer interface.
func (tc *TableConstraint) String() string {
	tokens := []string{}
	if tc.Tp == ConstrPrimaryKey {
		tokens = append(tokens, "PRIMARY KEY")
	} else {
		if tc.Tp == ConstrKey {
			tokens = append(tokens, "KEY")
		} else if tc.Tp == ConstrIndex {
			tokens = append(tokens, "INDEX")
		} else if tc.Tp == ConstrUniq {
			tokens = append(tokens, "UNIQUE")
		} else if tc.Tp == ConstrUniqKey {
			tokens = append(tokens, "UNIQUE KEY")
		} else if tc.Tp == ConstrUniqIndex {
			tokens = append(tokens, "UNIQUE INDEX")
		} else if tc.Tp == ConstrForeignKey {
			tokens = append(tokens, "FOREIGN KEY")
		}
		tokens = append(tokens, tc.ConstrName)
	}
	keysStr := make([]string, 0, len(tc.Keys))
	for _, v := range tc.Keys {
		keysStr = append(keysStr, v.String())
	}
	tokens = append(tokens, fmt.Sprintf("(%s)", strings.Join(keysStr, ", ")))
	if tc.Refer != nil {
		tokens = append(tokens, tc.Refer.String())
	}
	return strings.Join(tokens, " ")
}

// AuthOption is used for parsing create use statement.
type AuthOption struct {
	// AuthString/HashString can be empty, so we need to decide which one to use.
	ByAuthString bool
	AuthString   string
	HashString   string
	// TODO: support auth_plugin
}

// UserSpecification is used for parsing create use statement.
type UserSpecification struct {
	User    string
	AuthOpt *AuthOption
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sts"
	"os/user"
	"path/filepath"
	"time"
)

type CachingSessionTokenProvider struct {
	CredentialsCacherProvider
	Profile   string
	Duration  time.Duration
	MfaSerial string
}

func (p *CachingSessionTokenProvider) CacheFile() string {
	cacheDir = filepath.Dir(defaults.SharedCredentialsFilename())
	return filepath.Join(cacheDir, fmt.Sprintf(".aws_session_token_%s", p.Profile))
}

// Satisfies credentials.Provider
func (p *CachingSessionTokenProvider) Retrieve() (credentials.Value, error) {
	p.CredentialsCacherProvider.CacheFilename = p.CacheFile()
	creds, _ := p.CredentialsCacherProvider.Retrieve() // TODO let errors fall through?

	if p.IsExpired() {
		dur_secs := int64(p.Duration.Seconds())
		input := sts.GetSessionTokenInput{DurationSeconds: &dur_secs}

		if len(p.MfaSerial) > 0 {
			// Prompt for MFA code
			var mfa_code string
			fmt.Print("Enter MFA Code: ")
			fmt.Scanln(&mfa_code)

			input.SerialNumber = &p.MfaSerial
			input.TokenCode = &mfa_code
		}

		sess := session.Must(session.NewSessionWithOptions(
			session.Options{
				SharedConfigState: session.SharedConfigEnable,
				Profile:           p.Profile,
			}))

		s := sts.New(sess)
		res, err := s.GetSessionToken(&input)
		if err != nil {
			return credentials.Value{}, err
		}

		c := CacheableCredentials{
			AccessKeyId:     *res.Credentials.AccessKeyId,
			SecretAccessKey: *res.Credentials.SecretAccessKey,
			SessionToken:    *res.Credentials.SessionToken,
			Expiration:      (*res.Credentials.Expiration).Unix(),
		}
		p.CredentialsCacherProvider.Store(&c)
		creds, _ = p.CredentialsCacherProvider.Retrieve()
	}

	return creds, nil
}

// Satisfies credentials.Provider
func (p *CachingSessionTokenProvider) IsExpired() bool {
	expired := true
	expired = p.CredentialsCacherProvider.IsExpired()

	return expired
}

func (p *CachingSessionTokenProvider) AssumeRole(profile_cfg *AWSProfile) (*sts.Credentials, error) {
	username := "__"
	user, err := user.Current()
	if err == nil {
		username = user.Username
	}

	sesName := aws.String(fmt.Sprintf("AWS-RUNAS-%s-%d", username, time.Now().Unix()))
	input := sts.AssumeRoleInput{
		DurationSeconds: aws.Int64(int64(3600)),
		RoleArn:         aws.String(profile_cfg.RoleArn),
		RoleSessionName: sesName,
	}

	creds, err := p.Retrieve()
	if err != nil {
		return nil, err
	}

	sesOpts := session.Options{
		Profile:           profile_cfg.SourceProfile,
		SharedConfigState: session.SharedConfigEnable,
		Config:            aws.Config{Credentials: credentials.NewStaticCredentialsFromCreds(creds)},
	}
	s := session.Must(session.NewSessionWithOptions(sesOpts))
	sts := sts.New(s)
	res, err := sts.AssumeRole(&input)
	if err != nil {
		return nil, err
	}

	return res.Credentials, nil
}
<commit_msg>update CachingSessionTokenProvider.AssumeRole() to return a credentials.Value for consistency<commit_after>package main

import (
	"fmt"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sts"
	"os/user"
	"path/filepath"
	"time"
)

type CachingSessionTokenProvider struct {
	CredentialsCacherProvider
	Profile   string
	Duration  time.Duration
	MfaSerial string
}

func (p *CachingSessionTokenProvider) CacheFile() string {
	cacheDir = filepath.Dir(defaults.SharedCredentialsFilename())
	return filepath.Join(cacheDir, fmt.Sprintf(".aws_session_token_%s", p.Profile))
}

// Satisfies credentials.Provider
func (p *CachingSessionTokenProvider) Retrieve() (credentials.Value, error) {
	p.CredentialsCacherProvider.CacheFilename = p.CacheFile()
	creds, _ := p.CredentialsCacherProvider.Retrieve() // TODO let errors fall through?

	if p.IsExpired() {
		dur_secs := int64(p.Duration.Seconds())
		input := sts.GetSessionTokenInput{DurationSeconds: &dur_secs}

		if len(p.MfaSerial) > 0 {
			// Prompt for MFA code
			var mfa_code string
			fmt.Print("Enter MFA Code: ")
			fmt.Scanln(&mfa_code)

			input.SerialNumber = &p.MfaSerial
			input.TokenCode = &mfa_code
		}

		sess := session.Must(session.NewSessionWithOptions(
			session.Options{
				SharedConfigState: session.SharedConfigEnable,
				Profile:           p.Profile,
			}))

		s := sts.New(sess)
		res, err := s.GetSessionToken(&input)
		if err != nil {
			return credentials.Value{}, err
		}

		c := CacheableCredentials{
			AccessKeyId:     *res.Credentials.AccessKeyId,
			SecretAccessKey: *res.Credentials.SecretAccessKey,
			SessionToken:    *res.Credentials.SessionToken,
			Expiration:      (*res.Credentials.Expiration).Unix(),
		}
		p.CredentialsCacherProvider.Store(&c)
		creds, _ = p.CredentialsCacherProvider.Retrieve()
	}

	return creds, nil
}

// Satisfies credentials.Provider
func (p *CachingSessionTokenProvider) IsExpired() bool {
	expired := true
	expired = p.CredentialsCacherProvider.IsExpired()

	return expired
}

func (p *CachingSessionTokenProvider) AssumeRole(profile_cfg *AWSProfile) (credentials.Value, error) {
	username := "__"
	user, err := user.Current()
	if err == nil {
		username = user.Username
	}

	sesName := aws.String(fmt.Sprintf("AWS-RUNAS-%s-%d", username, time.Now().Unix()))
	input := sts.AssumeRoleInput{
		DurationSeconds: aws.Int64(int64(3600)),
		RoleArn:         aws.String(profile_cfg.RoleArn),
		RoleSessionName: sesName,
	}

	creds, err := p.Retrieve()
	if err != nil {
		return credentials.Value{}, err
	}

	sesOpts := session.Options{
		Profile:           profile_cfg.SourceProfile,
		SharedConfigState: session.SharedConfigEnable,
		Config:            aws.Config{Credentials: credentials.NewStaticCredentialsFromCreds(creds)},
	}
	s := session.Must(session.NewSessionWithOptions(sesOpts))
	sts := sts.New(s)
	res, err := sts.AssumeRole(&input)
	if err != nil {
		return credentials.Value{}, err
	}

	c := res.Credentials
	v := credentials.Value{
		AccessKeyID: *c.AccessKeyId,
		SecretAccessKey: *c.SecretAccessKey,
		SessionToken: *c.SessionToken,
		ProviderName: "CachingSessionTokenProvider",
	}
	return v, nil
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "os"
  "os/exec"
  "strings"
  "path/filepath"
  "crypto/sha1"
  "encoding/json"
  "io/ioutil"
  "syscall"
)

type Result struct {
  // Dreck! Die Felder muessen mit Grossbuchstaben anfangen
  // da sie sonst der feine Herr Golang nicht exportiert
  Output string `json:"output"`
  ExitCode int `json:"exitcode"`
  Serial int `json:"serial"`
}

func match() {
}

func loadResult(resultFile string) Result {
  var result Result;
  raw, err := ioutil.ReadFile(resultFile)
  if err != nil {
    result = Result{"", 0, 0}
  } else {
    json.Unmarshal(raw, &result)
  }
  return result
}

func saveResult(resultFile string, result Result) {
  json_result, err := json.Marshal(result)
  if err != nil {
    fmt.Println("json error:", err)
  }
  err = ioutil.WriteFile(resultFile, json_result, 0644)
  if err != nil {
    fmt.Printf("could not write resultFile %s\n", err)
  }
}

func initResultFile(args string) string {
  var resultDir string;
  sha1_hash := fmt.Sprintf("%x", sha1.Sum([]byte(args)))
  if (os.Getenv("OMD_ROOT") != "") {
    resultDir = filepath.Join(os.Getenv("OMD_ROOT"),
        "var", "tmp", "check_stable");

  } else {
    resultDir = filepath.Join("/", "var", "tmp", "check_stable");
  }
  os.MkdirAll(resultDir, 0755)
  return filepath.Join(resultDir, sha1_hash)
}

func main() {
  args := os.Args
  cmd := args[1]
  params := args[2:len(args)]
  exitCode := 0

  resultFile := initResultFile(strings.Join(args, ""))
  plugin := exec.Command(cmd, params...)

  pluginOutput, err := plugin.CombinedOutput()
  if err != nil {
    if exitError, ok := err.(*exec.ExitError); ok {
      exitCode = exitError.Sys().(syscall.WaitStatus).ExitStatus()
    }
  } else {
    exitCode = plugin.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
  }

  var errors = []string{
      "Return code of 127 is out of bounds - plugin may be missing",
      "Return code of 254 is out of bounds",
      "Return code of 255 is out of bounds",
      "Service Check Timed Out",
      "could not start controlmaster",
      "Could not open pipe: /usr/bin/ssh",
  }
  var error_found = false
  for i:= 0; i < len(errors); i++ {
    if strings.Index(string(pluginOutput), errors[i]) != -1 {
      error_found = true
      break
    }
  }

  if error_found {
    // plugin ended with one of these high-load side effects
    lastResult := loadResult(resultFile)
    if lastResult.Serial > 1 {
      // the error did not go away, time to alert
      fmt.Printf("%s\n", pluginOutput)
      os.Exit(exitCode)
    } else {
      // output a fake result and increment the counter
      saveResult(resultFile, Result{ lastResult.Output, lastResult.ExitCode, lastResult.Serial + 1 })
      fmt.Printf("(stabilized #%d) %s\n", lastResult.Serial, lastResult.Output)
      os.Exit(lastResult.ExitCode)
    }
  } else {
    // save the output, plugin had no problems
    saveResult(resultFile, Result{ string(pluginOutput), exitCode, 0 })
    // exit with the original plugin result
    fmt.Printf("%s\n", pluginOutput)
    os.Exit(exitCode)
  }
}

<commit_msg>add usage:<commit_after>package main

import (
  "fmt"
  "os"
  "os/exec"
  "strings"
  "path/filepath"
  "crypto/sha1"
  "encoding/json"
  "io/ioutil"
  "syscall"
)

type Result struct {
  // Dreck! Die Felder muessen mit Grossbuchstaben anfangen
  // da sie sonst der feine Herr Golang nicht exportiert
  Output string `json:"output"`
  ExitCode int `json:"exitcode"`
  Serial int `json:"serial"`
}

func match() {
}

func loadResult(resultFile string) Result {
  var result Result;
  raw, err := ioutil.ReadFile(resultFile)
  if err != nil {
    result = Result{"", 0, 0}
  } else {
    json.Unmarshal(raw, &result)
  }
  return result
}

func saveResult(resultFile string, result Result) {
  json_result, err := json.Marshal(result)
  if err != nil {
    fmt.Println("json error:", err)
  }
  err = ioutil.WriteFile(resultFile, json_result, 0644)
  if err != nil {
    fmt.Printf("could not write resultFile %s\n", err)
  }
}

func initResultFile(args string) string {
  var resultDir string;
  sha1_hash := fmt.Sprintf("%x", sha1.Sum([]byte(args)))
  if (os.Getenv("OMD_ROOT") != "") {
    resultDir = filepath.Join(os.Getenv("OMD_ROOT"),
        "var", "tmp", "check_stable");

  } else {
    resultDir = filepath.Join("/", "var", "tmp", "check_stable");
  }
  os.MkdirAll(resultDir, 0755)
  return filepath.Join(resultDir, sha1_hash)
}

func main() {
  var params []string
  args := os.Args
  if len(args) == 1 {
    fmt.Printf("usage: check_stable <command>\n")
    os.Exit(3)
  } else if len(args) >= 3 {
    params = args[2:len(args)]
  }
  cmd := args[1]
  exitCode := 0

  resultFile := initResultFile(strings.Join(args, ""))
  plugin := exec.Command(cmd, params...)

  pluginOutput, err := plugin.CombinedOutput()
  if err != nil {
    if exitError, ok := err.(*exec.ExitError); ok {
      exitCode = exitError.Sys().(syscall.WaitStatus).ExitStatus()
    }
  } else {
    exitCode = plugin.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
  }

  var errors = []string{
      "Return code of 127 is out of bounds - plugin may be missing",
      "Return code of 254 is out of bounds",
      "Return code of 255 is out of bounds",
      "Service Check Timed Out",
      "could not start controlmaster",
      "Could not open pipe: /usr/bin/ssh",
  }
  var error_found = false
  for i:= 0; i < len(errors); i++ {
    if strings.Index(string(pluginOutput), errors[i]) != -1 {
      error_found = true
      break
    }
  }

  if error_found {
    // plugin ended with one of these high-load side effects
    lastResult := loadResult(resultFile)
    if lastResult.Serial > 1 {
      // the error did not go away, time to alert
      fmt.Printf("%s\n", pluginOutput)
      os.Exit(exitCode)
    } else {
      // output a fake result and increment the counter
      saveResult(resultFile, Result{ lastResult.Output, lastResult.ExitCode, lastResult.Serial + 1 })
      fmt.Printf("(stabilized #%d) %s\n", lastResult.Serial, lastResult.Output)
      os.Exit(lastResult.ExitCode)
    }
  } else {
    // save the output, plugin had no problems
    saveResult(resultFile, Result{ string(pluginOutput), exitCode, 0 })
    // exit with the original plugin result
    fmt.Printf("%s\n", pluginOutput)
    os.Exit(exitCode)
  }
}

<|endoftext|>


<commit_before>package configure

import (
	"flag"
	"fmt"
	"os"
)

var (
	flags       = flag.NewFlagSet("configure command", flag.ExitOnError)
	commandName = "configure"

	aws    bool
	hosted bool
	docker bool
)

func Command(args []string) {
	parseFlags(args)
	awsIsDefault()
	onlyOnePlatformTypeSpecified()
	fmt.Printf("Flags: aws=%v, hosted=%v, docker=%v\n", aws, hosted, docker)
}

func awsIsDefault() {
	if platformType() != "" {
		return
	}

	aws = true
}

func platformFlagToInt(flag bool) int {
	if !flag {
		return 0
	}
	return 1
}

func onlyOnePlatformTypeSpecified() {
	if platformsSpecified() == 1 {
		return
	}

	fmt.Fprintf(
		os.Stderr,
		"Only one platform should be specified. Got: %d\n\n",
		platformsSpecified(),
	)

	flags.Usage()
}

func platformsSpecified() int {
	return 0 +
		platformFlagToInt(aws) +
		platformFlagToInt(hosted) +
		platformFlagToInt(docker)
}

func platformType() string {
	if aws {
		return "aws"
	}

	if hosted {
		return "hosted"
	}

	if docker {
		return "docker"
	}

	return ""
}

func parseFlags(args []string) {
	flags.BoolVar(&aws, "aws", false, "Configure nanoservice CLI tool for AWS [default] Not implemented yet.")
	flags.BoolVar(&hosted, "hosted", false, "Configure nanoservice CLI tool for hosted setup. Not implemented yet.")
	flags.BoolVar(&docker, "docker", false, "Configure nanoservice CLI tool for local docker setup.")

	flags.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s %s:\n", os.Args[0], commandName)
		flags.PrintDefaults()
	}

	flags.Parse(args)
}
<commit_msg>[closes nanoservice/roadmap#1] [configure] Make --aws and --hosted unsupported<commit_after>package configure

import (
	"flag"
	"fmt"
	"os"
)

var (
	flags       = flag.NewFlagSet("configure command", flag.ExitOnError)
	commandName = "configure"

	aws    bool
	hosted bool
	docker bool
)

func Command(args []string) {
	parseFlags(args)

	awsIsDefault()

	onlyOnePlatformTypeSpecified()

	unsupported("aws", aws)
	unsupported("hosted", hosted)

	fmt.Printf("Flags: aws=%v, hosted=%v, docker=%v\n", aws, hosted, docker)
}

func unsupported(name string, enabled bool) {
	if !enabled {
		return
	}

	fmt.Printf("--%s is unsupported yet\n", name)
	os.Exit(1)
}

func awsIsDefault() {
	if platformType() != "" {
		return
	}

	aws = true
}

func platformFlagToInt(flag bool) int {
	if !flag {
		return 0
	}
	return 1
}

func onlyOnePlatformTypeSpecified() {
	if platformsSpecified() == 1 {
		return
	}

	fmt.Fprintf(
		os.Stderr,
		"Only one platform should be specified. Got: %d\n\n",
		platformsSpecified(),
	)

	flags.Usage()
}

func platformsSpecified() int {
	return 0 +
		platformFlagToInt(aws) +
		platformFlagToInt(hosted) +
		platformFlagToInt(docker)
}

func platformType() string {
	if aws {
		return "aws"
	}

	if hosted {
		return "hosted"
	}

	if docker {
		return "docker"
	}

	return ""
}

func parseFlags(args []string) {
	flags.BoolVar(&aws, "aws", false, "Configure nanoservice CLI tool for AWS [default] Not implemented yet.")
	flags.BoolVar(&hosted, "hosted", false, "Configure nanoservice CLI tool for hosted setup. Not implemented yet.")
	flags.BoolVar(&docker, "docker", false, "Configure nanoservice CLI tool for local docker setup.")

	flags.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage of %s %s:\n", os.Args[0], commandName)
		flags.PrintDefaults()
		os.Exit(1)
	}

	flags.Parse(args)
}
<|endoftext|>