<commit_before>package main

import (
	"context"
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
)

var version = os.Getenv("VERSION")
var backend = os.Getenv("BACKEND_URL")

func main() {

	port := ":8080"
	flag.Parse()

	log.Printf("Frontend version: %s\n", version)

	r := gin.Default()
	r.LoadHTMLGlob("templates/*")
	r.GET("/", handleIndex)
	r.GET("/version", handleVersion)
	r.GET("/healthz", handleHealthz)

	srv := &http.Server{
		Addr:    port,
		Handler: r,
	}

	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	// Wait for interrupt signal to gracefully shutdown the server with
	// a timeout of 5 seconds.
	quit := make(chan os.Signal, 1)
	// kill (no param) default send syscall.SIGTERM
	// kill -2 is syscall.SIGINT
	// kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	log.Println("Shutting down server...")

	// The context is used to inform the server it has 5 seconds to finish
	// the request it is currently handling
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server forced to shutdown:", err)
	}

	log.Println("Server exiting")

}

func handleIndex(c *gin.Context) {
	// Call backend for info
	resp, err := http.Get(backend)
	if err != nil {
		c.String(http.StatusInternalServerError, "Request to backend server ()%s failed:\n%v", backend, err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		c.String(http.StatusInternalServerError, "Unable to read body from    backend request:\n%v", err)
		return
	}
	var p PodMetadata
	err = json.Unmarshal([]byte(body), &p)
	if err != nil {
		c.String(http.StatusInternalServerError, "Unable to parse JSON AMP REVIEfrom backend request:\n%v", err)
		return
	}
	c.HTML(http.StatusOK, "index.html", p)
}

func handleVersion(c *gin.Context) {
	c.String(http.StatusOK, "%s", c.Value("version"))
}

func handleHealthz(c *gin.Context) {
	c.String(http.StatusOK, "", "")
}

// PodMetadata represents info about an InstanceMetadata in GCE
type PodMetadata struct {
	Name       string
	Namespace  string
	HostIP     string
	PodIP      string
	StartTime  string
	RawRequest string
	Counter    string
}
<commit_msg>Remove message<commit_after>package main

import (
	"context"
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/gin-gonic/gin"
)

var version = os.Getenv("VERSION")
var backend = os.Getenv("BACKEND_URL")

func main() {

	port := ":8080"
	flag.Parse()

	log.Printf("Frontend version: %s\n", version)

	r := gin.Default()
	r.LoadHTMLGlob("templates/*")
	r.GET("/", handleIndex)
	r.GET("/version", handleVersion)
	r.GET("/healthz", handleHealthz)

	srv := &http.Server{
		Addr:    port,
		Handler: r,
	}

	go func() {
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	// Wait for interrupt signal to gracefully shutdown the server with
	// a timeout of 5 seconds.
	quit := make(chan os.Signal, 1)
	// kill (no param) default send syscall.SIGTERM
	// kill -2 is syscall.SIGINT
	// kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	log.Println("Shutting down server...")

	// The context is used to inform the server it has 5 seconds to finish
	// the request it is currently handling
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server forced to shutdown:", err)
	}

	log.Println("Server exiting")

}

func handleIndex(c *gin.Context) {
	// Call backend for info
	resp, err := http.Get(backend)
	if err != nil {
		c.String(http.StatusInternalServerError, "Request to backend server ()%s failed:\n%v", backend, err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		c.String(http.StatusInternalServerError, "Unable to read body from    backend request:\n%v", err)
		return
	}
	var p PodMetadata
	err = json.Unmarshal([]byte(body), &p)
	if err != nil {
		c.String(http.StatusInternalServerError, "Unable to parse JSON from backend request:\n%v", err)
		return
	}
	c.HTML(http.StatusOK, "index.html", p)
}

func handleVersion(c *gin.Context) {
	c.String(http.StatusOK, "%s", c.Value("version"))
}

func handleHealthz(c *gin.Context) {
	c.String(http.StatusOK, "", "")
}

// PodMetadata represents info about an InstanceMetadata in GCE
type PodMetadata struct {
	Name       string
	Namespace  string
	HostIP     string
	PodIP      string
	StartTime  string
	RawRequest string
	Counter    string
}
<|endoftext|>


<commit_before>package aerospike

import (
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal/errchan"
	"github.com/influxdata/telegraf/plugins/inputs"

	as "github.com/aerospike/aerospike-client-go"
)

type Aerospike struct {
	Servers []string
}

var sampleConfig = `
  ## Aerospike servers to connect to (with port)
  ## This plugin will query all namespaces the aerospike
  ## server has configured and get stats for them.
  servers = ["localhost:3000"]
 `

func (a *Aerospike) SampleConfig() string {
	return sampleConfig
}

func (a *Aerospike) Description() string {
	return "Read stats from aerospike server(s)"
}

func (a *Aerospike) Gather(acc telegraf.Accumulator) error {
	if len(a.Servers) == 0 {
		return a.gatherServer("127.0.0.1:3000", acc)
	}

	var wg sync.WaitGroup
	errChan := errchan.New(len(a.Servers))
	wg.Add(len(a.Servers))
	for _, server := range a.Servers {
		go func(serv string) {
			defer wg.Done()
			errChan.C <- a.gatherServer(serv, acc)
		}(server)
	}

	wg.Wait()
	return errChan.Error()
}

func (a *Aerospike) gatherServer(hostport string, acc telegraf.Accumulator) error {
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		return err
	}

	iport, err := strconv.Atoi(port)
	if err != nil {
		iport = 3000
	}

	c, err := as.NewClient(host, iport)
	if err != nil {
		return err
	}
	defer c.Close()

	nodes := c.GetNodes()
	for _, n := range nodes {
		tags := map[string]string{
			"aerospike_host": hostport,
		}
		fields := map[string]interface{}{
			"node_name": n.GetName(),
		}
		stats, err := as.RequestNodeStats(n)
		if err != nil {
			return err
		}
		for k, v := range stats {
			fields[strings.Replace(k, "-", "_", -1)] = parseValue(v)
		}
		acc.AddFields("aerospike_node", fields, tags, time.Now())

		info, err := as.RequestNodeInfo(n, "namespaces")
		if err != nil {
			return err
		}
		namespaces := strings.Split(info["namespaces"], ";")

		for _, namespace := range namespaces {
			nTags := map[string]string{
				"aerospike_host": hostport,
			}
			nTags["namespace"] = namespace
			nFields := map[string]interface{}{
				"node_name": n.GetName(),
			}
			info, err := as.RequestNodeInfo(n, "namespace/"+namespace)
			if err != nil {
				continue
			}
			stats := strings.Split(info["namespace/"+namespace], ";")
			for _, stat := range stats {
				parts := strings.Split(stat, "=")
				if len(parts) < 2 {
					continue
				}
				nFields[strings.Replace(parts[0], "-", "_", -1)] = parseValue(parts[1])
			}
			acc.AddFields("aerospike_namespace", nFields, nTags, time.Now())
		}
	}
	return nil
}

func parseValue(v string) interface{} {
	if parsed, err := strconv.ParseInt(v, 10, 64); err == nil {
		return parsed
	} else if parsed, err := strconv.ParseBool(v); err == nil {
		return parsed
	} else {
		return v
	}
}

func copyTags(m map[string]string) map[string]string {
	out := make(map[string]string)
	for k, v := range m {
		out[k] = v
	}
	return out
}

func init() {
	inputs.Add("aerospike", func() telegraf.Input {
		return &Aerospike{}
	})
}
<commit_msg>Handle negative integers coming as unsigned integers from Aerospike stats<commit_after>package aerospike

import (
	"net"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal/errchan"
	"github.com/influxdata/telegraf/plugins/inputs"

	as "github.com/aerospike/aerospike-client-go"
)

type Aerospike struct {
	Servers []string
}

var sampleConfig = `
  ## Aerospike servers to connect to (with port)
  ## This plugin will query all namespaces the aerospike
  ## server has configured and get stats for them.
  servers = ["localhost:3000"]
 `

func (a *Aerospike) SampleConfig() string {
	return sampleConfig
}

func (a *Aerospike) Description() string {
	return "Read stats from aerospike server(s)"
}

func (a *Aerospike) Gather(acc telegraf.Accumulator) error {
	if len(a.Servers) == 0 {
		return a.gatherServer("127.0.0.1:3000", acc)
	}

	var wg sync.WaitGroup
	errChan := errchan.New(len(a.Servers))
	wg.Add(len(a.Servers))
	for _, server := range a.Servers {
		go func(serv string) {
			defer wg.Done()
			errChan.C <- a.gatherServer(serv, acc)
		}(server)
	}

	wg.Wait()
	return errChan.Error()
}

func (a *Aerospike) gatherServer(hostport string, acc telegraf.Accumulator) error {
	host, port, err := net.SplitHostPort(hostport)
	if err != nil {
		return err
	}

	iport, err := strconv.Atoi(port)
	if err != nil {
		iport = 3000
	}

	c, err := as.NewClient(host, iport)
	if err != nil {
		return err
	}
	defer c.Close()

	nodes := c.GetNodes()
	for _, n := range nodes {
		tags := map[string]string{
			"aerospike_host": hostport,
		}
		fields := map[string]interface{}{
			"node_name": n.GetName(),
		}
		stats, err := as.RequestNodeStats(n)
		if err != nil {
			return err
		}
		for k, v := range stats {
			fields[strings.Replace(k, "-", "_", -1)] = parseValue(v)
		}
		acc.AddFields("aerospike_node", fields, tags, time.Now())

		info, err := as.RequestNodeInfo(n, "namespaces")
		if err != nil {
			return err
		}
		namespaces := strings.Split(info["namespaces"], ";")

		for _, namespace := range namespaces {
			nTags := map[string]string{
				"aerospike_host": hostport,
			}
			nTags["namespace"] = namespace
			nFields := map[string]interface{}{
				"node_name": n.GetName(),
			}
			info, err := as.RequestNodeInfo(n, "namespace/"+namespace)
			if err != nil {
				continue
			}
			stats := strings.Split(info["namespace/"+namespace], ";")
			for _, stat := range stats {
				parts := strings.Split(stat, "=")
				if len(parts) < 2 {
					continue
				}
				nFields[strings.Replace(parts[0], "-", "_", -1)] = parseValue(parts[1])
			}
			acc.AddFields("aerospike_namespace", nFields, nTags, time.Now())
		}
	}
	return nil
}

func parseValue(v string) interface{} {
	if parsed, err := strconv.ParseInt(v, 10, 64); err == nil {
		return parsed
	} else if parsed, err := strconv.ParseUint(v, 10, 64); err == nil {
		return -int64(parsed)
	} else if parsed, err := strconv.ParseBool(v); err == nil {
		return parsed
	} else {
		return v
	}
}

func copyTags(m map[string]string) map[string]string {
	out := make(map[string]string)
	for k, v := range m {
		out[k] = v
	}
	return out
}

func init() {
	inputs.Add("aerospike", func() telegraf.Input {
		return &Aerospike{}
	})
}
<|endoftext|>


<commit_before>package influxdb_test

import (
	"reflect"
	"testing"
	"time"

	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/metrics/influxdb"
	stdinflux "github.com/influxdata/influxdb/client/v2"
)

func TestInfluxdbCounter(t *testing.T) {
	expectedName := "test_counter"
	expectedTags := map[string]string{}
	expectedFields := []map[string]interface{}{
		{"value": "2"},
		{"value": "7"},
		{"value": "10"},
	}

	cl := &mockClient{}
	bp, _ := stdinflux.NewBatchPoints(stdinflux.BatchPointsConfig{
		Database:  "testing",
		Precision: "s",
	})

	tags := []metrics.Field{}
	for key, value := range expectedTags {
		tags = append(tags, metrics.Field{Key: key, Value: value})
	}

	triggerChan := make(chan time.Time)
	counter := influxdb.NewCounterTick(cl, bp, expectedName, tags, triggerChan)
	counter.Add(2)
	counter.Add(5)
	counter.Add(3)

	triggerChan <- time.Now()

	for i := 0; i <= 2; i++ {
		givenPoint := mockPoint{
			Name:   expectedName,
			Tags:   expectedTags,
			Fields: expectedFields[i],
		}
		comparePoint(t, i, givenPoint, cl.Points[i])
	}
}

func TestInfluxdbCounterWithTag(t *testing.T) {
	expectedName := "test_counter"
	expectedTags := map[string]string{
		"key1": "value1",
		"key2": "value2",
	}
	expectedFields := []map[string]interface{}{
		{"value": "2"},
		{"Test": "Test", "value": "7"},
		{"Test": "Test", "value": "10"},
	}

	cl := &mockClient{}
	bp, _ := stdinflux.NewBatchPoints(stdinflux.BatchPointsConfig{
		Database:  "testing",
		Precision: "s",
	})

	tags := []metrics.Field{}
	for key, value := range expectedTags {
		tags = append(tags, metrics.Field{Key: key, Value: value})
	}

	triggerChan := make(chan time.Time)
	counter := influxdb.NewCounterTick(cl, bp, expectedName, tags, triggerChan)
	counter.Add(2)
	counter = counter.With(metrics.Field{Key: "Test", Value: "Test"})
	counter.Add(5)
	counter.Add(3)

	triggerChan <- time.Now()

	for i := 0; i <= 2; i++ {
		givenPoint := mockPoint{
			Name:   expectedName,
			Tags:   expectedTags,
			Fields: expectedFields[i],
		}
		comparePoint(t, i, givenPoint, cl.Points[i])
	}
}

func comparePoint(t *testing.T, i int, expected mockPoint, given stdinflux.Point) {
	givenName := given.Name()
	if givenName != expected.Name {
		t.Errorf("Point %v invalid name, expected %v got %v", i, expected.Name, givenName)
	}

	tagsEqual := reflect.DeepEqual(expected.Tags, given.Tags())
	if !tagsEqual {
		t.Errorf("Point %v invalid tags, expected %v got %v", i, expected.Tags, given.Tags())
	}

	fieldsEqual := reflect.DeepEqual(expected.Fields, given.Fields())
	if !fieldsEqual {
		t.Errorf("Point %v invalid fields, expected %v got %v", i, expected.Fields, given.Fields())
	}
}

type mockClient struct {
	Points []stdinflux.Point
}

func (m *mockClient) Ping(timeout time.Duration) (time.Duration, string, error) {
	t := 0 * time.Millisecond
	return t, "", nil
}

func (m *mockClient) Write(bp stdinflux.BatchPoints) error {
	for _, p := range bp.Points() {
		m.Points = append(m.Points, *p)
	}

	return nil
}

func (m *mockClient) Query(q stdinflux.Query) (*stdinflux.Response, error) {
	return nil, nil
}

func (m *mockClient) Close() error {
	return nil
}

type mockPoint struct {
	Name   string
	Tags   map[string]string
	Fields map[string]interface{}
}
<commit_msg>Added WaitGroup to avoid data races in test client<commit_after>package influxdb_test

import (
	"reflect"
	"sync"
	"testing"
	"time"

	"github.com/go-kit/kit/metrics"
	"github.com/go-kit/kit/metrics/influxdb"
	stdinflux "github.com/influxdata/influxdb/client/v2"
)

func TestInfluxdbCounter(t *testing.T) {
	expectedName := "test_counter"
	expectedTags := map[string]string{}
	expectedFields := []map[string]interface{}{
		{"value": "2"},
		{"value": "7"},
		{"value": "10"},
	}

	cl := &mockClient{}
	cl.Add(3)
	bp, _ := stdinflux.NewBatchPoints(stdinflux.BatchPointsConfig{
		Database:  "testing",
		Precision: "s",
	})

	tags := []metrics.Field{}
	for key, value := range expectedTags {
		tags = append(tags, metrics.Field{Key: key, Value: value})
	}

	triggerChan := make(chan time.Time)
	counter := influxdb.NewCounterTick(cl, bp, expectedName, tags, triggerChan)
	counter.Add(2)
	counter.Add(5)
	counter.Add(3)

	triggerChan <- time.Now()
	cl.Wait()

	for i := 0; i <= 2; i++ {
		givenPoint := mockPoint{
			Name:   expectedName,
			Tags:   expectedTags,
			Fields: expectedFields[i],
		}
		comparePoint(t, i, givenPoint, cl.Points[i])
	}
}

func TestInfluxdbCounterWithTag(t *testing.T) {
	expectedName := "test_counter"
	expectedTags := map[string]string{
		"key1": "value1",
		"key2": "value2",
	}
	expectedFields := []map[string]interface{}{
		{"value": "2"},
		{"Test": "Test", "value": "7"},
		{"Test": "Test", "value": "10"},
	}

	cl := &mockClient{}
	cl.Add(3)
	bp, _ := stdinflux.NewBatchPoints(stdinflux.BatchPointsConfig{
		Database:  "testing",
		Precision: "s",
	})

	tags := []metrics.Field{}
	for key, value := range expectedTags {
		tags = append(tags, metrics.Field{Key: key, Value: value})
	}

	triggerChan := make(chan time.Time)
	counter := influxdb.NewCounterTick(cl, bp, expectedName, tags, triggerChan)
	counter.Add(2)
	counter = counter.With(metrics.Field{Key: "Test", Value: "Test"})
	counter.Add(5)
	counter.Add(3)

	triggerChan <- time.Now()
	cl.Wait()

	for i := 0; i <= 2; i++ {
		givenPoint := mockPoint{
			Name:   expectedName,
			Tags:   expectedTags,
			Fields: expectedFields[i],
		}
		comparePoint(t, i, givenPoint, cl.Points[i])
	}
}

func comparePoint(t *testing.T, i int, expected mockPoint, given stdinflux.Point) {
	givenName := given.Name()
	if givenName != expected.Name {
		t.Errorf("Point %v invalid name, expected %v got %v", i, expected.Name, givenName)
	}

	tagsEqual := reflect.DeepEqual(expected.Tags, given.Tags())
	if !tagsEqual {
		t.Errorf("Point %v invalid tags, expected %v got %v", i, expected.Tags, given.Tags())
	}

	fieldsEqual := reflect.DeepEqual(expected.Fields, given.Fields())
	if !fieldsEqual {
		t.Errorf("Point %v invalid fields, expected %v got %v", i, expected.Fields, given.Fields())
	}
}

type mockClient struct {
	Points []stdinflux.Point
	sync.WaitGroup
}

func (m *mockClient) Ping(timeout time.Duration) (time.Duration, string, error) {
	t := 0 * time.Millisecond
	return t, "", nil
}

func (m *mockClient) Write(bp stdinflux.BatchPoints) error {
	for _, p := range bp.Points() {
		m.Points = append(m.Points, *p)
		m.Done()
	}

	return nil
}

func (m *mockClient) Query(q stdinflux.Query) (*stdinflux.Response, error) {
	return nil, nil
}

func (m *mockClient) Close() error {
	return nil
}

type mockPoint struct {
	Name   string
	Tags   map[string]string
	Fields map[string]interface{}
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 inode

import (
	"errors"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/syncutil"
	"golang.org/x/net/context"
)

type FileInode struct {
	/////////////////////////
	// Constant data
	/////////////////////////

	id fuse.InodeID

	// The name of the GCS object backing the inode. This may or may not yet
	// exist.
	//
	// INVARIANT: name != ""
	// INVARIANT: name[len(name)-1] != '/'
	name string

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	Mu syncutil.InvariantMutex

	// The generation number of the GCS object from which this inode was
	// branched, or zero if it is newly created. This is used as a precondition
	// in object write requests.
	//
	// GUARDED_BY(Mu)
	srcGeneration uint64
}

var _ Inode = &FileInode{}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) ID() fuse.InodeID {
	return f.id
}

func (f *FileInode) Name() string {
	return f.name
}

func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuse.InodeAttributes, err error) {
	err = errors.New("TODO(jacobsa): Implement FileInode.Attributes.")
	return
}

// Return the generation number from which this inode was branched, or zero if
// it is newly created. This is used as a precondition in object write
// requests.
//
// TODO(jacobsa): Make sure to add a test for opening a file with O_CREAT then
// opening it again for reading, and sharing data across the two descriptors.
// This should fail if we have screwed up the fuse lookup process with regards
// to the zero generation. We probably want to make this always non-zero (add
// an invariant) by creating an empty object when opening with O_CREAT.
//
// SHARED_LOCKS_REQUIRED(f.Mu)
func (f *FileInode) SourceGeneration() uint64
<commit_msg>Implemented FileInode.SourceGeneration.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 inode

import (
	"errors"

	"github.com/jacobsa/fuse"
	"github.com/jacobsa/gcloud/syncutil"
	"golang.org/x/net/context"
)

type FileInode struct {
	/////////////////////////
	// Constant data
	/////////////////////////

	id fuse.InodeID

	// The name of the GCS object backing the inode. This may or may not yet
	// exist.
	//
	// INVARIANT: name != ""
	// INVARIANT: name[len(name)-1] != '/'
	name string

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	Mu syncutil.InvariantMutex

	// The generation number of the GCS object from which this inode was
	// branched, or zero if it is newly created. This is used as a precondition
	// in object write requests.
	//
	// GUARDED_BY(Mu)
	srcGeneration uint64
}

var _ Inode = &FileInode{}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) ID() fuse.InodeID {
	return f.id
}

func (f *FileInode) Name() string {
	return f.name
}

func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuse.InodeAttributes, err error) {
	err = errors.New("TODO(jacobsa): Implement FileInode.Attributes.")
	return
}

// Return the generation number from which this inode was branched, or zero if
// it is newly created. This is used as a precondition in object write
// requests.
//
// TODO(jacobsa): Make sure to add a test for opening a file with O_CREAT then
// opening it again for reading, and sharing data across the two descriptors.
// This should fail if we have screwed up the fuse lookup process with regards
// to the zero generation. We probably want to make this always non-zero (add
// an invariant) by creating an empty object when opening with O_CREAT.
//
// SHARED_LOCKS_REQUIRED(f.Mu)
func (f *FileInode) SourceGeneration() uint64 {
	return f.srcGeneration
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 inode

import (
	"errors"
	"fmt"
	"io"

	"github.com/googlecloudplatform/gcsfuse/internal/gcsx"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/syncutil"
	"github.com/jacobsa/timeutil"
	"golang.org/x/net/context"
)

type FileInode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	bucket gcs.Bucket
	syncer gcsx.Syncer
	clock  timeutil.Clock

	/////////////////////////
	// Constant data
	/////////////////////////

	id           fuseops.InodeID
	name         string
	attrs        fuseops.InodeAttributes
	gcsChunkSize uint64

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	mu syncutil.InvariantMutex

	// GUARDED_BY(mu)
	lc lookupCount

	// The source object from which this inode derives.
	//
	// INVARIANT: src.Name == name
	//
	// GUARDED_BY(mu)
	src gcs.Object

	// The current content of this inode, or nil if the source object is still
	// authoritative.
	content gcsx.TempFile

	// Has Destroy been called?
	//
	// GUARDED_BY(mu)
	destroyed bool
}

var _ Inode = &FileInode{}

// Create a file inode for the given object in GCS. The initial lookup count is
// zero.
//
// REQUIRES: o != nil
// REQUIRES: o.Generation > 0
// REQUIRES: len(o.Name) > 0
// REQUIRES: o.Name[len(o.Name)-1] != '/'
func NewFileInode(
	id fuseops.InodeID,
	o *gcs.Object,
	attrs fuseops.InodeAttributes,
	bucket gcs.Bucket,
	syncer gcsx.Syncer,
	clock timeutil.Clock) (f *FileInode) {
	// Set up the basic struct.
	f = &FileInode{
		bucket: bucket,
		syncer: syncer,
		clock:  clock,
		id:     id,
		name:   o.Name,
		attrs:  attrs,
		src:    *o,
	}

	f.lc.Init(id)

	// Set up invariant checking.
	f.mu = syncutil.NewInvariantMutex(f.checkInvariants)

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) checkInvariants() {
	if f.destroyed {
		return
	}

	// Make sure the name is legal.
	name := f.Name()
	if len(name) == 0 || name[len(name)-1] == '/' {
		panic("Illegal file name: " + name)
	}

	// INVARIANT: src.Name == name
	if f.src.Name != name {
		panic(fmt.Sprintf("Name mismatch: %q vs. %q", f.src.Name, name))
	}

	// INVARIANT: content.CheckInvariants() does not panic
	f.content.CheckInvariants()
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) clobbered(ctx context.Context) (b bool, err error) {
	// Stat the object in GCS.
	req := &gcs.StatObjectRequest{Name: f.name}
	o, err := f.bucket.StatObject(ctx, req)

	// Special case: "not found" means we have been clobbered.
	if _, ok := err.(*gcs.NotFoundError); ok {
		err = nil
		b = true
		return
	}

	// Propagate other errors.
	if err != nil {
		err = fmt.Errorf("StatObject: %v", err)
		return
	}

	// We are clobbered iff the generation doesn't match our source generation.
	b = (o.Generation != f.src.Generation)

	return
}

// Ensure that f.content != nil
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) ensureContent(ctx context.Context) (err error) {
	err = errors.New("TODO")
	return
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) Lock() {
	f.mu.Lock()
}

func (f *FileInode) Unlock() {
	f.mu.Unlock()
}

func (f *FileInode) ID() fuseops.InodeID {
	return f.id
}

func (f *FileInode) Name() string {
	return f.name
}

// Return the object generation number from which this inode was branched.
//
// LOCKS_REQUIRED(f)
func (f *FileInode) SourceGeneration() int64 {
	return f.src.Generation
}

// If true, it is safe to serve reads directly from the object generation given
// by f.SourceGeneration(), rather than calling f.ReadAt. Doing so may be more
// efficient, because f.ReadAt may cause the entire object to be faulted in and
// requires the inode to be locked during the read.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) SourceGenerationIsAuthoritative() bool {
	return f.content == nil
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) IncrementLookupCount() {
	f.lc.Inc()
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) DecrementLookupCount(n uint64) (destroy bool) {
	destroy = f.lc.Dec(n)
	return
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Destroy() (err error) {
	f.destroyed = true

	f.content.Destroy()
	return
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuseops.InodeAttributes, err error) {
	attrs = f.attrs

	// Obtain default information from the source object.
	attrs.Mtime = f.src.Updated
	attrs.Size = uint64(f.src.Size)

	// If GCS is no longer authoritative, stat our local content to obtain size
	// and mtime.
	if f.content != nil {
		var sr gcsx.StatResult
		sr, err = f.content.Stat()
		if err != nil {
			err = fmt.Errorf("Stat: %v", err)
			return
		}

		attrs.Size = uint64(sr.Size)
		if sr.Mtime != nil {
			attrs.Mtime = *sr.Mtime
		}
	}

	// If the object has been clobbered, we reflect that as the inode being
	// unlinked.
	clobbered, err := f.clobbered(ctx)
	if err != nil {
		err = fmt.Errorf("clobbered: %v", err)
		return
	}

	if !clobbered {
		attrs.Nlink = 1
	}

	return
}

// Serve a read for this file with semantics matching fuseops.ReadFileOp.
//
// The caller may be better off reading directly from GCS when
// f.SourceGenerationIsAuthoritative() is true.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Read(
	ctx context.Context,
	dst []byte,
	offset int64) (n int, err error) {
	// Make sure f.content != nil.
	err = f.ensureContent(ctx)
	if err != nil {
		err = fmt.Errorf("ensureContent: %v", err)
		return
	}

	// Read from the local content.
	n, err = f.content.ReadAt(dst, offset)

	// We don't return errors for EOF. Otherwise, propagate errors.
	if err == io.EOF {
		err = nil
	} else if err != nil {
		err = fmt.Errorf("ReadAt: %v", err)
		return
	}

	return
}

// Serve a write for this file with semantics matching fuseops.WriteFileOp.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Write(
	ctx context.Context,
	data []byte,
	offset int64) (err error) {
	// Make sure f.content != nil.
	err = f.ensureContent(ctx)
	if err != nil {
		err = fmt.Errorf("ensureContent: %v", err)
		return
	}

	// Write to the mutable content. Note that io.WriterAt guarantees it returns
	// an error for short writes.
	_, err = f.content.WriteAt(data, offset)

	return
}

// Write out contents to GCS. If this fails due to the generation having been
// clobbered, treat it as a non-error (simulating the inode having been
// unlinked).
//
// After this method succeeds, SourceGeneration will return the new generation
// by which this inode should be known (which may be the same as before). If it
// fails, the generation will not change.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Sync(ctx context.Context) (err error) {
	// If we have not been dirtied, there is nothing to do.
	if f.content == nil {
		return
	}

	// Write out the contents if they are dirty.
	newObj, err := f.syncer.SyncObject(ctx, &f.src, f.content)

	// Special case: a precondition error means we were clobbered, which we treat
	// as being unlinked. There's no reason to return an error in that case.
	if _, ok := err.(*gcs.PreconditionError); ok {
		err = nil
	}

	// Propagate other errors.
	if err != nil {
		err = fmt.Errorf("SyncObject: %v", err)
		return
	}

	// If we wrote out a new object, we need to update our state.
	if newObj != nil {
		f.src = *newObj
		f.content = nil
	}

	return
}

// Truncate the file to the specified size.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Truncate(
	ctx context.Context,
	size int64) (err error) {
	err = f.content.Truncate(ctx, size)
	return
}
<commit_msg>FileInode.Truncate<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 inode

import (
	"errors"
	"fmt"
	"io"

	"github.com/googlecloudplatform/gcsfuse/internal/gcsx"
	"github.com/jacobsa/fuse/fuseops"
	"github.com/jacobsa/gcloud/gcs"
	"github.com/jacobsa/syncutil"
	"github.com/jacobsa/timeutil"
	"golang.org/x/net/context"
)

type FileInode struct {
	/////////////////////////
	// Dependencies
	/////////////////////////

	bucket gcs.Bucket
	syncer gcsx.Syncer
	clock  timeutil.Clock

	/////////////////////////
	// Constant data
	/////////////////////////

	id           fuseops.InodeID
	name         string
	attrs        fuseops.InodeAttributes
	gcsChunkSize uint64

	/////////////////////////
	// Mutable state
	/////////////////////////

	// A mutex that must be held when calling certain methods. See documentation
	// for each method.
	mu syncutil.InvariantMutex

	// GUARDED_BY(mu)
	lc lookupCount

	// The source object from which this inode derives.
	//
	// INVARIANT: src.Name == name
	//
	// GUARDED_BY(mu)
	src gcs.Object

	// The current content of this inode, or nil if the source object is still
	// authoritative.
	content gcsx.TempFile

	// Has Destroy been called?
	//
	// GUARDED_BY(mu)
	destroyed bool
}

var _ Inode = &FileInode{}

// Create a file inode for the given object in GCS. The initial lookup count is
// zero.
//
// REQUIRES: o != nil
// REQUIRES: o.Generation > 0
// REQUIRES: len(o.Name) > 0
// REQUIRES: o.Name[len(o.Name)-1] != '/'
func NewFileInode(
	id fuseops.InodeID,
	o *gcs.Object,
	attrs fuseops.InodeAttributes,
	bucket gcs.Bucket,
	syncer gcsx.Syncer,
	clock timeutil.Clock) (f *FileInode) {
	// Set up the basic struct.
	f = &FileInode{
		bucket: bucket,
		syncer: syncer,
		clock:  clock,
		id:     id,
		name:   o.Name,
		attrs:  attrs,
		src:    *o,
	}

	f.lc.Init(id)

	// Set up invariant checking.
	f.mu = syncutil.NewInvariantMutex(f.checkInvariants)

	return
}

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) checkInvariants() {
	if f.destroyed {
		return
	}

	// Make sure the name is legal.
	name := f.Name()
	if len(name) == 0 || name[len(name)-1] == '/' {
		panic("Illegal file name: " + name)
	}

	// INVARIANT: src.Name == name
	if f.src.Name != name {
		panic(fmt.Sprintf("Name mismatch: %q vs. %q", f.src.Name, name))
	}

	// INVARIANT: content.CheckInvariants() does not panic
	f.content.CheckInvariants()
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) clobbered(ctx context.Context) (b bool, err error) {
	// Stat the object in GCS.
	req := &gcs.StatObjectRequest{Name: f.name}
	o, err := f.bucket.StatObject(ctx, req)

	// Special case: "not found" means we have been clobbered.
	if _, ok := err.(*gcs.NotFoundError); ok {
		err = nil
		b = true
		return
	}

	// Propagate other errors.
	if err != nil {
		err = fmt.Errorf("StatObject: %v", err)
		return
	}

	// We are clobbered iff the generation doesn't match our source generation.
	b = (o.Generation != f.src.Generation)

	return
}

// Ensure that f.content != nil
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) ensureContent(ctx context.Context) (err error) {
	err = errors.New("TODO")
	return
}

////////////////////////////////////////////////////////////////////////
// Public interface
////////////////////////////////////////////////////////////////////////

func (f *FileInode) Lock() {
	f.mu.Lock()
}

func (f *FileInode) Unlock() {
	f.mu.Unlock()
}

func (f *FileInode) ID() fuseops.InodeID {
	return f.id
}

func (f *FileInode) Name() string {
	return f.name
}

// Return the object generation number from which this inode was branched.
//
// LOCKS_REQUIRED(f)
func (f *FileInode) SourceGeneration() int64 {
	return f.src.Generation
}

// If true, it is safe to serve reads directly from the object generation given
// by f.SourceGeneration(), rather than calling f.ReadAt. Doing so may be more
// efficient, because f.ReadAt may cause the entire object to be faulted in and
// requires the inode to be locked during the read.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) SourceGenerationIsAuthoritative() bool {
	return f.content == nil
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) IncrementLookupCount() {
	f.lc.Inc()
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) DecrementLookupCount(n uint64) (destroy bool) {
	destroy = f.lc.Dec(n)
	return
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Destroy() (err error) {
	f.destroyed = true

	f.content.Destroy()
	return
}

// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Attributes(
	ctx context.Context) (attrs fuseops.InodeAttributes, err error) {
	attrs = f.attrs

	// Obtain default information from the source object.
	attrs.Mtime = f.src.Updated
	attrs.Size = uint64(f.src.Size)

	// If GCS is no longer authoritative, stat our local content to obtain size
	// and mtime.
	if f.content != nil {
		var sr gcsx.StatResult
		sr, err = f.content.Stat()
		if err != nil {
			err = fmt.Errorf("Stat: %v", err)
			return
		}

		attrs.Size = uint64(sr.Size)
		if sr.Mtime != nil {
			attrs.Mtime = *sr.Mtime
		}
	}

	// If the object has been clobbered, we reflect that as the inode being
	// unlinked.
	clobbered, err := f.clobbered(ctx)
	if err != nil {
		err = fmt.Errorf("clobbered: %v", err)
		return
	}

	if !clobbered {
		attrs.Nlink = 1
	}

	return
}

// Serve a read for this file with semantics matching fuseops.ReadFileOp.
//
// The caller may be better off reading directly from GCS when
// f.SourceGenerationIsAuthoritative() is true.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Read(
	ctx context.Context,
	dst []byte,
	offset int64) (n int, err error) {
	// Make sure f.content != nil.
	err = f.ensureContent(ctx)
	if err != nil {
		err = fmt.Errorf("ensureContent: %v", err)
		return
	}

	// Read from the local content.
	n, err = f.content.ReadAt(dst, offset)

	// We don't return errors for EOF. Otherwise, propagate errors.
	if err == io.EOF {
		err = nil
	} else if err != nil {
		err = fmt.Errorf("ReadAt: %v", err)
		return
	}

	return
}

// Serve a write for this file with semantics matching fuseops.WriteFileOp.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Write(
	ctx context.Context,
	data []byte,
	offset int64) (err error) {
	// Make sure f.content != nil.
	err = f.ensureContent(ctx)
	if err != nil {
		err = fmt.Errorf("ensureContent: %v", err)
		return
	}

	// Write to the mutable content. Note that io.WriterAt guarantees it returns
	// an error for short writes.
	_, err = f.content.WriteAt(data, offset)

	return
}

// Write out contents to GCS. If this fails due to the generation having been
// clobbered, treat it as a non-error (simulating the inode having been
// unlinked).
//
// After this method succeeds, SourceGeneration will return the new generation
// by which this inode should be known (which may be the same as before). If it
// fails, the generation will not change.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Sync(ctx context.Context) (err error) {
	// If we have not been dirtied, there is nothing to do.
	if f.content == nil {
		return
	}

	// Write out the contents if they are dirty.
	newObj, err := f.syncer.SyncObject(ctx, &f.src, f.content)

	// Special case: a precondition error means we were clobbered, which we treat
	// as being unlinked. There's no reason to return an error in that case.
	if _, ok := err.(*gcs.PreconditionError); ok {
		err = nil
	}

	// Propagate other errors.
	if err != nil {
		err = fmt.Errorf("SyncObject: %v", err)
		return
	}

	// If we wrote out a new object, we need to update our state.
	if newObj != nil {
		f.src = *newObj
		f.content = nil
	}

	return
}

// Truncate the file to the specified size.
//
// LOCKS_REQUIRED(f.mu)
func (f *FileInode) Truncate(
	ctx context.Context,
	size int64) (err error) {
	// Make sure f.content != nil.
	err = f.ensureContent(ctx)
	if err != nil {
		err = fmt.Errorf("ensureContent: %v", err)
		return
	}

	// Call through.
	err = f.content.Truncate(size)

	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/basho-labs/riak-mesos/metadata_manager"
)

var (
	zookeeperAddr string
	clusterName   string
	nodes         int
	frameworkName string
	cmd           string
	client        *SchedulerHTTPClient
)

func init() {
	flag.StringVar(&zookeeperAddr, "zk", "33.33.33.2:2181", "Zookeeper")
	flag.StringVar(&clusterName, "cluster-name", "", "Name of new cluster")
	flag.IntVar(&nodes, "nodes", 1, "Nodes in new cluster")
	flag.StringVar(&frameworkName, "name", "riak-mesos-go3", "Framework Instance Name")
	flag.StringVar(&cmd, "command", "get-url", "get-url, get-clusters, get-cluster, create-cluster, delete-cluster, get-nodes, add-node, add-nodes")
	flag.Parse()

	if cmd == "" {
		fmt.Println("Please specify command")
		os.Exit(1)
	}
	log.SetLevel(log.DebugLevel)
}

func main() {

	if cmd == "get-url" {
		fmt.Println(getURL())
		os.Exit(1)
	}

	client = NewSchedulerHTTPClient(getURL())

	switch cmd {
	case "get-clusters":
		respond(client.GetClusters())
	case "get-cluster":
		requireClusterName()
		respond(client.GetCluster(clusterName))
	case "create-cluster":
		requireClusterName()
		respond(client.CreateCluster(clusterName))
	case "delete-cluster":
		requireClusterName()
		respond(client.DeleteCluster(clusterName))
	case "get-nodes":
		requireClusterName()
		respond(client.GetNodes(clusterName))
	case "add-node":
	case "add-nodes":
		requireClusterName()
		for i := 1; i <= nodes; i++ {
			respond(client.AddNode(clusterName))
		}
	}
}

func respond(val string, err error) {
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(val)
}

func getURL() string {
	mgr := metadata_manager.NewMetadataManager(frameworkName, []string{zookeeperAddr})
	return string(mgr.GetRootNode().GetChild("uri").GetData())
}

func requireClusterName() {
	if clusterName == "" {
		fmt.Println("Please specify value for cluster name")
		os.Exit(1)
	}
}
<commit_msg>add single add node command<commit_after>package main

import (
	"flag"
	"fmt"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/basho-labs/riak-mesos/metadata_manager"
)

var (
	zookeeperAddr string
	clusterName   string
	nodes         int
	frameworkName string
	cmd           string
	client        *SchedulerHTTPClient
)

func init() {
	flag.StringVar(&zookeeperAddr, "zk", "33.33.33.2:2181", "Zookeeper")
	flag.StringVar(&clusterName, "cluster-name", "", "Name of new cluster")
	flag.IntVar(&nodes, "nodes", 1, "Nodes in new cluster")
	flag.StringVar(&frameworkName, "name", "riak-mesos-go3", "Framework Instance Name")
	flag.StringVar(&cmd, "command", "get-url", "get-url, get-clusters, get-cluster, create-cluster, delete-cluster, get-nodes, add-node, add-nodes")
	flag.Parse()

	if cmd == "" {
		fmt.Println("Please specify command")
		os.Exit(1)
	}
	log.SetLevel(log.DebugLevel)
}

func main() {

	if cmd == "get-url" {
		fmt.Println(getURL())
		os.Exit(1)
	}

	client = NewSchedulerHTTPClient(getURL())

	switch cmd {
	case "get-clusters":
		respond(client.GetClusters())
	case "get-cluster":
		requireClusterName()
		respond(client.GetCluster(clusterName))
	case "create-cluster":
		requireClusterName()
		respond(client.CreateCluster(clusterName))
	case "delete-cluster":
		requireClusterName()
		respond(client.DeleteCluster(clusterName))
	case "get-nodes":
		requireClusterName()
		respond(client.GetNodes(clusterName))
	case "add-node":
		requireClusterName()
		respond(client.AddNode(clusterName))
	case "add-nodes":
		requireClusterName()
		for i := 1; i <= nodes; i++ {
			respond(client.AddNode(clusterName))
		}
	default:
		log.Fatal("Unknown command")
	}
}

func respond(val string, err error) {
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(val)
}

func getURL() string {
	mgr := metadata_manager.NewMetadataManager(frameworkName, []string{zookeeperAddr})
	return string(mgr.GetRootNode().GetChild("uri").GetData())
}

func requireClusterName() {
	if clusterName == "" {
		fmt.Println("Please specify value for cluster name")
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package runner

import (
	"bytes"
	"fmt"
	"math/rand"
	"time"

	"github.com/BurntSushi/toml"
)

// tag is a struct that contains data
// about a tag for in a series
type tag struct {
	Key   string `toml:"key"`
	Value string `toml:"value"`
}

// tag is a struct that contains data
// about a field for in a series
type field struct {
	Key  string `toml:"key"`
	Type string `toml:"type"`
}

// series is a struct that contains data
// about the series that will be written
// during a stress test
type series struct {
	PointCount  int     `toml:"point_count"`
	Tick        string  `toml:"tick"`
	Jitter      bool    `toml:"jitter"`
	Measurement string  `toml:"measurement"`
	SeriesCount int     `toml:"series_count"`
	TagCount    int     `toml:"tag_count"`
	Tags        []tag   `toml:"tag"`
	Fields      []field `toml:"field"`
}

// write is a struct that contains the business
// logic for the stress test. e.g. where the
// influxdb instance is running, what database
// should points be written into
type write struct {
	Concurrency   int    `toml:"concurrency"`
	BatchSize     int    `toml:"batch_size"`
	BatchInterval string `toml:"batch_interval"`
	Database      string `toml:"database"`
	ResetDatabase bool   `toml:"reset_database"`
	Address       string `toml:"address"`
	Precision     string `toml:"precision"`
	StartDate     string `toml:"start_date"`
}

// query is a struct that contains the logic for
// a query that will be ran on during the stress
// test
type query struct {
	Enabled     bool     `toml:"enabled"`
	Concurrency int      `toml:"concurrency"`
	Aggregates  []string `toml:"aggregates"`
	Fields      []string `toml:"fields"`
}

// measurementQuery is a struct that contains
// the logic that runs a query against a measurement
// over a time period that is specified by
// `Offset`
type measurementQuery struct {
	query
	Offset string `toml:"offset"`
}

// seriesQuery is a struct that contains
// the logic that runs a query against a single
// series
type seriesQuery struct {
	query
	Interval string `toml:"interval"`
}

// Config is a struct that is passed into the `Run()` function.
type Config struct {
	Write             write            `toml:"write"`
	Series            []series         `toml:"series"`
	MeasurementQuery  measurementQuery `toml:"measurement_query"`
	SeriesQuery       seriesQuery      `toml:"series_query"`
	ChannelBufferSize int              `toml:"channel_buffer_size"`
	SSL               bool             `toml:"ssl"`
}

// NewSeries, takes a measurement, and point count,
// and a series count and returns a series
func NewSeries(m string, p int, sc int) series {
	s := series{
		PointCount:  p,
		SeriesCount: sc,
		Tick:        "1s",
		Measurement: m,
		Tags: []tag{
			tag{
				Key:   "host",
				Value: "server",
			},
		},
		Fields: []field{
			field{
				Key: "value",
			},
		},
	}

	return s
}

// NewConfig returns a pointer to a config
// with some default parameters set
func NewConfig() *Config {

	w := write{
		Concurrency:   10,
		BatchSize:     5000,
		BatchInterval: "0s",
		Database:      "stress",
		ResetDatabase: true,
		Address:       "localhost:8086",
		Precision:     "n",
	}

	c := &Config{
		Write: w,
	}

	return c
}

// DecodeFile takes a file path for a toml config file
// and returns a pointer to a Config Struct.
func DecodeFile(s string) (*Config, error) {
	t := &Config{}

	// Decode the toml file
	if _, err := toml.DecodeFile(s, t); err != nil {
		return nil, err
	}

	// Initialize Config struct
	// NOTE: Not happy with the implementation
	// but it will do for now
	for j, srs := range t.Series {
		for i := 0; i < srs.TagCount; i++ {

			tag := tag{
				Key:   fmt.Sprintf("tag-key-%d", i),
				Value: "tag-value",
			}

			srs.Tags = append(srs.Tags, tag)
			fmt.Println(srs)
		}

		t.Series[j] = srs
	}

	return t, nil
}

// seriesIter is a struct that contains a
// series and a count, where count is the
//number of points that have been written
// for the series `s`
type seriesIter struct {
	s         *series
	count     int
	timestamp time.Time
	precision string
}

// writeInterval returns a timestamp for the current time
// interval
func (s *series) writeInterval(i int, start time.Time) time.Time {
	var tick time.Duration
	var j int
	var err error

	tick, err = time.ParseDuration(s.Tick)
	if err != nil {
		panic(err)
	}

	if s.Jitter {
		j = rand.Intn(int(tick))
		if j%2 == 0 {
			j = -1 * j
		}
	}

	tick = tick*time.Duration(i) + time.Duration(j)

	return start.Add(tick)
}

// Iter returns a pointer to a seriesIter
func (s *series) Iter(i int, start time.Time, p string) *seriesIter {

	return &seriesIter{s: s, count: -1, timestamp: s.writeInterval(i, start), precision: p}
}

// Next returns a new point for a series.
// Currently, there is an off by one bug here.
func (iter *seriesIter) Next() ([]byte, bool) {
	var buf bytes.Buffer
	iter.count++

	buf.Write([]byte(fmt.Sprintf("%v,", iter.s.Measurement)))
	buf.Write(iter.s.newTagSet(iter.count))
	buf.Write([]byte(" "))
	buf.Write(iter.s.newFieldSet(iter.count))
	buf.Write([]byte(" "))

	switch iter.precision {
	case "s":
		buf.Write([]byte(fmt.Sprintf("%v", iter.timestamp.Unix())))
	default:
		buf.Write([]byte(fmt.Sprintf("%v", iter.timestamp.UnixNano())))
	}

	b := iter.count < iter.s.SeriesCount
	byt := buf.Bytes()

	return byt, b
}

// newTagSet returns a byte array representation
// of the tagset for a series
func (s *series) newTagSet(c int) []byte {
	var buf bytes.Buffer
	for _, tag := range s.Tags {
		buf.Write([]byte(fmt.Sprintf("%v=%v-%v,", tag.Key, tag.Value, c)))
	}

	b := buf.Bytes()
	b = b[0 : len(b)-1]

	return b
}

// newFieldSet returns a byte array representation
// of the field-set for a series
func (s *series) newFieldSet(c int) []byte {
	var buf bytes.Buffer

	for _, field := range s.Fields {
		switch field.Type {
		case "float64-flat":
			if rand.Intn(10) > 2 {
				buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, 100)))
			} else {
				buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, 100+rand.Intn(100))))
			}
		case "float64-inc+":
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, c+rand.Intn(2))))
		case "float64-inc":
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, c)))
		case "float64":
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, rand.Intn(1000))))
		case "int":
			buf.Write([]byte(fmt.Sprintf("%v=%vi,", field.Key, rand.Intn(1000))))
		case "bool":
			b := rand.Intn(2) == 1
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, b)))
		default:
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, rand.Intn(1000))))
		}
	}

	b := buf.Bytes()
	b = b[0 : len(b)-1]

	return b
}
<commit_msg>Fix timestamps<commit_after>package runner

import (
	"bytes"
	"fmt"
	"math/rand"
	"time"

	"github.com/BurntSushi/toml"
)

// tag is a struct that contains data
// about a tag for in a series
type tag struct {
	Key   string `toml:"key"`
	Value string `toml:"value"`
}

// tag is a struct that contains data
// about a field for in a series
type field struct {
	Key  string `toml:"key"`
	Type string `toml:"type"`
}

// series is a struct that contains data
// about the series that will be written
// during a stress test
type series struct {
	PointCount  int     `toml:"point_count"`
	Tick        string  `toml:"tick"`
	Jitter      bool    `toml:"jitter"`
	Measurement string  `toml:"measurement"`
	SeriesCount int     `toml:"series_count"`
	TagCount    int     `toml:"tag_count"`
	Tags        []tag   `toml:"tag"`
	Fields      []field `toml:"field"`
}

// write is a struct that contains the business
// logic for the stress test. e.g. where the
// influxdb instance is running, what database
// should points be written into
type write struct {
	Concurrency   int    `toml:"concurrency"`
	BatchSize     int    `toml:"batch_size"`
	BatchInterval string `toml:"batch_interval"`
	Database      string `toml:"database"`
	ResetDatabase bool   `toml:"reset_database"`
	Address       string `toml:"address"`
	Precision     string `toml:"precision"`
	StartDate     string `toml:"start_date"`
}

// query is a struct that contains the logic for
// a query that will be ran on during the stress
// test
type query struct {
	Enabled     bool     `toml:"enabled"`
	Concurrency int      `toml:"concurrency"`
	Aggregates  []string `toml:"aggregates"`
	Fields      []string `toml:"fields"`
}

// measurementQuery is a struct that contains
// the logic that runs a query against a measurement
// over a time period that is specified by
// `Offset`
type measurementQuery struct {
	query
	Offset string `toml:"offset"`
}

// seriesQuery is a struct that contains
// the logic that runs a query against a single
// series
type seriesQuery struct {
	query
	Interval string `toml:"interval"`
}

// Config is a struct that is passed into the `Run()` function.
type Config struct {
	Write             write            `toml:"write"`
	Series            []series         `toml:"series"`
	MeasurementQuery  measurementQuery `toml:"measurement_query"`
	SeriesQuery       seriesQuery      `toml:"series_query"`
	ChannelBufferSize int              `toml:"channel_buffer_size"`
	SSL               bool             `toml:"ssl"`
}

// NewSeries, takes a measurement, and point count,
// and a series count and returns a series
func NewSeries(m string, p int, sc int) series {
	s := series{
		PointCount:  p,
		SeriesCount: sc,
		Tick:        "1s",
		Measurement: m,
		Tags: []tag{
			tag{
				Key:   "host",
				Value: "server",
			},
		},
		Fields: []field{
			field{
				Key: "value",
			},
		},
	}

	return s
}

// NewConfig returns a pointer to a config
// with some default parameters set
func NewConfig() *Config {

	w := write{
		Concurrency:   10,
		BatchSize:     5000,
		BatchInterval: "0s",
		Database:      "stress",
		ResetDatabase: true,
		Address:       "localhost:8086",
		Precision:     "n",
	}

	c := &Config{
		Write: w,
	}

	return c
}

// DecodeFile takes a file path for a toml config file
// and returns a pointer to a Config Struct.
func DecodeFile(s string) (*Config, error) {
	t := &Config{}

	// Decode the toml file
	if _, err := toml.DecodeFile(s, t); err != nil {
		return nil, err
	}

	// Initialize Config struct
	// NOTE: Not happy with the implementation
	// but it will do for now
	for j, srs := range t.Series {
		for i := 0; i < srs.TagCount; i++ {

			tag := tag{
				Key:   fmt.Sprintf("tag-key-%d", i),
				Value: "tag-value",
			}

			srs.Tags = append(srs.Tags, tag)
			fmt.Println(srs)
		}

		t.Series[j] = srs
	}

	return t, nil
}

// seriesIter is a struct that contains a
// series and a count, where count is the
//number of points that have been written
// for the series `s`
type seriesIter struct {
	s         *series
	count     int
	timestamp time.Time
	precision string
}

// writeInterval returns a timestamp for the current time
// interval
func (s *series) writeInterval(i int, start time.Time) time.Time {
	var tick time.Duration
	var j int
	var err error

	tick, err = time.ParseDuration(s.Tick)
	if err != nil {
		panic(err)
	}

	if s.Jitter {
		j = rand.Intn(int(tick))
		if j%2 == 0 {
			j = -2 * j
		}
	}

	tick = tick*time.Duration(i) + time.Duration(j)

	return start.Add(tick)
}

// Iter returns a pointer to a seriesIter
func (s *series) Iter(i int, start time.Time, p string) *seriesIter {

	return &seriesIter{s: s, count: -1, timestamp: s.writeInterval(i, start), precision: p}
}

// Next returns a new point for a series.
// Currently, there is an off by one bug here.
func (iter *seriesIter) Next() ([]byte, bool) {
	var buf bytes.Buffer
	iter.count++

	buf.Write([]byte(fmt.Sprintf("%v,", iter.s.Measurement)))
	buf.Write(iter.s.newTagSet(iter.count))
	buf.Write([]byte(" "))
	buf.Write(iter.s.newFieldSet(iter.count))
	buf.Write([]byte(" "))

	switch iter.precision {
	case "s":
		buf.Write([]byte(fmt.Sprintf("%v", iter.timestamp.Unix())))
	default:
		buf.Write([]byte(fmt.Sprintf("%v", iter.timestamp.UnixNano())))
	}

	b := iter.count < iter.s.SeriesCount
	byt := buf.Bytes()

	return byt, b
}

// newTagSet returns a byte array representation
// of the tagset for a series
func (s *series) newTagSet(c int) []byte {
	var buf bytes.Buffer
	for _, tag := range s.Tags {
		buf.Write([]byte(fmt.Sprintf("%v=%v-%v,", tag.Key, tag.Value, c)))
	}

	b := buf.Bytes()
	b = b[0 : len(b)-1]

	return b
}

// newFieldSet returns a byte array representation
// of the field-set for a series
func (s *series) newFieldSet(c int) []byte {
	var buf bytes.Buffer

	for _, field := range s.Fields {
		switch field.Type {
		case "float64-flat":
			if rand.Intn(10) > 2 {
				buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, 100)))
			} else {
				buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, 100+rand.Intn(100))))
			}
		case "float64-inc+":
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, c+rand.Intn(2))))
		case "float64-inc":
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, c)))
		case "float64":
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, rand.Intn(1000))))
		case "int":
			buf.Write([]byte(fmt.Sprintf("%v=%vi,", field.Key, rand.Intn(1000))))
		case "bool":
			b := rand.Intn(2) == 1
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, b)))
		default:
			buf.Write([]byte(fmt.Sprintf("%v=%v,", field.Key, rand.Intn(1000))))
		}
	}

	b := buf.Bytes()
	b = b[0 : len(b)-1]

	return b
}
<|endoftext|>


<commit_before>package pgproto3

import (
	"encoding/binary"
	"encoding/json"
	"github.com/jackc/pgio"
)

type FunctionCall struct {
	Function         uint32
	ArgFormatCodes   []uint16
	Arguments        [][]byte
	ResultFormatCode uint16
}

// Frontend identifies this message as sendable by a PostgreSQL frontend.
func (*FunctionCall) Frontend() {}

// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
// type identifier and 4 byte message length.
func (dst *FunctionCall) Decode(src []byte) error {
	*dst = FunctionCall{}
	rp := 0
	// Specifies the object ID of the function to call.
	dst.Function = binary.BigEndian.Uint32(src[rp:])
	rp += 4
	// The number of argument format codes that follow (denoted C below).
	// This can be zero to indicate that there are no arguments or that the arguments all use the default format (text);
	// or one, in which case the specified format code is applied to all arguments;
	// or it can equal the actual number of arguments.
	nArgumentCodes := int(binary.BigEndian.Uint16(src[rp:]))
	rp += 2
	argumentCodes := make([]uint16, nArgumentCodes)
	for i := 0; i < nArgumentCodes; i++ {
		// The argument format codes. Each must presently be zero (text) or one (binary).
		ac := binary.BigEndian.Uint16(src[rp:])
		if ac != 0 && ac != 1 {
			return &invalidMessageFormatErr{messageType: "FunctionCall"}
		}
		argumentCodes[i] = ac
		rp += 2
	}
	dst.ArgFormatCodes = argumentCodes

	// Specifies the number of arguments being supplied to the function.
	nArguments := int(binary.BigEndian.Uint16(src[rp:]))
	rp += 2
	arguments := make([][]byte, nArguments)
	for i := 0; i < nArguments; i++ {
		// The length of the argument value, in bytes (this count does not include itself). Can be zero.
		// As a special case, -1 indicates a NULL argument value. No value bytes follow in the NULL case.
		argumentLength := int(binary.BigEndian.Uint32(src[rp:]))
		rp += 4
		if argumentLength == -1 {
			arguments[i] = nil
		} else {
			// The value of the argument, in the format indicated by the associated format code. n is the above length.
			argumentValue := src[rp : rp+argumentLength]
			rp += argumentLength
			arguments[i] = argumentValue
		}
	}
	dst.Arguments = arguments
	// The format code for the function result. Must presently be zero (text) or one (binary).
	resultFormatCode := binary.BigEndian.Uint16(src[rp:])
	if resultFormatCode != 0 && resultFormatCode != 1 {
		return &invalidMessageFormatErr{messageType: "FunctionCall"}
	}
	dst.ResultFormatCode = resultFormatCode
	return nil
}

// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *FunctionCall) Encode(dst []byte) []byte {
	dst = append(dst, 'F')
	sp := len(dst)
	dst = pgio.AppendUint32(dst, 0) // Unknown length, set it at the end
	dst = pgio.AppendUint32(dst, src.Function)
	dst = pgio.AppendUint16(dst, uint16(len(src.ArgFormatCodes)))
	for _, argFormatCode := range src.ArgFormatCodes {
		dst = pgio.AppendUint16(dst, argFormatCode)
	}
	dst = pgio.AppendUint16(dst, uint16(len(src.Arguments)))
	for _, argument := range src.Arguments {
		if argument == nil {
			dst = pgio.AppendInt32(dst, -1)
		} else {
			dst = pgio.AppendInt32(dst, int32(len(argument)))
			dst = append(dst, argument...)
		}
	}
	dst = pgio.AppendUint16(dst, src.ResultFormatCode)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
	return dst
}

// MarshalJSON implements encoding/json.Marshaler.
func (src FunctionCall) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Type string
	}{
		Type: "FunctionCall",
	})
}
<commit_msg>Remove unimplemented JSON marshalling for FunctionCall type.<commit_after>package pgproto3

import (
	"encoding/binary"
	"github.com/jackc/pgio"
)

type FunctionCall struct {
	Function         uint32
	ArgFormatCodes   []uint16
	Arguments        [][]byte
	ResultFormatCode uint16
}

// Frontend identifies this message as sendable by a PostgreSQL frontend.
func (*FunctionCall) Frontend() {}

// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
// type identifier and 4 byte message length.
func (dst *FunctionCall) Decode(src []byte) error {
	*dst = FunctionCall{}
	rp := 0
	// Specifies the object ID of the function to call.
	dst.Function = binary.BigEndian.Uint32(src[rp:])
	rp += 4
	// The number of argument format codes that follow (denoted C below).
	// This can be zero to indicate that there are no arguments or that the arguments all use the default format (text);
	// or one, in which case the specified format code is applied to all arguments;
	// or it can equal the actual number of arguments.
	nArgumentCodes := int(binary.BigEndian.Uint16(src[rp:]))
	rp += 2
	argumentCodes := make([]uint16, nArgumentCodes)
	for i := 0; i < nArgumentCodes; i++ {
		// The argument format codes. Each must presently be zero (text) or one (binary).
		ac := binary.BigEndian.Uint16(src[rp:])
		if ac != 0 && ac != 1 {
			return &invalidMessageFormatErr{messageType: "FunctionCall"}
		}
		argumentCodes[i] = ac
		rp += 2
	}
	dst.ArgFormatCodes = argumentCodes

	// Specifies the number of arguments being supplied to the function.
	nArguments := int(binary.BigEndian.Uint16(src[rp:]))
	rp += 2
	arguments := make([][]byte, nArguments)
	for i := 0; i < nArguments; i++ {
		// The length of the argument value, in bytes (this count does not include itself). Can be zero.
		// As a special case, -1 indicates a NULL argument value. No value bytes follow in the NULL case.
		argumentLength := int(binary.BigEndian.Uint32(src[rp:]))
		rp += 4
		if argumentLength == -1 {
			arguments[i] = nil
		} else {
			// The value of the argument, in the format indicated by the associated format code. n is the above length.
			argumentValue := src[rp : rp+argumentLength]
			rp += argumentLength
			arguments[i] = argumentValue
		}
	}
	dst.Arguments = arguments
	// The format code for the function result. Must presently be zero (text) or one (binary).
	resultFormatCode := binary.BigEndian.Uint16(src[rp:])
	if resultFormatCode != 0 && resultFormatCode != 1 {
		return &invalidMessageFormatErr{messageType: "FunctionCall"}
	}
	dst.ResultFormatCode = resultFormatCode
	return nil
}

// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
func (src *FunctionCall) Encode(dst []byte) []byte {
	dst = append(dst, 'F')
	sp := len(dst)
	dst = pgio.AppendUint32(dst, 0) // Unknown length, set it at the end
	dst = pgio.AppendUint32(dst, src.Function)
	dst = pgio.AppendUint16(dst, uint16(len(src.ArgFormatCodes)))
	for _, argFormatCode := range src.ArgFormatCodes {
		dst = pgio.AppendUint16(dst, argFormatCode)
	}
	dst = pgio.AppendUint16(dst, uint16(len(src.Arguments)))
	for _, argument := range src.Arguments {
		if argument == nil {
			dst = pgio.AppendInt32(dst, -1)
		} else {
			dst = pgio.AppendInt32(dst, int32(len(argument)))
			dst = append(dst, argument...)
		}
	}
	dst = pgio.AppendUint16(dst, src.ResultFormatCode)
	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
	return dst
}
<|endoftext|>


<commit_before>package brightbox

import (
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"log"

	"github.com/brightbox/gobrightbox"
	"github.com/hashicorp/terraform/helper/schema"
)

const (
	userdata_size_limit = 16384
)

func resourceBrightboxServer() *schema.Resource {
	return &schema.Resource{
		Create: resourceBrightboxServerCreate,
		Read:   resourceBrightboxServerRead,
		Update: resourceBrightboxServerUpdate,
		Delete: resourceBrightboxServerDelete,

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

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  nil,
			},

			"type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				Default:  nil,
				ForceNew: true,
			},

			"zone": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				Default:  nil,
				ForceNew: true,
			},

			"compatibility": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
				Default:  nil,
				ForceNew: true,
			},

			"user_data": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				StateFunc: func(v interface{}) string {
					switch v.(type) {
					case string:
						hash := sha1.Sum([]byte(v.(string)))
						return hex.EncodeToString(hash[:])
					default:
						return ""
					}
				},
			},

			"server_groups": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

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

			"locked": &schema.Schema{
				Type:     schema.TypeBool,
				Computed: true,
			},

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

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

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

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

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

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

			"ipv6_hostname": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"username": &schema.Schema{
				Type:	schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceBrightboxServerCreate(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*brightbox.Client)

	server_opts := &brightbox.ServerOptions{
		Image: d.Get("image").(string),
	}

	err := addUpdateableOptions(d, server_opts)
	if err != nil {
		return err
	}

	if attr, ok := d.GetOk("type"); ok {
		server_opts.ServerType = attr.(string)
	}
	if attr, ok := d.GetOk("zone"); ok {
		server_opts.Zone = attr.(string)
	}

	if sgs := d.Get("server_groups").(*schema.Set); sgs.Len() > 0 {
		var groups []string
		for _, v := range sgs.List() {
			groups = append(groups, v.(string))
		}
		server_opts.ServerGroups = &groups
	}

	log.Printf("[DEBUG] Server create configuration: %#v", server_opts)

	server, err := client.CreateServer(server_opts)
	if err != nil {
		return fmt.Errorf("Error creating server: %s", err)
	}

	d.SetId(server.Id)

	log.Printf("[INFO] Server ID: %s", d.Id())

	setServerAttributes(d, server)

	return nil
}

func resourceBrightboxServerRead(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*brightbox.Client)

	server, err := client.Server(d.Id())
	if err != nil {
		return fmt.Errorf("Error retrieving server details: %s", err)
	}

	setServerAttributes(d, server)

	return nil

}

func resourceBrightboxServerDelete(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*brightbox.Client)

	err := client.DestroyServer(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting server: %s", err)
	}
	return nil
}

func resourceBrightboxServerUpdate(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*brightbox.Client)

	server_opts := &brightbox.ServerOptions{
		Id: d.Id(),
	}

	err := addUpdateableOptions(d, server_opts)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Server update configuration: %#v", server_opts)

	server, err := client.UpdateServer(server_opts)
	if err != nil {
		return fmt.Errorf("Error updating server: %s", err)
	}

	setServerAttributes(d, server)

	return nil
}

func addUpdateableOptions(
	d *schema.ResourceData,
	opts *brightbox.ServerOptions,
) error {

	if attr, ok := d.GetOk("name"); ok {
		temp_name := attr.(string)
		opts.Name = &temp_name
	}

	if attr, ok := d.GetOk("userdata"); ok {
		encoded_userdata := base64.StdEncoding.EncodeToString([]byte(attr.(string)))

		if len(encoded_userdata) > userdata_size_limit {
			return fmt.Errorf(
				"The supplied user_data contains %d bytes after encoding, "+
					"this exeeds the limit of %d bytes", len(encoded_userdata), userdata_size_limit)
		}
		opts.UserData = &encoded_userdata
	}

	if attr, ok := d.GetOk("compatibility"); ok {
		temp_compat := attr.(bool)
		opts.CompatibilityMode = &temp_compat
	}

	return nil

}

func setServerAttributes(
	d *schema.ResourceData,
	server *brightbox.Server,
) {
	d.Set("image", server.Image.Id)
	d.Set("name", server.Name)
	d.Set("type", server.ServerType.Handle)
	d.Set("zone", server.Zone.Handle)
	d.Set("compatbility", server.CompatibilityMode)
	d.Set("status", server.Status)
	d.Set("locked", server.Locked)
	d.Set("hostname", server.Hostname)
	if server.Image.Username != "" {
		d.Set("username", server.Image.Username)
	}

	if len(server.Interfaces) > 0 {
		server_interface := server.Interfaces[0]
		d.Set("ipv4_address_private", server_interface.IPv4Address)
		d.Set("fqdn", server.Fqdn)
		d.Set("ipv6_address", server_interface.IPv6Address)
		d.Set("ipv6_hostname", "ipv6."+server.Fqdn)
	}

	if len(server.CloudIPs) > 0 {
		cloud_ip := server.CloudIPs[0]
		d.Set("ipv4_address", cloud_ip.PublicIP)
		d.Set("public_hostname", cloud_ip.Fqdn)
	}

	srvGrpIds := []string{}
	for _, sg := range server.ServerGroups {
		srvGrpIds = append(srvGrpIds, sg.Id)
	}
	d.Set("server_groups", srvGrpIds)

	SetConnectionDetails(d)

}

func SetConnectionDetails(d *schema.ResourceData) {
	var preferredSSHAddress string
	if attr, ok := d.GetOk("public_hostname"); ok {
		preferredSSHAddress = attr.(string)
	} else if attr, ok := d.GetOk("ipv6_hostname"); ok {
		preferredSSHAddress = attr.(string)
	} else if attr, ok := d.GetOk("fqdn"); ok {
		preferredSSHAddress = attr.(string)
	}

	if preferredSSHAddress != "" {
		connection_details := map[string]string{
			"type": "ssh",
			"host": preferredSSHAddress,
		}
		if attr, ok := d.GetOk("username"); ok {
			connection_details["user"] = attr.(string)
		}
		d.SetConnInfo(connection_details)
	}
}
<commit_msg>Add active status wait<commit_after>package brightbox

import (
	"crypto/sha1"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"log"
	"time"

	"github.com/brightbox/gobrightbox"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/resource"
)

const (
	userdata_size_limit = 16384
)

func resourceBrightboxServer() *schema.Resource {
	return &schema.Resource{
		Create: resourceBrightboxServerCreate,
		Read:   resourceBrightboxServerRead,
		Update: resourceBrightboxServerUpdate,
		Delete: resourceBrightboxServerDelete,

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

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Default:  nil,
			},

			"type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				Default:  nil,
				ForceNew: true,
			},

			"zone": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				Default:  nil,
				ForceNew: true,
			},

			"compatibility": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
				Computed: true,
				Default:  nil,
				ForceNew: true,
			},

			"user_data": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				StateFunc: func(v interface{}) string {
					switch v.(type) {
					case string:
						hash := sha1.Sum([]byte(v.(string)))
						return hex.EncodeToString(hash[:])
					default:
						return ""
					}
				},
			},

			"server_groups": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

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

			"locked": &schema.Schema{
				Type:     schema.TypeBool,
				Computed: true,
			},

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

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

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

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

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

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

			"ipv6_hostname": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
			"username": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceBrightboxServerCreate(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*brightbox.Client)

	server_opts := &brightbox.ServerOptions{
		Image: d.Get("image").(string),
	}

	err := addUpdateableOptions(d, server_opts)
	if err != nil {
		return err
	}

	if attr, ok := d.GetOk("type"); ok {
		server_opts.ServerType = attr.(string)
	}
	if attr, ok := d.GetOk("zone"); ok {
		server_opts.Zone = attr.(string)
	}

	if sgs := d.Get("server_groups").(*schema.Set); sgs.Len() > 0 {
		var groups []string
		for _, v := range sgs.List() {
			groups = append(groups, v.(string))
		}
		server_opts.ServerGroups = &groups
	}

	log.Printf("[DEBUG] Server create configuration: %#v", server_opts)

	server, err := client.CreateServer(server_opts)
	if err != nil {
		return fmt.Errorf("Error creating server: %s", err)
	}

	d.SetId(server.Id)

	log.Printf("[INFO] Waiting for Server (%s) to become available", d.Id())

	stateConf := resource.StateChangeConf{
		Pending:    []string{"creating"},
		Target:     []string{"active", "inactive"},
		Refresh:    serverStateRefresh(client, server.Id),
		Timeout:    5 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}
	active_server, err := stateConf.WaitForState()
	if err != nil {
		return err
	}

	setServerAttributes(d, active_server.(*brightbox.Server))

	return nil
}

func resourceBrightboxServerRead(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*brightbox.Client)

	server, err := client.Server(d.Id())
	if err != nil {
		return fmt.Errorf("Error retrieving server details: %s", err)
	}

	setServerAttributes(d, server)

	return nil

}

func resourceBrightboxServerDelete(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*brightbox.Client)

	err := client.DestroyServer(d.Id())
	if err != nil {
		return fmt.Errorf("Error deleting server: %s", err)
	}
	return nil
}

func resourceBrightboxServerUpdate(
	d *schema.ResourceData,
	meta interface{},
) error {
	client := meta.(*brightbox.Client)

	server_opts := &brightbox.ServerOptions{
		Id: d.Id(),
	}

	err := addUpdateableOptions(d, server_opts)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Server update configuration: %#v", server_opts)

	server, err := client.UpdateServer(server_opts)
	if err != nil {
		return fmt.Errorf("Error updating server: %s", err)
	}

	setServerAttributes(d, server)

	return nil
}

func addUpdateableOptions(
	d *schema.ResourceData,
	opts *brightbox.ServerOptions,
) error {

	if attr, ok := d.GetOk("name"); ok {
		temp_name := attr.(string)
		opts.Name = &temp_name
	}

	if attr, ok := d.GetOk("userdata"); ok {
		encoded_userdata := base64.StdEncoding.EncodeToString([]byte(attr.(string)))

		if len(encoded_userdata) > userdata_size_limit {
			return fmt.Errorf(
				"The supplied user_data contains %d bytes after encoding, "+
					"this exeeds the limit of %d bytes", len(encoded_userdata), userdata_size_limit)
		}
		opts.UserData = &encoded_userdata
	}

	if attr, ok := d.GetOk("compatibility"); ok {
		temp_compat := attr.(bool)
		opts.CompatibilityMode = &temp_compat
	}

	return nil

}

func setServerAttributes(
	d *schema.ResourceData,
	server *brightbox.Server,
) {
	d.Set("image", server.Image.Id)
	d.Set("name", server.Name)
	d.Set("type", server.ServerType.Handle)
	d.Set("zone", server.Zone.Handle)
	d.Set("compatbility", server.CompatibilityMode)
	d.Set("status", server.Status)
	d.Set("locked", server.Locked)
	d.Set("hostname", server.Hostname)
	if server.Image.Username != "" {
		d.Set("username", server.Image.Username)
	}

	if len(server.Interfaces) > 0 {
		server_interface := server.Interfaces[0]
		d.Set("ipv4_address_private", server_interface.IPv4Address)
		d.Set("fqdn", server.Fqdn)
		d.Set("ipv6_address", server_interface.IPv6Address)
		d.Set("ipv6_hostname", "ipv6."+server.Fqdn)
	}

	if len(server.CloudIPs) > 0 {
		cloud_ip := server.CloudIPs[0]
		d.Set("ipv4_address", cloud_ip.PublicIP)
		d.Set("public_hostname", cloud_ip.Fqdn)
	}

	srvGrpIds := []string{}
	for _, sg := range server.ServerGroups {
		srvGrpIds = append(srvGrpIds, sg.Id)
	}
	d.Set("server_groups", srvGrpIds)

	SetConnectionDetails(d)

}

func SetConnectionDetails(d *schema.ResourceData) {
	var preferredSSHAddress string
	if attr, ok := d.GetOk("public_hostname"); ok {
		preferredSSHAddress = attr.(string)
	} else if attr, ok := d.GetOk("ipv6_hostname"); ok {
		preferredSSHAddress = attr.(string)
	} else if attr, ok := d.GetOk("fqdn"); ok {
		preferredSSHAddress = attr.(string)
	}

	if preferredSSHAddress != "" {
		connection_details := map[string]string{
			"type": "ssh",
			"host": preferredSSHAddress,
		}
		if attr, ok := d.GetOk("username"); ok {
			connection_details["user"] = attr.(string)
		}
		d.SetConnInfo(connection_details)
	}
}

func serverStateRefresh(client *brightbox.Client, serverID string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		server, err := client.Server(serverID)
		if err != nil {
			log.Printf("Error on Server State Refresh: %s", err)
			return nil, "", err
		}
		return server, server.Status, nil
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
    "bytes"
    "net/http"
    "encoding/hex"
    "encoding/json"
    "io/ioutil"
    "flag"
    "fmt"
    "os"

    "github.com/FactomProject/factom"
)

var _ = hex.EncodeToString
var serverFct = "localhost:8089"

func sendCmd(cmd string, cmderror string) error {

    resp, err := http.Get(cmd)
    if err != nil {
        return err
    }

    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return err
    }
    resp.Body.Close()

    type x struct { Success bool }
    b := new(x)
    if err := json.Unmarshal(body, b); err != nil || !b.Success {
        fmt.Println(cmderror)
        return fmt.Errorf("Command Failed: ",string(body))
    }

    return nil
}

// Generates a new Address
func genfactoidaddress(args []string) error {

    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 1 {
        return man("generatefactoidaddress")
    }

    Addr,err := factom.GenerateFactoidAddress(args[0])
    if err != nil {
        fmt.Println(err)
    }else{
        fmt.Println(args[0]," = ",Addr)
    }

    return nil

}

func fctnewtrans(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 1 {
        fmt.Println("Missing Key")
        return fmt.Errorf("Missing Key")
    }

    str := fmt.Sprintf("http://%s/v1/factoid-new-transaction/%s", serverFct, args[0])
    err := sendCmd(str,"Duplicate or bad key")

    return err

}

func fctaddinput(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 3 {
        fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
        return fmt.Errorf("Missing Arguments")
    }
    // localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

    str := fmt.Sprintf("http://%s/v1/factoid-add-input/?key=%s&name=%s&amount=%s",
                       serverFct, args[0],args[1],args[2])
    err := sendCmd(str,"Failed to add input")

    return err
}

func fctaddoutput(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 3 {
        fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
        return fmt.Errorf("Missing Arguments")
    }
    // localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

    str := fmt.Sprintf("http://%s/v1/factoid-add-output/?key=%s&name=%s&amount=%s",
                       serverFct, args[0],args[1],args[2])
    err := sendCmd(str,"Failed to add output")

    return err
}

func fctaddecoutput(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 3 {
        fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
        return fmt.Errorf("Missing Arguments")
    }
    // localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

    str := fmt.Sprintf("http://%s/v1/factoid-add-ecoutput/?key=%s&name=%s&amount=%s",
                       serverFct, args[0],args[1],args[2])
    err := sendCmd(str,"Failed to add Entry Credit output")

    return err
}

func fctgetfee(args []string) error {
    resp, err := http.Get(fmt.Sprintf("http://%s/v1/factoid-get-fee/",serverFct))
    if err != nil {
        fmt.Println("Command Failed Get")
        return err
    }
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("Command Failed")
        return err
    }
    resp.Body.Close()

    // We pull the fee.  If the fee isn't positive, or if we fail to marshal, then there is a failure
    type x struct { Fee int64 }
    b := new(x)
    b.Fee = -1
    if err := json.Unmarshal(body, b); err != nil || b.Fee == -1 {
        fmt.Println("Command Failed")
        return fmt.Errorf("Command Failed")
    }
    tv := b.Fee/100000000
    lv := b.Fee-(tv*100000000)
    r := fmt.Sprintf("Fee: %d.%08d",tv,lv)
    var i int; for i=len(r)-1; r[i]=='0'; i-- {}
    if string(r[i])=="." { i +=1 }
    fmt.Println(r[:i+1])
    return nil
}

func fctsign(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 1 {
        fmt.Println("Missing Key")
        return fmt.Errorf("Missing Key")
    }

    str := fmt.Sprintf("http://%s/v1/factoid-sign-transaction/%s", serverFct, args[0])
    err := sendCmd(str,"Cannot sign transaction.  Check balances, inputs, transaction fees")

    return err
}

func fctsubmit(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 1 {
        fmt.Println("Missing Key")
        return fmt.Errorf("Missing Key")
    }

    s := struct{Transaction string}{args[0]}

    jdata, err := json.Marshal(s)
    if err != nil {
        fmt.Println("Submitt failed")
        return fmt.Errorf("Submit failed")
    }

    resp, err := http.Post(
        fmt.Sprintf("http://%s/v1/factoid-submit/", serverFct),
                           "application/json",
                           bytes.NewBuffer(jdata))
    if err != nil {
        fmt.Println("Submitt failed")
        return fmt.Errorf("Error returned by fctwallet")
    }
    resp.Body.Close()
    return nil
}<commit_msg>added postCmd and moved sendCmd to getCmd<commit_after>// Copyright 2015 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
    "bytes"
    "net/http"
    "encoding/hex"
    "encoding/json"
    "io/ioutil"
    "flag"
    "fmt"
    "os"

    "github.com/FactomProject/factom"
)

var _ = hex.EncodeToString
var serverFct = "localhost:8089"

func getCmd(cmd string, cmderror string) error {
	resp, err := http.Get(cmd)
	if err != nil {
		return err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	resp.Body.Close()

	type x struct{ Success bool }
	b := new(x)
	if err := json.Unmarshal(body, b); err != nil || !b.Success {
		fmt.Println(cmderror)
		return fmt.Errorf("Command Failed: ", string(body))
	}

	return nil
}

func postCmd(cmd string, cmderror string) error {
	resp, err := http.PostForm(cmd, nil)
	if err != nil {
		return err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	resp.Body.Close()

	type x struct{ Success bool }
	b := new(x)
	if err := json.Unmarshal(body, b); err != nil || !b.Success {
		fmt.Println(cmderror)
		return fmt.Errorf("Command Failed: ", string(body))
	}

	return nil
}

// Generates a new Address
func genfactoidaddress(args []string) error {

    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 1 {
        return man("generatefactoidaddress")
    }

    Addr,err := factom.GenerateFactoidAddress(args[0])
    if err != nil {
        fmt.Println(err)
    }else{
        fmt.Println(args[0]," = ",Addr)
    }

    return nil

}

func fctnewtrans(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 1 {
        fmt.Println("Missing Key")
        return fmt.Errorf("Missing Key")
    }

    str := fmt.Sprintf("http://%s/v1/factoid-new-transaction/%s", serverFct, args[0])
    err := postCmd(str, "Duplicate or bad key")

    return err

}

func fctaddinput(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 3 {
        fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
        return fmt.Errorf("Missing Arguments")
    }
    // localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

    str := fmt.Sprintf("http://%s/v1/factoid-add-input/?key=%s&name=%s&amount=%s",
                       serverFct, args[0],args[1],args[2])
    err := postCmd(str,"Failed to add input")

    return err
}

func fctaddoutput(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 3 {
        fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
        return fmt.Errorf("Missing Arguments")
    }
    // localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

    str := fmt.Sprintf("http://%s/v1/factoid-add-output/?key=%s&name=%s&amount=%s",
                       serverFct, args[0],args[1],args[2])
    err := postCmd(str,"Failed to add output")

    return err
}

func fctaddecoutput(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 3 {
        fmt.Println("Expecting a 1) transaction key, 2) an Address or Address name, and 3) an amount.")
        return fmt.Errorf("Missing Arguments")
    }
    // localhost:8089/v1/factoid-add-input/?key=<key>&name=<name or address>&amount=<amount>

    str := fmt.Sprintf("http://%s/v1/factoid-add-ecoutput/?key=%s&name=%s&amount=%s",
                       serverFct, args[0],args[1],args[2])
    err := postCmd(str,"Failed to add Entry Credit output")

    return err
}

func fctgetfee(args []string) error {
    resp, err := http.Get(fmt.Sprintf("http://%s/v1/factoid-get-fee/",serverFct))
    if err != nil {
        fmt.Println("Command Failed Get")
        return err
    }
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println("Command Failed")
        return err
    }
    resp.Body.Close()

    // We pull the fee.  If the fee isn't positive, or if we fail to marshal, then there is a failure
    type x struct { Fee int64 }
    b := new(x)
    b.Fee = -1
    if err := json.Unmarshal(body, b); err != nil || b.Fee == -1 {
        fmt.Println("Command Failed")
        return fmt.Errorf("Command Failed")
    }
    tv := b.Fee/100000000
    lv := b.Fee-(tv*100000000)
    r := fmt.Sprintf("Fee: %d.%08d",tv,lv)
    var i int; for i=len(r)-1; r[i]=='0'; i-- {}
    if string(r[i])=="." { i +=1 }
    fmt.Println(r[:i+1])
    return nil
}

func fctsign(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 1 {
        fmt.Println("Missing Key")
        return fmt.Errorf("Missing Key")
    }

    str := fmt.Sprintf("http://%s/v1/factoid-sign-transaction/%s", serverFct, args[0])
    err := postCmd(str,"Cannot sign transaction.  Check balances, inputs, transaction fees")

    return err
}

func fctsubmit(args []string) error {
    os.Args = args
    flag.Parse()
    args = flag.Args()
    if len(args) < 1 {
        fmt.Println("Missing Key")
        return fmt.Errorf("Missing Key")
    }

    s := struct{Transaction string}{args[0]}

    jdata, err := json.Marshal(s)
    if err != nil {
        fmt.Println("Submitt failed")
        return fmt.Errorf("Submit failed")
    }

    resp, err := http.Post(
        fmt.Sprintf("http://%s/v1/factoid-submit/", serverFct),
                           "application/json",
                           bytes.NewBuffer(jdata))
    if err != nil {
        fmt.Println("Submitt failed")
        return fmt.Errorf("Error returned by fctwallet")
    }
    resp.Body.Close()
    return nil
}<|endoftext|>


<commit_before>package main

import (
	"database/sql"							//used for unifrom database access
	"fmt"									//print statements
	"github.com/go-martini/martini"			//extra frame work build on net/http
	_ "github.com/lib/pq"					//go sql driver
	"net/http"								//framework
	"os"
)

func SetupDB() *sql.DB {
	//POSTGRESDB_PORT_5432_TCP_PORT  10.254.76.103
	db, err := sql.Open("postgres", "host=10.254.80.242 user=postgres dbname=postgres sslmode=disable") 		//my only lib/pq usage? login into postgres database
	PanicIf(err)

	return db
}

func PanicIf(err error) {
	if err != nil {
		panic(err)
	}
}

func ShowDB(db *sql.DB, r *http.Request, rw http.ResponseWriter) { //localhost:3000/?search=name
		search := "%" + r.URL.Query().Get("search") + "%"
		rows, err := db.Query(`SELECT fname, LName, cost, city
                           FROM custauth
                           WHERE FName ILIKE $1
                           OR LName ILIKE $1
                           OR city ILIKE $1`, search)
		PanicIf(err)
		defer rows.Close()

		var FirstName, LastName, cost, city string
		for rows.Next() {
			err := rows.Scan(&FirstName, &LastName, &cost, &city)
			PanicIf(err)
			fmt.Fprintf(rw, "First Name: %s\nLast Name: %s\nCost: %s\nCity: %s\n\n", FirstName, LastName, cost, city)
		}
	}

func InsertPur(r *http.Request, db *sql.DB){
//	_, err := db.Query("INSERT INTO custauth (custid, fname, lname, city,state, country,email,cost,errorflag) VALUES ($1, $2, $3, $4, $5, $6, $7, $8,$9)",
	_, err := db.Exec("INSERT INTO custauth (custid, fname, lname, city,state, country,email,cost,errorflag) VALUES ($1, $2, $3, $4, $5, $6, $7, $8,$9)",
	r.FormValue("custid"),
		r.FormValue("fname"),
		r.FormValue("lname"),
		r.FormValue("city"),
		r.FormValue("state"),
		r.FormValue("country"),
		r.FormValue("email"),
		r.FormValue("cost"),
		r.FormValue("errorflag"))

	PanicIf(err)
}

func main() {
	m := martini.Classic()
	m.Map(SetupDB())
	m.Get("/", func() string {return  "Hello to GoSQL database"})
  	m.Get("/var", func() []string {return  os.Environ() })
	m.Get("/show", ShowDB)
	m.Post("/add", InsertPur)
	m.Run()
}
<commit_msg>new hardcoded ip<commit_after>package main

import (
	"database/sql"							//used for unifrom database access
	"fmt"									//print statements
	"github.com/go-martini/martini"			//extra frame work build on net/http
	_ "github.com/lib/pq"					//go sql driver
	"net/http"								//framework
	"os"
)

func SetupDB() *sql.DB {
	//POSTGRESDB_PORT_5432_TCP_PORT  10.254.76.103
	db, err := sql.Open("postgres", "host=10.254.105.89 user=postgres dbname=postgres sslmode=disable") 		//my only lib/pq usage? login into postgres database
	PanicIf(err)

	return db
}

func PanicIf(err error) {
	if err != nil {
		panic(err)
	}
}

func ShowDB(db *sql.DB, r *http.Request, rw http.ResponseWriter) { //localhost:3000/?search=name
		search := "%" + r.URL.Query().Get("search") + "%"
		rows, err := db.Query(`SELECT fname, LName, cost, city
                           FROM custauth
                           WHERE FName ILIKE $1
                           OR LName ILIKE $1
                           OR city ILIKE $1`, search)
		PanicIf(err)
		defer rows.Close()

		var FirstName, LastName, cost, city string
		for rows.Next() {
			err := rows.Scan(&FirstName, &LastName, &cost, &city)
			PanicIf(err)
			fmt.Fprintf(rw, "First Name: %s\nLast Name: %s\nCost: %s\nCity: %s\n\n", FirstName, LastName, cost, city)
		}
	}

func InsertPur(r *http.Request, db *sql.DB){
//	_, err := db.Query("INSERT INTO custauth (custid, fname, lname, city,state, country,email,cost,errorflag) VALUES ($1, $2, $3, $4, $5, $6, $7, $8,$9)",
	_, err := db.Exec("INSERT INTO custauth (custid, fname, lname, city,state, country,email,cost,errorflag) VALUES ($1, $2, $3, $4, $5, $6, $7, $8,$9)",
	r.FormValue("custid"),
		r.FormValue("fname"),
		r.FormValue("lname"),
		r.FormValue("city"),
		r.FormValue("state"),
		r.FormValue("country"),
		r.FormValue("email"),
		r.FormValue("cost"),
		r.FormValue("errorflag"))

	PanicIf(err)
}

func main() {
	m := martini.Classic()
	m.Map(SetupDB())
	m.Get("/", func() string {return  "Hello to GoSQL database"})
  	m.Get("/var", func() []string {return  os.Environ() })
	m.Get("/show", ShowDB)
	m.Post("/add", InsertPur)
	m.Run()
}
<|endoftext|>


<commit_before>package main_test

import (
	"fmt"
	"log"
	"testing"

	dg "github.com/brimstone/go-domainglass"
)

var rawWhois = `% IANA WHOIS server
% for more information on IANA, visit http://www.iana.org
% This query returned 1 object

domain:       GLASS

organisation: Black Cover, LLC
address:      c/o Donuts Inc., 10500 NE 8th Street, Suite 350
address:      Bellevue, Washington 98004
address:      United States

contact:      administrative
name:         Richard Tindal
organisation: Donuts Inc.
address:      c/o Donuts Inc., 10500 NE 8th Street, Suite 350
address:      Bellevue, Washington 98004
address:      United States
phone:        +1.425.283.8248
fax-no:       +1.425.671.0020
e-mail:       richard@donuts.co

contact:      technical
name:         Chris Cowherd
organisation: Donuts Inc.
address:      c/o Donuts Inc., 10500 NE 8th Street, Suite 350
address:      Bellevue, Washington 98004
address:      United States
phone:        +1.425.296.6802
fax-no:       +1.425.671.0020
e-mail:       chris@donuts.co

nserver:      DEMAND.ALPHA.ARIDNS.NET.AU 2001:dcd:1:0:0:0:0:7 37.209.192.7
nserver:      DEMAND.BETA.ARIDNS.NET.AU 2001:dcd:2:0:0:0:0:7 37.209.194.7
nserver:      DEMAND.DELTA.ARIDNS.NET.AU 2001:dcd:4:0:0:0:0:7 37.209.198.7
nserver:      DEMAND.GAMMA.ARIDNS.NET.AU 2001:dcd:3:0:0:0:0:7 37.209.196.7
ds-rdata:     12799 8 1 9C1F9CB19B734D8E151F72C54FA50C46A561F937
ds-rdata:     12799 8 2 F1D217D39494BB123262FDC44F437C9D708653B0A83E9F43AB302091DAC72865

whois:        whois.donuts.co

status:       ACTIVE
remarks:      Registration information: http://donuts.co/

created:      2013-12-19
changed:      2015-06-29
source:       IANA

`

func TestGetWhoisRaw(*testing.T) {
	result, err := dg.GetWhoisRaw("whois.iana.org", "glass")
	if err != nil {
		log.Fatal("getWhoisRaw returned:", err)
	}

	if len(result) == 0 {
		log.Fatal("getWhoisRaw returned an empty string")
	}
}

func TestGetWhoisMap(*testing.T) {
	result, err := dg.GetWhoisMap(rawWhois)
	if err != nil {
		log.Fatal(err)
	}
	if len(result) == 0 {
		log.Fatal("Expected result of have multiple items")
	}
}

func TestGetWhoisInfo(*testing.T) {
	result, err := dg.GetWhoisInfo("domain.glass")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(result)
}
<commit_msg>Finishing off whois tests<commit_after>package main_test

import (
	"log"
	"testing"

	dg "github.com/brimstone/go-domainglass"
)

var rawWhois = `% IANA WHOIS server
% for more information on IANA, visit http://www.iana.org
% This query returned 1 object

domain:       GLASS

organisation: Black Cover, LLC
address:      c/o Donuts Inc., 10500 NE 8th Street, Suite 350
address:      Bellevue, Washington 98004
address:      United States

contact:      administrative
name:         Richard Tindal
organisation: Donuts Inc.
address:      c/o Donuts Inc., 10500 NE 8th Street, Suite 350
address:      Bellevue, Washington 98004
address:      United States
phone:        +1.425.283.8248
fax-no:       +1.425.671.0020
e-mail:       richard@donuts.co

contact:      technical
name:         Chris Cowherd
organisation: Donuts Inc.
address:      c/o Donuts Inc., 10500 NE 8th Street, Suite 350
address:      Bellevue, Washington 98004
address:      United States
phone:        +1.425.296.6802
fax-no:       +1.425.671.0020
e-mail:       chris@donuts.co

nserver:      DEMAND.ALPHA.ARIDNS.NET.AU 2001:dcd:1:0:0:0:0:7 37.209.192.7
nserver:      DEMAND.BETA.ARIDNS.NET.AU 2001:dcd:2:0:0:0:0:7 37.209.194.7
nserver:      DEMAND.DELTA.ARIDNS.NET.AU 2001:dcd:4:0:0:0:0:7 37.209.198.7
nserver:      DEMAND.GAMMA.ARIDNS.NET.AU 2001:dcd:3:0:0:0:0:7 37.209.196.7
ds-rdata:     12799 8 1 9C1F9CB19B734D8E151F72C54FA50C46A561F937
ds-rdata:     12799 8 2 F1D217D39494BB123262FDC44F437C9D708653B0A83E9F43AB302091DAC72865

whois:        whois.donuts.co

status:       ACTIVE
remarks:      Registration information: http://donuts.co/

created:      2013-12-19
changed:      2015-06-29
source:       IANA

`

func TestGetWhoisRaw(*testing.T) {
	result, err := dg.GetWhoisRaw("whois.iana.org", "glass")
	if err != nil {
		log.Fatal("getWhoisRaw returned:", err)
	}

	if len(result) == 0 {
		log.Fatal("getWhoisRaw returned an empty string")
	}
}

func TestGetWhoisMap(*testing.T) {
	result, err := dg.GetWhoisMap(rawWhois)
	if err != nil {
		log.Fatal(err)
	}
	if len(result) == 0 {
		log.Fatal("Expected result of have multiple items")
	}
}

func TestGetWhoisInfo(*testing.T) {
	result, err := dg.GetWhoisInfo("domain.glass")
	if err != nil {
		log.Fatal(err)
	}
	if len(result.Nameservers) == 0 {
		log.Fatal("Expected Nameservers")
	}
	if len(result.Emails) == 0 {
		log.Fatal("Expected Email addresses")
	}
}
<|endoftext|>