<commit_before>package ethchain

import (
	"fmt"
	"github.com/ethereum/eth-go/ethutil"
	"math/big"
	"time"
)

type BlockInfo struct {
	Number uint64
	Hash   []byte
	Parent []byte
}

func (bi *BlockInfo) RlpDecode(data []byte) {
	decoder := ethutil.NewValueFromBytes(data)

	bi.Number = decoder.Get(0).Uint()
	bi.Hash = decoder.Get(1).Bytes()
	bi.Parent = decoder.Get(2).Bytes()
}

func (bi *BlockInfo) RlpEncode() []byte {
	return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent})
}

type Block struct {
	// Hash to the previous block
	PrevHash []byte
	// Uncles of this block
	Uncles   []*Block
	UncleSha []byte
	// The coin base address
	Coinbase []byte
	// Block Trie state
	state *ethutil.Trie
	// Difficulty for the current block
	Difficulty *big.Int
	// Creation time
	Time int64
	// Extra data
	Extra string
	// Block Nonce for verification
	Nonce []byte
	// List of transactions and/or contracts
	transactions []*Transaction
	TxSha        []byte

	contractStates map[string]*ethutil.Trie
}

// New block takes a raw encoded string
// XXX DEPRICATED
func NewBlockFromData(raw []byte) *Block {
	return NewBlockFromBytes(raw)
}

func NewBlockFromBytes(raw []byte) *Block {
	block := &Block{}
	block.RlpDecode(raw)

	return block
}

// New block takes a raw encoded string
func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block {
	block := &Block{}
	block.RlpValueDecode(rlpValue)

	return block
}

func CreateBlock(root interface{},
	prevHash []byte,
	base []byte,
	Difficulty *big.Int,
	Nonce []byte,
	extra string,
	txes []*Transaction) *Block {

	block := &Block{
		// Slice of transactions to include in this block
		transactions:   txes,
		PrevHash:       prevHash,
		Coinbase:       base,
		Difficulty:     Difficulty,
		Nonce:          Nonce,
		Time:           time.Now().Unix(),
		Extra:          extra,
		UncleSha:       EmptyShaList,
		contractStates: make(map[string]*ethutil.Trie),
	}
	block.SetTransactions(txes)
	block.SetUncles([]*Block{})

	block.state = ethutil.NewTrie(ethutil.Config.Db, root)

	for _, tx := range txes {
		block.MakeContract(tx)
	}

	return block
}

// Returns a hash of the block
func (block *Block) Hash() []byte {
	return ethutil.Sha3Bin(block.Value().Encode())
}

func (block *Block) HashNoNonce() []byte {
	return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra}))
}

func (block *Block) PrintHash() {
	fmt.Println(block)
	fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce})))
}

func (block *Block) State() *ethutil.Trie {
	return block.state
}

func (block *Block) Transactions() []*Transaction {
	return block.transactions
}

func (block *Block) GetContract(addr []byte) *Contract {
	data := block.state.Get(string(addr))
	if data == "" {
		return nil
	}

	contract := &Contract{}
	contract.RlpDecode([]byte(data))

	cachedState := block.contractStates[string(addr)]
	if cachedState != nil {
		contract.state = cachedState
	} else {
		block.contractStates[string(addr)] = contract.state
	}

	return contract
}
func (block *Block) UpdateContract(addr []byte, contract *Contract) {
	// Make sure the state is synced
	//contract.State().Sync()

	block.state.Update(string(addr), string(contract.RlpEncode()))
}

func (block *Block) GetAddr(addr []byte) *Address {
	var address *Address

	data := block.State().Get(string(addr))
	if data == "" {
		address = NewAddress(big.NewInt(0))
	} else {
		address = NewAddressFromData([]byte(data))
	}

	return address
}
func (block *Block) UpdateAddr(addr []byte, address *Address) {
	block.state.Update(string(addr), string(address.RlpEncode()))
}

func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
	contract := block.GetContract(addr)
	// If we can't pay the fee return
	if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ {
		fmt.Println("Contract has insufficient funds", contract.Amount, fee)

		return false
	}

	base := new(big.Int)
	contract.Amount = base.Sub(contract.Amount, fee)
	block.state.Update(string(addr), string(contract.RlpEncode()))

	data := block.state.Get(string(block.Coinbase))

	// Get the ether (Coinbase) and add the fee (gief fee to miner)
	ether := NewAddressFromData([]byte(data))

	base = new(big.Int)
	ether.Amount = base.Add(ether.Amount, fee)

	block.state.Update(string(block.Coinbase), string(ether.RlpEncode()))

	return true
}

func (block *Block) BlockInfo() BlockInfo {
	bi := BlockInfo{}
	data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
	bi.RlpDecode(data)

	return bi
}

// Sync the block's state and contract respectively
func (block *Block) Sync() {
	// Sync all contracts currently in cache
	for _, val := range block.contractStates {
		val.Sync()
	}
	// Sync the block state itself
	block.state.Sync()
}

func (block *Block) Undo() {
	// Sync all contracts currently in cache
	for _, val := range block.contractStates {
		val.Undo()
	}
	// Sync the block state itself
	block.state.Undo()
}

func (block *Block) MakeContract(tx *Transaction) {
	// Create contract if there's no recipient
	if tx.IsContract() {
		addr := tx.Hash()[12:]

		value := tx.Value
		contract := NewContract(value, []byte(""))
		block.state.Update(string(addr), string(contract.RlpEncode()))
		for i, val := range tx.Data {
			if len(val) > 0 {
				bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256)
				contract.state.Update(string(bytNum), val)
			}
		}
		block.UpdateContract(addr, contract)

		block.contractStates[string(addr)] = contract.state
	}
}

/////// Block Encoding
func (block *Block) encodedUncles() interface{} {
	uncles := make([]interface{}, len(block.Uncles))
	for i, uncle := range block.Uncles {
		uncles[i] = uncle.RlpEncode()
	}

	return uncles
}

func (block *Block) encodedTxs() interface{} {
	// Marshal the transactions of this block
	encTx := make([]interface{}, len(block.transactions))
	for i, tx := range block.transactions {
		// Cast it to a string (safe)
		encTx[i] = tx.RlpData()
	}

	return encTx
}

func (block *Block) rlpTxs() interface{} {
	// Marshal the transactions of this block
	encTx := make([]interface{}, len(block.transactions))
	for i, tx := range block.transactions {
		// Cast it to a string (safe)
		encTx[i] = tx.RlpData()
	}

	return encTx
}

func (block *Block) rlpUncles() interface{} {
	// Marshal the transactions of this block
	uncles := make([]interface{}, len(block.Uncles))
	for i, uncle := range block.Uncles {
		// Cast it to a string (safe)
		uncles[i] = uncle.header()
	}

	return uncles
}

func (block *Block) SetUncles(uncles []*Block) {
	block.Uncles = uncles

	// Sha of the concatenated uncles
	block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles()))
}

func (block *Block) SetTransactions(txs []*Transaction) {
	block.transactions = txs

	block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs()))
}

func (block *Block) Value() *ethutil.Value {
	return ethutil.NewValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()})
}

func (block *Block) RlpEncode() []byte {
	// Encode a slice interface which contains the header and the list of
	// transactions.
	return block.Value().Encode()
}

func (block *Block) RlpDecode(data []byte) {
	rlpValue := ethutil.NewValueFromBytes(data)
	block.RlpValueDecode(rlpValue)
}

func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
	header := decoder.Get(0)

	block.PrevHash = header.Get(0).Bytes()
	block.UncleSha = header.Get(1).Bytes()
	block.Coinbase = header.Get(2).Bytes()
	block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
	block.TxSha = header.Get(4).Bytes()
	block.Difficulty = header.Get(5).BigInt()
	block.Time = int64(header.Get(6).BigInt().Uint64())
	block.Extra = header.Get(7).Str()
	block.Nonce = header.Get(8).Bytes()
	block.contractStates = make(map[string]*ethutil.Trie)

	// Tx list might be empty if this is an uncle. Uncles only have their
	// header set.
	if decoder.Get(1).IsNil() == false { // Yes explicitness
		txes := decoder.Get(1)
		block.transactions = make([]*Transaction, txes.Len())
		for i := 0; i < txes.Len(); i++ {
			tx := NewTransactionFromValue(txes.Get(i))

			block.transactions[i] = tx
		}

	}

	if decoder.Get(2).IsNil() == false { // Yes explicitness
		uncles := decoder.Get(2)
		block.Uncles = make([]*Block, uncles.Len())
		for i := 0; i < uncles.Len(); i++ {
			block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i))
		}
	}

}

func NewUncleBlockFromValue(header *ethutil.Value) *Block {
	block := &Block{}

	block.PrevHash = header.Get(0).Bytes()
	block.UncleSha = header.Get(1).Bytes()
	block.Coinbase = header.Get(2).Bytes()
	block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
	block.TxSha = header.Get(4).Bytes()
	block.Difficulty = header.Get(5).BigInt()
	block.Time = int64(header.Get(6).BigInt().Uint64())
	block.Extra = header.Get(7).Str()
	block.Nonce = header.Get(8).Bytes()

	return block
}

func (block *Block) String() string {
	return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions))
}

//////////// UNEXPORTED /////////////////
func (block *Block) header() []interface{} {
	return []interface{}{
		// Sha of the previous block
		block.PrevHash,
		// Sha of uncles
		block.UncleSha,
		// Coinbase address
		block.Coinbase,
		// root state
		block.state.Root,
		// Sha of tx
		block.TxSha,
		// Current block Difficulty
		block.Difficulty,
		// Time the block was found?
		block.Time,
		// Extra data
		block.Extra,
		// Block's Nonce for validation
		block.Nonce,
	}
}
<commit_msg>Changed MakeContract on block<commit_after>package ethchain

import (
	"fmt"
	"github.com/ethereum/eth-go/ethutil"
	"math/big"
	"time"
)

type BlockInfo struct {
	Number uint64
	Hash   []byte
	Parent []byte
}

func (bi *BlockInfo) RlpDecode(data []byte) {
	decoder := ethutil.NewValueFromBytes(data)

	bi.Number = decoder.Get(0).Uint()
	bi.Hash = decoder.Get(1).Bytes()
	bi.Parent = decoder.Get(2).Bytes()
}

func (bi *BlockInfo) RlpEncode() []byte {
	return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent})
}

type Block struct {
	// Hash to the previous block
	PrevHash []byte
	// Uncles of this block
	Uncles   []*Block
	UncleSha []byte
	// The coin base address
	Coinbase []byte
	// Block Trie state
	state *ethutil.Trie
	// Difficulty for the current block
	Difficulty *big.Int
	// Creation time
	Time int64
	// Extra data
	Extra string
	// Block Nonce for verification
	Nonce []byte
	// List of transactions and/or contracts
	transactions []*Transaction
	TxSha        []byte

	contractStates map[string]*ethutil.Trie
}

// New block takes a raw encoded string
// XXX DEPRICATED
func NewBlockFromData(raw []byte) *Block {
	return NewBlockFromBytes(raw)
}

func NewBlockFromBytes(raw []byte) *Block {
	block := &Block{}
	block.RlpDecode(raw)

	return block
}

// New block takes a raw encoded string
func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block {
	block := &Block{}
	block.RlpValueDecode(rlpValue)

	return block
}

func CreateBlock(root interface{},
	prevHash []byte,
	base []byte,
	Difficulty *big.Int,
	Nonce []byte,
	extra string,
	txes []*Transaction) *Block {

	block := &Block{
		// Slice of transactions to include in this block
		transactions:   txes,
		PrevHash:       prevHash,
		Coinbase:       base,
		Difficulty:     Difficulty,
		Nonce:          Nonce,
		Time:           time.Now().Unix(),
		Extra:          extra,
		UncleSha:       EmptyShaList,
		contractStates: make(map[string]*ethutil.Trie),
	}
	block.SetTransactions(txes)
	block.SetUncles([]*Block{})

	block.state = ethutil.NewTrie(ethutil.Config.Db, root)

	for _, tx := range txes {
		block.MakeContract(tx)
	}

	return block
}

// Returns a hash of the block
func (block *Block) Hash() []byte {
	return ethutil.Sha3Bin(block.Value().Encode())
}

func (block *Block) HashNoNonce() []byte {
	return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra}))
}

func (block *Block) PrintHash() {
	fmt.Println(block)
	fmt.Println(ethutil.NewValue(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Extra, block.Nonce})))
}

func (block *Block) State() *ethutil.Trie {
	return block.state
}

func (block *Block) Transactions() []*Transaction {
	return block.transactions
}

func (block *Block) GetContract(addr []byte) *Contract {
	data := block.state.Get(string(addr))
	if data == "" {
		return nil
	}

	contract := &Contract{}
	contract.RlpDecode([]byte(data))

	cachedState := block.contractStates[string(addr)]
	if cachedState != nil {
		contract.state = cachedState
	} else {
		block.contractStates[string(addr)] = contract.state
	}

	return contract
}
func (block *Block) UpdateContract(addr []byte, contract *Contract) {
	// Make sure the state is synced
	//contract.State().Sync()

	block.state.Update(string(addr), string(contract.RlpEncode()))
}

func (block *Block) GetAddr(addr []byte) *Address {
	var address *Address

	data := block.State().Get(string(addr))
	if data == "" {
		address = NewAddress(big.NewInt(0))
	} else {
		address = NewAddressFromData([]byte(data))
	}

	return address
}
func (block *Block) UpdateAddr(addr []byte, address *Address) {
	block.state.Update(string(addr), string(address.RlpEncode()))
}

func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
	contract := block.GetContract(addr)
	// If we can't pay the fee return
	if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ {
		fmt.Println("Contract has insufficient funds", contract.Amount, fee)

		return false
	}

	base := new(big.Int)
	contract.Amount = base.Sub(contract.Amount, fee)
	block.state.Update(string(addr), string(contract.RlpEncode()))

	data := block.state.Get(string(block.Coinbase))

	// Get the ether (Coinbase) and add the fee (gief fee to miner)
	ether := NewAddressFromData([]byte(data))

	base = new(big.Int)
	ether.Amount = base.Add(ether.Amount, fee)

	block.state.Update(string(block.Coinbase), string(ether.RlpEncode()))

	return true
}

func (block *Block) BlockInfo() BlockInfo {
	bi := BlockInfo{}
	data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...))
	bi.RlpDecode(data)

	return bi
}

// Sync the block's state and contract respectively
func (block *Block) Sync() {
	// Sync all contracts currently in cache
	for _, val := range block.contractStates {
		val.Sync()
	}
	// Sync the block state itself
	block.state.Sync()
}

func (block *Block) Undo() {
	// Sync all contracts currently in cache
	for _, val := range block.contractStates {
		val.Undo()
	}
	// Sync the block state itself
	block.state.Undo()
}

func (block *Block) MakeContract(tx *Transaction) {
	contract := MakeContract(tx, NewState(block.state))

	block.contractStates[string(tx.Hash()[12:])] = contract.state
}

/////// Block Encoding
func (block *Block) encodedUncles() interface{} {
	uncles := make([]interface{}, len(block.Uncles))
	for i, uncle := range block.Uncles {
		uncles[i] = uncle.RlpEncode()
	}

	return uncles
}

func (block *Block) encodedTxs() interface{} {
	// Marshal the transactions of this block
	encTx := make([]interface{}, len(block.transactions))
	for i, tx := range block.transactions {
		// Cast it to a string (safe)
		encTx[i] = tx.RlpData()
	}

	return encTx
}

func (block *Block) rlpTxs() interface{} {
	// Marshal the transactions of this block
	encTx := make([]interface{}, len(block.transactions))
	for i, tx := range block.transactions {
		// Cast it to a string (safe)
		encTx[i] = tx.RlpData()
	}

	return encTx
}

func (block *Block) rlpUncles() interface{} {
	// Marshal the transactions of this block
	uncles := make([]interface{}, len(block.Uncles))
	for i, uncle := range block.Uncles {
		// Cast it to a string (safe)
		uncles[i] = uncle.header()
	}

	return uncles
}

func (block *Block) SetUncles(uncles []*Block) {
	block.Uncles = uncles

	// Sha of the concatenated uncles
	block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles()))
}

func (block *Block) SetTransactions(txs []*Transaction) {
	block.transactions = txs

	block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs()))
}

func (block *Block) Value() *ethutil.Value {
	return ethutil.NewValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()})
}

func (block *Block) RlpEncode() []byte {
	// Encode a slice interface which contains the header and the list of
	// transactions.
	return block.Value().Encode()
}

func (block *Block) RlpDecode(data []byte) {
	rlpValue := ethutil.NewValueFromBytes(data)
	block.RlpValueDecode(rlpValue)
}

func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
	header := decoder.Get(0)

	block.PrevHash = header.Get(0).Bytes()
	block.UncleSha = header.Get(1).Bytes()
	block.Coinbase = header.Get(2).Bytes()
	block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
	block.TxSha = header.Get(4).Bytes()
	block.Difficulty = header.Get(5).BigInt()
	block.Time = int64(header.Get(6).BigInt().Uint64())
	block.Extra = header.Get(7).Str()
	block.Nonce = header.Get(8).Bytes()
	block.contractStates = make(map[string]*ethutil.Trie)

	// Tx list might be empty if this is an uncle. Uncles only have their
	// header set.
	if decoder.Get(1).IsNil() == false { // Yes explicitness
		txes := decoder.Get(1)
		block.transactions = make([]*Transaction, txes.Len())
		for i := 0; i < txes.Len(); i++ {
			tx := NewTransactionFromValue(txes.Get(i))

			block.transactions[i] = tx
		}

	}

	if decoder.Get(2).IsNil() == false { // Yes explicitness
		uncles := decoder.Get(2)
		block.Uncles = make([]*Block, uncles.Len())
		for i := 0; i < uncles.Len(); i++ {
			block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i))
		}
	}

}

func NewUncleBlockFromValue(header *ethutil.Value) *Block {
	block := &Block{}

	block.PrevHash = header.Get(0).Bytes()
	block.UncleSha = header.Get(1).Bytes()
	block.Coinbase = header.Get(2).Bytes()
	block.state = ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)
	block.TxSha = header.Get(4).Bytes()
	block.Difficulty = header.Get(5).BigInt()
	block.Time = int64(header.Get(6).BigInt().Uint64())
	block.Extra = header.Get(7).Str()
	block.Nonce = header.Get(8).Bytes()

	return block
}

func (block *Block) String() string {
	return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions))
}

//////////// UNEXPORTED /////////////////
func (block *Block) header() []interface{} {
	return []interface{}{
		// Sha of the previous block
		block.PrevHash,
		// Sha of uncles
		block.UncleSha,
		// Coinbase address
		block.Coinbase,
		// root state
		block.state.Root,
		// Sha of tx
		block.TxSha,
		// Current block Difficulty
		block.Difficulty,
		// Time the block was found?
		block.Time,
		// Extra data
		block.Extra,
		// Block's Nonce for validation
		block.Nonce,
	}
}
<|endoftext|>


<commit_before>package sourcegraph

import (
	"errors"
	"fmt"
	"net/url"
	"regexp"
	"strings"
	"time"

	"sourcegraph.com/sourcegraph/go-nnz/nnz"
)

// Repo is a code repository returned by the Sourcegraph API.
type Repo struct {
	// URI is a normalized identifier for this repository based on its primary
	// clone URL. E.g., "github.com/user/repo".
	URI string

	// URIAlias is another URI that, if accessed, will redirect to
	// this repository's primary URI. It's used, for example, to
	// redirect from GitHub repos to their canonical URI (such as Go
	// repos on gopkg.in).
	URIAlias nnz.String `db:"uri_alias"`

	// Name is the base name (the final path component) of the repository,
	// typically the name of the directory that the repository would be cloned
	// into. (For example, for git://example.com/foo.git, the name is "foo".)
	Name string

	// OwnerUserID is the account that owns this repository.
	OwnerUserID int `db:"owner_user_id"`

	// OwnerGitHubUserID is the GitHub user ID of this repository's owner, if this
	// is a GitHub repository.
	OwnerGitHubUserID nnz.Int `db:"owner_github_user_id" json:",omitempty"`

	// Description is a brief description of the repository.
	Description string `json:",omitempty"`

	// VCS is the short name of the VCS system that this repository uses: "git"
	// or "hg".
	VCS string `db:"vcs"`

	// HTTPCloneURL is the HTTPS clone URL of the repository (or the
	// HTTP clone URL, if no HTTPS clone URL is available).
	HTTPCloneURL string `db:"http_clone_url"`

	// SSHCloneURL is the SSH clone URL if the repository, if any.
	SSHCloneURL nnz.String `db:"ssh_clone_url"`

	// HomepageURL is the URL to the repository's homepage, if any.
	HomepageURL nnz.String `db:"homepage_url"`

	// DefaultBranch is the default VCS branch used (typically "master" for git
	// repositories and "default" for hg repositories).
	DefaultBranch string `db:"default_branch"`

	// Language is the primary programming language used in this repository.
	Language string

	// GitHubStars is the number of stargazers this repository has on GitHub (or
	// 0 if it is not a GitHub repository).
	GitHubStars int `db:"github_stars"`

	// GitHubID is the GitHub ID of this repository. If a GitHub repository is
	// renamed, the ID remains the same and should be used to resolve across the
	// name change.
	GitHubID nnz.Int `db:"github_id" json:",omitempty"`

	// Disabled is whether this repo should not be downloaded and processed by the worker.
	Disabled bool `json:",omitempty"`

	// Deprecated repositories are labeled as such and hidden from global search results.
	Deprecated bool

	// Fork is whether this repository is a fork.
	Fork bool

	// Mirror is whether this repository is a mirror.
	Mirror bool

	// Private is whether this repository is private.
	Private bool

	// CreatedAt is when this repository was created. If it represents
	// an externally hosted (e.g., GitHub) repository, the creation
	// date is when it was created at that origin.
	CreatedAt time.Time `db:"created_at"`

	// UpdatedAt is when this repository's metadata was last updated
	// (on its origin if it's an externally hosted repository).
	UpdatedAt time.Time `db:"updated_at"`

	// PushedAt is when this repository's was last (VCS-)pushed to.
	PushedAt time.Time `db:"pushed_at"`

	// Permissions describes the permissions that the current user (or
	// anonymous users, if there is no current user) is granted to
	// this repository.
	Permissions *RepoPermissions `db:"-" json:",omitempty"`
}

// IsGitHubRepo returns true iff this repository is hosted on GitHub.
func (r *Repo) IsGitHubRepo() bool { return r.GitHubID != 0 }

// GitHubHTMLURL returns URL to the GitHub HTML page (e.g.,
// https://github.com/foo/bar, not a clone URL) for this repo, if it's
// a GitHub repo. Otherwise it returns the empty string.
func (r *Repo) GitHubHTMLURL() string {
	var ghuri string
	if IsGitHubRepoURI(r.URI) {
		ghuri = r.URI
	} else if IsGitHubRepoURI(string(r.URIAlias)) {
		ghuri = string(r.URIAlias)
	}
	if ghuri == "" {
		return ""
	}
	return (&url.URL{Scheme: "https", Host: "github.com", Path: "/" + strings.TrimPrefix(ghuri, githubRepoURIPrefix)}).String()
}

const (
	Git = "git"
	Hg  = "hg"
)

func MapByURI(repos []*Repo) map[string]*Repo {
	repoMap := make(map[string]*Repo, len(repos))
	for _, repo := range repos {
		repoMap[repo.URI] = repo
	}
	return repoMap
}

type Repos []*Repo

func (rs Repos) URIs() (uris []string) {
	uris = make([]string, len(rs))
	for i, r := range rs {
		uris[i] = r.URI
	}
	return
}

const githubRepoURIPrefix = "github.com/"

// IsGitHubRepoURI returns true iff this repository is hosted on GitHub.
func IsGitHubRepoURI(repoURI string) bool {
	return strings.HasPrefix(strings.ToLower(repoURI), githubRepoURIPrefix)
}

// IsGoogleCodeRepoURI returns true iff this repository is hosted on Google
// Code (code.google.com).
func IsGoogleCodeRepoURI(repoURI string) bool {
	return strings.HasPrefix(strings.ToLower(repoURI), "code.google.com/p/")
}

// RepoSpec returns the RepoSpec that specifies r.
func (r *Repo) RepoSpec() RepoSpec {
	return RepoSpec{URI: r.URI}
}

// RepoPermissions describes the possible permissions that a user (or
// an anonymous user) can be granted to a repository.
type RepoPermissions struct {
	Read  bool
	Write bool
	Admin bool
}

// ErrRenamed is an error type that indicates that a repository was renamed from
// OldURI to NewURI.
type ErrRenamed struct {
	// OldURI is the previous repository URI.
	OldURI string

	// NewURI is the new URI that the repository was renamed to.
	NewURI string
}

func (e ErrRenamed) Error() string {
	return fmt.Sprintf("repository URI %q was renamed to %q; use the new name", e.OldURI, e.NewURI)
}

// ErrNotExist is an error definitively indicating that no such repository
// exists.
var ErrNotExist = errors.New("repository does not exist on external host")

// ErrForbidden is an error indicating that the repository can no longer be
// accessed due to server's refusal to serve it (possibly DMCA takedowns on
// github etc)
var ErrForbidden = errors.New("repository is unavailable")

// ErrNotPersisted is an error indicating that no such repository is persisted
// locally. The repository might exist on a remote host, but it must be
// explicitly added (it will not be implicitly added via a Get call).
var ErrNotPersisted = errors.New("repository is not persisted locally, but it might exist remotely (explicitly add it to check)")

// ErrNotPersisted is an error indicating that repository cannot be created
// without an explicit clone URL, because it has a non-standard URI. It implies
// ErrNotPersisted.
var ErrNonStandardURI = errors.New("cannot infer repository clone URL because repository host is not standard; try adding it explicitly")

// ErrNoRepoBuild indicates that no build could be found for a repo
// revspec.
var ErrNoRepoBuild = errors.New("no suitable repo build found for revspec")

type ErrRedirect struct {
	RedirectURI string
}

func (e ErrRedirect) Error() string {
	return fmt.Sprintf("the repository requested exists at another URI (%s)", e.RedirectURI)
}

var errRedirectMsgPattern = regexp.MustCompile(`the repository requested exists at another URI \(([^\(\)]*)\)`)

func ErrRedirectFromString(msg string) *ErrRedirect {
	if match := errRedirectMsgPattern.FindStringSubmatch(msg); len(match) == 2 {
		return &ErrRedirect{match[1]}
	}
	return nil
}

// IsNotPresent returns whether err is one of ErrNotExist, ErrNotPersisted, or
// ErrRedirected.
func IsNotPresent(err error) bool {
	return err == ErrNotExist || err == ErrNotPersisted
}

func IsForbidden(err error) bool {
	return err == ErrForbidden
}

// ErrNoScheme is an error indicating that a clone URL contained no scheme
// component (e.g., "http://").
var ErrNoScheme = errors.New("clone URL has no scheme")

// ExternalHostTimeout is the timeout for HTTP requests to external repository
// hosts.
var ExternalHostTimeout = time.Second * 7
<commit_msg>Repo.CloneURL()<commit_after>package sourcegraph

import (
	"errors"
	"fmt"
	"net/url"
	"regexp"
	"strings"
	"time"

	"sourcegraph.com/sourcegraph/go-nnz/nnz"
)

// Repo is a code repository returned by the Sourcegraph API.
type Repo struct {
	// URI is a normalized identifier for this repository based on its primary
	// clone URL. E.g., "github.com/user/repo".
	URI string

	// URIAlias is another URI that, if accessed, will redirect to
	// this repository's primary URI. It's used, for example, to
	// redirect from GitHub repos to their canonical URI (such as Go
	// repos on gopkg.in).
	URIAlias nnz.String `db:"uri_alias"`

	// Name is the base name (the final path component) of the repository,
	// typically the name of the directory that the repository would be cloned
	// into. (For example, for git://example.com/foo.git, the name is "foo".)
	Name string

	// OwnerUserID is the account that owns this repository.
	OwnerUserID int `db:"owner_user_id"`

	// OwnerGitHubUserID is the GitHub user ID of this repository's owner, if this
	// is a GitHub repository.
	OwnerGitHubUserID nnz.Int `db:"owner_github_user_id" json:",omitempty"`

	// Description is a brief description of the repository.
	Description string `json:",omitempty"`

	// VCS is the short name of the VCS system that this repository uses: "git"
	// or "hg".
	VCS string `db:"vcs"`

	// HTTPCloneURL is the HTTPS clone URL of the repository (or the
	// HTTP clone URL, if no HTTPS clone URL is available).
	HTTPCloneURL string `db:"http_clone_url"`

	// SSHCloneURL is the SSH clone URL if the repository, if any.
	SSHCloneURL nnz.String `db:"ssh_clone_url"`

	// HomepageURL is the URL to the repository's homepage, if any.
	HomepageURL nnz.String `db:"homepage_url"`

	// DefaultBranch is the default VCS branch used (typically "master" for git
	// repositories and "default" for hg repositories).
	DefaultBranch string `db:"default_branch"`

	// Language is the primary programming language used in this repository.
	Language string

	// GitHubStars is the number of stargazers this repository has on GitHub (or
	// 0 if it is not a GitHub repository).
	GitHubStars int `db:"github_stars"`

	// GitHubID is the GitHub ID of this repository. If a GitHub repository is
	// renamed, the ID remains the same and should be used to resolve across the
	// name change.
	GitHubID nnz.Int `db:"github_id" json:",omitempty"`

	// Disabled is whether this repo should not be downloaded and processed by the worker.
	Disabled bool `json:",omitempty"`

	// Deprecated repositories are labeled as such and hidden from global search results.
	Deprecated bool

	// Fork is whether this repository is a fork.
	Fork bool

	// Mirror is whether this repository is a mirror.
	Mirror bool

	// Private is whether this repository is private.
	Private bool

	// CreatedAt is when this repository was created. If it represents
	// an externally hosted (e.g., GitHub) repository, the creation
	// date is when it was created at that origin.
	CreatedAt time.Time `db:"created_at"`

	// UpdatedAt is when this repository's metadata was last updated
	// (on its origin if it's an externally hosted repository).
	UpdatedAt time.Time `db:"updated_at"`

	// PushedAt is when this repository's was last (VCS-)pushed to.
	PushedAt time.Time `db:"pushed_at"`

	// Permissions describes the permissions that the current user (or
	// anonymous users, if there is no current user) is granted to
	// this repository.
	Permissions *RepoPermissions `db:"-" json:",omitempty"`
}

// IsGitHubRepo returns true iff this repository is hosted on GitHub.
func (r *Repo) IsGitHubRepo() bool { return r.GitHubID != 0 }

// Returns the repository's canonical clone URL
func (r *Repo) CloneURL() *url.URL {
	var cloneURL string
	if r.HTTPCloneURL != "" {
		cloneURL = r.HTTPCloneURL
	} else if r.SSHCloneURL != "" {
		cloneURL = string(r.SSHCloneURL)
	} else {
		cloneURL = r.URI
	}
	u, _ := url.Parse(cloneURL)
	return u
}

// GitHubHTMLURL returns URL to the GitHub HTML page (e.g.,
// https://github.com/foo/bar, not a clone URL) for this repo, if it's
// a GitHub repo. Otherwise it returns the empty string.
func (r *Repo) GitHubHTMLURL() string {
	var ghuri string
	if IsGitHubRepoURI(r.URI) {
		ghuri = r.URI
	} else if IsGitHubRepoURI(string(r.URIAlias)) {
		ghuri = string(r.URIAlias)
	}
	if ghuri == "" {
		return ""
	}
	return (&url.URL{Scheme: "https", Host: "github.com", Path: "/" + strings.TrimPrefix(ghuri, githubRepoURIPrefix)}).String()
}

const (
	Git = "git"
	Hg  = "hg"
)

func MapByURI(repos []*Repo) map[string]*Repo {
	repoMap := make(map[string]*Repo, len(repos))
	for _, repo := range repos {
		repoMap[repo.URI] = repo
	}
	return repoMap
}

type Repos []*Repo

func (rs Repos) URIs() (uris []string) {
	uris = make([]string, len(rs))
	for i, r := range rs {
		uris[i] = r.URI
	}
	return
}

const githubRepoURIPrefix = "github.com/"

// IsGitHubRepoURI returns true iff this repository is hosted on GitHub.
func IsGitHubRepoURI(repoURI string) bool {
	return strings.HasPrefix(strings.ToLower(repoURI), githubRepoURIPrefix)
}

// IsGoogleCodeRepoURI returns true iff this repository is hosted on Google
// Code (code.google.com).
func IsGoogleCodeRepoURI(repoURI string) bool {
	return strings.HasPrefix(strings.ToLower(repoURI), "code.google.com/p/")
}

// RepoSpec returns the RepoSpec that specifies r.
func (r *Repo) RepoSpec() RepoSpec {
	return RepoSpec{URI: r.URI}
}

// RepoPermissions describes the possible permissions that a user (or
// an anonymous user) can be granted to a repository.
type RepoPermissions struct {
	Read  bool
	Write bool
	Admin bool
}

// ErrRenamed is an error type that indicates that a repository was renamed from
// OldURI to NewURI.
type ErrRenamed struct {
	// OldURI is the previous repository URI.
	OldURI string

	// NewURI is the new URI that the repository was renamed to.
	NewURI string
}

func (e ErrRenamed) Error() string {
	return fmt.Sprintf("repository URI %q was renamed to %q; use the new name", e.OldURI, e.NewURI)
}

// ErrNotExist is an error definitively indicating that no such repository
// exists.
var ErrNotExist = errors.New("repository does not exist on external host")

// ErrForbidden is an error indicating that the repository can no longer be
// accessed due to server's refusal to serve it (possibly DMCA takedowns on
// github etc)
var ErrForbidden = errors.New("repository is unavailable")

// ErrNotPersisted is an error indicating that no such repository is persisted
// locally. The repository might exist on a remote host, but it must be
// explicitly added (it will not be implicitly added via a Get call).
var ErrNotPersisted = errors.New("repository is not persisted locally, but it might exist remotely (explicitly add it to check)")

// ErrNotPersisted is an error indicating that repository cannot be created
// without an explicit clone URL, because it has a non-standard URI. It implies
// ErrNotPersisted.
var ErrNonStandardURI = errors.New("cannot infer repository clone URL because repository host is not standard; try adding it explicitly")

// ErrNoRepoBuild indicates that no build could be found for a repo
// revspec.
var ErrNoRepoBuild = errors.New("no suitable repo build found for revspec")

type ErrRedirect struct {
	RedirectURI string
}

func (e ErrRedirect) Error() string {
	return fmt.Sprintf("the repository requested exists at another URI (%s)", e.RedirectURI)
}

var errRedirectMsgPattern = regexp.MustCompile(`the repository requested exists at another URI \(([^\(\)]*)\)`)

func ErrRedirectFromString(msg string) *ErrRedirect {
	if match := errRedirectMsgPattern.FindStringSubmatch(msg); len(match) == 2 {
		return &ErrRedirect{match[1]}
	}
	return nil
}

// IsNotPresent returns whether err is one of ErrNotExist, ErrNotPersisted, or
// ErrRedirected.
func IsNotPresent(err error) bool {
	return err == ErrNotExist || err == ErrNotPersisted
}

func IsForbidden(err error) bool {
	return err == ErrForbidden
}

// ErrNoScheme is an error indicating that a clone URL contained no scheme
// component (e.g., "http://").
var ErrNoScheme = errors.New("clone URL has no scheme")

// ExternalHostTimeout is the timeout for HTTP requests to external repository
// hosts.
var ExternalHostTimeout = time.Second * 7
<|endoftext|>


<commit_before>package app

import (
	"bytes"
	"crypto/sha1"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var (
	notify         = make(chan Event, 10)
	query          = make(chan QueryCachedFiles, 10)
	cachedFiles    = make(map[string]*CachedFile)
	aliases        = make(map[string]string)
	cacheDirectory = ""
)

type Event struct {
	Name       string
	Attributes map[string]string
}

type QueryCachedFiles struct {
	Query    string
	Response chan *CachedFile
}

type CachedFile struct {
	Url     string
	Aliases []string
	Path    string
}

func (event Event) String() string {
	pairs := make([]string, 0, 0)
	for key, value := range event.Attributes {
		pairs = append(pairs, fmt.Sprintf("%s=%s", key, value))
	}
	return fmt.Sprintf("%s %s", event.Name, strings.Join(pairs, " "))
}

func PublishEvent(name string, attributes map[string]string) {
	notify <- Event{name, attributes}
}

func Query(token string) *CachedFile {
	search := QueryCachedFiles{token, make(chan *CachedFile)}
	defer close(search.Response)
	query <- search

	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	select {
	case result := <-search.Response:
		return result
	case <-timeout:
		return nil
	}
}

func init() {
	pwd, err := os.Getwd()
	if err != nil {
		panic(err.Error())
	}
	cacheDirectory = filepath.Join(pwd, ".cache")
	os.MkdirAll(cacheDirectory, 00777)

	go fileCache()
	PublishEvent("init", make(map[string]string))
}

func fileCache() {

	for {
		select {
		case event := <-notify:
			{
				switch event.Name {
				case "init":
					{
						fmt.Println("Running init")
					}
				case "download":
					{
						url, hasUrl := event.Attributes["url"]
						urlAliases, hasUrlAliases := event.Attributes["aliases"]
						if hasUrl && hasUrlAliases {
							cachedFile := findCachedFile(url)
							if cachedFile == nil {
								download(url, strings.Split(urlAliases, ","))
							}
						}
					}
				}
			}
		case search := <-query:
			{
				search.Response <- findCachedFile(search.Query)
			}
		}
	}
}

func findCachedFile(search string) *CachedFile {
	contentHash, hasContentHash := aliases[search]
	if hasContentHash {
		cachedFile, hasCachedFile := cachedFiles[contentHash]
		if hasCachedFile {
			return cachedFile
		}
	}
	return nil
}

func download(url string, urlAliases []string) {
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	urlHash := hash([]byte(url))
	contentHash := hash(body)
	path := filepath.Join(cacheDirectory, contentHash)

	fmt.Println("Storing url", url, "as id", urlHash, "with content addressed as", contentHash)

	ioutil.WriteFile(path, body, 00777)
	cachedFiles[contentHash] = &CachedFile{url, urlAliases, path}

	aliases[url] = contentHash
	aliases[urlHash] = contentHash
	for _, alias := range urlAliases {
		aliases[alias] = contentHash
	}

	var buffer bytes.Buffer
	buffer.WriteString(url)
	buffer.WriteString("\n" + contentHash)
	if len(urlAliases) > 0 {
		buffer.WriteString("\n")
		buffer.WriteString(strings.Join(urlAliases, "\n"))
	}
	ioutil.WriteFile(filepath.Join(cacheDirectory, contentHash+".aliases"), buffer.Bytes(), 00777)
}

func hash(bytes []byte) string {
	hasher := sha1.New()
	hasher.Write(bytes)
	return fmt.Sprintf("%x", hasher.Sum(nil))
}
<commit_msg>Adding init functionality<commit_after>package app

import (
	"bytes"
	"crypto/sha1"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var (
	notify         = make(chan Event, 10)
	query          = make(chan QueryCachedFiles, 10)
	cachedFiles    = make(map[string]*CachedFile)
	aliases        = make(map[string]string)
	cacheDirectory = ""
)

type Event struct {
	Name       string
	Attributes map[string]string
}

type QueryCachedFiles struct {
	Query    string
	Response chan *CachedFile
}

type CachedFile struct {
	Url     string
	Aliases []string
	Path    string
}

func (event Event) String() string {
	pairs := make([]string, 0, 0)
	for key, value := range event.Attributes {
		pairs = append(pairs, fmt.Sprintf("%s=%s", key, value))
	}
	return fmt.Sprintf("%s %s", event.Name, strings.Join(pairs, " "))
}

func PublishEvent(name string, attributes map[string]string) {
	notify <- Event{name, attributes}
}

func Query(token string) *CachedFile {
	search := QueryCachedFiles{token, make(chan *CachedFile)}
	defer close(search.Response)
	query <- search

	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(1 * time.Second)
		timeout <- true
	}()

	select {
	case result := <-search.Response:
		return result
	case <-timeout:
		return nil
	}
}

func init() {
	pwd, err := os.Getwd()
	if err != nil {
		panic(err.Error())
	}
	cacheDirectory = filepath.Join(pwd, ".cache")
	os.MkdirAll(cacheDirectory, 00777)

	go fileCache()
	PublishEvent("init", make(map[string]string))
}

func fileCache() {

	for {
		select {
		case event := <-notify:
			{
				switch event.Name {
				case "init":
					{
						initCachedFiles()
					}
				case "download":
					{
						url, hasUrl := event.Attributes["url"]
						urlAliases, hasUrlAliases := event.Attributes["aliases"]
						if hasUrl && hasUrlAliases {
							cachedFile := findCachedFile(url)
							if cachedFile == nil {
								download(url, strings.Split(urlAliases, ","))
							}
						}
					}
				}
			}
		case search := <-query:
			{
				search.Response <- findCachedFile(search.Query)
			}
		}
	}
}

func initCachedFiles() {
	Recurse := false
	walkFn := func(path string, info os.FileInfo, err error) error {
		stat, err := os.Stat(path)
		if err != nil {
			return err
		}

		if stat.IsDir() && path != cacheDirectory && !Recurse {
			return filepath.SkipDir
		}

		if err != nil {
			return err
		}
		if strings.HasSuffix(path, ".metadata") {
			content, err := ioutil.ReadFile(path)
			if err == nil {
				dir, fileName := filepath.Split(path)
				fileNameParts := strings.Split(fileName, ".")
				contentHash := fileNameParts[0]
				fileAliases := strings.Split(string(content), "\n")
				cachedFiles[contentHash] = &CachedFile{fileAliases[0], fileAliases, filepath.Join(dir, contentHash)}
				for _, alias := range fileAliases {
					aliases[alias] = contentHash
				}
			}
		}
		return nil
	}
	err := filepath.Walk(cacheDirectory, walkFn)
	if err != nil {
		fmt.Println(err.Error())
	}
}

func findCachedFile(search string) *CachedFile {
	contentHash, hasContentHash := aliases[search]
	if hasContentHash {
		cachedFile, hasCachedFile := cachedFiles[contentHash]
		if hasCachedFile {
			return cachedFile
		}
	}
	return nil
}

func download(url string, urlAliases []string) {
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	urlHash := hash([]byte(url))
	contentHash := hash(body)
	path := filepath.Join(cacheDirectory, contentHash)

	ioutil.WriteFile(path, body, 00777)
	cachedFiles[contentHash] = &CachedFile{url, urlAliases, path}

	aliases[url] = contentHash
	aliases[urlHash] = contentHash
	for _, alias := range urlAliases {
		aliases[alias] = contentHash
	}

	var buffer bytes.Buffer
	buffer.WriteString(url)
	buffer.WriteString("\n" + urlHash)
	if len(urlAliases) > 0 {
		buffer.WriteString("\n")
		buffer.WriteString(strings.Join(urlAliases, "\n"))
	}
	ioutil.WriteFile(filepath.Join(cacheDirectory, contentHash+".metadata"), buffer.Bytes(), 00777)
}

func hash(bytes []byte) string {
	hasher := sha1.New()
	hasher.Write(bytes)
	return fmt.Sprintf("%x", hasher.Sum(nil))
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package helpers

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

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	utilnet "k8s.io/utils/net"
)

/*
This file is duplicated from "k8s.io/kubernetes/pkg/api/v1/service/util.go"
in order for in-tree cloud providers to not depend on internal packages.
*/

const (
	defaultLoadBalancerSourceRanges = "0.0.0.0/0"

	// LoadBalancerCleanupFinalizer is the finalizer added to load balancer
	// services to ensure the Service resource is not fully deleted until
	// the correlating load balancer resources are deleted.
	LoadBalancerCleanupFinalizer = "service.kubernetes.io/load-balancer-cleanup"
)

// IsAllowAll checks whether the utilnet.IPNet allows traffic from 0.0.0.0/0
func IsAllowAll(ipnets utilnet.IPNetSet) bool {
	for _, s := range ipnets.StringSlice() {
		if s == "0.0.0.0/0" {
			return true
		}
	}
	return false
}

// GetLoadBalancerSourceRanges first try to parse and verify LoadBalancerSourceRanges field from a service.
// If the field is not specified, turn to parse and verify the AnnotationLoadBalancerSourceRangesKey annotation from a service,
// extracting the source ranges to allow, and if not present returns a default (allow-all) value.
func GetLoadBalancerSourceRanges(service *v1.Service) (utilnet.IPNetSet, error) {
	var ipnets utilnet.IPNetSet
	var err error
	// if SourceRange field is specified, ignore sourceRange annotation
	if len(service.Spec.LoadBalancerSourceRanges) > 0 {
		specs := service.Spec.LoadBalancerSourceRanges
		ipnets, err = utilnet.ParseIPNets(specs...)

		if err != nil {
			return nil, fmt.Errorf("service.Spec.LoadBalancerSourceRanges: %v is not valid. Expecting a list of IP ranges. For example, 10.0.0.0/24. Error msg: %v", specs, err)
		}
	} else {
		val := service.Annotations[v1.AnnotationLoadBalancerSourceRangesKey]
		val = strings.TrimSpace(val)
		if val == "" {
			val = defaultLoadBalancerSourceRanges
		}
		specs := strings.Split(val, ",")
		ipnets, err = utilnet.ParseIPNets(specs...)
		if err != nil {
			return nil, fmt.Errorf("%s: %s is not valid. Expecting a comma-separated list of source IP ranges. For example, 10.0.0.0/24,192.168.2.0/24", v1.AnnotationLoadBalancerSourceRangesKey, val)
		}
	}
	return ipnets, nil
}

// GetServiceHealthCheckPathPort returns the path and nodePort programmed into the Cloud LB Health Check
func GetServiceHealthCheckPathPort(service *v1.Service) (string, int32) {
	if !NeedsHealthCheck(service) {
		return "", 0
	}
	port := service.Spec.HealthCheckNodePort
	if port == 0 {
		return "", 0
	}
	return "/healthz", port
}

// RequestsOnlyLocalTraffic checks if service requests OnlyLocal traffic.
func RequestsOnlyLocalTraffic(service *v1.Service) bool {
	if service.Spec.Type != v1.ServiceTypeLoadBalancer &&
		service.Spec.Type != v1.ServiceTypeNodePort {
		return false
	}
	return service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal
}

// NeedsHealthCheck checks if service needs health check.
func NeedsHealthCheck(service *v1.Service) bool {
	if service.Spec.Type != v1.ServiceTypeLoadBalancer {
		return false
	}
	return RequestsOnlyLocalTraffic(service)
}

// HasLBFinalizer checks if service contains LoadBalancerCleanupFinalizer.
func HasLBFinalizer(service *v1.Service) bool {
	for _, finalizer := range service.ObjectMeta.Finalizers {
		if finalizer == LoadBalancerCleanupFinalizer {
			return true
		}
	}
	return false
}

// LoadBalancerStatusEqual checks if load balancer status are equal
func LoadBalancerStatusEqual(l, r *v1.LoadBalancerStatus) bool {
	return ingressSliceEqual(l.Ingress, r.Ingress)
}

// PatchService patches the given service's Status or ObjectMeta based on the original and
// updated ones. Change to spec will be ignored.
func PatchService(c corev1.CoreV1Interface, oldSvc, newSvc *v1.Service) (*v1.Service, error) {
	// Reset spec to make sure only patch for Status or ObjectMeta.
	newSvc.Spec = oldSvc.Spec

	patchBytes, err := getPatchBytes(oldSvc, newSvc)
	if err != nil {
		return nil, err
	}

	return c.Services(oldSvc.Namespace).Patch(context.TODO(), oldSvc.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status")

}

func getPatchBytes(oldSvc, newSvc *v1.Service) ([]byte, error) {
	oldData, err := json.Marshal(oldSvc)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal oldData for svc %s/%s: %v", oldSvc.Namespace, oldSvc.Name, err)
	}

	newData, err := json.Marshal(newSvc)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal newData for svc %s/%s: %v", newSvc.Namespace, newSvc.Name, err)
	}

	patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Service{})
	if err != nil {
		return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for svc %s/%s: %v", oldSvc.Namespace, oldSvc.Name, err)
	}
	return patchBytes, nil

}

func ingressSliceEqual(lhs, rhs []v1.LoadBalancerIngress) bool {
	if len(lhs) != len(rhs) {
		return false
	}
	for i := range lhs {
		if !ingressEqual(&lhs[i], &rhs[i]) {
			return false
		}
	}
	return true
}

func ingressEqual(lhs, rhs *v1.LoadBalancerIngress) bool {
	if lhs.IP != rhs.IP {
		return false
	}
	if lhs.Hostname != rhs.Hostname {
		return false
	}
	if lhs.IPMode != rhs.IPMode {
		return false
	}
	return true
}
<commit_msg>Revert "Merge pull request #92312 from Sh4d1/kep_1860"<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package helpers

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

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
	utilnet "k8s.io/utils/net"
)

/*
This file is duplicated from "k8s.io/kubernetes/pkg/api/v1/service/util.go"
in order for in-tree cloud providers to not depend on internal packages.
*/

const (
	defaultLoadBalancerSourceRanges = "0.0.0.0/0"

	// LoadBalancerCleanupFinalizer is the finalizer added to load balancer
	// services to ensure the Service resource is not fully deleted until
	// the correlating load balancer resources are deleted.
	LoadBalancerCleanupFinalizer = "service.kubernetes.io/load-balancer-cleanup"
)

// IsAllowAll checks whether the utilnet.IPNet allows traffic from 0.0.0.0/0
func IsAllowAll(ipnets utilnet.IPNetSet) bool {
	for _, s := range ipnets.StringSlice() {
		if s == "0.0.0.0/0" {
			return true
		}
	}
	return false
}

// GetLoadBalancerSourceRanges first try to parse and verify LoadBalancerSourceRanges field from a service.
// If the field is not specified, turn to parse and verify the AnnotationLoadBalancerSourceRangesKey annotation from a service,
// extracting the source ranges to allow, and if not present returns a default (allow-all) value.
func GetLoadBalancerSourceRanges(service *v1.Service) (utilnet.IPNetSet, error) {
	var ipnets utilnet.IPNetSet
	var err error
	// if SourceRange field is specified, ignore sourceRange annotation
	if len(service.Spec.LoadBalancerSourceRanges) > 0 {
		specs := service.Spec.LoadBalancerSourceRanges
		ipnets, err = utilnet.ParseIPNets(specs...)

		if err != nil {
			return nil, fmt.Errorf("service.Spec.LoadBalancerSourceRanges: %v is not valid. Expecting a list of IP ranges. For example, 10.0.0.0/24. Error msg: %v", specs, err)
		}
	} else {
		val := service.Annotations[v1.AnnotationLoadBalancerSourceRangesKey]
		val = strings.TrimSpace(val)
		if val == "" {
			val = defaultLoadBalancerSourceRanges
		}
		specs := strings.Split(val, ",")
		ipnets, err = utilnet.ParseIPNets(specs...)
		if err != nil {
			return nil, fmt.Errorf("%s: %s is not valid. Expecting a comma-separated list of source IP ranges. For example, 10.0.0.0/24,192.168.2.0/24", v1.AnnotationLoadBalancerSourceRangesKey, val)
		}
	}
	return ipnets, nil
}

// GetServiceHealthCheckPathPort returns the path and nodePort programmed into the Cloud LB Health Check
func GetServiceHealthCheckPathPort(service *v1.Service) (string, int32) {
	if !NeedsHealthCheck(service) {
		return "", 0
	}
	port := service.Spec.HealthCheckNodePort
	if port == 0 {
		return "", 0
	}
	return "/healthz", port
}

// RequestsOnlyLocalTraffic checks if service requests OnlyLocal traffic.
func RequestsOnlyLocalTraffic(service *v1.Service) bool {
	if service.Spec.Type != v1.ServiceTypeLoadBalancer &&
		service.Spec.Type != v1.ServiceTypeNodePort {
		return false
	}
	return service.Spec.ExternalTrafficPolicy == v1.ServiceExternalTrafficPolicyTypeLocal
}

// NeedsHealthCheck checks if service needs health check.
func NeedsHealthCheck(service *v1.Service) bool {
	if service.Spec.Type != v1.ServiceTypeLoadBalancer {
		return false
	}
	return RequestsOnlyLocalTraffic(service)
}

// HasLBFinalizer checks if service contains LoadBalancerCleanupFinalizer.
func HasLBFinalizer(service *v1.Service) bool {
	for _, finalizer := range service.ObjectMeta.Finalizers {
		if finalizer == LoadBalancerCleanupFinalizer {
			return true
		}
	}
	return false
}

// LoadBalancerStatusEqual checks if load balancer status are equal
func LoadBalancerStatusEqual(l, r *v1.LoadBalancerStatus) bool {
	return ingressSliceEqual(l.Ingress, r.Ingress)
}

// PatchService patches the given service's Status or ObjectMeta based on the original and
// updated ones. Change to spec will be ignored.
func PatchService(c corev1.CoreV1Interface, oldSvc, newSvc *v1.Service) (*v1.Service, error) {
	// Reset spec to make sure only patch for Status or ObjectMeta.
	newSvc.Spec = oldSvc.Spec

	patchBytes, err := getPatchBytes(oldSvc, newSvc)
	if err != nil {
		return nil, err
	}

	return c.Services(oldSvc.Namespace).Patch(context.TODO(), oldSvc.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}, "status")

}

func getPatchBytes(oldSvc, newSvc *v1.Service) ([]byte, error) {
	oldData, err := json.Marshal(oldSvc)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal oldData for svc %s/%s: %v", oldSvc.Namespace, oldSvc.Name, err)
	}

	newData, err := json.Marshal(newSvc)
	if err != nil {
		return nil, fmt.Errorf("failed to Marshal newData for svc %s/%s: %v", newSvc.Namespace, newSvc.Name, err)
	}

	patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Service{})
	if err != nil {
		return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for svc %s/%s: %v", oldSvc.Namespace, oldSvc.Name, err)
	}
	return patchBytes, nil

}

func ingressSliceEqual(lhs, rhs []v1.LoadBalancerIngress) bool {
	if len(lhs) != len(rhs) {
		return false
	}
	for i := range lhs {
		if !ingressEqual(&lhs[i], &rhs[i]) {
			return false
		}
	}
	return true
}

func ingressEqual(lhs, rhs *v1.LoadBalancerIngress) bool {
	if lhs.IP != rhs.IP {
		return false
	}
	if lhs.Hostname != rhs.Hostname {
		return false
	}
	return true
}
<|endoftext|>


<commit_before>package sslLabsClientSupport

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sort"
	"strconv"
	"strings"

	"github.com/mozilla/scribe"
	"github.com/mozilla/tls-observatory/connection"
	"github.com/mozilla/tls-observatory/constants"
	"github.com/mozilla/tls-observatory/logger"
	"github.com/mozilla/tls-observatory/worker"
)

var (
	workerName           = "sslLabsClientSupport"
	workerDesc           = "Determines client compatibility with a given target based on server certificate and ciphersuites."
	sslLabsClientDataURL = "https://api.ssllabs.com/api/v3/getClients"
	log                  = logger.GetLogger()
)

func init() {
	runner := new(slabscrunner)
	cs, err := getConffromURL(sslLabsClientDataURL)
	if err != nil {
		log.Printf("Failed to initialize %s: %v", workerName, err)
		return
	}
	runner.Clients = cs
	worker.RegisterWorker(workerName, worker.Info{Runner: runner, Description: workerDesc})
}

// getClientDataFrom retrieves the json containing the sslLabs client data
func getConffromURL(url string) (cs []Client, err error) {
	r, err := http.Get(url)
	if err != nil {
		return
	}
	defer r.Body.Close()
	err = json.NewDecoder(r.Body).Decode(&cs)
	return
}

type slabscrunner struct {
	Clients []Client
}

// Client is a definition of a TLS client with all the parameters it supports
type Client struct {
	ID                       int      `json:"id"`
	Name                     string   `json:"name"`
	Platform                 string   `json:"platform"`
	Version                  string   `json:"version"`
	HandshakeFormat          string   `json:"handshakeFormat"`
	LowestProtocol           int      `json:"lowestProtocol"`
	HighestProtocol          int      `json:"highestProtocol"`
	UserAgent                string   `json:"userAgent"`
	IsGrade0                 bool     `json:"isGrade0"`
	MaxDhBits                int      `json:"maxDhBits"`
	AbortsOnUnrecognizedName bool     `json:"abortsOnUnrecognizedName"`
	MaxRsaBits               int      `json:"maxRsaBits"`
	MinDhBits                int      `json:"minDhBits"`
	RequiresSha2             bool     `json:"requiresSha2"`
	MinRsaBits               int      `json:"minRsaBits"`
	MinEcdsaBits             int      `json:"minEcdsaBits"`
	SuiteIds                 []int    `json:"suiteIds"`
	SuiteNames               []string `json:"suiteNames"`
	SupportsSni              bool     `json:"supportsSni"`
	SupportsCompression      bool     `json:"supportsCompression"`
	SupportsStapling         bool     `json:"supportsStapling"`
	SupportsTickets          bool     `json:"supportsTickets"`
	SupportsRi               bool     `json:"supportsRi"`
	SignatureAlgorithms      []int    `json:"signatureAlgorithms"`
	EllipticCurves           []int    `json:"ellipticCurves"`
	SupportsNpn              bool     `json:"supportsNpn"`
	NpnProtocols             []string `json:"npnProtocols"`
	AlpnProtocols            []string `json:"alpnProtocols"`
}

// CipherSuite represent a ciphersuite generated and recognised by OpenSSL
type CipherSuite struct {
	IANAName   string     `json:"iana_name"`
	GnuTLSName string     `json:"gnutls_name"`
	NSSName    string     `json:"nss_name"`
	Proto      string     `json:"proto"`
	Kx         string     `json:"kx"`
	Au         string     `json:"au"`
	Enc        Encryption `json:"encryption"`
	Mac        string     `json:"mac"`
	Code       uint64     `json:"code"`
}

//Encryption represents the encryption aspects of a Ciphersuite
type Encryption struct {
	Cipher string `json:"cipher"`
	Bits   int    `json:"key"`
}

type ClientSupport struct {
	Name            string `json:"name"`
	Version         string `json:"version"`
	Platform        string `json:"platform"`
	IsSupported     bool   `json:"is_supported"`
	Ciphersuite     string `json:"ciphersuite,omitempty"`
	CiphersuiteCode uint64 `json:"ciphersuite_code,omitempty"`
	Curve           string `json:"curve,omitempty"`
	CurveCode       uint64 `json:"curve_code"`
	Protocol        string `json:"protocol,omitempty"`
	ProtocolCode    int    `json:"protocol_code"`
}

type ClientsSupport []ClientSupport

func (slice ClientsSupport) Len() int {
	return len(slice)
}

func (slice ClientsSupport) Less(i, j int) bool {
	return slice[i].Name < slice[j].Name
}

func (slice ClientsSupport) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

func (w slabscrunner) Run(in worker.Input, res chan worker.Result) {
	var clients ClientsSupport
	dedupClients := make(map[string]bool)
	// Loop over every client defined in the sslLabs document and check if they can
	// negotiate one of the ciphersuite measured on the server
	for _, client := range w.Clients {
		// if we already processed a client with this name, version and platform, skip it
		if _, ok := dedupClients[fmt.Sprintf("%s%s%s", client.Name, client.Version, client.Platform)]; ok {
			continue
		}
		for _, clientCiphersuite := range client.SuiteIds {
			for _, serverCiphersuite := range in.Connection.CipherSuite {
				serverCiphersuiteCode := constants.CipherSuites[serverCiphersuite.Cipher].Code
				if clientCiphersuite == int(serverCiphersuiteCode) {
					var (
						curve, protocol string
						curveCode       uint64
						protocolCode    int
					)
					// if the ciphersuite is DHE, verify that the client support the DH size
					if strings.HasPrefix(serverCiphersuite.Cipher, "DHE-") &&
						client.MaxDhBits > 0 &&
						!clientSupportsDHE(client, serverCiphersuite) {
						continue
					}
					// if the ciphersuite is ECDHE, verify that the client supports the curve
					if strings.HasPrefix(serverCiphersuite.Cipher, "ECDHE-") && len(client.EllipticCurves) > 0 {
						curve, curveCode = findClientCurve(client, serverCiphersuite)
						if curve == "" {
							continue
						}
					}
					protocol, protocolCode = findClientProtocol(client, serverCiphersuite)
					if protocol == "" {
						continue
					}
					// if we reached this point, the client is able to establish a connection
					// to the server. we flag it as supported and go to the next client.
					clients = append(clients, ClientSupport{
						Name:            client.Name,
						Version:         client.Version,
						Platform:        client.Platform,
						IsSupported:     true,
						Ciphersuite:     serverCiphersuite.Cipher,
						CiphersuiteCode: serverCiphersuite.Code,
						Curve:           curve,
						CurveCode:       curveCode,
						Protocol:        protocol,
						ProtocolCode:    protocolCode,
					})
					goto nextClient
				}
			}
		}
		// if we reach this point, it means no support was found for this client
		clients = append(clients, ClientSupport{
			Name:        client.Name,
			Version:     client.Version,
			IsSupported: false,
		})
	nextClient:
	}
	out, err := json.Marshal(clients)
	if err != nil {
		w.error(res, "Failed to marshal results: %v", err)
	}
	res <- worker.Result{
		Success:    true,
		WorkerName: workerName,
		Errors:     nil,
		Result:     out,
	}
}

func clientSupportsDHE(client Client, serverCiphersuite connection.Ciphersuite) bool {
	// extract the dhe bits from the pfs string
	split := strings.Split(serverCiphersuite.PFS, ",")
	if len(split) < 2 {
		return false
	}
	split = strings.Split(split[1], "b")
	if len(split) < 2 {
		return false
	}
	dhsize, err := strconv.Atoi(split[0])
	if err != nil {
		return false
	}
	if client.MaxDhBits < dhsize {
		return false
	}
	return true
}

func findClientCurve(client Client, serverCiphersuite connection.Ciphersuite) (string, uint64) {
	for _, code := range client.EllipticCurves {
		// convert curve code to name
		for _, curveRef := range constants.Curves {
			if int(curveRef.Code) == code {
				for _, serverCurves := range serverCiphersuite.Curves {
					if curveRef.Name == serverCurves || curveRef.OpenSSLName == serverCurves {
						return curveRef.Name, curveRef.Code
					}
				}
			}
		}
	}
	return "", 0
}

func findClientProtocol(client Client, serverCiphersuite connection.Ciphersuite) (string, int) {
	for _, serverProto := range serverCiphersuite.Protocols {
		var spcode int
		for _, proto := range constants.Protocols {
			if proto.OpenSSLName == serverProto {
				spcode = proto.Code
			}
		}
		if client.LowestProtocol <= spcode && client.HighestProtocol >= spcode {
			return serverProto, spcode
		}
	}
	return "", 0
}

func (w slabscrunner) error(res chan worker.Result, messageFormat string, args ...interface{}) {
	out, _ := json.Marshal(fmt.Sprintf(messageFormat, args...))
	res <- worker.Result{
		Success:    false,
		WorkerName: workerName,
		Result:     out,
	}
}

type eval struct {
}

func (w slabscrunner) AnalysisPrinter(r []byte, printAll interface{}) (results []string, err error) {
	var cs ClientsSupport
	err = json.Unmarshal(r, &cs)
	if err != nil {
		err = fmt.Errorf("SSLLabs Client Support: failed to parse results: %v", err)
		return
	}
	if printAll != nil && printAll.(bool) == true {
		results = append(results, "* SSLLabs Client Support: showing all clients compatibility")
	} else {
		results = append(results, "* SSLLabs Client Support: showing most recent compatible clients")
	}
	var productsSupport = make(map[string]ClientSupport)
	// sort the list of clients, it's nicer to display
	sort.Sort(cs)
	for _, client := range cs {
		// if we want all clients, store the result and go to next entry
		if printAll != nil && printAll.(bool) == true {
			result := fmt.Sprintf("  - %s %s", client.Name, client.Version)
			if client.Platform != "" {
				result += fmt.Sprintf(" (%s)", client.Platform)
			}
			if client.IsSupported {
				result += fmt.Sprintf(": yes, %s %s %s", client.Protocol, client.Ciphersuite, client.Curve)
			} else {
				result += fmt.Sprintf(": no")
			}
			results = append(results, result)
			continue
		}
		// Once we reach this point, we only want supported clients
		if !client.IsSupported {
			continue
		}
		// if we only want the oldest compatible client, some dark magic is required
		// to parse the version of each client, which varies in format, and figure out
		// the oldest
		if _, ok := productsSupport[client.Name]; !ok {
			// this is the first supported client of this name that we encounter,
			// no comparison needed, simply store it
			productsSupport[client.Name] = client
			continue
		}
		prevClient := productsSupport[client.Name]
		// FIXME: scribe doesn't like single number versions, so add a ".0" to work around it
		cVersion := client.Version
		_, err = strconv.Atoi(cVersion)
		if err == nil {
			cVersion += ".0"
		}
		pVersion := prevClient.Version
		_, err = strconv.Atoi(pVersion)
		if err == nil {
			pVersion += ".0"
		}
		// compare the version of the previous and current clients,
		// if the current client is older, store it instead of the previous one
		isOlder, err := scribe.TestEvrCompare(scribe.EVROP_LESS_THAN, cVersion, pVersion)
		if err != nil {
			log.Printf("Failed to compare version %s with version %s for client %s: %v",
				pVersion, cVersion, client.Name, err)
		}
		if isOlder {
			productsSupport[client.Name] = client
		}
	}
	if printAll != nil && printAll.(bool) == true {
		// if we just want to print all clients, return here
		return
	}
	// if we only want the oldest client, build the list here
	var supportedClients []string
	for _, clientName := range []string{"Firefox", "Chrome", "Edge", "IE", "Safari", "Opera", "Android", "OpenSSL", "Java"} {
		client := productsSupport[clientName]
		result := fmt.Sprintf("%s %s", client.Name, client.Version)
		supportedClients = append(supportedClients, result)
	}
	results = append(results, fmt.Sprintf("  - %s", strings.Join(supportedClients, ", ")))
	return
}
<commit_msg>Fix version testing in SSL Client support analysis printer<commit_after>package sslLabsClientSupport

import (
	"encoding/json"
	"fmt"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"unicode"

	"github.com/mozilla/scribe"
	"github.com/mozilla/tls-observatory/connection"
	"github.com/mozilla/tls-observatory/constants"
	"github.com/mozilla/tls-observatory/logger"
	"github.com/mozilla/tls-observatory/worker"
)

var (
	workerName           = "sslLabsClientSupport"
	workerDesc           = "Determines client compatibility with a given target based on server certificate and ciphersuites."
	sslLabsClientDataURL = "https://api.ssllabs.com/api/v3/getClients"
	log                  = logger.GetLogger()
)

func init() {
	runner := new(slabscrunner)
	cs, err := getConffromURL(sslLabsClientDataURL)
	if err != nil {
		log.Printf("Failed to initialize %s: %v", workerName, err)
		return
	}
	runner.Clients = cs
	worker.RegisterWorker(workerName, worker.Info{Runner: runner, Description: workerDesc})
}

// getClientDataFrom retrieves the json containing the sslLabs client data
func getConffromURL(url string) (cs []Client, err error) {
	r, err := http.Get(url)
	if err != nil {
		return
	}
	defer r.Body.Close()
	err = json.NewDecoder(r.Body).Decode(&cs)
	return
}

type slabscrunner struct {
	Clients []Client
}

// Client is a definition of a TLS client with all the parameters it supports
type Client struct {
	ID                       int      `json:"id"`
	Name                     string   `json:"name"`
	Platform                 string   `json:"platform"`
	Version                  string   `json:"version"`
	HandshakeFormat          string   `json:"handshakeFormat"`
	LowestProtocol           int      `json:"lowestProtocol"`
	HighestProtocol          int      `json:"highestProtocol"`
	UserAgent                string   `json:"userAgent"`
	IsGrade0                 bool     `json:"isGrade0"`
	MaxDhBits                int      `json:"maxDhBits"`
	AbortsOnUnrecognizedName bool     `json:"abortsOnUnrecognizedName"`
	MaxRsaBits               int      `json:"maxRsaBits"`
	MinDhBits                int      `json:"minDhBits"`
	RequiresSha2             bool     `json:"requiresSha2"`
	MinRsaBits               int      `json:"minRsaBits"`
	MinEcdsaBits             int      `json:"minEcdsaBits"`
	SuiteIds                 []int    `json:"suiteIds"`
	SuiteNames               []string `json:"suiteNames"`
	SupportsSni              bool     `json:"supportsSni"`
	SupportsCompression      bool     `json:"supportsCompression"`
	SupportsStapling         bool     `json:"supportsStapling"`
	SupportsTickets          bool     `json:"supportsTickets"`
	SupportsRi               bool     `json:"supportsRi"`
	SignatureAlgorithms      []int    `json:"signatureAlgorithms"`
	EllipticCurves           []int    `json:"ellipticCurves"`
	SupportsNpn              bool     `json:"supportsNpn"`
	NpnProtocols             []string `json:"npnProtocols"`
	AlpnProtocols            []string `json:"alpnProtocols"`
}

// CipherSuite represent a ciphersuite generated and recognised by OpenSSL
type CipherSuite struct {
	IANAName   string     `json:"iana_name"`
	GnuTLSName string     `json:"gnutls_name"`
	NSSName    string     `json:"nss_name"`
	Proto      string     `json:"proto"`
	Kx         string     `json:"kx"`
	Au         string     `json:"au"`
	Enc        Encryption `json:"encryption"`
	Mac        string     `json:"mac"`
	Code       uint64     `json:"code"`
}

//Encryption represents the encryption aspects of a Ciphersuite
type Encryption struct {
	Cipher string `json:"cipher"`
	Bits   int    `json:"key"`
}

type ClientSupport struct {
	Name            string `json:"name"`
	Version         string `json:"version"`
	Platform        string `json:"platform"`
	IsSupported     bool   `json:"is_supported"`
	Ciphersuite     string `json:"ciphersuite,omitempty"`
	CiphersuiteCode uint64 `json:"ciphersuite_code,omitempty"`
	Curve           string `json:"curve,omitempty"`
	CurveCode       uint64 `json:"curve_code"`
	Protocol        string `json:"protocol,omitempty"`
	ProtocolCode    int    `json:"protocol_code"`
}

type ClientsSupport []ClientSupport

func (slice ClientsSupport) Len() int {
	return len(slice)
}

func (slice ClientsSupport) Less(i, j int) bool {
	return slice[i].Name < slice[j].Name
}

func (slice ClientsSupport) Swap(i, j int) {
	slice[i], slice[j] = slice[j], slice[i]
}

func (w slabscrunner) Run(in worker.Input, res chan worker.Result) {
	var clients ClientsSupport
	dedupClients := make(map[string]bool)
	// Loop over every client defined in the sslLabs document and check if they can
	// negotiate one of the ciphersuite measured on the server
	for _, client := range w.Clients {
		// if we already processed a client with this name, version and platform, skip it
		if _, ok := dedupClients[fmt.Sprintf("%s%s%s", client.Name, client.Version, client.Platform)]; ok {
			continue
		}
		for _, clientCiphersuite := range client.SuiteIds {
			for _, serverCiphersuite := range in.Connection.CipherSuite {
				serverCiphersuiteCode := constants.CipherSuites[serverCiphersuite.Cipher].Code
				if clientCiphersuite == int(serverCiphersuiteCode) {
					var (
						curve, protocol string
						curveCode       uint64
						protocolCode    int
					)
					// if the ciphersuite is DHE, verify that the client support the DH size
					if strings.HasPrefix(serverCiphersuite.Cipher, "DHE-") &&
						client.MaxDhBits > 0 &&
						!clientSupportsDHE(client, serverCiphersuite) {
						continue
					}
					// if the ciphersuite is ECDHE, verify that the client supports the curve
					if strings.HasPrefix(serverCiphersuite.Cipher, "ECDHE-") && len(client.EllipticCurves) > 0 {
						curve, curveCode = findClientCurve(client, serverCiphersuite)
						if curve == "" {
							continue
						}
					}
					protocol, protocolCode = findClientProtocol(client, serverCiphersuite)
					if protocol == "" {
						continue
					}
					// if we reached this point, the client is able to establish a connection
					// to the server. we flag it as supported and go to the next client.
					clients = append(clients, ClientSupport{
						Name:            client.Name,
						Version:         client.Version,
						Platform:        client.Platform,
						IsSupported:     true,
						Ciphersuite:     serverCiphersuite.Cipher,
						CiphersuiteCode: serverCiphersuite.Code,
						Curve:           curve,
						CurveCode:       curveCode,
						Protocol:        protocol,
						ProtocolCode:    protocolCode,
					})
					goto nextClient
				}
			}
		}
		// if we reach this point, it means no support was found for this client
		clients = append(clients, ClientSupport{
			Name:        client.Name,
			Version:     client.Version,
			IsSupported: false,
		})
	nextClient:
	}
	out, err := json.Marshal(clients)
	if err != nil {
		w.error(res, "Failed to marshal results: %v", err)
	}
	res <- worker.Result{
		Success:    true,
		WorkerName: workerName,
		Errors:     nil,
		Result:     out,
	}
}

func clientSupportsDHE(client Client, serverCiphersuite connection.Ciphersuite) bool {
	// extract the dhe bits from the pfs string
	split := strings.Split(serverCiphersuite.PFS, ",")
	if len(split) < 2 {
		return false
	}
	split = strings.Split(split[1], "b")
	if len(split) < 2 {
		return false
	}
	dhsize, err := strconv.Atoi(split[0])
	if err != nil {
		return false
	}
	if client.MaxDhBits < dhsize {
		return false
	}
	return true
}

func findClientCurve(client Client, serverCiphersuite connection.Ciphersuite) (string, uint64) {
	for _, code := range client.EllipticCurves {
		// convert curve code to name
		for _, curveRef := range constants.Curves {
			if int(curveRef.Code) == code {
				for _, serverCurves := range serverCiphersuite.Curves {
					if curveRef.Name == serverCurves || curveRef.OpenSSLName == serverCurves {
						return curveRef.Name, curveRef.Code
					}
				}
			}
		}
	}
	return "", 0
}

func findClientProtocol(client Client, serverCiphersuite connection.Ciphersuite) (string, int) {
	for _, serverProto := range serverCiphersuite.Protocols {
		var spcode int
		for _, proto := range constants.Protocols {
			if proto.OpenSSLName == serverProto {
				spcode = proto.Code
			}
		}
		if client.LowestProtocol <= spcode && client.HighestProtocol >= spcode {
			return serverProto, spcode
		}
	}
	return "", 0
}

func (w slabscrunner) error(res chan worker.Result, messageFormat string, args ...interface{}) {
	out, _ := json.Marshal(fmt.Sprintf(messageFormat, args...))
	res <- worker.Result{
		Success:    false,
		WorkerName: workerName,
		Result:     out,
	}
}

type eval struct {
}

func (w slabscrunner) AnalysisPrinter(r []byte, printAll interface{}) (results []string, err error) {
	var cs ClientsSupport
	err = json.Unmarshal(r, &cs)
	if err != nil {
		err = fmt.Errorf("SSLLabs Client Support: failed to parse results: %v", err)
		return
	}
	if printAll != nil && printAll.(bool) == true {
		results = append(results, "* SSLLabs Client Support: showing all clients compatibility")
	} else {
		results = append(results, "* SSLLabs Client Support: showing most recent compatible clients")
	}
	var productsSupport = make(map[string]ClientSupport)
	// sort the list of clients, it's nicer to display
	sort.Sort(cs)
	for _, client := range cs {
		// if we want all clients, store the result and go to next entry
		if printAll != nil && printAll.(bool) == true {
			result := fmt.Sprintf("  - %s %s", client.Name, client.Version)
			if client.Platform != "" {
				result += fmt.Sprintf(" (%s)", client.Platform)
			}
			if client.IsSupported {
				result += fmt.Sprintf(": yes, %s %s %s", client.Protocol, client.Ciphersuite, client.Curve)
			} else {
				result += fmt.Sprintf(": no")
			}
			results = append(results, result)
			continue
		}
		// Once we reach this point, we only want supported clients
		if !client.IsSupported {
			continue
		}
		// if we only want the oldest compatible client, some dark magic is required
		// to parse the version of each client, which varies in format, and figure out
		// the oldest
		if _, ok := productsSupport[client.Name]; !ok {
			// this is the first supported client of this name that we encounter,
			// no comparison needed, simply store it
			productsSupport[client.Name] = client
			continue
		}
		prevClient := productsSupport[client.Name]

		// FIXME: scribe doesn't like single number versions, so add a ".0" to work around it
		cVersion := client.Version
		if len(cVersion) > 0 && unicode.IsDigit(rune(cVersion[0])) {
			_, err = strconv.Atoi(cVersion)
			if err == nil {
				cVersion += ".0"
			}
		}
		pVersion := prevClient.Version
		if len(pVersion) > 0 && unicode.IsDigit(rune(pVersion[0])) {
			_, err = strconv.Atoi(pVersion)
			if err == nil {
				pVersion += ".0"
			}
		}
		// compare the version of the previous and current clients,
		// if the current client is older, store it instead of the previous one
		isOlder, err := scribe.TestEvrCompare(scribe.EVROP_LESS_THAN, cVersion, pVersion)
		if err != nil {
			log.Printf("Failed to compare version %s with version %s for client %s: %v",
				pVersion, cVersion, client.Name, err)
		}
		if isOlder {
			productsSupport[client.Name] = client
		}
	}
	if printAll != nil && printAll.(bool) == true {
		// if we just want to print all clients, return here
		return
	}
	// if we only want the oldest client, build the list here
	var supportedClients []string
	for _, clientName := range []string{"Firefox", "Chrome", "Edge", "IE", "Safari", "Opera", "Android", "OpenSSL", "Java"} {
		client := productsSupport[clientName]
		result := fmt.Sprintf("%s %s", client.Name, client.Version)
		supportedClients = append(supportedClients, result)
	}
	results = append(results, fmt.Sprintf("  - %s", strings.Join(supportedClients, ", ")))
	return
}
<|endoftext|>


<commit_before>package http_test

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"testing"
	"time"

	"github.com/pilosa/pilosa"
	"github.com/pilosa/pilosa/http"
	"github.com/pilosa/pilosa/mock"
	"github.com/pilosa/pilosa/server"
	"github.com/pilosa/pilosa/test"
)

func newMockReadCloser() *mock.ReadCloser {
	return &mock.ReadCloser{
		ReadFunc: func(p []byte) (int, error) {
			return 0, io.EOF
		},
		CloseFunc: func() error {
			return nil
		},
	}
}

func TestTranslateStore_Reader(t *testing.T) {
	// Ensure client can connect and stream the translate store data.
	t.Run("OK", func(t *testing.T) {
		t.Run("ServerDisconnect", func(t *testing.T) {
			primary := test.MustRunCluster(t, 1)[0]

			hldr := test.Holder{Holder: primary.Server.Holder()}
			index := hldr.MustCreateIndexIfNotExists("i", pilosa.IndexOptions{Keys: true})
			_, err := index.CreateField("f", pilosa.OptFieldTypeDefault())
			if err != nil {
				t.Fatal(err)
			}

			// Set data on the primary node.
			if _, err := primary.API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `` +
				fmt.Sprintf("Set(%s, f=%d)\n", `"foo"`, 10) +
				fmt.Sprintf("Set(%s, f=%d)\n", `"bar"`, 10) +
				fmt.Sprintf("Set(%s, f=%d)\n", `"baz"`, 10),
			}); err != nil {
				t.Fatal(err)
			}

			// Wait to ensure writes make it to translate store
			time.Sleep(100 * time.Millisecond)

			// Connect to server and stream all available data.
			store := http.NewTranslateStore(primary.URL())

			rc, err := store.Reader(context.Background(), 11) // offset=11 skips the first entry: \n\x01\x01i\x00\x01\x01\x03foo

			// Close the primary to disconnect reader.
			primary.Close()

			if err != nil {
				t.Fatal(err)
			} else if data, err := ioutil.ReadAll(rc); err != nil {
				t.Fatal(err)
			} else if string(data) != "\n\x01\x01i\x00\x01\x02\x03bar\n\x01\x01i\x00\x01\x03\x03baz" {
				t.Fatalf("unexpected data: %q", data)
			} else if err := rc.Close(); err != nil {
				t.Fatal(err)
			}
		})

		// Ensure server closes store reader if client disconnects.
		t.Run("ClientDisconnect", func(t *testing.T) {
			t.Skip() // can't mock server from http package
			// Setup mock so that Read() hangs.
			done := make(chan struct{})

			var mrc mock.ReadCloser
			mrc.ReadFunc = func(p []byte) (int, error) {
				<-done
				return 0, io.EOF
			}

			closeInvoked := make(chan struct{})

			mrc.CloseFunc = func() error {
				close(closeInvoked)
				return nil
			}

			var translateStore mock.TranslateStore

			translateStore.ReaderFunc = func(ctx context.Context, off int64) (io.ReadCloser, error) {
				return &mrc, nil
			}

			opts := server.OptCommandServerOptions(pilosa.OptServerPrimaryTranslateStore(translateStore))
			primary := test.MustRunCluster(t, 1, []server.CommandOption{opts})[0]

			defer primary.Close()
			defer close(done)

			// Connect to server and begin streaming.
			ctx, cancel := context.WithCancel(context.Background())
			store := http.NewTranslateStore(primary.URL())
			if _, err := store.Reader(ctx, 0); err != nil {
				t.Fatal(err)
			}

			// Cancel the context and check if server is closed.
			cancel()
			select {
			case <-time.NewTimer(time.Millisecond * 100).C:
				t.Fatal("expected server close")
			case <-closeInvoked:
				return
			}
		})
	})

	// Ensure client is notified if the server doesn't support streaming replication.
	t.Run("ErrNotImplemented", func(t *testing.T) {
		t.Skip() // can't mock server from http package
		var translateStore mock.TranslateStore
		translateStore.ReaderFunc = func(ctx context.Context, off int64) (io.ReadCloser, error) {
			return nil, pilosa.ErrNotImplemented
		}

		opts := server.OptCommandServerOptions(pilosa.OptServerPrimaryTranslateStore(translateStore))
		primary := test.MustRunCluster(t, 1, []server.CommandOption{opts})[0]
		defer primary.Close()

		_, err := http.NewTranslateStore(primary.URL()).Reader(context.Background(), 0)
		if err != pilosa.ErrNotImplemented {
			t.Fatalf("unexpected error: %s", err)
		}
	})
}
<commit_msg>move sleep to be after replica sync<commit_after>package http_test

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"testing"
	"time"

	"github.com/pilosa/pilosa"
	"github.com/pilosa/pilosa/http"
	"github.com/pilosa/pilosa/mock"
	"github.com/pilosa/pilosa/server"
	"github.com/pilosa/pilosa/test"
)

func newMockReadCloser() *mock.ReadCloser {
	return &mock.ReadCloser{
		ReadFunc: func(p []byte) (int, error) {
			return 0, io.EOF
		},
		CloseFunc: func() error {
			return nil
		},
	}
}

func TestTranslateStore_Reader(t *testing.T) {
	// Ensure client can connect and stream the translate store data.
	t.Run("OK", func(t *testing.T) {
		t.Run("ServerDisconnect", func(t *testing.T) {
			primary := test.MustRunCluster(t, 1)[0]

			hldr := test.Holder{Holder: primary.Server.Holder()}
			index := hldr.MustCreateIndexIfNotExists("i", pilosa.IndexOptions{Keys: true})
			_, err := index.CreateField("f", pilosa.OptFieldTypeDefault())
			if err != nil {
				t.Fatal(err)
			}

			// Set data on the primary node.
			if _, err := primary.API.Query(context.Background(), &pilosa.QueryRequest{Index: "i", Query: `` +
				fmt.Sprintf("Set(%s, f=%d)\n", `"foo"`, 10) +
				fmt.Sprintf("Set(%s, f=%d)\n", `"bar"`, 10) +
				fmt.Sprintf("Set(%s, f=%d)\n", `"baz"`, 10),
			}); err != nil {
				t.Fatal(err)
			}

			// Connect to server and stream all available data.
			store := http.NewTranslateStore(primary.URL())

			// Wait to ensure writes make it to translate store
			time.Sleep(100 * time.Millisecond)

			rc, err := store.Reader(context.Background(), 11) // offset=11 skips the first entry: \n\x01\x01i\x00\x01\x01\x03foo

			// Close the primary to disconnect reader.
			primary.Close()

			if err != nil {
				t.Fatal(err)
			} else if data, err := ioutil.ReadAll(rc); err != nil {
				t.Fatal(err)
			} else if string(data) != "\n\x01\x01i\x00\x01\x02\x03bar\n\x01\x01i\x00\x01\x03\x03baz" {
				t.Fatalf("unexpected data: %q", data)
			} else if err := rc.Close(); err != nil {
				t.Fatal(err)
			}
		})

		// Ensure server closes store reader if client disconnects.
		t.Run("ClientDisconnect", func(t *testing.T) {
			t.Skip() // can't mock server from http package
			// Setup mock so that Read() hangs.
			done := make(chan struct{})

			var mrc mock.ReadCloser
			mrc.ReadFunc = func(p []byte) (int, error) {
				<-done
				return 0, io.EOF
			}

			closeInvoked := make(chan struct{})

			mrc.CloseFunc = func() error {
				close(closeInvoked)
				return nil
			}

			var translateStore mock.TranslateStore

			translateStore.ReaderFunc = func(ctx context.Context, off int64) (io.ReadCloser, error) {
				return &mrc, nil
			}

			opts := server.OptCommandServerOptions(pilosa.OptServerPrimaryTranslateStore(translateStore))
			primary := test.MustRunCluster(t, 1, []server.CommandOption{opts})[0]

			defer primary.Close()
			defer close(done)

			// Connect to server and begin streaming.
			ctx, cancel := context.WithCancel(context.Background())
			store := http.NewTranslateStore(primary.URL())
			if _, err := store.Reader(ctx, 0); err != nil {
				t.Fatal(err)
			}

			// Cancel the context and check if server is closed.
			cancel()
			select {
			case <-time.NewTimer(time.Millisecond * 100).C:
				t.Fatal("expected server close")
			case <-closeInvoked:
				return
			}
		})
	})

	// Ensure client is notified if the server doesn't support streaming replication.
	t.Run("ErrNotImplemented", func(t *testing.T) {
		t.Skip() // can't mock server from http package
		var translateStore mock.TranslateStore
		translateStore.ReaderFunc = func(ctx context.Context, off int64) (io.ReadCloser, error) {
			return nil, pilosa.ErrNotImplemented
		}

		opts := server.OptCommandServerOptions(pilosa.OptServerPrimaryTranslateStore(translateStore))
		primary := test.MustRunCluster(t, 1, []server.CommandOption{opts})[0]
		defer primary.Close()

		_, err := http.NewTranslateStore(primary.URL()).Reader(context.Background(), 0)
		if err != pilosa.ErrNotImplemented {
			t.Fatalf("unexpected error: %s", err)
		}
	})
}
<|endoftext|>


<commit_before>package vizzini_test

import (
	"flag"
	"fmt"
	"log"
	"net/url"
	"os"

	"github.com/onsi/say"
	"github.com/pivotal-golang/clock"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/lager/lagertest"

	"github.com/nu7hatch/gouuid"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"testing"
	"time"

	"github.com/cloudfoundry-incubator/bbs"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/consuladapter"
)

var bbsClient bbs.Client
var serviceClient bbs.ServiceClient
var domain string
var otherDomain string
var defaultRootFS string
var guid string
var startTime time.Time

var bbsAddress string
var bbsCA string
var bbsClientCert string
var bbsClientKey string
var consulAddress string
var routableDomainSuffix string
var hostAddress string
var logger lager.Logger

var timeout time.Duration
var dockerTimeout time.Duration

func init() {
	flag.StringVar(&bbsAddress, "bbs-address", "http://10.244.16.2:8889", "http address for the bbs (required)")
	flag.StringVar(&bbsCA, "bbs-ca", "", "bbs ca cert")
	flag.StringVar(&bbsClientCert, "bbs-client-cert", "", "bbs client ssl certificate")
	flag.StringVar(&bbsClientKey, "bbs-client-key", "", "bbs client ssl key")
	flag.StringVar(&consulAddress, "consul-address", "http://127.0.0.1:8500", "http address for the consul agent (required)")
	flag.StringVar(&routableDomainSuffix, "routable-domain-suffix", "bosh-lite.com", "suffix to use when constructing FQDN")
	flag.StringVar(&hostAddress, "host-address", "10.0.2.2", "address that a process running in a container on Diego can use to reach the machine running this test.  Typically the gateway on the vagrant VM.")
	flag.Parse()

	if bbsAddress == "" {
		log.Fatal("i need a bbs address to talk to Diego...")
	}

	if consulAddress == "" {
		log.Fatal("i need a consul address to talk to Diego...")
	}
}

func TestVizziniSuite(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Vizzini Suite")
}

func NewGuid() string {
	u, err := uuid.NewV4()
	Ω(err).ShouldNot(HaveOccurred())
	return domain + "-" + u.String()[:8]
}

var _ = BeforeSuite(func() {
	timeout = 10 * time.Second
	dockerTimeout = 120 * time.Second

	timeoutArg := os.Getenv("DEFAULT_EVENTUALLY_TIMEOUT")
	if timeoutArg != "" {
		timeout, err := time.ParseDuration(timeoutArg)
		Ω(err).ShouldNot(HaveOccurred(), "invalid value '"+timeoutArg+"' for DEFAULT_EVENTUALLY_TIMEOUT")
		fmt.Printf("Setting Default Eventually Timeout to %s\n", timeout)
	}

	SetDefaultEventuallyTimeout(timeout)
	SetDefaultEventuallyPollingInterval(500 * time.Millisecond)
	SetDefaultConsistentlyPollingInterval(200 * time.Millisecond)
	domain = fmt.Sprintf("vizzini-%d", GinkgoParallelNode())
	otherDomain = fmt.Sprintf("vizzini-other-%d", GinkgoParallelNode())
	defaultRootFS = models.PreloadedRootFS("cflinuxfs2")

	var err error
	bbsClient = initializeBBSClient()

	consulClient, err := consuladapter.NewClient(consulAddress)
	Ω(err).ShouldNot(HaveOccurred())

	sessionMgr := consuladapter.NewSessionManager(consulClient)
	consulSession, err := consuladapter.NewSession("vizzini", 10*time.Second, consulClient, sessionMgr)
	Ω(err).ShouldNot(HaveOccurred())

	logger = lagertest.NewTestLogger("vizzini")

	serviceClient = bbs.NewServiceClient(consulSession, clock.NewClock())
})

var _ = BeforeEach(func() {
	startTime = time.Now()
	guid = NewGuid()
})

var _ = AfterEach(func() {
	defer func() {
		endTime := time.Now()
		fmt.Fprint(GinkgoWriter, say.Cyan("\n%s\nThis test referenced GUID %s\nStart time: %s (%d)\nEnd time: %s (%d)\n", CurrentGinkgoTestDescription().FullTestText, guid, startTime, startTime.Unix(), endTime, endTime.Unix()))
	}()

	for _, domain := range []string{domain, otherDomain} {
		ClearOutTasksInDomain(domain)
		ClearOutDesiredLRPsInDomain(domain)
	}
})

var _ = AfterSuite(func() {
	for _, domain := range []string{domain, otherDomain} {
		bbsClient.UpsertDomain(domain, 5*time.Minute) //leave the domain around forever so that Diego cleans up if need be
	}

	for _, domain := range []string{domain, otherDomain} {
		ClearOutDesiredLRPsInDomain(domain)
		ClearOutTasksInDomain(domain)
	}
})

func initializeBBSClient() bbs.Client {
	bbsURL, err := url.Parse(bbsAddress)
	Ω(err).ShouldNot(HaveOccurred())

	if bbsURL.Scheme != "https" {
		return bbs.NewClient(bbsAddress)
	}

	bbsClient, err := bbs.NewSecureClient(bbsAddress, bbsCA, bbsClientCert, bbsClientKey, 0, 0)
	Ω(err).ShouldNot(HaveOccurred())
	return bbsClient
}
<commit_msg>Use skip-verify BBS client<commit_after>package vizzini_test

import (
	"flag"
	"fmt"
	"log"
	"net/url"
	"os"

	"github.com/onsi/say"
	"github.com/pivotal-golang/clock"
	"github.com/pivotal-golang/lager"
	"github.com/pivotal-golang/lager/lagertest"

	"github.com/nu7hatch/gouuid"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"testing"
	"time"

	"github.com/cloudfoundry-incubator/bbs"
	"github.com/cloudfoundry-incubator/bbs/models"
	"github.com/cloudfoundry-incubator/consuladapter"
)

var bbsClient bbs.Client
var serviceClient bbs.ServiceClient
var domain string
var otherDomain string
var defaultRootFS string
var guid string
var startTime time.Time

var bbsAddress string
var bbsClientCert string
var bbsClientKey string
var consulAddress string
var routableDomainSuffix string
var hostAddress string
var logger lager.Logger

var timeout time.Duration
var dockerTimeout time.Duration

func init() {
	flag.StringVar(&bbsAddress, "bbs-address", "http://10.244.16.2:8889", "http address for the bbs (required)")
	flag.StringVar(&bbsClientCert, "bbs-client-cert", "", "bbs client ssl certificate")
	flag.StringVar(&bbsClientKey, "bbs-client-key", "", "bbs client ssl key")
	flag.StringVar(&consulAddress, "consul-address", "http://127.0.0.1:8500", "http address for the consul agent (required)")
	flag.StringVar(&routableDomainSuffix, "routable-domain-suffix", "bosh-lite.com", "suffix to use when constructing FQDN")
	flag.StringVar(&hostAddress, "host-address", "10.0.2.2", "address that a process running in a container on Diego can use to reach the machine running this test.  Typically the gateway on the vagrant VM.")
	flag.Parse()

	if bbsAddress == "" {
		log.Fatal("i need a bbs address to talk to Diego...")
	}

	if consulAddress == "" {
		log.Fatal("i need a consul address to talk to Diego...")
	}
}

func TestVizziniSuite(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "Vizzini Suite")
}

func NewGuid() string {
	u, err := uuid.NewV4()
	Ω(err).ShouldNot(HaveOccurred())
	return domain + "-" + u.String()[:8]
}

var _ = BeforeSuite(func() {
	timeout = 10 * time.Second
	dockerTimeout = 120 * time.Second

	timeoutArg := os.Getenv("DEFAULT_EVENTUALLY_TIMEOUT")
	if timeoutArg != "" {
		timeout, err := time.ParseDuration(timeoutArg)
		Ω(err).ShouldNot(HaveOccurred(), "invalid value '"+timeoutArg+"' for DEFAULT_EVENTUALLY_TIMEOUT")
		fmt.Printf("Setting Default Eventually Timeout to %s\n", timeout)
	}

	SetDefaultEventuallyTimeout(timeout)
	SetDefaultEventuallyPollingInterval(500 * time.Millisecond)
	SetDefaultConsistentlyPollingInterval(200 * time.Millisecond)
	domain = fmt.Sprintf("vizzini-%d", GinkgoParallelNode())
	otherDomain = fmt.Sprintf("vizzini-other-%d", GinkgoParallelNode())
	defaultRootFS = models.PreloadedRootFS("cflinuxfs2")

	var err error
	bbsClient = initializeBBSClient()

	consulClient, err := consuladapter.NewClient(consulAddress)
	Ω(err).ShouldNot(HaveOccurred())

	sessionMgr := consuladapter.NewSessionManager(consulClient)
	consulSession, err := consuladapter.NewSession("vizzini", 10*time.Second, consulClient, sessionMgr)
	Ω(err).ShouldNot(HaveOccurred())

	logger = lagertest.NewTestLogger("vizzini")

	serviceClient = bbs.NewServiceClient(consulSession, clock.NewClock())
})

var _ = BeforeEach(func() {
	startTime = time.Now()
	guid = NewGuid()
})

var _ = AfterEach(func() {
	defer func() {
		endTime := time.Now()
		fmt.Fprint(GinkgoWriter, say.Cyan("\n%s\nThis test referenced GUID %s\nStart time: %s (%d)\nEnd time: %s (%d)\n", CurrentGinkgoTestDescription().FullTestText, guid, startTime, startTime.Unix(), endTime, endTime.Unix()))
	}()

	for _, domain := range []string{domain, otherDomain} {
		ClearOutTasksInDomain(domain)
		ClearOutDesiredLRPsInDomain(domain)
	}
})

var _ = AfterSuite(func() {
	for _, domain := range []string{domain, otherDomain} {
		bbsClient.UpsertDomain(domain, 5*time.Minute) //leave the domain around forever so that Diego cleans up if need be
	}

	for _, domain := range []string{domain, otherDomain} {
		ClearOutDesiredLRPsInDomain(domain)
		ClearOutTasksInDomain(domain)
	}
})

func initializeBBSClient() bbs.Client {
	bbsURL, err := url.Parse(bbsAddress)
	Ω(err).ShouldNot(HaveOccurred())

	if bbsURL.Scheme != "https" {
		return bbs.NewClient(bbsAddress)
	}

	bbsClient, err := bbs.NewSecureSkipVerifyClient(bbsAddress, bbsClientCert, bbsClientKey, 0, 0)
	Ω(err).ShouldNot(HaveOccurred())
	return bbsClient
}
<|endoftext|>


<commit_before>package shell

import (
	"testing"

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

func TestEnvironmentSet(t *testing.T) {
	env, _ := EnvironmentFromSlice([]string{})

	env.Set("    THIS_IS_THE_BEST   \n\n", "\"IT SURE IS\"\n\n")
	assert.Equal(t, env.Get("THIS_IS_THE_BEST"), "IT SURE IS")

	env.Set("NEW_LINES_STAY_IN_SINGLE_QUOTES", "  'indeed \n it\n does\n'  ")
	assert.Equal(t, env.Get("NEW_LINES_STAY_IN_SINGLE_QUOTES"), "indeed \n it\n does\n")

	env.Set("NEW_LINES_STAY_IN_DOUBLE_QUOTES", "  \"indeed \n it\n does\n\"      ")
	assert.Equal(t, env.Get("NEW_LINES_STAY_IN_DOUBLE_QUOTES"), "indeed \n it\n does\n")

	env.Set("REMOVES_WHITESPACE_FROM_NO_QUOTES", "\n       \n  new line party\n  \n  ")
	assert.Equal(t, env.Get("REMOVES_WHITESPACE_FROM_NO_QUOTES"), "new line party")

	env.Set("DOESNT_AFFECT_QUOTES_INSIDE", `oh "hello" there`)
	assert.Equal(t, env.Get("DOESNT_AFFECT_QUOTES_INSIDE"), `oh "hello" there`)
}

func TestEnvironmentRemove(t *testing.T) {
	env, _ := EnvironmentFromSlice([]string{"FOO=bar"})

	assert.Equal(t, env.Get("FOO"), "bar")
	assert.Equal(t, env.Remove("FOO"), "bar")
	assert.Equal(t, env.Get(""), "")
}

func TestEnvironmentMerge(t *testing.T) {
	env1, _ := EnvironmentFromSlice([]string{"FOO=bar"})
	env2, _ := EnvironmentFromSlice([]string{"BAR=foo"})

	env3 := env1.Merge(env2)

	assert.Equal(t, env3.ToSlice(), []string{"BAR=foo", "FOO=bar"})
}

func TestEnvironmentCopy(t *testing.T) {
	env1, _ := EnvironmentFromSlice([]string{"FOO=bar"})
	env2 := env1.Copy()

	assert.Equal(t, env2.ToSlice(), []string{"FOO=bar"})

	env1.Set("FOO", "not-bar-anymore")

	assert.Equal(t, env2.ToSlice(), []string{"FOO=bar"})
}

func TestEnvironmentToSlice(t *testing.T) {
	env, _ := EnvironmentFromSlice([]string{"\n\nTHIS_IS_GREAT=\"this is the \n best thing\"      "})

	assert.Equal(t, env.ToSlice(), []string{"THIS_IS_GREAT=this is the \n best thing"})
}
<commit_msg>Added a test for env.Exists<commit_after>package shell

import (
	"testing"

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

func TestEnvironmentExists(t *testing.T) {
	env, _ := EnvironmentFromSlice([]string{})

	env.Set("FOO", "bar")
	env.Set("EMPTY", "")

	assert.Equal(t, env.Exists("FOO"), true)
	assert.Equal(t, env.Exists("EMPTY"), true)
	assert.Equal(t, env.Exists("does not exist"), false)
}

func TestEnvironmentSet(t *testing.T) {
	env, _ := EnvironmentFromSlice([]string{})

	env.Set("    THIS_IS_THE_BEST   \n\n", "\"IT SURE IS\"\n\n")
	assert.Equal(t, env.Get("THIS_IS_THE_BEST"), "IT SURE IS")

	env.Set("NEW_LINES_STAY_IN_SINGLE_QUOTES", "  'indeed \n it\n does\n'  ")
	assert.Equal(t, env.Get("NEW_LINES_STAY_IN_SINGLE_QUOTES"), "indeed \n it\n does\n")

	env.Set("NEW_LINES_STAY_IN_DOUBLE_QUOTES", "  \"indeed \n it\n does\n\"      ")
	assert.Equal(t, env.Get("NEW_LINES_STAY_IN_DOUBLE_QUOTES"), "indeed \n it\n does\n")

	env.Set("REMOVES_WHITESPACE_FROM_NO_QUOTES", "\n       \n  new line party\n  \n  ")
	assert.Equal(t, env.Get("REMOVES_WHITESPACE_FROM_NO_QUOTES"), "new line party")

	env.Set("DOESNT_AFFECT_QUOTES_INSIDE", `oh "hello" there`)
	assert.Equal(t, env.Get("DOESNT_AFFECT_QUOTES_INSIDE"), `oh "hello" there`)
}

func TestEnvironmentRemove(t *testing.T) {
	env, _ := EnvironmentFromSlice([]string{"FOO=bar"})

	assert.Equal(t, env.Get("FOO"), "bar")
	assert.Equal(t, env.Remove("FOO"), "bar")
	assert.Equal(t, env.Get(""), "")
}

func TestEnvironmentMerge(t *testing.T) {
	env1, _ := EnvironmentFromSlice([]string{"FOO=bar"})
	env2, _ := EnvironmentFromSlice([]string{"BAR=foo"})

	env3 := env1.Merge(env2)

	assert.Equal(t, env3.ToSlice(), []string{"BAR=foo", "FOO=bar"})
}

func TestEnvironmentCopy(t *testing.T) {
	env1, _ := EnvironmentFromSlice([]string{"FOO=bar"})
	env2 := env1.Copy()

	assert.Equal(t, env2.ToSlice(), []string{"FOO=bar"})

	env1.Set("FOO", "not-bar-anymore")

	assert.Equal(t, env2.ToSlice(), []string{"FOO=bar"})
}

func TestEnvironmentToSlice(t *testing.T) {
	env, _ := EnvironmentFromSlice([]string{"\n\nTHIS_IS_GREAT=\"this is the \n best thing\"      "})

	assert.Equal(t, env.ToSlice(), []string{"THIS_IS_GREAT=this is the \n best thing"})
}
<|endoftext|>