<commit_before>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package provider

import (
	log "github.com/Sirupsen/logrus"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"

	"google.golang.org/api/dns/v1"
	googleapi "google.golang.org/api/googleapi"

	"github.com/kubernetes-incubator/external-dns/endpoint"
	"github.com/kubernetes-incubator/external-dns/plan"
)

type managedZonesCreateCallInterface interface {
	Do(opts ...googleapi.CallOption) (*dns.ManagedZone, error)
}

type managedZonesDeleteCallInterface interface {
	Do(opts ...googleapi.CallOption) error
}

type managedZonesListCallInterface interface {
	Pages(ctx context.Context, f func(*dns.ManagedZonesListResponse) error) error
}

type managedZonesServiceInterface interface {
	Create(project string, managedzone *dns.ManagedZone) managedZonesCreateCallInterface
	Delete(project string, managedZone string) managedZonesDeleteCallInterface
	List(project string) managedZonesListCallInterface
}

type resourceRecordSetsListCallInterface interface {
	Pages(ctx context.Context, f func(*dns.ResourceRecordSetsListResponse) error) error
}

type resourceRecordSetsClientInterface interface {
	List(project string, managedZone string) resourceRecordSetsListCallInterface
}

type changesCreateCallInterface interface {
	Do(opts ...googleapi.CallOption) (*dns.Change, error)
}

type changesServiceInterface interface {
	Create(project string, managedZone string, change *dns.Change) changesCreateCallInterface
}

type resourceRecordSetsService struct {
	service *dns.ResourceRecordSetsService
}

func (r resourceRecordSetsService) List(project string, managedZone string) resourceRecordSetsListCallInterface {
	return r.service.List(project, managedZone)
}

type managedZonesService struct {
	service *dns.ManagedZonesService
}

func (m managedZonesService) Create(project string, managedzone *dns.ManagedZone) managedZonesCreateCallInterface {
	return m.service.Create(project, managedzone)
}

func (m managedZonesService) Delete(project string, managedZone string) managedZonesDeleteCallInterface {
	return m.service.Delete(project, managedZone)
}

func (m managedZonesService) List(project string) managedZonesListCallInterface {
	return m.service.List(project)
}

type changesService struct {
	service *dns.ChangesService
}

func (c changesService) Create(project string, managedZone string, change *dns.Change) changesCreateCallInterface {
	return c.service.Create(project, managedZone, change)
}

// googleProvider is an implementation of Provider for Google CloudDNS.
type googleProvider struct {
	// The Google project to work in
	project string
	// Enabled dry-run will print any modifying actions rather than execute them.
	dryRun bool
	// A client for managing resource record sets
	resourceRecordSetsClient resourceRecordSetsClientInterface
	// A client for managing hosted zones
	managedZonesClient managedZonesServiceInterface
	// A client for managing change sets
	changesClient changesServiceInterface
}

// NewGoogleProvider initializes a new Google CloudDNS based Provider.
func NewGoogleProvider(project string, dryRun bool) (Provider, error) {
	gcloud, err := google.DefaultClient(context.TODO(), dns.NdevClouddnsReadwriteScope)
	if err != nil {
		return nil, err
	}

	dnsClient, err := dns.New(gcloud)
	if err != nil {
		return nil, err
	}

	provider := &googleProvider{
		project: project,
		dryRun:  dryRun,
		resourceRecordSetsClient: resourceRecordSetsService{dnsClient.ResourceRecordSets},
		managedZonesClient:       managedZonesService{dnsClient.ManagedZones},
		changesClient:            changesService{dnsClient.Changes},
	}

	return provider, nil
}

// Zones returns the list of hosted zones.
func (p *googleProvider) Zones() (zones []*dns.ManagedZone, _ error) {
	f := func(resp *dns.ManagedZonesListResponse) error {
		// each page is processed sequentially, no need for a mutex here.
		zones = append(zones, resp.ManagedZones...)
		return nil
	}

	err := p.managedZonesClient.List(p.project).Pages(context.TODO(), f)
	if err != nil {
		return nil, err
	}

	return zones, nil
}

// CreateZone creates a hosted zone given a name.
func (p *googleProvider) CreateZone(name, domain string) error {
	zone := &dns.ManagedZone{
		Name:        name,
		DnsName:     domain,
		Description: "Automatically managed zone by kubernetes.io/external-dns",
	}

	_, err := p.managedZonesClient.Create(p.project, zone).Do()
	if err != nil {
		return err
	}

	return nil
}

// DeleteZone deletes a hosted zone given a name.
func (p *googleProvider) DeleteZone(name string) error {
	err := p.managedZonesClient.Delete(p.project, name).Do()
	if err != nil {
		return err
	}

	return nil
}

// Records returns the list of A records in a given hosted zone.
func (p *googleProvider) Records(zone string) (endpoints []*endpoint.Endpoint, _ error) {
	f := func(resp *dns.ResourceRecordSetsListResponse) error {
		for _, r := range resp.Rrsets {
			// TODO(linki, ownership): Remove once ownership system is in place.
			// See: https://github.com/kubernetes-incubator/external-dns/pull/122/files/74e2c3d3e237411e619aefc5aab694742001cdec#r109863370
			switch r.Type {
			case "A", "CNAME", "TXT":
				break
			default:
				continue
			}

			for _, rr := range r.Rrdatas {
				// each page is processed sequentially, no need for a mutex here.
				endpoints = append(endpoints, endpoint.NewEndpoint(r.Name, rr, r.Type))
			}
		}

		return nil
	}

	err := p.resourceRecordSetsClient.List(p.project, zone).Pages(context.TODO(), f)
	if err != nil {
		return nil, err
	}

	return endpoints, nil
}

// CreateRecords creates a given set of DNS records in the given hosted zone.
func (p *googleProvider) CreateRecords(zone string, endpoints []*endpoint.Endpoint) error {
	change := &dns.Change{}

	change.Additions = append(change.Additions, newRecords(endpoints)...)

	return p.submitChange(zone, change)
}

// UpdateRecords updates a given set of old records to a new set of records in a given hosted zone.
func (p *googleProvider) UpdateRecords(zone string, records, oldRecords []*endpoint.Endpoint) error {
	change := &dns.Change{}

	change.Additions = append(change.Additions, newRecords(records)...)
	change.Deletions = append(change.Deletions, newRecords(oldRecords)...)

	return p.submitChange(zone, change)
}

// DeleteRecords deletes a given set of DNS records in a given zone.
func (p *googleProvider) DeleteRecords(zone string, endpoints []*endpoint.Endpoint) error {
	change := &dns.Change{}

	change.Deletions = append(change.Deletions, newRecords(endpoints)...)

	return p.submitChange(zone, change)
}

// ApplyChanges applies a given set of changes in a given zone.
func (p *googleProvider) ApplyChanges(zone string, changes *plan.Changes) error {
	change := &dns.Change{}

	change.Additions = append(change.Additions, newRecords(changes.Create)...)

	change.Additions = append(change.Additions, newRecords(changes.UpdateNew)...)
	change.Deletions = append(change.Deletions, newRecords(changes.UpdateOld)...)

	change.Deletions = append(change.Deletions, newRecords(changes.Delete)...)

	return p.submitChange(zone, change)
}

// submitChange takes a zone and a Change and sends it to Google.
func (p *googleProvider) submitChange(zone string, change *dns.Change) error {
	if p.dryRun {
		for _, del := range change.Deletions {
			log.Infof("Del records: %s %s %s", del.Name, del.Type, del.Rrdatas)
		}
		for _, add := range change.Additions {
			log.Infof("Add records: %s %s %s", add.Name, add.Type, add.Rrdatas)
		}

		return nil
	}

	if len(change.Additions) == 0 && len(change.Deletions) == 0 {
		return nil
	}

	_, err := p.changesClient.Create(p.project, zone, change).Do()
	if err != nil {
		return err
	}

	return nil
}

// newRecords returns a collection of RecordSets based on the given endpoints.
func newRecords(endpoints []*endpoint.Endpoint) []*dns.ResourceRecordSet {
	records := make([]*dns.ResourceRecordSet, len(endpoints))

	for i, endpoint := range endpoints {
		records[i] = newRecord(endpoint)
	}

	return records
}

// newRecord returns a RecordSet based on the given endpoint.
func newRecord(endpoint *endpoint.Endpoint) *dns.ResourceRecordSet {
	return &dns.ResourceRecordSet{
		Name:    endpoint.DNSName,
		Rrdatas: []string{endpoint.Target},
		Ttl:     300,
		Type:    suitableType(endpoint),
	}
}
<commit_msg>fix(google): ensure DNS records have trailing dot before sending (#159)<commit_after>/*
Copyright 2017 The Kubernetes Authors.

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

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

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

package provider

import (
	log "github.com/Sirupsen/logrus"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"

	"google.golang.org/api/dns/v1"
	googleapi "google.golang.org/api/googleapi"

	"github.com/kubernetes-incubator/external-dns/endpoint"
	"github.com/kubernetes-incubator/external-dns/plan"
)

type managedZonesCreateCallInterface interface {
	Do(opts ...googleapi.CallOption) (*dns.ManagedZone, error)
}

type managedZonesDeleteCallInterface interface {
	Do(opts ...googleapi.CallOption) error
}

type managedZonesListCallInterface interface {
	Pages(ctx context.Context, f func(*dns.ManagedZonesListResponse) error) error
}

type managedZonesServiceInterface interface {
	Create(project string, managedzone *dns.ManagedZone) managedZonesCreateCallInterface
	Delete(project string, managedZone string) managedZonesDeleteCallInterface
	List(project string) managedZonesListCallInterface
}

type resourceRecordSetsListCallInterface interface {
	Pages(ctx context.Context, f func(*dns.ResourceRecordSetsListResponse) error) error
}

type resourceRecordSetsClientInterface interface {
	List(project string, managedZone string) resourceRecordSetsListCallInterface
}

type changesCreateCallInterface interface {
	Do(opts ...googleapi.CallOption) (*dns.Change, error)
}

type changesServiceInterface interface {
	Create(project string, managedZone string, change *dns.Change) changesCreateCallInterface
}

type resourceRecordSetsService struct {
	service *dns.ResourceRecordSetsService
}

func (r resourceRecordSetsService) List(project string, managedZone string) resourceRecordSetsListCallInterface {
	return r.service.List(project, managedZone)
}

type managedZonesService struct {
	service *dns.ManagedZonesService
}

func (m managedZonesService) Create(project string, managedzone *dns.ManagedZone) managedZonesCreateCallInterface {
	return m.service.Create(project, managedzone)
}

func (m managedZonesService) Delete(project string, managedZone string) managedZonesDeleteCallInterface {
	return m.service.Delete(project, managedZone)
}

func (m managedZonesService) List(project string) managedZonesListCallInterface {
	return m.service.List(project)
}

type changesService struct {
	service *dns.ChangesService
}

func (c changesService) Create(project string, managedZone string, change *dns.Change) changesCreateCallInterface {
	return c.service.Create(project, managedZone, change)
}

// googleProvider is an implementation of Provider for Google CloudDNS.
type googleProvider struct {
	// The Google project to work in
	project string
	// Enabled dry-run will print any modifying actions rather than execute them.
	dryRun bool
	// A client for managing resource record sets
	resourceRecordSetsClient resourceRecordSetsClientInterface
	// A client for managing hosted zones
	managedZonesClient managedZonesServiceInterface
	// A client for managing change sets
	changesClient changesServiceInterface
}

// NewGoogleProvider initializes a new Google CloudDNS based Provider.
func NewGoogleProvider(project string, dryRun bool) (Provider, error) {
	gcloud, err := google.DefaultClient(context.TODO(), dns.NdevClouddnsReadwriteScope)
	if err != nil {
		return nil, err
	}

	dnsClient, err := dns.New(gcloud)
	if err != nil {
		return nil, err
	}

	provider := &googleProvider{
		project: project,
		dryRun:  dryRun,
		resourceRecordSetsClient: resourceRecordSetsService{dnsClient.ResourceRecordSets},
		managedZonesClient:       managedZonesService{dnsClient.ManagedZones},
		changesClient:            changesService{dnsClient.Changes},
	}

	return provider, nil
}

// Zones returns the list of hosted zones.
func (p *googleProvider) Zones() (zones []*dns.ManagedZone, _ error) {
	f := func(resp *dns.ManagedZonesListResponse) error {
		// each page is processed sequentially, no need for a mutex here.
		zones = append(zones, resp.ManagedZones...)
		return nil
	}

	err := p.managedZonesClient.List(p.project).Pages(context.TODO(), f)
	if err != nil {
		return nil, err
	}

	return zones, nil
}

// CreateZone creates a hosted zone given a name.
func (p *googleProvider) CreateZone(name, domain string) error {
	zone := &dns.ManagedZone{
		Name:        name,
		DnsName:     domain,
		Description: "Automatically managed zone by kubernetes.io/external-dns",
	}

	_, err := p.managedZonesClient.Create(p.project, zone).Do()
	if err != nil {
		return err
	}

	return nil
}

// DeleteZone deletes a hosted zone given a name.
func (p *googleProvider) DeleteZone(name string) error {
	err := p.managedZonesClient.Delete(p.project, name).Do()
	if err != nil {
		return err
	}

	return nil
}

// Records returns the list of A records in a given hosted zone.
func (p *googleProvider) Records(zone string) (endpoints []*endpoint.Endpoint, _ error) {
	f := func(resp *dns.ResourceRecordSetsListResponse) error {
		for _, r := range resp.Rrsets {
			// TODO(linki, ownership): Remove once ownership system is in place.
			// See: https://github.com/kubernetes-incubator/external-dns/pull/122/files/74e2c3d3e237411e619aefc5aab694742001cdec#r109863370
			switch r.Type {
			case "A", "CNAME", "TXT":
				break
			default:
				continue
			}

			for _, rr := range r.Rrdatas {
				// each page is processed sequentially, no need for a mutex here.
				endpoints = append(endpoints, endpoint.NewEndpoint(r.Name, rr, r.Type))
			}
		}

		return nil
	}

	err := p.resourceRecordSetsClient.List(p.project, zone).Pages(context.TODO(), f)
	if err != nil {
		return nil, err
	}

	return endpoints, nil
}

// CreateRecords creates a given set of DNS records in the given hosted zone.
func (p *googleProvider) CreateRecords(zone string, endpoints []*endpoint.Endpoint) error {
	change := &dns.Change{}

	change.Additions = append(change.Additions, newRecords(endpoints)...)

	return p.submitChange(zone, change)
}

// UpdateRecords updates a given set of old records to a new set of records in a given hosted zone.
func (p *googleProvider) UpdateRecords(zone string, records, oldRecords []*endpoint.Endpoint) error {
	change := &dns.Change{}

	change.Additions = append(change.Additions, newRecords(records)...)
	change.Deletions = append(change.Deletions, newRecords(oldRecords)...)

	return p.submitChange(zone, change)
}

// DeleteRecords deletes a given set of DNS records in a given zone.
func (p *googleProvider) DeleteRecords(zone string, endpoints []*endpoint.Endpoint) error {
	change := &dns.Change{}

	change.Deletions = append(change.Deletions, newRecords(endpoints)...)

	return p.submitChange(zone, change)
}

// ApplyChanges applies a given set of changes in a given zone.
func (p *googleProvider) ApplyChanges(zone string, changes *plan.Changes) error {
	change := &dns.Change{}

	change.Additions = append(change.Additions, newRecords(changes.Create)...)

	change.Additions = append(change.Additions, newRecords(changes.UpdateNew)...)
	change.Deletions = append(change.Deletions, newRecords(changes.UpdateOld)...)

	change.Deletions = append(change.Deletions, newRecords(changes.Delete)...)

	return p.submitChange(zone, change)
}

// submitChange takes a zone and a Change and sends it to Google.
func (p *googleProvider) submitChange(zone string, change *dns.Change) error {
	if p.dryRun {
		for _, del := range change.Deletions {
			log.Infof("Del records: %s %s %s", del.Name, del.Type, del.Rrdatas)
		}
		for _, add := range change.Additions {
			log.Infof("Add records: %s %s %s", add.Name, add.Type, add.Rrdatas)
		}

		return nil
	}

	if len(change.Additions) == 0 && len(change.Deletions) == 0 {
		return nil
	}

	_, err := p.changesClient.Create(p.project, zone, change).Do()
	if err != nil {
		return err
	}

	return nil
}

// newRecords returns a collection of RecordSets based on the given endpoints.
func newRecords(endpoints []*endpoint.Endpoint) []*dns.ResourceRecordSet {
	records := make([]*dns.ResourceRecordSet, len(endpoints))

	for i, endpoint := range endpoints {
		records[i] = newRecord(endpoint)
	}

	return records
}

// newRecord returns a RecordSet based on the given endpoint.
func newRecord(endpoint *endpoint.Endpoint) *dns.ResourceRecordSet {
	return &dns.ResourceRecordSet{
		Name:    ensureTrailingDot(endpoint.DNSName),
		Rrdatas: []string{ensureTrailingDot(endpoint.Target)},
		Ttl:     300,
		Type:    suitableType(endpoint),
	}
}
<|endoftext|>


<commit_before>package sinmetalcraft

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

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
	"google.golang.org/appengine/user"

	"google.golang.org/api/compute/v1"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
)

func init() {
	api := ServerApi{}

	http.HandleFunc("/api/1/server", api.Handler)
}

type ServerApi struct{}

type ServerApiPutParam struct {
	KeyStr    string `json:"key"`
	Operation string `json:"operation"`
}

func (a *ServerApi) Handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		a.Post(w, r)
	} else if r.Method == "PUT" {
		a.Put(w, r)
	} else if r.Method == "GET" {
		a.List(w, r)
	} else if r.Method == "DELETE" {
		a.Delete(w, r)
	} else {
		w.WriteHeader(http.StatusMethodNotAllowed)
	}
}

// create new instance
func (a *ServerApi) Post(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	u := user.Current(ctx)
	if u == nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusUnauthorized)
		loginURL, err := user.LoginURL(ctx, "")
		if err != nil {
			log.Errorf(ctx, "get user login URL error, %s", err.Error())
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		w.Write([]byte(fmt.Sprintf(`{"loginURL":"%s"}`, loginURL)))
		return
	}

	var form map[string]string
	err := json.NewDecoder(r.Body).Decode(&form)
	if err != nil {
		log.Infof(ctx, "rquest body, %v", r.Body)
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid request."}`))
		return
	}
	defer r.Body.Close()

	if len(form["key"]) < 1 {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "key is required."}`))
		return
	}
	key, err := datastore.DecodeKey(form["key"])
	if err != nil {
		log.Infof(ctx, "decode key error. param = %s, err = %s", form["key"], err.Error())
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid key."}`))
		return
	}

	var minecraft Minecraft
	err = datastore.Get(ctx, key, &minecraft)
	if err == datastore.ErrNoSuchEntity {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s is not found."}`, form["key"])))
		return
	}
	if err != nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s"}`, err.Error())))
		return
	}
	minecraft.Key = key

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	is := compute.NewInstancesService(s)
	name, err := createInstance(ctx, is, minecraft)
	if err != nil {
		log.Errorf(ctx, "ERROR compute instances create: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(http.StatusCreated)
	w.Write([]byte(fmt.Sprintf(`{"message" : "%s create done!"}`, name)))
}

// reset or start instance
func (a *ServerApi) Put(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	u := user.Current(ctx)
	if u == nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusUnauthorized)
		loginURL, err := user.LoginURL(ctx, "")
		if err != nil {
			log.Errorf(ctx, "get user login URL error, %s", err.Error())
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		w.Write([]byte(fmt.Sprintf(`{"loginURL":"%s"}`, loginURL)))
		return
	}

	var param ServerApiPutParam
	err := json.NewDecoder(r.Body).Decode(&param)
	if err != nil {
		log.Infof(ctx, "rquest body, %v", r.Body)
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid request."}`))
		return
	}
	defer r.Body.Close()

	key, err := datastore.DecodeKey(param.KeyStr)
	if err != nil {
		log.Infof(ctx, "invalid key, %v", r.Body)
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid key."}`))
		return
	}

	if param.Operation != "start" && param.Operation != "reset" {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"invalid request" : "operation param is start or reset"}`))
		return
	}

	var minecraft Minecraft
	err = datastore.Get(ctx, key, &minecraft)
	if err == datastore.ErrNoSuchEntity {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s is not found."}`, param.KeyStr)))
		return
	}
	if err != nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s"}`, err.Error())))
		return
	}
	minecraft.Key = key

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	is := compute.NewInstancesService(s)

	var name string
	if param.Operation == "start" {
		name, err = startInstance(ctx, is, minecraft)
		if err != nil {
			log.Errorf(ctx, "ERROR compute Instances Start: %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	} else if param.Operation == "reset" {
		name, err = resetInstance(ctx, is, minecraft)
		if err != nil {
			log.Errorf(ctx, "ERROR compute Instances Reset: %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	} else {
		log.Errorf(ctx, `{"invalid request" : "operation param is start or reset"}`)
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"invalid request" : "operation param is start or reset"}`))
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf(`"{"message": "%s %s done!"}`, name, param.Operation)))
}

// delete instance
func (a *ServerApi) Delete(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	u := user.Current(ctx)
	if u == nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusUnauthorized)
		loginURL, err := user.LoginURL(ctx, "")
		if err != nil {
			log.Errorf(ctx, "get user login URL error, %s", err.Error())
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		w.Write([]byte(fmt.Sprintf(`{"loginURL":"%s"}`, loginURL)))
		return
	}

	keyStr := r.FormValue("key")

	key, err := datastore.DecodeKey(keyStr)
	if err != nil {
		log.Infof(ctx, "invalid key, %v", r.Body)
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid key."}`))
		return
	}

	var minecraft Minecraft
	err = datastore.Get(ctx, key, &minecraft)
	if err == datastore.ErrNoSuchEntity {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s is not found."}`, keyStr)))
		return
	}
	if err != nil {
		log.Errorf(ctx, "ERROR, Get Minecraft error = %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	minecraft.Key = key

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	is := compute.NewInstancesService(s)

	name, err := deleteInstance(ctx, is, minecraft)
	if err != nil {
		log.Errorf(ctx, "ERROR compute Instances Delete: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf(`{"message": "%s delete done!"}`, name)))
}

// list instance
func (a *ServerApi) List(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	u := user.Current(ctx)
	if u == nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusUnauthorized)
		loginURL, err := user.LoginURL(ctx, "")
		if err != nil {
			log.Errorf(ctx, "get user login URL error, %s", err.Error())
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		w.Write([]byte(fmt.Sprintf(`{"loginURL":"%s"}`, loginURL)))
		return
	}
	if user.IsAdmin(ctx) == false {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusForbidden)
		return
	}

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	is := compute.NewInstancesService(s)
	instances, cursor, err := listInstance(ctx, is, "asia-east1-b")
	if err != nil {
		log.Errorf(ctx, "ERROR compute.Instance List: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	var res []MinecraftApiResponse
	for _, item := range instances {
		res = append(res, MinecraftApiResponse{
			InstanceName:      item.Name,
			Zone:              item.Zone,
			IPAddr:            item.NetworkInterfaces[0].AccessConfigs[0].NatIP,
			Status:            item.Status,
			CreationTimestamp: item.CreationTimestamp,
		})
	}

	apiRes := MinecraftApiListResponse{
		Items:  res,
		Cursor: cursor,
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(apiRes)
}
<commit_msg>server: ひとまずServer StartのAPIは認証無しにした<commit_after>package sinmetalcraft

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

	"google.golang.org/appengine"
	"google.golang.org/appengine/datastore"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/urlfetch"
	"google.golang.org/appengine/user"

	"google.golang.org/api/compute/v1"

	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
)

func init() {
	api := ServerApi{}

	http.HandleFunc("/api/1/server", api.Handler)
}

type ServerApi struct{}

type ServerApiPutParam struct {
	KeyStr    string `json:"key"`
	Operation string `json:"operation"`
}

func (a *ServerApi) Handler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		a.Post(w, r)
	} else if r.Method == "PUT" {
		a.Put(w, r)
	} else if r.Method == "GET" {
		a.List(w, r)
	} else if r.Method == "DELETE" {
		a.Delete(w, r)
	} else {
		w.WriteHeader(http.StatusMethodNotAllowed)
	}
}

// create new instance
func (a *ServerApi) Post(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	var form map[string]string
	err := json.NewDecoder(r.Body).Decode(&form)
	if err != nil {
		log.Infof(ctx, "rquest body, %v", r.Body)
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid request."}`))
		return
	}
	defer r.Body.Close()

	if len(form["key"]) < 1 {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "key is required."}`))
		return
	}
	key, err := datastore.DecodeKey(form["key"])
	if err != nil {
		log.Infof(ctx, "decode key error. param = %s, err = %s", form["key"], err.Error())
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid key."}`))
		return
	}

	var minecraft Minecraft
	err = datastore.Get(ctx, key, &minecraft)
	if err == datastore.ErrNoSuchEntity {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s is not found."}`, form["key"])))
		return
	}
	if err != nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s"}`, err.Error())))
		return
	}
	minecraft.Key = key

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	is := compute.NewInstancesService(s)
	name, err := createInstance(ctx, is, minecraft)
	if err != nil {
		log.Errorf(ctx, "ERROR compute instances create: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(http.StatusCreated)
	w.Write([]byte(fmt.Sprintf(`{"message" : "%s create done!"}`, name)))
}

// reset or start instance
func (a *ServerApi) Put(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	var param ServerApiPutParam
	err := json.NewDecoder(r.Body).Decode(&param)
	if err != nil {
		log.Infof(ctx, "rquest body, %v", r.Body)
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid request."}`))
		return
	}
	defer r.Body.Close()

	key, err := datastore.DecodeKey(param.KeyStr)
	if err != nil {
		log.Infof(ctx, "invalid key, %v", r.Body)
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid key."}`))
		return
	}

	if param.Operation != "start" && param.Operation != "reset" {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"invalid request" : "operation param is start or reset"}`))
		return
	}

	var minecraft Minecraft
	err = datastore.Get(ctx, key, &minecraft)
	if err == datastore.ErrNoSuchEntity {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s is not found."}`, param.KeyStr)))
		return
	}
	if err != nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s"}`, err.Error())))
		return
	}
	minecraft.Key = key

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	is := compute.NewInstancesService(s)

	var name string
	if param.Operation == "start" {
		name, err = startInstance(ctx, is, minecraft)
		if err != nil {
			log.Errorf(ctx, "ERROR compute Instances Start: %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	} else if param.Operation == "reset" {
		name, err = resetInstance(ctx, is, minecraft)
		if err != nil {
			log.Errorf(ctx, "ERROR compute Instances Reset: %s", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	} else {
		log.Errorf(ctx, `{"invalid request" : "operation param is start or reset"}`)
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"invalid request" : "operation param is start or reset"}`))
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf(`"{"message": "%s %s done!"}`, name, param.Operation)))
}

// delete instance
func (a *ServerApi) Delete(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	u := user.Current(ctx)
	if u == nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusUnauthorized)
		loginURL, err := user.LoginURL(ctx, "")
		if err != nil {
			log.Errorf(ctx, "get user login URL error, %s", err.Error())
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		w.Write([]byte(fmt.Sprintf(`{"loginURL":"%s"}`, loginURL)))
		return
	}

	keyStr := r.FormValue("key")

	key, err := datastore.DecodeKey(keyStr)
	if err != nil {
		log.Infof(ctx, "invalid key, %v", r.Body)
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte(`{"message": "invalid key."}`))
		return
	}

	var minecraft Minecraft
	err = datastore.Get(ctx, key, &minecraft)
	if err == datastore.ErrNoSuchEntity {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusNotFound)
		w.Write([]byte(fmt.Sprintf(`{"message": "%s is not found."}`, keyStr)))
		return
	}
	if err != nil {
		log.Errorf(ctx, "ERROR, Get Minecraft error = %s", err.Error())
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	minecraft.Key = key

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	is := compute.NewInstancesService(s)

	name, err := deleteInstance(ctx, is, minecraft)
	if err != nil {
		log.Errorf(ctx, "ERROR compute Instances Delete: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	w.Write([]byte(fmt.Sprintf(`{"message": "%s delete done!"}`, name)))
}

// list instance
func (a *ServerApi) List(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)

	u := user.Current(ctx)
	if u == nil {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusUnauthorized)
		loginURL, err := user.LoginURL(ctx, "")
		if err != nil {
			log.Errorf(ctx, "get user login URL error, %s", err.Error())
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		w.Write([]byte(fmt.Sprintf(`{"loginURL":"%s"}`, loginURL)))
		return
	}
	if user.IsAdmin(ctx) == false {
		w.Header().Set("Content-Type", "application/json; charset=utf-8")
		w.WriteHeader(http.StatusForbidden)
		return
	}

	client := &http.Client{
		Transport: &oauth2.Transport{
			Source: google.AppEngineTokenSource(ctx, compute.ComputeScope),
			Base:   &urlfetch.Transport{Context: ctx},
		},
	}
	s, err := compute.New(client)
	if err != nil {
		log.Errorf(ctx, "ERROR compute.New: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	is := compute.NewInstancesService(s)
	instances, cursor, err := listInstance(ctx, is, "asia-east1-b")
	if err != nil {
		log.Errorf(ctx, "ERROR compute.Instance List: %s", err)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}

	var res []MinecraftApiResponse
	for _, item := range instances {
		res = append(res, MinecraftApiResponse{
			InstanceName:      item.Name,
			Zone:              item.Zone,
			IPAddr:            item.NetworkInterfaces[0].AccessConfigs[0].NatIP,
			Status:            item.Status,
			CreationTimestamp: item.CreationTimestamp,
		})
	}

	apiRes := MinecraftApiListResponse{
		Items:  res,
		Cursor: cursor,
	}

	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(apiRes)
}
<|endoftext|>


<commit_before>package etcd

import (
	"context"
	"fmt"
	"sort"
	"strings"

	etcdv3 "github.com/coreos/etcd/clientv3"

	"github.com/hashicorp/terraform/internal/backend"
	"github.com/hashicorp/terraform/internal/states"
	"github.com/hashicorp/terraform/internal/states/remote"
	"github.com/hashicorp/terraform/internal/states/statemgr"
)

func (b *Backend) Workspaces() ([]string, error) {
	res, err := b.client.Get(context.TODO(), b.prefix, etcdv3.WithPrefix(), etcdv3.WithKeysOnly())
	if err != nil {
		return nil, err
	}

	result := make([]string, 1, len(res.Kvs)+1)
	result[0] = backend.DefaultStateName
	for _, kv := range res.Kvs {
		if strings.TrimPrefix(string(kv.Key), b.prefix) != backend.DefaultStateName {
			result = append(result, strings.TrimPrefix(string(kv.Key), b.prefix))
		}
	}
	sort.Strings(result[1:])

	return result, nil
}

func (b *Backend) DeleteWorkspace(name string) error {
	if name == backend.DefaultStateName || name == "" {
		return fmt.Errorf("Can't delete default state.")
	}

	key := b.determineKey(name)

	_, err := b.client.Delete(context.TODO(), key)
	return err
}

func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
	var stateMgr statemgr.Full = &remote.State{
		Client: &RemoteClient{
			Client: b.client,
			DoLock: b.lock,
			Key:    b.determineKey(name),
		},
	}

	if !b.lock {
		stateMgr = &statemgr.LockDisabled{Inner: stateMgr}
	}

	lockInfo := statemgr.NewLockInfo()
	lockInfo.Operation = "init"
	lockId, err := stateMgr.Lock(lockInfo)
	if err != nil {
		return nil, fmt.Errorf("Failed to lock state in etcd: %s.", err)
	}

	lockUnlock := func(parent error) error {
		if err := stateMgr.Unlock(lockId); err != nil {
			return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
		}
		return parent
	}

	if err := stateMgr.RefreshState(); err != nil {
		err = lockUnlock(err)
		return nil, err
	}

	if v := stateMgr.State(); v == nil {
		if err := stateMgr.WriteState(states.NewState()); err != nil {
			err = lockUnlock(err)
			return nil, err
		}
		if err := stateMgr.PersistState(); err != nil {
			err = lockUnlock(err)
			return nil, err
		}
	}

	if err := lockUnlock(nil); err != nil {
		return nil, err
	}

	return stateMgr, nil
}

func (b *Backend) determineKey(name string) string {
	return b.prefix + name
}

const errStateUnlock = `
Error unlocking etcd state. Lock ID: %s

Error: %s

You may have to force-unlock this state in order to use it again.
`
<commit_msg>StateMgr must be able to return with locked state<commit_after>package etcd

import (
	"context"
	"fmt"
	"sort"
	"strings"

	etcdv3 "github.com/coreos/etcd/clientv3"

	"github.com/hashicorp/terraform/internal/backend"
	"github.com/hashicorp/terraform/internal/states"
	"github.com/hashicorp/terraform/internal/states/remote"
	"github.com/hashicorp/terraform/internal/states/statemgr"
)

func (b *Backend) Workspaces() ([]string, error) {
	res, err := b.client.Get(context.TODO(), b.prefix, etcdv3.WithPrefix(), etcdv3.WithKeysOnly())
	if err != nil {
		return nil, err
	}

	result := make([]string, 1, len(res.Kvs)+1)
	result[0] = backend.DefaultStateName
	for _, kv := range res.Kvs {
		if strings.TrimPrefix(string(kv.Key), b.prefix) != backend.DefaultStateName {
			result = append(result, strings.TrimPrefix(string(kv.Key), b.prefix))
		}
	}
	sort.Strings(result[1:])

	return result, nil
}

func (b *Backend) DeleteWorkspace(name string) error {
	if name == backend.DefaultStateName || name == "" {
		return fmt.Errorf("Can't delete default state.")
	}

	key := b.determineKey(name)

	_, err := b.client.Delete(context.TODO(), key)
	return err
}

func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
	var stateMgr statemgr.Full = &remote.State{
		Client: &RemoteClient{
			Client: b.client,
			DoLock: b.lock,
			Key:    b.determineKey(name),
		},
	}

	if !b.lock {
		stateMgr = &statemgr.LockDisabled{Inner: stateMgr}
	}

	lockInfo := statemgr.NewLockInfo()
	lockInfo.Operation = "init"
	lockUnlock := func(parent error) error {
		return nil
	}

	if err := stateMgr.RefreshState(); err != nil {
		err = lockUnlock(err)
		return nil, err
	}

	if v := stateMgr.State(); v == nil {
		lockId, err := stateMgr.Lock(lockInfo)
		if err != nil {
			return nil, fmt.Errorf("Failed to lock state in etcd: %s.", err)
		}

		lockUnlock = func(parent error) error {
			if err := stateMgr.Unlock(lockId); err != nil {
				return fmt.Errorf(strings.TrimSpace(errStateUnlock), lockId, err)
			}
			return parent
		}

		if err := stateMgr.WriteState(states.NewState()); err != nil {
			err = lockUnlock(err)
			return nil, err
		}
		if err := stateMgr.PersistState(); err != nil {
			err = lockUnlock(err)
			return nil, err
		}
	}

	if err := lockUnlock(nil); err != nil {
		return nil, err
	}

	return stateMgr, nil
}

func (b *Backend) determineKey(name string) string {
	return b.prefix + name
}

const errStateUnlock = `
Error unlocking etcd state. Lock ID: %s

Error: %s

You may have to force-unlock this state in order to use it again.
`
<|endoftext|>


<commit_before>package riemann

import (
	"flag"
	"strconv"

	"github.com/readmill/metrics"
	"github.com/readmill/raidman"
)

type Riemann struct {
	addr   *string
	proto  *string
	client *raidman.Client
}

func (r *Riemann) Publish(evs ...*metrics.Event) error {
	if r.client == nil {
		client, err := r.open()
		if err != nil {
			return err
		}
		r.client = client
	}

	for _, e := range evs {
		ev := &raidman.Event{
			State:      e.State,
			Service:    e.Service,
			Metric:     e.Metric,
			Ttl:        e.Ttl,
			Attributes: e.Attributes,
		}
		if ev.Attributes == nil {
			ev.Attributes = map[string]string{}
		}
		if e.HttpStatus != 0 {
			ev.Attributes["status"] = strconv.Itoa(e.HttpStatus)
		}
		if e.Transient {
			ev.Attributes["persist"] = "false"
		}
		err := r.client.Send(ev)
		if err != nil {
			return err
		}
	}
	return nil
}

func (r *Riemann) open() (*raidman.Client, error) {
	return raidman.Dial(*r.proto, *r.addr)
}

func init() {
	addr := flag.String("riemann.addr", ":5555", "riemann host address")
	proto := flag.String("riemann.proto", "tcp", "riemann network protocol (tcp, udp)")
	metrics.Register("riemann", &Riemann{addr, proto, nil})
}
<commit_msg>Fix persist, use globals<commit_after>package riemann

import (
	"flag"
	"strconv"

	"github.com/readmill/metrics"
	"github.com/readmill/raidman"
)

var (
	HttpStatusAttr = "status"
	PersistAttr    = "persist"
)

type Riemann struct {
	addr   *string
	proto  *string
	client *raidman.Client
}

func (r *Riemann) Publish(evs ...*metrics.Event) error {
	if r.client == nil {
		client, err := r.open()
		if err != nil {
			return err
		}
		r.client = client
	}

	for _, e := range evs {
		ev := &raidman.Event{
			State:      e.State,
			Service:    e.Service,
			Metric:     e.Metric,
			Ttl:        e.Ttl,
			Attributes: e.Attributes,
		}
		if ev.Attributes == nil {
			ev.Attributes = map[string]string{}
		}
		if e.HttpStatus != 0 {
			ev.Attributes[HttpStatusAttr] = strconv.Itoa(e.HttpStatus)
		}
		if !e.Transient {
			ev.Attributes[PersistAttr] = "true"
		}
		err := r.client.Send(ev)
		if err != nil {
			return err
		}
	}
	return nil
}

func (r *Riemann) open() (*raidman.Client, error) {
	return raidman.Dial(*r.proto, *r.addr)
}

func init() {
	addr := flag.String("riemann.addr", ":5555", "riemann host address")
	proto := flag.String("riemann.proto", "tcp", "riemann network protocol (tcp, udp)")
	metrics.Register("riemann", &Riemann{addr, proto, nil})
}
<|endoftext|>


<commit_before>package extensions

import (
	"github.com/racker/perigee"
	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/pagination"
)

// Get retrieves information for a specific extension using its alias.
func Get(c *gophercloud.ServiceClient, alias string) GetResult {
	var res GetResult
	_, err := perigee.Request("GET", extensionURL(c, alias), perigee.Options{
		MoreHeaders: c.Provider.AuthenticatedHeaders(),
		Results:     &res.Resp,
		OkCodes:     []int{200},
	})
	res.Err = err
	return res
}

// List returns a Pager which allows you to iterate over the full collection of
// extensions. It does not accept query parameters.
func List(c *gophercloud.ServiceClient) pagination.Pager {
	return pagination.NewPager(c, listExtensionURL(c), func(r pagination.LastHTTPResponse) pagination.Page {
		return ExtensionPage{pagination.SinglePageBase(r)}
	})
}
<commit_msg>Documentation tweak :lipstick:<commit_after>package extensions

import (
	"github.com/racker/perigee"
	"github.com/rackspace/gophercloud"
	"github.com/rackspace/gophercloud/pagination"
)

// Get retrieves information for a specific extension using its alias.
func Get(c *gophercloud.ServiceClient, alias string) GetResult {
	var res GetResult
	_, err := perigee.Request("GET", extensionURL(c, alias), perigee.Options{
		MoreHeaders: c.Provider.AuthenticatedHeaders(),
		Results:     &res.Resp,
		OkCodes:     []int{200},
	})
	res.Err = err
	return res
}

// List returns a Pager which allows you to iterate over the full collection of extensions.
// It does not accept query parameters.
func List(c *gophercloud.ServiceClient) pagination.Pager {
	return pagination.NewPager(c, listExtensionURL(c), func(r pagination.LastHTTPResponse) pagination.Page {
		return ExtensionPage{pagination.SinglePageBase(r)}
	})
}
<|endoftext|>


<commit_before>package ttransport

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"sync"
	"testing"
	"time"

	crand "crypto/rand"
	mrand "math/rand"

	"github.com/libp2p/go-libp2p-core/mux"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/transport"
	"github.com/libp2p/go-libp2p-testing/race"

	ma "github.com/multiformats/go-multiaddr"
)

// VerboseDebugging can be set to true to enable verbose debug logging in the
// stream stress tests.
var VerboseDebugging = false

var randomness []byte

var StressTestTimeout = 1 * time.Minute

func init() {
	// read 1MB of randomness
	randomness = make([]byte, 1<<20)
	if _, err := crand.Read(randomness); err != nil {
		panic(err)
	}

	if timeout := os.Getenv("TEST_STRESS_TIMEOUT_MS"); timeout != "" {
		if v, err := strconv.ParseInt(timeout, 10, 32); err == nil {
			StressTestTimeout = time.Duration(v) * time.Millisecond
		}
	}
}

type Options struct {
	ConnNum   int
	StreamNum int
	MsgNum    int
	MsgMin    int
	MsgMax    int
}

func fullClose(t *testing.T, s mux.MuxedStream) {
	if err := s.CloseWrite(); err != nil {
		t.Error(err)
		s.Reset()
		return
	}
	b, err := ioutil.ReadAll(s)
	if err != nil {
		t.Error(err)
	}
	if len(b) != 0 {
		t.Error("expected to be done reading")
	}
	if err := s.Close(); err != nil {
		t.Error(err)
	}
}

func randBuf(size int) []byte {
	n := len(randomness) - size
	if size < 1 {
		panic(fmt.Errorf("requested too large buffer (%d). max is %d", size, len(randomness)))
	}

	start := mrand.Intn(n)
	return randomness[start : start+size]
}

func debugLog(t *testing.T, s string, args ...interface{}) {
	if VerboseDebugging {
		t.Logf(s, args...)
	}
}

func echoStream(t *testing.T, s mux.MuxedStream) {
	// echo everything
	var err error
	if VerboseDebugging {
		t.Logf("accepted stream")
		_, err = io.Copy(&logWriter{t, s}, s)
		t.Log("closing stream")
	} else {
		_, err = io.Copy(s, s) // echo everything
	}
	if err != nil {
		t.Error(err)
	}
}

type logWriter struct {
	t *testing.T
	W io.Writer
}

func (lw *logWriter) Write(buf []byte) (int, error) {
	lw.t.Logf("logwriter: writing %d bytes", len(buf))
	return lw.W.Write(buf)
}

func echo(t *testing.T, c transport.CapableConn) {
	var wg sync.WaitGroup
	defer wg.Wait()
	for {
		str, err := c.AcceptStream()
		if err != nil {
			break
		}
		wg.Add(1)
		go func() {
			defer wg.Done()
			defer str.Close()
			echoStream(t, str)
		}()
	}
}

func serve(t *testing.T, l transport.Listener) {
	var wg sync.WaitGroup
	defer wg.Wait()

	for {
		c, err := l.Accept()
		if err != nil {
			return
		}
		defer c.Close()

		wg.Add(1)
		debugLog(t, "accepted connection")
		go func() {
			defer wg.Done()
			echo(t, c)
		}()
	}
}

func SubtestStress(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID, opt Options) {
	msgsize := 1 << 11

	rateLimitN := 5000 // max of 5k funcs, because -race has 8k max.
	rateLimitChan := make(chan struct{}, rateLimitN)
	for i := 0; i < rateLimitN; i++ {
		rateLimitChan <- struct{}{}
	}

	rateLimit := func(f func()) {
		<-rateLimitChan
		f()
		rateLimitChan <- struct{}{}
	}

	writeStream := func(s mux.MuxedStream, bufs chan<- []byte) {
		debugLog(t, "writeStream %p, %d MsgNum", s, opt.MsgNum)

		for i := 0; i < opt.MsgNum; i++ {
			buf := randBuf(msgsize)
			bufs <- buf
			debugLog(t, "%p writing %d bytes (message %d/%d #%x)", s, len(buf), i, opt.MsgNum, buf[:3])
			if _, err := s.Write(buf); err != nil {
				t.Errorf("s.Write(buf): %s", err)
				continue
			}
		}
	}

	readStream := func(s mux.MuxedStream, bufs <-chan []byte) {
		debugLog(t, "readStream %p, %d MsgNum", s, opt.MsgNum)

		buf2 := make([]byte, msgsize)
		i := 0
		for buf1 := range bufs {
			i++
			debugLog(t, "%p reading %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.MsgNum, buf1[:3])

			if _, err := io.ReadFull(s, buf2); err != nil {
				t.Errorf("io.ReadFull(s, buf2): %s", err)
				debugLog(t, "%p failed to read %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.MsgNum, buf1[:3])
				continue
			}
			if !bytes.Equal(buf1, buf2) {
				t.Errorf("buffers not equal (%x != %x)", buf1[:3], buf2[:3])
			}
		}
	}

	openStreamAndRW := func(c mux.MuxedConn) {
		debugLog(t, "openStreamAndRW %p, %d opt.MsgNum", c, opt.MsgNum)

		s, err := c.OpenStream(context.Background())
		if err != nil {
			t.Errorf("failed to create NewStream: %s", err)
			return
		}

		bufs := make(chan []byte, opt.MsgNum)
		go func() {
			writeStream(s, bufs)
			close(bufs)
		}()

		readStream(s, bufs)
		fullClose(t, s)
	}

	openConnAndRW := func() {
		debugLog(t, "openConnAndRW")

		var wg sync.WaitGroup
		defer wg.Wait()

		l, err := ta.Listen(maddr)
		if err != nil {
			t.Error(err)
			return
		}
		defer l.Close()

		wg.Add(1)
		go func() {
			defer wg.Done()
			serve(t, l)
		}()

		c, err := tb.Dial(context.Background(), l.Multiaddr(), peerA)
		if err != nil {
			t.Error(err)
			return
		}

		// serve the outgoing conn, because some muxers assume
		// that we _always_ call serve. (this is an error?)
		wg.Add(1)
		go func() {
			defer wg.Done()
			defer c.Close()
			debugLog(t, "serving connection")
			echo(t, c)
		}()

		var openWg sync.WaitGroup
		for i := 0; i < opt.StreamNum; i++ {
			openWg.Add(1)
			go rateLimit(func() {
				defer openWg.Done()
				openStreamAndRW(c)
			})
		}
		openWg.Wait()
	}

	debugLog(t, "openConnsAndRW, %d conns", opt.ConnNum)

	var wg sync.WaitGroup
	defer wg.Wait()
	for i := 0; i < opt.ConnNum; i++ {
		wg.Add(1)
		go rateLimit(func() {
			defer wg.Done()
			openConnAndRW()
		})
	}
}

func SubtestStreamOpenStress(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	l, err := ta.Listen(maddr)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	count := 10000
	workers := 5

	if race.WithRace() {
		// the race detector can only deal with 8128 simultaneous goroutines, so let's make sure we don't go overboard.
		count = 1000
	}

	var (
		connA, connB transport.CapableConn
	)

	accepted := make(chan error, 1)
	go func() {
		var err error
		connA, err = l.Accept()
		accepted <- err
	}()
	connB, err = tb.Dial(context.Background(), l.Multiaddr(), peerA)
	if err != nil {
		t.Fatal(err)
	}
	err = <-accepted
	if err != nil {
		t.Fatal(err)
	}

	defer func() {
		if connA != nil {
			connA.Close()
		}
		if connB != nil {
			connB.Close()
		}
	}()

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		for j := 0; j < workers; j++ {
			wg.Add(1)
			go func() {
				defer wg.Done()
				for i := 0; i < count; i++ {
					s, err := connA.OpenStream(context.Background())
					if err != nil {
						t.Error(err)
						return
					}
					wg.Add(1)
					go func() {
						defer wg.Done()
						fullClose(t, s)
					}()
				}
			}()
		}
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 0; i < count*workers; i++ {
			str, err := connB.AcceptStream()
			if err != nil {
				break
			}
			wg.Add(1)
			go func() {
				defer wg.Done()
				fullClose(t, str)
			}()
		}
	}()

	timeout := time.After(StressTestTimeout)
	done := make(chan struct{})

	go func() {
		wg.Wait()
		close(done)
	}()

	select {
	case <-timeout:
		t.Fatal("timed out receiving streams")
	case <-done:
	}
}

func SubtestStreamReset(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	var wg sync.WaitGroup
	defer wg.Wait()

	l, err := ta.Listen(maddr)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	wg.Add(1)
	go func() {
		defer wg.Done()

		muxa, err := l.Accept()
		if err != nil {
			t.Error(err)
			return
		}
		defer muxa.Close()

		s, err := muxa.OpenStream(context.Background())
		if err != nil {
			t.Error(err)
			return
		}
		defer s.Close()

		// Some transports won't open the stream until we write. That's
		// fine.
		_, _ = s.Write([]byte("foo"))

		time.Sleep(time.Millisecond * 50)

		_, err = s.Write([]byte("bar"))
		if err == nil {
			t.Error("should have failed to write")
		}

	}()

	muxb, err := tb.Dial(context.Background(), l.Multiaddr(), peerA)
	if err != nil {
		t.Fatal(err)
	}
	defer muxb.Close()

	str, err := muxb.AcceptStream()
	if err != nil {
		t.Error(err)
		return
	}
	str.Reset()
}

func SubtestStress1Conn1Stream1Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 1,
		MsgNum:    1,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress1Conn1Stream100Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 1,
		MsgNum:    100,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress1Conn100Stream100Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 100,
		MsgNum:    100,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress50Conn10Stream50Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   50,
		StreamNum: 10,
		MsgNum:    50,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress1Conn1000Stream10Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 1000,
		MsgNum:    10,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress1Conn100Stream100Msg10MB(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 100,
		MsgNum:    100,
		MsgMax:    10000,
		MsgMin:    1000,
	})
}
<commit_msg>fix closing of dialed connections<commit_after>package ttransport

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"sync"
	"testing"
	"time"

	crand "crypto/rand"
	mrand "math/rand"

	"github.com/libp2p/go-libp2p-core/mux"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/transport"
	"github.com/libp2p/go-libp2p-testing/race"

	ma "github.com/multiformats/go-multiaddr"
)

// VerboseDebugging can be set to true to enable verbose debug logging in the
// stream stress tests.
var VerboseDebugging = false

var randomness []byte

var StressTestTimeout = 1 * time.Minute

func init() {
	// read 1MB of randomness
	randomness = make([]byte, 1<<20)
	if _, err := crand.Read(randomness); err != nil {
		panic(err)
	}

	if timeout := os.Getenv("TEST_STRESS_TIMEOUT_MS"); timeout != "" {
		if v, err := strconv.ParseInt(timeout, 10, 32); err == nil {
			StressTestTimeout = time.Duration(v) * time.Millisecond
		}
	}
}

type Options struct {
	ConnNum   int
	StreamNum int
	MsgNum    int
	MsgMin    int
	MsgMax    int
}

func fullClose(t *testing.T, s mux.MuxedStream) {
	if err := s.CloseWrite(); err != nil {
		t.Error(err)
		s.Reset()
		return
	}
	b, err := ioutil.ReadAll(s)
	if err != nil {
		t.Error(err)
	}
	if len(b) != 0 {
		t.Error("expected to be done reading")
	}
	if err := s.Close(); err != nil {
		t.Error(err)
	}
}

func randBuf(size int) []byte {
	n := len(randomness) - size
	if size < 1 {
		panic(fmt.Errorf("requested too large buffer (%d). max is %d", size, len(randomness)))
	}

	start := mrand.Intn(n)
	return randomness[start : start+size]
}

func debugLog(t *testing.T, s string, args ...interface{}) {
	if VerboseDebugging {
		t.Logf(s, args...)
	}
}

func echoStream(t *testing.T, s mux.MuxedStream) {
	// echo everything
	var err error
	if VerboseDebugging {
		t.Logf("accepted stream")
		_, err = io.Copy(&logWriter{t, s}, s)
		t.Log("closing stream")
	} else {
		_, err = io.Copy(s, s) // echo everything
	}
	if err != nil {
		t.Error(err)
	}
}

type logWriter struct {
	t *testing.T
	W io.Writer
}

func (lw *logWriter) Write(buf []byte) (int, error) {
	lw.t.Logf("logwriter: writing %d bytes", len(buf))
	return lw.W.Write(buf)
}

func echo(t *testing.T, c transport.CapableConn) {
	var wg sync.WaitGroup
	defer wg.Wait()
	for {
		str, err := c.AcceptStream()
		if err != nil {
			break
		}
		wg.Add(1)
		go func() {
			defer wg.Done()
			defer str.Close()
			echoStream(t, str)
		}()
	}
}

func serve(t *testing.T, l transport.Listener) {
	var wg sync.WaitGroup
	defer wg.Wait()

	for {
		c, err := l.Accept()
		if err != nil {
			return
		}
		defer c.Close()

		wg.Add(1)
		debugLog(t, "accepted connection")
		go func() {
			defer wg.Done()
			echo(t, c)
		}()
	}
}

func SubtestStress(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID, opt Options) {
	msgsize := 1 << 11

	rateLimitN := 5000 // max of 5k funcs, because -race has 8k max.
	rateLimitChan := make(chan struct{}, rateLimitN)
	for i := 0; i < rateLimitN; i++ {
		rateLimitChan <- struct{}{}
	}

	rateLimit := func(f func()) {
		<-rateLimitChan
		f()
		rateLimitChan <- struct{}{}
	}

	writeStream := func(s mux.MuxedStream, bufs chan<- []byte) {
		debugLog(t, "writeStream %p, %d MsgNum", s, opt.MsgNum)

		for i := 0; i < opt.MsgNum; i++ {
			buf := randBuf(msgsize)
			bufs <- buf
			debugLog(t, "%p writing %d bytes (message %d/%d #%x)", s, len(buf), i, opt.MsgNum, buf[:3])
			if _, err := s.Write(buf); err != nil {
				t.Errorf("s.Write(buf): %s", err)
				continue
			}
		}
	}

	readStream := func(s mux.MuxedStream, bufs <-chan []byte) {
		debugLog(t, "readStream %p, %d MsgNum", s, opt.MsgNum)

		buf2 := make([]byte, msgsize)
		i := 0
		for buf1 := range bufs {
			i++
			debugLog(t, "%p reading %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.MsgNum, buf1[:3])

			if _, err := io.ReadFull(s, buf2); err != nil {
				t.Errorf("io.ReadFull(s, buf2): %s", err)
				debugLog(t, "%p failed to read %d bytes (message %d/%d #%x)", s, len(buf1), i-1, opt.MsgNum, buf1[:3])
				continue
			}
			if !bytes.Equal(buf1, buf2) {
				t.Errorf("buffers not equal (%x != %x)", buf1[:3], buf2[:3])
			}
		}
	}

	openStreamAndRW := func(c mux.MuxedConn) {
		debugLog(t, "openStreamAndRW %p, %d opt.MsgNum", c, opt.MsgNum)

		s, err := c.OpenStream(context.Background())
		if err != nil {
			t.Errorf("failed to create NewStream: %s", err)
			return
		}

		bufs := make(chan []byte, opt.MsgNum)
		go func() {
			writeStream(s, bufs)
			close(bufs)
		}()

		readStream(s, bufs)
		fullClose(t, s)
	}

	openConnAndRW := func() {
		debugLog(t, "openConnAndRW")

		var wg sync.WaitGroup
		defer wg.Wait()

		l, err := ta.Listen(maddr)
		if err != nil {
			t.Error(err)
			return
		}
		defer l.Close()

		wg.Add(1)
		go func() {
			defer wg.Done()
			serve(t, l)
		}()

		c, err := tb.Dial(context.Background(), l.Multiaddr(), peerA)
		if err != nil {
			t.Error(err)
			return
		}
		defer c.Close()

		// serve the outgoing conn, because some muxers assume
		// that we _always_ call serve. (this is an error?)
		wg.Add(1)
		go func() {
			defer wg.Done()
			debugLog(t, "serving connection")
			echo(t, c)
		}()

		var openWg sync.WaitGroup
		for i := 0; i < opt.StreamNum; i++ {
			openWg.Add(1)
			go rateLimit(func() {
				defer openWg.Done()
				openStreamAndRW(c)
			})
		}
		openWg.Wait()
	}

	debugLog(t, "openConnsAndRW, %d conns", opt.ConnNum)

	var wg sync.WaitGroup
	defer wg.Wait()
	for i := 0; i < opt.ConnNum; i++ {
		wg.Add(1)
		go rateLimit(func() {
			defer wg.Done()
			openConnAndRW()
		})
	}
}

func SubtestStreamOpenStress(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	l, err := ta.Listen(maddr)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	count := 10000
	workers := 5

	if race.WithRace() {
		// the race detector can only deal with 8128 simultaneous goroutines, so let's make sure we don't go overboard.
		count = 1000
	}

	var (
		connA, connB transport.CapableConn
	)

	accepted := make(chan error, 1)
	go func() {
		var err error
		connA, err = l.Accept()
		accepted <- err
	}()
	connB, err = tb.Dial(context.Background(), l.Multiaddr(), peerA)
	if err != nil {
		t.Fatal(err)
	}
	err = <-accepted
	if err != nil {
		t.Fatal(err)
	}

	defer func() {
		if connA != nil {
			connA.Close()
		}
		if connB != nil {
			connB.Close()
		}
	}()

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		for j := 0; j < workers; j++ {
			wg.Add(1)
			go func() {
				defer wg.Done()
				for i := 0; i < count; i++ {
					s, err := connA.OpenStream(context.Background())
					if err != nil {
						t.Error(err)
						return
					}
					wg.Add(1)
					go func() {
						defer wg.Done()
						fullClose(t, s)
					}()
				}
			}()
		}
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 0; i < count*workers; i++ {
			str, err := connB.AcceptStream()
			if err != nil {
				break
			}
			wg.Add(1)
			go func() {
				defer wg.Done()
				fullClose(t, str)
			}()
		}
	}()

	timeout := time.After(StressTestTimeout)
	done := make(chan struct{})

	go func() {
		wg.Wait()
		close(done)
	}()

	select {
	case <-timeout:
		t.Fatal("timed out receiving streams")
	case <-done:
	}
}

func SubtestStreamReset(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	var wg sync.WaitGroup
	defer wg.Wait()

	l, err := ta.Listen(maddr)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()

	wg.Add(1)
	go func() {
		defer wg.Done()

		muxa, err := l.Accept()
		if err != nil {
			t.Error(err)
			return
		}
		defer muxa.Close()

		s, err := muxa.OpenStream(context.Background())
		if err != nil {
			t.Error(err)
			return
		}
		defer s.Close()

		// Some transports won't open the stream until we write. That's
		// fine.
		_, _ = s.Write([]byte("foo"))

		time.Sleep(time.Millisecond * 50)

		_, err = s.Write([]byte("bar"))
		if err == nil {
			t.Error("should have failed to write")
		}

	}()

	muxb, err := tb.Dial(context.Background(), l.Multiaddr(), peerA)
	if err != nil {
		t.Fatal(err)
	}
	defer muxb.Close()

	str, err := muxb.AcceptStream()
	if err != nil {
		t.Error(err)
		return
	}
	str.Reset()
}

func SubtestStress1Conn1Stream1Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 1,
		MsgNum:    1,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress1Conn1Stream100Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 1,
		MsgNum:    100,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress1Conn100Stream100Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 100,
		MsgNum:    100,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress50Conn10Stream50Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   50,
		StreamNum: 10,
		MsgNum:    50,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress1Conn1000Stream10Msg(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 1000,
		MsgNum:    10,
		MsgMax:    100,
		MsgMin:    100,
	})
}

func SubtestStress1Conn100Stream100Msg10MB(t *testing.T, ta, tb transport.Transport, maddr ma.Multiaddr, peerA peer.ID) {
	SubtestStress(t, ta, tb, maddr, peerA, Options{
		ConnNum:   1,
		StreamNum: 100,
		MsgNum:    100,
		MsgMax:    10000,
		MsgMin:    1000,
	})
}
<|endoftext|>


<commit_before>// +build linux

package common

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
)

func DoSysctrl(mib string) ([]string, error) {
	sysctl, err := exec.LookPath("sysctl")
	if err != nil {
		return []string{}, err
	}
	cmd := exec.Command(sysctl, "-n", mib)
	cmd.Env = getSysctrlEnv(os.Environ())
	out, err := cmd.Output()
	if err != nil {
		return []string{}, err
	}
	v := strings.Replace(string(out), "{ ", "", 1)
	v = strings.Replace(string(v), " }", "", 1)
	values := strings.Fields(string(v))

	return values, nil
}

func NumProcs() (uint64, error) {
	f, err := os.Open(HostProc())
	if err != nil {
		return 0, err
	}
	defer f.Close()

	list, err := f.Readdirnames(-1)
	if err != nil {
		return 0, err
	}
	return uint64(len(list)), err
}

// cachedBootTime must be accessed via atomic.Load/StoreUint64
var cachedBootTime uint64

func BootTimeWithContext(ctx context.Context) (uint64, error) {
	t := atomic.LoadUint64(&cachedBootTime)
	if t != 0 {
		return t, nil
	}

	system, role, err := Virtualization()
	if err != nil {
		return 0, err
	}

	statFile := "stat"
	if system == "lxc" && role == "guest" {
		// if lxc, /proc/uptime is used.
		statFile = "uptime"
	} else if system == "docker" && role == "guest" {
		// also docker, guest
		statFile = "uptime"
	}

	filename := HostProc(statFile)
	lines, err := ReadLines(filename)
	if err != nil {
		return 0, err
	}

	if statFile == "stat" {
		for _, line := range lines {
			if strings.HasPrefix(line, "btime") {
				f := strings.Fields(line)
				if len(f) != 2 {
					return 0, fmt.Errorf("wrong btime format")
				}
				b, err := strconv.ParseInt(f[1], 10, 64)
				if err != nil {
					return 0, err
				}
				t = uint64(b)
				atomic.StoreUint64(&cachedBootTime, t)
				return t, nil
			}
		}
	} else if statFile == "uptime" {
		if len(lines) != 1 {
			return 0, fmt.Errorf("wrong uptime format")
		}
		f := strings.Fields(lines[0])
		b, err := strconv.ParseFloat(f[0], 64)
		if err != nil {
			return 0, err
		}
		t = uint64(time.Now().Unix()) - uint64(b)
		atomic.StoreUint64(&cachedBootTime, t)
		return t, nil
	}

	return 0, fmt.Errorf("could not find btime")
}

func Virtualization() (string, string, error) {
	return VirtualizationWithContext(context.Background())
}

func VirtualizationWithContext(ctx context.Context) (string, string, error) {
	var system string
	var role string

	filename := HostProc("xen")
	if PathExists(filename) {
		system = "xen"
		role = "guest" // assume guest

		if PathExists(filepath.Join(filename, "capabilities")) {
			contents, err := ReadLines(filepath.Join(filename, "capabilities"))
			if err == nil {
				if StringsContains(contents, "control_d") {
					role = "host"
				}
			}
		}
	}

	filename = HostProc("modules")
	if PathExists(filename) {
		contents, err := ReadLines(filename)
		if err == nil {
			if StringsContains(contents, "kvm") {
				system = "kvm"
				role = "host"
			} else if StringsContains(contents, "vboxdrv") {
				system = "vbox"
				role = "host"
			} else if StringsContains(contents, "vboxguest") {
				system = "vbox"
				role = "guest"
			} else if StringsContains(contents, "vmware") {
				system = "vmware"
				role = "guest"
			}
		}
	}

	filename = HostProc("cpuinfo")
	if PathExists(filename) {
		contents, err := ReadLines(filename)
		if err == nil {
			if StringsContains(contents, "QEMU Virtual CPU") ||
				StringsContains(contents, "Common KVM processor") ||
				StringsContains(contents, "Common 32-bit KVM processor") {
				system = "kvm"
				role = "guest"
			}
		}
	}

	filename = HostProc()
	if PathExists(filepath.Join(filename, "bc", "0")) {
		system = "openvz"
		role = "host"
	} else if PathExists(filepath.Join(filename, "vz")) {
		system = "openvz"
		role = "guest"
	}

	// not use dmidecode because it requires root
	if PathExists(filepath.Join(filename, "self", "status")) {
		contents, err := ReadLines(filepath.Join(filename, "self", "status"))
		if err == nil {

			if StringsContains(contents, "s_context:") ||
				StringsContains(contents, "VxID:") {
				system = "linux-vserver"
			}
			// TODO: guest or host
		}
	}

	if PathExists(filepath.Join(filename, "self", "cgroup")) {
		contents, err := ReadLines(filepath.Join(filename, "self", "cgroup"))
		if err == nil {
			if StringsContains(contents, "lxc") {
				system = "lxc"
				role = "guest"
			} else if StringsContains(contents, "docker") {
				system = "docker"
				role = "guest"
			} else if StringsContains(contents, "machine-rkt") {
				system = "rkt"
				role = "guest"
			} else if PathExists("/usr/bin/lxc-version") {
				system = "lxc"
				role = "host"
			}
		}
	}

	if PathExists(HostEtc("os-release")) {
		p, _, err := GetOSRelease()
		if err == nil && p == "coreos" {
			system = "rkt" // Is it true?
			role = "host"
		}
	}
	return system, role, nil
}

func GetOSRelease() (platform string, version string, err error) {
	contents, err := ReadLines(HostEtc("os-release"))
	if err != nil {
		return "", "", nil // return empty
	}
	for _, line := range contents {
		field := strings.Split(line, "=")
		if len(field) < 2 {
			continue
		}
		switch field[0] {
		case "ID": // use ID for lowercase
			platform = field[1]
		case "VERSION":
			version = field[1]
		}
	}
	return platform, version, nil
}
<commit_msg>[host]linux: add #688 diff which is removed after merging #689<commit_after>// +build linux

package common

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
)

func DoSysctrl(mib string) ([]string, error) {
	sysctl, err := exec.LookPath("sysctl")
	if err != nil {
		return []string{}, err
	}
	cmd := exec.Command(sysctl, "-n", mib)
	cmd.Env = getSysctrlEnv(os.Environ())
	out, err := cmd.Output()
	if err != nil {
		return []string{}, err
	}
	v := strings.Replace(string(out), "{ ", "", 1)
	v = strings.Replace(string(v), " }", "", 1)
	values := strings.Fields(string(v))

	return values, nil
}

func NumProcs() (uint64, error) {
	f, err := os.Open(HostProc())
	if err != nil {
		return 0, err
	}
	defer f.Close()

	list, err := f.Readdirnames(-1)
	if err != nil {
		return 0, err
	}
	return uint64(len(list)), err
}

// cachedBootTime must be accessed via atomic.Load/StoreUint64
var cachedBootTime uint64

func BootTimeWithContext(ctx context.Context) (uint64, error) {
	t := atomic.LoadUint64(&cachedBootTime)
	if t != 0 {
		return t, nil
	}

	system, role, err := Virtualization()
	if err != nil {
		return 0, err
	}

	statFile := "stat"
	if system == "lxc" && role == "guest" {
		// if lxc, /proc/uptime is used.
		statFile = "uptime"
	} else if system == "docker" && role == "guest" {
		// also docker, guest
		statFile = "uptime"
	}

	filename := HostProc(statFile)
	lines, err := ReadLines(filename)
	if err != nil {
		return 0, err
	}

	if statFile == "stat" {
		for _, line := range lines {
			if strings.HasPrefix(line, "btime") {
				f := strings.Fields(line)
				if len(f) != 2 {
					return 0, fmt.Errorf("wrong btime format")
				}
				b, err := strconv.ParseInt(f[1], 10, 64)
				if err != nil {
					return 0, err
				}
				t = uint64(b)
				atomic.StoreUint64(&cachedBootTime, t)
				return t, nil
			}
		}
	} else if statFile == "uptime" {
		if len(lines) != 1 {
			return 0, fmt.Errorf("wrong uptime format")
		}
		f := strings.Fields(lines[0])
		b, err := strconv.ParseFloat(f[0], 64)
		if err != nil {
			return 0, err
		}
		t = uint64(time.Now().Unix()) - uint64(b)
		atomic.StoreUint64(&cachedBootTime, t)
		return t, nil
	}

	return 0, fmt.Errorf("could not find btime")
}

func Virtualization() (string, string, error) {
	return VirtualizationWithContext(context.Background())
}

func VirtualizationWithContext(ctx context.Context) (string, string, error) {
	var system string
	var role string

	filename := HostProc("xen")
	if PathExists(filename) {
		system = "xen"
		role = "guest" // assume guest

		if PathExists(filepath.Join(filename, "capabilities")) {
			contents, err := ReadLines(filepath.Join(filename, "capabilities"))
			if err == nil {
				if StringsContains(contents, "control_d") {
					role = "host"
				}
			}
		}
	}

	filename = HostProc("modules")
	if PathExists(filename) {
		contents, err := ReadLines(filename)
		if err == nil {
			if StringsContains(contents, "kvm") {
				system = "kvm"
				role = "host"
			} else if StringsContains(contents, "vboxdrv") {
				system = "vbox"
				role = "host"
			} else if StringsContains(contents, "vboxguest") {
				system = "vbox"
				role = "guest"
			} else if StringsContains(contents, "vmware") {
				system = "vmware"
				role = "guest"
			}
		}
	}

	filename = HostProc("cpuinfo")
	if PathExists(filename) {
		contents, err := ReadLines(filename)
		if err == nil {
			if StringsContains(contents, "QEMU Virtual CPU") ||
				StringsContains(contents, "Common KVM processor") ||
				StringsContains(contents, "Common 32-bit KVM processor") {
				system = "kvm"
				role = "guest"
			}
		}
	}

	filename = HostProc("bus/pci/devices")
	if PathExists(filename) {
		contents, err := ReadLines(filename)
		if err == nil {
			if StringsContains(contents, "virtio-pci") {
				role = "guest"
			}
		}
	}

	filename = HostProc()
	if PathExists(filepath.Join(filename, "bc", "0")) {
		system = "openvz"
		role = "host"
	} else if PathExists(filepath.Join(filename, "vz")) {
		system = "openvz"
		role = "guest"
	}

	// not use dmidecode because it requires root
	if PathExists(filepath.Join(filename, "self", "status")) {
		contents, err := ReadLines(filepath.Join(filename, "self", "status"))
		if err == nil {

			if StringsContains(contents, "s_context:") ||
				StringsContains(contents, "VxID:") {
				system = "linux-vserver"
			}
			// TODO: guest or host
		}
	}

	if PathExists(filepath.Join(filename, "self", "cgroup")) {
		contents, err := ReadLines(filepath.Join(filename, "self", "cgroup"))
		if err == nil {
			if StringsContains(contents, "lxc") {
				system = "lxc"
				role = "guest"
			} else if StringsContains(contents, "docker") {
				system = "docker"
				role = "guest"
			} else if StringsContains(contents, "machine-rkt") {
				system = "rkt"
				role = "guest"
			} else if PathExists("/usr/bin/lxc-version") {
				system = "lxc"
				role = "host"
			}
		}
	}

	if PathExists(HostEtc("os-release")) {
		p, _, err := GetOSRelease()
		if err == nil && p == "coreos" {
			system = "rkt" // Is it true?
			role = "host"
		}
	}
	return system, role, nil
}

func GetOSRelease() (platform string, version string, err error) {
	contents, err := ReadLines(HostEtc("os-release"))
	if err != nil {
		return "", "", nil // return empty
	}
	for _, line := range contents {
		field := strings.Split(line, "=")
		if len(field) < 2 {
			continue
		}
		switch field[0] {
		case "ID": // use ID for lowercase
			platform = field[1]
		case "VERSION":
			version = field[1]
		}
	}
	return platform, version, nil
}
<|endoftext|>


<commit_before>package notify

import (
	"testing"

	"github.com/axetroy/watchdog"
	"github.com/axetroy/watchdog/internal/tester"
	"github.com/stretchr/testify/assert"
)

func TestWebhook(t *testing.T) {
	type args struct {
		content  string
		reporter watchdog.Reporter
	}
	tests := []struct {
		name  string
		args  args
		error string
	}{
		{
			name: "local server",
			args: args{
				content: "test",
				reporter: watchdog.Reporter{
					Protocol: "webhook",
					Target:   []string{"http://localhost:3030"},
				},
			},
			error: "",
		},
		{
			name: "unknown server",
			args: args{
				content: "test",
				reporter: watchdog.Reporter{
					Protocol: "webhook",
					Target:   []string{"http://localhost:12345"},
				},
			},
			error: "Post \"http://localhost:12345\": dial tcp [::1]:12345: connect: connection refused",
		},
		{
			name: "multiple target server",
			args: args{
				content: "test",
				reporter: watchdog.Reporter{
					Protocol: "webhook",
					Target:   []string{"http://localhost:3030", "http://localhost:12345"},
				},
			},
			error: "Post \"http://localhost:12345\": dial tcp [::1]:12345: connect: connection refused",
		},
		{
			name: "multiple target server and all error",
			args: args{
				content: "test",
				reporter: watchdog.Reporter{
					Protocol: "webhook",
					Target:   []string{"http://localhost:54321", "http://localhost:12345"},
				},
			},
			error: "Post \"http://localhost:54321\": dial tcp [::1]:54321: connect: connection refused;Post \"http://localhost:12345\": dial tcp [::1]:12345: connect: connection refused",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			assert.Nil(t, tester.CreateHTTPEchoServer(":3030", func() {
				err := Webhook(tt.args.content, tt.args.reporter)
				if tt.error != "" {
					assert.EqualError(t, err, tt.error)
				} else {
					assert.Nil(t, err)
				}
			}))
		})
	}
}
<commit_msg>fix: webhook test<commit_after>package notify

import (
	"sort"
	"strings"
	"testing"

	"github.com/axetroy/watchdog"
	"github.com/axetroy/watchdog/internal/tester"
	"github.com/stretchr/testify/assert"
)

func TestWebhook(t *testing.T) {
	type args struct {
		content  string
		reporter watchdog.Reporter
	}
	tests := []struct {
		name  string
		args  args
		error string
	}{
		{
			name: "local server",
			args: args{
				content: "test",
				reporter: watchdog.Reporter{
					Protocol: "webhook",
					Target:   []string{"http://localhost:3030"},
				},
			},
			error: "",
		},
		{
			name: "unknown server",
			args: args{
				content: "test",
				reporter: watchdog.Reporter{
					Protocol: "webhook",
					Target:   []string{"http://localhost:12345"},
				},
			},
			error: "Post \"http://localhost:12345\": dial tcp [::1]:12345: connect: connection refused",
		},
		{
			name: "multiple target server",
			args: args{
				content: "test",
				reporter: watchdog.Reporter{
					Protocol: "webhook",
					Target:   []string{"http://localhost:3030", "http://localhost:12345"},
				},
			},
			error: "Post \"http://localhost:12345\": dial tcp [::1]:12345: connect: connection refused",
		},
		{
			name: "multiple target server and all error",
			args: args{
				content: "test",
				reporter: watchdog.Reporter{
					Protocol: "webhook",
					Target:   []string{"http://localhost:54321", "http://localhost:12345"},
				},
			},
			error: "Post \"http://localhost:12345\": dial tcp [::1]:12345: connect: connection refused;Post \"http://localhost:54321\": dial tcp [::1]:54321: connect: connection refused",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			assert.Nil(t, tester.CreateHTTPEchoServer(":3030", func() {
				err := Webhook(tt.args.content, tt.args.reporter)
				if tt.error != "" {
					arr := strings.Split(err.Error(), ";")
					sort.Strings(arr)
					assert.Equal(t, strings.Join(arr, ";"), tt.error)
				} else {
					assert.Nil(t, err)
				}
			}))
		})
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 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 transport

import (
	"errors"
	"net"
	"testing"
	"time"

	"golang.org/x/net/context"
	"google.golang.org/cloud"
	"google.golang.org/grpc"
)

// Check that user optioned grpc.WithDialer option overrides the App Engine hook.
func TestGRPCHook(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
	expected := false

	appengineDialerHook = (func(ctx context.Context) grpc.DialOption {
		return grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
			t.Error("did not expect a call to notExpected dialer, got one")
			cancel()
			return nil, errors.New("not expected")
		})
	})
	defer func() {
		appengineDialerHook = nil
	}()

	expectedDialer := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
		expected = true
		cancel()
		return nil, errors.New("expected")
	})

	conn, err := DialGRPC(ctx,
		cloud.WithGRPCDialOption(expectedDialer),
		cloud.WithEndpoint("example.google.com:443"))
	if err != nil {
		t.Errorf("DialGRPC: error %v, want nil", err)
	}

	// gRPC doesn't connect before the first call.
	grpc.Invoke(ctx, "foo", nil, nil, conn)
	conn.Close()

	if !expected {
		t.Error("expected a call to expected dialer, didn't get one")
	}
}
<commit_msg>internal/transport: add fake token source to test<commit_after>// Copyright 2016 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 transport

import (
	"errors"
	"net"
	"testing"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	"google.golang.org/cloud"
	"google.golang.org/grpc"
)

// Check that user optioned grpc.WithDialer option overrides the App Engine hook.
func TestGRPCHook(t *testing.T) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
	expected := false

	appengineDialerHook = (func(ctx context.Context) grpc.DialOption {
		return grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
			t.Error("did not expect a call to notExpected dialer, got one")
			cancel()
			return nil, errors.New("not expected")
		})
	})
	defer func() {
		appengineDialerHook = nil
	}()

	expectedDialer := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
		expected = true
		cancel()
		return nil, errors.New("expected")
	})

	conn, err := DialGRPC(ctx,
		cloud.WithTokenSource(oauth2.StaticTokenSource(nil)), // No creds.
		cloud.WithGRPCDialOption(expectedDialer),
		cloud.WithEndpoint("example.google.com:443"))
	if err != nil {
		t.Errorf("DialGRPC: error %v, want nil", err)
	}

	// gRPC doesn't connect before the first call.
	grpc.Invoke(ctx, "foo", nil, nil, conn)
	conn.Close()

	if !expected {
		t.Error("expected a call to expected dialer, didn't get one")
	}
}
<|endoftext|>


<commit_before>package backend

import (
	"reflect"
	"strconv"
	"strings"

	"github.com/cblomart/vsphere-graphite/utils"
)

// Point : Information collected for a point
type Point struct {
	VCenter      string   `influx:"tag,vcenter"`
	ObjectType   string   `influx:"tag,type"`
	ObjectName   string   `influx:"tag,name"`
	Group        string   `influx:"key,1"`
	Counter      string   `influx:"key,2"`
	Instance     string   `influx:"tag,instance"`
	Rollup       string   `influx:"key,3"`
	Value        int64    `influx:"value"`
	Datastore    []string `influx:"tag,datastore" json:",omitempty"`
	ESXi         string   `influx:"tag,host" json:",omitempty"`
	Cluster      string   `influx:"tag,cluster" json:",omitempty"`
	Network      []string `influx:"tag,network" json:",omitempty"`
	ResourcePool string   `influx:"tag,resourcepool" json:",omitempty"`
	Folder       string   `influx:"tag,folder" json:",omitempty"`
	ViTags       []string `influx:"tag,vitags" json:",omitempty"`
	NumCPU       int32    `influx:"tag,numcpu" json:",omitempty"`
	MemorySizeMB int32    `influx:"tag,memorysizemb" json:",omitempty"`
	Timestamp    int64    `influx:"time" elastic:"type:date,format:epoch_second"`
}

// GetTags returns the tags of point as a map of strings
func (point *Point) GetTags(noarray bool, separator string) map[string]string {
	tags := map[string]string{}
	tags["vcenter"] = point.VCenter
	tags["type"] = point.ObjectType
	tags["name"] = point.ObjectName
	if noarray {
		if len(point.Datastore) > 0 {
			tags["datastore"] = point.Datastore[0]
		}
	} else {
		if len(point.Datastore) > 0 {
			tags["datastore"] = strings.Join(point.Datastore, separator)
		}
	}
	if noarray {
		if len(point.Network) > 0 {
			tags["network"] = point.Network[0]
		}
	} else {
		if len(point.Network) > 0 {
			tags["network"] = strings.Join(point.Network, separator)
		}
	}
	if len(point.ESXi) > 0 {
		tags["host"] = point.ESXi
	}
	if len(point.Cluster) > 0 {
		tags["cluster"] = point.Cluster
	}
	if len(point.Instance) > 0 {
		tags["instance"] = point.Instance
	}
	if len(point.ResourcePool) > 0 {
		tags["resourcepool"] = point.ResourcePool
	}
	if len(point.Folder) > 0 {
		tags["folder"] = point.Folder
	}
	if noarray {
		if len(point.ViTags) > 0 {
			tags["vitags"] = point.ViTags[0]
		}
	} else {
		if len(point.ViTags) > 0 {
			tags["vitags"] = strings.Join(point.ViTags, separator)
		}
	}
	if point.NumCPU != 0 {
		tags["numcpu"] = strconv.FormatInt(int64(point.NumCPU), 10)
	}
	if point.MemorySizeMB != 0 {
		tags["memorysizemb"] = strconv.FormatInt(int64(point.MemorySizeMB), 10)
	}
	return tags
}

// GetInfluxPoint : convert a point to an influxpoint
func (p *Point) GetInfluxPoint(noarray bool, valuefield string) *InfluxPoint {
	keyParts := make(map[int]string)
	ip := InfluxPoint{
		Fields: make(map[string]string),
		Tags:   make(map[string]string),
	}
	v := reflect.ValueOf(p).Elem()
	for i := 0; i < v.NumField(); i++ {
		vfield := v.Field(i)
		tfield := v.Type().Field(i)
		tag := tfield.Tag.Get(InfluxTag)
		tagfields := strings.Split(tag, ",")
		if len(tagfields) == 0 || len(tagfields) > 2 {
			stdlog.Println("tag field ignored: " + tag)
			continue
		}
		tagtype := tagfields[0]
		tagname := strings.ToLower(tfield.Name)
		if len(tagfields) == 2 {
			tagname = tagfields[1]
		}
		switch tagtype {
		case "key":
			keyParts[utils.MustAtoi(tagname)] = utils.ValToString(vfield.Interface(), "_", false)
		case "tag":
			ip.Tags[tagname] = utils.ValToString(vfield.Interface(), "\\,", noarray)
		case "value":
			ip.Fields[valuefield] = utils.ValToString(vfield.Interface(), ",", true) + "i"
		case "time":
			ip.Timestamp = vfield.Int()
		default:
		}
	}
	// sort key part keys and join them
	ip.Key = utils.Join(keyParts, "_")
	return &ip
}

// ToInflux serialises the data to be consumed by influx line protocol
// see https://docs.influxdata.com/influxdb/v1.2/write_protocols/line_protocol_tutorial/
func (p *Point) ToInflux(noarray bool, valuefield string) string {
	return p.GetInfluxPoint(noarray, valuefield).ToInflux(noarray, valuefield)
}
<commit_msg>Align point in struct funcs<commit_after>package backend

import (
	"reflect"
	"strconv"
	"strings"

	"github.com/cblomart/vsphere-graphite/utils"
)

// Point : Information collected for a point
type Point struct {
	VCenter      string   `influx:"tag,vcenter"`
	ObjectType   string   `influx:"tag,type"`
	ObjectName   string   `influx:"tag,name"`
	Group        string   `influx:"key,1"`
	Counter      string   `influx:"key,2"`
	Instance     string   `influx:"tag,instance"`
	Rollup       string   `influx:"key,3"`
	Value        int64    `influx:"value"`
	Datastore    []string `influx:"tag,datastore" json:",omitempty"`
	ESXi         string   `influx:"tag,host" json:",omitempty"`
	Cluster      string   `influx:"tag,cluster" json:",omitempty"`
	Network      []string `influx:"tag,network" json:",omitempty"`
	ResourcePool string   `influx:"tag,resourcepool" json:",omitempty"`
	Folder       string   `influx:"tag,folder" json:",omitempty"`
	ViTags       []string `influx:"tag,vitags" json:",omitempty"`
	NumCPU       int32    `influx:"tag,numcpu" json:",omitempty"`
	MemorySizeMB int32    `influx:"tag,memorysizemb" json:",omitempty"`
	Timestamp    int64    `influx:"time" elastic:"type:date,format:epoch_second"`
}

// GetTags returns the tags of point as a map of strings
func (point *Point) GetTags(noarray bool, separator string) map[string]string {
	tags := map[string]string{}
	tags["vcenter"] = point.VCenter
	tags["type"] = point.ObjectType
	tags["name"] = point.ObjectName
	if noarray {
		if len(point.Datastore) > 0 {
			tags["datastore"] = point.Datastore[0]
		}
	} else {
		if len(point.Datastore) > 0 {
			tags["datastore"] = strings.Join(point.Datastore, separator)
		}
	}
	if noarray {
		if len(point.Network) > 0 {
			tags["network"] = point.Network[0]
		}
	} else {
		if len(point.Network) > 0 {
			tags["network"] = strings.Join(point.Network, separator)
		}
	}
	if len(point.ESXi) > 0 {
		tags["host"] = point.ESXi
	}
	if len(point.Cluster) > 0 {
		tags["cluster"] = point.Cluster
	}
	if len(point.Instance) > 0 {
		tags["instance"] = point.Instance
	}
	if len(point.ResourcePool) > 0 {
		tags["resourcepool"] = point.ResourcePool
	}
	if len(point.Folder) > 0 {
		tags["folder"] = point.Folder
	}
	if noarray {
		if len(point.ViTags) > 0 {
			tags["vitags"] = point.ViTags[0]
		}
	} else {
		if len(point.ViTags) > 0 {
			tags["vitags"] = strings.Join(point.ViTags, separator)
		}
	}
	if point.NumCPU != 0 {
		tags["numcpu"] = strconv.FormatInt(int64(point.NumCPU), 10)
	}
	if point.MemorySizeMB != 0 {
		tags["memorysizemb"] = strconv.FormatInt(int64(point.MemorySizeMB), 10)
	}
	return tags
}

// GetInfluxPoint : convert a point to an influxpoint
func (point *Point) GetInfluxPoint(noarray bool, valuefield string) *InfluxPoint {
	keyParts := make(map[int]string)
	ip := InfluxPoint{
		Fields: make(map[string]string),
		Tags:   make(map[string]string),
	}
	v := reflect.ValueOf(point).Elem()
	for i := 0; i < v.NumField(); i++ {
		vfield := v.Field(i)
		tfield := v.Type().Field(i)
		tag := tfield.Tag.Get(InfluxTag)
		tagfields := strings.Split(tag, ",")
		if len(tagfields) == 0 || len(tagfields) > 2 {
			stdlog.Println("tag field ignored: " + tag)
			continue
		}
		tagtype := tagfields[0]
		tagname := strings.ToLower(tfield.Name)
		if len(tagfields) == 2 {
			tagname = tagfields[1]
		}
		switch tagtype {
		case "key":
			keyParts[utils.MustAtoi(tagname)] = utils.ValToString(vfield.Interface(), "_", false)
		case "tag":
			ip.Tags[tagname] = utils.ValToString(vfield.Interface(), "\\,", noarray)
		case "value":
			ip.Fields[valuefield] = utils.ValToString(vfield.Interface(), ",", true) + "i"
		case "time":
			ip.Timestamp = vfield.Int()
		default:
		}
	}
	// sort key part keys and join them
	ip.Key = utils.Join(keyParts, "_")
	return &ip
}

// ToInflux serialises the data to be consumed by influx line protocol
// see https://docs.influxdata.com/influxdb/v1.2/write_protocols/line_protocol_tutorial/
func (point *Point) ToInflux(noarray bool, valuefield string) string {
	return point.GetInfluxPoint(noarray, valuefield).ToInflux(noarray, valuefield)
}
<|endoftext|>


<commit_before><commit_msg>Missing documentation<commit_after><|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// Version is the current version of the buffalo binary
const Version = "v0.9.1.1"

func init() {
	decorate("version", versionCmd)
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of buffalo",
	Long:  `All software has versions.  This is buffalo's.`,
	Run: func(c *cobra.Command, args []string) {
		fmt.Printf("Buffalo version is: %s\n", Version)
	},
	// needed to override the root level pre-run func
	PersistentPreRun: func(c *cobra.Command, args []string) {
	},
}
<commit_msg>version bump<commit_after>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

// Version is the current version of the buffalo binary
const Version = "v0.9.1.2"

func init() {
	decorate("version", versionCmd)
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of buffalo",
	Long:  `All software has versions.  This is buffalo's.`,
	Run: func(c *cobra.Command, args []string) {
		fmt.Printf("Buffalo version is: %s\n", Version)
	},
	// needed to override the root level pre-run func
	PersistentPreRun: func(c *cobra.Command, args []string) {
	},
}
<|endoftext|>