<commit_before>/*
Copyright 2019 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 metrics

import (
        "context"
        "fmt"
        "log"
        "time"

	apioption "google.golang.org/api/option"
	gax "github.com/googleapis/gax-go/v2"
        googlepb "github.com/golang/protobuf/ptypes/timestamp"
        metricpb "google.golang.org/genproto/googleapis/api/metric"
        monitoring "cloud.google.com/go/monitoring/apiv3"
        monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
        monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
)

const (
	samplePeriod	= 60 * time.Second
        endpoint	= "staging-monitoring.sandbox.googleapis.com:443"
)

var startTime time.Time
var codeCount map[string]int64

// metricClient is a client for interacting with Cloud Monitoring API.
type metricClient interface {
	CreateTimeSeries(ctx context.Context, req *monitoringpb.CreateTimeSeriesRequest, opts ...gax.CallOption) error
}

// fakeMetricClient is a stub of MetricClient for the purpose of testing
type fakeMetricClient struct {
	Requests []*monitoringpb.CreateTimeSeriesRequest
}

func (f *fakeMetricClient) CreateTimeSeries(ctx context.Context, req *monitoringpb.CreateTimeSeriesRequest, opts ...gax.CallOption) error {
	f.Requests = append(f.Requests, req)
	return nil
}

type MetricHandler struct {
	projectID string
	instanceID string
	instanceZone string
	metricDomain string
	ctx context.Context
	client metricClient
}

// NewFakeMetricHandler instantiates a fake metric client for the purpose of testing
func NewFakeMetricHandler(ctx context.Context, projectID, instanceID, instanceZone, metricDomain string) (*MetricHandler, error) {
	client := fakeMetricClient{}
	return newMetricHandlerHelper(ctx, projectID, instanceID, instanceZone, metricDomain, &client)
}

// NewMetricHandler instantiates a metric client for the purpose of writing metrics to cloud monarch
func NewMetricHandler(ctx context.Context, projectID, instanceID, instanceZone, metricDomain string) (*MetricHandler, error) {
	log.Printf("NewMetricHandler|instantiating metric handler")
	client, err := monitoring.NewMetricClient(
                ctx,
                apioption.WithEndpoint(endpoint),
        )
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
		return nil, err
	}
	return newMetricHandlerHelper(ctx, projectID, instanceID, instanceZone, metricDomain, client)
}

func newMetricHandlerHelper(ctx context.Context, projectID, instanceID, instanceZone, metricDomain string, client metricClient) (*MetricHandler, error) {
	if projectID == "" {
		err := fmt.Errorf("Failed to create metric handler: missing projectID")
		return nil, err
	}
	if instanceID == "" {
		err := fmt.Errorf("Failed to create metric handler: missing instanceID")
		return nil, err
	}
	if instanceZone == "" {
		err := fmt.Errorf("Failed to create metric handler: missing instanceZone")
		return nil, err
	}
	if metricDomain == "" {
		err := fmt.Errorf("Failed to create metric handler: missing metricDomain")
		return nil, err
	}

	startTime = time.Now()
	codeCount = make(map[string]int64)

	return &MetricHandler{
		projectID:	projectID,
		instanceID:	instanceID,
		instanceZone:	instanceZone,
		metricDomain:	metricDomain,
		ctx:		ctx,
		client:		client,
	}, nil
}

func (h *MetricHandler) WriteMetric(metricType string, statusCode int) error {
	if h == nil {
		return nil
	}
	if metricType == h.GetResponseCountMetricType() {
		err := h.writeResponseCodeMetric(statusCode)
		return err
	}
	return nil
}

func (h *MetricHandler) GetResponseCountMetricType() string {
	if h == nil {
		return ""
	}
	return fmt.Sprintf("%s/instance/proxy_agent/response_count", h.metricDomain)
}

// writeResponseCodeMetric will gather response codes and write to cloud monarch once sample period is over
func (h *MetricHandler) writeResponseCodeMetric(statusCode int) error {
	responseCode := fmt.Sprintf("%v", statusCode)

	// Update response code count for the current sample period
	if _, ok := codeCount[responseCode]; ok {
		codeCount[responseCode] += 1
	} else {
		codeCount[responseCode] = 1
	}

	// Only write time series after sample period is over
	if time.Since(startTime) < samplePeriod {
		return nil
	}

	// Write metric
	log.Printf("WriteMetric|attempting to write metrics at time: %v\n", time.Now())
	for responseCode, count := range codeCount {
		responseClass := fmt.Sprintf("%sXX", responseCode[0:1])
		timeSeries := h.newTimeSeries(h.GetResponseCountMetricType(), responseCode, responseClass, newDataPoint(count))

		log.Printf("got %v occurances of %s response code\n", count, responseCode)
		log.Printf("%v\n\n", timeSeries)

		if err := h.client.CreateTimeSeries(h.ctx, &monitoringpb.CreateTimeSeriesRequest{
			Name: monitoring.MetricProjectPath(h.projectID),
			TimeSeries: []*monitoringpb.TimeSeries{timeSeries},
		}); err != nil {
			log.Println("Failed to write time series data: ", err)
			return err
		}
	}

	// Clean up
	startTime = time.Now()
	codeCount = make(map[string]int64)

	return nil
}

// newTimeSeries creates and returns a new time series
func (h *MetricHandler) newTimeSeries(metricType, responseCode, responseClass string, dataPoint *monitoringpb.Point) *monitoringpb.TimeSeries {
        return &monitoringpb.TimeSeries{
		Metric: &metricpb.Metric{
			Type: metricType,
			Labels: map[string]string{
				"response_code": responseCode,
				"response_code_class": responseClass,
			},
		},
		Resource: &monitoredrespb.MonitoredResource{
			Type: "gce_instance",
			Labels: map[string]string{
				"instance_id": h.instanceID,
				"zone": h.instanceZone,
			},
		},
		Points: []*monitoringpb.Point{
			dataPoint,
		},
        }
}

// newDataPoint creates and returns a new data point
func newDataPoint(count int64) *monitoringpb.Point {
        return &monitoringpb.Point{
                Interval: &monitoringpb.TimeInterval{
                        StartTime: &googlepb.Timestamp{
                                Seconds: time.Now().Unix(),
                        },
                        EndTime: &googlepb.Timestamp{
                                Seconds: time.Now().Unix()+1,
                        },
                },
                Value: &monitoringpb.TypedValue{
                        Value: &monitoringpb.TypedValue_Int64Value{
                                Int64Value: count,
                        },
                },
        }
}

<commit_msg>change write endpoint to prod<commit_after>/*
Copyright 2019 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 metrics

import (
        "context"
        "fmt"
        "log"
        "time"

	apioption "google.golang.org/api/option"
	gax "github.com/googleapis/gax-go/v2"
        googlepb "github.com/golang/protobuf/ptypes/timestamp"
        metricpb "google.golang.org/genproto/googleapis/api/metric"
        monitoring "cloud.google.com/go/monitoring/apiv3"
        monitoringpb "google.golang.org/genproto/googleapis/monitoring/v3"
        monitoredrespb "google.golang.org/genproto/googleapis/api/monitoredres"
)

const (
	samplePeriod	= 60 * time.Second
        endpoint	= "monitoring.sandbox.googleapis.com:443"
)

var startTime time.Time
var codeCount map[string]int64

// metricClient is a client for interacting with Cloud Monitoring API.
type metricClient interface {
	CreateTimeSeries(ctx context.Context, req *monitoringpb.CreateTimeSeriesRequest, opts ...gax.CallOption) error
}

// fakeMetricClient is a stub of MetricClient for the purpose of testing
type fakeMetricClient struct {
	Requests []*monitoringpb.CreateTimeSeriesRequest
}

func (f *fakeMetricClient) CreateTimeSeries(ctx context.Context, req *monitoringpb.CreateTimeSeriesRequest, opts ...gax.CallOption) error {
	f.Requests = append(f.Requests, req)
	return nil
}

type MetricHandler struct {
	projectID string
	instanceID string
	instanceZone string
	metricDomain string
	ctx context.Context
	client metricClient
}

// NewFakeMetricHandler instantiates a fake metric client for the purpose of testing
func NewFakeMetricHandler(ctx context.Context, projectID, instanceID, instanceZone, metricDomain string) (*MetricHandler, error) {
	client := fakeMetricClient{}
	return newMetricHandlerHelper(ctx, projectID, instanceID, instanceZone, metricDomain, &client)
}

// NewMetricHandler instantiates a metric client for the purpose of writing metrics to cloud monarch
func NewMetricHandler(ctx context.Context, projectID, instanceID, instanceZone, metricDomain string) (*MetricHandler, error) {
	log.Printf("NewMetricHandler|instantiating metric handler")
	client, err := monitoring.NewMetricClient(
                ctx,
                apioption.WithEndpoint(endpoint),
        )
	if err != nil {
		log.Fatalf("Failed to create client: %v", err)
		return nil, err
	}
	return newMetricHandlerHelper(ctx, projectID, instanceID, instanceZone, metricDomain, client)
}

func newMetricHandlerHelper(ctx context.Context, projectID, instanceID, instanceZone, metricDomain string, client metricClient) (*MetricHandler, error) {
	if projectID == "" {
		err := fmt.Errorf("Failed to create metric handler: missing projectID")
		return nil, err
	}
	if instanceID == "" {
		err := fmt.Errorf("Failed to create metric handler: missing instanceID")
		return nil, err
	}
	if instanceZone == "" {
		err := fmt.Errorf("Failed to create metric handler: missing instanceZone")
		return nil, err
	}
	if metricDomain == "" {
		err := fmt.Errorf("Failed to create metric handler: missing metricDomain")
		return nil, err
	}

	startTime = time.Now()
	codeCount = make(map[string]int64)

	return &MetricHandler{
		projectID:	projectID,
		instanceID:	instanceID,
		instanceZone:	instanceZone,
		metricDomain:	metricDomain,
		ctx:		ctx,
		client:		client,
	}, nil
}

func (h *MetricHandler) WriteMetric(metricType string, statusCode int) error {
	if h == nil {
		return nil
	}
	if metricType == h.GetResponseCountMetricType() {
		err := h.writeResponseCodeMetric(statusCode)
		return err
	}
	return nil
}

func (h *MetricHandler) GetResponseCountMetricType() string {
	if h == nil {
		return ""
	}
	return fmt.Sprintf("%s/instance/proxy_agent/response_count", h.metricDomain)
}

// writeResponseCodeMetric will gather response codes and write to cloud monarch once sample period is over
func (h *MetricHandler) writeResponseCodeMetric(statusCode int) error {
	responseCode := fmt.Sprintf("%v", statusCode)

	// Update response code count for the current sample period
	if _, ok := codeCount[responseCode]; ok {
		codeCount[responseCode] += 1
	} else {
		codeCount[responseCode] = 1
	}

	// Only write time series after sample period is over
	if time.Since(startTime) < samplePeriod {
		return nil
	}

	// Write metric
	log.Printf("WriteMetric|attempting to write metrics at time: %v\n", time.Now())
	for responseCode, count := range codeCount {
		responseClass := fmt.Sprintf("%sXX", responseCode[0:1])
		timeSeries := h.newTimeSeries(h.GetResponseCountMetricType(), responseCode, responseClass, newDataPoint(count))

		log.Printf("got %v occurances of %s response code\n", count, responseCode)
		log.Printf("%v\n\n", timeSeries)

		if err := h.client.CreateTimeSeries(h.ctx, &monitoringpb.CreateTimeSeriesRequest{
			Name: monitoring.MetricProjectPath(h.projectID),
			TimeSeries: []*monitoringpb.TimeSeries{timeSeries},
		}); err != nil {
			log.Println("Failed to write time series data: ", err)
			return err
		}
	}

	// Clean up
	startTime = time.Now()
	codeCount = make(map[string]int64)

	return nil
}

// newTimeSeries creates and returns a new time series
func (h *MetricHandler) newTimeSeries(metricType, responseCode, responseClass string, dataPoint *monitoringpb.Point) *monitoringpb.TimeSeries {
        return &monitoringpb.TimeSeries{
		Metric: &metricpb.Metric{
			Type: metricType,
			Labels: map[string]string{
				"response_code": responseCode,
				"response_code_class": responseClass,
			},
		},
		Resource: &monitoredrespb.MonitoredResource{
			Type: "gce_instance",
			Labels: map[string]string{
				"instance_id": h.instanceID,
				"zone": h.instanceZone,
			},
		},
		Points: []*monitoringpb.Point{
			dataPoint,
		},
        }
}

// newDataPoint creates and returns a new data point
func newDataPoint(count int64) *monitoringpb.Point {
        return &monitoringpb.Point{
                Interval: &monitoringpb.TimeInterval{
                        StartTime: &googlepb.Timestamp{
                                Seconds: time.Now().Unix(),
                        },
                        EndTime: &googlepb.Timestamp{
                                Seconds: time.Now().Unix()+1,
                        },
                },
                Value: &monitoringpb.TypedValue{
                        Value: &monitoringpb.TypedValue_Int64Value{
                                Int64Value: count,
                        },
                },
        }
}

<|endoftext|>


<commit_before>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import "fmt"

// a Visitor's VisitBefore method is invoked for each node encountered by Walk.
// If the result Visitor v is not nil, Walk visits each of the children of that
// node with v.  VisitAfter is called on n at the end.
type Visitor interface {
	VisitBefore(n node) (v Visitor)
	VisitAfter(n node)
}

// convenience function
func walknodelist(v Visitor, list []node) {
	for _, x := range list {
		Walk(v, x)
	}
}

func Walk(v Visitor, node node) {
	// Returning nil from VisitBefore signals to Walk that the Visitor has
	// handled the children of this node.
	if v := v.VisitBefore(node); v == nil {
		return
	}

	switch n := node.(type) {
	case *stmtlistNode:
		walknodelist(v, n.children)
	case *exprlistNode:
		walknodelist(v, n.children)

	case *condNode:
		if n.cond != nil {
			Walk(v, n.cond)
		}
		Walk(v, n.truthNode)
		if n.elseNode != nil {
			Walk(v, n.elseNode)
		}

	case *builtinNode:
		if n.args != nil {
			Walk(v, n.args)
		}

	case *binaryExprNode:
		Walk(v, n.lhs)
		Walk(v, n.rhs)

	case *unaryExprNode:
		Walk(v, n.lhs)

	case *indexedExprNode:
		Walk(v, n.index)
		Walk(v, n.lhs)

	case *defNode:
		walknodelist(v, n.children)

	case *decoNode:
		walknodelist(v, n.children)

	case *regexNode, *idNode, *caprefNode, *declNode, *stringConstNode, *intConstNode, *floatConstNode, *nextNode, *otherwiseNode:
		// These nodes are terminals, have no children.

	default:
		panic(fmt.Sprintf("Walk: unexpected node type %T: %v", n, n))
	}

	v.VisitAfter(node)
}
<commit_msg>Updates a comment.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
// This file is available under the Apache license.

package vm

import "fmt"

// a Visitor's VisitBefore method is invoked for each node encountered by Walk.
// If the result Visitor v is not nil, Walk visits each of the children of that
// node with v.  VisitAfter is called on n at the end.
type Visitor interface {
	VisitBefore(n node) (v Visitor)
	VisitAfter(n node)
}

// convenience function
func walknodelist(v Visitor, list []node) {
	for _, x := range list {
		Walk(v, x)
	}
}

func Walk(v Visitor, node node) {
	// Returning nil from VisitBefore signals to Walk that the Visitor has
	// handled the children of this node.
	if v := v.VisitBefore(node); v == nil {
		return
	}

	switch n := node.(type) {
	case *stmtlistNode:
		walknodelist(v, n.children)
	case *exprlistNode:
		walknodelist(v, n.children)

	case *condNode:
		if n.cond != nil {
			Walk(v, n.cond)
		}
		Walk(v, n.truthNode)
		if n.elseNode != nil {
			Walk(v, n.elseNode)
		}

	case *builtinNode:
		if n.args != nil {
			Walk(v, n.args)
		}

	case *binaryExprNode:
		Walk(v, n.lhs)
		Walk(v, n.rhs)

	case *unaryExprNode:
		Walk(v, n.lhs)

	case *indexedExprNode:
		Walk(v, n.index)
		Walk(v, n.lhs)

	case *defNode:
		walknodelist(v, n.children)

	case *decoNode:
		walknodelist(v, n.children)

	case *regexNode, *idNode, *caprefNode, *declNode, *stringConstNode, *intConstNode, *floatConstNode, *nextNode, *otherwiseNode:
		// These nodes are terminals, thus have no children to walk.

	default:
		panic(fmt.Sprintf("Walk: unexpected node type %T: %v", n, n))
	}

	v.VisitAfter(node)
}
<|endoftext|>


<commit_before>package version

// Version the library version number
const Version = "1.6.0"
<commit_msg>Bump to v2.0.0<commit_after>package version

// Version the library version number
const Version = "2.0.0"
<|endoftext|>


<commit_before>package version

import (
	"bytes"
	"fmt"
)

var (
	// The git commit that was compiled. This will be filled in by the compiler.
	GitCommit   string
	GitDescribe string

	// The main version number that is being run at the moment.
	Version = "0.8.0"

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "dev"

	// VersionMetadata is metadata further describing the build type.
	VersionMetadata = ""
)

// VersionInfo
type VersionInfo struct {
	Revision          string
	Version           string
	VersionPrerelease string
	VersionMetadata   string
}

func GetVersion() *VersionInfo {
	ver := Version
	rel := VersionPrerelease
	md := VersionMetadata
	if GitDescribe != "" {
		ver = GitDescribe
	}
	if GitDescribe == "" && rel == "" && VersionPrerelease != "" {
		rel = "dev"
	}

	return &VersionInfo{
		Revision:          GitCommit,
		Version:           ver,
		VersionPrerelease: rel,
		VersionMetadata:   md,
	}
}

func (c *VersionInfo) VersionNumber() string {
	version := fmt.Sprintf("%s", c.Version)

	if c.VersionPrerelease != "" {
		version = fmt.Sprintf("%s-%s", version, c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		version = fmt.Sprintf("%s+%s", version, c.VersionMetadata)
	}

	return version
}

func (c *VersionInfo) FullVersionNumber(rev bool) string {
	var versionString bytes.Buffer

	fmt.Fprintf(&versionString, "Nomad v%s", c.Version)
	if c.VersionPrerelease != "" {
		fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		fmt.Fprintf(&versionString, "+%s", c.VersionMetadata)
	}

	if rev && c.Revision != "" {
		fmt.Fprintf(&versionString, " (%s)", c.Revision)
	}

	return versionString.String()
}
<commit_msg>Nomad v0.8.0-rc1<commit_after>package version

import (
	"bytes"
	"fmt"
)

var (
	// The git commit that was compiled. This will be filled in by the compiler.
	GitCommit   string
	GitDescribe string

	// The main version number that is being run at the moment.
	Version = "0.8.0"

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "rc1"

	// VersionMetadata is metadata further describing the build type.
	VersionMetadata = ""
)

// VersionInfo
type VersionInfo struct {
	Revision          string
	Version           string
	VersionPrerelease string
	VersionMetadata   string
}

func GetVersion() *VersionInfo {
	ver := Version
	rel := VersionPrerelease
	md := VersionMetadata
	if GitDescribe != "" {
		ver = GitDescribe
	}
	if GitDescribe == "" && rel == "" && VersionPrerelease != "" {
		rel = "dev"
	}

	return &VersionInfo{
		Revision:          GitCommit,
		Version:           ver,
		VersionPrerelease: rel,
		VersionMetadata:   md,
	}
}

func (c *VersionInfo) VersionNumber() string {
	version := fmt.Sprintf("%s", c.Version)

	if c.VersionPrerelease != "" {
		version = fmt.Sprintf("%s-%s", version, c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		version = fmt.Sprintf("%s+%s", version, c.VersionMetadata)
	}

	return version
}

func (c *VersionInfo) FullVersionNumber(rev bool) string {
	var versionString bytes.Buffer

	fmt.Fprintf(&versionString, "Nomad v%s", c.Version)
	if c.VersionPrerelease != "" {
		fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
	}

	if c.VersionMetadata != "" {
		fmt.Fprintf(&versionString, "+%s", c.VersionMetadata)
	}

	if rev && c.Revision != "" {
		fmt.Fprintf(&versionString, " (%s)", c.Revision)
	}

	return versionString.String()
}
<|endoftext|>


<commit_before>package version

import "fmt"

var (
	// Version return version no
	Version = "0.0.13"
	// GitCommit return Git commit
	GitCommit = "HEAD"
)

// FullVersion return full version string
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<commit_msg>Bump to v0.0.14<commit_after>package version

import "fmt"

var (
	// Version return version no
	Version = "0.0.14"
	// GitCommit return Git commit
	GitCommit = "HEAD"
)

// FullVersion return full version string
func FullVersion() string {
	return fmt.Sprintf("%s, build %s", Version, GitCommit)
}
<|endoftext|>


<commit_before>package version

// VERSION ...
const VERSION = "1.1.6"
<commit_msg>v1.1.7<commit_after>package version

// VERSION ...
const VERSION = "1.1.7"
<|endoftext|>


<commit_before>package version

// VERSION ...
const VERSION = "1.1.16"
<commit_msg>v1.1.17<commit_after>package version

// VERSION ...
const VERSION = "1.1.17"
<|endoftext|>


<commit_before>package version

import (
	"strings"
)

var (
	// The git commit that was compiled. These will be filled in by the
	// compiler.
	GitCommit string

	// The main version number that is being run at the moment.
	//
	// Version must conform to the format expected by github.com/hashicorp/go-version
	// for tests to work.
	Version = "1.11.0"

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "dev"
)

// GetHumanVersion composes the parts of the version in a way that's suitable
// for displaying to humans.
func GetHumanVersion() string {
	version := Version
	release := VersionPrerelease

	if release != "" {
		suffix := "-" + release
		if !strings.HasSuffix(version, suffix) {
			// if we tagged a prerelease version then the release is in the version already
			version += suffix
		}
	}

	// Strip off any single quotes added by the git information.
	return strings.ReplaceAll(version, "'", "")
}
<commit_msg>Update version to use 1.11.2 as base (#12127)<commit_after>package version

import (
	"strings"
)

var (
	// The git commit that was compiled. These will be filled in by the
	// compiler.
	GitCommit string

	// The main version number that is being run at the moment.
	//
	// Version must conform to the format expected by github.com/hashicorp/go-version
	// for tests to work.
	Version = "1.11.2"

	// A pre-release marker for the version. If this is "" (empty string)
	// then it means that it is a final release. Otherwise, this is a pre-release
	// such as "dev" (in development), "beta", "rc1", etc.
	VersionPrerelease = "dev"
)

// GetHumanVersion composes the parts of the version in a way that's suitable
// for displaying to humans.
func GetHumanVersion() string {
	version := Version
	release := VersionPrerelease

	if release != "" {
		suffix := "-" + release
		if !strings.HasSuffix(version, suffix) {
			// if we tagged a prerelease version then the release is in the version already
			version += suffix
		}
	}

	// Strip off any single quotes added by the git information.
	return strings.ReplaceAll(version, "'", "")
}
<|endoftext|>


<commit_before>package version

// Version is current packer-builder-sakuracloud version string
var Version = "0.2.2"
<commit_msg>bump to v0.3.0<commit_after>package version

// Version is current packer-builder-sakuracloud version string
var Version = "0.3.0"
<|endoftext|>


<commit_before>package version

var (
	// The full version string
	Version = "0.4.6"
	// GitCommit is set with --ldflags "-X main.gitCommit=$(git rev-parse HEAD)"
	GitCommit string
)

func init() {
	if GitCommit != "" {
		Version += "-" + GitCommit[:8]
	}
}
<commit_msg>update version to 0.4.7<commit_after>package version

var (
	// The full version string
	Version = "0.4.7"
	// GitCommit is set with --ldflags "-X main.gitCommit=$(git rev-parse HEAD)"
	GitCommit string
)

func init() {
	if GitCommit != "" {
		Version += "-" + GitCommit[:8]
	}
}
<|endoftext|>


<commit_before>package ezhttp

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"strings"
)

type EzClient struct {
	*http.Client
	body io.Reader
}

func NewInsecureClient() *EzClient {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	return &EzClient{Client: &http.Client{Transport: tr}}
}

func NewClient() *EzClient {
	return &EzClient{Client: &http.Client{}}
}

func (c *EzClient) JsonGet(url string, out interface{}) (int, error) {
	resp, err := c.Client.Get(url)
	if err != nil {
		return 0, err
	}
	return decodeJsonResponse(resp, out)
}

func (c *EzClient) JsonStr(j string) *EzClient {
	c.body = strings.NewReader(j)
	return c
}

func (c *EzClient) Json(j interface{}) *EzClient {
	b, err := json.Marshal(j)
	if err == nil {
		c.body = bytes.NewReader(b)
	}

	return c
}

func (c *EzClient) JsonPost(url string, out interface{}) (int, error) {
	resp, err := c.Client.Post(url, "application/json", c.body)
	if err != nil {
		return 0, err
	}
	return decodeJsonResponse(resp, out)
}

func decodeJsonResponse(resp *http.Response, out interface{}) (int, error) {
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	if resp.StatusCode > 299 {
		return resp.StatusCode, errors.New(string(body))
	}

	err := json.Unmarshal(body, out)
	if err != nil {
		return resp.StatusCode, err
	}
	return resp.StatusCode, nil
}

func (c *EzClient) PostFile(url, filepath, formName string, params map[string]string) (int, error) {
	// Setup body
	body := bytes.NewBufferString("")
	writer := multipart.NewWriter(body)
	defer writer.Close()

	// Create file form
	part, err := writer.CreateFormFile(formName, filepath)
	if err != nil {
		return 0, err
	}

	// Read file into form
	file, err := os.Open(filepath)
	if err != nil {
		return 0, err
	}
	defer file.Close()

	fileContents, err := ioutil.ReadAll(file)
	part.Write(fileContents)

	// Add boundary
	boundary := writer.Boundary()
	closeStr := fmt.Sprintf("\r\n--%s--\r\n", boundary)

	// Add additional params
	if params != nil {
		for key, value := range params {
			writer.WriteField(key, value)
		}
	}

	// Create the request and set headers
	closeBuf := bytes.NewBufferString(closeStr)
	reader := io.MultiReader(body, file, closeBuf)
	req, err := http.NewRequest("POST", url, reader)
	req.Header.Add("Content-Type", "multipart/form-data; boundary="+boundary)
	req.ContentLength = int64(body.Len()) + int64(closeBuf.Len())

	// Post the file
	resp, err := c.Client.Do(req)
	defer resp.Body.Close()
	b, _ := ioutil.ReadAll(resp.Body)

	// Return status and any error code
	if resp.StatusCode > 299 {
		return resp.StatusCode, errors.New(string(b))
	}

	return resp.StatusCode, nil
}
<commit_msg>Tell request to close after use.<commit_after>package ezhttp

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"strings"
)

type EzClient struct {
	*http.Client
	body io.Reader
}

func NewInsecureClient() *EzClient {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	return &EzClient{Client: &http.Client{Transport: tr}}
}

func NewClient() *EzClient {
	return &EzClient{Client: &http.Client{}}
}

func (c *EzClient) JsonGet(url string, out interface{}) (int, error) {
	resp, err := c.Client.Get(url)
	if err != nil {
		return 0, err
	}
	return decodeJsonResponse(resp, out)
}

func (c *EzClient) JsonStr(j string) *EzClient {
	c.body = strings.NewReader(j)
	return c
}

func (c *EzClient) Json(j interface{}) *EzClient {
	b, err := json.Marshal(j)
	if err == nil {
		c.body = bytes.NewReader(b)
	}

	return c
}

func (c *EzClient) JsonPost(url string, out interface{}) (int, error) {
	resp, err := c.Client.Post(url, "application/json", c.body)
	if err != nil {
		return 0, err
	}
	return decodeJsonResponse(resp, out)
}

func decodeJsonResponse(resp *http.Response, out interface{}) (int, error) {
	defer resp.Body.Close()
	body, _ := ioutil.ReadAll(resp.Body)

	if resp.StatusCode > 299 {
		return resp.StatusCode, errors.New(string(body))
	}

	err := json.Unmarshal(body, out)
	if err != nil {
		return resp.StatusCode, err
	}
	return resp.StatusCode, nil
}

func (c *EzClient) PostFile(url, filepath, formName string, params map[string]string) (int, error) {
	// Setup body
	body := bytes.NewBufferString("")
	writer := multipart.NewWriter(body)
	defer writer.Close()

	// Create file form
	part, err := writer.CreateFormFile(formName, filepath)
	if err != nil {
		return 0, err
	}

	// Read file into form
	file, err := os.Open(filepath)
	if err != nil {
		return 0, err
	}
	defer file.Close()

	fileContents, err := ioutil.ReadAll(file)
	part.Write(fileContents)

	// Add boundary
	boundary := writer.Boundary()
	closeStr := fmt.Sprintf("\r\n--%s--\r\n", boundary)

	// Add additional params
	if params != nil {
		for key, value := range params {
			writer.WriteField(key, value)
		}
	}

	// Create the request and set headers
	closeBuf := bytes.NewBufferString(closeStr)
	reader := io.MultiReader(body, file, closeBuf)
	req, err := http.NewRequest("POST", url, reader)
	req.Header.Add("Content-Type", "multipart/form-data; boundary="+boundary)
	req.ContentLength = int64(body.Len()) + int64(closeBuf.Len())
	req.Close = true

	// Post the file
	resp, err := c.Client.Do(req)
	defer resp.Body.Close()
	b, _ := ioutil.ReadAll(resp.Body)

	// Return status and any error code
	if resp.StatusCode > 299 {
		return resp.StatusCode, errors.New(string(b))
	}

	return resp.StatusCode, nil
}
<|endoftext|>


<commit_before>// Copyright 2014 The Serviced 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 facade

import (
	"fmt"
	"time"

	"github.com/control-center/serviced/auth"
	"github.com/control-center/serviced/datastore"
	"github.com/control-center/serviced/domain/addressassignment"
	"github.com/control-center/serviced/domain/host"
	"github.com/control-center/serviced/domain/hostkey"
	"github.com/control-center/serviced/domain/service"
	"github.com/zenoss/glog"
)

const (
	beforeHostUpdate = beforeEvent("BeforeHostUpdate")
	afterHostUpdate  = afterEvent("AfterHostUpdate")
	beforeHostAdd    = beforeEvent("BeforeHostAdd")
	afterHostAdd     = afterEvent("AfterHostAdd")
	beforeHostDelete = beforeEvent("BeforeHostDelete")
	afterHostDelete  = afterEvent("AfterHostDelete")
)

//---------------------------------------------------------------------------
// Host CRUD

// AddHost registers a host with serviced. Returns the host's private key.
// Returns an error if host already exists or if the host's IP is a virtual IP.
func (f *Facade) AddHost(ctx datastore.Context, entity *host.Host) ([]byte, error) {
	glog.V(2).Infof("Facade.AddHost: %v", entity)
	if err := f.DFSLock(ctx).LockWithTimeout("add host", userLockTimeout); err != nil {
		glog.Warningf("Cannot add host: %s", err)
		return nil, err
	}
	defer f.DFSLock(ctx).Unlock()
	return f.addHost(ctx, entity)
}

func (f *Facade) addHost(ctx datastore.Context, entity *host.Host) ([]byte, error) {
	exists, err := f.GetHost(ctx, entity.ID)
	if err != nil {
		return nil, err
	}
	if exists != nil {
		return nil, fmt.Errorf("host already exists: %s", entity.ID)
	}

	// validate Pool exists
	pool, err := f.GetResourcePool(ctx, entity.PoolID)
	if err != nil {
		return nil, fmt.Errorf("error verifying pool exists: %v", err)
	}
	if pool == nil {
		return nil, fmt.Errorf("error creating host, pool %s does not exists", entity.PoolID)
	}

	// verify that there are no virtual IPs with the given host IP(s)
	for _, ip := range entity.IPs {
		if exists, err := f.HasIP(ctx, pool.ID, ip.IPAddress); err != nil {
			return nil, fmt.Errorf("error verifying ip %s exists: %v", ip.IPAddress, err)
		} else if exists {
			return nil, fmt.Errorf("pool already has a virtual ip %s", ip.IPAddress)
		}
	}

	ec := newEventCtx()
	err = nil
	defer f.afterEvent(afterHostAdd, ec, entity, err)
	if err = f.beforeEvent(beforeHostAdd, ec, entity); err != nil {
		return nil, err
	}

	// Generate and store an RSA key for the host
	publicPEM, privatePEM, err := auth.GenerateRSAKeyPairPEM(nil)
	if err != nil {
		return nil, err
	}
	hostkeyEntity := hostkey.HostKey{PEM: string(publicPEM[:])}
	err = f.hostkeyStore.Put(ctx, entity.ID, &hostkeyEntity)
	if err != nil {
		return nil, err
	}

	now := time.Now()
	entity.CreatedAt = now
	entity.UpdatedAt = now

	if err = f.hostStore.Put(ctx, host.HostKey(entity.ID), entity); err != nil {
		return nil, err
	}
	err = f.zzk.AddHost(entity)
	return privatePEM, err
}

// UpdateHost information for a registered host
func (f *Facade) UpdateHost(ctx datastore.Context, entity *host.Host) error {
	glog.V(2).Infof("Facade.UpdateHost: %+v", entity)
	if err := f.DFSLock(ctx).LockWithTimeout("update host", userLockTimeout); err != nil {
		glog.Warningf("Cannot update host: %s", err)
		return err
	}
	defer f.DFSLock(ctx).Unlock()

	// validate the host exists
	if host, err := f.GetHost(ctx, entity.ID); err != nil {
		return err
	} else if host == nil {
		return fmt.Errorf("host does not exist: %s", entity.ID)
	}

	// validate the pool exists
	if pool, err := f.GetResourcePool(ctx, entity.PoolID); err != nil {
		return err
	} else if pool == nil {
		return fmt.Errorf("pool does not exist: %s", entity.PoolID)
	}

	var err error
	ec := newEventCtx()
	defer f.afterEvent(afterHostAdd, ec, entity, err)

	if err = f.beforeEvent(beforeHostAdd, ec, entity); err != nil {
		return err
	}

	entity.UpdatedAt = time.Now()
	if err = f.hostStore.Put(ctx, host.HostKey(entity.ID), entity); err != nil {
		return err
	}

	err = f.zzk.UpdateHost(entity)
	return err
}

// RemoveHost removes a Host from serviced
func (f *Facade) RemoveHost(ctx datastore.Context, hostID string) (err error) {
	glog.V(2).Infof("Facade.RemoveHost: %s", hostID)
	if err := f.DFSLock(ctx).LockWithTimeout("remove host", userLockTimeout); err != nil {
		glog.Warningf("Cannot remove host: %s", err)
		return err
	}
	defer f.DFSLock(ctx).Unlock()

	//assert valid host
	var _host *host.Host
	if _host, err = f.GetHost(ctx, hostID); err != nil {
		return err
	} else if _host == nil {
		return fmt.Errorf("HostID %s does not exist", hostID)
	}

	ec := newEventCtx()
	defer f.afterEvent(afterHostDelete, ec, hostID, err)
	if err = f.beforeEvent(beforeHostDelete, ec, hostID); err != nil {
		return err
	}

	//remove host from zookeeper
	if err = f.zzk.RemoveHost(_host); err != nil {
		return err
	}

	//remove host from datastore
	if err = f.hostStore.Delete(ctx, host.HostKey(hostID)); err != nil {
		return err
	}

	//grab all services that are address assigned the host's IPs
	var services []service.Service
	for _, ip := range _host.IPs {
		query := []string{fmt.Sprintf("Endpoints.AddressAssignment.IPAddr:%s", ip.IPAddress)}
		svcs, err := f.GetTaggedServices(ctx, query)
		if err != nil {
			glog.Errorf("Failed to grab services with endpoints assigned to ip %s on host %s: %s", ip.IPAddress, _host.Name, err)
			return err
		}
		services = append(services, svcs...)
	}

	// update address assignments
	for _, svc := range services {
		request := addressassignment.AssignmentRequest{
			ServiceID:      svc.ID,
			IPAddress:      "",
			AutoAssignment: true,
		}
		if err = f.AssignIPs(ctx, request); err != nil {
			glog.Warningf("Failed assigning another ip to service %s: %s", svc.ID, err)
		}
	}

	return nil
}

// GetHost gets a host by id. Returns nil if host not found
func (f *Facade) GetHost(ctx datastore.Context, hostID string) (*host.Host, error) {
	glog.V(2).Infof("Facade.GetHost: id=%s", hostID)

	var value host.Host
	err := f.hostStore.Get(ctx, host.HostKey(hostID), &value)
	glog.V(4).Infof("Facade.GetHost: get error %v", err)
	if datastore.IsErrNoSuchEntity(err) {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	return &value, nil
}

// GetHostKey gets a host key by id. Returns nil if host not found
func (f *Facade) GetHostKey(ctx datastore.Context, hostID string) ([]byte, error) {
	glog.V(2).Infof("Facade.GetHostKey: id=%s", hostID)

	if key, err := f.hostkeyStore.Get(ctx, hostID); err != nil {
		return nil, err
	} else {
		return []byte(key.PEM), nil
	}
}

// GetHosts returns a list of all registered hosts
func (f *Facade) GetHosts(ctx datastore.Context) ([]host.Host, error) {
	return f.hostStore.GetN(ctx, 10000)
}

// GetActiveHostIDs returns a list of active host ids
func (f *Facade) GetActiveHostIDs(ctx datastore.Context) ([]string, error) {
	hostids := []string{}
	pools, err := f.GetResourcePools(ctx)
	if err != nil {
		glog.Errorf("Could not get resource pools: %v", err)
		return nil, err
	}
	for _, p := range pools {
		var active []string
		if err := f.zzk.GetActiveHosts(p.ID, &active); err != nil {
			glog.Errorf("Could not get active host ids for pool: %v", err)
			return nil, err
		}
		hostids = append(hostids, active...)
	}
	return hostids, nil
}

// FindHostsInPool returns a list of all hosts with poolID
func (f *Facade) FindHostsInPool(ctx datastore.Context, poolID string) ([]host.Host, error) {
	return f.hostStore.FindHostsWithPoolID(ctx, poolID)
}

// GetHostByIP returns the host by IP address
func (f *Facade) GetHostByIP(ctx datastore.Context, hostIP string) (*host.Host, error) {
	return f.hostStore.GetHostByIP(ctx, hostIP)
}

// GetReadHosts returns list of all hosts using a minimal representation of a host
func (f *Facade) GetReadHosts(ctx datastore.Context) ([]host.ReadHost, error) {
	hosts, err := f.hostStore.GetN(ctx, 20000)
	if err != nil {
		return nil, err
	}

	return toReadHosts(hosts), nil
}

// FindReadHostsInPool returns list of all hosts for a pool using a minimal representation of a host
func (f *Facade) FindReadHostsInPool(ctx datastore.Context, poolID string) ([]host.ReadHost, error) {
	hosts, err := f.hostStore.FindHostsWithPoolID(ctx, poolID)
	if err != nil {
		return nil, err
	}

	return toReadHosts(hosts), nil
}

func toReadHosts(hosts []host.Host) []host.ReadHost {
	readHosts := []host.ReadHost{}
	for _, h := range hosts {
		readHosts = append(readHosts, toReadHost(h))
	}

	return readHosts
}

func toReadHost(h host.Host) host.ReadHost {
	return host.ReadHost{
		ID:            h.ID,
		Name:          h.Name,
		PoolID:        h.PoolID,
		Cores:         h.Cores,
		Memory:        h.Memory,
		RAMLimit:      h.RAMLimit,
		KernelVersion: h.KernelVersion,
		KernelRelease: h.KernelRelease,
		ServiceD: host.ReadServiced{
			Version: h.ServiceD.Version,
			Date:    h.ServiceD.Date,
			Release: h.ServiceD.Release,
		},
		CreatedAt: h.CreatedAt,
		UpdatedAt: h.UpdatedAt,
	}
}
<commit_msg>Attach master public key to addHost return value<commit_after>// Copyright 2014 The Serviced 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 facade

import (
	"fmt"
	"time"

	"github.com/control-center/serviced/auth"
	"github.com/control-center/serviced/datastore"
	"github.com/control-center/serviced/domain/addressassignment"
	"github.com/control-center/serviced/domain/host"
	"github.com/control-center/serviced/domain/hostkey"
	"github.com/control-center/serviced/domain/service"
	"github.com/zenoss/glog"
)

const (
	beforeHostUpdate = beforeEvent("BeforeHostUpdate")
	afterHostUpdate  = afterEvent("AfterHostUpdate")
	beforeHostAdd    = beforeEvent("BeforeHostAdd")
	afterHostAdd     = afterEvent("AfterHostAdd")
	beforeHostDelete = beforeEvent("BeforeHostDelete")
	afterHostDelete  = afterEvent("AfterHostDelete")
)

//---------------------------------------------------------------------------
// Host CRUD

// AddHost registers a host with serviced. Returns the host's private key.
// Returns an error if host already exists or if the host's IP is a virtual IP.
func (f *Facade) AddHost(ctx datastore.Context, entity *host.Host) ([]byte, error) {
	glog.V(2).Infof("Facade.AddHost: %v", entity)
	if err := f.DFSLock(ctx).LockWithTimeout("add host", userLockTimeout); err != nil {
		glog.Warningf("Cannot add host: %s", err)
		return nil, err
	}
	defer f.DFSLock(ctx).Unlock()
	return f.addHost(ctx, entity)
}

func (f *Facade) addHost(ctx datastore.Context, entity *host.Host) ([]byte, error) {
	exists, err := f.GetHost(ctx, entity.ID)
	if err != nil {
		return nil, err
	}
	if exists != nil {
		return nil, fmt.Errorf("host already exists: %s", entity.ID)
	}

	// validate Pool exists
	pool, err := f.GetResourcePool(ctx, entity.PoolID)
	if err != nil {
		return nil, fmt.Errorf("error verifying pool exists: %v", err)
	}
	if pool == nil {
		return nil, fmt.Errorf("error creating host, pool %s does not exists", entity.PoolID)
	}

	// verify that there are no virtual IPs with the given host IP(s)
	for _, ip := range entity.IPs {
		if exists, err := f.HasIP(ctx, pool.ID, ip.IPAddress); err != nil {
			return nil, fmt.Errorf("error verifying ip %s exists: %v", ip.IPAddress, err)
		} else if exists {
			return nil, fmt.Errorf("pool already has a virtual ip %s", ip.IPAddress)
		}
	}

	ec := newEventCtx()
	err = nil
	defer f.afterEvent(afterHostAdd, ec, entity, err)
	if err = f.beforeEvent(beforeHostAdd, ec, entity); err != nil {
		return nil, err
	}

	// Generate and store an RSA key for the host
	delegateHeaders := map[string]string{
		"purpose": "delegate",
		"host_ip": entity.IPAddr,
		"host_id": entity.ID}
	publicPEM, privatePEM, err := auth.GenerateRSAKeyPairPEM(delegateHeaders)
	if err != nil {
		return nil, err
	}
	hostkeyEntity := hostkey.HostKey{PEM: string(publicPEM[:])}
	err = f.hostkeyStore.Put(ctx, entity.ID, &hostkeyEntity)
	if err != nil {
		return nil, err
	}

	masterHeaders := map[string]string{"purpose": "master"}
	masterPEM, err := auth.PEMFromRSAPublicKey(auth.MasterPublicKey(), masterHeaders)
	if err != nil {
		return nil, err
	}

	now := time.Now()
	entity.CreatedAt = now
	entity.UpdatedAt = now

	if err = f.hostStore.Put(ctx, host.HostKey(entity.ID), entity); err != nil {
		return nil, err
	}
	err = f.zzk.AddHost(entity)

	PEMBlocks := append(privatePEM, masterPEM...)
	return PEMBlocks, nil
}

// UpdateHost information for a registered host
func (f *Facade) UpdateHost(ctx datastore.Context, entity *host.Host) error {
	glog.V(2).Infof("Facade.UpdateHost: %+v", entity)
	if err := f.DFSLock(ctx).LockWithTimeout("update host", userLockTimeout); err != nil {
		glog.Warningf("Cannot update host: %s", err)
		return err
	}
	defer f.DFSLock(ctx).Unlock()

	// validate the host exists
	if host, err := f.GetHost(ctx, entity.ID); err != nil {
		return err
	} else if host == nil {
		return fmt.Errorf("host does not exist: %s", entity.ID)
	}

	// validate the pool exists
	if pool, err := f.GetResourcePool(ctx, entity.PoolID); err != nil {
		return err
	} else if pool == nil {
		return fmt.Errorf("pool does not exist: %s", entity.PoolID)
	}

	var err error
	ec := newEventCtx()
	defer f.afterEvent(afterHostAdd, ec, entity, err)

	if err = f.beforeEvent(beforeHostAdd, ec, entity); err != nil {
		return err
	}

	entity.UpdatedAt = time.Now()
	if err = f.hostStore.Put(ctx, host.HostKey(entity.ID), entity); err != nil {
		return err
	}

	err = f.zzk.UpdateHost(entity)
	return err
}

// RemoveHost removes a Host from serviced
func (f *Facade) RemoveHost(ctx datastore.Context, hostID string) (err error) {
	glog.V(2).Infof("Facade.RemoveHost: %s", hostID)
	if err := f.DFSLock(ctx).LockWithTimeout("remove host", userLockTimeout); err != nil {
		glog.Warningf("Cannot remove host: %s", err)
		return err
	}
	defer f.DFSLock(ctx).Unlock()

	//assert valid host
	var _host *host.Host
	if _host, err = f.GetHost(ctx, hostID); err != nil {
		return err
	} else if _host == nil {
		return fmt.Errorf("HostID %s does not exist", hostID)
	}

	ec := newEventCtx()
	defer f.afterEvent(afterHostDelete, ec, hostID, err)
	if err = f.beforeEvent(beforeHostDelete, ec, hostID); err != nil {
		return err
	}

	//remove host from zookeeper
	if err = f.zzk.RemoveHost(_host); err != nil {
		return err
	}

	//remove host from datastore
	if err = f.hostStore.Delete(ctx, host.HostKey(hostID)); err != nil {
		return err
	}

	//grab all services that are address assigned the host's IPs
	var services []service.Service
	for _, ip := range _host.IPs {
		query := []string{fmt.Sprintf("Endpoints.AddressAssignment.IPAddr:%s", ip.IPAddress)}
		svcs, err := f.GetTaggedServices(ctx, query)
		if err != nil {
			glog.Errorf("Failed to grab services with endpoints assigned to ip %s on host %s: %s", ip.IPAddress, _host.Name, err)
			return err
		}
		services = append(services, svcs...)
	}

	// update address assignments
	for _, svc := range services {
		request := addressassignment.AssignmentRequest{
			ServiceID:      svc.ID,
			IPAddress:      "",
			AutoAssignment: true,
		}
		if err = f.AssignIPs(ctx, request); err != nil {
			glog.Warningf("Failed assigning another ip to service %s: %s", svc.ID, err)
		}
	}

	return nil
}

// GetHost gets a host by id. Returns nil if host not found
func (f *Facade) GetHost(ctx datastore.Context, hostID string) (*host.Host, error) {
	glog.V(2).Infof("Facade.GetHost: id=%s", hostID)

	var value host.Host
	err := f.hostStore.Get(ctx, host.HostKey(hostID), &value)
	glog.V(4).Infof("Facade.GetHost: get error %v", err)
	if datastore.IsErrNoSuchEntity(err) {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	return &value, nil
}

// GetHostKey gets a host key by id. Returns nil if host not found
func (f *Facade) GetHostKey(ctx datastore.Context, hostID string) ([]byte, error) {
	glog.V(2).Infof("Facade.GetHostKey: id=%s", hostID)

	if key, err := f.hostkeyStore.Get(ctx, hostID); err != nil {
		return nil, err
	} else {
		return []byte(key.PEM), nil
	}
}

// GetHosts returns a list of all registered hosts
func (f *Facade) GetHosts(ctx datastore.Context) ([]host.Host, error) {
	return f.hostStore.GetN(ctx, 10000)
}

// GetActiveHostIDs returns a list of active host ids
func (f *Facade) GetActiveHostIDs(ctx datastore.Context) ([]string, error) {
	hostids := []string{}
	pools, err := f.GetResourcePools(ctx)
	if err != nil {
		glog.Errorf("Could not get resource pools: %v", err)
		return nil, err
	}
	for _, p := range pools {
		var active []string
		if err := f.zzk.GetActiveHosts(p.ID, &active); err != nil {
			glog.Errorf("Could not get active host ids for pool: %v", err)
			return nil, err
		}
		hostids = append(hostids, active...)
	}
	return hostids, nil
}

// FindHostsInPool returns a list of all hosts with poolID
func (f *Facade) FindHostsInPool(ctx datastore.Context, poolID string) ([]host.Host, error) {
	return f.hostStore.FindHostsWithPoolID(ctx, poolID)
}

// GetHostByIP returns the host by IP address
func (f *Facade) GetHostByIP(ctx datastore.Context, hostIP string) (*host.Host, error) {
	return f.hostStore.GetHostByIP(ctx, hostIP)
}

// GetReadHosts returns list of all hosts using a minimal representation of a host
func (f *Facade) GetReadHosts(ctx datastore.Context) ([]host.ReadHost, error) {
	hosts, err := f.hostStore.GetN(ctx, 20000)
	if err != nil {
		return nil, err
	}

	return toReadHosts(hosts), nil
}

// FindReadHostsInPool returns list of all hosts for a pool using a minimal representation of a host
func (f *Facade) FindReadHostsInPool(ctx datastore.Context, poolID string) ([]host.ReadHost, error) {
	hosts, err := f.hostStore.FindHostsWithPoolID(ctx, poolID)
	if err != nil {
		return nil, err
	}

	return toReadHosts(hosts), nil
}

func toReadHosts(hosts []host.Host) []host.ReadHost {
	readHosts := []host.ReadHost{}
	for _, h := range hosts {
		readHosts = append(readHosts, toReadHost(h))
	}

	return readHosts
}

func toReadHost(h host.Host) host.ReadHost {
	return host.ReadHost{
		ID:            h.ID,
		Name:          h.Name,
		PoolID:        h.PoolID,
		Cores:         h.Cores,
		Memory:        h.Memory,
		RAMLimit:      h.RAMLimit,
		KernelVersion: h.KernelVersion,
		KernelRelease: h.KernelRelease,
		ServiceD: host.ReadServiced{
			Version: h.ServiceD.Version,
			Date:    h.ServiceD.Date,
			Release: h.ServiceD.Release,
		},
		CreatedAt: h.CreatedAt,
		UpdatedAt: h.UpdatedAt,
	}
}
<|endoftext|>


<commit_before>package debiaser

import (
	"fmt"
	"log"
	"math"
	"sort"

	"gonum.org/v1/gonum/floats"
	"gonum.org/v1/gonum/mat"

	"github.com/JaderDias/movingmedian"
)

// Debiaser implements inplace removal of bias from a mat64 of (scaled) values.
type Debiaser interface {
	Debias(*mat.Dense)
}

// Sorter provides method to sort and then unsort a mat64
type Sorter interface {
	Sort(*mat.Dense)
	Unsort(*mat.Dense)
}

// SortedDebiaser is useful when we need to: sort, then unbias based on that sort order, then unsort.
// An example of this is for GC bias.
type SortedDebiaser interface {
	Sorter
	Debiaser
}

// GeneralDebiaser is an implementation of a SortedDebiaser that can be used simply by setting attributes.int
// Window is the size of the moving window for correction.
// Usage is to Call GeneralDebiaser.Sort() then Debias(), then Unsort(). Presumbly, Those calls will be flanked
// by a scaler call such as to scaler.ZScore.
type GeneralDebiaser struct {
	Vals   []float64
	Window int
	inds   []int
	tmp    *mat.Dense
}

func (g *GeneralDebiaser) setTmp(r, c int) {
	if g.tmp == nil {
		g.tmp = mat.NewDense(r, c, nil)
	} else {
		gr, gc := g.tmp.Dims()
		if gr != r || gc != c {
			g.tmp = mat.NewDense(r, c, nil)
		}
	}
}

// Sort sorts the rows in mat according the order in g.Vals.
func (g *GeneralDebiaser) Sort(mat *mat.Dense) {
	if g.inds == nil {
		g.inds = make([]int, len(g.Vals))
	}
	floats.Argsort(g.Vals, g.inds)
	r, c := mat.Dims()
	g.setTmp(r, c)

	changed := false
	for ai, bi := range g.inds {
		if ai != bi {
			changed = true
		}
		g.tmp.SetRow(ai, mat.RawRowView(bi))
	}
	if !changed {
		log.Println("WARNING: no change after sorting. This usually means .Vals is unset or same as previous run")
	}
	// copy g.tmp into mat
	mat.Copy(g.tmp)
}

// Unsort reverts the values to be position sorted.
func (g *GeneralDebiaser) Unsort(mat *mat.Dense) {
	if g.inds == nil {
		panic("unsort: must call sort first")
	}
	r, c := mat.Dims()
	g.setTmp(r, c)
	// copy mat into g.tmp
	g.tmp.Copy(mat)
	tmp := make([]float64, len(g.Vals))
	for ai, bi := range g.inds {
		mat.SetRow(bi, g.tmp.RawRowView(ai))
		tmp[bi] = g.Vals[ai]
	}
	g.Vals = tmp
}

// Debias by subtracting moving median in each sample.
// It's assumed that g.Sort() has been called before this and that g.Unsort() will be called after.
// It's also assumed that the values in mat have been scaled, for example by a `scaler.ZScore`.
func (g *GeneralDebiaser) Debias(imat *mat.Dense) {
	r, c := imat.Dims()
	col := make([]float64, r)
	for sampleI := 0; sampleI < c; sampleI++ {
		mat.Col(col, sampleI, imat)

		mm := movingmedian.NewMovingMedian(g.Window)
		mid := (g.Window-1)/2 + 1
		for i := 0; i < mid; i++ {
			mm.Push(col[i])
		}
		for i := 0; i < mid; i++ {
			col[i] /= math.Max(mm.Median(), 1)
		}

		var i int
		for i = mid; i < len(col)-mid; i++ {
			mm.Push(col[i+mid])
			col[i] /= math.Max(mm.Median(), 1)
		}
		for ; i < len(col); i++ {
			col[i] /= math.Max(mm.Median(), 1)
		}
		imat.SetCol(sampleI, col)
	}
}

type ChunkDebiaser struct {
	GeneralDebiaser
	// ScoreWindow defines the range of Vals used per window.
	// E.g. if this is 0.1 then all values from 0.25-0.35 will be normalized to the median of
	// Depths occuring in that range.
	ScoreWindow float64
}

func (cd *ChunkDebiaser) Debias(imat *mat.Dense) {
	if cd.ScoreWindow == 0 {
		panic("must set ChunkDebiaser.ScoreWindow")
	}
	r, c := imat.Dims()
	col := make([]float64, r)

	slices := make([]int, 1, 100)
	v0 := cd.Vals[0]
	for i := 0; i < len(cd.Vals); i++ {
		if cd.Vals[i]-v0 > cd.ScoreWindow {
			v0 = cd.Vals[i]
			slices = append(slices, i)
		}
	}
	slices = append(slices, len(cd.Vals))
	dpSubset := make([]float64, 0, len(cd.Vals))

	for sampleI := 0; sampleI < c; sampleI++ {
		mat.Col(col, sampleI, imat)
		for i := 1; i < len(slices); i++ {
			si, ei := slices[i-1], slices[i]
			dpSubset = dpSubset[:(ei - si)]
			copy(dpSubset, col[si:ei])
			sort.Float64s(dpSubset)
			var k int
			for ; k < len(dpSubset) && dpSubset[k] == 0; k++ {
			}
			median := dpSubset[(ei-si-k)/2]

			if median > 0 {
				for j := si; j < ei; j++ {
					col[j] /= median
				}
			}
		}
		imat.SetCol(sampleI, col)
	}
}

type SVD struct {
	MinVariancePct float64
}

func (isvd *SVD) Debias(imat *mat.Dense) {
	var svd mat.SVD
	if ok := svd.Factorize(imat, mat.SVDThin); !ok {
		panic("error with SVD")
	}

	// get svd and zero out first n components.
	s, u, v := extractSVD(&svd)
	sum := floats.Sum(s)
	str := "variance:"

	var n int
	for n = 0; n < 15 && 100*s[n]/sum > isvd.MinVariancePct; n++ {
		str += fmt.Sprintf(" %.2f", 100*s[n]/sum)
	}
	log.Println(str)

	sigma := mat.NewDense(len(s), len(s), nil)
	// leave the first n as 0 and set the rest.
	for i := n; i < len(s); i++ {
		sigma.Set(i, i, s[i])
	}
	imat.Product(u, sigma, v.T())
}

func extractSVD(svd *mat.SVD) (s []float64, u, v *mat.Dense) {
	um := svd.UTo(nil)
	vm := svd.VTo(nil)
	s = svd.Values(nil)
	return s, um, vm
}
<commit_msg>update indexcov for gonum changes<commit_after>package debiaser

import (
	"fmt"
	"log"
	"math"
	"sort"

	"gonum.org/v1/gonum/floats"
	"gonum.org/v1/gonum/mat"

	"github.com/JaderDias/movingmedian"
)

// Debiaser implements inplace removal of bias from a mat64 of (scaled) values.
type Debiaser interface {
	Debias(*mat.Dense)
}

// Sorter provides method to sort and then unsort a mat64
type Sorter interface {
	Sort(*mat.Dense)
	Unsort(*mat.Dense)
}

// SortedDebiaser is useful when we need to: sort, then unbias based on that sort order, then unsort.
// An example of this is for GC bias.
type SortedDebiaser interface {
	Sorter
	Debiaser
}

// GeneralDebiaser is an implementation of a SortedDebiaser that can be used simply by setting attributes.int
// Window is the size of the moving window for correction.
// Usage is to Call GeneralDebiaser.Sort() then Debias(), then Unsort(). Presumbly, Those calls will be flanked
// by a scaler call such as to scaler.ZScore.
type GeneralDebiaser struct {
	Vals   []float64
	Window int
	inds   []int
	tmp    *mat.Dense
}

func (g *GeneralDebiaser) setTmp(r, c int) {
	if g.tmp == nil {
		g.tmp = mat.NewDense(r, c, nil)
	} else {
		gr, gc := g.tmp.Dims()
		if gr != r || gc != c {
			g.tmp = mat.NewDense(r, c, nil)
		}
	}
}

// Sort sorts the rows in mat according the order in g.Vals.
func (g *GeneralDebiaser) Sort(mat *mat.Dense) {
	if g.inds == nil {
		g.inds = make([]int, len(g.Vals))
	}
	floats.Argsort(g.Vals, g.inds)
	r, c := mat.Dims()
	g.setTmp(r, c)

	changed := false
	for ai, bi := range g.inds {
		if ai != bi {
			changed = true
		}
		g.tmp.SetRow(ai, mat.RawRowView(bi))
	}
	if !changed {
		log.Println("WARNING: no change after sorting. This usually means .Vals is unset or same as previous run")
	}
	// copy g.tmp into mat
	mat.Copy(g.tmp)
}

// Unsort reverts the values to be position sorted.
func (g *GeneralDebiaser) Unsort(mat *mat.Dense) {
	if g.inds == nil {
		panic("unsort: must call sort first")
	}
	r, c := mat.Dims()
	g.setTmp(r, c)
	// copy mat into g.tmp
	g.tmp.Copy(mat)
	tmp := make([]float64, len(g.Vals))
	for ai, bi := range g.inds {
		mat.SetRow(bi, g.tmp.RawRowView(ai))
		tmp[bi] = g.Vals[ai]
	}
	g.Vals = tmp
}

// Debias by subtracting moving median in each sample.
// It's assumed that g.Sort() has been called before this and that g.Unsort() will be called after.
// It's also assumed that the values in mat have been scaled, for example by a `scaler.ZScore`.
func (g *GeneralDebiaser) Debias(imat *mat.Dense) {
	r, c := imat.Dims()
	col := make([]float64, r)
	for sampleI := 0; sampleI < c; sampleI++ {
		mat.Col(col, sampleI, imat)

		mm := movingmedian.NewMovingMedian(g.Window)
		mid := (g.Window-1)/2 + 1
		for i := 0; i < mid; i++ {
			mm.Push(col[i])
		}
		for i := 0; i < mid; i++ {
			col[i] /= math.Max(mm.Median(), 1)
		}

		var i int
		for i = mid; i < len(col)-mid; i++ {
			mm.Push(col[i+mid])
			col[i] /= math.Max(mm.Median(), 1)
		}
		for ; i < len(col); i++ {
			col[i] /= math.Max(mm.Median(), 1)
		}
		imat.SetCol(sampleI, col)
	}
}

type ChunkDebiaser struct {
	GeneralDebiaser
	// ScoreWindow defines the range of Vals used per window.
	// E.g. if this is 0.1 then all values from 0.25-0.35 will be normalized to the median of
	// Depths occuring in that range.
	ScoreWindow float64
}

func (cd *ChunkDebiaser) Debias(imat *mat.Dense) {
	if cd.ScoreWindow == 0 {
		panic("must set ChunkDebiaser.ScoreWindow")
	}
	r, c := imat.Dims()
	col := make([]float64, r)

	slices := make([]int, 1, 100)
	v0 := cd.Vals[0]
	for i := 0; i < len(cd.Vals); i++ {
		if cd.Vals[i]-v0 > cd.ScoreWindow {
			v0 = cd.Vals[i]
			slices = append(slices, i)
		}
	}
	slices = append(slices, len(cd.Vals))
	dpSubset := make([]float64, 0, len(cd.Vals))

	for sampleI := 0; sampleI < c; sampleI++ {
		mat.Col(col, sampleI, imat)
		for i := 1; i < len(slices); i++ {
			si, ei := slices[i-1], slices[i]
			dpSubset = dpSubset[:(ei - si)]
			copy(dpSubset, col[si:ei])
			sort.Float64s(dpSubset)
			var k int
			for ; k < len(dpSubset) && dpSubset[k] == 0; k++ {
			}
			median := dpSubset[(ei-si-k)/2]

			if median > 0 {
				for j := si; j < ei; j++ {
					col[j] /= median
				}
			}
		}
		imat.SetCol(sampleI, col)
	}
}

type SVD struct {
	MinVariancePct float64
}

func (isvd *SVD) Debias(imat *mat.Dense) {
	var svd mat.SVD
	if ok := svd.Factorize(imat, mat.SVDThin); !ok {
		panic("error with SVD")
	}

	// get svd and zero out first n components.
	s, u, v := extractSVD(&svd)
	sum := floats.Sum(s)
	str := "variance:"

	var n int
	for n = 0; n < 15 && 100*s[n]/sum > isvd.MinVariancePct; n++ {
		str += fmt.Sprintf(" %.2f", 100*s[n]/sum)
	}
	log.Println(str)

	sigma := mat.NewDense(len(s), len(s), nil)
	// leave the first n as 0 and set the rest.
	for i := n; i < len(s); i++ {
		sigma.Set(i, i, s[i])
	}
	imat.Product(u, sigma, v.T())
}

func extractSVD(svd *mat.SVD) (s []float64, u, v *mat.Dense) {
	var um *mat.Dense
	var vm *mat.Dense
	svd.UTo(um)
	svd.VTo(vm)
	s = svd.Values(nil)
	return s, um, vm
}
<|endoftext|>


<commit_before>package web

import (
	"encoding/json"
	"html/template"
	"log"
	"net/http"

	"github.com/MiniProfiler/go/miniprofiler"
	"github.com/gorilla/mux"

	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/tsaf/sched"
)

var (
	tsdbHost  opentsdb.Host
	templates *template.Template
	router    = mux.NewRouter()
	schedule  = sched.DefaultSched
)

func init() {
	miniprofiler.Position = "bottomleft"
}

func Listen(addr, dir, host string) error {
	tsdbHost = opentsdb.Host(host)
	var err error
	templates, err = template.New("").ParseFiles(
		dir + "/templates/index.html",
	)
	if err != nil {
		log.Fatal(err)
	}
	router.Handle("/api/acknowledge/{alert}/{group}", JSON(Acknowledge))
	router.Handle("/api/alerts", JSON(Alerts))
	router.Handle("/api/expr", JSON(Expr))
	router.Handle("/api/metric", JSON(UniqueMetrics))
	router.Handle("/api/metric/{tagk}/{tagv}", JSON(MetricsByTagPair))
	router.Handle("/api/query", JSON(Query))
	router.Handle("/api/tagk/{metric}", JSON(TagKeysByMetric))
	router.Handle("/api/tagv/{tagk}", JSON(TagValuesByTagKey))
	router.Handle("/api/tagv/{tagk}/{metric}", JSON(TagValuesByMetricTagKey))
	http.Handle("/", miniprofiler.NewHandler(Index))
	http.Handle("/api/", router)
	http.Handle("/partials/", http.FileServer(http.Dir(dir)))
	http.Handle("/static/", http.FileServer(http.Dir(dir)))
	log.Println("TSAF web listening on:", addr)
	log.Println("TSAF web directory:", dir)
	return http.ListenAndServe(addr, nil)
}

func Index(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) {
	err := templates.ExecuteTemplate(w, "index.html", struct {
		Includes template.HTML
	}{
		t.Includes(),
	})
	if err != nil {
		serveError(w, err)
	}
}

func serveError(w http.ResponseWriter, err error) {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

func JSON(h func(miniprofiler.Timer, http.ResponseWriter, *http.Request) (interface{}, error)) http.Handler {
	return miniprofiler.NewHandler(func(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) {
		d, err := h(t, w, r)
		if err != nil {
			serveError(w, err)
			return
		}
		b, err := json.Marshal(d)
		if err != nil {
			serveError(w, err)
			return
		}
		w.Write(b)
	})
}

func Alerts(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	return schedule, nil
}

func Acknowledge(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	vars := mux.Vars(r)
	ak := sched.AlertKey{
		Name:  vars["alert"],
		Group: vars["group"],
	}
	log.Println("ACK", ak)
	schedule.Acknowledge(ak)
	return nil, nil
}
<commit_msg>Quick exit on nil content<commit_after>package web

import (
	"encoding/json"
	"html/template"
	"log"
	"net/http"

	"github.com/MiniProfiler/go/miniprofiler"
	"github.com/gorilla/mux"

	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/tsaf/sched"
)

var (
	tsdbHost  opentsdb.Host
	templates *template.Template
	router    = mux.NewRouter()
	schedule  = sched.DefaultSched
)

func init() {
	miniprofiler.Position = "bottomleft"
}

func Listen(addr, dir, host string) error {
	tsdbHost = opentsdb.Host(host)
	var err error
	templates, err = template.New("").ParseFiles(
		dir + "/templates/index.html",
	)
	if err != nil {
		log.Fatal(err)
	}
	router.Handle("/api/acknowledge/{alert}/{group}", JSON(Acknowledge))
	router.Handle("/api/alerts", JSON(Alerts))
	router.Handle("/api/expr", JSON(Expr))
	router.Handle("/api/metric", JSON(UniqueMetrics))
	router.Handle("/api/metric/{tagk}/{tagv}", JSON(MetricsByTagPair))
	router.Handle("/api/query", JSON(Query))
	router.Handle("/api/tagk/{metric}", JSON(TagKeysByMetric))
	router.Handle("/api/tagv/{tagk}", JSON(TagValuesByTagKey))
	router.Handle("/api/tagv/{tagk}/{metric}", JSON(TagValuesByMetricTagKey))
	http.Handle("/", miniprofiler.NewHandler(Index))
	http.Handle("/api/", router)
	http.Handle("/partials/", http.FileServer(http.Dir(dir)))
	http.Handle("/static/", http.FileServer(http.Dir(dir)))
	log.Println("TSAF web listening on:", addr)
	log.Println("TSAF web directory:", dir)
	return http.ListenAndServe(addr, nil)
}

func Index(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) {
	err := templates.ExecuteTemplate(w, "index.html", struct {
		Includes template.HTML
	}{
		t.Includes(),
	})
	if err != nil {
		serveError(w, err)
	}
}

func serveError(w http.ResponseWriter, err error) {
	http.Error(w, err.Error(), http.StatusInternalServerError)
}

func JSON(h func(miniprofiler.Timer, http.ResponseWriter, *http.Request) (interface{}, error)) http.Handler {
	return miniprofiler.NewHandler(func(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) {
		d, err := h(t, w, r)
		if err != nil {
			serveError(w, err)
			return
		}
		if d == nil {
			return
		}
		b, err := json.Marshal(d)
		if err != nil {
			serveError(w, err)
			return
		}
		w.Write(b)
	})
}

func Alerts(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	return schedule, nil
}

func Acknowledge(t miniprofiler.Timer, w http.ResponseWriter, r *http.Request) (interface{}, error) {
	vars := mux.Vars(r)
	ak := sched.AlertKey{
		Name:  vars["alert"],
		Group: vars["group"],
	}
	log.Println("ACK", ak)
	schedule.Acknowledge(ak)
	return nil, nil
}
<|endoftext|>


<commit_before>package swarm

import (
	"errors"
	"fmt"
	"sync"
	"time"

	conn "github.com/jbenet/go-ipfs/p2p/net/conn"
	addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
)

// dialAttempts governs how many times a goroutine will try to dial a given peer.
const dialAttempts = 3

// DialTimeout is the amount of time each dial attempt has. We can think about making
// this larger down the road, or putting more granular timeouts (i.e. within each
// subcomponent of Dial)
var DialTimeout time.Duration = time.Second * 30

// dialsync is a small object that helps manage ongoing dials.
// this way, if we receive many simultaneous dial requests, one
// can do its thing, while the rest wait.
//
// this interface is so would-be dialers can just:
//
//  for {
//  	c := findConnectionToPeer(peer)
//  	if c != nil {
//  		return c
//  	}
//
//  	// ok, no connections. should we dial?
//  	if ok, wait := dialsync.Lock(peer); !ok {
//  		<-wait // can optionally wait
//  		continue
//  	}
//  	defer dialsync.Unlock(peer)
//
//  	c := actuallyDial(peer)
//  	return c
//  }
//
type dialsync struct {
	// ongoing is a map of tickets for the current peers being dialed.
	// this way, we dont kick off N dials simultaneously.
	ongoing map[peer.ID]chan struct{}
	lock    sync.Mutex
}

// Lock governs the beginning of a dial attempt.
// If there are no ongoing dials, it returns true, and the client is now
// scheduled to dial. Every other goroutine that calls startDial -- with
//the same dst -- will block until client is done. The client MUST call
// ds.Unlock(p) when it is done, to unblock the other callers.
// The client is not reponsible for achieving a successful dial, only for
// reporting the end of the attempt (calling ds.Unlock(p)).
//
// see the example below `dialsync`
func (ds *dialsync) Lock(dst peer.ID) (bool, chan struct{}) {
	ds.lock.Lock()
	if ds.ongoing == nil { // init if not ready
		ds.ongoing = make(map[peer.ID]chan struct{})
	}
	wait, found := ds.ongoing[dst]
	if !found {
		ds.ongoing[dst] = make(chan struct{})
	}
	ds.lock.Unlock()

	if found {
		return false, wait
	}

	// ok! you're signed up to dial!
	return true, nil
}

// Unlock releases waiters to a dial attempt. see Lock.
// if Unlock(p) is called without calling Lock(p) first, Unlock panics.
func (ds *dialsync) Unlock(dst peer.ID) {
	ds.lock.Lock()
	wait, found := ds.ongoing[dst]
	if !found {
		panic("called dialDone with no ongoing dials to peer: " + dst.Pretty())
	}
	delete(ds.ongoing, dst) // remove ongoing dial
	close(wait)             // release everyone else
	ds.lock.Unlock()
}

// Dial connects to a peer.
//
// The idea is that the client of Swarm does not need to know what network
// the connection will happen over. Swarm can use whichever it choses.
// This allows us to use various transport protocols, do NAT traversal/relay,
// etc. to achive connection.
func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) {
	if p == s.local {
		return nil, errors.New("Attempted connection to self!")
	}

	// this loop is here because dials take time, and we should not be dialing
	// the same peer concurrently (silly waste). Additonally, it's structured
	// to check s.ConnectionsToPeer(p) _first_, and _between_ attempts because we
	// may have received an incoming connection! if so, we no longer must dial.
	//
	// During the dial attempts, we may be doing the dialing. if not, we wait.
	var err error
	var conn *Conn
	for i := 0; i < dialAttempts; i++ {
		// check if we already have an open connection first
		cs := s.ConnectionsToPeer(p)
		for _, conn = range cs {
			if conn != nil { // dump out the first one we find. (TODO pick better)
				return conn, nil
			}
		}

		// check if there's an ongoing dial to this peer
		if ok, wait := s.dsync.Lock(p); !ok {
			log.Debugf("swarm %s dialing %s -- waiting for ongoing dial", s.local, p)
			select {
			case <-wait: // wait for that dial to finish.
				continue // and see if it worked (loop), OR we got an incoming dial.
			case <-ctx.Done(): // or we may have to bail...
				return nil, ctx.Err()
			}
		}

		// ok, we have been charged to dial! let's do it.
		// if it succeeds, dial will add the conn to the swarm itself.
		log.Debugf("swarm %s dialing %s -- dial start", s.local, p)
		ctxT, _ := context.WithTimeout(ctx, DialTimeout)
		conn, err = s.dial(ctxT, p)
		s.dsync.Unlock(p)
		log.Debugf("swarm %s dialing %s -- dial end %s", s.local, p, conn)
		if err != nil {
			continue // ok, we failed. try again. (if loop is done, our error is output)
		}
		return conn, nil
	}
	if err == nil {
		err = fmt.Errorf("%s failed to dial %s after %d attempts", s.local, p, dialAttempts)
	}
	return nil, err
}

// dial is the actual swarm's dial logic, gated by Dial.
func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) {
	if p == s.local {
		return nil, errors.New("Attempted connection to self!")
	}

	sk := s.peers.PrivKey(s.local)
	if sk == nil {
		// may be fine for sk to be nil, just log a warning.
		log.Warning("Dial not given PrivateKey, so WILL NOT SECURE conn.")
	}

	// get our own addrs
	localAddrs := s.peers.Addresses(s.local)
	if len(localAddrs) == 0 {
		log.Debug("Dialing out with no local addresses.")
	}

	// get remote peer addrs
	remoteAddrs := s.peers.Addresses(p)
	// make sure we can use the addresses.
	remoteAddrs = addrutil.FilterUsableAddrs(remoteAddrs)
	// drop out any addrs that would just dial ourselves. use ListenAddresses
	// as that is a more authoritative view than localAddrs.
	ila, _ := InterfaceListenAddresses(s)
	remoteAddrs = addrutil.Subtract(remoteAddrs, ila)
	remoteAddrs = addrutil.Subtract(remoteAddrs, s.peers.Addresses(s.local))
	log.Debugf("%s swarm dialing %s -- remote:%s local:%s", s.local, p, remoteAddrs, s.ListenAddresses())
	if len(remoteAddrs) == 0 {
		return nil, errors.New("peer has no addresses")
	}

	// open connection to peer
	d := &conn.Dialer{
		LocalPeer:  s.local,
		LocalAddrs: localAddrs,
		PrivateKey: sk,
	}

	// try to get a connection to any addr
	connC, err := s.dialAddrs(ctx, d, p, remoteAddrs)
	if err != nil {
		return nil, err
	}

	// ok try to setup the new connection.
	swarmC, err := dialConnSetup(ctx, s, connC)
	if err != nil {
		log.Error("Dial newConnSetup failed. disconnecting.")
		log.Event(ctx, "dialFailureDisconnect", lgbl.NetConn(connC), lgbl.Error(err))
		connC.Close() // close the connection. didn't work out :(
		return nil, err
	}

	log.Event(ctx, "dial", p)
	return swarmC, nil
}

func (s *Swarm) dialAddrs(ctx context.Context, d *conn.Dialer, p peer.ID, remoteAddrs []ma.Multiaddr) (conn.Conn, error) {

	// try to connect to one of the peer's known addresses.
	// for simplicity, we do this sequentially.
	// A future commit will do this asynchronously.
	log.Debugf("%s swarm dialing %s %s", s.local, p, remoteAddrs)
	var err error
	for _, addr := range remoteAddrs {
		log.Debugf("%s swarm dialing %s %s", s.local, p, addr)
		var connC conn.Conn
		connC, err = d.Dial(ctx, addr, p)
		if err != nil {
			log.Info("%s --> %s dial attempt failed: %s", s.local, p, err)
			continue
		}

		// if the connection is not to whom we thought it would be...
		if connC.RemotePeer() != p {
			log.Infof("misdial to %s through %s (got %s)", p, addr, connC.RemotePeer())
			connC.Close()
			continue
		}

		// if the connection is to ourselves...
		// this can happen TONS when Loopback addrs are advertized.
		// (this should be caught by two checks above, but let's just make sure.)
		if connC.RemotePeer() == s.local {
			log.Infof("misdial to %s through %s", p, addr)
			connC.Close()
			continue
		}

		// success! we got one!
		return connC, nil
	}
	if err != nil {
		return nil, err
	}
	return nil, fmt.Errorf("failed to dial %s", p)
}

// dialConnSetup is the setup logic for a connection from the dial side. it
// needs to add the Conn to the StreamSwarm, then run newConnSetup
func dialConnSetup(ctx context.Context, s *Swarm, connC conn.Conn) (*Conn, error) {

	psC, err := s.swarm.AddConn(connC)
	if err != nil {
		// connC is closed by caller if we fail.
		return nil, fmt.Errorf("failed to add conn to ps.Swarm: %s", err)
	}

	// ok try to setup the new connection. (newConnSetup will add to group)
	swarmC, err := s.newConnSetup(ctx, psC)
	if err != nil {
		log.Error("Dial newConnSetup failed. disconnecting.")
		log.Event(ctx, "dialFailureDisconnect", lgbl.NetConn(connC), lgbl.Error(err))
		psC.Close() // we need to make sure psC is Closed.
		return nil, err
	}

	return swarmC, err
}
<commit_msg>p2p/net/swarm: dial timeout to 10s + dialer<commit_after>package swarm

import (
	"errors"
	"fmt"
	"net"
	"sync"
	"time"

	conn "github.com/jbenet/go-ipfs/p2p/net/conn"
	addrutil "github.com/jbenet/go-ipfs/p2p/net/swarm/addr"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
	manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
)

// dialAttempts governs how many times a goroutine will try to dial a given peer.
const dialAttempts = 3

// DialTimeout is the amount of time each dial attempt has. We can think about making
// this larger down the road, or putting more granular timeouts (i.e. within each
// subcomponent of Dial)
var DialTimeout time.Duration = time.Second * 10

// dialsync is a small object that helps manage ongoing dials.
// this way, if we receive many simultaneous dial requests, one
// can do its thing, while the rest wait.
//
// this interface is so would-be dialers can just:
//
//  for {
//  	c := findConnectionToPeer(peer)
//  	if c != nil {
//  		return c
//  	}
//
//  	// ok, no connections. should we dial?
//  	if ok, wait := dialsync.Lock(peer); !ok {
//  		<-wait // can optionally wait
//  		continue
//  	}
//  	defer dialsync.Unlock(peer)
//
//  	c := actuallyDial(peer)
//  	return c
//  }
//
type dialsync struct {
	// ongoing is a map of tickets for the current peers being dialed.
	// this way, we dont kick off N dials simultaneously.
	ongoing map[peer.ID]chan struct{}
	lock    sync.Mutex
}

// Lock governs the beginning of a dial attempt.
// If there are no ongoing dials, it returns true, and the client is now
// scheduled to dial. Every other goroutine that calls startDial -- with
//the same dst -- will block until client is done. The client MUST call
// ds.Unlock(p) when it is done, to unblock the other callers.
// The client is not reponsible for achieving a successful dial, only for
// reporting the end of the attempt (calling ds.Unlock(p)).
//
// see the example below `dialsync`
func (ds *dialsync) Lock(dst peer.ID) (bool, chan struct{}) {
	ds.lock.Lock()
	if ds.ongoing == nil { // init if not ready
		ds.ongoing = make(map[peer.ID]chan struct{})
	}
	wait, found := ds.ongoing[dst]
	if !found {
		ds.ongoing[dst] = make(chan struct{})
	}
	ds.lock.Unlock()

	if found {
		return false, wait
	}

	// ok! you're signed up to dial!
	return true, nil
}

// Unlock releases waiters to a dial attempt. see Lock.
// if Unlock(p) is called without calling Lock(p) first, Unlock panics.
func (ds *dialsync) Unlock(dst peer.ID) {
	ds.lock.Lock()
	wait, found := ds.ongoing[dst]
	if !found {
		panic("called dialDone with no ongoing dials to peer: " + dst.Pretty())
	}
	delete(ds.ongoing, dst) // remove ongoing dial
	close(wait)             // release everyone else
	ds.lock.Unlock()
}

// Dial connects to a peer.
//
// The idea is that the client of Swarm does not need to know what network
// the connection will happen over. Swarm can use whichever it choses.
// This allows us to use various transport protocols, do NAT traversal/relay,
// etc. to achive connection.
func (s *Swarm) Dial(ctx context.Context, p peer.ID) (*Conn, error) {
	if p == s.local {
		return nil, errors.New("Attempted connection to self!")
	}

	// this loop is here because dials take time, and we should not be dialing
	// the same peer concurrently (silly waste). Additonally, it's structured
	// to check s.ConnectionsToPeer(p) _first_, and _between_ attempts because we
	// may have received an incoming connection! if so, we no longer must dial.
	//
	// During the dial attempts, we may be doing the dialing. if not, we wait.
	var err error
	var conn *Conn
	for i := 0; i < dialAttempts; i++ {
		// check if we already have an open connection first
		cs := s.ConnectionsToPeer(p)
		for _, conn = range cs {
			if conn != nil { // dump out the first one we find. (TODO pick better)
				return conn, nil
			}
		}

		// check if there's an ongoing dial to this peer
		if ok, wait := s.dsync.Lock(p); !ok {
			log.Debugf("swarm %s dialing %s -- waiting for ongoing dial", s.local, p)
			select {
			case <-wait: // wait for that dial to finish.
				continue // and see if it worked (loop), OR we got an incoming dial.
			case <-ctx.Done(): // or we may have to bail...
				return nil, ctx.Err()
			}
		}

		// ok, we have been charged to dial! let's do it.
		// if it succeeds, dial will add the conn to the swarm itself.
		log.Debugf("swarm %s dialing %s -- dial start", s.local, p)
		ctxT, _ := context.WithTimeout(ctx, DialTimeout)
		conn, err = s.dial(ctxT, p)
		s.dsync.Unlock(p)
		log.Debugf("swarm %s dialing %s -- dial end %s", s.local, p, conn)
		if err != nil {
			continue // ok, we failed. try again. (if loop is done, our error is output)
		}
		return conn, nil
	}
	if err == nil {
		err = fmt.Errorf("%s failed to dial %s after %d attempts", s.local, p, dialAttempts)
	}
	return nil, err
}

// dial is the actual swarm's dial logic, gated by Dial.
func (s *Swarm) dial(ctx context.Context, p peer.ID) (*Conn, error) {
	if p == s.local {
		return nil, errors.New("Attempted connection to self!")
	}

	sk := s.peers.PrivKey(s.local)
	if sk == nil {
		// may be fine for sk to be nil, just log a warning.
		log.Warning("Dial not given PrivateKey, so WILL NOT SECURE conn.")
	}

	// get our own addrs
	localAddrs := s.peers.Addresses(s.local)
	if len(localAddrs) == 0 {
		log.Debug("Dialing out with no local addresses.")
	}

	// get remote peer addrs
	remoteAddrs := s.peers.Addresses(p)
	// make sure we can use the addresses.
	remoteAddrs = addrutil.FilterUsableAddrs(remoteAddrs)
	// drop out any addrs that would just dial ourselves. use ListenAddresses
	// as that is a more authoritative view than localAddrs.
	ila, _ := InterfaceListenAddresses(s)
	remoteAddrs = addrutil.Subtract(remoteAddrs, ila)
	remoteAddrs = addrutil.Subtract(remoteAddrs, s.peers.Addresses(s.local))
	log.Debugf("%s swarm dialing %s -- remote:%s local:%s", s.local, p, remoteAddrs, s.ListenAddresses())
	if len(remoteAddrs) == 0 {
		return nil, errors.New("peer has no addresses")
	}

	// open connection to peer
	d := &conn.Dialer{
		Dialer: manet.Dialer{
			Dialer: net.Dialer{
				Timeout: DialTimeout,
			},
		},
		LocalPeer:  s.local,
		LocalAddrs: localAddrs,
		PrivateKey: sk,
	}

	// try to get a connection to any addr
	connC, err := s.dialAddrs(ctx, d, p, remoteAddrs)
	if err != nil {
		return nil, err
	}

	// ok try to setup the new connection.
	swarmC, err := dialConnSetup(ctx, s, connC)
	if err != nil {
		log.Error("Dial newConnSetup failed. disconnecting.")
		log.Event(ctx, "dialFailureDisconnect", lgbl.NetConn(connC), lgbl.Error(err))
		connC.Close() // close the connection. didn't work out :(
		return nil, err
	}

	log.Event(ctx, "dial", p)
	return swarmC, nil
}

func (s *Swarm) dialAddrs(ctx context.Context, d *conn.Dialer, p peer.ID, remoteAddrs []ma.Multiaddr) (conn.Conn, error) {

	// try to connect to one of the peer's known addresses.
	// for simplicity, we do this sequentially.
	// A future commit will do this asynchronously.
	log.Debugf("%s swarm dialing %s %s", s.local, p, remoteAddrs)
	var err error
	for _, addr := range remoteAddrs {
		log.Debugf("%s swarm dialing %s %s", s.local, p, addr)
		var connC conn.Conn
		connC, err = d.Dial(ctx, addr, p)
		if err != nil {
			log.Info("%s --> %s dial attempt failed: %s", s.local, p, err)
			continue
		}

		// if the connection is not to whom we thought it would be...
		if connC.RemotePeer() != p {
			log.Infof("misdial to %s through %s (got %s)", p, addr, connC.RemotePeer())
			connC.Close()
			continue
		}

		// if the connection is to ourselves...
		// this can happen TONS when Loopback addrs are advertized.
		// (this should be caught by two checks above, but let's just make sure.)
		if connC.RemotePeer() == s.local {
			log.Infof("misdial to %s through %s", p, addr)
			connC.Close()
			continue
		}

		// success! we got one!
		return connC, nil
	}
	if err != nil {
		return nil, err
	}
	return nil, fmt.Errorf("failed to dial %s", p)
}

// dialConnSetup is the setup logic for a connection from the dial side. it
// needs to add the Conn to the StreamSwarm, then run newConnSetup
func dialConnSetup(ctx context.Context, s *Swarm, connC conn.Conn) (*Conn, error) {

	psC, err := s.swarm.AddConn(connC)
	if err != nil {
		// connC is closed by caller if we fail.
		return nil, fmt.Errorf("failed to add conn to ps.Swarm: %s", err)
	}

	// ok try to setup the new connection. (newConnSetup will add to group)
	swarmC, err := s.newConnSetup(ctx, psC)
	if err != nil {
		log.Error("Dial newConnSetup failed. disconnecting.")
		log.Event(ctx, "dialFailureDisconnect", lgbl.NetConn(connC), lgbl.Error(err))
		psC.Close() // we need to make sure psC is Closed.
		return nil, err
	}

	return swarmC, err
}
<|endoftext|>


<commit_before>package drivers

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/volume"
	"os"
	"strings"
)

const (
	EfsTemplateURI = "%s.%s.efs.%s.amazonaws.com"
)

type efsDriver struct {
	volumeDriver
	availzone string
	resolve   bool
	region    string
	resolver  *Resolver
	dnscache  map[string]string
}

func NewEFSDriver(root, az, nameserver string, resolve bool) efsDriver {

	d := efsDriver{
		volumeDriver: newVolumeDriver(root),
		resolve:      resolve,
		dnscache:     map[string]string{},
	}

	if resolve {
		d.resolver = NewResolver(nameserver)
	}
	md, err := fetchAWSMetaData()
	if err != nil {
		log.Fatalf("Error resolving AWS metadata: %s", err.Error())
		os.Exit(1)
	}
	d.region = md.Region
	if az == "" {
		d.availzone = md.AvailZone
	}
	return d
}

func (e efsDriver) Mount(r volume.MountRequest) volume.Response {
	e.m.Lock()
	defer e.m.Unlock()
	hostdir := mountpoint(e.root, r.Name)
	source := e.fixSource(r.Name, r.ID)

	if e.mountm.HasMount(r.Name) && e.mountm.Count(r.Name) > 0 {
		log.Infof("Using existing EFS volume mount: %s", hostdir)
		e.mountm.Increment(r.Name)
		return volume.Response{Mountpoint: hostdir}
	}

	log.Infof("Mounting EFS volume %s on %s", source, hostdir)

	if err := createDest(hostdir); err != nil {
		return volume.Response{Err: err.Error()}
	}

	if err := e.mountVolume(source, hostdir); err != nil {
		return volume.Response{Err: err.Error()}
	}
	e.mountm.Add(r.Name, hostdir)
	return volume.Response{Mountpoint: hostdir}
}

func (e efsDriver) Unmount(r volume.UnmountRequest) volume.Response {
	e.m.Lock()
	defer e.m.Unlock()
	hostdir := mountpoint(e.root, r.Name)
	source := e.fixSource(r.Name, r.ID)

	if e.mountm.HasMount(r.Name) {
		if e.mountm.Count(r.Name) > 1 {
			log.Infof("Skipping unmount for %s - in use by other containers", hostdir)
			e.mountm.Decrement(r.Name)
			return volume.Response{}
		}
		e.mountm.Decrement(r.Name)
	}

	log.Infof("Unmounting volume %s from %s", source, hostdir)

	if err := run(fmt.Sprintf("umount %s", hostdir)); err != nil {
		return volume.Response{Err: err.Error()}
	}

	e.mountm.DeleteIfNotManaged(r.Name)

	if err := os.RemoveAll(r.Name); err != nil {
		return volume.Response{Err: err.Error()}
	}

	return volume.Response{}
}

func (e efsDriver) fixSource(name, id string) string {
	if e.mountm.HasOption(name, ShareOpt) {
		name = e.mountm.GetOption(name, ShareOpt)
	}

	v := strings.Split(name, "/")
	uri := v[0]
	if e.resolve {
		uri = fmt.Sprintf(EfsTemplateURI, e.availzone, v[0], e.region)
		if i, ok := e.dnscache[uri]; ok {
			uri = i
		}

		log.Debugf("Attempting to resolve: %s", uri)
		if ip, err := e.resolver.Lookup(uri); err == nil {
			log.Debugf("Resolved Addresses: %s", ip)
			e.dnscache[uri] = ip
			uri = ip
		} else {
			log.Errorf("Error during resolve: %s", err.Error())
		}
	}
	v[0] = uri + ":"
	return strings.Join(v, "/")
}

func (e efsDriver) mountVolume(source, dest string) error {
	cmd := fmt.Sprintf("mount -t nfs4 -o nfsvers=4.1 %s %s", source, dest)
	log.Debugf("exec: %s\n", cmd)
	return run(cmd)
}
<commit_msg>EFS volume id extractor added for compatibility with docker-compose<commit_after>package drivers

import (
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/docker/go-plugins-helpers/volume"
	"os"
	"strings"
	"regexp"
)

const (
	EfsTemplateURI = "%s.%s.efs.%s.amazonaws.com"
)

type efsDriver struct {
	volumeDriver
	availzone string
	resolve   bool
	region    string
	resolver  *Resolver
	dnscache  map[string]string
}

func NewEFSDriver(root, az, nameserver string, resolve bool) efsDriver {

	d := efsDriver{
		volumeDriver: newVolumeDriver(root),
		resolve:      resolve,
		dnscache:     map[string]string{},
	}

	if resolve {
		d.resolver = NewResolver(nameserver)
	}
	md, err := fetchAWSMetaData()
	if err != nil {
		log.Fatalf("Error resolving AWS metadata: %s", err.Error())
		os.Exit(1)
	}
	d.region = md.Region
	if az == "" {
		d.availzone = md.AvailZone
	}
	return d
}

func (e efsDriver) Mount(r volume.MountRequest) volume.Response {
	e.m.Lock()
	defer e.m.Unlock()
	hostdir := mountpoint(e.root, r.Name)
	source := e.fixSource(r.Name, r.ID)

	if e.mountm.HasMount(r.Name) && e.mountm.Count(r.Name) > 0 {
		log.Infof("Using existing EFS volume mount: %s", hostdir)
		e.mountm.Increment(r.Name)
		return volume.Response{Mountpoint: hostdir}
	}

	log.Infof("Mounting EFS volume %s on %s", source, hostdir)

	if err := createDest(hostdir); err != nil {
		return volume.Response{Err: err.Error()}
	}

	if err := e.mountVolume(source, hostdir); err != nil {
		return volume.Response{Err: err.Error()}
	}
	e.mountm.Add(r.Name, hostdir)
	return volume.Response{Mountpoint: hostdir}
}

func (e efsDriver) Unmount(r volume.UnmountRequest) volume.Response {
	e.m.Lock()
	defer e.m.Unlock()
	hostdir := mountpoint(e.root, r.Name)
	source := e.fixSource(r.Name, r.ID)

	if e.mountm.HasMount(r.Name) {
		if e.mountm.Count(r.Name) > 1 {
			log.Infof("Skipping unmount for %s - in use by other containers", hostdir)
			e.mountm.Decrement(r.Name)
			return volume.Response{}
		}
		e.mountm.Decrement(r.Name)
	}

	log.Infof("Unmounting volume %s from %s", source, hostdir)

	if err := run(fmt.Sprintf("umount %s", hostdir)); err != nil {
		return volume.Response{Err: err.Error()}
	}

	e.mountm.DeleteIfNotManaged(r.Name)

	if err := os.RemoveAll(r.Name); err != nil {
		return volume.Response{Err: err.Error()}
	}

	return volume.Response{}
}

func (e efsDriver) fixSource(name, id string) string {
	reg, _ := regexp.Compile("(fs-[0-9a-f]+)$")
	name = reg.FindString(name)

	if e.mountm.HasOption(name, ShareOpt) {
		name = e.mountm.GetOption(name, ShareOpt)
	}

	v := strings.Split(name, "/")
	uri := v[0]
	if e.resolve {
		uri = fmt.Sprintf(EfsTemplateURI, e.availzone, v[0], e.region)
		if i, ok := e.dnscache[uri]; ok {
			uri = i
		}

		log.Debugf("Attempting to resolve: %s", uri)
		if ip, err := e.resolver.Lookup(uri); err == nil {
			log.Debugf("Resolved Addresses: %s", ip)
			e.dnscache[uri] = ip
			uri = ip
		} else {
			log.Errorf("Error during resolve: %s", err.Error())
		}
	}
	v[0] = uri + ":"
	return strings.Join(v, "/")
}

func (e efsDriver) mountVolume(source, dest string) error {
	cmd := fmt.Sprintf("mount -t nfs4 -o nfsvers=4.1 %s %s", source, dest)
	log.Debugf("exec: %s\n", cmd)
	return run(cmd)
}
<|endoftext|>


<commit_before>package main

import (
	"golang.org/x/net/context"
	"golang.org/x/net/websocket"
	"io"
	"log"
	"net/http"
	"time"
	"zenhack.net/go/sandstorm/grain"
	"zenhack.net/go/sandstorm/websession"
)

var mainPage = []byte(`<!doctype html>

		<title>Websocket echo server</title>

Connect to the echo server at:

`)

func main() {

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		w.Write(mainPage)
	})

	http.Handle("/connect", websocket.Handler(func(conn *websocket.Conn) {
		io.Copy(conn, conn)
	}))

	ctx := context.Background()
	_, err := grain.ConnectAPI(ctx, websession.FromHandler(ctx, http.DefaultServeMux))
	if err != nil {
		log.Fatalln(err)
	}
	<-ctx.Done()
}
<commit_msg>Remove unused import in websocket-echo example.<commit_after>package main

import (
	"golang.org/x/net/context"
	"golang.org/x/net/websocket"
	"io"
	"log"
	"net/http"
	"zenhack.net/go/sandstorm/grain"
	"zenhack.net/go/sandstorm/websession"
)

var mainPage = []byte(`<!doctype html>

		<title>Websocket echo server</title>

Connect to the echo server at:

`)

func main() {

	http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		w.Write(mainPage)
	})

	http.Handle("/connect", websocket.Handler(func(conn *websocket.Conn) {
		io.Copy(conn, conn)
	}))

	ctx := context.Background()
	_, err := grain.ConnectAPI(ctx, websession.FromHandler(ctx, http.DefaultServeMux))
	if err != nil {
		log.Fatalln(err)
	}
	<-ctx.Done()
}
<|endoftext|>