<commit_before>package main

import (
	"errors"
	"io/ioutil"
	"os"

	"gopkg.in/yaml.v2"

	httpfrontend "github.com/chihaya/chihaya/frontend/http"
	udpfrontend "github.com/chihaya/chihaya/frontend/udp"
	"github.com/chihaya/chihaya/middleware"
	"github.com/chihaya/chihaya/middleware/clientapproval"
	"github.com/chihaya/chihaya/middleware/jwt"
	"github.com/chihaya/chihaya/storage/memory"
)

type hookConfig struct {
	Name   string      `yaml:"name"`
	Config interface{} `yaml:"config"`
}

// ConfigFile represents a namespaced YAML configation file.
type ConfigFile struct {
	MainConfigBlock struct {
		middleware.Config
		PrometheusAddr string              `yaml:"prometheus_addr"`
		HTTPConfig     httpfrontend.Config `yaml:"http"`
		UDPConfig      udpfrontend.Config  `yaml:"udp"`
		Storage        memory.Config       `yaml:"storage"`
		PreHooks       []hookConfig        `yaml:"prehooks"`
		PostHooks      []hookConfig        `yaml:"posthooks"`
	} `yaml:"chihaya"`
}

// ParseConfigFile returns a new ConfigFile given the path to a YAML
// configuration file.
//
// It supports relative and absolute paths and environment variables.
func ParseConfigFile(path string) (*ConfigFile, error) {
	if path == "" {
		return nil, errors.New("no config path specified")
	}

	f, err := os.Open(os.ExpandEnv(path))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	contents, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	var cfgFile ConfigFile
	err = yaml.Unmarshal(contents, &cfgFile)
	if err != nil {
		return nil, err
	}

	return &cfgFile, nil
}

// CreateHooks creates instances of Hooks for all of the PreHooks and PostHooks
// configured in a ConfigFile.
func (cfg ConfigFile) CreateHooks() (preHooks, postHooks []middleware.Hook, err error) {
	for _, hookCfg := range cfg.MainConfigBlock.PreHooks {
		cfgBytes, err := yaml.Marshal(hookCfg.Config)
		if err != nil {
			panic("failed to remarshal valid YAML")
		}

		switch hookCfg.Name {
		case "jwt":
			var jwtCfg jwt.Config
			err := yaml.Unmarshal(cfgBytes, &jwtCfg)
			if err != nil {
				return nil, nil, errors.New("invalid JWT middleware config: " + err.Error())
			}
			hook, err := jwt.NewHook(jwtCfg)
			if err != nil {
				return nil, nil, errors.New("invalid JWT middleware config: " + err.Error())
			}
			preHooks = append(preHooks, hook)
		case "client approval":
			var caCfg clientapproval.Config
			err := yaml.Unmarshal(cfgBytes, &caCfg)
			if err != nil {
				return nil, nil, errors.New("invalid client approval middleware config: " + err.Error())
			}
			hook, err := clientapproval.NewHook(caCfg)
			if err != nil {
				return nil, nil, errors.New("invalid client approval middleware config: " + err.Error())
			}
			preHooks = append(preHooks, hook)
		}
	}

	for _, hookCfg := range cfg.MainConfigBlock.PostHooks {
		switch hookCfg.Name {
		}
	}

	return
}
<commit_msg>Fix configure file parse<commit_after>package main

import (
	"errors"
	"io/ioutil"
	"os"

	"gopkg.in/yaml.v2"

	httpfrontend "github.com/chihaya/chihaya/frontend/http"
	udpfrontend "github.com/chihaya/chihaya/frontend/udp"
	"github.com/chihaya/chihaya/middleware"
	"github.com/chihaya/chihaya/middleware/clientapproval"
	"github.com/chihaya/chihaya/middleware/jwt"
	"github.com/chihaya/chihaya/storage/memory"
)

type hookConfig struct {
	Name   string      `yaml:"name"`
	Config interface{} `yaml:"config"`
}

// ConfigFile represents a namespaced YAML configation file.
type ConfigFile struct {
	MainConfigBlock struct {
		middleware.Config `yaml:",inline"`
		PrometheusAddr    string              `yaml:"prometheus_addr"`
		HTTPConfig        httpfrontend.Config `yaml:"http"`
		UDPConfig         udpfrontend.Config  `yaml:"udp"`
		Storage           memory.Config       `yaml:"storage"`
		PreHooks          []hookConfig        `yaml:"prehooks"`
		PostHooks         []hookConfig        `yaml:"posthooks"`
	} `yaml:"chihaya"`
}

// ParseConfigFile returns a new ConfigFile given the path to a YAML
// configuration file.
//
// It supports relative and absolute paths and environment variables.
func ParseConfigFile(path string) (*ConfigFile, error) {
	if path == "" {
		return nil, errors.New("no config path specified")
	}

	f, err := os.Open(os.ExpandEnv(path))
	if err != nil {
		return nil, err
	}
	defer f.Close()

	contents, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}

	var cfgFile ConfigFile
	err = yaml.Unmarshal(contents, &cfgFile)
	if err != nil {
		return nil, err
	}

	return &cfgFile, nil
}

// CreateHooks creates instances of Hooks for all of the PreHooks and PostHooks
// configured in a ConfigFile.
func (cfg ConfigFile) CreateHooks() (preHooks, postHooks []middleware.Hook, err error) {
	for _, hookCfg := range cfg.MainConfigBlock.PreHooks {
		cfgBytes, err := yaml.Marshal(hookCfg.Config)
		if err != nil {
			panic("failed to remarshal valid YAML")
		}

		switch hookCfg.Name {
		case "jwt":
			var jwtCfg jwt.Config
			err := yaml.Unmarshal(cfgBytes, &jwtCfg)
			if err != nil {
				return nil, nil, errors.New("invalid JWT middleware config: " + err.Error())
			}
			hook, err := jwt.NewHook(jwtCfg)
			if err != nil {
				return nil, nil, errors.New("invalid JWT middleware config: " + err.Error())
			}
			preHooks = append(preHooks, hook)
		case "client approval":
			var caCfg clientapproval.Config
			err := yaml.Unmarshal(cfgBytes, &caCfg)
			if err != nil {
				return nil, nil, errors.New("invalid client approval middleware config: " + err.Error())
			}
			hook, err := clientapproval.NewHook(caCfg)
			if err != nil {
				return nil, nil, errors.New("invalid client approval middleware config: " + err.Error())
			}
			preHooks = append(preHooks, hook)
		}
	}

	for _, hookCfg := range cfg.MainConfigBlock.PostHooks {
		switch hookCfg.Name {
		}
	}

	return
}
<|endoftext|>


<commit_before>package termite

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"os"
	"rand"
	"crypto/hmac"
	"sync"
	"io"
)

const challengeLength = 20

func RandomBytes(n int) []byte {
	c := make([]byte, 0)
	for i := 0; i < n; i++ {
		c = append(c, byte(rand.Int31n(256)))
	}
	return c
}

func Authenticate(conn net.Conn, secret []byte) os.Error {
	challenge := RandomBytes(challengeLength)

	_, err := conn.Write(challenge)
	if err != nil {
		return err
	}
	h := hmac.NewSHA1(secret)
	_, err = h.Write(challenge)
	expected := h.Sum()

	remoteChallenge := make([]byte, challengeLength)
	n, err := conn.Read(remoteChallenge)
	if err != nil {
		return err
	}
	remoteChallenge = remoteChallenge[:n]
	remoteHash := hmac.NewSHA1(secret)
	remoteHash.Write(remoteChallenge)
	_, err = conn.Write(remoteHash.Sum())

	response := make([]byte, len(expected))
	n, err = conn.Read(response)
	if err != nil {
		return err
	}
	response = response[:n]

	if bytes.Compare(response, expected) != 0 {
		log.Println("Authentication failure from", conn.RemoteAddr())
		conn.Close()
		return os.NewError("Mismatch in response")
	}

	expectAck := []byte("OK")
	conn.Write(expectAck)

	ack := make([]byte, len(expectAck))
	n, err = conn.Read(ack)
	if err != nil {
		return err
	}

	ack = ack[:n]
	if bytes.Compare(expectAck, ack) != 0 {
		fmt.Println(expectAck, ack)
		return os.NewError("Missing ack reply")
	}

	return nil
}

func SetupServer(port int, secret []byte, output chan net.Conn) {
	addr := fmt.Sprintf(":%d", port)
	// TODO - also listen on localhost.
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal("net.Listen", err)
	}
	log.Println("Listening to", addr)

	for {
		conn, err := listener.Accept()
		if err != nil {
			panic(err)
		}

		err = Authenticate(conn, secret)
		if err != nil {
			log.Println("Authentication error: ", err)
			conn.Close()
			continue
		}
		output <- conn
	}
}

// ids:
//
const (
	RPC_CHANNEL = "rpc....."
	_ID_FMT     = "id%06d"
	HEADER_LEN  = 8
)

func ConnectionId() string {
	id := rand.Intn(1e6)
	return fmt.Sprintf(_ID_FMT, id)
}

type PendingConnection struct {
	Id    string
	Ready sync.Cond
	Conn  net.Conn
}

type PendingConnections struct {
	connectionsMutex sync.Mutex
	connections      map[string]*PendingConnection
}

func NewPendingConnections() *PendingConnections {
	return &PendingConnections{
		connections: make(map[string]*PendingConnection),
	}
}

func (me *PendingConnections) newPendingConnection(id string) *PendingConnection {
	p := &PendingConnection{
		Id: id,
	}
	p.Ready.L = &me.connectionsMutex
	return p
}

func (me *PendingConnections) WaitConnection(id string) net.Conn {
	me.connectionsMutex.Lock()
	defer me.connectionsMutex.Unlock()
	p := me.connections[id]
	if p == nil {
		p = me.newPendingConnection(id)
		me.connections[id] = p
	}

	for p.Conn == nil {
		p.Ready.Wait()
	}

	me.connections[id] = nil
	return p.Conn
}

func (me *PendingConnections) Accept(conn net.Conn) os.Error {
	idBytes := make([]byte, HEADER_LEN)
	n, err := conn.Read(idBytes)
	if n != HEADER_LEN || err != nil {
		return err
	}
	id := string(idBytes)

	me.connectionsMutex.Lock()
	defer me.connectionsMutex.Unlock()
	p := me.connections[id]
	if p == nil {
		p = me.newPendingConnection(id)
		me.connections[id] = p
	}

	p.Conn = conn
	p.Ready.Signal()
	return nil
}

func DialTypedConnection(addr string, id string, secret []byte) (net.Conn, os.Error) {
	if len(id) != HEADER_LEN {
		log.Fatal("id != 8", id, len(id))
	}
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}

	err = Authenticate(conn, secret)
	if err != nil {
		return nil, err
	}
	_, err = io.WriteString(conn, id)
	if err != nil {
		return nil, err
	}
	return conn, nil
}
<commit_msg>Set random seed for connection id generator.<commit_after>package termite

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"os"
	"rand"
	"crypto/hmac"
	"sync"
	"io"
	"time"
)

const challengeLength = 20

func RandomBytes(n int) []byte {
	c := make([]byte, 0)
	for i := 0; i < n; i++ {
		c = append(c, byte(rand.Int31n(256)))
	}
	return c
}

func Authenticate(conn net.Conn, secret []byte) os.Error {
	challenge := RandomBytes(challengeLength)

	_, err := conn.Write(challenge)
	if err != nil {
		return err
	}
	h := hmac.NewSHA1(secret)
	_, err = h.Write(challenge)
	expected := h.Sum()

	remoteChallenge := make([]byte, challengeLength)
	n, err := conn.Read(remoteChallenge)
	if err != nil {
		return err
	}
	remoteChallenge = remoteChallenge[:n]
	remoteHash := hmac.NewSHA1(secret)
	remoteHash.Write(remoteChallenge)
	_, err = conn.Write(remoteHash.Sum())

	response := make([]byte, len(expected))
	n, err = conn.Read(response)
	if err != nil {
		return err
	}
	response = response[:n]

	if bytes.Compare(response, expected) != 0 {
		log.Println("Authentication failure from", conn.RemoteAddr())
		conn.Close()
		return os.NewError("Mismatch in response")
	}

	expectAck := []byte("OK")
	conn.Write(expectAck)

	ack := make([]byte, len(expectAck))
	n, err = conn.Read(ack)
	if err != nil {
		return err
	}

	ack = ack[:n]
	if bytes.Compare(expectAck, ack) != 0 {
		fmt.Println(expectAck, ack)
		return os.NewError("Missing ack reply")
	}

	return nil
}

func SetupServer(port int, secret []byte, output chan net.Conn) {
	addr := fmt.Sprintf(":%d", port)
	// TODO - also listen on localhost.
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		log.Fatal("net.Listen", err)
	}
	log.Println("Listening to", addr)

	for {
		conn, err := listener.Accept()
		if err != nil {
			panic(err)
		}

		err = Authenticate(conn, secret)
		if err != nil {
			log.Println("Authentication error: ", err)
			conn.Close()
			continue
		}
		output <- conn
	}
}

// ids:
//
const (
	RPC_CHANNEL = "rpc....."
	_ID_FMT     = "id%06d"
	HEADER_LEN  = 8
)

func init () {
	rand.Seed(time.Nanoseconds() ^ int64(os.Getpid()))
}

func ConnectionId() string {
	id := rand.Intn(1e6)
	return fmt.Sprintf(_ID_FMT, id)
}

type PendingConnection struct {
	Id    string
	Ready sync.Cond
	Conn  net.Conn
}

type PendingConnections struct {
	connectionsMutex sync.Mutex
	connections      map[string]*PendingConnection
}

func NewPendingConnections() *PendingConnections {
	return &PendingConnections{
		connections: make(map[string]*PendingConnection),
	}
}

func (me *PendingConnections) newPendingConnection(id string) *PendingConnection {
	p := &PendingConnection{
		Id: id,
	}
	p.Ready.L = &me.connectionsMutex
	return p
}

func (me *PendingConnections) WaitConnection(id string) net.Conn {
	me.connectionsMutex.Lock()
	defer me.connectionsMutex.Unlock()
	p := me.connections[id]
	if p == nil {
		p = me.newPendingConnection(id)
		me.connections[id] = p
	}

	for p.Conn == nil {
		p.Ready.Wait()
	}

	me.connections[id] = nil
	return p.Conn
}

func (me *PendingConnections) Accept(conn net.Conn) os.Error {
	idBytes := make([]byte, HEADER_LEN)
	n, err := conn.Read(idBytes)
	if n != HEADER_LEN || err != nil {
		return err
	}
	id := string(idBytes)

	me.connectionsMutex.Lock()
	defer me.connectionsMutex.Unlock()
	p := me.connections[id]
	if p == nil {
		p = me.newPendingConnection(id)
		me.connections[id] = p
	}
	if p.Conn != nil {
		panic("accepted the same connection id twice")
	}
	p.Conn = conn
	p.Ready.Signal()
	return nil
}

func DialTypedConnection(addr string, id string, secret []byte) (net.Conn, os.Error) {
	if len(id) != HEADER_LEN {
		log.Fatal("id != 8", id, len(id))
	}
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}

	err = Authenticate(conn, secret)
	if err != nil {
		return nil, err
	}
	_, err = io.WriteString(conn, id)
	if err != nil {
		return nil, err
	}
	return conn, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package app

import (
	"fmt"
	"os"
	"time"

	"github.com/golang/glog"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes"

	"k8s.io/ingress-gce/pkg/loadbalancers"
	"k8s.io/ingress-gce/pkg/storage"
	"k8s.io/ingress-gce/pkg/utils"
)

const (
	// Key used to persist UIDs to configmaps.
	uidConfigMapName = "ingress-uid"
)

func NewNamer(kubeClient kubernetes.Interface, clusterName string, fwName string) (*utils.Namer, error) {
	name, err := getClusterUID(kubeClient, clusterName)
	if err != nil {
		return nil, err
	}
	fw_name, err := getFirewallName(kubeClient, fwName, name)
	if err != nil {
		return nil, err
	}

	namer := utils.NewNamer(name, fw_name)
	uidVault := storage.NewConfigMapVault(kubeClient, metav1.NamespaceSystem, uidConfigMapName)

	// Start a goroutine to poll the cluster UID config map
	// We don't watch because we know exactly which configmap we want and this
	// controller already watches 5 other resources, so it isn't worth the cost
	// of another connection and complexity.
	go wait.Forever(func() {
		for _, key := range [...]string{storage.UidDataKey, storage.ProviderDataKey} {
			val, found, err := uidVault.Get(key)
			if err != nil {
				glog.Errorf("Can't read uidConfigMap %v", uidConfigMapName)
			} else if !found {
				errmsg := fmt.Sprintf("Can't read %v from uidConfigMap %v", key, uidConfigMapName)
				if key == storage.UidDataKey {
					glog.Errorf(errmsg)
				} else {
					glog.V(4).Infof(errmsg)
				}
			} else {

				switch key {
				case storage.UidDataKey:
					if uid := namer.UID(); uid != val {
						glog.Infof("Cluster uid changed from %v -> %v", uid, val)
						namer.SetUID(val)
					}
				case storage.ProviderDataKey:
					if fw_name := namer.Firewall(); fw_name != val {
						glog.Infof("Cluster firewall name changed from %v -> %v", fw_name, val)
						namer.SetFirewall(val)
					}
				}
			}
		}
	}, 5*time.Second)
	return namer, nil
}

// useDefaultOrLookupVault returns either a 'default_name' or if unset, obtains a name from a ConfigMap.
// The returned value follows this priority:
// If the provided 'default_name' is not empty, that name is used.
//       This is effectively a client override via a command line flag.
// else, check cfgVault with 'cm_key' as a key and if found, use the associated value
// else, return an empty 'name' and pass along an error iff the configmap lookup is erroneous.
func useDefaultOrLookupVault(cfgVault *storage.ConfigMapVault, cm_key, default_name string) (string, error) {
	if default_name != "" {
		glog.Infof("Using user provided %v %v", cm_key, default_name)
		// Don't save the uid in the vault, so users can rollback through
		// setting the accompany flag to ""
		return default_name, nil
	}
	val, found, err := cfgVault.Get(cm_key)
	if err != nil {
		// This can fail because of:
		// 1. No such config map - found=false, err=nil
		// 2. No such key in config map - found=false, err=nil
		// 3. Apiserver flake - found=false, err!=nil
		// It is not safe to proceed in 3.
		return "", fmt.Errorf("failed to retrieve %v: %v, returning empty name", cm_key, err)
	} else if !found {
		// Not found but safe to proceed.
		return "", nil
	}
	glog.Infof("Using %v = %q saved in ConfigMap", cm_key, val)
	return val, nil
}

// getFirewallName returns the firewall rule name to use for this cluster. For
// backwards compatibility, the firewall name will default to the cluster UID.
// Use getFlagOrLookupVault to obtain a stored or overridden value for the firewall name.
// else, use the cluster UID as a backup (this retains backwards compatibility).
func getFirewallName(kubeClient kubernetes.Interface, name, cluster_uid string) (string, error) {
	cfgVault := storage.NewConfigMapVault(kubeClient, metav1.NamespaceSystem, uidConfigMapName)
	if fw_name, err := useDefaultOrLookupVault(cfgVault, storage.ProviderDataKey, name); err != nil {
		return "", err
	} else if fw_name != "" {
		return fw_name, cfgVault.Put(storage.ProviderDataKey, fw_name)
	} else {
		glog.Infof("Using cluster UID %v as firewall name", cluster_uid)
		return cluster_uid, cfgVault.Put(storage.ProviderDataKey, cluster_uid)
	}
}

// getClusterUID returns the cluster UID. Rules for UID generation:
// If the user specifies a --cluster-uid param it overwrites everything
// else, check UID config map for a previously recorded uid
// else, check if there are any working Ingresses
//	- remember that "" is the cluster uid
// else, allocate a new uid
func getClusterUID(kubeClient kubernetes.Interface, name string) (string, error) {
	cfgVault := storage.NewConfigMapVault(kubeClient, metav1.NamespaceSystem, uidConfigMapName)
	if name, err := useDefaultOrLookupVault(cfgVault, storage.UidDataKey, name); err != nil {
		return "", err
	} else if name != "" {
		return name, nil
	}

	// Check if the cluster has an Ingress with ip
	ings, err := kubeClient.Extensions().Ingresses(metav1.NamespaceAll).List(metav1.ListOptions{
		LabelSelector: labels.Everything().String(),
	})
	if err != nil {
		return "", err
	}
	namer := utils.NewNamer("", "")
	for _, ing := range ings.Items {
		if len(ing.Status.LoadBalancer.Ingress) != 0 {
			c := namer.ParseName(loadbalancers.GCEResourceName(ing.Annotations, "forwarding-rule"))
			if c.ClusterName != "" {
				return c.ClusterName, cfgVault.Put(storage.UidDataKey, c.ClusterName)
			}
			glog.Infof("Found a working Ingress, assuming uid is empty string")
			return "", cfgVault.Put(storage.UidDataKey, "")
		}
	}

	// Allocate new uid
	f, err := os.Open("/dev/urandom")
	if err != nil {
		return "", err
	}
	defer f.Close()
	b := make([]byte, 8)
	if _, err := f.Read(b); err != nil {
		return "", err
	}
	uid := fmt.Sprintf("%x", b)
	return uid, cfgVault.Put(storage.UidDataKey, uid)
}
<commit_msg>Some minor cleanups in namer.go<commit_after>/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package app

import (
	"crypto/rand"
	"fmt"
	"time"

	"github.com/golang/glog"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes"

	"k8s.io/ingress-gce/pkg/loadbalancers"
	"k8s.io/ingress-gce/pkg/storage"
	"k8s.io/ingress-gce/pkg/utils"
)

const (
	// Key used to persist UIDs to configmaps.
	uidConfigMapName = "ingress-uid"
	// uidByteLength is the length in bytes for the random UID.
	uidByteLength = 8
)

// NewNamer returns a new naming policy given the state of the cluster.
func NewNamer(kubeClient kubernetes.Interface, clusterName string, fwName string) (*utils.Namer, error) {
	name, err := getClusterUID(kubeClient, clusterName)
	if err != nil {
		return nil, err
	}
	fw_name, err := getFirewallName(kubeClient, fwName, name)
	if err != nil {
		return nil, err
	}

	namer := utils.NewNamer(name, fw_name)
	uidVault := storage.NewConfigMapVault(kubeClient, metav1.NamespaceSystem, uidConfigMapName)

	// Start a goroutine to poll the cluster UID config map.  We don't
	// watch because we know exactly which configmap we want and this
	// controller already watches 5 other resources, so it isn't worth the
	// cost of another connection and complexity.
	go wait.Forever(func() {
		for _, key := range [...]string{storage.UIDDataKey, storage.ProviderDataKey} {
			val, found, err := uidVault.Get(key)
			if err != nil {
				glog.Errorf("Can't read uidConfigMap %v", uidConfigMapName)
			} else if !found {
				errmsg := fmt.Sprintf("Can't read %v from uidConfigMap %v", key, uidConfigMapName)
				if key == storage.UIDDataKey {
					glog.Errorf(errmsg)
				} else {
					glog.V(4).Infof(errmsg)
				}
			} else {

				switch key {
				case storage.UIDDataKey:
					if uid := namer.UID(); uid != val {
						glog.Infof("Cluster uid changed from %v -> %v", uid, val)
						namer.SetUID(val)
					}
				case storage.ProviderDataKey:
					if fw_name := namer.Firewall(); fw_name != val {
						glog.Infof("Cluster firewall name changed from %v -> %v", fw_name, val)
						namer.SetFirewall(val)
					}
				}
			}
		}
	}, 5*time.Second)
	return namer, nil
}

// useDefaultOrLookupVault returns either a 'defaultName' or if unset, obtains
// a name from a ConfigMap.  The returned value follows this priority:
//
// If the provided 'defaultName' is not empty, that name is used.
//     This is effectively a client override via a command line flag.
// else, check cfgVault with 'configMapKey' as a key and if found, use the associated value
// else, return an empty 'name' and pass along an error iff the configmap lookup is erroneous.
func useDefaultOrLookupVault(cfgVault *storage.ConfigMapVault, configMapKey, defaultName string) (string, error) {
	if defaultName != "" {
		glog.Infof("Using user provided %v %v", configMapKey, defaultName)
		// Don't save the uid in the vault, so users can rollback
		// through setting the accompany flag to ""
		return defaultName, nil
	}
	val, found, err := cfgVault.Get(configMapKey)
	if err != nil {
		// This can fail because of:
		// 1. No such config map - found=false, err=nil
		// 2. No such key in config map - found=false, err=nil
		// 3. Apiserver flake - found=false, err!=nil
		// It is not safe to proceed in 3.
		return "", fmt.Errorf("failed to retrieve %v: %v, returning empty name", configMapKey, err)
	} else if !found {
		// Not found but safe to proceed.
		return "", nil
	}
	glog.Infof("Using %v = %q saved in ConfigMap", configMapKey, val)
	return val, nil
}

// getFirewallName returns the firewall rule name to use for this cluster. For
// backwards compatibility, the firewall name will default to the cluster UID.
// Use getFlagOrLookupVault to obtain a stored or overridden value for the firewall name.
// else, use the cluster UID as a backup (this retains backwards compatibility).
func getFirewallName(kubeClient kubernetes.Interface, name, clusterUID string) (string, error) {
	cfgVault := storage.NewConfigMapVault(kubeClient, metav1.NamespaceSystem, uidConfigMapName)
	if firewallName, err := useDefaultOrLookupVault(cfgVault, storage.ProviderDataKey, name); err != nil {
		return "", err
	} else if firewallName != "" {
		return firewallName, cfgVault.Put(storage.ProviderDataKey, firewallName)
	} else {
		glog.Infof("Using cluster UID %v as firewall name", clusterUID)
		return clusterUID, cfgVault.Put(storage.ProviderDataKey, clusterUID)
	}
}

// getClusterUID returns the cluster UID. Rules for UID generation:
// If the user specifies a --cluster-uid param it overwrites everything
// else, check UID config map for a previously recorded uid
// else, check if there are any working Ingresses
//	- remember that "" is the cluster uid
// else, allocate a new uid
func getClusterUID(kubeClient kubernetes.Interface, name string) (string, error) {
	cfgVault := storage.NewConfigMapVault(kubeClient, metav1.NamespaceSystem, uidConfigMapName)
	if name, err := useDefaultOrLookupVault(cfgVault, storage.UIDDataKey, name); err != nil {
		return "", err
	} else if name != "" {
		return name, nil
	}

	// Check if the cluster has an Ingress with ip
	ings, err := kubeClient.Extensions().Ingresses(metav1.NamespaceAll).List(metav1.ListOptions{
		LabelSelector: labels.Everything().String(),
	})
	if err != nil {
		return "", err
	}
	namer := utils.NewNamer("", "")
	for _, ing := range ings.Items {
		if len(ing.Status.LoadBalancer.Ingress) != 0 {
			c := namer.ParseName(loadbalancers.GCEResourceName(ing.Annotations, "forwarding-rule"))
			if c.ClusterName != "" {
				return c.ClusterName, cfgVault.Put(storage.UIDDataKey, c.ClusterName)
			}
			glog.Infof("Found a working Ingress, assuming uid is empty string")
			return "", cfgVault.Put(storage.UIDDataKey, "")
		}
	}

	uid, err := randomUID()
	if err != nil {
		return "", err
	}
	return uid, cfgVault.Put(storage.UIDDataKey, uid)
}

func randomUID() (string, error) {
	b := make([]byte, uidByteLength)
	if _, err := rand.Read(b); err != nil {
		return "", err
	}
	uid := fmt.Sprintf("%x", b)
	return uid, nil
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/sha256"
	"encoding/binary"
	"encoding/hex"
	"flag"
	"fmt"
	mdbs "github.com/msackman/gomdb/server"
	"goshawkdb.io/common"
	"goshawkdb.io/common/certs"
	goshawk "goshawkdb.io/server"
	"goshawkdb.io/server/configuration"
	"goshawkdb.io/server/db"
	"goshawkdb.io/server/network"
	"goshawkdb.io/server/paxos"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"runtime/trace"
	"sync"
	"syscall"
	"time"
)

func main() {
	log.SetPrefix(common.ProductName + " ")
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
	log.Println(os.Args)

	s, err := newServer()
	goshawk.CheckFatal(err)
	s.start()
}

func newServer() (*server, error) {
	var configFile, dataDir, certFile string
	var port int
	var version, genClusterCert, genClientCert bool

	flag.StringVar(&configFile, "config", "", "`Path` to configuration file")
	flag.StringVar(&dataDir, "dir", "", "`Path` to data directory")
	flag.StringVar(&certFile, "cert", "", "`Path` to cluster certificate and key file")
	flag.IntVar(&port, "port", common.DefaultPort, "Port to listen on")
	flag.BoolVar(&version, "version", false, "Display version and exit")
	flag.BoolVar(&genClusterCert, "gen-cluster-cert", false, "Generate new cluster certificate key pair")
	flag.BoolVar(&genClientCert, "gen-client-cert", false, "Generate client certificate key pair")
	flag.Parse()

	if version {
		log.Printf("%v version %v", common.ProductName, goshawk.ServerVersion)
		os.Exit(0)
	}

	if genClusterCert {
		certificatePrivateKeyPair, err := certs.NewClusterCertificate()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%v%v", certificatePrivateKeyPair.CertificatePEM, certificatePrivateKeyPair.PrivateKeyPEM)
		os.Exit(0)
	}

	if len(certFile) == 0 {
		return nil, fmt.Errorf("No certificate supplied (missing -cert parameter). Use -gen-cluster-cert to create cluster certificate")
	}
	certificate, err := ioutil.ReadFile(certFile)
	if err != nil {
		return nil, err
	}

	if genClientCert {
		certificatePrivateKeyPair, err := certs.NewClientCertificate(certificate)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Printf("%v%v", certificatePrivateKeyPair.CertificatePEM, certificatePrivateKeyPair.PrivateKeyPEM)
		fingerprint := sha256.Sum256(certificatePrivateKeyPair.Certificate)
		log.Printf("Fingerprint: %v\n", hex.EncodeToString(fingerprint[:]))
		os.Exit(0)
	}

	if dataDir == "" {
		dataDir, err = ioutil.TempDir("", common.ProductName+"_Data_")
		if err != nil {
			return nil, err
		}
		log.Printf("No data dir supplied (missing -dir parameter). Using %v for data.\n", dataDir)
	}
	err = os.MkdirAll(dataDir, 0750)
	if err != nil {
		return nil, err
	}

	if configFile != "" {
		_, err := ioutil.ReadFile(configFile)
		if err != nil {
			return nil, err
		}
	}

	if !(0 < port && port < 65536) {
		return nil, fmt.Errorf("Supplied port is illegal (%v). Port must be > 0 and < 65536", port)
	}

	s := &server{
		configFile:  configFile,
		certificate: certificate,
		dataDir:     dataDir,
		port:        uint16(port),
		onShutdown:  []func(){},
	}

	if err = s.ensureRMId(); err != nil {
		return nil, err
	}
	if err = s.ensureBootCount(); err != nil {
		return nil, err
	}

	return s, nil
}

type server struct {
	sync.WaitGroup
	configFile        string
	certificate       []byte
	dataDir           string
	port              uint16
	rmId              common.RMId
	bootCount         uint32
	connectionManager *network.ConnectionManager
	transmogrifier    *network.TopologyTransmogrifier
	profileFile       *os.File
	traceFile         *os.File
	onShutdown        []func()
}

func (s *server) start() {
	os.Stdin.Close()

	procs := runtime.NumCPU()
	if procs < 2 {
		procs = 2
	}
	runtime.GOMAXPROCS(procs)

	nodeCertPrivKeyPair, err := certs.GenerateNodeCertificatePrivateKeyPair(s.certificate)
	s.certificate = nil

	s.maybeShutdown(err)

	disk, err := mdbs.NewMDBServer(s.dataDir, 0, 0600, goshawk.MDBInitialSize, procs/2, time.Millisecond, db.DB)
	s.maybeShutdown(err)
	db := disk.(*db.Databases)
	s.addOnShutdown(db.Shutdown)

	commandLineConfig, err := s.commandLineConfig()
	s.maybeShutdown(err)

	if commandLineConfig == nil {
		commandLineConfig = configuration.BlankTopology("").Configuration
	}

	cm, transmogrifier := network.NewConnectionManager(s.rmId, s.bootCount, procs, db, nodeCertPrivKeyPair, s.port, commandLineConfig)
	s.addOnShutdown(func() { cm.Shutdown(paxos.Sync) })
	s.addOnShutdown(transmogrifier.Shutdown)
	s.connectionManager = cm
	s.transmogrifier = transmogrifier

	s.Add(1)
	go s.signalHandler()

	listener, err := network.NewListener(s.port, cm)
	s.addOnShutdown(listener.Shutdown)
	s.maybeShutdown(err)

	defer s.shutdown(nil)
	s.Wait()
}

func (s *server) addOnShutdown(f func()) {
	if f != nil {
		s.onShutdown = append(s.onShutdown, f)
	}
}

func (s *server) shutdown(err error) {
	for idx := len(s.onShutdown) - 1; idx >= 0; idx-- {
		s.onShutdown[idx]()
	}
	if err == nil {
		log.Println("Shutdown.")
	} else {
		log.Fatal("Shutdown due to fatal error: ", err)
	}
}

func (s *server) maybeShutdown(err error) {
	if err != nil {
		s.shutdown(err)
	}
}

func (s *server) ensureRMId() error {
	path := s.dataDir + "/rmid"
	if b, err := ioutil.ReadFile(path); err == nil {
		s.rmId = common.RMId(binary.BigEndian.Uint32(b))
		return nil

	} else {
		rng := rand.New(rand.NewSource(time.Now().UnixNano()))
		for s.rmId == common.RMIdEmpty {
			s.rmId = common.RMId(rng.Uint32())
		}
		b := make([]byte, 4)
		binary.BigEndian.PutUint32(b, uint32(s.rmId))
		return ioutil.WriteFile(path, b, 0400)
	}
}

func (s *server) ensureBootCount() error {
	path := s.dataDir + "/bootcount"
	if b, err := ioutil.ReadFile(path); err == nil {
		s.bootCount = binary.BigEndian.Uint32(b) + 1
	} else {
		s.bootCount = 1
	}
	b := make([]byte, 4)
	binary.BigEndian.PutUint32(b, s.bootCount)
	return ioutil.WriteFile(path, b, 0600)
}

func (s *server) commandLineConfig() (*configuration.Configuration, error) {
	if s.configFile != "" {
		return configuration.LoadConfigurationFromPath(s.configFile)
	}
	return nil, nil
}

func (s *server) signalShutdown() {
	// this may file if stdout has died
	log.Println("Shutting down.")
	s.Done()
}

func (s *server) signalStatus() {
	sc := goshawk.NewStatusConsumer()
	go sc.Consume(func(str string) {
		log.Printf("System Status for %v\n%v\nStatus End\n", s.rmId, str)
	})
	sc.Emit(fmt.Sprintf("Configuration File: %v", s.configFile))
	sc.Emit(fmt.Sprintf("Data Directory: %v", s.dataDir))
	sc.Emit(fmt.Sprintf("Port: %v", s.port))
	s.connectionManager.Status(sc)
}

func (s *server) signalReloadConfig() {
	if s.configFile == "" {
		log.Println("Attempt to reload config failed as no path to configuration provided on command line.")
		return
	}
	config, err := configuration.LoadConfigurationFromPath(s.configFile)
	if err != nil {
		log.Println("Cannot reload config due to error:", err)
		return
	}
	s.transmogrifier.RequestConfigurationChange(config)
}

func (s *server) signalDumpStacks() {
	size := 16384
	for {
		buf := make([]byte, size)
		if l := runtime.Stack(buf, true); l < size {
			log.Printf("Stacks dump\n%s\nStacks dump end", buf[:l])
			return
		} else {
			size += size
		}
	}
}

func (s *server) signalToggleCpuProfile() {
	if s.profileFile == nil {
		memFile, err := ioutil.TempFile("", common.ProductName+"_Mem_Profile_")
		if goshawk.CheckWarn(err) {
			return
		}
		if goshawk.CheckWarn(pprof.Lookup("heap").WriteTo(memFile, 0)) {
			return
		}
		if !goshawk.CheckWarn(memFile.Close()) {
			log.Println("Memory profile written to", memFile.Name())
		}

		profFile, err := ioutil.TempFile("", common.ProductName+"_CPU_Profile_")
		if goshawk.CheckWarn(err) {
			return
		}
		if goshawk.CheckWarn(pprof.StartCPUProfile(profFile)) {
			return
		}
		s.profileFile = profFile
		log.Println("Profiling started in", profFile.Name())

	} else {
		pprof.StopCPUProfile()
		if !goshawk.CheckWarn(s.profileFile.Close()) {
			log.Println("Profiling stopped in", s.profileFile.Name())
		}
		s.profileFile = nil
	}
}

func (s *server) signalToggleTrace() {
	if s.traceFile == nil {
		traceFile, err := ioutil.TempFile("", common.ProductName+"_Trace_")
		if goshawk.CheckWarn(err) {
			return
		}
		if goshawk.CheckWarn(trace.Start(traceFile)) {
			return
		}
		s.traceFile = traceFile
		log.Println("Tracing started in", traceFile.Name())

	} else {
		trace.Stop()
		if !goshawk.CheckWarn(s.traceFile.Close()) {
			log.Println("Tracing stopped in", s.traceFile.Name())
		}
		s.traceFile = nil
	}
}

func (s *server) signalHandler() {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGTERM, syscall.SIGPIPE, syscall.SIGQUIT, syscall.SIGHUP, syscall.SIGUSR1, syscall.SIGUSR2, os.Interrupt)
	for {
		sig := <-sigs
		switch sig {
		case syscall.SIGPIPE:
			if _, err := os.Stdout.WriteString("Socket has closed\n"); err != nil {
				s.signalShutdown()
				return
			}
		case syscall.SIGTERM, syscall.SIGINT:
			s.signalShutdown()
			return
		case syscall.SIGHUP:
			s.signalReloadConfig()
		case syscall.SIGQUIT:
			s.signalDumpStacks()
		case syscall.SIGUSR1:
			s.signalStatus()
		case syscall.SIGUSR2:
			s.signalToggleCpuProfile()
			//s.signalToggleTrace()
		}
	}
}
<commit_msg>Just tidying some return codes and such. Ref T18.<commit_after>package main

import (
	"crypto/sha256"
	"encoding/binary"
	"encoding/hex"
	"flag"
	"fmt"
	mdbs "github.com/msackman/gomdb/server"
	"goshawkdb.io/common"
	"goshawkdb.io/common/certs"
	goshawk "goshawkdb.io/server"
	"goshawkdb.io/server/configuration"
	"goshawkdb.io/server/db"
	"goshawkdb.io/server/network"
	"goshawkdb.io/server/paxos"
	"io/ioutil"
	"log"
	"math/rand"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"runtime/trace"
	"sync"
	"syscall"
	"time"
)

func main() {
	log.SetPrefix(common.ProductName + " ")
	log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
	log.Printf("Version %s; %v", goshawk.ServerVersion, os.Args)

	s, err := newServer()
	if err != nil {
		log.Fatalf("%v\nSee https://goshawkdb.io/starting.html for the Getting Started guide.", err)
	}
	if s != nil {
		s.start()
	}
}

func newServer() (*server, error) {
	var configFile, dataDir, certFile string
	var port int
	var version, genClusterCert, genClientCert bool

	flag.StringVar(&configFile, "config", "", "`Path` to configuration file.")
	flag.StringVar(&dataDir, "dir", "", "`Path` to data directory.")
	flag.StringVar(&certFile, "cert", "", "`Path` to cluster certificate and key file.")
	flag.IntVar(&port, "port", common.DefaultPort, "Port to listen on.")
	flag.BoolVar(&version, "version", false, "Display version and exit.")
	flag.BoolVar(&genClusterCert, "gen-cluster-cert", false, "Generate new cluster certificate key pair.")
	flag.BoolVar(&genClientCert, "gen-client-cert", false, "Generate client certificate key pair.")
	flag.Parse()

	if version {
		log.Printf("%v version %v", common.ProductName, goshawk.ServerVersion)
		return nil, nil
	}

	if genClusterCert {
		certificatePrivateKeyPair, err := certs.NewClusterCertificate()
		if err != nil {
			return nil, err
		}
		fmt.Printf("%v%v", certificatePrivateKeyPair.CertificatePEM, certificatePrivateKeyPair.PrivateKeyPEM)
		return nil, nil
	}

	if len(certFile) == 0 {
		return nil, fmt.Errorf("No certificate supplied (missing -cert parameter). Use -gen-cluster-cert to create cluster certificate.")
	}
	certificate, err := ioutil.ReadFile(certFile)
	if err != nil {
		return nil, err
	}

	if genClientCert {
		certificatePrivateKeyPair, err := certs.NewClientCertificate(certificate)
		if err != nil {
			return nil, err
		}
		fmt.Printf("%v%v", certificatePrivateKeyPair.CertificatePEM, certificatePrivateKeyPair.PrivateKeyPEM)
		fingerprint := sha256.Sum256(certificatePrivateKeyPair.Certificate)
		log.Printf("Fingerprint: %v\n", hex.EncodeToString(fingerprint[:]))
		return nil, nil
	}

	if dataDir == "" {
		dataDir, err = ioutil.TempDir("", common.ProductName+"_Data_")
		if err != nil {
			return nil, err
		}
		log.Printf("No data dir supplied (missing -dir parameter). Using %v for data.\n", dataDir)
	}
	err = os.MkdirAll(dataDir, 0750)
	if err != nil {
		return nil, err
	}

	if configFile != "" {
		_, err := ioutil.ReadFile(configFile)
		if err != nil {
			return nil, err
		}
	}

	if !(0 < port && port < 65536) {
		return nil, fmt.Errorf("Supplied port is illegal (%v). Port must be > 0 and < 65536", port)
	}

	s := &server{
		configFile:  configFile,
		certificate: certificate,
		dataDir:     dataDir,
		port:        uint16(port),
		onShutdown:  []func(){},
	}

	if err = s.ensureRMId(); err != nil {
		return nil, err
	}
	if err = s.ensureBootCount(); err != nil {
		return nil, err
	}

	return s, nil
}

type server struct {
	sync.WaitGroup
	configFile        string
	certificate       []byte
	dataDir           string
	port              uint16
	rmId              common.RMId
	bootCount         uint32
	connectionManager *network.ConnectionManager
	transmogrifier    *network.TopologyTransmogrifier
	profileFile       *os.File
	traceFile         *os.File
	onShutdown        []func()
}

func (s *server) start() {
	os.Stdin.Close()

	procs := runtime.NumCPU()
	if procs < 2 {
		procs = 2
	}
	runtime.GOMAXPROCS(procs)

	nodeCertPrivKeyPair, err := certs.GenerateNodeCertificatePrivateKeyPair(s.certificate)
	s.certificate = nil

	s.maybeShutdown(err)

	disk, err := mdbs.NewMDBServer(s.dataDir, 0, 0600, goshawk.MDBInitialSize, procs/2, time.Millisecond, db.DB)
	s.maybeShutdown(err)
	db := disk.(*db.Databases)
	s.addOnShutdown(db.Shutdown)

	commandLineConfig, err := s.commandLineConfig()
	s.maybeShutdown(err)

	if commandLineConfig == nil {
		commandLineConfig = configuration.BlankTopology("").Configuration
	}

	cm, transmogrifier := network.NewConnectionManager(s.rmId, s.bootCount, procs, db, nodeCertPrivKeyPair, s.port, commandLineConfig)
	s.addOnShutdown(func() { cm.Shutdown(paxos.Sync) })
	s.addOnShutdown(transmogrifier.Shutdown)
	s.connectionManager = cm
	s.transmogrifier = transmogrifier

	s.Add(1)
	go s.signalHandler()

	listener, err := network.NewListener(s.port, cm)
	s.addOnShutdown(listener.Shutdown)
	s.maybeShutdown(err)

	defer s.shutdown(nil)
	s.Wait()
}

func (s *server) addOnShutdown(f func()) {
	if f != nil {
		s.onShutdown = append(s.onShutdown, f)
	}
}

func (s *server) shutdown(err error) {
	for idx := len(s.onShutdown) - 1; idx >= 0; idx-- {
		s.onShutdown[idx]()
	}
	if err == nil {
		log.Println("Shutdown.")
	} else {
		log.Fatal("Shutdown due to fatal error: ", err)
	}
}

func (s *server) maybeShutdown(err error) {
	if err != nil {
		s.shutdown(err)
	}
}

func (s *server) ensureRMId() error {
	path := s.dataDir + "/rmid"
	if b, err := ioutil.ReadFile(path); err == nil {
		s.rmId = common.RMId(binary.BigEndian.Uint32(b))
		return nil

	} else {
		rng := rand.New(rand.NewSource(time.Now().UnixNano()))
		for s.rmId == common.RMIdEmpty {
			s.rmId = common.RMId(rng.Uint32())
		}
		b := make([]byte, 4)
		binary.BigEndian.PutUint32(b, uint32(s.rmId))
		return ioutil.WriteFile(path, b, 0400)
	}
}

func (s *server) ensureBootCount() error {
	path := s.dataDir + "/bootcount"
	if b, err := ioutil.ReadFile(path); err == nil {
		s.bootCount = binary.BigEndian.Uint32(b) + 1
	} else {
		s.bootCount = 1
	}
	b := make([]byte, 4)
	binary.BigEndian.PutUint32(b, s.bootCount)
	return ioutil.WriteFile(path, b, 0600)
}

func (s *server) commandLineConfig() (*configuration.Configuration, error) {
	if s.configFile != "" {
		return configuration.LoadConfigurationFromPath(s.configFile)
	}
	return nil, nil
}

func (s *server) signalShutdown() {
	// this may file if stdout has died
	log.Println("Shutting down.")
	s.Done()
}

func (s *server) signalStatus() {
	sc := goshawk.NewStatusConsumer()
	go sc.Consume(func(str string) {
		log.Printf("System Status for %v\n%v\nStatus End\n", s.rmId, str)
	})
	sc.Emit(fmt.Sprintf("Configuration File: %v", s.configFile))
	sc.Emit(fmt.Sprintf("Data Directory: %v", s.dataDir))
	sc.Emit(fmt.Sprintf("Port: %v", s.port))
	s.connectionManager.Status(sc)
}

func (s *server) signalReloadConfig() {
	if s.configFile == "" {
		log.Println("Attempt to reload config failed as no path to configuration provided on command line.")
		return
	}
	config, err := configuration.LoadConfigurationFromPath(s.configFile)
	if err != nil {
		log.Println("Cannot reload config due to error:", err)
		return
	}
	s.transmogrifier.RequestConfigurationChange(config)
}

func (s *server) signalDumpStacks() {
	size := 16384
	for {
		buf := make([]byte, size)
		if l := runtime.Stack(buf, true); l < size {
			log.Printf("Stacks dump\n%s\nStacks dump end", buf[:l])
			return
		} else {
			size += size
		}
	}
}

func (s *server) signalToggleCpuProfile() {
	if s.profileFile == nil {
		memFile, err := ioutil.TempFile("", common.ProductName+"_Mem_Profile_")
		if goshawk.CheckWarn(err) {
			return
		}
		if goshawk.CheckWarn(pprof.Lookup("heap").WriteTo(memFile, 0)) {
			return
		}
		if !goshawk.CheckWarn(memFile.Close()) {
			log.Println("Memory profile written to", memFile.Name())
		}

		profFile, err := ioutil.TempFile("", common.ProductName+"_CPU_Profile_")
		if goshawk.CheckWarn(err) {
			return
		}
		if goshawk.CheckWarn(pprof.StartCPUProfile(profFile)) {
			return
		}
		s.profileFile = profFile
		log.Println("Profiling started in", profFile.Name())

	} else {
		pprof.StopCPUProfile()
		if !goshawk.CheckWarn(s.profileFile.Close()) {
			log.Println("Profiling stopped in", s.profileFile.Name())
		}
		s.profileFile = nil
	}
}

func (s *server) signalToggleTrace() {
	if s.traceFile == nil {
		traceFile, err := ioutil.TempFile("", common.ProductName+"_Trace_")
		if goshawk.CheckWarn(err) {
			return
		}
		if goshawk.CheckWarn(trace.Start(traceFile)) {
			return
		}
		s.traceFile = traceFile
		log.Println("Tracing started in", traceFile.Name())

	} else {
		trace.Stop()
		if !goshawk.CheckWarn(s.traceFile.Close()) {
			log.Println("Tracing stopped in", s.traceFile.Name())
		}
		s.traceFile = nil
	}
}

func (s *server) signalHandler() {
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGTERM, syscall.SIGPIPE, syscall.SIGQUIT, syscall.SIGHUP, syscall.SIGUSR1, syscall.SIGUSR2, os.Interrupt)
	for {
		sig := <-sigs
		switch sig {
		case syscall.SIGPIPE:
			if _, err := os.Stdout.WriteString("Socket has closed\n"); err != nil {
				s.signalShutdown()
				return
			}
		case syscall.SIGTERM, syscall.SIGINT:
			s.signalShutdown()
			return
		case syscall.SIGHUP:
			s.signalReloadConfig()
		case syscall.SIGQUIT:
			s.signalDumpStacks()
		case syscall.SIGUSR1:
			s.signalStatus()
		case syscall.SIGUSR2:
			s.signalToggleCpuProfile()
			//s.signalToggleTrace()
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/keybase/go-ps"
	"github.com/shirou/gopsutil/process"
	"github.com/xiaonanln/goworld/engine/config"
	"github.com/xiaonanln/goworld/engine/gwlog"
)

// ServerStatus represents the status of a server
type ServerStatus struct {
	NumDispatcherRunning int
	NumGatesRunning      int
	NumGamesRunning      int

	DispatcherProcs []ps.Process
	GateProcs       []ps.Process
	GameProcs       []ps.Process
	ServerID        ServerID
}

// IsRunning returns if a server is running
func (ss *ServerStatus) IsRunning() bool {
	return ss.NumDispatcherRunning > 0 || ss.NumGatesRunning > 0 || ss.NumGamesRunning > 0
}

func getProcPath(proc ps.Process) (string, error) {
	path, err := proc.Path()

	if err == nil {
		return path, nil
	}

	if pathErr, ok := err.(*os.PathError); ok {
		path = pathErr.Path
		if strings.HasSuffix(path, " (deleted)") {
			path = path[:len(path)-10]
			return path, nil
		}
	}
	return "", err
}

func detectServerStatus() *ServerStatus {
	ss := &ServerStatus{}
	procs, err := ps.Processes()
	checkErrorOrQuit(err, "list processes failed")
	for _, proc := range procs {
		path, err := getProcPath(proc)
		if err != nil {
			continue
		}

		relpath, err := filepath.Rel(env.GoWorldRoot, path)
		if err != nil || strings.HasPrefix(relpath, "..") {
			continue
		}

		dir, file := filepath.Split(relpath)

		if file == "dispatcher"+BinaryExtension {
			ss.NumDispatcherRunning++
			ss.DispatcherProcs = append(ss.DispatcherProcs, proc)
		} else if file == "gate"+BinaryExtension {
			ss.NumGatesRunning++
			ss.GateProcs = append(ss.GateProcs, proc)
		} else {
			if strings.HasSuffix(dir, string(filepath.Separator)) {
				dir = dir[:len(dir)-1]
			}
			serverid := ServerID(strings.Join(strings.Split(dir, string(filepath.Separator)), "/"))
			if strings.HasPrefix(string(serverid), "cmd/") || strings.HasPrefix(string(serverid), "components/") || string(serverid) == "examples/test_client" {
				// this is a cmd or a component, not a game
				continue
			}
			ss.NumGamesRunning++
			ss.GameProcs = append(ss.GameProcs, proc)
			if ss.ServerID == "" {
				ss.ServerID = serverid
			}
		}
	}

	return ss
}

func status() {
	pids := process.Pids()
	gwlog.Infof("pids pids")
	ss := detectServerStatus()
	showServerStatus(ss)
}

func showServerStatus(ss *ServerStatus) {
	showMsg("%d dispatcher running, %d/%d gates running, %d/%d games (%s) running", ss.NumDispatcherRunning,
		ss.NumGatesRunning, config.GetGatesNum(),
		ss.NumGamesRunning, config.GetGamesNum(),
		ss.ServerID,
	)

	var listProcs []ps.Process
	listProcs = append(listProcs, ss.DispatcherProcs...)
	listProcs = append(listProcs, ss.GameProcs...)
	listProcs = append(listProcs, ss.GateProcs...)
	for _, proc := range listProcs {
		path, err := getProcPath(proc)
		if err != nil {
			path = "[" + proc.Executable() + "]"
		}
		showMsg("\t%-10d%-16s%s", proc.Pid(), proc.Executable(), path)
	}
}
<commit_msg>restore entities before running dispatcher<commit_after>package main

import (
	"os"
	"path/filepath"
	"strings"

	"github.com/keybase/go-ps"
	"github.com/xiaonanln/goworld/engine/config"
)

// ServerStatus represents the status of a server
type ServerStatus struct {
	NumDispatcherRunning int
	NumGatesRunning      int
	NumGamesRunning      int

	DispatcherProcs []ps.Process
	GateProcs       []ps.Process
	GameProcs       []ps.Process
	ServerID        ServerID
}

// IsRunning returns if a server is running
func (ss *ServerStatus) IsRunning() bool {
	return ss.NumDispatcherRunning > 0 || ss.NumGatesRunning > 0 || ss.NumGamesRunning > 0
}

func getProcPath(proc ps.Process) (string, error) {
	path, err := proc.Path()

	if err == nil {
		return path, nil
	}

	if pathErr, ok := err.(*os.PathError); ok {
		path = pathErr.Path
		if strings.HasSuffix(path, " (deleted)") {
			path = path[:len(path)-10]
			return path, nil
		}
	}
	return "", err
}

func detectServerStatus() *ServerStatus {
	ss := &ServerStatus{}
	procs, err := ps.Processes()
	checkErrorOrQuit(err, "list processes failed")
	for _, proc := range procs {
		path, err := getProcPath(proc)
		if err != nil {
			continue
		}

		relpath, err := filepath.Rel(env.GoWorldRoot, path)
		if err != nil || strings.HasPrefix(relpath, "..") {
			continue
		}

		dir, file := filepath.Split(relpath)

		if file == "dispatcher"+BinaryExtension {
			ss.NumDispatcherRunning++
			ss.DispatcherProcs = append(ss.DispatcherProcs, proc)
		} else if file == "gate"+BinaryExtension {
			ss.NumGatesRunning++
			ss.GateProcs = append(ss.GateProcs, proc)
		} else {
			if strings.HasSuffix(dir, string(filepath.Separator)) {
				dir = dir[:len(dir)-1]
			}
			serverid := ServerID(strings.Join(strings.Split(dir, string(filepath.Separator)), "/"))
			if strings.HasPrefix(string(serverid), "cmd/") || strings.HasPrefix(string(serverid), "components/") || string(serverid) == "examples/test_client" {
				// this is a cmd or a component, not a game
				continue
			}
			ss.NumGamesRunning++
			ss.GameProcs = append(ss.GameProcs, proc)
			if ss.ServerID == "" {
				ss.ServerID = serverid
			}
		}
	}

	return ss
}

func status() {
	ss := detectServerStatus()
	showServerStatus(ss)
}

func showServerStatus(ss *ServerStatus) {
	showMsg("%d dispatcher running, %d/%d gates running, %d/%d games (%s) running", ss.NumDispatcherRunning,
		ss.NumGatesRunning, config.GetGatesNum(),
		ss.NumGamesRunning, config.GetGamesNum(),
		ss.ServerID,
	)

	var listProcs []ps.Process
	listProcs = append(listProcs, ss.DispatcherProcs...)
	listProcs = append(listProcs, ss.GameProcs...)
	listProcs = append(listProcs, ss.GateProcs...)
	for _, proc := range listProcs {
		path, err := getProcPath(proc)
		if err != nil {
			path = "[" + proc.Executable() + "]"
		}
		showMsg("\t%-10d%-16s%s", proc.Pid(), proc.Executable(), path)
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main_test

// This file defines a test framework for guru queries.
//
// The files beneath testdata/src/main contain Go programs containing
// query annotations of the form:
//
//   @verb id "select"
//
// where verb is the query mode (e.g. "callers"), id is a unique name
// for this query, and "select" is a regular expression matching the
// substring of the current line that is the query's input selection.
//
// The expected output for each query is provided in the accompanying
// .golden file.
//
// (Location information is not included because it's too fragile to
// display as text.  TODO(adonovan): think about how we can test its
// correctness, since it is critical information.)
//
// Run this test with:
// 	% go test golang.org/x/tools/cmd/guru -update
// to update the golden files.

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"testing"

	guru "golang.org/x/tools/cmd/guru"
)

var updateFlag = flag.Bool("update", false, "Update the golden files.")

type query struct {
	id       string         // unique id
	verb     string         // query mode, e.g. "callees"
	posn     token.Position // query position
	filename string
	queryPos string // query position in command-line syntax
}

func parseRegexp(text string) (*regexp.Regexp, error) {
	pattern, err := strconv.Unquote(text)
	if err != nil {
		return nil, fmt.Errorf("can't unquote %s", text)
	}
	return regexp.Compile(pattern)
}

// parseQueries parses and returns the queries in the named file.
func parseQueries(t *testing.T, filename string) []*query {
	filedata, err := ioutil.ReadFile(filename)
	if err != nil {
		t.Fatal(err)
	}

	// Parse the file once to discover the test queries.
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filename, filedata, parser.ParseComments)
	if err != nil {
		t.Fatal(err)
	}

	lines := bytes.Split(filedata, []byte("\n"))

	var queries []*query
	queriesById := make(map[string]*query)

	// Find all annotations of these forms:
	expectRe := regexp.MustCompile(`@([a-z]+)\s+(\S+)\s+(\".*)$`) // @verb id "regexp"
	for _, c := range f.Comments {
		text := strings.TrimSpace(c.Text())
		if text == "" || text[0] != '@' {
			continue
		}
		posn := fset.Position(c.Pos())

		// @verb id "regexp"
		match := expectRe.FindStringSubmatch(text)
		if match == nil {
			t.Errorf("%s: ill-formed query: %s", posn, text)
			continue
		}

		id := match[2]
		if prev, ok := queriesById[id]; ok {
			t.Errorf("%s: duplicate id %s", posn, id)
			t.Errorf("%s: previously used here", prev.posn)
			continue
		}

		q := &query{
			id:       id,
			verb:     match[1],
			filename: filename,
			posn:     posn,
		}

		if match[3] != `"nopos"` {
			selectRe, err := parseRegexp(match[3])
			if err != nil {
				t.Errorf("%s: %s", posn, err)
				continue
			}

			// Find text of the current line, sans query.
			// (Queries must be // not /**/ comments.)
			line := lines[posn.Line-1][:posn.Column-1]

			// Apply regexp to current line to find input selection.
			loc := selectRe.FindIndex(line)
			if loc == nil {
				t.Errorf("%s: selection pattern %s doesn't match line %q",
					posn, match[3], string(line))
				continue
			}

			// Assumes ASCII. TODO(adonovan): test on UTF-8.
			linestart := posn.Offset - (posn.Column - 1)

			// Compute the file offsets.
			q.queryPos = fmt.Sprintf("%s:#%d,#%d",
				filename, linestart+loc[0], linestart+loc[1])
		}

		queries = append(queries, q)
		queriesById[id] = q
	}

	// Return the slice, not map, for deterministic iteration.
	return queries
}

// doQuery poses query q to the guru and writes its response and
// error (if any) to out.
func doQuery(out io.Writer, q *query, json bool) {
	fmt.Fprintf(out, "-------- @%s %s --------\n", q.verb, q.id)

	var buildContext = build.Default
	buildContext.GOPATH = "testdata"
	pkg := filepath.Dir(strings.TrimPrefix(q.filename, "testdata/src/"))

	gopathAbs, _ := filepath.Abs(buildContext.GOPATH)

	var outputMu sync.Mutex // guards outputs
	var outputs []string    // JSON objects or lines of text
	outputFn := func(fset *token.FileSet, qr guru.QueryResult) {
		outputMu.Lock()
		defer outputMu.Unlock()
		if json {
			jsonstr := string(qr.JSON(fset))
			// Sanitize any absolute filenames that creep in.
			jsonstr = strings.Replace(jsonstr, gopathAbs, "$GOPATH", -1)
			outputs = append(outputs, jsonstr)
		} else {
			// suppress position information
			qr.PrintPlain(func(_ interface{}, format string, args ...interface{}) {
				outputs = append(outputs, fmt.Sprintf(format, args...))
			})
		}
	}

	query := guru.Query{
		Pos:        q.queryPos,
		Build:      &buildContext,
		Scope:      []string{pkg},
		Reflection: true,
		Output:     outputFn,
	}

	if err := guru.Run(q.verb, &query); err != nil {
		fmt.Fprintf(out, "\nError: %s\n", err)
		return
	}

	// In a "referrers" query, references are sorted within each
	// package but packages are visited in arbitrary order,
	// so for determinism we sort them.  Line 0 is a caption.
	if q.verb == "referrers" {
		sort.Strings(outputs[1:])
	}

	for _, output := range outputs {
		fmt.Fprintf(out, "%s\n", output)
	}

	if !json {
		io.WriteString(out, "\n")
	}
}

func TestGuru(t *testing.T) {
	switch runtime.GOOS {
	case "android":
		t.Skipf("skipping test on %q (no testdata dir)", runtime.GOOS)
	case "windows":
		t.Skipf("skipping test on %q (no /usr/bin/diff)", runtime.GOOS)
	}

	for _, filename := range []string{
		"testdata/src/alias/alias.go", // iff guru.HasAlias (go1.9)
		"testdata/src/calls/main.go",
		"testdata/src/describe/main.go",
		"testdata/src/describe/main19.go", // iff go1.9
		"testdata/src/freevars/main.go",
		"testdata/src/implements/main.go",
		"testdata/src/implements-methods/main.go",
		"testdata/src/imports/main.go",
		"testdata/src/peers/main.go",
		"testdata/src/pointsto/main.go",
		"testdata/src/referrers/main.go",
		"testdata/src/reflection/main.go",
		"testdata/src/what/main.go",
		"testdata/src/whicherrs/main.go",
		"testdata/src/softerrs/main.go",
		// JSON:
		// TODO(adonovan): most of these are very similar; combine them.
		"testdata/src/calls-json/main.go",
		"testdata/src/peers-json/main.go",
		"testdata/src/definition-json/main.go",
		"testdata/src/definition-json/main19.go",
		"testdata/src/describe-json/main.go",
		"testdata/src/implements-json/main.go",
		"testdata/src/implements-methods-json/main.go",
		"testdata/src/pointsto-json/main.go",
		"testdata/src/referrers-json/main.go",
		"testdata/src/what-json/main.go",
	} {
		if filename == "testdata/src/referrers/main.go" && runtime.GOOS == "plan9" {
			// Disable this test on plan9 since it expects a particular
			// wording for a "no such file or directory" error.
			continue
		}
		if filename == "testdata/src/alias/alias.go" && !guru.HasAlias {
			continue
		}
		if strings.HasSuffix(filename, "19.go") && !contains(build.Default.ReleaseTags, "go1.9") {
			// TODO(adonovan): recombine the 'describe' and 'definition'
			// tests once we drop support for go1.8.
			continue
		}

		json := strings.Contains(filename, "-json/")
		queries := parseQueries(t, filename)
		golden := filename + "lden"
		got := filename + "t"
		gotfh, err := os.Create(got)
		if err != nil {
			t.Errorf("Create(%s) failed: %s", got, err)
			continue
		}
		defer os.Remove(got)
		defer gotfh.Close()

		// Run the guru on each query, redirecting its output
		// and error (if any) to the foo.got file.
		for _, q := range queries {
			doQuery(gotfh, q, json)
		}

		// Compare foo.got with foo.golden.
		var cmd *exec.Cmd
		switch runtime.GOOS {
		case "plan9":
			cmd = exec.Command("/bin/diff", "-c", golden, got)
		default:
			cmd = exec.Command("/usr/bin/diff", "-u", golden, got)
		}
		buf := new(bytes.Buffer)
		cmd.Stdout = buf
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			t.Errorf("Guru tests for %s failed: %s.\n%s\n",
				filename, err, buf)

			if *updateFlag {
				t.Logf("Updating %s...", golden)
				if err := exec.Command("/bin/cp", got, golden).Run(); err != nil {
					t.Errorf("Update failed: %s", err)
				}
			}
		}
	}
}

func contains(haystack []string, needle string) bool {
	for _, x := range haystack {
		if needle == x {
			return true
		}
	}
	return false
}

func TestIssue14684(t *testing.T) {
	var buildContext = build.Default
	buildContext.GOPATH = "testdata"
	query := guru.Query{
		Pos:   "testdata/src/README.txt:#1",
		Build: &buildContext,
	}
	err := guru.Run("freevars", &query)
	if err == nil {
		t.Fatal("guru query succeeded unexpectedly")
	}
	if got, want := err.Error(), "testdata/src/README.txt is not a Go source file"; got != want {
		t.Errorf("query error was %q, want %q", got, want)
	}
}
<commit_msg>cmd/guru: disable a failing test for now<commit_after>// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main_test

// This file defines a test framework for guru queries.
//
// The files beneath testdata/src/main contain Go programs containing
// query annotations of the form:
//
//   @verb id "select"
//
// where verb is the query mode (e.g. "callers"), id is a unique name
// for this query, and "select" is a regular expression matching the
// substring of the current line that is the query's input selection.
//
// The expected output for each query is provided in the accompanying
// .golden file.
//
// (Location information is not included because it's too fragile to
// display as text.  TODO(adonovan): think about how we can test its
// correctness, since it is critical information.)
//
// Run this test with:
// 	% go test golang.org/x/tools/cmd/guru -update
// to update the golden files.

import (
	"bytes"
	"flag"
	"fmt"
	"go/build"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"sync"
	"testing"

	guru "golang.org/x/tools/cmd/guru"
)

var updateFlag = flag.Bool("update", false, "Update the golden files.")

type query struct {
	id       string         // unique id
	verb     string         // query mode, e.g. "callees"
	posn     token.Position // query position
	filename string
	queryPos string // query position in command-line syntax
}

func parseRegexp(text string) (*regexp.Regexp, error) {
	pattern, err := strconv.Unquote(text)
	if err != nil {
		return nil, fmt.Errorf("can't unquote %s", text)
	}
	return regexp.Compile(pattern)
}

// parseQueries parses and returns the queries in the named file.
func parseQueries(t *testing.T, filename string) []*query {
	filedata, err := ioutil.ReadFile(filename)
	if err != nil {
		t.Fatal(err)
	}

	// Parse the file once to discover the test queries.
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, filename, filedata, parser.ParseComments)
	if err != nil {
		t.Fatal(err)
	}

	lines := bytes.Split(filedata, []byte("\n"))

	var queries []*query
	queriesById := make(map[string]*query)

	// Find all annotations of these forms:
	expectRe := regexp.MustCompile(`@([a-z]+)\s+(\S+)\s+(\".*)$`) // @verb id "regexp"
	for _, c := range f.Comments {
		text := strings.TrimSpace(c.Text())
		if text == "" || text[0] != '@' {
			continue
		}
		posn := fset.Position(c.Pos())

		// @verb id "regexp"
		match := expectRe.FindStringSubmatch(text)
		if match == nil {
			t.Errorf("%s: ill-formed query: %s", posn, text)
			continue
		}

		id := match[2]
		if prev, ok := queriesById[id]; ok {
			t.Errorf("%s: duplicate id %s", posn, id)
			t.Errorf("%s: previously used here", prev.posn)
			continue
		}

		q := &query{
			id:       id,
			verb:     match[1],
			filename: filename,
			posn:     posn,
		}

		if match[3] != `"nopos"` {
			selectRe, err := parseRegexp(match[3])
			if err != nil {
				t.Errorf("%s: %s", posn, err)
				continue
			}

			// Find text of the current line, sans query.
			// (Queries must be // not /**/ comments.)
			line := lines[posn.Line-1][:posn.Column-1]

			// Apply regexp to current line to find input selection.
			loc := selectRe.FindIndex(line)
			if loc == nil {
				t.Errorf("%s: selection pattern %s doesn't match line %q",
					posn, match[3], string(line))
				continue
			}

			// Assumes ASCII. TODO(adonovan): test on UTF-8.
			linestart := posn.Offset - (posn.Column - 1)

			// Compute the file offsets.
			q.queryPos = fmt.Sprintf("%s:#%d,#%d",
				filename, linestart+loc[0], linestart+loc[1])
		}

		queries = append(queries, q)
		queriesById[id] = q
	}

	// Return the slice, not map, for deterministic iteration.
	return queries
}

// doQuery poses query q to the guru and writes its response and
// error (if any) to out.
func doQuery(out io.Writer, q *query, json bool) {
	fmt.Fprintf(out, "-------- @%s %s --------\n", q.verb, q.id)

	var buildContext = build.Default
	buildContext.GOPATH = "testdata"
	pkg := filepath.Dir(strings.TrimPrefix(q.filename, "testdata/src/"))

	gopathAbs, _ := filepath.Abs(buildContext.GOPATH)

	var outputMu sync.Mutex // guards outputs
	var outputs []string    // JSON objects or lines of text
	outputFn := func(fset *token.FileSet, qr guru.QueryResult) {
		outputMu.Lock()
		defer outputMu.Unlock()
		if json {
			jsonstr := string(qr.JSON(fset))
			// Sanitize any absolute filenames that creep in.
			jsonstr = strings.Replace(jsonstr, gopathAbs, "$GOPATH", -1)
			outputs = append(outputs, jsonstr)
		} else {
			// suppress position information
			qr.PrintPlain(func(_ interface{}, format string, args ...interface{}) {
				outputs = append(outputs, fmt.Sprintf(format, args...))
			})
		}
	}

	query := guru.Query{
		Pos:        q.queryPos,
		Build:      &buildContext,
		Scope:      []string{pkg},
		Reflection: true,
		Output:     outputFn,
	}

	if err := guru.Run(q.verb, &query); err != nil {
		fmt.Fprintf(out, "\nError: %s\n", err)
		return
	}

	// In a "referrers" query, references are sorted within each
	// package but packages are visited in arbitrary order,
	// so for determinism we sort them.  Line 0 is a caption.
	if q.verb == "referrers" {
		sort.Strings(outputs[1:])
	}

	for _, output := range outputs {
		fmt.Fprintf(out, "%s\n", output)
	}

	if !json {
		io.WriteString(out, "\n")
	}
}

func TestGuru(t *testing.T) {
	switch runtime.GOOS {
	case "android":
		t.Skipf("skipping test on %q (no testdata dir)", runtime.GOOS)
	case "windows":
		t.Skipf("skipping test on %q (no /usr/bin/diff)", runtime.GOOS)
	}

	for _, filename := range []string{
		"testdata/src/alias/alias.go", // iff guru.HasAlias (go1.9)
		"testdata/src/calls/main.go",
		"testdata/src/describe/main.go",
		"testdata/src/describe/main19.go", // iff go1.9
		"testdata/src/freevars/main.go",
		"testdata/src/implements/main.go",
		"testdata/src/implements-methods/main.go",
		// "testdata/src/imports/main.go", // disabled until golang.org/issue/19464 is fixed
		"testdata/src/peers/main.go",
		"testdata/src/pointsto/main.go",
		"testdata/src/referrers/main.go",
		"testdata/src/reflection/main.go",
		"testdata/src/what/main.go",
		"testdata/src/whicherrs/main.go",
		"testdata/src/softerrs/main.go",
		// JSON:
		// TODO(adonovan): most of these are very similar; combine them.
		"testdata/src/calls-json/main.go",
		"testdata/src/peers-json/main.go",
		"testdata/src/definition-json/main.go",
		"testdata/src/definition-json/main19.go",
		"testdata/src/describe-json/main.go",
		"testdata/src/implements-json/main.go",
		"testdata/src/implements-methods-json/main.go",
		"testdata/src/pointsto-json/main.go",
		"testdata/src/referrers-json/main.go",
		"testdata/src/what-json/main.go",
	} {
		if filename == "testdata/src/referrers/main.go" && runtime.GOOS == "plan9" {
			// Disable this test on plan9 since it expects a particular
			// wording for a "no such file or directory" error.
			continue
		}
		if filename == "testdata/src/alias/alias.go" && !guru.HasAlias {
			continue
		}
		if strings.HasSuffix(filename, "19.go") && !contains(build.Default.ReleaseTags, "go1.9") {
			// TODO(adonovan): recombine the 'describe' and 'definition'
			// tests once we drop support for go1.8.
			continue
		}

		json := strings.Contains(filename, "-json/")
		queries := parseQueries(t, filename)
		golden := filename + "lden"
		got := filename + "t"
		gotfh, err := os.Create(got)
		if err != nil {
			t.Errorf("Create(%s) failed: %s", got, err)
			continue
		}
		defer os.Remove(got)
		defer gotfh.Close()

		// Run the guru on each query, redirecting its output
		// and error (if any) to the foo.got file.
		for _, q := range queries {
			doQuery(gotfh, q, json)
		}

		// Compare foo.got with foo.golden.
		var cmd *exec.Cmd
		switch runtime.GOOS {
		case "plan9":
			cmd = exec.Command("/bin/diff", "-c", golden, got)
		default:
			cmd = exec.Command("/usr/bin/diff", "-u", golden, got)
		}
		buf := new(bytes.Buffer)
		cmd.Stdout = buf
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			t.Errorf("Guru tests for %s failed: %s.\n%s\n",
				filename, err, buf)

			if *updateFlag {
				t.Logf("Updating %s...", golden)
				if err := exec.Command("/bin/cp", got, golden).Run(); err != nil {
					t.Errorf("Update failed: %s", err)
				}
			}
		}
	}
}

func contains(haystack []string, needle string) bool {
	for _, x := range haystack {
		if needle == x {
			return true
		}
	}
	return false
}

func TestIssue14684(t *testing.T) {
	var buildContext = build.Default
	buildContext.GOPATH = "testdata"
	query := guru.Query{
		Pos:   "testdata/src/README.txt:#1",
		Build: &buildContext,
	}
	err := guru.Run("freevars", &query)
	if err == nil {
		t.Fatal("guru query succeeded unexpectedly")
	}
	if got, want := err.Error(), "testdata/src/README.txt is not a Go source file"; got != want {
		t.Errorf("query error was %q, want %q", got, want)
	}
}
<|endoftext|>


<commit_before>// ledgerfmt pretty-prints ledger files.
package main

import (
	"bytes"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"os"

	"github.com/xconstruct/ledger/parse"
	"github.com/xconstruct/ledger/print"
)

var writeOutput = flag.Bool("w", false, "Write back to input file")

func main() {
	flag.Parse()

	var source io.Reader
	source = os.Stdin

	inFile := flag.Arg(0)
	if inFile != "" {
		sourceFile, err := os.Open(inFile)
		if err != nil {
			log.Fatalln("Couldn't open source file:", err)
		}

		source = sourceFile
		defer sourceFile.Close()
	}

	cnt, err := ioutil.ReadAll(source)
	if err != nil {
		log.Fatalln("Error reading input:", err)
	}

	t := parse.New("stdin", string(cnt))
	err = t.Parse()
	if err != nil {
		log.Fatalln("Parsing error:", err)
	}

	printer := print.New(t)

	buf := &bytes.Buffer{}
	err = printer.Print(buf)
	if err != nil {
		log.Fatalln("rendering ledger file:", err)
	}

	var dest io.Writer
	dest = os.Stdout
	if inFile != "" && *writeOutput {
		destFile, err := os.Create(inFile)
		if err != nil {
			log.Fatalln("Couldn't write to file:", inFile)
		}
		dest = destFile
		defer destFile.Close()
	}

	_, err = dest.Write(buf.Bytes())
	if err != nil {
		log.Fatalln("Error writing to file:", err)

	}
}
<commit_msg>ledgerfmt: fix filename<commit_after>// ledgerfmt pretty-prints ledger files.
package main

import (
	"bytes"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"os"

	"github.com/xconstruct/ledger/parse"
	"github.com/xconstruct/ledger/print"
)

var writeOutput = flag.Bool("w", false, "Write back to input file")

func main() {
	flag.Parse()

	var source io.Reader
	source = os.Stdin
	var filename = "stdin"

	inFile := flag.Arg(0)
	if inFile != "" {
		sourceFile, err := os.Open(inFile)
		if err != nil {
			log.Fatalln("Couldn't open source file:", err)
		}

		source = sourceFile
		filename = inFile
		defer sourceFile.Close()
	}

	cnt, err := ioutil.ReadAll(source)
	if err != nil {
		log.Fatalln("Error reading input:", err)
	}

	t := parse.New(filename, string(cnt))
	err = t.Parse()
	if err != nil {
		log.Fatalln("Parsing error:", err)
	}

	printer := print.New(t)

	buf := &bytes.Buffer{}
	err = printer.Print(buf)
	if err != nil {
		log.Fatalln("rendering ledger file:", err)
	}

	var dest io.Writer
	dest = os.Stdout
	if inFile != "" && *writeOutput {
		destFile, err := os.Create(inFile)
		if err != nil {
			log.Fatalln("Couldn't write to file:", inFile)
		}
		dest = destFile
		defer destFile.Close()
	}

	_, err = dest.Write(buf.Bytes())
	if err != nil {
		log.Fatalln("Error writing to file:", err)

	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"sync"
	"time"

	"github.com/dgnorton/norobo"
	"github.com/dgnorton/norobo/filter"
	"github.com/dgnorton/norobo/hayes"
)

func main() {
	var (
		connstr        string
		blockFile      string
		allowFile      string
		callLogFile    string
		twloAccountSID string
		twloToken      string
		execCommand    string
		execArgs       string
	)

	flag.StringVar(&connstr, "c", "/dev/ttyACM0,19200,n,8,1", "serial port connect string (port,baud,handshake,data-bits,stop-bits)")
	flag.StringVar(&blockFile, "block", "", "path to file containing patterns to block")
	flag.StringVar(&allowFile, "allow", "", "path to file containing patterns to allow")
	flag.StringVar(&callLogFile, "call-log", "", "path to call log file")
	flag.StringVar(&twloAccountSID, "twlo-sid", "", "Twilio account SID")
	flag.StringVar(&twloToken, "twlo-token", "", "Twilio token")
	flag.StringVar(&execCommand, "exec", "", "Command gets executed for every call")
	flag.StringVar(&execArgs, "exec-args", "-n {{.Number}}", "Arguments for exec command; uses text/template; availible vars are (Number, Name, Time)")
	flag.Parse()

	modem, err := hayes.Open(connstr)
	check(err)

	callHandler := newCallHandler(modem, blockFile, allowFile, twloAccountSID, twloToken, callLogFile, execCommand, execArgs)
	modem.SetCallHandler(callHandler)
	modem.EnableSoftwareCache(false)

	check(modem.Reset())

	infos, err := modem.Info()
	check(err)
	println("Modem info:")
	for _, info := range infos {
		println(info)
	}

	fcs, err := modem.FaxClasses()
	check(err)
	println("Fax classes:")
	for _, fc := range fcs {
		println(fc)
	}

	fc, err := modem.FaxClass()
	check(err)
	fmt.Printf("fax class: %s\n", fc)

	check(modem.SetFaxClass(hayes.FaxClass2))

	fc, err = modem.FaxClass()
	check(err)
	fmt.Printf("fax class: %s\n", fc)

	cidModes, err := modem.CallerIDModes()
	check(err)
	println("Caller ID modes:")
	for _, m := range cidModes {
		println(m)
	}

	cidMode, err := modem.CallerIDMode()
	check(err)
	fmt.Printf("caller ID mode: %s\n", cidMode)

	check(modem.SetCallerIDMode(hayes.CallerIDOn))

	cidMode, err = modem.CallerIDMode()
	check(err)
	fmt.Printf("caller ID mode: %s\n", cidMode)

	// Start call log web server.
	s := &http.Server{
		Addr:    ":7080",
		Handler: newWebHandler(callHandler),
	}

	check(s.ListenAndServe())

	modem.Close()
}

type webHandler struct {
	mux         *http.ServeMux
	callHandler *callHandler
}

func newWebHandler(h *callHandler) *webHandler {
	handler := &webHandler{
		mux:         http.NewServeMux(),
		callHandler: h,
	}

	handler.mux.Handle("/", http.FileServer(http.Dir("./web")))
	handler.mux.HandleFunc("/calls", handler.serveCalls)

	return handler
}

func (h *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.mux.ServeHTTP(w, r)
}

func (h *webHandler) serveCalls(w http.ResponseWriter, r *http.Request) {
	//<-h.callHandler.CallLogChanged(time.Now())
	log := h.callHandler.CallLog()
	b, err := json.Marshal(log)
	if err != nil {
		panic(err)
	}
	w.Header().Add("content-type", "application/json")
	w.Write(b)
}

type callHandler struct {
	modem          *hayes.Modem
	filters        norobo.Filters
	callLogFile    string
	mu             sync.RWMutex
	callLog        *norobo.CallLog
	callLogChanged chan struct{}
}

func newCallHandler(m *hayes.Modem, blockFile, allowFile, twloAccountSID, twloToken, callLogFile, execCommand, execArgs string) *callHandler {
	filters := norobo.Filters{}

	if blockFile != "" {
		block, err := filter.LoadFilterFile(blockFile, norobo.Block)
		if err != nil {
			panic(err)
		}
		filters = append(filters, block)
	}

	if allowFile != "" {
		allow, err := filter.LoadFilterFile(allowFile, norobo.Allow)
		if err != nil {
			panic(err)
		}
		filters = append(filters, allow)
	}

	filters = append(filters, filter.NewTwilio(twloAccountSID, twloToken))

	// Adds external cammand exec to filter list if command exists in flags
	if execCommand != "" {
		filters = append(filters, filter.NewExecFilter(execCommand, execArgs))
	}

	callLog, err := norobo.LoadCallLog(callLogFile)
	if err != nil {
		panic(err)
	}

	h := &callHandler{
		modem:          m,
		filters:        filters,
		callLogFile:    callLogFile,
		callLog:        callLog,
		callLogChanged: make(chan struct{}),
	}

	return h
}

func (h *callHandler) Handle(c *hayes.Call) {
	call := &norobo.Call{Call: c}

	call.FilterResult = h.filters.Run(call)
	if call.FilterResult.Action == norobo.Block {
		call.Block()
	}

	h.log(call)
}

func (h *callHandler) CallLog() *norobo.CallLog {
	h.mu.RLock()
	defer h.mu.RUnlock()
	return h.callLog
}

func (h *callHandler) CallLogChanged(after time.Time) chan struct{} {
	h.mu.RLock()
	defer h.mu.RUnlock()
	changedCh := make(chan struct{})
	ch := h.callLogChanged
	go func() {
		for {
			<-ch

			h.mu.RLock()
			changed := h.callLog.LastTime().After(after)

			if changed {
				close(changedCh)
				h.mu.RUnlock()
				return
			}

			ch = h.callLogChanged
			h.mu.RUnlock()
		}
	}()

	return changedCh
}

func (h *callHandler) log(c *norobo.Call) {
	f, err := os.OpenFile(h.callLogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0770)
	if err != nil {
		println(err)
		return
	}
	defer f.Close()
	r := c.FilterResult
	w := csv.NewWriter(f)
	msg := []string{c.Time.Format(time.RFC3339Nano), c.Name, c.Number, r.Action.String(), r.FilterDescription(), r.Description}

	h.mu.Lock()
	call := &norobo.CallEntry{
		Time:   c.Time,
		Name:   c.Name,
		Number: c.Number,
		Action: r.Action.String(),
		Filter: r.FilterDescription(),
		Reason: r.Description,
	}

	h.callLog.Calls = append(h.callLog.Calls, call)
	close(h.callLogChanged)
	h.callLogChanged = make(chan struct{})
	h.mu.Unlock()

	if err := w.Write(msg); err != nil {
		println(err)
	}
	w.Flush()
	fmt.Println(call)
}

func check(err error) {
	if err != nil {
		println(err.Error())
		os.Exit(1)
	}
}
<commit_msg>only use Twilio if SID & token provided<commit_after>package main

import (
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"net/http"
	"os"
	"sync"
	"time"

	"github.com/dgnorton/norobo"
	"github.com/dgnorton/norobo/filter"
	"github.com/dgnorton/norobo/hayes"
)

func main() {
	var (
		connstr        string
		blockFile      string
		allowFile      string
		callLogFile    string
		twloAccountSID string
		twloToken      string
		execCommand    string
		execArgs       string
	)

	flag.StringVar(&connstr, "c", "/dev/ttyACM0,19200,n,8,1", "serial port connect string (port,baud,handshake,data-bits,stop-bits)")
	flag.StringVar(&blockFile, "block", "", "path to file containing patterns to block")
	flag.StringVar(&allowFile, "allow", "", "path to file containing patterns to allow")
	flag.StringVar(&callLogFile, "call-log", "", "path to call log file")
	flag.StringVar(&twloAccountSID, "twlo-sid", "", "Twilio account SID")
	flag.StringVar(&twloToken, "twlo-token", "", "Twilio token")
	flag.StringVar(&execCommand, "exec", "", "Command gets executed for every call")
	flag.StringVar(&execArgs, "exec-args", "-n {{.Number}}", "Arguments for exec command; uses text/template; availible vars are (Number, Name, Time)")
	flag.Parse()

	modem, err := hayes.Open(connstr)
	check(err)

	callHandler := newCallHandler(modem, blockFile, allowFile, twloAccountSID, twloToken, callLogFile, execCommand, execArgs)
	modem.SetCallHandler(callHandler)
	modem.EnableSoftwareCache(false)

	check(modem.Reset())

	infos, err := modem.Info()
	check(err)
	println("Modem info:")
	for _, info := range infos {
		println(info)
	}

	fcs, err := modem.FaxClasses()
	check(err)
	println("Fax classes:")
	for _, fc := range fcs {
		println(fc)
	}

	fc, err := modem.FaxClass()
	check(err)
	fmt.Printf("fax class: %s\n", fc)

	check(modem.SetFaxClass(hayes.FaxClass2))

	fc, err = modem.FaxClass()
	check(err)
	fmt.Printf("fax class: %s\n", fc)

	cidModes, err := modem.CallerIDModes()
	check(err)
	println("Caller ID modes:")
	for _, m := range cidModes {
		println(m)
	}

	cidMode, err := modem.CallerIDMode()
	check(err)
	fmt.Printf("caller ID mode: %s\n", cidMode)

	check(modem.SetCallerIDMode(hayes.CallerIDOn))

	cidMode, err = modem.CallerIDMode()
	check(err)
	fmt.Printf("caller ID mode: %s\n", cidMode)

	// Start call log web server.
	s := &http.Server{
		Addr:    ":7080",
		Handler: newWebHandler(callHandler),
	}

	check(s.ListenAndServe())

	modem.Close()
}

type webHandler struct {
	mux         *http.ServeMux
	callHandler *callHandler
}

func newWebHandler(h *callHandler) *webHandler {
	handler := &webHandler{
		mux:         http.NewServeMux(),
		callHandler: h,
	}

	handler.mux.Handle("/", http.FileServer(http.Dir("./web")))
	handler.mux.HandleFunc("/calls", handler.serveCalls)

	return handler
}

func (h *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	h.mux.ServeHTTP(w, r)
}

func (h *webHandler) serveCalls(w http.ResponseWriter, r *http.Request) {
	//<-h.callHandler.CallLogChanged(time.Now())
	log := h.callHandler.CallLog()
	b, err := json.Marshal(log)
	if err != nil {
		panic(err)
	}
	w.Header().Add("content-type", "application/json")
	w.Write(b)
}

type callHandler struct {
	modem          *hayes.Modem
	filters        norobo.Filters
	callLogFile    string
	mu             sync.RWMutex
	callLog        *norobo.CallLog
	callLogChanged chan struct{}
}

func newCallHandler(m *hayes.Modem, blockFile, allowFile, twloAccountSID, twloToken, callLogFile, execCommand, execArgs string) *callHandler {
	filters := norobo.Filters{}

	if blockFile != "" {
		block, err := filter.LoadFilterFile(blockFile, norobo.Block)
		if err != nil {
			panic(err)
		}
		filters = append(filters, block)
	}

	if allowFile != "" {
		allow, err := filter.LoadFilterFile(allowFile, norobo.Allow)
		if err != nil {
			panic(err)
		}
		filters = append(filters, allow)
	}

	if twloAccountSID != "" && twloToken != "" {
		filters = append(filters, filter.NewTwilio(twloAccountSID, twloToken))
	}

	// Adds external cammand exec to filter list if command exists in flags
	if execCommand != "" {
		filters = append(filters, filter.NewExecFilter(execCommand, execArgs))
	}

	callLog, err := norobo.LoadCallLog(callLogFile)
	if err != nil {
		panic(err)
	}

	h := &callHandler{
		modem:          m,
		filters:        filters,
		callLogFile:    callLogFile,
		callLog:        callLog,
		callLogChanged: make(chan struct{}),
	}

	return h
}

func (h *callHandler) Handle(c *hayes.Call) {
	call := &norobo.Call{Call: c}

	call.FilterResult = h.filters.Run(call)
	if call.FilterResult.Action == norobo.Block {
		call.Block()
	}

	h.log(call)
}

func (h *callHandler) CallLog() *norobo.CallLog {
	h.mu.RLock()
	defer h.mu.RUnlock()
	return h.callLog
}

func (h *callHandler) CallLogChanged(after time.Time) chan struct{} {
	h.mu.RLock()
	defer h.mu.RUnlock()
	changedCh := make(chan struct{})
	ch := h.callLogChanged
	go func() {
		for {
			<-ch

			h.mu.RLock()
			changed := h.callLog.LastTime().After(after)

			if changed {
				close(changedCh)
				h.mu.RUnlock()
				return
			}

			ch = h.callLogChanged
			h.mu.RUnlock()
		}
	}()

	return changedCh
}

func (h *callHandler) log(c *norobo.Call) {
	f, err := os.OpenFile(h.callLogFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0770)
	if err != nil {
		println(err)
		return
	}
	defer f.Close()
	r := c.FilterResult
	w := csv.NewWriter(f)
	msg := []string{c.Time.Format(time.RFC3339Nano), c.Name, c.Number, r.Action.String(), r.FilterDescription(), r.Description}

	h.mu.Lock()
	call := &norobo.CallEntry{
		Time:   c.Time,
		Name:   c.Name,
		Number: c.Number,
		Action: r.Action.String(),
		Filter: r.FilterDescription(),
		Reason: r.Description,
	}

	h.callLog.Calls = append(h.callLog.Calls, call)
	close(h.callLogChanged)
	h.callLogChanged = make(chan struct{})
	h.mu.Unlock()

	if err := w.Write(msg); err != nil {
		println(err)
	}
	w.Flush()
	fmt.Println(call)
}

func check(err error) {
	if err != nil {
		println(err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom_test

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	. "github.com/FactomProject/factom"

	"testing"
)

func TestGetMultipleFCTBalances(t *testing.T) {
	badfa := "abcdef"
	if bs, err := GetMultipleFCTBalances(badfa); err != nil {
		t.Error(err)
	} else if bs.Balances[0].Err != "Error decoding address" {
		t.Error("should have recieved error for bad address instead got", err)
	}
	fas := []string{
		"FA1y5ZGuHSLmf2TqNf6hVMkPiNGyQpQDTFJvDLRkKQaoPo4bmbgu",
		"FA1y5ZGuHSLmf2TqNf6hVMkPiNGyQpQDTFJvDLRkKQaoPo4bmbgu",
		"FA3upjWMKHmStAHR5ZgKVK4zVHPb8U74L2wzKaaSDQEonHajiLeq",
	}
	bs, err := GetMultipleFCTBalances(fas...)
	if err != nil {
		t.Error(err)
	}
	t.Log(bs)
}

func TestGetMultipleECBalances(t *testing.T) {
	badec := "abcdef"
	if bs, err := GetMultipleECBalances(badec); err != nil {
		t.Error(err)
	} else if bs.Balances[0].Err != "Error decoding address" {
		t.Error("should have recieved error for bad address instead got", err)
	}
	ecs := []string{
		"EC1m9mouvUQeEidmqpUYpYtXg8fvTYi6GNHaKg8KMLbdMBrFfmUa",
		"EC1m9mouvUQeEidmqpUYpYtXg8fvTYi6GNHaKg8KMLbdMBrFfmUa",
		"EC3htx3MxKqKTrTMYj4ApWD8T3nYBCQw99veRvH1FLFdjgN6GuNK",
	}
	bs, err := GetMultipleECBalances(ecs...)
	if err != nil {
		t.Error(err)
	}
	t.Log(bs)
}

func TestGetECBalance(t *testing.T) {
	factomdResponse := `{
      "jsonrpc": "2.0",
      "id": 0,
      "result": {
        "balance": 2000
      }
    }`

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, factomdResponse)
	}))
	defer ts.Close()

	SetFactomdServer(ts.URL[7:])

	response, _ := GetECBalance("EC3MAHiZyfuEb5fZP2fSp2gXMv8WemhQEUFXyQ2f2HjSkYx7xY1S")

	//fmt.Println(response)
	expectedResponse := int64(2000)

	if expectedResponse != response {
		fmt.Println(response)
		fmt.Println(expectedResponse)
		t.Fail()
	}
}

func TestGetFactoidBalance(t *testing.T) {
	factomdResponse := `{
      "jsonrpc": "2.0",
      "id": 0,
      "result": {
        "balance": 966582271
      }
    }`

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, factomdResponse)
	}))
	defer ts.Close()

	SetFactomdServer(ts.URL[7:])

	response, _ := GetFactoidBalance("FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q")

	//fmt.Println(response)
	expectedResponse := int64(966582271)

	if expectedResponse != response {
		fmt.Println(response)
		fmt.Println(expectedResponse)
		t.Fail()
	}
}
<commit_msg>updated tests for balances<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package factom_test

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	. "github.com/FactomProject/factom"

	"testing"
)

func TestGetMultipleFCTBalances(t *testing.T) {
	factomdResponse := `{
	  "jsonrpc": "2.0",
	  "id": 3,
	  "result": {
	    "currentheight": 192663,
	    "lastsavedheight": 192662,
	    "balances": [
	      {
	        "ack": 4008,
	        "saved": 4008,
	        "err": ""
	      }, {
	        "ack": 4008,
	        "saved": 4008,
	        "err": ""
	      }, {
	        "ack": 4,
	        "saved": 4,
	        "err": ""
	      }
	    ]
	  }
	}`
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, factomdResponse)
	}))
	defer ts.Close()

	SetFactomdServer(ts.URL[7:])

	fas := []string{
		"FA1y5ZGuHSLmf2TqNf6hVMkPiNGyQpQDTFJvDLRkKQaoPo4bmbgu",
		"FA1y5ZGuHSLmf2TqNf6hVMkPiNGyQpQDTFJvDLRkKQaoPo4bmbgu",
		"FA3upjWMKHmStAHR5ZgKVK4zVHPb8U74L2wzKaaSDQEonHajiLeq",
	}
	bs, err := GetMultipleFCTBalances(fas...)
	if err != nil {
		t.Error(err)
	}
	t.Log(bs)
}

func TestGetMultipleECBalances(t *testing.T) {
	factomdResponse := `{
	  "jsonrpc": "2.0",
	  "id": 4,
	  "result": {
	    "currentheight": 192663,
	    "lastsavedheight": 192662,
	    "balances": [
	      {
	        "ack": 4008,
	        "saved": 4008,
	        "err": ""
	      }, {
	        "ack": 4008,
	        "saved": 4008,
	        "err": ""
	      }, {
	        "ack": 4,
	        "saved": 4,
	        "err": ""
	      }
	    ]
	  }
	}`
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, factomdResponse)
	}))
	defer ts.Close()

	SetFactomdServer(ts.URL[7:])

	ecs := []string{
		"EC1m9mouvUQeEidmqpUYpYtXg8fvTYi6GNHaKg8KMLbdMBrFfmUa",
		"EC1m9mouvUQeEidmqpUYpYtXg8fvTYi6GNHaKg8KMLbdMBrFfmUa",
		"EC3htx3MxKqKTrTMYj4ApWD8T3nYBCQw99veRvH1FLFdjgN6GuNK",
	}
	bs, err := GetMultipleECBalances(ecs...)
	if err != nil {
		t.Error(err)
	}
	t.Log(bs)
}

func TestGetECBalance(t *testing.T) {
	factomdResponse := `{
      "jsonrpc": "2.0",
      "id": 0,
      "result": {
        "balance": 2000
      }
    }`

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, factomdResponse)
	}))
	defer ts.Close()

	SetFactomdServer(ts.URL[7:])

	response, _ := GetECBalance("EC3MAHiZyfuEb5fZP2fSp2gXMv8WemhQEUFXyQ2f2HjSkYx7xY1S")

	//fmt.Println(response)
	expectedResponse := int64(2000)

	if expectedResponse != response {
		fmt.Println(response)
		fmt.Println(expectedResponse)
		t.Fail()
	}
}

func TestGetFactoidBalance(t *testing.T) {
	factomdResponse := `{
      "jsonrpc": "2.0",
      "id": 0,
      "result": {
        "balance": 966582271
      }
    }`

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		fmt.Fprintln(w, factomdResponse)
	}))
	defer ts.Close()

	SetFactomdServer(ts.URL[7:])

	response, _ := GetFactoidBalance("FA2jK2HcLnRdS94dEcU27rF3meoJfpUcZPSinpb7AwQvPRY6RL1Q")

	//fmt.Println(response)
	expectedResponse := int64(966582271)

	if expectedResponse != response {
		fmt.Println(response)
		fmt.Println(expectedResponse)
		t.Fail()
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"

	d "github.com/mobingilabs/mocli/pkg/debug"
	"github.com/mobingilabs/mocli/pkg/util"
	"github.com/spf13/cobra"
)

var tokenCmd = &cobra.Command{
	Use:   "token",
	Short: "get registry token",
	Long:  `Get registry token.`,
	Run:   token,
}

func init() {
	registryCmd.AddCommand(tokenCmd)
	tokenCmd.Flags().String("account", "", "subuser name")
	tokenCmd.Flags().String("username", "", "username (account subuser)")
	tokenCmd.Flags().String("password", "", "password (account subuser)")
	tokenCmd.Flags().String("service", "Mobingi Docker Registry", "service for authentication")
	tokenCmd.Flags().String("scope", "", "scope for authentication")
}

func token(cmd *cobra.Command, args []string) {
	passin := false
	user := util.GetCliStringFlag(cmd, "username")
	pass := util.GetCliStringFlag(cmd, "password")
	if user == "" {
		user = util.Username()
	}

	if user == "" {
		util.CheckErrorExit("username cannot be empty", 1)
	}

	if pass == "" {
		pass = util.Password()
		passin = true
	}

	if pass == "" {
		util.CheckErrorExit("password cannot be empty", 1)
	}

	if passin {
		fmt.Println("\n") // new line after the password input
	}

	var Url *url.URL
	Url, err := url.Parse(util.GetCliStringFlag(cmd, "url"))
	if err != nil {
		util.CheckErrorExit(err, 1)
	}

	Url.Path += "/" + util.GetCliStringFlag(cmd, "apiver") + "/docker/token"
	parameters := url.Values{}
	acct := util.GetCliStringFlag(cmd, "account")
	if acct == "" {
		acct = user
	}

	svc := util.GetCliStringFlag(cmd, "service")
	scope := util.GetCliStringFlag(cmd, "scope")
	parameters.Add("account", acct)
	parameters.Add("service", svc)
	parameters.Add("scope", scope)
	Url.RawQuery = parameters.Encode()

	client := &http.Client{}
	req, err := http.NewRequest("GET", Url.String(), nil)
	if err != nil {
		util.CheckErrorExit(err, 1)
	}

	req.SetBasicAuth(user, pass)
	d.Info(fmt.Sprintf("Get token for subuser '%s' with service '%s' and scope of '%s'.", user, svc, scope))
	resp, err := client.Do(req)
	if err != nil {
		util.CheckErrorExit(err, 1)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		util.CheckErrorExit(err, 1)
	}

	// output raw for now
	fmt.Println(string(body))
}
<commit_msg>Format options for token output.<commit_after>package cmd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"

	d "github.com/mobingilabs/mocli/pkg/debug"
	"github.com/mobingilabs/mocli/pkg/util"
	"github.com/spf13/cobra"
)

var tokenCmd = &cobra.Command{
	Use:   "token",
	Short: "get registry token",
	Long:  `Get registry token.`,
	Run:   token,
}

func init() {
	registryCmd.AddCommand(tokenCmd)
	tokenCmd.Flags().String("account", "", "subuser name")
	tokenCmd.Flags().String("username", "", "username (account subuser)")
	tokenCmd.Flags().String("password", "", "password (account subuser)")
	tokenCmd.Flags().String("service", "Mobingi Docker Registry", "service for authentication")
	tokenCmd.Flags().String("scope", "", "scope for authentication")
}

func token(cmd *cobra.Command, args []string) {
	passin := false
	user := util.GetCliStringFlag(cmd, "username")
	pass := util.GetCliStringFlag(cmd, "password")
	if user == "" {
		user = util.Username()
	}

	if user == "" {
		util.CheckErrorExit("username cannot be empty", 1)
	}

	if pass == "" {
		pass = util.Password()
		passin = true
	}

	if pass == "" {
		util.CheckErrorExit("password cannot be empty", 1)
	}

	if passin {
		fmt.Println("\n") // new line after the password input
	}

	var Url *url.URL
	Url, err := url.Parse(util.GetCliStringFlag(cmd, "url"))
	if err != nil {
		util.CheckErrorExit(err, 1)
	}

	Url.Path += "/" + util.GetCliStringFlag(cmd, "apiver") + "/docker/token"
	parameters := url.Values{}
	acct := util.GetCliStringFlag(cmd, "account")
	if acct == "" {
		acct = user
	}

	svc := util.GetCliStringFlag(cmd, "service")
	scope := util.GetCliStringFlag(cmd, "scope")
	parameters.Add("account", acct)
	parameters.Add("service", svc)
	parameters.Add("scope", scope)
	Url.RawQuery = parameters.Encode()

	client := &http.Client{}
	req, err := http.NewRequest("GET", Url.String(), nil)
	if err != nil {
		util.CheckErrorExit(err, 1)
	}

	req.SetBasicAuth(user, pass)
	d.Info(fmt.Sprintf("Get token for subuser '%s' with service '%s' and scope '%s'.", user, svc, scope))
	resp, err := client.Do(req)
	if err != nil {
		util.CheckErrorExit(err, 1)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		util.CheckErrorExit(err, 1)
	}

	pfmt := util.GetCliStringFlag(cmd, "fmt")
	switch pfmt {
	case "raw":
		// output raw for now
		fmt.Println(string(body))
	default:
		var m map[string]interface{}
		err = json.Unmarshal(body, &m)
		if err != nil {
			util.CheckErrorExit(err, 1)
		}

		t, found := m["token"]
		if !found {
			// should not happen :)
			d.Error("cannot find token")
		}

		d.Info("token:", fmt.Sprintf("%s", t))
	}
}
<|endoftext|>