<commit_before>// Copyright 2016 The go-qemu 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 qmp

import (
	"encoding/json"
	"testing"
	"time"

	"github.com/digitalocean/go-libvirt"
	"github.com/digitalocean/go-libvirt/libvirttest"
)

var testEvent = []byte{
	0x00, 0x00, 0x00, 0xb0, // length
	0x20, 0x00, 0x80, 0x87, // program
	0x00, 0x00, 0x00, 0x01, // version
	0x00, 0x00, 0x00, 0x06, // procedure
	0x00, 0x00, 0x00, 0x01, // type
	0x00, 0x00, 0x00, 0x00, // serial
	0x00, 0x00, 0x00, 0x00, // status
	0x00, 0x00, 0x00, 0x01, // callback id

	// domain name ("test")
	0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,

	// uuid (dc229f87d4de47198cfd2e21c6105b01)
	0xdc, 0x22, 0x9f, 0x87, 0xd4, 0xde, 0x47, 0x19,
	0x8c, 0xfd, 0x2e, 0x21, 0xc6, 0x10, 0x5b, 0x01,

	// domain id (14)
	0x00, 0x00, 0x00, 0x0e,

	// event name (BLOCK_JOB_COMPLETED)
	0x00, 0x00, 0x00, 0x13, 0x42, 0x4c, 0x4f, 0x43,
	0x4b, 0x5f, 0x4a, 0x4f, 0x42, 0x5f, 0x43, 0x4f,
	0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x00,

	// seconds (1462211891)
	0x00, 0x00, 0x00, 0x00, 0x57, 0x27, 0x95, 0x33,

	// microseconds (931791)
	0x00, 0x0e, 0x37, 0xcf,

	// event json data
	// ({"device":"drive-ide0-0-0","len":0,"offset":0,"speed":0,"type":"commit"})
	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48,
	0x7b, 0x22, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
	0x22, 0x3a, 0x22, 0x64, 0x72, 0x69, 0x76, 0x65,
	0x2d, 0x69, 0x64, 0x65, 0x30, 0x2d, 0x30, 0x2d,
	0x30, 0x22, 0x2c, 0x22, 0x6c, 0x65, 0x6e, 0x22,
	0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x66, 0x66, 0x73,
	0x65, 0x74, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73,
	0x70, 0x65, 0x65, 0x64, 0x22, 0x3a, 0x30, 0x2c,
	0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22,
	0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x22, 0x7d,
}

func TestNewLibvirtRPC(t *testing.T) {
	conn := libvirttest.New()

	domain := "test-1"
	rpc := NewLibvirtRPC(domain, conn)

	if rpc.Domain != domain {
		t.Errorf("expected domain %q, got %q", domain, rpc.Domain)
	}
}

func TestQMPEvent(t *testing.T) {
	e := &libvirt.DomainEvent{
		CallbackID:   1,
		Domain:       libvirt.Domain{Name: "test"},
		Event:        "test",
		Seconds:      1,
		Microseconds: 1,
		Details:      []byte(`{"device":"drive-virtio-disk0","len":0,"offset":0,"speed":0,"type":"commit"}`),
	}

	qe, err := qmpEvent(e)
	if err != nil {
		t.Error(err)
	}

	if qe.Event != e.Event {
		t.Errorf("expected event %q, got %q", e.Event, qe.Event)
	}

	if qe.Timestamp.Seconds != int64(e.Seconds) {
		t.Errorf("expected seconds to be %q, got %q", e.Seconds, qe.Timestamp.Seconds)
	}

	if qe.Timestamp.Microseconds != int64(e.Microseconds) {
		t.Errorf("expected microseconds to be %q, got %q", e.Microseconds, qe.Timestamp.Microseconds)
	}

	expected := "drive-virtio-disk0"
	actual, ok := qe.Data["device"]
	if !ok {
		t.Error("expected event data 'device'")
	}

	if actual != expected {
		t.Errorf("expected device %q, got %q", expected, actual)
	}
}

func TestLibvirtRPCConnect(t *testing.T) {
	conn := libvirttest.New()
	mon := NewLibvirtRPC("test", conn)

	err := mon.Connect()
	if err != nil {
		t.Error(err)
	}
}

func TestLibvirtRPCDisconnect(t *testing.T) {
	conn := libvirttest.New()
	mon := NewLibvirtRPC("test", conn)

	err := mon.Disconnect()
	if err != nil {
		t.Error(err)
	}
}

func TestLibvirtRPCRun(t *testing.T) {
	conn := libvirttest.New()
	mon := NewLibvirtRPC("test", conn)

	res, err := mon.Run([]byte(`{"query-version"}`))
	if err != nil {
		t.Error(err)
	}

	type version struct {
		Return struct {
			Package string `json:"package"`
			QEMU    struct {
				Major int `json:"major"`
				Micro int `json:"micro"`
				Minor int `json:"minor"`
			} `json:"qemu"`
		} `json:"return"`
	}

	var v version
	err = json.Unmarshal(res, &v)
	if err != nil {
		t.Error(err)
	}

	expected := 2
	if v.Return.QEMU.Major != expected {
		t.Errorf("expected qemu major version %d, got %d", expected, v.Return.QEMU.Major)
	}
}

func TestLibvirtRPCEvents(t *testing.T) {
	conn := libvirttest.New()
	mon := NewLibvirtRPC("test", conn)
	done := make(chan struct{})

	stream, err := mon.Events()
	if err != nil {
		t.Error(err)
	}

	go func() {
		var e Event
		select {
		case e = <-stream:
		case <-time.After(time.Second * 1):
			t.Error("expected event, received timeout")
		}

		expected := "drive-ide0-0-0"
		if e.Data["device"] != expected {
			t.Errorf("expected device %q, got %q", expected, e.Data["device"])
		}

		done <- struct{}{}
	}()

	// send an event to the listener goroutine
	conn.Test.Write(testEvent)

	// wait for completion
	<-done
}
<commit_msg>qmp: fix errcheck issue in rpc_test.go<commit_after>// Copyright 2016 The go-qemu 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 qmp

import (
	"encoding/json"
	"testing"
	"time"

	"github.com/digitalocean/go-libvirt"
	"github.com/digitalocean/go-libvirt/libvirttest"
)

var testEvent = []byte{
	0x00, 0x00, 0x00, 0xb0, // length
	0x20, 0x00, 0x80, 0x87, // program
	0x00, 0x00, 0x00, 0x01, // version
	0x00, 0x00, 0x00, 0x06, // procedure
	0x00, 0x00, 0x00, 0x01, // type
	0x00, 0x00, 0x00, 0x00, // serial
	0x00, 0x00, 0x00, 0x00, // status
	0x00, 0x00, 0x00, 0x01, // callback id

	// domain name ("test")
	0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,

	// uuid (dc229f87d4de47198cfd2e21c6105b01)
	0xdc, 0x22, 0x9f, 0x87, 0xd4, 0xde, 0x47, 0x19,
	0x8c, 0xfd, 0x2e, 0x21, 0xc6, 0x10, 0x5b, 0x01,

	// domain id (14)
	0x00, 0x00, 0x00, 0x0e,

	// event name (BLOCK_JOB_COMPLETED)
	0x00, 0x00, 0x00, 0x13, 0x42, 0x4c, 0x4f, 0x43,
	0x4b, 0x5f, 0x4a, 0x4f, 0x42, 0x5f, 0x43, 0x4f,
	0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x00,

	// seconds (1462211891)
	0x00, 0x00, 0x00, 0x00, 0x57, 0x27, 0x95, 0x33,

	// microseconds (931791)
	0x00, 0x0e, 0x37, 0xcf,

	// event json data
	// ({"device":"drive-ide0-0-0","len":0,"offset":0,"speed":0,"type":"commit"})
	0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48,
	0x7b, 0x22, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
	0x22, 0x3a, 0x22, 0x64, 0x72, 0x69, 0x76, 0x65,
	0x2d, 0x69, 0x64, 0x65, 0x30, 0x2d, 0x30, 0x2d,
	0x30, 0x22, 0x2c, 0x22, 0x6c, 0x65, 0x6e, 0x22,
	0x3a, 0x30, 0x2c, 0x22, 0x6f, 0x66, 0x66, 0x73,
	0x65, 0x74, 0x22, 0x3a, 0x30, 0x2c, 0x22, 0x73,
	0x70, 0x65, 0x65, 0x64, 0x22, 0x3a, 0x30, 0x2c,
	0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22,
	0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x22, 0x7d,
}

func TestNewLibvirtRPC(t *testing.T) {
	conn := libvirttest.New()

	domain := "test-1"
	rpc := NewLibvirtRPC(domain, conn)

	if rpc.Domain != domain {
		t.Errorf("expected domain %q, got %q", domain, rpc.Domain)
	}
}

func TestQMPEvent(t *testing.T) {
	e := &libvirt.DomainEvent{
		CallbackID:   1,
		Domain:       libvirt.Domain{Name: "test"},
		Event:        "test",
		Seconds:      1,
		Microseconds: 1,
		Details:      []byte(`{"device":"drive-virtio-disk0","len":0,"offset":0,"speed":0,"type":"commit"}`),
	}

	qe, err := qmpEvent(e)
	if err != nil {
		t.Error(err)
	}

	if qe.Event != e.Event {
		t.Errorf("expected event %q, got %q", e.Event, qe.Event)
	}

	if qe.Timestamp.Seconds != int64(e.Seconds) {
		t.Errorf("expected seconds to be %q, got %q", e.Seconds, qe.Timestamp.Seconds)
	}

	if qe.Timestamp.Microseconds != int64(e.Microseconds) {
		t.Errorf("expected microseconds to be %q, got %q", e.Microseconds, qe.Timestamp.Microseconds)
	}

	expected := "drive-virtio-disk0"
	actual, ok := qe.Data["device"]
	if !ok {
		t.Error("expected event data 'device'")
	}

	if actual != expected {
		t.Errorf("expected device %q, got %q", expected, actual)
	}
}

func TestLibvirtRPCConnect(t *testing.T) {
	conn := libvirttest.New()
	mon := NewLibvirtRPC("test", conn)

	err := mon.Connect()
	if err != nil {
		t.Error(err)
	}
}

func TestLibvirtRPCDisconnect(t *testing.T) {
	conn := libvirttest.New()
	mon := NewLibvirtRPC("test", conn)

	err := mon.Disconnect()
	if err != nil {
		t.Error(err)
	}
}

func TestLibvirtRPCRun(t *testing.T) {
	conn := libvirttest.New()
	mon := NewLibvirtRPC("test", conn)

	res, err := mon.Run([]byte(`{"query-version"}`))
	if err != nil {
		t.Error(err)
	}

	type version struct {
		Return struct {
			Package string `json:"package"`
			QEMU    struct {
				Major int `json:"major"`
				Micro int `json:"micro"`
				Minor int `json:"minor"`
			} `json:"qemu"`
		} `json:"return"`
	}

	var v version
	err = json.Unmarshal(res, &v)
	if err != nil {
		t.Error(err)
	}

	expected := 2
	if v.Return.QEMU.Major != expected {
		t.Errorf("expected qemu major version %d, got %d", expected, v.Return.QEMU.Major)
	}
}

func TestLibvirtRPCEvents(t *testing.T) {
	conn := libvirttest.New()
	mon := NewLibvirtRPC("test", conn)
	done := make(chan struct{})

	stream, err := mon.Events()
	if err != nil {
		t.Error(err)
	}

	go func() {
		var e Event
		select {
		case e = <-stream:
		case <-time.After(time.Second * 1):
			t.Error("expected event, received timeout")
		}

		expected := "drive-ide0-0-0"
		if e.Data["device"] != expected {
			t.Errorf("expected device %q, got %q", expected, e.Data["device"])
		}

		done <- struct{}{}
	}()

	// send an event to the listener goroutine
	_, _ = conn.Test.Write(testEvent)

	// wait for completion
	<-done
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// +build go1.3

package lxdclient

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/url"
	"os"
	"strconv"
	"strings"
	"syscall"

	"github.com/lxc/lxd"
	lxdshared "github.com/lxc/lxd/shared"

	"github.com/juju/errors"
	"github.com/juju/loggo"
)

var logger = loggo.GetLogger("juju.tools.lxdclient")

const LXDBridgeFile = "/etc/default/lxd-bridge"

// Client is a high-level wrapper around the LXD API client.
type Client struct {
	*serverConfigClient
	*certClient
	*profileClient
	*instanceClient
	*imageClient
	baseURL string
}

func (c Client) String() string {
	return fmt.Sprintf("Client(%s)", c.baseURL)
}

// Connect opens an API connection to LXD and returns a high-level
// Client wrapper around that connection.
func Connect(cfg Config) (*Client, error) {
	if err := cfg.Validate(); err != nil {
		return nil, errors.Trace(err)
	}

	remote := cfg.Remote.ID()

	raw, err := newRawClient(cfg.Remote)
	if err != nil {
		return nil, errors.Trace(err)
	}

	conn := &Client{
		serverConfigClient: &serverConfigClient{raw},
		certClient:         &certClient{raw},
		profileClient:      &profileClient{raw},
		instanceClient:     &instanceClient{raw, remote},
		imageClient:        &imageClient{raw},
		baseURL:            raw.BaseURL,
	}
	return conn, nil
}

var lxdNewClientFromInfo = lxd.NewClientFromInfo

// newRawClient connects to the LXD host that is defined in Config.
func newRawClient(remote Remote) (*lxd.Client, error) {
	host := remote.Host
	logger.Debugf("connecting to LXD remote %q: %q", remote.ID(), host)

	if remote.ID() == remoteIDForLocal && host == "" {
		host = "unix://" + lxdshared.VarPath("unix.socket")
	} else if !strings.HasPrefix(host, "unix://") {
		_, _, err := net.SplitHostPort(host)
		if err != nil {
			// There is no port here
			host = net.JoinHostPort(host, lxdshared.DefaultPort)
		}
	}

	clientCert := ""
	if remote.Cert != nil && remote.Cert.CertPEM != nil {
		clientCert = string(remote.Cert.CertPEM)
	}

	clientKey := ""
	if remote.Cert != nil && remote.Cert.KeyPEM != nil {
		clientKey = string(remote.Cert.KeyPEM)
	}

	static := false
	public := false
	if remote.Protocol == SimplestreamsProtocol {
		static = true
		public = true
	}

	client, err := lxdNewClientFromInfo(lxd.ConnectInfo{
		Name: remote.ID(),
		RemoteConfig: lxd.RemoteConfig{
			Addr:     host,
			Static:   static,
			Public:   public,
			Protocol: string(remote.Protocol),
		},
		ClientPEMCert: clientCert,
		ClientPEMKey:  clientKey,
		ServerPEMCert: remote.ServerPEMCert,
	})
	if err != nil {
		if remote.ID() == remoteIDForLocal {
			err = hoistLocalConnectErr(err)
			return nil, errors.Annotate(err, "can't connect to the local LXD server")
		}
		return nil, errors.Trace(err)
	}

	/* If this is the LXD provider on the localhost, let's do an extra
	 * check to make sure that lxdbr0 is configured.
	 */
	if remote.ID() == remoteIDForLocal {
		profile, err := client.ProfileConfig("default")
		if err != nil {
			return nil, errors.Trace(err)
		}

		/* If the default profile doesn't have eth0 in it, then the
		 * user has messed with it, so let's just use whatever they set up.
		 *
		 * Otherwise, if it looks like it's pointing at our lxdbr0,
		 * let's check and make sure that is configured.
		 */
		eth0, ok := profile.Devices["eth0"]
		if ok && eth0["type"] == "nic" && eth0["nictype"] == "bridged" && eth0["parent"] == "lxdbr0" {
			conf, err := ioutil.ReadFile(LXDBridgeFile)
			if err != nil {
				if !os.IsNotExist(err) {
					return nil, errors.Trace(err)
				} else {
					return nil, bridgeConfigError("lxdbr0 configured but no config file found at " + LXDBridgeFile)
				}
			}

			if err = checkLXDBridgeConfiguration(string(conf)); err != nil {
				return nil, errors.Trace(err)
			}
		}
	}

	return client, nil
}

func bridgeConfigError(err string) error {
	return errors.Errorf(`%s
It looks like your lxdbr0 has not yet been configured. Please configure it via:

	sudo dpkg-reconfigure -p medium lxd

and then bootstrap again.`, err)
}

func checkLXDBridgeConfiguration(conf string) error {
	foundSubnetConfig := false
	for _, line := range strings.Split(conf, "\n") {
		if strings.HasPrefix(line, "USE_LXD_BRIDGE=") {
			b, err := strconv.ParseBool(strings.Trim(line[len("USE_LXD_BRIDGE="):], " \""))
			if err != nil {
				logger.Warningf("couldn't parse bool, skipping USE_LXD_BRIDGE check: %s", err)
				continue
			}

			if !b {
				return bridgeConfigError("lxdbr0 not enabled but required")
			}
		} else if strings.HasPrefix(line, "LXD_BRIDGE=") {
			name := strings.Trim(line[len("LXD_BRIDGE="):], " \"")
			/* If we're here, we want lxdbr0 to be configured
			 * because the default profile that juju will use says
			 * lxdbr0. So let's fail if it doesn't.
			 */
			if name != "lxdbr0" {
				return bridgeConfigError(fmt.Sprintf(LXDBridgeFile+" has a bridge named %s, not lxdbr0", name))
			}
		} else if strings.HasPrefix(line, "LXD_IPV4_ADDR=") || strings.HasPrefix(line, "LXD_IPV6_ADDR=") {
			contents := strings.Trim(line[len("LXD_IPVN_ADDR="):], " \"")
			if len(contents) > 0 {
				foundSubnetConfig = true
			}
		}
	}

	if !foundSubnetConfig {
		return bridgeConfigError("lxdbr0 has no ipv4 or ipv6 subnet enabled")
	}

	return nil
}

func hoistLocalConnectErr(err error) error {
	var installed bool

	msg := err.Error()
	switch t := err.(type) {
	case *url.Error:
		switch u := t.Err.(type) {
		case *net.OpError:
			if u.Op == "dial" && u.Net == "unix" {
				switch errno := u.Err.(type) {
				case *os.SyscallError:
					switch errno.Err {
					case syscall.ENOENT:
						msg = "LXD socket not found; is LXD installed & running?"
					case syscall.ECONNREFUSED:
						installed = true
						msg = "LXD refused connections; is LXD running?"
					case syscall.EACCES:
						installed = true
						msg = "Permisson denied, are you in the lxd group?"
					}
				}
			}
		}
	}

	configureText := `
Please configure LXD by running:
	$ newgrp lxd
	$ lxd init
`

	installText := `
Please install LXD by running:
	$ sudo apt-get install lxd
and then configure it with:
	$ newgrp lxd
	$ lxd init
`

	hint := installText
	if installed {
		hint = configureText
	}

	return errors.Trace(fmt.Errorf("%s\n%s", msg, hint))
}
<commit_msg>lxd container type: split out giant case into extra function<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

// +build go1.3

package lxdclient

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/url"
	"os"
	"strconv"
	"strings"
	"syscall"

	"github.com/lxc/lxd"
	lxdshared "github.com/lxc/lxd/shared"

	"github.com/juju/errors"
	"github.com/juju/loggo"
)

var logger = loggo.GetLogger("juju.tools.lxdclient")

const LXDBridgeFile = "/etc/default/lxd-bridge"

// Client is a high-level wrapper around the LXD API client.
type Client struct {
	*serverConfigClient
	*certClient
	*profileClient
	*instanceClient
	*imageClient
	baseURL string
}

func (c Client) String() string {
	return fmt.Sprintf("Client(%s)", c.baseURL)
}

// Connect opens an API connection to LXD and returns a high-level
// Client wrapper around that connection.
func Connect(cfg Config) (*Client, error) {
	if err := cfg.Validate(); err != nil {
		return nil, errors.Trace(err)
	}

	remote := cfg.Remote.ID()

	raw, err := newRawClient(cfg.Remote)
	if err != nil {
		return nil, errors.Trace(err)
	}

	conn := &Client{
		serverConfigClient: &serverConfigClient{raw},
		certClient:         &certClient{raw},
		profileClient:      &profileClient{raw},
		instanceClient:     &instanceClient{raw, remote},
		imageClient:        &imageClient{raw},
		baseURL:            raw.BaseURL,
	}
	return conn, nil
}

var lxdNewClientFromInfo = lxd.NewClientFromInfo

// newRawClient connects to the LXD host that is defined in Config.
func newRawClient(remote Remote) (*lxd.Client, error) {
	host := remote.Host
	logger.Debugf("connecting to LXD remote %q: %q", remote.ID(), host)

	if remote.ID() == remoteIDForLocal && host == "" {
		host = "unix://" + lxdshared.VarPath("unix.socket")
	} else if !strings.HasPrefix(host, "unix://") {
		_, _, err := net.SplitHostPort(host)
		if err != nil {
			// There is no port here
			host = net.JoinHostPort(host, lxdshared.DefaultPort)
		}
	}

	clientCert := ""
	if remote.Cert != nil && remote.Cert.CertPEM != nil {
		clientCert = string(remote.Cert.CertPEM)
	}

	clientKey := ""
	if remote.Cert != nil && remote.Cert.KeyPEM != nil {
		clientKey = string(remote.Cert.KeyPEM)
	}

	static := false
	public := false
	if remote.Protocol == SimplestreamsProtocol {
		static = true
		public = true
	}

	client, err := lxdNewClientFromInfo(lxd.ConnectInfo{
		Name: remote.ID(),
		RemoteConfig: lxd.RemoteConfig{
			Addr:     host,
			Static:   static,
			Public:   public,
			Protocol: string(remote.Protocol),
		},
		ClientPEMCert: clientCert,
		ClientPEMKey:  clientKey,
		ServerPEMCert: remote.ServerPEMCert,
	})
	if err != nil {
		if remote.ID() == remoteIDForLocal {
			err = hoistLocalConnectErr(err)
			return nil, errors.Annotate(err, "can't connect to the local LXD server")
		}
		return nil, errors.Trace(err)
	}

	/* If this is the LXD provider on the localhost, let's do an extra
	 * check to make sure that lxdbr0 is configured.
	 */
	if remote.ID() == remoteIDForLocal {
		profile, err := client.ProfileConfig("default")
		if err != nil {
			return nil, errors.Trace(err)
		}

		/* If the default profile doesn't have eth0 in it, then the
		 * user has messed with it, so let's just use whatever they set up.
		 *
		 * Otherwise, if it looks like it's pointing at our lxdbr0,
		 * let's check and make sure that is configured.
		 */
		eth0, ok := profile.Devices["eth0"]
		if ok && eth0["type"] == "nic" && eth0["nictype"] == "bridged" && eth0["parent"] == "lxdbr0" {
			conf, err := ioutil.ReadFile(LXDBridgeFile)
			if err != nil {
				if !os.IsNotExist(err) {
					return nil, errors.Trace(err)
				} else {
					return nil, bridgeConfigError("lxdbr0 configured but no config file found at " + LXDBridgeFile)
				}
			}

			if err = checkLXDBridgeConfiguration(string(conf)); err != nil {
				return nil, errors.Trace(err)
			}
		}
	}

	return client, nil
}

func bridgeConfigError(err string) error {
	return errors.Errorf(`%s
It looks like your lxdbr0 has not yet been configured. Please configure it via:

	sudo dpkg-reconfigure -p medium lxd

and then bootstrap again.`, err)
}

func checkLXDBridgeConfiguration(conf string) error {
	foundSubnetConfig := false
	for _, line := range strings.Split(conf, "\n") {
		if strings.HasPrefix(line, "USE_LXD_BRIDGE=") {
			b, err := strconv.ParseBool(strings.Trim(line[len("USE_LXD_BRIDGE="):], " \""))
			if err != nil {
				logger.Warningf("couldn't parse bool, skipping USE_LXD_BRIDGE check: %s", err)
				continue
			}

			if !b {
				return bridgeConfigError("lxdbr0 not enabled but required")
			}
		} else if strings.HasPrefix(line, "LXD_BRIDGE=") {
			name := strings.Trim(line[len("LXD_BRIDGE="):], " \"")
			/* If we're here, we want lxdbr0 to be configured
			 * because the default profile that juju will use says
			 * lxdbr0. So let's fail if it doesn't.
			 */
			if name != "lxdbr0" {
				return bridgeConfigError(fmt.Sprintf(LXDBridgeFile+" has a bridge named %s, not lxdbr0", name))
			}
		} else if strings.HasPrefix(line, "LXD_IPV4_ADDR=") || strings.HasPrefix(line, "LXD_IPV6_ADDR=") {
			contents := strings.Trim(line[len("LXD_IPVN_ADDR="):], " \"")
			if len(contents) > 0 {
				foundSubnetConfig = true
			}
		}
	}

	if !foundSubnetConfig {
		return bridgeConfigError("lxdbr0 has no ipv4 or ipv6 subnet enabled")
	}

	return nil
}

func getMessageFromErr(err error) (bool, string) {
	msg := err.Error()
	t, ok := err.(*url.Error)
	if !ok {
		return false, msg
	}

	u, ok := t.Err.(*net.OpError)
	if !ok {
		return false, msg
	}

	if u.Op == "dial" && u.Net == "unix" {
		errno, ok := u.Err.(*os.SyscallError)
		if !ok {
			return false, msg
		}

		switch errno.Err {
		case syscall.ENOENT:
			return false, "LXD socket not found; is LXD installed & running?"
		case syscall.ECONNREFUSED:
			return true, "LXD refused connections; is LXD running?"
		case syscall.EACCES:
			return true, "Permisson denied, are you in the lxd group?"
		}
	}

	return false, msg
}

func hoistLocalConnectErr(err error) error {

	installed, msg := getMessageFromErr(err)

	configureText := `
Please configure LXD by running:
	$ newgrp lxd
	$ lxd init
`

	installText := `
Please install LXD by running:
	$ sudo apt-get install lxd
and then configure it with:
	$ newgrp lxd
	$ lxd init
`

	hint := installText
	if installed {
		hint = configureText
	}

	return errors.Trace(fmt.Errorf("%s\n%s", msg, hint))
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	sq "github.com/Masterminds/squirrel"
	"github.com/benmanns/goworker"
	_ "github.com/go-sql-driver/mysql"
	"github.com/sideshow/apns2"
	"github.com/sideshow/apns2/certificate"
	"github.com/sideshow/apns2/payload"
	"os"
)

var apnsClientProduction *apns2.Client
var apnsClientDevelopment *apns2.Client

func init() {
	goworker.Register("NotificationTweet", NotificationTweet)

	pemFile := os.Getenv("JUSTAWAY_APNS_PEM_PATH") // apns.pem

	cert, pemErr := certificate.FromPemFile(pemFile, "")
	if pemErr != nil {
		fmt.Println("Cert Error:", pemErr)
	}

	apnsClientProduction = apns2.NewClient(cert).Production()
	apnsClientDevelopment = apns2.NewClient(cert).Development()
}

func main() {
	if err := goworker.Work(); err != nil {
		fmt.Println("Error:", err)
	}
}

func NotificationTweet(queue string, args ...interface{}) error {
	userIdStr, ok := args[0].(string)
	if !ok {
		fmt.Printf("invalid data:%v\n", args)
		return nil
	}

	screenName, ok := args[1].(string)
	if !ok {
		fmt.Printf("invalid data:%v\n", args)
		return nil
	}

	event, ok := args[2].(string)
	if !ok {
		fmt.Printf("invalid data:%v\n", args)
		return nil
	}

	text, ok := args[3].(string)
	if !ok {
		fmt.Printf("invalid data:%v\n", args)
		return nil
	}

	switch event {
	case "retweet", "retweeted_retweet":
		sendNotification(userIdStr, "@"+screenName+"さんがリツイートしました\n"+text)
	case "reply":
		sendNotification(userIdStr, "@"+screenName+"さんからのリプライ\n"+text)
	case "favorite", "favorited_retweet":
		sendNotification(userIdStr, "@"+screenName+"さんがいいねしました\n"+text)
	case "quoted_tweet":
		sendNotification(userIdStr, "@"+screenName+"さんが引用しました\n"+text)
	default:
		sendNotification(userIdStr, "@"+screenName+"さんが"+event+"\n"+text)
	}

	return nil
}

func sendNotification(userIdStr string, message string) error {
	fmt.Printf("userId:%s message:%s\n", userIdStr, message)

	dbSource := os.Getenv("JUSTAWAY_EX_DB_SOURCE") // ex. justaway@tcp(192.168.0.10:3306)/justaway
	db, err := sql.Open("mysql", dbSource)
	if err != nil {
		return nil
	}

	stmt := sq.
		Select("name, token, platform").
		From("notification_device").
		Where(sq.Eq{"user_id": userIdStr}).
		OrderBy("id DESC").
		Limit(100)

	sql, args, err := stmt.ToSql()
	if err != nil {
		panic(err.Error())
	}

	rows, err := db.Query(sql, args...)
	if err != nil {
		panic(err.Error())
	}
	defer rows.Close()

	for rows.Next() {
		var name string
		var token string
		var platform string
		err = rows.Scan(&name, &token, &platform)
		if err != nil {
			fmt.Println("Error:", err)
			continue
		}
		switch platform {
		case "APNS":
			sendApnsProduction(token, message)
		case "APNS_SANDBOX":
			sendApnsDevelopment(token, message)
		}
	}

	return nil
}

func sendApnsProduction(token string, message string) {
	payload := payload.NewPayload().Alert(message)
	notification := &apns2.Notification{}
	notification.DeviceToken = token
	notification.Topic = "pw.aska.Justaway"
	notification.Payload = payload
	res, err := apnsClientProduction.Push(notification)

	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("APNs ID:", res.ApnsID)
}

func sendApnsDevelopment(token string, message string) {
	payload := payload.NewPayload().Alert(message)
	notification := &apns2.Notification{}
	notification.DeviceToken = token
	notification.Topic = "pw.aska.Justaway"
	notification.Payload = payload
	res, err := apnsClientDevelopment.Push(notification)

	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("APNs ID:", res.ApnsID)
}
<commit_msg>Refactor code<commit_after>package main

import (
	"database/sql"
	"fmt"
	sq "github.com/Masterminds/squirrel"
	"github.com/benmanns/goworker"
	_ "github.com/go-sql-driver/mysql"
	"github.com/sideshow/apns2"
	"github.com/sideshow/apns2/certificate"
	"github.com/sideshow/apns2/payload"
	"os"
)

var apnsClientProduction *apns2.Client
var apnsClientDevelopment *apns2.Client

func init() {
	goworker.Register("NotificationTweet", NotificationTweet)

	pemFile := os.Getenv("JUSTAWAY_APNS_PEM_PATH") // apns.pem

	cert, pemErr := certificate.FromPemFile(pemFile, "")
	if pemErr != nil {
		fmt.Println("Cert Error:", pemErr)
	}

	apnsClientProduction = apns2.NewClient(cert).Production()
	apnsClientDevelopment = apns2.NewClient(cert).Development()
}

func main() {
	if err := goworker.Work(); err != nil {
		fmt.Println("Error:", err)
	}
}

func NotificationTweet(queue string, args ...interface{}) error {
	userIdStr, ok := args[0].(string)
	if !ok {
		fmt.Printf("invalid data:%v\n", args)
		return nil
	}

	screenName, ok := args[1].(string)
	if !ok {
		fmt.Printf("invalid data:%v\n", args)
		return nil
	}

	event, ok := args[2].(string)
	if !ok {
		fmt.Printf("invalid data:%v\n", args)
		return nil
	}

	text, ok := args[3].(string)
	if !ok {
		fmt.Printf("invalid data:%v\n", args)
		return nil
	}

	message := makeNotificationMessage(event, screenName, text)
	if err := sendNotification(userIdStr, message); err != nil {
		fmt.Println("Error:", err)
		return nil
	}

	return nil
}

func makeNotificationMessage(event string, screenName string, text string) string {
	switch event {
	case "retweet", "retweeted_retweet":
		return "@" + screenName + "さんがリツイートしました\n" + text
	case "reply":
		return "@" + screenName + "さんからのリプライ\n" + text
	case "favorite", "favorited_retweet":
		return "@" + screenName + "さんがいいねしました\n" + text
	case "quoted_tweet":
		return "@" + screenName + "さんが引用しました\n" + text
	default:
		return "@" + screenName + "さんが" + event + "\n" + text
	}
}

func sendNotification(userIdStr string, message string) error {
	fmt.Printf("userId:%s message:%s\n", userIdStr, message)

	dbSource := os.Getenv("JUSTAWAY_EX_DB_SOURCE") // ex. justaway@tcp(192.168.0.10:3306)/justaway
	db, err := sql.Open("mysql", dbSource)
	if err != nil {
		return err
	}

	stmt := sq.
		Select("name, token, platform").
		From("notification_device").
		Where(sq.Eq{"user_id": userIdStr}).
		OrderBy("id DESC").
		Limit(100)

	sql, args, err := stmt.ToSql()
	if err != nil {
		return err
	}

	rows, err := db.Query(sql, args...)
	if err != nil {
		return err
	}
	defer rows.Close()

	for rows.Next() {
		var name string
		var token string
		var platform string

		err = rows.Scan(&name, &token, &platform)
		if err != nil {
			fmt.Println("Error:", err)
			continue
		}

		switch platform {
		case "APNS":
			sendApns(apnsClientProduction, token, message)
		case "APNS_SANDBOX":
			sendApns(apnsClientDevelopment, token, message)
		}
	}

	return nil
}

func sendApns(client *apns2.Client, token string, message string) {
	payload := payload.NewPayload().Alert(message)
	notification := &apns2.Notification{}
	notification.DeviceToken = token
	notification.Topic = "pw.aska.Justaway"
	notification.Payload = payload
	res, err := client.Push(notification)

	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println("APNs ID:", res.ApnsID)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"io/ioutil"

	"github.com/spf13/cobra"
)

// load-templateCmd represents the load-template command
var loadTemplateCmd = &cobra.Command{
	Use:   "load-template",
	Short: "Loads a template file",
	Long:  `load-template loads a template file to the cluster that can later be used for unit creation`,
	Run:   loadTemplate,
}

// TemplatepParams contains all the parameters needed to create a template
type TemplateParams struct {
	Name          string            `json:"name"`
	Ports         []int64           `json:"ports"`
	Constraints   map[string]string `json:"constraints"`
	UnitContent   string            `json:"unitContent"`
	MaxPerMachine int64             `json:"maxPerMachine"`
}

func init() {
	RootCmd.AddCommand(loadTemplateCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// load-templateCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// load-templateCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}

func loadTemplate(cmd *cobra.Command, args []string) {
	if len(args) < 2 {
		fmt.Println("Not enough arguments")
		return
	}

	fileBytes, err := ioutil.ReadFile(args[1])
	if err != nil {
		fmt.Println("Can't open file")
		return
	}

	params := TemplateParams{}
	params.Name = args[0]
	params.UnitContent = string(fileBytes)

	response := StandardResponse{}

	res, postErr := r.R().SetHeader("Content-Type", "application/json").SetBody(params).SetResult(&response).Post("/template")

	fmt.Println(string(res.Body()))

	if postErr != nil {
		fmt.Println(postErr)
		return
	}
	if response.Status == "error" {
		fmt.Println(response.Error)
		return
	}
	fmt.Println("Template has been loaded to the cluster")
}
<commit_msg>fix typo<commit_after>package cmd

import (
	"fmt"
	"io/ioutil"

	"github.com/spf13/cobra"
)

// load-templateCmd represents the load-template command
var loadTemplateCmd = &cobra.Command{
	Use:   "load-template",
	Short: "Loads a template file",
	Long:  `load-template loads a template file to the cluster that can later be used for unit creation`,
	Run:   loadTemplate,
}

// TemplateParams contains all the parameters needed to create a template
type TemplateParams struct {
	Name          string            `json:"name"`
	Ports         []int64           `json:"ports"`
	Constraints   map[string]string `json:"constraints"`
	UnitContent   string            `json:"unitContent"`
	MaxPerMachine int64             `json:"maxPerMachine"`
}

func init() {
	RootCmd.AddCommand(loadTemplateCmd)

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	// load-templateCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// load-templateCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

}

func loadTemplate(cmd *cobra.Command, args []string) {
	if len(args) < 2 {
		fmt.Println("Not enough arguments")
		return
	}

	fileBytes, err := ioutil.ReadFile(args[1])
	if err != nil {
		fmt.Println("Can't open file")
		return
	}

	params := TemplateParams{}
	params.Name = args[0]
	params.UnitContent = string(fileBytes)

	response := StandardResponse{}

	res, postErr := r.R().SetHeader("Content-Type", "application/json").SetBody(params).SetResult(&response).Post("/template")

	fmt.Println(string(res.Body()))

	if postErr != nil {
		fmt.Println(postErr)
		return
	}
	if response.Status == "error" {
		fmt.Println(response.Error)
		return
	}
	fmt.Println("Template has been loaded to the cluster")
}
<|endoftext|>


<commit_before>package mssql

import (
    "testing"
    "time"
    "bytes"
    "database/sql"
    "strings"
    "fmt"
)

func TestSelect(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    type testStruct struct {
        sql string
        val interface{}
    }

    longstr := strings.Repeat("x", 10000)

    values := []testStruct{
        {"1", int32(1)},
        {"cast(1 as tinyint)", uint8(1)},
        {"cast(1 as smallint)", int16(1)},
        {"cast(1 as bigint)", int64(1)},
        {"cast(1 as bit)", true},
        {"cast(0 as bit)", false},
        {"'abc'", string("abc")},
        {"cast(0.5 as float)", float64(0.5)},
        {"cast(0.5 as real)", float32(0.5)},
        {"cast(1 as decimal)", Decimal{[...]uint32{1, 0, 0, 0}, true, 18, 0}},
        {"cast(0.5 as decimal(18,1))", Decimal{[...]uint32{5, 0, 0, 0}, true, 18, 1}},
        {"cast(-0.5 as decimal(18,1))", Decimal{[...]uint32{5, 0, 0, 0}, false, 18, 1}},
        {"cast(-0.5 as numeric(18,1))", Decimal{[...]uint32{5, 0, 0, 0}, false, 18, 1}},
        {"N'abc'", string("abc")},
        {"cast(null as nvarchar(3))", nil},
        {"NULL", nil},
        {"cast('2000-01-01' as datetime)", time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)},
        {"cast('2000-01-01T12:13:14.12' as datetime)",
         time.Date(2000, 1, 1, 12, 13, 14, 120000000, time.UTC)},
        {"cast(NULL as datetime)", nil},
        {"cast('2000-01-01T12:13:00' as smalldatetime)",
         time.Date(2000, 1, 1, 12, 13, 0, 0, time.UTC)},
        {"cast('2000-01-01' as date)",
         time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)},
        {"cast(NULL as date)", nil},
        {"cast(0x6F9619FF8B86D011B42D00C04FC964FF as uniqueidentifier)",
         [...]byte{0x6F, 0x96, 0x19, 0xFF, 0x8B, 0x86, 0xD0, 0x11, 0xB4, 0x2D, 0x00, 0xC0, 0x4F, 0xC9, 0x64, 0xFF}},
        {"cast(NULL as uniqueidentifier)", nil},
        {"cast('00:00:45.123' as time(3))",
         time.Date(1, 1, 1, 00, 00, 45, 123000000, time.UTC) },
        {"cast('11:56:45.123' as time(3))",
         time.Date(1, 1, 1, 11, 56, 45, 123000000, time.UTC) },
        {"cast('2010-11-15T11:56:45.123' as datetime2(3))",
         time.Date(2010, 11, 15, 11, 56, 45, 123000000, time.UTC) },
        //{"cast('2010-11-15T11:56:45.123+10:00' as datetimeoffset(3))",
        // time.Date(2010, 11, 15, 11, 56, 45, 123000000, time.FixedZone("", 10*60*60)) },
        {"cast(0x1234 as varbinary(2))", []byte{0x12, 0x34}},
        {"cast(N'abc' as nvarchar(max))", "abc"},
        {"cast(null as nvarchar(max))", nil},
        {"cast('<root/>' as xml)", "<root/>"},
        {"cast('abc' as text)", "abc"},
        {"cast(null as text)", nil},
        {"cast(N'abc' as ntext)", "abc"},
        {"cast(0x1234 as image)", []byte{0x12, 0x34}},
        {"cast(N'проверка' as nvarchar(max))", "проверка"},
        {fmt.Sprintf("cast(N'%s' as nvarchar(max))", longstr), longstr},
    }

    for _, test := range values {
        stmt, err := conn.Prepare("select " + test.sql)
        if err != nil {
            t.Error("Prepare failed:", test.sql, err.Error())
            return
        }
        defer stmt.Close()

        row := stmt.QueryRow()
        var retval interface{}
        err = row.Scan(&retval)
        if err != nil {
            t.Error("Scan failed:", test.sql, err.Error())
            return
        }
        var same bool
        switch decodedval := retval.(type) {
        case []byte:
            switch decodedvaltest := test.val.(type) {
            case []byte:
                same = bytes.Equal(decodedval, decodedvaltest)
            default:
                same = false
            }
        default:
            same = retval == test.val
        }
        if !same {
            t.Error("Values don't match", test.sql, retval, test.val)
            return
        }
    }
}

func TestTrans(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    var tx *sql.Tx
    var err error
    if tx, err = conn.Begin(); err != nil {
        t.Fatal("Begin failed", err.Error())
    }
    if err = tx.Commit(); err != nil {
        t.Fatal("Commit failed", err.Error())
    }

    if tx, err = conn.Begin(); err != nil {
        t.Fatal("Begin failed", err.Error())
    }
    if _, err = tx.Exec("create table ##abc (fld int)"); err != nil {
        t.Fatal("Create table failed", err.Error())
    }
    if err = tx.Rollback(); err != nil {
        t.Fatal("Rollback failed", err.Error())
    }
}

func TestParams(t *testing.T) {
    longstr := strings.Repeat("x", 10000)
    values := []interface{}{
        int64(5),
        "hello",
        []byte{1,2,3},
        //float32(1.2),
        float64(1.12313554),
        true,
        false,
        nil,
        longstr,
    }

    conn := open(t)
    defer conn.Close()

    for _, val := range values {
        row := conn.QueryRow("select @p1", val)
        var retval interface{}
        err := row.Scan(&retval)
        if err != nil {
            t.Error("Scan failed", err.Error())
            return
        }
        var same bool
        switch decodedval := retval.(type) {
        case []byte:
            switch decodedvaltest := val.(type) {
            case []byte:
                same = bytes.Equal(decodedval, decodedvaltest)
            default:
                same = false
            }
        default:
            same = retval == val
        }
        if !same {
            t.Error("Value don't match", retval, val)
            return
        }
    }
}

func TestExec(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    res, err := conn.Exec("create table ##abc (fld int)")
    if err != nil {
        t.Fatal("Exec failed", err.Error())
    }
    _ = res
}

func TestTimeout(t *testing.T) {
    if testing.Short() {
        return
    }
    conn := open(t)
    defer conn.Close()

    res, err := conn.Exec("waitfor delay '00:31'")
    if err == nil {
        t.Fatal("Exec should fail with timeout")
    }
    if neterr, ok := err.(Error); !ok || !neterr.Timeout() {
        t.Fatal("Exec should fail with timeout, failed with", err)
    }
    _ = res
}

func TestTwoQueries(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    rows, err := conn.Query("select 1")
    if err != nil {
        t.Fatal("First exec failed", err)
    }
    if !rows.Next() {
        t.Fatal("First query didn't return row")
    }
    var i int
    if err = rows.Scan(&i); err != nil {
        t.Fatal("Scan failed", err)
    }
    if i != 1 {
        t.Fatalf("Wrong value returned %d, should be 1", i)
    }

    if rows, err = conn.Query("select 2"); err != nil {
        t.Fatal("Second query failed", err)
    }
    if !rows.Next() {
        t.Fatal("Second query didn't return row")
    }
    if err = rows.Scan(&i); err != nil {
        t.Fatal("Scan failed", err)
    }
    if i != 2 {
        t.Fatalf("Wrong value returned %d, should be 2", i)
    }
}

func TestError(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    _, err := conn.Query("exec bad")
    if err == nil {
        t.Fatal("Query should fail")
    }

    if err, ok := err.(Error); !ok {
        t.Fatalf("Should be sql error, actually %t, %v", err, err)
    } else {
        if err.Number != 2812 { // Could not find stored procedure 'bad'
            t.Fatalf("Should be specific error code 2812, actually %d %s", err.Number, err)
        }
    }
}

func TestQueryNoRows(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    var rows *sql.Rows
    var err error
    if rows, err = conn.Query("create table ##abc (fld int)"); err != nil {
        t.Fatal("Query failed", err)
    }
    if rows.Next() {
        t.Fatal("Query shoulnd't return any rows")
    }
}

func TestQueryManyNullsRow(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    var row *sql.Row
    var err error
    if row = conn.QueryRow("select null, null, null, null, null, null, null, null"); err != nil {
        t.Fatal("Query failed", err)
    }
    var v [8]sql.NullInt64
    if err = row.Scan(&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7]); err != nil {
        t.Fatal("Scan failed", err)
    }
}
<commit_msg>test long bytes<commit_after>package mssql

import (
    "testing"
    "time"
    "bytes"
    "database/sql"
    "strings"
    "fmt"
)

func TestSelect(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    type testStruct struct {
        sql string
        val interface{}
    }

    longstr := strings.Repeat("x", 10000)

    values := []testStruct{
        {"1", int32(1)},
        {"cast(1 as tinyint)", uint8(1)},
        {"cast(1 as smallint)", int16(1)},
        {"cast(1 as bigint)", int64(1)},
        {"cast(1 as bit)", true},
        {"cast(0 as bit)", false},
        {"'abc'", string("abc")},
        {"cast(0.5 as float)", float64(0.5)},
        {"cast(0.5 as real)", float32(0.5)},
        {"cast(1 as decimal)", Decimal{[...]uint32{1, 0, 0, 0}, true, 18, 0}},
        {"cast(0.5 as decimal(18,1))", Decimal{[...]uint32{5, 0, 0, 0}, true, 18, 1}},
        {"cast(-0.5 as decimal(18,1))", Decimal{[...]uint32{5, 0, 0, 0}, false, 18, 1}},
        {"cast(-0.5 as numeric(18,1))", Decimal{[...]uint32{5, 0, 0, 0}, false, 18, 1}},
        {"N'abc'", string("abc")},
        {"cast(null as nvarchar(3))", nil},
        {"NULL", nil},
        {"cast('2000-01-01' as datetime)", time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)},
        {"cast('2000-01-01T12:13:14.12' as datetime)",
         time.Date(2000, 1, 1, 12, 13, 14, 120000000, time.UTC)},
        {"cast(NULL as datetime)", nil},
        {"cast('2000-01-01T12:13:00' as smalldatetime)",
         time.Date(2000, 1, 1, 12, 13, 0, 0, time.UTC)},
        {"cast('2000-01-01' as date)",
         time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)},
        {"cast(NULL as date)", nil},
        {"cast(0x6F9619FF8B86D011B42D00C04FC964FF as uniqueidentifier)",
         [...]byte{0x6F, 0x96, 0x19, 0xFF, 0x8B, 0x86, 0xD0, 0x11, 0xB4, 0x2D, 0x00, 0xC0, 0x4F, 0xC9, 0x64, 0xFF}},
        {"cast(NULL as uniqueidentifier)", nil},
        {"cast('00:00:45.123' as time(3))",
         time.Date(1, 1, 1, 00, 00, 45, 123000000, time.UTC) },
        {"cast('11:56:45.123' as time(3))",
         time.Date(1, 1, 1, 11, 56, 45, 123000000, time.UTC) },
        {"cast('2010-11-15T11:56:45.123' as datetime2(3))",
         time.Date(2010, 11, 15, 11, 56, 45, 123000000, time.UTC) },
        //{"cast('2010-11-15T11:56:45.123+10:00' as datetimeoffset(3))",
        // time.Date(2010, 11, 15, 11, 56, 45, 123000000, time.FixedZone("", 10*60*60)) },
        {"cast(0x1234 as varbinary(2))", []byte{0x12, 0x34}},
        {"cast(N'abc' as nvarchar(max))", "abc"},
        {"cast(null as nvarchar(max))", nil},
        {"cast('<root/>' as xml)", "<root/>"},
        {"cast('abc' as text)", "abc"},
        {"cast(null as text)", nil},
        {"cast(N'abc' as ntext)", "abc"},
        {"cast(0x1234 as image)", []byte{0x12, 0x34}},
        {"cast(N'проверка' as nvarchar(max))", "проверка"},
        {fmt.Sprintf("cast(N'%s' as nvarchar(max))", longstr), longstr},
    }

    for _, test := range values {
        stmt, err := conn.Prepare("select " + test.sql)
        if err != nil {
            t.Error("Prepare failed:", test.sql, err.Error())
            return
        }
        defer stmt.Close()

        row := stmt.QueryRow()
        var retval interface{}
        err = row.Scan(&retval)
        if err != nil {
            t.Error("Scan failed:", test.sql, err.Error())
            return
        }
        var same bool
        switch decodedval := retval.(type) {
        case []byte:
            switch decodedvaltest := test.val.(type) {
            case []byte:
                same = bytes.Equal(decodedval, decodedvaltest)
            default:
                same = false
            }
        default:
            same = retval == test.val
        }
        if !same {
            t.Error("Values don't match", test.sql, retval, test.val)
            return
        }
    }
}

func TestTrans(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    var tx *sql.Tx
    var err error
    if tx, err = conn.Begin(); err != nil {
        t.Fatal("Begin failed", err.Error())
    }
    if err = tx.Commit(); err != nil {
        t.Fatal("Commit failed", err.Error())
    }

    if tx, err = conn.Begin(); err != nil {
        t.Fatal("Begin failed", err.Error())
    }
    if _, err = tx.Exec("create table ##abc (fld int)"); err != nil {
        t.Fatal("Create table failed", err.Error())
    }
    if err = tx.Rollback(); err != nil {
        t.Fatal("Rollback failed", err.Error())
    }
}

func TestParams(t *testing.T) {
    longstr := strings.Repeat("x", 10000)
    longbytes := make([]byte, 10000)
    values := []interface{}{
        int64(5),
        "hello",
        []byte{1,2,3},
        //float32(1.2),
        float64(1.12313554),
        true,
        false,
        nil,
        longstr,
        longbytes,
    }

    conn := open(t)
    defer conn.Close()

    for _, val := range values {
        row := conn.QueryRow("select @p1", val)
        var retval interface{}
        err := row.Scan(&retval)
        if err != nil {
            t.Error("Scan failed", err.Error())
            return
        }
        var same bool
        switch decodedval := retval.(type) {
        case []byte:
            switch decodedvaltest := val.(type) {
            case []byte:
                same = bytes.Equal(decodedval, decodedvaltest)
            default:
                same = false
            }
        default:
            same = retval == val
        }
        if !same {
            t.Error("Value don't match", retval, val)
            return
        }
    }
}

func TestExec(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    res, err := conn.Exec("create table ##abc (fld int)")
    if err != nil {
        t.Fatal("Exec failed", err.Error())
    }
    _ = res
}

func TestTimeout(t *testing.T) {
    if testing.Short() {
        return
    }
    conn := open(t)
    defer conn.Close()

    res, err := conn.Exec("waitfor delay '00:31'")
    if err == nil {
        t.Fatal("Exec should fail with timeout")
    }
    if neterr, ok := err.(Error); !ok || !neterr.Timeout() {
        t.Fatal("Exec should fail with timeout, failed with", err)
    }
    _ = res
}

func TestTwoQueries(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    rows, err := conn.Query("select 1")
    if err != nil {
        t.Fatal("First exec failed", err)
    }
    if !rows.Next() {
        t.Fatal("First query didn't return row")
    }
    var i int
    if err = rows.Scan(&i); err != nil {
        t.Fatal("Scan failed", err)
    }
    if i != 1 {
        t.Fatalf("Wrong value returned %d, should be 1", i)
    }

    if rows, err = conn.Query("select 2"); err != nil {
        t.Fatal("Second query failed", err)
    }
    if !rows.Next() {
        t.Fatal("Second query didn't return row")
    }
    if err = rows.Scan(&i); err != nil {
        t.Fatal("Scan failed", err)
    }
    if i != 2 {
        t.Fatalf("Wrong value returned %d, should be 2", i)
    }
}

func TestError(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    _, err := conn.Query("exec bad")
    if err == nil {
        t.Fatal("Query should fail")
    }

    if err, ok := err.(Error); !ok {
        t.Fatalf("Should be sql error, actually %t, %v", err, err)
    } else {
        if err.Number != 2812 { // Could not find stored procedure 'bad'
            t.Fatalf("Should be specific error code 2812, actually %d %s", err.Number, err)
        }
    }
}

func TestQueryNoRows(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    var rows *sql.Rows
    var err error
    if rows, err = conn.Query("create table ##abc (fld int)"); err != nil {
        t.Fatal("Query failed", err)
    }
    if rows.Next() {
        t.Fatal("Query shoulnd't return any rows")
    }
}

func TestQueryManyNullsRow(t *testing.T) {
    conn := open(t)
    defer conn.Close()

    var row *sql.Row
    var err error
    if row = conn.QueryRow("select null, null, null, null, null, null, null, null"); err != nil {
        t.Fatal("Query failed", err)
    }
    var v [8]sql.NullInt64
    if err = row.Scan(&v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7]); err != nil {
        t.Fatal("Scan failed", err)
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"context"
	"fmt"
	"net/url"
	"strings"

	"gopkg.in/olivere/elastic.v5/uritemplates"
)

// ClusterStatsService is documented at
// https://www.elastic.co/guide/en/elasticsearch/reference/5.2/cluster-stats.html.
type ClusterStatsService struct {
	client       *Client
	pretty       bool
	nodeId       []string
	flatSettings *bool
	human        *bool
}

// NewClusterStatsService creates a new ClusterStatsService.
func NewClusterStatsService(client *Client) *ClusterStatsService {
	return &ClusterStatsService{
		client: client,
		nodeId: make([]string, 0),
	}
}

// NodeId is documented as: A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes.
func (s *ClusterStatsService) NodeId(nodeId []string) *ClusterStatsService {
	s.nodeId = nodeId
	return s
}

// FlatSettings is documented as: Return settings in flat format (default: false).
func (s *ClusterStatsService) FlatSettings(flatSettings bool) *ClusterStatsService {
	s.flatSettings = &flatSettings
	return s
}

// Human is documented as: Whether to return time and byte values in human-readable format..
func (s *ClusterStatsService) Human(human bool) *ClusterStatsService {
	s.human = &human
	return s
}

// Pretty indicates that the JSON response be indented and human readable.
func (s *ClusterStatsService) Pretty(pretty bool) *ClusterStatsService {
	s.pretty = pretty
	return s
}

// buildURL builds the URL for the operation.
func (s *ClusterStatsService) buildURL() (string, url.Values, error) {
	// Build URL
	var err error
	var path string

	if len(s.nodeId) > 0 {
		path, err = uritemplates.Expand("/_cluster/stats/nodes/{node_id}", map[string]string{
			"node_id": strings.Join(s.nodeId, ","),
		})
		if err != nil {
			return "", url.Values{}, err
		}
	} else {
		path, err = uritemplates.Expand("/_cluster/stats", map[string]string{})
		if err != nil {
			return "", url.Values{}, err
		}
	}

	// Add query string parameters
	params := url.Values{}
	if s.pretty {
		params.Set("pretty", "1")
	}
	if s.flatSettings != nil {
		params.Set("flat_settings", fmt.Sprintf("%v", *s.flatSettings))
	}
	if s.human != nil {
		params.Set("human", fmt.Sprintf("%v", *s.human))
	}
	return path, params, nil
}

// Validate checks if the operation is valid.
func (s *ClusterStatsService) Validate() error {
	return nil
}

// Do executes the operation.
func (s *ClusterStatsService) Do(ctx context.Context) (*ClusterStatsResponse, error) {
	// Check pre-conditions
	if err := s.Validate(); err != nil {
		return nil, err
	}

	// Get URL for request
	path, params, err := s.buildURL()
	if err != nil {
		return nil, err
	}

	// Get HTTP response
	res, err := s.client.PerformRequest(ctx, "GET", path, params, nil)
	if err != nil {
		return nil, err
	}

	// Return operation response
	ret := new(ClusterStatsResponse)
	if err := s.client.decoder.Decode(res.Body, ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// ClusterStatsResponse is the response of ClusterStatsService.Do.
type ClusterStatsResponse struct {
	Timestamp   int64                `json:"timestamp"`
	ClusterName string               `json:"cluster_name"`
	ClusterUUID string               `json:"uuid"`
	Status      string               `json:"status"`
	Indices     *ClusterStatsIndices `json:"indices"`
	Nodes       *ClusterStatsNodes   `json:"nodes"`
}

type ClusterStatsIndices struct {
	Count       int                             `json:"count"`
	Shards      *ClusterStatsIndicesShards      `json:"shards"`
	Docs        *ClusterStatsIndicesDocs        `json:"docs"`
	Store       *ClusterStatsIndicesStore       `json:"store"`
	FieldData   *ClusterStatsIndicesFieldData   `json:"fielddata"`
	FilterCache *ClusterStatsIndicesFilterCache `json:"filter_cache"`
	IdCache     *ClusterStatsIndicesIdCache     `json:"id_cache"`
	Completion  *ClusterStatsIndicesCompletion  `json:"completion"`
	Segments    *ClusterStatsIndicesSegments    `json:"segments"`
	Percolate   *ClusterStatsIndicesPercolate   `json:"percolate"`
}

type ClusterStatsIndicesShards struct {
	Total       int                             `json:"total"`
	Primaries   int                             `json:"primaries"`
	Replication float64                         `json:"replication"`
	Index       *ClusterStatsIndicesShardsIndex `json:"index"`
}

type ClusterStatsIndicesShardsIndex struct {
	Shards      *ClusterStatsIndicesShardsIndexIntMinMax     `json:"shards"`
	Primaries   *ClusterStatsIndicesShardsIndexIntMinMax     `json:"primaries"`
	Replication *ClusterStatsIndicesShardsIndexFloat64MinMax `json:"replication"`
}

type ClusterStatsIndicesShardsIndexIntMinMax struct {
	Min int     `json:"min"`
	Max int     `json:"max"`
	Avg float64 `json:"avg"`
}

type ClusterStatsIndicesShardsIndexFloat64MinMax struct {
	Min float64 `json:"min"`
	Max float64 `json:"max"`
	Avg float64 `json:"avg"`
}

type ClusterStatsIndicesDocs struct {
	Count   int `json:"count"`
	Deleted int `json:"deleted"`
}

type ClusterStatsIndicesStore struct {
	Size                 string `json:"size"` // e.g. "5.3gb"
	SizeInBytes          int64  `json:"size_in_bytes"`
	ThrottleTime         string `json:"throttle_time"` // e.g. "0s"
	ThrottleTimeInMillis int64  `json:"throttle_time_in_millis"`
}

type ClusterStatsIndicesFieldData struct {
	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
	MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
	Evictions         int64  `json:"evictions"`
	Fields map[string]struct {
		MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
		MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
	} `json:"fields"`
}

type ClusterStatsIndicesFilterCache struct {
	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
	MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
	Evictions         int64  `json:"evictions"`
}

type ClusterStatsIndicesIdCache struct {
	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
	MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
}

type ClusterStatsIndicesCompletion struct {
	Size        string `json:"size"` // e.g. "61.3kb"
	SizeInBytes int64  `json:"size_in_bytes"`
	Fields map[string]struct {
		Size        string `json:"size"` // e.g. "61.3kb"
		SizeInBytes int64  `json:"size_in_bytes"`
	} `json:"fields"`
}

type ClusterStatsIndicesSegments struct {
	Count                       int64  `json:"count"`
	Memory                      string `json:"memory"` // e.g. "61.3kb"
	MemoryInBytes               int64  `json:"memory_in_bytes"`
	IndexWriterMemory           string `json:"index_writer_memory"` // e.g. "61.3kb"
	IndexWriterMemoryInBytes    int64  `json:"index_writer_memory_in_bytes"`
	IndexWriterMaxMemory        string `json:"index_writer_max_memory"` // e.g. "61.3kb"
	IndexWriterMaxMemoryInBytes int64  `json:"index_writer_max_memory_in_bytes"`
	VersionMapMemory            string `json:"version_map_memory"` // e.g. "61.3kb"
	VersionMapMemoryInBytes     int64  `json:"version_map_memory_in_bytes"`
	FixedBitSet                 string `json:"fixed_bit_set"` // e.g. "61.3kb"
	FixedBitSetInBytes          int64  `json:"fixed_bit_set_memory_in_bytes"`
}

type ClusterStatsIndicesPercolate struct {
	Total int64 `json:"total"`
	// TODO(oe) The JSON tag here is wrong as of ES 1.5.2 it seems
	Time              string `json:"get_time"` // e.g. "1s"
	TimeInBytes       int64  `json:"time_in_millis"`
	Current           int64  `json:"current"`
	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
	MemorySizeInBytes int64  `json:"memory_sitze_in_bytes"`
	Queries           int64  `json:"queries"`
}

// ---

type ClusterStatsNodes struct {
	Count    *ClusterStatsNodesCount        `json:"count"`
	Versions []string                       `json:"versions"`
	OS       *ClusterStatsNodesOsStats      `json:"os"`
	Process  *ClusterStatsNodesProcessStats `json:"process"`
	JVM      *ClusterStatsNodesJvmStats     `json:"jvm"`
	FS       *ClusterStatsNodesFsStats      `json:"fs"`
	Plugins  []*ClusterStatsNodesPlugin     `json:"plugins"`
}

type ClusterStatsNodesCount struct {
	Total            int `json:"total"`
	Data             int `json:"data"`
	CoordinatingOnly int `json:"coordinating_only"`
	Master           int `json:"master"`
	Ingest           int `json:"ingest"`
}

type ClusterStatsNodesOsStats struct {
	AvailableProcessors int                            `json:"available_processors"`
	Mem                 *ClusterStatsNodesOsStatsMem   `json:"mem"`
	CPU                 []*ClusterStatsNodesOsStatsCPU `json:"cpu"`
}

type ClusterStatsNodesOsStatsMem struct {
	Total        string `json:"total"` // e.g. "16gb"
	TotalInBytes int64  `json:"total_in_bytes"`
}

type ClusterStatsNodesOsStatsCPU struct {
	Vendor           string `json:"vendor"`
	Model            string `json:"model"`
	MHz              int    `json:"mhz"`
	TotalCores       int    `json:"total_cores"`
	TotalSockets     int    `json:"total_sockets"`
	CoresPerSocket   int    `json:"cores_per_socket"`
	CacheSize        string `json:"cache_size"` // e.g. "256b"
	CacheSizeInBytes int64  `json:"cache_size_in_bytes"`
	Count            int    `json:"count"`
}

type ClusterStatsNodesProcessStats struct {
	CPU                 *ClusterStatsNodesProcessStatsCPU                 `json:"cpu"`
	OpenFileDescriptors *ClusterStatsNodesProcessStatsOpenFileDescriptors `json:"open_file_descriptors"`
}

type ClusterStatsNodesProcessStatsCPU struct {
	Percent float64 `json:"percent"`
}

type ClusterStatsNodesProcessStatsOpenFileDescriptors struct {
	Min int64 `json:"min"`
	Max int64 `json:"max"`
	Avg int64 `json:"avg"`
}

type ClusterStatsNodesJvmStats struct {
	MaxUptime         string                              `json:"max_uptime"` // e.g. "5h"
	MaxUptimeInMillis int64                               `json:"max_uptime_in_millis"`
	Versions          []*ClusterStatsNodesJvmStatsVersion `json:"versions"`
	Mem               *ClusterStatsNodesJvmStatsMem       `json:"mem"`
	Threads           int64                               `json:"threads"`
}

type ClusterStatsNodesJvmStatsVersion struct {
	Version   string `json:"version"`    // e.g. "1.8.0_45"
	VMName    string `json:"vm_name"`    // e.g. "Java HotSpot(TM) 64-Bit Server VM"
	VMVersion string `json:"vm_version"` // e.g. "25.45-b02"
	VMVendor  string `json:"vm_vendor"`  // e.g. "Oracle Corporation"
	Count     int    `json:"count"`
}

type ClusterStatsNodesJvmStatsMem struct {
	HeapUsed        string `json:"heap_used"`
	HeapUsedInBytes int64  `json:"heap_used_in_bytes"`
	HeapMax         string `json:"heap_max"`
	HeapMaxInBytes  int64  `json:"heap_max_in_bytes"`
}

type ClusterStatsNodesFsStats struct {
	Path                 string `json:"path"`
	Mount                string `json:"mount"`
	Dev                  string `json:"dev"`
	Total                string `json:"total"` // e.g. "930.7gb"`
	TotalInBytes         int64  `json:"total_in_bytes"`
	Free                 string `json:"free"` // e.g. "930.7gb"`
	FreeInBytes          int64  `json:"free_in_bytes"`
	Available            string `json:"available"` // e.g. "930.7gb"`
	AvailableInBytes     int64  `json:"available_in_bytes"`
	DiskReads            int64  `json:"disk_reads"`
	DiskWrites           int64  `json:"disk_writes"`
	DiskIOOp             int64  `json:"disk_io_op"`
	DiskReadSize         string `json:"disk_read_size"` // e.g. "0b"`
	DiskReadSizeInBytes  int64  `json:"disk_read_size_in_bytes"`
	DiskWriteSize        string `json:"disk_write_size"` // e.g. "0b"`
	DiskWriteSizeInBytes int64  `json:"disk_write_size_in_bytes"`
	DiskIOSize           string `json:"disk_io_size"` // e.g. "0b"`
	DiskIOSizeInBytes    int64  `json:"disk_io_size_in_bytes"`
	DiskQueue            string `json:"disk_queue"`
	DiskServiceTime      string `json:"disk_service_time"`
}

type ClusterStatsNodesPlugin struct {
	Name        string `json:"name"`
	Version     string `json:"version"`
	Description string `json:"description"`
	URL         string `json:"url"`
	JVM         bool   `json:"jvm"`
	Site        bool   `json:"site"`
}
<commit_msg>Fix formatting<commit_after>// Copyright 2012-present Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"context"
	"fmt"
	"net/url"
	"strings"

	"gopkg.in/olivere/elastic.v5/uritemplates"
)

// ClusterStatsService is documented at
// https://www.elastic.co/guide/en/elasticsearch/reference/5.2/cluster-stats.html.
type ClusterStatsService struct {
	client       *Client
	pretty       bool
	nodeId       []string
	flatSettings *bool
	human        *bool
}

// NewClusterStatsService creates a new ClusterStatsService.
func NewClusterStatsService(client *Client) *ClusterStatsService {
	return &ClusterStatsService{
		client: client,
		nodeId: make([]string, 0),
	}
}

// NodeId is documented as: A comma-separated list of node IDs or names to limit the returned information; use `_local` to return information from the node you're connecting to, leave empty to get information from all nodes.
func (s *ClusterStatsService) NodeId(nodeId []string) *ClusterStatsService {
	s.nodeId = nodeId
	return s
}

// FlatSettings is documented as: Return settings in flat format (default: false).
func (s *ClusterStatsService) FlatSettings(flatSettings bool) *ClusterStatsService {
	s.flatSettings = &flatSettings
	return s
}

// Human is documented as: Whether to return time and byte values in human-readable format..
func (s *ClusterStatsService) Human(human bool) *ClusterStatsService {
	s.human = &human
	return s
}

// Pretty indicates that the JSON response be indented and human readable.
func (s *ClusterStatsService) Pretty(pretty bool) *ClusterStatsService {
	s.pretty = pretty
	return s
}

// buildURL builds the URL for the operation.
func (s *ClusterStatsService) buildURL() (string, url.Values, error) {
	// Build URL
	var err error
	var path string

	if len(s.nodeId) > 0 {
		path, err = uritemplates.Expand("/_cluster/stats/nodes/{node_id}", map[string]string{
			"node_id": strings.Join(s.nodeId, ","),
		})
		if err != nil {
			return "", url.Values{}, err
		}
	} else {
		path, err = uritemplates.Expand("/_cluster/stats", map[string]string{})
		if err != nil {
			return "", url.Values{}, err
		}
	}

	// Add query string parameters
	params := url.Values{}
	if s.pretty {
		params.Set("pretty", "1")
	}
	if s.flatSettings != nil {
		params.Set("flat_settings", fmt.Sprintf("%v", *s.flatSettings))
	}
	if s.human != nil {
		params.Set("human", fmt.Sprintf("%v", *s.human))
	}
	return path, params, nil
}

// Validate checks if the operation is valid.
func (s *ClusterStatsService) Validate() error {
	return nil
}

// Do executes the operation.
func (s *ClusterStatsService) Do(ctx context.Context) (*ClusterStatsResponse, error) {
	// Check pre-conditions
	if err := s.Validate(); err != nil {
		return nil, err
	}

	// Get URL for request
	path, params, err := s.buildURL()
	if err != nil {
		return nil, err
	}

	// Get HTTP response
	res, err := s.client.PerformRequest(ctx, "GET", path, params, nil)
	if err != nil {
		return nil, err
	}

	// Return operation response
	ret := new(ClusterStatsResponse)
	if err := s.client.decoder.Decode(res.Body, ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// ClusterStatsResponse is the response of ClusterStatsService.Do.
type ClusterStatsResponse struct {
	Timestamp   int64                `json:"timestamp"`
	ClusterName string               `json:"cluster_name"`
	ClusterUUID string               `json:"uuid"`
	Status      string               `json:"status"`
	Indices     *ClusterStatsIndices `json:"indices"`
	Nodes       *ClusterStatsNodes   `json:"nodes"`
}

type ClusterStatsIndices struct {
	Count       int                             `json:"count"`
	Shards      *ClusterStatsIndicesShards      `json:"shards"`
	Docs        *ClusterStatsIndicesDocs        `json:"docs"`
	Store       *ClusterStatsIndicesStore       `json:"store"`
	FieldData   *ClusterStatsIndicesFieldData   `json:"fielddata"`
	FilterCache *ClusterStatsIndicesFilterCache `json:"filter_cache"`
	IdCache     *ClusterStatsIndicesIdCache     `json:"id_cache"`
	Completion  *ClusterStatsIndicesCompletion  `json:"completion"`
	Segments    *ClusterStatsIndicesSegments    `json:"segments"`
	Percolate   *ClusterStatsIndicesPercolate   `json:"percolate"`
}

type ClusterStatsIndicesShards struct {
	Total       int                             `json:"total"`
	Primaries   int                             `json:"primaries"`
	Replication float64                         `json:"replication"`
	Index       *ClusterStatsIndicesShardsIndex `json:"index"`
}

type ClusterStatsIndicesShardsIndex struct {
	Shards      *ClusterStatsIndicesShardsIndexIntMinMax     `json:"shards"`
	Primaries   *ClusterStatsIndicesShardsIndexIntMinMax     `json:"primaries"`
	Replication *ClusterStatsIndicesShardsIndexFloat64MinMax `json:"replication"`
}

type ClusterStatsIndicesShardsIndexIntMinMax struct {
	Min int     `json:"min"`
	Max int     `json:"max"`
	Avg float64 `json:"avg"`
}

type ClusterStatsIndicesShardsIndexFloat64MinMax struct {
	Min float64 `json:"min"`
	Max float64 `json:"max"`
	Avg float64 `json:"avg"`
}

type ClusterStatsIndicesDocs struct {
	Count   int `json:"count"`
	Deleted int `json:"deleted"`
}

type ClusterStatsIndicesStore struct {
	Size                 string `json:"size"` // e.g. "5.3gb"
	SizeInBytes          int64  `json:"size_in_bytes"`
	ThrottleTime         string `json:"throttle_time"` // e.g. "0s"
	ThrottleTimeInMillis int64  `json:"throttle_time_in_millis"`
}

type ClusterStatsIndicesFieldData struct {
	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
	MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
	Evictions         int64  `json:"evictions"`
	Fields            map[string]struct {
		MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
		MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
	} `json:"fields"`
}

type ClusterStatsIndicesFilterCache struct {
	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
	MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
	Evictions         int64  `json:"evictions"`
}

type ClusterStatsIndicesIdCache struct {
	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
	MemorySizeInBytes int64  `json:"memory_size_in_bytes"`
}

type ClusterStatsIndicesCompletion struct {
	Size        string `json:"size"` // e.g. "61.3kb"
	SizeInBytes int64  `json:"size_in_bytes"`
	Fields      map[string]struct {
		Size        string `json:"size"` // e.g. "61.3kb"
		SizeInBytes int64  `json:"size_in_bytes"`
	} `json:"fields"`
}

type ClusterStatsIndicesSegments struct {
	Count                       int64  `json:"count"`
	Memory                      string `json:"memory"` // e.g. "61.3kb"
	MemoryInBytes               int64  `json:"memory_in_bytes"`
	IndexWriterMemory           string `json:"index_writer_memory"` // e.g. "61.3kb"
	IndexWriterMemoryInBytes    int64  `json:"index_writer_memory_in_bytes"`
	IndexWriterMaxMemory        string `json:"index_writer_max_memory"` // e.g. "61.3kb"
	IndexWriterMaxMemoryInBytes int64  `json:"index_writer_max_memory_in_bytes"`
	VersionMapMemory            string `json:"version_map_memory"` // e.g. "61.3kb"
	VersionMapMemoryInBytes     int64  `json:"version_map_memory_in_bytes"`
	FixedBitSet                 string `json:"fixed_bit_set"` // e.g. "61.3kb"
	FixedBitSetInBytes          int64  `json:"fixed_bit_set_memory_in_bytes"`
}

type ClusterStatsIndicesPercolate struct {
	Total int64 `json:"total"`
	// TODO(oe) The JSON tag here is wrong as of ES 1.5.2 it seems
	Time              string `json:"get_time"` // e.g. "1s"
	TimeInBytes       int64  `json:"time_in_millis"`
	Current           int64  `json:"current"`
	MemorySize        string `json:"memory_size"` // e.g. "61.3kb"
	MemorySizeInBytes int64  `json:"memory_sitze_in_bytes"`
	Queries           int64  `json:"queries"`
}

// ---

type ClusterStatsNodes struct {
	Count    *ClusterStatsNodesCount        `json:"count"`
	Versions []string                       `json:"versions"`
	OS       *ClusterStatsNodesOsStats      `json:"os"`
	Process  *ClusterStatsNodesProcessStats `json:"process"`
	JVM      *ClusterStatsNodesJvmStats     `json:"jvm"`
	FS       *ClusterStatsNodesFsStats      `json:"fs"`
	Plugins  []*ClusterStatsNodesPlugin     `json:"plugins"`
}

type ClusterStatsNodesCount struct {
	Total            int `json:"total"`
	Data             int `json:"data"`
	CoordinatingOnly int `json:"coordinating_only"`
	Master           int `json:"master"`
	Ingest           int `json:"ingest"`
}

type ClusterStatsNodesOsStats struct {
	AvailableProcessors int                            `json:"available_processors"`
	Mem                 *ClusterStatsNodesOsStatsMem   `json:"mem"`
	CPU                 []*ClusterStatsNodesOsStatsCPU `json:"cpu"`
}

type ClusterStatsNodesOsStatsMem struct {
	Total        string `json:"total"` // e.g. "16gb"
	TotalInBytes int64  `json:"total_in_bytes"`
}

type ClusterStatsNodesOsStatsCPU struct {
	Vendor           string `json:"vendor"`
	Model            string `json:"model"`
	MHz              int    `json:"mhz"`
	TotalCores       int    `json:"total_cores"`
	TotalSockets     int    `json:"total_sockets"`
	CoresPerSocket   int    `json:"cores_per_socket"`
	CacheSize        string `json:"cache_size"` // e.g. "256b"
	CacheSizeInBytes int64  `json:"cache_size_in_bytes"`
	Count            int    `json:"count"`
}

type ClusterStatsNodesProcessStats struct {
	CPU                 *ClusterStatsNodesProcessStatsCPU                 `json:"cpu"`
	OpenFileDescriptors *ClusterStatsNodesProcessStatsOpenFileDescriptors `json:"open_file_descriptors"`
}

type ClusterStatsNodesProcessStatsCPU struct {
	Percent float64 `json:"percent"`
}

type ClusterStatsNodesProcessStatsOpenFileDescriptors struct {
	Min int64 `json:"min"`
	Max int64 `json:"max"`
	Avg int64 `json:"avg"`
}

type ClusterStatsNodesJvmStats struct {
	MaxUptime         string                              `json:"max_uptime"` // e.g. "5h"
	MaxUptimeInMillis int64                               `json:"max_uptime_in_millis"`
	Versions          []*ClusterStatsNodesJvmStatsVersion `json:"versions"`
	Mem               *ClusterStatsNodesJvmStatsMem       `json:"mem"`
	Threads           int64                               `json:"threads"`
}

type ClusterStatsNodesJvmStatsVersion struct {
	Version   string `json:"version"`    // e.g. "1.8.0_45"
	VMName    string `json:"vm_name"`    // e.g. "Java HotSpot(TM) 64-Bit Server VM"
	VMVersion string `json:"vm_version"` // e.g. "25.45-b02"
	VMVendor  string `json:"vm_vendor"`  // e.g. "Oracle Corporation"
	Count     int    `json:"count"`
}

type ClusterStatsNodesJvmStatsMem struct {
	HeapUsed        string `json:"heap_used"`
	HeapUsedInBytes int64  `json:"heap_used_in_bytes"`
	HeapMax         string `json:"heap_max"`
	HeapMaxInBytes  int64  `json:"heap_max_in_bytes"`
}

type ClusterStatsNodesFsStats struct {
	Path                 string `json:"path"`
	Mount                string `json:"mount"`
	Dev                  string `json:"dev"`
	Total                string `json:"total"` // e.g. "930.7gb"`
	TotalInBytes         int64  `json:"total_in_bytes"`
	Free                 string `json:"free"` // e.g. "930.7gb"`
	FreeInBytes          int64  `json:"free_in_bytes"`
	Available            string `json:"available"` // e.g. "930.7gb"`
	AvailableInBytes     int64  `json:"available_in_bytes"`
	DiskReads            int64  `json:"disk_reads"`
	DiskWrites           int64  `json:"disk_writes"`
	DiskIOOp             int64  `json:"disk_io_op"`
	DiskReadSize         string `json:"disk_read_size"` // e.g. "0b"`
	DiskReadSizeInBytes  int64  `json:"disk_read_size_in_bytes"`
	DiskWriteSize        string `json:"disk_write_size"` // e.g. "0b"`
	DiskWriteSizeInBytes int64  `json:"disk_write_size_in_bytes"`
	DiskIOSize           string `json:"disk_io_size"` // e.g. "0b"`
	DiskIOSizeInBytes    int64  `json:"disk_io_size_in_bytes"`
	DiskQueue            string `json:"disk_queue"`
	DiskServiceTime      string `json:"disk_service_time"`
}

type ClusterStatsNodesPlugin struct {
	Name        string `json:"name"`
	Version     string `json:"version"`
	Description string `json:"description"`
	URL         string `json:"url"`
	JVM         bool   `json:"jvm"`
	Site        bool   `json:"site"`
}
<|endoftext|>


<commit_before>package vms

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"time"

	log "github.com/Sirupsen/logrus"
	govix "github.com/hooklift/govix"

	"github.com/c4milo/go-osx-builder/apperror"
	"github.com/c4milo/go-osx-builder/config"
	"github.com/julienschmidt/httprouter"
	"github.com/satori/go.uuid"
)

// Initializes module
func Init(router *httprouter.Router) {
	log.Infoln("Initializing vms module...")

	router.POST("/vms", CreateVM)
	//router.GET("/vms", ListVMs)
	router.GET("/vms/:id", GetVM)
	router.DELETE("/vms/:id", DestroyVM)
}

// Defines parameters supported by the CreateVM service
type CreateVMParams struct {
	// Number of virtual cpus to assign to the VM
	CPUs uint `json:"cpus"`
	// Memory for the virtual machine in IEC units. Ex: 1024mib, 1gib, 5120kib,
	Memory string `json:"memory"`
	// Network type, either "bridged", "nat" or "hostonly"
	NetType govix.NetworkType `json:"network_type"`
	// Guest OS image that is going to be used as Gold image for creating new VMs
	OSImage Image `json:"image"`
	// Script to run inside the Guest OS upon first boot
	BootstrapScript string `json:"bootstrap_script"`
	// Timeout value for waiting for VMWare Tools to initialize
	ToolsInitTimeout time.Duration `json:"tools_init_timeout"`
	// Whether or not to launch the user interface when creating the VM
	LaunchGUI bool `json:"launch_gui"`
	// Callback URL to post results once the VM creation process finishes. It
	// must support POST requests and be ready to receive JSON in the body of
	// the request.
	CallbackURL string `json:"callback_url"`
}

// Invokes callback URL with the results of the creation process
func sendResult(url string, obj interface{}) {
	if url == "" {
		return
	}
	data, err := json.Marshal(obj)
	if err != nil {
		log.WithFields(log.Fields{
			"vm":         obj,
			"code":       ErrCreatingVM.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrCbURL.Message)

		data, err = json.Marshal(ErrCbURL)
		if err != nil {
			return
		}
	}
	_, err = http.Post(url, "application/json", bytes.NewBuffer(data))
	if err != nil {
		log.WithFields(log.Fields{
			"vm":         obj,
			"code":       ErrCbURL.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrCbURL.Message)
	}
}

// Creates a virtual machine with the given parameters
func CreateVM(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	r := config.Render

	var params CreateVMParams
	body, err := ioutil.ReadAll(req.Body)

	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrReadingReqBody.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrReadingReqBody.Message)

		r.JSON(w, ErrReadingReqBody.HTTPStatus, ErrReadingReqBody)
		return
	}

	err = json.Unmarshal(body, &params)
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrParsingJSON.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrParsingJSON.Message)

		r.JSON(w, ErrParsingJSON.HTTPStatus, ErrParsingJSON)
		return
	}

	id := uuid.NewV4()

	vm := &VM{
		Provider:         govix.VMWARE_WORKSTATION,
		VerifySSL:        false,
		ID:               id.String(),
		Image:            params.OSImage,
		CPUs:             params.CPUs,
		Memory:           params.Memory,
		UpgradeVHardware: false,
		ToolsInitTimeout: params.ToolsInitTimeout,
		LaunchGUI:        params.LaunchGUI,
	}

	nic := &govix.NetworkAdapter{
		ConnType: params.NetType,
	}

	vm.VNetworkAdapters = make([]*govix.NetworkAdapter, 0, 1)
	vm.VNetworkAdapters = append(vm.VNetworkAdapters, nic)

	go func() {
		id, err := vm.Create()
		if err != nil {
			log.WithFields(log.Fields{
				"vm":         vm,
				"code":       ErrCreatingVM.Code,
				"error":      err.Error(),
				"stacktrace": apperror.GetStacktrace(),
			}).Error(ErrCreatingVM.Message)

			sendResult(params.CallbackURL, ErrCreatingVM)
			return
		}

		if vm.IPAddress == "" {
			vm.Refresh(id)
		}

		sendResult(params.CallbackURL, vm)
	}()

	r.JSON(w, http.StatusAccepted, vm)
}

// Defines parameters supported by the DestroyVM service
type DestroyVMParams struct {
	// Virtual machine ID to destroy
	ID string
}

// Destroys virtual machines by ID
func DestroyVM(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	r := config.Render

	params := DestroyVMParams{
		ID: ps.ByName("id"),
	}

	vm, err := FindVM(params.ID)
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrOpeningVM.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrOpeningVM.Message)

		r.JSON(w, ErrOpeningVM.HTTPStatus, ErrOpeningVM)
		return
	}

	if vm == nil {
		log.WithFields(log.Fields{
			"code":       ErrVMNotFound.Code,
			"error":      "",
			"stacktrace": "",
		}).Error(ErrVMNotFound.Message)

		r.JSON(w, ErrVMNotFound.HTTPStatus, ErrVMNotFound)
		return
	}

	err = vm.Destroy(vm.VMXFile)
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrInternal.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrInternal.Message)

		r.JSON(w, ErrInternal.HTTPStatus, ErrInternal)
		return
	}

	r.JSON(w, http.StatusNoContent, nil)
}

// Defines parameters supported by the ListVMs service
type ListVMsParams struct {
	Status string
}

// Returns the list of registered machines in VMWare Fusion/Workstation
// Due to limitations in VMware VIX, it only returns running machines.
func ListVMs(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	r := config.Render

	// params := ListVMsParams{
	// 	Status: req.URL.Query().Get("status"),
	// }

	vm := VM{
		Provider:  govix.VMWARE_WORKSTATION,
		VerifySSL: false,
	}

	host, err := vm.client()
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrInternal.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrInternal.Message)

		r.JSON(w, ErrInternal.HTTPStatus, ErrInternal)
		return
	}
	defer host.Disconnect()

	ids, err := host.FindItems(govix.FIND_RUNNING_VMS)
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrInternal.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrInternal.Message)

		r.JSON(w, ErrInternal.HTTPStatus, ErrInternal)
		return
	}

	r.JSON(w, http.StatusOK, ids)
}

// Defines parameters supported by the GetVM service
type GetVMParams struct {
	ID string
}

// Returns information of a virtual machine given its ID
func GetVM(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	r := config.Render

	params := GetVMParams{
		ID: ps.ByName("id"),
	}

	vm, err := FindVM(params.ID)

	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrOpeningVM.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrOpeningVM.Message)

		r.JSON(w, ErrOpeningVM.HTTPStatus, ErrOpeningVM)
		return
	}

	if vm == nil {
		log.WithFields(log.Fields{
			"code":       ErrVMNotFound.Code,
			"error":      "",
			"stacktrace": "",
		}).Error(ErrVMNotFound.Message)

		r.JSON(w, ErrVMNotFound.HTTPStatus, ErrVMNotFound)
		return
	}

	r.JSON(w, http.StatusOK, vm)
}
<commit_msg>Returns 200 and the removed resource instead<commit_after>package vms

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
	"time"

	log "github.com/Sirupsen/logrus"
	govix "github.com/hooklift/govix"

	"github.com/c4milo/go-osx-builder/apperror"
	"github.com/c4milo/go-osx-builder/config"
	"github.com/julienschmidt/httprouter"
	"github.com/satori/go.uuid"
)

// Initializes module
func Init(router *httprouter.Router) {
	log.Infoln("Initializing vms module...")

	router.POST("/vms", CreateVM)
	//router.GET("/vms", ListVMs)
	router.GET("/vms/:id", GetVM)
	router.DELETE("/vms/:id", DestroyVM)
}

// Defines parameters supported by the CreateVM service
type CreateVMParams struct {
	// Number of virtual cpus to assign to the VM
	CPUs uint `json:"cpus"`
	// Memory for the virtual machine in IEC units. Ex: 1024mib, 1gib, 5120kib,
	Memory string `json:"memory"`
	// Network type, either "bridged", "nat" or "hostonly"
	NetType govix.NetworkType `json:"network_type"`
	// Guest OS image that is going to be used as Gold image for creating new VMs
	OSImage Image `json:"image"`
	// Script to run inside the Guest OS upon first boot
	BootstrapScript string `json:"bootstrap_script"`
	// Timeout value for waiting for VMWare Tools to initialize
	ToolsInitTimeout time.Duration `json:"tools_init_timeout"`
	// Whether or not to launch the user interface when creating the VM
	LaunchGUI bool `json:"launch_gui"`
	// Callback URL to post results once the VM creation process finishes. It
	// must support POST requests and be ready to receive JSON in the body of
	// the request.
	CallbackURL string `json:"callback_url"`
}

// Invokes callback URL with the results of the creation process
func sendResult(url string, obj interface{}) {
	if url == "" {
		return
	}
	data, err := json.Marshal(obj)
	if err != nil {
		log.WithFields(log.Fields{
			"vm":         obj,
			"code":       ErrCreatingVM.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrCbURL.Message)

		data, err = json.Marshal(ErrCbURL)
		if err != nil {
			return
		}
	}
	_, err = http.Post(url, "application/json", bytes.NewBuffer(data))
	if err != nil {
		log.WithFields(log.Fields{
			"vm":         obj,
			"code":       ErrCbURL.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrCbURL.Message)
	}
}

// Creates a virtual machine with the given parameters
func CreateVM(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	r := config.Render

	var params CreateVMParams
	body, err := ioutil.ReadAll(req.Body)

	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrReadingReqBody.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrReadingReqBody.Message)

		r.JSON(w, ErrReadingReqBody.HTTPStatus, ErrReadingReqBody)
		return
	}

	err = json.Unmarshal(body, &params)
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrParsingJSON.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrParsingJSON.Message)

		r.JSON(w, ErrParsingJSON.HTTPStatus, ErrParsingJSON)
		return
	}

	id := uuid.NewV4()

	vm := &VM{
		Provider:         govix.VMWARE_WORKSTATION,
		VerifySSL:        false,
		ID:               id.String(),
		Image:            params.OSImage,
		CPUs:             params.CPUs,
		Memory:           params.Memory,
		UpgradeVHardware: false,
		ToolsInitTimeout: params.ToolsInitTimeout,
		LaunchGUI:        params.LaunchGUI,
	}

	nic := &govix.NetworkAdapter{
		ConnType: params.NetType,
	}

	vm.VNetworkAdapters = make([]*govix.NetworkAdapter, 0, 1)
	vm.VNetworkAdapters = append(vm.VNetworkAdapters, nic)

	go func() {
		id, err := vm.Create()
		if err != nil {
			log.WithFields(log.Fields{
				"vm":         vm,
				"code":       ErrCreatingVM.Code,
				"error":      err.Error(),
				"stacktrace": apperror.GetStacktrace(),
			}).Error(ErrCreatingVM.Message)

			sendResult(params.CallbackURL, ErrCreatingVM)
			return
		}

		if vm.IPAddress == "" {
			vm.Refresh(id)
		}

		sendResult(params.CallbackURL, vm)
	}()

	r.JSON(w, http.StatusAccepted, vm)
}

// Defines parameters supported by the DestroyVM service
type DestroyVMParams struct {
	// Virtual machine ID to destroy
	ID string
}

// Destroys virtual machines by ID
func DestroyVM(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	r := config.Render

	params := DestroyVMParams{
		ID: ps.ByName("id"),
	}

	vm, err := FindVM(params.ID)
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrOpeningVM.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrOpeningVM.Message)

		r.JSON(w, ErrOpeningVM.HTTPStatus, ErrOpeningVM)
		return
	}

	if vm == nil {
		log.WithFields(log.Fields{
			"code":       ErrVMNotFound.Code,
			"error":      "",
			"stacktrace": "",
		}).Error(ErrVMNotFound.Message)

		r.JSON(w, ErrVMNotFound.HTTPStatus, ErrVMNotFound)
		return
	}

	err = vm.Destroy(vm.VMXFile)
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrInternal.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrInternal.Message)

		r.JSON(w, ErrInternal.HTTPStatus, ErrInternal)
		return
	}

	r.JSON(w, http.StatusOK, vm)
}

// Defines parameters supported by the ListVMs service
type ListVMsParams struct {
	Status string
}

// Returns the list of registered machines in VMWare Fusion/Workstation
// Due to limitations in VMware VIX, it only returns running machines.
func ListVMs(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	r := config.Render

	// params := ListVMsParams{
	// 	Status: req.URL.Query().Get("status"),
	// }

	vm := VM{
		Provider:  govix.VMWARE_WORKSTATION,
		VerifySSL: false,
	}

	host, err := vm.client()
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrInternal.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrInternal.Message)

		r.JSON(w, ErrInternal.HTTPStatus, ErrInternal)
		return
	}
	defer host.Disconnect()

	ids, err := host.FindItems(govix.FIND_RUNNING_VMS)
	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrInternal.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrInternal.Message)

		r.JSON(w, ErrInternal.HTTPStatus, ErrInternal)
		return
	}

	r.JSON(w, http.StatusOK, ids)
}

// Defines parameters supported by the GetVM service
type GetVMParams struct {
	ID string
}

// Returns information of a virtual machine given its ID
func GetVM(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	r := config.Render

	params := GetVMParams{
		ID: ps.ByName("id"),
	}

	vm, err := FindVM(params.ID)

	if err != nil {
		log.WithFields(log.Fields{
			"code":       ErrOpeningVM.Code,
			"error":      err.Error(),
			"stacktrace": apperror.GetStacktrace(),
		}).Error(ErrOpeningVM.Message)

		r.JSON(w, ErrOpeningVM.HTTPStatus, ErrOpeningVM)
		return
	}

	if vm == nil {
		log.WithFields(log.Fields{
			"code":       ErrVMNotFound.Code,
			"error":      "",
			"stacktrace": "",
		}).Error(ErrVMNotFound.Message)

		r.JSON(w, ErrVMNotFound.HTTPStatus, ErrVMNotFound)
		return
	}

	r.JSON(w, http.StatusOK, vm)
}
<|endoftext|>


<commit_before>// A script to test kafka async and ack mechanism.
package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"syscall"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/golib/gofmt"
	"github.com/funkygao/golib/signal"
)

var (
	zone, cluster, topic string
	ack                  string
	messages             int
)

func init() {
	ctx.LoadFromHome()

	flag.StringVar(&zone, "z", "prod", "zone")
	flag.StringVar(&cluster, "c", "", "cluster")
	flag.StringVar(&topic, "t", "", "topic")
	flag.StringVar(&ack, "ack", "local", "local|none|all")
	flag.IntVar(&messages, "n", 2000, "flush messages")
	flag.Parse()

	if len(zone) == 0 || len(cluster) == 0 || len(topic) == 0 {
		panic("invalid flag")
	}
}

func main() {
	cf := sarama.NewConfig()
	cf.ChannelBufferSize = 256 * 4 // default was 256
	cf.Producer.Return.Errors = true
	cf.Producer.Return.Successes = true
	cf.Producer.Retry.Backoff = time.Millisecond * 300
	cf.Producer.Retry.Max = 3
	switch ack {
	case "none":
		cf.Producer.RequiredAcks = sarama.NoResponse
	case "local":
		cf.Producer.RequiredAcks = sarama.WaitForLocal
	case "all":
		cf.Producer.RequiredAcks = sarama.WaitForAll
	default:
		panic("invalid: " + ack)
	}
	cf.Producer.RequiredAcks = sarama.WaitForLocal
	cf.Producer.Flush.Frequency = time.Second
	cf.Producer.Flush.Messages = messages
	cf.Producer.Flush.MaxMessages = 0 // unlimited

	zkzone := zk.NewZkZone(zk.DefaultConfig(zone, ctx.ZoneZkAddrs(zone)))
	zkcluster := zkzone.NewCluster(cluster)
	p, err := sarama.NewAsyncProducer(zkcluster.BrokerList(), cf)
	if err != nil {
		panic(err)
	}

	quit := make(chan struct{})
	closed := make(chan struct{})
	signal.RegisterHandler(func(sig os.Signal) {
		close(quit)
		time.Sleep(time.Second)

		fmt.Printf("closed with %v\n", p.Close())
		close(closed)
	}, syscall.SIGINT)

	var (
		sent, sentOk int64
	)

	go func() {
		for {
			select {
			case <-quit:
				return

			case <-p.Successes():
				sentOk++

			case err := <-p.Errors():
				v, _ := err.Msg.Value.Encode()
				fmt.Println(string(v[:15]), err)
			}
		}
	}()

	go func() {
		for {
			fmt.Println(gofmt.Comma(sent), gofmt.Comma(sentOk), gofmt.Comma(sent-sentOk))
			time.Sleep(time.Second)
		}
	}()

	for {
		msg := sarama.StringEncoder(fmt.Sprintf("{%d} %s", sent, strings.Repeat("X", 1033)))
		select {
		case <-quit:
			goto BYE

		case p.Input() <- &sarama.ProducerMessage{
			Topic: topic,
			Value: msg,
		}:
			sent++
		}
	}

BYE:
	<-closed
}
<commit_msg>quit after met too many errors<commit_after>// A script to test kafka async and ack mechanism.
package main

import (
	"flag"
	"fmt"
	"os"
	"strings"
	"syscall"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/golib/gofmt"
	"github.com/funkygao/golib/signal"
)

var (
	zone, cluster, topic string
	ack                  string
	maxErrs              int64
	messages             int
)

func init() {
	ctx.LoadFromHome()

	flag.StringVar(&zone, "z", "prod", "zone")
	flag.StringVar(&cluster, "c", "", "cluster")
	flag.StringVar(&topic, "t", "", "topic")
	flag.StringVar(&ack, "ack", "local", "local|none|all")
	flag.Int64Var(&maxErrs, "e", 10, "max errors before quit")
	flag.IntVar(&messages, "n", 2000, "flush messages")
	flag.Parse()

	if len(zone) == 0 || len(cluster) == 0 || len(topic) == 0 {
		panic("invalid flag")
	}
}

func main() {
	cf := sarama.NewConfig()
	cf.ChannelBufferSize = 256 * 4 // default was 256
	cf.Producer.Return.Errors = true
	cf.Producer.Return.Successes = true
	cf.Producer.Retry.Backoff = time.Millisecond * 300
	cf.Producer.Retry.Max = 3
	switch ack {
	case "none":
		cf.Producer.RequiredAcks = sarama.NoResponse
	case "local":
		cf.Producer.RequiredAcks = sarama.WaitForLocal
	case "all":
		cf.Producer.RequiredAcks = sarama.WaitForAll
	default:
		panic("invalid: " + ack)
	}
	cf.Producer.RequiredAcks = sarama.WaitForLocal
	cf.Producer.Flush.Frequency = time.Second
	cf.Producer.Flush.Messages = messages
	cf.Producer.Flush.MaxMessages = 0 // unlimited

	zkzone := zk.NewZkZone(zk.DefaultConfig(zone, ctx.ZoneZkAddrs(zone)))
	zkcluster := zkzone.NewCluster(cluster)
	p, err := sarama.NewAsyncProducer(zkcluster.BrokerList(), cf)
	if err != nil {
		panic(err)
	}

	quit := make(chan struct{})
	closed := make(chan struct{})
	signal.RegisterHandler(func(sig os.Signal) {
		close(quit)
		time.Sleep(time.Second)

		fmt.Printf("closed with %v\n", p.Close())
		close(closed)
	}, syscall.SIGINT)

	var (
		sent, sentOk int64
	)

	go func() {
		var errN int64
		for {
			select {
			case <-quit:
				return

			case <-p.Successes():
				sentOk++

			case err := <-p.Errors():
				v, _ := err.Msg.Value.Encode()
				fmt.Println(string(v[:15]), err)

				errN++
				if maxErrs > 0 && errN >= maxErrs {
					close(quit)
					time.Sleep(time.Second)

					fmt.Printf("closed with %v\n", p.Close())
					close(closed)
				}
			}
		}
	}()

	go func() {
		for {
			fmt.Println(gofmt.Comma(sent), gofmt.Comma(sentOk), gofmt.Comma(sent-sentOk))
			time.Sleep(time.Second)
		}
	}()

	for {
		msg := sarama.StringEncoder(fmt.Sprintf("{%d} %s", sent, strings.Repeat("X", 1033)))
		select {
		case <-quit:
			goto BYE

		case p.Input() <- &sarama.ProducerMessage{
			Topic: topic,
			Value: msg,
		}:
			sent++
		}
	}

BYE:
	<-closed
}
<|endoftext|>


<commit_before>// A script to test kafka async and ack mechanism.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/dbus/pkg/kafka"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/golib/gofmt"
	"github.com/funkygao/golib/signal"
	"github.com/funkygao/golib/sync2"
	"github.com/funkygao/log4go"
)

var (
	zone, cluster, topic string
	ack                  string
	maxErrs              int64
	messages             int
)

func init() {
	ctx.LoadFromHome()

	flag.StringVar(&zone, "z", "prod", "zone")
	flag.StringVar(&cluster, "c", "", "cluster")
	flag.StringVar(&topic, "t", "", "topic")
	flag.StringVar(&ack, "ack", "local", "local|none|all")
	flag.Int64Var(&maxErrs, "e", 10, "max errors before quit")
	flag.IntVar(&messages, "n", 2000, "flush messages")
	flag.Parse()

	if len(zone) == 0 || len(cluster) == 0 || len(topic) == 0 {
		panic("invalid flag")
	}

	log4go.SetLevel(log4go.TRACE)
}

func main() {
	cf := kafka.DefaultConfig()
	switch ack {
	case "none":
		cf.Ack(sarama.NoResponse)
	case "local":
		cf.Ack(sarama.WaitForLocal)
	case "all":
		cf.Ack(sarama.WaitForAll)
	default:
		panic("invalid: " + ack)
	}
	p, err := kafka.NewProducer("tester", zk.NewZkZone(zk.DefaultConfig(zone, ctx.ZoneZkAddrs(zone))).NewCluster(cluster).BrokerList(), cf)
	if err != nil {
		panic(err)
	}

	var (
		sent, sentOk sync2.AtomicInt64
	)

	p.SetErrorHandler(func(err *sarama.ProducerError) {
		v, _ := err.Msg.Value.Encode()
		log.Println(string(v[:12]), err)
	})
	p.SetSuccessHandler(func(msg *sarama.ProducerMessage) {
		sentOk.Add(1)
	})
	if err := p.Start(); err != nil {
		panic(err)
	}

	stopProducer := make(chan struct{})
	closed := make(chan struct{})
	var once sync.Once
	quitFn := func() {
		once.Do(func() {
			close(stopProducer)
			time.Sleep(time.Second)

			log.Printf("%d/%d, closed with %v", sentOk.Get(), sent.Get(), p.Close())
			close(closed)
		})
	}

	signal.RegisterHandler(func(sig os.Signal) {
		log.Printf("got signal %s", sig)
		quitFn()
	}, syscall.SIGINT)

	go func() {
		for {
			log.Println(gofmt.Comma(sent.Get()), gofmt.Comma(sentOk.Get()), gofmt.Comma(sent.Get()-sentOk.Get()))
			time.Sleep(time.Second)
		}
	}()

	for {
		msg := sarama.StringEncoder(fmt.Sprintf("{%d} %s", sent.Get(),
			strings.Repeat("X", 10331)))
		p.Send(&sarama.ProducerMessage{
			Topic: topic,
			Value: msg,
		})
		sent.Add(1)
	}

	<-closed
}
<commit_msg>graceful stopping<commit_after>// A script to test kafka async and ack mechanism.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/dbus/pkg/kafka"
	"github.com/funkygao/gafka/ctx"
	"github.com/funkygao/gafka/zk"
	"github.com/funkygao/golib/gofmt"
	"github.com/funkygao/golib/signal"
	"github.com/funkygao/golib/sync2"
	"github.com/funkygao/log4go"
)

var (
	zone, cluster, topic string
	ack                  string
	maxErrs              int64
	messages             int
)

func init() {
	ctx.LoadFromHome()

	flag.StringVar(&zone, "z", "prod", "zone")
	flag.StringVar(&cluster, "c", "", "cluster")
	flag.StringVar(&topic, "t", "", "topic")
	flag.StringVar(&ack, "ack", "local", "local|none|all")
	flag.Int64Var(&maxErrs, "e", 10, "max errors before quit")
	flag.IntVar(&messages, "n", 2000, "flush messages")
	flag.Parse()

	if len(zone) == 0 || len(cluster) == 0 || len(topic) == 0 {
		panic("invalid flag")
	}

	log4go.SetLevel(log4go.TRACE)
}

func main() {
	cf := kafka.DefaultConfig()
	switch ack {
	case "none":
		cf.Ack(sarama.NoResponse)
	case "local":
		cf.Ack(sarama.WaitForLocal)
	case "all":
		cf.Ack(sarama.WaitForAll)
	default:
		panic("invalid: " + ack)
	}
	p, err := kafka.NewProducer("tester", zk.NewZkZone(zk.DefaultConfig(zone, ctx.ZoneZkAddrs(zone))).NewCluster(cluster).BrokerList(), cf)
	if err != nil {
		panic(err)
	}

	var (
		sent, sentOk sync2.AtomicInt64
	)

	p.SetErrorHandler(func(err *sarama.ProducerError) {
		v, _ := err.Msg.Value.Encode()
		log.Println(string(v[:12]), err)
	})
	p.SetSuccessHandler(func(msg *sarama.ProducerMessage) {
		sentOk.Add(1)
	})
	if err := p.Start(); err != nil {
		panic(err)
	}

	stopProducer := make(chan struct{})
	closed := make(chan struct{})
	var once sync.Once
	quitFn := func() {
		once.Do(func() {
			close(stopProducer)
			time.Sleep(time.Second)

			log.Printf("%d/%d, closed with %v", sentOk.Get(), sent.Get(), p.Close())
			close(closed)
		})
	}

	signal.RegisterHandler(func(sig os.Signal) {
		log.Printf("got signal %s", sig)
		quitFn()
	}, syscall.SIGINT)

	go func() {
		for {
			log.Println(gofmt.Comma(sent.Get()), gofmt.Comma(sentOk.Get()), gofmt.Comma(sent.Get()-sentOk.Get()))
			time.Sleep(time.Second)
		}
	}()

	for {
		msg := sarama.StringEncoder(fmt.Sprintf("{%d} %s", sent.Get(),
			strings.Repeat("X", 10331)))
		if err := p.Send(&sarama.ProducerMessage{
			Topic: topic,
			Value: msg,
		}); err != nil {
			log.Println(err)
			break
		}
		sent.Add(1)
	}

	<-closed
}
<|endoftext|>