<commit_before>// Package vector implements persistent vector.
package vector

import (
	"bytes"
	"encoding/json"
	"fmt"
)

const (
	chunkBits  = 5
	nodeSize   = 1 << chunkBits
	tailMaxLen = nodeSize
	chunkMask  = nodeSize - 1
)

// Vector is a persistent sequential container for arbitrary values. It supports
// O(1) lookup by index, modification by index, and insertion and removal
// operations at the end. Being a persistent variant of the data structure, it
// is immutable, and provides O(1) operations to create modified versions of the
// vector that shares the underlying data structure, making it suitable for
// concurrent access. The empty value is a valid empty vector.
type Vector interface {
	json.Marshaler
	// Len returns the length of the vector.
	Len() int
	// Index returns the i-th element of the vector, if it exists. The second
	// return value indicates whether the element exists.
	Index(i int) (interface{}, bool)
	// Assoc returns an almost identical Vector, with the i-th element
	// replaced. If the index is smaller than 0 or greater than the length of
	// the vector, it returns nil. If the index is equal to the size of the
	// vector, it is equivalent to Cons.
	Assoc(i int, val interface{}) Vector
	// Cons returns an almost identical Vector, with an additional element
	// appended to the end.
	Cons(val interface{}) Vector
	// Pop returns an almost identical Vector, with the last element removed. It
	// returns nil if the vector is already empty.
	Pop() Vector
	// SubVector returns a subvector containing the elements from i up to but
	// not including j.
	SubVector(i, j int) Vector
	// Iterator returns an iterator over the vector.
	Iterator() Iterator
}

// Iterator is an iterator over vector elements. It can be used like this:
//
//     for it := v.Iterator(); it.HasElem(); it.Next() {
//         elem := it.Elem()
//         // do something with elem...
//     }
type Iterator interface {
	// Elem returns the element at the current position.
	Elem() interface{}
	// HasElem returns whether the iterator is pointing to an element.
	HasElem() bool
	// Next moves the iterator to the next position.
	Next()
}

type vector struct {
	count int
	// height of the tree structure, defined to be 0 when root is a leaf.
	height uint
	root   node
	tail   []interface{}
}

// Empty is an empty Vector.
var Empty Vector = &vector{}

// node is a node in the vector tree. It is always of the size nodeSize.
type node *[nodeSize]interface{}

func newNode() node {
	return node(&[nodeSize]interface{}{})
}

func clone(n node) node {
	a := *n
	return node(&a)
}

func nodeFromSlice(s []interface{}) node {
	var n [nodeSize]interface{}
	copy(n[:], s)
	return &n
}

// Count returns the number of elements in a Vector.
func (v *vector) Len() int {
	return v.count
}

// treeSize returns the number of elements stored in the tree (as opposed to the
// tail).
func (v *vector) treeSize() int {
	if v.count < tailMaxLen {
		return 0
	}
	return ((v.count - 1) >> chunkBits) << chunkBits
}

func (v *vector) Index(i int) (interface{}, bool) {
	if i < 0 || i >= v.count {
		return nil, false
	}

	// The following is very similar to sliceFor, but is implemented separately
	// to avoid unncessary copying.
	if i >= v.treeSize() {
		return v.tail[i&chunkMask], true
	}
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		n = n[(i>>shift)&chunkMask].(node)
	}
	return n[i&chunkMask], true
}

// sliceFor returns the slice where the i-th element is stored. The index must
// be in bound.
func (v *vector) sliceFor(i int) []interface{} {
	if i >= v.treeSize() {
		return v.tail
	}
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		n = n[(i>>shift)&chunkMask].(node)
	}
	return n[:]
}

func (v *vector) Assoc(i int, val interface{}) Vector {
	if i < 0 || i > v.count {
		return nil
	} else if i == v.count {
		return v.Cons(val)
	}
	if i >= v.treeSize() {
		newTail := append([]interface{}(nil), v.tail...)
		newTail[i&chunkMask] = val
		return &vector{v.count, v.height, v.root, newTail}
	}
	return &vector{v.count, v.height, doAssoc(v.height, v.root, i, val), v.tail}
}

// doAssoc returns an almost identical tree, with the i-th element replaced by
// val.
func doAssoc(height uint, n node, i int, val interface{}) node {
	m := clone(n)
	if height == 0 {
		m[i&chunkMask] = val
	} else {
		sub := (i >> (height * chunkBits)) & chunkMask
		m[sub] = doAssoc(height-1, m[sub].(node), i, val)
	}
	return m
}

func (v *vector) Cons(val interface{}) Vector {
	// Room in tail?
	if v.count-v.treeSize() < tailMaxLen {
		newTail := make([]interface{}, len(v.tail)+1)
		copy(newTail, v.tail)
		newTail[len(v.tail)] = val
		return &vector{v.count + 1, v.height, v.root, newTail}
	}
	// Full tail; push into tree.
	tailNode := nodeFromSlice(v.tail)
	newHeight := v.height
	var newRoot node
	// Overflow root?
	if (v.count >> chunkBits) > (1 << (v.height * chunkBits)) {
		newRoot = newNode()
		newRoot[0] = v.root
		newRoot[1] = newPath(v.height, tailNode)
		newHeight++
	} else {
		newRoot = v.pushTail(v.height, v.root, tailNode)
	}
	return &vector{v.count + 1, newHeight, newRoot, []interface{}{val}}
}

// pushTail returns a tree with tail appended.
func (v *vector) pushTail(height uint, n node, tail node) node {
	if height == 0 {
		return tail
	}
	idx := ((v.count - 1) >> (height * chunkBits)) & chunkMask
	m := clone(n)
	child := n[idx]
	if child == nil {
		m[idx] = newPath(height-1, tail)
	} else {
		m[idx] = v.pushTail(height-1, child.(node), tail)
	}
	return m
}

// newPath creates a left-branching tree of specified height and leaf.
func newPath(height uint, leaf node) node {
	if height == 0 {
		return leaf
	}
	ret := newNode()
	ret[0] = newPath(height-1, leaf)
	return ret
}

func (v *vector) Pop() Vector {
	switch v.count {
	case 0:
		return nil
	case 1:
		return Empty
	}
	if v.count-v.treeSize() > 1 {
		newTail := make([]interface{}, len(v.tail)-1)
		copy(newTail, v.tail)
		return &vector{v.count - 1, v.height, v.root, newTail}
	}
	newTail := v.sliceFor(v.count - 2)
	newRoot := v.popTail(v.height, v.root)
	newHeight := v.height
	if v.height > 0 && newRoot[1] == nil {
		newRoot = newRoot[0].(node)
		newHeight--
	}
	return &vector{v.count - 1, newHeight, newRoot, newTail}
}

// popTail returns a new tree with the last leaf removed.
func (v *vector) popTail(level uint, n node) node {
	idx := ((v.count - 2) >> (level * chunkBits)) & chunkMask
	if level > 1 {
		newChild := v.popTail(level-1, n[idx].(node))
		if newChild == nil && idx == 0 {
			return nil
		}
		m := clone(n)
		if newChild == nil {
			// This is needed since `m[idx] = newChild` would store an
			// interface{} with a non-nil type part, which is non-nil
			m[idx] = nil
		} else {
			m[idx] = newChild
		}
		return m
	} else if idx == 0 {
		return nil
	} else {
		m := clone(n)
		m[idx] = nil
		return m
	}
}

func (v *vector) SubVector(begin, end int) Vector {
	if begin < 0 || begin > end || end > v.count {
		return nil
	}
	return &subVector{v, begin, end}
}

func (v *vector) Iterator() Iterator {
	return newIterator(v)
}

func (v *vector) MarshalJSON() ([]byte, error) {
	return marshalJSON(v.Iterator())
}

type subVector struct {
	v     *vector
	begin int
	end   int
}

func (s *subVector) Len() int {
	return s.end - s.begin
}

func (s *subVector) Index(i int) (interface{}, bool) {
	if i < 0 || s.begin+i >= s.end {
		return nil, false
	}
	return s.v.Index(s.begin + i)
}

func (s *subVector) Assoc(i int, val interface{}) Vector {
	if i < 0 || s.begin+i > s.end {
		return nil
	} else if s.begin+i == s.end {
		return s.Cons(val)
	}
	return s.v.Assoc(s.begin+i, val).SubVector(s.begin, s.end)
}

func (s *subVector) Cons(val interface{}) Vector {
	return s.v.Assoc(s.end, val).SubVector(s.begin, s.end+1)
}

func (s *subVector) Pop() Vector {
	switch s.Len() {
	case 0:
		return nil
	case 1:
		return Empty
	default:
		return s.v.SubVector(s.begin, s.end-1)
	}
}

func (s *subVector) SubVector(i, j int) Vector {
	return s.v.SubVector(s.begin+i, s.begin+j)
}

func (s *subVector) Iterator() Iterator {
	return newIteratorWithRange(s.v, s.begin, s.end)
}

func (s *subVector) MarshalJSON() ([]byte, error) {
	return marshalJSON(s.Iterator())
}

type iterator struct {
	v        *vector
	treeSize int
	index    int
	end      int
	path     []pathEntry
}

type pathEntry struct {
	node  node
	index int
}

func (e pathEntry) current() interface{} {
	return e.node[e.index]
}

func newIterator(v *vector) *iterator {
	return newIteratorWithRange(v, 0, v.Len())
}

func newIteratorWithRange(v *vector, begin, end int) *iterator {
	it := &iterator{v, v.treeSize(), begin, end, nil}
	if it.index >= it.treeSize {
		return it
	}
	// Find the node for begin, remembering all nodes along the path.
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		idx := (begin >> shift) & chunkMask
		it.path = append(it.path, pathEntry{n, idx})
		n = n[idx].(node)
	}
	it.path = append(it.path, pathEntry{n, begin & chunkMask})
	return it
}

func (it *iterator) Elem() interface{} {
	if it.index >= it.treeSize {
		return it.v.tail[it.index-it.treeSize]
	}
	return it.path[len(it.path)-1].current()
}

func (it *iterator) HasElem() bool {
	return it.index < it.end
}

func (it *iterator) Next() {
	if it.index+1 >= it.treeSize {
		// Next element is in tail. Just increment the index.
		it.index++
		return
	}
	// Find the deepest level that can be advanced.
	var i int
	for i = len(it.path) - 1; i >= 0; i-- {
		e := it.path[i]
		if e.index+1 < len(e.node) {
			break
		}
	}
	if i == -1 {
		panic("cannot advance; vector iterator bug")
	}
	// Advance on this node, and re-populate all deeper levels.
	it.path[i].index++
	for i++; i < len(it.path); i++ {
		it.path[i] = pathEntry{it.path[i-1].current().(node), 0}
	}
	it.index++
}

type marshalError struct {
	index int
	cause error
}

func (err *marshalError) Error() string {
	return fmt.Sprintf("element %d: %s", err.index, err.cause)
}

func marshalJSON(it Iterator) ([]byte, error) {
	var buf bytes.Buffer
	buf.WriteByte('[')
	index := 0
	for ; it.HasElem(); it.Next() {
		if index > 0 {
			buf.WriteByte(',')
		}
		elemBytes, err := json.Marshal(it.Elem())
		if err != nil {
			return nil, &marshalError{index, err}
		}
		buf.Write(elemBytes)
		index++
	}
	buf.WriteByte(']')
	return buf.Bytes(), nil
}
<commit_msg>Add more info in the vector package's godoc.<commit_after>// Package vector implements persistent vector.
//
// This is a Go clone of Clojure's PersistentVector type
// (https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentVector.java).
// For an introduction to the internals, see
// https://hypirion.com/musings/understanding-persistent-vector-pt-1.
package vector

import (
	"bytes"
	"encoding/json"
	"fmt"
)

const (
	chunkBits  = 5
	nodeSize   = 1 << chunkBits
	tailMaxLen = nodeSize
	chunkMask  = nodeSize - 1
)

// Vector is a persistent sequential container for arbitrary values. It supports
// O(1) lookup by index, modification by index, and insertion and removal
// operations at the end. Being a persistent variant of the data structure, it
// is immutable, and provides O(1) operations to create modified versions of the
// vector that shares the underlying data structure, making it suitable for
// concurrent access. The empty value is a valid empty vector.
type Vector interface {
	json.Marshaler
	// Len returns the length of the vector.
	Len() int
	// Index returns the i-th element of the vector, if it exists. The second
	// return value indicates whether the element exists.
	Index(i int) (interface{}, bool)
	// Assoc returns an almost identical Vector, with the i-th element
	// replaced. If the index is smaller than 0 or greater than the length of
	// the vector, it returns nil. If the index is equal to the size of the
	// vector, it is equivalent to Cons.
	Assoc(i int, val interface{}) Vector
	// Cons returns an almost identical Vector, with an additional element
	// appended to the end.
	Cons(val interface{}) Vector
	// Pop returns an almost identical Vector, with the last element removed. It
	// returns nil if the vector is already empty.
	Pop() Vector
	// SubVector returns a subvector containing the elements from i up to but
	// not including j.
	SubVector(i, j int) Vector
	// Iterator returns an iterator over the vector.
	Iterator() Iterator
}

// Iterator is an iterator over vector elements. It can be used like this:
//
//     for it := v.Iterator(); it.HasElem(); it.Next() {
//         elem := it.Elem()
//         // do something with elem...
//     }
type Iterator interface {
	// Elem returns the element at the current position.
	Elem() interface{}
	// HasElem returns whether the iterator is pointing to an element.
	HasElem() bool
	// Next moves the iterator to the next position.
	Next()
}

type vector struct {
	count int
	// height of the tree structure, defined to be 0 when root is a leaf.
	height uint
	root   node
	tail   []interface{}
}

// Empty is an empty Vector.
var Empty Vector = &vector{}

// node is a node in the vector tree. It is always of the size nodeSize.
type node *[nodeSize]interface{}

func newNode() node {
	return node(&[nodeSize]interface{}{})
}

func clone(n node) node {
	a := *n
	return node(&a)
}

func nodeFromSlice(s []interface{}) node {
	var n [nodeSize]interface{}
	copy(n[:], s)
	return &n
}

// Count returns the number of elements in a Vector.
func (v *vector) Len() int {
	return v.count
}

// treeSize returns the number of elements stored in the tree (as opposed to the
// tail).
func (v *vector) treeSize() int {
	if v.count < tailMaxLen {
		return 0
	}
	return ((v.count - 1) >> chunkBits) << chunkBits
}

func (v *vector) Index(i int) (interface{}, bool) {
	if i < 0 || i >= v.count {
		return nil, false
	}

	// The following is very similar to sliceFor, but is implemented separately
	// to avoid unncessary copying.
	if i >= v.treeSize() {
		return v.tail[i&chunkMask], true
	}
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		n = n[(i>>shift)&chunkMask].(node)
	}
	return n[i&chunkMask], true
}

// sliceFor returns the slice where the i-th element is stored. The index must
// be in bound.
func (v *vector) sliceFor(i int) []interface{} {
	if i >= v.treeSize() {
		return v.tail
	}
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		n = n[(i>>shift)&chunkMask].(node)
	}
	return n[:]
}

func (v *vector) Assoc(i int, val interface{}) Vector {
	if i < 0 || i > v.count {
		return nil
	} else if i == v.count {
		return v.Cons(val)
	}
	if i >= v.treeSize() {
		newTail := append([]interface{}(nil), v.tail...)
		newTail[i&chunkMask] = val
		return &vector{v.count, v.height, v.root, newTail}
	}
	return &vector{v.count, v.height, doAssoc(v.height, v.root, i, val), v.tail}
}

// doAssoc returns an almost identical tree, with the i-th element replaced by
// val.
func doAssoc(height uint, n node, i int, val interface{}) node {
	m := clone(n)
	if height == 0 {
		m[i&chunkMask] = val
	} else {
		sub := (i >> (height * chunkBits)) & chunkMask
		m[sub] = doAssoc(height-1, m[sub].(node), i, val)
	}
	return m
}

func (v *vector) Cons(val interface{}) Vector {
	// Room in tail?
	if v.count-v.treeSize() < tailMaxLen {
		newTail := make([]interface{}, len(v.tail)+1)
		copy(newTail, v.tail)
		newTail[len(v.tail)] = val
		return &vector{v.count + 1, v.height, v.root, newTail}
	}
	// Full tail; push into tree.
	tailNode := nodeFromSlice(v.tail)
	newHeight := v.height
	var newRoot node
	// Overflow root?
	if (v.count >> chunkBits) > (1 << (v.height * chunkBits)) {
		newRoot = newNode()
		newRoot[0] = v.root
		newRoot[1] = newPath(v.height, tailNode)
		newHeight++
	} else {
		newRoot = v.pushTail(v.height, v.root, tailNode)
	}
	return &vector{v.count + 1, newHeight, newRoot, []interface{}{val}}
}

// pushTail returns a tree with tail appended.
func (v *vector) pushTail(height uint, n node, tail node) node {
	if height == 0 {
		return tail
	}
	idx := ((v.count - 1) >> (height * chunkBits)) & chunkMask
	m := clone(n)
	child := n[idx]
	if child == nil {
		m[idx] = newPath(height-1, tail)
	} else {
		m[idx] = v.pushTail(height-1, child.(node), tail)
	}
	return m
}

// newPath creates a left-branching tree of specified height and leaf.
func newPath(height uint, leaf node) node {
	if height == 0 {
		return leaf
	}
	ret := newNode()
	ret[0] = newPath(height-1, leaf)
	return ret
}

func (v *vector) Pop() Vector {
	switch v.count {
	case 0:
		return nil
	case 1:
		return Empty
	}
	if v.count-v.treeSize() > 1 {
		newTail := make([]interface{}, len(v.tail)-1)
		copy(newTail, v.tail)
		return &vector{v.count - 1, v.height, v.root, newTail}
	}
	newTail := v.sliceFor(v.count - 2)
	newRoot := v.popTail(v.height, v.root)
	newHeight := v.height
	if v.height > 0 && newRoot[1] == nil {
		newRoot = newRoot[0].(node)
		newHeight--
	}
	return &vector{v.count - 1, newHeight, newRoot, newTail}
}

// popTail returns a new tree with the last leaf removed.
func (v *vector) popTail(level uint, n node) node {
	idx := ((v.count - 2) >> (level * chunkBits)) & chunkMask
	if level > 1 {
		newChild := v.popTail(level-1, n[idx].(node))
		if newChild == nil && idx == 0 {
			return nil
		}
		m := clone(n)
		if newChild == nil {
			// This is needed since `m[idx] = newChild` would store an
			// interface{} with a non-nil type part, which is non-nil
			m[idx] = nil
		} else {
			m[idx] = newChild
		}
		return m
	} else if idx == 0 {
		return nil
	} else {
		m := clone(n)
		m[idx] = nil
		return m
	}
}

func (v *vector) SubVector(begin, end int) Vector {
	if begin < 0 || begin > end || end > v.count {
		return nil
	}
	return &subVector{v, begin, end}
}

func (v *vector) Iterator() Iterator {
	return newIterator(v)
}

func (v *vector) MarshalJSON() ([]byte, error) {
	return marshalJSON(v.Iterator())
}

type subVector struct {
	v     *vector
	begin int
	end   int
}

func (s *subVector) Len() int {
	return s.end - s.begin
}

func (s *subVector) Index(i int) (interface{}, bool) {
	if i < 0 || s.begin+i >= s.end {
		return nil, false
	}
	return s.v.Index(s.begin + i)
}

func (s *subVector) Assoc(i int, val interface{}) Vector {
	if i < 0 || s.begin+i > s.end {
		return nil
	} else if s.begin+i == s.end {
		return s.Cons(val)
	}
	return s.v.Assoc(s.begin+i, val).SubVector(s.begin, s.end)
}

func (s *subVector) Cons(val interface{}) Vector {
	return s.v.Assoc(s.end, val).SubVector(s.begin, s.end+1)
}

func (s *subVector) Pop() Vector {
	switch s.Len() {
	case 0:
		return nil
	case 1:
		return Empty
	default:
		return s.v.SubVector(s.begin, s.end-1)
	}
}

func (s *subVector) SubVector(i, j int) Vector {
	return s.v.SubVector(s.begin+i, s.begin+j)
}

func (s *subVector) Iterator() Iterator {
	return newIteratorWithRange(s.v, s.begin, s.end)
}

func (s *subVector) MarshalJSON() ([]byte, error) {
	return marshalJSON(s.Iterator())
}

type iterator struct {
	v        *vector
	treeSize int
	index    int
	end      int
	path     []pathEntry
}

type pathEntry struct {
	node  node
	index int
}

func (e pathEntry) current() interface{} {
	return e.node[e.index]
}

func newIterator(v *vector) *iterator {
	return newIteratorWithRange(v, 0, v.Len())
}

func newIteratorWithRange(v *vector, begin, end int) *iterator {
	it := &iterator{v, v.treeSize(), begin, end, nil}
	if it.index >= it.treeSize {
		return it
	}
	// Find the node for begin, remembering all nodes along the path.
	n := v.root
	for shift := v.height * chunkBits; shift > 0; shift -= chunkBits {
		idx := (begin >> shift) & chunkMask
		it.path = append(it.path, pathEntry{n, idx})
		n = n[idx].(node)
	}
	it.path = append(it.path, pathEntry{n, begin & chunkMask})
	return it
}

func (it *iterator) Elem() interface{} {
	if it.index >= it.treeSize {
		return it.v.tail[it.index-it.treeSize]
	}
	return it.path[len(it.path)-1].current()
}

func (it *iterator) HasElem() bool {
	return it.index < it.end
}

func (it *iterator) Next() {
	if it.index+1 >= it.treeSize {
		// Next element is in tail. Just increment the index.
		it.index++
		return
	}
	// Find the deepest level that can be advanced.
	var i int
	for i = len(it.path) - 1; i >= 0; i-- {
		e := it.path[i]
		if e.index+1 < len(e.node) {
			break
		}
	}
	if i == -1 {
		panic("cannot advance; vector iterator bug")
	}
	// Advance on this node, and re-populate all deeper levels.
	it.path[i].index++
	for i++; i < len(it.path); i++ {
		it.path[i] = pathEntry{it.path[i-1].current().(node), 0}
	}
	it.index++
}

type marshalError struct {
	index int
	cause error
}

func (err *marshalError) Error() string {
	return fmt.Sprintf("element %d: %s", err.index, err.cause)
}

func marshalJSON(it Iterator) ([]byte, error) {
	var buf bytes.Buffer
	buf.WriteByte('[')
	index := 0
	for ; it.HasElem(); it.Next() {
		if index > 0 {
			buf.WriteByte(',')
		}
		elemBytes, err := json.Marshal(it.Elem())
		if err != nil {
			return nil, &marshalError{index, err}
		}
		buf.Write(elemBytes)
		index++
	}
	buf.WriteByte(']')
	return buf.Bytes(), nil
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpcDhcpOptions() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVpcDhcpOptionsCreate,
		Read:   resourceAwsVpcDhcpOptionsRead,
		Update: resourceAwsVpcDhcpOptionsUpdate,
		Delete: resourceAwsVpcDhcpOptionsDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"domain_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"domain_name_servers": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"ntp_servers": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"netbios_node_type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"netbios_name_servers": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"tags": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
			},
		},
	}
}

func resourceAwsVpcDhcpOptionsCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	setDHCPOption := func(key string) *ec2.NewDhcpConfiguration {
		log.Printf("[DEBUG] Setting DHCP option %s...", key)
		tfKey := strings.Replace(key, "-", "_", -1)

		value, ok := d.GetOk(tfKey)
		if !ok {
			return nil
		}

		if v, ok := value.(string); ok {
			return &ec2.NewDhcpConfiguration{
				Key: aws.String(key),
				Values: []*string{
					aws.String(v),
				},
			}
		}

		if v, ok := value.([]interface{}); ok {
			var s []*string
			for _, attr := range v {
				s = append(s, aws.String(attr.(string)))
			}

			return &ec2.NewDhcpConfiguration{
				Key:    aws.String(key),
				Values: s,
			}
		}

		return nil
	}

	createOpts := &ec2.CreateDhcpOptionsInput{
		DhcpConfigurations: []*ec2.NewDhcpConfiguration{
			setDHCPOption("domain-name"),
			setDHCPOption("domain-name-servers"),
			setDHCPOption("ntp-servers"),
			setDHCPOption("netbios-node-type"),
			setDHCPOption("netbios-name-servers"),
		},
	}

	resp, err := conn.CreateDhcpOptions(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating DHCP Options Set: %s", err)
	}

	dos := resp.DhcpOptions
	d.SetId(*dos.DhcpOptionsId)
	log.Printf("[INFO] DHCP Options Set ID: %s", d.Id())

	// Wait for the DHCP Options to become available
	log.Printf("[DEBUG] Waiting for DHCP Options (%s) to become available", d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  []string{"created"},
		Refresh: resourceDHCPOptionsStateRefreshFunc(conn, d.Id()),
		Timeout: 5 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for DHCP Options (%s) to become available: %s",
			d.Id(), err)
	}

	return resourceAwsVpcDhcpOptionsUpdate(d, meta)
}

func resourceAwsVpcDhcpOptionsRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	req := &ec2.DescribeDhcpOptionsInput{
		DhcpOptionsIds: []*string{
			aws.String(d.Id()),
		},
	}

	resp, err := conn.DescribeDhcpOptions(req)
	if err != nil {
		ec2err, ok := err.(awserr.Error)
		if !ok {
			return fmt.Errorf("Error retrieving DHCP Options: %s", err.Error())
		}

		if ec2err.Code() == "InvalidDhcpOptionID.NotFound" {
			log.Printf("[WARN] DHCP Options (%s) not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving DHCP Options: %s", err.Error())
	}

	if len(resp.DhcpOptions) == 0 {
		return nil
	}

	opts := resp.DhcpOptions[0]
	d.Set("tags", tagsToMap(opts.Tags))

	for _, cfg := range opts.DhcpConfigurations {
		tfKey := strings.Replace(*cfg.Key, "-", "_", -1)

		if _, ok := d.Get(tfKey).(string); ok {
			d.Set(tfKey, cfg.Values[0].Value)
		} else {
			values := make([]string, 0, len(cfg.Values))
			for _, v := range cfg.Values {
				values = append(values, *v.Value)
			}

			d.Set(tfKey, values)
		}
	}

	return nil
}

func resourceAwsVpcDhcpOptionsUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	return setTags(conn, d)
}

func resourceAwsVpcDhcpOptionsDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	return resource.Retry(3*time.Minute, func() *resource.RetryError {
		log.Printf("[INFO] Deleting DHCP Options ID %s...", d.Id())
		_, err := conn.DeleteDhcpOptions(&ec2.DeleteDhcpOptionsInput{
			DhcpOptionsId: aws.String(d.Id()),
		})

		if err == nil {
			return nil
		}

		log.Printf("[WARN] %s", err)

		ec2err, ok := err.(awserr.Error)
		if !ok {
			return resource.RetryableError(err)
		}

		switch ec2err.Code() {
		case "InvalidDhcpOptionsID.NotFound":
			return nil
		case "DependencyViolation":
			// If it is a dependency violation, we want to disassociate
			// all VPCs using the given DHCP Options ID, and retry deleting.
			vpcs, err2 := findVPCsByDHCPOptionsID(conn, d.Id())
			if err2 != nil {
				log.Printf("[ERROR] %s", err2)
				return resource.RetryableError(err2)
			}

			for _, vpc := range vpcs {
				log.Printf("[INFO] Disassociating DHCP Options Set %s from VPC %s...", d.Id(), *vpc.VpcId)
				if _, err := conn.AssociateDhcpOptions(&ec2.AssociateDhcpOptionsInput{
					DhcpOptionsId: aws.String("default"),
					VpcId:         vpc.VpcId,
				}); err != nil {
					return resource.RetryableError(err)
				}
			}
			return resource.RetryableError(err)
		default:
			return resource.NonRetryableError(err)
		}
	})
}

func findVPCsByDHCPOptionsID(conn *ec2.EC2, id string) ([]*ec2.Vpc, error) {
	req := &ec2.DescribeVpcsInput{
		Filters: []*ec2.Filter{
			&ec2.Filter{
				Name: aws.String("dhcp-options-id"),
				Values: []*string{
					aws.String(id),
				},
			},
		},
	}

	resp, err := conn.DescribeVpcs(req)
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpcID.NotFound" {
			return nil, nil
		}
		return nil, err
	}

	return resp.Vpcs, nil
}

func resourceDHCPOptionsStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		DescribeDhcpOpts := &ec2.DescribeDhcpOptionsInput{
			DhcpOptionsIds: []*string{
				aws.String(id),
			},
		}

		resp, err := conn.DescribeDhcpOptions(DescribeDhcpOpts)
		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidDhcpOptionsID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on DHCPOptionsStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		dos := resp.DhcpOptions[0]
		return dos, "created", nil
	}
}
<commit_msg>Update not found error message for DescribeDhcpOptions.<commit_after>package aws

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsVpcDhcpOptions() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsVpcDhcpOptionsCreate,
		Read:   resourceAwsVpcDhcpOptionsRead,
		Update: resourceAwsVpcDhcpOptionsUpdate,
		Delete: resourceAwsVpcDhcpOptionsDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"domain_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"domain_name_servers": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"ntp_servers": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"netbios_node_type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"netbios_name_servers": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"tags": &schema.Schema{
				Type:     schema.TypeMap,
				Optional: true,
			},
		},
	}
}

func resourceAwsVpcDhcpOptionsCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	setDHCPOption := func(key string) *ec2.NewDhcpConfiguration {
		log.Printf("[DEBUG] Setting DHCP option %s...", key)
		tfKey := strings.Replace(key, "-", "_", -1)

		value, ok := d.GetOk(tfKey)
		if !ok {
			return nil
		}

		if v, ok := value.(string); ok {
			return &ec2.NewDhcpConfiguration{
				Key: aws.String(key),
				Values: []*string{
					aws.String(v),
				},
			}
		}

		if v, ok := value.([]interface{}); ok {
			var s []*string
			for _, attr := range v {
				s = append(s, aws.String(attr.(string)))
			}

			return &ec2.NewDhcpConfiguration{
				Key:    aws.String(key),
				Values: s,
			}
		}

		return nil
	}

	createOpts := &ec2.CreateDhcpOptionsInput{
		DhcpConfigurations: []*ec2.NewDhcpConfiguration{
			setDHCPOption("domain-name"),
			setDHCPOption("domain-name-servers"),
			setDHCPOption("ntp-servers"),
			setDHCPOption("netbios-node-type"),
			setDHCPOption("netbios-name-servers"),
		},
	}

	resp, err := conn.CreateDhcpOptions(createOpts)
	if err != nil {
		return fmt.Errorf("Error creating DHCP Options Set: %s", err)
	}

	dos := resp.DhcpOptions
	d.SetId(*dos.DhcpOptionsId)
	log.Printf("[INFO] DHCP Options Set ID: %s", d.Id())

	// Wait for the DHCP Options to become available
	log.Printf("[DEBUG] Waiting for DHCP Options (%s) to become available", d.Id())
	stateConf := &resource.StateChangeConf{
		Pending: []string{"pending"},
		Target:  []string{"created"},
		Refresh: resourceDHCPOptionsStateRefreshFunc(conn, d.Id()),
		Timeout: 5 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf(
			"Error waiting for DHCP Options (%s) to become available: %s",
			d.Id(), err)
	}

	return resourceAwsVpcDhcpOptionsUpdate(d, meta)
}

func resourceAwsVpcDhcpOptionsRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	req := &ec2.DescribeDhcpOptionsInput{
		DhcpOptionsIds: []*string{
			aws.String(d.Id()),
		},
	}

	resp, err := conn.DescribeDhcpOptions(req)
	if err != nil {
		ec2err, ok := err.(awserr.Error)
		if !ok {
			return fmt.Errorf("Error retrieving DHCP Options: %s", err.Error())
		}

		if ec2err.Code() == "InvalidDhcpOptionID.NotFound" {
			log.Printf("[WARN] DHCP Options (%s) not found, removing from state", d.Id())
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error retrieving DHCP Options: %s", err.Error())
	}

	if len(resp.DhcpOptions) == 0 {
		return nil
	}

	opts := resp.DhcpOptions[0]
	d.Set("tags", tagsToMap(opts.Tags))

	for _, cfg := range opts.DhcpConfigurations {
		tfKey := strings.Replace(*cfg.Key, "-", "_", -1)

		if _, ok := d.Get(tfKey).(string); ok {
			d.Set(tfKey, cfg.Values[0].Value)
		} else {
			values := make([]string, 0, len(cfg.Values))
			for _, v := range cfg.Values {
				values = append(values, *v.Value)
			}

			d.Set(tfKey, values)
		}
	}

	return nil
}

func resourceAwsVpcDhcpOptionsUpdate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn
	return setTags(conn, d)
}

func resourceAwsVpcDhcpOptionsDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).ec2conn

	return resource.Retry(3*time.Minute, func() *resource.RetryError {
		log.Printf("[INFO] Deleting DHCP Options ID %s...", d.Id())
		_, err := conn.DeleteDhcpOptions(&ec2.DeleteDhcpOptionsInput{
			DhcpOptionsId: aws.String(d.Id()),
		})

		if err == nil {
			return nil
		}

		log.Printf("[WARN] %s", err)

		ec2err, ok := err.(awserr.Error)
		if !ok {
			return resource.RetryableError(err)
		}

		switch ec2err.Code() {
		case "InvalidDhcpOptionsID.NotFound":
			return nil
		case "DependencyViolation":
			// If it is a dependency violation, we want to disassociate
			// all VPCs using the given DHCP Options ID, and retry deleting.
			vpcs, err2 := findVPCsByDHCPOptionsID(conn, d.Id())
			if err2 != nil {
				log.Printf("[ERROR] %s", err2)
				return resource.RetryableError(err2)
			}

			for _, vpc := range vpcs {
				log.Printf("[INFO] Disassociating DHCP Options Set %s from VPC %s...", d.Id(), *vpc.VpcId)
				if _, err := conn.AssociateDhcpOptions(&ec2.AssociateDhcpOptionsInput{
					DhcpOptionsId: aws.String("default"),
					VpcId:         vpc.VpcId,
				}); err != nil {
					return resource.RetryableError(err)
				}
			}
			return resource.RetryableError(err)
		default:
			return resource.NonRetryableError(err)
		}
	})
}

func findVPCsByDHCPOptionsID(conn *ec2.EC2, id string) ([]*ec2.Vpc, error) {
	req := &ec2.DescribeVpcsInput{
		Filters: []*ec2.Filter{
			&ec2.Filter{
				Name: aws.String("dhcp-options-id"),
				Values: []*string{
					aws.String(id),
				},
			},
		},
	}

	resp, err := conn.DescribeVpcs(req)
	if err != nil {
		if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidVpcID.NotFound" {
			return nil, nil
		}
		return nil, err
	}

	return resp.Vpcs, nil
}

func resourceDHCPOptionsStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		DescribeDhcpOpts := &ec2.DescribeDhcpOptionsInput{
			DhcpOptionsIds: []*string{
				aws.String(id),
			},
		}

		resp, err := conn.DescribeDhcpOptions(DescribeDhcpOpts)
		if err != nil {
			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidDhcpOptionID.NotFound" {
				resp = nil
			} else {
				log.Printf("Error on DHCPOptionsStateRefresh: %s", err)
				return nil, "", err
			}
		}

		if resp == nil {
			// Sometimes AWS just has consistency issues and doesn't see
			// our instance yet. Return an empty state.
			return nil, "", nil
		}

		dos := resp.DhcpOptions[0]
		return dos, "created", nil
	}
}
<|endoftext|>


<commit_before>package manta

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"path"

	uuid "github.com/hashicorp/go-uuid"
	"github.com/hashicorp/terraform/state"
	"github.com/hashicorp/terraform/state/remote"
	tritonErrors "github.com/joyent/triton-go/errors"
	"github.com/joyent/triton-go/storage"
)

const (
	mantaDefaultRootStore = "/stor"
	lockFileName          = "tflock"
)

type RemoteClient struct {
	storageClient *storage.StorageClient
	directoryName string
	keyName       string
	statePath     string
}

func (c *RemoteClient) Get() (*remote.Payload, error) {
	output, err := c.storageClient.Objects().Get(context.Background(), &storage.GetObjectInput{
		ObjectPath: path.Join(mantaDefaultRootStore, c.directoryName, c.keyName),
	})
	if err != nil {
		if tritonErrors.IsResourceNotFound(err) {
			return nil, nil
		}
		return nil, err
	}
	defer output.ObjectReader.Close()

	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, output.ObjectReader); err != nil {
		return nil, fmt.Errorf("Failed to read remote state: %s", err)
	}

	payload := &remote.Payload{
		Data: buf.Bytes(),
	}

	// If there was no data, then return nil
	if len(payload.Data) == 0 {
		return nil, nil
	}

	return payload, nil

}

func (c *RemoteClient) Put(data []byte) error {
	contentType := "application/json"
	contentLength := int64(len(data))

	params := &storage.PutObjectInput{
		ContentType:   contentType,
		ContentLength: uint64(contentLength),
		ObjectPath:    path.Join(mantaDefaultRootStore, c.directoryName, c.keyName),
		ObjectReader:  bytes.NewReader(data),
	}

	log.Printf("[DEBUG] Uploading remote state to Manta: %#v", params)
	err := c.storageClient.Objects().Put(context.Background(), params)
	if err != nil {
		return err
	}

	return nil
}

func (c *RemoteClient) Delete() error {
	err := c.storageClient.Objects().Delete(context.Background(), &storage.DeleteObjectInput{
		ObjectPath: path.Join(mantaDefaultRootStore, c.directoryName, c.keyName),
	})

	return err
}

func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
	//At Joyent, we want to make sure that the State directory exists before we interact with it
	//We don't expect users to have to create it in advance
	//The order of operations of Backend State as follows:
	// * Get - if this doesn't exist then we continue as though it's new
	// * Lock - we make sure that the state directory exists as it's the entrance to writing to Manta
	// * Put - put the state up there
	// * Unlock - unlock the directory
	//We can always guarantee that the user can put their state in the specified location because of this
	err := c.storageClient.Dir().Put(context.Background(), &storage.PutDirectoryInput{
		DirectoryName: path.Join(mantaDefaultRootStore, c.directoryName),
	})
	if err != nil {
		return "", err
	}

	//firstly we want to check that a lock doesn't already exist
	lockErr := &state.LockError{}
	lockInfo, err := c.getLockInfo()
	if err != nil {
		if !tritonErrors.IsResourceNotFound(err) {
			lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
			return "", lockErr
		}
	}

	if lockInfo != nil {
		lockErr := &state.LockError{
			Err:  fmt.Errorf("A lock is already acquired"),
			Info: lockInfo,
		}
		return "", lockErr
	}

	info.Path = path.Join(c.directoryName, lockFileName)

	if info.ID == "" {
		lockID, err := uuid.GenerateUUID()
		if err != nil {
			return "", err
		}

		info.ID = lockID
	}

	data := info.Marshal()

	contentType := "application/json"
	contentLength := int64(len(data))

	params := &storage.PutObjectInput{
		ContentType:   contentType,
		ContentLength: uint64(contentLength),
		ObjectPath:    path.Join(mantaDefaultRootStore, c.directoryName, lockFileName),
		ObjectReader:  bytes.NewReader(data),
	}

	log.Printf("[DEBUG] Creating manta state lock: %#v", params)
	err = c.storageClient.Objects().Put(context.Background(), params)
	if err != nil {
		return "", err
	}

	return info.ID, nil
}

func (c *RemoteClient) Unlock(id string) error {
	lockErr := &state.LockError{}

	lockInfo, err := c.getLockInfo()
	if err != nil {
		lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
		return lockErr
	}
	lockErr.Info = lockInfo

	if lockInfo.ID != id {
		lockErr.Err = fmt.Errorf("lock id %q does not match existing lock", id)
		return lockErr
	}

	err = c.storageClient.Objects().Delete(context.Background(), &storage.DeleteObjectInput{
		ObjectPath: path.Join(mantaDefaultRootStore, c.directoryName, lockFileName),
	})

	return err
}

func (c *RemoteClient) getLockInfo() (*state.LockInfo, error) {
	output, err := c.storageClient.Objects().Get(context.Background(), &storage.GetObjectInput{
		ObjectPath: path.Join(mantaDefaultRootStore, c.directoryName, lockFileName),
	})
	if err != nil {
		return nil, err
	}

	defer output.ObjectReader.Close()

	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, output.ObjectReader); err != nil {
		return nil, fmt.Errorf("Failed to read lock info: %s", err)
	}

	lockInfo := &state.LockInfo{}
	err = json.Unmarshal(buf.Bytes(), lockInfo)
	if err != nil {
		return nil, err
	}

	return lockInfo, nil
}
<commit_msg>backend/manta: Add support for manta backend tiered path structure<commit_after>package manta

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"path"

	uuid "github.com/hashicorp/go-uuid"
	"github.com/hashicorp/terraform/state"
	"github.com/hashicorp/terraform/state/remote"
	tritonErrors "github.com/joyent/triton-go/errors"
	"github.com/joyent/triton-go/storage"
)

const (
	mantaDefaultRootStore = "/stor"
	lockFileName          = "tflock"
)

type RemoteClient struct {
	storageClient *storage.StorageClient
	directoryName string
	keyName       string
	statePath     string
}

func (c *RemoteClient) Get() (*remote.Payload, error) {
	output, err := c.storageClient.Objects().Get(context.Background(), &storage.GetObjectInput{
		ObjectPath: path.Join(mantaDefaultRootStore, c.directoryName, c.keyName),
	})
	if err != nil {
		if tritonErrors.IsResourceNotFound(err) {
			return nil, nil
		}
		return nil, err
	}
	defer output.ObjectReader.Close()

	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, output.ObjectReader); err != nil {
		return nil, fmt.Errorf("Failed to read remote state: %s", err)
	}

	payload := &remote.Payload{
		Data: buf.Bytes(),
	}

	// If there was no data, then return nil
	if len(payload.Data) == 0 {
		return nil, nil
	}

	return payload, nil

}

func (c *RemoteClient) Put(data []byte) error {
	contentType := "application/json"
	contentLength := int64(len(data))

	params := &storage.PutObjectInput{
		ContentType:   contentType,
		ContentLength: uint64(contentLength),
		ObjectPath:    path.Join(mantaDefaultRootStore, c.directoryName, c.keyName),
		ObjectReader:  bytes.NewReader(data),
	}

	log.Printf("[DEBUG] Uploading remote state to Manta: %#v", params)
	err := c.storageClient.Objects().Put(context.Background(), params)
	if err != nil {
		return err
	}

	return nil
}

func (c *RemoteClient) Delete() error {
	err := c.storageClient.Objects().Delete(context.Background(), &storage.DeleteObjectInput{
		ObjectPath: path.Join(mantaDefaultRootStore, c.directoryName, c.keyName),
	})

	return err
}

func (c *RemoteClient) Lock(info *state.LockInfo) (string, error) {
	//At Joyent, we want to make sure that the State directory exists before we interact with it
	//We don't expect users to have to create it in advance
	//The order of operations of Backend State as follows:
	// * Get - if this doesn't exist then we continue as though it's new
	// * Lock - we make sure that the state directory exists as it's the entrance to writing to Manta
	// * Put - put the state up there
	// * Unlock - unlock the directory
	//We can always guarantee that the user can put their state in the specified location because of this
	err := c.storageClient.Dir().Put(context.Background(), &storage.PutDirectoryInput{
		DirectoryName: path.Join(mantaDefaultRootStore, c.directoryName),
	})
	if err != nil {
		return "", err
	}

	//firstly we want to check that a lock doesn't already exist
	lockErr := &state.LockError{}
	lockInfo, err := c.getLockInfo()
	if err != nil {
		if !tritonErrors.IsResourceNotFound(err) {
			lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
			return "", lockErr
		}
	}

	if lockInfo != nil {
		lockErr := &state.LockError{
			Err:  fmt.Errorf("A lock is already acquired"),
			Info: lockInfo,
		}
		return "", lockErr
	}

	info.Path = path.Join(c.directoryName, lockFileName)

	if info.ID == "" {
		lockID, err := uuid.GenerateUUID()
		if err != nil {
			return "", err
		}

		info.ID = lockID
	}

	data := info.Marshal()

	contentType := "application/json"
	contentLength := int64(len(data))

	params := &storage.PutObjectInput{
		ContentType:   contentType,
		ContentLength: uint64(contentLength),
		ObjectPath:    path.Join(mantaDefaultRootStore, c.directoryName, lockFileName),
		ObjectReader:  bytes.NewReader(data),
		ForceInsert:   true,
	}

	log.Printf("[DEBUG] Creating manta state lock: %#v", params)
	err = c.storageClient.Objects().Put(context.Background(), params)
	if err != nil {
		return "", err
	}

	return info.ID, nil
}

func (c *RemoteClient) Unlock(id string) error {
	lockErr := &state.LockError{}

	lockInfo, err := c.getLockInfo()
	if err != nil {
		lockErr.Err = fmt.Errorf("failed to retrieve lock info: %s", err)
		return lockErr
	}
	lockErr.Info = lockInfo

	if lockInfo.ID != id {
		lockErr.Err = fmt.Errorf("lock id %q does not match existing lock", id)
		return lockErr
	}

	err = c.storageClient.Objects().Delete(context.Background(), &storage.DeleteObjectInput{
		ObjectPath: path.Join(mantaDefaultRootStore, c.directoryName, lockFileName),
	})

	return err
}

func (c *RemoteClient) getLockInfo() (*state.LockInfo, error) {
	output, err := c.storageClient.Objects().Get(context.Background(), &storage.GetObjectInput{
		ObjectPath: path.Join(mantaDefaultRootStore, c.directoryName, lockFileName),
	})
	if err != nil {
		return nil, err
	}

	defer output.ObjectReader.Close()

	buf := bytes.NewBuffer(nil)
	if _, err := io.Copy(buf, output.ObjectReader); err != nil {
		return nil, fmt.Errorf("Failed to read lock info: %s", err)
	}

	lockInfo := &state.LockInfo{}
	err = json.Unmarshal(buf.Bytes(), lockInfo)
	if err != nil {
		return nil, err
	}

	return lockInfo, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2021 The Kubernetes Authors.

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

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

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

package managedfields

import (
	"bytes"
	"fmt"

	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
	"sigs.k8s.io/structured-merge-diff/v4/typed"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
)

// ExtractInto extracts the applied configuration state from object for fieldManager
// into applyConfiguration. If no managed fields are found for the given fieldManager,
// no error is returned, but applyConfiguration is left unpopulated. It is possible
// that no managed fields were found for the fieldManager because other field managers
// have taken ownership of all the fields previously owned by the fieldManager. It is
// also possible the fieldManager never owned fields.
//
// The provided object MUST bo a root resource object since subresource objects
// do not contain their own managed fields. For example, an autoscaling.Scale
// object read from a "scale" subresource does not have any managed fields and so
// cannot be used as the object.
//
// If the fields of a subresource are a subset of the fields of the root object,
// and their field paths and types are exactly the same, then ExtractInto can be
// called with the root resource as the object and the subresource as the
// applyConfiguration. This works for "status", obviously, because status is
// represented by the exact same object as the root resource. This this does NOT
// work, for example, with the "scale" subresources of Deployment, ReplicaSet and
// StatefulSet. While the spec.replicas, status.replicas fields are in the same
// exact field path locations as they are in autoscaling.Scale, the selector
// fields are in different locations, and are a different type.
func ExtractInto(object runtime.Object, objectType typed.ParseableType, fieldManager string, applyConfiguration interface{}, subresource string) error {
	typedObj, err := toTyped(object, objectType)
	if err != nil {
		return fmt.Errorf("error converting obj to typed: %w", err)
	}

	accessor, err := meta.Accessor(object)
	if err != nil {
		return fmt.Errorf("error accessing metadata: %w", err)
	}
	fieldsEntry, ok := findManagedFields(accessor, fieldManager, subresource)
	if !ok {
		return nil
	}
	fieldset := &fieldpath.Set{}
	err = fieldset.FromJSON(bytes.NewReader(fieldsEntry.FieldsV1.Raw))
	if err != nil {
		return fmt.Errorf("error marshalling FieldsV1 to JSON: %w", err)
	}

	u := typedObj.ExtractItems(fieldset.Leaves()).AsValue().Unstructured()
	m, ok := u.(map[string]interface{})
	if !ok {
		return fmt.Errorf("unable to convert managed fields for %s to unstructured, expected map, got %T", fieldManager, u)
	}

	// set the type meta manually if it doesn't exist to avoid missing kind errors
	// when decoding from unstructured JSON
	if _, ok := m["kind"]; !ok {
		m["kind"] = object.GetObjectKind().GroupVersionKind().Kind
		m["apiVersion"] = object.GetObjectKind().GroupVersionKind().GroupVersion().String()
	}
	if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, applyConfiguration); err != nil {
		return fmt.Errorf("error extracting into obj from unstructured: %w", err)
	}
	return nil
}

func findManagedFields(accessor metav1.Object, fieldManager string, subresource string) (metav1.ManagedFieldsEntry, bool) {
	objManagedFields := accessor.GetManagedFields()
	for _, mf := range objManagedFields {
		if mf.Manager == fieldManager && mf.Operation == metav1.ManagedFieldsOperationApply && mf.Subresource == subresource {
			return mf, true
		}
	}
	return metav1.ManagedFieldsEntry{}, false
}

func toTyped(obj runtime.Object, objectType typed.ParseableType) (*typed.TypedValue, error) {
	switch o := obj.(type) {
	case *unstructured.Unstructured:
		return objectType.FromUnstructured(o.Object)
	default:
		return objectType.FromStructured(o)
	}
}
<commit_msg>fix extract_test<commit_after>/*
Copyright 2021 The Kubernetes Authors.

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

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

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

package managedfields

import (
	"bytes"
	"fmt"

	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
	"sigs.k8s.io/structured-merge-diff/v4/typed"

	"k8s.io/apimachinery/pkg/api/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime"
)

// ExtractInto extracts the applied configuration state from object for fieldManager
// into applyConfiguration. If no managed fields are found for the given fieldManager,
// no error is returned, but applyConfiguration is left unpopulated. It is possible
// that no managed fields were found for the fieldManager because other field managers
// have taken ownership of all the fields previously owned by the fieldManager. It is
// also possible the fieldManager never owned fields.
//
// The provided object MUST bo a root resource object since subresource objects
// do not contain their own managed fields. For example, an autoscaling.Scale
// object read from a "scale" subresource does not have any managed fields and so
// cannot be used as the object.
//
// If the fields of a subresource are a subset of the fields of the root object,
// and their field paths and types are exactly the same, then ExtractInto can be
// called with the root resource as the object and the subresource as the
// applyConfiguration. This works for "status", obviously, because status is
// represented by the exact same object as the root resource. This this does NOT
// work, for example, with the "scale" subresources of Deployment, ReplicaSet and
// StatefulSet. While the spec.replicas, status.replicas fields are in the same
// exact field path locations as they are in autoscaling.Scale, the selector
// fields are in different locations, and are a different type.
func ExtractInto(object runtime.Object, objectType typed.ParseableType, fieldManager string, applyConfiguration interface{}, subresource string) error {
	typedObj, err := toTyped(object, objectType)
	if err != nil {
		return fmt.Errorf("error converting obj to typed: %w", err)
	}

	accessor, err := meta.Accessor(object)
	if err != nil {
		return fmt.Errorf("error accessing metadata: %w", err)
	}
	fieldsEntry, ok := findManagedFields(accessor, fieldManager, subresource)
	if !ok {
		return nil
	}
	fieldset := &fieldpath.Set{}
	err = fieldset.FromJSON(bytes.NewReader(fieldsEntry.FieldsV1.Raw))
	if err != nil {
		return fmt.Errorf("error marshalling FieldsV1 to JSON: %w", err)
	}

	u := typedObj.ExtractItems(fieldset.Leaves()).AsValue().Unstructured()
	m, ok := u.(map[string]interface{})
	if !ok {
		return fmt.Errorf("unable to convert managed fields for %s to unstructured, expected map, got %T", fieldManager, u)
	}

	// set the type meta manually if it doesn't exist to avoid missing kind errors
	// when decoding from unstructured JSON
	if _, ok := m["kind"]; !ok && object.GetObjectKind().GroupVersionKind().Kind != "" {
		m["kind"] = object.GetObjectKind().GroupVersionKind().Kind
		m["apiVersion"] = object.GetObjectKind().GroupVersionKind().GroupVersion().String()
	}
	if err := runtime.DefaultUnstructuredConverter.FromUnstructured(m, applyConfiguration); err != nil {
		return fmt.Errorf("error extracting into obj from unstructured: %w", err)
	}
	return nil
}

func findManagedFields(accessor metav1.Object, fieldManager string, subresource string) (metav1.ManagedFieldsEntry, bool) {
	objManagedFields := accessor.GetManagedFields()
	for _, mf := range objManagedFields {
		if mf.Manager == fieldManager && mf.Operation == metav1.ManagedFieldsOperationApply && mf.Subresource == subresource {
			return mf, true
		}
	}
	return metav1.ManagedFieldsEntry{}, false
}

func toTyped(obj runtime.Object, objectType typed.ParseableType) (*typed.TypedValue, error) {
	switch o := obj.(type) {
	case *unstructured.Unstructured:
		return objectType.FromUnstructured(o.Object)
	default:
		return objectType.FromStructured(o)
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 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 syscall_test

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"
	"testing"
)

func TestWin32finddata(t *testing.T) {
	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	path := filepath.Join(dir, "long_name.and_extension")
	f, err := os.Create(path)
	if err != nil {
		t.Fatalf("failed to create %v: %v", path, err)
	}
	f.Close()

	type X struct {
		fd  syscall.Win32finddata1
		got byte
		pad [10]byte // to protect ourselves

	}
	var want byte = 2 // it is unlikely to have this character in the filename
	x := X{got: want}

	h, err := syscall.FindFirstFile1(syscall.StringToUTF16Ptr(path), &(x.fd))
	if err != nil {
		t.Fatalf("FindFirstFile failed: %v", err)
	}
	err = syscall.FindClose(h)
	if err != nil {
		t.Fatalf("FindClose failed: %v", err)
	}

	if x.got != want {
		t.Fatalf("memory corruption: want=%d got=%d", want, x.got)
	}
}
<commit_msg>syscall: fix windows build<commit_after>// Copyright 2012 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 syscall_test

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"
	"testing"
)

func TestWin32finddata(t *testing.T) {
	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	path := filepath.Join(dir, "long_name.and_extension")
	f, err := os.Create(path)
	if err != nil {
		t.Fatalf("failed to create %v: %v", path, err)
	}
	f.Close()

	type X struct {
		fd  syscall.Win32finddata
		got byte
		pad [10]byte // to protect ourselves

	}
	var want byte = 2 // it is unlikely to have this character in the filename
	x := X{got: want}

	h, err := syscall.FindFirstFile(syscall.StringToUTF16Ptr(path), &(x.fd))
	if err != nil {
		t.Fatalf("FindFirstFile failed: %v", err)
	}
	err = syscall.FindClose(h)
	if err != nil {
		t.Fatalf("FindClose failed: %v", err)
	}

	if x.got != want {
		t.Fatalf("memory corruption: want=%d got=%d", want, x.got)
	}
}
<|endoftext|>


<commit_before>package ofutils

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"math/rand"
	"os"
	"sort"
	"strconv"
	"time"

	"github.com/astaxie/beego/orm"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandString(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

func MD5(text string) string {
	hasher := md5.New()
	hasher.Write([]byte(text))
	return hex.EncodeToString(hasher.Sum(nil))
}

func ToString(str interface{}) string {
	if str == nil {
		return ""
	}
	return fmt.Sprintf("%v", str)
}

func ToInt(val interface{}) int {
	if val == nil {
		return 0
	}
	s, ok := val.(string)
	if ok {
		i, err := strconv.Atoi(s)
		if err != nil {
			return 0
		}
		return i
	}
	i, ok := val.(int)
	if ok {
		return i
	} else {
		return 0
	}
}

func GetWeekFirstDay() string {
	week := time.Now().Weekday().String()
	var day time.Duration
	switch week {
	case "Sunday":
		day = 6
		break
	case "Monday":
		day = 0
		break
	case "Tuesday":
		day = 1
		break
	case "Wednesday":
		day = 2
		break
	case "Thursday":
		day = 3
		break
	case "Friday":
		day = 4
		break
	case "Saturday":
		day = 5
		break
	}
	date := time.Now().Add(-day * 24 * time.Hour)
	return date.Format("2006-01-02")
}

type ByKey struct {
	Key  string
	List []orm.Params
}

func (a ByKey) Len() int {
	return len(a.List)
}
func (a ByKey) Swap(i, j int) {
	a.List[i], a.List[j] = a.List[j], a.List[i]
}
func (a ByKey) Less(i, j int) bool {
	return ToInt(a.List[i][a.Key]) > ToInt(a.List[j][a.Key])
}

func Sort(list []orm.Params, key string) []orm.Params {
	byKey := ByKey{List: list, Key: key}
	sort.Sort(byKey)
	return byKey.List
}

func SubString(str string, begin, length int) (substr string) {
	// 将字符串的转换成[]rune
	rs := []rune(str)
	lth := len(rs)

	// 简单的越界判断
	if begin < 0 {
		begin = 0
	}
	if begin >= lth {
		begin = lth
	}
	end := begin + length
	if end > lth {
		end = lth
	}
	// 返回子串
	return string(rs[begin:end])
}

func ToFloat(str interface{}) float64 {
	if str == nil {
		return 0
	}
	tf, err := strconv.ParseFloat(ToString(str), 64)
	if err != nil {
		return 0
	}
	return tf
}
func GetEncryptPhone(phone interface{}) string {
	temp := ToString(phone)
	if len(temp) == 11 {
		start := SubString(temp, 0, 3)
		end := SubString(temp, 7, 11)
		temp = start + "****" + end
	}
	return temp
}
func Exist(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}
<commit_msg>update<commit_after>package ofutils

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"math/rand"
	"os"
	"sort"
	"strconv"
	"time"

	"github.com/astaxie/beego/orm"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

func RandString(n int) string {
	b := make([]rune, n)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

func MD5(text string) string {
	hasher := md5.New()
	hasher.Write([]byte(text))
	return hex.EncodeToString(hasher.Sum(nil))
}

func ToString(str interface{}) string {
	if str == nil {
		return ""
	}
	return fmt.Sprintf("%v", str)
}

func ToInt(val interface{}) int {
	if val == nil {
		return 0
	}
	s, ok := val.(string)
	if ok {
		i, err := strconv.Atoi(s)
		if err != nil {
			return 0
		}
		return i
	}
	i, ok := val.(int)
	if ok {
		return i
	} else {
		return 0
	}
}

func GetWeekFirstDay() string {
	week := time.Now().Weekday().String()
	var day time.Duration
	switch week {
	case "Sunday":
		day = 6
		break
	case "Monday":
		day = 0
		break
	case "Tuesday":
		day = 1
		break
	case "Wednesday":
		day = 2
		break
	case "Thursday":
		day = 3
		break
	case "Friday":
		day = 4
		break
	case "Saturday":
		day = 5
		break
	}
	date := time.Now().Add(-day * 24 * time.Hour)
	return date.Format("2006-01-02")
}

type ByKey struct {
	Key  string
	List []orm.Params
}

func (a ByKey) Len() int {
	return len(a.List)
}
func (a ByKey) Swap(i, j int) {
	a.List[i], a.List[j] = a.List[j], a.List[i]
}
func (a ByKey) Less(i, j int) bool {
	return ToInt(a.List[i][a.Key]) > ToInt(a.List[j][a.Key])
}

func Sort(list []orm.Params, key string) []orm.Params {
	byKey := ByKey{List: list, Key: key}
	sort.Sort(byKey)
	return byKey.List
}

func SubString(str string, begin, length int) (substr string) {
	// 将字符串的转换成[]rune
	rs := []rune(str)
	lth := len(rs)

	// 简单的越界判断
	if begin < 0 {
		begin = 0
	}
	if begin >= lth {
		begin = lth
	}
	end := begin + length
	if end > lth {
		end = lth
	}
	// 返回子串
	return string(rs[begin:end])
}

func ToFloat(str interface{}) float64 {
	if str == nil {
		return 0
	}
	tf, err := strconv.ParseFloat(ToString(str), 64)
	if err != nil {
		return 0
	}
	return tf
}
func ToJson(datas interface{}) string {
	jsonString, _ := json.Marshal(datas)
	return string(jsonString)
}
func GetEncryptPhone(phone interface{}) string {
	temp := ToString(phone)
	if len(temp) == 11 {
		start := SubString(temp, 0, 3)
		end := SubString(temp, 7, 11)
		temp = start + "****" + end
	}
	return temp
}
func Exist(filename string) bool {
	_, err := os.Stat(filename)
	return err == nil || os.IsExist(err)
}
<|endoftext|>


<commit_before>package csrf

import "net/http"

// Option describes a functional option for configuring the the CSRF handler.
type Option func(*csrf)

// MaxAge sets the maximum age (in seconds) of a CSRF token's underlying cookie.
// Defaults to 12 hours.
func MaxAge(age int) Option {
	return func(cs *csrf) {
		cs.opts.MaxAge = age
	}
}

// Domain sets the cookie domain. Defaults to the current domain of the request
// only (recommended).
//
// This should be a hostname and not a URL. If set, the domain is treated as
// being prefixed with a '.' - e.g. "example.com" becomes ".example.com" and
// matches "www.example.com" and "secure.example.com".
func Domain(domain string) Option {
	return func(cs *csrf) {
		cs.opts.Domain = domain
	}
}

// Path sets the cookie path. Defaults to the path the cookie was issued from
// (recommended).
//
// This instructs clients to only respond with cookie for that path and its
// subpaths - i.e. a cookie issued from "/register" would be included in requests
// to "/register/step2" and "/register/submit".
func Path(p string) Option {
	return func(cs *csrf) {
		cs.opts.Path = p
	}
}

// Secure sets the 'Secure' flag on the cookie. Defaults to true (recommended).
// Set this to 'false' in your development environment otherwise the cookie won't
// be sent over an insecure channel. Setting this via the presence of a 'DEV'
// environmental variable is a good way of making sure this won't make it to a
// production environment.
func Secure(s bool) Option {
	return func(cs *csrf) {
		cs.opts.Secure = s
	}
}

// HttpOnly sets the 'HttpOnly' flag on the cookie. Defaults to true (recommended).
func HttpOnly(h bool) Option {
	return func(cs *csrf) {
		// Note that the function and field names match the case of the
		// related http.Cookie field instead of the "correct" HTTPOnly name
		// that golint suggests.
		cs.opts.HttpOnly = h
	}
}

// ErrorHandler allows you to change the handler called when CSRF request
// processing encounters an invalid token or request. A typical use would be to
// provide a handler that returns a static HTML file with a HTTP 403 status. By
// default a HTTP 404 status and a plain text CSRF failure reason are served.
//
// Note that a custom error handler can also access the csrf.Failure(r)
// function to retrieve the CSRF validation reason from the request context.
func ErrorHandler(h http.Handler) Option {
	return func(cs *csrf) {
		cs.opts.ErrorHandler = h
	}
}

// RequestHeader allows you to change the request header the CSRF middleware
// inspects. The default is X-CSRF-Token.
func RequestHeader(header string) Option {
	return func(cs *csrf) {
		cs.opts.RequestHeader = header
	}
}

// FieldName allows you to change the name value of the hidden <input> field
// generated by csrf.FormField. The default is {{ .csrfToken }}
func FieldName(name string) Option {
	return func(cs *csrf) {
		cs.opts.FieldName = name
	}
}

// CookieName changes the name of the CSRF cookie issued to clients.
//
// Note that cookie names should not contain whitespace, commas, semicolons,
// backslashes or control characters as per RFC6265.
func CookieName(name string) Option {
	return func(cs *csrf) {
		cs.opts.CookieName = name
	}
}

// setStore sets the store used by the CSRF middleware.
// Note: this is private (for now) to allow for internal API changes.
func setStore(s store) Option {
	return func(cs *csrf) {
		cs.st = s
	}
}

// parseOptions parses the supplied options functions and returns a configured
// csrf handler.
func parseOptions(h http.Handler, opts ...Option) *csrf {
	// Set the handler to call after processing.
	cs := &csrf{
		h: h,
	}

	// Default to true. See Secure & HttpOnly function comments for rationale.
	// Set here to allow package users to override the default.
	cs.opts.Secure = true
	cs.opts.HttpOnly = true

	// Range over each options function and apply it
	// to our csrf type to configure it. Options functions are
	// applied in order, with any conflicting options overriding
	// earlier calls.
	for _, option := range opts {
		option(cs)
	}

	return cs
}
<commit_msg>[docs] Corrected status code in docs (404 => 403).<commit_after>package csrf

import "net/http"

// Option describes a functional option for configuring the the CSRF handler.
type Option func(*csrf)

// MaxAge sets the maximum age (in seconds) of a CSRF token's underlying cookie.
// Defaults to 12 hours.
func MaxAge(age int) Option {
	return func(cs *csrf) {
		cs.opts.MaxAge = age
	}
}

// Domain sets the cookie domain. Defaults to the current domain of the request
// only (recommended).
//
// This should be a hostname and not a URL. If set, the domain is treated as
// being prefixed with a '.' - e.g. "example.com" becomes ".example.com" and
// matches "www.example.com" and "secure.example.com".
func Domain(domain string) Option {
	return func(cs *csrf) {
		cs.opts.Domain = domain
	}
}

// Path sets the cookie path. Defaults to the path the cookie was issued from
// (recommended).
//
// This instructs clients to only respond with cookie for that path and its
// subpaths - i.e. a cookie issued from "/register" would be included in requests
// to "/register/step2" and "/register/submit".
func Path(p string) Option {
	return func(cs *csrf) {
		cs.opts.Path = p
	}
}

// Secure sets the 'Secure' flag on the cookie. Defaults to true (recommended).
// Set this to 'false' in your development environment otherwise the cookie won't
// be sent over an insecure channel. Setting this via the presence of a 'DEV'
// environmental variable is a good way of making sure this won't make it to a
// production environment.
func Secure(s bool) Option {
	return func(cs *csrf) {
		cs.opts.Secure = s
	}
}

// HttpOnly sets the 'HttpOnly' flag on the cookie. Defaults to true (recommended).
func HttpOnly(h bool) Option {
	return func(cs *csrf) {
		// Note that the function and field names match the case of the
		// related http.Cookie field instead of the "correct" HTTPOnly name
		// that golint suggests.
		cs.opts.HttpOnly = h
	}
}

// ErrorHandler allows you to change the handler called when CSRF request
// processing encounters an invalid token or request. A typical use would be to
// provide a handler that returns a static HTML file with a HTTP 403 status. By
// default a HTTP 403 status and a plain text CSRF failure reason are served.
//
// Note that a custom error handler can also access the csrf.Failure(r)
// function to retrieve the CSRF validation reason from the request context.
func ErrorHandler(h http.Handler) Option {
	return func(cs *csrf) {
		cs.opts.ErrorHandler = h
	}
}

// RequestHeader allows you to change the request header the CSRF middleware
// inspects. The default is X-CSRF-Token.
func RequestHeader(header string) Option {
	return func(cs *csrf) {
		cs.opts.RequestHeader = header
	}
}

// FieldName allows you to change the name value of the hidden <input> field
// generated by csrf.FormField. The default is {{ .csrfToken }}
func FieldName(name string) Option {
	return func(cs *csrf) {
		cs.opts.FieldName = name
	}
}

// CookieName changes the name of the CSRF cookie issued to clients.
//
// Note that cookie names should not contain whitespace, commas, semicolons,
// backslashes or control characters as per RFC6265.
func CookieName(name string) Option {
	return func(cs *csrf) {
		cs.opts.CookieName = name
	}
}

// setStore sets the store used by the CSRF middleware.
// Note: this is private (for now) to allow for internal API changes.
func setStore(s store) Option {
	return func(cs *csrf) {
		cs.st = s
	}
}

// parseOptions parses the supplied options functions and returns a configured
// csrf handler.
func parseOptions(h http.Handler, opts ...Option) *csrf {
	// Set the handler to call after processing.
	cs := &csrf{
		h: h,
	}

	// Default to true. See Secure & HttpOnly function comments for rationale.
	// Set here to allow package users to override the default.
	cs.opts.Secure = true
	cs.opts.HttpOnly = true

	// Range over each options function and apply it
	// to our csrf type to configure it. Options functions are
	// applied in order, with any conflicting options overriding
	// earlier calls.
	for _, option := range opts {
		option(cs)
	}

	return cs
}
<|endoftext|>


<commit_before>package daemon

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/noironetworks/cilium-net/common"
	"github.com/noironetworks/cilium-net/common/types"

	consulAPI "github.com/noironetworks/cilium-net/Godeps/_workspace/src/github.com/hashicorp/consul/api"
)

func (d *Daemon) initializeFreeID() error {
	path := common.LastFreeIDKeyPath
	freeIDByte, err := json.Marshal(common.FirstFreeID)
	if err != nil {
		return err
	}
	session, _, err := d.consul.Session().CreateNoChecks(nil, nil)
	if err != nil {
		return err
	}

	p := &consulAPI.KVPair{Key: path, Value: freeIDByte}
	lockPair := &consulAPI.KVPair{Key: common.GetLockPath(path), Session: session}
	log.Debug("Trying to acquire lock for free ID...")
	acq, _, err := d.consul.KV().Acquire(lockPair, nil)
	if err != nil {
		return err
	}
	if !acq {
		return nil
	}
	defer d.consul.KV().Release(lockPair, nil)

	log.Debug("Trying to acquire free ID...")
	k, _, err := d.consul.KV().Get(path, nil)
	if err != nil {
		return err
	}
	if k != nil {
		// FreeID already set
		return nil
	}
	log.Info("Trying to put free ID...")
	_, err = d.consul.KV().Put(p, nil)
	if err != nil {
		return err
	}
	log.Info("Free ID successfully initialized")

	return nil
}

func (d *Daemon) updateIDRef(secCtxLabels *types.SecCtxLabel) error {
	var err error
	lblKey := &consulAPI.KVPair{Key: common.IDKeyPath + strconv.Itoa(secCtxLabels.ID)}
	lblKey.Value, err = json.Marshal(secCtxLabels)
	if err != nil {
		return err
	}
	_, err = d.consul.KV().Put(lblKey, nil)
	return err
}

// gasNewID gets and sets a New ID.
func (d *Daemon) gasNewID(labels *types.SecCtxLabel) error {
	freeID, err := d.GetMaxID()
	if err != nil {
		return err
	}

	setID2Label := func(lockPair *consulAPI.KVPair) error {
		defer d.consul.KV().Release(lockPair, nil)
		labels.ID = freeID
		if err := d.updateIDRef(labels); err != nil {
			return err
		}
		return d.setMaxID(freeID + 1)
	}

	session, _, err := d.consul.Session().CreateNoChecks(nil, nil)
	if err != nil {
		return err
	}

	beginning := freeID
	for {
		log.Debugf("Trying to aquire a new free ID %d", freeID)
		path := common.IDKeyPath + strconv.Itoa(freeID)

		lockPair := &consulAPI.KVPair{Key: common.GetLockPath(path), Session: session}
		acq, _, err := d.consul.KV().Acquire(lockPair, nil)
		if err != nil {
			return err
		}

		if acq {
			lblKey, _, err := d.consul.KV().Get(path, nil)
			if err != nil {
				d.consul.KV().Release(lockPair, nil)
				return err
			}
			if lblKey == nil {
				return setID2Label(lockPair)
			}
			var consulLabels types.SecCtxLabel
			if err := json.Unmarshal(lblKey.Value, &consulLabels); err != nil {
				d.consul.KV().Release(lockPair, nil)
				return err
			}
			if consulLabels.RefCount == 0 {
				log.Info("Recycling ID %d", freeID)
				return setID2Label(lockPair)
			}
			d.consul.KV().Release(lockPair, nil)
		}
		freeID++
		if freeID > common.MaxSetOfLabels {
			freeID = common.FirstFreeID
		}
		if beginning == freeID {
			return fmt.Errorf("Reached maximum set of labels available.")
		}
	}
	return nil
}

func (d *Daemon) lockPath(path string) (*consulAPI.Lock, <-chan struct{}, error) {
	log.Debugf("Creating lock for %s", path)
	opts := &consulAPI.LockOptions{
		Key: common.GetLockPath(path),
	}
	lockKey, err := d.consul.LockOpts(opts)
	if err != nil {
		return nil, nil, err
	}
	c, err := lockKey.Lock(nil)
	log.Debugf("Locked for %s", path)
	return lockKey, c, err
}

// PutLabels stores to given labels in consul and returns the SecCtxLabels created for
// the given labels.
func (d *Daemon) PutLabels(labels types.Labels) (*types.SecCtxLabel, bool, error) {
	log.Debugf("Putting labels %+v", labels)
	isNew := false

	// Retrieve unique SHA256Sum for labels
	sha256Sum, err := labels.SHA256Sum()
	if err != nil {
		return nil, false, err
	}
	lblPath := common.LabelsKeyPath + sha256Sum

	// Lock that sha256Sum
	lockKey, locker, err := d.lockPath(lblPath)
	if err != nil {
		return nil, false, err
	}
	if locker == nil {
		return nil, false, fmt.Errorf("locker is nil\n")
	}
	defer lockKey.Unlock()

	// After lock complete, get label's path
	pair, _, err := d.consul.KV().Get(lblPath, nil)
	if err != nil {
		return nil, false, err
	}

	var secCtxLbls types.SecCtxLabel
	if pair == nil {
		pair = &consulAPI.KVPair{Key: lblPath}
		secCtxLbls.Labels = labels
		secCtxLbls.RefCount = 1
		isNew = true
	} else {
		if err := json.Unmarshal(pair.Value, &secCtxLbls); err != nil {
			return nil, false, err
		}
		// If RefCount is 0 then we have to retrieve a new ID
		if secCtxLbls.RefCount == 0 {
			isNew = true
		}
		secCtxLbls.RefCount++
	}

	if isNew {
		if err := d.gasNewID(&secCtxLbls); err != nil {
			return nil, false, err
		}
	} else if err := d.updateIDRef(&secCtxLbls); err != nil {
		return nil, false, err
	}
	log.Debugf("Incrementing label %d ref-count to %d\n", secCtxLbls.ID, secCtxLbls.RefCount)

	secCtxLblsByte, err := json.Marshal(secCtxLbls)
	if err != nil {
		return nil, false, err
	}

	pair.Value = secCtxLblsByte
	_, err = d.consul.KV().Put(pair, nil)
	if err != nil {
		return nil, false, err
	}

	return &secCtxLbls, isNew, nil
}

// GetLabels returns the SecCtxLabels that belongs to id.
func (d *Daemon) GetLabels(id int) (*types.SecCtxLabel, error) {
	strID := strconv.Itoa(id)
	pair, _, err := d.consul.KV().Get(common.IDKeyPath+strID, nil)
	if err != nil {
		return nil, err
	}
	if pair == nil {
		return nil, nil
	}
	var secCtxLabels types.SecCtxLabel
	if err := json.Unmarshal(pair.Value, &secCtxLabels); err != nil {
		return nil, err
	}
	if secCtxLabels.RefCount == 0 {
		return nil, nil
	}
	return &secCtxLabels, nil
}

// DeleteLabelsByUUID deletes the SecCtxLabels belonging to id.
func (d *Daemon) DeleteLabelsByUUID(id int) error {
	secCtxLabels, err := d.GetLabels(id)
	if err != nil {
		return err
	}
	if secCtxLabels == nil {
		return nil
	}
	sha256sum, err := secCtxLabels.Labels.SHA256Sum()
	if err != nil {
		return err
	}

	return d.DeleteLabelsBySHA256(sha256sum)
}

// DeleteLabelsBySHA256 deletes the SecCtxLabels that belong to the labels' sha256Sum.
func (d *Daemon) DeleteLabelsBySHA256(sha256Sum string) error {
	if sha256Sum == "" {
		return nil
	}
	lblPath := common.LabelsKeyPath + sha256Sum
	// Lock that sha256Sum
	lockKey, locker, err := d.lockPath(lblPath)
	if err != nil {
		return err
	}
	if locker == nil {
		return fmt.Errorf("locker is nil\n")
	}
	defer lockKey.Unlock()

	// After lock complete, get label's path
	pair, _, err := d.consul.KV().Get(lblPath, nil)
	if err != nil {
		return err
	}

	var dbSecCtxLbls types.SecCtxLabel
	if pair == nil {
		return nil
	}
	if err := json.Unmarshal(pair.Value, &dbSecCtxLbls); err != nil {
		return err
	}
	if dbSecCtxLbls.RefCount > 0 {
		dbSecCtxLbls.RefCount--
	}
	if err := d.updateIDRef(&dbSecCtxLbls); err != nil {
		return err
	}
	log.Debugf("Decremented label %d ref-count to %d\n", dbSecCtxLbls.ID, dbSecCtxLbls.RefCount)

	secCtxLblsByte, err := json.Marshal(dbSecCtxLbls)
	if err != nil {
		return err
	}

	pair.Value = secCtxLblsByte
	_, err = d.consul.KV().Put(pair, nil)
	if err != nil {
		return err
	}

	return nil
}

// GetMaxID returns the maximum possible free UUID stored in consul.
func (d *Daemon) GetMaxID() (int, error) {
	k, _, err := d.consul.KV().Get(common.LastFreeIDKeyPath, nil)
	if err != nil {
		return -1, err
	}
	if k == nil {
		// FreeID is empty? We should set it out!
		log.Infof("Empty FreeID, setting it up with default value %d", common.FirstFreeID)
		if err := d.initializeFreeID(); err != nil {
			return -1, err
		}
		k, _, err = d.consul.KV().Get(common.LastFreeIDKeyPath, nil)
		if k == nil {
			// Something is really wrong
			errMsg := "Unable to retrieve last free ID because the key is always empty\n"
			log.Errorf(errMsg)
			return -1, fmt.Errorf(errMsg)
		}
	}
	var freeID int
	log.Debugf("Retrieving max free ID %v", k.Value)
	if err := json.Unmarshal(k.Value, &freeID); err != nil {
		return -1, err
	}
	return freeID, nil
}

func (d *Daemon) setMaxID(freeID int) error {
	k, _, err := d.consul.KV().Get(common.LastFreeIDKeyPath, nil)
	if err != nil {
		return err
	}
	if k == nil {
		// FreeIDs is empty? We should set it out!
		if err := d.initializeFreeID(); err != nil {
			return err
		}
		k, _, err = d.consul.KV().Get(common.LastFreeIDKeyPath, nil)
		if k == nil {
			// Something is really wrong
			errMsg := "Unable to setting ID because the key is always empty\n"
			log.Errorf(errMsg)
			return fmt.Errorf(errMsg)
		}
	}
	k.Value, err = json.Marshal(freeID)
	if err != nil {
		return err
	}
	_, err = d.consul.KV().Put(k, nil)
	return err
}
<commit_msg>Deleting unreachable code in label's daemon<commit_after>package daemon

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/noironetworks/cilium-net/common"
	"github.com/noironetworks/cilium-net/common/types"

	consulAPI "github.com/noironetworks/cilium-net/Godeps/_workspace/src/github.com/hashicorp/consul/api"
)

func (d *Daemon) initializeFreeID() error {
	path := common.LastFreeIDKeyPath
	freeIDByte, err := json.Marshal(common.FirstFreeID)
	if err != nil {
		return err
	}
	session, _, err := d.consul.Session().CreateNoChecks(nil, nil)
	if err != nil {
		return err
	}

	p := &consulAPI.KVPair{Key: path, Value: freeIDByte}
	lockPair := &consulAPI.KVPair{Key: common.GetLockPath(path), Session: session}
	log.Debug("Trying to acquire lock for free ID...")
	acq, _, err := d.consul.KV().Acquire(lockPair, nil)
	if err != nil {
		return err
	}
	if !acq {
		return nil
	}
	defer d.consul.KV().Release(lockPair, nil)

	log.Debug("Trying to acquire free ID...")
	k, _, err := d.consul.KV().Get(path, nil)
	if err != nil {
		return err
	}
	if k != nil {
		// FreeID already set
		return nil
	}
	log.Info("Trying to put free ID...")
	_, err = d.consul.KV().Put(p, nil)
	if err != nil {
		return err
	}
	log.Info("Free ID successfully initialized")

	return nil
}

func (d *Daemon) updateIDRef(secCtxLabels *types.SecCtxLabel) error {
	var err error
	lblKey := &consulAPI.KVPair{Key: common.IDKeyPath + strconv.Itoa(secCtxLabels.ID)}
	lblKey.Value, err = json.Marshal(secCtxLabels)
	if err != nil {
		return err
	}
	_, err = d.consul.KV().Put(lblKey, nil)
	return err
}

// gasNewID gets and sets a New ID.
func (d *Daemon) gasNewID(labels *types.SecCtxLabel) error {
	freeID, err := d.GetMaxID()
	if err != nil {
		return err
	}

	setID2Label := func(lockPair *consulAPI.KVPair) error {
		defer d.consul.KV().Release(lockPair, nil)
		labels.ID = freeID
		if err := d.updateIDRef(labels); err != nil {
			return err
		}
		return d.setMaxID(freeID + 1)
	}

	session, _, err := d.consul.Session().CreateNoChecks(nil, nil)
	if err != nil {
		return err
	}

	beginning := freeID
	for {
		log.Debugf("Trying to aquire a new free ID %d", freeID)
		path := common.IDKeyPath + strconv.Itoa(freeID)

		lockPair := &consulAPI.KVPair{Key: common.GetLockPath(path), Session: session}
		acq, _, err := d.consul.KV().Acquire(lockPair, nil)
		if err != nil {
			return err
		}

		if acq {
			lblKey, _, err := d.consul.KV().Get(path, nil)
			if err != nil {
				d.consul.KV().Release(lockPair, nil)
				return err
			}
			if lblKey == nil {
				return setID2Label(lockPair)
			}
			var consulLabels types.SecCtxLabel
			if err := json.Unmarshal(lblKey.Value, &consulLabels); err != nil {
				d.consul.KV().Release(lockPair, nil)
				return err
			}
			if consulLabels.RefCount == 0 {
				log.Info("Recycling ID %d", freeID)
				return setID2Label(lockPair)
			}
			d.consul.KV().Release(lockPair, nil)
		}
		freeID++
		if freeID > common.MaxSetOfLabels {
			freeID = common.FirstFreeID
		}
		if beginning == freeID {
			return fmt.Errorf("Reached maximum set of labels available.")
		}
	}
}

func (d *Daemon) lockPath(path string) (*consulAPI.Lock, <-chan struct{}, error) {
	log.Debugf("Creating lock for %s", path)
	opts := &consulAPI.LockOptions{
		Key: common.GetLockPath(path),
	}
	lockKey, err := d.consul.LockOpts(opts)
	if err != nil {
		return nil, nil, err
	}
	c, err := lockKey.Lock(nil)
	log.Debugf("Locked for %s", path)
	return lockKey, c, err
}

// PutLabels stores to given labels in consul and returns the SecCtxLabels created for
// the given labels.
func (d *Daemon) PutLabels(labels types.Labels) (*types.SecCtxLabel, bool, error) {
	log.Debugf("Putting labels %+v", labels)
	isNew := false

	// Retrieve unique SHA256Sum for labels
	sha256Sum, err := labels.SHA256Sum()
	if err != nil {
		return nil, false, err
	}
	lblPath := common.LabelsKeyPath + sha256Sum

	// Lock that sha256Sum
	lockKey, locker, err := d.lockPath(lblPath)
	if err != nil {
		return nil, false, err
	}
	if locker == nil {
		return nil, false, fmt.Errorf("locker is nil\n")
	}
	defer lockKey.Unlock()

	// After lock complete, get label's path
	pair, _, err := d.consul.KV().Get(lblPath, nil)
	if err != nil {
		return nil, false, err
	}

	var secCtxLbls types.SecCtxLabel
	if pair == nil {
		pair = &consulAPI.KVPair{Key: lblPath}
		secCtxLbls.Labels = labels
		secCtxLbls.RefCount = 1
		isNew = true
	} else {
		if err := json.Unmarshal(pair.Value, &secCtxLbls); err != nil {
			return nil, false, err
		}
		// If RefCount is 0 then we have to retrieve a new ID
		if secCtxLbls.RefCount == 0 {
			isNew = true
		}
		secCtxLbls.RefCount++
	}

	if isNew {
		if err := d.gasNewID(&secCtxLbls); err != nil {
			return nil, false, err
		}
	} else if err := d.updateIDRef(&secCtxLbls); err != nil {
		return nil, false, err
	}
	log.Debugf("Incrementing label %d ref-count to %d\n", secCtxLbls.ID, secCtxLbls.RefCount)

	secCtxLblsByte, err := json.Marshal(secCtxLbls)
	if err != nil {
		return nil, false, err
	}

	pair.Value = secCtxLblsByte
	_, err = d.consul.KV().Put(pair, nil)
	if err != nil {
		return nil, false, err
	}

	return &secCtxLbls, isNew, nil
}

// GetLabels returns the SecCtxLabels that belongs to id.
func (d *Daemon) GetLabels(id int) (*types.SecCtxLabel, error) {
	strID := strconv.Itoa(id)
	pair, _, err := d.consul.KV().Get(common.IDKeyPath+strID, nil)
	if err != nil {
		return nil, err
	}
	if pair == nil {
		return nil, nil
	}
	var secCtxLabels types.SecCtxLabel
	if err := json.Unmarshal(pair.Value, &secCtxLabels); err != nil {
		return nil, err
	}
	if secCtxLabels.RefCount == 0 {
		return nil, nil
	}
	return &secCtxLabels, nil
}

// DeleteLabelsByUUID deletes the SecCtxLabels belonging to id.
func (d *Daemon) DeleteLabelsByUUID(id int) error {
	secCtxLabels, err := d.GetLabels(id)
	if err != nil {
		return err
	}
	if secCtxLabels == nil {
		return nil
	}
	sha256sum, err := secCtxLabels.Labels.SHA256Sum()
	if err != nil {
		return err
	}

	return d.DeleteLabelsBySHA256(sha256sum)
}

// DeleteLabelsBySHA256 deletes the SecCtxLabels that belong to the labels' sha256Sum.
func (d *Daemon) DeleteLabelsBySHA256(sha256Sum string) error {
	if sha256Sum == "" {
		return nil
	}
	lblPath := common.LabelsKeyPath + sha256Sum
	// Lock that sha256Sum
	lockKey, locker, err := d.lockPath(lblPath)
	if err != nil {
		return err
	}
	if locker == nil {
		return fmt.Errorf("locker is nil\n")
	}
	defer lockKey.Unlock()

	// After lock complete, get label's path
	pair, _, err := d.consul.KV().Get(lblPath, nil)
	if err != nil {
		return err
	}

	var dbSecCtxLbls types.SecCtxLabel
	if pair == nil {
		return nil
	}
	if err := json.Unmarshal(pair.Value, &dbSecCtxLbls); err != nil {
		return err
	}
	if dbSecCtxLbls.RefCount > 0 {
		dbSecCtxLbls.RefCount--
	}
	if err := d.updateIDRef(&dbSecCtxLbls); err != nil {
		return err
	}
	log.Debugf("Decremented label %d ref-count to %d\n", dbSecCtxLbls.ID, dbSecCtxLbls.RefCount)

	secCtxLblsByte, err := json.Marshal(dbSecCtxLbls)
	if err != nil {
		return err
	}

	pair.Value = secCtxLblsByte
	_, err = d.consul.KV().Put(pair, nil)
	if err != nil {
		return err
	}

	return nil
}

// GetMaxID returns the maximum possible free UUID stored in consul.
func (d *Daemon) GetMaxID() (int, error) {
	k, _, err := d.consul.KV().Get(common.LastFreeIDKeyPath, nil)
	if err != nil {
		return -1, err
	}
	if k == nil {
		// FreeID is empty? We should set it out!
		log.Infof("Empty FreeID, setting it up with default value %d", common.FirstFreeID)
		if err := d.initializeFreeID(); err != nil {
			return -1, err
		}
		k, _, err = d.consul.KV().Get(common.LastFreeIDKeyPath, nil)
		if k == nil {
			// Something is really wrong
			errMsg := "Unable to retrieve last free ID because the key is always empty\n"
			log.Errorf(errMsg)
			return -1, fmt.Errorf(errMsg)
		}
	}
	var freeID int
	log.Debugf("Retrieving max free ID %v", k.Value)
	if err := json.Unmarshal(k.Value, &freeID); err != nil {
		return -1, err
	}
	return freeID, nil
}

func (d *Daemon) setMaxID(freeID int) error {
	k, _, err := d.consul.KV().Get(common.LastFreeIDKeyPath, nil)
	if err != nil {
		return err
	}
	if k == nil {
		// FreeIDs is empty? We should set it out!
		if err := d.initializeFreeID(); err != nil {
			return err
		}
		k, _, err = d.consul.KV().Get(common.LastFreeIDKeyPath, nil)
		if k == nil {
			// Something is really wrong
			errMsg := "Unable to setting ID because the key is always empty\n"
			log.Errorf(errMsg)
			return fmt.Errorf(errMsg)
		}
	}
	k.Value, err = json.Marshal(freeID)
	if err != nil {
		return err
	}
	_, err = d.consul.KV().Put(k, nil)
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mitchellh/go-homedir"
)

var (
	ShortGitHubURI = regexp.MustCompile(`^[\w\-.]+/[\w\-.]+$`)
)

func ToSourceURI(uri string) (string, error) {
	switch {
	case ShortGitHubURI.MatchString(uri):
		return "https://github.com/" + uri, nil
	default:
		return uri, nil
	}
}

var (
	home, errInit = homedir.Dir()
	dotvim        = filepath.Join(home, ".vim")
)

func ToDestinationPath(uri, filetype string) (string, error) {
	name := filepath.Base(uri)
	if filetype == "" {
		return filepath.Join(dotvim, "bundle", name), nil
	}
	return filepath.Join(dotvim, "ftbundle", filetype, name), nil
}

type Package struct {
	src string
	dst string
}

func NewPackage(uri, filetype string) (*Package, error) {
	src, err := ToSourceURI(uri)
	if err != nil {
		return nil, err
	}
	dst, err := ToDestinationPath(uri, filetype)
	if err != nil {
		return nil, err
	}
	return &Package{
		src: src,
		dst: dst,
	}, nil
}

func (p *Package) toInstallCommand() *exec.Cmd {
	return exec.Command("git", "clone", p.src, p.dst)
}

func (p *Package) installed() bool {
	_, err := os.Stat(p.dst)
	return err == nil
}

func (p *Package) Install() error {
	if p.installed() {
		return nil
	}
	if _, err := exec.LookPath("git"); err != nil {
		return err
	}

	errMessage := bytes.NewBuffer(make([]byte, 0))

	installcmd := p.toInstallCommand()
	installcmd.Stderr = errMessage
	if err := installcmd.Run(); err != nil {
		return fmt.Errorf("%s", strings.TrimSpace(errMessage.String()))
	}
	return nil
}

func (p *Package) Remove() error {
	if !p.installed() {
		return nil
	}
	return os.RemoveAll(p.dst)
}

func (p *Package) Update() error {
	if p.installed() {
		return p.Remove()
	}
	return p.Install()
}
<commit_msg>Fix exit without install if installed package at update<commit_after>package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/mitchellh/go-homedir"
)

var (
	ShortGitHubURI = regexp.MustCompile(`^[\w\-.]+/[\w\-.]+$`)
)

func ToSourceURI(uri string) (string, error) {
	switch {
	case ShortGitHubURI.MatchString(uri):
		return "https://github.com/" + uri, nil
	default:
		return uri, nil
	}
}

var (
	home, errInit = homedir.Dir()
	dotvim        = filepath.Join(home, ".vim")
)

func ToDestinationPath(uri, filetype string) (string, error) {
	name := filepath.Base(uri)
	if filetype == "" {
		return filepath.Join(dotvim, "bundle", name), nil
	}
	return filepath.Join(dotvim, "ftbundle", filetype, name), nil
}

type Package struct {
	src string
	dst string
}

func NewPackage(uri, filetype string) (*Package, error) {
	src, err := ToSourceURI(uri)
	if err != nil {
		return nil, err
	}
	dst, err := ToDestinationPath(uri, filetype)
	if err != nil {
		return nil, err
	}
	return &Package{
		src: src,
		dst: dst,
	}, nil
}

func (p *Package) toInstallCommand() *exec.Cmd {
	return exec.Command("git", "clone", p.src, p.dst)
}

func (p *Package) installed() bool {
	_, err := os.Stat(p.dst)
	return err == nil
}

func (p *Package) Install() error {
	if p.installed() {
		return nil
	}
	if _, err := exec.LookPath("git"); err != nil {
		return err
	}

	errMessage := bytes.NewBuffer(make([]byte, 0))

	installcmd := p.toInstallCommand()
	installcmd.Stderr = errMessage
	if err := installcmd.Run(); err != nil {
		return fmt.Errorf("%s", strings.TrimSpace(errMessage.String()))
	}
	return nil
}

func (p *Package) Remove() error {
	if !p.installed() {
		return nil
	}
	return os.RemoveAll(p.dst)
}

func (p *Package) Update() error {
	if p.installed() {
		p.Remove()
	}
	return p.Install()
}
<|endoftext|>