<commit_before>//+build ignore

/*
 * Copyright (c) 2013-2016 The btcsuite developers
 * Copyright (c) 2015 The Decred developers
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package wallet

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"strconv"

	"github.com/btcsuite/btclog"

	"github.com/decred/bitset"
	"github.com/decred/dcrutil"
	"github.com/decred/dcrwallet/chain"
	"github.com/decred/dcrwallet/waddrmgr"
	"github.com/decred/dcrwallet/walletdb"
)

// finalScanLength is the final length of accounts to scan for the
// function below.
var finalAcctScanLength = 50

// acctSeekWidth is the number of addresses for both internal and external
// branches to scan to determine whether or not an account exists and should
// be rescanned. This is the tolerance for account gaps as well.
var acctSeekWidth uint32 = 5

// accountIsUsed checks if an account has ever been used by scanning the
// first acctSeekWidth many addresses for usage.
func (w *Wallet) accountIsUsed(account uint32, chainClient *chain.RPCClient) bool {
	// Search external branch then internal branch for a used
	// address. We need to set the address function to use based
	// on whether or not this is the initial sync. The function
	// AddressDerivedFromCointype is able to see addresses that
	// exists in accounts that have not yet been created, while
	// AddressDerivedFromDbAcct can not.
	addrFunc := w.Manager.AddressDerivedFromDbAcct
	if w.initiallyUnlocked {
		addrFunc = w.Manager.AddressDerivedFromCointype
	}

	for branch := uint32(0); branch < 2; branch++ {
		for i := uint32(0); i < acctSeekWidth; i++ {
			var addr dcrutil.Address
			err := walletdb.View(w.db, func(tx walletdb.ReadTx) error {
				addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
				var err error
				addr, err = addrFunc(addrmgrNs, i, account, branch)
				return err
			})
			if err != nil {
				// Skip erroneous keys, which happen rarely.
				continue
			}

			exists, err := chainClient.ExistsAddress(addr)
			if err != nil {
				return false
			}
			if exists {
				return true
			}
		}
	}

	return false
}

// bisectLastAcctIndex is a helper function for searching through accounts to
// find the last used account. It uses logarithmic scanning to determine if
// an account has been used.
func (w *Wallet) bisectLastAcctIndex(hi, low int) int {
	chainClient, err := w.requireChainClient()
	if err != nil {
		return 0
	}

	offset := low
	for i := hi - low - 1; i > 0; i /= 2 {
		if i+offset+int(acctSeekWidth) < waddrmgr.MaxAddressesPerAccount {
			for j := i + offset + int(addrSeekWidth); j >= i+offset; j-- {
				if w.accountIsUsed(uint32(j), chainClient) {
					return i + offset
				}
			}
		} else {
			if w.accountIsUsed(uint32(i+offset), chainClient) {
				return i + offset
			}
		}
	}

	return 0
}

// findAcctEnd is a helper function for searching for the last used account by
// logarithmic scanning of the account indexes.
func (w *Wallet) findAcctEnd(start, stop int) int {
	indexStart := w.bisectLastAcctIndex(stop, start)
	indexLast := 0
	for {
		indexLastStored := indexStart
		low := indexLastStored
		hi := indexLast + ((indexStart - indexLast) * 2) + 1
		indexStart = w.bisectLastAcctIndex(hi, low)
		indexLast = indexLastStored

		if indexStart == 0 {
			break
		}
	}

	return indexLast
}

// scanAccountIndex identifies the last used address in an HD keychain of public
// keys. It returns the index of the last used key, along with the address of
// this key.
func (w *Wallet) scanAccountIndex(start int, end int) (uint32, error) {
	chainClient, err := w.requireChainClient()
	if err != nil {
		return 0, err
	}

	// Find the last used account. Scan from it to the end in case there was a
	// gap from that position, which is possible. Then, return the account
	// in that position.
	lastUsed := w.findAcctEnd(start, end)
	if lastUsed != 0 {
		for i := lastUsed + finalAcctScanLength; i >= lastUsed; i-- {
			if w.accountIsUsed(uint32(i), chainClient) {
				return uint32(i), nil
			}
		}
	}

	// We can't find any used addresses. The account is
	// unused.
	return 0, nil
}

// debugScanLength is the final length of keys to scan past the
// last index returned from the logarithmic scanning function
// when creating the debug string of used addresses.
var debugAddrScanLength = 3500

// addrSeekWidth is the number of new addresses to generate and add to the
// address manager when trying to sync up a wallet to the main chain. This
// is the maximum gap introduced by a resyncing as well, and should be less
// than finalScanLength above.
// TODO Optimize the scanning so that rather than overshooting the end address,
// you instead step through addresses incrementally until reaching idx so that
// you don't reach a gap. This can be done by keeping track of where the current
// cursor is and adding addresses in big chunks until you hit the end.
var addrSeekWidth uint32 = 20

// errDerivation is an error type signifying that the waddrmgr failed to
// derive a key.
var errDerivation = fmt.Errorf("failed to derive key")

// scanAddressRange scans backwards from end to start many addresses in the
// account branch, and return the first index that is found on the blockchain.
// If the address doesn't exist, false is returned as the first argument.
func (w *Wallet) scanAddressRange(account uint32, branch uint32, start int,
	end int, chainClient *chain.RPCClient) (bool, int, error) {

	var addresses []dcrutil.Address
	err := walletdb.View(w.db, func(tx walletdb.ReadTx) error {
		addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
		var err error
		addresses, err = w.Manager.AddressesDerivedFromDbAcct(addrmgrNs,
			uint32(start), uint32(end+1), account, branch)
		if err != nil {
			return errDerivation
		}
		return nil
	})
	if err != nil {
		return false, 0, err
	}

	// Whether or not the addresses exist is encoded as a binary
	// bitset.
	exists, err := chainClient.ExistsAddresses(addresses)
	if err != nil {
		return false, 0, err
	}
	existsB, err := hex.DecodeString(exists)
	if err != nil {
		return false, 0, err
	}
	set := bitset.Bytes(existsB)

	// Prevent a panic when an empty message is passed as a response.
	if len(set) == 0 {
		return false, 0, nil
	}

	// Scan backwards and return if we find an address exists.
	idx := end
	itr := len(addresses) - 1
	for idx >= start {
		// If the address exists in the mempool or blockchain according
		// to the bit set returned, return this index.
		if set.Get(itr) {
			return true, idx, nil
		}

		itr--
		idx--
	}

	return false, 0, nil
}

// bisectLastAddrIndex is a helper function for search through addresses.
func (w *Wallet) bisectLastAddrIndex(hi, low int, account uint32, branch uint32) int {
	chainClient, err := w.requireChainClient()
	if err != nil {
		return 0
	}

	// Logarithmically scan address indexes to find the last used
	// address index. Each time the algorithm receives an end point,
	// scans a chunk of addresses at the end point, and if no
	// addresses are found, divides the address index by two and
	// repeats until it finds the last used index.
	offset := low
	for i := hi - low - 1; i > 0; i /= 2 {
		if i+offset+int(addrSeekWidth) < waddrmgr.MaxAddressesPerAccount {
			start := i + offset
			end := i + offset + int(addrSeekWidth)
			exists, idx, err := w.scanAddressRange(account, branch, start, end,
				chainClient)
			// Skip erroneous keys, which happen rarely. Don't skip
			// other errors.
			if err == errDerivation {
				continue
			}
			if err != nil {
				log.Warnf("unexpected error encountered during bisection "+
					"scan of account %v, branch %v: %s", account, branch,
					err.Error())
				return 0
			}
			if exists {
				return idx
			}
		} else {
			var addr dcrutil.Address
			err := walletdb.View(w.db, func(tx walletdb.ReadTx) error {
				addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
				var err error
				addr, err = w.Manager.AddressDerivedFromDbAcct(addrmgrNs,
					uint32(i+offset), account, branch)
				return err
			})
			// Skip erroneous keys, which happen rarely.
			if err != nil {
				continue
			}

			exists, err := chainClient.ExistsAddress(addr)
			if err != nil {
				return 0
			}
			if exists {
				return i + offset
			}
		}
	}

	return 0
}

// findEnd is a helper function for searching for used addresses.
func (w *Wallet) findAddrEnd(start, stop int, account uint32, branch uint32) int {
	indexStart := w.bisectLastAddrIndex(stop, start, account, branch)
	indexLast := 0
	for {
		indexLastStored := indexStart
		low := indexLastStored
		hi := indexLast + ((indexStart - indexLast) * 2) + 1
		indexStart = w.bisectLastAddrIndex(hi, low, account, branch)
		indexLast = indexLastStored

		if indexStart == 0 {
			break
		}
	}

	return indexLast
}

// debugAccountAddrGapsString is a debug function that prints a graphical outlook
// of address usage to a string, from the perspective of the daemon.
func debugAccountAddrGapsString(scanBackFrom int, account uint32, branch uint32,
	w *Wallet) (string, error) {

	chainClient, err := w.requireChainClient()
	if err != nil {
		return "", err
	}

	var buf bytes.Buffer
	str := fmt.Sprintf("Begin debug address scan scanning backwards from "+
		"idx %v, account %v, branch %v\n", scanBackFrom, account, branch)
	buf.WriteString(str)
	firstUsedIndex := 0
	for i := scanBackFrom; i > 0; i-- {
		var addr dcrutil.Address
		err := walletdb.View(w.db, func(tx walletdb.ReadTx) error {
			addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
			var err error
			addr, err = w.Manager.AddressDerivedFromDbAcct(addrmgrNs,
				uint32(i), account, branch)
			return err
		})
		// Skip erroneous keys.
		if err != nil {
			continue
		}

		exists, err := chainClient.ExistsAddress(addr)
		if err != nil {
			return "", fmt.Errorf("failed to access chain server: %v",
				err.Error())
		}

		if exists {
			firstUsedIndex = i
			break
		}
	}

	str = fmt.Sprintf("Last used index found: %v\n", firstUsedIndex)
	buf.WriteString(str)

	batchSize := 50
	batches := (firstUsedIndex / batchSize) + 1
	lastBatchSize := 0
	if firstUsedIndex%batchSize != 0 {
		lastBatchSize = firstUsedIndex - ((batches - 1) * batchSize)
	}

	for i := 0; i < batches; i++ {
		str = fmt.Sprintf("%8v", i*batchSize)
		buf.WriteString(str)

		start := i * batchSize
		end := (i + 1) * batchSize
		if i == batches-1 {
			// Nothing to do because last batch empty.
			if lastBatchSize == 0 {
				break
			}
			end = (i*batchSize + lastBatchSize) + 1
		}

		for j := start; j < end; j++ {
			if j%10 == 0 {
				buf.WriteString("  ")
			}

			char := "_"
			var addr dcrutil.Address
			err := walletdb.View(w.db, func(tx walletdb.ReadTx) error {
				addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
				var err error
				addr, err = w.Manager.AddressDerivedFromDbAcct(addrmgrNs,
					uint32(j), account, branch)
				return err
			})
			if err != nil {
				char = "X"
			}

			exists, err := chainClient.ExistsAddress(addr)
			if err != nil {
				return "", fmt.Errorf("failed to access chain server: %v",
					err.Error())
			}
			if exists {
				char = "#"
			}

			buf.WriteString(char)
		}

		buf.WriteString("\n")
	}

	return buf.String(), nil
}

// scanAddressIndex identifies the last used address in an HD keychain of public
// keys. It returns the index of the last used key, along with the address of
// this key.
func (w *Wallet) scanAddressIndex(start int, end int, account uint32,
	branch uint32) (uint32, dcrutil.Address, error) {
	chainClient, err := w.requireChainClient()
	if err != nil {
		return 0, nil, err
	}

	// Find the last used address. Scan from it to the end in case there was a
	// gap from that position, which is possible. Then, return the address
	// in that position.
	lastUsed := w.findAddrEnd(start, end, account, branch)

	// If debug is on, do an exhaustive check and a graphical printout
	// of what the used addresses currently look like.
	if log.Level() == btclog.DebugLvl || log.Level() == btclog.TraceLvl {
		dbgStr, err := debugAccountAddrGapsString(lastUsed+debugAddrScanLength,
			account, branch, w)
		if err != nil {
			log.Debugf("Failed to debug address gaps for account %v, "+
				"branch %v: %v", account, branch, err)
		} else {
			log.Debugf("%v", dbgStr)
		}
	}

	// If there was a last used index, do an exhaustive final scan that
	// reexamines the last used addresses and ensures that the final index
	// we have found is correct.
	if lastUsed != 0 {
		start := lastUsed
		end := lastUsed + w.addrIdxScanLen
		exists, idx, err := w.scanAddressRange(account, branch, start, end,
			chainClient)
		if err != nil {
			return 0, nil, err
		}

		if exists {
			lastUsed = idx
			var addr dcrutil.Address
			err := walletdb.View(w.db, func(tx walletdb.ReadTx) error {
				addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
				var err error
				addr, err = w.Manager.AddressDerivedFromDbAcct(addrmgrNs,
					uint32(lastUsed), account, branch)
				return err
			})
			if err != nil {
				return 0, nil, err
			}
			return uint32(lastUsed), addr, nil
		}
	}

	// In the case that 0 was returned as the last used address,
	// make sure the the 0th address was not used. If it was,
	// return this address to let the caller know that this
	// 0th address was used.
	if lastUsed == 0 {
		var addr dcrutil.Address
		err := walletdb.View(w.db, func(tx walletdb.ReadTx) error {
			addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey)
			var err error
			addr, err = w.Manager.AddressDerivedFromDbAcct(addrmgrNs, 0,
				account, branch)
			return err
		})
		// Skip erroneous keys.
		if err != nil {
			return 0, nil, err
		}

		exists, err := chainClient.ExistsAddress(addr)
		if err != nil {
			return 0, nil, fmt.Errorf("failed to access chain server: %v",
				err.Error())
		}

		if exists {
			return 0, addr, nil
		}
	}

	// We can't find any used addresses for this account's
	// branch.
	return 0, nil, nil
}

// rescanActiveAddresses accesses the daemon to discover all the addresses that
// have been used by an HD keychain stemming from this wallet in the default
// account.
func (w *Wallet) rescanActiveAddresses() error {
	log.Infof("Beginning a rescan of active addresses using the daemon. " +
		"This may take a while.")

	// Start by rescanning the accounts and determining what the
	// current account index is. This scan should only ever be
	// performed if we're restoring our wallet from seed.
	lastAcct := uint32(0)
	var err error
	if w.initiallyUnlocked {
		min := 0
		max := waddrmgr.MaxAccountNum
		lastAcct, err = w.scanAccountIndex(min, max)
		if err != nil {
			return err
		}
	}

	err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
		addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
		lastAcctMgr, err := w.Manager.LastAccount(addrmgrNs)
		if err != nil {
			return err
		}

		// The address manager is not synced (wallet has been restored
		// from seed?). In this case, spawn the accounts in the address
		// manager first. The accounts are named by their respective
		// index number, as strings.
		if lastAcctMgr < lastAcct {
			for i := lastAcctMgr + 1; i <= lastAcct; i++ {
				_, err := w.Manager.NewAccount(
					addrmgrNs, strconv.Itoa(int(i)))
				if err != nil {
					return err
				}
			}
		}

		// The account manager has a greater index than the rescan.
		// It is likely that the end user created a new account but
		// did not use it yet. Rescan it anyway so that the address
		// pool is created.
		if lastAcctMgr > lastAcct {
			lastAcct = lastAcctMgr
		}
		return nil
	})
	if err != nil {
		return err
	}

	log.Infof("The last used account was %v. Beginning a rescan for "+
		"all active addresses in known accounts.", lastAcct)

	// Rescan addresses for the both the internal and external
	// branches of the account. Insert a new address pool for
	// the respective account and initialize it.
	for acct := uint32(0); acct <= lastAcct; acct++ {
		var extIdx, intIdx uint32
		min := 0
		max := waddrmgr.MaxAddressesPerAccount

		// Do this for both external (0) and internal (1) branches.
		for branch := uint32(0); branch < 2; branch++ {
			idx, lastAddr, err := w.scanAddressIndex(min, max, acct, branch)
			if err != nil {
				return err
			}

			err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
				addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)

				// If the account is unused, buffer the initial address pool
				// by syncing the address manager upstream.
				unusedAcct := (lastAddr == nil)
				if unusedAcct {
					_, err := w.Manager.SyncAccountToAddrIndex(
						addrmgrNs, acct, addressPoolBuffer, branch)
					if err != nil {
						// A ErrSyncToIndex error indicates that we're already
						// synced to beyond the end of the account in the
						// waddrmgr.
						errWaddrmgr, ok := err.(waddrmgr.ManagerError)
						if !ok || errWaddrmgr.ErrorCode != waddrmgr.ErrSyncToIndex {
							return fmt.Errorf("failed to create initial waddrmgr "+
								"address buffer for the address pool, "+
								"account %v, branch %v: %s", acct, branch,
								err.Error())
						}
					}
				}

				branchString := "external"
				if branch == waddrmgr.InternalBranch {
					branchString = "internal"
				}

				// Fetch the address pool index for this account and
				// branch from the database meta bucket.
				isInternal := branch == waddrmgr.InternalBranch
				oldIdx, err := w.Manager.NextToUseAddrPoolIndex(
					addrmgrNs, isInternal, acct)
				unexpectedError := false
				if err != nil {
					mErr, ok := err.(waddrmgr.ManagerError)
					if !ok {
						unexpectedError = true
					} else {
						// Skip errors where the account's address index
						// has not been store. For this case, oldIdx will
						// be the special case 0 which will always be
						// skipped in the initialization step below.
						if mErr.ErrorCode != waddrmgr.ErrMetaPoolIdxNoExist {
							unexpectedError = true
						}
					}
					if unexpectedError {
						return fmt.Errorf("got unexpected error trying to "+
							"retrieve last known addr index for acct %v, "+
							"%s branch: %v", acct, branchString, err)
					}
				}

				// If the stored index is further along than the sync-to
				// index determined by the contents of daemon's addrindex,
				// use it to initialize the address pool instead.
				nextToUseIdx := idx
				if !unusedAcct {
					nextToUseIdx++
				}
				if oldIdx > nextToUseIdx {
					nextToUseIdx = oldIdx
				}
				nextToUseAddr, err := w.Manager.AddressDerivedFromDbAcct(
					addrmgrNs, nextToUseIdx, acct, branch)
				if err != nil {
					return fmt.Errorf("failed to derive next address for "+
						"account %v, branch %v: %s", acct, branch,
						err.Error())
				}

				// Save these for the address pool startup later.
				if isInternal {
					intIdx = nextToUseIdx
				} else {
					extIdx = nextToUseIdx
				}

				// Synchronize the account manager to our address index plus
				// an extra chunk of addresses that are used as a buffer
				// in the address pool.
				_, err = w.Manager.SyncAccountToAddrIndex(addrmgrNs,
					acct, nextToUseIdx+addressPoolBuffer, branch)
				if err != nil {
					// A ErrSyncToIndex error indicates that we're already
					// synced to beyond the end of the account in the
					// waddrmgr.
					errWaddrmgr, ok := err.(waddrmgr.ManagerError)
					if !ok || errWaddrmgr.ErrorCode != waddrmgr.ErrSyncToIndex {
						return fmt.Errorf("couldn't sync %s addresses in "+
							"address manager: %v", branchString, err.Error())
					}
				}

				// Set the next address in the waddrmgr database so that the
				// address pool can synchronize properly after.
				err = w.Manager.StoreNextToUseAddress(
					addrmgrNs, isInternal, acct, nextToUseIdx)
				if err != nil {
					log.Errorf("Failed to store next to use pool idx for "+
						"%s pool in the manager on init sync: %v",
						branchString, err.Error())
				}

				log.Infof("Successfully synchronized the address manager to "+
					"%s address %v (key index %v) for account %v",
					branchString,
					nextToUseAddr.String(),
					nextToUseIdx,
					acct)
				return nil
			})
			if err != nil {
				return err
			}
		}

		pool, err := newAddressPools(acct, intIdx, extIdx, w)
		if err != nil {
			return err
		}

		w.addrPoolsMtx.Lock()
		w.addrPools[acct] = pool
		w.addrPoolsMtx.Unlock()
	}

	log.Infof("Successfully synchronized wallet accounts to account "+
		"number %v.", lastAcct)

	return nil
}
<commit_msg>wallet: remove sync.go, references decred<commit_after><|endoftext|>


<commit_before>package wallit

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

	"github.com/mit-dci/lit/wire"
	"github.com/mit-dci/lit/btcutil/hdkeychain"
	"github.com/boltdb/bolt"
	"github.com/mit-dci/lit/coinparam"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/powless"
	"github.com/mit-dci/lit/uspv"
)

func NewWallit(
	rootkey *hdkeychain.ExtendedKey, birthHeight int32, resync bool,
	spvhost, path string, p *coinparam.Params) *Wallit {

	var w Wallit
	w.rootPrivKey = rootkey
	w.Param = p
	w.FreezeSet = make(map[wire.OutPoint]*FrozenTx)

	w.FeeRate = w.Param.FeePerByte

	wallitpath := filepath.Join(path, p.Name)

	// create wallit sub dir if it's not there
	_, err := os.Stat(wallitpath)
	if os.IsNotExist(err) {
		os.Mkdir(wallitpath, 0700)
	}

	// Tricky part here is that we want the sync height to tell the chainhook,
	// so we have to open the db first, then turn on the chainhook, THEN tell
	// chainhook about all our addresses.

	// use powless for chainhook if the host string has https in it
	// this is a bit hacky for now

	if strings.Contains(spvhost, "https") {
		w.Hook = new(powless.APILink)
	} else {
		// no https; use uSPV for chainhook
		w.Hook = new(uspv.SPVCon)
	}

	wallitdbname := filepath.Join(wallitpath, "utxo.db")
	err = w.OpenDB(wallitdbname)
	if err != nil {
		log.Printf("NewWallit crash  %s ", err.Error())
	}
	// get height
	height := w.CurrentHeight()
	log.Printf("DB height %d\n", height)

	// bring height up to birthheight, or back down in case of resync
	if height < birthHeight || resync {
		height = birthHeight
		w.SetDBSyncHeight(height)
	}

	log.Printf("DB height %d\n", height)
	incomingTx, incomingBlockheight, err := w.Hook.Start(height, spvhost, wallitpath, p)
	if err != nil {
		log.Printf("NewWallit Hook.Start crash  %s ", err.Error())
	}

	// check if there are any addresses.  If there aren't (initial wallet setup)
	// then make an address.
	adrs, err := w.AdrDump()
	if err != nil {
		log.Printf("NewWallit crash  %s ", err.Error())
	}
	if len(adrs) == 0 {
		_, err := w.NewAdr()
		if err != nil {
			log.Printf("NewWallit crash  %s ", err.Error())
		}
	}

	// send all those adrs to the hook
	for _, a := range adrs {
		err = w.Hook.RegisterAddress(a)
		if err != nil {
			log.Printf("NewWallit RegisterAddress crash %s ", err.Error())
		}
	}

	// send outpoints (if any) to the hook
	utxos, err := w.UtxoDump()
	if err != nil {
		log.Printf("NewWallit crash  %s ", err.Error())
	}
	for _, utxo := range utxos {
		err = w.Hook.RegisterOutPoint(utxo.Op)
		if err != nil {
			log.Printf("NewWallit crash  %s ", err.Error())
		}
	}

	// deal with the incoming txs
	go w.TxHandler(incomingTx)

	// deal with incoming height
	go w.HeightHandler(incomingBlockheight)

	return &w
}

// TxHandler is the goroutine that receives & ingests new txs for the wallit.
func (w *Wallit) TxHandler(incomingTxAndHeight chan lnutil.TxAndHeight) {
	for {
		txah := <-incomingTxAndHeight
		w.Ingest(txah.Tx, txah.Height)
		log.Printf("got tx %s at height %d\n",
			txah.Tx.TxHash().String(), txah.Height)
	}
}

func (w *Wallit) HeightHandler(incomingHeight chan int32) {
	var prevHeight int32
	for {
		h := <-incomingHeight
		// detect reorg
		if h < prevHeight {
			log.Printf("HeightHandler: oh no, reorg!\n")
			err := w.RollBack(h)
			if err != nil {
				log.Printf("Rollback crash  %s ", err.Error())
			}
		}

		err := w.SetDBSyncHeight(h)
		if err != nil {
			log.Printf("HeightHandler crash  %s ", err.Error())
		}
		prevHeight = h
	}
}

// OpenDB starts up the database.  Creates the file if it doesn't exist.
func (w *Wallit) OpenDB(filename string) error {
	var err error
	var numKeys uint32
	w.StateDB, err = bolt.Open(filename, 0644, nil)
	if err != nil {
		return err
	}
	// create buckets if they're not already there
	err = w.StateDB.Update(func(btx *bolt.Tx) error {
		_, err = btx.CreateBucketIfNotExists(BKToutpoint)
		if err != nil {
			return err
		}
		_, err = btx.CreateBucketIfNotExists(BKTadr)
		if err != nil {
			return err
		}
		_, err = btx.CreateBucketIfNotExists(BKTStxos)
		if err != nil {
			return err
		}
		_, err = btx.CreateBucketIfNotExists(BKTTxns)
		if err != nil {
			return err
		}

		sta, err := btx.CreateBucketIfNotExists(BKTState)
		if err != nil {
			return err
		}

		numKeysBytes := sta.Get(KEYNumKeys)
		if numKeysBytes != nil { // NumKeys exists, read into uint32
			numKeys = lnutil.BtU32(numKeysBytes)
			log.Printf("db says %d keys\n", numKeys)
		} else { // no adrs yet, make it 0.  Then make an address.
			log.Printf("NumKeys not in DB, must be new DB. 0 Keys\n")
			numKeys = 0
			b0 := lnutil.U32tB(numKeys)
			err = sta.Put(KEYNumKeys, b0)
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>[trivial] edit log messages (#204)<commit_after>package wallit

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

	"github.com/mit-dci/lit/wire"
	"github.com/mit-dci/lit/btcutil/hdkeychain"
	"github.com/boltdb/bolt"
	"github.com/mit-dci/lit/coinparam"
	"github.com/mit-dci/lit/lnutil"
	"github.com/mit-dci/lit/powless"
	"github.com/mit-dci/lit/uspv"
)

func NewWallit(
	rootkey *hdkeychain.ExtendedKey, birthHeight int32, resync bool,
	spvhost, path string, p *coinparam.Params) *Wallit {

	var w Wallit
	w.rootPrivKey = rootkey
	w.Param = p
	w.FreezeSet = make(map[wire.OutPoint]*FrozenTx)

	w.FeeRate = w.Param.FeePerByte

	wallitpath := filepath.Join(path, p.Name)

	// create wallit sub dir if it's not there
	_, err := os.Stat(wallitpath)
	if os.IsNotExist(err) {
		os.Mkdir(wallitpath, 0700)
	}

	// Tricky part here is that we want the sync height to tell the chainhook,
	// so we have to open the db first, then turn on the chainhook, THEN tell
	// chainhook about all our addresses.

	// use powless for chainhook if the host string has https in it
	// this is a bit hacky for now

	if strings.Contains(spvhost, "https") {
		w.Hook = new(powless.APILink)
	} else {
		// no https; use uSPV for chainhook
		w.Hook = new(uspv.SPVCon)
	}

	wallitdbname := filepath.Join(wallitpath, "utxo.db")
	err = w.OpenDB(wallitdbname)
	if err != nil {
		log.Printf("NewWallit crash  %s ", err.Error())
	}
	// get height
	height := w.CurrentHeight()
	log.Printf("DB current height %d\n", height)

	// bring height up to birthheight, or back down in case of resync
	if height < birthHeight || resync {
		height = birthHeight
		w.SetDBSyncHeight(height)
	}

	log.Printf("DB corrected height %d\n", height)
	incomingTx, incomingBlockheight, err := w.Hook.Start(height, spvhost, wallitpath, p)
	if err != nil {
		log.Printf("NewWallit Hook.Start crash  %s ", err.Error())
	}

	// check if there are any addresses.  If there aren't (initial wallet setup)
	// then make an address.
	adrs, err := w.AdrDump()
	if err != nil {
		log.Printf("NewWallit crash  %s ", err.Error())
	}
	if len(adrs) == 0 {
		_, err := w.NewAdr()
		if err != nil {
			log.Printf("NewWallit crash  %s ", err.Error())
		}
	}

	// send all those adrs to the hook
	for _, a := range adrs {
		err = w.Hook.RegisterAddress(a)
		if err != nil {
			log.Printf("NewWallit RegisterAddress crash %s ", err.Error())
		}
	}

	// send outpoints (if any) to the hook
	utxos, err := w.UtxoDump()
	if err != nil {
		log.Printf("NewWallit crash  %s ", err.Error())
	}
	for _, utxo := range utxos {
		err = w.Hook.RegisterOutPoint(utxo.Op)
		if err != nil {
			log.Printf("NewWallit crash  %s ", err.Error())
		}
	}

	// deal with the incoming txs
	go w.TxHandler(incomingTx)

	// deal with incoming height
	go w.HeightHandler(incomingBlockheight)

	return &w
}

// TxHandler is the goroutine that receives & ingests new txs for the wallit.
func (w *Wallit) TxHandler(incomingTxAndHeight chan lnutil.TxAndHeight) {
	for {
		txah := <-incomingTxAndHeight
		w.Ingest(txah.Tx, txah.Height)
		log.Printf("got tx %s at height %d\n",
			txah.Tx.TxHash().String(), txah.Height)
	}
}

func (w *Wallit) HeightHandler(incomingHeight chan int32) {
	var prevHeight int32
	for {
		h := <-incomingHeight
		// detect reorg
		if h < prevHeight {
			log.Printf("HeightHandler: oh no, reorg!\n")
			err := w.RollBack(h)
			if err != nil {
				log.Printf("Rollback crash  %s ", err.Error())
			}
		}

		err := w.SetDBSyncHeight(h)
		if err != nil {
			log.Printf("HeightHandler crash  %s ", err.Error())
		}
		prevHeight = h
	}
}

// OpenDB starts up the database.  Creates the file if it doesn't exist.
func (w *Wallit) OpenDB(filename string) error {
	var err error
	var numKeys uint32
	w.StateDB, err = bolt.Open(filename, 0644, nil)
	if err != nil {
		return err
	}
	// create buckets if they're not already there
	err = w.StateDB.Update(func(btx *bolt.Tx) error {
		_, err = btx.CreateBucketIfNotExists(BKToutpoint)
		if err != nil {
			return err
		}
		_, err = btx.CreateBucketIfNotExists(BKTadr)
		if err != nil {
			return err
		}
		_, err = btx.CreateBucketIfNotExists(BKTStxos)
		if err != nil {
			return err
		}
		_, err = btx.CreateBucketIfNotExists(BKTTxns)
		if err != nil {
			return err
		}

		sta, err := btx.CreateBucketIfNotExists(BKTState)
		if err != nil {
			return err
		}

		numKeysBytes := sta.Get(KEYNumKeys)
		if numKeysBytes != nil { // NumKeys exists, read into uint32
			numKeys = lnutil.BtU32(numKeysBytes)
			log.Printf("db says %d keys\n", numKeys)
		} else { // no adrs yet, make it 0.  Then make an address.
			log.Printf("NumKeys not in DB, must be new DB. 0 Keys\n")
			numKeys = 0
			b0 := lnutil.U32tB(numKeys)
			err = sta.Put(KEYNumKeys, b0)
			if err != nil {
				return err
			}
		}

		return nil
	})
	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package imagebuildah

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/containers/storage/pkg/reexec"
	"github.com/pkg/errors"
	"golang.org/x/sys/unix"
)

const (
	symlinkChrootedCommand = "chrootsymlinks-resolve"
	symlinkModifiedTime    = "modtimesymlinks-resolve"
	maxSymlinksResolved    = 40
)

func init() {
	reexec.Register(symlinkChrootedCommand, resolveChrootedSymlinks)
	reexec.Register(symlinkModifiedTime, resolveSymlinkTimeModified)
}

// main() for resolveSymlink()'s subprocess.
func resolveChrootedSymlinks() {
	status := 0
	flag.Parse()
	if len(flag.Args()) < 2 {
		fmt.Fprintf(os.Stderr, "%s needs two arguments\n", symlinkChrootedCommand)
		os.Exit(1)
	}
	// Our first parameter is the directory to chroot into.
	if err := unix.Chdir(flag.Arg(0)); err != nil {
		fmt.Fprintf(os.Stderr, "chdir(): %v\n", err)
		os.Exit(1)
	}
	if err := unix.Chroot(flag.Arg(0)); err != nil {
		fmt.Fprintf(os.Stderr, "chroot(): %v\n", err)
		os.Exit(1)
	}

	// Our second parameter is the path name to evaluate for symbolic links
	symLink, err := getSymbolicLink(flag.Arg(1))
	if err != nil {
		fmt.Fprintf(os.Stderr, "error getting symbolic links: %v\n", err)
		os.Exit(1)
	}
	if _, err := os.Stdout.WriteString(symLink); err != nil {
		fmt.Fprintf(os.Stderr, "error writing string to stdout: %v\n", err)
		os.Exit(1)
	}
	os.Exit(status)
}

// resolveSymlink uses a child subprocess to resolve any symlinks in filename
// in the context of rootdir.
func resolveSymlink(rootdir, filename string) (string, error) {
	// The child process expects a chroot and one path that
	// will be consulted relative to the chroot directory and evaluated
	// for any symbolic links present.
	cmd := reexec.Command(symlinkChrootedCommand, rootdir, filename)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return "", errors.Wrapf(err, string(output))
	}

	// Hand back the resolved symlink, will be filename if a symlink is not found
	return string(output), nil
}

// main() for grandparent subprocess.  Its main job is to shuttle stdio back
// and forth, managing a pseudo-terminal if we want one, for our child, the
// parent subprocess.
func resolveSymlinkTimeModified() {
	status := 0
	flag.Parse()
	if len(flag.Args()) < 1 {
		os.Exit(1)
	}
	// Our first parameter is the directory to chroot into.
	if err := unix.Chdir(flag.Arg(0)); err != nil {
		fmt.Fprintf(os.Stderr, "chdir(): %v\n", err)
		os.Exit(1)
	}
	if err := unix.Chroot(flag.Arg(0)); err != nil {
		fmt.Fprintf(os.Stderr, "chroot(): %v\n", err)
		os.Exit(1)
	}

	// Our second parameter is the path name to evaluate for symbolic links.
	// Our third parameter is the time the cached intermediate image was created.
	// We check whether the modified time of the filepath we provide is after the time the cached image was created.
	timeIsGreater, err := modTimeIsGreater(flag.Arg(0), flag.Arg(1), flag.Arg(2))
	if err != nil {
		fmt.Fprintf(os.Stderr, "error checking if modified time of resolved symbolic link is greater: %v\n", err)
		os.Exit(1)
	}
	if _, err := os.Stdout.WriteString(fmt.Sprintf("%v", timeIsGreater)); err != nil {
		fmt.Fprintf(os.Stderr, "error writing string to stdout: %v\n", err)
		os.Exit(1)
	}
	os.Exit(status)
}

// resolveModifiedTime (in the grandparent process) checks filename for any symlinks,
// resolves it and compares the modified time of the file with historyTime, which is
// the creation time of the cached image. It returns true if filename was modified after
// historyTime, otherwise returns false.
func resolveModifiedTime(rootdir, filename, historyTime string) (bool, error) {
	// The child process expects a chroot and one path that
	// will be consulted relative to the chroot directory and evaluated
	// for any symbolic links present.
	cmd := reexec.Command(symlinkModifiedTime, rootdir, filename, historyTime)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return false, errors.Wrapf(err, string(output))
	}
	// Hand back true/false depending on in the file was modified after the caches image was created.
	return string(output) == "true", nil
}

// modTimeIsGreater goes through the files added/copied in using the Dockerfile and
// checks the time stamp (follows symlinks) with the time stamp of when the cached
// image was created. IT compares the two and returns true if the file was modified
// after the cached image was created, otherwise it returns false.
func modTimeIsGreater(rootdir, path string, historyTime string) (bool, error) {
	var timeIsGreater bool

	// the Walk below doesn't work if rootdir and path are equal
	if rootdir == path {
		return false, nil
	}

	// Convert historyTime from string to time.Time for comparison
	histTime, err := time.Parse(time.RFC3339Nano, historyTime)
	if err != nil {
		return false, errors.Wrapf(err, "error converting string to time.Time %q", historyTime)
	}
	// Walk the file tree and check the time stamps.
	// Since we are chroot in rootdir, only want the path of the actual filename, i.e path - rootdir.
	// +1 to account for the extra "/" (e.g rootdir=/home/user/mydir, path=/home/user/mydir/myfile.json)
	err = filepath.Walk(path[len(rootdir)+1:], func(path string, info os.FileInfo, err error) error {
		// If using cached images, it is possible for files that are being copied to come from
		// previous build stages. But if using cached images, then the copied file won't exist
		// since a container won't have been created for the previous build stage and info will be nil.
		// In that case just return nil and continue on with using the cached image for the whole build process.
		if info == nil {
			return nil
		}
		modTime := info.ModTime()
		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
			// Evaluate any symlink that occurs to get updated modified information
			resolvedPath, err := filepath.EvalSymlinks(path)
			if err != nil && os.IsNotExist(err) {
				return errors.Wrapf(errDanglingSymlink, "%q", path)
			}
			if err != nil {
				return errors.Wrapf(err, "error evaluating symlink %q", path)
			}
			fileInfo, err := os.Stat(resolvedPath)
			if err != nil {
				return errors.Wrapf(err, "error getting file info %q", resolvedPath)
			}
			modTime = fileInfo.ModTime()
		}
		if modTime.After(histTime) {
			timeIsGreater = true
			return nil
		}
		return nil
	})

	if err != nil {
		// if error is due to dangling symlink, ignore error and return nil
		if errors.Cause(err) == errDanglingSymlink {
			return false, nil
		}
		return false, errors.Wrapf(err, "error walking file tree %q", path)
	}
	return timeIsGreater, err
}

// getSymbolic link goes through each part of the path and continues resolving symlinks as they appear.
// Returns what the whole target path for what "path" resolves to.
func getSymbolicLink(path string) (string, error) {
	var (
		symPath          string
		symLinksResolved int
	)
	// Splitting path as we need to resolve each part of the path at a time
	splitPath := strings.Split(path, "/")
	if splitPath[0] == "" {
		splitPath = splitPath[1:]
		symPath = "/"
	}
	for _, p := range splitPath {
		// If we have resolved 40 symlinks, that means something is terribly wrong
		// will return an error and exit
		if symLinksResolved >= maxSymlinksResolved {
			return "", errors.Errorf("have resolved %q symlinks, something is terribly wrong!", maxSymlinksResolved)
		}
		symPath = filepath.Join(symPath, p)
		isSymlink, resolvedPath, err := hasSymlink(symPath)
		if err != nil {
			return "", errors.Wrapf(err, "error checking symlink for %q", symPath)
		}
		// if isSymlink is true, check if resolvedPath is potentially another symlink
		// keep doing this till resolvedPath is not a symlink and isSymlink is false
		for isSymlink == true {
			// Need to keep track of number of symlinks resolved
			// Will also return an error if the symlink points to itself as that will exceed maxSymlinksResolved
			if symLinksResolved >= maxSymlinksResolved {
				return "", errors.Errorf("have resolved %q symlinks, something is terribly wrong!", maxSymlinksResolved)
			}
			isSymlink, resolvedPath, err = hasSymlink(resolvedPath)
			if err != nil {
				return "", errors.Wrapf(err, "error checking symlink for %q", resolvedPath)
			}
			symLinksResolved++
		}
		// Assign resolvedPath to symPath. The next part of the loop will append the next part of the original path
		// and continue resolving
		symPath = resolvedPath
		symLinksResolved++
	}
	return symPath, nil
}

// hasSymlink returns true and the target if path is symlink
// otherwise it returns false and path
func hasSymlink(path string) (bool, string, error) {
	info, err := os.Lstat(path)
	if err != nil {
		if os.IsNotExist(err) {
			if err = os.MkdirAll(path, 0755); err != nil {
				return false, "", errors.Wrapf(err, "error ensuring volume path %q exists", path)
			}
			info, err = os.Lstat(path)
			if err != nil {
				return false, "", errors.Wrapf(err, "error running lstat on %q", path)
			}
		} else {
			return false, path, errors.Wrapf(err, "error get stat of path %q", path)
		}
	}

	// Return false and path as path if not a symlink
	if info.Mode()&os.ModeSymlink != os.ModeSymlink {
		return false, path, nil
	}

	// Read the symlink to get what it points to
	targetDir, err := os.Readlink(path)
	if err != nil {
		return false, "", errors.Wrapf(err, "error reading link %q", path)
	}
	// if the symlink points to a relative path, prepend the path till now to the resolved path
	if !filepath.IsAbs(targetDir) {
		targetDir = filepath.Join(filepath.Dir(path), targetDir)
	}
	// run filepath.Clean to remove the ".." from relative paths
	return true, filepath.Clean(targetDir), nil
}
<commit_msg>Detect changes in rootdir<commit_after>package imagebuildah

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/containers/storage/pkg/reexec"
	"github.com/pkg/errors"
	"golang.org/x/sys/unix"
)

const (
	symlinkChrootedCommand = "chrootsymlinks-resolve"
	symlinkModifiedTime    = "modtimesymlinks-resolve"
	maxSymlinksResolved    = 40
)

func init() {
	reexec.Register(symlinkChrootedCommand, resolveChrootedSymlinks)
	reexec.Register(symlinkModifiedTime, resolveSymlinkTimeModified)
}

// main() for resolveSymlink()'s subprocess.
func resolveChrootedSymlinks() {
	status := 0
	flag.Parse()
	if len(flag.Args()) < 2 {
		fmt.Fprintf(os.Stderr, "%s needs two arguments\n", symlinkChrootedCommand)
		os.Exit(1)
	}
	// Our first parameter is the directory to chroot into.
	if err := unix.Chdir(flag.Arg(0)); err != nil {
		fmt.Fprintf(os.Stderr, "chdir(): %v\n", err)
		os.Exit(1)
	}
	if err := unix.Chroot(flag.Arg(0)); err != nil {
		fmt.Fprintf(os.Stderr, "chroot(): %v\n", err)
		os.Exit(1)
	}

	// Our second parameter is the path name to evaluate for symbolic links
	symLink, err := getSymbolicLink(flag.Arg(1))
	if err != nil {
		fmt.Fprintf(os.Stderr, "error getting symbolic links: %v\n", err)
		os.Exit(1)
	}
	if _, err := os.Stdout.WriteString(symLink); err != nil {
		fmt.Fprintf(os.Stderr, "error writing string to stdout: %v\n", err)
		os.Exit(1)
	}
	os.Exit(status)
}

// resolveSymlink uses a child subprocess to resolve any symlinks in filename
// in the context of rootdir.
func resolveSymlink(rootdir, filename string) (string, error) {
	// The child process expects a chroot and one path that
	// will be consulted relative to the chroot directory and evaluated
	// for any symbolic links present.
	cmd := reexec.Command(symlinkChrootedCommand, rootdir, filename)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return "", errors.Wrapf(err, string(output))
	}

	// Hand back the resolved symlink, will be filename if a symlink is not found
	return string(output), nil
}

// main() for grandparent subprocess.  Its main job is to shuttle stdio back
// and forth, managing a pseudo-terminal if we want one, for our child, the
// parent subprocess.
func resolveSymlinkTimeModified() {
	status := 0
	flag.Parse()
	if len(flag.Args()) < 1 {
		os.Exit(1)
	}
	// Our first parameter is the directory to chroot into.
	if err := unix.Chdir(flag.Arg(0)); err != nil {
		fmt.Fprintf(os.Stderr, "chdir(): %v\n", err)
		os.Exit(1)
	}
	if err := unix.Chroot(flag.Arg(0)); err != nil {
		fmt.Fprintf(os.Stderr, "chroot(): %v\n", err)
		os.Exit(1)
	}

	// Our second parameter is the path name to evaluate for symbolic links.
	// Our third parameter is the time the cached intermediate image was created.
	// We check whether the modified time of the filepath we provide is after the time the cached image was created.
	timeIsGreater, err := modTimeIsGreater(flag.Arg(0), flag.Arg(1), flag.Arg(2))
	if err != nil {
		fmt.Fprintf(os.Stderr, "error checking if modified time of resolved symbolic link is greater: %v\n", err)
		os.Exit(1)
	}
	if _, err := os.Stdout.WriteString(fmt.Sprintf("%v", timeIsGreater)); err != nil {
		fmt.Fprintf(os.Stderr, "error writing string to stdout: %v\n", err)
		os.Exit(1)
	}
	os.Exit(status)
}

// resolveModifiedTime (in the grandparent process) checks filename for any symlinks,
// resolves it and compares the modified time of the file with historyTime, which is
// the creation time of the cached image. It returns true if filename was modified after
// historyTime, otherwise returns false.
func resolveModifiedTime(rootdir, filename, historyTime string) (bool, error) {
	// The child process expects a chroot and one path that
	// will be consulted relative to the chroot directory and evaluated
	// for any symbolic links present.
	cmd := reexec.Command(symlinkModifiedTime, rootdir, filename, historyTime)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return false, errors.Wrapf(err, string(output))
	}
	// Hand back true/false depending on in the file was modified after the caches image was created.
	return string(output) == "true", nil
}

// modTimeIsGreater goes through the files added/copied in using the Dockerfile and
// checks the time stamp (follows symlinks) with the time stamp of when the cached
// image was created. IT compares the two and returns true if the file was modified
// after the cached image was created, otherwise it returns false.
func modTimeIsGreater(rootdir, path string, historyTime string) (bool, error) {
	var timeIsGreater bool

	// Convert historyTime from string to time.Time for comparison
	histTime, err := time.Parse(time.RFC3339Nano, historyTime)
	if err != nil {
		return false, errors.Wrapf(err, "error converting string to time.Time %q", historyTime)
	}

	// Since we are chroot in rootdir, we want a relative path, i.e (path - rootdir)
	relPath, err := filepath.Rel(rootdir, path)
	if err != nil {
		return false, errors.Wrapf(err, "error making path %q relative to %q", path, rootdir)
	}

	// Walk the file tree and check the time stamps.
	err = filepath.Walk(relPath, func(path string, info os.FileInfo, err error) error {
		// If using cached images, it is possible for files that are being copied to come from
		// previous build stages. But if using cached images, then the copied file won't exist
		// since a container won't have been created for the previous build stage and info will be nil.
		// In that case just return nil and continue on with using the cached image for the whole build process.
		if info == nil {
			return nil
		}
		modTime := info.ModTime()
		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
			// Evaluate any symlink that occurs to get updated modified information
			resolvedPath, err := filepath.EvalSymlinks(path)
			if err != nil && os.IsNotExist(err) {
				return errors.Wrapf(errDanglingSymlink, "%q", path)
			}
			if err != nil {
				return errors.Wrapf(err, "error evaluating symlink %q", path)
			}
			fileInfo, err := os.Stat(resolvedPath)
			if err != nil {
				return errors.Wrapf(err, "error getting file info %q", resolvedPath)
			}
			modTime = fileInfo.ModTime()
		}
		if modTime.After(histTime) {
			timeIsGreater = true
			return nil
		}
		return nil
	})

	if err != nil {
		// if error is due to dangling symlink, ignore error and return nil
		if errors.Cause(err) == errDanglingSymlink {
			return false, nil
		}
		return false, errors.Wrapf(err, "error walking file tree %q", path)
	}
	return timeIsGreater, err
}

// getSymbolic link goes through each part of the path and continues resolving symlinks as they appear.
// Returns what the whole target path for what "path" resolves to.
func getSymbolicLink(path string) (string, error) {
	var (
		symPath          string
		symLinksResolved int
	)
	// Splitting path as we need to resolve each part of the path at a time
	splitPath := strings.Split(path, "/")
	if splitPath[0] == "" {
		splitPath = splitPath[1:]
		symPath = "/"
	}
	for _, p := range splitPath {
		// If we have resolved 40 symlinks, that means something is terribly wrong
		// will return an error and exit
		if symLinksResolved >= maxSymlinksResolved {
			return "", errors.Errorf("have resolved %q symlinks, something is terribly wrong!", maxSymlinksResolved)
		}
		symPath = filepath.Join(symPath, p)
		isSymlink, resolvedPath, err := hasSymlink(symPath)
		if err != nil {
			return "", errors.Wrapf(err, "error checking symlink for %q", symPath)
		}
		// if isSymlink is true, check if resolvedPath is potentially another symlink
		// keep doing this till resolvedPath is not a symlink and isSymlink is false
		for isSymlink == true {
			// Need to keep track of number of symlinks resolved
			// Will also return an error if the symlink points to itself as that will exceed maxSymlinksResolved
			if symLinksResolved >= maxSymlinksResolved {
				return "", errors.Errorf("have resolved %q symlinks, something is terribly wrong!", maxSymlinksResolved)
			}
			isSymlink, resolvedPath, err = hasSymlink(resolvedPath)
			if err != nil {
				return "", errors.Wrapf(err, "error checking symlink for %q", resolvedPath)
			}
			symLinksResolved++
		}
		// Assign resolvedPath to symPath. The next part of the loop will append the next part of the original path
		// and continue resolving
		symPath = resolvedPath
		symLinksResolved++
	}
	return symPath, nil
}

// hasSymlink returns true and the target if path is symlink
// otherwise it returns false and path
func hasSymlink(path string) (bool, string, error) {
	info, err := os.Lstat(path)
	if err != nil {
		if os.IsNotExist(err) {
			if err = os.MkdirAll(path, 0755); err != nil {
				return false, "", errors.Wrapf(err, "error ensuring volume path %q exists", path)
			}
			info, err = os.Lstat(path)
			if err != nil {
				return false, "", errors.Wrapf(err, "error running lstat on %q", path)
			}
		} else {
			return false, path, errors.Wrapf(err, "error get stat of path %q", path)
		}
	}

	// Return false and path as path if not a symlink
	if info.Mode()&os.ModeSymlink != os.ModeSymlink {
		return false, path, nil
	}

	// Read the symlink to get what it points to
	targetDir, err := os.Readlink(path)
	if err != nil {
		return false, "", errors.Wrapf(err, "error reading link %q", path)
	}
	// if the symlink points to a relative path, prepend the path till now to the resolved path
	if !filepath.IsAbs(targetDir) {
		targetDir = filepath.Join(filepath.Dir(path), targetDir)
	}
	// run filepath.Clean to remove the ".." from relative paths
	return true, filepath.Clean(targetDir), nil
}
<|endoftext|>


<commit_before>package actors

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/cloudfoundry/bosh-bootloader/integration-test"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

const (
	AWSIAAS = iota
	GCPIAAS
)

type BBL struct {
	stateDirectory string
	pathToBBL      string
	configuration  integration.Config
}

type IAAS int

func NewBBL(stateDirectory string, pathToBBL string, configuration integration.Config) BBL {
	return BBL{
		stateDirectory: stateDirectory,
		pathToBBL:      pathToBBL,
		configuration:  configuration,
	}
}

func (b BBL) Up(iaas IAAS) {
	args := []string{
		"--state-dir", b.stateDirectory,
		"up",
		"--name", "bbl-ci-env",
	}

	switch iaas {
	case AWSIAAS:
		args = append(args, []string{
			"--iaas", "aws",
			"--aws-access-key-id", b.configuration.AWSAccessKeyID,
			"--aws-secret-access-key", b.configuration.AWSSecretAccessKey,
			"--aws-region", b.configuration.AWSRegion,
		}...)
	case GCPIAAS:
		args = append(args, []string{
			"--iaas", "gcp",
			"--gcp-service-account-key", b.configuration.GCPServiceAccountKeyPath,
			"--gcp-project-id", b.configuration.GCPProjectID,
			"--gcp-region", b.configuration.GCPRegion,
			"--gcp-zone", b.configuration.GCPZone,
		}...)
	default:
		panic(errors.New("invalid iaas"))
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 40*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) UpWithInvalidAWSCredentials() {
	args := []string{
		"--state-dir", b.stateDirectory,
		"up",
		"--iaas", "aws",
		"--aws-access-key-id", "some-bad-access-key-id",
		"--aws-secret-access-key", "some-bad-secret-access-key",
		"--aws-region", b.configuration.AWSRegion,
	}
	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Second).Should(gexec.Exit(1))
}

func (b BBL) Destroy() {
	session := b.execute([]string{
		"--state-dir", b.stateDirectory,
		"destroy",
		"--no-confirm",
	}, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) SaveDirectorCA() string {
	stdout := bytes.NewBuffer([]byte{})
	session := b.execute([]string{
		"--state-dir", b.stateDirectory,
		"director-ca-cert",
	}, stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))

	file, err := ioutil.TempFile("", "")
	defer file.Close()
	Expect(err).NotTo(HaveOccurred())

	file.Write(stdout.Bytes())

	return file.Name()
}

func (b BBL) DirectorUsername() string {
	return b.fetchValue("director-username")
}

func (b BBL) DirectorPassword() string {
	return b.fetchValue("director-password")
}

func (b BBL) DirectorAddress() string {
	return b.fetchValue("director-address")
}

func (b BBL) EnvID() string {
	return b.fetchValue("env-id")
}

func (b BBL) CreateLB(loadBalancerType string, cert string, key string, chain string) {
	args := []string{
		"--state-dir", b.stateDirectory,
		"create-lbs",
		"--type", loadBalancerType,
		"--cert", cert,
		"--key", key,
		"--chain", chain,
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) CreateGCPLB(loadBalancerType string) {
	args := []string{
		"--state-dir", b.stateDirectory,
		"create-lbs",
		"--type", loadBalancerType,
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) LBs() *gexec.Session {
	args := []string{
		"--state-dir", b.stateDirectory,
		"lbs",
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))

	return session
}

func (b BBL) UpdateLB(certPath, keyPath string) {
	args := []string{
		"--state-dir", b.stateDirectory,
		"update-lbs",
		"--cert", certPath,
		"--key", keyPath,
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) DeleteLB() {
	args := []string{
		"--state-dir", b.stateDirectory,
		"delete-lbs",
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) fetchValue(value string) string {
	args := []string{
		"--state-dir", b.stateDirectory,
		value,
	}

	stdout := bytes.NewBuffer([]byte{})
	stderr := bytes.NewBuffer([]byte{})
	b.execute(args, stdout, stderr).Wait()

	return strings.TrimSpace(string(stdout.Bytes()))
}

func (b BBL) execute(args []string, stdout io.Writer, stderr io.Writer) *gexec.Session {
	cmd := exec.Command(b.pathToBBL, args...)
	session, err := gexec.Start(cmd, stdout, stderr)
	Expect(err).NotTo(HaveOccurred())

	return session
}
<commit_msg>Revert "Name bbl env for integration tests"<commit_after>package actors

import (
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/cloudfoundry/bosh-bootloader/integration-test"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

const (
	AWSIAAS = iota
	GCPIAAS
)

type BBL struct {
	stateDirectory string
	pathToBBL      string
	configuration  integration.Config
}

type IAAS int

func NewBBL(stateDirectory string, pathToBBL string, configuration integration.Config) BBL {
	return BBL{
		stateDirectory: stateDirectory,
		pathToBBL:      pathToBBL,
		configuration:  configuration,
	}
}

func (b BBL) Up(iaas IAAS) {
	args := []string{
		"--state-dir", b.stateDirectory,
		"up",
	}

	switch iaas {
	case AWSIAAS:
		args = append(args, []string{
			"--iaas", "aws",
			"--aws-access-key-id", b.configuration.AWSAccessKeyID,
			"--aws-secret-access-key", b.configuration.AWSSecretAccessKey,
			"--aws-region", b.configuration.AWSRegion,
		}...)
	case GCPIAAS:
		args = append(args, []string{
			"--iaas", "gcp",
			"--gcp-service-account-key", b.configuration.GCPServiceAccountKeyPath,
			"--gcp-project-id", b.configuration.GCPProjectID,
			"--gcp-region", b.configuration.GCPRegion,
			"--gcp-zone", b.configuration.GCPZone,
		}...)
	default:
		panic(errors.New("invalid iaas"))
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 40*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) UpWithInvalidAWSCredentials() {
	args := []string{
		"--state-dir", b.stateDirectory,
		"up",
		"--iaas", "aws",
		"--aws-access-key-id", "some-bad-access-key-id",
		"--aws-secret-access-key", "some-bad-secret-access-key",
		"--aws-region", b.configuration.AWSRegion,
	}
	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Second).Should(gexec.Exit(1))
}

func (b BBL) Destroy() {
	session := b.execute([]string{
		"--state-dir", b.stateDirectory,
		"destroy",
		"--no-confirm",
	}, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) SaveDirectorCA() string {
	stdout := bytes.NewBuffer([]byte{})
	session := b.execute([]string{
		"--state-dir", b.stateDirectory,
		"director-ca-cert",
	}, stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))

	file, err := ioutil.TempFile("", "")
	defer file.Close()
	Expect(err).NotTo(HaveOccurred())

	file.Write(stdout.Bytes())

	return file.Name()
}

func (b BBL) DirectorUsername() string {
	return b.fetchValue("director-username")
}

func (b BBL) DirectorPassword() string {
	return b.fetchValue("director-password")
}

func (b BBL) DirectorAddress() string {
	return b.fetchValue("director-address")
}

func (b BBL) EnvID() string {
	return b.fetchValue("env-id")
}

func (b BBL) CreateLB(loadBalancerType string, cert string, key string, chain string) {
	args := []string{
		"--state-dir", b.stateDirectory,
		"create-lbs",
		"--type", loadBalancerType,
		"--cert", cert,
		"--key", key,
		"--chain", chain,
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) CreateGCPLB(loadBalancerType string) {
	args := []string{
		"--state-dir", b.stateDirectory,
		"create-lbs",
		"--type", loadBalancerType,
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) LBs() *gexec.Session {
	args := []string{
		"--state-dir", b.stateDirectory,
		"lbs",
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))

	return session
}

func (b BBL) UpdateLB(certPath, keyPath string) {
	args := []string{
		"--state-dir", b.stateDirectory,
		"update-lbs",
		"--cert", certPath,
		"--key", keyPath,
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) DeleteLB() {
	args := []string{
		"--state-dir", b.stateDirectory,
		"delete-lbs",
	}

	session := b.execute(args, os.Stdout, os.Stderr)
	Eventually(session, 10*time.Minute).Should(gexec.Exit(0))
}

func (b BBL) fetchValue(value string) string {
	args := []string{
		"--state-dir", b.stateDirectory,
		value,
	}

	stdout := bytes.NewBuffer([]byte{})
	stderr := bytes.NewBuffer([]byte{})
	b.execute(args, stdout, stderr).Wait()

	return strings.TrimSpace(string(stdout.Bytes()))
}

func (b BBL) execute(args []string, stdout io.Writer, stderr io.Writer) *gexec.Session {
	cmd := exec.Command(b.pathToBBL, args...)
	session, err := gexec.Start(cmd, stdout, stderr)
	Expect(err).NotTo(HaveOccurred())

	return session
}
<|endoftext|>


<commit_before>package main

import (
	"path/filepath"
	"time"

	"github.com/docker/containerd/api/grpc/types"
	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (cs *ContainerdSuite) TestStartBusyboxLsSlash(t *check.C) {
	expectedOutput := `bin
dev
etc
home
lib
lib64
linuxrc
media
mnt
opt
proc
root
run
sbin
sys
tmp
usr
var
`
	if err := CreateBusyboxBundle("busybox-ls-slash", []string{"ls", "/"}); err != nil {
		t.Fatal(err)
	}

	c, err := cs.RunContainer("myls", "busybox-ls-slash")
	if err != nil {
		t.Fatal(err)
	}

	t.Assert(c.io.stdoutBuffer.String(), checker.Equals, expectedOutput)
}

func (cs *ContainerdSuite) TestStartBusyboxNoSuchFile(t *check.C) {
	expectedOutput := `oci runtime error: exec: \"NoSuchFile\": executable file not found in $PATH`

	if err := CreateBusyboxBundle("busybox-no-such-file", []string{"NoSuchFile"}); err != nil {
		t.Fatal(err)
	}

	_, err := cs.RunContainer("NoSuchFile", "busybox-no-such-file")
	t.Assert(err.Error(), checker.Contains, expectedOutput)
}

func (cs *ContainerdSuite) TestStartBusyboxTop(t *check.C) {
	bundleName := "busybox-top"
	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
		t.Fatal(err)
	}

	_, err := cs.StartContainer("top", bundleName)
	t.Assert(err, checker.Equals, nil)

	containers, err := cs.ListRunningContainers()
	if err != nil {
		t.Fatal(err)
	}
	t.Assert(len(containers), checker.Equals, 1)
	t.Assert(containers[0].Id, checker.Equals, "top")
	t.Assert(containers[0].Status, checker.Equals, "running")
	t.Assert(containers[0].BundlePath, check.Equals, filepath.Join(cs.cwd, GetBundle(bundleName).Path))
}

func (cs *ContainerdSuite) TestStartBusyboxLsEvents(t *check.C) {
	if err := CreateBusyboxBundle("busybox-ls", []string{"ls"}); err != nil {
		t.Fatal(err)
	}

	containerId := "ls-events"
	c, err := cs.StartContainer(containerId, "busybox-ls")
	if err != nil {
		t.Fatal(err)
	}

	for _, evt := range []types.Event{
		{
			Type:   "start-container",
			Id:     containerId,
			Status: 0,
			Pid:    "",
		},
		{
			Type:   "exit",
			Id:     containerId,
			Status: 0,
			Pid:    "init",
		},
	} {
		ch := c.GetEventsChannel()
		select {
		case e := <-ch:
			evt.Timestamp = e.Timestamp

			t.Assert(*e, checker.Equals, evt)
		case <-time.After(2 * time.Second):
			t.Fatal("Container took more than 2 seconds to terminate")
		}
	}
}

func (cs *ContainerdSuite) TestStartBusyboxSleep(t *check.C) {
	if err := CreateBusyboxBundle("busybox-sleep-5", []string{"sleep", "5"}); err != nil {
		t.Fatal(err)
	}

	ch := make(chan interface{})
	filter := func(e *types.Event) {
		if e.Type == "exit" && e.Pid == "init" {
			ch <- nil
		}
	}

	start := time.Now()
	_, err := cs.StartContainerWithEventFilter("sleep5", "busybox-sleep-5", filter)
	if err != nil {
		t.Fatal(err)
	}

	// We add a generous 20% marge of error
	select {
	case <-ch:
		t.Assert(uint64(time.Now().Sub(start)), checker.LessOrEqualThan, uint64(6*time.Second))
	case <-time.After(6 * time.Second):
		t.Fatal("Container took more than 6 seconds to exit")
	}
}
<commit_msg>Add test for the kill/signal operations<commit_after>package main

import (
	"path/filepath"
	"syscall"
	"time"

	"github.com/docker/containerd/api/grpc/types"
	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (cs *ContainerdSuite) TestStartBusyboxLsSlash(t *check.C) {
	expectedOutput := `bin
dev
etc
home
lib
lib64
linuxrc
media
mnt
opt
proc
root
run
sbin
sys
tmp
usr
var
`
	if err := CreateBusyboxBundle("busybox-ls-slash", []string{"ls", "/"}); err != nil {
		t.Fatal(err)
	}

	c, err := cs.RunContainer("myls", "busybox-ls-slash")
	if err != nil {
		t.Fatal(err)
	}

	t.Assert(c.io.stdoutBuffer.String(), checker.Equals, expectedOutput)
}

func (cs *ContainerdSuite) TestStartBusyboxNoSuchFile(t *check.C) {
	expectedOutput := `oci runtime error: exec: \"NoSuchFile\": executable file not found in $PATH`

	if err := CreateBusyboxBundle("busybox-no-such-file", []string{"NoSuchFile"}); err != nil {
		t.Fatal(err)
	}

	_, err := cs.RunContainer("NoSuchFile", "busybox-no-such-file")
	t.Assert(err.Error(), checker.Contains, expectedOutput)
}

func (cs *ContainerdSuite) TestStartBusyboxTop(t *check.C) {
	bundleName := "busybox-top"
	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
		t.Fatal(err)
	}

	_, err := cs.StartContainer("top", bundleName)
	t.Assert(err, checker.Equals, nil)

	containers, err := cs.ListRunningContainers()
	if err != nil {
		t.Fatal(err)
	}
	t.Assert(len(containers), checker.Equals, 1)
	t.Assert(containers[0].Id, checker.Equals, "top")
	t.Assert(containers[0].Status, checker.Equals, "running")
	t.Assert(containers[0].BundlePath, check.Equals, filepath.Join(cs.cwd, GetBundle(bundleName).Path))
}

func (cs *ContainerdSuite) TestStartBusyboxLsEvents(t *check.C) {
	if err := CreateBusyboxBundle("busybox-ls", []string{"ls"}); err != nil {
		t.Fatal(err)
	}

	containerId := "ls-events"
	c, err := cs.StartContainer(containerId, "busybox-ls")
	if err != nil {
		t.Fatal(err)
	}

	for _, evt := range []types.Event{
		{
			Type:   "start-container",
			Id:     containerId,
			Status: 0,
			Pid:    "",
		},
		{
			Type:   "exit",
			Id:     containerId,
			Status: 0,
			Pid:    "init",
		},
	} {
		ch := c.GetEventsChannel()
		select {
		case e := <-ch:
			evt.Timestamp = e.Timestamp

			t.Assert(*e, checker.Equals, evt)
		case <-time.After(2 * time.Second):
			t.Fatal("Container took more than 2 seconds to terminate")
		}
	}
}

func (cs *ContainerdSuite) TestStartBusyboxSleep(t *check.C) {
	if err := CreateBusyboxBundle("busybox-sleep-5", []string{"sleep", "5"}); err != nil {
		t.Fatal(err)
	}

	ch := make(chan interface{})
	filter := func(e *types.Event) {
		if e.Type == "exit" && e.Pid == "init" {
			ch <- nil
		}
	}

	start := time.Now()
	_, err := cs.StartContainerWithEventFilter("sleep5", "busybox-sleep-5", filter)
	if err != nil {
		t.Fatal(err)
	}

	// We add a generous 20% marge of error
	select {
	case <-ch:
		t.Assert(uint64(time.Now().Sub(start)), checker.LessOrEqualThan, uint64(6*time.Second))
	case <-time.After(6 * time.Second):
		t.Fatal("Container took more than 6 seconds to exit")
	}
}

func (cs *ContainerdSuite) TestStartBusyboxTopKill(t *check.C) {
	bundleName := "busybox-top"
	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
		t.Fatal(err)
	}

	containerId := "top"
	c, err := cs.StartContainer("top", bundleName)
	if err != nil {
		t.Fatal(err)
	}

	<-time.After(1 * time.Second)

	err = cs.KillContainer(containerId)
	if err != nil {
		t.Fatal(err)
	}

	for _, evt := range []types.Event{
		{
			Type:   "start-container",
			Id:     containerId,
			Status: 0,
			Pid:    "",
		},
		{
			Type:   "exit",
			Id:     containerId,
			Status: 128 + uint32(syscall.SIGKILL),
			Pid:    "init",
		},
	} {
		ch := c.GetEventsChannel()
		select {
		case e := <-ch:
			evt.Timestamp = e.Timestamp

			t.Assert(*e, checker.Equals, evt)
		case <-time.After(2 * time.Second):
			t.Fatal("Container took more than 2 seconds to terminate")
		}
	}
}

func (cs *ContainerdSuite) TestStartBusyboxTopSignalSigterm(t *check.C) {
	bundleName := "busybox-top"
	if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil {
		t.Fatal(err)
	}

	containerId := "top"
	c, err := cs.StartContainer("top", bundleName)
	if err != nil {
		t.Fatal(err)
	}

	<-time.After(1 * time.Second)

	err = cs.SignalContainer(containerId, uint32(syscall.SIGTERM))
	if err != nil {
		t.Fatal(err)
	}

	for _, evt := range []types.Event{
		{
			Type:   "start-container",
			Id:     containerId,
			Status: 0,
			Pid:    "",
		},
		{
			Type:   "exit",
			Id:     containerId,
			Status: 128 + uint32(syscall.SIGTERM),
			Pid:    "init",
		},
	} {
		ch := c.GetEventsChannel()
		select {
		case e := <-ch:
			evt.Timestamp = e.Timestamp

			t.Assert(*e, checker.Equals, evt)
		case <-time.After(2 * time.Second):
			t.Fatal("Container took more than 2 seconds to terminate")
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (s *RunVSuite) TestStartHelloworld(c *check.C) {
	//TODO: enable this after fixing
	//c.Skip("enable this after fixing!")

	spec := defaultTestSpec
	spec.Process.Args = []string{"echo", "hello"}
	c.Assert(s.addSpec(&spec), checker.IsNil)

	out, exitCode := s.runvCommand(c, "start", "--bundle", s.bundlePath, "testStartHelloWorld")
	c.Assert(out, checker.Equals, "hello\n")
	c.Assert(exitCode, checker.Equals, 0)
}
<commit_msg>integration test for start --pid-file<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (s *RunVSuite) TestStartHelloworld(c *check.C) {
	//TODO: enable this after fixing
	//c.Skip("enable this after fixing!")

	spec := defaultTestSpec
	spec.Process.Args = []string{"echo", "hello"}
	c.Assert(s.addSpec(&spec), checker.IsNil)

	out, exitCode := s.runvCommand(c, "start", "--bundle", s.bundlePath, "testStartHelloWorld")
	c.Assert(out, checker.Equals, "hello\n")
	c.Assert(exitCode, checker.Equals, 0)
}

func (s *RunVSuite) TestStartPid(c *check.C) {
	//TODO: enable this after fixing!!!
	//c.Skip("enable this after fixing")

	ctrName := "testStartPid"
	spec := defaultTestSpec
	spec.Process.Args = []string{"sleep", "10"}
	c.Assert(s.addSpec(&spec), checker.IsNil)
	exitChan := make(chan struct{}, 0)

	pidFilePath := filepath.Join(s.bundlePath, "pid.file")
	go func() {
		defer close(exitChan)
		_, exitCode := s.runvCommand(c, "start", "--bundle", s.bundlePath, "--pid-file", pidFilePath, ctrName)
		c.Assert(exitCode, checker.Equals, 0)
	}()

	var stateOut string
	for count := 0; count < 10; count++ {
		out, exitCode, err := s.runvCommandWithError("state", ctrName)
		if exitCode == 0 {
			c.Assert(err, checker.IsNil)
			stateOut = out
			break
		}
		time.Sleep(1 * time.Second)
	}

	decoder := json.NewDecoder(strings.NewReader(stateOut))
	c.Assert(decoder, checker.NotNil)

	cs := &cState{}
	c.Assert(decoder.Decode(cs), checker.IsNil)

	var pidData []byte
	var err error
	t := time.NewTimer(time.Second * 3)
	for {
		// in case that the pid file hasn't been created alreay
		select {
		case <-t.C:
			c.Assert(err, checker.IsNil)
		default:
		}
		pidData, err = ioutil.ReadFile(pidFilePath)
		if err == nil {
			break
		}
	}

	pid := strconv.Itoa(cs.InitProcessPid)
	c.Assert(string(pidData), checker.Equals, pid)

	<-exitChan
}
<|endoftext|>


<commit_before>package wl_integration_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("basic root functionality", func() {
	It("gets root correctly", func() {
		root, err := client.Root()
		Expect(err).NotTo(HaveOccurred())

		Expect(root.ID).To(BeNumerically(">", 0))
	})
})
<commit_msg>Reduce flakiness in root test.<commit_after>package wl_integration_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/robdimsdale/wl"
)

var _ = Describe("basic root functionality", func() {
	It("gets root correctly", func() {
		var err error
		var root wl.Root
		Eventually(func() error {
			root, err = client.Root()
			return err
		}).Should(Succeed())

		Expect(root.ID).To(BeNumerically(">", 0))
	})
})
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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 keyrotation

import (
	"time"

	"github.com/google/exposure-notifications-server/internal/database"
	"github.com/google/exposure-notifications-server/internal/observability"
	"github.com/google/exposure-notifications-server/internal/revision"
	"github.com/google/exposure-notifications-server/internal/setup"
	"github.com/google/exposure-notifications-server/pkg/secrets"
)

// Compile-time check to assert this config matches requirements.
var _ setup.DatabaseConfigProvider = (*Config)(nil)
var _ setup.SecretManagerConfigProvider = (*Config)(nil)
var _ setup.ObservabilityExporterConfigProvider = (*Config)(nil)

// Config represents the configuration and associated environment variables for
// the key rotation components.
type Config struct {
	Database              database.Config
	SecretManager         secrets.Config
	ObservabilityExporter observability.Config
	RevisionToken         revision.Config

	Port string `env:"PORT, default=8080"`

	// NewKeyPeriod is the duration after which we will rotate encryption keys. By default we
	// generate a new key every two weeks.
	NewKeyPeriod time.Duration `env:"NEW_KEY_PERIOD, default=168h"`

	// DeleteOldKeyPeriod is the duration after which it is safe to delete old keys.
	// We delete old data after two weeks after which it should be safe to also delete
	// the associated key - we default to 15d to buffer for potential timezones issues.
	DeleteOldKeyPeriod time.Duration `env:"DELETE_OLD_KEY_PERIOD, default=360h"`
}

func (c *Config) DatabaseConfig() *database.Config {
	return &c.Database
}

func (c *Config) SecretManagerConfig() *secrets.Config {
	return &c.SecretManager
}

func (c *Config) ObservabilityExporterConfig() *observability.Config {
	return &c.ObservabilityExporter
}
<commit_msg>Override KeyManagerConfigProvider (#832)<commit_after>// Copyright 2020 Google LLC
//
// 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 keyrotation

import (
	"time"

	"github.com/google/exposure-notifications-server/internal/database"
	"github.com/google/exposure-notifications-server/internal/observability"
	"github.com/google/exposure-notifications-server/internal/revision"
	"github.com/google/exposure-notifications-server/internal/setup"
	"github.com/google/exposure-notifications-server/pkg/keys"
	"github.com/google/exposure-notifications-server/pkg/secrets"
)

// Compile-time check to assert this config matches requirements.
var _ setup.DatabaseConfigProvider = (*Config)(nil)
var _ setup.SecretManagerConfigProvider = (*Config)(nil)
var _ setup.ObservabilityExporterConfigProvider = (*Config)(nil)
var _ setup.KeyManagerConfigProvider = (*Config)(nil)

// Config represents the configuration and associated environment variables for
// the key rotation components.
type Config struct {
	Database              database.Config
	SecretManager         secrets.Config
	ObservabilityExporter observability.Config
	RevisionToken         revision.Config
	KeyManager            keys.Config

	Port string `env:"PORT, default=8080"`

	// NewKeyPeriod is the duration after which we will rotate encryption keys. By default we
	// generate a new key every two weeks.
	NewKeyPeriod time.Duration `env:"NEW_KEY_PERIOD, default=168h"`

	// DeleteOldKeyPeriod is the duration after which it is safe to delete old keys.
	// We delete old data after two weeks after which it should be safe to also delete
	// the associated key - we default to 15d to buffer for potential timezones issues.
	DeleteOldKeyPeriod time.Duration `env:"DELETE_OLD_KEY_PERIOD, default=360h"`
}

func (c *Config) DatabaseConfig() *database.Config {
	return &c.Database
}

func (c *Config) SecretManagerConfig() *secrets.Config {
	return &c.SecretManager
}

func (c *Config) ObservabilityExporterConfig() *observability.Config {
	return &c.ObservabilityExporter
}

func (c *Config) KeyManagerConfig() *keys.Config {
	return &c.KeyManager
}
<|endoftext|>


<commit_before>package docker

import (
	. "atlantis/supervisor/constant"
	"atlantis/supervisor/crypto"
	"atlantis/supervisor/helper"
	"atlantis/supervisor/rpc/types"
	atypes "atlantis/types"
	"fmt"
	"github.com/fsouza/go-dockerclient"
)

func NewDockerPort(port, proto string) docker.Port {
	return docker.Port(fmt.Sprintf("%s/%s", port, proto))
}

func ContainerAppCfgs(c *types.Container) (*atypes.AppConfig, error) {
	var err error
	deps := map[string]map[string]interface{}{}
	if c.Manifest.Deps != nil {
		for name, appDep := range c.Manifest.Deps {
			deps[name], err = crypto.DecryptedAppDepData(appDep)
			if err != nil {
				return nil, err
			}
		}
	}
	return &atypes.AppConfig{
		HTTPPort:       c.PrimaryPort,
		SecondaryPorts: c.SecondaryPorts,
		Container: &atypes.ContainerConfig{
			ID:   c.ID,
			Host: c.Host,
			Env:  c.Env,
		},
		Dependencies: deps,
	}, nil
}

func ContainerDockerCfgs(c *types.Container) (*docker.Config, *docker.HostConfig) {
	// get env cfg
	envs := []string{
		"ATLANTIS=true",
		fmt.Sprintf("CONTAINER_ID=%s", c.ID),
		fmt.Sprintf("CONTAINER_HOST=%s", c.Host),
		fmt.Sprintf("CONTAINER_ENV=%s", c.Env),
		fmt.Sprintf("HTTP_PORT=%d", c.PrimaryPort),
		fmt.Sprintf("SSHD_PORT=%d", c.SSHPort),
	}

	// get port cfg
	exposedPorts := map[docker.Port]struct{}{}
	portBindings := map[docker.Port][]docker.PortBinding{}
	sPrimaryPort := fmt.Sprintf("%d", c.PrimaryPort)
	dPrimaryPort := NewDockerPort(sPrimaryPort, "tcp")
	exposedPorts[dPrimaryPort] = struct{}{}
	portBindings[dPrimaryPort] = []docker.PortBinding{docker.PortBinding{
		HostIp:   "",
		HostPort: sPrimaryPort,
	}}
	sSSHPort := fmt.Sprintf("%d", c.SSHPort)
	dSSHPort := NewDockerPort(sSSHPort, "tcp")
	exposedPorts[dSSHPort] = struct{}{}
	portBindings[dSSHPort] = []docker.PortBinding{docker.PortBinding{
		HostIp:   "",
		HostPort: sSSHPort,
	}}
	for i, port := range c.SecondaryPorts {
		sPort := fmt.Sprintf("%d", port)
		dPort := NewDockerPort(sPort, "tcp")
		exposedPorts[dPort] = struct{}{}
		portBindings[dPort] = []docker.PortBinding{docker.PortBinding{
			HostIp:   "",
			HostPort: sPort,
		}}
		envs = append(envs, fmt.Sprintf("SECONDARY_PORT%d=%d", i, port))
	}

	// setup actual cfg
	dCfg := &docker.Config{
		CpuShares:    int64(c.Manifest.CPUShares),
		Memory:       int64(c.Manifest.MemoryLimit) * int64(1024*1024), // this is in bytes
		MemorySwap:   int64(-1),                                        // -1 turns swap off
		ExposedPorts: exposedPorts,
		Env:          envs,
		Cmd:          []string{
			"/bin/sh",
			"-c",
			"runsvdir",
			"/etc/service",
		},
		Image:        fmt.Sprintf("%s/%s/%s-%s", RegistryHost, c.GetDockerRepo(), c.App, c.Sha),
		Volumes: map[string]struct{}{
			ContainerLogDir:           struct{}{},
			atypes.ContainerConfigDir: struct{}{},
		},
	}
	dHostCfg := &docker.HostConfig{
		PortBindings: portBindings,
		Binds: []string{
			fmt.Sprintf("%s:%s", helper.HostLogDir(c.ID), ContainerLogDir),
			fmt.Sprintf("%s:%s", helper.HostConfigDir(c.ID), atypes.ContainerConfigDir),
		},
		// call veth something we can actually look up later:
		LxcConf: []docker.KeyValuePair{
			docker.KeyValuePair{
				Key:   "lxc.network.veth.pair",
				Value: "veth" + c.RandomID(),
			},
		},
	}
	return dCfg, dHostCfg
}
<commit_msg>yay for testing on staging<commit_after>package docker

import (
	. "atlantis/supervisor/constant"
	"atlantis/supervisor/crypto"
	"atlantis/supervisor/helper"
	"atlantis/supervisor/rpc/types"
	atypes "atlantis/types"
	"fmt"
	"github.com/fsouza/go-dockerclient"
)

func NewDockerPort(port, proto string) docker.Port {
	return docker.Port(fmt.Sprintf("%s/%s", port, proto))
}

func ContainerAppCfgs(c *types.Container) (*atypes.AppConfig, error) {
	var err error
	deps := map[string]map[string]interface{}{}
	if c.Manifest.Deps != nil {
		for name, appDep := range c.Manifest.Deps {
			deps[name], err = crypto.DecryptedAppDepData(appDep)
			if err != nil {
				return nil, err
			}
		}
	}
	return &atypes.AppConfig{
		HTTPPort:       c.PrimaryPort,
		SecondaryPorts: c.SecondaryPorts,
		Container: &atypes.ContainerConfig{
			ID:   c.ID,
			Host: c.Host,
			Env:  c.Env,
		},
		Dependencies: deps,
	}, nil
}

func ContainerDockerCfgs(c *types.Container) (*docker.Config, *docker.HostConfig) {
	// get env cfg
	envs := []string{
		"ATLANTIS=true",
		fmt.Sprintf("CONTAINER_ID=%s", c.ID),
		fmt.Sprintf("CONTAINER_HOST=%s", c.Host),
		fmt.Sprintf("CONTAINER_ENV=%s", c.Env),
		fmt.Sprintf("HTTP_PORT=%d", c.PrimaryPort),
		fmt.Sprintf("SSHD_PORT=%d", c.SSHPort),
	}

	// get port cfg
	exposedPorts := map[docker.Port]struct{}{}
	portBindings := map[docker.Port][]docker.PortBinding{}
	sPrimaryPort := fmt.Sprintf("%d", c.PrimaryPort)
	dPrimaryPort := NewDockerPort(sPrimaryPort, "tcp")
	exposedPorts[dPrimaryPort] = struct{}{}
	portBindings[dPrimaryPort] = []docker.PortBinding{docker.PortBinding{
		HostIp:   "",
		HostPort: sPrimaryPort,
	}}
	sSSHPort := fmt.Sprintf("%d", c.SSHPort)
	dSSHPort := NewDockerPort(sSSHPort, "tcp")
	exposedPorts[dSSHPort] = struct{}{}
	portBindings[dSSHPort] = []docker.PortBinding{docker.PortBinding{
		HostIp:   "",
		HostPort: sSSHPort,
	}}
	for i, port := range c.SecondaryPorts {
		sPort := fmt.Sprintf("%d", port)
		dPort := NewDockerPort(sPort, "tcp")
		exposedPorts[dPort] = struct{}{}
		portBindings[dPort] = []docker.PortBinding{docker.PortBinding{
			HostIp:   "",
			HostPort: sPort,
		}}
		envs = append(envs, fmt.Sprintf("SECONDARY_PORT%d=%d", i, port))
	}

	// setup actual cfg
	dCfg := &docker.Config{
		CpuShares:    int64(c.Manifest.CPUShares),
		Memory:       int64(c.Manifest.MemoryLimit) * int64(1024*1024), // this is in bytes
		MemorySwap:   int64(-1),                                        // -1 turns swap off
		ExposedPorts: exposedPorts,
		Env:          envs,
		Cmd:          []string{
			"runsvdir",
			"/etc/service",
		},
		Image:        fmt.Sprintf("%s/%s/%s-%s", RegistryHost, c.GetDockerRepo(), c.App, c.Sha),
		Volumes: map[string]struct{}{
			ContainerLogDir:           struct{}{},
			atypes.ContainerConfigDir: struct{}{},
		},
	}
	dHostCfg := &docker.HostConfig{
		PortBindings: portBindings,
		Binds: []string{
			fmt.Sprintf("%s:%s", helper.HostLogDir(c.ID), ContainerLogDir),
			fmt.Sprintf("%s:%s", helper.HostConfigDir(c.ID), atypes.ContainerConfigDir),
		},
		// call veth something we can actually look up later:
		LxcConf: []docker.KeyValuePair{
			docker.KeyValuePair{
				Key:   "lxc.network.veth.pair",
				Value: "veth" + c.RandomID(),
			},
		},
	}
	return dCfg, dHostCfg
}
<|endoftext|>


<commit_before>package wats

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/onsi/gomega/gbytes"

	. "github.com/cloudfoundry-incubator/cf-test-helpers/workflowhelpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

func appRunning(appName string, instances int, timeout time.Duration) func() error {
	return func() error {
		type StatsResponse map[string]struct {
			State string `json:"state"`
		}

		buf, err := runCfWithOutput("app", appName, "--guid")
		if err != nil {
			return err
		}
		appGuid := strings.Replace(string(buf.Contents()), "\n", "", -1)

		endpoint := fmt.Sprintf("/v2/apps/%s/stats", appGuid)

		var response StatsResponse
		ApiRequest("GET", endpoint, &response, timeout)

		err = nil
		for k, v := range response {
			if v.State != "RUNNING" {
				err = errors.New(fmt.Sprintf("App %s instance %s is not running: State = %s", appName, k, v.State))
			}
		}
		return err
	}
}

func runCfWithOutput(values ...string) (*gbytes.Buffer, error) {
	session := cf.Cf(values...)
	session.Wait(CF_PUSH_TIMEOUT)
	if session.ExitCode() == 0 {
		return session.Out, nil
	}

	return nil, errors.New("non zero exit code")
}

func DopplerUrl() string {
	doppler := os.Getenv("DOPPLER_URL")
	if doppler == "" {
		cfInfoBuffer, err := runCfWithOutput("curl", "/v2/info")
		Expect(err).NotTo(HaveOccurred())

		var cfInfo struct {
			DopplerLoggingEndpoint string `json:"doppler_logging_endpoint"`
		}

		err = json.NewDecoder(bytes.NewReader(cfInfoBuffer.Contents())).Decode(&cfInfo)
		Expect(err).NotTo(HaveOccurred())

		doppler = cfInfo.DopplerLoggingEndpoint
	}
	return doppler
}

func pushAndStartNora(appName string) {
	By("pushing it")
	Expect(pushNora(appName).Wait(CF_PUSH_TIMEOUT)).To(gexec.Exit(0))

	By("staging and running it on Diego")
	enableDiego(appName)
	Expect(cf.Cf("start", appName).Wait(CF_PUSH_TIMEOUT)).To(gexec.Exit(0))

	By("verifying it's up")
	Eventually(helpers.CurlingAppRoot(config, appName)).Should(ContainSubstring("hello i am nora"))
}

func pushNora(appName string) *gexec.Session {
	return pushNoraWithOptions(appName, 1, "256m")
}

func pushNoraWithOptions(appName string, instances int, memory string) *gexec.Session {
	return pushApp(appName, "../../assets/nora/NoraPublished", instances, memory, hwcBuildPackURL)
}

func pushApp(appName, path string, instances int, memory, buildpack string) *gexec.Session {
	return cf.Cf(
		"push", appName,
		"-p", path,
		"--no-start",
		"-i", strconv.Itoa(instances),
		"-m", memory,
		"-b", buildpack,
		"-s", "windows2012R2")
}

func setTotalMemoryLimit(memoryLimit string) {
	type quotaDefinitionUrl struct {
		Resources []struct {
			Entity struct {
				QuotaDefinitionUrl string `json:"quota_definition_url"`
			} `json:"entity"`
		} `json:"resources"`
	}

	orgEndpoint := fmt.Sprintf("/v2/organizations?q=name%%3A%s", environment.GetOrganizationName())
	var org quotaDefinitionUrl
	ApiRequest("GET", orgEndpoint, &org, DEFAULT_TIMEOUT)
	Expect(org.Resources).ToNot(BeEmpty())

	type quotaDefinition struct {
		Entity struct {
			Name string `json:"name"`
		} `json:"entity"`
	}
	var quota quotaDefinition
	ApiRequest("GET", org.Resources[0].Entity.QuotaDefinitionUrl, &quota, DEFAULT_TIMEOUT)
	Expect(quota.Entity.Name).ToNot(BeEmpty())

	AsUser(environment.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("update-quota", quota.Entity.Name, "-m", memoryLimit).Wait(DEFAULT_TIMEOUT)).To(gexec.Exit(0))
	})
}
<commit_msg>return cf command output even on error<commit_after>package wats

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/cloudfoundry-incubator/cf-test-helpers/cf"
	"github.com/cloudfoundry-incubator/cf-test-helpers/helpers"
	"github.com/onsi/gomega/gbytes"

	. "github.com/cloudfoundry-incubator/cf-test-helpers/workflowhelpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gexec"
)

func appRunning(appName string, instances int, timeout time.Duration) func() error {
	return func() error {
		type StatsResponse map[string]struct {
			State string `json:"state"`
		}

		buf, err := runCfWithOutput("app", appName, "--guid")
		if err != nil {
			return err
		}
		appGuid := strings.Replace(string(buf.Contents()), "\n", "", -1)

		endpoint := fmt.Sprintf("/v2/apps/%s/stats", appGuid)

		var response StatsResponse
		ApiRequest("GET", endpoint, &response, timeout)

		err = nil
		for k, v := range response {
			if v.State != "RUNNING" {
				err = errors.New(fmt.Sprintf("App %s instance %s is not running: State = %s", appName, k, v.State))
			}
		}
		return err
	}
}

func runCfWithOutput(values ...string) (*gbytes.Buffer, error) {
	session := cf.Cf(values...)
	session.Wait(CF_PUSH_TIMEOUT)
	if session.ExitCode() == 0 {
		return session.Out, nil
	}

	return session.Out, fmt.Errorf("non zero exit code %d", session.ExitCode())
}

func DopplerUrl() string {
	doppler := os.Getenv("DOPPLER_URL")
	if doppler == "" {
		cfInfoBuffer, err := runCfWithOutput("curl", "/v2/info")
		Expect(err).NotTo(HaveOccurred())

		var cfInfo struct {
			DopplerLoggingEndpoint string `json:"doppler_logging_endpoint"`
		}

		err = json.NewDecoder(bytes.NewReader(cfInfoBuffer.Contents())).Decode(&cfInfo)
		Expect(err).NotTo(HaveOccurred())

		doppler = cfInfo.DopplerLoggingEndpoint
	}
	return doppler
}

func pushAndStartNora(appName string) {
	By("pushing it")
	Expect(pushNora(appName).Wait(CF_PUSH_TIMEOUT)).To(gexec.Exit(0))

	By("staging and running it on Diego")
	enableDiego(appName)
	Expect(cf.Cf("start", appName).Wait(CF_PUSH_TIMEOUT)).To(gexec.Exit(0))

	By("verifying it's up")
	Eventually(helpers.CurlingAppRoot(config, appName)).Should(ContainSubstring("hello i am nora"))
}

func pushNora(appName string) *gexec.Session {
	return pushNoraWithOptions(appName, 1, "256m")
}

func pushNoraWithOptions(appName string, instances int, memory string) *gexec.Session {
	return pushApp(appName, "../../assets/nora/NoraPublished", instances, memory, hwcBuildPackURL)
}

func pushApp(appName, path string, instances int, memory, buildpack string) *gexec.Session {
	return cf.Cf(
		"push", appName,
		"-p", path,
		"--no-start",
		"-i", strconv.Itoa(instances),
		"-m", memory,
		"-b", buildpack,
		"-s", "windows2012R2")
}

func setTotalMemoryLimit(memoryLimit string) {
	type quotaDefinitionUrl struct {
		Resources []struct {
			Entity struct {
				QuotaDefinitionUrl string `json:"quota_definition_url"`
			} `json:"entity"`
		} `json:"resources"`
	}

	orgEndpoint := fmt.Sprintf("/v2/organizations?q=name%%3A%s", environment.GetOrganizationName())
	var org quotaDefinitionUrl
	ApiRequest("GET", orgEndpoint, &org, DEFAULT_TIMEOUT)
	Expect(org.Resources).ToNot(BeEmpty())

	type quotaDefinition struct {
		Entity struct {
			Name string `json:"name"`
		} `json:"entity"`
	}
	var quota quotaDefinition
	ApiRequest("GET", org.Resources[0].Entity.QuotaDefinitionUrl, &quota, DEFAULT_TIMEOUT)
	Expect(quota.Entity.Name).ToNot(BeEmpty())

	AsUser(environment.AdminUserContext(), DEFAULT_TIMEOUT, func() {
		Expect(cf.Cf("update-quota", quota.Entity.Name, "-m", memoryLimit).Wait(DEFAULT_TIMEOUT)).To(gexec.Exit(0))
	})
}
<|endoftext|>