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

// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
// defined in FIPS 186-3.
//
// This implementation derives the nonce from an AES-CTR CSPRNG keyed by:
//
// SHA2-512(priv.D || entropy || hash)[:32]
//
// The CSPRNG key is indifferentiable from a random oracle as shown in
// [Coron], the AES-CTR stream is indifferentiable from a random oracle
// under standard cryptographic assumptions (see [Larsson] for examples).
//
// References:
//   [Coron]
//     https://cs.nyu.edu/~dodis/ps/merkle.pdf
//   [Larsson]
//     https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf
package ecdsa

// Further references:
//   [NSA]: Suite B implementer's guide to FIPS 186-3
//     https://apps.nsa.gov/iaarchive/library/ia-guidance/ia-solutions-for-classified/algorithm-guidance/suite-b-implementers-guide-to-fips-186-3-ecdsa.cfm
//   [SECG]: SECG, SEC1
//     http://www.secg.org/sec1-v2.pdf

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/internal/randutil"
	"crypto/sha512"
	"errors"
	"io"
	"math/big"

	"golang.org/x/crypto/cryptobyte"
	"golang.org/x/crypto/cryptobyte/asn1"
)

// A invertible implements fast inverse mod Curve.Params().N
type invertible interface {
	// Inverse returns the inverse of k in GF(P)
	Inverse(k *big.Int) *big.Int
}

// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point)
type combinedMult interface {
	CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
}

const (
	aesIV = "IV for ECDSA CTR"
)

// PublicKey represents an ECDSA public key.
type PublicKey struct {
	elliptic.Curve
	X, Y *big.Int
}

// Any methods implemented on PublicKey might need to also be implemented on
// PrivateKey, as the latter embeds the former and will expose its methods.

// Equal reports whether pub and x have the same value.
//
// Two keys are only considered to have the same value if they have the same Curve value.
// Note that for example elliptic.P256() and elliptic.P256().Params() are different
// values, as the latter is a generic not constant time implementation.
func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
	xx, ok := x.(*PublicKey)
	if !ok {
		return false
	}
	return pub.X.Cmp(xx.X) == 0 && pub.Y.Cmp(xx.Y) == 0 &&
		// Standard library Curve implementations are singletons, so this check
		// will work for those. Other Curves might be equivalent even if not
		// singletons, but there is no definitive way to check for that, and
		// better to err on the side of safety.
		pub.Curve == xx.Curve
}

// PrivateKey represents an ECDSA private key.
type PrivateKey struct {
	PublicKey
	D *big.Int
}

// Public returns the public key corresponding to priv.
func (priv *PrivateKey) Public() crypto.PublicKey {
	return &priv.PublicKey
}

// Equal reports whether priv and x have the same value.
//
// See PublicKey.Equal for details on how Curve is compared.
func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
	xx, ok := x.(*PrivateKey)
	if !ok {
		return false
	}
	return priv.PublicKey.Equal(&xx.PublicKey) && priv.D.Cmp(xx.D) == 0
}

// Sign signs digest with priv, reading randomness from rand. The opts argument
// is not currently used but, in keeping with the crypto.Signer interface,
// should be the hash function used to digest the message.
//
// This method implements crypto.Signer, which is an interface to support keys
// where the private part is kept in, for example, a hardware module. Common
// uses should use the Sign function in this package directly.
func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
	r, s, err := Sign(rand, priv, digest)
	if err != nil {
		return nil, err
	}

	var b cryptobyte.Builder
	b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
		b.AddASN1BigInt(r)
		b.AddASN1BigInt(s)
	})
	return b.Bytes()
}

var one = new(big.Int).SetInt64(1)

// randFieldElement returns a random element of the field underlying the given
// curve using the procedure given in [NSA] A.2.1.
func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
	params := c.Params()
	b := make([]byte, params.BitSize/8+8)
	_, err = io.ReadFull(rand, b)
	if err != nil {
		return
	}

	k = new(big.Int).SetBytes(b)
	n := new(big.Int).Sub(params.N, one)
	k.Mod(k, n)
	k.Add(k, one)
	return
}

// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
	k, err := randFieldElement(c, rand)
	if err != nil {
		return nil, err
	}

	priv := new(PrivateKey)
	priv.PublicKey.Curve = c
	priv.D = k
	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
	return priv, nil
}

// hashToInt converts a hash value to an integer. There is some disagreement
// about how this is done. [NSA] suggests that this is done in the obvious
// manner, but [SECG] truncates the hash to the bit-length of the curve order
// first. We follow [SECG] because that's what OpenSSL does. Additionally,
// OpenSSL right shifts excess bits from the number if the hash is too large
// and we mirror that too.
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
	orderBits := c.Params().N.BitLen()
	orderBytes := (orderBits + 7) / 8
	if len(hash) > orderBytes {
		hash = hash[:orderBytes]
	}

	ret := new(big.Int).SetBytes(hash)
	excess := len(hash)*8 - orderBits
	if excess > 0 {
		ret.Rsh(ret, uint(excess))
	}
	return ret
}

// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
// This has better constant-time properties than Euclid's method (implemented
// in math/big.Int.ModInverse) although math/big itself isn't strictly
// constant-time so it's not perfect.
func fermatInverse(k, N *big.Int) *big.Int {
	two := big.NewInt(2)
	nMinus2 := new(big.Int).Sub(N, two)
	return new(big.Int).Exp(k, nMinus2, N)
}

var errZeroParam = errors.New("zero parameter")

// Sign signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. If the hash is longer than the bit-length of the
// private key's curve order, the hash will be truncated to that length. It
// returns the signature as a pair of integers. The security of the private key
// depends on the entropy of rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	randutil.MaybeReadByte(rand)

	// Get min(log2(q) / 2, 256) bits of entropy from rand.
	entropylen := (priv.Curve.Params().BitSize + 7) / 16
	if entropylen > 32 {
		entropylen = 32
	}
	entropy := make([]byte, entropylen)
	_, err = io.ReadFull(rand, entropy)
	if err != nil {
		return
	}

	// Initialize an SHA-512 hash context; digest ...
	md := sha512.New()
	md.Write(priv.D.Bytes()) // the private key,
	md.Write(entropy)        // the entropy,
	md.Write(hash)           // and the input hash;
	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
	// which is an indifferentiable MAC.

	// Create an AES-CTR instance to use as a CSPRNG.
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}

	// Create a CSPRNG that xors a stream of zeros with
	// the output of the AES-CTR instance.
	csprng := cipher.StreamReader{
		R: zeroReader,
		S: cipher.NewCTR(block, []byte(aesIV)),
	}

	// See [NSA] 3.4.1
	c := priv.PublicKey.Curve
	return sign(priv, &csprng, c, hash)
}

func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) {
	N := c.Params().N
	if N.Sign() == 0 {
		return nil, nil, errZeroParam
	}
	var k, kInv *big.Int
	for {
		for {
			k, err = randFieldElement(c, *csprng)
			if err != nil {
				r = nil
				return
			}

			if in, ok := priv.Curve.(invertible); ok {
				kInv = in.Inverse(k)
			} else {
				kInv = fermatInverse(k, N) // N != 0
			}

			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
			r.Mod(r, N)
			if r.Sign() != 0 {
				break
			}
		}

		e := hashToInt(hash, c)
		s = new(big.Int).Mul(priv.D, r)
		s.Add(s, e)
		s.Mul(s, kInv)
		s.Mod(s, N) // N != 0
		if s.Sign() != 0 {
			break
		}
	}

	return
}

// SignASN1 signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. If the hash is longer than the bit-length of the
// private key's curve order, the hash will be truncated to that length. It
// returns the ASN.1 encoded signature. The security of the private key
// depends on the entropy of rand.
func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
	return priv.Sign(rand, hash, nil)
}

// Verify verifies the signature in r, s of hash using the public key, pub. Its
// return value records whether the signature is valid.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// See [NSA] 3.4.2
	c := pub.Curve
	N := c.Params().N

	if r.Sign() <= 0 || s.Sign() <= 0 {
		return false
	}
	if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
		return false
	}
	return verify(pub, c, hash, r, s)
}

func verifyGeneric(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool {
	e := hashToInt(hash, c)
	var w *big.Int
	N := c.Params().N
	if in, ok := c.(invertible); ok {
		w = in.Inverse(s)
	} else {
		w = new(big.Int).ModInverse(s, N)
	}

	u1 := e.Mul(e, w)
	u1.Mod(u1, N)
	u2 := w.Mul(r, w)
	u2.Mod(u2, N)

	// Check if implements S1*g + S2*p
	var x, y *big.Int
	if opt, ok := c.(combinedMult); ok {
		x, y = opt.CombinedMult(pub.X, pub.Y, u1.Bytes(), u2.Bytes())
	} else {
		x1, y1 := c.ScalarBaseMult(u1.Bytes())
		x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
		x, y = c.Add(x1, y1, x2, y2)
	}

	if x.Sign() == 0 && y.Sign() == 0 {
		return false
	}
	x.Mod(x, N)
	return x.Cmp(r) == 0
}

// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the
// public key, pub. Its return value records whether the signature is valid.
func VerifyASN1(pub *PublicKey, hash, sig []byte) bool {
	var (
		r, s  = &big.Int{}, &big.Int{}
		inner cryptobyte.String
	)
	input := cryptobyte.String(sig)
	if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
		!input.Empty() ||
		!inner.ReadASN1Integer(r) ||
		!inner.ReadASN1Integer(s) ||
		!inner.Empty() {
		return false
	}
	return Verify(pub, hash, r, s)
}

type zr struct {
	io.Reader
}

// Read replaces the contents of dst with zeros.
func (z *zr) Read(dst []byte) (n int, err error) {
	for i := range dst {
		dst[i] = 0
	}
	return len(dst), nil
}

var zeroReader = &zr{}
<commit_msg>crypto/ecdsa: draw a fixed amount of entropy while signing<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
// defined in FIPS 186-3.
//
// This implementation derives the nonce from an AES-CTR CSPRNG keyed by:
//
// SHA2-512(priv.D || entropy || hash)[:32]
//
// The CSPRNG key is indifferentiable from a random oracle as shown in
// [Coron], the AES-CTR stream is indifferentiable from a random oracle
// under standard cryptographic assumptions (see [Larsson] for examples).
//
// References:
//   [Coron]
//     https://cs.nyu.edu/~dodis/ps/merkle.pdf
//   [Larsson]
//     https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf
package ecdsa

// Further references:
//   [NSA]: Suite B implementer's guide to FIPS 186-3
//     https://apps.nsa.gov/iaarchive/library/ia-guidance/ia-solutions-for-classified/algorithm-guidance/suite-b-implementers-guide-to-fips-186-3-ecdsa.cfm
//   [SECG]: SECG, SEC1
//     http://www.secg.org/sec1-v2.pdf

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/elliptic"
	"crypto/internal/randutil"
	"crypto/sha512"
	"errors"
	"io"
	"math/big"

	"golang.org/x/crypto/cryptobyte"
	"golang.org/x/crypto/cryptobyte/asn1"
)

// A invertible implements fast inverse mod Curve.Params().N
type invertible interface {
	// Inverse returns the inverse of k in GF(P)
	Inverse(k *big.Int) *big.Int
}

// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point)
type combinedMult interface {
	CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
}

const (
	aesIV = "IV for ECDSA CTR"
)

// PublicKey represents an ECDSA public key.
type PublicKey struct {
	elliptic.Curve
	X, Y *big.Int
}

// Any methods implemented on PublicKey might need to also be implemented on
// PrivateKey, as the latter embeds the former and will expose its methods.

// Equal reports whether pub and x have the same value.
//
// Two keys are only considered to have the same value if they have the same Curve value.
// Note that for example elliptic.P256() and elliptic.P256().Params() are different
// values, as the latter is a generic not constant time implementation.
func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
	xx, ok := x.(*PublicKey)
	if !ok {
		return false
	}
	return pub.X.Cmp(xx.X) == 0 && pub.Y.Cmp(xx.Y) == 0 &&
		// Standard library Curve implementations are singletons, so this check
		// will work for those. Other Curves might be equivalent even if not
		// singletons, but there is no definitive way to check for that, and
		// better to err on the side of safety.
		pub.Curve == xx.Curve
}

// PrivateKey represents an ECDSA private key.
type PrivateKey struct {
	PublicKey
	D *big.Int
}

// Public returns the public key corresponding to priv.
func (priv *PrivateKey) Public() crypto.PublicKey {
	return &priv.PublicKey
}

// Equal reports whether priv and x have the same value.
//
// See PublicKey.Equal for details on how Curve is compared.
func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
	xx, ok := x.(*PrivateKey)
	if !ok {
		return false
	}
	return priv.PublicKey.Equal(&xx.PublicKey) && priv.D.Cmp(xx.D) == 0
}

// Sign signs digest with priv, reading randomness from rand. The opts argument
// is not currently used but, in keeping with the crypto.Signer interface,
// should be the hash function used to digest the message.
//
// This method implements crypto.Signer, which is an interface to support keys
// where the private part is kept in, for example, a hardware module. Common
// uses should use the Sign function in this package directly.
func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
	r, s, err := Sign(rand, priv, digest)
	if err != nil {
		return nil, err
	}

	var b cryptobyte.Builder
	b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
		b.AddASN1BigInt(r)
		b.AddASN1BigInt(s)
	})
	return b.Bytes()
}

var one = new(big.Int).SetInt64(1)

// randFieldElement returns a random element of the field underlying the given
// curve using the procedure given in [NSA] A.2.1.
func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
	params := c.Params()
	b := make([]byte, params.BitSize/8+8)
	_, err = io.ReadFull(rand, b)
	if err != nil {
		return
	}

	k = new(big.Int).SetBytes(b)
	n := new(big.Int).Sub(params.N, one)
	k.Mod(k, n)
	k.Add(k, one)
	return
}

// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
	k, err := randFieldElement(c, rand)
	if err != nil {
		return nil, err
	}

	priv := new(PrivateKey)
	priv.PublicKey.Curve = c
	priv.D = k
	priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
	return priv, nil
}

// hashToInt converts a hash value to an integer. There is some disagreement
// about how this is done. [NSA] suggests that this is done in the obvious
// manner, but [SECG] truncates the hash to the bit-length of the curve order
// first. We follow [SECG] because that's what OpenSSL does. Additionally,
// OpenSSL right shifts excess bits from the number if the hash is too large
// and we mirror that too.
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
	orderBits := c.Params().N.BitLen()
	orderBytes := (orderBits + 7) / 8
	if len(hash) > orderBytes {
		hash = hash[:orderBytes]
	}

	ret := new(big.Int).SetBytes(hash)
	excess := len(hash)*8 - orderBits
	if excess > 0 {
		ret.Rsh(ret, uint(excess))
	}
	return ret
}

// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
// This has better constant-time properties than Euclid's method (implemented
// in math/big.Int.ModInverse) although math/big itself isn't strictly
// constant-time so it's not perfect.
func fermatInverse(k, N *big.Int) *big.Int {
	two := big.NewInt(2)
	nMinus2 := new(big.Int).Sub(N, two)
	return new(big.Int).Exp(k, nMinus2, N)
}

var errZeroParam = errors.New("zero parameter")

// Sign signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. If the hash is longer than the bit-length of the
// private key's curve order, the hash will be truncated to that length. It
// returns the signature as a pair of integers. The security of the private key
// depends on the entropy of rand.
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
	randutil.MaybeReadByte(rand)

	// Get 256 bits of entropy from rand.
	entropy := make([]byte, 32)
	_, err = io.ReadFull(rand, entropy)
	if err != nil {
		return
	}

	// Initialize an SHA-512 hash context; digest ...
	md := sha512.New()
	md.Write(priv.D.Bytes()) // the private key,
	md.Write(entropy)        // the entropy,
	md.Write(hash)           // and the input hash;
	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
	// which is an indifferentiable MAC.

	// Create an AES-CTR instance to use as a CSPRNG.
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, nil, err
	}

	// Create a CSPRNG that xors a stream of zeros with
	// the output of the AES-CTR instance.
	csprng := cipher.StreamReader{
		R: zeroReader,
		S: cipher.NewCTR(block, []byte(aesIV)),
	}

	// See [NSA] 3.4.1
	c := priv.PublicKey.Curve
	return sign(priv, &csprng, c, hash)
}

func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) {
	N := c.Params().N
	if N.Sign() == 0 {
		return nil, nil, errZeroParam
	}
	var k, kInv *big.Int
	for {
		for {
			k, err = randFieldElement(c, *csprng)
			if err != nil {
				r = nil
				return
			}

			if in, ok := priv.Curve.(invertible); ok {
				kInv = in.Inverse(k)
			} else {
				kInv = fermatInverse(k, N) // N != 0
			}

			r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
			r.Mod(r, N)
			if r.Sign() != 0 {
				break
			}
		}

		e := hashToInt(hash, c)
		s = new(big.Int).Mul(priv.D, r)
		s.Add(s, e)
		s.Mul(s, kInv)
		s.Mod(s, N) // N != 0
		if s.Sign() != 0 {
			break
		}
	}

	return
}

// SignASN1 signs a hash (which should be the result of hashing a larger message)
// using the private key, priv. If the hash is longer than the bit-length of the
// private key's curve order, the hash will be truncated to that length. It
// returns the ASN.1 encoded signature. The security of the private key
// depends on the entropy of rand.
func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
	return priv.Sign(rand, hash, nil)
}

// Verify verifies the signature in r, s of hash using the public key, pub. Its
// return value records whether the signature is valid.
func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
	// See [NSA] 3.4.2
	c := pub.Curve
	N := c.Params().N

	if r.Sign() <= 0 || s.Sign() <= 0 {
		return false
	}
	if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
		return false
	}
	return verify(pub, c, hash, r, s)
}

func verifyGeneric(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool {
	e := hashToInt(hash, c)
	var w *big.Int
	N := c.Params().N
	if in, ok := c.(invertible); ok {
		w = in.Inverse(s)
	} else {
		w = new(big.Int).ModInverse(s, N)
	}

	u1 := e.Mul(e, w)
	u1.Mod(u1, N)
	u2 := w.Mul(r, w)
	u2.Mod(u2, N)

	// Check if implements S1*g + S2*p
	var x, y *big.Int
	if opt, ok := c.(combinedMult); ok {
		x, y = opt.CombinedMult(pub.X, pub.Y, u1.Bytes(), u2.Bytes())
	} else {
		x1, y1 := c.ScalarBaseMult(u1.Bytes())
		x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
		x, y = c.Add(x1, y1, x2, y2)
	}

	if x.Sign() == 0 && y.Sign() == 0 {
		return false
	}
	x.Mod(x, N)
	return x.Cmp(r) == 0
}

// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the
// public key, pub. Its return value records whether the signature is valid.
func VerifyASN1(pub *PublicKey, hash, sig []byte) bool {
	var (
		r, s  = &big.Int{}, &big.Int{}
		inner cryptobyte.String
	)
	input := cryptobyte.String(sig)
	if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
		!input.Empty() ||
		!inner.ReadASN1Integer(r) ||
		!inner.ReadASN1Integer(s) ||
		!inner.Empty() {
		return false
	}
	return Verify(pub, hash, r, s)
}

type zr struct {
	io.Reader
}

// Read replaces the contents of dst with zeros.
func (z *zr) Read(dst []byte) (n int, err error) {
	for i := range dst {
		dst[i] = 0
	}
	return len(dst), nil
}

var zeroReader = &zr{}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"compress/flate"
	"encoding/binary"
	"fmt"
	"os"
)

type PDFormat struct {
	Name             [32]byte //start at byte 0
	Attributes       uint16   //32
	Version          uint16   //34
	CreationDate     uint32   //36
	ModifyDate       uint32   //40
	BackupDate       uint32   //44
	ModifyNumber     uint32   //48
	AppInfoID        uint32   //52
	SortInfoID       uint32   //56
	Type             [4]byte  //60
	Creator          [4]byte  //64
	UniqueIDSeed     uint32   //68
	NextRecordListID uint32   //72
	SectionCount     uint16   //76-78
}

type PDRecordInfoSection struct {
	DataOffset uint32  //starts at byte 0
	Attributes byte    //4
	UniqueID   [3]byte //5-8
}

type PDHeader struct {
	CompressionType uint16 //starts at byte 0
	_               uint16 //2 (always zero?)
	TextLength      uint32 //4
	RecordCount     uint16 //8
	RecordSize      uint16 //10
	CurrentPosition uint32 //12-16
}

type Mobi8Header struct {
	//note that since the values are being read
	//by bytes.Read, we can't use "_" as a name,
	//or have any unexported fields.
	//This is stupid, but whatever.
	//We use the name "SkipX" instead.
	CompressionType     uint16   //start at byte 0
	Skip1               uint16   //2 (always zero?)
	TextLength          uint32   //4
	RecordCount         uint16   //8
	RecordSize          uint16   //10
	CryptoType          uint16   //12
	Skip2               uint16   //14 filler
	Identifier          [4]byte  //16
	HeaderLength        uint32   //20
	Type                uint32   //24
	TextEncoding        uint32   //28
	UniqueID            uint32   //32
	Version             uint32   //36
	OrtographicIndex    uint32   //40
	IncflectionIndex    uint32   //44
	IndexNames          uint32   //48
	IndexKeys           uint32   //52
	Extra               [24]byte //56
	FirstNontext        uint32   //80
	TitleOffset         uint32   //84
	TitleLength         uint32   //88
	Locale              uint32   //92
	InputLanguage       uint32   //96
	OutputLanguage      uint32   //100
	MinVersion          uint32   //104
	FirstImageOffset    uint32   //108
	HuffmanRecordOffset uint32   //112
	HuffmanRecordCount  uint32   //116
	HuffmanTableOffset  uint32   //120
	HuffTableLength     uint32   //124
	ExthFlags           uint32   //128
	Skip3               [32]byte //132
	Unknown0            uint32   //164
	DrmOffset           uint32   //168
	DrmCount            uint32   //172
	DrmSize             uint32   //176
	DrmFlags            uint32   //180
	Skip4               [8]byte  //184
	FirstContentNumber  uint32   //192
	FdstFlowCount       uint32   //196
	FcisOffset          uint32   //200
	FcisCount           uint32   //204
	FlisOffset          uint32   //208
	FlisCount           uint32   //212
	Skip5               [8]byte  //216
	SrcsOffset          uint32   //224
	SrcsCount           uint32   //228
	Skip6               [8]byte  //232
	TrailDataFlags      uint16   //240
	NcxIndex            uint32   //242
	FragmentIndex       uint32   //246
	SkeletonIndex       uint32   //250
	DatpOffset          uint32   //254
	GuideIndex          uint32   //258-262
}

func GetStruct(file *os.File, hd interface{}, length int, offset int64) (rd int, err error) {
	b := make([]byte, length)
	rd, err = file.ReadAt(b, offset)
	if err != nil {
		return
	}
	buf := bytes.NewBuffer(b)
	err = binary.Read(buf, binary.BigEndian, hd)
	return
}

type ExthHeader struct {
	Identifier   uint32 //starts at byte 0
	HeaderLength uint32 //4
	RecordCount  uint32 //8-12
}

type ExthRecordInfo struct {
	RecordType   uint32 //starts at 0
	RecordLength uint32 //4-8
}

type ExthRecordData []byte

type FileHeader struct {
	Format     PDFormat
	Sections   []PDRecordInfoSection
	MobiHeader Mobi8Header
	Fcis       FcisRecord
}

type FcisRecord struct {
	Identifier [4]byte //starts at 0, to 4 "FCIS"
	Skip1      uint32  //4     20
	Skip2      uint32  //8     16
	Skip3      uint32  //12    1
	Skip4      uint32  //16    0
	TextLength uint32  //20    Same as PDHeader
	Skip5      uint32  //24    0
	Skip6      uint32  //28    32
	Skip7      uint32  //32    8
	Skip8      uint16  //36    1
	Skip9      uint16  //38    1
	Skip10     uint32  //40-44 0
}

func main() {
	hd, err := GetFileHeader("file.mobi")
	check(err)
	fmt.Printf("%#v\n", hd.Format)
	fmt.Printf("%#v %#v\n", hd.Sections[0], hd.Sections[181])
	fmt.Printf("%#v\n", hd.MobiHeader)
	fmt.Printf("%#v\n", hd.Fcis)
}

//GetPDRecordInfoSectionList reads `count` items from `file`,
//starting at byte `offset` and placing the result in in `ris`.
//Returns the number of records read, and any error.
func GetPDRecordInfoSectionList(file *os.File, ris *[]PDRecordInfoSection, count int, start int) (ii int, err error) {
	for ii = 0; ii < count; ii++ {
		var section PDRecordInfoSection
		_, err = GetStruct(file, &section, 8, int64(start+ii*8))
		if err != nil {
			return
		}
		*ris = append(*ris, section)
	}
	return
}

//GetFileHeader reads the header information from the file at path `path`.
//Returns the FileHeader as read, and any error.
func GetFileHeader(path string) (hd FileHeader, err error) {
	file, err := os.Open(path)
	defer file.Close()
	start := 0
	if err != nil {
		return
	}

	start, err = GetStruct(file, &hd.Format, 78, 0)
	fmt.Println(start)
	if err != nil {
		return
	}

	rdr := flate.NewReader(file)
	defer rdr.Close()

	a, err := GetPDRecordInfoSectionList(file, &hd.Sections, int(hd.Format.SectionCount), start)
	fmt.Println(a)
	if err != nil {
		return
	}

	a, err = GetStruct(file, &hd.MobiHeader, 262, int64(hd.Sections[0].DataOffset))
	fmt.Println(a, err)

    if hd.MobiHeader.FcisCount > 0 {
        offset := int64(hd.Sections[hd.MobiHeader.FcisOffset].DataOffset)
        a, err = GetStruct(file, &hd.Fcis, 44, offset)
        fmt.Println("FCIS", a, err)
    }

	return
}

//check panics when there's an error.
func check(err error) {
	if err != nil {
		panic(err)
	}
}
<commit_msg>added support for flis record<commit_after>package main

import (
	"bytes"
	"compress/flate"
	"encoding/binary"
	"fmt"
	"os"
)

type PDFormat struct {
	Name             [32]byte //start at byte 0
	Attributes       uint16   //32
	Version          uint16   //34
	CreationDate     uint32   //36
	ModifyDate       uint32   //40
	BackupDate       uint32   //44
	ModifyNumber     uint32   //48
	AppInfoID        uint32   //52
	SortInfoID       uint32   //56
	Type             [4]byte  //60
	Creator          [4]byte  //64
	UniqueIDSeed     uint32   //68
	NextRecordListID uint32   //72
	SectionCount     uint16   //76-78
}

type PDRecordInfoSection struct {
	DataOffset uint32  //starts at byte 0
	Attributes byte    //4
	UniqueID   [3]byte //5-8
}

type PDHeader struct {
	CompressionType uint16 //starts at byte 0
	_               uint16 //2 (always zero?)
	TextLength      uint32 //4
	RecordCount     uint16 //8
	RecordSize      uint16 //10
	CurrentPosition uint32 //12-16
}

type Mobi8Header struct {
	//note that since the values are being read
	//by bytes.Read, we can't use "_" as a name,
	//or have any unexported fields.
	//This is stupid, but whatever.
	//We use the name "SkipX" instead.
	CompressionType     uint16   //start at byte 0
	Skip1               uint16   //2 (always zero?)
	TextLength          uint32   //4
	RecordCount         uint16   //8
	RecordSize          uint16   //10
	CryptoType          uint16   //12
	Skip2               uint16   //14 filler
	Identifier          [4]byte  //16
	HeaderLength        uint32   //20
	Type                uint32   //24
	TextEncoding        uint32   //28
	UniqueID            uint32   //32
	Version             uint32   //36
	OrtographicIndex    uint32   //40
	IncflectionIndex    uint32   //44
	IndexNames          uint32   //48
	IndexKeys           uint32   //52
	Extra               [24]byte //56
	FirstNontext        uint32   //80
	TitleOffset         uint32   //84
	TitleLength         uint32   //88
	Locale              uint32   //92
	InputLanguage       uint32   //96
	OutputLanguage      uint32   //100
	MinVersion          uint32   //104
	FirstImageOffset    uint32   //108
	HuffmanRecordOffset uint32   //112
	HuffmanRecordCount  uint32   //116
	HuffmanTableOffset  uint32   //120
	HuffTableLength     uint32   //124
	ExthFlags           uint32   //128
	Skip3               [32]byte //132
	Unknown0            uint32   //164
	DrmOffset           uint32   //168
	DrmCount            uint32   //172
	DrmSize             uint32   //176
	DrmFlags            uint32   //180
	Skip4               [8]byte  //184
	FirstContentNumber  uint32   //192
	FdstFlowCount       uint32   //196
	FcisOffset          uint32   //200
	FcisCount           uint32   //204
	FlisOffset          uint32   //208
	FlisCount           uint32   //212
	Skip5               [8]byte  //216
	SrcsOffset          uint32   //224
	SrcsCount           uint32   //228
	Skip6               [8]byte  //232
	TrailDataFlags      uint16   //240
	NcxIndex            uint32   //242
	FragmentIndex       uint32   //246
	SkeletonIndex       uint32   //250
	DatpOffset          uint32   //254
	GuideIndex          uint32   //258-262
}

func GetStruct(file *os.File, hd interface{}, length int, offset int64) (rd int, err error) {
	b := make([]byte, length)
	rd, err = file.ReadAt(b, offset)
	if err != nil {
		return
	}
	buf := bytes.NewBuffer(b)
	err = binary.Read(buf, binary.BigEndian, hd)
	return
}

type ExthHeader struct {
	Identifier   uint32 //starts at byte 0
	HeaderLength uint32 //4
	RecordCount  uint32 //8-12
}

type ExthRecordInfo struct {
	RecordType   uint32 //starts at 0
	RecordLength uint32 //4-8
}

type ExthRecordData []byte

type FileHeader struct {
	Format     PDFormat
	Sections   []PDRecordInfoSection
	MobiHeader Mobi8Header
	Fcis       FcisRecord
	Flis       FlisRecord
}

type FlisRecord struct {
	Identifier [4]byte //starts at 0, "FLIS"
	Skip1      uint32  //4            8
	Skip2      uint16  //8            65
	Skip3      uint16  //10           0
	Skip4      uint32  //12           0
	Skip5      uint32  //16          -1
	Skip6      uint16  //20           1
	Skip7      uint16  //22           3
	Skip8      uint32  //24           3
	Skip9      uint32  //28           1
	Skip10     uint32  //32-36       -1
}

type FcisRecord struct {
	Identifier [4]byte //starts at 0, to 4 "FCIS"
	Skip1      uint32  //4     20
	Skip2      uint32  //8     16
	Skip3      uint32  //12    1
	Skip4      uint32  //16    0
	TextLength uint32  //20    Same as PDHeader
	Skip5      uint32  //24    0
	Skip6      uint32  //28    32
	Skip7      uint32  //32    8
	Skip8      uint16  //36    1
	Skip9      uint16  //38    1
	Skip10     uint32  //40-44 0
}

func main() {
	hd, err := GetFileHeader("file.mobi")
	check(err)
	fmt.Printf("%#v\n", hd.Format)
	fmt.Printf("%#v %#v\n", hd.Sections[0], hd.Sections[181])
	fmt.Printf("%#v\n", hd.MobiHeader)
	fmt.Printf("%#v\n", hd.Fcis)
	fmt.Printf("%#v\n", hd.Flis)
}

//GetPDRecordInfoSectionList reads `count` items from `file`,
//starting at byte `offset` and placing the result in in `ris`.
//Returns the number of records read, and any error.
func GetPDRecordInfoSectionList(file *os.File, ris *[]PDRecordInfoSection, count int, start int) (ii int, err error) {
	for ii = 0; ii < count; ii++ {
		var section PDRecordInfoSection
		_, err = GetStruct(file, &section, 8, int64(start+ii*8))
		if err != nil {
			return
		}
		*ris = append(*ris, section)
	}
	return
}

//GetFileHeader reads the header information from the file at path `path`.
//Returns the FileHeader as read, and any error.
func GetFileHeader(path string) (hd FileHeader, err error) {
	file, err := os.Open(path)
	defer file.Close()
	start := 0
	if err != nil {
		return
	}

	start, err = GetStruct(file, &hd.Format, 78, 0)
	fmt.Println(start)
	if err != nil {
		return
	}

	rdr := flate.NewReader(file)
	defer rdr.Close()

	a, err := GetPDRecordInfoSectionList(file, &hd.Sections, int(hd.Format.SectionCount), start)
	fmt.Println(a)
	if err != nil {
		return
	}

	a, err = GetStruct(file, &hd.MobiHeader, 262, int64(hd.Sections[0].DataOffset))
	fmt.Println(a, err)

	if hd.MobiHeader.FcisCount > 0 {
		offset := int64(hd.Sections[hd.MobiHeader.FcisOffset].DataOffset)
		a, err = GetStruct(file, &hd.Fcis, 44, offset)
		fmt.Println("FCIS", a, err)
	}

	if hd.MobiHeader.FlisCount > 0 {
		offset := int64(hd.Sections[hd.MobiHeader.FlisOffset].DataOffset)
		a, err = GetStruct(file, &hd.Flis, 44, offset)
		fmt.Println("FCIS", a, err)
	}

	return
}

//check panics when there's an error.
func check(err error) {
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"io"
	"os"

	"github.com/gin-gonic/gin/binding"
)

const ENV_GIN_MODE = "GIN_MODE"

const (
	DebugMode   string = "debug"
	ReleaseMode string = "release"
	TestMode    string = "test"
)
const (
	debugCode   = iota
	releaseCode
	testCode
)

// DefaultWriter is the default io.Writer used the Gin for debug output and
// middleware output like Logger() or Recovery().
// Note that both Logger and Recovery provides custom ways to configure their
// output io.Writer.
// To support coloring in Windows use:
// 		import "github.com/mattn/go-colorable"
// 		gin.DefaultWriter = colorable.NewColorableStdout()
var DefaultWriter io.Writer = os.Stdout
var DefaultErrorWriter io.Writer = os.Stderr

var ginMode = debugCode
var modeName = DebugMode

func init() {
	mode := os.Getenv(ENV_GIN_MODE)
	if len(mode) == 0 {
		SetMode(DebugMode)
	} else {
		SetMode(mode)
	}
}

func SetMode(value string) {
	switch value {
	case DebugMode:
		ginMode = debugCode
	case ReleaseMode:
		ginMode = releaseCode
	case TestMode:
		ginMode = testCode
	default:
		panic("gin mode unknown: " + value)
	}
	modeName = value
}

func DisableBindValidation() {
	binding.Validator = nil
}

func Mode() string {
	return modeName
}
<commit_msg>fix: gofmt error. (#833)<commit_after>// Copyright 2014 Manu Martinez-Almeida.  All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.

package gin

import (
	"io"
	"os"

	"github.com/gin-gonic/gin/binding"
)

const ENV_GIN_MODE = "GIN_MODE"

const (
	DebugMode   string = "debug"
	ReleaseMode string = "release"
	TestMode    string = "test"
)
const (
	debugCode = iota
	releaseCode
	testCode
)

// DefaultWriter is the default io.Writer used the Gin for debug output and
// middleware output like Logger() or Recovery().
// Note that both Logger and Recovery provides custom ways to configure their
// output io.Writer.
// To support coloring in Windows use:
// 		import "github.com/mattn/go-colorable"
// 		gin.DefaultWriter = colorable.NewColorableStdout()
var DefaultWriter io.Writer = os.Stdout
var DefaultErrorWriter io.Writer = os.Stderr

var ginMode = debugCode
var modeName = DebugMode

func init() {
	mode := os.Getenv(ENV_GIN_MODE)
	if len(mode) == 0 {
		SetMode(DebugMode)
	} else {
		SetMode(mode)
	}
}

func SetMode(value string) {
	switch value {
	case DebugMode:
		ginMode = debugCode
	case ReleaseMode:
		ginMode = releaseCode
	case TestMode:
		ginMode = testCode
	default:
		panic("gin mode unknown: " + value)
	}
	modeName = value
}

func DisableBindValidation() {
	binding.Validator = nil
}

func Mode() string {
	return modeName
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"sync"

	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

var MaxClientIdLen = 8
var MaxRetryCount = 3

type MQTTClient struct {
	Client     *MQTT.Client
	Opts       *MQTT.ClientOptions
	RetryCount int
	Subscribed map[string]byte

	lock *sync.Mutex // use for reconnect
}

// Connects connect to the MQTT broker with Options.
func (m *MQTTClient) Connect() (*MQTT.Client, error) {

	m.Client = MQTT.NewClient(m.Opts)

	log.Info("connecting...")

	if token := m.Client.Connect(); token.Wait() && token.Error() != nil {
		return nil, token.Error()
	}
	return m.Client, nil
}

func (m *MQTTClient) Publish(topic string, payload []byte, qos int, retain bool, sync bool) error {
	token := m.Client.Publish(topic, byte(qos), retain, payload)

	if sync == true {
		token.Wait()
	}

	return token.Error()
}

func (m *MQTTClient) Disconnect() error {
	if m.Client.IsConnected() {
		m.Client.Disconnect(20)
		log.Info("client disconnected")
	}
	return nil
}

func (m *MQTTClient) SubscribeOnConnect(client *MQTT.Client) {
	log.Infof("client connected")

	token := client.SubscribeMultiple(m.Subscribed, m.onMessageReceived)
	token.Wait()
	if token.Error() != nil {
		log.Error(token.Error())
	}
}

func (m *MQTTClient) ConnectionLost(client *MQTT.Client, reason error) {
	log.Errorf("client disconnected: %s", reason)
}

func (m *MQTTClient) onMessageReceived(client *MQTT.Client, message MQTT.Message) {
	log.Infof("topic:%s  / msg:%s", message.Topic(), message.Payload())
	fmt.Println(string(message.Payload()))
}

func getCertPool(pemPath string) (*x509.CertPool, error) {
	certs := x509.NewCertPool()

	pemData, err := ioutil.ReadFile(pemPath)
	if err != nil {
		return nil, err
	}
	certs.AppendCertsFromPEM(pemData)
	return certs, nil
}

// getRandomClientId returns randomized ClientId.
func getRandomClientId() string {
	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	var bytes = make([]byte, MaxClientIdLen)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}
	return "mqttcli-" + string(bytes)
}

// NewOption returns ClientOptions via parsing command line options.
func NewOption(c *cli.Context) (*MQTT.ClientOptions, error) {
	opts := MQTT.NewClientOptions()

	host := c.String("host")
	port := c.Int("p")

	if host == "" {
		getSettingsFromFile(c.String("conf"), opts)
	}

	clientId := c.String("i")
	if clientId == "" {
		clientId = getRandomClientId()
	}
	opts.SetClientID(clientId)

	TLSConfig := &tls.Config{InsecureSkipVerify: false}
	cafile := c.String("cafile")
	scheme := "tcp"
	if cafile != "" {
		scheme = "ssl"
		certPool, err := getCertPool(cafile)
		if err != nil {
			return nil, err
		}
		TLSConfig.RootCAs = certPool
	}
	insecure := c.Bool("insecure")
	if insecure {
		TLSConfig.InsecureSkipVerify = true
	}
	opts.SetTLSConfig(TLSConfig)

	user := c.String("u")
	if user != "" {
		opts.SetUsername(user)
	}
	password := c.String("P")
	if password != "" {
		opts.SetPassword(password)
	}

	if host != "" {
		brokerUri := fmt.Sprintf("%s://%s:%d", scheme, host, port)
		log.Infof("Broker URI: %s", brokerUri)

		opts.AddBroker(brokerUri)
	}

	opts.SetAutoReconnect(true)
	return opts, nil
}
<commit_msg>not subscribe if publish or subscribe not set.<commit_after>package main

import (
	"crypto/rand"
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"sync"

	MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
	log "github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

var MaxClientIdLen = 8
var MaxRetryCount = 3

type MQTTClient struct {
	Client     *MQTT.Client
	Opts       *MQTT.ClientOptions
	RetryCount int
	Subscribed map[string]byte

	lock *sync.Mutex // use for reconnect
}

// Connects connect to the MQTT broker with Options.
func (m *MQTTClient) Connect() (*MQTT.Client, error) {

	m.Client = MQTT.NewClient(m.Opts)

	log.Info("connecting...")

	if token := m.Client.Connect(); token.Wait() && token.Error() != nil {
		return nil, token.Error()
	}
	return m.Client, nil
}

func (m *MQTTClient) Publish(topic string, payload []byte, qos int, retain bool, sync bool) error {
	token := m.Client.Publish(topic, byte(qos), retain, payload)

	if sync == true {
		token.Wait()
	}

	return token.Error()
}

func (m *MQTTClient) Disconnect() error {
	if m.Client.IsConnected() {
		m.Client.Disconnect(20)
		log.Info("client disconnected")
	}
	return nil
}

func (m *MQTTClient) SubscribeOnConnect(client *MQTT.Client) {
	log.Infof("client connected")

	if len(m.Subscribed) > 0 {
		token := client.SubscribeMultiple(m.Subscribed, m.onMessageReceived)
		token.Wait()
		if token.Error() != nil {
			log.Error(token.Error())
		}
	}
}

func (m *MQTTClient) ConnectionLost(client *MQTT.Client, reason error) {
	log.Errorf("client disconnected: %s", reason)
}

func (m *MQTTClient) onMessageReceived(client *MQTT.Client, message MQTT.Message) {
	log.Infof("topic:%s / msg:%s", message.Topic(), message.Payload())
	fmt.Println(string(message.Payload()))
}

func getCertPool(pemPath string) (*x509.CertPool, error) {
	certs := x509.NewCertPool()

	pemData, err := ioutil.ReadFile(pemPath)
	if err != nil {
		return nil, err
	}
	certs.AppendCertsFromPEM(pemData)
	return certs, nil
}

// getRandomClientId returns randomized ClientId.
func getRandomClientId() string {
	const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
	var bytes = make([]byte, MaxClientIdLen)
	rand.Read(bytes)
	for i, b := range bytes {
		bytes[i] = alphanum[b%byte(len(alphanum))]
	}
	return "mqttcli-" + string(bytes)
}

// NewOption returns ClientOptions via parsing command line options.
func NewOption(c *cli.Context) (*MQTT.ClientOptions, error) {
	opts := MQTT.NewClientOptions()

	host := c.String("host")
	port := c.Int("p")

	if host == "" {
		getSettingsFromFile(c.String("conf"), opts)
	}

	clientId := c.String("i")
	if clientId == "" {
		clientId = getRandomClientId()
	}
	opts.SetClientID(clientId)

	TLSConfig := &tls.Config{InsecureSkipVerify: false}
	cafile := c.String("cafile")
	scheme := "tcp"
	if cafile != "" {
		scheme = "ssl"
		certPool, err := getCertPool(cafile)
		if err != nil {
			return nil, err
		}
		TLSConfig.RootCAs = certPool
	}
	insecure := c.Bool("insecure")
	if insecure {
		TLSConfig.InsecureSkipVerify = true
	}
	opts.SetTLSConfig(TLSConfig)

	user := c.String("u")
	if user != "" {
		opts.SetUsername(user)
	}
	password := c.String("P")
	if password != "" {
		opts.SetPassword(password)
	}

	if host != "" {
		brokerUri := fmt.Sprintf("%s://%s:%d", scheme, host, port)
		log.Infof("Broker URI: %s", brokerUri)

		opts.AddBroker(brokerUri)
	}

	opts.SetAutoReconnect(true)
	return opts, nil
}
<|endoftext|>


<commit_before>package main

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

var (
	statements map[string]string = map[string]string{
		"by_email": "SELECT * FROM `bucket-1` WHERE email='%s'",
	}
)

type queryClient struct {
	url, index, consistency string
}

func newQueryClient(config nbConfig) *queryClient {
	client := queryClient{
		url:         fmt.Sprintf("%s/query/service", config.Database.Address.N1QL),
		index:       config.Query.Index,
		consistency: config.Query.Consistency,
	}
	return &client
}

func (c *queryClient) post(statement string) error {
	values := url.Values{
		"statement":        []string{statement},
		"scan_consistency": []string{c.consistency},
	}

	resp, err := http.PostForm(c.url, values)
	defer resp.Body.Close()
	if err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		return errors.New(fmt.Sprintf("unexpected status code: %d", resp.StatusCode))
	}

	if _, err = ioutil.ReadAll(resp.Body); err != nil {
		return err
	}

	return nil
}

func (c *queryClient) query(value doc) error {
	var statement string

	switch c.index {
	case "by_email":
		statement = fmt.Sprintf(statements[c.index], value.Email)
	default:
		fatalf("unknown index: %s\n", c.index)
	}

	return c.post(statement)
}
<commit_msg>Fix golint issue<commit_after>package main

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

var (
	statements map[string]string = map[string]string{
		"by_email": "SELECT * FROM `bucket-1` WHERE email='%s'",
	}
)

type queryClient struct {
	url, index, consistency string
}

func newQueryClient(config nbConfig) *queryClient {
	client := queryClient{
		url:         fmt.Sprintf("%s/query/service", config.Database.Address.N1QL),
		index:       config.Query.Index,
		consistency: config.Query.Consistency,
	}
	return &client
}

func (c *queryClient) post(statement string) error {
	values := url.Values{
		"statement":        []string{statement},
		"scan_consistency": []string{c.consistency},
	}

	resp, err := http.PostForm(c.url, values)
	defer resp.Body.Close()
	if err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
	}

	if _, err = ioutil.ReadAll(resp.Body); err != nil {
		return err
	}

	return nil
}

func (c *queryClient) query(value doc) error {
	var statement string

	switch c.index {
	case "by_email":
		statement = fmt.Sprintf(statements[c.index], value.Email)
	default:
		fatalf("unknown index: %s\n", c.index)
	}

	return c.post(statement)
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Xuyuan Pang <xuyuanp # gmail dot com>
 *
 * 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 hador

import (
	"container/list"
	"fmt"
	"net/http"
	"regexp"
	"strings"

	"github.com/Xuyuanp/hador/swagger"
)

func splitSegments(path string) []string {
	path = trimPath(path)
	if len(path) == 0 {
		return []string{}
	}
	return strings.Split(path, "/")
}

func isReg(segment string) bool {
	if regSegmentRegexp.MatchString(segment) {
		return true
	}
	if strings.HasPrefix(segment, "{") && strings.HasSuffix(segment, "}") {
		return true
	}
	return false
}

var regSegmentRegexp = regexp.MustCompile(`\(\?P<.+>.+\)`)

type dispatcher struct {
	node *Node
}

func (d *dispatcher) Serve(ctx *Context) {
	n := d.node

	segment := ctx.segment()

	// path matches
	if len(segment) == 0 {
		n.doServe(ctx)
		return
	}

	// find next node
	next := n.findNext(segment)
	if next != nil {
		if next.paramReg != nil {
			ctx.Params()[next.paramName] = segment
		}
		next.Serve(ctx)
		return
	}
	// 404 not found
	ctx.OnError(http.StatusNotFound)
}

// Node struct
type Node struct {
	*FilterChain
	h           *Hador
	parent      *Node
	depth       int
	segment     string
	paramName   string
	paramReg    *regexp.Regexp
	rawChildren map[string]*Node
	regChildren []*Node
	leaves      map[Method]*Leaf
}

// NewNode creates new Node instance.
func NewNode(h *Hador, segment string, depth int) *Node {
	paramName, paramReg := resolveSegment(segment)
	n := &Node{
		h:           h,
		segment:     segment,
		depth:       depth,
		paramName:   paramName,
		paramReg:    paramReg,
		rawChildren: make(map[string]*Node),
		regChildren: make([]*Node, 0),
		leaves:      make(map[Method]*Leaf),
	}
	n.FilterChain = NewFilterChain(&dispatcher{node: n})
	return n
}

func resolveSegment(segment string) (paramName string, paramReg *regexp.Regexp) {
	var splits []string
	if strings.HasPrefix(segment, "{") && strings.HasSuffix(segment, "}") {
		seg := segment[1 : len(segment)-1]
		splits = strings.SplitN(seg, ":", 2)
		if len(splits) == 1 {
			splits = append(splits, ".+")
		}
	} else if regSegmentRegexp.MatchString(segment) {
		seg := segment[4 : len(segment)-1]
		splits = strings.SplitN(seg, ">", 2)
	}
	if splits != nil && len(splits) == 2 {
		paramName = splits[0]
		regstr := splits[1]
		if !strings.HasPrefix(regstr, "^") {
			regstr = "^" + regstr
		}
		if !strings.HasSuffix(regstr, "$") {
			regstr = regstr + "$"
		}
		paramReg = regexp.MustCompile(regstr)
	}
	return
}

// AddRoute adds a new route with method, pattern and handler
func (n *Node) AddRoute(method Method, pattern string, h interface{}, filters ...Filter) *Leaf {
	handler := parseHandler(h)
	segments := splitSegments(pattern)
	if _, l, ok := n.add(segments, method, handler, filters...); ok {
		return l
	}
	panic(fmt.Errorf("pattern: %s has been registered", pattern))
}

func (n *Node) add(segments []string, method Method, handler Handler, filters ...Filter) (*Node, *Leaf, bool) {
	if len(segments) == 0 {
		if method != "" && handler != nil {
			l, ok := n.handle(method, handler, filters...)
			return n, l, ok
		}
		n.AddFilters(filters...)
		return n, nil, true
	}

	segment := segments[0]
	next := n.findOrCreateNext(segment)
	return next.add(segments[1:], method, handler, filters...)
}

func (n *Node) handle(method Method, handler Handler, filters ...Filter) (l *Leaf, ok bool) {
	if _, ok := n.leaves[method]; ok {
		return nil, false
	}
	l = NewLeaf(n, method, handler)
	n.leaves[method] = l
	l.AddFilters(filters...)
	return l, true
}

func (n *Node) findOrCreateNext(segment string) (next *Node) {
	if !isReg(segment) {
		if ne, ok := n.rawChildren[segment]; ok {
			next = ne
		} else {
			next = NewNode(n.h, segment, n.depth+1)
			n.rawChildren[segment] = next
		}
	} else {
		found := false
		for _, next = range n.regChildren {
			if next.segment == segment {
				found = true
				break
			}
		}
		if !found {
			next = NewNode(n.h, segment, n.depth+1)
			n.regChildren = append(n.regChildren, next)
		}
	}
	next.parent = n
	return
}

func (n *Node) findNext(segment string) (next *Node) {
	if ne, ok := n.rawChildren[segment]; ok {
		next = ne
	} else {
		for _, ne := range n.regChildren {
			if ne.MatchRegexp(segment) {
				next = ne
				break
			}
		}
	}
	return
}

func (n *Node) doServe(ctx *Context) {
	// 404 not found
	if len(n.leaves) == 0 {
		ctx.OnError(http.StatusNotFound)
		return
	}
	// method matches
	if l, ok := n.leaves[Method(ctx.Request.Method)]; ok {
		l.Serve(ctx)
		return
	}
	// ANY matches
	if l, ok := n.leaves["ANY"]; ok {
		l.Serve(ctx)
		return
	}
	// 405 method not allowed
	methods := make([]Method, len(n.leaves))
	i := 0
	for m := range n.leaves {
		methods[i] = m
		i++
	}
	ctx.OnError(http.StatusMethodNotAllowed, methods)
}

// MatchRegexp checks if the segment match regexp in node
func (n *Node) MatchRegexp(segment string) bool {
	if n.paramReg != nil && n.paramReg.MatchString(segment) {
		return true
	}
	return false
}

// Setter returns a setter-chain to add a new route.
func (n *Node) Setter() MethodSetter {
	return func(method Method) PathSetter {
		return func(path string) HandlerSetter {
			return func(handler interface{}, filters ...Filter) *swagger.Operation {
				return n.AddRoute(method, path, handler, filters...).SwaggerOperation()
			}
		}
	}
}

// Path returns the full path from root to the node
func (n *Node) Path() string {
	if n.parent == nil {
		return "/"
	}
	ppath := n.parent.Path()
	if ppath == "/" {
		ppath = ""
	}
	if n.paramName != "" {
		return ppath + "/{" + n.paramName + "}"
	}
	return ppath + "/" + n.segment
}

// Parent returns the node's parent node
func (n *Node) Parent() *Node {
	return n.parent
}

// Depth returns the nodes' depth
func (n *Node) Depth() int {
	return n.depth
}

// Segment returns node's segment
func (n *Node) Segment() string {
	return n.segment
}

// Leaves returns all of node's leaves
func (n *Node) Leaves() []*Leaf {
	leaves := make([]*Leaf, len(n.leaves))
	i := 0
	for _, l := range n.leaves {
		leaves[i] = l
		i++
	}
	return leaves[:i]
}

func (n *Node) travel(llist *list.List) {
	for _, l := range n.leaves {
		llist.PushBack(l)
	}
	for _, child := range n.rawChildren {
		child.travel(llist)
	}
	for _, child := range n.regChildren {
		child.travel(llist)
	}
}
<commit_msg>Removed dispatcher; Node serves requests by itself.<commit_after>/*
 * Copyright 2015 Xuyuan Pang <xuyuanp # gmail dot com>
 *
 * 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 hador

import (
	"container/list"
	"fmt"
	"net/http"
	"regexp"
	"strings"

	"github.com/Xuyuanp/hador/swagger"
)

func splitSegments(path string) []string {
	path = trimPath(path)
	if len(path) == 0 {
		return []string{}
	}
	return strings.Split(path, "/")
}

func isReg(segment string) bool {
	if regSegmentRegexp.MatchString(segment) {
		return true
	}
	if strings.HasPrefix(segment, "{") && strings.HasSuffix(segment, "}") {
		return true
	}
	return false
}

var regSegmentRegexp = regexp.MustCompile(`\(\?P<.+>.+\)`)

// Node struct
type Node struct {
	h           *Hador
	parent      *Node
	depth       int
	segment     string
	paramName   string
	paramReg    *regexp.Regexp
	rawChildren map[string]*Node
	regChildren []*Node
	leaves      map[Method]*Leaf
}

// NewNode creates new Node instance.
func NewNode(h *Hador, segment string, depth int) *Node {
	paramName, paramReg := resolveSegment(segment)
	n := &Node{
		h:           h,
		segment:     segment,
		depth:       depth,
		paramName:   paramName,
		paramReg:    paramReg,
		rawChildren: make(map[string]*Node),
		regChildren: make([]*Node, 0),
		leaves:      make(map[Method]*Leaf),
	}
	return n
}

func resolveSegment(segment string) (paramName string, paramReg *regexp.Regexp) {
	var splits []string
	if strings.HasPrefix(segment, "{") && strings.HasSuffix(segment, "}") {
		seg := segment[1 : len(segment)-1]
		splits = strings.SplitN(seg, ":", 2)
		if len(splits) == 1 {
			splits = append(splits, ".+")
		}
	} else if regSegmentRegexp.MatchString(segment) {
		seg := segment[4 : len(segment)-1]
		splits = strings.SplitN(seg, ">", 2)
	}
	if splits != nil && len(splits) == 2 {
		paramName = splits[0]
		regstr := splits[1]
		if !strings.HasPrefix(regstr, "^") {
			regstr = "^" + regstr
		}
		if !strings.HasSuffix(regstr, "$") {
			regstr = regstr + "$"
		}
		paramReg = regexp.MustCompile(regstr)
	}
	return
}

// AddRoute adds a new route with method, pattern and handler
func (n *Node) AddRoute(method Method, pattern string, h interface{}, filters ...Filter) *Leaf {
	handler := parseHandler(h)
	segments := splitSegments(pattern)
	if _, l, ok := n.add(segments, method, handler, filters...); ok {
		return l
	}
	panic(fmt.Errorf("pattern: %s has been registered", pattern))
}

func (n *Node) add(segments []string, method Method, handler Handler, filters ...Filter) (*Node, *Leaf, bool) {
	if len(segments) == 0 {
		if method != "" && handler != nil {
			l, ok := n.handle(method, handler, filters...)
			return n, l, ok
		}
		return n, nil, true
	}

	segment := segments[0]
	next := n.findOrCreateNext(segment)
	return next.add(segments[1:], method, handler, filters...)
}

func (n *Node) handle(method Method, handler Handler, filters ...Filter) (l *Leaf, ok bool) {
	if _, ok := n.leaves[method]; ok {
		return nil, false
	}
	l = NewLeaf(n, method, handler)
	n.leaves[method] = l
	l.AddFilters(filters...)
	return l, true
}

func (n *Node) findOrCreateNext(segment string) (next *Node) {
	if !isReg(segment) {
		if ne, ok := n.rawChildren[segment]; ok {
			next = ne
		} else {
			next = NewNode(n.h, segment, n.depth+1)
			n.rawChildren[segment] = next
		}
	} else {
		found := false
		for _, next = range n.regChildren {
			if next.segment == segment {
				found = true
				break
			}
		}
		if !found {
			next = NewNode(n.h, segment, n.depth+1)
			n.regChildren = append(n.regChildren, next)
		}
	}
	next.parent = n
	return
}

func (n *Node) findNext(segment string) (next *Node) {
	if ne, ok := n.rawChildren[segment]; ok {
		next = ne
	} else {
		for _, ne := range n.regChildren {
			if ne.MatchRegexp(segment) {
				next = ne
				break
			}
		}
	}
	return
}

func (n *Node) Serve(ctx *Context) {
	segment := ctx.segment()

	// path matches
	if len(segment) == 0 {
		n.doServe(ctx)
		return
	}

	// find next node
	next := n.findNext(segment)
	if next != nil {
		if next.paramReg != nil {
			ctx.Params()[next.paramName] = segment
		}
		next.Serve(ctx)
		return
	}
	// 404 not found
	ctx.OnError(http.StatusNotFound)
}

func (n *Node) doServe(ctx *Context) {
	// 404 not found
	if len(n.leaves) == 0 {
		ctx.OnError(http.StatusNotFound)
		return
	}
	// method matches
	if l, ok := n.leaves[Method(ctx.Request.Method)]; ok {
		l.Serve(ctx)
		return
	}
	// ANY matches
	if l, ok := n.leaves["ANY"]; ok {
		l.Serve(ctx)
		return
	}
	// 405 method not allowed
	methods := make([]Method, len(n.leaves))
	i := 0
	for m := range n.leaves {
		methods[i] = m
		i++
	}
	ctx.OnError(http.StatusMethodNotAllowed, methods)
}

// MatchRegexp checks if the segment match regexp in node
func (n *Node) MatchRegexp(segment string) bool {
	if n.paramReg != nil && n.paramReg.MatchString(segment) {
		return true
	}
	return false
}

// Setter returns a setter-chain to add a new route.
func (n *Node) Setter() MethodSetter {
	return func(method Method) PathSetter {
		return func(path string) HandlerSetter {
			return func(handler interface{}, filters ...Filter) *swagger.Operation {
				return n.AddRoute(method, path, handler, filters...).SwaggerOperation()
			}
		}
	}
}

// Path returns the full path from root to the node
func (n *Node) Path() string {
	if n.parent == nil {
		return "/"
	}
	ppath := n.parent.Path()
	if ppath == "/" {
		ppath = ""
	}
	if n.paramName != "" {
		return ppath + "/{" + n.paramName + "}"
	}
	return ppath + "/" + n.segment
}

// Parent returns the node's parent node
func (n *Node) Parent() *Node {
	return n.parent
}

// Depth returns the nodes' depth
func (n *Node) Depth() int {
	return n.depth
}

// Segment returns node's segment
func (n *Node) Segment() string {
	return n.segment
}

// Leaves returns all of node's leaves
func (n *Node) Leaves() []*Leaf {
	leaves := make([]*Leaf, len(n.leaves))
	i := 0
	for _, l := range n.leaves {
		leaves[i] = l
		i++
	}
	return leaves[:i]
}

func (n *Node) travel(llist *list.List) {
	for _, l := range n.leaves {
		llist.PushBack(l)
	}
	for _, child := range n.rawChildren {
		child.travel(llist)
	}
	for _, child := range n.regChildren {
		child.travel(llist)
	}
}
<|endoftext|>


<commit_before>package jiracmd

import (
	"fmt"
	"net/http"

	"github.com/coryb/figtree"
	"github.com/coryb/oreo"
	"github.com/go-jira/jira"
	"github.com/go-jira/jira/jiracli"
	"github.com/mgutz/ansi"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

func CmdLoginRegistry() *jiracli.CommandRegistryEntry {
	opts := jiracli.CommonOptions{}
	return &jiracli.CommandRegistryEntry{
		"Attempt to login into jira server",
		func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
			jiracli.LoadConfigs(cmd, fig, &opts)
			return nil
		},
		func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
			return CmdLogin(o, globals, &opts)
		},
	}
}

func authCallback(req *http.Request, resp *http.Response) (*http.Response, error) {
	if resp.StatusCode == 403 {
		defer resp.Body.Close()
		// X-Authentication-Denied-Reason: CAPTCHA_CHALLENGE; login-url=https://jira/login.jsp
		if reason := resp.Header.Get("X-Authentication-Denied-Reason"); reason != "" {
			return resp, fmt.Errorf("Authenticaion Failed: " + reason)
		}
		return resp, fmt.Errorf("Authenticaion Failed: Unkown Reason")
	} else if resp.StatusCode == 200 {
		if reason := resp.Header.Get("X-Seraph-Loginreason"); reason == "AUTHENTICATION_DENIED" {
			defer resp.Body.Close()
			return resp, fmt.Errorf("Authentication Failed: " + reason)
		}
	}

	return resp, nil
}

// CmdLogin will attempt to login into jira server
func CmdLogin(o *oreo.Client, globals *jiracli.GlobalOptions, opts *jiracli.CommonOptions) error {
	if globals.AuthMethod() == "api-token" {
		log.Noticef("No need to login when using api-token authentication method")
		return nil
	}

	ua := o.WithoutRedirect().WithRetries(0).WithoutCallbacks().WithPostCallback(authCallback)
	for {
		if session, err := jira.GetSession(o, globals.Endpoint.Value); err != nil {
			// No active session so try to create a new one
			_, err := jira.NewSession(ua, globals.Endpoint.Value, globals)
			if err != nil {
				// reset password on failed session
				globals.SetPass("")
				log.Errorf("%s", err)
				continue
			}
			if !globals.Quiet.Value {
				fmt.Println(ansi.Color("OK", "green"), "New session for", globals.User)
			}
			break
		} else {
			if !globals.Quiet.Value {
				fmt.Println(ansi.Color("OK", "green"), "Found session for", session.Name)
			}
			break
		}
	}
	return nil
}
<commit_msg>Remove (possible) infinite loop from CmdLogin.<commit_after>package jiracmd

import (
	"fmt"
	"net/http"

	"github.com/coryb/figtree"
	"github.com/coryb/oreo"
	"github.com/go-jira/jira"
	"github.com/go-jira/jira/jiracli"
	"github.com/mgutz/ansi"
	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

func CmdLoginRegistry() *jiracli.CommandRegistryEntry {
	opts := jiracli.CommonOptions{}
	return &jiracli.CommandRegistryEntry{
		"Attempt to login into jira server",
		func(fig *figtree.FigTree, cmd *kingpin.CmdClause) error {
			jiracli.LoadConfigs(cmd, fig, &opts)
			return nil
		},
		func(o *oreo.Client, globals *jiracli.GlobalOptions) error {
			return CmdLogin(o, globals, &opts)
		},
	}
}

func authCallback(req *http.Request, resp *http.Response) (*http.Response, error) {
	if resp.StatusCode == 403 {
		defer resp.Body.Close()
		// X-Authentication-Denied-Reason: CAPTCHA_CHALLENGE; login-url=https://jira/login.jsp
		if reason := resp.Header.Get("X-Authentication-Denied-Reason"); reason != "" {
			return resp, fmt.Errorf("Authenticaion Failed: " + reason)
		}
		return resp, fmt.Errorf("Authenticaion Failed: Unkown Reason")
	} else if resp.StatusCode == 200 {
		if reason := resp.Header.Get("X-Seraph-Loginreason"); reason == "AUTHENTICATION_DENIED" {
			defer resp.Body.Close()
			return resp, fmt.Errorf("Authentication Failed: " + reason)
		}
	}

	return resp, nil
}

// CmdLogin will attempt to login into jira server
func CmdLogin(o *oreo.Client, globals *jiracli.GlobalOptions, opts *jiracli.CommonOptions) error {
	if globals.AuthMethod() == "api-token" {
		log.Noticef("No need to login when using api-token authentication method")
		return nil
	}

	ua := o.WithoutRedirect().WithRetries(0).WithoutCallbacks().WithPostCallback(authCallback)

	if session, err := jira.GetSession(o, globals.Endpoint.Value); err != nil {
		// No active session so try to create a new one
		_, err := jira.NewSession(ua, globals.Endpoint.Value, globals)
		if err != nil {
			// reset password on failed session
			globals.SetPass("")
			log.Errorf("%s", err)
		} else if !globals.Quiet.Value {
			fmt.Println(ansi.Color("OK", "green"), "New session for", globals.User)
		}
	} else {
		if !globals.Quiet.Value {
			fmt.Println(ansi.Color("OK", "green"), "Found session for", session.Name)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package diff

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/engine/apply/action/component"
	"github.com/Aptomi/aptomi/pkg/engine/apply/action/global"
	"github.com/Aptomi/aptomi/pkg/engine/resolve"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/lang"
	"github.com/Aptomi/aptomi/pkg/lang/builder"
	"github.com/Aptomi/aptomi/pkg/util"
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestDiffEmpty(t *testing.T) {
	b := makePolicyBuilder()
	resolvedPrev := resolvePolicy(t, b)
	resolvedNext := resolvePolicy(t, b)

	// diff should be empty
	diff := NewPolicyResolutionDiff(resolvedNext, resolvedPrev, 0)
	verifyDiff(t, diff, 0, 0, 0, 0, 0, 0, 0)
}

func TestDiffComponentCreationAndAttachDependency(t *testing.T) {
	b := makePolicyBuilder()
	resolvedPrev := resolvePolicy(t, b)

	// add dependency
	d1 := b.AddDependency(b.AddUser(), b.Policy().GetObjectsByKind(lang.ContractObject.Kind)[0].(*lang.Contract))
	d1.Labels["param"] = "value1"
	resolvedNext := resolvePolicy(t, b)

	// diff should contain instantiated component
	diff := NewPolicyResolutionDiff(resolvedNext, resolvedPrev, 0)
	verifyDiff(t, diff, 2, 0, 0, 2, 0, 2, 1)

	// add another dependency
	d2 := b.AddDependency(b.AddUser(), b.Policy().GetObjectsByKind(lang.ContractObject.Kind)[0].(*lang.Contract))
	d2.Labels["param"] = "value1"
	resolvedNextAgain := resolvePolicy(t, b)

	// component should not be instantiated again (it's already there), just new dependency should be attached
	diffAgain := NewPolicyResolutionDiff(resolvedNextAgain, resolvedNext, 0)
	verifyDiff(t, diffAgain, 0, 0, 0, 2, 0, 2, 1)
}

func TestDiffComponentUpdate(t *testing.T) {
	b := makePolicyBuilder()
	resolvedPrev := resolvePolicy(t, b)

	// add dependency
	d1 := b.AddDependency(b.AddUser(), b.Policy().GetObjectsByKind(lang.ContractObject.Kind)[0].(*lang.Contract))
	d1.Labels["param"] = "value1"
	resolvedNext := resolvePolicy(t, b)

	// diff should contain instantiated component
	diff := NewPolicyResolutionDiff(resolvedNext, resolvedPrev, 0)
	verifyDiff(t, diff, 2, 0, 0, 2, 0, 2, 1)

	// update dependency
	d1.Labels["param"] = "value2"
	resolvedNextAgain := resolvePolicy(t, b)

	// component should be updated
	diffAgain := NewPolicyResolutionDiff(resolvedNextAgain, resolvedNext, 0)
	verifyDiff(t, diffAgain, 0, 0, 2, 0, 0, 1, 1)
}

func TestDiffComponentDelete(t *testing.T) {
	b := makePolicyBuilder()
	resolvedPrev := resolvePolicy(t, b)

	// add dependency
	d1 := b.AddDependency(b.AddUser(), b.Policy().GetObjectsByKind(lang.ContractObject.Kind)[0].(*lang.Contract))
	d1.Labels["param"] = "value1"
	resolvedNext := resolvePolicy(t, b)

	// diff should contain instantiated component
	diff := NewPolicyResolutionDiff(resolvedNext, resolvedPrev, 0)
	verifyDiff(t, diff, 2, 0, 0, 2, 0, 2, 1)

	// resolve empty policy
	resolvedEmpty := resolvePolicy(t, builder.NewPolicyBuilder())

	// diff should contain destructed component
	diffAgain := NewPolicyResolutionDiff(resolvedEmpty, resolvedNext, 0)
	verifyDiff(t, diffAgain, 0, 2, 0, 0, 2, 2, 1)
}

/*
	Helpers
*/

func makePolicyBuilder() *builder.PolicyBuilder {
	b := builder.NewPolicyBuilder()

	// create a service
	service := b.AddService()
	b.AddServiceComponent(service,
		b.CodeComponent(
			util.NestedParameterMap{"param": "{{ .Labels.param }}"},
			nil,
		),
	)
	b.AddContract(service, b.CriteriaTrue())

	// add rules to allow all dependencies
	clusterObj := b.AddCluster()
	b.AddRule(b.CriteriaTrue(), b.RuleActions(lang.NewLabelOperationsSetSingleLabel(lang.LabelCluster, clusterObj.Name)))

	return b
}

func resolvePolicy(t *testing.T, builder *builder.PolicyBuilder) *resolve.PolicyResolution {
	t.Helper()
	resolver := resolve.NewPolicyResolver(builder.Policy(), builder.External())
	result, eventLog, err := resolver.ResolveAllDependencies()
	if !assert.NoError(t, err, "Policy should be resolved without errors") {
		hook := &event.HookConsole{}
		eventLog.Save(hook)
		t.FailNow()
	}
	return result
}

func verifyDiff(t *testing.T, diff *PolicyResolutionDiff, componentInstantiate int, componentDestruct int, componentUpdate int, componentAttachDependency int, componentDetachDependency int, componentEndpoints int, clusters int) {
	t.Helper()
	cnt := struct {
		create    int
		update    int
		delete    int
		attach    int
		detach    int
		endpoints int
		clusters  int
	}{}
	s := []string{}
	for _, act := range diff.Actions {
		switch act.(type) {
		case *component.CreateAction:
			cnt.create++
		case *component.DeleteAction:
			cnt.delete++
		case *component.UpdateAction:
			cnt.update++
		case *component.AttachDependencyAction:
			cnt.attach++
		case *component.DetachDependencyAction:
			cnt.detach++
		case *component.EndpointsAction:
			cnt.endpoints++
		case *global.PostProcessAction:
			cnt.clusters++
		default:
			t.Fatalf("Incorrect action type: %T", act)
		}
		s = append(s, fmt.Sprintf("%+v", act))
	}

	ok := assert.Equal(t, componentInstantiate, cnt.create, "Diff: component instantiations")
	ok = ok && assert.Equal(t, componentDestruct, cnt.delete, "Diff: component destructions")
	ok = ok && assert.Equal(t, componentUpdate, cnt.update, "Diff: component updates")
	ok = ok && assert.Equal(t, componentAttachDependency, cnt.attach, "Diff: dependencies attached to components")
	ok = ok && assert.Equal(t, componentDetachDependency, cnt.detach, "Diff: dependencies removed from components")
	ok = ok && assert.Equal(t, componentEndpoints, cnt.endpoints, "Diff: component endpoints")
	ok = ok && assert.Equal(t, clusters, cnt.clusters, "Diff: all clusters post processing")

	if !ok {
		t.Logf("Log of diff actions: %s", s)
		t.FailNow()
	}
}
<commit_msg>clusters -> postprocess<commit_after>package diff

import (
	"fmt"
	"github.com/Aptomi/aptomi/pkg/engine/apply/action/component"
	"github.com/Aptomi/aptomi/pkg/engine/apply/action/global"
	"github.com/Aptomi/aptomi/pkg/engine/resolve"
	"github.com/Aptomi/aptomi/pkg/event"
	"github.com/Aptomi/aptomi/pkg/lang"
	"github.com/Aptomi/aptomi/pkg/lang/builder"
	"github.com/Aptomi/aptomi/pkg/util"
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestDiffEmpty(t *testing.T) {
	b := makePolicyBuilder()
	resolvedPrev := resolvePolicy(t, b)
	resolvedNext := resolvePolicy(t, b)

	// diff should be empty
	diff := NewPolicyResolutionDiff(resolvedNext, resolvedPrev, 0)
	verifyDiff(t, diff, 0, 0, 0, 0, 0, 0, 0)
}

func TestDiffComponentCreationAndAttachDependency(t *testing.T) {
	b := makePolicyBuilder()
	resolvedPrev := resolvePolicy(t, b)

	// add dependency
	d1 := b.AddDependency(b.AddUser(), b.Policy().GetObjectsByKind(lang.ContractObject.Kind)[0].(*lang.Contract))
	d1.Labels["param"] = "value1"
	resolvedNext := resolvePolicy(t, b)

	// diff should contain instantiated component
	diff := NewPolicyResolutionDiff(resolvedNext, resolvedPrev, 0)
	verifyDiff(t, diff, 2, 0, 0, 2, 0, 2, 1)

	// add another dependency
	d2 := b.AddDependency(b.AddUser(), b.Policy().GetObjectsByKind(lang.ContractObject.Kind)[0].(*lang.Contract))
	d2.Labels["param"] = "value1"
	resolvedNextAgain := resolvePolicy(t, b)

	// component should not be instantiated again (it's already there), just new dependency should be attached
	diffAgain := NewPolicyResolutionDiff(resolvedNextAgain, resolvedNext, 0)
	verifyDiff(t, diffAgain, 0, 0, 0, 2, 0, 2, 1)
}

func TestDiffComponentUpdate(t *testing.T) {
	b := makePolicyBuilder()
	resolvedPrev := resolvePolicy(t, b)

	// add dependency
	d1 := b.AddDependency(b.AddUser(), b.Policy().GetObjectsByKind(lang.ContractObject.Kind)[0].(*lang.Contract))
	d1.Labels["param"] = "value1"
	resolvedNext := resolvePolicy(t, b)

	// diff should contain instantiated component
	diff := NewPolicyResolutionDiff(resolvedNext, resolvedPrev, 0)
	verifyDiff(t, diff, 2, 0, 0, 2, 0, 2, 1)

	// update dependency
	d1.Labels["param"] = "value2"
	resolvedNextAgain := resolvePolicy(t, b)

	// component should be updated
	diffAgain := NewPolicyResolutionDiff(resolvedNextAgain, resolvedNext, 0)
	verifyDiff(t, diffAgain, 0, 0, 2, 0, 0, 1, 1)
}

func TestDiffComponentDelete(t *testing.T) {
	b := makePolicyBuilder()
	resolvedPrev := resolvePolicy(t, b)

	// add dependency
	d1 := b.AddDependency(b.AddUser(), b.Policy().GetObjectsByKind(lang.ContractObject.Kind)[0].(*lang.Contract))
	d1.Labels["param"] = "value1"
	resolvedNext := resolvePolicy(t, b)

	// diff should contain instantiated component
	diff := NewPolicyResolutionDiff(resolvedNext, resolvedPrev, 0)
	verifyDiff(t, diff, 2, 0, 0, 2, 0, 2, 1)

	// resolve empty policy
	resolvedEmpty := resolvePolicy(t, builder.NewPolicyBuilder())

	// diff should contain destructed component
	diffAgain := NewPolicyResolutionDiff(resolvedEmpty, resolvedNext, 0)
	verifyDiff(t, diffAgain, 0, 2, 0, 0, 2, 2, 1)
}

/*
	Helpers
*/

func makePolicyBuilder() *builder.PolicyBuilder {
	b := builder.NewPolicyBuilder()

	// create a service
	service := b.AddService()
	b.AddServiceComponent(service,
		b.CodeComponent(
			util.NestedParameterMap{"param": "{{ .Labels.param }}"},
			nil,
		),
	)
	b.AddContract(service, b.CriteriaTrue())

	// add rules to allow all dependencies
	clusterObj := b.AddCluster()
	b.AddRule(b.CriteriaTrue(), b.RuleActions(lang.NewLabelOperationsSetSingleLabel(lang.LabelCluster, clusterObj.Name)))

	return b
}

func resolvePolicy(t *testing.T, builder *builder.PolicyBuilder) *resolve.PolicyResolution {
	t.Helper()
	resolver := resolve.NewPolicyResolver(builder.Policy(), builder.External())
	result, eventLog, err := resolver.ResolveAllDependencies()
	if !assert.NoError(t, err, "Policy should be resolved without errors") {
		hook := &event.HookConsole{}
		eventLog.Save(hook)
		t.FailNow()
	}
	return result
}

func verifyDiff(t *testing.T, diff *PolicyResolutionDiff, componentInstantiate int, componentDestruct int, componentUpdate int, componentAttachDependency int, componentDetachDependency int, componentEndpoints int, clusters int) {
	t.Helper()
	cnt := struct {
		create      int
		update      int
		delete      int
		attach      int
		detach      int
		endpoints   int
		postprocess int
	}{}
	s := []string{}
	for _, act := range diff.Actions {
		switch act.(type) {
		case *component.CreateAction:
			cnt.create++
		case *component.DeleteAction:
			cnt.delete++
		case *component.UpdateAction:
			cnt.update++
		case *component.AttachDependencyAction:
			cnt.attach++
		case *component.DetachDependencyAction:
			cnt.detach++
		case *component.EndpointsAction:
			cnt.endpoints++
		case *global.PostProcessAction:
			cnt.postprocess++
		default:
			t.Fatalf("Incorrect action type: %T", act)
		}
		s = append(s, fmt.Sprintf("%+v", act))
	}

	ok := assert.Equal(t, componentInstantiate, cnt.create, "Diff: component instantiations")
	ok = ok && assert.Equal(t, componentDestruct, cnt.delete, "Diff: component destructions")
	ok = ok && assert.Equal(t, componentUpdate, cnt.update, "Diff: component updates")
	ok = ok && assert.Equal(t, componentAttachDependency, cnt.attach, "Diff: dependencies attached to components")
	ok = ok && assert.Equal(t, componentDetachDependency, cnt.detach, "Diff: dependencies removed from components")
	ok = ok && assert.Equal(t, componentEndpoints, cnt.endpoints, "Diff: component endpoints")
	ok = ok && assert.Equal(t, clusters, cnt.postprocess, "Diff: post processing")

	if !ok {
		t.Logf("Log of diff actions: %s", s)
		t.FailNow()
	}
}
<|endoftext|>


<commit_before>package gwr

import (
	"fmt"
	"io"
)

// DataSource is the interface implemented by all
// data sources.
type DataSource interface {
	// NOTE: implementation is self encoding, but may abstract internally
	Info() DataSourceInfo
	Get(format string, w io.Writer) error
	Watch(format string, w io.Writer) error
}

// DataSourceInfo provides a description of each
// data source, such as name and supported formats.
type DataSourceInfo struct {
	Name    string                 `json:"name"`
	Formats []string               `json:"formats"`
	Attrs   map[string]interface{} `json:"attrs"`
}

// DataSources is a flat collection of DataSources
// with a meta introspection data source.
type DataSources struct {
	sources   map[string]DataSource
	metaNouns metaNounDataSource
}

// NewDataSources creates a DataSources structure
// an sets up its "/meta/nouns" data source.
func NewDataSources() *DataSources {
	dss := &DataSources{}
	dss.init()
	return dss
}

func (dss *DataSources) init() {
	dss.sources = make(map[string]DataSource, 2)
	dss.metaNouns.sources = dss
	dss.AddMarshaledDataSource(&dss.metaNouns)
}

// Info returns a map of all DataSource.Info() data
func (dss *DataSources) Info() map[string]DataSourceInfo {
	info := make(map[string]DataSourceInfo, len(dss.sources))
	for name, ds := range dss.sources {
		info[name] = ds.Info()
	}
	return info
}

// AddMarshaledDataSource adds a generically-marshaled data source. It is a
// convenience for AddDataSource(NewMarshaledDataSource(gds, nil))
func (dss *DataSources) AddMarshaledDataSource(gds GenericDataSource) error {
	mds := NewMarshaledDataSource(gds, nil)
	// TODO: useful to return mds?
	return dss.AddDataSource(mds)
}

// AddDataSource adds a DataSource, if none is
// already defined for the given name.
func (dss *DataSources) AddDataSource(ds DataSource) error {
	info := ds.Info()
	_, ok := dss.sources[info.Name]
	if ok {
		return fmt.Errorf("data source already defined")
	}
	dss.sources[info.Name] = ds
	dss.metaNouns.dataSourceAdded(ds)
	return nil
}

// TODO: do we really need to support removing data sources?  I can see the
// case for intermediaries perhaps, and suspect that is needed... but punting
// for now.
<commit_msg>Add DefaultDataSources<commit_after>package gwr

import (
	"fmt"
	"io"
)

// The default data sources registry which data sources are added to by the
// module-level Add* functions.
var DefaultDataSources DataSources

func init() {
	DefaultDataSources.init()
}

// AddDataSource adds a data source to the default data sources registry.
func AddDataSource(ds DataSource) error {
	return DefaultDataSources.AddDataSource(ds)
}

// AddMarshaledDataSource adds a generically marshaled data source to the
// default data sources registry.
func AddMarshaledDataSource(gds GenericDataSource) error {
	return DefaultDataSources.AddMarshaledDataSource(gds)
}

// DataSource is the interface implemented by all
// data sources.
type DataSource interface {
	// NOTE: implementation is self encoding, but may abstract internally
	Info() DataSourceInfo
	Get(format string, w io.Writer) error
	Watch(format string, w io.Writer) error
}

// DataSourceInfo provides a description of each
// data source, such as name and supported formats.
type DataSourceInfo struct {
	Name    string                 `json:"name"`
	Formats []string               `json:"formats"`
	Attrs   map[string]interface{} `json:"attrs"`
}

// DataSources is a flat collection of DataSources
// with a meta introspection data source.
type DataSources struct {
	sources   map[string]DataSource
	metaNouns metaNounDataSource
}

// NewDataSources creates a DataSources structure
// an sets up its "/meta/nouns" data source.
func NewDataSources() *DataSources {
	dss := &DataSources{}
	dss.init()
	return dss
}

func (dss *DataSources) init() {
	dss.sources = make(map[string]DataSource, 2)
	dss.metaNouns.sources = dss
	dss.AddMarshaledDataSource(&dss.metaNouns)
}

// Info returns a map of all DataSource.Info() data
func (dss *DataSources) Info() map[string]DataSourceInfo {
	info := make(map[string]DataSourceInfo, len(dss.sources))
	for name, ds := range dss.sources {
		info[name] = ds.Info()
	}
	return info
}

// AddMarshaledDataSource adds a generically-marshaled data source. It is a
// convenience for AddDataSource(NewMarshaledDataSource(gds, nil))
func (dss *DataSources) AddMarshaledDataSource(gds GenericDataSource) error {
	mds := NewMarshaledDataSource(gds, nil)
	// TODO: useful to return mds?
	return dss.AddDataSource(mds)
}

// AddDataSource adds a DataSource, if none is
// already defined for the given name.
func (dss *DataSources) AddDataSource(ds DataSource) error {
	info := ds.Info()
	_, ok := dss.sources[info.Name]
	if ok {
		return fmt.Errorf("data source already defined")
	}
	dss.sources[info.Name] = ds
	dss.metaNouns.dataSourceAdded(ds)
	return nil
}

// TODO: do we really need to support removing data sources?  I can see the
// case for intermediaries perhaps, and suspect that is needed... but punting
// for now.
<|endoftext|>


<commit_before>/*
 *  Copyright 2016 Adobe Systems Incorporated. All rights reserved.
 *  This file is licensed to you 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 REPRESENTATIONS
 *  OF ANY KIND, either express or implied. See the License for the specific language
 *  governing permissions and limitations under the License.
 */
package build

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	"github.com/adobe-platform/porter/aws/cloudformation"
	"github.com/adobe-platform/porter/aws_session"
	"github.com/adobe-platform/porter/cfn"
	"github.com/adobe-platform/porter/conf"
	"github.com/adobe-platform/porter/constants"
	"github.com/adobe-platform/porter/hook"
	"github.com/adobe-platform/porter/logger"
	"github.com/adobe-platform/porter/provision"
	"github.com/adobe-platform/porter/provision_output"
	"github.com/phylake/go-cli"
)

var sleepDuration = constants.StackCreationPollInterval()

type (
	ProvisionStackCmd struct{}
)

func (recv *ProvisionStackCmd) Name() string {
	return "provision"
}

func (recv *ProvisionStackCmd) ShortHelp() string {
	return "Provision a new stack"
}

func (recv *ProvisionStackCmd) LongHelp() string {
	return `NAME
    provision -- Provision a new stack

SYNOPSIS
    provision -e <environment out of .porter/config>

DESCRIPTION
    Provision a new stack for a given environment.

    This command is similar to create-stack but it works with multiple regions
    and should be run from a build box.`
}

func (recv *ProvisionStackCmd) SubCommands() []cli.Command {
	return nil
}

func (recv *ProvisionStackCmd) Execute(args []string) bool {

	if len(args) > 0 {
		var environment string
		flagSet := flag.NewFlagSet("", flag.ExitOnError)
		flagSet.StringVar(&environment, "e", "", "")
		flagSet.Usage = func() {
			fmt.Println(recv.LongHelp())
		}
		flagSet.Parse(args)

		ProvisionStack(environment)
		return true
	}

	return false
}

func ProvisionStack(env string) {

	log := logger.CLI("cmd", "build-provision")

	provisionOutput := provision_output.Environment{
		Environment: env,
		Regions:     make([]provision_output.Region, 0),
	}

	config, success := conf.GetAlteredConfig(log)
	if !success {
		os.Exit(1)
	}

	environment, err := config.GetEnvironment(env)
	if err != nil {
		log.Error("GetEnvironment", "Error", err)
		os.Exit(1)
	}

	err = environment.IsWithinBlackoutWindow()
	if err != nil {
		log.Error("Blackout window is active", "Error", err, "Environment", environment.Name)
		os.Exit(1)
	}

	_, err = os.Stat(constants.PayloadPath)
	if err != nil {
		log.Error("Service payload not found", "ServicePayloadPath", constants.PayloadPath, "Error", err)
		os.Exit(1)
	}

	stackArgs := provision.StackArgs{
		Environment: env,
	}

	if !hook.Execute(log, constants.HookPreProvision, env, nil) {
		os.Exit(1)
	}

	stackOutput, success := provision.CreateStack(log, config, stackArgs)
	if !success {
		os.Exit(1)
	}

	regionCount := len(environment.Regions)
	outputChan := make(chan provision_output.Region, regionCount)
	failureChan := make(chan struct{}, regionCount)

	for _, regionOutput := range stackOutput.Regions {
		go provisionStackPoll(environment, regionOutput, outputChan, failureChan)
	}

	commandFailed := false
	for i := 0; i < regionCount; i++ {
		select {
		case regionOutput := <-outputChan:
			provisionOutput.Regions = append(provisionOutput.Regions, regionOutput)
		case _ = <-failureChan:
			commandFailed = true
		}
	}

	if commandFailed {

		if len(provisionOutput.Regions) > 0 {
			log.Warn("Some regions failed to create. Deleting the successful ones")

			for _, pr := range provisionOutput.Regions {
				roleARN, err := environment.GetRoleARN(pr.AWSRegion)
				if err != nil {
					log.Error("GetRoleARN", "Error", err)
					continue
				}

				roleSession := aws_session.STS(pr.AWSRegion, roleARN, 0)
				cfnClient := cloudformation.New(roleSession)

				log.Info("DeleteStack", "StackId", pr.StackId)
				cloudformation.DeleteStack(cfnClient, pr.StackId)
			}
		}

		os.Exit(1)
	}

	provisionBytes, err := json.Marshal(provisionOutput)
	if err != nil {
		log.Error("json.Marshal", "Error", err)
	}

	// write the stackoutput into porter tmp directory
	err = ioutil.WriteFile(constants.ProvisionOutputPath, provisionBytes, 0644)
	if err != nil {
		log.Error("Unable to write provision output", "Error", err)
		os.Exit(1)
	}

	if !hook.Execute(log, constants.HookPostProvision, env, provisionOutput.Regions) {
		os.Exit(1)
	}
}

func provisionStackPoll(environment *conf.Environment, stackRegionOutput provision.CreateStackRegionOutput, outputChan chan provision_output.Region, failureChan chan struct{}) {
	var (
		stackProvisioned bool
		elbLogicalId     string
	)

	log := logger.CLI("cmd", "build-provision", "Region", stackRegionOutput.Region)

	region, err := environment.GetRegion(stackRegionOutput.Region)
	if err != nil {
		log.Error("GetRegion", "Error", err)
		return
	}

	roleARN, err := environment.GetRoleARN(region.Name)
	if err != nil {
		log.Error("GetRoleARN", "Error", err)
		return
	}

	roleSession := aws_session.STS(region.Name, roleARN, constants.StackCreationTimeout())
	cfnClient := cloudformation.New(roleSession)

	n := int(constants.StackCreationTimeout().Seconds() / sleepDuration.Seconds())

stackEventPoll:
	for i := 0; i < n; i++ {

		stackStatus, err := cloudformation.DescribeStack(cfnClient, stackRegionOutput.StackId)
		if err != nil {
			log.Error("DescribeStack", "Error", err)
			failureChan <- struct{}{}
			return
		}
		if stackStatus == nil || len(stackStatus.Stacks) != 1 {
			log.Error("unexpected stack status")
			failureChan <- struct{}{}
			return
		}

		log.Info("Stack status", "StackStatus", *stackStatus.Stacks[0].StackStatus)

		switch *stackStatus.Stacks[0].StackStatus {
		case "CREATE_COMPLETE":
			stackProvisioned = true
			break stackEventPoll
		case "CREATE_FAILED":
			log.Error("Stack creation failed")
			failureChan <- struct{}{}
			return
		case "DELETE_IN_PROGRESS":
			log.Error("Stack is being deleted")
			failureChan <- struct{}{}
			return
		case "ROLLBACK_IN_PROGRESS":
			log.Error("Stack is rolling back")
			failureChan <- struct{}{}
			return
		}

		time.Sleep(sleepDuration)
	}

	if !stackProvisioned {
		log.Error("stack provision timeout")
		failureChan <- struct{}{}
		return
	}

	cfnTemplateByte, err := ioutil.ReadFile(constants.CloudFormationTemplatePath)
	if err != nil {
		log.Error("CloudFormationTemplate read file error", "Error", err)
	}

	cfnTemplate := cfn.NewTemplate()

	err = json.Unmarshal(cfnTemplateByte, &cfnTemplate)
	if err != nil {
		log.Error("json unmarshal error on cfn template", "Error", err)
		failureChan <- struct{}{}
		return
	}

	cfnTemplate.ParseResources()

	elbLogicalId, err = cfnTemplate.GetResourceName(cfn.ElasticLoadBalancing_LoadBalancer)
	if err != nil {
		log.Error("GetResourceName", "Error", err)
		failureChan <- struct{}{}
		return
	}

	//Once stack provisioned get the provisoned elb
	physicalResourceID, err := cloudformation.DescribeStackResource(cfnClient, stackRegionOutput.StackId, elbLogicalId)

	if err != nil {
		log.Error("Error on getting physicalResourceId", "Error", err)
		failureChan <- struct{}{}
		return
	}

	provisionDetails := provision_output.Region{
		AWSRegion:          region.Name,
		StackId:            stackRegionOutput.StackId,
		ProvisionedELBName: physicalResourceID,
	}

	outputChan <- provisionDetails

}
<commit_msg>Retry DescribeStackResource calls in provision<commit_after>/*
 *  Copyright 2016 Adobe Systems Incorporated. All rights reserved.
 *  This file is licensed to you 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 REPRESENTATIONS
 *  OF ANY KIND, either express or implied. See the License for the specific language
 *  governing permissions and limitations under the License.
 */
package build

import (
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"time"

	"github.com/adobe-platform/porter/aws/cloudformation"
	"github.com/adobe-platform/porter/aws_session"
	"github.com/adobe-platform/porter/cfn"
	"github.com/adobe-platform/porter/conf"
	"github.com/adobe-platform/porter/constants"
	"github.com/adobe-platform/porter/hook"
	"github.com/adobe-platform/porter/logger"
	"github.com/adobe-platform/porter/provision"
	"github.com/adobe-platform/porter/provision_output"
	"github.com/adobe-platform/porter/util"
	"github.com/phylake/go-cli"
)

var sleepDuration = constants.StackCreationPollInterval()

type (
	ProvisionStackCmd struct{}
)

func (recv *ProvisionStackCmd) Name() string {
	return "provision"
}

func (recv *ProvisionStackCmd) ShortHelp() string {
	return "Provision a new stack"
}

func (recv *ProvisionStackCmd) LongHelp() string {
	return `NAME
    provision -- Provision a new stack

SYNOPSIS
    provision -e <environment out of .porter/config>

DESCRIPTION
    Provision a new stack for a given environment.

    This command is similar to create-stack but it works with multiple regions
    and should be run from a build box.`
}

func (recv *ProvisionStackCmd) SubCommands() []cli.Command {
	return nil
}

func (recv *ProvisionStackCmd) Execute(args []string) bool {

	if len(args) > 0 {
		var environment string
		flagSet := flag.NewFlagSet("", flag.ExitOnError)
		flagSet.StringVar(&environment, "e", "", "")
		flagSet.Usage = func() {
			fmt.Println(recv.LongHelp())
		}
		flagSet.Parse(args)

		ProvisionStack(environment)
		return true
	}

	return false
}

func ProvisionStack(env string) {

	log := logger.CLI("cmd", "build-provision")

	provisionOutput := provision_output.Environment{
		Environment: env,
		Regions:     make([]provision_output.Region, 0),
	}

	config, success := conf.GetAlteredConfig(log)
	if !success {
		os.Exit(1)
	}

	environment, err := config.GetEnvironment(env)
	if err != nil {
		log.Error("GetEnvironment", "Error", err)
		os.Exit(1)
	}

	err = environment.IsWithinBlackoutWindow()
	if err != nil {
		log.Error("Blackout window is active", "Error", err, "Environment", environment.Name)
		os.Exit(1)
	}

	_, err = os.Stat(constants.PayloadPath)
	if err != nil {
		log.Error("Service payload not found", "ServicePayloadPath", constants.PayloadPath, "Error", err)
		os.Exit(1)
	}

	stackArgs := provision.StackArgs{
		Environment: env,
	}

	if !hook.Execute(log, constants.HookPreProvision, env, nil) {
		os.Exit(1)
	}

	stackOutput, success := provision.CreateStack(log, config, stackArgs)
	if !success {
		os.Exit(1)
	}

	regionCount := len(environment.Regions)
	outputChan := make(chan provision_output.Region, regionCount)
	failureChan := make(chan struct{}, regionCount)

	for _, regionOutput := range stackOutput.Regions {
		go provisionStackPoll(environment, regionOutput, outputChan, failureChan)
	}

	commandFailed := false
	for i := 0; i < regionCount; i++ {
		select {
		case regionOutput := <-outputChan:
			provisionOutput.Regions = append(provisionOutput.Regions, regionOutput)
		case _ = <-failureChan:
			commandFailed = true
		}
	}

	if commandFailed {

		if len(provisionOutput.Regions) > 0 {
			log.Warn("Some regions failed to create. Deleting the successful ones")

			for _, pr := range provisionOutput.Regions {
				roleARN, err := environment.GetRoleARN(pr.AWSRegion)
				if err != nil {
					log.Error("GetRoleARN", "Error", err)
					continue
				}

				roleSession := aws_session.STS(pr.AWSRegion, roleARN, 0)
				cfnClient := cloudformation.New(roleSession)

				log.Info("DeleteStack", "StackId", pr.StackId)
				cloudformation.DeleteStack(cfnClient, pr.StackId)
			}
		}

		os.Exit(1)
	}

	provisionBytes, err := json.Marshal(provisionOutput)
	if err != nil {
		log.Error("json.Marshal", "Error", err)
	}

	// write the stackoutput into porter tmp directory
	err = ioutil.WriteFile(constants.ProvisionOutputPath, provisionBytes, 0644)
	if err != nil {
		log.Error("Unable to write provision output", "Error", err)
		os.Exit(1)
	}

	if !hook.Execute(log, constants.HookPostProvision, env, provisionOutput.Regions) {
		os.Exit(1)
	}
}

func provisionStackPoll(environment *conf.Environment, stackRegionOutput provision.CreateStackRegionOutput, outputChan chan provision_output.Region, failureChan chan struct{}) {
	var (
		stackProvisioned   bool
		elbLogicalId       string
		physicalResourceID string
	)

	log := logger.CLI("cmd", "build-provision", "Region", stackRegionOutput.Region)

	region, err := environment.GetRegion(stackRegionOutput.Region)
	if err != nil {
		log.Error("GetRegion", "Error", err)
		return
	}

	roleARN, err := environment.GetRoleARN(region.Name)
	if err != nil {
		log.Error("GetRoleARN", "Error", err)
		return
	}

	roleSession := aws_session.STS(region.Name, roleARN, constants.StackCreationTimeout())
	cfnClient := cloudformation.New(roleSession)

	n := int(constants.StackCreationTimeout().Seconds() / sleepDuration.Seconds())

stackEventPoll:
	for i := 0; i < n; i++ {

		stackStatus, err := cloudformation.DescribeStack(cfnClient, stackRegionOutput.StackId)
		if err != nil {
			log.Error("DescribeStack", "Error", err)
			failureChan <- struct{}{}
			return
		}
		if stackStatus == nil || len(stackStatus.Stacks) != 1 {
			log.Error("unexpected stack status")
			failureChan <- struct{}{}
			return
		}

		log.Info("Stack status", "StackStatus", *stackStatus.Stacks[0].StackStatus)

		switch *stackStatus.Stacks[0].StackStatus {
		case "CREATE_COMPLETE":
			stackProvisioned = true
			break stackEventPoll
		case "CREATE_FAILED":
			log.Error("Stack creation failed")
			failureChan <- struct{}{}
			return
		case "DELETE_IN_PROGRESS":
			log.Error("Stack is being deleted")
			failureChan <- struct{}{}
			return
		case "ROLLBACK_IN_PROGRESS":
			log.Error("Stack is rolling back")
			failureChan <- struct{}{}
			return
		}

		time.Sleep(sleepDuration)
	}

	if !stackProvisioned {
		log.Error("stack provision timeout")
		failureChan <- struct{}{}
		return
	}

	cfnTemplateByte, err := ioutil.ReadFile(constants.CloudFormationTemplatePath)
	if err != nil {
		log.Error("CloudFormationTemplate read file error", "Error", err)
	}

	cfnTemplate := cfn.NewTemplate()

	err = json.Unmarshal(cfnTemplateByte, &cfnTemplate)
	if err != nil {
		log.Error("json unmarshal error on cfn template", "Error", err)
		failureChan <- struct{}{}
		return
	}

	cfnTemplate.ParseResources()

	elbLogicalId, err = cfnTemplate.GetResourceName(cfn.ElasticLoadBalancing_LoadBalancer)
	if err != nil {
		log.Error("GetResourceName", "Error", err)
		failureChan <- struct{}{}
		return
	}

	//Once stack provisioned get the provisoned elb
	retryMsg := func(i int) { log.Warn("DescribeStackResource retrying", "Count", i) }
	if !util.SuccessRetryer(9, retryMsg, func() bool {
		physicalResourceID, err = cloudformation.DescribeStackResource(cfnClient, stackRegionOutput.StackId, elbLogicalId)
		if err != nil {
			log.Error("Error on getting physicalResourceId", "Error", err)
			return false
		}
		return true
	}) {
		failureChan <- struct{}{}
		return
	}

	provisionDetails := provision_output.Region{
		AWSRegion:          region.Name,
		StackId:            stackRegionOutput.StackId,
		ProvisionedELBName: physicalResourceID,
	}

	outputChan <- provisionDetails

}
<|endoftext|>


<commit_before>// Copyright © 2015,2016 Phil Pennock.
// All rights reserved, except as granted under license.
// Licensed per file LICENSE.txt

package version

import (
	"fmt"
	"runtime"

	"github.com/spf13/cobra"

	"github.com/philpennock/character/commands/root"
)

// VersionString is expected to be set by the linker during build.
// If make(1) is used for build, this will happen.
var VersionString string

// Library version functions should be defined in other files in this dir,
// under appropriate build-tag constraints, and those files should use
// the add function below in their init() routines.  Each function should
// return a short library name, and any lines of output for versioning.
// If the short library name is empty, then the library's name is assumed
// to be embedded in the output lines already.
var libraryVersionFuncs []func() (string, []string)

func addLibraryVersionFunc(f func() (string, []string)) {
	libraryVersionFuncs = append(libraryVersionFuncs, f)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "show version of character",
	Run: func(cmd *cobra.Command, args []string) {
		if VersionString == "" {
			VersionString = "<unknown>"
		}
		fmt.Printf("%s: version %s\n", cmd.Root().Name(), VersionString)
		fmt.Printf("Golang: Runtime: %s\n", runtime.Version())
		for _, f := range libraryVersionFuncs {
			name, infoLines := f()
			for _, l := range infoLines {
				if name != "" {
					fmt.Printf("%s: %s\n", name, l)
				} else {
					fmt.Printf("%s\n", l)
				}
			}
		}
	},
}

func init() {
	root.AddCommand(versionCmd)
}
<commit_msg>Source URL as part of version output<commit_after>// Copyright © 2015,2016 Phil Pennock.
// All rights reserved, except as granted under license.
// Licensed per file LICENSE.txt

package version

import (
	"fmt"
	"runtime"

	"github.com/spf13/cobra"

	"github.com/philpennock/character/commands/root"
)

// SourceURL is so that the version command identifies where this came from.
// It can be overriden at link time, but is not expected to be.
var SourceURL = "https://github.com/philpennock/character"

// VersionString is expected to be set by the linker during build.
// If make(1) is used for build, this will happen.
var VersionString string

// Library version functions should be defined in other files in this dir,
// under appropriate build-tag constraints, and those files should use
// the add function below in their init() routines.  Each function should
// return a short library name, and any lines of output for versioning.
// If the short library name is empty, then the library's name is assumed
// to be embedded in the output lines already.
var libraryVersionFuncs []func() (string, []string)

func addLibraryVersionFunc(f func() (string, []string)) {
	libraryVersionFuncs = append(libraryVersionFuncs, f)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "show version of character",
	Run: func(cmd *cobra.Command, args []string) {
		if VersionString == "" {
			VersionString = "<unknown>"
		}
		fmt.Printf("%s: version %s\n", cmd.Root().Name(), VersionString)
		fmt.Printf("Golang: Runtime: %s\n", runtime.Version())
		for _, f := range libraryVersionFuncs {
			name, infoLines := f()
			for _, l := range infoLines {
				if name != "" {
					fmt.Printf("%s: %s\n", name, l)
				} else {
					fmt.Printf("%s\n", l)
				}
			}
		}
		fmt.Printf("%s: Source URL <%s>\n", cmd.Root().Name(), SourceURL)
	},
}

func init() {
	root.AddCommand(versionCmd)
}
<|endoftext|>