<commit_before>package router

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"io"
	"sync"
)

type Peers struct {
	sync.RWMutex
	ourself *LocalPeer
	table   map[PeerName]*Peer
	onGC    func(*Peer)
}

type UnknownPeerError struct {
	Name PeerName
}

type NameCollisionError struct {
	Name PeerName
}

type PeerNameSet map[PeerName]struct{}

type PeerSummary struct {
	NameByte []byte
	NickName string
	UID      PeerUID
	Version  uint64
}

type ConnectionSummary struct {
	NameByte      []byte
	RemoteTCPAddr string
	Outbound      bool
	Established   bool
}

func NewPeers(ourself *LocalPeer, onGC func(*Peer)) *Peers {
	return &Peers{
		ourself: ourself,
		table:   make(map[PeerName]*Peer),
		onGC:    onGC}
}

func (peers *Peers) FetchWithDefault(peer *Peer) *Peer {
	peers.Lock()
	defer peers.Unlock()
	if existingPeer, found := peers.table[peer.Name]; found {
		if existingPeer.UID != peer.UID {
			return nil
		}
		existingPeer.localRefCount++
		return existingPeer
	}
	peers.table[peer.Name] = peer
	peer.localRefCount++
	return peer
}

func (peers *Peers) Fetch(name PeerName) (*Peer, bool) {
	peers.RLock()
	defer peers.RUnlock()
	peer, found := peers.table[name]
	return peer, found // GRRR, why can't I inline this!?
}

func (peers *Peers) Dereference(peer *Peer) {
	peers.Lock()
	defer peers.Unlock()
	peer.localRefCount--
}

func (peers *Peers) ForEach(fun func(*Peer)) {
	peers.RLock()
	defer peers.RUnlock()
	for _, peer := range peers.table {
		fun(peer)
	}
}

// Merge an incoming update with our own topology.
//
// We add peers hitherto unknown to us, and update peers for which the
// update contains a more recent version than known to us. The return
// value is a) a representation of the received update, and b) an
// "improved" update containing just these new/updated elements.
func (peers *Peers) ApplyUpdate(update []byte) (PeerNameSet, PeerNameSet, error) {
	peers.Lock()

	newPeers, decodedUpdate, decodedConns, err := peers.decodeUpdate(update)
	if err != nil {
		peers.Unlock()
		return nil, nil, err
	}

	// By this point, we know the update doesn't refer to any peers we
	// have no knowledge of. We can now apply the update. Start by
	// adding in any new peers into the cache.
	for name, newPeer := range newPeers {
		peers.table[name] = newPeer
	}

	// Now apply the updates
	newUpdate := peers.applyUpdate(decodedUpdate, decodedConns)

	for _, peerRemoved := range peers.garbageCollect() {
		delete(newUpdate, peerRemoved.Name)
	}

	// Don't need to hold peers lock any longer
	peers.Unlock()

	updateNames := make(PeerNameSet)
	for _, peer := range decodedUpdate {
		updateNames[peer.Name] = void
	}
	return updateNames, setFromPeersMap(newUpdate), nil
}

func (peers *Peers) Names() PeerNameSet {
	peers.RLock()
	defer peers.RUnlock()
	return setFromPeersMap(peers.table)
}

func (peers *Peers) EncodePeers(names PeerNameSet) []byte {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	peers.RLock()
	defer peers.RUnlock()
	peerList := make([]*Peer, 0, len(names))
	for name := range names {
		if peer, found := peers.table[name]; found {
			if peer == peers.ourself.Peer {
				peers.ourself.Peer.Encode(enc)
			} else {
				peer.Encode(enc)
			}
			peerList = append(peerList, peer)
		}
	}
	return buf.Bytes()
}

func (peers *Peers) GarbageCollect() []*Peer {
	peers.Lock()
	defer peers.Unlock()
	return peers.garbageCollect()
}

func (peers *Peers) String() string {
	var buf bytes.Buffer
	printConnection := func(conn Connection) {
		established := ""
		if !conn.Established() {
			established = " (unestablished)"
		}
		fmt.Fprintf(&buf, "   -> %s [%v%s]\n", conn.Remote(), conn.RemoteTCPAddr(), established)
	}
	peers.ForEach(func(peer *Peer) {
		if peer == peers.ourself.Peer {
			fmt.Fprintln(&buf, peers.ourself.Info())
			for conn := range peers.ourself.Connections() {
				printConnection(conn)
			}
		} else {
			fmt.Fprintln(&buf, peer.Info())
			// Modifying peer.connections requires a write lock on
			// Peers, and since we are holding a read lock (due to the
			// ForEach), access without locking the peer is safe.
			for _, conn := range peer.connections {
				printConnection(conn)
			}
		}
	})
	return buf.String()
}

func (peers *Peers) garbageCollect() []*Peer {
	removed := []*Peer{}
	peers.ourself.RLock()
	_, reached := peers.ourself.Routes(nil, false)
	peers.ourself.RUnlock()
	for name, peer := range peers.table {
		if _, found := reached[peer.Name]; !found && peer.localRefCount == 0 {
			delete(peers.table, name)
			peers.onGC(peer)
			removed = append(removed, peer)
		}
	}
	return removed
}

func setFromPeersMap(peers map[PeerName]*Peer) PeerNameSet {
	names := make(PeerNameSet)
	for name := range peers {
		names[name] = void
	}
	return names
}

func (peers *Peers) decodeUpdate(update []byte) (newPeers map[PeerName]*Peer, decodedUpdate []*Peer, decodedConns [][]ConnectionSummary, err error) {
	newPeers = make(map[PeerName]*Peer)
	decodedUpdate = []*Peer{}
	decodedConns = [][]ConnectionSummary{}

	updateBuf := new(bytes.Buffer)
	updateBuf.Write(update)
	decoder := gob.NewDecoder(updateBuf)

	for {
		peerSummary, connSummaries, decErr := decodePeer(decoder)
		if decErr == io.EOF {
			break
		} else if decErr != nil {
			err = decErr
			return
		}
		name := PeerNameFromBin(peerSummary.NameByte)
		newPeer := NewPeer(name, peerSummary.NickName, peerSummary.UID, peerSummary.Version)
		decodedUpdate = append(decodedUpdate, newPeer)
		decodedConns = append(decodedConns, connSummaries)
		existingPeer, found := peers.table[name]
		if !found {
			newPeers[name] = newPeer
		} else if existingPeer.UID != newPeer.UID {
			err = NameCollisionError{Name: newPeer.Name}
			return
		}
	}

	for _, connSummaries := range decodedConns {
		for _, connSummary := range connSummaries {
			remoteName := PeerNameFromBin(connSummary.NameByte)
			if _, found := newPeers[remoteName]; found {
				continue
			}
			if _, found := peers.table[remoteName]; found {
				continue
			}
			// Update refers to a peer which we have no knowledge
			// of. Thus we can't apply the update. Abort.
			err = UnknownPeerError{remoteName}
			return
		}
	}
	return
}

func (peers *Peers) applyUpdate(decodedUpdate []*Peer, decodedConns [][]ConnectionSummary) map[PeerName]*Peer {
	newUpdate := make(map[PeerName]*Peer)
	for idx, newPeer := range decodedUpdate {
		connSummaries := decodedConns[idx]
		name := newPeer.Name
		// guaranteed to find peer in the peers.table
		peer := peers.table[name]
		if peer != newPeer &&
			(peer == peers.ourself.Peer || peer.version >= newPeer.version) {
			// Nobody but us updates us. And if we know more about a
			// peer than what's in the the update, we ignore the
			// latter.
			continue
		}
		// If we're here, either it was a new peer, or the update has
		// more info about the peer than we do. Either case, we need
		// to set version and conns and include the updated peer in
		// the outgoing update.

		// Can peer have been updated by anyone else in the mean time?
		// No - we know that peer is not ourself, so the only prospect
		// for an update would be someone else calling
		// router.Peers.ApplyUpdate. But ApplyUpdate takes the Lock on
		// the router.Peers, so there can be no race here.
		peer.version = newPeer.version
		peer.connections = makeConnsMap(peer, connSummaries, peers.table)
		newUpdate[name] = peer
	}
	return newUpdate
}

func (peer *Peer) Encode(enc *gob.Encoder) {
	checkFatal(enc.Encode(PeerSummary{
		peer.NameByte,
		peer.NickName,
		peer.UID,
		peer.version}))

	connSummaries := []ConnectionSummary{}
	for _, conn := range peer.connections {
		connSummaries = append(connSummaries, ConnectionSummary{
			conn.Remote().NameByte,
			conn.RemoteTCPAddr(),
			conn.Outbound(),
			// DANGER holding rlock on peer, going to take rlock on conn
			conn.Established(),
		})
	}

	checkFatal(enc.Encode(connSummaries))
}

func (peer *LocalPeer) Encode(enc *gob.Encoder) {
	peer.RLock()
	defer peer.RUnlock()
	peer.Peer.Encode(enc)
}

func decodePeer(dec *gob.Decoder) (peerSummary PeerSummary, connSummaries []ConnectionSummary, err error) {
	if err = dec.Decode(&peerSummary); err != nil {
		return
	}
	if err = dec.Decode(&connSummaries); err != nil {
		return
	}
	return
}

func makeConnsMap(peer *Peer, connSummaries []ConnectionSummary, table map[PeerName]*Peer) map[PeerName]Connection {
	conns := make(map[PeerName]Connection)
	for _, connSummary := range connSummaries {
		name := PeerNameFromBin(connSummary.NameByte)
		remotePeer := table[name]
		conn := NewRemoteConnection(peer, remotePeer, connSummary.RemoteTCPAddr, connSummary.Outbound, connSummary.Established)
		conns[name] = conn
	}
	return conns
}
<commit_msg>Remove redundant variable<commit_after>package router

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"io"
	"sync"
)

type Peers struct {
	sync.RWMutex
	ourself *LocalPeer
	table   map[PeerName]*Peer
	onGC    func(*Peer)
}

type UnknownPeerError struct {
	Name PeerName
}

type NameCollisionError struct {
	Name PeerName
}

type PeerNameSet map[PeerName]struct{}

type PeerSummary struct {
	NameByte []byte
	NickName string
	UID      PeerUID
	Version  uint64
}

type ConnectionSummary struct {
	NameByte      []byte
	RemoteTCPAddr string
	Outbound      bool
	Established   bool
}

func NewPeers(ourself *LocalPeer, onGC func(*Peer)) *Peers {
	return &Peers{
		ourself: ourself,
		table:   make(map[PeerName]*Peer),
		onGC:    onGC}
}

func (peers *Peers) FetchWithDefault(peer *Peer) *Peer {
	peers.Lock()
	defer peers.Unlock()
	if existingPeer, found := peers.table[peer.Name]; found {
		if existingPeer.UID != peer.UID {
			return nil
		}
		existingPeer.localRefCount++
		return existingPeer
	}
	peers.table[peer.Name] = peer
	peer.localRefCount++
	return peer
}

func (peers *Peers) Fetch(name PeerName) (*Peer, bool) {
	peers.RLock()
	defer peers.RUnlock()
	peer, found := peers.table[name]
	return peer, found // GRRR, why can't I inline this!?
}

func (peers *Peers) Dereference(peer *Peer) {
	peers.Lock()
	defer peers.Unlock()
	peer.localRefCount--
}

func (peers *Peers) ForEach(fun func(*Peer)) {
	peers.RLock()
	defer peers.RUnlock()
	for _, peer := range peers.table {
		fun(peer)
	}
}

// Merge an incoming update with our own topology.
//
// We add peers hitherto unknown to us, and update peers for which the
// update contains a more recent version than known to us. The return
// value is a) a representation of the received update, and b) an
// "improved" update containing just these new/updated elements.
func (peers *Peers) ApplyUpdate(update []byte) (PeerNameSet, PeerNameSet, error) {
	peers.Lock()

	newPeers, decodedUpdate, decodedConns, err := peers.decodeUpdate(update)
	if err != nil {
		peers.Unlock()
		return nil, nil, err
	}

	// By this point, we know the update doesn't refer to any peers we
	// have no knowledge of. We can now apply the update. Start by
	// adding in any new peers into the cache.
	for name, newPeer := range newPeers {
		peers.table[name] = newPeer
	}

	// Now apply the updates
	newUpdate := peers.applyUpdate(decodedUpdate, decodedConns)

	for _, peerRemoved := range peers.garbageCollect() {
		delete(newUpdate, peerRemoved.Name)
	}

	// Don't need to hold peers lock any longer
	peers.Unlock()

	updateNames := make(PeerNameSet)
	for _, peer := range decodedUpdate {
		updateNames[peer.Name] = void
	}
	return updateNames, setFromPeersMap(newUpdate), nil
}

func (peers *Peers) Names() PeerNameSet {
	peers.RLock()
	defer peers.RUnlock()
	return setFromPeersMap(peers.table)
}

func (peers *Peers) EncodePeers(names PeerNameSet) []byte {
	buf := new(bytes.Buffer)
	enc := gob.NewEncoder(buf)
	peers.RLock()
	defer peers.RUnlock()
	for name := range names {
		if peer, found := peers.table[name]; found {
			if peer == peers.ourself.Peer {
				peers.ourself.Peer.Encode(enc)
			} else {
				peer.Encode(enc)
			}
		}
	}
	return buf.Bytes()
}

func (peers *Peers) GarbageCollect() []*Peer {
	peers.Lock()
	defer peers.Unlock()
	return peers.garbageCollect()
}

func (peers *Peers) String() string {
	var buf bytes.Buffer
	printConnection := func(conn Connection) {
		established := ""
		if !conn.Established() {
			established = " (unestablished)"
		}
		fmt.Fprintf(&buf, "   -> %s [%v%s]\n", conn.Remote(), conn.RemoteTCPAddr(), established)
	}
	peers.ForEach(func(peer *Peer) {
		if peer == peers.ourself.Peer {
			fmt.Fprintln(&buf, peers.ourself.Info())
			for conn := range peers.ourself.Connections() {
				printConnection(conn)
			}
		} else {
			fmt.Fprintln(&buf, peer.Info())
			// Modifying peer.connections requires a write lock on
			// Peers, and since we are holding a read lock (due to the
			// ForEach), access without locking the peer is safe.
			for _, conn := range peer.connections {
				printConnection(conn)
			}
		}
	})
	return buf.String()
}

func (peers *Peers) garbageCollect() []*Peer {
	removed := []*Peer{}
	peers.ourself.RLock()
	_, reached := peers.ourself.Routes(nil, false)
	peers.ourself.RUnlock()
	for name, peer := range peers.table {
		if _, found := reached[peer.Name]; !found && peer.localRefCount == 0 {
			delete(peers.table, name)
			peers.onGC(peer)
			removed = append(removed, peer)
		}
	}
	return removed
}

func setFromPeersMap(peers map[PeerName]*Peer) PeerNameSet {
	names := make(PeerNameSet)
	for name := range peers {
		names[name] = void
	}
	return names
}

func (peers *Peers) decodeUpdate(update []byte) (newPeers map[PeerName]*Peer, decodedUpdate []*Peer, decodedConns [][]ConnectionSummary, err error) {
	newPeers = make(map[PeerName]*Peer)
	decodedUpdate = []*Peer{}
	decodedConns = [][]ConnectionSummary{}

	updateBuf := new(bytes.Buffer)
	updateBuf.Write(update)
	decoder := gob.NewDecoder(updateBuf)

	for {
		peerSummary, connSummaries, decErr := decodePeer(decoder)
		if decErr == io.EOF {
			break
		} else if decErr != nil {
			err = decErr
			return
		}
		name := PeerNameFromBin(peerSummary.NameByte)
		newPeer := NewPeer(name, peerSummary.NickName, peerSummary.UID, peerSummary.Version)
		decodedUpdate = append(decodedUpdate, newPeer)
		decodedConns = append(decodedConns, connSummaries)
		existingPeer, found := peers.table[name]
		if !found {
			newPeers[name] = newPeer
		} else if existingPeer.UID != newPeer.UID {
			err = NameCollisionError{Name: newPeer.Name}
			return
		}
	}

	for _, connSummaries := range decodedConns {
		for _, connSummary := range connSummaries {
			remoteName := PeerNameFromBin(connSummary.NameByte)
			if _, found := newPeers[remoteName]; found {
				continue
			}
			if _, found := peers.table[remoteName]; found {
				continue
			}
			// Update refers to a peer which we have no knowledge
			// of. Thus we can't apply the update. Abort.
			err = UnknownPeerError{remoteName}
			return
		}
	}
	return
}

func (peers *Peers) applyUpdate(decodedUpdate []*Peer, decodedConns [][]ConnectionSummary) map[PeerName]*Peer {
	newUpdate := make(map[PeerName]*Peer)
	for idx, newPeer := range decodedUpdate {
		connSummaries := decodedConns[idx]
		name := newPeer.Name
		// guaranteed to find peer in the peers.table
		peer := peers.table[name]
		if peer != newPeer &&
			(peer == peers.ourself.Peer || peer.version >= newPeer.version) {
			// Nobody but us updates us. And if we know more about a
			// peer than what's in the the update, we ignore the
			// latter.
			continue
		}
		// If we're here, either it was a new peer, or the update has
		// more info about the peer than we do. Either case, we need
		// to set version and conns and include the updated peer in
		// the outgoing update.

		// Can peer have been updated by anyone else in the mean time?
		// No - we know that peer is not ourself, so the only prospect
		// for an update would be someone else calling
		// router.Peers.ApplyUpdate. But ApplyUpdate takes the Lock on
		// the router.Peers, so there can be no race here.
		peer.version = newPeer.version
		peer.connections = makeConnsMap(peer, connSummaries, peers.table)
		newUpdate[name] = peer
	}
	return newUpdate
}

func (peer *Peer) Encode(enc *gob.Encoder) {
	checkFatal(enc.Encode(PeerSummary{
		peer.NameByte,
		peer.NickName,
		peer.UID,
		peer.version}))

	connSummaries := []ConnectionSummary{}
	for _, conn := range peer.connections {
		connSummaries = append(connSummaries, ConnectionSummary{
			conn.Remote().NameByte,
			conn.RemoteTCPAddr(),
			conn.Outbound(),
			// DANGER holding rlock on peer, going to take rlock on conn
			conn.Established(),
		})
	}

	checkFatal(enc.Encode(connSummaries))
}

func (peer *LocalPeer) Encode(enc *gob.Encoder) {
	peer.RLock()
	defer peer.RUnlock()
	peer.Peer.Encode(enc)
}

func decodePeer(dec *gob.Decoder) (peerSummary PeerSummary, connSummaries []ConnectionSummary, err error) {
	if err = dec.Decode(&peerSummary); err != nil {
		return
	}
	if err = dec.Decode(&connSummaries); err != nil {
		return
	}
	return
}

func makeConnsMap(peer *Peer, connSummaries []ConnectionSummary, table map[PeerName]*Peer) map[PeerName]Connection {
	conns := make(map[PeerName]Connection)
	for _, connSummary := range connSummaries {
		name := PeerNameFromBin(connSummary.NameByte)
		remotePeer := table[name]
		conn := NewRemoteConnection(peer, remotePeer, connSummary.RemoteTCPAddr, connSummary.Outbound, connSummary.Established)
		conns[name] = conn
	}
	return conns
}
<|endoftext|>


<commit_before>package netutil

import (
	"bytes"

	"gopkg.in/vmihailenco/msgpack.v2"
)

// MessagePackMsgPacker packs and unpacks message in MessagePack format
type MessagePackMsgPacker struct{}

// PackMsg packs message to bytes in MessagePack format
func (mp MessagePackMsgPacker) PackMsg(msg interface{}, buf []byte) ([]byte, error) {
	buffer := bytes.NewBuffer(buf)

	encoder := msgpack.NewEncoder(buffer)
	err := encoder.Encode(msg)
	if err != nil {
		return buf, err
	}
	buf = buffer.Bytes()
	return buf, nil
}

// UnpackMsg unpacksbytes in MessagePack format to message
func (mp MessagePackMsgPacker) UnpackMsg(data []byte, msg interface{}) error {
	err := msgpack.Unmarshal(data, msg)
	//if pv, ok := msg.(*interface{}); ok {
	//	*pv = mp.convertToStringKeys(*pv)
	//} else if pv, ok := msg.(*[]interface{}); ok {
	//	*pv = mp.convertToStringKeys(*pv).([]interface{})
	//} else if pv, ok := msg.(*map[string]interface{}); ok {
	//	*pv = mp.convertToStringKeys(*pv).(map[string]interface{})
	//} else if pv, ok := msg.(*map[interface{}]interface{}); ok {
	//	*pv = mp.convertToStringKeys(*pv).(map[interface{}]interface{})
	//}

	return err
}

//func (mp MessagePackMsgPacker) convertToStringKeys(v interface{}) interface{} {
//	defer func() {
//		err := recover()
//		if err != nil {
//			gwlog.Errorf("MessagePackMsgPacker.convertToStringKeys failed")
//			panic(err)
//		}
//	}()
//
//	if rv, ok := v.(map[interface{}]interface{}); ok {
//		rrv := make(map[string]interface{}, len(rv))
//		for k, _v := range rv {
//			ks, ok := k.(string)
//			if !ok {
//				gwlog.Panicf("%v is not string, but %T", k, k)
//			}
//
//			rrv[ks] = mp.convertToStringKeys(_v)
//		}
//		return rrv
//	}
//
//	if rv, ok := v.(map[string]interface{}); ok {
//		for k, _v := range rv {
//			rv[k] = mp.convertToStringKeys(_v)
//		}
//		return rv
//	}
//
//	if rv, ok := v.([]interface{}); ok {
//		for i, _v := range rv {
//			rv[i] = mp.convertToStringKeys(_v)
//		}
//		return rv
//	}
//
//	return v
//}
<commit_msg>convertToStringKeys not necessary anymore<commit_after>package netutil

import (
	"bytes"

	"gopkg.in/vmihailenco/msgpack.v2"
)

// MessagePackMsgPacker packs and unpacks message in MessagePack format
type MessagePackMsgPacker struct{}

// PackMsg packs message to bytes in MessagePack format
func (mp MessagePackMsgPacker) PackMsg(msg interface{}, buf []byte) ([]byte, error) {
	buffer := bytes.NewBuffer(buf)

	encoder := msgpack.NewEncoder(buffer)
	err := encoder.Encode(msg)
	if err != nil {
		return buf, err
	}
	buf = buffer.Bytes()
	return buf, nil
}

// UnpackMsg unpacksbytes in MessagePack format to message
func (mp MessagePackMsgPacker) UnpackMsg(data []byte, msg interface{}) error {
	err := msgpack.Unmarshal(data, msg)
	return err
}

//func (mp MessagePackMsgPacker) convertToStringKeys(v interface{}) interface{} {
//	defer func() {
//		err := recover()
//		if err != nil {
//			gwlog.Errorf("MessagePackMsgPacker.convertToStringKeys failed")
//			panic(err)
//		}
//	}()
//
//	if rv, ok := v.(map[interface{}]interface{}); ok {
//		rrv := make(map[string]interface{}, len(rv))
//		for k, _v := range rv {
//			ks, ok := k.(string)
//			if !ok {
//				gwlog.Panicf("%v is not string, but %T", k, k)
//			}
//
//			rrv[ks] = mp.convertToStringKeys(_v)
//		}
//		return rrv
//	}
//
//	if rv, ok := v.(map[string]interface{}); ok {
//		for k, _v := range rv {
//			rv[k] = mp.convertToStringKeys(_v)
//		}
//		return rv
//	}
//
//	if rv, ok := v.([]interface{}); ok {
//		for i, _v := range rv {
//			rv[i] = mp.convertToStringKeys(_v)
//		}
//		return rv
//	}
//
//	return v
//}
<|endoftext|>


<commit_before>package tests

import (
	"os"
	"testing"

	"github.com/ktrysmt/go-bitbucket"
)

var (
	user  = os.Getenv("BITBUCKET_TEST_USERNAME")
	pass  = os.Getenv("BITBUCKET_TEST_PASSWORD")
	owner = os.Getenv("BITBUCKET_TEST_OWNER")
	repo  = os.Getenv("BITBUCKET_TEST_REPOSLUG")
)

func setup(t *testing.T) *bitbucket.Client {

	if user == "" {
		t.Error("BITBUCKET_TEST_USERNAME is empty.")
	}
	if pass == "" {
		t.Error("BITBUCKET_TEST_PASSWORD is empty.")
	}
	if owner == "" {
		t.Error("BITBUCKET_TEST_OWNER is empty.")
	}
	if repo == "" {
		t.Error("BITBUCKET_TEST_REPOSLUG is empty.")
	}

	c := bitbucket.NewBasicAuth(user, pass)
	return c
}

func TestCreateBranchRestrictionsKindPush(t *testing.T) {

	c := setup(t)

	opt := &bitbucket.BranchRestrictionsOptions{
		Owner:    owner,
		Pattern:  "develop",
		RepoSlug: repo,
		Kind:     "push",
		Users:    []string{user},
	}
	res, err := c.Repositories.BranchRestrictions.Create(opt)
	if err != nil {
		t.Error(err)
	}
	jsonMap := res.(map[string]interface{})
	if jsonMap["type"] != "branchrestriction" {
		t.Error("is not branchrestriction type")
	}
	if jsonMap["kind"] != "push" {
		t.Error("did not match branchrestriction kind")
	}
}

func TestCreateBranchRestrictionsKindRequirePassingBuilds(t *testing.T) {

	c := setup(t)

	opt := &bitbucket.BranchRestrictionsOptions{
		Owner:    owner,
		Pattern:  "master",
		RepoSlug: repo,
		Kind:     "require_passing_builds_to_merge",
		Value:    2,
	}
	res, err := c.Repositories.BranchRestrictions.Create(opt)
	if err != nil {
		t.Error(err)
	}
	jsonMap := res.(map[string]interface{})
	if jsonMap["type"] != "branchrestriction" {
		t.Error("is not branchrestriction type")
	}
	if jsonMap["kind"] != "require_passing_builds_to_merge" {
		t.Error("did not match branchrestriction kind")
	}
}
<commit_msg>Remove type assertion as no longer an interface (#147)<commit_after>package tests

import (
	"os"
	"testing"

	"github.com/ktrysmt/go-bitbucket"
)

var (
	user  = os.Getenv("BITBUCKET_TEST_USERNAME")
	pass  = os.Getenv("BITBUCKET_TEST_PASSWORD")
	owner = os.Getenv("BITBUCKET_TEST_OWNER")
	repo  = os.Getenv("BITBUCKET_TEST_REPOSLUG")
)

func setup(t *testing.T) *bitbucket.Client {

	if user == "" {
		t.Error("BITBUCKET_TEST_USERNAME is empty.")
	}
	if pass == "" {
		t.Error("BITBUCKET_TEST_PASSWORD is empty.")
	}
	if owner == "" {
		t.Error("BITBUCKET_TEST_OWNER is empty.")
	}
	if repo == "" {
		t.Error("BITBUCKET_TEST_REPOSLUG is empty.")
	}

	c := bitbucket.NewBasicAuth(user, pass)
	return c
}

func TestCreateBranchRestrictionsKindPush(t *testing.T) {

	c := setup(t)

	opt := &bitbucket.BranchRestrictionsOptions{
		Owner:    owner,
		Pattern:  "develop",
		RepoSlug: repo,
		Kind:     "push",
		Users:    []string{user},
	}
	res, err := c.Repositories.BranchRestrictions.Create(opt)
	if err != nil {
		t.Error(err)
	}
	if res.Kind != "push" {
		t.Error("did not match branchrestriction kind")
	}
}

func TestCreateBranchRestrictionsKindRequirePassingBuilds(t *testing.T) {

	c := setup(t)

	opt := &bitbucket.BranchRestrictionsOptions{
		Owner:    owner,
		Pattern:  "master",
		RepoSlug: repo,
		Kind:     "require_passing_builds_to_merge",
		Value:    2,
	}
	res, err := c.Repositories.BranchRestrictions.Create(opt)
	if err != nil {
		t.Error(err)
	}
	if res.Kind != "require_passing_builds_to_merge" {
		t.Error("did not match branchrestriction kind")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/nsqio/go-nsq"
	"github.com/raintank/met/helper"
	"github.com/raintank/raintank-metric/metricdef"
	"github.com/raintank/raintank-metric/msg"
	"github.com/raintank/raintank-metric/schema"
	"testing"
)

func BenchmarkHandler_HandleMessage(b *testing.B) {
	stats, _ := helper.New(false, "", "standard", "metrics_tank", "")
	clusterStatus = NewClusterStatus("default", false)
	initMetrics(stats)

	store := NewDevnullStore()
	aggmetrics := NewAggMetrics(store, 600, 10, 800, 8000, 10000, make([]aggSetting, 0))
	defCache := NewDefCache(metricdef.NewDefsMock())
	handler := NewHandler(aggmetrics, defCache)

	metrics := make([]*schema.MetricData, 10)
	for i := 0; i < len(metrics); i++ {
		metrics[i] = &schema.MetricData{
			Id:         "some.id.of.a.metric",
			OrgId:      500,
			Name:       "some.id",
			Metric:     "metric",
			Interval:   60,
			Value:      1234.567,
			Unit:       "ms",
			Time:       int64(i - len(metrics) + 1),
			TargetType: "gauge",
			Tags:       []string{"some_tag", "ok"},
		}
	}
	// timestamps start at 1 and go up from there. (we can't use 0, see AggMetric.Add())
	msgs := make([]*nsq.Message, b.N)
	for i := 0; i < len(msgs); i++ {
		id := nsq.MessageID{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 's', 'd', 'f', 'g', 'h'}
		for j := 0; j < len(metrics); j++ {
			metrics[j].Time += 10
		}
		data, err := msg.CreateMsg(metrics, 1, msg.FormatMetricDataArrayMsgp)
		if err != nil {
			panic(err)
		}
		msgs[i] = nsq.NewMessage(id, data)
	}

	b.StartTimer()
	for i := 0; i < b.N; i++ {
		err := handler.HandleMessage(msgs[i])
		if err != nil {
			panic(err)
		}
	}
}
<commit_msg>fix: use ResetTimer to ignore impact of previous code<commit_after>package main

import (
	"github.com/nsqio/go-nsq"
	"github.com/raintank/met/helper"
	"github.com/raintank/raintank-metric/metricdef"
	"github.com/raintank/raintank-metric/msg"
	"github.com/raintank/raintank-metric/schema"
	"testing"
)

func BenchmarkHandler_HandleMessage(b *testing.B) {
	stats, _ := helper.New(false, "", "standard", "metrics_tank", "")
	clusterStatus = NewClusterStatus("default", false)
	initMetrics(stats)

	store := NewDevnullStore()
	aggmetrics := NewAggMetrics(store, 600, 10, 800, 8000, 10000, make([]aggSetting, 0))
	defCache := NewDefCache(metricdef.NewDefsMock())
	handler := NewHandler(aggmetrics, defCache)

	metrics := make([]*schema.MetricData, 10)
	for i := 0; i < len(metrics); i++ {
		metrics[i] = &schema.MetricData{
			Id:         "some.id.of.a.metric",
			OrgId:      500,
			Name:       "some.id",
			Metric:     "metric",
			Interval:   60,
			Value:      1234.567,
			Unit:       "ms",
			Time:       int64(i - len(metrics) + 1),
			TargetType: "gauge",
			Tags:       []string{"some_tag", "ok"},
		}
	}
	// timestamps start at 1 and go up from there. (we can't use 0, see AggMetric.Add())
	msgs := make([]*nsq.Message, b.N)
	for i := 0; i < len(msgs); i++ {
		id := nsq.MessageID{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 's', 'd', 'f', 'g', 'h'}
		for j := 0; j < len(metrics); j++ {
			metrics[j].Time += 10
		}
		data, err := msg.CreateMsg(metrics, 1, msg.FormatMetricDataArrayMsgp)
		if err != nil {
			panic(err)
		}
		msgs[i] = nsq.NewMessage(id, data)
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err := handler.HandleMessage(msgs[i])
		if err != nil {
			panic(err)
		}
	}
}
<|endoftext|>


<commit_before>package graphite

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/util/conn"
)

// Emitter is a struct to manage connections and orchestrate the emission of
// metrics to a Graphite system.
type Emitter struct {
	mtx        sync.Mutex
	prefix     string
	mgr        *conn.Manager
	counters   []*counter
	histograms []*windowedHistogram
	gauges     []*gauge
	logger     log.Logger
	quitc      chan chan struct{}
}

// NewEmitter will return an Emitter that will prefix all metrics names with the
// given prefix. Once started, it will attempt to create a connection with the
// given network and address via `net.Dial` and periodically post metrics to the
// connection in the Graphite plaintext protocol.
func NewEmitter(network, address string, metricsPrefix string, flushInterval time.Duration, logger log.Logger) *Emitter {
	return NewEmitterDial(net.Dial, network, address, metricsPrefix, flushInterval, logger)
}

// NewEmitterDial is the same as NewEmitter, but allows you to specify your own
// Dialer function. This is primarily useful for tests.
func NewEmitterDial(dialer conn.Dialer, network, address string, metricsPrefix string, flushInterval time.Duration, logger log.Logger) *Emitter {
	e := &Emitter{
		prefix: metricsPrefix,
		mgr:    conn.NewManager(dialer, network, address, time.After, logger),
		logger: logger,
		quitc:  make(chan chan struct{}),
	}
	go e.loop(flushInterval)
	return e
}

// NewCounter returns a Counter whose value will be periodically emitted in
// a Graphite-compatible format once the Emitter is started. Fields are ignored.
func (e *Emitter) NewCounter(name string) metrics.Counter {
	e.mtx.Lock()
	defer e.mtx.Unlock()
	c := newCounter(name)
	e.counters = append(e.counters, c)
	return c
}

// NewHistogram is taken from http://github.com/codahale/metrics. It returns a
// windowed HDR histogram which drops data older than five minutes.
//
// The histogram exposes metrics for each passed quantile as gauges. Quantiles
// should be integers in the range 1..99. The gauge names are assigned by using
// the passed name as a prefix and appending "_pNN" e.g. "_p50".
//
// The values of this histogram will be periodically emitted in a
// Graphite-compatible format once the Emitter is started. Fields are ignored.
func (e *Emitter) NewHistogram(name string, minValue, maxValue int64, sigfigs int, quantiles ...int) (metrics.Histogram, error) {
	gauges := map[int]metrics.Gauge{}
	for _, quantile := range quantiles {
		if quantile <= 0 || quantile >= 100 {
			return nil, fmt.Errorf("invalid quantile %d", quantile)
		}
		gauges[quantile] = e.gauge(fmt.Sprintf("%s_p%02d", name, quantile))
	}
	h := newWindowedHistogram(name, minValue, maxValue, sigfigs, gauges, e.logger)

	e.mtx.Lock()
	defer e.mtx.Unlock()
	e.histograms = append(e.histograms, h)
	return h, nil
}

// NewGauge returns a Gauge whose value will be periodically emitted in a
// Graphite-compatible format once the Emitter is started. Fields are ignored.
func (e *Emitter) NewGauge(name string) metrics.Gauge {
	e.mtx.Lock()
	defer e.mtx.Unlock()
	return e.gauge(name)
}

func (e *Emitter) gauge(name string) metrics.Gauge {
	g := &gauge{name, 0}
	e.gauges = append(e.gauges, g)
	return g
}

func (e *Emitter) loop(d time.Duration) {
	ticker := time.NewTicker(d)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			e.Flush()

		case q := <-e.quitc:
			e.Flush()
			close(q)
			return
		}
	}
}

// Stop will flush the current metrics and close the active connection. Calling
// stop more than once is a programmer error.
func (e *Emitter) Stop() {
	q := make(chan struct{})
	e.quitc <- q
	<-q
}

// Flush will write the current metrics to the Emitter's connection in the
// Graphite plaintext protocol.
func (e *Emitter) Flush() {
	e.mtx.Lock() // one flush at a time
	defer e.mtx.Unlock()

	conn := e.mgr.Take()
	if conn == nil {
		e.logger.Log("during", "flush", "err", "connection unavailable")
		return
	}

	err := e.flush(conn)
	if err != nil {
		e.logger.Log("during", "flush", "err", err)
	}
	e.mgr.Put(err)
}

func (e *Emitter) flush(conn io.Writer) error {
	w := bufio.NewWriter(conn)

	for _, c := range e.counters {
		c.flush(w, e.prefix)
	}

	for _, h := range e.histograms {
		h.flush(w, e.prefix)
	}

	for _, g := range e.gauges {
		g.flush(w, e.prefix)
	}

	return w.Flush()
}
<commit_msg>code review  cleanup<commit_after>package graphite

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"sync"
	"time"

	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/util/conn"
)

// Emitter is a struct to manage connections and orchestrate the emission of
// metrics to a Graphite system.
type Emitter struct {
	mtx        sync.Mutex
	prefix     string
	mgr        *conn.Manager
	counters   []*counter
	histograms []*windowedHistogram
	gauges     []*gauge
	logger     log.Logger
	quitc      chan chan struct{}
}

// NewEmitter will return an Emitter that will prefix all metrics names with the
// given prefix. Once started, it will attempt to create a connection with the
// given network and address via `net.Dial` and periodically post metrics to the
// connection in the Graphite plaintext protocol.
func NewEmitter(network, address string, metricsPrefix string, flushInterval time.Duration, logger log.Logger) *Emitter {
	return NewEmitterDial(net.Dial, network, address, metricsPrefix, flushInterval, logger)
}

// NewEmitterDial is the same as NewEmitter, but allows you to specify your own
// Dialer function. This is primarily useful for tests.
func NewEmitterDial(dialer conn.Dialer, network, address string, metricsPrefix string, flushInterval time.Duration, logger log.Logger) *Emitter {
	e := &Emitter{
		prefix: metricsPrefix,
		mgr:    conn.NewManager(dialer, network, address, time.After, logger),
		logger: logger,
		quitc:  make(chan chan struct{}),
	}
	go e.loop(flushInterval)
	return e
}

// NewCounter returns a Counter whose value will be periodically emitted in
// a Graphite-compatible format once the Emitter is started. Fields are ignored.
func (e *Emitter) NewCounter(name string) metrics.Counter {
	e.mtx.Lock()
	defer e.mtx.Unlock()
	c := newCounter(name)
	e.counters = append(e.counters, c)
	return c
}

// NewHistogram is taken from http://github.com/codahale/metrics. It returns a
// windowed HDR histogram which drops data older than five minutes.
//
// The histogram exposes metrics for each passed quantile as gauges. Quantiles
// should be integers in the range 1..99. The gauge names are assigned by using
// the passed name as a prefix and appending "_pNN" e.g. "_p50".
//
// The values of this histogram will be periodically emitted in a
// Graphite-compatible format once the Emitter is started. Fields are ignored.
func (e *Emitter) NewHistogram(name string, minValue, maxValue int64, sigfigs int, quantiles ...int) (metrics.Histogram, error) {
	gauges := map[int]metrics.Gauge{}
	for _, quantile := range quantiles {
		if quantile <= 0 || quantile >= 100 {
			return nil, fmt.Errorf("invalid quantile %d", quantile)
		}
		gauges[quantile] = e.gauge(fmt.Sprintf("%s_p%02d", name, quantile))
	}
	h := newWindowedHistogram(name, minValue, maxValue, sigfigs, gauges, e.logger)

	e.mtx.Lock()
	defer e.mtx.Unlock()
	e.histograms = append(e.histograms, h)
	return h, nil
}

// NewGauge returns a Gauge whose value will be periodically emitted in a
// Graphite-compatible format once the Emitter is started. Fields are ignored.
func (e *Emitter) NewGauge(name string) metrics.Gauge {
	e.mtx.Lock()
	defer e.mtx.Unlock()
	return e.gauge(name)
}

func (e *Emitter) gauge(name string) metrics.Gauge {
	g := &gauge{name, 0}
	e.gauges = append(e.gauges, g)
	return g
}

func (e *Emitter) loop(d time.Duration) {
	ticker := time.NewTicker(d)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			e.Flush()

		case q := <-e.quitc:
			e.Flush()
			close(q)
			return
		}
	}
}

// Stop will flush the current metrics and close the active connection. Calling
// stop more than once is a programmer error.
func (e *Emitter) Stop() {
	q := make(chan struct{})
	e.quitc <- q
	<-q
}

// Flush will write the current metrics to the Emitter's connection in the
// Graphite plaintext protocol.
func (e *Emitter) Flush() {
	e.mtx.Lock() // one flush at a time
	defer e.mtx.Unlock()

	conn := e.mgr.Take()
	if conn == nil {
		e.logger.Log("during", "flush", "err", "connection unavailable")
		return
	}

	err := e.flush(conn)
	if err != nil {
		e.logger.Log("during", "flush", "err", err)
	}
	e.mgr.Put(err)
}

func (e *Emitter) flush(w io.Writer) error {
	bw := bufio.NewWriter(w)

	for _, c := range e.counters {
		c.flush(bw, e.prefix)
	}

	for _, h := range e.histograms {
		h.flush(bw, e.prefix)
	}

	for _, g := range e.gauges {
		g.flush(bw, e.prefix)
	}

	return bw.Flush()
}
<|endoftext|>


<commit_before>// +build windows

package windows

import (
	"syscall"
	"unsafe"

	"github.com/mackerelio/mackerel-agent/logging"
	"github.com/mackerelio/mackerel-agent/metrics"
	"github.com/mackerelio/mackerel-agent/util/windows"
)

// CPUUsageGenerator is struct of windows api
type CPUUsageGenerator struct {
	query    syscall.Handle
	counters []*windows.CounterInfo
}

var cpuUsageLogger = logging.GetLogger("cpu.user.percentage")

// NewCPUUsageGenerator is set up windows api
func NewCPUUsageGenerator() (*CPUUsageGenerator, error) {
	g := &CPUUsageGenerator{0, nil}

	var err error
	g.query, err = windows.CreateQuery()
	if err != nil {
		cpuUsageLogger.Criticalf(err.Error())
		return nil, err
	}
	var counter *windows.CounterInfo

	counter, err = windows.CreateCounter(g.query, "cpu.user.percentage", `\Processor(_Total)\% User Time`)
	if err != nil {
		cpuUsageLogger.Criticalf(err.Error())
		return nil, err
	}
	g.counters = append(g.counters, counter)

	counter, err = windows.CreateCounter(g.query, "cpu.system.percentage", `\Processor(_Total)\% Privileged Time`)
	if err != nil {
		cpuUsageLogger.Criticalf(err.Error())
		return nil, err
	}
	g.counters = append(g.counters, counter)

	counter, err = windows.CreateCounter(g.query, "cpu.idle.percentage", `\Processor(_Total)\% Idle Time`)
	if err != nil {
		cpuUsageLogger.Criticalf(err.Error())
		return nil, err
	}
	g.counters = append(g.counters, counter)
	return g, nil
}

// Generate XXX
func (g *CPUUsageGenerator) Generate() (metrics.Values, error) {

	r, _, err := windows.PdhCollectQueryData.Call(uintptr(g.query))
	if r != 0 && err != nil {
		if r == windows.PDH_NO_DATA {
			cpuUsageLogger.Infof("this metric has not data. ")
			return nil, err
		}
		return nil, err
	}

	results := make(map[string]float64)
	sumPercentage := float64(0)
	for _, v := range g.counters {
		var fmtValue windows.PDH_FMT_COUNTERVALUE_DOUBLE
		r, _, err := windows.PdhGetFormattedCounterValue.Call(uintptr(v.Counter), windows.PDH_FMT_DOUBLE, uintptr(0), uintptr(unsafe.Pointer(&fmtValue)))
		if r != 0 && r != windows.PDH_INVALID_DATA {
			return nil, err
		}
		results[v.PostName] = fmtValue.DoubleValue
		sumPercentage += fmtValue.DoubleValue
	}

	cpuUsageLogger.Debugf("cpuusage: %q", results)

	return results, nil
}
<commit_msg>delete unnecessary variable<commit_after>// +build windows

package windows

import (
	"syscall"
	"unsafe"

	"github.com/mackerelio/mackerel-agent/logging"
	"github.com/mackerelio/mackerel-agent/metrics"
	"github.com/mackerelio/mackerel-agent/util/windows"
)

// CPUUsageGenerator is struct of windows api
type CPUUsageGenerator struct {
	query    syscall.Handle
	counters []*windows.CounterInfo
}

var cpuUsageLogger = logging.GetLogger("cpu.user.percentage")

// NewCPUUsageGenerator is set up windows api
func NewCPUUsageGenerator() (*CPUUsageGenerator, error) {
	g := &CPUUsageGenerator{0, nil}

	var err error
	g.query, err = windows.CreateQuery()
	if err != nil {
		cpuUsageLogger.Criticalf(err.Error())
		return nil, err
	}
	var counter *windows.CounterInfo

	counter, err = windows.CreateCounter(g.query, "cpu.user.percentage", `\Processor(_Total)\% User Time`)
	if err != nil {
		cpuUsageLogger.Criticalf(err.Error())
		return nil, err
	}
	g.counters = append(g.counters, counter)

	counter, err = windows.CreateCounter(g.query, "cpu.system.percentage", `\Processor(_Total)\% Privileged Time`)
	if err != nil {
		cpuUsageLogger.Criticalf(err.Error())
		return nil, err
	}
	g.counters = append(g.counters, counter)

	counter, err = windows.CreateCounter(g.query, "cpu.idle.percentage", `\Processor(_Total)\% Idle Time`)
	if err != nil {
		cpuUsageLogger.Criticalf(err.Error())
		return nil, err
	}
	g.counters = append(g.counters, counter)
	return g, nil
}

// Generate XXX
func (g *CPUUsageGenerator) Generate() (metrics.Values, error) {

	r, _, err := windows.PdhCollectQueryData.Call(uintptr(g.query))
	if r != 0 && err != nil {
		if r == windows.PDH_NO_DATA {
			cpuUsageLogger.Infof("this metric has not data. ")
			return nil, err
		}
		return nil, err
	}

	results := make(map[string]float64)
	for _, v := range g.counters {
		var fmtValue windows.PDH_FMT_COUNTERVALUE_DOUBLE
		r, _, err := windows.PdhGetFormattedCounterValue.Call(uintptr(v.Counter), windows.PDH_FMT_DOUBLE, uintptr(0), uintptr(unsafe.Pointer(&fmtValue)))
		if r != 0 && r != windows.PDH_INVALID_DATA {
			return nil, err
		}
		results[v.PostName] = fmtValue.DoubleValue
	}

	cpuUsageLogger.Debugf("cpuusage: %q", results)

	return results, nil
}
<|endoftext|>


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

// +build java android nacl wspr
//
// We only expose the functionality below for the above build tags, to
// discourage general usage.  The binaries that currently require this
// functionality are our langage proxies:
//   java/android: jni
//   nacl:         browspr (for JavaScript)
//   wsprd:        wsprd (for JavaScript)

package security

import (
	"v.io/v23/context"
)

// OverrideCaveatValidation overrides the validation mechanism for all caveats;
// e.g. for use in proxies that delegate caveat validation to another process.
// It may be called at most once in an address space; subsequent calls with
// panic.
//
// The given fn is used to validate sets of caveats in RemoteBlessingNames,
// where the fn is invoked with the context and call representing the current
// security state, along with the sets of caveats to validate.  It should return
// a slice of errors where len(sets) == len(errors), and errors[x] corresponds
// to the result of validating sets[x].
//
// WARNING: This is not meant as a general API, and may change without notice.
// It is restricted to specific build tags to discourage general usage.
func OverrideCaveatValidation(fn func(ctx *context.T, call Call, sets [][]Caveat) []error) {
	overrideCaveatValidation(fn)
}
<commit_msg>v23: remove references to wspr: servicerunner & security<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build java android
//
// We only expose the functionality below for the above build tags, to
// discourage general usage.  The binaries that currently require this
// functionality are our langage proxies:
//   java/android: jni

package security

import (
	"v.io/v23/context"
)

// OverrideCaveatValidation overrides the validation mechanism for all caveats;
// e.g. for use in proxies that delegate caveat validation to another process.
// It may be called at most once in an address space; subsequent calls with
// panic.
//
// The given fn is used to validate sets of caveats in RemoteBlessingNames,
// where the fn is invoked with the context and call representing the current
// security state, along with the sets of caveats to validate.  It should return
// a slice of errors where len(sets) == len(errors), and errors[x] corresponds
// to the result of validating sets[x].
//
// WARNING: This is not meant as a general API, and may change without notice.
// It is restricted to specific build tags to discourage general usage.
func OverrideCaveatValidation(fn func(ctx *context.T, call Call, sets [][]Caveat) []error) {
	overrideCaveatValidation(fn)
}
<|endoftext|>


<commit_before>/*
	This file is part of go-ethereum

	go-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	go-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/*

For each request type, define the following:

1. RpcRequest "To" method [message.go], which does basic validation and conversion to "Args" type via json.Decoder()
2. json.Decoder() calls "UnmarshalON" defined on each "Args" struct
3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to ON

*/
package rpc

import (
	"fmt"
	"math/big"
	"strings"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/xeth"
)

type RpcServer interface {
	Start()
	Stop()
}

func NewEthereumApi(xeth *xeth.XEth) *EthereumApi {
	return &EthereumApi{xeth: xeth}
}

type EthereumApi struct {
	xeth *xeth.XEth
}

func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}

	if args.BlockNumber > 0 {
		*reply = p.xeth.BlockByNumber(args.BlockNumber)
	} else {
		*reply = p.xeth.BlockByHash(args.Hash)
	}
	return nil
}

func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	result, _ := p.xeth.Transact( /* TODO specify account */ args.Recipient, args.Value, args.Gas, args.GasPrice, args.Data)
	fmt.Println("result:", result)
	*reply = result
	return nil
}

func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error {
	err := args.requirementsContract()
	if err != nil {
		return err
	}

	result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Value, args.Gas, args.GasPrice, args.Data)
	*reply = result
	return nil
}

func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
	err := args.requirementsPushTx()
	if err != nil {
		return err
	}
	result, _ := p.xeth.PushTx(args.Tx)
	*reply = result
	return nil
}

func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}

	state := p.xeth.State().SafeGet(args.Address)

	var hx string
	if strings.Index(args.Key, "0x") == 0 {
		hx = string([]byte(args.Key)[2:])
	} else {
		// Convert the incoming string (which is a bigint) into hex
		i, _ := new(big.Int).SetString(args.Key, 10)
		hx = ethutil.Bytes2Hex(i.Bytes())
	}
	rpclogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx)
	value := state.Storage(ethutil.Hex2Bytes(hx))
	*reply = GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()}
	return nil
}

func (p *EthereumApi) GetPeerCount(reply *interface{}) error {
	*reply = p.xeth.PeerCount()
	return nil
}

func (p *EthereumApi) GetIsListening(reply *interface{}) error {
	*reply = p.xeth.IsListening()
	return nil
}

func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
	*reply = p.xeth.Coinbase()
	return nil
}

func (p *EthereumApi) GetIsMining(reply *interface{}) error {
	*reply = p.xeth.IsMining()
	return nil
}

func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	*reply = p.xeth.TxCountAt(args.Address)
	return nil
}

func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	state := p.xeth.State().SafeGet(args.Address)
	*reply = BalanceRes{Balance: state.Balance().String(), Address: args.Address}
	return nil
}

func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	*reply = p.xeth.CodeAt(args.Address)
	return nil
}

func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error {
	*reply = ethutil.Bytes2Hex(crypto.Sha3(ethutil.Hex2Bytes(args.Data)))
	return nil
}

func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
	// Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC
	rpclogger.DebugDetailf("%T %s", req.Params, req.Params)
	switch req.Method {
	case "eth_coinbase":
		return p.GetCoinbase(reply)
	case "eth_listening":
		return p.GetIsListening(reply)
	case "eth_mining":
		return p.GetIsMining(reply)
	case "eth_peerCount":
		return p.GetPeerCount(reply)
	case "eth_countAt":
		args, err := req.ToGetTxCountArgs()
		if err != nil {
			return err
		}
		return p.GetTxCountAt(args, reply)
	case "eth_codeAt":
		args, err := req.ToGetCodeAtArgs()
		if err != nil {
			return err
		}
		return p.GetCodeAt(args, reply)
	case "eth_balanceAt":
		args, err := req.ToGetBalanceArgs()
		if err != nil {
			return err
		}
		return p.GetBalanceAt(args, reply)
	case "eth_stateAt":
		args, err := req.ToGetStorageArgs()
		if err != nil {
			return err
		}
		return p.GetStorageAt(args, reply)
	case "eth_blockByNumber", "eth_blockByHash":
		args, err := req.ToGetBlockArgs()
		if err != nil {
			return err
		}
		return p.GetBlock(args, reply)
	case "eth_transact":
		args, err := req.ToNewTxArgs()
		if err != nil {
			return err
		}
		return p.Transact(args, reply)
	case "web3_sha3":
		args, err := req.ToSha3Args()
		if err != nil {
			return err
		}
		return p.Sha3(args, reply)
	default:
		return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method))
	}

	rpclogger.DebugDetailf("Reply: %T %s", reply, reply)
	return nil
}
<commit_msg>removed create<commit_after>/*
	This file is part of go-ethereum

	go-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	go-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with go-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/*

For each request type, define the following:

1. RpcRequest "To" method [message.go], which does basic validation and conversion to "Args" type via json.Decoder()
2. json.Decoder() calls "UnmarshalON" defined on each "Args" struct
3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to ON

*/
package rpc

import (
	"fmt"
	"math/big"
	"strings"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/ethereum/go-ethereum/ethutil"
	"github.com/ethereum/go-ethereum/xeth"
)

type RpcServer interface {
	Start()
	Stop()
}

func NewEthereumApi(xeth *xeth.XEth) *EthereumApi {
	return &EthereumApi{xeth: xeth}
}

type EthereumApi struct {
	xeth *xeth.XEth
}

func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}

	if args.BlockNumber > 0 {
		*reply = p.xeth.BlockByNumber(args.BlockNumber)
	} else {
		*reply = p.xeth.BlockByHash(args.Hash)
	}
	return nil
}

func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	result, _ := p.xeth.Transact( /* TODO specify account */ args.Recipient, args.Value, args.Gas, args.GasPrice, args.Data)
	fmt.Println("result:", result)
	*reply = result
	return nil
}

func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error {
	err := args.requirementsPushTx()
	if err != nil {
		return err
	}
	result, _ := p.xeth.PushTx(args.Tx)
	*reply = result
	return nil
}

func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}

	state := p.xeth.State().SafeGet(args.Address)

	var hx string
	if strings.Index(args.Key, "0x") == 0 {
		hx = string([]byte(args.Key)[2:])
	} else {
		// Convert the incoming string (which is a bigint) into hex
		i, _ := new(big.Int).SetString(args.Key, 10)
		hx = ethutil.Bytes2Hex(i.Bytes())
	}
	rpclogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx)
	value := state.Storage(ethutil.Hex2Bytes(hx))
	*reply = GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()}
	return nil
}

func (p *EthereumApi) GetPeerCount(reply *interface{}) error {
	*reply = p.xeth.PeerCount()
	return nil
}

func (p *EthereumApi) GetIsListening(reply *interface{}) error {
	*reply = p.xeth.IsListening()
	return nil
}

func (p *EthereumApi) GetCoinbase(reply *interface{}) error {
	*reply = p.xeth.Coinbase()
	return nil
}

func (p *EthereumApi) GetIsMining(reply *interface{}) error {
	*reply = p.xeth.IsMining()
	return nil
}

func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	*reply = p.xeth.TxCountAt(args.Address)
	return nil
}

func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	state := p.xeth.State().SafeGet(args.Address)
	*reply = BalanceRes{Balance: state.Balance().String(), Address: args.Address}
	return nil
}

func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error {
	err := args.requirements()
	if err != nil {
		return err
	}
	*reply = p.xeth.CodeAt(args.Address)
	return nil
}

func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error {
	*reply = ethutil.Bytes2Hex(crypto.Sha3(ethutil.Hex2Bytes(args.Data)))
	return nil
}

func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
	// Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC
	rpclogger.DebugDetailf("%T %s", req.Params, req.Params)
	switch req.Method {
	case "eth_coinbase":
		return p.GetCoinbase(reply)
	case "eth_listening":
		return p.GetIsListening(reply)
	case "eth_mining":
		return p.GetIsMining(reply)
	case "eth_peerCount":
		return p.GetPeerCount(reply)
	case "eth_countAt":
		args, err := req.ToGetTxCountArgs()
		if err != nil {
			return err
		}
		return p.GetTxCountAt(args, reply)
	case "eth_codeAt":
		args, err := req.ToGetCodeAtArgs()
		if err != nil {
			return err
		}
		return p.GetCodeAt(args, reply)
	case "eth_balanceAt":
		args, err := req.ToGetBalanceArgs()
		if err != nil {
			return err
		}
		return p.GetBalanceAt(args, reply)
	case "eth_stateAt":
		args, err := req.ToGetStorageArgs()
		if err != nil {
			return err
		}
		return p.GetStorageAt(args, reply)
	case "eth_blockByNumber", "eth_blockByHash":
		args, err := req.ToGetBlockArgs()
		if err != nil {
			return err
		}
		return p.GetBlock(args, reply)
	case "eth_transact":
		args, err := req.ToNewTxArgs()
		if err != nil {
			return err
		}
		return p.Transact(args, reply)
	case "web3_sha3":
		args, err := req.ToSha3Args()
		if err != nil {
			return err
		}
		return p.Sha3(args, reply)
	default:
		return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method))
	}

	rpclogger.DebugDetailf("Reply: %T %s", reply, reply)
	return nil
}
<|endoftext|>


<commit_before>package rpc_test

import (
	"encoding/json"
	"fmt"
	"io"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/rpc"
	"launchpad.net/juju-core/testing"
	"net"
	stdtesting "testing"
)

type suite struct {
	testing.LoggingSuite
}

var _ = Suite(&suite{})

func TestAll(t *stdtesting.T) {
	TestingT(t)
}

type callInfo struct {
	rcvr   interface{}
	method string
	arg    interface{}
}

type callError callInfo

func (e *callError) Error() string {
	return fmt.Sprintf("error calling %s", e.method)
}

type stringVal struct {
	Val string
}

type TRoot struct {
	t *testContext
}

func (r *TRoot) A(id string) (*A, error) {
	if id == "" || id[0] != 'a' {
		return nil, fmt.Errorf("unknown a id")
	}
	return r.t.newA(id)
}

type A struct {
	t  *testContext
	id string
}

// Each Call method is named in this standard form:
//
//     Call<narg>r<nret><e>
//
// where narg is the number of arguments, nret is the number of returned
// values (not including the error) and e is the letter 'e' if the
// method returns an error.

func (a *A) Call0r0() {
	a.t.called(a, "Call0r0", nil)
}

func (a *A) Call0r1() stringVal {
	a.t.called(a, "Call0r1", nil)
	return stringVal{"Call0r1 ret"}
}

func (a *A) Call0r1e() (stringVal, error) {
	a.t.called(a, "Call0r1e", nil)
	return stringVal{"Call0r1e ret"}, &callError{a, "Call0r1e", nil}
}

func (a *A) Call0r0e() error {
	a.t.called(a, "Call0r0e", nil)
	return &callError{a, "Call0r0e", nil}
}

func (a *A) Call1r0(s stringVal) {
	a.t.called(a, "Call1r0", s)
}

func (a *A) Call1r1(s stringVal) stringVal {
	a.t.called(a, "Call1r1", s)
	return stringVal{"Call1r1 ret"}
}

func (a *A) Call1r1e(s stringVal) (stringVal, error) {
	a.t.called(a, "Call1r1e", s)
	return stringVal{}, &callError{a, "Call1r1e", s}
}

func (a *A) Call1r0e(s stringVal) error {
	a.t.called(a, "Call1r0e", s)
	return &callError{a, "Call1r0e", s}
}

type testContext struct {
	calls []*callInfo
	as    map[string]*A
}

func (t *testContext) called(rcvr interface{}, method string, arg interface{}) {
	t.calls = append(t.calls, &callInfo{rcvr, method, arg})
}

func (t *testContext) newA(id string) (*A, error) {
	if a := t.as[id]; a != nil {
		return a, nil
	}
	return nil, fmt.Errorf("A(%s) not found", id)
}

func (*suite) TestRPC(c *C) {
	srv, err := rpc.NewServer(&TRoot{})
	c.Assert(err, IsNil)

	l, err := net.Listen("tcp", ":0")
	c.Assert(err, IsNil)
	defer l.Close()

	rootc := make(chan *TRoot)
	srvDone := make(chan error)
	go func() {
		newRoot := func(net.Conn) (interface{}, error) {
			return <-rootc, nil
		}
		err := srv.Accept(l, newRoot, NewJSONServerCodec)
		c.Logf("accept status: %v", err)
		srvDone <- err
	}()

	conn, err := net.Dial("tcp", l.Addr().String())
	c.Assert(err, IsNil)
	defer conn.Close()
	t := &testContext{
		as: map[string]*A{},
	}
	t.as["a99"] = &A{id: "a99", t: t}
	rootc <- &TRoot{t}
	client := rpc.NewClientWithCodec(NewJSONClientCodec(conn))
	for narg := 0; narg < 2; narg++ {
		for nret := 0; nret < 2; nret++ {
			for nerr := 0; nerr < 2; nerr++ {
				t.calls = nil
				t.testCall(c, client, narg, nret, nerr != 0)
			}
		}
	}
	l.Close()
	<-srvDone
}

func (t *testContext) testCall(c *C, client *rpc.Client, narg, nret int, retErr bool) {
	e := ""
	if retErr {
		e = "e"
	}
	method := fmt.Sprintf("Call%dr%d%s", narg, nret, e)
	c.Logf("test call %s", method)
	var r stringVal
	err := client.Call("A", "a99", method, stringVal{"arg"}, &r)
	c.Assert(t.calls, HasLen, 1, Commentf("err %v", err))
	expectCall := callInfo{
		rcvr:   t.as["a99"],
		method: method,
	}
	if narg > 0 {
		expectCall.arg = stringVal{"arg"}
	}
	c.Assert(*t.calls[0], Equals, expectCall)
	switch {
	case retErr:
		c.Assert(err, DeepEquals, &rpc.ServerError{
			fmt.Sprintf("error calling %s", method),
		})
	case nret > 0:
		c.Assert(r, Equals, stringVal{method + " ret"})
	}
}

type generalServerCodec struct {
	io.Closer
	enc encoder
	dec decoder
}

type encoder interface {
	Encode(e interface{}) error
}

type decoder interface {
	Decode(e interface{}) error
}

func (c *generalServerCodec) ReadRequestHeader(req *rpc.Request) error {
	return c.dec.Decode(req)
}

func (c *generalServerCodec) ReadRequestBody(argp interface{}) error {
	if argp == nil {
		argp = &struct{}{}
	}
	return c.dec.Decode(argp)
}

func (c *generalServerCodec) WriteResponse(resp *rpc.Response, v interface{}) error {
	if err := c.enc.Encode(resp); err != nil {
		return err
	}
	return c.enc.Encode(v)
}

type generalClientCodec struct {
	io.Closer
	enc encoder
	dec decoder
}

func (c *generalClientCodec) WriteRequest(req *rpc.Request, x interface{}) error {
	log.Printf("send client request header: %#v", req)
	if err := c.enc.Encode(req); err != nil {
		return err
	}
	log.Printf("send client request body: %#v", x)
	return c.enc.Encode(x)
}

func (c *generalClientCodec) ReadResponseHeader(resp *rpc.Response) error {
	err := c.dec.Decode(resp)
	log.Printf("got response header %#v", resp)
	return err
}

func (c *generalClientCodec) ReadResponseBody(r interface{}) error {
	var m json.RawMessage
	err := c.dec.Decode(&m)
	if err != nil {
		return err
	}
	log.Printf("got response body: %q", m)
	if r == nil {
		r = &struct{}{}
	}
	err = json.Unmarshal(m, r)
	log.Printf("unmarshalled into %#v", r)
	return err
}

func NewJSONServerCodec(c io.ReadWriteCloser) rpc.ServerCodec {
	return &generalServerCodec{
		Closer: c,
		enc:    json.NewEncoder(c),
		dec:    json.NewDecoder(c),
	}
}

func NewJSONClientCodec(c io.ReadWriteCloser) rpc.ClientCodec {
	return &generalClientCodec{
		Closer: c,
		enc:    json.NewEncoder(c),
		dec:    json.NewDecoder(c),
	}
}
<commit_msg>rpc: slightly simplify test<commit_after>package rpc_test

import (
	"encoding/json"
	"fmt"
	"io"
	. "launchpad.net/gocheck"
	"launchpad.net/juju-core/log"
	"launchpad.net/juju-core/rpc"
	"launchpad.net/juju-core/testing"
	"net"
	stdtesting "testing"
)

type suite struct {
	testing.LoggingSuite
}

var _ = Suite(&suite{})

func TestAll(t *stdtesting.T) {
	TestingT(t)
}

type callInfo struct {
	rcvr   interface{}
	method string
	arg    interface{}
}

type callError callInfo

func (e *callError) Error() string {
	return fmt.Sprintf("error calling %s", e.method)
}

type stringVal struct {
	Val string
}

type TRoot struct {
	t *testContext
}

func (r *TRoot) A(id string) (*A, error) {
	if id == "" || id[0] != 'a' {
		return nil, fmt.Errorf("unknown a id")
	}
	return r.t.newA(id)
}

type A struct {
	t  *testContext
	id string
}

// Each Call method is named in this standard form:
//
//     Call<narg>r<nret><e>
//
// where narg is the number of arguments, nret is the number of returned
// values (not including the error) and e is the letter 'e' if the
// method returns an error.

func (a *A) Call0r0() {
	a.t.called(a, "Call0r0", nil)
}

func (a *A) Call0r1() stringVal {
	a.t.called(a, "Call0r1", nil)
	return stringVal{"Call0r1 ret"}
}

func (a *A) Call0r1e() (stringVal, error) {
	a.t.called(a, "Call0r1e", nil)
	return stringVal{"Call0r1e ret"}, &callError{a, "Call0r1e", nil}
}

func (a *A) Call0r0e() error {
	a.t.called(a, "Call0r0e", nil)
	return &callError{a, "Call0r0e", nil}
}

func (a *A) Call1r0(s stringVal) {
	a.t.called(a, "Call1r0", s)
}

func (a *A) Call1r1(s stringVal) stringVal {
	a.t.called(a, "Call1r1", s)
	return stringVal{"Call1r1 ret"}
}

func (a *A) Call1r1e(s stringVal) (stringVal, error) {
	a.t.called(a, "Call1r1e", s)
	return stringVal{}, &callError{a, "Call1r1e", s}
}

func (a *A) Call1r0e(s stringVal) error {
	a.t.called(a, "Call1r0e", s)
	return &callError{a, "Call1r0e", s}
}

type testContext struct {
	calls []*callInfo
	as    map[string]*A
}

func (t *testContext) called(rcvr interface{}, method string, arg interface{}) {
	t.calls = append(t.calls, &callInfo{rcvr, method, arg})
}

func (t *testContext) newA(id string) (*A, error) {
	if a := t.as[id]; a != nil {
		return a, nil
	}
	return nil, fmt.Errorf("A(%s) not found", id)
}

func (*suite) TestRPC(c *C) {
	srv, err := rpc.NewServer(&TRoot{})
	c.Assert(err, IsNil)

	l, err := net.Listen("tcp", ":0")
	c.Assert(err, IsNil)
	defer l.Close()

	srvDone := make(chan error)
	t := &testContext{
			as: make(map[string]*A),
	}
	troot := &TRoot{
		t: t,
	}
	troot.t.as["a99"] = &A{id: "a99", t: t}
	go func() {
		newRoot := func(net.Conn) (interface{}, error) {
			return troot, nil
		}
		err := srv.Accept(l, newRoot, NewJSONServerCodec)
		c.Logf("accept status: %v", err)
		srvDone <- err
	}()

	conn, err := net.Dial("tcp", l.Addr().String())
	c.Assert(err, IsNil)
	defer conn.Close()
	client := rpc.NewClientWithCodec(NewJSONClientCodec(conn))
	for narg := 0; narg < 2; narg++ {
		for nret := 0; nret < 2; nret++ {
			for nerr := 0; nerr < 2; nerr++ {
				t.calls = nil
				t.testCall(c, client, narg, nret, nerr != 0)
			}
		}
	}
	l.Close()
	<-srvDone
}

func (t *testContext) testCall(c *C, client *rpc.Client, narg, nret int, retErr bool) {
	e := ""
	if retErr {
		e = "e"
	}
	method := fmt.Sprintf("Call%dr%d%s", narg, nret, e)
	c.Logf("test call %s", method)
	var r stringVal
	err := client.Call("A", "a99", method, stringVal{"arg"}, &r)
	c.Assert(t.calls, HasLen, 1, Commentf("err %v", err))
	expectCall := callInfo{
		rcvr:   t.as["a99"],
		method: method,
	}
	if narg > 0 {
		expectCall.arg = stringVal{"arg"}
	}
	c.Assert(*t.calls[0], Equals, expectCall)
	switch {
	case retErr:
		c.Assert(err, DeepEquals, &rpc.ServerError{
			fmt.Sprintf("error calling %s", method),
		})
	case nret > 0:
		c.Assert(r, Equals, stringVal{method + " ret"})
	}
}

type generalServerCodec struct {
	io.Closer
	enc encoder
	dec decoder
}

type encoder interface {
	Encode(e interface{}) error
}

type decoder interface {
	Decode(e interface{}) error
}

func (c *generalServerCodec) ReadRequestHeader(req *rpc.Request) error {
	return c.dec.Decode(req)
}

func (c *generalServerCodec) ReadRequestBody(argp interface{}) error {
	if argp == nil {
		argp = &struct{}{}
	}
	return c.dec.Decode(argp)
}

func (c *generalServerCodec) WriteResponse(resp *rpc.Response, v interface{}) error {
	if err := c.enc.Encode(resp); err != nil {
		return err
	}
	return c.enc.Encode(v)
}

type generalClientCodec struct {
	io.Closer
	enc encoder
	dec decoder
}

func (c *generalClientCodec) WriteRequest(req *rpc.Request, x interface{}) error {
	log.Printf("send client request header: %#v", req)
	if err := c.enc.Encode(req); err != nil {
		return err
	}
	log.Printf("send client request body: %#v", x)
	return c.enc.Encode(x)
}

func (c *generalClientCodec) ReadResponseHeader(resp *rpc.Response) error {
	err := c.dec.Decode(resp)
	log.Printf("got response header %#v", resp)
	return err
}

func (c *generalClientCodec) ReadResponseBody(r interface{}) error {
	var m json.RawMessage
	err := c.dec.Decode(&m)
	if err != nil {
		return err
	}
	log.Printf("got response body: %q", m)
	if r == nil {
		r = &struct{}{}
	}
	err = json.Unmarshal(m, r)
	log.Printf("unmarshalled into %#v", r)
	return err
}

func NewJSONServerCodec(c io.ReadWriteCloser) rpc.ServerCodec {
	return &generalServerCodec{
		Closer: c,
		enc:    json.NewEncoder(c),
		dec:    json.NewDecoder(c),
	}
}

func NewJSONClientCodec(c io.ReadWriteCloser) rpc.ClientCodec {
	return &generalClientCodec{
		Closer: c,
		enc:    json.NewEncoder(c),
		dec:    json.NewDecoder(c),
	}
}
<|endoftext|>


<commit_before>// tra
package rpcdb

import (
	"bytes"
	"fmt"
	"io"
	"net/rpc"
	"net/http"

	"github.com/ssbl/trago/db"
)

func Run(localDir, localAddr, remoteDir, remoteAddr string) error {
	args := 1 					// unused arg variable

	localClient, err := rpc.DialHTTP("tcp", localAddr)
	if err != nil {
		return err
	}
	remoteClient, err := rpc.DialHTTP("tcp", remoteAddr)
	if err != nil {
		return err
	}

	err = startSrv(localClient, localDir)
	if err != nil {
		return err
	}
	err = startSrv(remoteClient, remoteDir)
	if err != nil {
		return err
	}

	localDb := db.TraDb{}
	err = localClient.Call("TraSrv.GetDb", &args, &localDb)
	if err != nil {
		return err
	}

	fmt.Printf("Reply from local trasrv:\n%v\n", localDb)

	remoteDb := db.TraDb{}
	err = remoteClient.Call("TraSrv.GetDb", &args, &remoteDb)
	if err != nil {
		return err
	}

	fmt.Printf("Reply from remote trasrv:\n%v\n", remoteDb)

	fmt.Println("Comparing local with remote...")
	tags := localDb.Compare(&remoteDb)

	for file, tag := range tags {
		reply := 1
		if tag == db.File {
			response, err := http.Get("http://"+remoteAddr+"/files/"+file)
			if err != nil {
				return err
			}
			defer response.Body.Close()

			buf := new(bytes.Buffer)
			_, err = io.Copy(buf, response.Body)
			if err != nil {
				return err
			}

			fileData := db.FileData{Name: file, Data: buf.Bytes()}
			err = localClient.Call("TraSrv.PutFile", &fileData, &reply)
			if err != nil {
				return err
			}

			localDb.Files[file] = remoteDb.Files[file]
		} else if tag == db.Deleted {
			err = localClient.Call("TraSrv.RemoveFile", &file, &reply)
			if err != nil {
				return err
			}
			delete(localDb.Files, file)
		} else if tag == db.Conflict {
			// TODO: send the file with a different name
			err = localClient.Call("TraSrv.ShowConflict", &file, &reply)
			if err != nil {
				return err
			}
		}
	}

	fmt.Println("Comparing remote with local...")
	tags = remoteDb.Compare(&localDb)

	for file, tag := range tags {
		reply := 1
		if tag == db.File {
			response, err := http.Get("http://"+localAddr+"/files/"+file)
			if err != nil {
				return err
			}
			defer response.Body.Close()

			buf := new(bytes.Buffer)
			_, err = io.Copy(buf, response.Body)
			if err != nil {
				return err
			}

			fileData := db.FileData{Name: file, Data: buf.Bytes()}
			err = remoteClient.Call("TraSrv.PutFile", &fileData, &reply)
			if err != nil {
				return err
			}
		} else if tag == db.Deleted {
			err = remoteClient.Call("TraSrv.RemoveFile", &file, &reply)
			if err != nil {
				return err
			}
			delete(remoteDb.Files, file)
		} else if tag == db.Conflict {
			err = remoteClient.Call("TraSrv.ShowConflict", &file, &reply)
			if err != nil {
				return err
			}
		}
	}

	db.CombineVectors(localDb.VersionVec, remoteDb.VersionVec)
	remoteDb.VersionVec = localDb.VersionVec
	fmt.Println(localDb.VersionVec, remoteDb.VersionVec)

	if err := localClient.Call("TraSrv.PutDb", &localDb, &args); err != nil {
		return err
	}
	if err := remoteClient.Call("TraSrv.PutDb", &remoteDb, &args); err != nil {
		return err
	}

	return nil
}

func startSrv(client *rpc.Client, dir string) error {
	var reply int

	err := client.Call("TraSrv.InitSrv", &dir, &reply)
	return err
}
<commit_msg>report conflict on both servers<commit_after>// tra
package rpcdb

import (
	"bytes"
	"fmt"
	"io"
	"net/rpc"
	"net/http"

	"github.com/ssbl/trago/db"
)

func Run(localDir, localAddr, remoteDir, remoteAddr string) error {
	args := 1 					// unused arg variable

	localClient, err := rpc.DialHTTP("tcp", localAddr)
	if err != nil {
		return err
	}
	remoteClient, err := rpc.DialHTTP("tcp", remoteAddr)
	if err != nil {
		return err
	}

	err = startSrv(localClient, localDir)
	if err != nil {
		return err
	}
	err = startSrv(remoteClient, remoteDir)
	if err != nil {
		return err
	}

	localDb := db.TraDb{}
	err = localClient.Call("TraSrv.GetDb", &args, &localDb)
	if err != nil {
		return err
	}

	fmt.Printf("Reply from local trasrv:\n%v\n", localDb)

	remoteDb := db.TraDb{}
	err = remoteClient.Call("TraSrv.GetDb", &args, &remoteDb)
	if err != nil {
		return err
	}

	fmt.Printf("Reply from remote trasrv:\n%v\n", remoteDb)

	fmt.Println("Comparing local with remote...")
	tags := localDb.Compare(&remoteDb)

	for file, tag := range tags {
		reply := 1
		if tag == db.File {
			response, err := http.Get("http://"+remoteAddr+"/files/"+file)
			if err != nil {
				return err
			}
			defer response.Body.Close()

			buf := new(bytes.Buffer)
			_, err = io.Copy(buf, response.Body)
			if err != nil {
				return err
			}

			fileData := db.FileData{Name: file, Data: buf.Bytes()}
			err = localClient.Call("TraSrv.PutFile", &fileData, &reply)
			if err != nil {
				return err
			}

			localDb.Files[file] = remoteDb.Files[file]
		} else if tag == db.Deleted {
			err = localClient.Call("TraSrv.RemoveFile", &file, &reply)
			if err != nil {
				return err
			}
			delete(localDb.Files, file)
		} else if tag == db.Conflict {
			// TODO: send the file with a different name
			err = localClient.Call("TraSrv.ShowConflict", &file, &reply)
			if err != nil {
				return err
			}
		}
	}

	fmt.Println("Comparing remote with local...")
	tags = remoteDb.Compare(&localDb)

	for file, tag := range tags {
		reply := 1
		if tag == db.File {
			response, err := http.Get("http://"+localAddr+"/files/"+file)
			if err != nil {
				return err
			}
			defer response.Body.Close()

			buf := new(bytes.Buffer)
			_, err = io.Copy(buf, response.Body)
			if err != nil {
				return err
			}

			fileData := db.FileData{Name: file, Data: buf.Bytes()}
			err = remoteClient.Call("TraSrv.PutFile", &fileData, &reply)
			if err != nil {
				return err
			}
		} else if tag == db.Deleted {
			err = remoteClient.Call("TraSrv.RemoveFile", &file, &reply)
			if err != nil {
				return err
			}
			delete(remoteDb.Files, file)
		} else if tag == db.Conflict {
			err = remoteClient.Call("TraSrv.ShowConflict", &file, &reply)
			if err != nil {
				return err
			}
		} else if tag == db.Conflict {
			err = remoteClient.Call("TraSrv.ShowConflict", &file, &reply)
			if err != nil {
				return err
			}
		}
	}

	db.CombineVectors(localDb.VersionVec, remoteDb.VersionVec)
	remoteDb.VersionVec = localDb.VersionVec
	fmt.Println(localDb.VersionVec, remoteDb.VersionVec)

	if err := localClient.Call("TraSrv.PutDb", &localDb, &args); err != nil {
		return err
	}
	if err := remoteClient.Call("TraSrv.PutDb", &remoteDb, &args); err != nil {
		return err
	}

	return nil
}

func startSrv(client *rpc.Client, dir string) error {
	var reply int

	err := client.Call("TraSrv.InitSrv", &dir, &reply)
	return err
}
<|endoftext|>


<commit_before>package securitygroup

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

	cfclient "github.com/cloudfoundry-community/go-cfclient"
	"github.com/pivotalservices/cf-mgmt/config"
	"github.com/pivotalservices/cf-mgmt/space"
	"github.com/pkg/errors"
	"github.com/xchapter7x/lo"
)

//NewManager -
func NewManager(client CFClient, spaceMgr space.Manager, cfg config.Reader, peek bool) Manager {
	return &DefaultManager{
		Cfg:          cfg,
		Client:       client,
		SpaceManager: spaceMgr,
		Peek:         peek,
	}
}

//DefaultSecurityGroupManager -
type DefaultManager struct {
	Cfg          config.Reader
	SpaceManager space.Manager
	Client       CFClient
	Peek         bool
}

//CreateApplicationSecurityGroups -
func (m *DefaultManager) CreateApplicationSecurityGroups() error {
	spaceConfigs, err := m.Cfg.GetSpaceConfigs()
	if err != nil {
		return err
	}
	sgs, err := m.ListNonDefaultSecurityGroups()
	if err != nil {
		return err
	}

	for _, input := range spaceConfigs {
		space, err := m.SpaceManager.FindSpace(input.Org, input.Space)
		if err != nil {
			return err
		}

		existingSpaceSecurityGroups, err := m.ListSpaceSecurityGroups(space.Guid)
		if err != nil {
			return errors.Wrapf(err, "Unabled to list existing space security groups for org/space [%s/%s]", input.Org, input.Space)
		}
		lo.G.Debugf("Existing space security groups %+v", existingSpaceSecurityGroups)
		// iterate through and assign named security groups to the space - ensuring that they are up to date is
		// done elsewhere.
		for _, securityGroupName := range input.ASGs {
			if sgInfo, ok := sgs[securityGroupName]; ok {
				if _, ok := existingSpaceSecurityGroups[securityGroupName]; !ok {
					err := m.AssignSecurityGroupToSpace(space, sgInfo)
					if err != nil {
						return err
					}
				} else {
					delete(existingSpaceSecurityGroups, securityGroupName)
				}
			} else {
				return fmt.Errorf("Security group [%s] does not exist as a non-running and non-staging security group [%v+]", securityGroupName, sgs)
			}
		}

		spaceSecurityGroupName := fmt.Sprintf("%s-%s", input.Org, input.Space)
		if input.EnableSecurityGroup {
			var sgInfo cfclient.SecGroup
			var ok bool
			if sgInfo, ok = sgs[spaceSecurityGroupName]; ok {
				changed, err := m.hasSecurityGroupChanged(sgInfo, input.GetSecurityGroupContents())
				if err != nil {
					return errors.Wrapf(err, "Checking if security group %s has changed", spaceSecurityGroupName)
				}
				if changed {
					if err := m.UpdateSecurityGroup(sgInfo, input.GetSecurityGroupContents()); err != nil {
						return err
					}
				}
			} else {
				securityGroup, err := m.CreateSecurityGroup(spaceSecurityGroupName, input.GetSecurityGroupContents())
				if err != nil {
					return err
				}
				sgInfo = *securityGroup
			}
			if _, ok := existingSpaceSecurityGroups[spaceSecurityGroupName]; !ok {
				err := m.AssignSecurityGroupToSpace(space, sgInfo)
				if err != nil {
					return err
				}
			} else {
				delete(existingSpaceSecurityGroups, spaceSecurityGroupName)
			}
		}

		if input.EnableUnassignSecurityGroup {
			lo.G.Debugf("Existing space security groups after %+v", existingSpaceSecurityGroups)
			for sgName, _ := range existingSpaceSecurityGroups {
				if sgInfo, ok := sgs[sgName]; ok {
					err := m.UnassignSecurityGroupToSpace(space, sgInfo)
					if err != nil {
						return err
					}
				} else {
					return fmt.Errorf("Security group [%s] does not exist as a non-running and non-staging security group [%v+]", sgName, sgs)
				}
			}
		}
	}
	return nil
}

func (m *DefaultManager) ListSecurityGroups() (map[string]cfclient.SecGroup, error) {
	securityGroups := make(map[string]cfclient.SecGroup)
	secGroups, err := m.Client.ListSecGroups()
	if err != nil {
		return securityGroups, err
	}
	lo.G.Debug("Total security groups returned :", len(secGroups))
	for _, sg := range secGroups {
		securityGroups[sg.Name] = sg
	}
	return securityGroups, nil
}

//CreateGlobalSecurityGroups -
func (m *DefaultManager) CreateGlobalSecurityGroups() error {
	sgs, err := m.ListSecurityGroups()
	if err != nil {
		return err
	}
	securityGroupConfigs, err := m.Cfg.GetASGConfigs()
	if err != nil {
		return err
	}
	defaultSecurityGroupConfigs, err := m.Cfg.GetDefaultASGConfigs()
	if err != nil {
		return err
	}
	err = m.processSecurityGroups(securityGroupConfigs, sgs)
	if err != nil {
		return err
	}
	err = m.processSecurityGroups(defaultSecurityGroupConfigs, sgs)
	if err != nil {
		return err
	}

	return nil
}

//AssignDefaultSecurityGroups -
func (m *DefaultManager) AssignDefaultSecurityGroups() error {
	sgs, err := m.ListSecurityGroups()
	if err != nil {
		return err
	}
	globalConfig, err := m.Cfg.GetGlobalConfig()
	if err != nil {
		return err
	}

	for _, runningGroup := range globalConfig.RunningSecurityGroups {
		if group, ok := sgs[runningGroup]; ok {
			if !group.Running {
				err = m.AssignRunningSecurityGroup(group)
				if err != nil {
					return err
				}
			}
		} else {
			if !m.Peek {
				return fmt.Errorf("Running security group [%s] does not exist", runningGroup)
			} else {
				lo.G.Infof("[dry-run]: assigning yet to be created sg %s as running security group", runningGroup)
			}
		}
	}

	for _, stagingGroup := range globalConfig.StagingSecurityGroups {
		if group, ok := sgs[stagingGroup]; ok {
			if !group.Staging {
				err = m.AssignStagingSecurityGroup(group)
				if err != nil {
					return err
				}
			}
		} else {
			if !m.Peek {
				return fmt.Errorf("Staging security group [%s] does not exist", stagingGroup)
			} else {
				lo.G.Infof("[dry-run]: assigning yet to be created sg %s as staging security group", stagingGroup)
			}
		}
	}

	if globalConfig.EnableUnassignSecurityGroups {
		for groupName, group := range sgs {
			if group.Running && !m.contains(globalConfig.RunningSecurityGroups, groupName) {
				err = m.UnassignRunningSecurityGroup(group)
				if err != nil {
					return err
				}
			}
			if group.Staging && !m.contains(globalConfig.StagingSecurityGroups, groupName) {
				err = m.UnassignStagingSecurityGroup(group)
				if err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (m *DefaultManager) contains(list []string, groupName string) bool {
	groupNameToUpper := strings.ToUpper(groupName)
	for _, v := range list {
		if strings.ToUpper(v) == groupNameToUpper {
			return true
		}
	}
	return false
}

func (m *DefaultManager) processSecurityGroups(securityGroupConfigs []config.ASGConfig, sgs map[string]cfclient.SecGroup) error {
	for _, input := range securityGroupConfigs {
		sgName := input.Name

		// For every named security group
		// Check if it's a new group or Update
		if sgInfo, ok := sgs[sgName]; ok {
			changed, err := m.hasSecurityGroupChanged(sgInfo, input.Rules)
			if err != nil {
				return err
			}
			if changed {
				if err := m.UpdateSecurityGroup(sgInfo, input.Rules); err != nil {
					return err
				}
			}
		} else {
			if _, err := m.CreateSecurityGroup(sgName, input.Rules); err != nil {
				return err
			}
		}
	}

	return nil
}

func (m *DefaultManager) hasSecurityGroupChanged(sgInfo cfclient.SecGroup, rules string) (bool, error) {
	jsonBytes, err := json.Marshal(sgInfo.Rules)
	if err != nil {
		return false, err
	}
	secRules := []cfclient.SecGroupRule{}
	err = json.Unmarshal([]byte(rules), &secRules)
	if err != nil {
		return false, err
	}
	jsonBytesToCompare, err := json.Marshal(secRules)
	if err != nil {
		return false, err
	}
	match, err := DoesJsonMatch(string(jsonBytes), string(jsonBytesToCompare))
	if err != nil {
		return false, err
	}
	return !match, nil
}

func (m *DefaultManager) AssignSecurityGroupToSpace(space cfclient.Space, secGroup cfclient.SecGroup) error {
	for _, configuredSpace := range secGroup.SpacesData {
		if configuredSpace.Entity.Guid == space.Guid {
			return nil
		}
	}
	if m.Peek {
		lo.G.Infof("[dry-run]: assigning security group %s to space %s", secGroup.Name, space.Name)
		return nil
	}
	lo.G.Infof("assigning security group %s to space %s", secGroup.Name, space.Name)
	return m.Client.BindSecGroup(secGroup.Guid, space.Guid)
}

func (m *DefaultManager) UnassignSecurityGroupToSpace(space cfclient.Space, secGroup cfclient.SecGroup) error {
	for _, configuredSpace := range secGroup.SpacesData {
		if configuredSpace.Entity.Guid == space.Guid {
			return nil
		}
	}
	if m.Peek {
		lo.G.Infof("[dry-run]: unassigning security group %s to space %s", secGroup.Name, space.Name)
		return nil
	}
	lo.G.Infof("unassigning security group %s to space %s", secGroup.Name, space.Name)
	return m.Client.UnbindSecGroup(secGroup.Guid, space.Guid)
}

func (m *DefaultManager) CreateSecurityGroup(sgName, contents string) (*cfclient.SecGroup, error) {
	if m.Peek {
		lo.G.Infof("[dry-run]: creating securityGroup %s with contents %s", sgName, contents)
		return &cfclient.SecGroup{Name: "dry-run-name", Guid: "dry-run-guid"}, nil
	}
	securityGroupRules := []cfclient.SecGroupRule{}
	err := json.Unmarshal([]byte(contents), &securityGroupRules)
	if err != nil {
		return nil, err
	}
	lo.G.Infof("creating securityGroup %s with contents %s", sgName, contents)
	return m.Client.CreateSecGroup(sgName, securityGroupRules, nil)
}

func (m *DefaultManager) UpdateSecurityGroup(sg cfclient.SecGroup, contents string) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: updating securityGroup %s with contents %s", sg.Name, contents)
		return nil
	}
	securityGroupRules := []cfclient.SecGroupRule{}
	err := json.Unmarshal([]byte(contents), &securityGroupRules)
	if err != nil {
		return err
	}
	lo.G.Infof("[dry-run]: updating securityGroup %s with contents %s", sg.Name, contents)
	_, err = m.Client.UpdateSecGroup(sg.Guid, sg.Name, securityGroupRules, nil)
	return err
}
func (m *DefaultManager) ListNonDefaultSecurityGroups() (map[string]cfclient.SecGroup, error) {
	securityGroups := make(map[string]cfclient.SecGroup)
	groupMap, err := m.ListSecurityGroups()
	if err != nil {
		return nil, err
	}
	for key, groupMap := range groupMap {
		if groupMap.Running == false && groupMap.Staging == false {
			securityGroups[key] = groupMap
		}
	}
	return securityGroups, nil
}

func (m *DefaultManager) ListDefaultSecurityGroups() (map[string]cfclient.SecGroup, error) {
	securityGroups := make(map[string]cfclient.SecGroup)
	groupMap, err := m.ListSecurityGroups()
	if err != nil {
		return nil, err
	}
	for key, groupMap := range groupMap {
		if groupMap.Running == true || groupMap.Staging == true {
			securityGroups[key] = groupMap
		}
	}
	return securityGroups, nil
}

func (m *DefaultManager) AssignRunningSecurityGroup(sg cfclient.SecGroup) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: assigning sg %s as running security group", sg.Name)
		return nil
	}
	lo.G.Infof("assigning sg %s as running security group", sg.Name)
	return m.Client.BindRunningSecGroup(sg.Guid)
}
func (m *DefaultManager) AssignStagingSecurityGroup(sg cfclient.SecGroup) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: assigning sg %s as staging security group", sg.Name)
		return nil
	}
	lo.G.Infof("assigning sg %s as staging security group", sg.Name)
	return m.Client.BindStagingSecGroup(sg.Guid)
}
func (m *DefaultManager) UnassignRunningSecurityGroup(sg cfclient.SecGroup) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: unassinging sg %s as running security group", sg.Name)
		return nil
	}
	lo.G.Infof("unassinging sg %s as running security group", sg.Name)
	return m.Client.UnbindRunningSecGroup(sg.Guid)
}
func (m *DefaultManager) UnassignStagingSecurityGroup(sg cfclient.SecGroup) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: unassigning sg %s as staging security group", sg.Name)
		return nil
	}
	lo.G.Infof("unassigning sg %s as staging security group", sg.Name)
	return m.Client.UnbindStagingSecGroup(sg.Guid)
}

func (m *DefaultManager) GetSecurityGroupRules(sgGUID string) ([]byte, error) {
	secGroup, err := m.Client.GetSecGroup(sgGUID)
	if err != nil {
		return nil, err
	}
	return json.MarshalIndent(secGroup.Rules, "", "\t")
}

func (m *DefaultManager) ListSpaceSecurityGroups(spaceGUID string) (map[string]string, error) {
	secGroups, err := m.Client.ListSpaceSecGroups(spaceGUID)
	if err != nil {
		return nil, err
	}
	lo.G.Debug("Total security groups returned :", len(secGroups))
	names := make(map[string]string)
	for _, sg := range secGroups {
		if sg.Running == false && sg.Staging == false {
			names[sg.Name] = sg.Guid
		}
	}
	return names, nil
}
<commit_msg>adding more context to error messages - https://github.com/pivotalservices/cf-mgmt/issues/194<commit_after>package securitygroup

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

	cfclient "github.com/cloudfoundry-community/go-cfclient"
	"github.com/pivotalservices/cf-mgmt/config"
	"github.com/pivotalservices/cf-mgmt/space"
	"github.com/pkg/errors"
	"github.com/xchapter7x/lo"
)

//NewManager -
func NewManager(client CFClient, spaceMgr space.Manager, cfg config.Reader, peek bool) Manager {
	return &DefaultManager{
		Cfg:          cfg,
		Client:       client,
		SpaceManager: spaceMgr,
		Peek:         peek,
	}
}

//DefaultSecurityGroupManager -
type DefaultManager struct {
	Cfg          config.Reader
	SpaceManager space.Manager
	Client       CFClient
	Peek         bool
}

//CreateApplicationSecurityGroups -
func (m *DefaultManager) CreateApplicationSecurityGroups() error {
	spaceConfigs, err := m.Cfg.GetSpaceConfigs()
	if err != nil {
		return errors.Wrap(err, "Getting space configs")
	}
	sgs, err := m.ListNonDefaultSecurityGroups()
	if err != nil {
		return err
	}

	for _, input := range spaceConfigs {
		space, err := m.SpaceManager.FindSpace(input.Org, input.Space)
		if err != nil {
			return errors.Wrapf(err, "Finding org/space %s/%s", input.Org, input.Space)
		}
		existingSpaceSecurityGroups, err := m.ListSpaceSecurityGroups(space.Guid)
		if err != nil {
			return errors.Wrapf(err, "Unabled to list existing space security groups for org/space [%s/%s]", input.Org, input.Space)
		}
		lo.G.Debugf("Existing space security groups %+v", existingSpaceSecurityGroups)
		// iterate through and assign named security groups to the space - ensuring that they are up to date is
		// done elsewhere.
		for _, securityGroupName := range input.ASGs {
			if sgInfo, ok := sgs[securityGroupName]; ok {
				if _, ok := existingSpaceSecurityGroups[securityGroupName]; !ok {
					err := m.AssignSecurityGroupToSpace(space, sgInfo)
					if err != nil {
						return err
					}
				} else {
					delete(existingSpaceSecurityGroups, securityGroupName)
				}
			} else {
				return fmt.Errorf("Security group [%s] does not exist as a non-running and non-staging security group [%v+]", securityGroupName, sgs)
			}
		}

		spaceSecurityGroupName := fmt.Sprintf("%s-%s", input.Org, input.Space)
		if input.EnableSecurityGroup {
			var sgInfo cfclient.SecGroup
			var ok bool
			if sgInfo, ok = sgs[spaceSecurityGroupName]; ok {
				changed, err := m.hasSecurityGroupChanged(sgInfo, input.GetSecurityGroupContents())
				if err != nil {
					return errors.Wrapf(err, "Checking if security group %s has changed", spaceSecurityGroupName)
				}
				if changed {
					if err := m.UpdateSecurityGroup(sgInfo, input.GetSecurityGroupContents()); err != nil {
						return err
					}
				}
			} else {
				securityGroup, err := m.CreateSecurityGroup(spaceSecurityGroupName, input.GetSecurityGroupContents())
				if err != nil {
					return errors.Wrapf(err, "Creating security group %s for %s/%s security-group.json", spaceSecurityGroupName, input.Org, input.Space)
				}
				sgInfo = *securityGroup
			}
			if _, ok := existingSpaceSecurityGroups[spaceSecurityGroupName]; !ok {
				err := m.AssignSecurityGroupToSpace(space, sgInfo)
				if err != nil {
					return err
				}
			} else {
				delete(existingSpaceSecurityGroups, spaceSecurityGroupName)
			}
		}

		if input.EnableUnassignSecurityGroup {
			lo.G.Debugf("Existing space security groups after %+v", existingSpaceSecurityGroups)
			for sgName, _ := range existingSpaceSecurityGroups {
				if sgInfo, ok := sgs[sgName]; ok {
					err := m.UnassignSecurityGroupToSpace(space, sgInfo)
					if err != nil {
						return err
					}
				} else {
					return fmt.Errorf("Security group [%s] does not exist as a non-running and non-staging security group [%v+]", sgName, sgs)
				}
			}
		}
	}
	return nil
}

func (m *DefaultManager) ListSecurityGroups() (map[string]cfclient.SecGroup, error) {
	securityGroups := make(map[string]cfclient.SecGroup)
	secGroups, err := m.Client.ListSecGroups()
	if err != nil {
		return securityGroups, err
	}
	lo.G.Debug("Total security groups returned :", len(secGroups))
	for _, sg := range secGroups {
		securityGroups[sg.Name] = sg
	}
	return securityGroups, nil
}

//CreateGlobalSecurityGroups -
func (m *DefaultManager) CreateGlobalSecurityGroups() error {
	sgs, err := m.ListSecurityGroups()
	if err != nil {
		return err
	}
	securityGroupConfigs, err := m.Cfg.GetASGConfigs()
	if err != nil {
		return errors.Wrap(err, "Getting ASG Configs")
	}
	defaultSecurityGroupConfigs, err := m.Cfg.GetDefaultASGConfigs()
	if err != nil {
		return errors.Wrap(err, "Getting Default ASG Configs")
	}
	err = m.processSecurityGroups(securityGroupConfigs, sgs)
	if err != nil {
		return err
	}
	err = m.processSecurityGroups(defaultSecurityGroupConfigs, sgs)
	if err != nil {
		return err
	}

	return nil
}

//AssignDefaultSecurityGroups -
func (m *DefaultManager) AssignDefaultSecurityGroups() error {
	sgs, err := m.ListSecurityGroups()
	if err != nil {
		return err
	}
	globalConfig, err := m.Cfg.GetGlobalConfig()
	if err != nil {
		return err
	}

	for _, runningGroup := range globalConfig.RunningSecurityGroups {
		if group, ok := sgs[runningGroup]; ok {
			if !group.Running {
				err = m.AssignRunningSecurityGroup(group)
				if err != nil {
					return err
				}
			}
		} else {
			if !m.Peek {
				return fmt.Errorf("Running security group [%s] does not exist", runningGroup)
			} else {
				lo.G.Infof("[dry-run]: assigning yet to be created sg %s as running security group", runningGroup)
			}
		}
	}

	for _, stagingGroup := range globalConfig.StagingSecurityGroups {
		if group, ok := sgs[stagingGroup]; ok {
			if !group.Staging {
				err = m.AssignStagingSecurityGroup(group)
				if err != nil {
					return err
				}
			}
		} else {
			if !m.Peek {
				return fmt.Errorf("Staging security group [%s] does not exist", stagingGroup)
			} else {
				lo.G.Infof("[dry-run]: assigning yet to be created sg %s as staging security group", stagingGroup)
			}
		}
	}

	if globalConfig.EnableUnassignSecurityGroups {
		for groupName, group := range sgs {
			if group.Running && !m.contains(globalConfig.RunningSecurityGroups, groupName) {
				err = m.UnassignRunningSecurityGroup(group)
				if err != nil {
					return err
				}
			}
			if group.Staging && !m.contains(globalConfig.StagingSecurityGroups, groupName) {
				err = m.UnassignStagingSecurityGroup(group)
				if err != nil {
					return err
				}
			}
		}
	}

	return nil
}

func (m *DefaultManager) contains(list []string, groupName string) bool {
	groupNameToUpper := strings.ToUpper(groupName)
	for _, v := range list {
		if strings.ToUpper(v) == groupNameToUpper {
			return true
		}
	}
	return false
}

func (m *DefaultManager) processSecurityGroups(securityGroupConfigs []config.ASGConfig, sgs map[string]cfclient.SecGroup) error {
	for _, input := range securityGroupConfigs {
		sgName := input.Name

		// For every named security group
		// Check if it's a new group or Update
		if sgInfo, ok := sgs[sgName]; ok {
			changed, err := m.hasSecurityGroupChanged(sgInfo, input.Rules)
			if err != nil {
				return errors.Wrapf(err, "Processing %s security group", sgName)
			}
			if changed {
				if err := m.UpdateSecurityGroup(sgInfo, input.Rules); err != nil {
					return err
				}
			}
		} else {
			if _, err := m.CreateSecurityGroup(sgName, input.Rules); err != nil {
				return err
			}
		}
	}

	return nil
}

func (m *DefaultManager) hasSecurityGroupChanged(sgInfo cfclient.SecGroup, rules string) (bool, error) {
	jsonBytes, err := json.Marshal(sgInfo.Rules)
	if err != nil {
		return false, err
	}
	secRules := []cfclient.SecGroupRule{}
	err = json.Unmarshal([]byte(rules), &secRules)
	if err != nil {
		return false, err
	}
	jsonBytesToCompare, err := json.Marshal(secRules)
	if err != nil {
		return false, err
	}
	match, err := DoesJsonMatch(string(jsonBytes), string(jsonBytesToCompare))
	if err != nil {
		return false, err
	}
	return !match, nil
}

func (m *DefaultManager) AssignSecurityGroupToSpace(space cfclient.Space, secGroup cfclient.SecGroup) error {
	for _, configuredSpace := range secGroup.SpacesData {
		if configuredSpace.Entity.Guid == space.Guid {
			return nil
		}
	}
	if m.Peek {
		lo.G.Infof("[dry-run]: assigning security group %s to space %s", secGroup.Name, space.Name)
		return nil
	}
	lo.G.Infof("assigning security group %s to space %s", secGroup.Name, space.Name)
	return m.Client.BindSecGroup(secGroup.Guid, space.Guid)
}

func (m *DefaultManager) UnassignSecurityGroupToSpace(space cfclient.Space, secGroup cfclient.SecGroup) error {
	for _, configuredSpace := range secGroup.SpacesData {
		if configuredSpace.Entity.Guid == space.Guid {
			return nil
		}
	}
	if m.Peek {
		lo.G.Infof("[dry-run]: unassigning security group %s to space %s", secGroup.Name, space.Name)
		return nil
	}
	lo.G.Infof("unassigning security group %s to space %s", secGroup.Name, space.Name)
	return m.Client.UnbindSecGroup(secGroup.Guid, space.Guid)
}

func (m *DefaultManager) CreateSecurityGroup(sgName, contents string) (*cfclient.SecGroup, error) {
	if m.Peek {
		lo.G.Infof("[dry-run]: creating securityGroup %s with contents %s", sgName, contents)
		return &cfclient.SecGroup{Name: "dry-run-name", Guid: "dry-run-guid"}, nil
	}
	securityGroupRules := []cfclient.SecGroupRule{}
	err := json.Unmarshal([]byte(contents), &securityGroupRules)
	if err != nil {
		return nil, err
	}
	lo.G.Infof("creating securityGroup %s with contents %s", sgName, contents)
	return m.Client.CreateSecGroup(sgName, securityGroupRules, nil)
}

func (m *DefaultManager) UpdateSecurityGroup(sg cfclient.SecGroup, contents string) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: updating securityGroup %s with contents %s", sg.Name, contents)
		return nil
	}
	securityGroupRules := []cfclient.SecGroupRule{}
	err := json.Unmarshal([]byte(contents), &securityGroupRules)
	if err != nil {
		return err
	}
	lo.G.Infof("[dry-run]: updating securityGroup %s with contents %s", sg.Name, contents)
	_, err = m.Client.UpdateSecGroup(sg.Guid, sg.Name, securityGroupRules, nil)
	return err
}
func (m *DefaultManager) ListNonDefaultSecurityGroups() (map[string]cfclient.SecGroup, error) {
	securityGroups := make(map[string]cfclient.SecGroup)
	groupMap, err := m.ListSecurityGroups()
	if err != nil {
		return nil, err
	}
	for key, groupMap := range groupMap {
		if groupMap.Running == false && groupMap.Staging == false {
			securityGroups[key] = groupMap
		}
	}
	return securityGroups, nil
}

func (m *DefaultManager) ListDefaultSecurityGroups() (map[string]cfclient.SecGroup, error) {
	securityGroups := make(map[string]cfclient.SecGroup)
	groupMap, err := m.ListSecurityGroups()
	if err != nil {
		return nil, err
	}
	for key, groupMap := range groupMap {
		if groupMap.Running == true || groupMap.Staging == true {
			securityGroups[key] = groupMap
		}
	}
	return securityGroups, nil
}

func (m *DefaultManager) AssignRunningSecurityGroup(sg cfclient.SecGroup) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: assigning sg %s as running security group", sg.Name)
		return nil
	}
	lo.G.Infof("assigning sg %s as running security group", sg.Name)
	return m.Client.BindRunningSecGroup(sg.Guid)
}
func (m *DefaultManager) AssignStagingSecurityGroup(sg cfclient.SecGroup) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: assigning sg %s as staging security group", sg.Name)
		return nil
	}
	lo.G.Infof("assigning sg %s as staging security group", sg.Name)
	return m.Client.BindStagingSecGroup(sg.Guid)
}
func (m *DefaultManager) UnassignRunningSecurityGroup(sg cfclient.SecGroup) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: unassinging sg %s as running security group", sg.Name)
		return nil
	}
	lo.G.Infof("unassinging sg %s as running security group", sg.Name)
	return m.Client.UnbindRunningSecGroup(sg.Guid)
}
func (m *DefaultManager) UnassignStagingSecurityGroup(sg cfclient.SecGroup) error {
	if m.Peek {
		lo.G.Infof("[dry-run]: unassigning sg %s as staging security group", sg.Name)
		return nil
	}
	lo.G.Infof("unassigning sg %s as staging security group", sg.Name)
	return m.Client.UnbindStagingSecGroup(sg.Guid)
}

func (m *DefaultManager) GetSecurityGroupRules(sgGUID string) ([]byte, error) {
	secGroup, err := m.Client.GetSecGroup(sgGUID)
	if err != nil {
		return nil, err
	}
	return json.MarshalIndent(secGroup.Rules, "", "\t")
}

func (m *DefaultManager) ListSpaceSecurityGroups(spaceGUID string) (map[string]string, error) {
	secGroups, err := m.Client.ListSpaceSecGroups(spaceGUID)
	if err != nil {
		return nil, err
	}
	lo.G.Debug("Total security groups returned :", len(secGroups))
	names := make(map[string]string)
	for _, sg := range secGroups {
		if sg.Running == false && sg.Staging == false {
			names[sg.Name] = sg.Guid
		}
	}
	return names, nil
}
<|endoftext|>