<commit_before>package main

import (
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"

	"github.com/ninjasphere/go-openzwave"
	"github.com/ninjasphere/go-openzwave/NT"
)

const (
	driverName = "com.ninjablocks.zwave"
)

var (
	log  = logger.GetLogger(driverName)
	info = ninja.LoadModuleInfo("./package.json")
)

/*model.Module{
	ID:          "com.ninjablocks.zwave",
	Name:        "ZWave Driver",
	Version:     "0.2.0",
	Description: "Ninja Blocks ZWave driver",
	Author:      "Jon Seymour <jon@ninjablocks.com>",
	License:     "MIT",
}*/

type zwaveDriver struct {
	config    *ZWaveDriverConfig
	conn      *ninja.Connection
	debug     bool
	zwaveAPI  openzwave.API
	exit      chan int
	sendEvent func(event string, payload interface{}) error
}

type ZWaveDriverConfig struct {
}

func defaultConfig() *ZWaveDriverConfig {
	return &ZWaveDriverConfig{}
}

func (driver *zwaveDriver) GetOpenZWaveAPI() openzwave.API {
	return driver.zwaveAPI
}

func (driver *zwaveDriver) GetNinjaDriver() ninja.Driver {
	return driver
}

func (driver *zwaveDriver) GetNinjaConnection() *ninja.Connection {
	return driver.conn
}

func newZWaveDriver(debug bool) (*zwaveDriver, error) {

	conn, err := ninja.Connect(driverName)

	if err != nil {
		log.Fatalf("Failed to create %s driver: %s", driverName, err)
	}

	driver := &zwaveDriver{
		config:    defaultConfig(),
		conn:      conn,
		sendEvent: nil,
		debug:     debug,
		zwaveAPI:  nil,
		exit:      make(chan int, 0),
	}

	err = conn.ExportDriver(driver)

	if err != nil {
		log.Fatalf("Failed to export %s driver: %s", driverName, err)
	}

	return driver, nil
}

func (d *zwaveDriver) Start(config *ZWaveDriverConfig) error {
	log.Infof("Driver %s starting with config %v", driverName, config)

	d.config = config

	zwaveDeviceFactory := func(api openzwave.API, node openzwave.Node) openzwave.Device {
		d.zwaveAPI = api
		return GetLibrary().GetDeviceFactory(*node.GetProductId())(d, node)
	}

	shuttingDown := false

	notificationCallback := func(api openzwave.API, nt openzwave.Notification) {
		switch nt.GetNotificationType().Code {
		case NT.NODE_REMOVED:
			//
			// Currently the RPC layer prevents us releasing the resources associated
			// with removed nodes. If the nodes come back (when, say, the zwave controller
			// is re-inserted), we can't build new device  wrappers for them because the
			// devices are already registered with the RPC layer.
			//
			// We could fix the RPC layer or we could attempt to work around the
			// problems with the RPC layer by using "patch" proxies for each ninja device
			// that allows us to change the actual zwave device.
			//
			// For now, it is simpler if we simply restart the driver process in the event of node
			// removal. This also avoids potential race conditions between
			// event dispatch and freeing of the resources associated with the
			// removed node.
			//
			if !shuttingDown {
				shuttingDown = true
				api.Logger().Infof("ZWave driver shutdown in response to node removed event.")
				api.Shutdown(openzwave.EXIT_NODE_REMOVED)
			}
		default:

		}
	}

	configurator := openzwave.
		BuildAPI("/usr/local/etc/openzwave", ".", "").
		SetLogger(log).
		SetNotificationCallback(notificationCallback).
		SetDeviceFactory(zwaveDeviceFactory)

	if d.debug {
		callback := func(api openzwave.API, notification openzwave.Notification) {
			api.Logger().Infof("%v\n", notification)
			notificationCallback(api, notification)
		}

		configurator.SetNotificationCallback(callback)
	}

	go func() {
		// slightly racy - we would like a guarantee we have replied to Start
		// before we start generating advice about new nodes.
		d.exit <- configurator.Run()
	}()

	d.sendEvent("config", config)

	return nil
}

func (d *zwaveDriver) Stop() error {
	// TODO: propagate shutdown request to ZWave driver and let it take it down
	log.Infof("Stop received - shutting down")
	d.exit <- 0
	return nil
}

// wait until the drivers are ready for us to shutdown.
func (d *zwaveDriver) Wait() int {
	return <-d.exit
}

func (d *zwaveDriver) GetModuleInfo() *model.Module {
	return info
}

func (d *zwaveDriver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}
<commit_msg>rename zwaveDriver -> driver.<commit_after>package main

import (
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"

	"github.com/ninjasphere/go-openzwave"
	"github.com/ninjasphere/go-openzwave/NT"
)

const (
	driverName = "com.ninjablocks.zwave"
)

var (
	log  = logger.GetLogger(driverName)
	info = ninja.LoadModuleInfo("./package.json")
)

/*model.Module{
	ID:          "com.ninjablocks.zwave",
	Name:        "ZWave Driver",
	Version:     "0.2.0",
	Description: "Ninja Blocks ZWave driver",
	Author:      "Jon Seymour <jon@ninjablocks.com>",
	License:     "MIT",
}*/

type driver struct {
	config    *ZWaveDriverConfig
	conn      *ninja.Connection
	debug     bool
	zwaveAPI  openzwave.API
	exit      chan int
	sendEvent func(event string, payload interface{}) error
}

type ZWaveDriverConfig struct {
}

func defaultConfig() *ZWaveDriverConfig {
	return &ZWaveDriverConfig{}
}

func (driver *driver) GetOpenZWaveAPI() openzwave.API {
	return driver.zwaveAPI
}

func (driver *driver) GetNinjaDriver() ninja.Driver {
	return driver
}

func (driver *driver) GetNinjaConnection() *ninja.Connection {
	return driver.conn
}

func newZWaveDriver(debug bool) (*driver, error) {

	conn, err := ninja.Connect(driverName)

	if err != nil {
		log.Fatalf("Failed to create %s driver: %s", driverName, err)
	}

	driver := &driver{
		config:    defaultConfig(),
		conn:      conn,
		sendEvent: nil,
		debug:     debug,
		zwaveAPI:  nil,
		exit:      make(chan int, 0),
	}

	err = conn.ExportDriver(driver)

	if err != nil {
		log.Fatalf("Failed to export %s driver: %s", driverName, err)
	}

	return driver, nil
}

func (d *driver) Start(config *ZWaveDriverConfig) error {
	log.Infof("Driver %s starting with config %v", driverName, config)

	d.config = config

	zwaveDeviceFactory := func(api openzwave.API, node openzwave.Node) openzwave.Device {
		d.zwaveAPI = api
		return GetLibrary().GetDeviceFactory(*node.GetProductId())(d, node)
	}

	shuttingDown := false

	notificationCallback := func(api openzwave.API, nt openzwave.Notification) {
		switch nt.GetNotificationType().Code {
		case NT.NODE_REMOVED:
			//
			// Currently the RPC layer prevents us releasing the resources associated
			// with removed nodes. If the nodes come back (when, say, the zwave controller
			// is re-inserted), we can't build new device  wrappers for them because the
			// devices are already registered with the RPC layer.
			//
			// We could fix the RPC layer or we could attempt to work around the
			// problems with the RPC layer by using "patch" proxies for each ninja device
			// that allows us to change the actual zwave device.
			//
			// For now, it is simpler if we simply restart the driver process in the event of node
			// removal. This also avoids potential race conditions between
			// event dispatch and freeing of the resources associated with the
			// removed node.
			//
			if !shuttingDown {
				shuttingDown = true
				api.Logger().Infof("ZWave driver shutdown in response to node removed event.")
				api.Shutdown(openzwave.EXIT_NODE_REMOVED)
			}
		default:

		}
	}

	configurator := openzwave.
		BuildAPI("/usr/local/etc/openzwave", ".", "").
		SetLogger(log).
		SetNotificationCallback(notificationCallback).
		SetDeviceFactory(zwaveDeviceFactory)

	if d.debug {
		callback := func(api openzwave.API, notification openzwave.Notification) {
			api.Logger().Infof("%v\n", notification)
			notificationCallback(api, notification)
		}

		configurator.SetNotificationCallback(callback)
	}

	go func() {
		// slightly racy - we would like a guarantee we have replied to Start
		// before we start generating advice about new nodes.
		d.exit <- configurator.Run()
	}()

	d.sendEvent("config", config)

	return nil
}

func (d *driver) Stop() error {
	// TODO: propagate shutdown request to ZWave driver and let it take it down
	log.Infof("Stop received - shutting down")
	d.exit <- 0
	return nil
}

// wait until the drivers are ready for us to shutdown.
func (d *driver) Wait() int {
	return <-d.exit
}

func (d *driver) GetModuleInfo() *model.Module {
	return info
}

func (d *driver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/go-sonos"
	"github.com/ninjasphere/go-sonos/ssdp"
	"github.com/ninjasphere/go-sonos/upnp"
)

const (
	DiscoveryPort = 13104
	EventingPort  = 13105
)

var info = ninja.LoadModuleInfo("./package.json")

type sonosDriver struct {
	config    *SonosConfig
	log       *logger.Logger
	players   map[ssdp.UUID]*sonosPlayer
	conn      *ninja.Connection
	reactor   upnp.Reactor
	sendEvent func(event string, payload interface{}) error
}

type SonosConfig struct {
}

func StartSonosDriver() {
	d := &sonosDriver{
		log:     logger.GetLogger(info.Name),
		players: make(map[ssdp.UUID]*sonosPlayer),
	}

	conn, err := ninja.Connect(info.ID)
	if err != nil {
		d.log.Fatalf("Failed to connect to MQTT: %s", err)
	}

	err = conn.ExportDriver(d)

	if err != nil {
		d.log.Fatalf("Failed to export driver: %s", err)
	}

	if nil != err {
		nlog.HandleError(err, "Could not locate interface to bind to")
	}

	d.reactor = sonos.MakeReactor(EventingPort)

	go func() {
		events := d.reactor.Channel()

		for {
			event := <-events

			d.log.Infof(spew.Sprintf("event %v", event))

			// TODO need to emit state once we get the event which contains player status
		}
	}()

	d.conn = conn
}

func (d *sonosDriver) Start(config *SonosConfig) error {
	d.log.Infof("Starting")
	go d.discover()
	return nil
}

func (d *sonosDriver) Stop() error {
	// TODO: Doesn't aactually stop the devices? Should it?
	return nil
}

func (d *sonosDriver) discover() {

	zonePlayers, err := d.discoverZonePlayers()

	if err != nil {
		d.log.Warningf("Failed to discover ZonePlayers: %s", err)
	} else {
		for uuid, device := range zonePlayers {
			if _, ok := d.players[uuid]; !ok {
				spew.Dump(device)
				unit := sonos.Connect(device, d.reactor, sonos.SVC_RENDERING_CONTROL|sonos.SVC_AV_TRANSPORT|sonos.SVC_ZONE_GROUP_TOPOLOGY|sonos.SVC_MUSIC_SERVICES)
				spew.Dump(unit)

				player, err := NewPlayer(d, d.conn, unit)

				if err != nil {

				} else {
					d.players[uuid] = player
				}

			}
		}
	}

}

func (d *sonosDriver) discoverZonePlayers() (zonePlayers ssdp.DeviceMap, err error) {

	d.log.Infof("loading discovery mgr")
	mgr, err := sonos.Discover(DiscoveryPort)
	if nil != err {
		return
	}

	zonePlayers = make(ssdp.DeviceMap)
	for uuid, device := range mgr.Devices() {
		if device.Product() == "Sonos" && device.Name() == "ZonePlayer" {
			zonePlayers[uuid] = device
		}
	}
	return
}

func (d *sonosDriver) GetModuleInfo() *model.Module {
	return info
}

func (d *sonosDriver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}
<commit_msg>Removed some unused debugging statements.<commit_after>package main

import (
	"github.com/davecgh/go-spew/spew"
	"github.com/ninjasphere/go-ninja/api"
	"github.com/ninjasphere/go-ninja/logger"
	"github.com/ninjasphere/go-ninja/model"
	"github.com/ninjasphere/go-sonos"
	"github.com/ninjasphere/go-sonos/ssdp"
	"github.com/ninjasphere/go-sonos/upnp"
)

const (
	DiscoveryPort = 13104
	EventingPort  = 13105
)

var info = ninja.LoadModuleInfo("./package.json")

type sonosDriver struct {
	config    *SonosConfig
	log       *logger.Logger
	players   map[ssdp.UUID]*sonosPlayer
	conn      *ninja.Connection
	reactor   upnp.Reactor
	sendEvent func(event string, payload interface{}) error
}

type SonosConfig struct {
}

func StartSonosDriver() {
	d := &sonosDriver{
		log:     logger.GetLogger(info.Name),
		players: make(map[ssdp.UUID]*sonosPlayer),
	}

	conn, err := ninja.Connect(info.ID)
	if err != nil {
		d.log.Fatalf("Failed to connect to MQTT: %s", err)
	}

	err = conn.ExportDriver(d)

	if err != nil {
		d.log.Fatalf("Failed to export driver: %s", err)
	}

	if nil != err {
		nlog.HandleError(err, "Could not locate interface to bind to")
	}

	d.reactor = sonos.MakeReactor(EventingPort)

	go func() {
		events := d.reactor.Channel()

		for {
			event := <-events

			d.log.Infof(spew.Sprintf("event %v", event))

			// TODO need to emit state once we get the event which contains player status
		}
	}()

	d.conn = conn
}

func (d *sonosDriver) Start(config *SonosConfig) error {
	d.log.Infof("Starting")
	go d.discover()
	return nil
}

func (d *sonosDriver) Stop() error {
	// TODO: Doesn't aactually stop the devices? Should it?
	return nil
}

func (d *sonosDriver) discover() {

	zonePlayers, err := d.discoverZonePlayers()

	if err != nil {
		d.log.Warningf("Failed to discover ZonePlayers: %s", err)
	} else {
		for uuid, device := range zonePlayers {
			if _, ok := d.players[uuid]; !ok {
				// spew.Dump(device)
				unit := sonos.Connect(device, d.reactor, sonos.SVC_RENDERING_CONTROL|sonos.SVC_AV_TRANSPORT|sonos.SVC_ZONE_GROUP_TOPOLOGY|sonos.SVC_MUSIC_SERVICES)
				//spew.Dump(unit)

				player, err := NewPlayer(d, d.conn, unit)

				if err != nil {

				} else {
					d.players[uuid] = player
				}

			}
		}
	}

}

func (d *sonosDriver) discoverZonePlayers() (zonePlayers ssdp.DeviceMap, err error) {

	d.log.Infof("loading discovery mgr")
	mgr, err := sonos.Discover(DiscoveryPort)
	if nil != err {
		return
	}

	zonePlayers = make(ssdp.DeviceMap)
	for uuid, device := range mgr.Devices() {
		if device.Product() == "Sonos" && device.Name() == "ZonePlayer" {
			zonePlayers[uuid] = device
		}
	}
	return
}

func (d *sonosDriver) GetModuleInfo() *model.Module {
	return info
}

func (d *sonosDriver) SetEventHandler(sendEvent func(event string, payload interface{}) error) {
	d.sendEvent = sendEvent
}
<|endoftext|>


<commit_before>package agent

import (
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/buildkite/agent/api"
	"github.com/buildkite/agent/logger"
	"github.com/buildkite/agent/retry"
	"github.com/buildkite/agent/signalwatcher"
	"github.com/buildkite/agent/system"
)

type AgentPool struct {
	APIClient          *api.Client
	Token              string
	ConfigFilePath     string
	Name               string
	Priority           string
	MetaData           []string
	MetaDataEC2        bool
	MetaDataEC2Tags    bool
	MetaDataGCP        bool
	Endpoint           string
	AgentConfiguration *AgentConfiguration
}

func (r *AgentPool) Start() error {
	// Show the welcome banner and config options used
	r.ShowBanner()

	// Create the agent registration API Client
	r.APIClient = APIClient{Endpoint: r.Endpoint, Token: r.Token}.Create()

	// Create the agent template. We use pass this template to the register
	// call, at which point we get back a real agent.
	template := r.CreateAgentTemplate()

	logger.Info("Registering agent with Buildkite...")

	// Register the agent
	registered, err := r.RegisterAgent(template)
	if err != nil {
		logger.Fatal("%s", err)
	}

	logger.Info("Successfully registered agent \"%s\" with meta-data %s", registered.Name, registered.MetaData)

	logger.Debug("Ping interval: %ds", registered.PingInterval)
	logger.Debug("Job status interval: %ds", registered.JobStatusInterval)
	logger.Debug("Heartbeat interval: %ds", registered.HearbeatInterval)

	// Now that we have a registered agent, we can connect it to the API,
	// and start running jobs.
	worker := AgentWorker{Agent: registered, AgentConfiguration: r.AgentConfiguration, Endpoint: r.Endpoint}.Create()

	logger.Info("Connecting to Buildkite...")
	if err := worker.Connect(); err != nil {
		logger.Fatal("%s", err)
	}

	logger.Info("Agent successfully connected")
	logger.Info("You can press Ctrl-C to stop the agent")
	logger.Info("Waiting for work...")

	// Start a signalwatcher so we can monitor signals and handle shutdowns
	signalwatcher.Watch(func(sig signalwatcher.Signal) {
		if sig == signalwatcher.QUIT {
			logger.Debug("Received signal `%s`", sig.String())
			worker.Stop(false)
		} else if sig == signalwatcher.TERM || sig == signalwatcher.INT {
			logger.Debug("Received signal `%s`", sig.String())
			worker.Stop(true)
		} else {
			logger.Debug("Ignoring signal `%s`", sig.String())
		}
	})

	// Starts the agent worker. This will block until the agent has
	// finished or is stopped.
	if err := worker.Start(); err != nil {
		logger.Fatal("%s", err)
	}

	// Now that the agent has stopped, we can disconnect it
	logger.Info("Disconnecting %s...", worker.Agent.Name)
	worker.Disconnect()

	return nil
}

// Takes the options passed to the CLI, and creates an api.Agent record that
// will be sent to the Buildkite Agent API for registration.
func (r *AgentPool) CreateAgentTemplate() *api.Agent {
	agent := &api.Agent{
		Name:              r.Name,
		Priority:          r.Priority,
		MetaData:          r.MetaData,
		ScriptEvalEnabled: r.AgentConfiguration.CommandEval,
		Version:           Version(),
		Build:             BuildVersion(),
		PID:               os.Getpid(),
		Arch:              runtime.GOARCH,
	}

	// Attempt to add the EC2 meta-data
	if r.MetaDataEC2 {
		logger.Info("Fetching EC2 meta-data...")

		err := retry.Do(func(s *retry.Stats) error {
			tags, err := EC2MetaData{}.Get()
			if err != nil {
				logger.Warn("%s (%s)", err, s)
			} else {
				logger.Info("Successfully fetched EC2 meta-data")
				for tag, value := range tags {
					agent.MetaData = append(agent.MetaData, fmt.Sprintf("%s=%s", tag, value))
				}
				s.Break()
			}

			return err
		}, &retry.Config{Maximum: 5, Interval: 1 * time.Second, Jitter: true})

		// Don't blow up if we can't find them, just show a nasty error.
		if err != nil {
			logger.Error(fmt.Sprintf("Failed to fetch EC2 meta-data: %s", err.Error()))
		}
	}

	// Attempt to add the EC2 tags
	if r.MetaDataEC2Tags {
		logger.Info("Fetching EC2 tags...")

		// same as above
		err := retry.Do(func(s *retry.Stats) error {
			tags, err := EC2Tags{}.Get()
			if err != nil {
				logger.Warn("%s (%s)", err, s)
			} else {
				logger.Info("Successfully fetched EC2 tags")
				for tag, value := range tags {
					agent.MetaData = append(agent.MetaData, fmt.Sprintf("%s=%s", tag, value))
				}
				s.Break()
			}

			return err
		}, &retry.Config{Maximum: 5, Interval: 1 * time.Second, Jitter: true})

		// Don't blow up if we can't find them, just show a nasty error.
		if err != nil {
			logger.Error(fmt.Sprintf("Failed to find EC2 tags: %s", err.Error()))
		}
	}

	// Attempt to add the Google Cloud meta-data
	if r.MetaDataGCP {
		tags, err := GCPMetaData{}.Get()
		if err != nil {
			// Don't blow up if we can't find them, just show a nasty error.
			logger.Error(fmt.Sprintf("Failed to fetch Google Cloud meta-data: %s", err.Error()))
		} else {
			for tag, value := range tags {
				agent.MetaData = append(agent.MetaData, fmt.Sprintf("%s=%s", tag, value))
			}
		}
	}

	var err error

	// Add the hostname
	agent.Hostname, err = os.Hostname()
	if err != nil {
		logger.Warn("Failed to find hostname: %s", err)
	}

	// Add the OS dump
	agent.OS, err = system.VersionDump()
	if err != nil {
		logger.Warn("Failed to find OS information: %s", err)
	}

	return agent
}

// Takes the agent template and returns a registered agent. The registered
// agent includes the Access Token used to communicate with the Buildkite Agent
// API
func (r *AgentPool) RegisterAgent(agent *api.Agent) (*api.Agent, error) {
	var registered *api.Agent
	var err error
	var resp *api.Response

	register := func(s *retry.Stats) error {
		registered, resp, err = r.APIClient.Agents.Register(agent)
		if err != nil {
			if resp != nil && resp.StatusCode == 401 {
				logger.Warn("Buildkite rejected the registration (%s)", err)
				s.Break()
			} else {
				logger.Warn("%s (%s)", err, s)
			}
		}

		return err
	}

	// Try to register, retrying every 10 seconds for a maximum of 30 attempts (5 minutes)
	err = retry.Do(register, &retry.Config{Maximum: 30, Interval: 10 * time.Second})

	return registered, err
}

// Shows the welcome banner and the configuration options used when starting
// this agent.
func (r *AgentPool) ShowBanner() {
	welcomeMessage :=
		"\n" +
			"%s  _           _ _     _ _    _ _                                _\n" +
			" | |         (_) |   | | |  (_) |                              | |\n" +
			" | |__  _   _ _| | __| | | ___| |_ ___    __ _  __ _  ___ _ __ | |_\n" +
			" | '_ \\| | | | | |/ _` | |/ / | __/ _ \\  / _` |/ _` |/ _ \\ '_ \\| __|\n" +
			" | |_) | |_| | | | (_| |   <| | ||  __/ | (_| | (_| |  __/ | | | |_\n" +
			" |_.__/ \\__,_|_|_|\\__,_|_|\\_\\_|\\__\\___|  \\__,_|\\__, |\\___|_| |_|\\__|\n" +
			"                                                __/ |\n" +
			" http://buildkite.com/agent                    |___/\n%s\n"

	if logger.ColorsEnabled() {
		fmt.Fprintf(logger.OutputPipe(), welcomeMessage, "\x1b[32m", "\x1b[0m")
	} else {
		fmt.Fprintf(logger.OutputPipe(), welcomeMessage, "", "")
	}

	logger.Notice("Starting buildkite-agent v%s with PID: %s", Version(), fmt.Sprintf("%d", os.Getpid()))
	logger.Notice("The agent source code can be found here: https://github.com/buildkite/agent")
	logger.Notice("For questions and support, email us at: hello@buildkite.com")

	if r.ConfigFilePath != "" {
		logger.Info("Configuration loaded from: %s", r.ConfigFilePath)
	}

	logger.Debug("Bootstrap command: %s", r.AgentConfiguration.BootstrapScript)
	logger.Debug("Build path: %s", r.AgentConfiguration.BuildPath)
	logger.Debug("Hooks directory: %s", r.AgentConfiguration.HooksPath)
	logger.Debug("Plugins directory: %s", r.AgentConfiguration.PluginsPath)

	if !r.AgentConfiguration.SSHFingerprintVerification {
		logger.Debug("Automatic SSH fingerprint verification has been disabled")
	}

	if !r.AgentConfiguration.CommandEval {
		logger.Debug("Evaluating console commands has been disabled")
	}

	if !r.AgentConfiguration.RunInPty {
		logger.Debug("Running builds within a pseudoterminal (PTY) has been disabled")
	}

	if r.AgentConfiguration.DisconnectAfterJob {
		logger.Debug("Agent will disconnect after a job run has completed")
	}
}
<commit_msg>Bit more logging around auto disconnect<commit_after>package agent

import (
	"fmt"
	"os"
	"runtime"
	"time"

	"github.com/buildkite/agent/api"
	"github.com/buildkite/agent/logger"
	"github.com/buildkite/agent/retry"
	"github.com/buildkite/agent/signalwatcher"
	"github.com/buildkite/agent/system"
)

type AgentPool struct {
	APIClient          *api.Client
	Token              string
	ConfigFilePath     string
	Name               string
	Priority           string
	MetaData           []string
	MetaDataEC2        bool
	MetaDataEC2Tags    bool
	MetaDataGCP        bool
	Endpoint           string
	AgentConfiguration *AgentConfiguration
}

func (r *AgentPool) Start() error {
	// Show the welcome banner and config options used
	r.ShowBanner()

	// Create the agent registration API Client
	r.APIClient = APIClient{Endpoint: r.Endpoint, Token: r.Token}.Create()

	// Create the agent template. We use pass this template to the register
	// call, at which point we get back a real agent.
	template := r.CreateAgentTemplate()

	logger.Info("Registering agent with Buildkite...")

	// Register the agent
	registered, err := r.RegisterAgent(template)
	if err != nil {
		logger.Fatal("%s", err)
	}

	logger.Info("Successfully registered agent \"%s\" with meta-data %s", registered.Name, registered.MetaData)

	logger.Debug("Ping interval: %ds", registered.PingInterval)
	logger.Debug("Job status interval: %ds", registered.JobStatusInterval)
	logger.Debug("Heartbeat interval: %ds", registered.HearbeatInterval)

	// Now that we have a registered agent, we can connect it to the API,
	// and start running jobs.
	worker := AgentWorker{Agent: registered, AgentConfiguration: r.AgentConfiguration, Endpoint: r.Endpoint}.Create()

	logger.Info("Connecting to Buildkite...")
	if err := worker.Connect(); err != nil {
		logger.Fatal("%s", err)
	}

	logger.Info("Agent successfully connected")
	logger.Info("You can press Ctrl-C to stop the agent")

	if r.AgentConfiguration.DisconnectAfterJob {
		logger.Info("Waiting for first job to be assigned...")
		logger.Info("The agent will automatically disconnect after %d seconds if no job is assigned", r.AgentConfiguration.DisconnectAfterJobTimeout)
	} else {
		logger.Info("Waiting for work...")
	}

	// Start a signalwatcher so we can monitor signals and handle shutdowns
	signalwatcher.Watch(func(sig signalwatcher.Signal) {
		if sig == signalwatcher.QUIT {
			logger.Debug("Received signal `%s`", sig.String())
			worker.Stop(false)
		} else if sig == signalwatcher.TERM || sig == signalwatcher.INT {
			logger.Debug("Received signal `%s`", sig.String())
			worker.Stop(true)
		} else {
			logger.Debug("Ignoring signal `%s`", sig.String())
		}
	})

	// Starts the agent worker. This will block until the agent has
	// finished or is stopped.
	if err := worker.Start(); err != nil {
		logger.Fatal("%s", err)
	}

	// Now that the agent has stopped, we can disconnect it
	logger.Info("Disconnecting %s...", worker.Agent.Name)
	worker.Disconnect()

	return nil
}

// Takes the options passed to the CLI, and creates an api.Agent record that
// will be sent to the Buildkite Agent API for registration.
func (r *AgentPool) CreateAgentTemplate() *api.Agent {
	agent := &api.Agent{
		Name:              r.Name,
		Priority:          r.Priority,
		MetaData:          r.MetaData,
		ScriptEvalEnabled: r.AgentConfiguration.CommandEval,
		Version:           Version(),
		Build:             BuildVersion(),
		PID:               os.Getpid(),
		Arch:              runtime.GOARCH,
	}

	// Attempt to add the EC2 meta-data
	if r.MetaDataEC2 {
		logger.Info("Fetching EC2 meta-data...")

		err := retry.Do(func(s *retry.Stats) error {
			tags, err := EC2MetaData{}.Get()
			if err != nil {
				logger.Warn("%s (%s)", err, s)
			} else {
				logger.Info("Successfully fetched EC2 meta-data")
				for tag, value := range tags {
					agent.MetaData = append(agent.MetaData, fmt.Sprintf("%s=%s", tag, value))
				}
				s.Break()
			}

			return err
		}, &retry.Config{Maximum: 5, Interval: 1 * time.Second, Jitter: true})

		// Don't blow up if we can't find them, just show a nasty error.
		if err != nil {
			logger.Error(fmt.Sprintf("Failed to fetch EC2 meta-data: %s", err.Error()))
		}
	}

	// Attempt to add the EC2 tags
	if r.MetaDataEC2Tags {
		logger.Info("Fetching EC2 tags...")

		// same as above
		err := retry.Do(func(s *retry.Stats) error {
			tags, err := EC2Tags{}.Get()
			if err != nil {
				logger.Warn("%s (%s)", err, s)
			} else {
				logger.Info("Successfully fetched EC2 tags")
				for tag, value := range tags {
					agent.MetaData = append(agent.MetaData, fmt.Sprintf("%s=%s", tag, value))
				}
				s.Break()
			}

			return err
		}, &retry.Config{Maximum: 5, Interval: 1 * time.Second, Jitter: true})

		// Don't blow up if we can't find them, just show a nasty error.
		if err != nil {
			logger.Error(fmt.Sprintf("Failed to find EC2 tags: %s", err.Error()))
		}
	}

	// Attempt to add the Google Cloud meta-data
	if r.MetaDataGCP {
		tags, err := GCPMetaData{}.Get()
		if err != nil {
			// Don't blow up if we can't find them, just show a nasty error.
			logger.Error(fmt.Sprintf("Failed to fetch Google Cloud meta-data: %s", err.Error()))
		} else {
			for tag, value := range tags {
				agent.MetaData = append(agent.MetaData, fmt.Sprintf("%s=%s", tag, value))
			}
		}
	}

	var err error

	// Add the hostname
	agent.Hostname, err = os.Hostname()
	if err != nil {
		logger.Warn("Failed to find hostname: %s", err)
	}

	// Add the OS dump
	agent.OS, err = system.VersionDump()
	if err != nil {
		logger.Warn("Failed to find OS information: %s", err)
	}

	return agent
}

// Takes the agent template and returns a registered agent. The registered
// agent includes the Access Token used to communicate with the Buildkite Agent
// API
func (r *AgentPool) RegisterAgent(agent *api.Agent) (*api.Agent, error) {
	var registered *api.Agent
	var err error
	var resp *api.Response

	register := func(s *retry.Stats) error {
		registered, resp, err = r.APIClient.Agents.Register(agent)
		if err != nil {
			if resp != nil && resp.StatusCode == 401 {
				logger.Warn("Buildkite rejected the registration (%s)", err)
				s.Break()
			} else {
				logger.Warn("%s (%s)", err, s)
			}
		}

		return err
	}

	// Try to register, retrying every 10 seconds for a maximum of 30 attempts (5 minutes)
	err = retry.Do(register, &retry.Config{Maximum: 30, Interval: 10 * time.Second})

	return registered, err
}

// Shows the welcome banner and the configuration options used when starting
// this agent.
func (r *AgentPool) ShowBanner() {
	welcomeMessage :=
		"\n" +
			"%s  _           _ _     _ _    _ _                                _\n" +
			" | |         (_) |   | | |  (_) |                              | |\n" +
			" | |__  _   _ _| | __| | | ___| |_ ___    __ _  __ _  ___ _ __ | |_\n" +
			" | '_ \\| | | | | |/ _` | |/ / | __/ _ \\  / _` |/ _` |/ _ \\ '_ \\| __|\n" +
			" | |_) | |_| | | | (_| |   <| | ||  __/ | (_| | (_| |  __/ | | | |_\n" +
			" |_.__/ \\__,_|_|_|\\__,_|_|\\_\\_|\\__\\___|  \\__,_|\\__, |\\___|_| |_|\\__|\n" +
			"                                                __/ |\n" +
			" http://buildkite.com/agent                    |___/\n%s\n"

	if logger.ColorsEnabled() {
		fmt.Fprintf(logger.OutputPipe(), welcomeMessage, "\x1b[32m", "\x1b[0m")
	} else {
		fmt.Fprintf(logger.OutputPipe(), welcomeMessage, "", "")
	}

	logger.Notice("Starting buildkite-agent v%s with PID: %s", Version(), fmt.Sprintf("%d", os.Getpid()))
	logger.Notice("The agent source code can be found here: https://github.com/buildkite/agent")
	logger.Notice("For questions and support, email us at: hello@buildkite.com")

	if r.ConfigFilePath != "" {
		logger.Info("Configuration loaded from: %s", r.ConfigFilePath)
	}

	logger.Debug("Bootstrap command: %s", r.AgentConfiguration.BootstrapScript)
	logger.Debug("Build path: %s", r.AgentConfiguration.BuildPath)
	logger.Debug("Hooks directory: %s", r.AgentConfiguration.HooksPath)
	logger.Debug("Plugins directory: %s", r.AgentConfiguration.PluginsPath)

	if !r.AgentConfiguration.SSHFingerprintVerification {
		logger.Debug("Automatic SSH fingerprint verification has been disabled")
	}

	if !r.AgentConfiguration.CommandEval {
		logger.Debug("Evaluating console commands has been disabled")
	}

	if !r.AgentConfiguration.RunInPty {
		logger.Debug("Running builds within a pseudoterminal (PTY) has been disabled")
	}

	if r.AgentConfiguration.DisconnectAfterJob {
		logger.Debug("Agent will disconnect after a job run has completed with a timeout of %d seconds", r.AgentConfiguration.DisconnectAfterJobTimeout)
	}
}
<|endoftext|>


<commit_before>package ipam

import (
	"encoding/json"
	"errors"
	"fmt"
	"path"
	"path/filepath"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/libkv"
	"github.com/docker/libkv/store"
	etcdkv "github.com/docker/libkv/store/etcd"
	zkkv "github.com/docker/libkv/store/zookeeper"
)

var (
	keyNetwork = "swan/network" // baseKey, note: no leading '/' to make fit with zk store
	keyPool    = "pool"         // subnet sub key name
	keyConfig  = "config"       // subnet sub key name
)

var (
	errIPOutOfPool    = errors.New("ip address out of pool")
	errIPAllocated    = errors.New("ip address already allocated")
	errNoAvaliableIP  = errors.New("no avaliable ips")
	errIPRemoveDenied = errors.New("deny to remove assigned ip from pool")
)

func init() {
	etcdkv.Register()
	zkkv.Register()
}

type kvStore struct {
	kv store.Store
}

func (m *IPAM) StoreSetup() error {
	var (
		typ       = m.cfg.StoreType
		etcdAddrs = m.cfg.EtcdAddrs
		zkAddrs   = m.cfg.ZKAddrs

		kv  store.Store
		err error
	)

	switch typ {
	case "etcd":
		kv, err = libkv.NewStore(
			store.ETCD,
			etcdAddrs,
			&store.Config{
				ConnectionTimeout: time.Second * 10,
			})
	case "zk":
		kv, err = libkv.NewStore(
			store.ZK,
			zkAddrs,
			&store.Config{
				ConnectionTimeout: time.Second * 10,
			})
	}
	if err != nil {
		return err
	}

	if ok, _ := kv.Exists(keyNetwork); !ok {
		err := kv.Put(keyNetwork, nil, &store.WriteOptions{IsDir: true})
		if err != nil {
			log.Warnf("ensure base directory %s error: %v", keyNetwork, err)
		}
	}

	m.store = &kvStore{kv: kv}
	return nil
}

// Subnet
//
//
func (s *kvStore) ListSubNets() ([]*SubNet, error) {
	kvPairs, err := s.kv.List(s.normalize(""))
	if err != nil {
		return nil, err
	}

	ret := make([]*SubNet, len(kvPairs))
	for idx, kvPair := range kvPairs {
		var (
			subnetID = filepath.Base(kvPair.Key)
		)

		subnet, err := s.GetSubNet(subnetID)
		if err != nil {
			return nil, fmt.Errorf("subnet %s error: %v", subnetID, err)
		}

		ret[idx] = subnet
	}
	return ret, nil
}

func (s *kvStore) CreateSubNet(subnet *SubNet) error {
	bs, err := s.encode(subnet)
	if err != nil {
		return err
	}

	err = s.kv.Put(s.normalize(subnet.ID, keyConfig), bs, nil)
	if err != nil {
		return err
	}

	return s.kv.Put(s.normalize(subnet.ID, keyPool), nil, &store.WriteOptions{IsDir: true})
}

func (s *kvStore) GetSubNet(id string) (*SubNet, error) {
	kvPair, err := s.kv.Get(s.normalize(id, keyConfig))
	if err != nil {
		return nil, err
	}

	var subnet *SubNet
	if err := s.decode(kvPair.Value, &subnet); err != nil {
		return nil, err
	}

	return subnet, nil
}

func (s *kvStore) RemoveSubNet(id string) error {
	subnet, err := s.GetSubNet(id)
	if err != nil {
		if err == store.ErrKeyNotFound {
			return nil
		}
		return err
	}

	infos, err := s.ListIPs(subnet.ID)
	if err != nil {
		return err
	}

	var (
		n   int
		ips = make([]string, len(infos))
	)
	for idx, info := range infos {
		ips[idx] = info[0]
		if assigned, _ := strconv.ParseBool(info[1]); assigned {
			n++
		}
	}
	if n > 0 {
		return errIPRemoveDenied
	}

	if err = s.RemoveIPsFromPool(subnet.ID, ips); err != nil {
		return err
	}

	return s.kv.DeleteTree(s.normalize(subnet.ID))
}

// Subnet IPs
//
//
func (s *kvStore) ListIPs(subnetID string) ([][2]string, error) {
	kvPairs, err := s.kv.List(s.normalize(subnetID, keyPool))
	if err != nil {
		return nil, err
	}

	ret := make([][2]string, 0, 0)
	for _, kvPair := range kvPairs {
		if len(kvPair.Value) == 0 { // maybe temporary store lock
			continue
		}
		var (
			ipAddr   = filepath.Base(kvPair.Key)
			assigned = strconv.FormatBool(kvPair.Value[0] == '1')
		)
		ret = append(ret, [2]string{ipAddr, assigned})
	}
	return ret, nil
}

func (s *kvStore) RequestIP(subnetID, preferIP string) (string, error) {
	subnet, err := s.GetSubNet(subnetID)
	if err != nil {
		return "", err
	}

	var (
		respIP   string
		assigned bool
	)

	// request next random subnet ip
	if preferIP == "" {
		respIP, err = s.getRandomIP(subnet.ID)
		if err != nil {
			return "", err
		}

		goto END
	}

	// request prefered IP
	assigned, err = s.checkIP(subnet.ID, preferIP)
	if err != nil {
		if err == store.ErrKeyNotFound {
			return "", errIPOutOfPool
		}
		return "", err
	}
	if assigned {
		return "", errIPAllocated
	}

	respIP = preferIP

END:

	if respIP == "" {
		return "", errNoAvaliableIP
	}

	err = s.markIPAssigned(subnet.ID, respIP)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("%s/%d", respIP, subnet.Mask), nil
}

func (s *kvStore) ReleaseIP(subnetID, ipAddr string) error {
	subnet, err := s.GetSubNet(subnetID)
	if err != nil {
		if err == store.ErrKeyNotFound {
			return nil
		}
		return err
	}

	return s.markIPFree(subnet.ID, ipAddr)
}

func (s *kvStore) AddIPsToPool(subnetID string, ips []string) error {
	_, err := s.GetSubNet(subnetID)
	if err != nil {
		return fmt.Errorf("subnet %s error: %v", subnetID, err)
	}

	for _, ip := range ips {

		var (
			key = s.normalize(subnetID, keyPool, ip)
			bs  = []byte{'0'}
		)

		if exists, _ := s.kv.Exists(key); exists {
			log.Warnf("ip %s already in the pool of subnet %s", ip, subnetID)
			continue
		}

		if err := s.kv.Put(key, bs, nil); err != nil {
			return err
		}
	}

	return nil
}

func (s *kvStore) RemoveIPsFromPool(subnetID string, ips []string) error {
	for _, ip := range ips {
		if err := s.kv.Delete(s.normalize(subnetID, keyPool, ip)); err != nil {
			if err != store.ErrKeyNotFound {
				return err
			}
		}
	}

	return nil
}

func (s *kvStore) checkIP(subnetID, ip string) (assigned bool, err error) {
	kvPair, err := s.kv.Get(s.normalize(subnetID, keyPool, ip))
	if err != nil {
		return
	}

	assigned = kvPair.Value[0] == '1'
	return
}

func (s *kvStore) getRandomIP(subnetID string) (string, error) {
	lock, err := s.kv.NewLock(
		s.normalize(subnetID, keyPool, "_lock"),
		&store.LockOptions{TTL: time.Second * 120},
	)
	if err != nil {
		return "", fmt.Errorf("store.NewLock() on pool error: %v", err)
	}

	if _, err := lock.Lock(nil); err != nil {
		return "", fmt.Errorf("store.Lock() on pool error: %v", err)
	}
	defer lock.Unlock()

	infos, err := s.ListIPs(subnetID)
	if err != nil {
		return "", err
	}

	for _, info := range infos {
		if assigned, _ := strconv.ParseBool(info[1]); !assigned {
			return info[0], nil
		}
	}

	return "", errNoAvaliableIP
}

func (s *kvStore) markIPAssigned(subnetID, ip string) error {
	previous, err := s.kv.Get(s.normalize(subnetID, keyPool, ip))
	if err != nil {
		return fmt.Errorf("Get ip's current kv property failed: [%v]", err)
	}

	return s.updateIP(subnetID, ip, previous, true)
}

func (s *kvStore) markIPFree(subnetID, ip string) error {
	previous, err := s.kv.Get(s.normalize(subnetID, keyPool, ip))
	if err != nil {
		return fmt.Errorf("Get ip's current kv property failed: [%v]", err)
	}

	return s.updateIP(subnetID, ip, previous, false)
}

func (s *kvStore) updateIP(subnetID, ip string, previous *store.KVPair, assigned bool) error {
	key := s.normalize(subnetID, keyPool, ip)

	if assigned {
		previous.Value = []byte{'0'}
		_, _, err := s.kv.AtomicPut(key, []byte{'1'}, previous, nil)
		return err
	}

	previous.Value = []byte{'1'}
	_, _, err := s.kv.AtomicPut(key, []byte{'0'}, previous, nil)
	return err
}

func (s *kvStore) normalize(keys ...string) string {
	elems := []string{keyNetwork}
	elems = append(elems, keys...)
	return path.Clean(path.Join(elems...))
}

// encode & decode is just short-hands for json Marshal/Unmarshal
func (s *kvStore) encode(data interface{}) ([]byte, error) {
	return json.Marshal(data)
}

func (s *kvStore) decode(bs []byte, v interface{}) error {
	return json.Unmarshal(bs, v)
}
<commit_msg>bugfix on ipam subnet removal<commit_after>package ipam

import (
	"encoding/json"
	"errors"
	"fmt"
	"path"
	"path/filepath"
	"strconv"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/libkv"
	"github.com/docker/libkv/store"
	etcdkv "github.com/docker/libkv/store/etcd"
	zkkv "github.com/docker/libkv/store/zookeeper"
)

var (
	keyNetwork = "swan/network" // baseKey, note: no leading '/' to make fit with zk store
	keyPool    = "pool"         // subnet sub key name
	keyConfig  = "config"       // subnet sub key name
)

var (
	errIPOutOfPool    = errors.New("ip address out of pool")
	errIPAllocated    = errors.New("ip address already allocated")
	errNoAvaliableIP  = errors.New("no avaliable ips")
	errIPRemoveDenied = errors.New("deny to remove assigned ip from pool")
)

func init() {
	etcdkv.Register()
	zkkv.Register()
}

type kvStore struct {
	kv store.Store
}

func (m *IPAM) StoreSetup() error {
	var (
		typ       = m.cfg.StoreType
		etcdAddrs = m.cfg.EtcdAddrs
		zkAddrs   = m.cfg.ZKAddrs

		kv  store.Store
		err error
	)

	switch typ {
	case "etcd":
		kv, err = libkv.NewStore(
			store.ETCD,
			etcdAddrs,
			&store.Config{
				ConnectionTimeout: time.Second * 10,
			})
	case "zk":
		kv, err = libkv.NewStore(
			store.ZK,
			zkAddrs,
			&store.Config{
				ConnectionTimeout: time.Second * 10,
			})
	}
	if err != nil {
		return err
	}

	if ok, _ := kv.Exists(keyNetwork); !ok {
		err := kv.Put(keyNetwork, nil, &store.WriteOptions{IsDir: true})
		if err != nil {
			log.Warnf("ensure base directory %s error: %v", keyNetwork, err)
		}
	}

	m.store = &kvStore{kv: kv}
	return nil
}

// Subnet
//
//
func (s *kvStore) ListSubNets() ([]*SubNet, error) {
	kvPairs, err := s.kv.List(s.normalize(""))
	if err != nil {
		return nil, err
	}

	ret := make([]*SubNet, len(kvPairs))
	for idx, kvPair := range kvPairs {
		var (
			subnetID = filepath.Base(kvPair.Key)
		)

		subnet, err := s.GetSubNet(subnetID)
		if err != nil {
			return nil, fmt.Errorf("subnet %s error: %v", subnetID, err)
		}

		ret[idx] = subnet
	}
	return ret, nil
}

func (s *kvStore) CreateSubNet(subnet *SubNet) error {
	bs, err := s.encode(subnet)
	if err != nil {
		return err
	}

	err = s.kv.Put(s.normalize(subnet.ID, keyConfig), bs, nil)
	if err != nil {
		return err
	}

	return s.kv.Put(s.normalize(subnet.ID, keyPool), nil, &store.WriteOptions{IsDir: true})
}

func (s *kvStore) GetSubNet(id string) (*SubNet, error) {
	kvPair, err := s.kv.Get(s.normalize(id, keyConfig))
	if err != nil {
		return nil, err
	}

	var subnet *SubNet
	if err := s.decode(kvPair.Value, &subnet); err != nil {
		return nil, err
	}

	return subnet, nil
}

func (s *kvStore) RemoveSubNet(id string) error {
	subnet, err := s.GetSubNet(id)
	if err != nil {
		if err == store.ErrKeyNotFound {
			return nil
		}
		return err
	}

	infos, err := s.ListIPs(subnet.ID)
	if err != nil {
		return err
	}

	var (
		n   int
		ips = make([]string, len(infos))
	)
	for idx, info := range infos {
		ips[idx] = info[0]
		if assigned, _ := strconv.ParseBool(info[1]); assigned {
			n++
		}
	}
	if n > 0 {
		return errIPRemoveDenied
	}

	if err = s.RemoveIPsFromPool(subnet.ID, ips); err != nil {
		return err
	}

	// to make fit with zk & etcd to ensure the keys removed
	s.kv.DeleteTree(s.normalize(subnet.ID))
	return s.kv.Delete(s.normalize(subnet.ID))
}

// Subnet IPs
//
//
func (s *kvStore) ListIPs(subnetID string) ([][2]string, error) {
	kvPairs, err := s.kv.List(s.normalize(subnetID, keyPool))
	if err != nil {
		return nil, err
	}

	ret := make([][2]string, 0, 0)
	for _, kvPair := range kvPairs {
		if len(kvPair.Value) == 0 { // maybe temporary store lock
			continue
		}
		var (
			ipAddr   = filepath.Base(kvPair.Key)
			assigned = strconv.FormatBool(kvPair.Value[0] == '1')
		)
		ret = append(ret, [2]string{ipAddr, assigned})
	}
	return ret, nil
}

func (s *kvStore) RequestIP(subnetID, preferIP string) (string, error) {
	subnet, err := s.GetSubNet(subnetID)
	if err != nil {
		return "", err
	}

	var (
		respIP   string
		assigned bool
	)

	// request next random subnet ip
	if preferIP == "" {
		respIP, err = s.getRandomIP(subnet.ID)
		if err != nil {
			return "", err
		}

		goto END
	}

	// request prefered IP
	assigned, err = s.checkIP(subnet.ID, preferIP)
	if err != nil {
		if err == store.ErrKeyNotFound {
			return "", errIPOutOfPool
		}
		return "", err
	}
	if assigned {
		return "", errIPAllocated
	}

	respIP = preferIP

END:

	if respIP == "" {
		return "", errNoAvaliableIP
	}

	err = s.markIPAssigned(subnet.ID, respIP)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("%s/%d", respIP, subnet.Mask), nil
}

func (s *kvStore) ReleaseIP(subnetID, ipAddr string) error {
	subnet, err := s.GetSubNet(subnetID)
	if err != nil {
		if err == store.ErrKeyNotFound {
			return nil
		}
		return err
	}

	return s.markIPFree(subnet.ID, ipAddr)
}

func (s *kvStore) AddIPsToPool(subnetID string, ips []string) error {
	_, err := s.GetSubNet(subnetID)
	if err != nil {
		return fmt.Errorf("subnet %s error: %v", subnetID, err)
	}

	for _, ip := range ips {

		var (
			key = s.normalize(subnetID, keyPool, ip)
			bs  = []byte{'0'}
		)

		if exists, _ := s.kv.Exists(key); exists {
			log.Warnf("ip %s already in the pool of subnet %s", ip, subnetID)
			continue
		}

		if err := s.kv.Put(key, bs, nil); err != nil {
			return err
		}
	}

	return nil
}

func (s *kvStore) RemoveIPsFromPool(subnetID string, ips []string) error {
	for _, ip := range ips {
		if err := s.kv.Delete(s.normalize(subnetID, keyPool, ip)); err != nil {
			if err != store.ErrKeyNotFound {
				return err
			}
		}
	}

	return nil
}

func (s *kvStore) checkIP(subnetID, ip string) (assigned bool, err error) {
	kvPair, err := s.kv.Get(s.normalize(subnetID, keyPool, ip))
	if err != nil {
		return
	}

	assigned = kvPair.Value[0] == '1'
	return
}

func (s *kvStore) getRandomIP(subnetID string) (string, error) {
	lock, err := s.kv.NewLock(
		s.normalize(subnetID, keyPool, "_lock"),
		&store.LockOptions{TTL: time.Second * 120},
	)
	if err != nil {
		return "", fmt.Errorf("store.NewLock() on pool error: %v", err)
	}

	if _, err := lock.Lock(nil); err != nil {
		return "", fmt.Errorf("store.Lock() on pool error: %v", err)
	}
	defer lock.Unlock()

	infos, err := s.ListIPs(subnetID)
	if err != nil {
		return "", err
	}

	for _, info := range infos {
		if assigned, _ := strconv.ParseBool(info[1]); !assigned {
			return info[0], nil
		}
	}

	return "", errNoAvaliableIP
}

func (s *kvStore) markIPAssigned(subnetID, ip string) error {
	previous, err := s.kv.Get(s.normalize(subnetID, keyPool, ip))
	if err != nil {
		return fmt.Errorf("Get ip's current kv property failed: [%v]", err)
	}

	return s.updateIP(subnetID, ip, previous, true)
}

func (s *kvStore) markIPFree(subnetID, ip string) error {
	previous, err := s.kv.Get(s.normalize(subnetID, keyPool, ip))
	if err != nil {
		return fmt.Errorf("Get ip's current kv property failed: [%v]", err)
	}

	return s.updateIP(subnetID, ip, previous, false)
}

func (s *kvStore) updateIP(subnetID, ip string, previous *store.KVPair, assigned bool) error {
	key := s.normalize(subnetID, keyPool, ip)

	if assigned {
		previous.Value = []byte{'0'}
		_, _, err := s.kv.AtomicPut(key, []byte{'1'}, previous, nil)
		return err
	}

	previous.Value = []byte{'1'}
	_, _, err := s.kv.AtomicPut(key, []byte{'0'}, previous, nil)
	return err
}

func (s *kvStore) normalize(keys ...string) string {
	elems := []string{keyNetwork}
	elems = append(elems, keys...)
	return path.Clean(path.Join(elems...))
}

// encode & decode is just short-hands for json Marshal/Unmarshal
func (s *kvStore) encode(data interface{}) ([]byte, error) {
	return json.Marshal(data)
}

func (s *kvStore) decode(bs []byte, v interface{}) error {
	return json.Unmarshal(bs, v)
}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/functions.go                                   *
 *                                                        *
 * some functions of promise for Go.                      *
 *                                                        *
 * LastModified: Aug 14, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import (
	"errors"
	"sync/atomic"
	"time"
)

// Create creates a Promise object containing the result of asynchronously
// calling computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Create(computation func() (interface{}, error)) Promise {
	promise := New()
	go call(promise, computation)
	return promise
}

// Sync creates a Promise object containing the result of immediately calling
// computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Sync(computation func() (interface{}, error)) Promise {
	promise := New()
	call(promise, computation)
	return promise
}

// Delayed creates a Promise object with the given value after a delay.
//
// If the value is a Callable function, it will be executed after the given
// duration has passed, and the Promise object is completed with the result.
func Delayed(duration time.Duration, value interface{}) Promise {
	promise := New()
	go func() {
		time.Sleep(duration)
		switch computation := value.(type) {
		case func() (interface{}, error):
			call(promise, computation)
		case func():
			call1(promise, computation)
		default:
			promise.Resolve(value)
		}
	}()
	return promise
}

// All function returns a promise that resolves when all of the promises in the
// iterable argument have resolved, or rejects with the reason of the first
// passed promise that rejects.
func All(iterable ...interface{}) Promise {
	count := int64(len(iterable))
	if count == 0 {
		return Resolve(nil)
	}
	result := make([]interface{}, count)
	promise := New()
	for index, value := range iterable {
		ToPromise(value).Then(func(index int) func(value interface{}) {
			return func(value interface{}) {
				result[index] = value
				if atomic.AddInt64(&count, -1) == 0 {
					promise.Resolve(result)
				}
			}
		}(index), promise.Reject)
	}
	return promise
}

// Race function returns a promise that resolves or rejects as soon as one of
// the promises in the iterable resolves or rejects, with the value or reason
// from that promise.
func Race(iterable ...interface{}) Promise {
	promise := New()
	for _, value := range iterable {
		ToPromise(value).Fill(promise)
	}
	return promise
}

// Any function is a competitive race that allows one winner.
//
// The returned promise will fulfill as soon as any one of the input promises
// fulfills, with the value of the fulfilled input promise.
//
// Or reject with a IllegalArgumentError if the input iterable is empty--i.e. it
// is impossible to have one winner.
//
// Or reject with an iterable of all the rejection reasons, if the input
// iterable is non-empty, and all input promises reject.
func Any(iterable ...interface{}) Promise {
	count := int64(len(iterable))
	if count == 0 {
		return Reject(IllegalArgumentError("any(): iterable must not be empty"))
	}
	promise := New()
	for _, value := range iterable {
		ToPromise(value).Then(promise.Resolve, func() {
			if atomic.AddInt64(&count, -1) == 0 {
				promise.Reject(errors.New("any(): all promises failed"))
			}
		})
	}
	return promise
}

// Each function executes a provided function once per element of iterable.
//
// The callback parameter is a function to execute for each element:
//
//		func(index int, value interface{})
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Each(callback func(int, interface{}), iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) {
		if a != nil {
			each(callback, a.([]interface{}))
		}
	})
}

func each(callback func(int, interface{}), iterable []interface{}) {
	for index, value := range iterable {
		callback(index, value)
	}
}

// Every function tests whether all elements in the iterable pass the test
// implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
//
// The returned promise will fulfill with false if the callback function returns
// false for any iterable element immediately. Otherwise, if callback returned
// a true value for all elements, Every will return promise fulfill with true.
//
// If iterable is empty, The returned promise will fulfill with true.
func Every(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return true, nil
		}
		return every(callback, a.([]interface{})), nil
	})
}

func every(callback func(int, interface{}) bool, iterable []interface{}) bool {
	for index, value := range iterable {
		if !callback(index, value) {
			return false
		}
	}
	return true
}

// Some function tests whether some element in the iterable passes the test
// implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
//
// The returned promise will fulfill with true if the callback function returns
// true for any iterable element immediately. Otherwise, if callback returned a
// false value for all elements, Some will return promise fulfill with false.
//
// If iterable is empty, The returned promise will fulfill with false.
func Some(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return false, nil
		}
		return some(callback, a.([]interface{})), nil
	})
}

func some(callback func(int, interface{}) bool, iterable []interface{}) bool {
	for index, value := range iterable {
		if callback(index, value) {
			return true
		}
	}
	return false
}

// Filter function returns a promise fulfill with a slice that has all elements
// pass the test implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Filter(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return nil, nil
		}
		return filter(callback, a.([]interface{})), nil
	})
}

func filter(callback func(int, interface{}) bool, iterable []interface{}) []interface{} {
	result := make([]interface{}, 0, len(iterable))
	for index, value := range iterable {
		if callback(index, value) {
			result = append(result, value)
		}
	}
	return result
}

// Map function returns a promise fulfill with a slice that has the results of
// calling a provided function on every element in iterable.
//
// The callback parameter produces an element of the new slice:
//
//		func(index int, value interface{}) interface{}
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Map(callback func(int, interface{}) interface{}, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return nil, nil
		}
		iterable := a.([]interface{})
		result := make([]interface{}, len(iterable))
		for index, value := range iterable {
			result[index] = callback(index, value)
		}
		return result, nil
	})
}
<commit_msg>Update All<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * promise/functions.go                                   *
 *                                                        *
 * some functions of promise for Go.                      *
 *                                                        *
 * LastModified: Aug 14, 2016                             *
 * Author: Ma Bingyao <andot@hprose.com>                  *
 *                                                        *
\**********************************************************/

package promise

import (
	"errors"
	"sync/atomic"
	"time"
)

// Create creates a Promise object containing the result of asynchronously
// calling computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Create(computation func() (interface{}, error)) Promise {
	promise := New()
	go call(promise, computation)
	return promise
}

// Sync creates a Promise object containing the result of immediately calling
// computation.
//
// If calling computation returns error, the returned Promise is rejected with
// the error.
//
// If calling computation returns a Promise object, completion of the created
// Promise will wait until the returned Promise completes, and will then
// complete with the same result.
//
// If calling computation returns a non-Promise value, the returned Promise is
// completed with that value.
func Sync(computation func() (interface{}, error)) Promise {
	promise := New()
	call(promise, computation)
	return promise
}

// Delayed creates a Promise object with the given value after a delay.
//
// If the value is a Callable function, it will be executed after the given
// duration has passed, and the Promise object is completed with the result.
func Delayed(duration time.Duration, value interface{}) Promise {
	promise := New()
	go func() {
		time.Sleep(duration)
		switch computation := value.(type) {
		case func() (interface{}, error):
			call(promise, computation)
		case func():
			call1(promise, computation)
		default:
			promise.Resolve(value)
		}
	}()
	return promise
}

// All function returns a promise that resolves when all of the promises in the
// iterable argument have resolved, or rejects with the reason of the first
// passed promise that rejects.
func All(iterable ...interface{}) Promise {
	count := int64(len(iterable))
	if count == 0 {
		return Resolve(nil)
	}
	result := make([]interface{}, count)
	promise := New()
	for index, value := range iterable {
		ToPromise(value).Then(
			allHandler(promise, result, index, &count),
			promise.Reject)
	}
	return promise
}

func allHandler(promise Promise, result []interface{}, index int, count *int64) func(value interface{}) {
	return func(value interface{}) {
		result[index] = value
		if atomic.AddInt64(count, -1) == 0 {
			promise.Resolve(result)
		}
	}
}

// Race function returns a promise that resolves or rejects as soon as one of
// the promises in the iterable resolves or rejects, with the value or reason
// from that promise.
func Race(iterable ...interface{}) Promise {
	promise := New()
	for _, value := range iterable {
		ToPromise(value).Fill(promise)
	}
	return promise
}

// Any function is a competitive race that allows one winner.
//
// The returned promise will fulfill as soon as any one of the input promises
// fulfills, with the value of the fulfilled input promise.
//
// Or reject with a IllegalArgumentError if the input iterable is empty--i.e. it
// is impossible to have one winner.
//
// Or reject with an iterable of all the rejection reasons, if the input
// iterable is non-empty, and all input promises reject.
func Any(iterable ...interface{}) Promise {
	count := int64(len(iterable))
	if count == 0 {
		return Reject(IllegalArgumentError("any(): iterable must not be empty"))
	}
	promise := New()
	for _, value := range iterable {
		ToPromise(value).Then(promise.Resolve, func() {
			if atomic.AddInt64(&count, -1) == 0 {
				promise.Reject(errors.New("any(): all promises failed"))
			}
		})
	}
	return promise
}

// Each function executes a provided function once per element of iterable.
//
// The callback parameter is a function to execute for each element:
//
//		func(index int, value interface{})
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Each(callback func(int, interface{}), iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) {
		if a != nil {
			each(callback, a.([]interface{}))
		}
	})
}

func each(callback func(int, interface{}), iterable []interface{}) {
	for index, value := range iterable {
		callback(index, value)
	}
}

// Every function tests whether all elements in the iterable pass the test
// implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
//
// The returned promise will fulfill with false if the callback function returns
// false for any iterable element immediately. Otherwise, if callback returned
// a true value for all elements, Every will return promise fulfill with true.
//
// If iterable is empty, The returned promise will fulfill with true.
func Every(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return true, nil
		}
		return every(callback, a.([]interface{})), nil
	})
}

func every(callback func(int, interface{}) bool, iterable []interface{}) bool {
	for index, value := range iterable {
		if !callback(index, value) {
			return false
		}
	}
	return true
}

// Some function tests whether some element in the iterable passes the test
// implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
//
// The returned promise will fulfill with true if the callback function returns
// true for any iterable element immediately. Otherwise, if callback returned a
// false value for all elements, Some will return promise fulfill with false.
//
// If iterable is empty, The returned promise will fulfill with false.
func Some(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return false, nil
		}
		return some(callback, a.([]interface{})), nil
	})
}

func some(callback func(int, interface{}) bool, iterable []interface{}) bool {
	for index, value := range iterable {
		if callback(index, value) {
			return true
		}
	}
	return false
}

// Filter function returns a promise fulfill with a slice that has all elements
// pass the test implemented by the provided function.
//
// The callback parameter is a function to test for each element:
//
//		func(index int, value interface{}) bool
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Filter(callback func(int, interface{}) bool, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return nil, nil
		}
		return filter(callback, a.([]interface{})), nil
	})
}

func filter(callback func(int, interface{}) bool, iterable []interface{}) []interface{} {
	result := make([]interface{}, 0, len(iterable))
	for index, value := range iterable {
		if callback(index, value) {
			result = append(result, value)
		}
	}
	return result
}

// Map function returns a promise fulfill with a slice that has the results of
// calling a provided function on every element in iterable.
//
// The callback parameter produces an element of the new slice:
//
//		func(index int, value interface{}) interface{}
//
// index: The index of the current element being processed.
//
// value: The current element being processed.
//
// If any of the promises in iterable is rejected, the callback will not be
// executed. the returned promise will be rejected with the rejection reason
// of the first promise that was rejected.
func Map(callback func(int, interface{}) interface{}, iterable ...interface{}) Promise {
	return All(iterable...).Then(func(a interface{}) (interface{}, error) {
		if a == nil {
			return nil, nil
		}
		iterable := a.([]interface{})
		result := make([]interface{}, len(iterable))
		for index, value := range iterable {
			result[index] = callback(index, value)
		}
		return result, nil
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package defaultserviceplan

import (
	"fmt"
	"io"

	"github.com/golang/glog"

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apiserver/pkg/admission"

	informers "github.com/kubernetes-incubator/service-catalog/pkg/client/informers_generated/internalversion"
	internalversion "github.com/kubernetes-incubator/service-catalog/pkg/client/listers_generated/servicecatalog/internalversion"

	"github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog"
	scadmission "github.com/kubernetes-incubator/service-catalog/pkg/apiserver/admission"
)

const (
	// PluginName is name of admission plug-in
	PluginName = "DefaultServicePlan"
)

// Register registers a plugin
func Register(plugins *admission.Plugins) {
	plugins.Register(PluginName, func(io.Reader) (admission.Interface, error) {
		return NewDefaultServicePlan()
	})
}

// exists is an implementation of admission.Interface.
// It checks to see if Service Instance is being created without
// a Service Plan if there is only one Service Plan for the
// specified Service and defaults to that value.
// that the cluster actually has support for it.
type defaultServicePlan struct {
	*admission.Handler
	scLister internalversion.ServiceClassLister
}

var _ = scadmission.WantsInternalServiceCatalogInformerFactory(&defaultServicePlan{})

func (d *defaultServicePlan) Admit(a admission.Attributes) error {
	// we need to wait for our caches to warm
	if !d.WaitForReady() {
		return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
	}

	// We only care about service Instances
	if a.GetResource().Group != servicecatalog.GroupName || a.GetResource().GroupResource() != servicecatalog.Resource("instances") {
		return nil
	}
	instance, ok := a.GetObject().(*servicecatalog.Instance)
	if !ok {
		return errors.NewBadRequest("Resource was marked with kind Instance but was unable to be converted")
	}
	// If the plan is specified, let it through and have the controller
	// deal with finding the right plan, etc.
	if len(instance.Spec.PlanName) > 0 {
		return nil
	}

	sc, err := d.scLister.Get(instance.Spec.ServiceClassName)
	if err != nil {
		if !errors.IsNotFound(err) {
			return errors.NewInternalError(err)
		}
		msg := fmt.Sprintf("ServiceClass %q does not exist, PlanName must be specified", instance.Spec.ServiceClassName)
		glog.V(4).Info(msg)
		return admission.NewForbidden(a, fmt.Errorf(msg))
	}
	if len(sc.Plans) > 1 {
		msg := fmt.Sprintf("ServiceClass %q has more than one plan, PlanName must be specified", instance.Spec.ServiceClassName)
		glog.V(4).Info(msg)
		return admission.NewForbidden(a, fmt.Errorf(msg))
	}

	p := sc.Plans[0]
	glog.V(4).Infof("Using default plan %s for Service Class %s for instance %s",
		p.Name, sc.Name, instance.Name)
	instance.Spec.PlanName = p.Name
	return nil
}

// NewDefaultServicePlan creates a new admission control handler that
// fills in a default Service Plan if omitted from Service Instance
// creation request and if there exists only one plan in the
// specified Service Class
func NewDefaultServicePlan() (admission.Interface, error) {
	return &defaultServicePlan{
		Handler: admission.NewHandler(admission.Create, admission.Update),
	}, nil
}

func (d *defaultServicePlan) SetInternalServiceCatalogInformerFactory(f informers.SharedInformerFactory) {
	scInformer := f.Servicecatalog().InternalVersion().ServiceClasses()
	d.scLister = scInformer.Lister()
	d.SetReadyFunc(scInformer.Informer().HasSynced)
}

func (d *defaultServicePlan) Validate() error {
	if d.scLister == nil {
		return fmt.Errorf("missing service class lister")
	}
	return nil
}
<commit_msg>address PR comments<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package defaultserviceplan

import (
	"fmt"
	"io"

	"github.com/golang/glog"

	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apiserver/pkg/admission"

	informers "github.com/kubernetes-incubator/service-catalog/pkg/client/informers_generated/internalversion"
	internalversion "github.com/kubernetes-incubator/service-catalog/pkg/client/listers_generated/servicecatalog/internalversion"

	"github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog"
	scadmission "github.com/kubernetes-incubator/service-catalog/pkg/apiserver/admission"
)

const (
	// PluginName is name of admission plug-in
	PluginName = "DefaultServicePlan"
)

// Register registers a plugin
func Register(plugins *admission.Plugins) {
	plugins.Register(PluginName, func(io.Reader) (admission.Interface, error) {
		return NewDefaultServicePlan()
	})
}

// exists is an implementation of admission.Interface.
// It checks to see if Service Instance is being created without
// a Service Plan if there is only one Service Plan for the
// specified Service and defaults to that value.
// that the cluster actually has support for it.
type defaultServicePlan struct {
	*admission.Handler
	scLister internalversion.ServiceClassLister
}

var _ = scadmission.WantsInternalServiceCatalogInformerFactory(&defaultServicePlan{})

func (d *defaultServicePlan) Admit(a admission.Attributes) error {
	// we need to wait for our caches to warm
	if !d.WaitForReady() {
		return admission.NewForbidden(a, fmt.Errorf("not yet ready to handle request"))
	}

	// We only care about service Instances
	if a.GetResource().Group != servicecatalog.GroupName || a.GetResource().GroupResource() != servicecatalog.Resource("instances") {
		return nil
	}
	instance, ok := a.GetObject().(*servicecatalog.Instance)
	if !ok {
		return errors.NewBadRequest("Resource was marked with kind Instance but was unable to be converted")
	}
	// If the plan is specified, let it through and have the controller
	// deal with finding the right plan, etc.
	if len(instance.Spec.PlanName) > 0 {
		return nil
	}

	sc, err := d.scLister.Get(instance.Spec.ServiceClassName)
	if err != nil {
		if !errors.IsNotFound(err) {
			return errors.NewInternalError(err)
		}
		msg := fmt.Sprintf("ServiceClass %q does not exist, can not figure out the default Service Plan.", instance.Spec.ServiceClassName)
		glog.V(4).Info(msg)
		return admission.NewForbidden(a, fmt.Errorf(msg))
	}
	if len(sc.Plans) > 1 {
		msg := fmt.Sprintf("ServiceClass %q has more than one plan, PlanName must be specified", instance.Spec.ServiceClassName)
		glog.V(4).Info(msg)
		return admission.NewForbidden(a, fmt.Errorf(msg))
	}

	p := sc.Plans[0]
	glog.V(4).Infof("Using default plan %s for Service Class %s for instance %s",
		p.Name, sc.Name, instance.Name)
	instance.Spec.PlanName = p.Name
	return nil
}

// NewDefaultServicePlan creates a new admission control handler that
// fills in a default Service Plan if omitted from Service Instance
// creation request and if there exists only one plan in the
// specified Service Class
func NewDefaultServicePlan() (admission.Interface, error) {
	return &defaultServicePlan{
		Handler: admission.NewHandler(admission.Create, admission.Update),
	}, nil
}

func (d *defaultServicePlan) SetInternalServiceCatalogInformerFactory(f informers.SharedInformerFactory) {
	scInformer := f.Servicecatalog().InternalVersion().ServiceClasses()
	d.scLister = scInformer.Lister()
	d.SetReadyFunc(scInformer.Informer().HasSynced)
}

func (d *defaultServicePlan) Validate() error {
	if d.scLister == nil {
		return fmt.Errorf("missing service class lister")
	}
	return nil
}
<|endoftext|>


<commit_before>//  Copyright (c) 2013 Couchbase, Inc.
//  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 goyacc

import (
	"encoding/json"
	"log"
	"reflect"
	"testing"

	"github.com/couchbaselabs/tuqtng/ast"
)

var validQueries = []string{
	// this section is all basic expression testing
	`SELECT null`,
	`SELECT NULL`,
	`SELECT NuLl`,
	`SELECT true`,
	`SELECT TRUE`,
	`SELECT tRuE`,
	`SELECT false`,
	`SELECT FALSE`,
	`SELECT fAlSe`,
	`SELECT 1`,
	`SELECT -3`,
	`SELECT 1.5`,
	`SELECT -3.14`,
	`SELECT 1e6`,
	`SELECT 1.3e23`,
	`SELECT -4e-4`,
	`SELECT []`,
	`SELECT [null, false, true, 7, 3.14, "bob"]`,
	`SELECT {}`,
	`SELECT {"bob": "wood"}`,
	`SELECT {"bob": 1}`,
	`SELECT {"null": null, "bool": true, "number": 7, "array": [2, 3, "cat"], "object": {"nested": 99}}`,
	"SELECT `bob wood`",
	`SELECT 3 > 7`,
	`SELECT 1 < 2`,
	`SELECT 1 == 3`,
	`SELECT 2 = 4`,
	`SELECT 3 <> cat`,
	`SELECT dog != cat`,
	`SELECT wow >= what`,
	`SELECT [] <= 7`,
	`SELECT a + b`,
	`SELECT d - c`,
	`SELECT x * y`,
	`SELECT z / 2`,
	`SELECT minutes % 60`,
	`SELECT str1 || str2`,
	`SELECT (3 + c) * 7`,
	`SELECT cat IS NULL`,
	`SELECT dog IS NOT NULL`,
	`SELECT steve IS MISSING`,
	`SELECT gerald IS NOT MISSING`,
	`SELECT siri IS VALUED`,
	`SELECT marty IS NOT VALUED`,
	`SELECT noone LIKE them`,
	`SELECT someone NOT LIKE me`,
	`SELECT -abv`,
	`SELECT contact.name`,
	`SELECT contact.name.first`,
	`SELECT {"bob": "wood"}.wood`,
	`SELECT family["father"]`,
	`SELECT [a,b,c][0]`,
	`SELECT [0,[1,2,[3,4,5]]][1][2][1]`,
	`SELECT cat.a+b`,  // DOT has higher precedance than PLUS so this is valid
	`SELECT cat[a+b]`, // if you wanted to evaluate a+b and use that as property name
	// more complicated query testing
	`SELECT bob FROM cat WHERE foo = bar ORDER BY this LIMIT 10 OFFSET 20`,
	`SELECT bob FROM cat WHERE foo = bar LIMIT 10 OFFSET 20`,
	`SELECT bob FROM cat WHERE foo = bar LIMIT 10`,
	`SELECT bob FROM cat WHERE foo = bar`,
	`SELECT bob FROM cat`,
	`SELECT bob FROM cat WHERE foo = bar and 3 > 4`,
	`SELECT bob, bill FROM cat WHERE foo = bar and 3 > 4`,
	`SELECT bob AS bill, bill AS bob FROM cat WHERE foo = bar and 3 > 4`,
	`SELECT *, bob AS bill, bill AS bob FROM cat WHERE foo = bar and 3 > 4`,
	`SELECT *, names.*, bob AS bill, bill AS bob FROM cat WHERE foo = bar and 3 > 4`,
}

var invalidQueries = []string{
	`bob`,         // must have select
	`SELECT 01`,   // numbers cannot start with leading zeros
	`SELECT 3dog`, // unescaped identifiers cannot start with number
	`SELECT bob FROM cat WHERE foo = bar ORDER BY this OFFSET 20`,                  // offset requires limit
	`SELECT * AS all, bob AS bill, bill AS bob FROM cat WHERE foo = bar and 3 > 4`, // cannot alias *
}

func TestParser(t *testing.T) {
	DebugTokens = false
	DebugGrammar = false
	unqlParser := NewUnqlParser()

	for _, v := range validQueries {
		_, err := unqlParser.Parse(v)
		if err != nil {
			t.Errorf("Valid Query Parse Failed: %v - %v", v, err)
			//enable debugging and run it again
			log.Printf("Debug for input: %v", v)
			DebugTokens = true
			DebugGrammar = true
			unqlParser.Parse(v)
			DebugTokens = false
			DebugGrammar = false
		}
	}

	for _, v := range invalidQueries {
		_, err := unqlParser.Parse(v)
		if err == nil {
			t.Errorf("Invalid Query Parsed Successfully: %v - %v", v, err)
		}
	}

}

func TestParserASTOutput(t *testing.T) {

	tests := []struct {
		input  string
		output *ast.SelectStatement
	}{
		{"SELECT * FROM test WHERE true",
			&ast.SelectStatement{
				Select: ast.ResultExpressionList{
					ast.NewStarResultExpression(),
				},
				From:  nil,
				Where: ast.NewLiteralBool(true),
			},
		},
		{"SELECT * FROM test ORDER BY foo",
			&ast.SelectStatement{
				Select: ast.ResultExpressionList{
					ast.NewStarResultExpression(),
				},
				From:  nil,
				Where: nil,
				OrderBy: []*ast.SortExpression{
					ast.NewSortExpression(ast.NewProperty("foo"), true),
				},
			},
		},
		{"SELECT * FROM test LIMIT 10 OFFSET 3",
			&ast.SelectStatement{
				Select: ast.ResultExpressionList{
					ast.NewStarResultExpression(),
				},
				From:   nil,
				Where:  nil,
				Limit:  10,
				Offset: 3,
			},
		},
		{"SELECT a FROM test",
			&ast.SelectStatement{
				Select: ast.ResultExpressionList{
					ast.NewResultExpression(ast.NewProperty("a")),
				},
				From:  nil,
				Where: nil,
			},
		},
	}

	DebugTokens = false
	DebugGrammar = false
	unqlParser := NewUnqlParser()

	for _, v := range tests {
		query, err := unqlParser.Parse(v.input)
		if err != nil {
			t.Errorf("Valid Query Parse Failed: %v - %v", v, err)
		}

		if !reflect.DeepEqual(query, v.output) {
			t.Errorf("Expected %v, got %v", v.output, query)

			json, err := json.Marshal(query)
			if err == nil {
				log.Printf("%v", string(json))
			}
		}
	}

}
<commit_msg>fix tests I broken, limit defaults to -1<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//  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 goyacc

import (
	"encoding/json"
	"log"
	"reflect"
	"testing"

	"github.com/couchbaselabs/tuqtng/ast"
)

var validQueries = []string{
	// this section is all basic expression testing
	`SELECT null`,
	`SELECT NULL`,
	`SELECT NuLl`,
	`SELECT true`,
	`SELECT TRUE`,
	`SELECT tRuE`,
	`SELECT false`,
	`SELECT FALSE`,
	`SELECT fAlSe`,
	`SELECT 1`,
	`SELECT -3`,
	`SELECT 1.5`,
	`SELECT -3.14`,
	`SELECT 1e6`,
	`SELECT 1.3e23`,
	`SELECT -4e-4`,
	`SELECT []`,
	`SELECT [null, false, true, 7, 3.14, "bob"]`,
	`SELECT {}`,
	`SELECT {"bob": "wood"}`,
	`SELECT {"bob": 1}`,
	`SELECT {"null": null, "bool": true, "number": 7, "array": [2, 3, "cat"], "object": {"nested": 99}}`,
	"SELECT `bob wood`",
	`SELECT 3 > 7`,
	`SELECT 1 < 2`,
	`SELECT 1 == 3`,
	`SELECT 2 = 4`,
	`SELECT 3 <> cat`,
	`SELECT dog != cat`,
	`SELECT wow >= what`,
	`SELECT [] <= 7`,
	`SELECT a + b`,
	`SELECT d - c`,
	`SELECT x * y`,
	`SELECT z / 2`,
	`SELECT minutes % 60`,
	`SELECT str1 || str2`,
	`SELECT (3 + c) * 7`,
	`SELECT cat IS NULL`,
	`SELECT dog IS NOT NULL`,
	`SELECT steve IS MISSING`,
	`SELECT gerald IS NOT MISSING`,
	`SELECT siri IS VALUED`,
	`SELECT marty IS NOT VALUED`,
	`SELECT noone LIKE them`,
	`SELECT someone NOT LIKE me`,
	`SELECT -abv`,
	`SELECT contact.name`,
	`SELECT contact.name.first`,
	`SELECT {"bob": "wood"}.wood`,
	`SELECT family["father"]`,
	`SELECT [a,b,c][0]`,
	`SELECT [0,[1,2,[3,4,5]]][1][2][1]`,
	`SELECT cat.a+b`,  // DOT has higher precedance than PLUS so this is valid
	`SELECT cat[a+b]`, // if you wanted to evaluate a+b and use that as property name
	// more complicated query testing
	`SELECT bob FROM cat WHERE foo = bar ORDER BY this LIMIT 10 OFFSET 20`,
	`SELECT bob FROM cat WHERE foo = bar LIMIT 10 OFFSET 20`,
	`SELECT bob FROM cat WHERE foo = bar LIMIT 10`,
	`SELECT bob FROM cat WHERE foo = bar`,
	`SELECT bob FROM cat`,
	`SELECT bob FROM cat WHERE foo = bar and 3 > 4`,
	`SELECT bob, bill FROM cat WHERE foo = bar and 3 > 4`,
	`SELECT bob AS bill, bill AS bob FROM cat WHERE foo = bar and 3 > 4`,
	`SELECT *, bob AS bill, bill AS bob FROM cat WHERE foo = bar and 3 > 4`,
	`SELECT *, names.*, bob AS bill, bill AS bob FROM cat WHERE foo = bar and 3 > 4`,
}

var invalidQueries = []string{
	`bob`,         // must have select
	`SELECT 01`,   // numbers cannot start with leading zeros
	`SELECT 3dog`, // unescaped identifiers cannot start with number
	`SELECT bob FROM cat WHERE foo = bar ORDER BY this OFFSET 20`,                  // offset requires limit
	`SELECT * AS all, bob AS bill, bill AS bob FROM cat WHERE foo = bar and 3 > 4`, // cannot alias *
}

func TestParser(t *testing.T) {
	DebugTokens = false
	DebugGrammar = false
	unqlParser := NewUnqlParser()

	for _, v := range validQueries {
		_, err := unqlParser.Parse(v)
		if err != nil {
			t.Errorf("Valid Query Parse Failed: %v - %v", v, err)
			//enable debugging and run it again
			log.Printf("Debug for input: %v", v)
			DebugTokens = true
			DebugGrammar = true
			unqlParser.Parse(v)
			DebugTokens = false
			DebugGrammar = false
		}
	}

	for _, v := range invalidQueries {
		_, err := unqlParser.Parse(v)
		if err == nil {
			t.Errorf("Invalid Query Parsed Successfully: %v - %v", v, err)
		}
	}

}

func TestParserASTOutput(t *testing.T) {

	tests := []struct {
		input  string
		output *ast.SelectStatement
	}{
		{"SELECT * FROM test WHERE true",
			&ast.SelectStatement{
				Select: ast.ResultExpressionList{
					ast.NewStarResultExpression(),
				},
				From:  nil,
				Where: ast.NewLiteralBool(true),
				Limit: -1,
			},
		},
		{"SELECT * FROM test ORDER BY foo",
			&ast.SelectStatement{
				Select: ast.ResultExpressionList{
					ast.NewStarResultExpression(),
				},
				From:  nil,
				Where: nil,
				OrderBy: []*ast.SortExpression{
					ast.NewSortExpression(ast.NewProperty("foo"), true),
				},
				Limit: -1,
			},
		},
		{"SELECT * FROM test LIMIT 10 OFFSET 3",
			&ast.SelectStatement{
				Select: ast.ResultExpressionList{
					ast.NewStarResultExpression(),
				},
				From:   nil,
				Where:  nil,
				Limit:  10,
				Offset: 3,
			},
		},
		{"SELECT a FROM test",
			&ast.SelectStatement{
				Select: ast.ResultExpressionList{
					ast.NewResultExpression(ast.NewProperty("a")),
				},
				From:  nil,
				Where: nil,
				Limit: -1,
			},
		},
	}

	DebugTokens = false
	DebugGrammar = false
	unqlParser := NewUnqlParser()

	for _, v := range tests {
		query, err := unqlParser.Parse(v.input)
		if err != nil {
			t.Errorf("Valid Query Parse Failed: %v - %v", v, err)
		}

		if !reflect.DeepEqual(query, v.output) {
			t.Errorf("Expected %v, got %v", v.output, query)

			json, err := json.Marshal(query)
			if err == nil {
				log.Printf("%v", string(json))
			}
		}
	}

}
<|endoftext|>