<commit_before>// Copyright 2018 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.

// This file implements type parameter substitution.

package types

import (
	"bytes"
	"go/token"
)

// TODO(rFindley) decide error codes for the errors in this file, and check
//                if error spans can be improved

type substMap map[*TypeParam]Type

// makeSubstMap creates a new substitution map mapping tpars[i] to targs[i].
// If targs[i] is nil, tpars[i] is not substituted.
func makeSubstMap(tpars []*TypeName, targs []Type) substMap {
	assert(len(tpars) == len(targs))
	proj := make(substMap, len(tpars))
	for i, tpar := range tpars {
		proj[tpar.typ.(*TypeParam)] = targs[i]
	}
	return proj
}

func (m substMap) empty() bool {
	return len(m) == 0
}

func (m substMap) lookup(tpar *TypeParam) Type {
	if t := m[tpar]; t != nil {
		return t
	}
	return tpar
}

// subst returns the type typ with its type parameters tpars replaced by
// the corresponding type arguments targs, recursively.
// subst is functional in the sense that it doesn't modify the incoming
// type. If a substitution took place, the result type is different from
// from the incoming type.
//
// If the given typMap is nil and check is non-nil, check.typMap is used.
func (check *Checker) subst(pos token.Pos, typ Type, smap substMap, typMap map[string]*Named) Type {
	if smap.empty() {
		return typ
	}

	// common cases
	switch t := typ.(type) {
	case *Basic:
		return typ // nothing to do
	case *TypeParam:
		return smap.lookup(t)
	}

	// general case
	var subst subster
	subst.pos = pos
	subst.smap = smap

	if check != nil {
		subst.check = check
		if typMap == nil {
			typMap = check.typMap
		}
	}
	if typMap == nil {
		// If we don't have a *Checker and its global type map,
		// use a local version. Besides avoiding duplicate work,
		// the type map prevents infinite recursive substitution
		// for recursive types (example: type T[P any] *T[P]).
		typMap = make(map[string]*Named)
	}
	subst.typMap = typMap

	return subst.typ(typ)
}

type subster struct {
	pos    token.Pos
	smap   substMap
	check  *Checker // nil if called via Instantiate
	typMap map[string]*Named
}

func (subst *subster) typ(typ Type) Type {
	switch t := typ.(type) {
	case nil:
		// Call typOrNil if it's possible that typ is nil.
		panic("nil typ")

	case *Basic, *top:
		// nothing to do

	case *Array:
		elem := subst.typOrNil(t.elem)
		if elem != t.elem {
			return &Array{len: t.len, elem: elem}
		}

	case *Slice:
		elem := subst.typOrNil(t.elem)
		if elem != t.elem {
			return &Slice{elem: elem}
		}

	case *Struct:
		if fields, copied := subst.varList(t.fields); copied {
			return &Struct{fields: fields, tags: t.tags}
		}

	case *Pointer:
		base := subst.typ(t.base)
		if base != t.base {
			return &Pointer{base: base}
		}

	case *Tuple:
		return subst.tuple(t)

	case *Signature:
		// TODO(gri) rethink the recv situation with respect to methods on parameterized types
		// recv := subst.var_(t.recv) // TODO(gri) this causes a stack overflow - explain
		recv := t.recv
		params := subst.tuple(t.params)
		results := subst.tuple(t.results)
		if recv != t.recv || params != t.params || results != t.results {
			return &Signature{
				rparams: t.rparams,
				// TODO(rFindley) why can't we nil out tparams here, rather than in
				//                instantiate above?
				tparams:  t.tparams,
				scope:    t.scope,
				recv:     recv,
				params:   params,
				results:  results,
				variadic: t.variadic,
			}
		}

	case *Union:
		terms, copied := subst.termlist(t.terms)
		if copied {
			// term list substitution may introduce duplicate terms (unlikely but possible).
			// This is ok; lazy type set computation will determine the actual type set
			// in normal form.
			return &Union{terms, nil}
		}

	case *Interface:
		methods, mcopied := subst.funcList(t.methods)
		embeddeds, ecopied := subst.typeList(t.embeddeds)
		if mcopied || ecopied {
			iface := &Interface{methods: methods, embeddeds: embeddeds, complete: t.complete}
			if subst.check == nil {
				panic("internal error: cannot instantiate interfaces yet")
			}
			return iface
		}

	case *Map:
		key := subst.typ(t.key)
		elem := subst.typ(t.elem)
		if key != t.key || elem != t.elem {
			return &Map{key: key, elem: elem}
		}

	case *Chan:
		elem := subst.typ(t.elem)
		if elem != t.elem {
			return &Chan{dir: t.dir, elem: elem}
		}

	case *Named:
		// dump is for debugging
		dump := func(string, ...interface{}) {}
		if subst.check != nil && trace {
			subst.check.indent++
			defer func() {
				subst.check.indent--
			}()
			dump = func(format string, args ...interface{}) {
				subst.check.trace(subst.pos, format, args...)
			}
		}

		if t.TParams().Len() == 0 {
			dump(">>> %s is not parameterized", t)
			return t // type is not parameterized
		}

		var newTArgs []Type
		assert(len(t.targs) == t.TParams().Len())

		// already instantiated
		dump(">>> %s already instantiated", t)
		// For each (existing) type argument targ, determine if it needs
		// to be substituted; i.e., if it is or contains a type parameter
		// that has a type argument for it.
		for i, targ := range t.targs {
			dump(">>> %d targ = %s", i, targ)
			new_targ := subst.typ(targ)
			if new_targ != targ {
				dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
				if newTArgs == nil {
					newTArgs = make([]Type, t.TParams().Len())
					copy(newTArgs, t.targs)
				}
				newTArgs[i] = new_targ
			}
		}

		if newTArgs == nil {
			dump(">>> nothing to substitute in %s", t)
			return t // nothing to substitute
		}

		// before creating a new named type, check if we have this one already
		h := instantiatedHash(t, newTArgs)
		dump(">>> new type hash: %s", h)
		if named, found := subst.typMap[h]; found {
			dump(">>> found %s", named)
			return named
		}

		// create a new named type and populate typMap to avoid endless recursion
		tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
		t.load()
		named := subst.check.newNamed(tname, t.orig, t.underlying, t.TParams(), t.methods) // method signatures are updated lazily
		named.targs = newTArgs
		subst.typMap[h] = named
		t.expand(subst.typMap) // must happen after typMap update to avoid infinite recursion

		// do the substitution
		dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTArgs)
		named.underlying = subst.typOrNil(t.underlying)
		dump(">>> underlying: %v", named.underlying)
		assert(named.underlying != nil)
		named.fromRHS = named.underlying // for cycle detection (Checker.validType)

		return named

	case *TypeParam:
		return subst.smap.lookup(t)

	default:
		panic("unimplemented")
	}

	return typ
}

var instanceHashing = 0

func instantiatedHash(typ *Named, targs []Type) string {
	assert(instanceHashing == 0)
	instanceHashing++
	var buf bytes.Buffer
	writeTypeName(&buf, typ.obj, nil)
	buf.WriteByte('[')
	writeTypeList(&buf, targs, nil, nil)
	buf.WriteByte(']')
	instanceHashing--

	// With respect to the represented type, whether a
	// type is fully expanded or stored as instance
	// does not matter - they are the same types.
	// Remove the instanceMarkers printed for instances.
	res := buf.Bytes()
	i := 0
	for _, b := range res {
		if b != instanceMarker {
			res[i] = b
			i++
		}
	}

	return string(res[:i])
}

func typeListString(list []Type) string {
	var buf bytes.Buffer
	writeTypeList(&buf, list, nil, nil)
	return buf.String()
}

// typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid].
// A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_))
// where an array/slice element is accessed before it is set up.
func (subst *subster) typOrNil(typ Type) Type {
	if typ == nil {
		return Typ[Invalid]
	}
	return subst.typ(typ)
}

func (subst *subster) var_(v *Var) *Var {
	if v != nil {
		if typ := subst.typ(v.typ); typ != v.typ {
			copy := *v
			copy.typ = typ
			return &copy
		}
	}
	return v
}

func (subst *subster) tuple(t *Tuple) *Tuple {
	if t != nil {
		if vars, copied := subst.varList(t.vars); copied {
			return &Tuple{vars: vars}
		}
	}
	return t
}

func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
	out = in
	for i, v := range in {
		if w := subst.var_(v); w != v {
			if !copied {
				// first variable that got substituted => allocate new out slice
				// and copy all variables
				new := make([]*Var, len(in))
				copy(new, out)
				out = new
				copied = true
			}
			out[i] = w
		}
	}
	return
}

func (subst *subster) func_(f *Func) *Func {
	if f != nil {
		if typ := subst.typ(f.typ); typ != f.typ {
			copy := *f
			copy.typ = typ
			return &copy
		}
	}
	return f
}

func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
	out = in
	for i, f := range in {
		if g := subst.func_(f); g != f {
			if !copied {
				// first function that got substituted => allocate new out slice
				// and copy all functions
				new := make([]*Func, len(in))
				copy(new, out)
				out = new
				copied = true
			}
			out[i] = g
		}
	}
	return
}

func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
	out = in
	for i, t := range in {
		if u := subst.typ(t); u != t {
			if !copied {
				// first function that got substituted => allocate new out slice
				// and copy all functions
				new := make([]Type, len(in))
				copy(new, out)
				out = new
				copied = true
			}
			out[i] = u
		}
	}
	return
}

func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
	out = in
	for i, t := range in {
		if u := subst.typ(t.typ); u != t.typ {
			if !copied {
				// first function that got substituted => allocate new out slice
				// and copy all functions
				new := make([]*Term, len(in))
				copy(new, out)
				out = new
				copied = true
			}
			out[i] = NewTerm(t.tilde, u)
		}
	}
	return
}
<commit_msg>go/types: no need to validate substituted instances<commit_after>// Copyright 2018 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.

// This file implements type parameter substitution.

package types

import (
	"bytes"
	"go/token"
)

// TODO(rFindley) decide error codes for the errors in this file, and check
//                if error spans can be improved

type substMap map[*TypeParam]Type

// makeSubstMap creates a new substitution map mapping tpars[i] to targs[i].
// If targs[i] is nil, tpars[i] is not substituted.
func makeSubstMap(tpars []*TypeName, targs []Type) substMap {
	assert(len(tpars) == len(targs))
	proj := make(substMap, len(tpars))
	for i, tpar := range tpars {
		proj[tpar.typ.(*TypeParam)] = targs[i]
	}
	return proj
}

func (m substMap) empty() bool {
	return len(m) == 0
}

func (m substMap) lookup(tpar *TypeParam) Type {
	if t := m[tpar]; t != nil {
		return t
	}
	return tpar
}

// subst returns the type typ with its type parameters tpars replaced by
// the corresponding type arguments targs, recursively.
// subst is functional in the sense that it doesn't modify the incoming
// type. If a substitution took place, the result type is different from
// from the incoming type.
//
// If the given typMap is nil and check is non-nil, check.typMap is used.
func (check *Checker) subst(pos token.Pos, typ Type, smap substMap, typMap map[string]*Named) Type {
	if smap.empty() {
		return typ
	}

	// common cases
	switch t := typ.(type) {
	case *Basic:
		return typ // nothing to do
	case *TypeParam:
		return smap.lookup(t)
	}

	// general case
	var subst subster
	subst.pos = pos
	subst.smap = smap

	if check != nil {
		subst.check = check
		if typMap == nil {
			typMap = check.typMap
		}
	}
	if typMap == nil {
		// If we don't have a *Checker and its global type map,
		// use a local version. Besides avoiding duplicate work,
		// the type map prevents infinite recursive substitution
		// for recursive types (example: type T[P any] *T[P]).
		typMap = make(map[string]*Named)
	}
	subst.typMap = typMap

	return subst.typ(typ)
}

type subster struct {
	pos    token.Pos
	smap   substMap
	check  *Checker // nil if called via Instantiate
	typMap map[string]*Named
}

func (subst *subster) typ(typ Type) Type {
	switch t := typ.(type) {
	case nil:
		// Call typOrNil if it's possible that typ is nil.
		panic("nil typ")

	case *Basic, *top:
		// nothing to do

	case *Array:
		elem := subst.typOrNil(t.elem)
		if elem != t.elem {
			return &Array{len: t.len, elem: elem}
		}

	case *Slice:
		elem := subst.typOrNil(t.elem)
		if elem != t.elem {
			return &Slice{elem: elem}
		}

	case *Struct:
		if fields, copied := subst.varList(t.fields); copied {
			return &Struct{fields: fields, tags: t.tags}
		}

	case *Pointer:
		base := subst.typ(t.base)
		if base != t.base {
			return &Pointer{base: base}
		}

	case *Tuple:
		return subst.tuple(t)

	case *Signature:
		// TODO(gri) rethink the recv situation with respect to methods on parameterized types
		// recv := subst.var_(t.recv) // TODO(gri) this causes a stack overflow - explain
		recv := t.recv
		params := subst.tuple(t.params)
		results := subst.tuple(t.results)
		if recv != t.recv || params != t.params || results != t.results {
			return &Signature{
				rparams: t.rparams,
				// TODO(rFindley) why can't we nil out tparams here, rather than in
				//                instantiate above?
				tparams:  t.tparams,
				scope:    t.scope,
				recv:     recv,
				params:   params,
				results:  results,
				variadic: t.variadic,
			}
		}

	case *Union:
		terms, copied := subst.termlist(t.terms)
		if copied {
			// term list substitution may introduce duplicate terms (unlikely but possible).
			// This is ok; lazy type set computation will determine the actual type set
			// in normal form.
			return &Union{terms, nil}
		}

	case *Interface:
		methods, mcopied := subst.funcList(t.methods)
		embeddeds, ecopied := subst.typeList(t.embeddeds)
		if mcopied || ecopied {
			iface := &Interface{methods: methods, embeddeds: embeddeds, complete: t.complete}
			if subst.check == nil {
				panic("internal error: cannot instantiate interfaces yet")
			}
			return iface
		}

	case *Map:
		key := subst.typ(t.key)
		elem := subst.typ(t.elem)
		if key != t.key || elem != t.elem {
			return &Map{key: key, elem: elem}
		}

	case *Chan:
		elem := subst.typ(t.elem)
		if elem != t.elem {
			return &Chan{dir: t.dir, elem: elem}
		}

	case *Named:
		// dump is for debugging
		dump := func(string, ...interface{}) {}
		if subst.check != nil && trace {
			subst.check.indent++
			defer func() {
				subst.check.indent--
			}()
			dump = func(format string, args ...interface{}) {
				subst.check.trace(subst.pos, format, args...)
			}
		}

		if t.TParams().Len() == 0 {
			dump(">>> %s is not parameterized", t)
			return t // type is not parameterized
		}

		var newTArgs []Type
		assert(len(t.targs) == t.TParams().Len())

		// already instantiated
		dump(">>> %s already instantiated", t)
		// For each (existing) type argument targ, determine if it needs
		// to be substituted; i.e., if it is or contains a type parameter
		// that has a type argument for it.
		for i, targ := range t.targs {
			dump(">>> %d targ = %s", i, targ)
			new_targ := subst.typ(targ)
			if new_targ != targ {
				dump(">>> substituted %d targ %s => %s", i, targ, new_targ)
				if newTArgs == nil {
					newTArgs = make([]Type, t.TParams().Len())
					copy(newTArgs, t.targs)
				}
				newTArgs[i] = new_targ
			}
		}

		if newTArgs == nil {
			dump(">>> nothing to substitute in %s", t)
			return t // nothing to substitute
		}

		// before creating a new named type, check if we have this one already
		h := instantiatedHash(t, newTArgs)
		dump(">>> new type hash: %s", h)
		if named, found := subst.typMap[h]; found {
			dump(">>> found %s", named)
			return named
		}

		// Create a new named type and populate typMap to avoid endless recursion.
		// The position used here is irrelevant because validation only occurs on t
		// (we don't call validType on named), but we use subst.pos to help with
		// debugging.
		tname := NewTypeName(subst.pos, t.obj.pkg, t.obj.name, nil)
		t.load()
		// It's ok to provide a nil *Checker because the newly created type
		// doesn't need to be (lazily) expanded; it's expanded below.
		named := (*Checker)(nil).newNamed(tname, t.orig, nil, t.tparams, t.methods) // t is loaded, so tparams and methods are available
		named.targs = newTArgs
		subst.typMap[h] = named
		t.expand(subst.typMap) // must happen after typMap update to avoid infinite recursion

		// do the substitution
		dump(">>> subst %s with %s (new: %s)", t.underlying, subst.smap, newTArgs)
		named.underlying = subst.typOrNil(t.underlying)
		dump(">>> underlying: %v", named.underlying)
		assert(named.underlying != nil)
		named.fromRHS = named.underlying // for consistency, though no cycle detection is necessary

		return named

	case *TypeParam:
		return subst.smap.lookup(t)

	default:
		panic("unimplemented")
	}

	return typ
}

var instanceHashing = 0

func instantiatedHash(typ *Named, targs []Type) string {
	assert(instanceHashing == 0)
	instanceHashing++
	var buf bytes.Buffer
	writeTypeName(&buf, typ.obj, nil)
	buf.WriteByte('[')
	writeTypeList(&buf, targs, nil, nil)
	buf.WriteByte(']')
	instanceHashing--

	// With respect to the represented type, whether a
	// type is fully expanded or stored as instance
	// does not matter - they are the same types.
	// Remove the instanceMarkers printed for instances.
	res := buf.Bytes()
	i := 0
	for _, b := range res {
		if b != instanceMarker {
			res[i] = b
			i++
		}
	}

	return string(res[:i])
}

func typeListString(list []Type) string {
	var buf bytes.Buffer
	writeTypeList(&buf, list, nil, nil)
	return buf.String()
}

// typOrNil is like typ but if the argument is nil it is replaced with Typ[Invalid].
// A nil type may appear in pathological cases such as type T[P any] []func(_ T([]_))
// where an array/slice element is accessed before it is set up.
func (subst *subster) typOrNil(typ Type) Type {
	if typ == nil {
		return Typ[Invalid]
	}
	return subst.typ(typ)
}

func (subst *subster) var_(v *Var) *Var {
	if v != nil {
		if typ := subst.typ(v.typ); typ != v.typ {
			copy := *v
			copy.typ = typ
			return &copy
		}
	}
	return v
}

func (subst *subster) tuple(t *Tuple) *Tuple {
	if t != nil {
		if vars, copied := subst.varList(t.vars); copied {
			return &Tuple{vars: vars}
		}
	}
	return t
}

func (subst *subster) varList(in []*Var) (out []*Var, copied bool) {
	out = in
	for i, v := range in {
		if w := subst.var_(v); w != v {
			if !copied {
				// first variable that got substituted => allocate new out slice
				// and copy all variables
				new := make([]*Var, len(in))
				copy(new, out)
				out = new
				copied = true
			}
			out[i] = w
		}
	}
	return
}

func (subst *subster) func_(f *Func) *Func {
	if f != nil {
		if typ := subst.typ(f.typ); typ != f.typ {
			copy := *f
			copy.typ = typ
			return &copy
		}
	}
	return f
}

func (subst *subster) funcList(in []*Func) (out []*Func, copied bool) {
	out = in
	for i, f := range in {
		if g := subst.func_(f); g != f {
			if !copied {
				// first function that got substituted => allocate new out slice
				// and copy all functions
				new := make([]*Func, len(in))
				copy(new, out)
				out = new
				copied = true
			}
			out[i] = g
		}
	}
	return
}

func (subst *subster) typeList(in []Type) (out []Type, copied bool) {
	out = in
	for i, t := range in {
		if u := subst.typ(t); u != t {
			if !copied {
				// first function that got substituted => allocate new out slice
				// and copy all functions
				new := make([]Type, len(in))
				copy(new, out)
				out = new
				copied = true
			}
			out[i] = u
		}
	}
	return
}

func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) {
	out = in
	for i, t := range in {
		if u := subst.typ(t.typ); u != t.typ {
			if !copied {
				// first function that got substituted => allocate new out slice
				// and copy all functions
				new := make([]*Term, len(in))
				copy(new, out)
				out = new
				copied = true
			}
			out[i] = NewTerm(t.tilde, u)
		}
	}
	return
}
<|endoftext|>


<commit_before>package goat

// Holds information for request from database
type Request struct {
	Query        string
	ResponseChan chan Response
}

// Holds information for response from database
type Response struct {
	Data, Id string
}

// DbHandler interface method HandleDb defines a database handler which handles requests
type DbHandler interface {
	HandleDb()
}

// MapDb is a key value storage database
// Id will be an identification for sharding
type MapDb struct {
	Id string
	Db map[string]interface{}
}

// Handle data MapDb requests
func (m MapDb) HandleDb() {

}

// SqlDb is a sql based database
type SqlDb struct {
}

// Handle Sql based requests
func (s SqlDb) HandleDb() {

}
<commit_msg>Request<commit_after>package goat

// Holds information for request from database
type Request struct {
	Id           string
	Read, Write  bool
	Data         interface{}
	ResponseChan chan Response
}

// Holds information for response from database
type Response struct {
	Data, Id string
}

// DbHandler interface method HandleDb defines a database handler which handles requests
type DbHandler interface {
	HandleDb()
}

// MapDb is a key value storage database
// Id will be an identification for sharding
type MapDb struct {
	Id string
	Db map[string]interface{}
}

// Handle data MapDb requests
func (m MapDb) HandleDb() {

}

// SqlDb is a sql based database
type SqlDb struct {
}

// Handle Sql based requests
func (s SqlDb) HandleDb() {

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
)

// Start
type cmdStart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("start")
	cmd.Use = i18n.G("start [<remote>:]<instance> [[<remote>:]<instance>...]")
	cmd.Short = i18n.G("Start instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Start instances`))

	return cmd
}

// Pause
type cmdPause struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdPause) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("pause")
	cmd.Use = i18n.G("pause [<remote>:]<instance> [[<remote>:]<instance>...]")
	cmd.Short = i18n.G("Pause instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Pause instances`))
	cmd.Hidden = true

	return cmd
}

// Restart
type cmdRestart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdRestart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("restart")
	cmd.Use = i18n.G("restart [<remote>:]<instance> [[<remote>:]<instance>...]")
	cmd.Short = i18n.G("Restart instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Restart instances

The opposite of "lxc pause" is "lxc start".`))

	return cmd
}

// Stop
type cmdStop struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStop) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("stop")
	cmd.Use = i18n.G("stop [<remote>:]<instance> [[<remote>:]<instance>...]")
	cmd.Short = i18n.G("Stop instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Stop instances`))

	return cmd
}

type cmdAction struct {
	global *cmdGlobal

	flagAll       bool
	flagConsole   bool
	flagForce     bool
	flagStateful  bool
	flagStateless bool
	flagTimeout   int
}

func (c *cmdAction) Command(action string) *cobra.Command {
	cmd := &cobra.Command{}
	cmd.RunE = c.Run

	cmd.Flags().BoolVar(&c.flagAll, "all", false, i18n.G("Run against all instances"))

	if action == "stop" {
		cmd.Flags().BoolVar(&c.flagStateful, "stateful", false, i18n.G("Store the instance state"))
	} else if action == "start" {
		cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Ignore the instance state"))
		cmd.Flags().BoolVar(&c.flagConsole, "console", false, i18n.G("Immediately attach to the console"))
	} else if action == "restart" {
		cmd.Flags().BoolVar(&c.flagConsole, "console", false, i18n.G("Immediately attach to the console"))
	}

	if shared.StringInSlice(action, []string{"restart", "stop"}) {
		cmd.Flags().BoolVarP(&c.flagForce, "force", "f", false, i18n.G("Force the instance to shutdown"))
		cmd.Flags().IntVar(&c.flagTimeout, "timeout", -1, i18n.G("Time to wait for the instance before killing it")+"``")
	}

	return cmd
}

func (c *cmdAction) doAction(action string, conf *config.Config, nameArg string) error {
	state := false

	// Pause is called freeze
	if action == "pause" {
		action = "freeze"
	}

	// Only store state if asked to
	if action == "stop" && c.flagStateful {
		state = true
	}

	remote, name, err := conf.ParseRemote(nameArg)
	if err != nil {
		return err
	}

	d, err := conf.GetInstanceServer(remote)
	if err != nil {
		return err
	}

	if name == "" {
		return fmt.Errorf(i18n.G("Must supply instance name for: ")+"\"%s\"", nameArg)
	}

	if action == "start" {
		current, _, err := d.GetInstance(name)
		if err != nil {
			return err
		}

		// "start" for a frozen instance means "unfreeze"
		if current.StatusCode == api.Frozen {
			action = "unfreeze"
		}

		// Always restore state (if present) unless asked not to
		if action == "start" && current.Stateful && !c.flagStateless {
			state = true
		}
	}

	req := api.InstanceStatePut{
		Action:   action,
		Timeout:  c.flagTimeout,
		Force:    c.flagForce,
		Stateful: state,
	}

	op, err := d.UpdateInstanceState(name, req, "")
	if err != nil {
		return err
	}

	progress := utils.ProgressRenderer{
		Quiet: c.global.flagQuiet,
	}
	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}

	// Wait for operation to finish
	err = utils.CancelableWait(op, &progress)
	if err != nil {
		progress.Done("")
		return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, nameArg)
	}

	progress.Done("")

	// Handle console attach
	if c.flagConsole {
		console := cmdConsole{}
		console.global = c.global
		return console.Console(d, name)
	}

	return nil
}

func (c *cmdAction) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	var names []string
	if c.flagAll {
		// If no server passed, use current default.
		if len(args) == 0 {
			args = []string{fmt.Sprintf("%s:", conf.DefaultRemote)}
		}

		// Get all the servers.
		resources, err := c.global.ParseServers(args...)
		if err != nil {
			return err
		}

		for _, resource := range resources {
			// We don't allow instance names with --all.
			if resource.name != "" {
				return fmt.Errorf(i18n.G("Both --all and instance name given"))
			}

			ctslist, err := resource.server.GetInstances(api.InstanceTypeAny)
			if err != nil {
				return err
			}

			for _, ct := range ctslist {
				switch cmd.Name() {
				case "start":
					if ct.StatusCode == api.Running {
						continue
					}
				case "stop":
					if ct.StatusCode == api.Stopped {
						continue
					}
				}
				names = append(names, fmt.Sprintf("%s:%s", resource.remote, ct.Name))
			}
		}
	} else {
		names = args
	}

	if c.flagConsole {
		if c.flagAll {
			return fmt.Errorf(i18n.G("--console can't be used with --all"))
		}

		if len(names) != 1 {
			return fmt.Errorf(i18n.G("--console only works with a single instance"))
		}
	}

	// Run the action for every listed instance
	results := runBatch(names, func(name string) error { return c.doAction(cmd.Name(), conf, name) })

	// Single instance is easy
	if len(results) == 1 {
		return results[0].err
	}

	// Do fancier rendering for batches
	success := true

	for _, result := range results {
		if result.err == nil {
			continue
		}

		success = false
		msg := fmt.Sprintf(i18n.G("error: %v"), result.err)
		for _, line := range strings.Split(msg, "\n") {
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s: %s", result.name, line))
		}
	}

	if !success {
		fmt.Fprintln(os.Stderr, "")
		return fmt.Errorf(i18n.G("Some instances failed to %s"), cmd.Name())
	}

	return nil
}
<commit_msg>lxc/action: Show usage on missing target<commit_after>package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"

	"github.com/lxc/lxd/lxc/config"
	"github.com/lxc/lxd/lxc/utils"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	cli "github.com/lxc/lxd/shared/cmd"
	"github.com/lxc/lxd/shared/i18n"
)

// Start
type cmdStart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("start")
	cmd.Use = i18n.G("start [<remote>:]<instance> [[<remote>:]<instance>...]")
	cmd.Short = i18n.G("Start instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Start instances`))

	return cmd
}

// Pause
type cmdPause struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdPause) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("pause")
	cmd.Use = i18n.G("pause [<remote>:]<instance> [[<remote>:]<instance>...]")
	cmd.Short = i18n.G("Pause instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Pause instances`))
	cmd.Hidden = true

	return cmd
}

// Restart
type cmdRestart struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdRestart) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("restart")
	cmd.Use = i18n.G("restart [<remote>:]<instance> [[<remote>:]<instance>...]")
	cmd.Short = i18n.G("Restart instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Restart instances

The opposite of "lxc pause" is "lxc start".`))

	return cmd
}

// Stop
type cmdStop struct {
	global *cmdGlobal
	action *cmdAction
}

func (c *cmdStop) Command() *cobra.Command {
	cmdAction := cmdAction{global: c.global}
	c.action = &cmdAction

	cmd := c.action.Command("stop")
	cmd.Use = i18n.G("stop [<remote>:]<instance> [[<remote>:]<instance>...]")
	cmd.Short = i18n.G("Stop instances")
	cmd.Long = cli.FormatSection(i18n.G("Description"), i18n.G(
		`Stop instances`))

	return cmd
}

type cmdAction struct {
	global *cmdGlobal

	flagAll       bool
	flagConsole   bool
	flagForce     bool
	flagStateful  bool
	flagStateless bool
	flagTimeout   int
}

func (c *cmdAction) Command(action string) *cobra.Command {
	cmd := &cobra.Command{}
	cmd.RunE = c.Run

	cmd.Flags().BoolVar(&c.flagAll, "all", false, i18n.G("Run against all instances"))

	if action == "stop" {
		cmd.Flags().BoolVar(&c.flagStateful, "stateful", false, i18n.G("Store the instance state"))
	} else if action == "start" {
		cmd.Flags().BoolVar(&c.flagStateless, "stateless", false, i18n.G("Ignore the instance state"))
		cmd.Flags().BoolVar(&c.flagConsole, "console", false, i18n.G("Immediately attach to the console"))
	} else if action == "restart" {
		cmd.Flags().BoolVar(&c.flagConsole, "console", false, i18n.G("Immediately attach to the console"))
	}

	if shared.StringInSlice(action, []string{"restart", "stop"}) {
		cmd.Flags().BoolVarP(&c.flagForce, "force", "f", false, i18n.G("Force the instance to shutdown"))
		cmd.Flags().IntVar(&c.flagTimeout, "timeout", -1, i18n.G("Time to wait for the instance before killing it")+"``")
	}

	return cmd
}

func (c *cmdAction) doAction(action string, conf *config.Config, nameArg string) error {
	state := false

	// Pause is called freeze
	if action == "pause" {
		action = "freeze"
	}

	// Only store state if asked to
	if action == "stop" && c.flagStateful {
		state = true
	}

	remote, name, err := conf.ParseRemote(nameArg)
	if err != nil {
		return err
	}

	d, err := conf.GetInstanceServer(remote)
	if err != nil {
		return err
	}

	if name == "" {
		return fmt.Errorf(i18n.G("Must supply instance name for: ")+"\"%s\"", nameArg)
	}

	if action == "start" {
		current, _, err := d.GetInstance(name)
		if err != nil {
			return err
		}

		// "start" for a frozen instance means "unfreeze"
		if current.StatusCode == api.Frozen {
			action = "unfreeze"
		}

		// Always restore state (if present) unless asked not to
		if action == "start" && current.Stateful && !c.flagStateless {
			state = true
		}
	}

	req := api.InstanceStatePut{
		Action:   action,
		Timeout:  c.flagTimeout,
		Force:    c.flagForce,
		Stateful: state,
	}

	op, err := d.UpdateInstanceState(name, req, "")
	if err != nil {
		return err
	}

	progress := utils.ProgressRenderer{
		Quiet: c.global.flagQuiet,
	}
	_, err = op.AddHandler(progress.UpdateOp)
	if err != nil {
		progress.Done("")
		return err
	}

	// Wait for operation to finish
	err = utils.CancelableWait(op, &progress)
	if err != nil {
		progress.Done("")
		return fmt.Errorf("%s\n"+i18n.G("Try `lxc info --show-log %s` for more info"), err, nameArg)
	}

	progress.Done("")

	// Handle console attach
	if c.flagConsole {
		console := cmdConsole{}
		console.global = c.global
		return console.Console(d, name)
	}

	return nil
}

func (c *cmdAction) Run(cmd *cobra.Command, args []string) error {
	conf := c.global.conf

	var names []string
	if c.flagAll {
		// If no server passed, use current default.
		if len(args) == 0 {
			args = []string{fmt.Sprintf("%s:", conf.DefaultRemote)}
		}

		// Get all the servers.
		resources, err := c.global.ParseServers(args...)
		if err != nil {
			return err
		}

		for _, resource := range resources {
			// We don't allow instance names with --all.
			if resource.name != "" {
				return fmt.Errorf(i18n.G("Both --all and instance name given"))
			}

			ctslist, err := resource.server.GetInstances(api.InstanceTypeAny)
			if err != nil {
				return err
			}

			for _, ct := range ctslist {
				switch cmd.Name() {
				case "start":
					if ct.StatusCode == api.Running {
						continue
					}
				case "stop":
					if ct.StatusCode == api.Stopped {
						continue
					}
				}
				names = append(names, fmt.Sprintf("%s:%s", resource.remote, ct.Name))
			}
		}
	} else {
		names = args

		if len(args) == 0 {
			cmd.Usage()
			return nil
		}
	}

	if c.flagConsole {
		if c.flagAll {
			return fmt.Errorf(i18n.G("--console can't be used with --all"))
		}

		if len(names) != 1 {
			return fmt.Errorf(i18n.G("--console only works with a single instance"))
		}
	}

	// Run the action for every listed instance
	results := runBatch(names, func(name string) error { return c.doAction(cmd.Name(), conf, name) })

	// Single instance is easy
	if len(results) == 1 {
		return results[0].err
	}

	// Do fancier rendering for batches
	success := true

	for _, result := range results {
		if result.err == nil {
			continue
		}

		success = false
		msg := fmt.Sprintf(i18n.G("error: %v"), result.err)
		for _, line := range strings.Split(msg, "\n") {
			fmt.Fprintln(os.Stderr, fmt.Sprintf("%s: %s", result.name, line))
		}
	}

	if !success {
		fmt.Fprintln(os.Stderr, "")
		return fmt.Errorf(i18n.G("Some instances failed to %s"), cmd.Name())
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"database/sql"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"strings"

	"github.com/gorilla/mux"
	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	_ "github.com/mattn/go-sqlite3"
	"gopkg.in/tomb.v2"
)

// A Daemon can respond to requests from a shared client.
type Daemon struct {
	tomb        tomb.Tomb
	unixl       net.Listener
	tcpl        net.Listener
	IdmapSet    *shared.IdmapSet
	lxcpath     string
	certf       string
	keyf        string
	mux         *mux.Router
	clientCerts []x509.Certificate
	db          *sql.DB

	tlsconfig *tls.Config
}

type Command struct {
	name          string
	untrustedGet  bool
	untrustedPost bool
	get           func(d *Daemon, r *http.Request) Response
	put           func(d *Daemon, r *http.Request) Response
	post          func(d *Daemon, r *http.Request) Response
	delete        func(d *Daemon, r *http.Request) Response
}

func (d *Daemon) httpGetSync(url string) (*lxd.Response, error) {
	var err error
	if d.tlsconfig == nil {
		d.tlsconfig, err = shared.GetTLSConfig(d.certf, d.keyf)
		if err != nil {
			return nil, err
		}
	}
	tr := &http.Transport{
		TLSClientConfig: d.tlsconfig,
		Dial:            shared.RFC3493Dialer,
	}
	myhttp := http.Client{
		Transport: tr,
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("User-Agent", shared.UserAgent)

	r, err := myhttp.Do(req)
	if err != nil {
		return nil, err
	}

	resp, err := lxd.ParseResponse(r)
	if err != nil {
		return nil, err
	}

	if resp.Type != lxd.Sync {
		return nil, fmt.Errorf("unexpected non-sync response!")
	}

	return resp, nil
}

func (d *Daemon) httpGetFile(url string) (*http.Response, error) {
	var err error
	if d.tlsconfig == nil {
		d.tlsconfig, err = shared.GetTLSConfig(d.certf, d.keyf)
		if err != nil {
			return nil, err
		}
	}
	tr := &http.Transport{
		TLSClientConfig: d.tlsconfig,
		Dial:            shared.RFC3493Dialer,
	}
	myhttp := http.Client{
		Transport: tr,
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("User-Agent", shared.UserAgent)

	raw, err := myhttp.Do(req)
	if err != nil {
		return nil, err
	}

	if raw.StatusCode != 200 {
		_, err := lxd.HoistResponse(raw, lxd.Error)
		if err != nil {
			return nil, err
		}

		return nil, fmt.Errorf("non-200 status with no error response?")
	}

	return raw, nil
}

func readMyCert() (string, string, error) {
	certf := shared.VarPath("server.crt")
	keyf := shared.VarPath("server.key")
	shared.Debugf("looking for existing certificates: %s %s", certf, keyf)

	err := shared.FindOrGenCert(certf, keyf)

	return certf, keyf, err
}

func (d *Daemon) isTrustedClient(r *http.Request) bool {
	if r.RemoteAddr == "@" {
		// Unix socket
		return true
	}
	if r.TLS == nil {
		return false
	}
	for i := range r.TLS.PeerCertificates {
		if d.CheckTrustState(*r.TLS.PeerCertificates[i]) {
			return true
		}
	}
	return false
}

func isJsonRequest(r *http.Request) bool {
	for k, vs := range r.Header {
		if strings.ToLower(k) == "content-type" &&
			len(vs) == 1 && strings.ToLower(vs[0]) == "application/json" {
			return true
		}
	}

	return false
}

func (d *Daemon) isRecursionRequest(r *http.Request) bool {
	recursion_str := r.FormValue("recursion")
	recursion, err := strconv.Atoi(recursion_str)
	if err != nil {
		return false
	}

	return recursion == 1
}

func (d *Daemon) createCmd(version string, c Command) {
	var uri string
	if c.name == "" {
		uri = fmt.Sprintf("/%s", version)
	} else {
		uri = fmt.Sprintf("/%s/%s", version, c.name)
	}

	d.mux.HandleFunc(uri, func(w http.ResponseWriter, r *http.Request) {

		if d.isTrustedClient(r) {
			shared.Debugf("handling %s %s", r.Method, r.URL.RequestURI())
		} else if r.Method == "GET" && c.untrustedGet {
			shared.Debugf("allowing untrusted GET to %s", r.URL.RequestURI())
		} else if r.Method == "POST" && c.untrustedPost {
			shared.Debugf("allowing untrusted POST to %s", r.URL.RequestURI())
		} else {
			shared.Debugf("rejecting request from untrusted client")
			Forbidden.Render(w)
			return
		}

		if *debug && r.Method != "GET" && isJsonRequest(r) {
			newBody := &bytes.Buffer{}
			captured := &bytes.Buffer{}
			multiW := io.MultiWriter(newBody, captured)
			if _, err := io.Copy(multiW, r.Body); err != nil {
				InternalError(err).Render(w)
				return
			}

			r.Body = shared.BytesReadCloser{Buf: newBody}
			shared.DebugJson(captured)
		}

		var resp Response
		resp = NotImplemented

		switch r.Method {
		case "GET":
			if c.get != nil {
				resp = c.get(d, r)
			}
		case "PUT":
			if c.put != nil {
				resp = c.put(d, r)
			}
		case "POST":
			if c.post != nil {
				resp = c.post(d, r)
			}
		case "DELETE":
			if c.delete != nil {
				resp = c.delete(d, r)
			}
		default:
			resp = NotFound
		}

		if err := resp.Render(w); err != nil {
			err := InternalError(err).Render(w)
			if err != nil {
				shared.Debugf("failed writing error for error, giving up.")
			}
		}

		/*
		 * When we create a new lxc.Container, it adds a finalizer (via
		 * SetFinalizer) that frees the struct. However, it sometimes
		 * takes the go GC a while to actually free the struct,
		 * presumably since it is a small amount of memory.
		 * Unfortunately, the struct also keeps the log fd open, so if
		 * we leave too many of these around, we end up running out of
		 * fds. So, let's explicitly do a GC to collect these at the
		 * end of each request.
		 */
		runtime.GC()
	})
}

// StartDaemon starts the shared daemon with the provided configuration.
func StartDaemon(listenAddr string) (*Daemon, error) {
	d := &Daemon{}

	d.lxcpath = shared.VarPath("lxc")
	err := os.MkdirAll(shared.VarPath("/"), 0755)
	if err != nil {
		return nil, err
	}
	err = os.MkdirAll(d.lxcpath, 0755)
	if err != nil {
		return nil, err
	}

	certf, keyf, err := readMyCert()
	if err != nil {
		return nil, err
	}
	d.certf = certf
	d.keyf = keyf

	err = initDb(d)
	if err != nil {
		return nil, err
	}

	readSavedClientCAList(d)

	d.mux = mux.NewRouter()

	d.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		SyncResponse(true, []string{"/1.0"}).Render(w)
	})

	for _, c := range api10 {
		d.createCmd("1.0", c)
	}

	d.mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		shared.Debugf("sending top level 404: %s", r.URL)
		NotFound.Render(w)
	})

	d.IdmapSet, err = shared.DefaultIdmapSet()
	if err != nil {
		shared.Logf("error reading idmap: %s", err.Error())
		shared.Logf("operations requiring idmap will not be available")
	} else {
		shared.Debugf("idmap is: %q\n", d.IdmapSet)
	}

	localSocket := shared.VarPath("unix.socket")

	// If the socket exists, let's try to connect to it and see if there's
	// a lxd running.
	if _, err := os.Stat(localSocket); err == nil {
		c := &lxd.Config{Remotes: map[string]lxd.RemoteConfig{}}
		_, err := lxd.NewClient(c, "")
		if err != nil {
			shared.Debugf("Detected old but dead unix socket, deleting it...")
			// Connecting failed, so let's delete the socket and
			// listen on it ourselves.
			err = os.Remove(localSocket)
			if err != nil {
				return nil, err
			}
		}
	}

	unixAddr, err := net.ResolveUnixAddr("unix", localSocket)
	if err != nil {
		return nil, fmt.Errorf("cannot resolve unix socket address: %v", err)
	}
	unixl, err := net.ListenUnix("unix", unixAddr)
	if err != nil {
		return nil, fmt.Errorf("cannot listen on unix socket: %v", err)
	}
	d.unixl = unixl

	if err := os.Chmod(localSocket, 0660); err != nil {
		return nil, err
	}

	gid, err := shared.GroupId(*group)
	if err != nil {
		return nil, err
	}

	if err := os.Chown(localSocket, os.Getuid(), gid); err != nil {
		return nil, err
	}

	var tcpListen func() error
	if listenAddr != "" {
		config, err := shared.GetTLSConfig(d.certf, d.keyf)
		if err != nil {
			d.unixl.Close()
			return nil, err
		}

		tcpl, err := tls.Listen("tcp", listenAddr, config)
		if err != nil {
			d.unixl.Close()
			return nil, fmt.Errorf("cannot listen on unix socket: %v", err)
		}
		d.tcpl = tcpl
		tcpListen = func() error { return http.Serve(d.tcpl, d.mux) }
	}

	containersWatch(d)

	d.tomb.Go(func() error {
		if tcpListen != nil {
			d.tomb.Go(tcpListen)
		}
		d.tomb.Go(func() error { return http.Serve(d.unixl, d.mux) })
		return nil
	})

	return d, nil
}

func (d *Daemon) CheckTrustState(cert x509.Certificate) bool {
	for k, v := range d.clientCerts {
		if bytes.Compare(cert.Raw, v.Raw) == 0 {
			shared.Debugf("found cert for %s", k)
			return true
		}
		shared.Debugf("client cert != key for %s", k)
	}
	return false
}

var errStop = fmt.Errorf("requested stop")

// Stop stops the shared daemon.
func (d *Daemon) Stop() error {
	d.tomb.Kill(errStop)
	d.unixl.Close()
	if d.tcpl != nil {
		d.tcpl.Close()
	}
	err := d.tomb.Wait()
	if err == errStop {
		return nil
	}
	return err
}
<commit_msg>Fix printing of uid/gid at startup<commit_after>package main

import (
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"database/sql"
	"fmt"
	"io"
	"net"
	"net/http"
	"os"
	"runtime"
	"strconv"
	"strings"

	"github.com/gorilla/mux"
	"github.com/lxc/lxd"
	"github.com/lxc/lxd/shared"
	_ "github.com/mattn/go-sqlite3"
	"gopkg.in/tomb.v2"
)

// A Daemon can respond to requests from a shared client.
type Daemon struct {
	tomb        tomb.Tomb
	unixl       net.Listener
	tcpl        net.Listener
	IdmapSet    *shared.IdmapSet
	lxcpath     string
	certf       string
	keyf        string
	mux         *mux.Router
	clientCerts []x509.Certificate
	db          *sql.DB

	tlsconfig *tls.Config
}

type Command struct {
	name          string
	untrustedGet  bool
	untrustedPost bool
	get           func(d *Daemon, r *http.Request) Response
	put           func(d *Daemon, r *http.Request) Response
	post          func(d *Daemon, r *http.Request) Response
	delete        func(d *Daemon, r *http.Request) Response
}

func (d *Daemon) httpGetSync(url string) (*lxd.Response, error) {
	var err error
	if d.tlsconfig == nil {
		d.tlsconfig, err = shared.GetTLSConfig(d.certf, d.keyf)
		if err != nil {
			return nil, err
		}
	}
	tr := &http.Transport{
		TLSClientConfig: d.tlsconfig,
		Dial:            shared.RFC3493Dialer,
	}
	myhttp := http.Client{
		Transport: tr,
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("User-Agent", shared.UserAgent)

	r, err := myhttp.Do(req)
	if err != nil {
		return nil, err
	}

	resp, err := lxd.ParseResponse(r)
	if err != nil {
		return nil, err
	}

	if resp.Type != lxd.Sync {
		return nil, fmt.Errorf("unexpected non-sync response!")
	}

	return resp, nil
}

func (d *Daemon) httpGetFile(url string) (*http.Response, error) {
	var err error
	if d.tlsconfig == nil {
		d.tlsconfig, err = shared.GetTLSConfig(d.certf, d.keyf)
		if err != nil {
			return nil, err
		}
	}
	tr := &http.Transport{
		TLSClientConfig: d.tlsconfig,
		Dial:            shared.RFC3493Dialer,
	}
	myhttp := http.Client{
		Transport: tr,
	}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, err
	}

	req.Header.Set("User-Agent", shared.UserAgent)

	raw, err := myhttp.Do(req)
	if err != nil {
		return nil, err
	}

	if raw.StatusCode != 200 {
		_, err := lxd.HoistResponse(raw, lxd.Error)
		if err != nil {
			return nil, err
		}

		return nil, fmt.Errorf("non-200 status with no error response?")
	}

	return raw, nil
}

func readMyCert() (string, string, error) {
	certf := shared.VarPath("server.crt")
	keyf := shared.VarPath("server.key")
	shared.Debugf("looking for existing certificates: %s %s", certf, keyf)

	err := shared.FindOrGenCert(certf, keyf)

	return certf, keyf, err
}

func (d *Daemon) isTrustedClient(r *http.Request) bool {
	if r.RemoteAddr == "@" {
		// Unix socket
		return true
	}
	if r.TLS == nil {
		return false
	}
	for i := range r.TLS.PeerCertificates {
		if d.CheckTrustState(*r.TLS.PeerCertificates[i]) {
			return true
		}
	}
	return false
}

func isJsonRequest(r *http.Request) bool {
	for k, vs := range r.Header {
		if strings.ToLower(k) == "content-type" &&
			len(vs) == 1 && strings.ToLower(vs[0]) == "application/json" {
			return true
		}
	}

	return false
}

func (d *Daemon) isRecursionRequest(r *http.Request) bool {
	recursion_str := r.FormValue("recursion")
	recursion, err := strconv.Atoi(recursion_str)
	if err != nil {
		return false
	}

	return recursion == 1
}

func (d *Daemon) createCmd(version string, c Command) {
	var uri string
	if c.name == "" {
		uri = fmt.Sprintf("/%s", version)
	} else {
		uri = fmt.Sprintf("/%s/%s", version, c.name)
	}

	d.mux.HandleFunc(uri, func(w http.ResponseWriter, r *http.Request) {

		if d.isTrustedClient(r) {
			shared.Debugf("handling %s %s", r.Method, r.URL.RequestURI())
		} else if r.Method == "GET" && c.untrustedGet {
			shared.Debugf("allowing untrusted GET to %s", r.URL.RequestURI())
		} else if r.Method == "POST" && c.untrustedPost {
			shared.Debugf("allowing untrusted POST to %s", r.URL.RequestURI())
		} else {
			shared.Debugf("rejecting request from untrusted client")
			Forbidden.Render(w)
			return
		}

		if *debug && r.Method != "GET" && isJsonRequest(r) {
			newBody := &bytes.Buffer{}
			captured := &bytes.Buffer{}
			multiW := io.MultiWriter(newBody, captured)
			if _, err := io.Copy(multiW, r.Body); err != nil {
				InternalError(err).Render(w)
				return
			}

			r.Body = shared.BytesReadCloser{Buf: newBody}
			shared.DebugJson(captured)
		}

		var resp Response
		resp = NotImplemented

		switch r.Method {
		case "GET":
			if c.get != nil {
				resp = c.get(d, r)
			}
		case "PUT":
			if c.put != nil {
				resp = c.put(d, r)
			}
		case "POST":
			if c.post != nil {
				resp = c.post(d, r)
			}
		case "DELETE":
			if c.delete != nil {
				resp = c.delete(d, r)
			}
		default:
			resp = NotFound
		}

		if err := resp.Render(w); err != nil {
			err := InternalError(err).Render(w)
			if err != nil {
				shared.Debugf("failed writing error for error, giving up.")
			}
		}

		/*
		 * When we create a new lxc.Container, it adds a finalizer (via
		 * SetFinalizer) that frees the struct. However, it sometimes
		 * takes the go GC a while to actually free the struct,
		 * presumably since it is a small amount of memory.
		 * Unfortunately, the struct also keeps the log fd open, so if
		 * we leave too many of these around, we end up running out of
		 * fds. So, let's explicitly do a GC to collect these at the
		 * end of each request.
		 */
		runtime.GC()
	})
}

// StartDaemon starts the shared daemon with the provided configuration.
func StartDaemon(listenAddr string) (*Daemon, error) {
	d := &Daemon{}

	d.lxcpath = shared.VarPath("lxc")
	err := os.MkdirAll(shared.VarPath("/"), 0755)
	if err != nil {
		return nil, err
	}
	err = os.MkdirAll(d.lxcpath, 0755)
	if err != nil {
		return nil, err
	}

	certf, keyf, err := readMyCert()
	if err != nil {
		return nil, err
	}
	d.certf = certf
	d.keyf = keyf

	err = initDb(d)
	if err != nil {
		return nil, err
	}

	readSavedClientCAList(d)

	d.mux = mux.NewRouter()

	d.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		SyncResponse(true, []string{"/1.0"}).Render(w)
	})

	for _, c := range api10 {
		d.createCmd("1.0", c)
	}

	d.mux.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		shared.Debugf("sending top level 404: %s", r.URL)
		NotFound.Render(w)
	})

	d.IdmapSet, err = shared.DefaultIdmapSet()
	if err != nil {
		shared.Logf("error reading idmap: %s", err.Error())
		shared.Logf("operations requiring idmap will not be available")
	} else {
		shared.Debugf("Default uid/gid map:")
		for _, lxcmap := range d.IdmapSet.ToLxcString() {
			shared.Debugf(" - " + lxcmap)
		}
	}

	localSocket := shared.VarPath("unix.socket")

	// If the socket exists, let's try to connect to it and see if there's
	// a lxd running.
	if _, err := os.Stat(localSocket); err == nil {
		c := &lxd.Config{Remotes: map[string]lxd.RemoteConfig{}}
		_, err := lxd.NewClient(c, "")
		if err != nil {
			shared.Debugf("Detected old but dead unix socket, deleting it...")
			// Connecting failed, so let's delete the socket and
			// listen on it ourselves.
			err = os.Remove(localSocket)
			if err != nil {
				return nil, err
			}
		}
	}

	unixAddr, err := net.ResolveUnixAddr("unix", localSocket)
	if err != nil {
		return nil, fmt.Errorf("cannot resolve unix socket address: %v", err)
	}
	unixl, err := net.ListenUnix("unix", unixAddr)
	if err != nil {
		return nil, fmt.Errorf("cannot listen on unix socket: %v", err)
	}
	d.unixl = unixl

	if err := os.Chmod(localSocket, 0660); err != nil {
		return nil, err
	}

	gid, err := shared.GroupId(*group)
	if err != nil {
		return nil, err
	}

	if err := os.Chown(localSocket, os.Getuid(), gid); err != nil {
		return nil, err
	}

	var tcpListen func() error
	if listenAddr != "" {
		config, err := shared.GetTLSConfig(d.certf, d.keyf)
		if err != nil {
			d.unixl.Close()
			return nil, err
		}

		tcpl, err := tls.Listen("tcp", listenAddr, config)
		if err != nil {
			d.unixl.Close()
			return nil, fmt.Errorf("cannot listen on unix socket: %v", err)
		}
		d.tcpl = tcpl
		tcpListen = func() error { return http.Serve(d.tcpl, d.mux) }
	}

	containersWatch(d)

	d.tomb.Go(func() error {
		if tcpListen != nil {
			d.tomb.Go(tcpListen)
		}
		d.tomb.Go(func() error { return http.Serve(d.unixl, d.mux) })
		return nil
	})

	return d, nil
}

func (d *Daemon) CheckTrustState(cert x509.Certificate) bool {
	for k, v := range d.clientCerts {
		if bytes.Compare(cert.Raw, v.Raw) == 0 {
			shared.Debugf("found cert for %s", k)
			return true
		}
		shared.Debugf("client cert != key for %s", k)
	}
	return false
}

var errStop = fmt.Errorf("requested stop")

// Stop stops the shared daemon.
func (d *Daemon) Stop() error {
	d.tomb.Kill(errStop)
	d.unixl.Close()
	if d.tcpl != nil {
		d.tcpl.Close()
	}
	err := d.tomb.Wait()
	if err == errStop {
		return nil
	}
	return err
}
<|endoftext|>


<commit_before>package ecslogs

import (
	"reflect"
	"time"
)

func levelValue(v interface{}) (lvl Level, ok bool) {
	var err error

	if s, x := stringValue(v); !x {
		return
	} else if lvl, err = ParseLevel(s); err != nil {
		return
	}

	ok = true
	return
}

func timeValue(v interface{}) (t time.Time, ok bool) {
	var err error

	if s, x := stringValue(v); !x {
		return
	} else if t, err = time.Parse(time.RFC3339Nano, s); err != nil {
		return
	}

	ok = true
	return
}

func intValue(v interface{}) (n int, ok bool) {
	switch x := reflect.ValueOf(v); x.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		n = int(x.Int())

	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		n = int(x.Uint())

	case reflect.Float32, reflect.Float64:
		n = int(x.Float())

	default:
		return
	}

	ok = true
	return
}

func stringValue(v interface{}) (s string, ok bool) {
	switch x := v.(type) {
	case string:
		s = x

	case []byte:
		s = string(x)

	default:
		switch x := reflect.ValueOf(v); x.Kind() {
		case reflect.String:
			s = x.String()

		default:
			return
		}
	}

	ok = true
	return
}
<commit_msg>remove unused file<commit_after><|endoftext|>


<commit_before>// Package libsacloud is the SAKURA CLOUD API v1.1 Client for Go.
package libsacloud

// Version バージョン
const Version = "1.17.1"
<commit_msg>Bump to v1.17.2<commit_after>// Package libsacloud is the SAKURA CLOUD API v1.1 Client for Go.
package libsacloud

// Version バージョン
const Version = "1.17.2"
<|endoftext|>


<commit_before>package log

import (
	"context"
	"fmt"
	"os"
	"time"

	"github.com/alauda/bergamot/contexts"
	"github.com/alauda/bergamot/loggo"
	aloggo "github.com/alauda/loggo"
)

// StandardLogger stan
type StandardLogger interface {
	Tracef(format string, args ...interface{})
	Debugf(format string, args ...interface{})
	Infof(format string, args ...interface{})
	Warningf(format string, args ...interface{})
	Errorf(format string, args ...interface{})
}

// StructuredLogger simplified structured logger signature
type StructuredLogger interface {
	Trace(msg string, keyValues ...interface{})
	Debug(msg string, keyValues ...interface{})
	Info(msg string, keyValues ...interface{})
	Warning(msg string, keyValues ...interface{})
	Error(msg string, keyValues ...interface{})
}

// StLogger St logging functions for using with loggo.Fields
type StLogger interface {
	StCritical(message string, fields loggo.Fields)
	StError(message string, fields loggo.Fields)
	StWarning(message string, fields loggo.Fields)
	StInfo(message string, fields loggo.Fields)
	StDebug(message string, fields loggo.Fields)
	StTrace(message string, fields loggo.Fields)
}

// Logger interface to define a logger entity
type Logger interface {
	StandardLogger
	StructuredLogger
	StLogger
}

// Level defines log levels
type Level int

const (
	// LevelTrace prints all tracing and up
	LevelTrace Level = iota
	// LevelDebug prints all messages
	LevelDebug
	// LevelInfo prints only info or higher
	LevelInfo
	// LevelError prints only error messages
	LevelError
)

// SetLevel Sets logging levels
func SetLevel(level Level) {
	var config string
	switch level {

	case LevelInfo:
		config = "<root>=INFO"
	case LevelError:
		config = "<root>=ERROR"
	case LevelDebug:
		config = "<root>=DEBUG"
	case LevelTrace:
		fallthrough
	default:
		config = "<root>=TRACE"

	}
	loggo.ConfigureLoggers(config)
}

// GetFields get fields using a context
func GetFields(ctx context.Context) (fields loggo.Fields) {
	fields = loggo.Fields{}
	return AddRequestID(ctx, fields)
}

// AddRequestID adds the request Id to fields if one is there
func AddRequestID(ctx context.Context, fields loggo.Fields) loggo.Fields {
	if ctx != nil {
		if request := contexts.GetRequestID(ctx); request != "" {
			fields["request_id"] = request
		}
	}
	return fields
}

// NewLogger constructs a new logger for package
// @param: packageName stands for the package of your logger
// @param: depth given one integer will set the depth in which will find during runtime the file and line number
// recommended to use 3 as a number (only the first integer will be used)
func NewLogger(packageName string, size ...int) Logger {
	return loggo.GetLogger(packageName, size...)
}

// NewStandardLogger constructs a standard logger
func NewStandardLogger(packageName string, depth ...int) StandardLogger {
	return aloggo.GetLogger(packageName, depth...)
}

// NewNoCodeLogger will not print file
func NewNoCodeLogger(name string, size ...int) Logger {
	writter := loggo.NewSimpleWriter(os.Stdout, NoCodeFormat)
	loggo.ReplaceDefaultWriter(writter)
	return loggo.GetLogger(name, size...)
}

// NoCodeFormat will remove the code reference from msg
func NoCodeFormat(entry loggo.Entry) string {
	ts := entry.Timestamp.In(time.UTC).Format("2006-01-02 15:04:05")
	return fmt.Sprintf("%s %s %s %s", ts, entry.Level, entry.Module, entry.Message)
}

// F generates a map using a key-value pairs as arguments
// for example, if given arguments are "key" and 1 will return
// map[string]interface{}{"key": 1}
// PS: will not add key if the value is missing
func F(args ...interface{}) (res map[string]interface{}) {
	res = make(map[string]interface{})
	if len(args) > 0 {
		// avoiding nil cases
		var (
			k  string
			ok bool
		)
		for i, v := range args {
			if i%2 == 0 {
				if k, ok = v.(string); !ok {
					k = fmt.Sprintf("%v", v)
				}
			} else {
				res[k] = v
			}
		}
	}
	return
}
<commit_msg>fix typos<commit_after>package log

import (
	"context"
	"fmt"
	"os"
	"time"

	"github.com/alauda/bergamot/contexts"
	"github.com/alauda/bergamot/loggo"
	aloggo "github.com/alauda/loggo"
)

// StandardLogger stan
type StandardLogger interface {
	Tracef(format string, args ...interface{})
	Debugf(format string, args ...interface{})
	Infof(format string, args ...interface{})
	Warningf(format string, args ...interface{})
	Errorf(format string, args ...interface{})
}

// StructuredLogger simplified structured logger signature
type StructuredLogger interface {
	Trace(msg string, keyValues ...interface{})
	Debug(msg string, keyValues ...interface{})
	Info(msg string, keyValues ...interface{})
	Warning(msg string, keyValues ...interface{})
	Error(msg string, keyValues ...interface{})
}

// StLogger St logging functions for using with loggo.Fields
type StLogger interface {
	StCritical(message string, fields loggo.Fields)
	StError(message string, fields loggo.Fields)
	StWarning(message string, fields loggo.Fields)
	StInfo(message string, fields loggo.Fields)
	StDebug(message string, fields loggo.Fields)
	StTrace(message string, fields loggo.Fields)
}

// Logger interface to define a logger entity
type Logger interface {
	StandardLogger
	StructuredLogger
	StLogger
}

// Level defines log levels
type Level int

const (
	// LevelTrace prints all tracing and up
	LevelTrace Level = iota
	// LevelDebug prints all messages
	LevelDebug
	// LevelInfo prints only info or higher
	LevelInfo
	// LevelError prints only error messages
	LevelError
)

// SetLevel Sets logging levels
func SetLevel(level Level) {
	var config string
	switch level {
	case LevelInfo:
		config = "<root>=INFO"
	case LevelError:
		config = "<root>=ERROR"
	case LevelDebug:
		config = "<root>=DEBUG"
	case LevelTrace:
		fallthrough
	default:
		config = "<root>=TRACE"
	}

	loggo.ConfigureLoggers(config)
}

// GetFields get fields using a context
func GetFields(ctx context.Context) (fields loggo.Fields) {
	fields = loggo.Fields{}
	return AddRequestID(ctx, fields)
}

// AddRequestID adds the request Id to fields if one is there
func AddRequestID(ctx context.Context, fields loggo.Fields) loggo.Fields {
	if ctx != nil {
		if request := contexts.GetRequestID(ctx); request != "" {
			fields["request_id"] = request
		}
	}
	return fields
}

// NewLogger constructs a new logger for package
// @param: packageName stands for the package of your logger
// @param: depth given one integer will set the depth in which will find during runtime the file and line number
// recommended to use 3 as a number (only the first integer will be used)
func NewLogger(packageName string, size ...int) Logger {
	return loggo.GetLogger(packageName, size...)
}

// NewStandardLogger constructs a standard logger
func NewStandardLogger(packageName string, depth ...int) StandardLogger {
	return aloggo.GetLogger(packageName, depth...)
}

// NewNoCodeLogger will not print file
func NewNoCodeLogger(name string, size ...int) Logger {
	writter := loggo.NewSimpleWriter(os.Stdout, NoCodeFormat)
	loggo.ReplaceDefaultWriter(writter)
	return loggo.GetLogger(name, size...)
}

// NoCodeFormat will remove the code reference from msg
func NoCodeFormat(entry loggo.Entry) string {
	ts := entry.Timestamp.In(time.UTC).Format("2006-01-02 15:04:05")
	return fmt.Sprintf("%s %s %s %s", ts, entry.Level, entry.Module, entry.Message)
}

// F generates a map using a key-value pairs as arguments
// for example, if given arguments are "key" and 1 will return
// map[string]interface{}{"key": 1}
// PS: will not add key if the value is missing
func F(args ...interface{}) (res map[string]interface{}) {
	res = make(map[string]interface{})
	if len(args) > 0 {
		// avoiding nil cases
		var (
			k  string
			ok bool
		)
		for i, v := range args {
			if i%2 == 0 {
				if k, ok = v.(string); !ok {
					k = fmt.Sprintf("%v", v)
				}
			} else {
				res[k] = v
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>/*
	restClient - convenience library fro REST API calls based on JSON

	- Provides a generic interface for any http method

	- Provides transparent JSON marshaling and unmarshaling (assuming appropriately-tagged structs)

	- Support for Basic authentication

	- Support for request timeouts (default: 2s)

	- Classifies status codes and returns appropriate error type

	- Returns http.Status and http.StatusType with error

	Both request and response bodies are expected to be pointers to
	Golang structs with JSON tags.

*/
package restclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"

	"time"
)

// Logger
var Logger *log.Logger

func init() {
	// Null logger, by default
	Logger = log.New(ioutil.Discard, "restclient", log.LstdFlags|log.Lshortfile)
}

// Auth struct to contain username and password for authentication
type Auth struct {
	Username string
	Password string
}

// Request structures a REST request and provides convenience
// methods for making REST API calls
type Request struct {
	Method string // HTTP Method to use (GET,POST,PUT,DELETE,etc.)
	Url    string // URL to dial (as expected by net.Dial)
	Auth   Auth   // Structure for username and password authentication

	QueryParameters map[string]string // Parameters to attach to the QueryString
	RequestBody     interface{}       // The body of the request
	RequestType     string            // Request type for request (defaults to "json", options are: "json","form")
	ResponseBody    interface{}       // The body of the response

	RequestReader io.Reader // Reader interface to the encoded body
	ResponseRaw   []byte    // Raw (usually JSON-encoded) response body

	Timeout time.Duration // Maximum time to wait for response

	Client   http.Client    // Raw http.Client object
	Request  *http.Request  // Raw http.Request object
	Response *http.Response // Raw http.Response object
}

func NewRequest(method string, url string, auth Auth) Request {
	req := Request{Method: method, Url: url, Auth: auth}

	// Set default timeout
	req.Timeout = 2 * time.Second

	// Return new Request
	return req
}

// NewRequest creates a new, basic Request object
func NewRequestBasic(method string, url string) Request {
	auth := Auth{}
	return NewRequest(method, url, auth)
}

// NewRequest creates a new, authenticating Request object
func NewRequestAuth(method string, url string, username string, password string) Request {
	auth := Auth{username, password}
	return NewRequest(method, url, auth)
}

/*
	Do makes a (web) request to the url, populating the 'ret' interface provided,
	and returning the result code from the request

	It is a wrapper around http.Client.Do which JSON-encodes anything going out
	and JSON-decodes anything coming back.

	Basic HTTP response code classifications are performed and the appropriate error
	type are returned.

	In general, this method should not be called directly.
*/
func (r *Request) Do() error {
	Logger.Println("Do: started")

	// Encode body to Json from the given body object
	err := r.EncodeRequestBody()
	if err != nil {
		return err
	}

	// Create the client object
	r.createHTTPClient()

	// Create the request object
	err = r.createHTTPRequest()
	if err != nil {
		return err
	}

	switch r.RequestType {
	case "":
		Logger.Println("No RequestType specified; using json")
		r.Request.Header.Add("Content-Type", "application/json")
	case "json":
		r.Request.Header.Add("Content-Type", "application/json")
	case "form":
		r.Request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	default:
		Logger.Println("Unhandled request type:", r.RequestType)
	}

	// Apply authentication information
	if r.Auth.Username != "" {
		Logger.Printf("Adding authentication information: (%+v)", r.Auth)
		r.Request.SetBasicAuth(r.Auth.Username, r.Auth.Password)
	}

	// Send request
	Logger.Println("Sending request to server")
	err = r.Execute()
	if err != nil {
		return err
	}

	Logger.Println("Do: completed")
	return nil
}

// Execute transacts with the remote server, actually executing
// the Request with the Client.  It sets the Response property on
// successful communication
func (r *Request) Execute() error {
	Logger.Println("Execute: started")
	var err error
	r.Response, err = r.Client.Do(r.Request)
	if err != nil {
		Logger.Println("Failed to make request to server:", err)
		return err
	}
	defer r.Response.Body.Close()

	Logger.Println("Server response:", r.Response)

	// Check for error codes
	err = r.ProcessStatusCode()
	if err != nil {
		return err
	}

	// Decode the body
	err = r.DecodeResponse()
	if err != nil {
		return err
	}

	Logger.Println("MakeRequest: completed")
	return nil
}

// EncodeRequestBody performs the selected encoding on the
// provided request body, populating the RequestReader
func (r *Request) EncodeRequestBody() error {
	Logger.Println("EncodeRequestBody: started")
	// Encode body to Json from the given body object
	if r.RequestBody == nil {
		Logger.Println("Nothing to encode")
		return nil
	}

	// Find encoding type
	if r.RequestType == "" {
		r.RequestType = "json"
	}
	var encodedBytes []byte
	var err error
	switch r.RequestType {
	case "form":
		encodedBytes, err = r.encodeForm()
		if err != nil {
			Logger.Println("Failed to encode form:", err.Error())
			return err
		}
	case "json":
		encodedBytes, err = r.encodeJson()
		if err != nil {
			Logger.Println("Failed to encode form:", err.Error())
			return err
		}
	}

	r.RequestReader = bytes.NewReader(encodedBytes)
	Logger.Println("EncodeRequestBody: completed")
	return nil
}

// encodeJson encodes the request body to Json
func (r *Request) encodeJson() ([]byte, error) {
	Logger.Printf("Encoding bodyObject (%+v) to json", r.RequestBody)
	return json.Marshal(r.RequestBody)
}

// ProcessStatusCode processes and returns classified errors resulting
// from the Response's StatusCode
func (r *Request) ProcessStatusCode() error {
	Logger.Println("ProcessStatusCode: started")
	resp := r.Response
	if (resp.StatusCode >= 300) || (resp.StatusCode < 200) {
		Logger.Printf("Non-2XX response: (%d) %s", resp.StatusCode, resp.Status)
		switch {
		case resp.StatusCode == 404:
			return NotFoundError{resp.StatusCode, resp.Status, fmt.Errorf("%s", resp.Status)}
		case resp.StatusCode >= 400 && resp.StatusCode < 500:
			return RequestError{resp.StatusCode, resp.Status, fmt.Errorf("%s", resp.Status)}
		case resp.StatusCode >= 500 && resp.StatusCode < 600:
			return ServerError{resp.StatusCode, resp.Status, fmt.Errorf("%s", resp.Status)}
		default:
			return fmt.Errorf("Unhandled StatusCode: %s", resp.Status)
		}
	}

	Logger.Println("ProcessStatusCode: completed")
	return nil
}

func (r *Request) DecodeResponse() error {
	Logger.Println("DecodeResponse: started")

	// Read the body into []byte
	responseJson, err := ioutil.ReadAll(r.Response.Body)
	if err != nil {
		Logger.Println("Failed to read from body:", r.Response.Body, err)
		return fmt.Errorf("Failed to read from body:", err)
	}

	// Unmarshal into response object
	if len(responseJson) > 0 {
		Logger.Println("Decoding response")
		err = json.Unmarshal(responseJson, r.ResponseBody)
		if err != nil {
			Logger.Println("Failed to decode response body:", responseJson, err)
			return fmt.Errorf("Failed to decode response: %v", err.Error())
		}
	} else {
		Logger.Println("Zero-length response body")
	}

	Logger.Println("DecodeResponse: completed")
	return nil
}

// createHTTPClient generates the http.Client object
// from default parameters
func (r *Request) createHTTPClient() {
	Logger.Println("createHTTPClient: started")

	// Create transport for the request
	Logger.Println("Creating http.Transport")
	dial := timeoutDialer(r.Timeout)
	transport := http.Transport{
		Dial: dial,
	}

	// Create Client
	Logger.Println("Creating http.Client")
	r.Client = http.Client{
		Transport: &transport,
	}
	Logger.Println("createHTTPClient: completed")
}

// createHTTPRequest generates the actual http.Request object
// from default parameters
func (r *Request) createHTTPRequest() error {
	Logger.Println("createHTTPRequest: started")
	// Create the new request
	var err error
	r.Request, err = http.NewRequest(r.Method, r.Url, r.RequestReader)
	if err != nil {
		Logger.Println("Failed to create request:", err)
		return err
	}

	Logger.Println("createHTTPRequest: completed")
	return nil
}

// Get is a shorthand MakeRequest with method = "GET"
func Get(url string, auth Auth, ret interface{}) error {
	r := NewRequest("GET", url, auth)
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// Post is a shorthand MakeRequest with method "POST"
func Post(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("POST", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// PostForm is a shorthand MakeRequest with method "POST" with form encoding
func PostForm(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("POST", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	r.RequestType = "form"
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// Put is a shorthand MakeRequest with method "PUT"
func Put(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("PUT", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// Delete is a shorthand MakeRequest with method "DELETE"
func Delete(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("DELETE", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// Patch is a shorthand MakeRequest with method "PATCH"
func Patch(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("PATCH", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// timeoutDialer is a wrapper function which returns a customized
// Dial function with a built-in timer for the provided timeout
// duration
func timeoutDialer(timeout time.Duration) func(network, addr string) (net.Conn, error) {
	return func(network string, address string) (net.Conn, error) {
		return net.DialTimeout(network, address, timeout)
	}
}

// NotFoundError indicates a 404 status code was received
// from the server
type NotFoundError struct {
	StatusCode int
	Status     string
	Err        error
}

func (e NotFoundError) Error() string {
	return "Request: Not Found: " + e.Err.Error()
}

// RequestError indicates a 4xx-level code other than 404
// was received from the server
type RequestError struct {
	StatusCode int
	Status     string
	Err        error
}

func (e RequestError) Error() string {
	return "Request: Request failed: " + e.Status + ": " + e.Err.Error()
}

// ServerError indicates a 5xx-level code was received from
// the server
type ServerError struct {
	StatusCode int
	Status     string
	Err        error
}

func (e ServerError) Error() string {
	err := "Request: Server failure: " + e.Status + ": " + e.Err.Error()
	return err
}
<commit_msg>Normalize returned errors<commit_after>/*
	restClient - convenience library fro REST API calls based on JSON

	- Provides a generic interface for any http method

	- Provides transparent JSON marshaling and unmarshaling (assuming appropriately-tagged structs)

	- Support for Basic authentication

	- Support for request timeouts (default: 2s)

	- Classifies status codes and returns appropriate error type

	- Returns http.Status and http.StatusType with error

	Both request and response bodies are expected to be pointers to
	Golang structs with JSON tags.

*/
package restclient

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"

	"time"
)

// Logger
var Logger *log.Logger

func init() {
	// Null logger, by default
	Logger = log.New(ioutil.Discard, "restclient", log.LstdFlags|log.Lshortfile)
}

// Auth struct to contain username and password for authentication
type Auth struct {
	Username string
	Password string
}

// Request structures a REST request and provides convenience
// methods for making REST API calls
type Request struct {
	Method string // HTTP Method to use (GET,POST,PUT,DELETE,etc.)
	Url    string // URL to dial (as expected by net.Dial)
	Auth   Auth   // Structure for username and password authentication

	QueryParameters map[string]string // Parameters to attach to the QueryString
	RequestBody     interface{}       // The body of the request
	RequestType     string            // Request type for request (defaults to "json", options are: "json","form")
	ResponseBody    interface{}       // The body of the response

	RequestReader io.Reader // Reader interface to the encoded body
	ResponseRaw   []byte    // Raw (usually JSON-encoded) response body

	Timeout time.Duration // Maximum time to wait for response

	Client   http.Client    // Raw http.Client object
	Request  *http.Request  // Raw http.Request object
	Response *http.Response // Raw http.Response object
}

func NewRequest(method string, url string, auth Auth) Request {
	req := Request{Method: method, Url: url, Auth: auth}

	// Set default timeout
	req.Timeout = 2 * time.Second

	// Return new Request
	return req
}

// NewRequest creates a new, basic Request object
func NewRequestBasic(method string, url string) Request {
	auth := Auth{}
	return NewRequest(method, url, auth)
}

// NewRequest creates a new, authenticating Request object
func NewRequestAuth(method string, url string, username string, password string) Request {
	auth := Auth{username, password}
	return NewRequest(method, url, auth)
}

/*
	Do makes a (web) request to the url, populating the 'ret' interface provided,
	and returning the result code from the request

	It is a wrapper around http.Client.Do which JSON-encodes anything going out
	and JSON-decodes anything coming back.

	Basic HTTP response code classifications are performed and the appropriate error
	type are returned.

	In general, this method should not be called directly.
*/
func (r *Request) Do() error {
	Logger.Println("Do: started")

	// Encode body to Json from the given body object
	err := r.EncodeRequestBody()
	if err != nil {
		return err
	}

	// Create the client object
	r.createHTTPClient()

	// Create the request object
	err = r.createHTTPRequest()
	if err != nil {
		return err
	}

	switch r.RequestType {
	case "":
		Logger.Println("No RequestType specified; using json")
		r.Request.Header.Add("Content-Type", "application/json")
	case "json":
		r.Request.Header.Add("Content-Type", "application/json")
	case "form":
		r.Request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	default:
		Logger.Println("Unhandled request type:", r.RequestType)
	}

	// Apply authentication information
	if r.Auth.Username != "" {
		Logger.Printf("Adding authentication information: (%+v)", r.Auth)
		r.Request.SetBasicAuth(r.Auth.Username, r.Auth.Password)
	}

	// Send request
	Logger.Println("Sending request to server")
	err = r.Execute()
	if err != nil {
		return err
	}

	Logger.Println("Do: completed")
	return nil
}

// Execute transacts with the remote server, actually executing
// the Request with the Client.  It sets the Response property on
// successful communication
func (r *Request) Execute() error {
	Logger.Println("Execute: started")
	var err error
	r.Response, err = r.Client.Do(r.Request)
	if err != nil {
		Logger.Println("Failed to make request to server:", err)
		return err
	}
	defer r.Response.Body.Close()

	Logger.Println("Server response:", r.Response)

	// Check for error codes
	err = r.ProcessStatusCode()
	if err != nil {
		return err
	}

	// Decode the body
	err = r.DecodeResponse()
	if err != nil {
		return err
	}

	Logger.Println("MakeRequest: completed")
	return nil
}

// EncodeRequestBody performs the selected encoding on the
// provided request body, populating the RequestReader
func (r *Request) EncodeRequestBody() error {
	Logger.Println("EncodeRequestBody: started")
	// Encode body to Json from the given body object
	if r.RequestBody == nil {
		Logger.Println("Nothing to encode")
		return nil
	}

	// Find encoding type
	if r.RequestType == "" {
		r.RequestType = "json"
	}
	var encodedBytes []byte
	var err error
	switch r.RequestType {
	case "form":
		encodedBytes, err = r.encodeForm()
		if err != nil {
			Logger.Println("Failed to encode form:", err.Error())
			return err
		}
	case "json":
		encodedBytes, err = r.encodeJson()
		if err != nil {
			Logger.Println("Failed to encode form:", err.Error())
			return err
		}
	}

	r.RequestReader = bytes.NewReader(encodedBytes)
	Logger.Println("EncodeRequestBody: completed")
	return nil
}

// encodeJson encodes the request body to Json
func (r *Request) encodeJson() ([]byte, error) {
	Logger.Printf("Encoding bodyObject (%+v) to json", r.RequestBody)
	return json.Marshal(r.RequestBody)
}

// ProcessStatusCode processes and returns classified errors resulting
// from the Response's StatusCode
func (r *Request) ProcessStatusCode() error {
	Logger.Println("ProcessStatusCode: started")
	resp := r.Response
	if (resp.StatusCode >= 300) || (resp.StatusCode < 200) {
		Logger.Printf("Non-2XX response: (%d) %s", resp.StatusCode, resp.Status)
		switch {
		case resp.StatusCode == 404:
			return NotFoundError{resp.StatusCode, resp.Status, fmt.Errorf("%s", resp.Status)}
		case resp.StatusCode >= 400 && resp.StatusCode < 500:
			return RequestError{resp.StatusCode, resp.Status, fmt.Errorf("%s", resp.Status)}
		case resp.StatusCode >= 500 && resp.StatusCode < 600:
			return ServerError{resp.StatusCode, resp.Status, fmt.Errorf("%s", resp.Status)}
		default:
			return BaseError{0, "Unhandled Status", fmt.Errorf("Unhandled StatusCode: %s", resp.Status)}
		}
	}

	Logger.Println("ProcessStatusCode: completed")
	return nil
}

func (r *Request) DecodeResponse() error {
	Logger.Println("DecodeResponse: started")

	// Read the body into []byte
	responseJson, err := ioutil.ReadAll(r.Response.Body)
	if err != nil {
		Logger.Println("Failed to read from body:", r.Response.Body, err)
		return BaseError{0, "Decode Error", fmt.Errorf("Failed to read from body:", err)}
	}

	// Unmarshal into response object
	if len(responseJson) > 0 {
		Logger.Println("Decoding response")
		err = json.Unmarshal(responseJson, r.ResponseBody)
		if err != nil {
			Logger.Println("Failed to decode response body:", responseJson, err)
			return BaseError{0, "Decode Error", fmt.Errorf("Failed to decode response: %v", err.Error())}
		}
	} else {
		Logger.Println("Zero-length response body")
	}

	Logger.Println("DecodeResponse: completed")
	return nil
}

// createHTTPClient generates the http.Client object
// from default parameters
func (r *Request) createHTTPClient() {
	Logger.Println("createHTTPClient: started")

	// Create transport for the request
	Logger.Println("Creating http.Transport")
	dial := timeoutDialer(r.Timeout)
	transport := http.Transport{
		Dial: dial,
	}

	// Create Client
	Logger.Println("Creating http.Client")
	r.Client = http.Client{
		Transport: &transport,
	}
	Logger.Println("createHTTPClient: completed")
}

// createHTTPRequest generates the actual http.Request object
// from default parameters
func (r *Request) createHTTPRequest() error {
	Logger.Println("createHTTPRequest: started")
	// Create the new request
	var err error
	r.Request, err = http.NewRequest(r.Method, r.Url, r.RequestReader)
	if err != nil {
		Logger.Println("Failed to create request:", err)
		return err
	}

	Logger.Println("createHTTPRequest: completed")
	return nil
}

// Get is a shorthand MakeRequest with method = "GET"
func Get(url string, auth Auth, ret interface{}) error {
	r := NewRequest("GET", url, auth)
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// Post is a shorthand MakeRequest with method "POST"
func Post(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("POST", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// PostForm is a shorthand MakeRequest with method "POST" with form encoding
func PostForm(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("POST", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	r.RequestType = "form"
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// Put is a shorthand MakeRequest with method "PUT"
func Put(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("PUT", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// Delete is a shorthand MakeRequest with method "DELETE"
func Delete(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("DELETE", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// Patch is a shorthand MakeRequest with method "PATCH"
func Patch(url string, auth Auth, req interface{}, ret interface{}) error {
	r := NewRequest("PATCH", url, auth)
	r.RequestBody = req
	r.ResponseBody = ret
	//r.Request.Header.Set("Accept", "application/json")
	return r.Do()
}

// timeoutDialer is a wrapper function which returns a customized
// Dial function with a built-in timer for the provided timeout
// duration
func timeoutDialer(timeout time.Duration) func(network, addr string) (net.Conn, error) {
	return func(network string, address string) (net.Conn, error) {
		return net.DialTimeout(network, address, timeout)
	}
}

type Error interface {
	Error() string
	Code() int
	Message() string
}

type BaseError struct {
	StatusCode int
	Status     string
	Err        error
}

func (e BaseError) Error() string {
	return e.Err.Error()
}

func (e BaseError) Code() int {
	return e.StatusCode
}

func (e BaseError) Message() string {
	return e.Status
}

// NotFoundError indicates a 404 status code was received
// from the server
type NotFoundError BaseError

func (e NotFoundError) Error() string {
	return "Request: Not Found: " + e.Err.Error()
}

// RequestError indicates a 4xx-level code other than 404
// was received from the server
type RequestError BaseError

func (e RequestError) Error() string {
	return "Request: Request failed: " + e.Status + ": " + e.Err.Error()
}

// ServerError indicates a 5xx-level code was received from
// the server
type ServerError BaseError

func (e ServerError) Error() string {
	err := "Request: Server failure: " + e.Status + ": " + e.Err.Error()
	return err
}
<|endoftext|>


<commit_before>package cloudstack

import (
	"fmt"
	"log"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/xanzy/go-cloudstack/cloudstack"
)

func resourceCloudStackLoadBalancerRule() *schema.Resource {
	return &schema.Resource{
		Create: resourceCloudStackLoadBalancerRuleCreate,
		Read:   resourceCloudStackLoadBalancerRuleRead,
		Update: resourceCloudStackLoadBalancerRuleUpdate,
		Delete: resourceCloudStackLoadBalancerRuleDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"description": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"ip_address_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

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

			"algorithm": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"private_port": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"public_port": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"member_ids": &schema.Schema{
				Type:     schema.TypeList,
				Required: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

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

func resourceCloudStackLoadBalancerRuleCreate(d *schema.ResourceData, meta interface{}) error {
	cs := meta.(*cloudstack.CloudStackClient)
	d.Partial(true)

	// Create a new parameter struct
	p := cs.LoadBalancer.NewCreateLoadBalancerRuleParams(
		d.Get("algorithm").(string),
		d.Get("name").(string),
		d.Get("private_port").(int),
		d.Get("public_port").(int),
	)

	// Don't autocreate a firewall rule, use a resource if needed
	p.SetOpenfirewall(false)

	// Set the description
	if description, ok := d.GetOk("description"); ok {
		p.SetDescription(description.(string))
	} else {
		p.SetDescription(d.Get("name").(string))
	}

	if networkid, ok := d.GetOk("network_id"); ok {
		// Set the network id
		p.SetNetworkid(networkid.(string))
	}

	// Set the ipaddress id
	p.SetPublicipid(d.Get("ip_address_id").(string))

	// Create the load balancer rule
	r, err := cs.LoadBalancer.CreateLoadBalancerRule(p)
	if err != nil {
		return err
	}

	// Set the load balancer rule ID and set partials
	d.SetId(r.Id)
	d.SetPartial("name")
	d.SetPartial("description")
	d.SetPartial("ip_address_id")
	d.SetPartial("network_id")
	d.SetPartial("algorithm")
	d.SetPartial("private_port")
	d.SetPartial("public_port")

	// Create a new parameter struct
	ap := cs.LoadBalancer.NewAssignToLoadBalancerRuleParams(r.Id)

	var mbs []string
	for _, id := range d.Get("member_ids").([]interface{}) {
		mbs = append(mbs, id.(string))
	}

	ap.SetVirtualmachineids(mbs)

	_, err = cs.LoadBalancer.AssignToLoadBalancerRule(ap)
	if err != nil {
		return err
	}

	d.SetPartial("member_ids")
	d.Partial(false)

	return resourceCloudStackLoadBalancerRuleRead(d, meta)
}

func resourceCloudStackLoadBalancerRuleRead(d *schema.ResourceData, meta interface{}) error {
	cs := meta.(*cloudstack.CloudStackClient)

	// Get the load balancer details
	lb, count, err := cs.LoadBalancer.GetLoadBalancerRuleByID(
		d.Id(),
		cloudstack.WithProject(d.Get("project").(string)),
	)
	if err != nil {
		if count == 0 {
			log.Printf("[DEBUG] Load balancer rule %s does no longer exist", d.Get("name").(string))
			d.SetId("")
			return nil
		}

		return err
	}

	d.Set("algorithm", lb.Algorithm)
	d.Set("public_port", lb.Publicport)
	d.Set("private_port", lb.Privateport)
	d.Set("ip_address_id", lb.Publicipid)

	// Only set network if user specified it to avoid spurious diffs
	if _, ok := d.GetOk("network_id"); ok {
		d.Set("network_id", lb.Networkid)
	}

	setValueOrID(d, "project", lb.Project, lb.Projectid)

	return nil
}

func resourceCloudStackLoadBalancerRuleUpdate(d *schema.ResourceData, meta interface{}) error {
	cs := meta.(*cloudstack.CloudStackClient)

	if d.HasChange("name") || d.HasChange("description") || d.HasChange("algorithm") {
		name := d.Get("name").(string)

		// Create new parameter struct
		p := cs.LoadBalancer.NewUpdateLoadBalancerRuleParams(d.Id())

		if d.HasChange("name") {
			log.Printf("[DEBUG] Name has changed for load balancer rule %s, starting update", name)

			p.SetName(name)
		}

		if d.HasChange("description") {
			log.Printf(
				"[DEBUG] Description has changed for load balancer rule %s, starting update", name)

			p.SetDescription(d.Get("description").(string))
		}

		if d.HasChange("algorithm") {
			algorithm := d.Get("algorithm").(string)

			log.Printf(
				"[DEBUG] Algorithm has changed to %s for load balancer rule %s, starting update",
				algorithm,
				name,
			)

			// Set the new Algorithm
			p.SetAlgorithm(algorithm)
		}

		_, err := cs.LoadBalancer.UpdateLoadBalancerRule(p)
		if err != nil {
			return fmt.Errorf(
				"Error updating load balancer rule %s", name)
		}
	}
	return resourceCloudStackLoadBalancerRuleRead(d, meta)
}

func resourceCloudStackLoadBalancerRuleDelete(d *schema.ResourceData, meta interface{}) error {
	cs := meta.(*cloudstack.CloudStackClient)

	// Create a new parameter struct
	p := cs.LoadBalancer.NewDeleteLoadBalancerRuleParams(d.Id())

	log.Printf("[INFO] Deleting load balancer rule: %s", d.Get("name").(string))
	if _, err := cs.LoadBalancer.DeleteLoadBalancerRule(p); err != nil {
		// This is a very poor way to be told the ID does no longer exist :(
		if !strings.Contains(err.Error(), fmt.Sprintf(
			"Invalid parameter id value=%s due to incorrect long value format, "+
				"or entity does not exist", d.Id())) {
			return err
		}
	}

	return nil
}
<commit_msg>provider/cloudstack: do not force a new resource when updating load balancer members (#11786)<commit_after>package cloudstack

import (
	"fmt"
	"log"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/xanzy/go-cloudstack/cloudstack"
)

func resourceCloudStackLoadBalancerRule() *schema.Resource {
	return &schema.Resource{
		Create: resourceCloudStackLoadBalancerRuleCreate,
		Read:   resourceCloudStackLoadBalancerRuleRead,
		Update: resourceCloudStackLoadBalancerRuleUpdate,
		Delete: resourceCloudStackLoadBalancerRuleDelete,

		Schema: map[string]*schema.Schema{
			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"description": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"ip_address_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

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

			"algorithm": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"private_port": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"public_port": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"member_ids": &schema.Schema{
				Type:     schema.TypeSet,
				Required: true,
				ForceNew: false,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

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

func resourceCloudStackLoadBalancerRuleCreate(d *schema.ResourceData, meta interface{}) error {
	cs := meta.(*cloudstack.CloudStackClient)
	d.Partial(true)

	// Create a new parameter struct
	p := cs.LoadBalancer.NewCreateLoadBalancerRuleParams(
		d.Get("algorithm").(string),
		d.Get("name").(string),
		d.Get("private_port").(int),
		d.Get("public_port").(int),
	)

	// Don't autocreate a firewall rule, use a resource if needed
	p.SetOpenfirewall(false)

	// Set the description
	if description, ok := d.GetOk("description"); ok {
		p.SetDescription(description.(string))
	} else {
		p.SetDescription(d.Get("name").(string))
	}

	if networkid, ok := d.GetOk("network_id"); ok {
		// Set the network id
		p.SetNetworkid(networkid.(string))
	}

	// Set the ipaddress id
	p.SetPublicipid(d.Get("ip_address_id").(string))

	// Create the load balancer rule
	r, err := cs.LoadBalancer.CreateLoadBalancerRule(p)
	if err != nil {
		return err
	}

	// Set the load balancer rule ID and set partials
	d.SetId(r.Id)
	d.SetPartial("name")
	d.SetPartial("description")
	d.SetPartial("ip_address_id")
	d.SetPartial("network_id")
	d.SetPartial("algorithm")
	d.SetPartial("private_port")
	d.SetPartial("public_port")

	// Create a new parameter struct
	ap := cs.LoadBalancer.NewAssignToLoadBalancerRuleParams(r.Id)

	var mbs []string
	for _, id := range d.Get("member_ids").(*schema.Set).List() {
		mbs = append(mbs, id.(string))
	}

	ap.SetVirtualmachineids(mbs)

	_, err = cs.LoadBalancer.AssignToLoadBalancerRule(ap)
	if err != nil {
		return err
	}

	d.SetPartial("member_ids")
	d.Partial(false)

	return resourceCloudStackLoadBalancerRuleRead(d, meta)
}

func resourceCloudStackLoadBalancerRuleRead(d *schema.ResourceData, meta interface{}) error {
	cs := meta.(*cloudstack.CloudStackClient)

	// Get the load balancer details
	lb, count, err := cs.LoadBalancer.GetLoadBalancerRuleByID(
		d.Id(),
		cloudstack.WithProject(d.Get("project").(string)),
	)
	if err != nil {
		if count == 0 {
			log.Printf("[DEBUG] Load balancer rule %s does no longer exist", d.Get("name").(string))
			d.SetId("")
			return nil
		}

		return err
	}

	d.Set("algorithm", lb.Algorithm)
	d.Set("public_port", lb.Publicport)
	d.Set("private_port", lb.Privateport)
	d.Set("ip_address_id", lb.Publicipid)

	// Only set network if user specified it to avoid spurious diffs
	if _, ok := d.GetOk("network_id"); ok {
		d.Set("network_id", lb.Networkid)
	}

	setValueOrID(d, "project", lb.Project, lb.Projectid)

	p := cs.LoadBalancer.NewListLoadBalancerRuleInstancesParams(d.Id())
	l, err := cs.LoadBalancer.ListLoadBalancerRuleInstances(p)
	if err != nil {
		return err
	}

	var mbs []string
	for _, i := range l.LoadBalancerRuleInstances {
		mbs = append(mbs, i.Id)
	}
	d.Set("member_ids", mbs)

	return nil
}

func resourceCloudStackLoadBalancerRuleUpdate(d *schema.ResourceData, meta interface{}) error {
	cs := meta.(*cloudstack.CloudStackClient)

	if d.HasChange("name") || d.HasChange("description") || d.HasChange("algorithm") {
		name := d.Get("name").(string)

		// Create new parameter struct
		p := cs.LoadBalancer.NewUpdateLoadBalancerRuleParams(d.Id())

		if d.HasChange("name") {
			log.Printf("[DEBUG] Name has changed for load balancer rule %s, starting update", name)

			p.SetName(name)
		}

		if d.HasChange("description") {
			log.Printf(
				"[DEBUG] Description has changed for load balancer rule %s, starting update", name)

			p.SetDescription(d.Get("description").(string))
		}

		if d.HasChange("algorithm") {
			algorithm := d.Get("algorithm").(string)

			log.Printf(
				"[DEBUG] Algorithm has changed to %s for load balancer rule %s, starting update",
				algorithm,
				name,
			)

			// Set the new Algorithm
			p.SetAlgorithm(algorithm)
		}

		_, err := cs.LoadBalancer.UpdateLoadBalancerRule(p)
		if err != nil {
			return fmt.Errorf(
				"Error updating load balancer rule %s", name)
		}
	}

	if d.HasChange("member_ids") {
		o, n := d.GetChange("member_ids")
		ombs, nmbs := o.(*schema.Set), n.(*schema.Set)

		setToStringList := func(s *schema.Set) []string {
			l := make([]string, s.Len())
			for i, v := range s.List() {
				l[i] = v.(string)
			}
			return l
		}

		membersToAdd := setToStringList(nmbs.Difference(ombs))
		membersToRemove := setToStringList(ombs.Difference(nmbs))

		log.Printf("[DEBUG] Members to add: %v, remove: %v", membersToAdd, membersToRemove)

		if len(membersToAdd) > 0 {
			p := cs.LoadBalancer.NewAssignToLoadBalancerRuleParams(d.Id())
			p.SetVirtualmachineids(membersToAdd)
			if _, err := cs.LoadBalancer.AssignToLoadBalancerRule(p); err != nil {
				return err
			}
		}

		if len(membersToRemove) > 0 {
			p := cs.LoadBalancer.NewRemoveFromLoadBalancerRuleParams(d.Id())
			p.SetVirtualmachineids(membersToRemove)
			if _, err := cs.LoadBalancer.RemoveFromLoadBalancerRule(p); err != nil {
				return err
			}
		}
	}

	return resourceCloudStackLoadBalancerRuleRead(d, meta)
}

func resourceCloudStackLoadBalancerRuleDelete(d *schema.ResourceData, meta interface{}) error {
	cs := meta.(*cloudstack.CloudStackClient)

	// Create a new parameter struct
	p := cs.LoadBalancer.NewDeleteLoadBalancerRuleParams(d.Id())

	log.Printf("[INFO] Deleting load balancer rule: %s", d.Get("name").(string))
	if _, err := cs.LoadBalancer.DeleteLoadBalancerRule(p); err != nil {
		// This is a very poor way to be told the ID does no longer exist :(
		if !strings.Contains(err.Error(), fmt.Sprintf(
			"Invalid parameter id value=%s due to incorrect long value format, "+
				"or entity does not exist", d.Id())) {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// +build !windows

package chroot

import (
	"errors"
	"os"
	"syscall"
)

// See: http://linux.die.net/include/sys/file.h
const LOCK_EX = 2
const LOCK_NB = 4
const LOCK_UN = 8

func lockFile(f *os.File) error {
	err := syscall.Flock(int(f.Fd()), LOCK_EX)
	if err != nil {
		return err
	}

	return nil
}

func unlockFile(f *os.File) error {
	return syscall.Flock(int(f.Fd()), LOCK_UN)
}
<commit_msg>builder/amazon/chroot: remove unused import<commit_after>// +build !windows

package chroot

import (
	"os"
	"syscall"
)

// See: http://linux.die.net/include/sys/file.h
const LOCK_EX = 2
const LOCK_NB = 4
const LOCK_UN = 8

func lockFile(f *os.File) error {
	err := syscall.Flock(int(f.Fd()), LOCK_EX)
	if err != nil {
		return err
	}

	return nil
}

func unlockFile(f *os.File) error {
	return syscall.Flock(int(f.Fd()), LOCK_UN)
}
<|endoftext|>