<commit_before>package p2p

import (
	"crypto/ecdsa"
	"crypto/rand"
	"fmt"
	"io"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/obscuren/ecies"
	"github.com/obscuren/secp256k1-go"
)

var (
	sskLen int = 16  // ecies.MaxSharedKeyLength(pubKey) / 2
	sigLen int = 65  // elliptic S256
	pubLen int = 64  // 512 bit pubkey in uncompressed representation without format byte
	keyLen int = 32  // ECDSA
	msgLen int = 194 // sigLen + keyLen + pubLen + keyLen + 1 = 194
	resLen int = 97  // pubLen + keyLen + 1
)

// aesSecret, macSecret, egressMac, ingress
type secretRW struct {
	aesSecret, macSecret, egressMac, ingressMac []byte
}

type cryptoId struct {
	prvKey  *ecdsa.PrivateKey
	pubKey  *ecdsa.PublicKey
	pubKeyS []byte
}

func newCryptoId(id ClientIdentity) (self *cryptoId, err error) {
	// will be at server  init
	var prvKeyS []byte = id.PrivKey()
	if prvKeyS == nil {
		err = fmt.Errorf("no private key for client")
		return
	}
	// initialise ecies private key via importing keys (known via our own clientIdentity)
	// the key format is what elliptic package is using: elliptic.Marshal(Curve, X, Y)
	var prvKey = crypto.ToECDSA(prvKeyS)
	if prvKey == nil {
		err = fmt.Errorf("invalid private key for client")
		return
	}
	self = &cryptoId{
		prvKey: prvKey,
		// initialise public key from the imported private key
		pubKey: &prvKey.PublicKey,
		// to be created at server init shared between peers and sessions
		// for reuse, call wth ReadAt, no reset seek needed
	}
	self.pubKeyS = id.Pubkey()
	return
}

func (self *cryptoId) Run(conn io.ReadWriter, remotePubKeyS []byte, sessionToken []byte, initiator bool) (token []byte, rw *secretRW, err error) {
	var auth, initNonce, recNonce []byte
	var randomPrivKey *ecdsa.PrivateKey
	var remoteRandomPubKey *ecdsa.PublicKey
	if initiator {
		if auth, initNonce, randomPrivKey, _, err = self.startHandshake(remotePubKeyS, sessionToken); err != nil {
			return
		}
		conn.Write(auth)
		var response []byte
		conn.Read(response)
		// write out auth message
		// wait for response, then call complete
		if recNonce, remoteRandomPubKey, _, err = self.completeHandshake(response); err != nil {
			return
		}
	} else {
		conn.Read(auth)
		// we are listening connection. we are responders in the handshake.
		// Extract info from the authentication. The initiator starts by sending us a handshake that we need to respond to.
		// so we read auth message first, then respond
		var response []byte
		if response, recNonce, initNonce, randomPrivKey, remoteRandomPubKey, err = self.respondToHandshake(auth, remotePubKeyS, sessionToken); err != nil {
			return
		}
		conn.Write(response)
	}
	return self.newSession(initNonce, recNonce, auth, randomPrivKey, remoteRandomPubKey)
}

/* startHandshake is called by peer if it initiated the connection.
 By protocol spec, the party who initiates the connection (initiator) will send an 'auth' packet
New: authInitiator -> E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
     authRecipient -> E(remote-pubk, ecdhe-random-pubk || nonce || 0x0)

Known: authInitiator = E(remote-pubk, S(ecdhe-random, token^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x1)
       authRecipient = E(remote-pubk, ecdhe-random-pubk || nonce || 0x1) // token found
       authRecipient = E(remote-pubk, ecdhe-random-pubk || nonce || 0x0) // token not found

The caller provides the public key of the peer as conjuctured from lookup based on IP:port, given as user input or proven by signatures. The caller must have access to persistant information about the peers, and pass the previous session token as an argument to cryptoId.

The handshake is the process by which the peers establish their connection for a session.

*/

func ImportPublicKey(pubKey []byte) (pubKeyEC *ecdsa.PublicKey, err error) {
	var pubKey65 []byte
	switch len(pubKey) {
	case 64:
		pubKey65 = append([]byte{0x04}, pubKey...)
	case 65:
		pubKey65 = pubKey
	default:
		return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey))
	}
	return crypto.ToECDSAPub(pubKey65), nil
}

func ExportPublicKey(pubKeyEC *ecdsa.PublicKey) (pubKey []byte, err error) {
	if pubKeyEC == nil {
		return nil, fmt.Errorf("no ECDSA public key given")
	}
	return crypto.FromECDSAPub(pubKeyEC)[1:], nil
}

func (self *cryptoId) startHandshake(remotePubKeyS, sessionToken []byte) (auth []byte, initNonce []byte, randomPrvKey *ecdsa.PrivateKey, remotePubKey *ecdsa.PublicKey, err error) {
	// session init, common to both parties
	if remotePubKey, err = ImportPublicKey(remotePubKeyS); err != nil {
		return
	}

	var tokenFlag byte
	if sessionToken == nil {
		// no session token found means we need to generate shared secret.
		// ecies shared secret is used as initial session token for new peers
		// generate shared key from prv and remote pubkey
		if sessionToken, err = ecies.ImportECDSA(self.prvKey).GenerateShared(ecies.ImportECDSAPublic(remotePubKey), sskLen, sskLen); err != nil {
			return
		}
		// tokenFlag = 0x00 // redundant
	} else {
		// for known peers, we use stored token from the previous session
		tokenFlag = 0x01
	}

	//E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
	// E(remote-pubk, S(ecdhe-random, token^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x1)
	// allocate msgLen long message,
	var msg []byte = make([]byte, msgLen)
	initNonce = msg[msgLen-keyLen-1 : msgLen-1]
	if _, err = rand.Read(initNonce); err != nil {
		return
	}
	// create known message
	// ecdh-shared-secret^nonce for new peers
	// token^nonce for old peers
	var sharedSecret = Xor(sessionToken, initNonce)

	// generate random keypair to use for signing
	if randomPrvKey, err = crypto.GenerateKey(); err != nil {
		return
	}
	// sign shared secret (message known to both parties): shared-secret
	var signature []byte
	// signature = sign(ecdhe-random, shared-secret)
	// uses secp256k1.Sign
	if signature, err = crypto.Sign(sharedSecret, randomPrvKey); err != nil {
		return
	}

	// message
	// signed-shared-secret || H(ecdhe-random-pubk) || pubk || nonce || 0x0
	copy(msg, signature) // copy signed-shared-secret
	// H(ecdhe-random-pubk)
	var randomPubKey64 []byte
	if randomPubKey64, err = ExportPublicKey(&randomPrvKey.PublicKey); err != nil {
		return
	}
	copy(msg[sigLen:sigLen+keyLen], crypto.Sha3(randomPubKey64))
	// pubkey copied to the correct segment.
	copy(msg[sigLen+keyLen:sigLen+keyLen+pubLen], self.pubKeyS)
	// nonce is already in the slice
	// stick tokenFlag byte to the end
	msg[msgLen-1] = tokenFlag

	// encrypt using remote-pubk
	// auth = eciesEncrypt(remote-pubk, msg)

	if auth, err = crypto.Encrypt(remotePubKey, msg); err != nil {
		return
	}

	return
}

// verifyAuth is called by peer if it accepted (but not initiated) the connection
func (self *cryptoId) respondToHandshake(auth, remotePubKeyS, sessionToken []byte) (authResp []byte, respNonce []byte, initNonce []byte, randomPrivKey *ecdsa.PrivateKey, remoteRandomPubKey *ecdsa.PublicKey, err error) {
	var msg []byte
	var remotePubKey *ecdsa.PublicKey
	if remotePubKey, err = ImportPublicKey(remotePubKeyS); err != nil {
		return
	}

	// they prove that msg is meant for me,
	// I prove I possess private key if i can read it
	if msg, err = crypto.Decrypt(self.prvKey, auth); err != nil {
		return
	}

	var tokenFlag byte
	if sessionToken == nil {
		// no session token found means we need to generate shared secret.
		// ecies shared secret is used as initial session token for new peers
		// generate shared key from prv and remote pubkey
		if sessionToken, err = ecies.ImportECDSA(self.prvKey).GenerateShared(ecies.ImportECDSAPublic(remotePubKey), sskLen, sskLen); err != nil {
			return
		}
		// tokenFlag = 0x00 // redundant
	} else {
		// for known peers, we use stored token from the previous session
		tokenFlag = 0x01
	}

	// the initiator nonce is read off the end of the message
	initNonce = msg[msgLen-keyLen-1 : msgLen-1]
	// I prove that i own prv key (to derive shared secret, and read nonce off encrypted msg) and that I own shared secret
	// they prove they own the private key belonging to ecdhe-random-pubk
	// we can now reconstruct the signed message and recover the peers pubkey
	var signedMsg = Xor(sessionToken, initNonce)
	var remoteRandomPubKeyS []byte
	if remoteRandomPubKeyS, err = secp256k1.RecoverPubkey(signedMsg, msg[:sigLen]); err != nil {
		return
	}
	// convert to ECDSA standard
	if remoteRandomPubKey, err = ImportPublicKey(remoteRandomPubKeyS); err != nil {
		return
	}

	// now we find ourselves a long task too, fill it random
	var resp = make([]byte, resLen)
	// generate keyLen long nonce
	respNonce = resp[pubLen : pubLen+keyLen]
	if _, err = rand.Read(respNonce); err != nil {
		return
	}
	// generate random keypair for session
	if randomPrivKey, err = crypto.GenerateKey(); err != nil {
		return
	}
	// responder auth message
	// E(remote-pubk, ecdhe-random-pubk || nonce || 0x0)
	var randomPubKeyS []byte
	if randomPubKeyS, err = ExportPublicKey(&randomPrivKey.PublicKey); err != nil {
		return
	}
	copy(resp[:pubLen], randomPubKeyS)
	// nonce is already in the slice
	resp[resLen-1] = tokenFlag

	// encrypt using remote-pubk
	// auth = eciesEncrypt(remote-pubk, msg)
	// why not encrypt with ecdhe-random-remote
	if authResp, err = crypto.Encrypt(remotePubKey, resp); err != nil {
		return
	}
	return
}

func (self *cryptoId) completeHandshake(auth []byte) (respNonce []byte, remoteRandomPubKey *ecdsa.PublicKey, tokenFlag bool, err error) {
	var msg []byte
	// they prove that msg is meant for me,
	// I prove I possess private key if i can read it
	if msg, err = crypto.Decrypt(self.prvKey, auth); err != nil {
		return
	}

	respNonce = msg[pubLen : pubLen+keyLen]
	var remoteRandomPubKeyS = msg[:pubLen]
	if remoteRandomPubKey, err = ImportPublicKey(remoteRandomPubKeyS); err != nil {
		return
	}
	if msg[resLen-1] == 0x01 {
		tokenFlag = true
	}
	return
}

func (self *cryptoId) newSession(initNonce, respNonce, auth []byte, privKey *ecdsa.PrivateKey, remoteRandomPubKey *ecdsa.PublicKey) (sessionToken []byte, rw *secretRW, err error) {
	// 3) Now we can trust ecdhe-random-pubk to derive new keys
	//ecdhe-shared-secret = ecdh.agree(ecdhe-random, remote-ecdhe-random-pubk)
	var dhSharedSecret []byte
	pubKey := ecies.ImportECDSAPublic(remoteRandomPubKey)
	if dhSharedSecret, err = ecies.ImportECDSA(privKey).GenerateShared(pubKey, sskLen, sskLen); err != nil {
		return
	}
	// shared-secret = crypto.Sha3(ecdhe-shared-secret || crypto.Sha3(nonce || initiator-nonce))
	var sharedSecret = crypto.Sha3(append(dhSharedSecret, crypto.Sha3(append(respNonce, initNonce...))...))
	// token = crypto.Sha3(shared-secret)
	sessionToken = crypto.Sha3(sharedSecret)
	// aes-secret = crypto.Sha3(ecdhe-shared-secret || shared-secret)
	var aesSecret = crypto.Sha3(append(dhSharedSecret, sharedSecret...))
	// # destroy shared-secret
	// mac-secret = crypto.Sha3(ecdhe-shared-secret || aes-secret)
	var macSecret = crypto.Sha3(append(dhSharedSecret, aesSecret...))
	// # destroy ecdhe-shared-secret
	// egress-mac = crypto.Sha3(mac-secret^nonce || auth)
	var egressMac = crypto.Sha3(append(Xor(macSecret, respNonce), auth...))
	// # destroy nonce
	// ingress-mac = crypto.Sha3(mac-secret^initiator-nonce || auth),
	var ingressMac = crypto.Sha3(append(Xor(macSecret, initNonce), auth...))
	// # destroy remote-nonce
	rw = &secretRW{
		aesSecret:  aesSecret,
		macSecret:  macSecret,
		egressMac:  egressMac,
		ingressMac: ingressMac,
	}
	return
}

// should use cipher.xorBytes from crypto/cipher/xor.go for fast xor
func Xor(one, other []byte) (xor []byte) {
	xor = make([]byte, len(one))
	for i := 0; i < len(one); i++ {
		xor[i] = one[i] ^ other[i]
	}
	return
}
<commit_msg>add code documentation<commit_after>package p2p

import (
	"crypto/ecdsa"
	"crypto/rand"
	"fmt"
	"io"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/obscuren/ecies"
	"github.com/obscuren/secp256k1-go"
)

var (
	sskLen int = 16  // ecies.MaxSharedKeyLength(pubKey) / 2
	sigLen int = 65  // elliptic S256
	pubLen int = 64  // 512 bit pubkey in uncompressed representation without format byte
	keyLen int = 32  // ECDSA
	msgLen int = 194 // sigLen + keyLen + pubLen + keyLen + 1 = 194
	resLen int = 97  // pubLen + keyLen + 1
)

// secretRW implements a message read writer with encryption and authentication
// it is initialised by cryptoId.Run() after a successful crypto handshake
// aesSecret, macSecret, egressMac, ingress
type secretRW struct {
	aesSecret, macSecret, egressMac, ingressMac []byte
}

/*
cryptoId implements the crypto layer for the p2p networking
It is initialised on the node's own identity (which has access to the node's private key) and run separately on a peer connection to set up a secure session after a crypto handshake
After it performs a crypto handshake it returns
*/
type cryptoId struct {
	prvKey  *ecdsa.PrivateKey
	pubKey  *ecdsa.PublicKey
	pubKeyS []byte
}

/*
newCryptoId(id ClientIdentity) initialises a crypto layer manager. This object has a short lifecycle when the peer connection starts. It is survived by a secretRW (an message read writer with encryption and authentication) if the crypto handshake is successful.
*/
func newCryptoId(id ClientIdentity) (self *cryptoId, err error) {
	// will be at server  init
	var prvKeyS []byte = id.PrivKey()
	if prvKeyS == nil {
		err = fmt.Errorf("no private key for client")
		return
	}
	// initialise ecies private key via importing keys (known via our own clientIdentity)
	// the key format is what elliptic package is using: elliptic.Marshal(Curve, X, Y)
	var prvKey = crypto.ToECDSA(prvKeyS)
	if prvKey == nil {
		err = fmt.Errorf("invalid private key for client")
		return
	}
	self = &cryptoId{
		prvKey: prvKey,
		// initialise public key from the imported private key
		pubKey: &prvKey.PublicKey,
		// to be created at server init shared between peers and sessions
		// for reuse, call wth ReadAt, no reset seek needed
	}
	self.pubKeyS = id.Pubkey()
	return
}

/*
Run(connection, remotePublicKey, sessionToken) is called when the peer connection starts to set up a secure session by performing a crypto handshake.

 connection is (a buffered) network connection.

 remotePublicKey is the remote peer's node Id.

 sessionToken is the token from the previous session with this same peer. Nil if no token is found.

 initiator is a boolean flag. True if the node represented by cryptoId is the initiator of the connection (ie., remote is an outbound peer reached by dialing out). False if the connection was established by accepting a call from the remote peer via a listener.

 It returns a secretRW which implements the MsgReadWriter interface.
*/

func (self *cryptoId) Run(conn io.ReadWriter, remotePubKeyS []byte, sessionToken []byte, initiator bool) (token []byte, rw *secretRW, err error) {
	var auth, initNonce, recNonce []byte
	var randomPrivKey *ecdsa.PrivateKey
	var remoteRandomPubKey *ecdsa.PublicKey
	if initiator {
		if auth, initNonce, randomPrivKey, _, err = self.startHandshake(remotePubKeyS, sessionToken); err != nil {
			return
		}
		conn.Write(auth)
		var response []byte
		conn.Read(response)
		// write out auth message
		// wait for response, then call complete
		if recNonce, remoteRandomPubKey, _, err = self.completeHandshake(response); err != nil {
			return
		}
	} else {
		conn.Read(auth)
		// we are listening connection. we are responders in the handshake.
		// Extract info from the authentication. The initiator starts by sending us a handshake that we need to respond to.
		// so we read auth message first, then respond
		var response []byte
		if response, recNonce, initNonce, randomPrivKey, remoteRandomPubKey, err = self.respondToHandshake(auth, remotePubKeyS, sessionToken); err != nil {
			return
		}
		conn.Write(response)
	}
	return self.newSession(initNonce, recNonce, auth, randomPrivKey, remoteRandomPubKey)
}

/*
ImportPublicKey creates a 512 bit *ecsda.PublicKey from a byte slice. It accepts the simple 64 byte uncompressed format or the 65 byte format given by calling elliptic.Marshal on the EC point represented by the key. Any other length will result in an invalid public key error.
*/
func ImportPublicKey(pubKey []byte) (pubKeyEC *ecdsa.PublicKey, err error) {
	var pubKey65 []byte
	switch len(pubKey) {
	case 64:
		pubKey65 = append([]byte{0x04}, pubKey...)
	case 65:
		pubKey65 = pubKey
	default:
		return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey))
	}
	return crypto.ToECDSAPub(pubKey65), nil
}

/*
ExportPublicKey exports a *ecdsa.PublicKey into a byte slice using a simple 64-byte format. and is used for simple serialisation in network communication
*/
func ExportPublicKey(pubKeyEC *ecdsa.PublicKey) (pubKey []byte, err error) {
	if pubKeyEC == nil {
		return nil, fmt.Errorf("no ECDSA public key given")
	}
	return crypto.FromECDSAPub(pubKeyEC)[1:], nil
}

/* startHandshake is called by if the node is the initiator of the connection.

The caller provides the public key of the peer as conjuctured from lookup based on IP:port, given as user input or proven by signatures. The caller must have access to persistant information about the peers, and pass the previous session token as an argument to cryptoId.

The first return value is the auth message that is to be sent out to the remote receiver.
*/
func (self *cryptoId) startHandshake(remotePubKeyS, sessionToken []byte) (auth []byte, initNonce []byte, randomPrvKey *ecdsa.PrivateKey, remotePubKey *ecdsa.PublicKey, err error) {
	// session init, common to both parties
	if remotePubKey, err = ImportPublicKey(remotePubKeyS); err != nil {
		return
	}

	var tokenFlag byte
	if sessionToken == nil {
		// no session token found means we need to generate shared secret.
		// ecies shared secret is used as initial session token for new peers
		// generate shared key from prv and remote pubkey
		if sessionToken, err = ecies.ImportECDSA(self.prvKey).GenerateShared(ecies.ImportECDSAPublic(remotePubKey), sskLen, sskLen); err != nil {
			return
		}
		// tokenFlag = 0x00 // redundant
	} else {
		// for known peers, we use stored token from the previous session
		tokenFlag = 0x01
	}

	//E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
	// E(remote-pubk, S(ecdhe-random, token^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x1)
	// allocate msgLen long message,
	var msg []byte = make([]byte, msgLen)
	initNonce = msg[msgLen-keyLen-1 : msgLen-1]
	if _, err = rand.Read(initNonce); err != nil {
		return
	}
	// create known message
	// ecdh-shared-secret^nonce for new peers
	// token^nonce for old peers
	var sharedSecret = Xor(sessionToken, initNonce)

	// generate random keypair to use for signing
	if randomPrvKey, err = crypto.GenerateKey(); err != nil {
		return
	}
	// sign shared secret (message known to both parties): shared-secret
	var signature []byte
	// signature = sign(ecdhe-random, shared-secret)
	// uses secp256k1.Sign
	if signature, err = crypto.Sign(sharedSecret, randomPrvKey); err != nil {
		return
	}

	// message
	// signed-shared-secret || H(ecdhe-random-pubk) || pubk || nonce || 0x0
	copy(msg, signature) // copy signed-shared-secret
	// H(ecdhe-random-pubk)
	var randomPubKey64 []byte
	if randomPubKey64, err = ExportPublicKey(&randomPrvKey.PublicKey); err != nil {
		return
	}
	copy(msg[sigLen:sigLen+keyLen], crypto.Sha3(randomPubKey64))
	// pubkey copied to the correct segment.
	copy(msg[sigLen+keyLen:sigLen+keyLen+pubLen], self.pubKeyS)
	// nonce is already in the slice
	// stick tokenFlag byte to the end
	msg[msgLen-1] = tokenFlag

	// encrypt using remote-pubk
	// auth = eciesEncrypt(remote-pubk, msg)

	if auth, err = crypto.Encrypt(remotePubKey, msg); err != nil {
		return
	}

	return
}

/*
respondToHandshake is called by peer if it accepted (but not initiated) the connection from the remote. It is passed the initiator handshake received, the public key and session token belonging to the remote initiator.

The first return value is the authentication response (aka receiver handshake) that is to be sent to the remote initiator.
*/
func (self *cryptoId) respondToHandshake(auth, remotePubKeyS, sessionToken []byte) (authResp []byte, respNonce []byte, initNonce []byte, randomPrivKey *ecdsa.PrivateKey, remoteRandomPubKey *ecdsa.PublicKey, err error) {
	var msg []byte
	var remotePubKey *ecdsa.PublicKey
	if remotePubKey, err = ImportPublicKey(remotePubKeyS); err != nil {
		return
	}

	// they prove that msg is meant for me,
	// I prove I possess private key if i can read it
	if msg, err = crypto.Decrypt(self.prvKey, auth); err != nil {
		return
	}

	var tokenFlag byte
	if sessionToken == nil {
		// no session token found means we need to generate shared secret.
		// ecies shared secret is used as initial session token for new peers
		// generate shared key from prv and remote pubkey
		if sessionToken, err = ecies.ImportECDSA(self.prvKey).GenerateShared(ecies.ImportECDSAPublic(remotePubKey), sskLen, sskLen); err != nil {
			return
		}
		// tokenFlag = 0x00 // redundant
	} else {
		// for known peers, we use stored token from the previous session
		tokenFlag = 0x01
	}

	// the initiator nonce is read off the end of the message
	initNonce = msg[msgLen-keyLen-1 : msgLen-1]
	// I prove that i own prv key (to derive shared secret, and read nonce off encrypted msg) and that I own shared secret
	// they prove they own the private key belonging to ecdhe-random-pubk
	// we can now reconstruct the signed message and recover the peers pubkey
	var signedMsg = Xor(sessionToken, initNonce)
	var remoteRandomPubKeyS []byte
	if remoteRandomPubKeyS, err = secp256k1.RecoverPubkey(signedMsg, msg[:sigLen]); err != nil {
		return
	}
	// convert to ECDSA standard
	if remoteRandomPubKey, err = ImportPublicKey(remoteRandomPubKeyS); err != nil {
		return
	}

	// now we find ourselves a long task too, fill it random
	var resp = make([]byte, resLen)
	// generate keyLen long nonce
	respNonce = resp[pubLen : pubLen+keyLen]
	if _, err = rand.Read(respNonce); err != nil {
		return
	}
	// generate random keypair for session
	if randomPrivKey, err = crypto.GenerateKey(); err != nil {
		return
	}
	// responder auth message
	// E(remote-pubk, ecdhe-random-pubk || nonce || 0x0)
	var randomPubKeyS []byte
	if randomPubKeyS, err = ExportPublicKey(&randomPrivKey.PublicKey); err != nil {
		return
	}
	copy(resp[:pubLen], randomPubKeyS)
	// nonce is already in the slice
	resp[resLen-1] = tokenFlag

	// encrypt using remote-pubk
	// auth = eciesEncrypt(remote-pubk, msg)
	// why not encrypt with ecdhe-random-remote
	if authResp, err = crypto.Encrypt(remotePubKey, resp); err != nil {
		return
	}
	return
}

/*
completeHandshake is called when the initiator receives an authentication response (aka receiver handshake). It completes the handshake by reading off parameters the remote peer provides needed to set up the secure session
*/
func (self *cryptoId) completeHandshake(auth []byte) (respNonce []byte, remoteRandomPubKey *ecdsa.PublicKey, tokenFlag bool, err error) {
	var msg []byte
	// they prove that msg is meant for me,
	// I prove I possess private key if i can read it
	if msg, err = crypto.Decrypt(self.prvKey, auth); err != nil {
		return
	}

	respNonce = msg[pubLen : pubLen+keyLen]
	var remoteRandomPubKeyS = msg[:pubLen]
	if remoteRandomPubKey, err = ImportPublicKey(remoteRandomPubKeyS); err != nil {
		return
	}
	if msg[resLen-1] == 0x01 {
		tokenFlag = true
	}
	return
}

/*
newSession is called after the handshake is completed. The arguments are values negotiated in the handshake and the return value is a new session : a new session Token to be remembered for the next time we connect with this peer. And a MsgReadWriter that implements an encrypted and authenticated connection with key material obtained from the crypto handshake key exchange
*/
func (self *cryptoId) newSession(initNonce, respNonce, auth []byte, privKey *ecdsa.PrivateKey, remoteRandomPubKey *ecdsa.PublicKey) (sessionToken []byte, rw *secretRW, err error) {
	// 3) Now we can trust ecdhe-random-pubk to derive new keys
	//ecdhe-shared-secret = ecdh.agree(ecdhe-random, remote-ecdhe-random-pubk)
	var dhSharedSecret []byte
	pubKey := ecies.ImportECDSAPublic(remoteRandomPubKey)
	if dhSharedSecret, err = ecies.ImportECDSA(privKey).GenerateShared(pubKey, sskLen, sskLen); err != nil {
		return
	}
	// shared-secret = crypto.Sha3(ecdhe-shared-secret || crypto.Sha3(nonce || initiator-nonce))
	var sharedSecret = crypto.Sha3(append(dhSharedSecret, crypto.Sha3(append(respNonce, initNonce...))...))
	// token = crypto.Sha3(shared-secret)
	sessionToken = crypto.Sha3(sharedSecret)
	// aes-secret = crypto.Sha3(ecdhe-shared-secret || shared-secret)
	var aesSecret = crypto.Sha3(append(dhSharedSecret, sharedSecret...))
	// # destroy shared-secret
	// mac-secret = crypto.Sha3(ecdhe-shared-secret || aes-secret)
	var macSecret = crypto.Sha3(append(dhSharedSecret, aesSecret...))
	// # destroy ecdhe-shared-secret
	// egress-mac = crypto.Sha3(mac-secret^nonce || auth)
	var egressMac = crypto.Sha3(append(Xor(macSecret, respNonce), auth...))
	// # destroy nonce
	// ingress-mac = crypto.Sha3(mac-secret^initiator-nonce || auth),
	var ingressMac = crypto.Sha3(append(Xor(macSecret, initNonce), auth...))
	// # destroy remote-nonce
	rw = &secretRW{
		aesSecret:  aesSecret,
		macSecret:  macSecret,
		egressMac:  egressMac,
		ingressMac: ingressMac,
	}
	return
}

// TODO: optimisation
// should use cipher.xorBytes from crypto/cipher/xor.go for fast xor
func Xor(one, other []byte) (xor []byte) {
	xor = make([]byte, len(one))
	for i := 0; i < len(one); i++ {
		xor[i] = one[i] ^ other[i]
	}
	return
}
<|endoftext|>


<commit_before>package p2p

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/rand"
	"fmt"
	"io"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/obscuren/ecies"
	"github.com/obscuren/secp256k1-go"
)

var (
	skLen     int = 32                             // ecies.MaxSharedKeyLength(pubKey) / 2
	sigLen    int = 32                             // elliptic S256
	pubKeyLen int = 32                             // ECDSA
	msgLen    int = sigLen + 1 + pubKeyLen + skLen // 97
)

//, aesSecret, macSecret, egressMac, ingress
type secretRW struct {
	aesSecret, macSecret, egressMac, ingressMac []byte
}

type cryptoId struct {
	prvKey  *ecdsa.PrivateKey
	pubKey  *ecdsa.PublicKey
	pubKeyR io.ReaderAt
}

func newCryptoId(id ClientIdentity) (self *cryptoId, err error) {
	// will be at server  init
	var prvKeyDER []byte = id.PrivKey()
	if prvKeyDER == nil {
		err = fmt.Errorf("no private key for client")
		return
	}
	// initialise ecies private key via importing DER encoded keys (known via our own clientIdentity)
	var prvKey = crypto.ToECDSA(prvKeyDER)
	if prvKey == nil {
		err = fmt.Errorf("invalid private key for client")
		return
	}
	self = &cryptoId{
		prvKey: prvKey,
		// initialise public key from the imported private key
		pubKey: &prvKey.PublicKey,
		// to be created at server init shared between peers and sessions
		// for reuse, call wth ReadAt, no reset seek needed
	}
	self.pubKeyR = bytes.NewReader(id.Pubkey())
	return
}

//
func (self *cryptoId) setupAuth(remotePubKeyDER, sessionToken []byte) (auth []byte, nonce []byte, sharedKnowledge []byte, err error) {
	// session init, common to both parties
	var remotePubKey = crypto.ToECDSAPub(remotePubKeyDER)
	if remotePubKey == nil {
		err = fmt.Errorf("invalid remote public key")
		return
	}
	var sharedSecret []byte
	// generate shared key from prv and remote pubkey
	sharedSecret, err = ecies.ImportECDSA(self.prvKey).GenerateShared(ecies.ImportECDSAPublic(remotePubKey), skLen, skLen)
	if err != nil {
		return
	}
	// check previous session token
	if sessionToken == nil {
		err = fmt.Errorf("no session token for peer")
		return
	}
	// allocate msgLen long message
	var msg []byte = make([]byte, msgLen)
	// generate skLen long nonce at the end
	nonce = msg[msgLen-skLen:]
	if _, err = rand.Read(nonce); err != nil {
		return
	}
	// create known message
	// should use
	// cipher.xorBytes from crypto/cipher/xor.go for fast xor
	sharedKnowledge = Xor(sharedSecret, sessionToken)
	var signedMsg = Xor(sharedKnowledge, nonce)

	// generate random keypair to use for signing
	var ecdsaRandomPrvKey *ecdsa.PrivateKey
	if ecdsaRandomPrvKey, err = crypto.GenerateKey(); err != nil {
		return
	}
	// var ecdsaRandomPubKey *ecdsa.PublicKey
	//  ecdsaRandomPubKey= &ecdsaRandomPrvKey.PublicKey

	// message known to both parties ecdh-shared-secret^nonce^token
	var signature []byte
	// signature = sign(ecdhe-random, ecdh-shared-secret^nonce^token)
	// uses secp256k1.Sign
	if signature, err = crypto.Sign(signedMsg, ecdsaRandomPrvKey); err != nil {
		return
	}
	// msg = signature || 0x80 || pubk || nonce
	copy(msg, signature)
	msg[sigLen] = 0x80
	self.pubKeyR.ReadAt(msg[sigLen+1:], int64(pubKeyLen)) // gives pubKeyLen, io.EOF (since we dont read onto the nonce)

	// auth = eciesEncrypt(remote-pubk, msg)
	if auth, err = crypto.Encrypt(remotePubKey, msg); err != nil {
		return
	}
	return
}

func (self *cryptoId) verifyAuth(auth, nonce, sharedKnowledge []byte) (sessionToken []byte, rw *secretRW, err error) {
	var msg []byte
	// they prove that msg is meant for me,
	// I prove I possess private key if i can read it
	if msg, err = crypto.Decrypt(self.prvKey, auth); err != nil {
		return
	}

	var remoteNonce []byte = msg[msgLen-skLen:]
	// I prove that i possess prv key (to derive shared secret, and read nonce off encrypted msg) and that I posessed the earlier one , our shared history
	// they prove they possess their private key to derive the same shared secret, plus the same shared history (previous session token)
	var signedMsg = Xor(sharedKnowledge, remoteNonce)
	var remoteRandomPubKeyDER []byte
	if remoteRandomPubKeyDER, err = secp256k1.RecoverPubkey(signedMsg, msg[:32]); err != nil {
		return
	}
	var remoteRandomPubKey = crypto.ToECDSAPub(remoteRandomPubKeyDER)
	if remoteRandomPubKey == nil {
		err = fmt.Errorf("invalid remote public key")
		return
	}
	// 3) Now we can trust ecdhe-random-pubk to derive keys
	//ecdhe-shared-secret = ecdh.agree(ecdhe-random, remote-ecdhe-random-pubk)
	var dhSharedSecret []byte
	dhSharedSecret, err = ecies.ImportECDSA(self.prvKey).GenerateShared(ecies.ImportECDSAPublic(remoteRandomPubKey), skLen, skLen)
	if err != nil {
		return
	}
	// shared-secret = crypto.Sha3(ecdhe-shared-secret || crypto.Sha3(nonce || initiator-nonce))
	var sharedSecret []byte = crypto.Sha3(append(dhSharedSecret, crypto.Sha3(append(nonce, remoteNonce...))...))
	// token = crypto.Sha3(shared-secret)
	sessionToken = crypto.Sha3(sharedSecret)
	// aes-secret = crypto.Sha3(ecdhe-shared-secret || shared-secret)
	var aesSecret = crypto.Sha3(append(dhSharedSecret, sharedSecret...))
	// # destroy shared-secret
	// mac-secret = crypto.Sha3(ecdhe-shared-secret || aes-secret)
	var macSecret = crypto.Sha3(append(dhSharedSecret, aesSecret...))
	// # destroy ecdhe-shared-secret
	// egress-mac = crypto.Sha3(mac-secret^nonce || auth)
	var egressMac = crypto.Sha3(append(Xor(macSecret, nonce), auth...))
	// # destroy nonce
	// ingress-mac = crypto.Sha3(mac-secret^initiator-nonce || auth),
	var ingressMac = crypto.Sha3(append(Xor(macSecret, remoteNonce), auth...))
	// # destroy remote-nonce
	rw = &secretRW{
		aesSecret:  aesSecret,
		macSecret:  macSecret,
		egressMac:  egressMac,
		ingressMac: ingressMac,
	}
	return
}

func Xor(one, other []byte) (xor []byte) {
	for i := 0; i < len(one); i++ {
		xor[i] = one[i] ^ other[i]
	}
	return
}
<commit_msg>rewrite to comply with latest spec - correct sizes for the blocks : sec signature 65, ecies sklen 16, keylength 32 - added allocation to Xor (should be optimized later) - no pubkey reader needed, just do with copy - restructuring now into INITIATE, RESPOND, COMPLETE -> newSession initialises the encryption/authentication layer - crypto identity can be part of client identity, some initialisation when server created<commit_after>package p2p

import (
	// "bytes"
	"crypto/ecdsa"
	"crypto/rand"
	"fmt"
	// "io"

	"github.com/ethereum/go-ethereum/crypto"
	"github.com/obscuren/ecies"
	"github.com/obscuren/secp256k1-go"
)

var (
	sskLen int = 16                    // ecies.MaxSharedKeyLength(pubKey) / 2
	sigLen int = 65                    // elliptic S256
	keyLen int = 32                    // ECDSA
	msgLen int = sigLen + 3*keyLen + 1 // 162
	resLen int = 65
)

// aesSecret, macSecret, egressMac, ingress
type secretRW struct {
	aesSecret, macSecret, egressMac, ingressMac []byte
}

type cryptoId struct {
	prvKey    *ecdsa.PrivateKey
	pubKey    *ecdsa.PublicKey
	pubKeyDER []byte
}

func newCryptoId(id ClientIdentity) (self *cryptoId, err error) {
	// will be at server  init
	var prvKeyDER []byte = id.PrivKey()
	if prvKeyDER == nil {
		err = fmt.Errorf("no private key for client")
		return
	}
	// initialise ecies private key via importing DER encoded keys (known via our own clientIdentity)
	var prvKey = crypto.ToECDSA(prvKeyDER)
	if prvKey == nil {
		err = fmt.Errorf("invalid private key for client")
		return
	}
	self = &cryptoId{
		prvKey: prvKey,
		// initialise public key from the imported private key
		pubKey: &prvKey.PublicKey,
		// to be created at server init shared between peers and sessions
		// for reuse, call wth ReadAt, no reset seek needed
	}
	self.pubKeyDER = id.Pubkey()
	return
}

// initAuth is called by peer if it initiated the connection
func (self *cryptoId) initAuth(remotePubKeyDER, sessionToken []byte) (auth []byte, initNonce []byte, remotePubKey *ecdsa.PublicKey, err error) {
	// session init, common to both parties
	remotePubKey = crypto.ToECDSAPub(remotePubKeyDER)
	if remotePubKey == nil {
		err = fmt.Errorf("invalid remote public key")
		return
	}

	var tokenFlag byte
	if sessionToken == nil {
		// no session token found means we need to generate shared secret.
		// ecies shared secret is used as initial session token for new peers
		// generate shared key from prv and remote pubkey
		if sessionToken, err = ecies.ImportECDSA(self.prvKey).GenerateShared(ecies.ImportECDSAPublic(remotePubKey), sskLen, sskLen); err != nil {
			return
		}
		fmt.Printf("secret generated: %v %x", len(sessionToken), sessionToken)
		// tokenFlag = 0x00 // redundant
	} else {
		// for known peers, we use stored token from the previous session
		tokenFlag = 0x01
	}

	//E(remote-pubk, S(ecdhe-random, ecdh-shared-secret^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x0)
	// E(remote-pubk, S(ecdhe-random, token^nonce) || H(ecdhe-random-pubk) || pubk || nonce || 0x1)
	// allocate msgLen long message,
	var msg []byte = make([]byte, msgLen)
	// generate sskLen long nonce
	initNonce = msg[msgLen-keyLen-1 : msgLen-1]
	// nonce = msg[msgLen-sskLen-1 : msgLen-1]
	if _, err = rand.Read(initNonce); err != nil {
		return
	}
	// create known message
	// ecdh-shared-secret^nonce for new peers
	// token^nonce for old peers
	var sharedSecret = Xor(sessionToken, initNonce)

	// generate random keypair to use for signing
	var ecdsaRandomPrvKey *ecdsa.PrivateKey
	if ecdsaRandomPrvKey, err = crypto.GenerateKey(); err != nil {
		return
	}
	// sign shared secret (message known to both parties): shared-secret
	var signature []byte
	// signature = sign(ecdhe-random, shared-secret)
	// uses secp256k1.Sign
	if signature, err = crypto.Sign(sharedSecret, ecdsaRandomPrvKey); err != nil {
		return
	}
	fmt.Printf("signature generated: %v %x", len(signature), signature)

	// message
	// signed-shared-secret || H(ecdhe-random-pubk) || pubk || nonce || 0x0
	copy(msg, signature) // copy signed-shared-secret
	// H(ecdhe-random-pubk)
	copy(msg[sigLen:sigLen+keyLen], crypto.Sha3(crypto.FromECDSAPub(&ecdsaRandomPrvKey.PublicKey)))
	// pubkey copied to the correct segment.
	copy(msg[sigLen+keyLen:sigLen+2*keyLen], self.pubKeyDER)
	// nonce is already in the slice
	// stick tokenFlag byte to the end
	msg[msgLen-1] = tokenFlag

	fmt.Printf("plaintext message generated: %v %x", len(msg), msg)

	// encrypt using remote-pubk
	// auth = eciesEncrypt(remote-pubk, msg)

	if auth, err = crypto.Encrypt(remotePubKey, msg); err != nil {
		return
	}
	fmt.Printf("encrypted message generated: %v %x\n used pubkey: %x\n", len(auth), auth, crypto.FromECDSAPub(remotePubKey))

	return
}

// verifyAuth is called by peer if it accepted (but not initiated) the connection
func (self *cryptoId) verifyAuth(auth, sharedSecret []byte, remotePubKey *ecdsa.PublicKey) (authResp []byte, respNonce []byte, initNonce []byte, remoteRandomPubKey *ecdsa.PublicKey, err error) {
	var msg []byte
	fmt.Printf("encrypted message received: %v %x\n used pubkey: %x\n", len(auth), auth, crypto.FromECDSAPub(self.pubKey))
	// they prove that msg is meant for me,
	// I prove I possess private key if i can read it
	if msg, err = crypto.Decrypt(self.prvKey, auth); err != nil {
		return
	}

	// var remoteNonce []byte = msg[msgLen-skLen-1 : msgLen-1]
	initNonce = msg[msgLen-keyLen-1 : msgLen-1]
	// I prove that i own prv key (to derive shared secret, and read nonce off encrypted msg) and that I own shared secret
	// they prove they own the private key belonging to ecdhe-random-pubk
	var signedMsg = Xor(sharedSecret, initNonce)
	var remoteRandomPubKeyDER []byte
	if remoteRandomPubKeyDER, err = secp256k1.RecoverPubkey(signedMsg, msg[:sigLen]); err != nil {
		return
	}
	remoteRandomPubKey = crypto.ToECDSAPub(remoteRandomPubKeyDER)
	if remoteRandomPubKey == nil {
		err = fmt.Errorf("invalid remote public key")
		return
	}

	var resp = make([]byte, 2*keyLen+1)
	// generate sskLen long nonce
	respNonce = msg[msgLen-keyLen-1 : msgLen-1]
	if _, err = rand.Read(respNonce); err != nil {
		return
	}
	// generate random keypair
	var ecdsaRandomPrvKey *ecdsa.PrivateKey
	if ecdsaRandomPrvKey, err = crypto.GenerateKey(); err != nil {
		return
	}
	// var ecdsaRandomPubKey *ecdsa.PublicKey
	//  ecdsaRandomPubKey= &ecdsaRandomPrvKey.PublicKey

	// message
	// E(remote-pubk, ecdhe-random-pubk || nonce || 0x0)
	copy(resp[:keyLen], crypto.FromECDSAPub(&ecdsaRandomPrvKey.PublicKey))
	// pubkey copied to the correct segment.
	copy(resp[keyLen:2*keyLen], self.pubKeyDER)
	// nonce is already in the slice
	// stick tokenFlag byte to the end
	var tokenFlag byte
	if sharedSecret == nil {
	} else {
		// for known peers, we use stored token from the previous session
		tokenFlag = 0x01
	}
	resp[resLen] = tokenFlag

	// encrypt using remote-pubk
	// auth = eciesEncrypt(remote-pubk, msg)
	// why not encrypt with ecdhe-random-remote
	if authResp, err = crypto.Encrypt(remotePubKey, resp); err != nil {
		return
	}
	return
}

func (self *cryptoId) verifyAuthResp(auth []byte) (respNonce []byte, remoteRandomPubKey *ecdsa.PublicKey, tokenFlag bool, err error) {
	var msg []byte
	// they prove that msg is meant for me,
	// I prove I possess private key if i can read it
	if msg, err = crypto.Decrypt(self.prvKey, auth); err != nil {
		return
	}

	respNonce = msg[resLen-keyLen-1 : resLen-1]
	var remoteRandomPubKeyDER = msg[:keyLen]
	remoteRandomPubKey = crypto.ToECDSAPub(remoteRandomPubKeyDER)
	if remoteRandomPubKey == nil {
		err = fmt.Errorf("invalid ecdh random remote public key")
		return
	}
	if msg[resLen-1] == 0x01 {
		tokenFlag = true
	}
	return
}

func (self *cryptoId) newSession(initNonce, respNonce, auth []byte, remoteRandomPubKey *ecdsa.PublicKey) (sessionToken []byte, rw *secretRW, err error) {
	// 3) Now we can trust ecdhe-random-pubk to derive new keys
	//ecdhe-shared-secret = ecdh.agree(ecdhe-random, remote-ecdhe-random-pubk)
	var dhSharedSecret []byte
	dhSharedSecret, err = ecies.ImportECDSA(self.prvKey).GenerateShared(ecies.ImportECDSAPublic(remoteRandomPubKey), sskLen, sskLen)
	if err != nil {
		return
	}
	// shared-secret = crypto.Sha3(ecdhe-shared-secret || crypto.Sha3(nonce || initiator-nonce))
	var sharedSecret = crypto.Sha3(append(dhSharedSecret, crypto.Sha3(append(respNonce, initNonce...))...))
	// token = crypto.Sha3(shared-secret)
	sessionToken = crypto.Sha3(sharedSecret)
	// aes-secret = crypto.Sha3(ecdhe-shared-secret || shared-secret)
	var aesSecret = crypto.Sha3(append(dhSharedSecret, sharedSecret...))
	// # destroy shared-secret
	// mac-secret = crypto.Sha3(ecdhe-shared-secret || aes-secret)
	var macSecret = crypto.Sha3(append(dhSharedSecret, aesSecret...))
	// # destroy ecdhe-shared-secret
	// egress-mac = crypto.Sha3(mac-secret^nonce || auth)
	var egressMac = crypto.Sha3(append(Xor(macSecret, respNonce), auth...))
	// # destroy nonce
	// ingress-mac = crypto.Sha3(mac-secret^initiator-nonce || auth),
	var ingressMac = crypto.Sha3(append(Xor(macSecret, initNonce), auth...))
	// # destroy remote-nonce
	rw = &secretRW{
		aesSecret:  aesSecret,
		macSecret:  macSecret,
		egressMac:  egressMac,
		ingressMac: ingressMac,
	}
	return
}

// should use cipher.xorBytes from crypto/cipher/xor.go for fast xor
func Xor(one, other []byte) (xor []byte) {
	xor = make([]byte, len(one))
	for i := 0; i < len(one); i++ {
		xor[i] = one[i] ^ other[i]
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// A collection of tests for a file system backed by a GCS bucket, where in
// most cases we interact with the file system directly for creating and
// mofiying files (rather than through the side channel of the GCS bucket
// itself).
//
// These tests are registered by RegisterFSTests.

package fstesting

import (
	"io/ioutil"
	"math"
	"os"
	"path"
	"time"

	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////////////////
// Read-write interaction
////////////////////////////////////////////////////////////////////////

type readWriteTest struct {
	fsTest
}

func (t *readWriteTest) OpenNonExistent_CreateFlagNotSet() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenNonExistent_ReadOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenNonExistent_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenNonExistent_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenExistingFile_ReadOnly() {
	// Create a file.
	const contents = "tacoburritoenchilada"
	AssertEq(
		nil,
		ioutil.WriteFile(
			path.Join(t.mfs.Dir(), "foo"),
			[]byte(contents),
			os.FileMode(0644)))

	// Open the file for reading.
	f, err := os.Open(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	defer func() {
		ExpectEq(nil, f.Close())
	}()

	// Check its vitals.
	ExpectEq(path.Join(t.mfs.Dir(), "foo"), f.Name())

	fi, err := f.Stat()
	ExpectEq("foo", fi.Name())
	ExpectEq(len(contents), fi.Size())
	ExpectEq(os.FileMode(0644), fi.Mode())
	ExpectLt(math.Abs(time.Since(fi.ModTime()).Seconds()), 10)
	ExpectFalse(fi.IsDir())

	// Read its contents.
	fileContents, err := ioutil.ReadAll(f)
	AssertEq(nil, err)
	ExpectEq(contents, string(fileContents))
}

func (t *readWriteTest) OpenExistingFile_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenExistingFile_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateExistingFile_ReadOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateExistingFile_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateExistingFile_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenAlreadyOpenedFile_ReadOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenAlreadyOpenedFile_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenAlreadyOpenedFile_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenReadOnlyFileForWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Seek() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Stat() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Sync() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Truncate() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) CreateEmptyDirectory() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) CreateWithinSubDirectory() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenWithinSubDirectory() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateWithinSubDirectory() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) ReadFromWriteOnlyFile() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) WriteToReadOnlyFile() {
	AssertTrue(false, "TODO")
}
<commit_msg>Added some test names.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)
//
// A collection of tests for a file system backed by a GCS bucket, where in
// most cases we interact with the file system directly for creating and
// mofiying files (rather than through the side channel of the GCS bucket
// itself).
//
// These tests are registered by RegisterFSTests.

package fstesting

import (
	"io/ioutil"
	"math"
	"os"
	"path"
	"time"

	. "github.com/jacobsa/ogletest"
)

////////////////////////////////////////////////////////////////////////
// Read-write interaction
////////////////////////////////////////////////////////////////////////

type readWriteTest struct {
	fsTest
}

func (t *readWriteTest) OpenNonExistent_CreateFlagNotSet() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenNonExistent_ReadOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenNonExistent_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenNonExistent_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenExistingFile_ReadOnly() {
	// Create a file.
	const contents = "tacoburritoenchilada"
	AssertEq(
		nil,
		ioutil.WriteFile(
			path.Join(t.mfs.Dir(), "foo"),
			[]byte(contents),
			os.FileMode(0644)))

	// Open the file for reading.
	f, err := os.Open(path.Join(t.mfs.Dir(), "foo"))
	AssertEq(nil, err)

	defer func() {
		ExpectEq(nil, f.Close())
	}()

	// Check its vitals.
	ExpectEq(path.Join(t.mfs.Dir(), "foo"), f.Name())

	fi, err := f.Stat()
	ExpectEq("foo", fi.Name())
	ExpectEq(len(contents), fi.Size())
	ExpectEq(os.FileMode(0644), fi.Mode())
	ExpectLt(math.Abs(time.Since(fi.ModTime()).Seconds()), 10)
	ExpectFalse(fi.IsDir())

	// Read its contents.
	fileContents, err := ioutil.ReadAll(f)
	AssertEq(nil, err)
	ExpectEq(contents, string(fileContents))
}

func (t *readWriteTest) OpenExistingFile_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenExistingFile_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateExistingFile_ReadOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateExistingFile_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateExistingFile_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenAlreadyOpenedFile_ReadOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenAlreadyOpenedFile_WriteOnly() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenAlreadyOpenedFile_ReadWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenReadOnlyFileForWrite() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Seek() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Stat() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Sync() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) Truncate() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) CreateEmptyDirectory() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) CreateWithinSubDirectory() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) OpenWithinSubDirectory() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) TruncateWithinSubDirectory() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) ReadFromWriteOnlyFile() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) WriteToReadOnlyFile() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) StatUnopenedFile() {
	AssertTrue(false, "TODO")
}

func (t *readWriteTest) LstatUnopenedFile() {
	AssertTrue(false, "TODO")
}
<|endoftext|>


<commit_before>package mantle

import (
	"errors"
	"fmt"
	"github.com/bradfitz/gomemcache/memcache"
	"github.com/vireshas/minimal_vitess_pool/pools"
	"strings"
	"time"
)

var MemcachePoolSize = 10
var DefaultMemcacheIpAndHost = []string{"localhost:11211"}

func CreateMemcacheConnection(Instance interface{}) (pools.Resource, error) {
	mcInstance := Instance.(*Memcache)
	hostNPorts := mcInstance.Settings.HostAndPorts
	servers := strings.Join(hostNPorts, ",")
	fmt.Println("connecting to ", servers)
	cli := memcache.New(servers)
	return &MemConn{cli}, nil
}

type MemConn struct {
	*memcache.Client
}

func (m *MemConn) Close() {
}

type Memcache struct {
	Settings PoolSettings
	pool     *ResourcePool
}

func (m *Memcache) GetClient() *MemConn {
	connection, err := m.pool.GetConn(m.Settings.Timeout)
	if err != nil {
		panic(err)
	}
	return connection.(*MemConn)
}

func (m *Memcache) PutClient(c *MemConn) {
	m.pool.PutConn(c)
}

func (m *Memcache) SetDefaults() {
	if len(m.Settings.HostAndPorts) == 0 {
		m.Settings.HostAndPorts = DefaultMemcacheIpAndHost
	}
	if m.Settings.Capacity == 0 {
		m.Settings.Capacity = MemcachePoolSize
	}
	if m.Settings.MaxCapacity == 0 {
		m.Settings.MaxCapacity = MemcachePoolSize
	}
	m.Settings.Timeout = time.Minute
	m.pool = NewPool(CreateMemcacheConnection, m, m.Settings)
}

func (m *Memcache) Configure(settings PoolSettings) {
	m.Settings = settings
	m.SetDefaults()
}

func (m *Memcache) Execute(cmd string, args ...interface{}) (interface{}, error) {
	return "inside GEt", nil
}

func (m *Memcache) Delete(key string) int {
	mc := m.GetClient()
	err := mc.Delete(key)
	m.PutClient(mc)
	return err
}

func (m *Memcache) Get(key string) (string, error) {
	mc := m.GetClient()
	it, erm := mc.Get(key)
	m.PutClient(mc)
	if erm != nil {
		errMsg := fmt.Sprintf("Error in getting key %s: %s", key, erm)
		return nil, errors.New(errMsg)
	}
	return string(it.Value), nil
}

func (m *Memcache) Set(key string, value string) (bool, error) {
	mc := m.GetClient()
	erm := mc.Set(&memcache.Item{Key: key, Value: []byte(value)})
	m.PutClient(mc)
	if erm != nil {
		return false, errors.New()
	}
	return true, nil
}

func (m *Memcache) MGet(keys []string) ([]string, error) {
	mc := m.GetClient()
	items, err := mc.GetMulti(keys)
	m.PutClient(mc)
	if err != nil {
		return []string{}, err
	}
	arr := make([]string{})
	for _, key := range keys {
		if item, ok := items[key]; ok {
			arr = append(arr, string(item.Value))
		} else {
			arr = append(arr, "")
		}
	}
	return arr, nil
}

func (m *Memcache) Expire(key string, duration int) error {
	mc := m.GetClient()
	err := mc.Touch(key, duration)
	m.PutClient(mc)
	return err
}

func (m *Memcache) SetEx(key string, duration int, val string) error {
	mc := m.GetClient()
	erm := mc.Set(&memcache.Item{Key: key, Value: []byte(val)})
	if erm != nil {
		return fmt.Sprintf("Failed to set key: %s", erm)
	} else {
		err := mc.Touch(key, duration)
		m.PutClient(mc)
		return err
	}
}
<commit_msg>fix memcache to implement mantle<commit_after>package mantle

import (
	"fmt"
	"github.com/bradfitz/gomemcache/memcache"
	"github.com/vireshas/minimal_vitess_pool/pools"
	"strings"
	"time"
)

var MemcachePoolSize = 10
var DefaultMemcacheIpAndHost = []string{"localhost:11211"}

func CreateMemcacheConnection(Instance interface{}) (pools.Resource, error) {
	mcInstance := Instance.(*Memcache)
	hostNPorts := mcInstance.Settings.HostAndPorts
	servers := strings.Join(hostNPorts, ",")
	fmt.Println("connecting to ", servers)
	cli := memcache.New(servers)
	return &MemConn{cli}, nil
}

type MemConn struct {
	*memcache.Client
}

func (m *MemConn) Close() {
}

type Memcache struct {
	Settings PoolSettings
	pool     *ResourcePool
}

func (m *Memcache) GetClient() *MemConn {
	connection, err := m.pool.GetConn(m.Settings.Timeout)
	if err != nil {
		panic(err)
	}
	return connection.(*MemConn)
}

func (m *Memcache) PutClient(c *MemConn) {
	m.pool.PutConn(c)
}

func (m *Memcache) SetDefaults() {
	if len(m.Settings.HostAndPorts) == 0 {
		m.Settings.HostAndPorts = DefaultMemcacheIpAndHost
	}
	if m.Settings.Capacity == 0 {
		m.Settings.Capacity = MemcachePoolSize
	}
	if m.Settings.MaxCapacity == 0 {
		m.Settings.MaxCapacity = MemcachePoolSize
	}
	m.Settings.Timeout = time.Minute
	m.pool = NewPool(CreateMemcacheConnection, m, m.Settings)
}

func (m *Memcache) Configure(settings PoolSettings) {
	m.Settings = settings
	m.SetDefaults()
}

func (m *Memcache) Execute(cmd string, args ...interface{}) (interface{}, error) {
	return "inside GEt", nil
}

func (m *Memcache) Delete(keys ...interface{}) int {
	mc := m.GetClient()
	for _, key := range keys {
		skey := key.(string)
		err := mc.Delete(skey)
		if err != nil {
			fmt.Println("error deleting key:", err)
		}
	}
	m.PutClient(mc)
	return 1
}

func (m *Memcache) Get(key string) string {
	mc := m.GetClient()
	it, erm := mc.Get(key)
	m.PutClient(mc)
	if erm != nil {
		errMsg := fmt.Sprintf("Error in getting key %s: %s", key, erm)
		fmt.Println(errMsg)
		return ""
	}
	return string(it.Value)
}

func (m *Memcache) Set(key string, value interface{}) bool {
	svalue := value.(string)
	mc := m.GetClient()
	erm := mc.Set(&memcache.Item{Key: key, Value: []byte(svalue)})
	m.PutClient(mc)
	if erm != nil {
		fmt.Println(erm)
		return false
	}
	return true
}

func (m *Memcache) MSet(keyValMap map[string]interface{}) bool {
	return false
}

func (m *Memcache) MGet(keys ...interface{}) []string {
	skeys := make([]string, len(keys))
	for _, key := range keys {
		skeys = append(skeys, key.(string))
	}
	mc := m.GetClient()
	items, err := mc.GetMulti(skeys)
	m.PutClient(mc)
	if err != nil {
		return []string{}
	}
	arr := make([]string, 10)
	for _, key := range skeys {
		if item, ok := items[key]; ok {
			arr = append(arr, string(item.Value))
		} else {
			arr = append(arr, "")
		}
	}
	return arr
}

func (m *Memcache) Expire(key string, duration int) bool {
	mc := m.GetClient()
	err := mc.Touch(key, int32(duration))
	m.PutClient(mc)
	if err != nil {
		return false
	}
	return true
}

func (m *Memcache) Setex(key string, duration int, val interface{}) bool {
	mc := m.GetClient()
	defer m.PutClient(mc)
	sval := val.(string)
	erm := mc.Set(&memcache.Item{Key: key, Value: []byte(sval)})
	if erm != nil {
		return false
	} else {
		err := mc.Touch(key, int32(duration))

		if err != nil {
			return false
		}
	}
	return true
}
<|endoftext|>


<commit_before>package hdfs

import (
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func waitTruncate(t *testing.T, client *Client, name string, size int64) {
	done, err := client.Truncate(name, size)
	require.NoError(t, err)

	var stat os.FileInfo
	if !done {
		for i := 0; i < 5; i++ {
			stat, err = client.Stat(name)
			require.NoError(t, err)

			if stat.Size() == size {
				break
			}

			time.Sleep(500 * time.Millisecond)
			t.Log("Waiting for truncate to finish")
		}
	} else {
		stat, err = client.Stat(name)
		require.NoError(t, err)
	}

	assert.EqualValues(t, size, stat.Size())
}

func TestTruncate(t *testing.T) {
	client := getClient(t)

	baleet(t, "/_test/truncate/1.txt")
	mkdirp(t, "/_test/truncate")
	f, err := client.Create("/_test/truncate/1.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("foobar\nfoobar\n"))
	assert.Equal(t, 14, n)
	require.NoError(t, err)

	assertClose(t, f)

	waitTruncate(t, client, "/_test/truncate/1.txt", 4)
}

func TestTruncateToZero(t *testing.T) {
	client := getClient(t)

	baleet(t, "/_test/truncate/2.txt")
	mkdirp(t, "/_test/truncate")
	f, err := client.Create("/_test/truncate/2.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("foobarbaz"))
	assert.Equal(t, 9, n)
	require.NoError(t, err)

	assertClose(t, f)

	waitTruncate(t, client, "/_test/truncate/2.txt", 0)
}

func TestTruncateSizeTooBig(t *testing.T) {
	client := getClient(t)

	baleet(t, "/_test/truncate/3.txt")
	mkdirp(t, "/_test/truncate")

	f, err := client.Create("/_test/truncate/3.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("foo"))
	assert.Equal(t, 3, n)
	require.NoError(t, err)

	assertClose(t, f)

	done, err := client.Truncate("/_test/truncate/3.txt", 100)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/truncate/3.txt", os.ErrInvalid)
}

func TestTruncateSizeNegative(t *testing.T) {
	client := getClient(t)

	baleet(t, "/_test/truncate/4.txt")
	mkdirp(t, "/_test/truncate")

	f, err := client.Create("/_test/truncate/4.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("foo"))
	assert.Equal(t, 3, n)
	require.NoError(t, err)

	assertClose(t, f)

	done, err := client.Truncate("/_test/truncate/4.txt", -10)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/truncate/4.txt", os.ErrInvalid)
}

func TestTruncateNoExist(t *testing.T) {
	client := getClient(t)

	done, err := client.Truncate("/_test/nonexistent", 100)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/nonexistent", os.ErrNotExist)
}

func TestTruncateDir(t *testing.T) {
	client := getClient(t)

	mkdirp(t, "/_test/truncate")

	done, err := client.Truncate("/_test/truncate", 100)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/truncate", os.ErrNotExist)
}

func TestTruncateWithoutPermission(t *testing.T) {
	client := getClient(t)
	client2 := getClientForUser(t, "gohdfs2")

	baleet(t, "/_test/truncate/5.txt")
	mkdirp(t, "/_test/truncate")

	f, err := client.Create("/_test/truncate/5.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("barbar"))
	assert.Equal(t, 6, n)
	require.NoError(t, err)

	assertClose(t, f)

	done, err := client2.Truncate("/_test/truncate/5.txt", 1)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/truncate/5.txt", os.ErrPermission)

	stat, err := client.Stat("/_test/truncate/5.txt")
	require.NoError(t, err)
	assert.EqualValues(t, 6, stat.Size())
}
<commit_msg>Wait longer for Truncate to finish in tests<commit_after>package hdfs

import (
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func waitTruncate(t *testing.T, client *Client, name string, size int64) {
	done, err := client.Truncate(name, size)
	require.NoError(t, err)

	var stat os.FileInfo
	if !done {
		for i := 0; i < 10; i++ {
			stat, err = client.Stat(name)
			require.NoError(t, err)

			if stat.Size() == size {
				break
			}

			time.Sleep(500 * time.Millisecond)
			t.Log("Waiting for truncate to finish")
		}
	} else {
		stat, err = client.Stat(name)
		require.NoError(t, err)
	}

	assert.EqualValues(t, size, stat.Size())
}

func TestTruncate(t *testing.T) {
	client := getClient(t)

	baleet(t, "/_test/truncate/1.txt")
	mkdirp(t, "/_test/truncate")
	f, err := client.Create("/_test/truncate/1.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("foobar\nfoobar\n"))
	assert.Equal(t, 14, n)
	require.NoError(t, err)

	assertClose(t, f)

	waitTruncate(t, client, "/_test/truncate/1.txt", 4)
}

func TestTruncateToZero(t *testing.T) {
	client := getClient(t)

	baleet(t, "/_test/truncate/2.txt")
	mkdirp(t, "/_test/truncate")
	f, err := client.Create("/_test/truncate/2.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("foobarbaz"))
	assert.Equal(t, 9, n)
	require.NoError(t, err)

	assertClose(t, f)

	waitTruncate(t, client, "/_test/truncate/2.txt", 0)
}

func TestTruncateSizeTooBig(t *testing.T) {
	client := getClient(t)

	baleet(t, "/_test/truncate/3.txt")
	mkdirp(t, "/_test/truncate")

	f, err := client.Create("/_test/truncate/3.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("foo"))
	assert.Equal(t, 3, n)
	require.NoError(t, err)

	assertClose(t, f)

	done, err := client.Truncate("/_test/truncate/3.txt", 100)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/truncate/3.txt", os.ErrInvalid)
}

func TestTruncateSizeNegative(t *testing.T) {
	client := getClient(t)

	baleet(t, "/_test/truncate/4.txt")
	mkdirp(t, "/_test/truncate")

	f, err := client.Create("/_test/truncate/4.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("foo"))
	assert.Equal(t, 3, n)
	require.NoError(t, err)

	assertClose(t, f)

	done, err := client.Truncate("/_test/truncate/4.txt", -10)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/truncate/4.txt", os.ErrInvalid)
}

func TestTruncateNoExist(t *testing.T) {
	client := getClient(t)

	done, err := client.Truncate("/_test/nonexistent", 100)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/nonexistent", os.ErrNotExist)
}

func TestTruncateDir(t *testing.T) {
	client := getClient(t)

	mkdirp(t, "/_test/truncate")

	done, err := client.Truncate("/_test/truncate", 100)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/truncate", os.ErrNotExist)
}

func TestTruncateWithoutPermission(t *testing.T) {
	client := getClient(t)
	client2 := getClientForUser(t, "gohdfs2")

	baleet(t, "/_test/truncate/5.txt")
	mkdirp(t, "/_test/truncate")

	f, err := client.Create("/_test/truncate/5.txt")
	require.NoError(t, err)

	n, err := f.Write([]byte("barbar"))
	assert.Equal(t, 6, n)
	require.NoError(t, err)

	assertClose(t, f)

	done, err := client2.Truncate("/_test/truncate/5.txt", 1)
	assert.False(t, done)
	assertPathError(t, err, "truncate", "/_test/truncate/5.txt", os.ErrPermission)

	stat, err := client.Stat("/_test/truncate/5.txt")
	require.NoError(t, err)
	assert.EqualValues(t, 6, stat.Size())
}
<|endoftext|>


<commit_before>package server

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"

	"github.com/Sirupsen/logrus"
	"github.com/kubernetes-incubator/ocid/oci"
	"github.com/kubernetes-incubator/ocid/utils"
	"github.com/opencontainers/runtime-tools/generate"
	"golang.org/x/net/context"
	pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
)

const (
	// ContainerStateCreated represents the created state of a container
	ContainerStateCreated = "created"
	// ContainerStateRunning represents the running state of a container
	ContainerStateRunning = "running"
	// ContainerStateStopped represents the stopped state of a container
	ContainerStateStopped = "stopped"
)

// CreateContainer creates a new container in specified PodSandbox
func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerRequest) (*pb.CreateContainerResponse, error) {
	// The id of the PodSandbox
	podSandboxID := req.GetPodSandboxId()
	sb := s.getSandbox(podSandboxID)
	if sb == nil {
		return nil, fmt.Errorf("the pod sandbox (%s) does not exist", podSandboxID)
	}
	// The config of the container
	containerConfig := req.GetConfig()
	if containerConfig == nil {
		return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig is nil")
	}

	name := containerConfig.GetMetadata().GetName()
	if name == "" {
		return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Name is empty")
	}

	// containerDir is the dir for the container bundle.
	containerDir := filepath.Join(s.runtime.ContainerDir(), name)

	if _, err := os.Stat(containerDir); err == nil {
		return nil, fmt.Errorf("container (%s) already exists", containerDir)
	}

	if err := os.MkdirAll(containerDir, 0755); err != nil {
		return nil, err
	}

	container, err := s.createSandboxContainer(name, sb, req.GetSandboxConfig(), containerDir, containerConfig)
	if err != nil {
		return nil, err
	}

	if err := s.runtime.CreateContainer(container); err != nil {
		return nil, err
	}

	if err := s.runtime.UpdateStatus(container); err != nil {
		return nil, err
	}

	s.addContainer(container)

	return &pb.CreateContainerResponse{
		ContainerId: &name,
	}, nil
}

func (s *Server) createSandboxContainer(name string, sb *sandbox, SandboxConfig *pb.PodSandboxConfig, containerDir string, containerConfig *pb.ContainerConfig) (*oci.Container, error) {
	if sb == nil {
		return nil, errors.New("createSandboxContainer needs a sandbox")
	}
	// creates a spec Generator with the default spec.
	specgen := generate.New()

	// by default, the root path is an empty string.
	// here set it to be "rootfs".
	specgen.SetRootPath("rootfs")

	args := containerConfig.GetArgs()
	if args == nil {
		args = []string{"/bin/sh"}
	}
	specgen.SetProcessArgs(args)

	cwd := containerConfig.GetWorkingDir()
	if cwd == "" {
		cwd = "/"
	}
	specgen.SetProcessCwd(cwd)

	envs := containerConfig.GetEnvs()
	if envs != nil {
		for _, item := range envs {
			key := item.GetKey()
			value := item.GetValue()
			if key == "" {
				continue
			}
			env := fmt.Sprintf("%s=%s", key, value)
			specgen.AddProcessEnv(env)
		}
	}

	mounts := containerConfig.GetMounts()
	for _, mount := range mounts {
		dest := mount.GetContainerPath()
		if dest == "" {
			return nil, fmt.Errorf("Mount.ContainerPath is empty")
		}

		src := mount.GetHostPath()
		if src == "" {
			return nil, fmt.Errorf("Mount.HostPath is empty")
		}

		options := "rw"
		if mount.GetReadonly() {
			options = "ro"
		}

		//TODO(hmeng): how to use this info? Do we need to handle relabel a FS with Selinux?
		//selinuxRelabel := mount.GetSelinuxRelabel()

		specgen.AddBindMount(src, dest, options)

	}

	labels := containerConfig.GetLabels()

	annotations := containerConfig.GetAnnotations()
	if annotations != nil {
		for k, v := range annotations {
			specgen.AddAnnotation(k, v)
		}
	}

	if containerConfig.GetPrivileged() {
		specgen.SetupPrivileged(true)
	}

	if containerConfig.GetReadonlyRootfs() {
		specgen.SetRootReadonly(true)
	}

	logPath := containerConfig.GetLogPath()

	if containerConfig.GetTty() {
		specgen.SetProcessTerminal(true)
	}

	linux := containerConfig.GetLinux()
	if linux != nil {
		resources := linux.GetResources()
		if resources != nil {
			cpuPeriod := resources.GetCpuPeriod()
			if cpuPeriod != 0 {
				specgen.SetLinuxResourcesCPUPeriod(uint64(cpuPeriod))
			}

			cpuQuota := resources.GetCpuQuota()
			if cpuQuota != 0 {
				specgen.SetLinuxResourcesCPUQuota(uint64(cpuQuota))
			}

			cpuShares := resources.GetCpuShares()
			if cpuShares != 0 {
				specgen.SetLinuxResourcesCPUShares(uint64(cpuShares))
			}

			memoryLimit := resources.GetMemoryLimitInBytes()
			if memoryLimit != 0 {
				specgen.SetLinuxResourcesMemoryLimit(uint64(memoryLimit))
			}

			oomScoreAdj := resources.GetOomScoreAdj()
			specgen.SetLinuxResourcesOOMScoreAdj(int(oomScoreAdj))
		}

		capabilities := linux.GetCapabilities()
		if capabilities != nil {
			addCaps := capabilities.GetAddCapabilities()
			if addCaps != nil {
				for _, cap := range addCaps {
					if err := specgen.AddProcessCapability(cap); err != nil {
						return nil, err
					}
				}
			}

			dropCaps := capabilities.GetDropCapabilities()
			if dropCaps != nil {
				for _, cap := range dropCaps {
					if err := specgen.DropProcessCapability(cap); err != nil {
						return nil, err
					}
				}
			}
		}

		selinuxOptions := linux.GetSelinuxOptions()
		if selinuxOptions != nil {
			user := selinuxOptions.GetUser()
			if user == "" {
				return nil, fmt.Errorf("SELinuxOption.User is empty")
			}

			role := selinuxOptions.GetRole()
			if role == "" {
				return nil, fmt.Errorf("SELinuxOption.Role is empty")
			}

			t := selinuxOptions.GetType()
			if t == "" {
				return nil, fmt.Errorf("SELinuxOption.Type is empty")
			}

			level := selinuxOptions.GetLevel()
			if level == "" {
				return nil, fmt.Errorf("SELinuxOption.Level is empty")
			}

			specgen.SetProcessSelinuxLabel(fmt.Sprintf("%s:%s:%s:%s", user, role, t, level))
		}

		user := linux.GetUser()
		if user != nil {
			uid := user.GetUid()
			specgen.SetProcessUID(uint32(uid))

			gid := user.GetGid()
			specgen.SetProcessGID(uint32(gid))

			groups := user.GetAdditionalGids()
			if groups != nil {
				for _, group := range groups {
					specgen.AddProcessAdditionalGid(uint32(group))
				}
			}
		}
	}
	// Join the namespace paths for the pod sandbox container.
	podContainerName := sb.name + "-infra"
	podInfraContainer := s.state.containers.Get(podContainerName)
	podInfraState := s.runtime.ContainerStatus(podInfraContainer)

	logrus.Infof("pod container state %v", podInfraState)

	for nsType, nsFile := range map[string]string{
		"ipc":     "ipc",
		"uts":     "uts",
		"network": "net",
	} {
		nsPath := fmt.Sprintf("/proc/%d/ns/%s", podInfraState.Pid, nsFile)
		if err := specgen.AddOrReplaceLinuxNamespace(nsType, nsPath); err != nil {
			return nil, err
		}
	}

	if err := specgen.SaveToFile(filepath.Join(containerDir, "config.json")); err != nil {
		return nil, err
	}

	imageSpec := containerConfig.GetImage()
	if imageSpec == nil {
		return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Image is nil")
	}

	image := imageSpec.GetImage()
	if image == "" {
		return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Image.Image is empty")
	}

	// TODO: copy the rootfs into the bundle.
	// Currently, utils.CreateFakeRootfs is used to populate the rootfs.
	if err := utils.CreateFakeRootfs(containerDir, image); err != nil {
		return nil, err
	}

	container, err := oci.NewContainer(name, containerDir, logPath, labels, sb.id, containerConfig.GetTty())
	if err != nil {
		return nil, err
	}

	return container, nil
}

// StartContainer starts the container.
func (s *Server) StartContainer(ctx context.Context, req *pb.StartContainerRequest) (*pb.StartContainerResponse, error) {
	containerName := req.ContainerId

	if *containerName == "" {
		return nil, fmt.Errorf("container ID should not be empty")
	}
	c := s.state.containers.Get(*containerName)
	if c == nil {
		return nil, fmt.Errorf("specified container not found: %s", *containerName)
	}

	if err := s.runtime.StartContainer(c); err != nil {
		return nil, fmt.Errorf("failed to start container %s in sandbox %s: %v", c.Name(), *containerName, err)
	}

	return &pb.StartContainerResponse{}, nil
}

// StopContainer stops a running container with a grace period (i.e., timeout).
func (s *Server) StopContainer(ctx context.Context, req *pb.StopContainerRequest) (*pb.StopContainerResponse, error) {
	containerName := req.ContainerId

	if *containerName == "" {
		return nil, fmt.Errorf("container ID should not be empty")
	}
	c := s.state.containers.Get(*containerName)
	if c == nil {
		return nil, fmt.Errorf("specified container not found: %s", *containerName)
	}

	if err := s.runtime.StopContainer(c); err != nil {
		return nil, fmt.Errorf("failed to stop container %s: %v", *containerName, err)
	}

	return &pb.StopContainerResponse{}, nil
}

// RemoveContainer removes the container. If the container is running, the container
// should be force removed.
func (s *Server) RemoveContainer(ctx context.Context, req *pb.RemoveContainerRequest) (*pb.RemoveContainerResponse, error) {
	containerName := req.ContainerId

	if *containerName == "" {
		return nil, fmt.Errorf("container ID should not be empty")
	}
	c := s.state.containers.Get(*containerName)
	if c == nil {
		return nil, fmt.Errorf("specified container not found: %s", *containerName)
	}

	if err := s.runtime.DeleteContainer(c); err != nil {
		return nil, fmt.Errorf("failed to delete container %s: %v", *containerName, err)
	}

	containerDir := filepath.Join(s.runtime.ContainerDir(), *containerName)
	if err := os.RemoveAll(containerDir); err != nil {
		return nil, fmt.Errorf("failed to remove container %s directory: %v", *containerName, err)
	}

	s.removeContainer(c)

	return &pb.RemoveContainerResponse{}, nil
}

// ListContainers lists all containers by filters.
func (s *Server) ListContainers(context.Context, *pb.ListContainersRequest) (*pb.ListContainersResponse, error) {
	return nil, nil
}

// ContainerStatus returns status of the container.
func (s *Server) ContainerStatus(ctx context.Context, req *pb.ContainerStatusRequest) (*pb.ContainerStatusResponse, error) {
	containerName := req.ContainerId

	if *containerName == "" {
		return nil, fmt.Errorf("container ID should not be empty")
	}
	c := s.state.containers.Get(*containerName)

	if c == nil {
		return nil, fmt.Errorf("specified container not found: %s", *containerName)
	}

	if err := s.runtime.UpdateStatus(c); err != nil {
		return nil, err
	}

	csr := &pb.ContainerStatusResponse{
		Status: &pb.ContainerStatus{
			Id: containerName,
		},
	}

	cState := s.runtime.ContainerStatus(c)
	rStatus := pb.ContainerState_UNKNOWN

	switch cState.Status {
	case ContainerStateCreated:
		rStatus = pb.ContainerState_CREATED
		created := cState.Created.Unix()
		csr.Status.CreatedAt = int64Ptr(created)
	case ContainerStateRunning:
		rStatus = pb.ContainerState_RUNNING
		created := cState.Created.Unix()
		csr.Status.CreatedAt = int64Ptr(created)
		started := cState.Started.Unix()
		csr.Status.StartedAt = int64Ptr(started)
	case ContainerStateStopped:
		rStatus = pb.ContainerState_EXITED
		created := cState.Created.Unix()
		csr.Status.CreatedAt = int64Ptr(created)
		started := cState.Started.Unix()
		csr.Status.StartedAt = int64Ptr(started)
		finished := cState.Finished.Unix()
		csr.Status.FinishedAt = int64Ptr(finished)
		csr.Status.ExitCode = int32Ptr(cState.ExitCode)
	}

	csr.Status.State = &rStatus

	return csr, nil
}

// Exec executes the command in the container.
func (s *Server) Exec(pb.RuntimeService_ExecServer) error {
	return nil
}
<commit_msg>Allow specifying short pod IDs for container create<commit_after>package server

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"

	"github.com/Sirupsen/logrus"
	"github.com/kubernetes-incubator/ocid/oci"
	"github.com/kubernetes-incubator/ocid/utils"
	"github.com/opencontainers/runtime-tools/generate"
	"golang.org/x/net/context"
	pb "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
)

const (
	// ContainerStateCreated represents the created state of a container
	ContainerStateCreated = "created"
	// ContainerStateRunning represents the running state of a container
	ContainerStateRunning = "running"
	// ContainerStateStopped represents the stopped state of a container
	ContainerStateStopped = "stopped"
)

// CreateContainer creates a new container in specified PodSandbox
func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerRequest) (*pb.CreateContainerResponse, error) {
	sbID := req.GetPodSandboxId()
	if sbID == "" {
		return nil, fmt.Errorf("PodSandboxId should not be empty")
	}

	sandboxID, err := s.podIDIndex.Get(sbID)
	if err != nil {
		return nil, fmt.Errorf("PodSandbox with ID starting with %s not found: %v", sbID, err)
	}

	sb := s.getSandbox(sandboxID)
	if sb == nil {
		return nil, fmt.Errorf("specified sandbox not found: %s", sandboxID)
	}

	// The config of the container
	containerConfig := req.GetConfig()
	if containerConfig == nil {
		return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig is nil")
	}

	name := containerConfig.GetMetadata().GetName()
	if name == "" {
		return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Name is empty")
	}

	// containerDir is the dir for the container bundle.
	containerDir := filepath.Join(s.runtime.ContainerDir(), name)

	if _, err = os.Stat(containerDir); err == nil {
		return nil, fmt.Errorf("container (%s) already exists", containerDir)
	}

	if err = os.MkdirAll(containerDir, 0755); err != nil {
		return nil, err
	}

	container, err := s.createSandboxContainer(name, sb, req.GetSandboxConfig(), containerDir, containerConfig)
	if err != nil {
		return nil, err
	}

	if err := s.runtime.CreateContainer(container); err != nil {
		return nil, err
	}

	if err := s.runtime.UpdateStatus(container); err != nil {
		return nil, err
	}

	s.addContainer(container)

	return &pb.CreateContainerResponse{
		ContainerId: &name,
	}, nil
}

func (s *Server) createSandboxContainer(name string, sb *sandbox, SandboxConfig *pb.PodSandboxConfig, containerDir string, containerConfig *pb.ContainerConfig) (*oci.Container, error) {
	if sb == nil {
		return nil, errors.New("createSandboxContainer needs a sandbox")
	}
	// creates a spec Generator with the default spec.
	specgen := generate.New()

	// by default, the root path is an empty string.
	// here set it to be "rootfs".
	specgen.SetRootPath("rootfs")

	args := containerConfig.GetArgs()
	if args == nil {
		args = []string{"/bin/sh"}
	}
	specgen.SetProcessArgs(args)

	cwd := containerConfig.GetWorkingDir()
	if cwd == "" {
		cwd = "/"
	}
	specgen.SetProcessCwd(cwd)

	envs := containerConfig.GetEnvs()
	if envs != nil {
		for _, item := range envs {
			key := item.GetKey()
			value := item.GetValue()
			if key == "" {
				continue
			}
			env := fmt.Sprintf("%s=%s", key, value)
			specgen.AddProcessEnv(env)
		}
	}

	mounts := containerConfig.GetMounts()
	for _, mount := range mounts {
		dest := mount.GetContainerPath()
		if dest == "" {
			return nil, fmt.Errorf("Mount.ContainerPath is empty")
		}

		src := mount.GetHostPath()
		if src == "" {
			return nil, fmt.Errorf("Mount.HostPath is empty")
		}

		options := "rw"
		if mount.GetReadonly() {
			options = "ro"
		}

		//TODO(hmeng): how to use this info? Do we need to handle relabel a FS with Selinux?
		//selinuxRelabel := mount.GetSelinuxRelabel()

		specgen.AddBindMount(src, dest, options)

	}

	labels := containerConfig.GetLabels()

	annotations := containerConfig.GetAnnotations()
	if annotations != nil {
		for k, v := range annotations {
			specgen.AddAnnotation(k, v)
		}
	}

	if containerConfig.GetPrivileged() {
		specgen.SetupPrivileged(true)
	}

	if containerConfig.GetReadonlyRootfs() {
		specgen.SetRootReadonly(true)
	}

	logPath := containerConfig.GetLogPath()

	if containerConfig.GetTty() {
		specgen.SetProcessTerminal(true)
	}

	linux := containerConfig.GetLinux()
	if linux != nil {
		resources := linux.GetResources()
		if resources != nil {
			cpuPeriod := resources.GetCpuPeriod()
			if cpuPeriod != 0 {
				specgen.SetLinuxResourcesCPUPeriod(uint64(cpuPeriod))
			}

			cpuQuota := resources.GetCpuQuota()
			if cpuQuota != 0 {
				specgen.SetLinuxResourcesCPUQuota(uint64(cpuQuota))
			}

			cpuShares := resources.GetCpuShares()
			if cpuShares != 0 {
				specgen.SetLinuxResourcesCPUShares(uint64(cpuShares))
			}

			memoryLimit := resources.GetMemoryLimitInBytes()
			if memoryLimit != 0 {
				specgen.SetLinuxResourcesMemoryLimit(uint64(memoryLimit))
			}

			oomScoreAdj := resources.GetOomScoreAdj()
			specgen.SetLinuxResourcesOOMScoreAdj(int(oomScoreAdj))
		}

		capabilities := linux.GetCapabilities()
		if capabilities != nil {
			addCaps := capabilities.GetAddCapabilities()
			if addCaps != nil {
				for _, cap := range addCaps {
					if err := specgen.AddProcessCapability(cap); err != nil {
						return nil, err
					}
				}
			}

			dropCaps := capabilities.GetDropCapabilities()
			if dropCaps != nil {
				for _, cap := range dropCaps {
					if err := specgen.DropProcessCapability(cap); err != nil {
						return nil, err
					}
				}
			}
		}

		selinuxOptions := linux.GetSelinuxOptions()
		if selinuxOptions != nil {
			user := selinuxOptions.GetUser()
			if user == "" {
				return nil, fmt.Errorf("SELinuxOption.User is empty")
			}

			role := selinuxOptions.GetRole()
			if role == "" {
				return nil, fmt.Errorf("SELinuxOption.Role is empty")
			}

			t := selinuxOptions.GetType()
			if t == "" {
				return nil, fmt.Errorf("SELinuxOption.Type is empty")
			}

			level := selinuxOptions.GetLevel()
			if level == "" {
				return nil, fmt.Errorf("SELinuxOption.Level is empty")
			}

			specgen.SetProcessSelinuxLabel(fmt.Sprintf("%s:%s:%s:%s", user, role, t, level))
		}

		user := linux.GetUser()
		if user != nil {
			uid := user.GetUid()
			specgen.SetProcessUID(uint32(uid))

			gid := user.GetGid()
			specgen.SetProcessGID(uint32(gid))

			groups := user.GetAdditionalGids()
			if groups != nil {
				for _, group := range groups {
					specgen.AddProcessAdditionalGid(uint32(group))
				}
			}
		}
	}
	// Join the namespace paths for the pod sandbox container.
	podContainerName := sb.name + "-infra"
	podInfraContainer := s.state.containers.Get(podContainerName)
	podInfraState := s.runtime.ContainerStatus(podInfraContainer)

	logrus.Infof("pod container state %v", podInfraState)

	for nsType, nsFile := range map[string]string{
		"ipc":     "ipc",
		"uts":     "uts",
		"network": "net",
	} {
		nsPath := fmt.Sprintf("/proc/%d/ns/%s", podInfraState.Pid, nsFile)
		if err := specgen.AddOrReplaceLinuxNamespace(nsType, nsPath); err != nil {
			return nil, err
		}
	}

	if err := specgen.SaveToFile(filepath.Join(containerDir, "config.json")); err != nil {
		return nil, err
	}

	imageSpec := containerConfig.GetImage()
	if imageSpec == nil {
		return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Image is nil")
	}

	image := imageSpec.GetImage()
	if image == "" {
		return nil, fmt.Errorf("CreateContainerRequest.ContainerConfig.Image.Image is empty")
	}

	// TODO: copy the rootfs into the bundle.
	// Currently, utils.CreateFakeRootfs is used to populate the rootfs.
	if err := utils.CreateFakeRootfs(containerDir, image); err != nil {
		return nil, err
	}

	container, err := oci.NewContainer(name, containerDir, logPath, labels, sb.id, containerConfig.GetTty())
	if err != nil {
		return nil, err
	}

	return container, nil
}

// StartContainer starts the container.
func (s *Server) StartContainer(ctx context.Context, req *pb.StartContainerRequest) (*pb.StartContainerResponse, error) {
	containerName := req.ContainerId

	if *containerName == "" {
		return nil, fmt.Errorf("container ID should not be empty")
	}
	c := s.state.containers.Get(*containerName)
	if c == nil {
		return nil, fmt.Errorf("specified container not found: %s", *containerName)
	}

	if err := s.runtime.StartContainer(c); err != nil {
		return nil, fmt.Errorf("failed to start container %s in sandbox %s: %v", c.Name(), *containerName, err)
	}

	return &pb.StartContainerResponse{}, nil
}

// StopContainer stops a running container with a grace period (i.e., timeout).
func (s *Server) StopContainer(ctx context.Context, req *pb.StopContainerRequest) (*pb.StopContainerResponse, error) {
	containerName := req.ContainerId

	if *containerName == "" {
		return nil, fmt.Errorf("container ID should not be empty")
	}
	c := s.state.containers.Get(*containerName)
	if c == nil {
		return nil, fmt.Errorf("specified container not found: %s", *containerName)
	}

	if err := s.runtime.StopContainer(c); err != nil {
		return nil, fmt.Errorf("failed to stop container %s: %v", *containerName, err)
	}

	return &pb.StopContainerResponse{}, nil
}

// RemoveContainer removes the container. If the container is running, the container
// should be force removed.
func (s *Server) RemoveContainer(ctx context.Context, req *pb.RemoveContainerRequest) (*pb.RemoveContainerResponse, error) {
	containerName := req.ContainerId

	if *containerName == "" {
		return nil, fmt.Errorf("container ID should not be empty")
	}
	c := s.state.containers.Get(*containerName)
	if c == nil {
		return nil, fmt.Errorf("specified container not found: %s", *containerName)
	}

	if err := s.runtime.DeleteContainer(c); err != nil {
		return nil, fmt.Errorf("failed to delete container %s: %v", *containerName, err)
	}

	containerDir := filepath.Join(s.runtime.ContainerDir(), *containerName)
	if err := os.RemoveAll(containerDir); err != nil {
		return nil, fmt.Errorf("failed to remove container %s directory: %v", *containerName, err)
	}

	s.removeContainer(c)

	return &pb.RemoveContainerResponse{}, nil
}

// ListContainers lists all containers by filters.
func (s *Server) ListContainers(context.Context, *pb.ListContainersRequest) (*pb.ListContainersResponse, error) {
	return nil, nil
}

// ContainerStatus returns status of the container.
func (s *Server) ContainerStatus(ctx context.Context, req *pb.ContainerStatusRequest) (*pb.ContainerStatusResponse, error) {
	containerName := req.ContainerId

	if *containerName == "" {
		return nil, fmt.Errorf("container ID should not be empty")
	}
	c := s.state.containers.Get(*containerName)

	if c == nil {
		return nil, fmt.Errorf("specified container not found: %s", *containerName)
	}

	if err := s.runtime.UpdateStatus(c); err != nil {
		return nil, err
	}

	csr := &pb.ContainerStatusResponse{
		Status: &pb.ContainerStatus{
			Id: containerName,
		},
	}

	cState := s.runtime.ContainerStatus(c)
	rStatus := pb.ContainerState_UNKNOWN

	switch cState.Status {
	case ContainerStateCreated:
		rStatus = pb.ContainerState_CREATED
		created := cState.Created.Unix()
		csr.Status.CreatedAt = int64Ptr(created)
	case ContainerStateRunning:
		rStatus = pb.ContainerState_RUNNING
		created := cState.Created.Unix()
		csr.Status.CreatedAt = int64Ptr(created)
		started := cState.Started.Unix()
		csr.Status.StartedAt = int64Ptr(started)
	case ContainerStateStopped:
		rStatus = pb.ContainerState_EXITED
		created := cState.Created.Unix()
		csr.Status.CreatedAt = int64Ptr(created)
		started := cState.Started.Unix()
		csr.Status.StartedAt = int64Ptr(started)
		finished := cState.Finished.Unix()
		csr.Status.FinishedAt = int64Ptr(finished)
		csr.Status.ExitCode = int32Ptr(cState.ExitCode)
	}

	csr.Status.State = &rStatus

	return csr, nil
}

// Exec executes the command in the container.
func (s *Server) Exec(pb.RuntimeService_ExecServer) error {
	return nil
}
<|endoftext|>


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

package tsuru

import (
	"errors"
	"strings"

	"github.com/tsuru/tsuru-autoscale/db"
	"gopkg.in/mgo.v2/bson"
)

// Instance represents a tsuru service instance.
type Instance struct {
	ID   bson.ObjectId `bson:"_id"`
	Name string
	User string
	Team string
	Apps []string
}

func (i *Instance) update() error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	return conn.Instances().UpdateId(i.ID, i)
}

func contains(list []string, item string) bool {
	for _, i := range list {
		if i == item {
			return true
		}
	}
	return false
}

func appFromHost(host string) string {
	return strings.Split(host, ".")[0]
}

// AddApp add new app to an instance.
func (i *Instance) AddApp(host string) error {
	app := appFromHost(host)
	if contains(i.Apps, app) {
		return errors.New("")
	}
	i.Apps = append(i.Apps, app)
	return i.update()
}

// NewInstance creates a new service instance.
func NewInstance(i *Instance) error {
	if i.ID.Hex() == "" {
		i.ID = bson.NewObjectId()
	}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	return conn.Instances().Insert(i)
}

// GetInstanceByName finds a service instance by name.
func GetInstanceByName(name string) (*Instance, error) {
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	var i Instance
	err = conn.Instances().Find(bson.M{"name": name}).One(&i)
	if err != nil {
		return nil, err
	}
	return &i, nil
}
<commit_msg>tsuru: add more logs.<commit_after>// Copyright 2015 tsuru-autoscale authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package tsuru

import (
	"errors"
	stdlog "log"
	"strings"

	"github.com/tsuru/tsuru-autoscale/db"
	"github.com/tsuru/tsuru-autoscale/log"
	"gopkg.in/mgo.v2/bson"
)

func logger() *stdlog.Logger {
	return log.Logger()
}

// Instance represents a tsuru service instance.
type Instance struct {
	ID   bson.ObjectId `bson:"_id"`
	Name string
	User string
	Team string
	Apps []string
}

func (i *Instance) update() error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	return conn.Instances().UpdateId(i.ID, i)
}

func contains(list []string, item string) bool {
	for _, i := range list {
		if i == item {
			return true
		}
	}
	return false
}

func appFromHost(host string) string {
	return strings.Split(host, ".")[0]
}

// AddApp add new app to an instance.
func (i *Instance) AddApp(host string) error {
	app := appFromHost(host)
	if contains(i.Apps, app) {
		return errors.New("")
	}
	i.Apps = append(i.Apps, app)
	return i.update()
}

// NewInstance creates a new service instance.
func NewInstance(i *Instance) error {
	if i.ID.Hex() == "" {
		i.ID = bson.NewObjectId()
	}
	conn, err := db.Conn()
	if err != nil {
		logger().Print(err.Error())
		return err
	}
	defer conn.Close()
	return conn.Instances().Insert(i)
}

// GetInstanceByName finds a service instance by name.
func GetInstanceByName(name string) (*Instance, error) {
	conn, err := db.Conn()
	if err != nil {
		logger().Print(err.Error())
		return nil, err
	}
	defer conn.Close()
	var i Instance
	err = conn.Instances().Find(bson.M{"name": name}).One(&i)
	if err != nil {
		logger().Print(err.Error())
		return nil, err
	}
	return &i, nil
}
<|endoftext|>


<commit_before>package tun

import (
	"net"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"unsafe"
)

const (
	cIFF_TUN   = 0x0001
	cIFF_TAP   = 0x0002
	cIFF_NO_PI = 0x1000
)

type ifReq struct {
	Name  [0x10]byte
	Flags uint16
	pad   [0x28 - 0x10 - 2]byte
}

func openDevice(name string) (*os.File, error) {
	return os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
}

func createInterface(file *os.File, name string) (string, error) {
	var req ifReq
	req.Flags = 0
	copy(req.Name[:15], name)
	req.Flags = cIFF_TUN | cIFF_NO_PI
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		file.Fd(),
		uintptr(syscall.TUNSETIFF),
		uintptr(unsafe.Pointer(&req)),
	)
	if err != 0 {
		return "", err
	}
	return strings.Trim(string(req.Name[:]), "\x00"), nil
}

func setupInterface(name string, local_ip string) error {
	err := exec.Command("ip", "link", "set", name, "up").Run()
	if err != nil {
		return err
	}

	ip_net := net.IPNet{net.ParseIP(local_ip), net.CIDRMask(24, 32)}
	err = exec.Command("ip", "link", "add", ip_net.String(), "dev", name).Run()
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>setup interface under linux<commit_after>package tun

import (
	"net"
	"os"
	"os/exec"
	"strings"
	"syscall"
	"unsafe"
	"log"
)

const (
	cIFF_TUN   = 0x0001
	cIFF_TAP   = 0x0002
	cIFF_NO_PI = 0x1000
)

type ifReq struct {
	Name  [0x10]byte
	Flags uint16
	pad   [0x28 - 0x10 - 2]byte
}

func openDevice(name string) (*os.File, error) {
	return os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
}

func createInterface(file *os.File, name string) (string, error) {
	var req ifReq
	req.Flags = 0
	copy(req.Name[:15], name)
	req.Flags = cIFF_TUN | cIFF_NO_PI
	_, _, err := syscall.Syscall(syscall.SYS_IOCTL,
		file.Fd(),
		uintptr(syscall.TUNSETIFF),
		uintptr(unsafe.Pointer(&req)),
	)
	if err != 0 {
		return "", err
	}
	return strings.Trim(string(req.Name[:]), "\x00"), nil
}

func setupInterface(name string, local_ip string) error {
	ip_net := net.IPNet{net.ParseIP(local_ip), net.CIDRMask(24, 32)}

	log.Printf("ifconfig %s %s", name, ip_net.String())
	err = exec.Command("ifconfig", name, ip_net.String()).Run()
	if err != nil {
		return err
	}

	log.Printf("ifconfig %s mtu 1500 up", name)
	err = exec.Command("ifconfig", name, "mtu", "1500", "up").Run()
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package cloudflare

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"github.com/pkg/errors"
)

// TunnelRoute is the full record for a route.
type TunnelRoute struct {
	Network    string     `json:"network"`
	TunnelId   string     `json:"tunnel_id"`
	TunnelName string     `json:"tunnel_name"`
	Comment    string     `json:"comment"`
	CreatedAt  *time.Time `json:"created_at"`
	DeletedAt  *time.Time `json:"deleted_at"`
}

type TunnelRoutesListParams struct {
	PaginationOptions
	TunnelId        string     `json:"tunnel_id,omitempty"`
	Comment         string     `json:"comment,omitempty"`
	IsDeleted       *bool      `json:"is_deleted,omitempty"`
	NetworkSubset   string     `json:"network_subset,omitempty"`
	NetworkSuperset string     `json:"network_superset,omitempty"`
	ExistedAt       *time.Time `json:"existed_at,omitempty"`
}

// tunnelRouteListResponse is the API response for listing tunnel routes.
type tunnelRouteListResponse struct {
	Response
	Result []TunnelRoute `json:"result"`
}

type tunnelRouteResponse struct {
	Response
	Result TunnelRoute `json:"result"`
}

func extractTunnelRouteResponse(responseBody []byte, err error) (TunnelRoute, error) {
	if err != nil {
		return TunnelRoute{}, err
	}

	var routeResponse tunnelRouteResponse
	err = json.Unmarshal(responseBody, &routeResponse)
	if err != nil {
		return TunnelRoute{}, errors.Wrap(err, errUnmarshalError)
	}

	return routeResponse.Result, nil
}

// TunnelRoutes lists all defined routes for tunnels in the account.
//
// See: https://api.cloudflare.com/#tunnel-route-list-tunnel-routes
func (api *API) TunnelRoutes(ctx context.Context, params TunnelRoutesListParams) ([]TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes", AccountRouteRoot, api.AccountID)
	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, params)

	if err != nil {
		return []TunnelRoute{}, err
	}

	var resp tunnelRouteListResponse
	err = json.Unmarshal(res, &resp)
	if err != nil {
		return []TunnelRoute{}, errors.Wrap(err, errUnmarshalError)
	}

	return resp.Result, nil
}

// TunnelRouteForIp finds the Tunnel Route that encompasses the given IP
//
// See: https://api.cloudflare.com/#tunnel-route-get-tunnel-route-by-ip
func (api *API) TunnelRouteForIP(ctx context.Context, ip string) (TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes/ip/%s", AccountRouteRoot, api.AccountID, ip)
	return extractTunnelRouteResponse(api.makeRequestContext(ctx, http.MethodGet, uri, nil))
}

// CreateTunnelRoute add a new route to the account's routing table for the given tunnel.
//
// See: https://api.cloudflare.com/#tunnel-route-create-route
func (api *API) CreateTunnelRoute(ctx context.Context, tunnelId string, ipNetwork string, comment string) (TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes/network/%s", AccountRouteRoot, api.AccountID, url.PathEscape(ipNetwork))

	params := make(map[string]string)
	params["tunnel_id"] = tunnelId
	if comment != "" {
		params["comment"] = comment
	}

	return extractTunnelRouteResponse(api.makeRequestContext(ctx, http.MethodPost, uri, params))
}

// DeleteTunnelRoute delete an existing route from the account's routing table
//
// See: https://api.cloudflare.com/#tunnel-route-delete-route
func (api *API) DeleteTunnelRoute(ctx context.Context, ipNetwork string) (TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes/network/%s", AccountRouteRoot, api.AccountID, url.PathEscape(ipNetwork))
	return extractTunnelRouteResponse(api.makeRequestContext(ctx, http.MethodDelete, uri, nil))
}

// UpdateTunnelRoute update an existing route in the account's routing table for the given tunnel
//
// See: https://api.cloudflare.com/#tunnel-route-update-route
func (api *API) UpdateTunnelRoute(ctx context.Context, tunnelId string, currentNetwork, newNetwork, comment string) (TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes/network/%s", AccountRouteRoot, api.AccountID, url.PathEscape(currentNetwork))

	params := map[string]string{
		"tunnel_id":   tunnelId,
		"new_network": newNetwork,
	}
	if comment != "" {
		params["comment"] = comment
	}

	return extractTunnelRouteResponse(api.makeRequestContext(ctx, http.MethodPatch, uri, params))
}
<commit_msg>Inline `extractTunnelRouteResponse` where it was used.<commit_after>package cloudflare

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"github.com/pkg/errors"
)

// TunnelRoute is the full record for a route.
type TunnelRoute struct {
	Network    string     `json:"network"`
	TunnelId   string     `json:"tunnel_id"`
	TunnelName string     `json:"tunnel_name"`
	Comment    string     `json:"comment"`
	CreatedAt  *time.Time `json:"created_at"`
	DeletedAt  *time.Time `json:"deleted_at"`
}

type TunnelRoutesListParams struct {
	PaginationOptions
	TunnelId        string     `json:"tunnel_id,omitempty"`
	Comment         string     `json:"comment,omitempty"`
	IsDeleted       *bool      `json:"is_deleted,omitempty"`
	NetworkSubset   string     `json:"network_subset,omitempty"`
	NetworkSuperset string     `json:"network_superset,omitempty"`
	ExistedAt       *time.Time `json:"existed_at,omitempty"`
}

// tunnelRouteListResponse is the API response for listing tunnel routes.
type tunnelRouteListResponse struct {
	Response
	Result []TunnelRoute `json:"result"`
}

type tunnelRouteResponse struct {
	Response
	Result TunnelRoute `json:"result"`
}

// TunnelRoutes lists all defined routes for tunnels in the account.
//
// See: https://api.cloudflare.com/#tunnel-route-list-tunnel-routes
func (api *API) TunnelRoutes(ctx context.Context, params TunnelRoutesListParams) ([]TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes", AccountRouteRoot, api.AccountID)
	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, params)

	if err != nil {
		return []TunnelRoute{}, err
	}

	var resp tunnelRouteListResponse
	err = json.Unmarshal(res, &resp)
	if err != nil {
		return []TunnelRoute{}, errors.Wrap(err, errUnmarshalError)
	}

	return resp.Result, nil
}

// TunnelRouteForIp finds the Tunnel Route that encompasses the given IP
//
// See: https://api.cloudflare.com/#tunnel-route-get-tunnel-route-by-ip
func (api *API) TunnelRouteForIP(ctx context.Context, ip string) (TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes/ip/%s", AccountRouteRoot, api.AccountID, ip)

	responseBody, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
	if err != nil {
		return TunnelRoute{}, err
	}

	var routeResponse tunnelRouteResponse
	err = json.Unmarshal(responseBody, &routeResponse)
	if err != nil {
		return TunnelRoute{}, errors.Wrap(err, errUnmarshalError)
	}

	return routeResponse.Result, nil
}

// CreateTunnelRoute add a new route to the account's routing table for the given tunnel.
//
// See: https://api.cloudflare.com/#tunnel-route-create-route
func (api *API) CreateTunnelRoute(ctx context.Context, tunnelId string, ipNetwork string, comment string) (TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes/network/%s", AccountRouteRoot, api.AccountID, url.PathEscape(ipNetwork))

	params := make(map[string]string)
	params["tunnel_id"] = tunnelId
	if comment != "" {
		params["comment"] = comment
	}

	responseBody, err := api.makeRequestContext(ctx, http.MethodPost, uri, params)
	if err != nil {
		return TunnelRoute{}, err
	}

	var routeResponse tunnelRouteResponse
	err = json.Unmarshal(responseBody, &routeResponse)
	if err != nil {
		return TunnelRoute{}, errors.Wrap(err, errUnmarshalError)
	}

	return routeResponse.Result, nil
}

// DeleteTunnelRoute delete an existing route from the account's routing table
//
// See: https://api.cloudflare.com/#tunnel-route-delete-route
func (api *API) DeleteTunnelRoute(ctx context.Context, ipNetwork string) (TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes/network/%s", AccountRouteRoot, api.AccountID, url.PathEscape(ipNetwork))

	responseBody, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
	if err != nil {
		return TunnelRoute{}, err
	}

	var routeResponse tunnelRouteResponse
	err = json.Unmarshal(responseBody, &routeResponse)
	if err != nil {
		return TunnelRoute{}, errors.Wrap(err, errUnmarshalError)
	}

	return routeResponse.Result, nil
}

// UpdateTunnelRoute update an existing route in the account's routing table for the given tunnel
//
// See: https://api.cloudflare.com/#tunnel-route-update-route
func (api *API) UpdateTunnelRoute(ctx context.Context, tunnelId string, currentNetwork, newNetwork, comment string) (TunnelRoute, error) {
	uri := fmt.Sprintf("/%s/%s/teamnet/routes/network/%s", AccountRouteRoot, api.AccountID, url.PathEscape(currentNetwork))

	params := map[string]string{
		"tunnel_id":   tunnelId,
		"new_network": newNetwork,
	}
	if comment != "" {
		params["comment"] = comment
	}

	responseBody, err := api.makeRequestContext(ctx, http.MethodPatch, uri, params)
	if err != nil {
		return TunnelRoute{}, err
	}

	var routeResponse tunnelRouteResponse
	err = json.Unmarshal(responseBody, &routeResponse)
	if err != nil {
		return TunnelRoute{}, errors.Wrap(err, errUnmarshalError)
	}

	return routeResponse.Result, nil
}
<|endoftext|>