<commit_before>package rados

// #cgo LDFLAGS: -lrados
// #include <stdlib.h>
// #include <rados/librados.h>
import "C"

import (
	"bytes"
	"unsafe"

	"github.com/ceph/go-ceph/internal/retry"
)

// ClusterStat represents Ceph cluster statistics.
type ClusterStat struct {
	Kb          uint64
	Kb_used     uint64
	Kb_avail    uint64
	Num_objects uint64
}

// Conn is a connection handle to a Ceph cluster.
type Conn struct {
	cluster   C.rados_t
	connected bool
}

// ClusterRef represents a fundamental RADOS cluster connection.
type ClusterRef C.rados_t

// Cluster returns the underlying RADOS cluster reference for this Conn.
func (c *Conn) Cluster() ClusterRef {
	return ClusterRef(c.cluster)
}

// PingMonitor sends a ping to a monitor and returns the reply.
func (c *Conn) PingMonitor(id string) (string, error) {
	c_id := C.CString(id)
	defer C.free(unsafe.Pointer(c_id))

	var strlen C.size_t
	var strout *C.char

	ret := C.rados_ping_monitor(c.cluster, c_id, &strout, &strlen)
	defer C.rados_buffer_free(strout)

	if ret == 0 {
		reply := C.GoStringN(strout, (C.int)(strlen))
		return reply, nil
	}
	return "", getError(ret)
}

// Connect establishes a connection to a RADOS cluster. It returns an error,
// if any.
func (c *Conn) Connect() error {
	ret := C.rados_connect(c.cluster)
	if ret != 0 {
		return getError(ret)
	}
	c.connected = true
	return nil
}

// Shutdown disconnects from the cluster.
func (c *Conn) Shutdown() {
	if err := c.ensure_connected(); err != nil {
		return
	}
	freeConn(c)
}

// ReadConfigFile configures the connection using a Ceph configuration file.
func (c *Conn) ReadConfigFile(path string) error {
	c_path := C.CString(path)
	defer C.free(unsafe.Pointer(c_path))
	ret := C.rados_conf_read_file(c.cluster, c_path)
	return getError(ret)
}

// ReadDefaultConfigFile configures the connection using a Ceph configuration
// file located at default locations.
func (c *Conn) ReadDefaultConfigFile() error {
	ret := C.rados_conf_read_file(c.cluster, nil)
	return getError(ret)
}

// OpenIOContext creates and returns a new IOContext for the given pool.
//
// Implements:
//  int rados_ioctx_create(rados_t cluster, const char *pool_name,
//                         rados_ioctx_t *ioctx);
func (c *Conn) OpenIOContext(pool string) (*IOContext, error) {
	c_pool := C.CString(pool)
	defer C.free(unsafe.Pointer(c_pool))
	ioctx := &IOContext{}
	ret := C.rados_ioctx_create(c.cluster, c_pool, &ioctx.ioctx)
	if ret == 0 {
		return ioctx, nil
	}
	return nil, getError(ret)
}

// ListPools returns the names of all existing pools.
func (c *Conn) ListPools() (names []string, err error) {
	buf := make([]byte, 4096)
	for {
		ret := C.rados_pool_list(c.cluster,
			(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))
		if ret < 0 {
			return nil, getError(ret)
		}

		if int(ret) > len(buf) {
			buf = make([]byte, ret)
			continue
		}

		tmp := bytes.SplitAfter(buf[:ret-1], []byte{0})
		for _, s := range tmp {
			if len(s) > 0 {
				name := C.GoString((*C.char)(unsafe.Pointer(&s[0])))
				names = append(names, name)
			}
		}

		return names, nil
	}
}

// SetConfigOption sets the value of the configuration option identified by
// the given name.
func (c *Conn) SetConfigOption(option, value string) error {
	c_opt, c_val := C.CString(option), C.CString(value)
	defer C.free(unsafe.Pointer(c_opt))
	defer C.free(unsafe.Pointer(c_val))
	ret := C.rados_conf_set(c.cluster, c_opt, c_val)
	return getError(ret)
}

// GetConfigOption returns the value of the Ceph configuration option
// identified by the given name.
func (c *Conn) GetConfigOption(name string) (value string, err error) {
	cOption := C.CString(name)
	defer C.free(unsafe.Pointer(cOption))

	var buf []byte
	// range from 4k to 256KiB
	retry.WithSizes(4096, 1<<18, func(size int) retry.Hint {
		buf = make([]byte, size)
		ret := C.rados_conf_get(
			c.cluster,
			cOption,
			(*C.char)(unsafe.Pointer(&buf[0])),
			C.size_t(len(buf)))
		err = getError(ret)
		return retry.DoubleSize.If(err == errNameTooLong)
	})
	if err != nil {
		return "", err
	}
	value = C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
	return value, nil
}

// WaitForLatestOSDMap blocks the caller until the latest OSD map has been
// retrieved.
func (c *Conn) WaitForLatestOSDMap() error {
	ret := C.rados_wait_for_latest_osdmap(c.cluster)
	return getError(ret)
}

func (c *Conn) ensure_connected() error {
	if c.connected {
		return nil
	}
	return ErrNotConnected
}

// GetClusterStats returns statistics about the cluster associated with the
// connection.
func (c *Conn) GetClusterStats() (stat ClusterStat, err error) {
	if err := c.ensure_connected(); err != nil {
		return ClusterStat{}, err
	}
	c_stat := C.struct_rados_cluster_stat_t{}
	ret := C.rados_cluster_stat(c.cluster, &c_stat)
	if ret < 0 {
		return ClusterStat{}, getError(ret)
	}
	return ClusterStat{
		Kb:          uint64(c_stat.kb),
		Kb_used:     uint64(c_stat.kb_used),
		Kb_avail:    uint64(c_stat.kb_avail),
		Num_objects: uint64(c_stat.num_objects),
	}, nil
}

// ParseCmdLineArgs configures the connection from command line arguments.
func (c *Conn) ParseCmdLineArgs(args []string) error {
	// add an empty element 0 -- Ceph treats the array as the actual contents
	// of argv and skips the first element (the executable name)
	argc := C.int(len(args) + 1)
	argv := make([]*C.char, argc)

	// make the first element a string just in case it is ever examined
	argv[0] = C.CString("placeholder")
	defer C.free(unsafe.Pointer(argv[0]))

	for i, arg := range args {
		argv[i+1] = C.CString(arg)
		defer C.free(unsafe.Pointer(argv[i+1]))
	}

	ret := C.rados_conf_parse_argv(c.cluster, argc, &argv[0])
	return getError(ret)
}

// ParseDefaultConfigEnv configures the connection from the default Ceph
// environment variable(s).
func (c *Conn) ParseDefaultConfigEnv() error {
	ret := C.rados_conf_parse_env(c.cluster, nil)
	return getError(ret)
}

// GetFSID returns the fsid of the cluster as a hexadecimal string. The fsid
// is a unique identifier of an entire Ceph cluster.
func (c *Conn) GetFSID() (fsid string, err error) {
	buf := make([]byte, 37)
	ret := C.rados_cluster_fsid(c.cluster,
		(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))
	// FIXME: the success case isn't documented correctly in librados.h
	if ret == 36 {
		fsid = C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
		return fsid, nil
	}
	return "", getError(ret)
}

// GetInstanceID returns a globally unique identifier for the cluster
// connection instance.
func (c *Conn) GetInstanceID() uint64 {
	// FIXME: are there any error cases for this?
	return uint64(C.rados_get_instance_id(c.cluster))
}

// MakePool creates a new pool with default settings.
func (c *Conn) MakePool(name string) error {
	c_name := C.CString(name)
	defer C.free(unsafe.Pointer(c_name))
	ret := C.rados_pool_create(c.cluster, c_name)
	return getError(ret)
}

// DeletePool deletes a pool and all the data inside the pool.
func (c *Conn) DeletePool(name string) error {
	if err := c.ensure_connected(); err != nil {
		return err
	}
	c_name := C.CString(name)
	defer C.free(unsafe.Pointer(c_name))
	ret := C.rados_pool_delete(c.cluster, c_name)
	return getError(ret)
}

// GetPoolByName returns the ID of the pool with a given name.
func (c *Conn) GetPoolByName(name string) (int64, error) {
	if err := c.ensure_connected(); err != nil {
		return 0, err
	}
	c_name := C.CString(name)
	defer C.free(unsafe.Pointer(c_name))
	ret := int64(C.rados_pool_lookup(c.cluster, c_name))
	if ret < 0 {
		return 0, radosError(ret)
	}
	return ret, nil
}

// GetPoolByID returns the name of a pool by a given ID.
func (c *Conn) GetPoolByID(id int64) (string, error) {
	buf := make([]byte, 4096)
	if err := c.ensure_connected(); err != nil {
		return "", err
	}
	c_id := C.int64_t(id)
	ret := int(C.rados_pool_reverse_lookup(c.cluster, c_id, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
	if ret < 0 {
		return "", radosError(ret)
	}
	return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil
}
<commit_msg>rados: convert ListPools to use cutil.SplitSparseBuffer<commit_after>package rados

// #cgo LDFLAGS: -lrados
// #include <stdlib.h>
// #include <rados/librados.h>
import "C"

import (
	"unsafe"

	"github.com/ceph/go-ceph/internal/cutil"
	"github.com/ceph/go-ceph/internal/retry"
)

// ClusterStat represents Ceph cluster statistics.
type ClusterStat struct {
	Kb          uint64
	Kb_used     uint64
	Kb_avail    uint64
	Num_objects uint64
}

// Conn is a connection handle to a Ceph cluster.
type Conn struct {
	cluster   C.rados_t
	connected bool
}

// ClusterRef represents a fundamental RADOS cluster connection.
type ClusterRef C.rados_t

// Cluster returns the underlying RADOS cluster reference for this Conn.
func (c *Conn) Cluster() ClusterRef {
	return ClusterRef(c.cluster)
}

// PingMonitor sends a ping to a monitor and returns the reply.
func (c *Conn) PingMonitor(id string) (string, error) {
	c_id := C.CString(id)
	defer C.free(unsafe.Pointer(c_id))

	var strlen C.size_t
	var strout *C.char

	ret := C.rados_ping_monitor(c.cluster, c_id, &strout, &strlen)
	defer C.rados_buffer_free(strout)

	if ret == 0 {
		reply := C.GoStringN(strout, (C.int)(strlen))
		return reply, nil
	}
	return "", getError(ret)
}

// Connect establishes a connection to a RADOS cluster. It returns an error,
// if any.
func (c *Conn) Connect() error {
	ret := C.rados_connect(c.cluster)
	if ret != 0 {
		return getError(ret)
	}
	c.connected = true
	return nil
}

// Shutdown disconnects from the cluster.
func (c *Conn) Shutdown() {
	if err := c.ensure_connected(); err != nil {
		return
	}
	freeConn(c)
}

// ReadConfigFile configures the connection using a Ceph configuration file.
func (c *Conn) ReadConfigFile(path string) error {
	c_path := C.CString(path)
	defer C.free(unsafe.Pointer(c_path))
	ret := C.rados_conf_read_file(c.cluster, c_path)
	return getError(ret)
}

// ReadDefaultConfigFile configures the connection using a Ceph configuration
// file located at default locations.
func (c *Conn) ReadDefaultConfigFile() error {
	ret := C.rados_conf_read_file(c.cluster, nil)
	return getError(ret)
}

// OpenIOContext creates and returns a new IOContext for the given pool.
//
// Implements:
//  int rados_ioctx_create(rados_t cluster, const char *pool_name,
//                         rados_ioctx_t *ioctx);
func (c *Conn) OpenIOContext(pool string) (*IOContext, error) {
	c_pool := C.CString(pool)
	defer C.free(unsafe.Pointer(c_pool))
	ioctx := &IOContext{}
	ret := C.rados_ioctx_create(c.cluster, c_pool, &ioctx.ioctx)
	if ret == 0 {
		return ioctx, nil
	}
	return nil, getError(ret)
}

// ListPools returns the names of all existing pools.
func (c *Conn) ListPools() (names []string, err error) {
	buf := make([]byte, 4096)
	for {
		ret := C.rados_pool_list(c.cluster,
			(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))
		if ret < 0 {
			return nil, getError(ret)
		}

		if int(ret) > len(buf) {
			buf = make([]byte, ret)
			continue
		}

		names = cutil.SplitSparseBuffer(buf[:ret])
		return names, nil
	}
}

// SetConfigOption sets the value of the configuration option identified by
// the given name.
func (c *Conn) SetConfigOption(option, value string) error {
	c_opt, c_val := C.CString(option), C.CString(value)
	defer C.free(unsafe.Pointer(c_opt))
	defer C.free(unsafe.Pointer(c_val))
	ret := C.rados_conf_set(c.cluster, c_opt, c_val)
	return getError(ret)
}

// GetConfigOption returns the value of the Ceph configuration option
// identified by the given name.
func (c *Conn) GetConfigOption(name string) (value string, err error) {
	cOption := C.CString(name)
	defer C.free(unsafe.Pointer(cOption))

	var buf []byte
	// range from 4k to 256KiB
	retry.WithSizes(4096, 1<<18, func(size int) retry.Hint {
		buf = make([]byte, size)
		ret := C.rados_conf_get(
			c.cluster,
			cOption,
			(*C.char)(unsafe.Pointer(&buf[0])),
			C.size_t(len(buf)))
		err = getError(ret)
		return retry.DoubleSize.If(err == errNameTooLong)
	})
	if err != nil {
		return "", err
	}
	value = C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
	return value, nil
}

// WaitForLatestOSDMap blocks the caller until the latest OSD map has been
// retrieved.
func (c *Conn) WaitForLatestOSDMap() error {
	ret := C.rados_wait_for_latest_osdmap(c.cluster)
	return getError(ret)
}

func (c *Conn) ensure_connected() error {
	if c.connected {
		return nil
	}
	return ErrNotConnected
}

// GetClusterStats returns statistics about the cluster associated with the
// connection.
func (c *Conn) GetClusterStats() (stat ClusterStat, err error) {
	if err := c.ensure_connected(); err != nil {
		return ClusterStat{}, err
	}
	c_stat := C.struct_rados_cluster_stat_t{}
	ret := C.rados_cluster_stat(c.cluster, &c_stat)
	if ret < 0 {
		return ClusterStat{}, getError(ret)
	}
	return ClusterStat{
		Kb:          uint64(c_stat.kb),
		Kb_used:     uint64(c_stat.kb_used),
		Kb_avail:    uint64(c_stat.kb_avail),
		Num_objects: uint64(c_stat.num_objects),
	}, nil
}

// ParseCmdLineArgs configures the connection from command line arguments.
func (c *Conn) ParseCmdLineArgs(args []string) error {
	// add an empty element 0 -- Ceph treats the array as the actual contents
	// of argv and skips the first element (the executable name)
	argc := C.int(len(args) + 1)
	argv := make([]*C.char, argc)

	// make the first element a string just in case it is ever examined
	argv[0] = C.CString("placeholder")
	defer C.free(unsafe.Pointer(argv[0]))

	for i, arg := range args {
		argv[i+1] = C.CString(arg)
		defer C.free(unsafe.Pointer(argv[i+1]))
	}

	ret := C.rados_conf_parse_argv(c.cluster, argc, &argv[0])
	return getError(ret)
}

// ParseDefaultConfigEnv configures the connection from the default Ceph
// environment variable(s).
func (c *Conn) ParseDefaultConfigEnv() error {
	ret := C.rados_conf_parse_env(c.cluster, nil)
	return getError(ret)
}

// GetFSID returns the fsid of the cluster as a hexadecimal string. The fsid
// is a unique identifier of an entire Ceph cluster.
func (c *Conn) GetFSID() (fsid string, err error) {
	buf := make([]byte, 37)
	ret := C.rados_cluster_fsid(c.cluster,
		(*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf)))
	// FIXME: the success case isn't documented correctly in librados.h
	if ret == 36 {
		fsid = C.GoString((*C.char)(unsafe.Pointer(&buf[0])))
		return fsid, nil
	}
	return "", getError(ret)
}

// GetInstanceID returns a globally unique identifier for the cluster
// connection instance.
func (c *Conn) GetInstanceID() uint64 {
	// FIXME: are there any error cases for this?
	return uint64(C.rados_get_instance_id(c.cluster))
}

// MakePool creates a new pool with default settings.
func (c *Conn) MakePool(name string) error {
	c_name := C.CString(name)
	defer C.free(unsafe.Pointer(c_name))
	ret := C.rados_pool_create(c.cluster, c_name)
	return getError(ret)
}

// DeletePool deletes a pool and all the data inside the pool.
func (c *Conn) DeletePool(name string) error {
	if err := c.ensure_connected(); err != nil {
		return err
	}
	c_name := C.CString(name)
	defer C.free(unsafe.Pointer(c_name))
	ret := C.rados_pool_delete(c.cluster, c_name)
	return getError(ret)
}

// GetPoolByName returns the ID of the pool with a given name.
func (c *Conn) GetPoolByName(name string) (int64, error) {
	if err := c.ensure_connected(); err != nil {
		return 0, err
	}
	c_name := C.CString(name)
	defer C.free(unsafe.Pointer(c_name))
	ret := int64(C.rados_pool_lookup(c.cluster, c_name))
	if ret < 0 {
		return 0, radosError(ret)
	}
	return ret, nil
}

// GetPoolByID returns the name of a pool by a given ID.
func (c *Conn) GetPoolByID(id int64) (string, error) {
	buf := make([]byte, 4096)
	if err := c.ensure_connected(); err != nil {
		return "", err
	}
	c_id := C.int64_t(id)
	ret := int(C.rados_pool_reverse_lookup(c.cluster, c_id, (*C.char)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))))
	if ret < 0 {
		return "", radosError(ret)
	}
	return C.GoString((*C.char)(unsafe.Pointer(&buf[0]))), nil
}
<|endoftext|>


<commit_before>package rados

import (
    "bytes"
    "fmt"
    "os"
    "testing"
    "time"
)

func errorOnError(t *testing.T, e error, message string, parameters ...interface{}) {
    if e != nil {
        t.Errorf("%v : %v", e, fmt.Sprintf(message, parameters...))
    }
}

func fatalOnError(t *testing.T, e error, message string, parameters ...interface{}) {
    if e != nil {
        t.Fatalf("%v : %v", e, fmt.Sprintf(message, parameters...))
    }
}

func poolName() string {
    return fmt.Sprintf("rados.go.test.%d.%d", time.Now().Unix(), os.Getpid())
}

func Test_RadosNew(t *testing.T) {
    var rados *Rados
    var err error

    rados, err = NewDefault()
    fatalOnError(t, err, "New")

    err = rados.Release()
    fatalOnError(t, err, "Release")

    if rados, err = New("path that does not exist"); err == nil {
        t.Errorf("New should have failed")
        rados.Release()
    }
}

func Test_RadosPoolCreateDelete(t *testing.T) {
    var rados *Rados
    var err error

    rados, err = NewDefault()
    fatalOnError(t, err, "New")
    defer rados.Release()

    poolName := poolName()
    err = rados.PoolCreate(poolName)
    fatalOnError(t, err, "PoolCreate")

    err = rados.PoolDelete(poolName)
    fatalOnError(t, err, "PoolDelete")
}

func Test_RadosContext(t *testing.T) {
    var rados *Rados
    var err error

    rados, err = New("")
    fatalOnError(t, err, "New")
    defer rados.Release()

    ctx, err := rados.NewContext("test")
    fatalOnError(t, err, "NewContext")
    ctx.Release()

    if ctx, err = rados.NewContext("pool that does not exist"); err == nil {
        t.Errorf("NewContext should have failed")
        ctx.Release()
    }
}

func Test_RadosObject(t *testing.T) {
    var rados *Rados
    var err error

    rados, err = New("")
    fatalOnError(t, err, "New")
    defer rados.Release()

    ctx, err := rados.NewContext("test")
    fatalOnError(t, err, "NewContext")
    defer ctx.Release()

    name := "test-object"
    name2 := "test-object2"
    data := []byte("test data")

    // Create an object
    _, err = ctx.Create(name)
    errorOnError(t, err, "Create")

    // Make sure it's there
    objInfo, err := ctx.Stat(name)
    fatalOnError(t, err, "Stat")

    if objInfo.Size() != int64(0) {
        t.Errorf("Object size mismatch, was %s, expected %s", objInfo.Size(), 0)
    }

    // Put data in the object
    err = ctx.Put(name, data)
    errorOnError(t, err, "Put")

    // Make sure everything looks right
    objInfo, err = ctx.Stat(name)
    fatalOnError(t, err, "Stat")

    if objInfo.Name() != name {
        t.Errorf("Object name mismatch, was %s, expected %s", objInfo.Name(), name)
    }

    if objInfo.Size() != int64(len(data)) {
        t.Errorf("Object size mismatch, was %d, expected %d", objInfo.Size(), len(data))
    }

    // Get the data back
    data2, err := ctx.Get(name)
    fatalOnError(t, err, "Get")

    // It better be the same
    if !bytes.Equal(data, data2) {
        t.Errorf("Object data mismatch, was %s, expected %s", data2, data)
    }

    // Open an existing object
    obj, err := ctx.Open(name)
    fatalOnError(t, err, "Open")

    // Make sure everything looks right
    if obj.Name() != name {
        t.Errorf("Object name mismatch, was %s, expected %s", obj.Name(), name)
    }

    if obj.Size() != int64(len(data)) {
        t.Errorf("Object size mismatch, was %d, expected %d", obj.Size(), len(data))
    }

    // Open a new object
    obj, err = ctx.Open(name2)
    fatalOnError(t, err, "Open")

    // Make sure it's there
    objInfo, err = ctx.Stat(name2)
    fatalOnError(t, err, "Stat")

    if objInfo.Size() != int64(0) {
        t.Errorf("Object size mismatch, was %d, expected %d", objInfo.Size(), 0)
    }

    // Remove the objects
    err = ctx.Remove(name)
    errorOnError(t, err, "Remove")
    err = ctx.Remove(name2)
    errorOnError(t, err, "Remove")

    // They should be gone
    objInfo, err = ctx.Stat(name)
    if err == nil {
        t.Errorf("Object %s should have been deleted be status returned success", name)
    }

    objInfo, err = ctx.Stat(name2)
    if err == nil {
        t.Errorf("Object %s should have been deleted be status returned success", name2)
    }
}
<commit_msg>Testing infrastruture. Add setup()/teardown() functions and test state structure.<commit_after>package rados

import (
    "bytes"
    "fmt"
    "os"
    "testing"
    "time"
)

func errorOnError(t *testing.T, e error, message string, parameters ...interface{}) {
    if e != nil {
        t.Errorf("%v : %v", e, fmt.Sprintf(message, parameters...))
    }
}

func fatalOnError(t *testing.T, e error, message string, parameters ...interface{}) {
    if e != nil {
        t.Fatalf("%v : %v", e, fmt.Sprintf(message, parameters...))
    }
}

func poolName() string {
    return fmt.Sprintf("rados.go.test.%d.%d", time.Now().Unix(), os.Getpid())
}

type radosTest struct {
    t        *testing.T
    rados    *Rados
    poolName string
}

func setup(t *testing.T) *radosTest {
    var rados *Rados
    var err error

    rados, err = NewDefault()
    fatalOnError(t, err, "Setup: New")

    poolName := poolName()
    err = rados.PoolCreate(poolName)
    fatalOnError(t, err, "Setup: PoolCreate")

    return &radosTest{
        rados:    rados,
        poolName: poolName,
    }
}

func teardown(t *testing.T, test *radosTest) {
    var err error

    err = test.rados.PoolDelete(test.poolName)
    fatalOnError(t, err, "Teardown: PoolDelete")

    err = test.rados.Release()
    fatalOnError(t, err, "Teardown: Release")
}

func Test_RadosNew(t *testing.T) {
    var rados *Rados
    var err error

    rados, err = NewDefault()
    fatalOnError(t, err, "New")

    err = rados.Release()
    fatalOnError(t, err, "Release")

    if rados, err = New("path that does not exist"); err == nil {
        t.Errorf("New should have failed")
        rados.Release()
    }
}

func Test_RadosPoolCreateDelete(t *testing.T) {
    var rados *Rados
    var err error

    rados, err = NewDefault()
    fatalOnError(t, err, "New")
    defer rados.Release()

    poolName := poolName()
    err = rados.PoolCreate(poolName)
    fatalOnError(t, err, "PoolCreate")

    err = rados.PoolDelete(poolName)
    fatalOnError(t, err, "PoolDelete")
}

func Test_RadosContext(t *testing.T) {
    test := setup(t)
    defer teardown(t, test)

    ctx, err := test.rados.NewContext(test.poolName)
    fatalOnError(t, err, "NewContext")
    ctx.Release()

    if ctx, err = test.rados.NewContext("pool that does not exist"); err == nil {
        t.Errorf("NewContext should have failed")
        ctx.Release()
    }
}

func Test_RadosObject(t *testing.T) {
    test := setup(t)
    defer teardown(t, test)

    ctx, err := test.rados.NewContext(test.poolName)
    fatalOnError(t, err, "NewContext")
    defer ctx.Release()

    name := "test-object"
    name2 := "test-object2"
    data := []byte("test data")

    // Create an object
    _, err = ctx.Create(name)
    errorOnError(t, err, "Create")

    // Make sure it's there
    objInfo, err := ctx.Stat(name)
    fatalOnError(t, err, "Stat")

    if objInfo.Size() != int64(0) {
        t.Errorf("Object size mismatch, was %s, expected %s", objInfo.Size(), 0)
    }

    // Put data in the object
    err = ctx.Put(name, data)
    errorOnError(t, err, "Put")

    // Make sure everything looks right
    objInfo, err = ctx.Stat(name)
    fatalOnError(t, err, "Stat")

    if objInfo.Name() != name {
        t.Errorf("Object name mismatch, was %s, expected %s", objInfo.Name(), name)
    }

    if objInfo.Size() != int64(len(data)) {
        t.Errorf("Object size mismatch, was %d, expected %d", objInfo.Size(), len(data))
    }

    // Get the data back
    data2, err := ctx.Get(name)
    fatalOnError(t, err, "Get")

    // It better be the same
    if !bytes.Equal(data, data2) {
        t.Errorf("Object data mismatch, was %s, expected %s", data2, data)
    }

    // Open an existing object
    obj, err := ctx.Open(name)
    fatalOnError(t, err, "Open")

    // Make sure everything looks right
    if obj.Name() != name {
        t.Errorf("Object name mismatch, was %s, expected %s", obj.Name(), name)
    }

    if obj.Size() != int64(len(data)) {
        t.Errorf("Object size mismatch, was %d, expected %d", obj.Size(), len(data))
    }

    // Open a new object
    obj, err = ctx.Open(name2)
    fatalOnError(t, err, "Open")

    // Make sure it's there
    objInfo, err = ctx.Stat(name2)
    fatalOnError(t, err, "Stat")

    if objInfo.Size() != int64(0) {
        t.Errorf("Object size mismatch, was %d, expected %d", objInfo.Size(), 0)
    }

    // Remove the objects
    err = ctx.Remove(name)
    errorOnError(t, err, "Remove")
    err = ctx.Remove(name2)
    errorOnError(t, err, "Remove")

    // They should be gone
    objInfo, err = ctx.Stat(name)
    if err == nil {
        t.Errorf("Object %s should have been deleted be status returned success", name)
    }

    objInfo, err = ctx.Stat(name2)
    if err == nil {
        t.Errorf("Object %s should have been deleted be status returned success", name2)
    }
}
<|endoftext|>


<commit_before>package raft

import (
	"math/rand"
	"time"
)

const (
	// DefaultApplyInterval is the default time between checks to apply commands.
	DefaultApplyInterval = 10 * time.Millisecond

	// DefaultElectionTimeout is the default time before starting an election.
	DefaultElectionTimeout = 1 * time.Second

	// DefaultHeartbeatInterval is the default time to wait between heartbeats.
	DefaultHeartbeatInterval = 100 * time.Millisecond

	// DefaultReconnectTimeout is the default time to wait before reconnecting.
	DefaultReconnectTimeout = 10 * time.Millisecond
)

// Clock implements an interface to the real-time clock.
type Clock struct {
	ApplyInterval     time.Duration
	ElectionTimeout   time.Duration
	HeartbeatInterval time.Duration
	ReconnectTimeout  time.Duration
}

// NewClock returns a instance of Clock with defaults set.
func NewClock() *Clock {
	return &Clock{
		ApplyInterval:     DefaultApplyInterval,
		ElectionTimeout:   DefaultElectionTimeout,
		HeartbeatInterval: DefaultHeartbeatInterval,
		ReconnectTimeout:  DefaultReconnectTimeout,
	}
}

// AfterApplyInterval returns a channel that fires after the apply interval.
func (c *Clock) AfterApplyInterval() <-chan chan struct{} { return newClockChan(c.ApplyInterval) }

// AfterElectionTimeout returns a channel that fires after a duration that is
// between the election timeout and double the election timeout.
func (c *Clock) AfterElectionTimeout() <-chan chan struct{} {
	d := c.ElectionTimeout + time.Duration(rand.Intn(int(c.ElectionTimeout)))
	return newClockChan(d)
}

// AfterHeartbeatInterval returns a channel that fires after the heartbeat interval.
func (c *Clock) AfterHeartbeatInterval() <-chan chan struct{} {
	return newClockChan(c.HeartbeatInterval)
}

// AfterReconnectTimeout returns a channel that fires after the reconnection timeout.
func (c *Clock) AfterReconnectTimeout() <-chan chan struct{} { return newClockChan(c.ReconnectTimeout) }

// Now returns the current wall clock time.
func (c *Clock) Now() time.Time { return time.Now() }

// newClockChan returns a channel that sends a channel after a given duration.
// The channel being sent, over the channel that is returned, can be used to
// notify the sender when an action is done.
func newClockChan(d time.Duration) <-chan chan struct{} {
	ch := make(chan chan struct{}, 1)
	go func() { time.Sleep(d); ch <- make(chan struct{}) }()
	return ch
}
<commit_msg>Give a seed to rand to make it really random<commit_after>package raft

import (
	"math/rand"
	"time"
)

const (
	// DefaultApplyInterval is the default time between checks to apply commands.
	DefaultApplyInterval = 10 * time.Millisecond

	// DefaultElectionTimeout is the default time before starting an election.
	DefaultElectionTimeout = 1 * time.Second

	// DefaultHeartbeatInterval is the default time to wait between heartbeats.
	DefaultHeartbeatInterval = 100 * time.Millisecond

	// DefaultReconnectTimeout is the default time to wait before reconnecting.
	DefaultReconnectTimeout = 10 * time.Millisecond
)

// Clock implements an interface to the real-time clock.
type Clock struct {
	ApplyInterval     time.Duration
	ElectionTimeout   time.Duration
	HeartbeatInterval time.Duration
	ReconnectTimeout  time.Duration
}

// NewClock returns a instance of Clock with defaults set.
func NewClock() *Clock {
	return &Clock{
		ApplyInterval:     DefaultApplyInterval,
		ElectionTimeout:   DefaultElectionTimeout,
		HeartbeatInterval: DefaultHeartbeatInterval,
		ReconnectTimeout:  DefaultReconnectTimeout,
	}
}

// AfterApplyInterval returns a channel that fires after the apply interval.
func (c *Clock) AfterApplyInterval() <-chan chan struct{} { return newClockChan(c.ApplyInterval) }

// AfterElectionTimeout returns a channel that fires after a duration that is
// between the election timeout and double the election timeout.
func (c *Clock) AfterElectionTimeout() <-chan chan struct{} {
	rand.Seed(time.Now().UnixNano())
	d := c.ElectionTimeout + time.Duration(rand.Intn(int(c.ElectionTimeout)))
	return newClockChan(d)
}

// AfterHeartbeatInterval returns a channel that fires after the heartbeat interval.
func (c *Clock) AfterHeartbeatInterval() <-chan chan struct{} {
	return newClockChan(c.HeartbeatInterval)
}

// AfterReconnectTimeout returns a channel that fires after the reconnection timeout.
func (c *Clock) AfterReconnectTimeout() <-chan chan struct{} { return newClockChan(c.ReconnectTimeout) }

// Now returns the current wall clock time.
func (c *Clock) Now() time.Time { return time.Now() }

// newClockChan returns a channel that sends a channel after a given duration.
// The channel being sent, over the channel that is returned, can be used to
// notify the sender when an action is done.
func newClockChan(d time.Duration) <-chan chan struct{} {
	ch := make(chan chan struct{}, 1)
	go func() { time.Sleep(d); ch <- make(chan struct{}) }()
	return ch
}
<|endoftext|>


<commit_before>package ram

type Type string

const (
	Custom Type = "Custom"
	System Type = "System"
)

type PolicyRequest struct {
	PolicyName     string
	PolicyType     Type
	Description    string
	PolicyDocument string
	SetAsDefault   string
	VersionId      string
}
type PolicyListResponse struct {
	RamCommonResponse
	Policies struct {
		Policy []Policy
	}
}

type PolicyResponse struct {
	RamCommonResponse
	Policy Policy
}

type PolicyQueryRequest struct {
	PolicyType Type
	Marker     string
	MaxItems   int8
}

type PolicyQueryResponse struct {
	RamCommonResponse
	IsTruncated bool
	Marker      string
	Policies    struct {
		Policy []Policy
	}
}

type PolicyVersionResponse struct {
	RamCommonResponse
	IsDefaultVersion bool
	VersionId        string
	CreateDate       string
	PolicyDocument   string
}

type AttachPolicyRequest struct {
	PolicyRequest
	UserName string
}

type AttachPolicyToRoleRequest struct {
	PolicyRequest
	RoleName string
}

type PolicyVersionResponseNew struct {
	RamCommonResponse
	PolicyVersion struct {
		IsDefaultVersion bool
		VersionId        string
		CreateDate       string
		PolicyDocument   string
	}
}

type AttachPolicyToGroupRequest struct {
	PolicyRequest
	GroupName string
}

type PolicyVersionsResponse struct {
	RamCommonResponse
	PolicyVersions struct {
		PolicyVersion []PolicyVersion
	}
}

type PolicyListEntitiesResponse struct {
	RamCommonResponse
	Groups struct {
		Group []Group
	}
	Users struct {
		User []User
	}
	Roles struct {
		Role []Role
	}
}

func (client *RamClient) CreatePolicy(policyReq PolicyRequest) (PolicyResponse, error) {
	var resp PolicyResponse
	err := client.Invoke("CreatePolicy", policyReq, &resp)
	if err != nil {
		return PolicyResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) GetPolicy(policyReq PolicyRequest) (PolicyResponse, error) {
	var resp PolicyResponse
	err := client.Invoke("GetPolicy", policyReq, &resp)
	if err != nil {
		return PolicyResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) DeletePolicy(policyReq PolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DeletePolicy", policyReq, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPolicies(policyQuery PolicyQueryRequest) (PolicyQueryResponse, error) {
	var resp PolicyQueryResponse
	err := client.Invoke("ListPolicies", policyQuery, &resp)
	if err != nil {
		return PolicyQueryResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) CreatePolicyVersion(policyReq PolicyRequest) (PolicyVersionResponse, error) {
	var resp PolicyVersionResponse
	err := client.Invoke("CreatePolicyVersion", policyReq, &resp)
	if err != nil {
		return PolicyVersionResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) GetPolicyVersion(policyReq PolicyRequest) (PolicyVersionResponse, error) {
	var resp PolicyVersionResponse
	err := client.Invoke("GetPolicyVersion", policyReq, &resp)
	if err != nil {
		return PolicyVersionResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) GetPolicyVersionNew(policyReq PolicyRequest) (PolicyVersionResponseNew, error) {
	var resp PolicyVersionResponseNew
	err := client.Invoke("GetPolicyVersion", policyReq, &resp)
	if err != nil {
		return PolicyVersionResponseNew{}, err
	}
	return resp, nil
}

func (client *RamClient) DeletePolicyVersion(policyReq PolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DeletePolicyVersion", policyReq, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPolicyVersions(policyReq PolicyRequest) (PolicyVersionResponse, error) {
	var resp PolicyVersionResponse
	err := client.Invoke("ListPolicyVersions", policyReq, &resp)
	if err != nil {
		return PolicyVersionResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPolicyVersionsNew(policyReq PolicyRequest) (PolicyVersionsResponse, error) {
	var resp PolicyVersionsResponse
	err := client.Invoke("ListPolicyVersions", policyReq, &resp)
	if err != nil {
		return PolicyVersionsResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) SetDefaultPolicyVersion(policyReq PolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("SetDefaultPolicyVersion", policyReq, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) AttachPolicyToUser(attachPolicyRequest AttachPolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("AttachPolicyToUser", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) DetachPolicyFromUser(attachPolicyRequest AttachPolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DetachPolicyFromUser", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListEntitiesForPolicy(policyReq PolicyRequest) (PolicyListEntitiesResponse, error) {
	var resp PolicyListEntitiesResponse
	err := client.Invoke("ListEntitiesForPolicy", policyReq, &resp)
	if err != nil {
		return PolicyListEntitiesResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPoliciesForUser(userQuery UserQueryRequest) (PolicyListResponse, error) {
	var resp PolicyListResponse
	err := client.Invoke("ListPoliciesForUser", userQuery, &resp)
	if err != nil {
		return PolicyListResponse{}, err
	}
	return resp, nil
}

//
//Role related
//
func (client *RamClient) AttachPolicyToRole(attachPolicyRequest AttachPolicyToRoleRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("AttachPolicyToRole", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) DetachPolicyFromRole(attachPolicyRequest AttachPolicyToRoleRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DetachPolicyFromRole", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPoliciesForRole(roleQuery RoleQueryRequest) (PolicyListResponse, error) {
	var resp PolicyListResponse
	err := client.Invoke("ListPoliciesForRole", roleQuery, &resp)
	if err != nil {
		return PolicyListResponse{}, err
	}
	return resp, nil
}

//
//Group related
//
func (client *RamClient) AttachPolicyToGroup(attachPolicyRequest AttachPolicyToGroupRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("AttachPolicyToGroup", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) DetachPolicyFromGroup(attachPolicyRequest AttachPolicyToGroupRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DetachPolicyFromGroup", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPoliciesForGroup(groupQuery GroupQueryRequest) (PolicyListResponse, error) {
	var resp PolicyListResponse
	err := client.Invoke("ListPoliciesForGroup", groupQuery, &resp)
	if err != nil {
		return PolicyListResponse{}, err
	}
	return resp, nil
}
<commit_msg>add DefaultPolicyVersion to PolicyResponse<commit_after>package ram

type Type string

const (
	Custom Type = "Custom"
	System Type = "System"
)

type PolicyRequest struct {
	PolicyName     string
	PolicyType     Type
	Description    string
	PolicyDocument string
	SetAsDefault   string
	VersionId      string
}
type PolicyListResponse struct {
	RamCommonResponse
	Policies struct {
		Policy []Policy
	}
}

type PolicyResponse struct {
	RamCommonResponse
	Policy               Policy
	DefaultPolicyVersion PolicyVersion
}

type PolicyQueryRequest struct {
	PolicyType Type
	Marker     string
	MaxItems   int8
}

type PolicyQueryResponse struct {
	RamCommonResponse
	IsTruncated bool
	Marker      string
	Policies    struct {
		Policy []Policy
	}
}

type PolicyVersionResponse struct {
	RamCommonResponse
	IsDefaultVersion bool
	VersionId        string
	CreateDate       string
	PolicyDocument   string
}

type AttachPolicyRequest struct {
	PolicyRequest
	UserName string
}

type AttachPolicyToRoleRequest struct {
	PolicyRequest
	RoleName string
}

type PolicyVersionResponseNew struct {
	RamCommonResponse
	PolicyVersion struct {
		IsDefaultVersion bool
		VersionId        string
		CreateDate       string
		PolicyDocument   string
	}
}

type AttachPolicyToGroupRequest struct {
	PolicyRequest
	GroupName string
}

type PolicyVersionsResponse struct {
	RamCommonResponse
	PolicyVersions struct {
		PolicyVersion []PolicyVersion
	}
}

type PolicyListEntitiesResponse struct {
	RamCommonResponse
	Groups struct {
		Group []Group
	}
	Users struct {
		User []User
	}
	Roles struct {
		Role []Role
	}
}

func (client *RamClient) CreatePolicy(policyReq PolicyRequest) (PolicyResponse, error) {
	var resp PolicyResponse
	err := client.Invoke("CreatePolicy", policyReq, &resp)
	if err != nil {
		return PolicyResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) GetPolicy(policyReq PolicyRequest) (PolicyResponse, error) {
	var resp PolicyResponse
	err := client.Invoke("GetPolicy", policyReq, &resp)
	if err != nil {
		return PolicyResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) DeletePolicy(policyReq PolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DeletePolicy", policyReq, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPolicies(policyQuery PolicyQueryRequest) (PolicyQueryResponse, error) {
	var resp PolicyQueryResponse
	err := client.Invoke("ListPolicies", policyQuery, &resp)
	if err != nil {
		return PolicyQueryResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) CreatePolicyVersion(policyReq PolicyRequest) (PolicyVersionResponse, error) {
	var resp PolicyVersionResponse
	err := client.Invoke("CreatePolicyVersion", policyReq, &resp)
	if err != nil {
		return PolicyVersionResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) GetPolicyVersion(policyReq PolicyRequest) (PolicyVersionResponse, error) {
	var resp PolicyVersionResponse
	err := client.Invoke("GetPolicyVersion", policyReq, &resp)
	if err != nil {
		return PolicyVersionResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) GetPolicyVersionNew(policyReq PolicyRequest) (PolicyVersionResponseNew, error) {
	var resp PolicyVersionResponseNew
	err := client.Invoke("GetPolicyVersion", policyReq, &resp)
	if err != nil {
		return PolicyVersionResponseNew{}, err
	}
	return resp, nil
}

func (client *RamClient) DeletePolicyVersion(policyReq PolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DeletePolicyVersion", policyReq, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPolicyVersions(policyReq PolicyRequest) (PolicyVersionResponse, error) {
	var resp PolicyVersionResponse
	err := client.Invoke("ListPolicyVersions", policyReq, &resp)
	if err != nil {
		return PolicyVersionResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPolicyVersionsNew(policyReq PolicyRequest) (PolicyVersionsResponse, error) {
	var resp PolicyVersionsResponse
	err := client.Invoke("ListPolicyVersions", policyReq, &resp)
	if err != nil {
		return PolicyVersionsResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) SetDefaultPolicyVersion(policyReq PolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("SetDefaultPolicyVersion", policyReq, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) AttachPolicyToUser(attachPolicyRequest AttachPolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("AttachPolicyToUser", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) DetachPolicyFromUser(attachPolicyRequest AttachPolicyRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DetachPolicyFromUser", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListEntitiesForPolicy(policyReq PolicyRequest) (PolicyListEntitiesResponse, error) {
	var resp PolicyListEntitiesResponse
	err := client.Invoke("ListEntitiesForPolicy", policyReq, &resp)
	if err != nil {
		return PolicyListEntitiesResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPoliciesForUser(userQuery UserQueryRequest) (PolicyListResponse, error) {
	var resp PolicyListResponse
	err := client.Invoke("ListPoliciesForUser", userQuery, &resp)
	if err != nil {
		return PolicyListResponse{}, err
	}
	return resp, nil
}

//
//Role related
//
func (client *RamClient) AttachPolicyToRole(attachPolicyRequest AttachPolicyToRoleRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("AttachPolicyToRole", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) DetachPolicyFromRole(attachPolicyRequest AttachPolicyToRoleRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DetachPolicyFromRole", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPoliciesForRole(roleQuery RoleQueryRequest) (PolicyListResponse, error) {
	var resp PolicyListResponse
	err := client.Invoke("ListPoliciesForRole", roleQuery, &resp)
	if err != nil {
		return PolicyListResponse{}, err
	}
	return resp, nil
}

//
//Group related
//
func (client *RamClient) AttachPolicyToGroup(attachPolicyRequest AttachPolicyToGroupRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("AttachPolicyToGroup", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) DetachPolicyFromGroup(attachPolicyRequest AttachPolicyToGroupRequest) (RamCommonResponse, error) {
	var resp RamCommonResponse
	err := client.Invoke("DetachPolicyFromGroup", attachPolicyRequest, &resp)
	if err != nil {
		return RamCommonResponse{}, err
	}
	return resp, nil
}

func (client *RamClient) ListPoliciesForGroup(groupQuery GroupQueryRequest) (PolicyListResponse, error) {
	var resp PolicyListResponse
	err := client.Invoke("ListPoliciesForGroup", groupQuery, &resp)
	if err != nil {
		return PolicyListResponse{}, err
	}
	return resp, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package widget

import (
	"github.com/richardwilkes/ui"
	"github.com/richardwilkes/ui/border"
	"github.com/richardwilkes/ui/color"
	"github.com/richardwilkes/ui/draw"
	"github.com/richardwilkes/ui/event"
	"github.com/richardwilkes/ui/geom"
	"reflect"
)

// Block is the basic graphical block in a window.
type Block struct {
	eventHandlers *event.Handlers
	window        ui.Window
	parent        ui.Widget
	children      []ui.Widget
	sizer         ui.Sizer
	layout        ui.Layout
	border        border.Border
	bounds        geom.Rect
	layoutData    interface{}
	background    color.Color
	needLayout    bool
	disabled      bool
	focusable     bool
	padding       bool // Just here to quiet aligncheck, since there is nothing I can do about it
}

// NewBlock creates a new, empty block.
func NewBlock() *Block {
	return &Block{}
}

// EventHandlers implements the event.Target interface.
func (b *Block) EventHandlers() *event.Handlers {
	if b.eventHandlers == nil {
		b.eventHandlers = &event.Handlers{}
	}
	return b.eventHandlers
}

// ParentTarget implements the event.Target interface.
func (b *Block) ParentTarget() event.Target {
	if b.parent != nil {
		return b.parent
	}
	return b.window
}

// Sizer implements the Widget interface.
func (b *Block) Sizer() ui.Sizer {
	return b.sizer
}

// SetSizer implements the Widget interface.
func (b *Block) SetSizer(sizer ui.Sizer) {
	b.sizer = sizer
}

// Layout implements the Widget interface.
func (b *Block) Layout() ui.Layout {
	return b.layout
}

// SetLayout implements the Widget interface.
func (b *Block) SetLayout(layout ui.Layout) {
	b.layout = layout
	b.SetNeedLayout(true)
}

// NeedLayout implements the Widget interface.
func (b *Block) NeedLayout() bool {
	return b.needLayout
}

// SetNeedLayout implements the Widget interface.
func (b *Block) SetNeedLayout(needLayout bool) {
	b.needLayout = needLayout
}

// LayoutData implements the Widget interface.
func (b *Block) LayoutData() interface{} {
	return b.layoutData
}

// SetLayoutData implements the Widget interface.
func (b *Block) SetLayoutData(data interface{}) {
	if b.layoutData != data {
		b.layoutData = data
		b.SetNeedLayout(true)
	}
}

// ValidateLayout implements the Widget interface.
func (b *Block) ValidateLayout() {
	if b.NeedLayout() {
		if layout := b.Layout(); layout != nil {
			layout.Layout()
			b.Repaint()
		}
		b.SetNeedLayout(false)
	}
	for _, child := range b.children {
		child.ValidateLayout()
	}
}

// Border implements the Widget interface.
func (b *Block) Border() border.Border {
	return b.border
}

// SetBorder implements the Widget interface.
func (b *Block) SetBorder(border border.Border) {
	b.border = border
}

// Repaint implements the Widget interface.
func (b *Block) Repaint() {
	b.RepaintBounds(b.LocalBounds())
}

// RepaintBounds implements the Widget interface.
func (b *Block) RepaintBounds(bounds geom.Rect) {
	bounds.Intersect(b.LocalBounds())
	if !bounds.IsEmpty() {
		if p := b.Parent(); p != nil {
			bounds.X += b.bounds.X
			bounds.Y += b.bounds.Y
			p.RepaintBounds(bounds)
		} else if b.RootOfWindow() {
			b.Window().RepaintBounds(bounds)
		}
	}
}

// Paint implements the Widget interface.
func (b *Block) Paint(g draw.Graphics, dirty geom.Rect) {
	dirty.Intersect(b.LocalBounds())
	if !dirty.IsEmpty() {
		b.paintSelf(g, dirty)
		for _, child := range b.children {
			adjusted := dirty
			adjusted.Intersect(child.Bounds())
			if !adjusted.IsEmpty() {
				b.paintChild(child, g, adjusted)
			}
		}
	}
}

func (b *Block) paintSelf(gc draw.Graphics, dirty geom.Rect) {
	gc.Save()
	gc.ClipRect(dirty)
	if b.background.Alpha() > 0 {
		gc.SetFillColor(b.background)
		gc.FillRect(dirty)
	}
	gc.Save()
	event.Dispatch(event.NewPaint(b, gc, dirty))
	gc.Restore()
	b.paintBorder(gc)
	gc.Restore()
}

func (b *Block) paintBorder(gc draw.Graphics) {
	if border := b.Border(); border != nil {
		gc.Save()
		defer gc.Restore()
		border.Draw(gc, b.LocalBounds())
	}
}

func (b *Block) paintChild(child ui.Widget, g draw.Graphics, dirty geom.Rect) {
	g.Save()
	defer g.Restore()
	bounds := child.Bounds()
	g.Translate(bounds.X, bounds.Y)
	dirty.X -= bounds.X
	dirty.Y -= bounds.Y
	child.Paint(g, dirty)
}

// Enabled implements the Widget interface.
func (b *Block) Enabled() bool {
	return !b.disabled
}

// SetEnabled implements the Widget interface.
func (b *Block) SetEnabled(enabled bool) {
	disabled := !enabled
	if b.disabled != disabled {
		b.disabled = disabled
		b.Repaint()
	}
}

// Focusable implements the Widget interface.
func (b *Block) Focusable() bool {
	return b.focusable && !b.disabled
}

// SetFocusable implements the Widget interface.
func (b *Block) SetFocusable(focusable bool) {
	if b.focusable != focusable {
		b.focusable = focusable
	}
}

// Focused implements the Widget interface.
func (b *Block) Focused() bool {
	if window := b.Window(); window != nil {
		return reflect.ValueOf(ui.Widget(b)).Pointer() == reflect.ValueOf(window.Focus()).Pointer()
	}
	return false
}

// Children implements the Widget interface.
func (b *Block) Children() []ui.Widget {
	return b.children
}

// IndexOfChild implements the Widget interface.
func (b *Block) IndexOfChild(child ui.Widget) int {
	for i, one := range b.children {
		if one == child {
			return i
		}
	}
	return -1
}

// AddChild implements the Widget interface.
func (b *Block) AddChild(child ui.Widget) {
	child.RemoveFromParent()
	b.children = append(b.children, child)
	child.SetParent(b)
	b.SetNeedLayout(true)
}

// AddChildAtIndex implements the Widget interface.
func (b *Block) AddChildAtIndex(child ui.Widget, index int) {
	child.RemoveFromParent()
	if index < 0 {
		index = 0
	}
	if index >= len(b.children) {
		b.children = append(b.children, child)
	} else {
		b.children = append(b.children, nil)
		copy(b.children[index+1:], b.children[index:])
		b.children[index] = child
	}
	child.SetParent(b)
	b.SetNeedLayout(true)
}

// RemoveChild implements the Widget interface.
func (b *Block) RemoveChild(child ui.Widget) {
	b.RemoveChildAtIndex(b.IndexOfChild(child))
}

// RemoveChildAtIndex implements the Widget interface.
func (b *Block) RemoveChildAtIndex(index int) {
	if index >= 0 && index < len(b.children) {
		child := b.children[index]
		copy(b.children[index:], b.children[index+1:])
		length := len(b.children) - 1
		b.children[length] = nil
		b.children = b.children[:length]
		b.SetNeedLayout(true)
		child.SetParent(nil)
	}
}

// RemoveFromParent implements the Widget interface.
func (b *Block) RemoveFromParent() {
	if p := b.Parent(); p != nil {
		p.RemoveChild(b)
	}
}

// Parent implements the Widget interface.
func (b *Block) Parent() ui.Widget {
	return b.parent
}

// SetParent implements the Widget interface.
func (b *Block) SetParent(parent ui.Widget) {
	b.parent = parent
}

// Window implements the Widget interface.
func (b *Block) Window() ui.Window {
	if b.window != nil {
		return b.window
	}
	if b.parent != nil {
		return b.parent.Window()
	}
	return nil
}

// RootOfWindow implements the Widget interface.
func (b *Block) RootOfWindow() bool {
	return b.window != nil
}

// Bounds implements the Widget interface.
func (b *Block) Bounds() geom.Rect {
	return b.bounds
}

// LocalBounds implements the Widget interface.
func (b *Block) LocalBounds() geom.Rect {
	return b.bounds.CopyAndZeroLocation()
}

// LocalInsetBounds implements the Widget interface.
func (b *Block) LocalInsetBounds() geom.Rect {
	bounds := b.LocalBounds()
	if border := b.Border(); border != nil {
		bounds.Inset(border.Insets())
	}
	return bounds
}

// SetBounds implements the Widget interface.
func (b *Block) SetBounds(bounds geom.Rect) {
	moved := b.bounds.X != bounds.X || b.bounds.Y != bounds.Y
	resized := b.bounds.Width != bounds.Width || b.bounds.Height != bounds.Height
	if moved || resized {
		b.Repaint()
		if moved {
			b.bounds.Point = bounds.Point
		}
		if resized {
			b.bounds.Size = bounds.Size
			b.SetNeedLayout(true)
			event.Dispatch(event.NewResized(b))
		}
		b.Repaint()
	}
}

// Location implements the Widget interface.
func (b *Block) Location() geom.Point {
	return b.bounds.Point
}

// SetLocation implements the Widget interface.
func (b *Block) SetLocation(pt geom.Point) {
	if b.bounds.Point != pt {
		b.Repaint()
		b.bounds.Point = pt
		b.Repaint()
	}
}

// Size implements the Widget interface.
func (b *Block) Size() geom.Size {
	return b.bounds.Size
}

// SetSize implements the Widget interface.
func (b *Block) SetSize(size geom.Size) {
	if b.bounds.Size != size {
		b.Repaint()
		b.bounds.Size = size
		b.SetNeedLayout(true)
		event.Dispatch(event.NewResized(b))
		b.Repaint()
	}
}

// WidgetAt implements the Widget interface.
func (b *Block) WidgetAt(pt geom.Point) ui.Widget {
	for _, child := range b.children {
		bounds := child.Bounds()
		if bounds.Contains(pt) {
			pt.Subtract(bounds.Point)
			return child.WidgetAt(pt)
		}
	}
	return b
}

// ToWindow implements the Widget interface.
func (b *Block) ToWindow(pt geom.Point) geom.Point {
	pt.Add(b.bounds.Point)
	parent := b.parent
	for parent != nil {
		pt.Add(parent.Bounds().Point)
		parent = parent.Parent()
	}
	return pt
}

// FromWindow implements the Widget interface.
func (b *Block) FromWindow(pt geom.Point) geom.Point {
	pt.Subtract(b.bounds.Point)
	parent := b.parent
	for parent != nil {
		pt.Subtract(parent.Bounds().Point)
		parent = parent.Parent()
	}
	return pt
}

// Background implements the Widget interface.
func (b *Block) Background() color.Color {
	return b.background
}

// SetBackground implements the Widget interface.
func (b *Block) SetBackground(color color.Color) {
	if color != b.background {
		b.background = color
		b.Repaint()
	}
}

// ScrollIntoView attempts to scroll the block into view.
func (b *Block) ScrollIntoView() {
	// RAW: Implement
}
<commit_msg>Always draw the border after the block and its children have drawn<commit_after>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package widget

import (
	"github.com/richardwilkes/ui"
	"github.com/richardwilkes/ui/border"
	"github.com/richardwilkes/ui/color"
	"github.com/richardwilkes/ui/draw"
	"github.com/richardwilkes/ui/event"
	"github.com/richardwilkes/ui/geom"
	"reflect"
)

// Block is the basic graphical block in a window.
type Block struct {
	eventHandlers *event.Handlers
	window        ui.Window
	parent        ui.Widget
	children      []ui.Widget
	sizer         ui.Sizer
	layout        ui.Layout
	border        border.Border
	bounds        geom.Rect
	layoutData    interface{}
	background    color.Color
	needLayout    bool
	disabled      bool
	focusable     bool
	padding       bool // Just here to quiet aligncheck, since there is nothing I can do about it
}

// NewBlock creates a new, empty block.
func NewBlock() *Block {
	return &Block{}
}

// EventHandlers implements the event.Target interface.
func (b *Block) EventHandlers() *event.Handlers {
	if b.eventHandlers == nil {
		b.eventHandlers = &event.Handlers{}
	}
	return b.eventHandlers
}

// ParentTarget implements the event.Target interface.
func (b *Block) ParentTarget() event.Target {
	if b.parent != nil {
		return b.parent
	}
	return b.window
}

// Sizer implements the Widget interface.
func (b *Block) Sizer() ui.Sizer {
	return b.sizer
}

// SetSizer implements the Widget interface.
func (b *Block) SetSizer(sizer ui.Sizer) {
	b.sizer = sizer
}

// Layout implements the Widget interface.
func (b *Block) Layout() ui.Layout {
	return b.layout
}

// SetLayout implements the Widget interface.
func (b *Block) SetLayout(layout ui.Layout) {
	b.layout = layout
	b.SetNeedLayout(true)
}

// NeedLayout implements the Widget interface.
func (b *Block) NeedLayout() bool {
	return b.needLayout
}

// SetNeedLayout implements the Widget interface.
func (b *Block) SetNeedLayout(needLayout bool) {
	b.needLayout = needLayout
}

// LayoutData implements the Widget interface.
func (b *Block) LayoutData() interface{} {
	return b.layoutData
}

// SetLayoutData implements the Widget interface.
func (b *Block) SetLayoutData(data interface{}) {
	if b.layoutData != data {
		b.layoutData = data
		b.SetNeedLayout(true)
	}
}

// ValidateLayout implements the Widget interface.
func (b *Block) ValidateLayout() {
	if b.NeedLayout() {
		if layout := b.Layout(); layout != nil {
			layout.Layout()
			b.Repaint()
		}
		b.SetNeedLayout(false)
	}
	for _, child := range b.children {
		child.ValidateLayout()
	}
}

// Border implements the Widget interface.
func (b *Block) Border() border.Border {
	return b.border
}

// SetBorder implements the Widget interface.
func (b *Block) SetBorder(border border.Border) {
	b.border = border
}

// Repaint implements the Widget interface.
func (b *Block) Repaint() {
	b.RepaintBounds(b.LocalBounds())
}

// RepaintBounds implements the Widget interface.
func (b *Block) RepaintBounds(bounds geom.Rect) {
	bounds.Intersect(b.LocalBounds())
	if !bounds.IsEmpty() {
		if p := b.Parent(); p != nil {
			bounds.X += b.bounds.X
			bounds.Y += b.bounds.Y
			p.RepaintBounds(bounds)
		} else if b.RootOfWindow() {
			b.Window().RepaintBounds(bounds)
		}
	}
}

// Paint implements the Widget interface.
func (b *Block) Paint(g draw.Graphics, dirty geom.Rect) {
	dirty.Intersect(b.LocalBounds())
	if !dirty.IsEmpty() {
		b.paintSelf(g, dirty)
		for _, child := range b.children {
			adjusted := dirty
			adjusted.Intersect(child.Bounds())
			if !adjusted.IsEmpty() {
				b.paintChild(child, g, adjusted)
			}
		}
		b.paintBorder(g)
	}
}

func (b *Block) paintSelf(gc draw.Graphics, dirty geom.Rect) {
	gc.Save()
	gc.ClipRect(dirty)
	if b.background.Alpha() > 0 {
		gc.SetFillColor(b.background)
		gc.FillRect(dirty)
	}
	event.Dispatch(event.NewPaint(b, gc, dirty))
	gc.Restore()
}

func (b *Block) paintBorder(gc draw.Graphics) {
	if border := b.Border(); border != nil {
		gc.Save()
		defer gc.Restore()
		border.Draw(gc, b.LocalBounds())
	}
}

func (b *Block) paintChild(child ui.Widget, g draw.Graphics, dirty geom.Rect) {
	g.Save()
	defer g.Restore()
	bounds := child.Bounds()
	g.Translate(bounds.X, bounds.Y)
	dirty.X -= bounds.X
	dirty.Y -= bounds.Y
	child.Paint(g, dirty)
}

// Enabled implements the Widget interface.
func (b *Block) Enabled() bool {
	return !b.disabled
}

// SetEnabled implements the Widget interface.
func (b *Block) SetEnabled(enabled bool) {
	disabled := !enabled
	if b.disabled != disabled {
		b.disabled = disabled
		b.Repaint()
	}
}

// Focusable implements the Widget interface.
func (b *Block) Focusable() bool {
	return b.focusable && !b.disabled
}

// SetFocusable implements the Widget interface.
func (b *Block) SetFocusable(focusable bool) {
	if b.focusable != focusable {
		b.focusable = focusable
	}
}

// Focused implements the Widget interface.
func (b *Block) Focused() bool {
	if window := b.Window(); window != nil {
		return reflect.ValueOf(ui.Widget(b)).Pointer() == reflect.ValueOf(window.Focus()).Pointer()
	}
	return false
}

// Children implements the Widget interface.
func (b *Block) Children() []ui.Widget {
	return b.children
}

// IndexOfChild implements the Widget interface.
func (b *Block) IndexOfChild(child ui.Widget) int {
	for i, one := range b.children {
		if one == child {
			return i
		}
	}
	return -1
}

// AddChild implements the Widget interface.
func (b *Block) AddChild(child ui.Widget) {
	child.RemoveFromParent()
	b.children = append(b.children, child)
	child.SetParent(b)
	b.SetNeedLayout(true)
}

// AddChildAtIndex implements the Widget interface.
func (b *Block) AddChildAtIndex(child ui.Widget, index int) {
	child.RemoveFromParent()
	if index < 0 {
		index = 0
	}
	if index >= len(b.children) {
		b.children = append(b.children, child)
	} else {
		b.children = append(b.children, nil)
		copy(b.children[index+1:], b.children[index:])
		b.children[index] = child
	}
	child.SetParent(b)
	b.SetNeedLayout(true)
}

// RemoveChild implements the Widget interface.
func (b *Block) RemoveChild(child ui.Widget) {
	b.RemoveChildAtIndex(b.IndexOfChild(child))
}

// RemoveChildAtIndex implements the Widget interface.
func (b *Block) RemoveChildAtIndex(index int) {
	if index >= 0 && index < len(b.children) {
		child := b.children[index]
		copy(b.children[index:], b.children[index+1:])
		length := len(b.children) - 1
		b.children[length] = nil
		b.children = b.children[:length]
		b.SetNeedLayout(true)
		child.SetParent(nil)
	}
}

// RemoveFromParent implements the Widget interface.
func (b *Block) RemoveFromParent() {
	if p := b.Parent(); p != nil {
		p.RemoveChild(b)
	}
}

// Parent implements the Widget interface.
func (b *Block) Parent() ui.Widget {
	return b.parent
}

// SetParent implements the Widget interface.
func (b *Block) SetParent(parent ui.Widget) {
	b.parent = parent
}

// Window implements the Widget interface.
func (b *Block) Window() ui.Window {
	if b.window != nil {
		return b.window
	}
	if b.parent != nil {
		return b.parent.Window()
	}
	return nil
}

// RootOfWindow implements the Widget interface.
func (b *Block) RootOfWindow() bool {
	return b.window != nil
}

// Bounds implements the Widget interface.
func (b *Block) Bounds() geom.Rect {
	return b.bounds
}

// LocalBounds implements the Widget interface.
func (b *Block) LocalBounds() geom.Rect {
	return b.bounds.CopyAndZeroLocation()
}

// LocalInsetBounds implements the Widget interface.
func (b *Block) LocalInsetBounds() geom.Rect {
	bounds := b.LocalBounds()
	if border := b.Border(); border != nil {
		bounds.Inset(border.Insets())
	}
	return bounds
}

// SetBounds implements the Widget interface.
func (b *Block) SetBounds(bounds geom.Rect) {
	moved := b.bounds.X != bounds.X || b.bounds.Y != bounds.Y
	resized := b.bounds.Width != bounds.Width || b.bounds.Height != bounds.Height
	if moved || resized {
		b.Repaint()
		if moved {
			b.bounds.Point = bounds.Point
		}
		if resized {
			b.bounds.Size = bounds.Size
			b.SetNeedLayout(true)
			event.Dispatch(event.NewResized(b))
		}
		b.Repaint()
	}
}

// Location implements the Widget interface.
func (b *Block) Location() geom.Point {
	return b.bounds.Point
}

// SetLocation implements the Widget interface.
func (b *Block) SetLocation(pt geom.Point) {
	if b.bounds.Point != pt {
		b.Repaint()
		b.bounds.Point = pt
		b.Repaint()
	}
}

// Size implements the Widget interface.
func (b *Block) Size() geom.Size {
	return b.bounds.Size
}

// SetSize implements the Widget interface.
func (b *Block) SetSize(size geom.Size) {
	if b.bounds.Size != size {
		b.Repaint()
		b.bounds.Size = size
		b.SetNeedLayout(true)
		event.Dispatch(event.NewResized(b))
		b.Repaint()
	}
}

// WidgetAt implements the Widget interface.
func (b *Block) WidgetAt(pt geom.Point) ui.Widget {
	for _, child := range b.children {
		bounds := child.Bounds()
		if bounds.Contains(pt) {
			pt.Subtract(bounds.Point)
			return child.WidgetAt(pt)
		}
	}
	return b
}

// ToWindow implements the Widget interface.
func (b *Block) ToWindow(pt geom.Point) geom.Point {
	pt.Add(b.bounds.Point)
	parent := b.parent
	for parent != nil {
		pt.Add(parent.Bounds().Point)
		parent = parent.Parent()
	}
	return pt
}

// FromWindow implements the Widget interface.
func (b *Block) FromWindow(pt geom.Point) geom.Point {
	pt.Subtract(b.bounds.Point)
	parent := b.parent
	for parent != nil {
		pt.Subtract(parent.Bounds().Point)
		parent = parent.Parent()
	}
	return pt
}

// Background implements the Widget interface.
func (b *Block) Background() color.Color {
	return b.background
}

// SetBackground implements the Widget interface.
func (b *Block) SetBackground(color color.Color) {
	if color != b.background {
		b.background = color
		b.Repaint()
	}
}

// ScrollIntoView attempts to scroll the block into view.
func (b *Block) ScrollIntoView() {
	// RAW: Implement
}
<|endoftext|>


<commit_before>package data_types

import (
	"time"
)

type SoftLayer_Virtual_Guest_Parameters struct {
	Parameters []SoftLayer_Virtual_Guest `json:"parameters"`
}

type SoftLayer_Virtual_Guest struct {
	AccountId                    int        `json:"accountId,omitempty"`
	CreateDate                   *time.Time `json:"createDate,omitempty"`
	DedicatedAccountHostOnlyFlag bool       `json:"dedicatedAccountHostOnlyFlag,omitempty"`
	Domain                       string     `json:"domain,omitempty"`
	FullyQualifiedDomainName     string     `json:"fullyQualifiedDomainName,omitempty"`
	Hostname                     string     `json:"hostname,omitempty"`
	Id                           int        `json:"id,omitempty"`
	LastPowerStateId             int        `json:"lastPowerStateId,omitempty"`
	LastVerifiedDate             *time.Time `json:"lastVerifiedDate,omitempty"`
	MaxCpu                       int        `json:"maxCpu,omitempty"`
	MaxCpuUnits                  string     `json:"maxCpuUnits,omitempty"`
	MaxMemory                    int        `json:"maxMemory,omitempty"`
	MetricPollDate               *time.Time `json:"metricPollDate,omitempty"`
	ModifyDate                   *time.Time `json:"modifyDate,omitempty"`
	Notes                        string     `json:"notes,omitempty"`
	PostInstallScriptUri         string     `json:"postInstallScriptUri,omitempty"`
	PrivateNetworkOnlyFlag       bool       `json:"privateNetworkOnlyFlag,omitempty"`
	StartCpus                    int        `json:"startCpus,omitempty"`
	StatusId                     int        `json:"statusId,omitempty"`
	Uuid                         string     `json:"uuid,omitempty"`
	LocalDiskFlag                bool       `json:"localDiskFlag,omitempty"`
	HourlyBillingFlag            bool       `json:"hourlyBillingFlag,omitempty"`

	GlobalIdentifier        string `json:"globalIdentifier,omitempty"`
	ManagedResourceFlag     bool   `json:"managedResourceFlag,omitempty"`
	PrimaryBackendIpAddress string `json:"primaryBackendIpAddress,omitempty"`
	PrimaryIpAddress        string `json:"primaryIpAddress,omitempty"`

	PrimaryNetworkComponent        *SoftLayer_Virtual_Guest_Network_Component `json:"primaryNetworkComponent,omitempty"`
	PrimaryBackendNetworkComponent *SoftLayer_Virtual_Guest_Network_Component `json:"primaryBackendNetworkComponent,omitempty"`

	Location          *SoftLayer_Location                         `json:"location"`
	Datacenter        *SoftLayer_Location                         `json:"datacenter"`
	NetworkComponents []SoftLayer_Virtual_Guest_Network_Component `json:"networkComponents,omitempty"`
	UserData          []UserData                                  `json:"userData,omitempty"`

	OperatingSystem *SoftLayer_Operating_System `json:"operatingSystem"`

	BlockDeviceTemplateGroup *BlockDeviceTemplateGroup `json:"blockDeviceTemplateGroup,omitempty"`
}

type SoftLayer_Operating_System struct {
	Passwords []SoftLayer_Password `json:"passwords"`
}

type SoftLayer_Password struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type SoftLayer_Virtual_Guest_Template_Parameters struct {
	Parameters []SoftLayer_Virtual_Guest_Template `json:"parameters"`
}

type SoftLayer_Virtual_Guest_Template struct {
	//Required
	Hostname          string     `json:"hostname"`
	Domain            string     `json:"domain"`
	StartCpus         int        `json:"startCpus"`
	MaxMemory         int        `json:"maxMemory"`
	Datacenter        Datacenter `json:"datacenter"`
	HourlyBillingFlag bool       `json:"hourlyBillingFlag"`
	LocalDiskFlag     bool       `json:"localDiskFlag"`

	//Conditionally required
	OperatingSystemReferenceCode string                    `json:"operatingSystemReferenceCode,omitempty"`
	BlockDeviceTemplateGroup     *BlockDeviceTemplateGroup `json:"blockDeviceTemplateGroup,omitempty"`

	//Optional
	DedicatedAccountHostOnlyFlag   bool                            `json:"dedicatedAccountHostOnlyFlag,omitempty"`
	NetworkComponents              []NetworkComponents             `json:"networkComponents,omitempty"`
	PrivateNetworkOnlyFlag         bool                            `json:"privateNetworkOnlyFlag,omitempty"`
	PrimaryNetworkComponent        *PrimaryNetworkComponent        `json:"primaryNetworkComponent,omitempty"`
	PrimaryBackendNetworkComponent *PrimaryBackendNetworkComponent `json:"primaryBackendNetworkComponent,omitempty"`
	PostInstallScriptUri           string                          `json:"postInstallScriptUri,omitempty"`

	BlockDevices []BlockDevice `json:"blockDevices,omitempty"`
	UserData     []UserData    `json:"userData,omitempty"`
	SshKeys      []SshKey      `json:"sshKeys,omitempty"`
}

type Datacenter struct {
	//Required
	Name string `json:"name"`
}

type NetworkVlan struct {
	//Required
	Id int `json:"id,omitempty"`
}

type PrimaryNetworkComponent struct {
	//Required
	NetworkVlan NetworkVlan `json:"networkVlan,omitempty"`
}

type PrimaryBackendNetworkComponent struct {
	//Required
	NetworkVlan NetworkVlan `json:"networkVlan,omitempty"`
}

type BlockDeviceTemplateGroup struct {
	//Required
	GlobalIdentifier string `json:"globalIdentifier,omitempty"`
}

type NetworkComponents struct {
	//Required, defaults to 10
	MaxSpeed int `json:"maxSpeed,omitempty"`
}

type DiskImage struct {
	//Required
	Capacity int `json:"capacity,omitempty"`
}

type BlockDevice struct {
	//Required
	Device    string    `json:"device,omitempty"`
	DiskImage DiskImage `json:"diskImage,omitempty"`
}

type UserData struct {
	//Required
	Value string `json:"value,omitempty"`
}

type SshKey struct {
	//Required
	Id int `json:"id,omitempty"`
}

type SoftLayer_Virtual_Guest_SetTags_Parameters struct {
	Parameters []string `json:"parameters"`
}

type Image_Template_Config struct {
	ImageTemplateId string `json:"imageTemplateId"`
}
<commit_msg>Add PrimarySubnetId property in NetworkVlan<commit_after>package data_types

import (
	"time"
)

type SoftLayer_Virtual_Guest_Parameters struct {
	Parameters []SoftLayer_Virtual_Guest `json:"parameters"`
}

type SoftLayer_Virtual_Guest struct {
	AccountId                    int        `json:"accountId,omitempty"`
	CreateDate                   *time.Time `json:"createDate,omitempty"`
	DedicatedAccountHostOnlyFlag bool       `json:"dedicatedAccountHostOnlyFlag,omitempty"`
	Domain                       string     `json:"domain,omitempty"`
	FullyQualifiedDomainName     string     `json:"fullyQualifiedDomainName,omitempty"`
	Hostname                     string     `json:"hostname,omitempty"`
	Id                           int        `json:"id,omitempty"`
	LastPowerStateId             int        `json:"lastPowerStateId,omitempty"`
	LastVerifiedDate             *time.Time `json:"lastVerifiedDate,omitempty"`
	MaxCpu                       int        `json:"maxCpu,omitempty"`
	MaxCpuUnits                  string     `json:"maxCpuUnits,omitempty"`
	MaxMemory                    int        `json:"maxMemory,omitempty"`
	MetricPollDate               *time.Time `json:"metricPollDate,omitempty"`
	ModifyDate                   *time.Time `json:"modifyDate,omitempty"`
	Notes                        string     `json:"notes,omitempty"`
	PostInstallScriptUri         string     `json:"postInstallScriptUri,omitempty"`
	PrivateNetworkOnlyFlag       bool       `json:"privateNetworkOnlyFlag,omitempty"`
	StartCpus                    int        `json:"startCpus,omitempty"`
	StatusId                     int        `json:"statusId,omitempty"`
	Uuid                         string     `json:"uuid,omitempty"`
	LocalDiskFlag                bool       `json:"localDiskFlag,omitempty"`
	HourlyBillingFlag            bool       `json:"hourlyBillingFlag,omitempty"`

	GlobalIdentifier        string `json:"globalIdentifier,omitempty"`
	ManagedResourceFlag     bool   `json:"managedResourceFlag,omitempty"`
	PrimaryBackendIpAddress string `json:"primaryBackendIpAddress,omitempty"`
	PrimaryIpAddress        string `json:"primaryIpAddress,omitempty"`

	PrimaryNetworkComponent        *SoftLayer_Virtual_Guest_Network_Component `json:"primaryNetworkComponent,omitempty"`
	PrimaryBackendNetworkComponent *SoftLayer_Virtual_Guest_Network_Component `json:"primaryBackendNetworkComponent,omitempty"`

	Location          *SoftLayer_Location                         `json:"location"`
	Datacenter        *SoftLayer_Location                         `json:"datacenter"`
	NetworkComponents []SoftLayer_Virtual_Guest_Network_Component `json:"networkComponents,omitempty"`
	UserData          []UserData                                  `json:"userData,omitempty"`

	OperatingSystem *SoftLayer_Operating_System `json:"operatingSystem"`

	BlockDeviceTemplateGroup *BlockDeviceTemplateGroup `json:"blockDeviceTemplateGroup,omitempty"`
}

type SoftLayer_Operating_System struct {
	Passwords []SoftLayer_Password `json:"passwords"`
}

type SoftLayer_Password struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type SoftLayer_Virtual_Guest_Template_Parameters struct {
	Parameters []SoftLayer_Virtual_Guest_Template `json:"parameters"`
}

type SoftLayer_Virtual_Guest_Template struct {
	//Required
	Hostname          string     `json:"hostname"`
	Domain            string     `json:"domain"`
	StartCpus         int        `json:"startCpus"`
	MaxMemory         int        `json:"maxMemory"`
	Datacenter        Datacenter `json:"datacenter"`
	HourlyBillingFlag bool       `json:"hourlyBillingFlag"`
	LocalDiskFlag     bool       `json:"localDiskFlag"`

	//Conditionally required
	OperatingSystemReferenceCode string                    `json:"operatingSystemReferenceCode,omitempty"`
	BlockDeviceTemplateGroup     *BlockDeviceTemplateGroup `json:"blockDeviceTemplateGroup,omitempty"`

	//Optional
	DedicatedAccountHostOnlyFlag   bool                            `json:"dedicatedAccountHostOnlyFlag,omitempty"`
	NetworkComponents              []NetworkComponents             `json:"networkComponents,omitempty"`
	PrivateNetworkOnlyFlag         bool                            `json:"privateNetworkOnlyFlag,omitempty"`
	PrimaryNetworkComponent        *PrimaryNetworkComponent        `json:"primaryNetworkComponent,omitempty"`
	PrimaryBackendNetworkComponent *PrimaryBackendNetworkComponent `json:"primaryBackendNetworkComponent,omitempty"`
	PostInstallScriptUri           string                          `json:"postInstallScriptUri,omitempty"`

	BlockDevices []BlockDevice `json:"blockDevices,omitempty"`
	UserData     []UserData    `json:"userData,omitempty"`
	SshKeys      []SshKey      `json:"sshKeys,omitempty"`
}

type Datacenter struct {
	//Required
	Name string `json:"name"`
}

type NetworkVlan struct {
	//Required
	Id              int `json:"id,omitempty"`
	PrimarySubnetId int `json:"primarySubnetId,omitempty"`
}

type PrimaryNetworkComponent struct {
	//Required
	NetworkVlan NetworkVlan `json:"networkVlan,omitempty"`
}

type PrimaryBackendNetworkComponent struct {
	//Required
	NetworkVlan NetworkVlan `json:"networkVlan,omitempty"`
}

type BlockDeviceTemplateGroup struct {
	//Required
	GlobalIdentifier string `json:"globalIdentifier,omitempty"`
}

type NetworkComponents struct {
	//Required, defaults to 10
	MaxSpeed int `json:"maxSpeed,omitempty"`
}

type DiskImage struct {
	//Required
	Capacity int `json:"capacity,omitempty"`
}

type BlockDevice struct {
	//Required
	Device    string    `json:"device,omitempty"`
	DiskImage DiskImage `json:"diskImage,omitempty"`
}

type UserData struct {
	//Required
	Value string `json:"value,omitempty"`
}

type SshKey struct {
	//Required
	Id int `json:"id,omitempty"`
}

type SoftLayer_Virtual_Guest_SetTags_Parameters struct {
	Parameters []string `json:"parameters"`
}

type Image_Template_Config struct {
	ImageTemplateId string `json:"imageTemplateId"`
}
<|endoftext|>


<commit_before>package rmarsh_test

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"math/big"
	"testing"

	"github.com/samcday/rmarsh"
)

func testGenerator(t *testing.T, exp string, f func(gen *rmarsh.Generator) error) {
	b := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(b)
	if err := f(gen); err != nil {
		t.Fatal(err)
	}

	str := rbDecode(t, b.Bytes())
	if str != exp {
		t.Fatalf("Generated stream %s != %s\nRaw marshal:\n%s\n", str, exp, hex.Dump(b.Bytes()))
	}
}

func TestGenNil(t *testing.T) {
	testGenerator(t, "nil", func(gen *rmarsh.Generator) error {
		return gen.Nil()
	})
}

func BenchmarkGenNil(b *testing.B) {
	buf := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(buf)

	for i := 0; i < b.N; i++ {
		buf.Reset()
		gen.Reset()

		if err := gen.Nil(); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenOverflow(t *testing.T) {
	b := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(b)
	if err := gen.Nil(); err != nil {
		t.Fatal(err)
	}
	if err := gen.Nil(); err != rmarsh.ErrGeneratorFinished {
		t.Fatalf("Err %s != rmarsh.ErrGeneratorFinished", err)
	}
}

func TestGenBool(t *testing.T) {
	testGenerator(t, "true", func(gen *rmarsh.Generator) error {
		return gen.Bool(true)
	})
	testGenerator(t, "false", func(gen *rmarsh.Generator) error {
		return gen.Bool(false)
	})
}

func BenchmarkGenBool(b *testing.B) {
	buf := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(buf)

	for i := 0; i < b.N; i++ {
		buf.Reset()
		gen.Reset()

		if err := gen.Bool(true); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenFixnums(t *testing.T) {
	testGenerator(t, "123", func(gen *rmarsh.Generator) error {
		return gen.Fixnum(123)
	})
	testGenerator(t, "666", func(gen *rmarsh.Generator) error {
		return gen.Fixnum(666)
	})
	testGenerator(t, fmt.Sprintf("%d", 0xDEADCAFEBEEF), func(gen *rmarsh.Generator) error {
		return gen.Fixnum(0xDEADCAFEBEEF)
	})
}

func BenchmarkGenFixnum(b *testing.B) {
	buf := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(buf)

	for i := 0; i < b.N; i++ {
		buf.Reset()
		gen.Reset()

		if err := gen.Fixnum(123); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenBignum(t *testing.T) {
	var bigpos, bigneg big.Int
	bigpos.SetString("+DEADCAFEBEEFEEBAE", 16)
	bigneg.SetString("-DEADCAFEBEEFEEBAE", 16)
	testGenerator(t, bigpos.String(), func(gen *rmarsh.Generator) error {
		return gen.Bignum(&bigpos)
	})
	testGenerator(t, bigneg.String(), func(gen *rmarsh.Generator) error {
		return gen.Bignum(&bigneg)
	})
}

func BenchmarkGenBignum(b *testing.B) {
	buf := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(buf)
	var bnum big.Int
	bnum.SetString("DEADCAFEBEEFEEBAE", 16)

	for i := 0; i < b.N; i++ {
		buf.Reset()
		gen.Reset()

		if err := gen.Bignum(&bnum); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenSymbol(t *testing.T) {
	testGenerator(t, ":test", func(gen *rmarsh.Generator) error {
		return gen.Symbol("test")
	})
}

func BenchmarkGenSymbol(b *testing.B) {
	buf := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(buf)

	for i := 0; i < b.N; i++ {
		buf.Reset()
		gen.Reset()

		if err := gen.Symbol("test"); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenString(t *testing.T) {
	testGenerator(t, `"foobar"`, func(gen *rmarsh.Generator) error {
		return gen.String("foobar")
	})
}

func BenchmarkGenString(b *testing.B) {
	buf := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(buf)

	for i := 0; i < b.N; i++ {
		buf.Reset()
		gen.Reset()

		if err := gen.String("test"); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenFloat(t *testing.T) {
	testGenerator(t, `123.123123123`, func(gen *rmarsh.Generator) error {
		return gen.Float(123.123123123)
	})
}

func BenchmarkGenFloat(b *testing.B) {
	buf := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(buf)

	for i := 0; i < b.N; i++ {
		buf.Reset()
		gen.Reset()

		if err := gen.Float(123.123123123); err != nil {
			b.Fatal(err)
		}
	}
}
<commit_msg>generator: use ioutil.Discard for writing<commit_after>package rmarsh_test

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"math/big"
	"testing"

	"github.com/samcday/rmarsh"
)

func testGenerator(t *testing.T, exp string, f func(gen *rmarsh.Generator) error) {
	b := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(b)
	if err := f(gen); err != nil {
		t.Fatal(err)
	}

	str := rbDecode(t, b.Bytes())
	if str != exp {
		t.Fatalf("Generated stream %s != %s\nRaw marshal:\n%s\n", str, exp, hex.Dump(b.Bytes()))
	}
}

func TestGenNil(t *testing.T) {
	testGenerator(t, "nil", func(gen *rmarsh.Generator) error {
		return gen.Nil()
	})
}

func BenchmarkGenNil(b *testing.B) {
	gen := rmarsh.NewGenerator(ioutil.Discard)

	for i := 0; i < b.N; i++ {
		gen.Reset()

		if err := gen.Nil(); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenOverflow(t *testing.T) {
	b := new(bytes.Buffer)
	gen := rmarsh.NewGenerator(b)
	if err := gen.Nil(); err != nil {
		t.Fatal(err)
	}
	if err := gen.Nil(); err != rmarsh.ErrGeneratorFinished {
		t.Fatalf("Err %s != rmarsh.ErrGeneratorFinished", err)
	}
}

func TestGenBool(t *testing.T) {
	testGenerator(t, "true", func(gen *rmarsh.Generator) error {
		return gen.Bool(true)
	})
	testGenerator(t, "false", func(gen *rmarsh.Generator) error {
		return gen.Bool(false)
	})
}

func BenchmarkGenBool(b *testing.B) {
	gen := rmarsh.NewGenerator(ioutil.Discard)

	for i := 0; i < b.N; i++ {
		gen.Reset()

		if err := gen.Bool(true); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenFixnums(t *testing.T) {
	testGenerator(t, "123", func(gen *rmarsh.Generator) error {
		return gen.Fixnum(123)
	})
	testGenerator(t, "666", func(gen *rmarsh.Generator) error {
		return gen.Fixnum(666)
	})
	testGenerator(t, fmt.Sprintf("%d", 0xDEADCAFEBEEF), func(gen *rmarsh.Generator) error {
		return gen.Fixnum(0xDEADCAFEBEEF)
	})
}

func BenchmarkGenFixnum(b *testing.B) {
	gen := rmarsh.NewGenerator(ioutil.Discard)

	for i := 0; i < b.N; i++ {
		gen.Reset()

		if err := gen.Fixnum(123); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenBignum(t *testing.T) {
	var bigpos, bigneg big.Int
	bigpos.SetString("+DEADCAFEBEEFEEBAE", 16)
	bigneg.SetString("-DEADCAFEBEEFEEBAE", 16)
	testGenerator(t, bigpos.String(), func(gen *rmarsh.Generator) error {
		return gen.Bignum(&bigpos)
	})
	testGenerator(t, bigneg.String(), func(gen *rmarsh.Generator) error {
		return gen.Bignum(&bigneg)
	})
}

func BenchmarkGenBignum(b *testing.B) {
	gen := rmarsh.NewGenerator(ioutil.Discard)
	var bnum big.Int
	bnum.SetString("DEADCAFEBEEFEEBAE", 16)

	for i := 0; i < b.N; i++ {
		gen.Reset()

		if err := gen.Bignum(&bnum); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenSymbol(t *testing.T) {
	testGenerator(t, ":test", func(gen *rmarsh.Generator) error {
		return gen.Symbol("test")
	})
}

func BenchmarkGenSymbol(b *testing.B) {
	gen := rmarsh.NewGenerator(ioutil.Discard)

	for i := 0; i < b.N; i++ {
		gen.Reset()

		if err := gen.Symbol("test"); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenString(t *testing.T) {
	testGenerator(t, `"foobar"`, func(gen *rmarsh.Generator) error {
		return gen.String("foobar")
	})
}

func BenchmarkGenString(b *testing.B) {
	gen := rmarsh.NewGenerator(ioutil.Discard)

	for i := 0; i < b.N; i++ {
		gen.Reset()

		if err := gen.String("test"); err != nil {
			b.Fatal(err)
		}
	}
}

func TestGenFloat(t *testing.T) {
	testGenerator(t, `123.123123123`, func(gen *rmarsh.Generator) error {
		return gen.Float(123.123123123)
	})
}

func BenchmarkGenFloat(b *testing.B) {
	gen := rmarsh.NewGenerator(ioutil.Discard)

	for i := 0; i < b.N; i++ {
		gen.Reset()

		if err := gen.Float(123.123123123); err != nil {
			b.Fatal(err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016,2017 Yaacov Zamir <kobi.zamir@gmail.com>
// and other contributors.
//
// 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 alerts for alert rules
package alerts

import (
	"time"
	"fmt"
	"encoding/json"

	"github.com/MohawkTSDB/mohawk/storage"
)

const (
	BETWEEN RangeIntervalType = iota
	HIGHER_THAN
	LOWER_THAN
)

type RangeIntervalType int

type Alert struct {
	ID      string            `mapstructure:"id"`
	Metric  string            `mapstructure:"metric"`
	Tenant  string            `mapstructure:"tenant"`
	State   bool              `mapstructure:"state"`
	From    float64           `mapstructure:"from"`
	To      float64           `mapstructure:"to"`
	Type    RangeIntervalType `mapstructure:"type"`
}

type Alerts struct{
	Backend storage.Backend `mapstrcuture: "storage"`
	Verbose bool            `mapstrcuture: "verbose"`
	Alerts  []*Alert        `mapstructure: "alerts"`
}

// Init fill in missing configuration data, and start the alert checking loop
func (a *Alerts) Init() {
	// if user omit the tenant field in the alerts config, fallback to default
	// tenant
	for _, alert := range a.Alerts {
		// fall back to _ops
		if alert.Tenant == "" {
			alert.Tenant = "_ops"
		}
	}

	// check for alerts periodically.
	go a.run()
}

// check for alert status chenge periodically
func (a *Alerts) run() {
	c := time.Tick(time.Second * 10)

	// once a minute check for alerts in data
	for range c {
		fmt.Printf("alert check: start\n")
		a.checkAlerts()
	}
}

// updateAlertState update the alert status
func (alert *Alert) updateAlertState(value float64) {
	// valid metric values are:
	//    from < value >= to
	//    values outside this range will triger an alert
	switch alert.Type {
	case BETWEEN:
		alert.State = value <= alert.From || value > alert.To
	case HIGHER_THAN:
		alert.State = value > alert.To
	case LOWER_THAN:
		alert.State = value <= alert.From
	}
}

// loop on all alerts and check for status change
func (a *Alerts) checkAlerts() {
	var end      int64
	var start    int64
	var tenant   string
	var metric   string
	var oldState bool

	for _, alert := range a.Alerts {
		// look for last values
		end = int64(time.Now().UTC().Unix() * 1000)
		start = end - 60*60*1000

		// check out values for the alert metric
		tenant = alert.Tenant
		metric = alert.Metric
		rawData := a.Backend.GetRawData(tenant, metric, end, start, 1, "ASC")

		// if we have new data check for alert status change
		// [ if no new data found, leave alert status un changed ]
		if len(rawData) > 0 {
			oldState = alert.State

			// update alert state and report to user if changed.
			alert.updateAlertState(rawData[0].Value)
			if alert.State != oldState {
				if b, err := json.Marshal(alert); err == nil {
					fmt.Println(string(b))
				}
			}
		}
	}
}
<commit_msg>we do not get alerts from config file, only []alert<commit_after>// Copyright 2016,2017 Yaacov Zamir <kobi.zamir@gmail.com>
// and other contributors.
//
// 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 alerts for alert rules
package alerts

import (
	"time"
	"fmt"
	"encoding/json"

	"github.com/MohawkTSDB/mohawk/storage"
)

const (
	BETWEEN RangeIntervalType = iota
	HIGHER_THAN
	LOWER_THAN
)

type RangeIntervalType int

type Alert struct {
	ID      string            `mapstructure:"id"`
	Metric  string            `mapstructure:"metric"`
	Tenant  string            `mapstructure:"tenant"`
	State   bool              `mapstructure:"state"`
	From    float64           `mapstructure:"from"`
	To      float64           `mapstructure:"to"`
	Type    RangeIntervalType `mapstructure:"type"`
}

type Alerts struct{
	Backend storage.Backend
	Verbose bool
	Alerts  []*Alert
}

// Init fill in missing configuration data, and start the alert checking loop
func (a *Alerts) Init() {
	// if user omit the tenant field in the alerts config, fallback to default
	// tenant
	for _, alert := range a.Alerts {
		// fall back to _ops
		if alert.Tenant == "" {
			alert.Tenant = "_ops"
		}
	}

	// check for alerts periodically.
	go a.run()
}

// check for alert status chenge periodically
func (a *Alerts) run() {
	c := time.Tick(time.Second * 10)

	// once a minute check for alerts in data
	for range c {
		fmt.Printf("alert check: start\n")
		a.checkAlerts()
	}
}

// updateAlertState update the alert status
func (alert *Alert) updateAlertState(value float64) {
	// valid metric values are:
	//    from < value >= to
	//    values outside this range will triger an alert
	switch alert.Type {
	case BETWEEN:
		alert.State = value <= alert.From || value > alert.To
	case HIGHER_THAN:
		alert.State = value > alert.To
	case LOWER_THAN:
		alert.State = value <= alert.From
	}
}

// loop on all alerts and check for status change
func (a *Alerts) checkAlerts() {
	var end      int64
	var start    int64
	var tenant   string
	var metric   string
	var oldState bool

	for _, alert := range a.Alerts {
		// look for last values
		end = int64(time.Now().UTC().Unix() * 1000)
		start = end - 60*60*1000

		// check out values for the alert metric
		tenant = alert.Tenant
		metric = alert.Metric
		rawData := a.Backend.GetRawData(tenant, metric, end, start, 1, "ASC")

		// if we have new data check for alert status change
		// [ if no new data found, leave alert status un changed ]
		if len(rawData) > 0 {
			oldState = alert.State

			// update alert state and report to user if changed.
			alert.updateAlertState(rawData[0].Value)
			if alert.State != oldState {
				if b, err := json.Marshal(alert); err == nil {
					fmt.Println(string(b))
				}
			}
		}
	}
}
<|endoftext|>