<commit_before>// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package fx

import "go.uber.org/dig"

// In can be embedded in a constructor's parameter struct to take advantage of
// advanced dependency injection features.
//
// Modules should take a single parameter struct that embeds an In in order to
// provide a forward-compatible API: since adding fields to a struct is
// backward-compatible, modules can then add optional dependencies in minor
// releases.
//
// # Parameter Structs
//
// Fx constructors declare their dependencies as function parameters. This can
// quickly become unreadable if the constructor has a lot of dependencies.
//
//	func NewHandler(users *UserGateway, comments *CommentGateway, posts *PostGateway, votes *VoteGateway, authz *AuthZGateway) *Handler {
//	  // ...
//	}
//
// To improve the readability of constructors like this, create a struct that
// lists all the dependencies as fields and change the function to accept that
// struct instead. The new struct is called a parameter struct.
//
// Fx has first class support for parameter structs: any struct embedding
// fx.In gets treated as a parameter struct, so the individual fields in the
// struct are supplied via dependency injection. Using a parameter struct, we
// can make the constructor above much more readable:
//
//	type HandlerParams struct {
//	  fx.In
//
//	  Users    *UserGateway
//	  Comments *CommentGateway
//	  Posts    *PostGateway
//	  Votes    *VoteGateway
//	  AuthZ    *AuthZGateway
//	}
//
//	func NewHandler(p HandlerParams) *Handler {
//	  // ...
//	}
//
// Though it's rarely a good idea, constructors can receive any combination of
// parameter structs and parameters.
//
//	func NewHandler(p HandlerParams, l *log.Logger) *Handler {
//	  // ...
//	}
//
// # Optional Dependencies
//
// Constructors often have soft dependencies on some types: if those types are
// missing, they can operate in a degraded state. Fx supports optional
// dependencies via the `optional:"true"` tag to fields on parameter structs.
//
//	type UserGatewayParams struct {
//	  fx.In
//
//	  Conn  *sql.DB
//	  Cache *redis.Client `optional:"true"`
//	}
//
// If an optional field isn't available in the container, the constructor
// receives the field's zero value.
//
//	func NewUserGateway(p UserGatewayParams, log *log.Logger) (*UserGateway, error) {
//	  if p.Cache == nil {
//	    log.Print("Caching disabled")
//	  }
//	  // ...
//	}
//
// Constructors that declare optional dependencies MUST gracefully handle
// situations in which those dependencies are absent.
//
// The optional tag also allows adding new dependencies without breaking
// existing consumers of the constructor.
//
// # Named Values
//
// Some use cases require the application container to hold multiple values of
// the same type. For details on producing named values, see the documentation
// for the Out type.
//
// Fx allows functions to consume named values via the `name:".."` tag on
// parameter structs. Note that both the name AND type of the fields on the
// parameter struct must match the corresponding result struct.
//
//	type GatewayParams struct {
//	  fx.In
//
//	  WriteToConn  *sql.DB `name:"rw"`
//	  ReadFromConn *sql.DB `name:"ro"`
//	}
//
// The name tag may be combined with the optional tag to declare the
// dependency optional.
//
//	type GatewayParams struct {
//	  fx.In
//
//	  WriteToConn  *sql.DB `name:"rw"`
//	  ReadFromConn *sql.DB `name:"ro" optional:"true"`
//	}
//
//	func NewCommentGateway(p GatewayParams, log *log.Logger) (*CommentGateway, error) {
//	  if p.ReadFromConn == nil {
//	    log.Print("Warning: Using RW connection for reads")
//	    p.ReadFromConn = p.WriteToConn
//	  }
//	  // ...
//	}
//
// # Value Groups
//
// To make it easier to produce and consume many values of the same type, Fx
// supports named, unordered collections called value groups. For details on
// producing value groups, see the documentation for the Out type.
//
// Functions can depend on a value group by requesting a slice tagged with
// `group:".."`. This will execute all constructors that provide a value to
// that group in an unspecified order, then collect all the results into a
// single slice. Keep in mind that this makes the types of the parameter and
// result struct fields different: if a group of constructors each returns
// type T, parameter structs consuming the group must use a field of type []T.
//
//	type ServerParams struct {
//	  fx.In
//
//	  Handlers []Handler `group:"server"`
//	}
//
//	func NewServer(p ServerParams) *Server {
//	  server := newServer()
//	  for _, h := range p.Handlers {
//	    server.Register(h)
//	  }
//	  return server
//	}
//
// Note that values in a value group are unordered. Fx makes no guarantees
// about the order in which these values will be produced.
//
// To declare a soft relationship between a group and its constructors, use
// the `soft` option on the group tag (`group:"[groupname],soft"`), this
// option can only be used for input parameters, e.g. `fx.In` structures.
// A soft group will be populated only with values from already-executed
// constructors.
//
//	 type Params struct {
//	   fx.In
//
//	   Handlers []Handler `group:"server"`
//	   Logger   *zap.Logger
//	 }
//
//	 NewHandlerAndLogger := func() (Handler, *zap.Logger) { ... }
//	 NewHandler := func() Handler { ... }
//	 Foo := func(Params) { ... }
//
//	app := fx.New(
//	  fx.Provide(NewHandlerAndLogger),
//	  fx.Provide(NewHandler),
//	  fx.Invoke(Foo),
//	)
//
// The only constructor called is `NewHandler`, because this also provides
// `*zap.Logger` needed in the `Params` struct received by `foo`
//
// In the next example, the slice `s` isn't populated as the provider would be
// called only because of `strings` soft group value
//
//	  app := fx.New(
//	    fx.Provide(
//	      fx.Annotate(
//	        func() (string,int) { return "hello" },
//	        fx.ResultTags(`group:"strings"`),
//	      ),
//	    ),
//	    fx.Invoke(
//	      fx.Annotate(func(s []string) {
//	        // s will be an empty slice
//	      }, fx.ParamTags(`group:"strings,soft"`)),
//	    ),
//	 )
//
//	In the next example, the slice `s` will be populated because there is a
//	consumer for the same type which hasn't a `soft` dependency
//
//	  app := fx.New(
//	    fx.Provide(
//	      fx.Annotate(
//	        func() string { "hello" },
//	        fx.ResultTags(`group:"strings"`),
//	      ),
//	    ),
//	    fx.Invoke(
//	      fx.Annotate(func(b []string) {
//	        // b will be ["hello"]
//	      }, fx.ParamTags(`group:"strings"`)),
//	    ),
//	    fx.Invoke(
//	      fx.Annotate(func(s []string) {
//	        // s will be ["hello"]
//	      }, fx.ParamTags(`group:"strings,soft"`)),
//	    ),
//	 )
//
// # Unexported fields
//
// By default, a type that embeds fx.In may not have any unexported fields. The
// following will return an error if used with Fx.
//
//	type Params struct {
//	  fx.In
//
//	  Logger *zap.Logger
//	  mu     sync.Mutex
//	}
//
// If you have need of unexported fields on such a type, you may opt-into
// ignoring unexported fields by adding the ignore-unexported struct tag to the
// fx.In. For example,
//
//	type Params struct {
//	  fx.In `ignore-unexported:"true"`
//
//	  Logger *zap.Logger
//	  mu     sync.Mutex
//	}
type In = dig.In

// Out is the inverse of In: it can be embedded in result structs to take
// advantage of advanced features.
//
// Modules should return a single result struct that embeds an Out in order to
// provide a forward-compatible API: since adding fields to a struct is
// backward-compatible, minor releases can provide additional types.
//
// # Result Structs
//
// Result structs are the inverse of parameter structs (discussed in the In
// documentation). These structs represent multiple outputs from a
// single function as fields. Fx treats all structs embedding fx.Out as result
// structs, so other constructors can rely on the result struct's fields
// directly.
//
// Without result structs, we sometimes have function definitions like this:
//
//	func SetupGateways(conn *sql.DB) (*UserGateway, *CommentGateway, *PostGateway, error) {
//	  // ...
//	}
//
// With result structs, we can make this both more readable and easier to
// modify in the future:
//
//	type Gateways struct {
//	  fx.Out
//
//	  Users    *UserGateway
//	  Comments *CommentGateway
//	  Posts    *PostGateway
//	}
//
//	func SetupGateways(conn *sql.DB) (Gateways, error) {
//	  // ...
//	}
//
// # Named Values
//
// Some use cases require the application container to hold multiple values of
// the same type. For details on consuming named values, see the documentation
// for the In type.
//
// A constructor that produces a result struct can tag any field with
// `name:".."` to have the corresponding value added to the graph under the
// specified name. An application may contain at most one unnamed value of a
// given type, but may contain any number of named values of the same type.
//
//	type ConnectionResult struct {
//	  fx.Out
//
//	  ReadWrite *sql.DB `name:"rw"`
//	  ReadOnly  *sql.DB `name:"ro"`
//	}
//
//	func ConnectToDatabase(...) (ConnectionResult, error) {
//	  // ...
//	  return ConnectionResult{ReadWrite: rw, ReadOnly:  ro}, nil
//	}
//
// # Value Groups
//
// To make it easier to produce and consume many values of the same type, Fx
// supports named, unordered collections called value groups. For details on
// consuming value groups, see the documentation for the In type.
//
// Constructors can send values into value groups by returning a result struct
// tagged with `group:".."`.
//
//	type HandlerResult struct {
//	  fx.Out
//
//	  Handler Handler `group:"server"`
//	}
//
//	func NewHelloHandler() HandlerResult {
//	  // ...
//	}
//
//	func NewEchoHandler() HandlerResult {
//	  // ...
//	}
//
// Any number of constructors may provide values to this named collection, but
// the ordering of the final collection is unspecified. Keep in mind that
// value groups require parameter and result structs to use fields with
// different types: if a group of constructors each returns type T, parameter
// structs consuming the group must use a field of type []T.
//
// To provide multiple values for a group from a result struct, produce a
// slice and use the `,flatten` option on the group tag. This indicates that
// each element in the slice should be injected into the group individually.
//
//	type IntResult struct {
//	  fx.Out
//
//	  Handler []int `group:"server"`         // Consume as [][]int
//	  Handler []int `group:"server,flatten"` // Consume as []int
//	}
type Out = dig.Out
<commit_msg>Docs change for soft value groups (#913)<commit_after>// Copyright (c) 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package fx

import "go.uber.org/dig"

// In can be embedded in a constructor's parameter struct to take advantage of
// advanced dependency injection features.
//
// Modules should take a single parameter struct that embeds an In in order to
// provide a forward-compatible API: since adding fields to a struct is
// backward-compatible, modules can then add optional dependencies in minor
// releases.
//
// # Parameter Structs
//
// Fx constructors declare their dependencies as function parameters. This can
// quickly become unreadable if the constructor has a lot of dependencies.
//
//	func NewHandler(users *UserGateway, comments *CommentGateway, posts *PostGateway, votes *VoteGateway, authz *AuthZGateway) *Handler {
//	  // ...
//	}
//
// To improve the readability of constructors like this, create a struct that
// lists all the dependencies as fields and change the function to accept that
// struct instead. The new struct is called a parameter struct.
//
// Fx has first class support for parameter structs: any struct embedding
// fx.In gets treated as a parameter struct, so the individual fields in the
// struct are supplied via dependency injection. Using a parameter struct, we
// can make the constructor above much more readable:
//
//	type HandlerParams struct {
//	  fx.In
//
//	  Users    *UserGateway
//	  Comments *CommentGateway
//	  Posts    *PostGateway
//	  Votes    *VoteGateway
//	  AuthZ    *AuthZGateway
//	}
//
//	func NewHandler(p HandlerParams) *Handler {
//	  // ...
//	}
//
// Though it's rarely a good idea, constructors can receive any combination of
// parameter structs and parameters.
//
//	func NewHandler(p HandlerParams, l *log.Logger) *Handler {
//	  // ...
//	}
//
// # Optional Dependencies
//
// Constructors often have optional dependencies on some types: if those types are
// missing, they can operate in a degraded state. Fx supports optional
// dependencies via the `optional:"true"` tag to fields on parameter structs.
//
//	type UserGatewayParams struct {
//	  fx.In
//
//	  Conn  *sql.DB
//	  Cache *redis.Client `optional:"true"`
//	}
//
// If an optional field isn't available in the container, the constructor
// receives the field's zero value.
//
//	func NewUserGateway(p UserGatewayParams, log *log.Logger) (*UserGateway, error) {
//	  if p.Cache == nil {
//	    log.Print("Caching disabled")
//	  }
//	  // ...
//	}
//
// Constructors that declare optional dependencies MUST gracefully handle
// situations in which those dependencies are absent.
//
// The optional tag also allows adding new dependencies without breaking
// existing consumers of the constructor.
//
// # Named Values
//
// Some use cases require the application container to hold multiple values of
// the same type. For details on producing named values, see the documentation
// for the Out type.
//
// Fx allows functions to consume named values via the `name:".."` tag on
// parameter structs. Note that both the name AND type of the fields on the
// parameter struct must match the corresponding result struct.
//
//	type GatewayParams struct {
//	  fx.In
//
//	  WriteToConn  *sql.DB `name:"rw"`
//	  ReadFromConn *sql.DB `name:"ro"`
//	}
//
// The name tag may be combined with the optional tag to declare the
// dependency optional.
//
//	type GatewayParams struct {
//	  fx.In
//
//	  WriteToConn  *sql.DB `name:"rw"`
//	  ReadFromConn *sql.DB `name:"ro" optional:"true"`
//	}
//
//	func NewCommentGateway(p GatewayParams, log *log.Logger) (*CommentGateway, error) {
//	  if p.ReadFromConn == nil {
//	    log.Print("Warning: Using RW connection for reads")
//	    p.ReadFromConn = p.WriteToConn
//	  }
//	  // ...
//	}
//
// # Value Groups
//
// To make it easier to produce and consume many values of the same type, Fx
// supports named, unordered collections called value groups. For details on
// producing value groups, see the documentation for the Out type.
//
// Functions can depend on a value group by requesting a slice tagged with
// `group:".."`. This will execute all constructors that provide a value to
// that group in an unspecified order, then collect all the results into a
// single slice. Keep in mind that this makes the types of the parameter and
// result struct fields different: if a group of constructors each returns
// type T, parameter structs consuming the group must use a field of type []T.
//
//	type ServerParams struct {
//	  fx.In
//
//	  Handlers []Handler `group:"server"`
//	}
//
//	func NewServer(p ServerParams) *Server {
//	  server := newServer()
//	  for _, h := range p.Handlers {
//	    server.Register(h)
//	  }
//	  return server
//	}
//
// Note that values in a value group are unordered. Fx makes no guarantees
// about the order in which these values will be produced.
//
// # Soft Value Groups
//
// A soft value group can be thought of as a best-attempt at populating the
// group with values from constructors that have already run. In other words,
// if a constructor's output type is only consumed by a soft value group,
// it will not be run.
//
// Note that Fx does not guarantee precise execution order of constructors
// or invokers, which means that the change in code that affects execution
// ordering of other constructors or functions will affect the values
// populated in this group.
//
// To declare a soft relationship between a group and its constructors, use
// the `soft` option on the group tag (`group:"[groupname],soft"`).
// This option is only valid for input parameters.
//
//	type Params struct {
//	  fx.In
//
//	  Handlers []Handler `group:"server"`
//	  Logger   *zap.Logger
//	}
//
//	NewHandlerAndLogger := func() (Handler, *zap.Logger) { ... }
//	NewHandler := func() Handler { ... }
//	Foo := func(Params) { ... }
//
//	app := fx.New(
//	  fx.Provide(NewHandlerAndLogger),
//	  fx.Provide(NewHandler),
//	  fx.Invoke(Foo),
//	)
//
// The only constructor called is `NewHandler`, because this also provides
// `*zap.Logger` needed in the `Params` struct received by `Foo`.
//
// In the next example, the slice `s` isn't populated as the provider would be
// called only because `strings` soft group value is its only consumer.
//
//	 app := fx.New(
//	   fx.Provide(
//	     fx.Annotate(
//	       func() (string,int) { return "hello" },
//	       fx.ResultTags(`group:"strings"`),
//	     ),
//	   ),
//	   fx.Invoke(
//	     fx.Annotate(func(s []string) {
//	       // s will be an empty slice
//	     }, fx.ParamTags(`group:"strings,soft"`)),
//	   ),
//	)
//
// In the next example, the slice `s` will be populated because there is a
// consumer for the same type which is not a `soft` dependency.
//
//	 app := fx.New(
//	   fx.Provide(
//	     fx.Annotate(
//	       func() string { "hello" },
//	       fx.ResultTags(`group:"strings"`),
//	     ),
//	   ),
//	   fx.Invoke(
//	     fx.Annotate(func(b []string) {
//	       // b is []string{"hello"}
//	     }, fx.ParamTags(`group:"strings"`)),
//	   ),
//	   fx.Invoke(
//	     fx.Annotate(func(s []string) {
//	       // s is []string{"hello"}
//	     }, fx.ParamTags(`group:"strings,soft"`)),
//	   ),
//	)
//
// # Unexported fields
//
// By default, a type that embeds fx.In may not have any unexported fields. The
// following will return an error if used with Fx.
//
//	type Params struct {
//	  fx.In
//
//	  Logger *zap.Logger
//	  mu     sync.Mutex
//	}
//
// If you have need of unexported fields on such a type, you may opt-into
// ignoring unexported fields by adding the ignore-unexported struct tag to the
// fx.In. For example,
//
//	type Params struct {
//	  fx.In `ignore-unexported:"true"`
//
//	  Logger *zap.Logger
//	  mu     sync.Mutex
//	}
type In = dig.In

// Out is the inverse of In: it can be embedded in result structs to take
// advantage of advanced features.
//
// Modules should return a single result struct that embeds an Out in order to
// provide a forward-compatible API: since adding fields to a struct is
// backward-compatible, minor releases can provide additional types.
//
// # Result Structs
//
// Result structs are the inverse of parameter structs (discussed in the In
// documentation). These structs represent multiple outputs from a
// single function as fields. Fx treats all structs embedding fx.Out as result
// structs, so other constructors can rely on the result struct's fields
// directly.
//
// Without result structs, we sometimes have function definitions like this:
//
//	func SetupGateways(conn *sql.DB) (*UserGateway, *CommentGateway, *PostGateway, error) {
//	  // ...
//	}
//
// With result structs, we can make this both more readable and easier to
// modify in the future:
//
//	type Gateways struct {
//	  fx.Out
//
//	  Users    *UserGateway
//	  Comments *CommentGateway
//	  Posts    *PostGateway
//	}
//
//	func SetupGateways(conn *sql.DB) (Gateways, error) {
//	  // ...
//	}
//
// # Named Values
//
// Some use cases require the application container to hold multiple values of
// the same type. For details on consuming named values, see the documentation
// for the In type.
//
// A constructor that produces a result struct can tag any field with
// `name:".."` to have the corresponding value added to the graph under the
// specified name. An application may contain at most one unnamed value of a
// given type, but may contain any number of named values of the same type.
//
//	type ConnectionResult struct {
//	  fx.Out
//
//	  ReadWrite *sql.DB `name:"rw"`
//	  ReadOnly  *sql.DB `name:"ro"`
//	}
//
//	func ConnectToDatabase(...) (ConnectionResult, error) {
//	  // ...
//	  return ConnectionResult{ReadWrite: rw, ReadOnly:  ro}, nil
//	}
//
// # Value Groups
//
// To make it easier to produce and consume many values of the same type, Fx
// supports named, unordered collections called value groups. For details on
// consuming value groups, see the documentation for the In type.
//
// Constructors can send values into value groups by returning a result struct
// tagged with `group:".."`.
//
//	type HandlerResult struct {
//	  fx.Out
//
//	  Handler Handler `group:"server"`
//	}
//
//	func NewHelloHandler() HandlerResult {
//	  // ...
//	}
//
//	func NewEchoHandler() HandlerResult {
//	  // ...
//	}
//
// Any number of constructors may provide values to this named collection, but
// the ordering of the final collection is unspecified. Keep in mind that
// value groups require parameter and result structs to use fields with
// different types: if a group of constructors each returns type T, parameter
// structs consuming the group must use a field of type []T.
//
// To provide multiple values for a group from a result struct, produce a
// slice and use the `,flatten` option on the group tag. This indicates that
// each element in the slice should be injected into the group individually.
//
//	type IntResult struct {
//	  fx.Out
//
//	  Handler []int `group:"server"`         // Consume as [][]int
//	  Handler []int `group:"server,flatten"` // Consume as []int
//	}
type Out = dig.Out
<|endoftext|>


<commit_before>// +build js

package sync

import (
	"unsafe"
)

type Pool struct {
	local     unsafe.Pointer
	localSize uintptr

	store []interface{}
	New   func() interface{}
}

func (p *Pool) Get() interface{} {
	if len(p.store) == 0 {
		if p.New != nil {
			return p.New()
		}
		return nil
	}
	x := p.store[len(p.store)-1]
	p.store = p.store[:len(p.store)-1]
	return x
}

func (p *Pool) Put(x interface{}) {
	if x == nil {
		return
	}
	p.store = append(p.store, x)
}

func runtime_registerPoolCleanup(cleanup func()) {
}

// var sems []chan struct{} = []chan struct{}{nil}

// func getSem(s *uint32) chan struct{} {
// 	sem := sems[*s]
// 	if sem == nil {
// 		*s = uint32(len(sems))
// 		sems = append(sems, make(chan struct{}))
// 	}
// 	return sem
// }

// func runtime_Semacquire(s *uint32) {
// 	<-getSem(s)
// }

// func runtime_Semrelease(s *uint32) {
// 	getSem(s) <- struct{}{}
// }

func runtime_Syncsemcheck(size uintptr) {
}

func (c *copyChecker) check() {
}
<commit_msg>Implement runtime_Semacquire and runtime_Semrelease.<commit_after>// +build js

package sync

import (
	"unsafe"
)

type Pool struct {
	local     unsafe.Pointer
	localSize uintptr

	store []interface{}
	New   func() interface{}
}

func (p *Pool) Get() interface{} {
	if len(p.store) == 0 {
		if p.New != nil {
			return p.New()
		}
		return nil
	}
	x := p.store[len(p.store)-1]
	p.store = p.store[:len(p.store)-1]
	return x
}

func (p *Pool) Put(x interface{}) {
	if x == nil {
		return
	}
	p.store = append(p.store, x)
}

func runtime_registerPoolCleanup(cleanup func()) {
}

var semWaiters = make(map[*uint32][]chan struct{})

func runtime_Semacquire(s *uint32) {
	if *s == 0 {
		ch := make(chan struct{})
		semWaiters[s] = append(semWaiters[s], ch)
		<-ch
	}
	*s--
}

func runtime_Semrelease(s *uint32) {
	*s++

	w := semWaiters[s]
	if len(w) == 0 {
		return
	}

	ch := w[0]
	if len(w) == 1 {
		delete(semWaiters, s)
	} else {
		semWaiters[s] = w[1:]
	}

	ch <- struct{}{}
}

func runtime_Syncsemcheck(size uintptr) {
}

func (c *copyChecker) check() {
}
<|endoftext|>


<commit_before>// Package junos allows you to run commands and configure Junos devices.
package junos

import (
	"encoding/xml"
	"errors"
	"fmt"
	"github.com/Juniper/go-netconf/netconf"
	"log"
)

// Session holds the connection information to our Junos device.
type Session struct {
	Conn *netconf.Session
}

// rollbackXML parses our rollback configuration.
type rollbackXML struct {
	XMLName xml.Name `xml:"rollback-information"`
	Config  string   `xml:"configuration-information>configuration-output"`
}

// RescueXML parses our rescue configuration.
type rescueXML struct {
	XMLName xml.Name `xml:"rescue-information"`
	Config  string   `xml:"configuration-information>configuration-output"`
}

// CommandXML parses our operational command responses.
type commandXML struct {
	Config string `xml:",innerxml"`
}

// NewSession establishes a new connection to a Junos device that we will use
// to run our commands against.
func NewSession(host, user, password string) *Session {
	s, err := netconf.DialSSH(host, netconf.SSHConfigPassword(user, password))
	if err != nil {
		log.Fatal(err)
	}

	return &Session{
		Conn: s,
	}
}

// Lock locks the candidate configuration.
func (s *Session) Lock() error {
	resp, err := s.Conn.Exec(rpcCommand["lock"])
	if err != nil {
		log.Fatal(err)
	}

	if resp.Ok == false {
		for _, m := range resp.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// Unlock unlocks the candidate configuration.
func (s *Session) Unlock() error {
	resp, err := s.Conn.Exec(rpcCommand["unlock"])
	if err != nil {
		log.Fatal(err)
	}

	if resp.Ok == false {
		for _, m := range resp.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// GetRollbackConfig returns the configuration of a given rollback configuration.
func (s *Session) GetRollbackConfig(number int) (string, error) {
	rb := &rollbackXML{}
	command := fmt.Sprintf(rpcCommand["get-rollback-information"], number)
	reply, err := s.Conn.Exec(command)

	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), rb)
	if err != nil {
		log.Fatal(err)
	}

	return rb.Config, nil
}

// RollbackDiff compares the current active configuration to a given rollback configuration.
func (s *Session) RollbackDiff(compare int) (string, error) {
	rb := &rollbackXML{}
	command := fmt.Sprintf(rpcCommand["get-rollback-information-compare"], compare)
	reply, err := s.Conn.Exec(command)

	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), rb)
	if err != nil {
		log.Fatal(err)
	}

	return rb.Config, nil
}

// GetRescueConfig returns the rescue configuration if one has been set.
func (s *Session) GetRescueConfig() (string, error) {
	rescue := &rescueXML{}
	reply, err := s.Conn.Exec(rpcCommand["get-rescue-information"])

	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), rescue)
	if err != nil {
		log.Fatal(err)
	}

	if rescue.Config == "" {
		return "No rescue configuration set.", nil
	}

	return rescue.Config, nil
}

// Command runs any operational mode command, such as "show" or "request."
// Format is either "text" or "xml".
func (s *Session) Command(cmd, format string) (string, error) {
	c := &commandXML{}
	var command string

	switch format {
	case "xml":
		command = fmt.Sprintf(rpcCommand["command-xml"], cmd)
	default:
		command = fmt.Sprintf(rpcCommand["command"], cmd)
	}
	reply, err := s.Conn.Exec(command)
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), &c)
	if err != nil {
		log.Fatal(err)
	}

	if c.Config == "" {
		return "No output available.", nil
	}

	return c.Config, nil
}

// Close disconnects our session to the device.
func (s *Session) Close() {
	s.Conn.Close()
}
<commit_msg>Updated package synopsis<commit_after>// Package junos allows you to run commands on and configure Junos devices.
package junos

import (
	"encoding/xml"
	"errors"
	"fmt"
	"github.com/Juniper/go-netconf/netconf"
	"log"
)

// Session holds the connection information to our Junos device.
type Session struct {
	Conn *netconf.Session
}

// rollbackXML parses our rollback configuration.
type rollbackXML struct {
	XMLName xml.Name `xml:"rollback-information"`
	Config  string   `xml:"configuration-information>configuration-output"`
}

// RescueXML parses our rescue configuration.
type rescueXML struct {
	XMLName xml.Name `xml:"rescue-information"`
	Config  string   `xml:"configuration-information>configuration-output"`
}

// CommandXML parses our operational command responses.
type commandXML struct {
	Config string `xml:",innerxml"`
}

// NewSession establishes a new connection to a Junos device that we will use
// to run our commands against.
func NewSession(host, user, password string) *Session {
	s, err := netconf.DialSSH(host, netconf.SSHConfigPassword(user, password))
	if err != nil {
		log.Fatal(err)
	}

	return &Session{
		Conn: s,
	}
}

// Lock locks the candidate configuration.
func (s *Session) Lock() error {
	resp, err := s.Conn.Exec(rpcCommand["lock"])
	if err != nil {
		log.Fatal(err)
	}

	if resp.Ok == false {
		for _, m := range resp.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// Unlock unlocks the candidate configuration.
func (s *Session) Unlock() error {
	resp, err := s.Conn.Exec(rpcCommand["unlock"])
	if err != nil {
		log.Fatal(err)
	}

	if resp.Ok == false {
		for _, m := range resp.Errors {
			return errors.New(m.Message)
		}
	}

	return nil
}

// GetRollbackConfig returns the configuration of a given rollback configuration.
func (s *Session) GetRollbackConfig(number int) (string, error) {
	rb := &rollbackXML{}
	command := fmt.Sprintf(rpcCommand["get-rollback-information"], number)
	reply, err := s.Conn.Exec(command)

	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), rb)
	if err != nil {
		log.Fatal(err)
	}

	return rb.Config, nil
}

// RollbackDiff compares the current active configuration to a given rollback configuration.
func (s *Session) RollbackDiff(compare int) (string, error) {
	rb := &rollbackXML{}
	command := fmt.Sprintf(rpcCommand["get-rollback-information-compare"], compare)
	reply, err := s.Conn.Exec(command)

	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), rb)
	if err != nil {
		log.Fatal(err)
	}

	return rb.Config, nil
}

// GetRescueConfig returns the rescue configuration if one has been set.
func (s *Session) GetRescueConfig() (string, error) {
	rescue := &rescueXML{}
	reply, err := s.Conn.Exec(rpcCommand["get-rescue-information"])

	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), rescue)
	if err != nil {
		log.Fatal(err)
	}

	if rescue.Config == "" {
		return "No rescue configuration set.", nil
	}

	return rescue.Config, nil
}

// Command runs any operational mode command, such as "show" or "request."
// Format is either "text" or "xml".
func (s *Session) Command(cmd, format string) (string, error) {
	c := &commandXML{}
	var command string

	switch format {
	case "xml":
		command = fmt.Sprintf(rpcCommand["command-xml"], cmd)
	default:
		command = fmt.Sprintf(rpcCommand["command"], cmd)
	}
	reply, err := s.Conn.Exec(command)
	if err != nil {
		log.Fatal(err)
	}

	if reply.Ok == false {
		for _, m := range reply.Errors {
			return "", errors.New(m.Message)
		}
	}

	err = xml.Unmarshal([]byte(reply.Data), &c)
	if err != nil {
		log.Fatal(err)
	}

	if c.Config == "" {
		return "No output available.", nil
	}

	return c.Config, nil
}

// Close disconnects our session to the device.
func (s *Session) Close() {
	s.Conn.Close()
}
<|endoftext|>


<commit_before>package cloudup

import (
	"encoding/json"
	"fmt"
	"github.com/golang/glog"
	"k8s.io/kops/upup/pkg/api"
	"k8s.io/kops/upup/pkg/fi/vfs"
	"k8s.io/kubernetes/pkg/util/sets"
	"strings"
)

const IAMPolicyDefaultVersion = "2012-10-17"

type IAMPolicy struct {
	Version   string
	Statement []*IAMStatement
}

func (p *IAMPolicy) AsJSON() (string, error) {
	j, err := json.MarshalIndent(p, "", "  ")
	if err != nil {
		return "", fmt.Errorf("error marshaling policy to JSON: %v", err)
	}
	return string(j), nil
}

type IAMStatementEffect string

const IAMStatementEffectAllow IAMStatementEffect = "Allow"

type IAMStatement struct {
	Effect   IAMStatementEffect
	Action   []string
	Resource []string
}

type IAMPolicyBuilder struct {
	Cluster *api.Cluster
	Role    api.InstanceGroupRole
	Region  string
}

func (b *IAMPolicyBuilder) BuildAWSIAMPolicy() (*IAMPolicy, error) {
	iamPrefix := b.IAMPrefix()

	p := &IAMPolicy{
		Version: IAMPolicyDefaultVersion,
	}

	if b.Role == api.InstanceGroupRoleNode {
		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"ec2:Describe*"},
			Resource: []string{"*"},
		})

		// No longer needed in 1.3
		//p.Statement = append(p.Statement, &IAMStatement{
		//	Effect: IAMStatementEffectAllow,
		//	Action: []string{ "ec2:AttachVolume" },
		//	Resource: []string{"*"},
		//})
		//p.Statement = append(p.Statement, &IAMStatement{
		//	Effect: IAMStatementEffectAllow,
		//	Action: []string{ "ec2:DetachVolume" },
		//	Resource: []string{"*"},
		//})

		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"route53:*"},
			Resource: []string{"*"},
		})

		p.Statement = append(p.Statement, &IAMStatement{
			Effect: IAMStatementEffectAllow,
			Action: []string{
				"ecr:GetAuthorizationToken",
				"ecr:BatchCheckLayerAvailability",
				"ecr:GetDownloadUrlForLayer",
				"ecr:GetRepositoryPolicy",
				"ecr:DescribeRepositories",
				"ecr:ListImages",
				"ecr:BatchGetImage",
			},
			Resource: []string{"*"},
		})
	}

	if b.Role == api.InstanceGroupRoleMaster {
		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"ec2:*"},
			Resource: []string{"*"},
		})

		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"route53:*"},
			Resource: []string{"*"},
		})

		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"elasticloadbalancing:*"},
			Resource: []string{"*"},
		})

		// Restrict the KMS permissions to only the keys that are being used
		kmsKeyIDs := sets.NewString()
		for _, e := range b.Cluster.Spec.EtcdClusters {
			for _, m := range e.Members {
				if m.KmsKeyId != nil {
					kmsKeyIDs.Insert(*m.KmsKeyId)
				}
			}
		}

		if kmsKeyIDs.Len() > 0 {
			p.Statement = append(p.Statement, &IAMStatement{
				Effect: IAMStatementEffectAllow,
				Action: []string{
					"kms:Encrypt",
					"kms:Decrypt",
					"kms:ReEncrypt*",
					"kms:GenerateDataKey*",
					"kms:DescribeKey",
					"kms:CreateGrant",
					"kms:ListGrants",
					"kms:RevokeGrant",
				},
				Resource: kmsKeyIDs.List(),
			})
		}
	}

	// For S3 IAM permissions, we grant permissions to subtrees.  So find the parents;
	// we don't need to grant mypath and mypath/child.
	var roots []string
	{
		var locations []string

		for _, p := range []string{
			b.Cluster.Spec.KeyStore,
			b.Cluster.Spec.SecretStore,
			b.Cluster.Spec.ConfigStore,
		} {
			if p == "" {
				continue
			}

			if !strings.HasSuffix(p, "/") {
				p = p + "/"
			}
			locations = append(locations, p)
		}

		for i, l := range locations {
			isTopLevel := true
			for j := range locations {
				if i == j {
					continue
				}
				if strings.HasPrefix(l, locations[j]) {
					glog.V(4).Infof("Ignoring location %q because found parent %q", l, locations[j])
					isTopLevel = false
				}
			}
			if isTopLevel {
				glog.V(4).Infof("Found root location %q", l)
				roots = append(roots, l)
			}
		}
	}

	for _, root := range roots {
		vfsPath, err := vfs.Context.BuildVfsPath(root)
		if err != nil {
			return nil, fmt.Errorf("cannot parse VFS path %q: %v", root, err)
		}

		if s3Path, ok := vfsPath.(*vfs.S3Path); ok {
			// Note that the config store may itself be a subdirectory of a bucket
			iamS3Path := s3Path.Bucket() + "/" + s3Path.Key()
			iamS3Path = strings.TrimSuffix(iamS3Path, "/")

			p.Statement = append(p.Statement, &IAMStatement{
				Effect: IAMStatementEffectAllow,
				Action: []string{"s3:*"},
				Resource: []string{
					iamPrefix + ":s3:::" + iamS3Path,
					iamPrefix + ":s3:::" + iamS3Path + "/*",
				},
			})

			p.Statement = append(p.Statement, &IAMStatement{
				Effect: IAMStatementEffectAllow,
				Action: []string{"s3:GetBucketLocation", "s3:ListBucket"},
				Resource: []string{
					iamPrefix + ":s3:::" + s3Path.Bucket(),
				},
			})
		} else {
			// We could implement this approach, but it seems better to get all clouds using cluster-readable storage
			return nil, fmt.Errorf("path is not cluster readable: %v", root)
		}
	}

	return p, nil
}

// IAMPrefix returns the prefix for AWS ARNs in the current region, for use with IAM
// it is arn:aws everywhere but in cn-north, where it is arn:aws-cn
func (b *IAMPolicyBuilder) IAMPrefix() string {
	switch b.Region {
	case "cn-north-1":
		return "arn:aws-cn"
	default:
		return "arn:aws"
	}
}
<commit_msg>Support ECR roles on the master also<commit_after>package cloudup

import (
	"encoding/json"
	"fmt"
	"github.com/golang/glog"
	"k8s.io/kops/upup/pkg/api"
	"k8s.io/kops/upup/pkg/fi/vfs"
	"k8s.io/kubernetes/pkg/util/sets"
	"strings"
)

const IAMPolicyDefaultVersion = "2012-10-17"

type IAMPolicy struct {
	Version   string
	Statement []*IAMStatement
}

func (p *IAMPolicy) AsJSON() (string, error) {
	j, err := json.MarshalIndent(p, "", "  ")
	if err != nil {
		return "", fmt.Errorf("error marshaling policy to JSON: %v", err)
	}
	return string(j), nil
}

type IAMStatementEffect string

const IAMStatementEffectAllow IAMStatementEffect = "Allow"

type IAMStatement struct {
	Effect   IAMStatementEffect
	Action   []string
	Resource []string
}

type IAMPolicyBuilder struct {
	Cluster *api.Cluster
	Role    api.InstanceGroupRole
	Region  string
}

func (b *IAMPolicyBuilder) BuildAWSIAMPolicy() (*IAMPolicy, error) {
	iamPrefix := b.IAMPrefix()

	p := &IAMPolicy{
		Version: IAMPolicyDefaultVersion,
	}

	if b.Role == api.InstanceGroupRoleNode {
		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"ec2:Describe*"},
			Resource: []string{"*"},
		})

		// No longer needed in 1.3
		//p.Statement = append(p.Statement, &IAMStatement{
		//	Effect: IAMStatementEffectAllow,
		//	Action: []string{ "ec2:AttachVolume" },
		//	Resource: []string{"*"},
		//})
		//p.Statement = append(p.Statement, &IAMStatement{
		//	Effect: IAMStatementEffectAllow,
		//	Action: []string{ "ec2:DetachVolume" },
		//	Resource: []string{"*"},
		//})

		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"route53:*"},
			Resource: []string{"*"},
		})
	}

	{
		// We provide ECR access on the nodes (naturally), but we also provide access on the master.
		// We shouldn't be running lots of pods on the master, but it is perfectly reasonable to run
		// a private logging pod or similar.
		p.Statement = append(p.Statement, &IAMStatement{
			Effect: IAMStatementEffectAllow,
			Action: []string{
				"ecr:GetAuthorizationToken",
				"ecr:BatchCheckLayerAvailability",
				"ecr:GetDownloadUrlForLayer",
				"ecr:GetRepositoryPolicy",
				"ecr:DescribeRepositories",
				"ecr:ListImages",
				"ecr:BatchGetImage",
			},
			Resource: []string{"*"},
		})
	}

	if b.Role == api.InstanceGroupRoleMaster {
		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"ec2:*"},
			Resource: []string{"*"},
		})

		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"route53:*"},
			Resource: []string{"*"},
		})

		p.Statement = append(p.Statement, &IAMStatement{
			Effect:   IAMStatementEffectAllow,
			Action:   []string{"elasticloadbalancing:*"},
			Resource: []string{"*"},
		})

		// Restrict the KMS permissions to only the keys that are being used
		kmsKeyIDs := sets.NewString()
		for _, e := range b.Cluster.Spec.EtcdClusters {
			for _, m := range e.Members {
				if m.KmsKeyId != nil {
					kmsKeyIDs.Insert(*m.KmsKeyId)
				}
			}
		}

		if kmsKeyIDs.Len() > 0 {
			p.Statement = append(p.Statement, &IAMStatement{
				Effect: IAMStatementEffectAllow,
				Action: []string{
					"kms:Encrypt",
					"kms:Decrypt",
					"kms:ReEncrypt*",
					"kms:GenerateDataKey*",
					"kms:DescribeKey",
					"kms:CreateGrant",
					"kms:ListGrants",
					"kms:RevokeGrant",
				},
				Resource: kmsKeyIDs.List(),
			})
		}
	}

	// For S3 IAM permissions, we grant permissions to subtrees.  So find the parents;
	// we don't need to grant mypath and mypath/child.
	var roots []string
	{
		var locations []string

		for _, p := range []string{
			b.Cluster.Spec.KeyStore,
			b.Cluster.Spec.SecretStore,
			b.Cluster.Spec.ConfigStore,
		} {
			if p == "" {
				continue
			}

			if !strings.HasSuffix(p, "/") {
				p = p + "/"
			}
			locations = append(locations, p)
		}

		for i, l := range locations {
			isTopLevel := true
			for j := range locations {
				if i == j {
					continue
				}
				if strings.HasPrefix(l, locations[j]) {
					glog.V(4).Infof("Ignoring location %q because found parent %q", l, locations[j])
					isTopLevel = false
				}
			}
			if isTopLevel {
				glog.V(4).Infof("Found root location %q", l)
				roots = append(roots, l)
			}
		}
	}

	for _, root := range roots {
		vfsPath, err := vfs.Context.BuildVfsPath(root)
		if err != nil {
			return nil, fmt.Errorf("cannot parse VFS path %q: %v", root, err)
		}

		if s3Path, ok := vfsPath.(*vfs.S3Path); ok {
			// Note that the config store may itself be a subdirectory of a bucket
			iamS3Path := s3Path.Bucket() + "/" + s3Path.Key()
			iamS3Path = strings.TrimSuffix(iamS3Path, "/")

			p.Statement = append(p.Statement, &IAMStatement{
				Effect: IAMStatementEffectAllow,
				Action: []string{"s3:*"},
				Resource: []string{
					iamPrefix + ":s3:::" + iamS3Path,
					iamPrefix + ":s3:::" + iamS3Path + "/*",
				},
			})

			p.Statement = append(p.Statement, &IAMStatement{
				Effect: IAMStatementEffectAllow,
				Action: []string{"s3:GetBucketLocation", "s3:ListBucket"},
				Resource: []string{
					iamPrefix + ":s3:::" + s3Path.Bucket(),
				},
			})
		} else {
			// We could implement this approach, but it seems better to get all clouds using cluster-readable storage
			return nil, fmt.Errorf("path is not cluster readable: %v", root)
		}
	}

	return p, nil
}

// IAMPrefix returns the prefix for AWS ARNs in the current region, for use with IAM
// it is arn:aws everywhere but in cn-north, where it is arn:aws-cn
func (b *IAMPolicyBuilder) IAMPrefix() string {
	switch b.Region {
	case "cn-north-1":
		return "arn:aws-cn"
	default:
		return "arn:aws"
	}
}
<|endoftext|>


<commit_before>package cfclient

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

	"github.com/pkg/errors"
)

type UserProvidedServiceInstancesResponse struct {
	Count     int                                   `json:"total_results"`
	Pages     int                                   `json:"total_pages"`
	NextUrl   string                                `json:"next_url"`
	Resources []UserProvidedServiceInstanceResource `json:"resources"`
}

type UserProvidedServiceInstanceResource struct {
	Meta   Meta                        `json:"metadata"`
	Entity UserProvidedServiceInstance `json:"entity"`
}

type UserProvidedServiceInstance struct {
	Name               string                 `json:"name"`
	Credentials        map[string]interface{} `json:"credentials"`
	SpaceGuid          string                 `json:"space_guid"`
	Type               string                 `json:"type"`
	Tags               []string               `json:"tags"`
	SpaceUrl           string                 `json:"space_url"`
	ServiceBindingsUrl string                 `json:"service_bindings_url"`
	RoutesUrl          string                 `json:"routes_url"`
	RouteServiceUrl    string                 `json:"route_service_url"`
	SyslogDrainUrl     string                 `json:"syslog_drain_url"`
	Guid               string                 `json:"guid"`
	c                  *Client
}

type UserProvidedServiceInstanceRequest struct {
	Name            string                 `json:"name"`
	Credentials     map[string]interface{} `json:"credentials"`
	SpaceGuid       string                 `json:"space_guid"`
	Tags            []string               `json:"tags"`
	RouteServiceUrl string                 `json:"route_service_url"`
	SyslogDrainUrl  string                 `json:"syslog_drain_url"`
}

func (c *Client) ListUserProvidedServiceInstancesByQuery(query url.Values) ([]UserProvidedServiceInstance, error) {
	var instances []UserProvidedServiceInstance

	requestUrl := "/v2/user_provided_service_instances?" + query.Encode()
	for {
		var sir UserProvidedServiceInstancesResponse
		r := c.NewRequest("GET", requestUrl)
		resp, err := c.DoRequest(r)
		if err != nil {
			return nil, errors.Wrap(err, "Error requesting user provided service instances")
		}
		resBody, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, errors.Wrap(err, "Error reading user provided service instances request:")
		}

		err = json.Unmarshal(resBody, &sir)
		if err != nil {
			return nil, errors.Wrap(err, "Error unmarshaling user provided service instances")
		}
		for _, instance := range sir.Resources {
			instance.Entity.Guid = instance.Meta.Guid
			instance.Entity.c = c
			instances = append(instances, instance.Entity)
		}

		requestUrl = sir.NextUrl
		if requestUrl == "" {
			break
		}
	}
	return instances, nil
}

func (c *Client) ListUserProvidedServiceInstances() ([]UserProvidedServiceInstance, error) {
	return c.ListUserProvidedServiceInstancesByQuery(nil)
}

func (c *Client) GetUserProvidedServiceInstanceByGuid(guid string) (UserProvidedServiceInstance, error) {
	var sir UserProvidedServiceInstanceResource
	req := c.NewRequest("GET", "/v2/user_provided_service_instances/"+guid)
	res, err := c.DoRequest(req)
	if err != nil {
		return UserProvidedServiceInstance{}, errors.Wrap(err, "Error requesting user provided service instance")
	}

	data, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return UserProvidedServiceInstance{}, errors.Wrap(err, "Error reading user provided service instance response")
	}
	err = json.Unmarshal(data, &sir)
	if err != nil {
		return UserProvidedServiceInstance{}, errors.Wrap(err, "Error JSON parsing user provided service instance response")
	}
	sir.Entity.Guid = sir.Meta.Guid
	sir.Entity.c = c
	return sir.Entity, nil
}

func (c *Client) UserProvidedServiceInstanceByGuid(guid string) (UserProvidedServiceInstance, error) {
	return c.GetUserProvidedServiceInstanceByGuid(guid)
}

func (c *Client) CreateUserProvidedServiceInstance(req UserProvidedServiceInstanceRequest) (UserProvidedServiceInstance, error) {
	buf := bytes.NewBuffer(nil)
	err := json.NewEncoder(buf).Encode(req)
	if err != nil {
		return UserProvidedServiceInstance{}, err
	}
	r := c.NewRequestWithBody("POST", "/v2/user_provided_service_instances", buf)
	resp, err := c.DoRequest(r)
	if err != nil {
		return UserProvidedServiceInstance{}, err
	}
	if resp.StatusCode != http.StatusCreated {
		return UserProvidedServiceInstance{}, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
	}

	return c.handleUserProvidedServiceInstanceResp(resp)
}

func (c *Client) handleUserProvidedServiceInstanceResp(resp *http.Response) (UserProvidedServiceInstance, error) {
	body, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return UserProvidedServiceInstance{}, err
	}
	var upsResource UserProvidedServiceInstanceResource
	err = json.Unmarshal(body, &upsResource)
	if err != nil {
		return UserProvidedServiceInstance{}, err
	}
	return c.mergeUserProvidedServiceInstanceResource(upsResource), nil
}

func (c *Client) mergeUserProvidedServiceInstanceResource(ups UserProvidedServiceInstanceResource) UserProvidedServiceInstance {
	ups.Entity.Guid = ups.Meta.Guid
	ups.Entity.c = c
	return ups.Entity
}
<commit_msg>Return a pointer instead of an instance<commit_after>package cfclient

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

	"github.com/pkg/errors"
)

type UserProvidedServiceInstancesResponse struct {
	Count     int                                   `json:"total_results"`
	Pages     int                                   `json:"total_pages"`
	NextUrl   string                                `json:"next_url"`
	Resources []UserProvidedServiceInstanceResource `json:"resources"`
}

type UserProvidedServiceInstanceResource struct {
	Meta   Meta                        `json:"metadata"`
	Entity UserProvidedServiceInstance `json:"entity"`
}

type UserProvidedServiceInstance struct {
	Name               string                 `json:"name"`
	Credentials        map[string]interface{} `json:"credentials"`
	SpaceGuid          string                 `json:"space_guid"`
	Type               string                 `json:"type"`
	Tags               []string               `json:"tags"`
	SpaceUrl           string                 `json:"space_url"`
	ServiceBindingsUrl string                 `json:"service_bindings_url"`
	RoutesUrl          string                 `json:"routes_url"`
	RouteServiceUrl    string                 `json:"route_service_url"`
	SyslogDrainUrl     string                 `json:"syslog_drain_url"`
	Guid               string                 `json:"guid"`
	c                  *Client
}

type UserProvidedServiceInstanceRequest struct {
	Name            string                 `json:"name"`
	Credentials     map[string]interface{} `json:"credentials"`
	SpaceGuid       string                 `json:"space_guid"`
	Tags            []string               `json:"tags"`
	RouteServiceUrl string                 `json:"route_service_url"`
	SyslogDrainUrl  string                 `json:"syslog_drain_url"`
}

func (c *Client) ListUserProvidedServiceInstancesByQuery(query url.Values) ([]UserProvidedServiceInstance, error) {
	var instances []UserProvidedServiceInstance

	requestUrl := "/v2/user_provided_service_instances?" + query.Encode()
	for {
		var sir UserProvidedServiceInstancesResponse
		r := c.NewRequest("GET", requestUrl)
		resp, err := c.DoRequest(r)
		if err != nil {
			return nil, errors.Wrap(err, "Error requesting user provided service instances")
		}
		resBody, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, errors.Wrap(err, "Error reading user provided service instances request:")
		}

		err = json.Unmarshal(resBody, &sir)
		if err != nil {
			return nil, errors.Wrap(err, "Error unmarshaling user provided service instances")
		}
		for _, instance := range sir.Resources {
			instance.Entity.Guid = instance.Meta.Guid
			instance.Entity.c = c
			instances = append(instances, instance.Entity)
		}

		requestUrl = sir.NextUrl
		if requestUrl == "" {
			break
		}
	}
	return instances, nil
}

func (c *Client) ListUserProvidedServiceInstances() ([]UserProvidedServiceInstance, error) {
	return c.ListUserProvidedServiceInstancesByQuery(nil)
}

func (c *Client) GetUserProvidedServiceInstanceByGuid(guid string) (UserProvidedServiceInstance, error) {
	var sir UserProvidedServiceInstanceResource
	req := c.NewRequest("GET", "/v2/user_provided_service_instances/"+guid)
	res, err := c.DoRequest(req)
	if err != nil {
		return UserProvidedServiceInstance{}, errors.Wrap(err, "Error requesting user provided service instance")
	}

	data, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return UserProvidedServiceInstance{}, errors.Wrap(err, "Error reading user provided service instance response")
	}
	err = json.Unmarshal(data, &sir)
	if err != nil {
		return UserProvidedServiceInstance{}, errors.Wrap(err, "Error JSON parsing user provided service instance response")
	}
	sir.Entity.Guid = sir.Meta.Guid
	sir.Entity.c = c
	return sir.Entity, nil
}

func (c *Client) UserProvidedServiceInstanceByGuid(guid string) (UserProvidedServiceInstance, error) {
	return c.GetUserProvidedServiceInstanceByGuid(guid)
}

func (c *Client) CreateUserProvidedServiceInstance(req UserProvidedServiceInstanceRequest) (*UserProvidedServiceInstance, error) {
	buf := bytes.NewBuffer(nil)
	err := json.NewEncoder(buf).Encode(req)
	if err != nil {
		return nil, err
	}
	r := c.NewRequestWithBody("POST", "/v2/user_provided_service_instances", buf)
	resp, err := c.DoRequest(r)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != http.StatusCreated {
		return nil, fmt.Errorf("CF API returned with status code %d", resp.StatusCode)
	}

	return c.handleUserProvidedServiceInstanceResp(resp)
}

func (c *Client) handleUserProvidedServiceInstanceResp(resp *http.Response) (*UserProvidedServiceInstance, error) {
	body, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return nil, err
	}
	var upsResource UserProvidedServiceInstanceResource
	err = json.Unmarshal(body, &upsResource)
	if err != nil {
		return nil, err
	}
	return c.mergeUserProvidedServiceInstanceResource(upsResource), nil
}

func (c *Client) mergeUserProvidedServiceInstanceResource(ups UserProvidedServiceInstanceResource) *UserProvidedServiceInstance {
	ups.Entity.Guid = ups.Meta.Guid
	ups.Entity.c = c
	return &ups.Entity
}
<|endoftext|>


<commit_before>package gcppubsub

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"sync"
	"time"

	"cloud.google.com/go/pubsub"
	"github.com/RichardKnop/machinery/v1/brokers/iface"
	"github.com/RichardKnop/machinery/v1/common"
	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/log"
	"github.com/RichardKnop/machinery/v1/tasks"
)

// Broker represents an Google Cloud Pub/Sub broker
type Broker struct {
	common.Broker

	service          *pubsub.Client
	subscriptionName string
	MaxExtension     time.Duration

	processingWG sync.WaitGroup
}

// New creates new Broker instance
func New(cnf *config.Config, projectID, subscriptionName string) (iface.Broker, error) {
	b := &Broker{Broker: common.NewBroker(cnf)}
	b.subscriptionName = subscriptionName

	ctx := context.Background()

	if cnf.GCPPubSub != nil {
		b.MaxExtension = cnf.GCPPubSub.MaxExtension
	}

	if cnf.GCPPubSub != nil && cnf.GCPPubSub.Client != nil {
		b.service = cnf.GCPPubSub.Client
	} else {
		pubsubClient, err := pubsub.NewClient(ctx, projectID)
		if err != nil {
			return nil, err
		}
		b.service = pubsubClient
		cnf.GCPPubSub = &config.GCPPubSubConfig{
			Client: pubsubClient,
		}
	}

	// Validate topic exists
	defaultQueue := b.GetConfig().DefaultQueue
	topic := b.service.Topic(defaultQueue)
	defer topic.Stop()

	topicExists, err := topic.Exists(ctx)
	if err != nil {
		return nil, err
	}
	if !topicExists {
		return nil, fmt.Errorf("topic does not exist, instead got %s", defaultQueue)
	}

	// Validate subscription exists
	sub := b.service.Subscription(b.subscriptionName)

	if b.MaxExtension != 0 {
		sub.ReceiveSettings.MaxExtension = b.MaxExtension
	}

	subscriptionExists, err := sub.Exists(ctx)
	if err != nil {
		return nil, err
	}
	if !subscriptionExists {
		return nil, fmt.Errorf("subscription does not exist, instead got %s", b.subscriptionName)
	}

	return b, nil
}

// StartConsuming enters a loop and waits for incoming messages
func (b *Broker) StartConsuming(consumerTag string, concurrency int, taskProcessor iface.TaskProcessor) (bool, error) {
	b.Broker.StartConsuming(consumerTag, concurrency, taskProcessor)
	deliveries := make(chan *pubsub.Message)

	sub := b.service.Subscription(b.subscriptionName)

	if b.MaxExtension != 0 {
		sub.ReceiveSettings.MaxExtension = b.MaxExtension
	}

	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		log.INFO.Print("[*] Waiting for messages. To exit press CTRL+C")

		for {
			select {
			// A way to stop this goroutine from b.StopConsuming
			case <-b.GetStopChan():
				cancel()
				return
			default:
				err := sub.Receive(ctx, func(_ctx context.Context, msg *pubsub.Message) {
					deliveries <- msg
				})

				if err != nil {
					log.ERROR.Printf("Error when receiving messages. Error: %v", err)
					continue
				}
			}
		}
	}()

	if err := b.consume(deliveries, concurrency, taskProcessor); err != nil {
		return b.GetRetry(), err
	}

	return b.GetRetry(), nil
}

// StopConsuming quits the loop
func (b *Broker) StopConsuming() {
	b.Broker.StopConsuming()

	// Waiting for any tasks being processed to finish
	b.processingWG.Wait()
}

// Publish places a new message on the default queue
func (b *Broker) Publish(ctx context.Context, signature *tasks.Signature) error {
	// Adjust routing key (this decides which queue the message will be published to)
	b.AdjustRoutingKey(signature)

	msg, err := json.Marshal(signature)
	if err != nil {
		return fmt.Errorf("JSON marshal error: %s", err)
	}

	defaultQueue := b.GetConfig().DefaultQueue
	topic := b.service.Topic(defaultQueue)
	defer topic.Stop()

	// Check the ETA signature field, if it is set and it is in the future,
	// delay the task
	if signature.ETA != nil {
		now := time.Now().UTC()

		if signature.ETA.After(now) {
			topic.PublishSettings.DelayThreshold = signature.ETA.Sub(now)
		}
	}

	result := topic.Publish(ctx, &pubsub.Message{
		Data: msg,
	})

	id, err := result.Get(ctx)
	if err != nil {
		log.ERROR.Printf("Error when sending a message: %v", err)
		return err
	}

	log.INFO.Printf("Sending a message successfully, server-generated message ID %v", id)
	return nil
}

// consume takes delivered messages from the channel and manages a worker pool
// to process tasks concurrently
func (b *Broker) consume(deliveries <-chan *pubsub.Message, concurrency int, taskProcessor iface.TaskProcessor) error {
	pool := make(chan struct{}, concurrency)

	// initialize worker pool with maxWorkers workers
	go func() {
		for i := 0; i < concurrency; i++ {
			pool <- struct{}{}
		}
	}()

	errorsChan := make(chan error)

	for {
		select {
		case err := <-errorsChan:
			return err
		case d := <-deliveries:
			if concurrency > 0 {
				// get worker from pool (blocks until one is available)
				<-pool
			}

			b.processingWG.Add(1)

			// Consume the task inside a gotourine so multiple tasks
			// can be processed concurrently
			go func() {
				if err := b.consumeOne(d, taskProcessor); err != nil {
					errorsChan <- err
				}

				b.processingWG.Done()

				if concurrency > 0 {
					// give worker back to pool
					pool <- struct{}{}
				}
			}()
		case <-b.GetStopChan():
			return nil
		}
	}
}

// consumeOne processes a single message using TaskProcessor
func (b *Broker) consumeOne(delivery *pubsub.Message, taskProcessor iface.TaskProcessor) error {
	if len(delivery.Data) == 0 {
		delivery.Nack()
		log.ERROR.Printf("received an empty message, the delivery was %v", delivery)
		return errors.New("Received an empty message")
	}

	sig := new(tasks.Signature)
	decoder := json.NewDecoder(bytes.NewBuffer(delivery.Data))
	decoder.UseNumber()
	if err := decoder.Decode(sig); err != nil {
		delivery.Nack()
		log.ERROR.Printf("unmarshal error. the delivery is %v", delivery)
		return err
	}

	// If the task is not registered return an error
	// and leave the message in the queue
	if !b.IsTaskRegistered(sig.Name) {
		delivery.Nack()
		return fmt.Errorf("task %s is not registered", sig.Name)
	}

	err := taskProcessor.Process(sig)
	if err != nil {
		delivery.Nack()
		return err
	}

	// Call Ack() after successfully consuming and processing the message
	delivery.Ack()

	return err
}
<commit_msg>Make sure PubSub consumes in concurrency number of Go routines.<commit_after>package gcppubsub

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"sync"
	"time"

	"cloud.google.com/go/pubsub"
	"github.com/RichardKnop/machinery/v1/brokers/iface"
	"github.com/RichardKnop/machinery/v1/common"
	"github.com/RichardKnop/machinery/v1/config"
	"github.com/RichardKnop/machinery/v1/log"
	"github.com/RichardKnop/machinery/v1/tasks"
)

// Broker represents an Google Cloud Pub/Sub broker
type Broker struct {
	common.Broker

	service          *pubsub.Client
	subscriptionName string
	MaxExtension     time.Duration

	processingWG sync.WaitGroup
}

// New creates new Broker instance
func New(cnf *config.Config, projectID, subscriptionName string) (iface.Broker, error) {
	b := &Broker{Broker: common.NewBroker(cnf)}
	b.subscriptionName = subscriptionName

	ctx := context.Background()

	if cnf.GCPPubSub != nil {
		b.MaxExtension = cnf.GCPPubSub.MaxExtension
	}

	if cnf.GCPPubSub != nil && cnf.GCPPubSub.Client != nil {
		b.service = cnf.GCPPubSub.Client
	} else {
		pubsubClient, err := pubsub.NewClient(ctx, projectID)
		if err != nil {
			return nil, err
		}
		b.service = pubsubClient
		cnf.GCPPubSub = &config.GCPPubSubConfig{
			Client: pubsubClient,
		}
	}

	// Validate topic exists
	defaultQueue := b.GetConfig().DefaultQueue
	topic := b.service.Topic(defaultQueue)
	defer topic.Stop()

	topicExists, err := topic.Exists(ctx)
	if err != nil {
		return nil, err
	}
	if !topicExists {
		return nil, fmt.Errorf("topic does not exist, instead got %s", defaultQueue)
	}

	// Validate subscription exists
	sub := b.service.Subscription(b.subscriptionName)

	if b.MaxExtension != 0 {
		sub.ReceiveSettings.MaxExtension = b.MaxExtension
	}

	subscriptionExists, err := sub.Exists(ctx)
	if err != nil {
		return nil, err
	}
	if !subscriptionExists {
		return nil, fmt.Errorf("subscription does not exist, instead got %s", b.subscriptionName)
	}

	return b, nil
}

// StartConsuming enters a loop and waits for incoming messages
func (b *Broker) StartConsuming(consumerTag string, concurrency int, taskProcessor iface.TaskProcessor) (bool, error) {
	b.Broker.StartConsuming(consumerTag, concurrency, taskProcessor)
	deliveries := make(chan *pubsub.Message)

	sub := b.service.Subscription(b.subscriptionName)

	if b.MaxExtension != 0 {
		sub.ReceiveSettings.MaxExtension = b.MaxExtension
		sub.ReceiveSettings.NumGoroutines = concurrency
	}

	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		log.INFO.Print("[*] Waiting for messages. To exit press CTRL+C")

		for {
			select {
			// A way to stop this goroutine from b.StopConsuming
			case <-b.GetStopChan():
				cancel()
				return
			default:
				err := sub.Receive(ctx, func(_ctx context.Context, msg *pubsub.Message) {
					deliveries <- msg
				})

				if err != nil {
					log.ERROR.Printf("Error when receiving messages. Error: %v", err)
					continue
				}
			}
		}
	}()

	if err := b.consume(deliveries, concurrency, taskProcessor); err != nil {
		return b.GetRetry(), err
	}

	return b.GetRetry(), nil
}

// StopConsuming quits the loop
func (b *Broker) StopConsuming() {
	b.Broker.StopConsuming()

	// Waiting for any tasks being processed to finish
	b.processingWG.Wait()
}

// Publish places a new message on the default queue
func (b *Broker) Publish(ctx context.Context, signature *tasks.Signature) error {
	// Adjust routing key (this decides which queue the message will be published to)
	b.AdjustRoutingKey(signature)

	msg, err := json.Marshal(signature)
	if err != nil {
		return fmt.Errorf("JSON marshal error: %s", err)
	}

	defaultQueue := b.GetConfig().DefaultQueue
	topic := b.service.Topic(defaultQueue)
	defer topic.Stop()

	// Check the ETA signature field, if it is set and it is in the future,
	// delay the task
	if signature.ETA != nil {
		now := time.Now().UTC()

		if signature.ETA.After(now) {
			topic.PublishSettings.DelayThreshold = signature.ETA.Sub(now)
		}
	}

	result := topic.Publish(ctx, &pubsub.Message{
		Data: msg,
	})

	id, err := result.Get(ctx)
	if err != nil {
		log.ERROR.Printf("Error when sending a message: %v", err)
		return err
	}

	log.INFO.Printf("Sending a message successfully, server-generated message ID %v", id)
	return nil
}

// consume takes delivered messages from the channel and manages a worker pool
// to process tasks concurrently
func (b *Broker) consume(deliveries <-chan *pubsub.Message, concurrency int, taskProcessor iface.TaskProcessor) error {
	pool := make(chan struct{}, concurrency)

	// initialize worker pool with maxWorkers workers
	go func() {
		for i := 0; i < concurrency; i++ {
			pool <- struct{}{}
		}
	}()

	errorsChan := make(chan error)

	for {
		select {
		case err := <-errorsChan:
			return err
		case d := <-deliveries:
			if concurrency > 0 {
				// get worker from pool (blocks until one is available)
				<-pool
			}

			b.processingWG.Add(1)

			// Consume the task inside a gotourine so multiple tasks
			// can be processed concurrently
			go func() {
				if err := b.consumeOne(d, taskProcessor); err != nil {
					errorsChan <- err
				}

				b.processingWG.Done()

				if concurrency > 0 {
					// give worker back to pool
					pool <- struct{}{}
				}
			}()
		case <-b.GetStopChan():
			return nil
		}
	}
}

// consumeOne processes a single message using TaskProcessor
func (b *Broker) consumeOne(delivery *pubsub.Message, taskProcessor iface.TaskProcessor) error {
	if len(delivery.Data) == 0 {
		delivery.Nack()
		log.ERROR.Printf("received an empty message, the delivery was %v", delivery)
		return errors.New("Received an empty message")
	}

	sig := new(tasks.Signature)
	decoder := json.NewDecoder(bytes.NewBuffer(delivery.Data))
	decoder.UseNumber()
	if err := decoder.Decode(sig); err != nil {
		delivery.Nack()
		log.ERROR.Printf("unmarshal error. the delivery is %v", delivery)
		return err
	}

	// If the task is not registered return an error
	// and leave the message in the queue
	if !b.IsTaskRegistered(sig.Name) {
		delivery.Nack()
		return fmt.Errorf("task %s is not registered", sig.Name)
	}

	err := taskProcessor.Process(sig)
	if err != nil {
		delivery.Nack()
		return err
	}

	// Call Ack() after successfully consuming and processing the message
	delivery.Ack()

	return err
}
<|endoftext|>


<commit_before>package logfanout

import (
	"errors"
	"io"
	"sync"
)

type LogDB interface {
	BuildLog(job string, build int) ([]byte, error)
	AppendBuildLog(job string, build int, log []byte) error
}

type LogFanout struct {
	job   string
	build int
	db    LogDB

	lock *sync.Mutex

	sinks []io.WriteCloser

	closed        bool
	waitForClosed chan struct{}
}

func NewLogFanout(job string, build int, db LogDB) *LogFanout {
	return &LogFanout{
		job:   job,
		build: build,
		db:    db,

		lock:          new(sync.Mutex),
		waitForClosed: make(chan struct{}),
	}
}

func (fanout *LogFanout) Write(data []byte) (int, error) {
	fanout.lock.Lock()

	err := fanout.db.AppendBuildLog(fanout.job, fanout.build, data)
	if err != nil {
		return 0, err
	}

	newSinks := []io.WriteCloser{}
	for _, sink := range fanout.sinks {
		_, err := sink.Write(data)
		if err != nil {
			continue
		}

		newSinks = append(newSinks, sink)
	}

	fanout.sinks = newSinks

	fanout.lock.Unlock()

	return len(data), nil
}

func (fanout *LogFanout) Attach(sink io.WriteCloser) error {
	fanout.lock.Lock()

	log, err := fanout.db.BuildLog(fanout.job, fanout.build)
	if err == nil {
		_, err = sink.Write(log)
		if err != nil {
			fanout.lock.Unlock()
			return err
		}
	}

	if fanout.closed {
		sink.Close()
	} else {
		fanout.sinks = append(fanout.sinks, sink)
	}

	fanout.lock.Unlock()

	<-fanout.waitForClosed

	return nil
}

func (fanout *LogFanout) Close() error {
	fanout.lock.Lock()
	defer fanout.lock.Unlock()

	if fanout.closed {
		return errors.New("close twice")
	}

	for _, sink := range fanout.sinks {
		sink.Close()
	}

	fanout.closed = true
	fanout.sinks = nil

	close(fanout.waitForClosed)

	return nil
}
<commit_msg>fix deadlock when appending logs to db fails<commit_after>package logfanout

import (
	"errors"
	"io"
	"sync"
)

type LogDB interface {
	BuildLog(job string, build int) ([]byte, error)
	AppendBuildLog(job string, build int, log []byte) error
}

type LogFanout struct {
	job   string
	build int
	db    LogDB

	lock *sync.Mutex

	sinks []io.WriteCloser

	closed        bool
	waitForClosed chan struct{}
}

func NewLogFanout(job string, build int, db LogDB) *LogFanout {
	return &LogFanout{
		job:   job,
		build: build,
		db:    db,

		lock:          new(sync.Mutex),
		waitForClosed: make(chan struct{}),
	}
}

func (fanout *LogFanout) Write(data []byte) (int, error) {
	fanout.lock.Lock()
	defer fanout.lock.Unlock()

	err := fanout.db.AppendBuildLog(fanout.job, fanout.build, data)
	if err != nil {
		return 0, err
	}

	newSinks := []io.WriteCloser{}
	for _, sink := range fanout.sinks {
		_, err := sink.Write(data)
		if err != nil {
			continue
		}

		newSinks = append(newSinks, sink)
	}

	fanout.sinks = newSinks

	return len(data), nil
}

func (fanout *LogFanout) Attach(sink io.WriteCloser) error {
	fanout.lock.Lock()

	log, err := fanout.db.BuildLog(fanout.job, fanout.build)
	if err == nil {
		_, err = sink.Write(log)
		if err != nil {
			fanout.lock.Unlock()
			return err
		}
	}

	if fanout.closed {
		sink.Close()
	} else {
		fanout.sinks = append(fanout.sinks, sink)
	}

	fanout.lock.Unlock()

	<-fanout.waitForClosed

	return nil
}

func (fanout *LogFanout) Close() error {
	fanout.lock.Lock()
	defer fanout.lock.Unlock()

	if fanout.closed {
		return errors.New("close twice")
	}

	for _, sink := range fanout.sinks {
		sink.Close()
	}

	fanout.closed = true
	fanout.sinks = nil

	close(fanout.waitForClosed)

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2017 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package validation provides a helper for performing config validations.
package validation

import (
	"fmt"
	"regexp"
	"strings"
)

const hostnameSegmentPattern = "[a-z0-9]([a-z0-9-]*[a-z0-9])*"

var hostnameRegexp = regexp.MustCompile(fmt.Sprintf(
	"^%s([.]%s)*$",
	hostnameSegmentPattern,
	hostnameSegmentPattern,
))

// ValidateHostname returns an error if the given string is not a valid
// RFC1123 hostname.
func ValidateHostname(hostname string) error {
	if len(hostname) > 255 {
		return fmt.Errorf("length exceeds 255 bytes")
	}
	if !hostnameRegexp.MatchString(hostname) {
		return fmt.Errorf("hostname does not match regex %q", hostnameRegexp)
	}
	for _, s := range strings.Split(hostname, ".") {
		if len(s) > 63 {
			return fmt.Errorf("segment %q exceeds 63 bytes", s)
		}
	}
	return nil
}
<commit_msg>[validation] delete spurious godoc line.<commit_after>// Copyright 2017 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package validation

import (
	"fmt"
	"regexp"
	"strings"
)

const hostnameSegmentPattern = "[a-z0-9]([a-z0-9-]*[a-z0-9])*"

var hostnameRegexp = regexp.MustCompile(fmt.Sprintf(
	"^%s([.]%s)*$",
	hostnameSegmentPattern,
	hostnameSegmentPattern,
))

// ValidateHostname returns an error if the given string is not a valid
// RFC1123 hostname.
func ValidateHostname(hostname string) error {
	if len(hostname) > 255 {
		return fmt.Errorf("length exceeds 255 bytes")
	}
	if !hostnameRegexp.MatchString(hostname) {
		return fmt.Errorf("hostname does not match regex %q", hostnameRegexp)
	}
	for _, s := range strings.Split(hostname, ".") {
		if len(s) > 63 {
			return fmt.Errorf("segment %q exceeds 63 bytes", s)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package v2

import (
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/laincloud/lainlet/api"
	"github.com/laincloud/lainlet/auth"
	"github.com/laincloud/lainlet/watcher"
	"github.com/laincloud/lainlet/watcher/podgroup"
)

type ContainerForWebrouter struct {
	IP     string `json:"ContainerIp"`
	Expose int
}

type PodInfoForWebrouter struct {
	Annotation string
	Containers []ContainerForWebrouter `json:"ContainerInfos"`
}

// Coreinfo type
type CoreInfoForWebrouter struct {
	PodInfos []PodInfoForWebrouter
}

// Coreinfo API
type WebrouterInfo struct {
	Data map[string]CoreInfoForWebrouter
}

func (wi *WebrouterInfo) Decode(r []byte) error {
	return json.Unmarshal(r, &wi.Data)
}

func (wi *WebrouterInfo) Encode() ([]byte, error) {
	return json.Marshal(wi.Data)
}

func (wi *WebrouterInfo) URI() string {
	return "/webrouter/webprocs"
}

func (wi *WebrouterInfo) WatcherName() string {
	return watcher.PODGROUP
}

func (wi *WebrouterInfo) Make(data map[string]interface{}) (api.API, bool, error) {
	ret := &WebrouterInfo{
		Data: make(map[string]CoreInfoForWebrouter),
	}
	for _, item := range data {
		pg := item.(podgroup.PodGroup)
		parts := strings.Split(pg.Spec.Name, ".")
		// Webrouter only cares about web procs
		if len(parts) != 3 || parts[1] != "web" {
			continue
		}
		ci := CoreInfoForWebrouter{
			PodInfos: make([]PodInfoForWebrouter, len(pg.Pods)),
		}
		for i, pod := range pg.Pods {
			ci.PodInfos[i] = PodInfoForWebrouter{
				Annotation: pg.Spec.Pod.Annotation,
				Containers: make([]ContainerForWebrouter, len(pod.Containers)),
			}
			for j, container := range pod.Containers {
				ci.PodInfos[i].Containers[j] = ContainerForWebrouter{
					IP:     container.ContainerIp,
					Expose: pg.Spec.Pod.Containers[j].Expose,
				}
			}
		}
		ret.Data[pg.Spec.Name] = ci
	}
	return ret, !reflect.DeepEqual(wi.Data, ret.Data), nil
}

func (wi *WebrouterInfo) Key(r *http.Request) (string, error) {
	appName := api.GetString(r, "appname", "*")
	if !auth.Pass(r.RemoteAddr, appName) {
		if appName == "*" { // try to set the appname automatically by remoteip
			appName, err := auth.AppName(r.RemoteAddr)
			if err != nil {
				return "", fmt.Errorf("authorize failed, can not confirm the app by request ip")
			}
			return appName, nil
		}
		return "", fmt.Errorf("authorize failed, no permission")
	}
	return appName, nil
}
<commit_msg>fixbug: webrouter_webprocs api can not handle resource type app<commit_after>package v2

import (
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/laincloud/lainlet/api"
	"github.com/laincloud/lainlet/auth"
	"github.com/laincloud/lainlet/watcher"
	"github.com/laincloud/lainlet/watcher/podgroup"
)

type ContainerForWebrouter struct {
	IP     string `json:"ContainerIp"`
	Expose int
}

type PodInfoForWebrouter struct {
	Annotation string
	Containers []ContainerForWebrouter `json:"ContainerInfos"`
}

// Coreinfo type
type CoreInfoForWebrouter struct {
	PodInfos []PodInfoForWebrouter
}

// Coreinfo API
type WebrouterInfo struct {
	Data map[string]CoreInfoForWebrouter
}

func (wi *WebrouterInfo) Decode(r []byte) error {
	return json.Unmarshal(r, &wi.Data)
}

func (wi *WebrouterInfo) Encode() ([]byte, error) {
	return json.Marshal(wi.Data)
}

func (wi *WebrouterInfo) URI() string {
	return "/webrouter/webprocs"
}

func (wi *WebrouterInfo) WatcherName() string {
	return watcher.PODGROUP
}

func (wi *WebrouterInfo) Make(data map[string]interface{}) (api.API, bool, error) {
	ret := &WebrouterInfo{
		Data: make(map[string]CoreInfoForWebrouter),
	}
	for _, item := range data {
		pg := item.(podgroup.PodGroup)
		parts := strings.Split(pg.Spec.Name, ".")
		// Webrouter only cares about web procs
		if len(parts) < 3 || parts[len(parts)-2] != "web" {
			continue
		}
		ci := CoreInfoForWebrouter{
			PodInfos: make([]PodInfoForWebrouter, len(pg.Pods)),
		}
		for i, pod := range pg.Pods {
			ci.PodInfos[i] = PodInfoForWebrouter{
				Annotation: pg.Spec.Pod.Annotation,
				Containers: make([]ContainerForWebrouter, len(pod.Containers)),
			}
			for j, container := range pod.Containers {
				ci.PodInfos[i].Containers[j] = ContainerForWebrouter{
					IP:     container.ContainerIp,
					Expose: pg.Spec.Pod.Containers[j].Expose,
				}
			}
		}
		ret.Data[pg.Spec.Name] = ci
	}
	return ret, !reflect.DeepEqual(wi.Data, ret.Data), nil
}

func (wi *WebrouterInfo) Key(r *http.Request) (string, error) {
	appName := api.GetString(r, "appname", "*")
	if !auth.Pass(r.RemoteAddr, appName) {
		if appName == "*" { // try to set the appname automatically by remoteip
			appName, err := auth.AppName(r.RemoteAddr)
			if err != nil {
				return "", fmt.Errorf("authorize failed, can not confirm the app by request ip")
			}
			return appName, nil
		}
		return "", fmt.Errorf("authorize failed, no permission")
	}
	return appName, nil
}
<|endoftext|>


<commit_before>package vacuum

import (
	"os"

	"github.com/xiaonanln/vacuum/common"
)

type _FuncPtrStringDelegate struct {
	init func(s *String, args ...interface{})
	loop func(s *String, msg common.StringMessage)
	fini func(s *String)
}

func (d *_FuncPtrStringDelegate) Init(s *String, args ...interface{}) {
	if d.init != nil {
		d.init(s, args...)
	}
}

func (d *_FuncPtrStringDelegate) Fini(s *String) {
	if d.fini != nil {
		d.fini(s)
	}
}

func (d *_FuncPtrStringDelegate) Loop(s *String, msg common.StringMessage) {
	if d.loop != nil {
		d.loop(s, msg)
	}
}

func InitStringDelegateMaker(init func(s *String, args ...interface{})) StringDelegateMaker {
	return func() StringDelegate {
		return &_FuncPtrStringDelegate{
			init: func(s *String, args ...interface{}) {
				init(s, args...)
				s.Send(s.ID, nil) // trick: make string quit immediately
			},
			loop: nil,
			fini: nil,
		}
	}
}

func RegisterMain(main func(s *String)) {
	RegisterString("Main", InitStringDelegateMaker(func(s *String, args ...interface{}) {
		main(s)
		os.Exit(0)
	}))
}
<commit_msg>LoopOnlyStringDelegateMaker<commit_after>package vacuum

import (
	"os"

	"github.com/xiaonanln/vacuum/common"
)

type _FuncPtrStringDelegate struct {
	init func(s *String, args ...interface{})
	loop func(s *String, msg common.StringMessage)
	fini func(s *String)
}

func (d *_FuncPtrStringDelegate) Init(s *String, args ...interface{}) {
	if d.init != nil {
		d.init(s, args...)
	}
}

func (d *_FuncPtrStringDelegate) Fini(s *String) {
	if d.fini != nil {
		d.fini(s)
	}
}

func (d *_FuncPtrStringDelegate) Loop(s *String, msg common.StringMessage) {
	if d.loop != nil {
		d.loop(s, msg)
	}
}

func InitOnlyStringDelegateMaker(init func(s *String, args ...interface{})) StringDelegateMaker {
	return func() StringDelegate {
		return &_FuncPtrStringDelegate{
			init: func(s *String, args ...interface{}) {
				init(s, args...)
				s.Send(s.ID, nil) // trick: make string quit immediately
			},
			loop: nil,
			fini: nil,
		}
	}
}

func LoopOnlyStringDelegateMaker(loop func(s *String, msg common.StringMessage)) StringDelegateMaker {
	return func() StringDelegate {
		return &_FuncPtrStringDelegate{
			init: nil,
			loop: loop,
			fini: nil,
		}
	}
}

func RegisterMain(main func(s *String)) {
	RegisterString("Main", InitOnlyStringDelegateMaker(func(s *String, args ...interface{}) {
		main(s)
		os.Exit(0)
	}))
}
<|endoftext|>


<commit_before>package lb

import (
	"encoding/json"
	"fmt"

	"github.com/codegangsta/cli"
	"github.com/mikebeyer/clc-sdk/sdk/clc"
	"github.com/mikebeyer/clc-sdk/sdk/lb"
)

func Commands(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "load-balancer",
		Aliases: []string{"lb"},
		Usage:   "load balancer api",
		Subcommands: []cli.Command{
			get(client),
			create(client),
			getPool(client),
			createPool(client),
			getNode(client),
		},
	}
}

func get(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "get",
		Aliases: []string{"g"},
		Usage:   "get load balancer details",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "all", Usage: "list all load balancers for location"},
			cli.StringFlag{Name: "id", Usage: "load balancer id"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
		},
		Before: func(c *cli.Context) error {
			if c.String("location") == "" {
				fmt.Printf("location flag is required.\n")
				return fmt.Errorf("")
			}
			return nil
		},
		Action: func(c *cli.Context) {
			if c.Bool("all") || c.String("id") == "" {
				resp, err := client.LB.GetAll(c.String("location"))
				if err != nil {
					fmt.Printf("failed to get %s\n", c.Args().First())
					return
				}
				b, err := json.MarshalIndent(resp, "", "  ")
				if err != nil {
					fmt.Printf("%s\n", err)
					return
				}
				fmt.Printf("%s\n", b)
				return
			}
			resp, err := client.LB.Get(c.String("location"), c.String("id"))
			if err != nil {
				fmt.Printf("failed to get %s\n", c.Args().First())
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}

func create(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "create",
		Aliases: []string{"c"},
		Usage:   "create shared load balancer",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "name, n", Usage: "load balancer name [required]"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
			cli.StringFlag{Name: "description, d", Usage: "load balancer description"},
		},
		Action: func(c *cli.Context) {
			name := c.String("name")
			loc := c.String("location")
			if name == "" || loc == "" {
				fmt.Printf("missing required flags to create load balancer. [use --help to show required flags]\n")
				return
			}

			lb := lb.LoadBalancer{Name: name, Description: c.String("description")}
			resp, err := client.LB.Create(loc, lb)
			if err != nil {
				fmt.Printf("failed to create load balancer [%s] in %s\n", name, loc)
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}

func getPool(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "get-pool",
		Aliases: []string{"gp"},
		Usage:   "get load balancer pool details",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "all", Usage: "list all load balancers for location"},
			cli.StringFlag{Name: "id", Usage: "load balancer id [required]"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
			cli.StringFlag{Name: "pool", Usage: "load balancer pool id"},
		},
		Before: func(c *cli.Context) error {
			if c.String("location") == "" || c.String("id") == "" {
				fmt.Printf("missing required flags to get pool. [use --help to show required flags]\n")
				return fmt.Errorf("")
			}
			return nil
		},
		Action: func(c *cli.Context) {
			if c.Bool("all") || c.String("pool") == "" {
				resp, err := client.LB.GetAllPools(c.String("location"), c.String("id"))
				if err != nil {
					fmt.Printf("failed to get %s\n", c.Args().First())
					return
				}
				b, err := json.MarshalIndent(resp, "", "  ")
				if err != nil {
					fmt.Printf("%s\n", err)
					return
				}
				fmt.Printf("%s\n", b)
				return
			}
			resp, err := client.LB.GetPool(c.String("location"), c.String("id"), c.String("pool"))
			if err != nil {
				fmt.Printf("failed to get %s\n", c.Args().First())
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}

func createPool(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "create-pool",
		Aliases: []string{"cp"},
		Usage:   "create load balancer pool",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "id", Usage: "load balancer id [required]"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
			cli.IntFlag{Name: "port", Usage: "pool port [required]"},
			cli.BoolFlag{Name: "sticky", Usage: "use stick persistence"},
			cli.BoolFlag{Name: "standard", Usage: "use standard persistence [default]"},
			cli.BoolFlag{Name: "least-connection, lc", Usage: "use least-connection load balacing"},
			cli.BoolFlag{Name: "round-robin, rr", Usage: "use round-robin load balacing [default]"},
		},
		Before: func(c *cli.Context) error {
			if c.Bool("sticky") && c.Bool("standard") {
				fmt.Println("only one of sticky and standard can be selected")
				return fmt.Errorf("")
			}

			if c.Bool("least-connection") && c.Bool("round-robin") {
				fmt.Println("only one of least-connection and round-robin can be selected")
				return fmt.Errorf("")
			}

			if c.String("id") == "" || c.String("location") == "" || c.Int("port") == 0 {
				fmt.Println("missing required flags, --help for more details")
				return fmt.Errorf("")
			}
			return nil
		},
		Action: func(c *cli.Context) {
			pool := lb.Pool{Port: c.Int("port")}
			if c.Bool("sticky") {
				pool.Persistence = lb.Sticky
			} else {
				pool.Persistence = lb.Standard
			}

			if c.Bool("least-connection") {
				pool.Method = lb.LeastConn
			} else {
				pool.Method = lb.RoundRobin
			}

			resp, err := client.LB.CreatePool(c.String("location"), c.String("id"), pool)
			if err != nil {
				fmt.Printf("failed to create load balancer pool for [%s] in %s\n", c.String("id"), c.String("location"))
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}

func getNode(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "get-node",
		Aliases: []string{"gn"},
		Usage:   "get load balancer node details",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "id", Usage: "load balancer id [required]"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
			cli.StringFlag{Name: "pool", Usage: "load balancer pool id [required]"},
		},
		Before: func(c *cli.Context) error {
			if c.String("location") == "" || c.String("id") == "" || c.String("pool") == "" {
				fmt.Printf("missing required flags to get pool. [use --help to show required flags]\n")
				return fmt.Errorf("")
			}
			return nil
		},
		Action: func(c *cli.Context) {
			resp, err := client.LB.GetAllNodes(c.String("location"), c.String("id"), c.String("pool"))
			if err != nil {
				fmt.Printf("failed to get %s\n", c.Args().First())
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}
<commit_msg>added update node for cli<commit_after>package lb

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

	"github.com/codegangsta/cli"
	"github.com/mikebeyer/clc-sdk/sdk/clc"
	"github.com/mikebeyer/clc-sdk/sdk/lb"
)

func Commands(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "load-balancer",
		Aliases: []string{"lb"},
		Usage:   "load balancer api",
		Subcommands: []cli.Command{
			get(client),
			create(client),
			getPool(client),
			createPool(client),
			getNode(client),
			updateNode(client),
		},
	}
}

func get(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "get",
		Aliases: []string{"g"},
		Usage:   "get load balancer details",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "all", Usage: "list all load balancers for location"},
			cli.StringFlag{Name: "id", Usage: "load balancer id"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
		},
		Before: func(c *cli.Context) error {
			if c.String("location") == "" {
				fmt.Printf("location flag is required.\n")
				return fmt.Errorf("")
			}
			return nil
		},
		Action: func(c *cli.Context) {
			if c.Bool("all") || c.String("id") == "" {
				resp, err := client.LB.GetAll(c.String("location"))
				if err != nil {
					fmt.Printf("failed to get %s\n", c.Args().First())
					return
				}
				b, err := json.MarshalIndent(resp, "", "  ")
				if err != nil {
					fmt.Printf("%s\n", err)
					return
				}
				fmt.Printf("%s\n", b)
				return
			}
			resp, err := client.LB.Get(c.String("location"), c.String("id"))
			if err != nil {
				fmt.Printf("failed to get %s\n", c.Args().First())
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}

func create(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "create",
		Aliases: []string{"c"},
		Usage:   "create shared load balancer",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "name, n", Usage: "load balancer name [required]"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
			cli.StringFlag{Name: "description, d", Usage: "load balancer description"},
		},
		Action: func(c *cli.Context) {
			name := c.String("name")
			loc := c.String("location")
			if name == "" || loc == "" {
				fmt.Printf("missing required flags to create load balancer. [use --help to show required flags]\n")
				return
			}

			lb := lb.LoadBalancer{Name: name, Description: c.String("description")}
			resp, err := client.LB.Create(loc, lb)
			if err != nil {
				fmt.Printf("failed to create load balancer [%s] in %s\n", name, loc)
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}

func getPool(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "get-pool",
		Aliases: []string{"gp"},
		Usage:   "get load balancer pool details",
		Flags: []cli.Flag{
			cli.BoolFlag{Name: "all", Usage: "list all load balancers for location"},
			cli.StringFlag{Name: "id", Usage: "load balancer id [required]"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
			cli.StringFlag{Name: "pool, p", Usage: "load balancer pool id"},
		},
		Before: func(c *cli.Context) error {
			if c.String("location") == "" || c.String("id") == "" {
				fmt.Printf("missing required flags to get pool. [use --help to show required flags]\n")
				return fmt.Errorf("")
			}
			return nil
		},
		Action: func(c *cli.Context) {
			if c.Bool("all") || c.String("pool") == "" {
				resp, err := client.LB.GetAllPools(c.String("location"), c.String("id"))
				if err != nil {
					fmt.Printf("failed to get %s\n", c.Args().First())
					return
				}
				b, err := json.MarshalIndent(resp, "", "  ")
				if err != nil {
					fmt.Printf("%s\n", err)
					return
				}
				fmt.Printf("%s\n", b)
				return
			}
			resp, err := client.LB.GetPool(c.String("location"), c.String("id"), c.String("pool"))
			if err != nil {
				fmt.Printf("failed to get %s\n", c.Args().First())
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}

func createPool(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "create-pool",
		Aliases: []string{"cp"},
		Usage:   "create load balancer pool",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "id", Usage: "load balancer id [required]"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
			cli.IntFlag{Name: "port", Usage: "pool port [required]"},
			cli.BoolFlag{Name: "sticky", Usage: "use stick persistence"},
			cli.BoolFlag{Name: "standard", Usage: "use standard persistence [default]"},
			cli.BoolFlag{Name: "least-connection, lc", Usage: "use least-connection load balacing"},
			cli.BoolFlag{Name: "round-robin, rr", Usage: "use round-robin load balacing [default]"},
		},
		Before: func(c *cli.Context) error {
			if c.Bool("sticky") && c.Bool("standard") {
				fmt.Println("only one of sticky and standard can be selected")
				return fmt.Errorf("")
			}

			if c.Bool("least-connection") && c.Bool("round-robin") {
				fmt.Println("only one of least-connection and round-robin can be selected")
				return fmt.Errorf("")
			}

			if c.String("id") == "" || c.String("location") == "" || c.Int("port") == 0 {
				fmt.Println("missing required flags, --help for more details")
				return fmt.Errorf("")
			}
			return nil
		},
		Action: func(c *cli.Context) {
			pool := lb.Pool{Port: c.Int("port")}
			if c.Bool("sticky") {
				pool.Persistence = lb.Sticky
			} else {
				pool.Persistence = lb.Standard
			}

			if c.Bool("least-connection") {
				pool.Method = lb.LeastConn
			} else {
				pool.Method = lb.RoundRobin
			}

			resp, err := client.LB.CreatePool(c.String("location"), c.String("id"), pool)
			if err != nil {
				fmt.Printf("failed to create load balancer pool for [%s] in %s\n", c.String("id"), c.String("location"))
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}

func getNode(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "get-node",
		Aliases: []string{"gn"},
		Usage:   "get load balancer node details",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "id", Usage: "load balancer id [required]"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
			cli.StringFlag{Name: "pool, p", Usage: "load balancer pool id [required]"},
		},
		Before: func(c *cli.Context) error {
			if c.String("location") == "" || c.String("id") == "" || c.String("pool") == "" {
				fmt.Printf("missing required flags to get pool. [use --help to show required flags]\n")
				return fmt.Errorf("")
			}
			return nil
		},
		Action: func(c *cli.Context) {
			resp, err := client.LB.GetAllNodes(c.String("location"), c.String("id"), c.String("pool"))
			if err != nil {
				fmt.Printf("failed to get %s\n", c.Args().First())
				return
			}
			b, err := json.MarshalIndent(resp, "", "  ")
			if err != nil {
				fmt.Printf("%s\n", err)
				return
			}
			fmt.Printf("%s\n", b)
		},
	}
}

func updateNode(client *clc.Client) cli.Command {
	return cli.Command{
		Name:    "update-node",
		Aliases: []string{"un"},
		Usage:   "update load balancer node details",
		Flags: []cli.Flag{
			cli.StringFlag{Name: "id", Usage: "load balancer id [required]"},
			cli.StringFlag{Name: "location, l", Usage: "load balancer location [required]"},
			cli.StringFlag{Name: "pool, p", Usage: "load balancer pool id [required]"},
			cli.StringSliceFlag{Name: "host, h", Usage: "node hostname and port (ex. 10.10.10.10:8080)"},
		},
		Before: func(c *cli.Context) error {
			if c.String("location") == "" || c.String("id") == "" || c.String("pool") == "" {
				fmt.Printf("missing required flags to get pool. [use --help to show required flags]\n")
				return fmt.Errorf("")
			}
			return nil
		},
		Action: func(c *cli.Context) {
			nodes := make([]lb.Node, len(c.StringSlice("host")))
			for i, v := range c.StringSlice("host") {
				split := strings.Split(v, ":")
				port, err := strconv.Atoi(split[1])
				if err != nil {
					fmt.Printf("failed parsing %s", v)
					return
				}
				node := lb.Node{
					IPaddress:   split[0],
					PrivatePort: port,
				}
				nodes[i] = node
			}
			err := client.LB.UpdateNodes(c.String("location"), c.String("id"), c.String("pool"), nodes...)
			if err != nil {
				fmt.Printf("failed to update nodes\n")
				return
			}
			fmt.Printf("nodes updates for pool %s\n", c.String("pool"))
		},
	}
}
<|endoftext|>