<commit_before>// Copyright 2018 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.

package vmbased

import (
	"fmt"
	"strings"

	"openpitrix.io/openpitrix/pkg/constants"
	"openpitrix.io/openpitrix/pkg/models"
	"openpitrix.io/openpitrix/pkg/pb/metadata/types"
	"openpitrix.io/openpitrix/pkg/pi"
	"openpitrix.io/openpitrix/pkg/util/jsonutil"
)

type Frontgate struct {
	*Frame
}

/*
cat /opt/openpitrix/conf/drone.conf
IMAGE="mysql:5.7"
MOUNT_POINT="/data"
FILE_NAME="frontgate.conf"
FILE_CONF={\\"id\\":\\"cln-abcdefgh\\",\\"listen_port\\":9111,\\"pilot_host\\":192.168.0.1,\\"pilot_port\\":9110}
*/
func (f *Frontgate) getUserDataValue(nodeId string) string {
	var result string
	clusterNode := f.ClusterWrapper.ClusterNodesWithKeyPairs[nodeId]
	role := clusterNode.Role
	if strings.HasSuffix(role, constants.ReplicaRoleSuffix) {
		role = string([]byte(role)[:len(role)-len(constants.ReplicaRoleSuffix)])
	}
	clusterRole, _ := f.ClusterWrapper.ClusterRoles[role]
	clusterCommon, _ := f.ClusterWrapper.ClusterCommons[role]
	mountPoint := clusterRole.MountPoint
	// Empty string can not be a parameter
	if len(mountPoint) == 0 {
		mountPoint = "#"
	}
	imageId := clusterCommon.ImageId

	frontgateConf := make(map[string]interface{})
	frontgateConf["id"] = f.ClusterWrapper.Cluster.ClusterId
	frontgateConf["node_id"] = nodeId
	frontgateConf["listen_port"] = constants.FrontgateServicePort
	frontgateConf["pilot_host"] = pi.Global().GlobalConfig().Pilot.Ip
	frontgateConf["pilot_port"] = constants.PilotServicePort
	frontgateConfStr := strings.Replace(jsonutil.ToString(frontgateConf), "\"", "\\\\\"", -1)

	result += fmt.Sprintf("IMAGE=\"%s\"\n", imageId)
	result += fmt.Sprintf("MOUNT_POINT=\"%s\"\n", mountPoint)
	result += fmt.Sprintf("FILE_NAME=\"%s\"\n", FrontgateConfFile)
	result += fmt.Sprintf("FILE_CONF=%s\n", frontgateConfStr)

	return result
}

func (f *Frame) pingFrontgateLayer(failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	task := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionPingFrontgate,
		Target:         constants.TargetPilot,
		NodeId:         f.ClusterWrapper.Cluster.ClusterId,
		Directive:      directive,
		FailureAllowed: failureAllowed,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, task)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) setFrontgateConfigLayer(nodeIds []string, failureAllowed bool) *models.TaskLayer {
	var tasks []*models.Task
	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	for _, nodeId := range nodeIds {
		// get frontgate config when pre task
		task := &models.Task{
			JobId:          f.Job.JobId,
			Owner:          f.Job.Owner,
			TaskAction:     ActionSetFrontgateConfig,
			Target:         constants.TargetPilot,
			NodeId:         nodeId,
			Directive:      directive,
			FailureAllowed: failureAllowed,
		}
		tasks = append(tasks, task)
	}
	return &models.TaskLayer{
		Tasks: tasks,
	}
}

func (f *Frontgate) removeContainerLayer(nodeIds []string, failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	for nodeId, clusterNode := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		ip := clusterNode.PrivateIp
		cmd := fmt.Sprintf("%s \"docker rm -f default\"", HostCmdPrefix)
		request := &pbtypes.RunCommandOnFrontgateRequest{
			Endpoint: &pbtypes.FrontgateEndpoint{
				FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
				FrontgateNodeId: nodeId,
				NodeIp:          ip,
				NodePort:        constants.FrontgateServicePort,
			},
			Command:        cmd,
			TimeoutSeconds: TimeoutRemoveContainer,
		}
		directive := jsonutil.ToString(request)
		formatVolumeTask := &models.Task{
			JobId:          f.Job.JobId,
			Owner:          f.Job.Owner,
			TaskAction:     ActionRemoveContainerOnFrontgate,
			Target:         constants.TargetPilot,
			NodeId:         nodeId,
			Directive:      directive,
			FailureAllowed: failureAllowed,
		}
		taskLayer.Tasks = append(taskLayer.Tasks, formatVolumeTask)
	}
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) CreateClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.createVolumesLayer(nodeIds, false)).        // create volume
		Append(f.runInstancesLayer(nodeIds, false)).         // run instance and attach volume to instance
		Append(f.pingFrontgateLayer(false)).                 // ping frontgate
		Append(f.formatAndMountVolumeLayer(nodeIds, false)). // format and mount volume to instance
		Append(f.removeContainerLayer(nodeIds, false)).      // remove default container
		Append(f.pingFrontgateLayer(false)).                 // ping frontgate
		Append(f.setFrontgateConfigLayer(nodeIds, false))    // set frontgate config

	return headTaskLayer.Child
}

func (f *Frontgate) DeleteClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	if f.ClusterWrapper.Cluster.Status == constants.StatusActive {
		headTaskLayer.
			Append(f.umountVolumeLayer(nodeIds, true)).  // umount volume from instance
			Append(f.stopInstancesLayer(nodeIds, true)). // stop instance
			Append(f.detachVolumesLayer(nodeIds, false)) // detach volume from instance
	}

	headTaskLayer.
		Append(f.deleteInstancesLayer(nodeIds, false)). // delete instance
		Append(f.deleteVolumesLayer(nodeIds, false))    // delete volume
	return headTaskLayer.Child
}

func (f *Frontgate) StartClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.attachVolumesLayer(false)).              // attach volume to instance, will auto mount
		Append(f.startInstancesLayer(false)).             // run instance and attach volume to instance
		Append(f.pingFrontgateLayer(false)).              // ping frontgate
		Append(f.setFrontgateConfigLayer(nodeIds, false)) // set frontgate config

	return headTaskLayer.Child
}

func (f *Frontgate) StopClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.umountVolumeLayer(nodeIds, true)).   // umount volume from instance
		Append(f.detachVolumesLayer(nodeIds, false)). // detach volume from instance
		Append(f.stopInstancesLayer(nodeIds, false))  // delete instance

	return headTaskLayer.Child
}
<commit_msg>Attach/Detach key pairs to frontgate node<commit_after>// Copyright 2018 The OpenPitrix Authors. All rights reserved.
// Use of this source code is governed by a Apache license
// that can be found in the LICENSE file.

package vmbased

import (
	"fmt"
	"strings"

	"openpitrix.io/openpitrix/pkg/constants"
	"openpitrix.io/openpitrix/pkg/models"
	"openpitrix.io/openpitrix/pkg/pb/metadata/types"
	"openpitrix.io/openpitrix/pkg/pi"
	"openpitrix.io/openpitrix/pkg/util/jsonutil"
	"openpitrix.io/openpitrix/pkg/util/sshutil"
)

type Frontgate struct {
	*Frame
}

/*
cat /opt/openpitrix/conf/drone.conf
IMAGE="mysql:5.7"
MOUNT_POINT="/data"
FILE_NAME="frontgate.conf"
FILE_CONF={\\"id\\":\\"cln-abcdefgh\\",\\"listen_port\\":9111,\\"pilot_host\\":192.168.0.1,\\"pilot_port\\":9110}
*/
func (f *Frontgate) getUserDataValue(nodeId string) string {
	var result string
	clusterNode := f.ClusterWrapper.ClusterNodesWithKeyPairs[nodeId]
	role := clusterNode.Role
	if strings.HasSuffix(role, constants.ReplicaRoleSuffix) {
		role = string([]byte(role)[:len(role)-len(constants.ReplicaRoleSuffix)])
	}
	clusterRole, _ := f.ClusterWrapper.ClusterRoles[role]
	clusterCommon, _ := f.ClusterWrapper.ClusterCommons[role]
	mountPoint := clusterRole.MountPoint
	// Empty string can not be a parameter
	if len(mountPoint) == 0 {
		mountPoint = "#"
	}
	imageId := clusterCommon.ImageId

	frontgateConf := make(map[string]interface{})
	frontgateConf["id"] = f.ClusterWrapper.Cluster.ClusterId
	frontgateConf["node_id"] = nodeId
	frontgateConf["listen_port"] = constants.FrontgateServicePort
	frontgateConf["pilot_host"] = pi.Global().GlobalConfig().Pilot.Ip
	frontgateConf["pilot_port"] = constants.PilotServicePort
	frontgateConfStr := strings.Replace(jsonutil.ToString(frontgateConf), "\"", "\\\\\"", -1)

	result += fmt.Sprintf("IMAGE=\"%s\"\n", imageId)
	result += fmt.Sprintf("MOUNT_POINT=\"%s\"\n", mountPoint)
	result += fmt.Sprintf("FILE_NAME=\"%s\"\n", FrontgateConfFile)
	result += fmt.Sprintf("FILE_CONF=%s\n", frontgateConfStr)

	return result
}

func (f *Frontgate) pingFrontgateLayer(failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	task := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionPingFrontgate,
		Target:         constants.TargetPilot,
		NodeId:         f.ClusterWrapper.Cluster.ClusterId,
		Directive:      directive,
		FailureAllowed: failureAllowed,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, task)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) setFrontgateConfigLayer(nodeIds []string, failureAllowed bool) *models.TaskLayer {
	var tasks []*models.Task
	directive := jsonutil.ToString(&models.Meta{
		ClusterId: f.ClusterWrapper.Cluster.ClusterId,
	})

	for _, nodeId := range nodeIds {
		// get frontgate config when pre task
		task := &models.Task{
			JobId:          f.Job.JobId,
			Owner:          f.Job.Owner,
			TaskAction:     ActionSetFrontgateConfig,
			Target:         constants.TargetPilot,
			NodeId:         nodeId,
			Directive:      directive,
			FailureAllowed: failureAllowed,
		}
		tasks = append(tasks, task)
	}
	return &models.TaskLayer{
		Tasks: tasks,
	}
}

func (f *Frontgate) removeContainerLayer(nodeIds []string, failureAllowed bool) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)

	for nodeId, clusterNode := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		ip := clusterNode.PrivateIp
		cmd := fmt.Sprintf("%s \"docker rm -f default\"", HostCmdPrefix)
		request := &pbtypes.RunCommandOnFrontgateRequest{
			Endpoint: &pbtypes.FrontgateEndpoint{
				FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
				FrontgateNodeId: nodeId,
				NodeIp:          ip,
				NodePort:        constants.FrontgateServicePort,
			},
			Command:        cmd,
			TimeoutSeconds: TimeoutRemoveContainer,
		}
		directive := jsonutil.ToString(request)
		formatVolumeTask := &models.Task{
			JobId:          f.Job.JobId,
			Owner:          f.Job.Owner,
			TaskAction:     ActionRemoveContainerOnFrontgate,
			Target:         constants.TargetPilot,
			NodeId:         nodeId,
			Directive:      directive,
			FailureAllowed: failureAllowed,
		}
		taskLayer.Tasks = append(taskLayer.Tasks, formatVolumeTask)
	}
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) attachKeyPairLayer(nodeKeyPairDetail *models.NodeKeyPairDetail) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)
	clusterNode := nodeKeyPairDetail.ClusterNode
	request := &pbtypes.RunCommandOnFrontgateRequest{
		Endpoint: &pbtypes.FrontgateEndpoint{
			FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
			FrontgateNodeId: clusterNode.NodeId,
			NodeIp:          clusterNode.PrivateIp,
			NodePort:        constants.FrontgateServicePort,
		},
		Command:        fmt.Sprintf("%s \"%s\"", HostCmdPrefix, sshutil.DoAttachCmd(nodeKeyPairDetail.KeyPair.PubKey)),
		TimeoutSeconds: TimeoutKeyPair,
	}
	directive := jsonutil.ToString(request)
	attachKeyPairTask := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionRunCommandOnFrontgateNode,
		Target:         constants.TargetPilot,
		NodeId:         clusterNode.NodeId,
		Directive:      directive,
		FailureAllowed: false,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, attachKeyPairTask)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) detachKeyPairLayer(nodeKeyPairDetail *models.NodeKeyPairDetail) *models.TaskLayer {
	taskLayer := new(models.TaskLayer)
	clusterNode := nodeKeyPairDetail.ClusterNode
	request := &pbtypes.RunCommandOnFrontgateRequest{
		Endpoint: &pbtypes.FrontgateEndpoint{
			FrontgateId:     f.ClusterWrapper.Cluster.ClusterId,
			FrontgateNodeId: clusterNode.NodeId,
			NodeIp:          clusterNode.PrivateIp,
			NodePort:        constants.FrontgateServicePort,
		},
		Command:        fmt.Sprintf("%s \"%s\"", HostCmdPrefix, sshutil.DoDetachCmd(nodeKeyPairDetail.KeyPair.PubKey)),
		TimeoutSeconds: TimeoutKeyPair,
	}
	directive := jsonutil.ToString(request)
	attachKeyPairTask := &models.Task{
		JobId:          f.Job.JobId,
		Owner:          f.Job.Owner,
		TaskAction:     ActionRunCommandOnFrontgateNode,
		Target:         constants.TargetPilot,
		NodeId:         clusterNode.NodeId,
		Directive:      directive,
		FailureAllowed: false,
	}
	taskLayer.Tasks = append(taskLayer.Tasks, attachKeyPairTask)
	if len(taskLayer.Tasks) > 0 {
		return taskLayer
	} else {
		return nil
	}
}

func (f *Frontgate) CreateClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.createVolumesLayer(nodeIds, false)).        // create volume
		Append(f.runInstancesLayer(nodeIds, false)).         // run instance and attach volume to instance
		Append(f.pingFrontgateLayer(false)).                 // ping frontgate
		Append(f.formatAndMountVolumeLayer(nodeIds, false)). // format and mount volume to instance
		Append(f.removeContainerLayer(nodeIds, false)).      // remove default container
		Append(f.pingFrontgateLayer(false)).                 // ping frontgate
		Append(f.setFrontgateConfigLayer(nodeIds, false))    // set frontgate config

	return headTaskLayer.Child
}

func (f *Frontgate) DeleteClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	if f.ClusterWrapper.Cluster.Status == constants.StatusActive {
		headTaskLayer.
			Append(f.umountVolumeLayer(nodeIds, true)).  // umount volume from instance
			Append(f.stopInstancesLayer(nodeIds, true)). // stop instance
			Append(f.detachVolumesLayer(nodeIds, false)) // detach volume from instance
	}

	headTaskLayer.
		Append(f.deleteInstancesLayer(nodeIds, false)). // delete instance
		Append(f.deleteVolumesLayer(nodeIds, false))    // delete volume
	return headTaskLayer.Child
}

func (f *Frontgate) StartClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.attachVolumesLayer(false)).              // attach volume to instance, will auto mount
		Append(f.startInstancesLayer(false)).             // run instance and attach volume to instance
		Append(f.pingFrontgateLayer(false)).              // ping frontgate
		Append(f.setFrontgateConfigLayer(nodeIds, false)) // set frontgate config

	return headTaskLayer.Child
}

func (f *Frontgate) StopClusterLayer() *models.TaskLayer {
	var nodeIds []string
	for nodeId := range f.ClusterWrapper.ClusterNodesWithKeyPairs {
		nodeIds = append(nodeIds, nodeId)
	}
	headTaskLayer := new(models.TaskLayer)

	headTaskLayer.
		Append(f.umountVolumeLayer(nodeIds, true)).   // umount volume from instance
		Append(f.detachVolumesLayer(nodeIds, false)). // detach volume from instance
		Append(f.stopInstancesLayer(nodeIds, false))  // delete instance

	return headTaskLayer.Child
}

func (f *Frontgate) AttachKeyPairsLayer(nodeKeyPairDetails models.NodeKeyPairDetails) *models.TaskLayer {
	headTaskLayer := new(models.TaskLayer)

	for _, nodeKeyPairDetail := range nodeKeyPairDetails {
		headTaskLayer.Append(f.attachKeyPairLayer(&nodeKeyPairDetail))
	}

	return headTaskLayer.Child
}

func (f *Frontgate) DetachKeyPairsLayer(nodeKeyPairDetails models.NodeKeyPairDetails) *models.TaskLayer {
	headTaskLayer := new(models.TaskLayer)

	for _, nodeKeyPairDetail := range nodeKeyPairDetails {
		headTaskLayer.Append(f.detachKeyPairLayer(&nodeKeyPairDetail))
	}

	return headTaskLayer.Child
}
<|endoftext|>


<commit_before>package driver

import (
	"fmt"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/jmoiron/sqlx"
	"github.com/olekukonko/tablewriter"
	migrate "github.com/rubenv/sql-migrate"

	"github.com/ory/hydra/client"
	"github.com/ory/hydra/consent"
	"github.com/ory/hydra/jwk"
	"github.com/ory/hydra/oauth2"
	"github.com/ory/hydra/x"
	"github.com/ory/x/dbal"
	"github.com/ory/x/sqlcon"
	"github.com/ory/x/urlx"
)

type RegistrySQL struct {
	*RegistryBase
	db          *sqlx.DB
	dbalOptions []sqlcon.OptionModifier
}

var _ Registry = new(RegistrySQL)

var multiSpace = regexp.MustCompile("\\s+")

func init() {
	dbal.RegisterDriver(NewRegistrySQL())
}

type schemaCreator interface {
	CreateSchemas(dbName string) (int, error)
	PlanMigration(dbName string) ([]*migrate.PlannedMigration, error)
}

func NewRegistrySQL() *RegistrySQL {
	r := &RegistrySQL{
		RegistryBase: new(RegistryBase),
	}
	r.RegistryBase.with(r)
	return r
}

func (m *RegistrySQL) WithDB(db *sqlx.DB) Registry {
	m.db = db
	return m
}

func (m *RegistrySQL) Init() error {
	if m.db != nil {
		return nil
	}

	options := append([]sqlcon.OptionModifier{}, m.dbalOptions...)
	if m.Tracer().IsLoaded() {
		options = append(options, sqlcon.WithDistributedTracing(), sqlcon.WithOmitArgsFromTraceSpans())
	}

	connection, err := sqlcon.NewSQLConnection(m.c.DSN(), m.Logger(), options...)
	if err != nil {
		return err
	}

	m.db, err = connection.GetDatabaseRetry(time.Second*5, time.Minute*5)
	if err != nil {
		return err
	}

	return err
}

func (m *RegistrySQL) DB() *sqlx.DB {
	if m.db == nil {
		if err := m.Init(); err != nil {
			m.Logger().WithError(err).Fatalf("Unable to initialize database.")
		}
	}

	return m.db
}

func (m *RegistrySQL) SchemaMigrationPlan(dbName string) (*tablewriter.Table, error) {
	names := map[int]string{
		0: "JSON Web Keys",
		1: "OAuth 2.0 Clients",
		2: "Login &Consent",
		3: "OAuth 2.0",
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
	table.SetCenterSeparator("|")
	table.SetAutoMergeCells(true)
	table.SetRowLine(true)
	table.SetColMinWidth(4, 20)
	table.SetHeader([]string{
		"Driver",
		"Module",
		"ID",
		"#",
		"Query",
	})

	for _, s := range []schemaCreator{
		m.KeyManager().(schemaCreator),
		m.ClientManager().(schemaCreator),
		m.ConsentManager().(schemaCreator),
		m.OAuth2Storage().(schemaCreator),
	} {
		plans, err := s.PlanMigration(dbName)
		if err != nil {
			return nil, err
		}

		for _, plan := range plans {
			for k, up := range plan.Up {
				up = strings.Replace("\n", "", strings.TrimSpace(up), -1)
				up = strings.Join(strings.Fields(up), " ")
				if len(up) > 0 {
					table.Append([]string{m.db.DriverName(), names[k], plan.Id + ".sql", fmt.Sprintf("%d", k), up})
				}
			}
		}
	}

	return table, nil
}

func (m *RegistrySQL) CreateSchemas(dbName string) (int, error) {
	var total int

	m.Logger().Debugf("Applying %s SQL migrations...", dbName)
	for k, s := range []schemaCreator{
		m.KeyManager().(schemaCreator),
		m.ClientManager().(schemaCreator),
		m.ConsentManager().(schemaCreator),
		m.OAuth2Storage().(schemaCreator),
	} {
		m.Logger().Debugf("Applying %s SQL migrations for manager: %T (%d)", dbName, s, k)
		if c, err := s.CreateSchemas(dbName); err != nil {
			return c, err
		} else {
			m.Logger().Debugf("Successfully applied %d %s SQL migrations from manager: %T (%d)", c, dbName, s, k)
			total += c
		}
	}
	m.Logger().Debugf("Applied %d %s SQL migrations", total, dbName)

	return total, nil
}

func (m *RegistrySQL) CanHandle(dsn string) bool {
	s := dbal.Canonicalize(urlx.ParseOrFatal(m.l, dsn).Scheme)
	return s == dbal.DriverMySQL || s == dbal.DriverPostgreSQL || s == dbal.DriverCockroachDB
}

func (m *RegistrySQL) Ping() error {
	return m.DB().Ping()
}

func (m *RegistrySQL) ClientManager() client.Manager {
	if m.cm == nil {
		m.cm = client.NewSQLManager(m.DB(), m)
	}
	return m.cm
}

func (m *RegistrySQL) ConsentManager() consent.Manager {
	if m.com == nil {
		m.com = consent.NewSQLManager(m.DB(), m)
	}
	return m.com
}

func (m *RegistrySQL) OAuth2Storage() x.FositeStorer {
	if m.fs == nil {
		m.fs = oauth2.NewFositeSQLStore(m.DB(), m.r, m.c)
	}
	return m.fs
}

func (m *RegistrySQL) KeyManager() jwk.Manager {
	if m.km == nil {
		m.km = jwk.NewSQLManager(m.DB(), m)
	}
	return m.km
}
<commit_msg>driver: Fix migration plan output (#1504)<commit_after>package driver

import (
	"fmt"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/jmoiron/sqlx"
	"github.com/olekukonko/tablewriter"
	migrate "github.com/rubenv/sql-migrate"

	"github.com/ory/x/dbal"
	"github.com/ory/x/sqlcon"
	"github.com/ory/x/urlx"

	"github.com/ory/hydra/client"
	"github.com/ory/hydra/consent"
	"github.com/ory/hydra/jwk"
	"github.com/ory/hydra/oauth2"
	"github.com/ory/hydra/x"
)

type RegistrySQL struct {
	*RegistryBase
	db          *sqlx.DB
	dbalOptions []sqlcon.OptionModifier
}

var _ Registry = new(RegistrySQL)

var multiSpace = regexp.MustCompile("\\s+")

func init() {
	dbal.RegisterDriver(NewRegistrySQL())
}

type schemaCreator interface {
	CreateSchemas(dbName string) (int, error)
	PlanMigration(dbName string) ([]*migrate.PlannedMigration, error)
}

func NewRegistrySQL() *RegistrySQL {
	r := &RegistrySQL{
		RegistryBase: new(RegistryBase),
	}
	r.RegistryBase.with(r)
	return r
}

func (m *RegistrySQL) WithDB(db *sqlx.DB) Registry {
	m.db = db
	return m
}

func (m *RegistrySQL) Init() error {
	if m.db != nil {
		return nil
	}

	options := append([]sqlcon.OptionModifier{}, m.dbalOptions...)
	if m.Tracer().IsLoaded() {
		options = append(options, sqlcon.WithDistributedTracing(), sqlcon.WithOmitArgsFromTraceSpans())
	}

	connection, err := sqlcon.NewSQLConnection(m.c.DSN(), m.Logger(), options...)
	if err != nil {
		return err
	}

	m.db, err = connection.GetDatabaseRetry(time.Second*5, time.Minute*5)
	if err != nil {
		return err
	}

	return err
}

func (m *RegistrySQL) DB() *sqlx.DB {
	if m.db == nil {
		if err := m.Init(); err != nil {
			m.Logger().WithError(err).Fatalf("Unable to initialize database.")
		}
	}

	return m.db
}

func (m *RegistrySQL) SchemaMigrationPlan(dbName string) (*tablewriter.Table, error) {
	names := map[int]string{
		0: "JSON Web Keys",
		1: "OAuth 2.0 Clients",
		2: "Login &Consent",
		3: "OAuth 2.0",
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
	table.SetCenterSeparator("|")
	table.SetAutoMergeCells(true)
	table.SetRowLine(true)
	table.SetColMinWidth(4, 20)
	table.SetHeader([]string{
		"Driver",
		"Module",
		"ID",
		"#",
		"Query",
	})

	for component, s := range []schemaCreator{
		m.KeyManager().(schemaCreator),
		m.ClientManager().(schemaCreator),
		m.ConsentManager().(schemaCreator),
		m.OAuth2Storage().(schemaCreator),
	} {
		plans, err := s.PlanMigration(dbName)
		if err != nil {
			return nil, err
		}

		for _, plan := range plans {
			for k, up := range plan.Up {
				up = strings.Replace(strings.TrimSpace(up), "\n", "", -1)
				up = strings.Join(strings.Fields(up), " ")
				if len(up) > 0 {
					table.Append([]string{m.db.DriverName(), names[component], plan.Id + ".sql", fmt.Sprintf("%d", k), up})
				}
			}
		}
	}

	return table, nil
}

func (m *RegistrySQL) CreateSchemas(dbName string) (int, error) {
	var total int

	m.Logger().Debugf("Applying %s SQL migrations...", dbName)
	for k, s := range []schemaCreator{
		m.KeyManager().(schemaCreator),
		m.ClientManager().(schemaCreator),
		m.ConsentManager().(schemaCreator),
		m.OAuth2Storage().(schemaCreator),
	} {
		m.Logger().Debugf("Applying %s SQL migrations for manager: %T (%d)", dbName, s, k)
		if c, err := s.CreateSchemas(dbName); err != nil {
			return c, err
		} else {
			m.Logger().Debugf("Successfully applied %d %s SQL migrations from manager: %T (%d)", c, dbName, s, k)
			total += c
		}
	}
	m.Logger().Debugf("Applied %d %s SQL migrations", total, dbName)

	return total, nil
}

func (m *RegistrySQL) CanHandle(dsn string) bool {
	s := dbal.Canonicalize(urlx.ParseOrFatal(m.l, dsn).Scheme)
	return s == dbal.DriverMySQL || s == dbal.DriverPostgreSQL || s == dbal.DriverCockroachDB
}

func (m *RegistrySQL) Ping() error {
	return m.DB().Ping()
}

func (m *RegistrySQL) ClientManager() client.Manager {
	if m.cm == nil {
		m.cm = client.NewSQLManager(m.DB(), m)
	}
	return m.cm
}

func (m *RegistrySQL) ConsentManager() consent.Manager {
	if m.com == nil {
		m.com = consent.NewSQLManager(m.DB(), m)
	}
	return m.com
}

func (m *RegistrySQL) OAuth2Storage() x.FositeStorer {
	if m.fs == nil {
		m.fs = oauth2.NewFositeSQLStore(m.DB(), m.r, m.c)
	}
	return m.fs
}

func (m *RegistrySQL) KeyManager() jwk.Manager {
	if m.km == nil {
		m.km = jwk.NewSQLManager(m.DB(), m)
	}
	return m.km
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Skaffold 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 trigger

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"sync/atomic"
	"time"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/color"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
	"github.com/rjeczalik/notify"
	"github.com/sirupsen/logrus"
)

// Trigger describes a mechanism that triggers the watch.
type Trigger interface {
	Start(context.Context) (<-chan bool, error)
	LogWatchToUser(io.Writer)
	Debounce() bool
}

// NewTrigger creates a new trigger.
func NewTrigger(runctx *runcontext.RunContext) (Trigger, error) {
	switch strings.ToLower(runctx.Opts.Trigger) {
	case "polling":
		return &pollTrigger{
			Interval: time.Duration(runctx.Opts.WatchPollInterval) * time.Millisecond,
		}, nil
	case "notify":
		return newFSNotifyTrigger(runctx)
	case "manual":
		return &manualTrigger{}, nil
	default:
		return nil, fmt.Errorf("unsupported trigger: %s", runctx.Opts.Trigger)
	}
}

func newFSNotifyTrigger(runctx *runcontext.RunContext) (*fsNotifyTrigger, error) {
	workspaces := map[string]struct{}{}
	for _, a := range runctx.Cfg.Build.Artifacts {
		workspaces[a.Workspace] = struct{}{}
	}
	return &fsNotifyTrigger{
		Interval:   time.Duration(runctx.Opts.WatchPollInterval) * time.Millisecond,
		workspaces: workspaces,
	}, nil
}

// pollTrigger watches for changes on a given interval of time.
type pollTrigger struct {
	Interval time.Duration
}

// Debounce tells the watcher to debounce rapid sequence of changes.
func (t *pollTrigger) Debounce() bool {
	return true
}

func (t *pollTrigger) LogWatchToUser(out io.Writer) {
	color.Yellow.Fprintf(out, "Watching for changes every %v...\n", t.Interval)
}

// Start starts a timer.
func (t *pollTrigger) Start(ctx context.Context) (<-chan bool, error) {
	trigger := make(chan bool)

	ticker := time.NewTicker(t.Interval)
	go func() {
		for {
			select {
			case <-ticker.C:
				trigger <- true
			case <-ctx.Done():
				ticker.Stop()
				return
			}
		}
	}()

	return trigger, nil
}

// manualTrigger watches for changes when the user presses a key.
type manualTrigger struct{}

// Debounce tells the watcher to not debounce rapid sequence of changes.
func (t *manualTrigger) Debounce() bool {
	return false
}

func (t *manualTrigger) LogWatchToUser(out io.Writer) {
	color.Yellow.Fprintln(out, "Press any key to rebuild/redeploy the changes")
}

// Start starts listening to pressed keys.
func (t *manualTrigger) Start(ctx context.Context) (<-chan bool, error) {
	trigger := make(chan bool)

	var stopped int32
	go func() {
		<-ctx.Done()
		atomic.StoreInt32(&stopped, 1)
	}()

	reader := bufio.NewReader(os.Stdin)
	go func() {
		for {
			_, _, err := reader.ReadRune()
			if err != nil {
				logrus.Debugf("manual trigger error: %s", err)
			}

			// Wait until the context is cancelled.
			if atomic.LoadInt32(&stopped) == 1 {
				return
			}
			trigger <- true
		}
	}()

	return trigger, nil
}

// notifyTrigger watches for changes with fsnotify
type fsNotifyTrigger struct {
	Interval   time.Duration
	workspaces map[string]struct{}
}

// Debounce tells the watcher to not debounce rapid sequence of changes.
func (t *fsNotifyTrigger) Debounce() bool {
	// This trigger has built-in debouncing.
	return false
}

func (t *fsNotifyTrigger) LogWatchToUser(out io.Writer) {
	color.Yellow.Fprintln(out, "Watching for changes...")
}

// Start listening for file system changes
func (t *fsNotifyTrigger) Start(ctx context.Context) (<-chan bool, error) {
	c := make(chan notify.EventInfo, 100)

	// Watch current directory recursively
	if err := notify.Watch("./...", c, notify.All); err != nil {
		return nil, err
	}

	// Watch all workspaces recursively
	for w := range t.workspaces {
		if err := notify.Watch(filepath.Join(w, "..."), c, notify.All); err != nil {
			return nil, err
		}
	}

	// Since the file watcher runs in a separate go routine
	// and can take some time to start, it can lose the very first change.
	// As a mitigation, we act as if a change was detected.
	go func() { c <- nil }()

	trigger := make(chan bool)
	go func() {
		timer := time.NewTimer(1<<63 - 1) // Forever

		for {
			select {
			case e := <-c:
				logrus.Debugln("Change detected", e)

				// Wait t.interval before triggering.
				// This way, rapid stream of events will be grouped.
				timer.Reset(t.Interval)
			case <-timer.C:
				trigger <- true
			case <-ctx.Done():
				timer.Stop()
				return
			}
		}
	}()

	return trigger, nil
}

// StartTrigger attempts to start a trigger.
// It will attempt to start as a polling trigger if it tried unsuccessfully to start a notify trigger.
func StartTrigger(ctx context.Context, t Trigger) (<-chan bool, error) {
	ret, err := t.Start(ctx)
	if err == nil {
		return ret, err
	}
	if notifyTrigger, ok := t.(*fsNotifyTrigger); ok {
		logrus.Debugln("Couldn't start notify trigger. Falling back to a polling trigger")

		t = &pollTrigger{
			Interval: notifyTrigger.Interval,
		}
		ret, err = t.Start(ctx)
	}

	return ret, err
}
<commit_msg>fix lint<commit_after>/*
Copyright 2019 The Skaffold 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 trigger

import (
	"bufio"
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"sync/atomic"
	"time"

	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/color"
	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/runner/runcontext"
	"github.com/rjeczalik/notify"
	"github.com/sirupsen/logrus"
)

// Trigger describes a mechanism that triggers the watch.
type Trigger interface {
	Start(context.Context) (<-chan bool, error)
	LogWatchToUser(io.Writer)
	Debounce() bool
}

// NewTrigger creates a new trigger.
func NewTrigger(runctx *runcontext.RunContext) (Trigger, error) {
	switch strings.ToLower(runctx.Opts.Trigger) {
	case "polling":
		return &pollTrigger{
			Interval: time.Duration(runctx.Opts.WatchPollInterval) * time.Millisecond,
		}, nil
	case "notify":
		return newFSNotifyTrigger(runctx), nil
	case "manual":
		return &manualTrigger{}, nil
	default:
		return nil, fmt.Errorf("unsupported trigger: %s", runctx.Opts.Trigger)
	}
}

func newFSNotifyTrigger(runctx *runcontext.RunContext) *fsNotifyTrigger {
	workspaces := map[string]struct{}{}
	for _, a := range runctx.Cfg.Build.Artifacts {
		workspaces[a.Workspace] = struct{}{}
	}
	return &fsNotifyTrigger{
		Interval:   time.Duration(runctx.Opts.WatchPollInterval) * time.Millisecond,
		workspaces: workspaces,
	}
}

// pollTrigger watches for changes on a given interval of time.
type pollTrigger struct {
	Interval time.Duration
}

// Debounce tells the watcher to debounce rapid sequence of changes.
func (t *pollTrigger) Debounce() bool {
	return true
}

func (t *pollTrigger) LogWatchToUser(out io.Writer) {
	color.Yellow.Fprintf(out, "Watching for changes every %v...\n", t.Interval)
}

// Start starts a timer.
func (t *pollTrigger) Start(ctx context.Context) (<-chan bool, error) {
	trigger := make(chan bool)

	ticker := time.NewTicker(t.Interval)
	go func() {
		for {
			select {
			case <-ticker.C:
				trigger <- true
			case <-ctx.Done():
				ticker.Stop()
				return
			}
		}
	}()

	return trigger, nil
}

// manualTrigger watches for changes when the user presses a key.
type manualTrigger struct{}

// Debounce tells the watcher to not debounce rapid sequence of changes.
func (t *manualTrigger) Debounce() bool {
	return false
}

func (t *manualTrigger) LogWatchToUser(out io.Writer) {
	color.Yellow.Fprintln(out, "Press any key to rebuild/redeploy the changes")
}

// Start starts listening to pressed keys.
func (t *manualTrigger) Start(ctx context.Context) (<-chan bool, error) {
	trigger := make(chan bool)

	var stopped int32
	go func() {
		<-ctx.Done()
		atomic.StoreInt32(&stopped, 1)
	}()

	reader := bufio.NewReader(os.Stdin)
	go func() {
		for {
			_, _, err := reader.ReadRune()
			if err != nil {
				logrus.Debugf("manual trigger error: %s", err)
			}

			// Wait until the context is cancelled.
			if atomic.LoadInt32(&stopped) == 1 {
				return
			}
			trigger <- true
		}
	}()

	return trigger, nil
}

// notifyTrigger watches for changes with fsnotify
type fsNotifyTrigger struct {
	Interval   time.Duration
	workspaces map[string]struct{}
}

// Debounce tells the watcher to not debounce rapid sequence of changes.
func (t *fsNotifyTrigger) Debounce() bool {
	// This trigger has built-in debouncing.
	return false
}

func (t *fsNotifyTrigger) LogWatchToUser(out io.Writer) {
	color.Yellow.Fprintln(out, "Watching for changes...")
}

// Start listening for file system changes
func (t *fsNotifyTrigger) Start(ctx context.Context) (<-chan bool, error) {
	c := make(chan notify.EventInfo, 100)

	// Watch current directory recursively
	if err := notify.Watch("./...", c, notify.All); err != nil {
		return nil, err
	}

	// Watch all workspaces recursively
	for w := range t.workspaces {
		if err := notify.Watch(filepath.Join(w, "..."), c, notify.All); err != nil {
			return nil, err
		}
	}

	// Since the file watcher runs in a separate go routine
	// and can take some time to start, it can lose the very first change.
	// As a mitigation, we act as if a change was detected.
	go func() { c <- nil }()

	trigger := make(chan bool)
	go func() {
		timer := time.NewTimer(1<<63 - 1) // Forever

		for {
			select {
			case e := <-c:
				logrus.Debugln("Change detected", e)

				// Wait t.interval before triggering.
				// This way, rapid stream of events will be grouped.
				timer.Reset(t.Interval)
			case <-timer.C:
				trigger <- true
			case <-ctx.Done():
				timer.Stop()
				return
			}
		}
	}()

	return trigger, nil
}

// StartTrigger attempts to start a trigger.
// It will attempt to start as a polling trigger if it tried unsuccessfully to start a notify trigger.
func StartTrigger(ctx context.Context, t Trigger) (<-chan bool, error) {
	ret, err := t.Start(ctx)
	if err == nil {
		return ret, err
	}
	if notifyTrigger, ok := t.(*fsNotifyTrigger); ok {
		logrus.Debugln("Couldn't start notify trigger. Falling back to a polling trigger")

		t = &pollTrigger{
			Interval: notifyTrigger.Interval,
		}
		ret, err = t.Start(ctx)
	}

	return ret, err
}
<|endoftext|>


<commit_before>package prometheus

import (
	"fmt"
	"runtime"
	"runtime/debug"
	"time"
)

type goCollector struct {
	goroutines Gauge
	gcDesc     *Desc

	memstats *memStatCollector
}

// NewGoCollector returns a collector which exports metrics about the current
// go process.
func NewGoCollector() *goCollector {
	return &goCollector{
		goroutines: NewGauge(GaugeOpts{
			Namespace: "go",
			Name:      "goroutines",
			Help:      "Number of goroutines that currently exist.",
		}),
		gcDesc: NewDesc(
			"go_gc_duration_seconds",
			"A summary of the GC invocation durations.",
			nil, nil),
		memstats: &memStatCollector{
			ms: new(runtime.MemStats),
			metrics: memStatsMetrics{
				{
					desc: NewDesc(
						memstatNamespace("alloc_bytes"),
						"Number of bytes allocated and still in use.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("alloc_bytes_total"),
						"Total number of bytes allocated, even if freed.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
					valType: CounterValue,
				}, {
					desc: NewDesc(
						memstatNamespace("sys_bytes"),
						"Number of bytes obtained from system",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
					valType: CounterValue,
				}, {
					desc: NewDesc(
						memstatNamespace("lookups_total"),
						"Total number of pointer lookups.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
					valType: CounterValue,
				}, {
					desc: NewDesc(
						memstatNamespace("mallocs_total"),
						"Total number of mallocs.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
					valType: CounterValue,
				}, {
					desc: NewDesc(
						memstatNamespace("frees_total"),
						"Total number of frees.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
					valType: CounterValue,
				}, {
					desc: NewDesc(
						memstatNamespace("heap_alloc_bytes"),
						"Number heap bytes allocated and still in use.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("heap_sys_bytes"),
						"Total bytes in heap obtained from system.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("heap_idle_bytes"),
						"Number bytes in heap waiting to be used.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("heap_inuse_bytes"),
						"Number of bytes in heap that are in use.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("heap_released_bytes"),
						"Number of bytes in heap released to OS.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("heap_objects"),
						"Number of allocated objects.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("stack_bytes_inuse"),
						"Number of bytes in use by the stack allocator.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("stack_sys_bytes"),
						"Number of bytes in obtained from system for stack allocator.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("mspan_inuse"),
						"Number of mspan structures in use.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("mspan_sys"),
						"Number of mspan structures obtained from system.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("mcache_inuse"),
						"Number of mcache structures in use.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("mcache_sys"),
						"Number of mcache structures obtained from system.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("buck_hash_sys"),
						"Profiling bucket hash table.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("gc_metadata"),
						"GC metadata.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("other_sys"),
						"Other system allocations.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("next_gc"),
						"Next collection will happen when HeapAlloc ≥ this amount.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
					valType: GaugeValue,
				}, {
					desc: NewDesc(
						memstatNamespace("last_gc"),
						"End time of last garbage collection (nanoseconds since 1970).",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) },
					valType: CounterValue,
				}, {
					desc: NewDesc(
						memstatNamespace("pause_total"),
						"Total garbage collection pauses for all collections.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.PauseTotalNs) },
					valType: CounterValue,
				}, {
					desc: NewDesc(
						memstatNamespace("gc_total"),
						"Number of garbage collection.",
						nil, nil,
					),
					eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NumGC) },
					valType: CounterValue,
				},
			},
		},
	}
}

func memstatNamespace(s string) string {
	return fmt.Sprintf("go_memstats_%s", s)
}

// Describe returns all descriptions of the collector.
func (c *goCollector) Describe(ch chan<- *Desc) {
	ch <- c.goroutines.Desc()
	ch <- c.gcDesc

	c.memstats.Describe(ch)
}

// Collect returns the current state of all metrics of the collector.
func (c *goCollector) Collect(ch chan<- Metric) {
	c.goroutines.Set(float64(runtime.NumGoroutine()))
	ch <- c.goroutines

	var stats debug.GCStats
	stats.PauseQuantiles = make([]time.Duration, 5)
	debug.ReadGCStats(&stats)

	quantiles := make(map[float64]float64)
	for idx, pq := range stats.PauseQuantiles[1:] {
		quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds()
	}
	quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
	ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles)

	c.memstats.Collect(ch)
}

// metrics that provide description, value, and value type for memstat metrics
type memStatsMetrics []struct {
	desc    *Desc
	eval    func(*runtime.MemStats) float64
	valType ValueType
}

type memStatCollector struct {
	// memstats object to reuse
	ms *runtime.MemStats
	// metrics to describe and collect
	metrics memStatsMetrics
}

func (c *memStatCollector) Describe(ch chan<- *Desc) {
	for _, i := range c.metrics {
		ch <- i.desc
	}
}

func (c *memStatCollector) Collect(ch chan<- Metric) {
	runtime.ReadMemStats(c.ms)
	for _, i := range c.metrics {
		ch <- MustNewConstMetric(i.desc, i.valType, i.eval(c.ms))
	}
}
<commit_msg>unembed memstats collector<commit_after>package prometheus

import (
	"fmt"
	"runtime"
	"runtime/debug"
	"time"
)

type goCollector struct {
	goroutines Gauge
	gcDesc     *Desc

	// memstats object to reuse
	ms *runtime.MemStats
	// metrics to describe and collect
	metrics memStatsMetrics
}

// NewGoCollector returns a collector which exports metrics about the current
// go process.
func NewGoCollector() *goCollector {
	return &goCollector{
		ms: new(runtime.MemStats),
		goroutines: NewGauge(GaugeOpts{
			Namespace: "go",
			Name:      "goroutines",
			Help:      "Number of goroutines that currently exist.",
		}),
		gcDesc: NewDesc(
			"go_gc_duration_seconds",
			"A summary of the GC invocation durations.",
			nil, nil),
		metrics: memStatsMetrics{
			{
				desc: NewDesc(
					memstatNamespace("alloc_bytes"),
					"Number of bytes allocated and still in use.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Alloc) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("alloc_bytes_total"),
					"Total number of bytes allocated, even if freed.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.TotalAlloc) },
				valType: CounterValue,
			}, {
				desc: NewDesc(
					memstatNamespace("sys_bytes"),
					"Number of bytes obtained from system",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Sys) },
				valType: CounterValue,
			}, {
				desc: NewDesc(
					memstatNamespace("lookups_total"),
					"Total number of pointer lookups.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Lookups) },
				valType: CounterValue,
			}, {
				desc: NewDesc(
					memstatNamespace("mallocs_total"),
					"Total number of mallocs.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Mallocs) },
				valType: CounterValue,
			}, {
				desc: NewDesc(
					memstatNamespace("frees_total"),
					"Total number of frees.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.Frees) },
				valType: CounterValue,
			}, {
				desc: NewDesc(
					memstatNamespace("heap_alloc_bytes"),
					"Number heap bytes allocated and still in use.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapAlloc) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("heap_sys_bytes"),
					"Total bytes in heap obtained from system.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapSys) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("heap_idle_bytes"),
					"Number bytes in heap waiting to be used.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapIdle) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("heap_inuse_bytes"),
					"Number of bytes in heap that are in use.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapInuse) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("heap_released_bytes"),
					"Number of bytes in heap released to OS.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapReleased) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("heap_objects"),
					"Number of allocated objects.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.HeapObjects) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("stack_bytes_inuse"),
					"Number of bytes in use by the stack allocator.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackInuse) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("stack_sys_bytes"),
					"Number of bytes in obtained from system for stack allocator.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.StackSys) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("mspan_inuse"),
					"Number of mspan structures in use.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanInuse) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("mspan_sys"),
					"Number of mspan structures obtained from system.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MSpanSys) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("mcache_inuse"),
					"Number of mcache structures in use.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheInuse) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("mcache_sys"),
					"Number of mcache structures obtained from system.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.MCacheSys) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("buck_hash_sys"),
					"Profiling bucket hash table.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.BuckHashSys) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("gc_metadata"),
					"GC metadata.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.GCSys) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("other_sys"),
					"Other system allocations.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.OtherSys) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("next_gc"),
					"Next collection will happen when HeapAlloc ≥ this amount.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NextGC) },
				valType: GaugeValue,
			}, {
				desc: NewDesc(
					memstatNamespace("last_gc"),
					"End time of last garbage collection (nanoseconds since 1970).",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.LastGC) },
				valType: CounterValue,
			}, {
				desc: NewDesc(
					memstatNamespace("pause_total"),
					"Total garbage collection pauses for all collections.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.PauseTotalNs) },
				valType: CounterValue,
			}, {
				desc: NewDesc(
					memstatNamespace("gc_total"),
					"Number of garbage collection.",
					nil, nil,
				),
				eval:    func(ms *runtime.MemStats) float64 { return float64(ms.NumGC) },
				valType: CounterValue,
			},
		},
	}
}

func memstatNamespace(s string) string {
	return fmt.Sprintf("go_memstats_%s", s)
}

// Describe returns all descriptions of the collector.
func (c *goCollector) Describe(ch chan<- *Desc) {
	ch <- c.goroutines.Desc()
	ch <- c.gcDesc

	for _, i := range c.metrics {
		ch <- i.desc
	}
}

// Collect returns the current state of all metrics of the collector.
func (c *goCollector) Collect(ch chan<- Metric) {
	c.goroutines.Set(float64(runtime.NumGoroutine()))
	ch <- c.goroutines

	var stats debug.GCStats
	stats.PauseQuantiles = make([]time.Duration, 5)
	debug.ReadGCStats(&stats)

	quantiles := make(map[float64]float64)
	for idx, pq := range stats.PauseQuantiles[1:] {
		quantiles[float64(idx+1)/float64(len(stats.PauseQuantiles)-1)] = pq.Seconds()
	}
	quantiles[0.0] = stats.PauseQuantiles[0].Seconds()
	ch <- MustNewConstSummary(c.gcDesc, uint64(stats.NumGC), float64(stats.PauseTotal.Seconds()), quantiles)

	runtime.ReadMemStats(c.ms)
	for _, i := range c.metrics {
		ch <- MustNewConstMetric(i.desc, i.valType, i.eval(c.ms))
	}
}

// memStatsMetrics provide description, value, and value type for memstat metrics
type memStatsMetrics []struct {
	desc    *Desc
	eval    func(*runtime.MemStats) float64
	valType ValueType
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"errors"
	"github.com/megamsys/libgo/action"
	"github.com/megamsys/libgo/exec"
	log "code.google.com/p/log4go"
	"strings"
	"github.com/tsuru/config"
	"os"
	"path"
	"bufio"
	"github.com/megamsys/megamd/provisioner"
)

func CommandExecutor(app *provisioner.AssemblyResult) (action.Result, error) {
    var e exec.OsExecutor
    var commandWords []string

    commandWords = strings.Fields(app.Command)

    megam_home, ckberr := config.GetString("MEGAM_HOME")
	if ckberr != nil {
		return nil, ckberr
	}
    appName := app.Name + "." + app.Components[0].Inputs.Domain
	basePath := megam_home + "logs"
	dir := path.Join(basePath, appName)
	fileOutPath := path.Join(dir, appName + "_out" )
	fileErrPath := path.Join(dir, appName + "_err" )
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		fmt.Printf("no such file or directory: %s", dir)
		if errm := os.MkdirAll(dir, 0777); errm != nil {
			return nil, errm
		}
	}
		// open output file
		fout, outerr := os.OpenFile(fileOutPath, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
		if outerr != nil {
			return nil, outerr
		}
		defer fout.Close()

		fmt.Println(fout)
		// open Error file
		ferr, errerr := os.OpenFile(fileErrPath, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
		if errerr != nil {
			return nil, errerr
		}
		defer ferr.Close()

	foutwriter := bufio.NewWriter(fout)
	ferrwriter := bufio.NewWriter(ferr)
    fmt.Println(commandWords, len(commandWords))
    if len(commandWords) > 0 {
       if err := e.Execute(commandWords[0], commandWords[1:], nil, foutwriter, ferrwriter); err != nil {
           return nil, err
        }
     }

   foutwriter.Flush()
   ferrwriter.Flush()

  return &app, nil
}

var launchedApp = action.Action{
	Name: "launchedapp",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		var app provisioner.AssemblyResult
		switch ctx.Params[0].(type) {
		case provisioner.AssemblyResult:
			app = ctx.Params[0].(provisioner.AssemblyResult)
		case *provisioner.AssemblyResult:
			app = *ctx.Params[0].(*provisioner.AssemblyResult)
		default:
			return nil, errors.New("First parameter must be App or *assemblies.AssemblyResult.")
		}

		return CommandExecutor(&app)
	},
	Backward: func(ctx action.BWContext) {
		log.Info("[%s] Nothing to recover")
	},
	MinParams: 1,
}

<commit_msg>clear println lines<commit_after>package app

import (
	"fmt"
	"errors"
	"github.com/megamsys/libgo/action"
	"github.com/megamsys/libgo/exec"
	log "code.google.com/p/log4go"
	"strings"
	"github.com/tsuru/config"
	"os"
	"path"
	"bufio"
	"github.com/megamsys/megamd/provisioner"
)

func CommandExecutor(app *provisioner.AssemblyResult) (action.Result, error) {
    var e exec.OsExecutor
    var commandWords []string

    commandWords = strings.Fields(app.Command)

    megam_home, ckberr := config.GetString("MEGAM_HOME")
	if ckberr != nil {
		return nil, ckberr
	}
    appName := app.Name + "." + app.Components[0].Inputs.Domain
	basePath := megam_home + "logs"
	dir := path.Join(basePath, appName)

	fileOutPath := path.Join(dir, appName + "_out" )
	fileErrPath := path.Join(dir, appName + "_err" )
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		fmt.Printf("no such file or directory: %s", dir)
		if errm := os.MkdirAll(dir, 0777); errm != nil {
			return nil, errm
		}
	}
		// open output file
		fout, outerr := os.OpenFile(fileOutPath, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
		if outerr != nil {
			return nil, outerr
		}
		defer fout.Close()
		// open Error file
		ferr, errerr := os.OpenFile(fileErrPath, os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
		if errerr != nil {
			return nil, errerr
		}
		defer ferr.Close()

	foutwriter := bufio.NewWriter(fout)
	ferrwriter := bufio.NewWriter(ferr)
    fmt.Println(commandWords, len(commandWords))
    if len(commandWords) > 0 {
       if err := e.Execute(commandWords[0], commandWords[1:], nil, foutwriter, ferrwriter); err != nil {
           return nil, err
        }
     }

   foutwriter.Flush()
   ferrwriter.Flush()

  return &app, nil
}

var launchedApp = action.Action{
	Name: "launchedapp",
	Forward: func(ctx action.FWContext) (action.Result, error) {
		var app provisioner.AssemblyResult
		switch ctx.Params[0].(type) {
		case provisioner.AssemblyResult:
			app = ctx.Params[0].(provisioner.AssemblyResult)
		case *provisioner.AssemblyResult:
			app = *ctx.Params[0].(*provisioner.AssemblyResult)
		default:
			return nil, errors.New("First parameter must be App or *assemblies.AssemblyResult.")
		}

		return CommandExecutor(&app)
	},
	Backward: func(ctx action.BWContext) {
		log.Info("[%s] Nothing to recover")
	},
	MinParams: 1,
}

<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors 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 cinder

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"sync/atomic"
	"testing"
	"time"

	"github.com/golang/glog"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/types"
	"k8s.io/kubernetes/pkg/util/mount"
	utiltesting "k8s.io/kubernetes/pkg/util/testing"
	"k8s.io/kubernetes/pkg/volume"
)

func TestCanSupport(t *testing.T) {
	tmpDir, err := utiltesting.MkTmpdir("cinderTest")
	if err != nil {
		t.Fatalf("can't make a temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)
	plugMgr := volume.VolumePluginMgr{}
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost(tmpDir, nil, nil))

	plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	if plug.Name() != "kubernetes.io/cinder" {
		t.Errorf("Wrong name: %s", plug.Name())
	}
	if !plug.CanSupport(&volume.Spec{Volume: &api.Volume{VolumeSource: api.VolumeSource{Cinder: &api.CinderVolumeSource{}}}}) {
		t.Errorf("Expected true")
	}

	if !plug.CanSupport(&volume.Spec{PersistentVolume: &api.PersistentVolume{Spec: api.PersistentVolumeSpec{PersistentVolumeSource: api.PersistentVolumeSource{Cinder: &api.CinderVolumeSource{}}}}}) {
		t.Errorf("Expected true")
	}
}

type fakePDManager struct {
	// How long should AttachDisk/DetachDisk take - we need slower AttachDisk in a test.
	attachDetachDuration time.Duration
}

func getFakeDeviceName(host volume.VolumeHost, pdName string) string {
	return path.Join(host.GetPluginDir(cinderVolumePluginName), "device", pdName)
}

// Real Cinder AttachDisk attaches a cinder volume. If it is not yet mounted,
// it mounts it it to globalPDPath.
// We create a dummy directory (="device") and bind-mount it to globalPDPath
func (fake *fakePDManager) AttachDisk(b *cinderVolumeBuilder, globalPDPath string) error {
	globalPath := makeGlobalPDName(b.plugin.host, b.pdName)
	fakeDeviceName := getFakeDeviceName(b.plugin.host, b.pdName)
	err := os.MkdirAll(fakeDeviceName, 0750)
	if err != nil {
		return err
	}
	// Attaching a Cinder volume can be slow...
	time.Sleep(fake.attachDetachDuration)

	// The volume is "attached", bind-mount it if it's not mounted yet.
	notmnt, err := b.mounter.IsLikelyNotMountPoint(globalPath)
	if err != nil {
		if os.IsNotExist(err) {
			if err := os.MkdirAll(globalPath, 0750); err != nil {
				return err
			}
			notmnt = true
		} else {
			return err
		}
	}
	if notmnt {
		err = b.mounter.Mount(fakeDeviceName, globalPath, "", []string{"bind"})
		if err != nil {
			return err
		}
	}
	return nil
}

func (fake *fakePDManager) DetachDisk(c *cinderVolumeCleaner) error {
	globalPath := makeGlobalPDName(c.plugin.host, c.pdName)
	fakeDeviceName := getFakeDeviceName(c.plugin.host, c.pdName)
	// unmount the bind-mount - should be fast
	err := c.mounter.Unmount(globalPath)
	if err != nil {
		return err
	}

	// "Detach" the fake "device"
	err = os.RemoveAll(fakeDeviceName)
	if err != nil {
		return err
	}
	return nil
}

func (fake *fakePDManager) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, err error) {
	return "test-volume-name", 1, nil
}

func (fake *fakePDManager) DeleteVolume(cd *cinderVolumeDeleter) error {
	if cd.pdName != "test-volume-name" {
		return fmt.Errorf("Deleter got unexpected volume name: %s", cd.pdName)
	}
	return nil
}

func TestPlugin(t *testing.T) {
	tmpDir, err := utiltesting.MkTmpdir("cinderTest")
	if err != nil {
		t.Fatalf("can't make a temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)
	plugMgr := volume.VolumePluginMgr{}
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost(tmpDir, nil, nil))

	plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	spec := &api.Volume{
		Name: "vol1",
		VolumeSource: api.VolumeSource{
			Cinder: &api.CinderVolumeSource{
				VolumeID: "pd",
				FSType:   "ext4",
			},
		},
	}
	builder, err := plug.(*cinderPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{0}, &mount.FakeMounter{})
	if err != nil {
		t.Errorf("Failed to make a new Builder: %v", err)
	}
	if builder == nil {
		t.Errorf("Got a nil Builder: %v")
	}
	volPath := path.Join(tmpDir, "pods/poduid/volumes/kubernetes.io~cinder/vol1")
	path := builder.GetPath()
	if path != volPath {
		t.Errorf("Got unexpected path: %s", path)
	}

	if err := builder.SetUp(nil); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume path not created: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume path not created: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}

	cleaner, err := plug.(*cinderPlugin).newCleanerInternal("vol1", types.UID("poduid"), &fakePDManager{0}, &mount.FakeMounter{})
	if err != nil {
		t.Errorf("Failed to make a new Cleaner: %v", err)
	}
	if cleaner == nil {
		t.Errorf("Got a nil Cleaner: %v")
	}

	if err := cleaner.TearDown(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err == nil {
		t.Errorf("TearDown() failed, volume path still exists: %s", path)
	} else if !os.IsNotExist(err) {
		t.Errorf("SetUp() failed: %v", err)
	}

	// Test Provisioner
	cap := resource.MustParse("100Mi")
	options := volume.VolumeOptions{
		Capacity: cap,
		AccessModes: []api.PersistentVolumeAccessMode{
			api.ReadWriteOnce,
		},
		PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
	}
	provisioner, err := plug.(*cinderPlugin).newProvisionerInternal(options, &fakePDManager{0})
	persistentSpec, err := provisioner.NewPersistentVolumeTemplate()
	if err != nil {
		t.Errorf("NewPersistentVolumeTemplate() failed: %v", err)
	}

	// get 2nd Provisioner - persistent volume controller will do the same
	provisioner, err = plug.(*cinderPlugin).newProvisionerInternal(options, &fakePDManager{0})
	err = provisioner.Provision(persistentSpec)
	if err != nil {
		t.Errorf("Provision() failed: %v", err)
	}

	if persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID != "test-volume-name" {
		t.Errorf("Provision() returned unexpected volume ID: %s", persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID)
	}
	cap = persistentSpec.Spec.Capacity[api.ResourceStorage]
	size := cap.Value()
	if size != 1024*1024*1024 {
		t.Errorf("Provision() returned unexpected volume size: %v", size)
	}

	// Test Deleter
	volSpec := &volume.Spec{
		PersistentVolume: persistentSpec,
	}
	deleter, err := plug.(*cinderPlugin).newDeleterInternal(volSpec, &fakePDManager{0})
	err = deleter.Delete()
	if err != nil {
		t.Errorf("Deleter() failed: %v", err)
	}
}

// Test a race when a volume is simultaneously SetUp and TearedDown
func TestAttachDetachRace(t *testing.T) {
	tmpDir, err := ioutil.TempDir(os.TempDir(), "cinderTest")
	if err != nil {
		t.Fatalf("can't make a temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)
	plugMgr := volume.VolumePluginMgr{}
	host := volume.NewFakeVolumeHost(tmpDir, nil, nil)
	plugMgr.InitPlugins(ProbeVolumePlugins(), host)

	plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	spec := &api.Volume{
		Name: "vol1",
		VolumeSource: api.VolumeSource{
			Cinder: &api.CinderVolumeSource{
				VolumeID: "pd",
				FSType:   "ext4",
			},
		},
	}
	fakeMounter := &mount.FakeMounter{}
	// SetUp the volume for 1st time
	builder, err := plug.(*cinderPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{time.Second}, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Builder: %v", err)
	}
	if builder == nil {
		t.Errorf("Got a nil Builder: %v")
	}

	if err := builder.SetUp(nil); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	path := builder.GetPath()

	// TearDown the 1st volume and SetUp the 2nd volume (to different pod) at the same time
	builder, err = plug.(*cinderPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid2"), &fakePDManager{time.Second}, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Builder: %v", err)
	}
	if builder == nil {
		t.Errorf("Got a nil Builder: %v")
	}

	cleaner, err := plug.(*cinderPlugin).newCleanerInternal("vol1", types.UID("poduid"), &fakePDManager{time.Second}, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Cleaner: %v", err)
	}

	var buildComplete uint32 = 0

	go func() {
		glog.Infof("Attaching volume")
		if err := builder.SetUp(nil); err != nil {
			t.Errorf("Expected success, got: %v", err)
		}
		glog.Infof("Volume attached")
		atomic.AddUint32(&buildComplete, 1)
	}()

	// builder is attaching the volume, which takes 1 second. Detach it in the middle of this interval
	time.Sleep(time.Second / 2)

	glog.Infof("Detaching volume")
	if err = cleaner.TearDown(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	glog.Infof("Volume detached")

	// wait for the builder to finish
	for atomic.LoadUint32(&buildComplete) == 0 {
		time.Sleep(time.Millisecond * 100)
	}

	// The volume should still be attached
	devicePath := getFakeDeviceName(host, "pd")
	if _, err := os.Stat(devicePath); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume detached by simultaneous TearDown: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}

	// TearDown the 2nd volume
	cleaner, err = plug.(*cinderPlugin).newCleanerInternal("vol1", types.UID("poduid2"), &fakePDManager{0}, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Cleaner: %v", err)
	}
	if cleaner == nil {
		t.Errorf("Got a nil Cleaner: %v")
	}

	if err := cleaner.TearDown(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err == nil {
		t.Errorf("TearDown() failed, volume path still exists: %s", path)
	} else if !os.IsNotExist(err) {
		t.Errorf("SetUp() failed: %v", err)
	}
	if _, err := os.Stat(devicePath); err == nil {
		t.Errorf("TearDown() failed, volume is still attached: %s", devicePath)
	} else if !os.IsNotExist(err) {
		t.Errorf("SetUp() failed: %v", err)
	}
}
<commit_msg>fix a few go-vet errors<commit_after>/*
Copyright 2015 The Kubernetes Authors 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 cinder

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"sync/atomic"
	"testing"
	"time"

	"github.com/golang/glog"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/types"
	"k8s.io/kubernetes/pkg/util/mount"
	utiltesting "k8s.io/kubernetes/pkg/util/testing"
	"k8s.io/kubernetes/pkg/volume"
)

func TestCanSupport(t *testing.T) {
	tmpDir, err := utiltesting.MkTmpdir("cinderTest")
	if err != nil {
		t.Fatalf("can't make a temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)
	plugMgr := volume.VolumePluginMgr{}
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost(tmpDir, nil, nil))

	plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	if plug.Name() != "kubernetes.io/cinder" {
		t.Errorf("Wrong name: %s", plug.Name())
	}
	if !plug.CanSupport(&volume.Spec{Volume: &api.Volume{VolumeSource: api.VolumeSource{Cinder: &api.CinderVolumeSource{}}}}) {
		t.Errorf("Expected true")
	}

	if !plug.CanSupport(&volume.Spec{PersistentVolume: &api.PersistentVolume{Spec: api.PersistentVolumeSpec{PersistentVolumeSource: api.PersistentVolumeSource{Cinder: &api.CinderVolumeSource{}}}}}) {
		t.Errorf("Expected true")
	}
}

type fakePDManager struct {
	// How long should AttachDisk/DetachDisk take - we need slower AttachDisk in a test.
	attachDetachDuration time.Duration
}

func getFakeDeviceName(host volume.VolumeHost, pdName string) string {
	return path.Join(host.GetPluginDir(cinderVolumePluginName), "device", pdName)
}

// Real Cinder AttachDisk attaches a cinder volume. If it is not yet mounted,
// it mounts it it to globalPDPath.
// We create a dummy directory (="device") and bind-mount it to globalPDPath
func (fake *fakePDManager) AttachDisk(b *cinderVolumeBuilder, globalPDPath string) error {
	globalPath := makeGlobalPDName(b.plugin.host, b.pdName)
	fakeDeviceName := getFakeDeviceName(b.plugin.host, b.pdName)
	err := os.MkdirAll(fakeDeviceName, 0750)
	if err != nil {
		return err
	}
	// Attaching a Cinder volume can be slow...
	time.Sleep(fake.attachDetachDuration)

	// The volume is "attached", bind-mount it if it's not mounted yet.
	notmnt, err := b.mounter.IsLikelyNotMountPoint(globalPath)
	if err != nil {
		if os.IsNotExist(err) {
			if err := os.MkdirAll(globalPath, 0750); err != nil {
				return err
			}
			notmnt = true
		} else {
			return err
		}
	}
	if notmnt {
		err = b.mounter.Mount(fakeDeviceName, globalPath, "", []string{"bind"})
		if err != nil {
			return err
		}
	}
	return nil
}

func (fake *fakePDManager) DetachDisk(c *cinderVolumeCleaner) error {
	globalPath := makeGlobalPDName(c.plugin.host, c.pdName)
	fakeDeviceName := getFakeDeviceName(c.plugin.host, c.pdName)
	// unmount the bind-mount - should be fast
	err := c.mounter.Unmount(globalPath)
	if err != nil {
		return err
	}

	// "Detach" the fake "device"
	err = os.RemoveAll(fakeDeviceName)
	if err != nil {
		return err
	}
	return nil
}

func (fake *fakePDManager) CreateVolume(c *cinderVolumeProvisioner) (volumeID string, volumeSizeGB int, err error) {
	return "test-volume-name", 1, nil
}

func (fake *fakePDManager) DeleteVolume(cd *cinderVolumeDeleter) error {
	if cd.pdName != "test-volume-name" {
		return fmt.Errorf("Deleter got unexpected volume name: %s", cd.pdName)
	}
	return nil
}

func TestPlugin(t *testing.T) {
	tmpDir, err := utiltesting.MkTmpdir("cinderTest")
	if err != nil {
		t.Fatalf("can't make a temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)
	plugMgr := volume.VolumePluginMgr{}
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost(tmpDir, nil, nil))

	plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	spec := &api.Volume{
		Name: "vol1",
		VolumeSource: api.VolumeSource{
			Cinder: &api.CinderVolumeSource{
				VolumeID: "pd",
				FSType:   "ext4",
			},
		},
	}
	builder, err := plug.(*cinderPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{0}, &mount.FakeMounter{})
	if err != nil {
		t.Errorf("Failed to make a new Builder: %v", err)
	}
	if builder == nil {
		t.Errorf("Got a nil Builder")
	}
	volPath := path.Join(tmpDir, "pods/poduid/volumes/kubernetes.io~cinder/vol1")
	path := builder.GetPath()
	if path != volPath {
		t.Errorf("Got unexpected path: %s", path)
	}

	if err := builder.SetUp(nil); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume path not created: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}
	if _, err := os.Stat(path); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume path not created: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}

	cleaner, err := plug.(*cinderPlugin).newCleanerInternal("vol1", types.UID("poduid"), &fakePDManager{0}, &mount.FakeMounter{})
	if err != nil {
		t.Errorf("Failed to make a new Cleaner: %v", err)
	}
	if cleaner == nil {
		t.Errorf("Got a nil Cleaner")
	}

	if err := cleaner.TearDown(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err == nil {
		t.Errorf("TearDown() failed, volume path still exists: %s", path)
	} else if !os.IsNotExist(err) {
		t.Errorf("SetUp() failed: %v", err)
	}

	// Test Provisioner
	cap := resource.MustParse("100Mi")
	options := volume.VolumeOptions{
		Capacity: cap,
		AccessModes: []api.PersistentVolumeAccessMode{
			api.ReadWriteOnce,
		},
		PersistentVolumeReclaimPolicy: api.PersistentVolumeReclaimDelete,
	}
	provisioner, err := plug.(*cinderPlugin).newProvisionerInternal(options, &fakePDManager{0})
	persistentSpec, err := provisioner.NewPersistentVolumeTemplate()
	if err != nil {
		t.Errorf("NewPersistentVolumeTemplate() failed: %v", err)
	}

	// get 2nd Provisioner - persistent volume controller will do the same
	provisioner, err = plug.(*cinderPlugin).newProvisionerInternal(options, &fakePDManager{0})
	err = provisioner.Provision(persistentSpec)
	if err != nil {
		t.Errorf("Provision() failed: %v", err)
	}

	if persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID != "test-volume-name" {
		t.Errorf("Provision() returned unexpected volume ID: %s", persistentSpec.Spec.PersistentVolumeSource.Cinder.VolumeID)
	}
	cap = persistentSpec.Spec.Capacity[api.ResourceStorage]
	size := cap.Value()
	if size != 1024*1024*1024 {
		t.Errorf("Provision() returned unexpected volume size: %v", size)
	}

	// Test Deleter
	volSpec := &volume.Spec{
		PersistentVolume: persistentSpec,
	}
	deleter, err := plug.(*cinderPlugin).newDeleterInternal(volSpec, &fakePDManager{0})
	err = deleter.Delete()
	if err != nil {
		t.Errorf("Deleter() failed: %v", err)
	}
}

// Test a race when a volume is simultaneously SetUp and TearedDown
func TestAttachDetachRace(t *testing.T) {
	tmpDir, err := ioutil.TempDir(os.TempDir(), "cinderTest")
	if err != nil {
		t.Fatalf("can't make a temp dir: %v", err)
	}
	defer os.RemoveAll(tmpDir)
	plugMgr := volume.VolumePluginMgr{}
	host := volume.NewFakeVolumeHost(tmpDir, nil, nil)
	plugMgr.InitPlugins(ProbeVolumePlugins(), host)

	plug, err := plugMgr.FindPluginByName("kubernetes.io/cinder")
	if err != nil {
		t.Errorf("Can't find the plugin by name")
	}
	spec := &api.Volume{
		Name: "vol1",
		VolumeSource: api.VolumeSource{
			Cinder: &api.CinderVolumeSource{
				VolumeID: "pd",
				FSType:   "ext4",
			},
		},
	}
	fakeMounter := &mount.FakeMounter{}
	// SetUp the volume for 1st time
	builder, err := plug.(*cinderPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid"), &fakePDManager{time.Second}, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Builder: %v", err)
	}
	if builder == nil {
		t.Errorf("Got a nil Builder")
	}

	if err := builder.SetUp(nil); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	path := builder.GetPath()

	// TearDown the 1st volume and SetUp the 2nd volume (to different pod) at the same time
	builder, err = plug.(*cinderPlugin).newBuilderInternal(volume.NewSpecFromVolume(spec), types.UID("poduid2"), &fakePDManager{time.Second}, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Builder: %v", err)
	}
	if builder == nil {
		t.Errorf("Got a nil Builder")
	}

	cleaner, err := plug.(*cinderPlugin).newCleanerInternal("vol1", types.UID("poduid"), &fakePDManager{time.Second}, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Cleaner: %v", err)
	}

	var buildComplete uint32 = 0

	go func() {
		glog.Infof("Attaching volume")
		if err := builder.SetUp(nil); err != nil {
			t.Errorf("Expected success, got: %v", err)
		}
		glog.Infof("Volume attached")
		atomic.AddUint32(&buildComplete, 1)
	}()

	// builder is attaching the volume, which takes 1 second. Detach it in the middle of this interval
	time.Sleep(time.Second / 2)

	glog.Infof("Detaching volume")
	if err = cleaner.TearDown(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	glog.Infof("Volume detached")

	// wait for the builder to finish
	for atomic.LoadUint32(&buildComplete) == 0 {
		time.Sleep(time.Millisecond * 100)
	}

	// The volume should still be attached
	devicePath := getFakeDeviceName(host, "pd")
	if _, err := os.Stat(devicePath); err != nil {
		if os.IsNotExist(err) {
			t.Errorf("SetUp() failed, volume detached by simultaneous TearDown: %s", path)
		} else {
			t.Errorf("SetUp() failed: %v", err)
		}
	}

	// TearDown the 2nd volume
	cleaner, err = plug.(*cinderPlugin).newCleanerInternal("vol1", types.UID("poduid2"), &fakePDManager{0}, fakeMounter)
	if err != nil {
		t.Errorf("Failed to make a new Cleaner: %v", err)
	}
	if cleaner == nil {
		t.Errorf("Got a nil Cleaner")
	}

	if err := cleaner.TearDown(); err != nil {
		t.Errorf("Expected success, got: %v", err)
	}
	if _, err := os.Stat(path); err == nil {
		t.Errorf("TearDown() failed, volume path still exists: %s", path)
	} else if !os.IsNotExist(err) {
		t.Errorf("SetUp() failed: %v", err)
	}
	if _, err := os.Stat(devicePath); err == nil {
		t.Errorf("TearDown() failed, volume is still attached: %s", devicePath)
	} else if !os.IsNotExist(err) {
		t.Errorf("SetUp() failed: %v", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strconv"

	"ratings/controller"
	"ratings/handler"

	"github.com/facebookgo/grace/gracehttp"
	"github.com/labstack/echo"
)

func main() {
	port := 5000
	routes := map[string]echo.HandlerFunc{
		"OptionsRoot":    controller.OptionsRoot,
		"OptionsRatings": controller.OptionsRatings,
		"PostRatings":    controller.PostRatings}

	handler := handler.Handler(port, routes).(*echo.Echo) // Casting via type assertion

	fmt.Println("Started server on port", strconv.Itoa(port))

	handler.Logger.Fatal(gracehttp.Serve(handler.Server))
}
<commit_msg>Made it possible to set the port with an environment variable<commit_after>package main

import (
	"fmt"
	"os"
	"strconv"

	"ratings/controller"
	"ratings/handler"

	"github.com/facebookgo/grace/gracehttp"
	"github.com/labstack/echo"
)

func main() {
	port, parseErr := strconv.Atoi(os.Getenv("API_RATINGS_PORT"))

	if parseErr != nil {
		port = 5000
	}

	routes := map[string]echo.HandlerFunc{
		"OptionsRoot":    controller.OptionsRoot,
		"OptionsRatings": controller.OptionsRatings,
		"PostRatings":    controller.PostRatings}

	handler, castOk := handler.Handler(port, routes).(*echo.Echo)

	if !castOk {
		handler.Logger.Fatal("Could not start server")
	}

	banner := `
_  _ ____ ____ _  _ ____ ____
|__| |___ |__/ |\/| |___ [__
|  | |___ |  \ |  | |___ ___] `

	fmt.Println("\n", banner)
	fmt.Println("\n\n✅  Server started on port", strconv.Itoa(port))
	fmt.Print("\n\n\033[?25l")

	handler.Logger.Fatal(gracehttp.Serve(handler.Server))
}
<|endoftext|>


<commit_before>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd netbsd openbsd

package route

import (
	"os"
	"syscall"
	"testing"
	"time"
)

func TestFetchAndParseRIB(t *testing.T) {
	for _, typ := range []RIBType{sysNET_RT_DUMP, sysNET_RT_IFLIST} {
		var lastErr error
		var ms []Message
		for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
			rs, err := fetchAndParseRIB(af, typ)
			if err != nil {
				lastErr = err
				continue
			}
			ms = append(ms, rs...)
		}
		if len(ms) == 0 && lastErr != nil {
			t.Error(typ, lastErr)
			continue
		}
		ss, err := msgs(ms).validate()
		if err != nil {
			t.Error(typ, err)
			continue
		}
		for _, s := range ss {
			t.Log(typ, s)
		}
	}
}

var (
	rtmonSock int
	rtmonErr  error
)

func init() {
	// We need to keep rtmonSock alive to avoid treading on
	// recycled socket descriptors.
	rtmonSock, rtmonErr = syscall.Socket(sysAF_ROUTE, sysSOCK_RAW, sysAF_UNSPEC)
}

// TestMonitorAndParseRIB leaks a worker goroutine and a socket
// descriptor but that's intentional.
func TestMonitorAndParseRIB(t *testing.T) {
	if testing.Short() || os.Getuid() != 0 {
		t.Skip("must be root")
	}

	if rtmonErr != nil {
		t.Fatal(rtmonErr)
	}

	// We suppose that using an IPv4 link-local address and the
	// dot1Q ID for Token Ring and FDDI doesn't harm anyone.
	pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"}
	if err := pv.configure(1002); err != nil {
		t.Skip(err)
	}
	if err := pv.setup(); err != nil {
		t.Skip(err)
	}
	pv.teardown()

	go func() {
		b := make([]byte, os.Getpagesize())
		for {
			// There's no easy way to unblock this read
			// call because the routing message exchange
			// over routing socket is a connectionless
			// message-oriented protocol, no control plane
			// for signaling connectivity, and we cannot
			// use the net package of standard library due
			// to the lack of support for routing socket
			// and circular dependency.
			n, err := syscall.Read(rtmonSock, b)
			if err != nil {
				return
			}
			ms, err := ParseRIB(0, b[:n])
			if err != nil {
				t.Error(err)
				return
			}
			ss, err := msgs(ms).validate()
			if err != nil {
				t.Error(err)
				return
			}
			for _, s := range ss {
				t.Log(s)
			}
		}
	}()

	for _, vid := range []int{1002, 1003, 1004, 1005} {
		pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"}
		if err := pv.configure(vid); err != nil {
			t.Fatal(err)
		}
		if err := pv.setup(); err != nil {
			t.Fatal(err)
		}
		time.Sleep(200 * time.Millisecond)
		if err := pv.teardown(); err != nil {
			t.Fatal(err)
		}
		time.Sleep(200 * time.Millisecond)
	}
}

func TestParseRIBWithFuzz(t *testing.T) {
	for _, fuzz := range []string{
		"0\x00\x05\x050000000000000000" +
			"00000000000000000000" +
			"00000000000000000000" +
			"00000000000000000000" +
			"0000000000000\x02000000" +
			"00000000",
		"\x02\x00\x05\f0000000000000000" +
			"0\x0200000000000000",
		"\x02\x00\x05\x100000000000000\x1200" +
			"0\x00\xff\x00",
		"\x02\x00\x05\f0000000000000000" +
			"0\x12000\x00\x02\x0000",
		"\x00\x00\x00\x01\x00",
		"00000",
	} {
		for typ := RIBType(0); typ < 256; typ++ {
			ParseRIB(typ, []byte(fuzz))
		}
	}
}

func TestRouteMessage(t *testing.T) {
	s, err := syscall.Socket(sysAF_ROUTE, sysSOCK_RAW, sysAF_UNSPEC)
	if err != nil {
		t.Fatal(err)
	}
	defer syscall.Close(s)

	var ms []RouteMessage
	for _, af := range []int{sysAF_INET, sysAF_INET6} {
		if _, err := fetchAndParseRIB(af, sysNET_RT_DUMP); err != nil {
			t.Log(err)
			continue
		}
		switch af {
		case sysAF_INET:
			ms = append(ms, []RouteMessage{
				{
					Type: sysRTM_GET,
					Addrs: []Addr{
						&Inet4Addr{IP: [4]byte{127, 0, 0, 1}},
						nil,
						nil,
						nil,
						&LinkAddr{},
						&Inet4Addr{},
						nil,
						&Inet4Addr{},
					},
				},
				{
					Type: sysRTM_GET,
					Addrs: []Addr{
						&Inet4Addr{IP: [4]byte{127, 0, 0, 1}},
					},
				},
			}...)
		case sysAF_INET6:
			ms = append(ms, []RouteMessage{
				{
					Type: sysRTM_GET,
					Addrs: []Addr{
						&Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
						nil,
						nil,
						nil,
						&LinkAddr{},
						&Inet6Addr{},
						nil,
						&Inet6Addr{},
					},
				},
				{
					Type: sysRTM_GET,
					Addrs: []Addr{
						&Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
					},
				},
			}...)
		}
	}
	for i, m := range ms {
		m.ID = uintptr(os.Getpid())
		m.Seq = i + 1
		wb, err := m.Marshal()
		if err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		if _, err := syscall.Write(s, wb); err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		rb := make([]byte, os.Getpagesize())
		n, err := syscall.Read(s, rb)
		if err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		rms, err := ParseRIB(0, rb[:n])
		if err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		for _, rm := range rms {
			err := rm.(*RouteMessage).Err
			if err != nil {
				t.Errorf("%v: %v", m, err)
			}
		}
		ss, err := msgs(rms).validate()
		if err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		for _, s := range ss {
			t.Log(s)
		}
	}
}
<commit_msg>route: fix TestRouteMessage<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd netbsd openbsd

package route

import (
	"os"
	"syscall"
	"testing"
	"time"
)

func TestFetchAndParseRIB(t *testing.T) {
	for _, typ := range []RIBType{sysNET_RT_DUMP, sysNET_RT_IFLIST} {
		var lastErr error
		var ms []Message
		for _, af := range []int{sysAF_UNSPEC, sysAF_INET, sysAF_INET6} {
			rs, err := fetchAndParseRIB(af, typ)
			if err != nil {
				lastErr = err
				continue
			}
			ms = append(ms, rs...)
		}
		if len(ms) == 0 && lastErr != nil {
			t.Error(typ, lastErr)
			continue
		}
		ss, err := msgs(ms).validate()
		if err != nil {
			t.Error(typ, err)
			continue
		}
		for _, s := range ss {
			t.Log(typ, s)
		}
	}
}

var (
	rtmonSock int
	rtmonErr  error
)

func init() {
	// We need to keep rtmonSock alive to avoid treading on
	// recycled socket descriptors.
	rtmonSock, rtmonErr = syscall.Socket(sysAF_ROUTE, sysSOCK_RAW, sysAF_UNSPEC)
}

// TestMonitorAndParseRIB leaks a worker goroutine and a socket
// descriptor but that's intentional.
func TestMonitorAndParseRIB(t *testing.T) {
	if testing.Short() || os.Getuid() != 0 {
		t.Skip("must be root")
	}

	if rtmonErr != nil {
		t.Fatal(rtmonErr)
	}

	// We suppose that using an IPv4 link-local address and the
	// dot1Q ID for Token Ring and FDDI doesn't harm anyone.
	pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"}
	if err := pv.configure(1002); err != nil {
		t.Skip(err)
	}
	if err := pv.setup(); err != nil {
		t.Skip(err)
	}
	pv.teardown()

	go func() {
		b := make([]byte, os.Getpagesize())
		for {
			// There's no easy way to unblock this read
			// call because the routing message exchange
			// over routing socket is a connectionless
			// message-oriented protocol, no control plane
			// for signaling connectivity, and we cannot
			// use the net package of standard library due
			// to the lack of support for routing socket
			// and circular dependency.
			n, err := syscall.Read(rtmonSock, b)
			if err != nil {
				return
			}
			ms, err := ParseRIB(0, b[:n])
			if err != nil {
				t.Error(err)
				return
			}
			ss, err := msgs(ms).validate()
			if err != nil {
				t.Error(err)
				return
			}
			for _, s := range ss {
				t.Log(s)
			}
		}
	}()

	for _, vid := range []int{1002, 1003, 1004, 1005} {
		pv := &propVirtual{addr: "169.254.0.1", mask: "255.255.255.0"}
		if err := pv.configure(vid); err != nil {
			t.Fatal(err)
		}
		if err := pv.setup(); err != nil {
			t.Fatal(err)
		}
		time.Sleep(200 * time.Millisecond)
		if err := pv.teardown(); err != nil {
			t.Fatal(err)
		}
		time.Sleep(200 * time.Millisecond)
	}
}

func TestParseRIBWithFuzz(t *testing.T) {
	for _, fuzz := range []string{
		"0\x00\x05\x050000000000000000" +
			"00000000000000000000" +
			"00000000000000000000" +
			"00000000000000000000" +
			"0000000000000\x02000000" +
			"00000000",
		"\x02\x00\x05\f0000000000000000" +
			"0\x0200000000000000",
		"\x02\x00\x05\x100000000000000\x1200" +
			"0\x00\xff\x00",
		"\x02\x00\x05\f0000000000000000" +
			"0\x12000\x00\x02\x0000",
		"\x00\x00\x00\x01\x00",
		"00000",
	} {
		for typ := RIBType(0); typ < 256; typ++ {
			ParseRIB(typ, []byte(fuzz))
		}
	}
}

func TestRouteMessage(t *testing.T) {
	s, err := syscall.Socket(sysAF_ROUTE, sysSOCK_RAW, sysAF_UNSPEC)
	if err != nil {
		t.Fatal(err)
	}
	defer syscall.Close(s)

	var ms []RouteMessage
	for _, af := range []int{sysAF_INET, sysAF_INET6} {
		if _, err := fetchAndParseRIB(af, sysNET_RT_DUMP); err != nil {
			t.Log(err)
			continue
		}
		switch af {
		case sysAF_INET:
			ms = append(ms, []RouteMessage{
				{
					Type: sysRTM_GET,
					Addrs: []Addr{
						sysRTAX_DST:     &Inet4Addr{IP: [4]byte{127, 0, 0, 1}},
						sysRTAX_GATEWAY: nil,
						sysRTAX_NETMASK: nil,
						sysRTAX_GENMASK: nil,
						sysRTAX_IFP:     &LinkAddr{},
						sysRTAX_IFA:     &Inet4Addr{},
						sysRTAX_AUTHOR:  nil,
						sysRTAX_BRD:     &Inet4Addr{},
					},
				},
				{
					Type: sysRTM_GET,
					Addrs: []Addr{
						sysRTAX_DST: &Inet4Addr{IP: [4]byte{127, 0, 0, 1}},
					},
				},
			}...)
		case sysAF_INET6:
			ms = append(ms, []RouteMessage{
				{
					Type: sysRTM_GET,
					Addrs: []Addr{
						sysRTAX_DST:     &Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
						sysRTAX_GATEWAY: nil,
						sysRTAX_NETMASK: nil,
						sysRTAX_GENMASK: nil,
						sysRTAX_IFP:     &LinkAddr{},
						sysRTAX_IFA:     &Inet6Addr{},
						sysRTAX_AUTHOR:  nil,
						sysRTAX_BRD:     &Inet6Addr{},
					},
				},
				{
					Type: sysRTM_GET,
					Addrs: []Addr{
						sysRTAX_DST: &Inet6Addr{IP: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
					},
				},
			}...)
		}
	}
	for i, m := range ms {
		m.ID = uintptr(os.Getpid())
		m.Seq = i + 1
		wb, err := m.Marshal()
		if err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		if _, err := syscall.Write(s, wb); err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		rb := make([]byte, os.Getpagesize())
		n, err := syscall.Read(s, rb)
		if err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		rms, err := ParseRIB(0, rb[:n])
		if err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		for _, rm := range rms {
			if rm, ok := rm.(*RouteMessage); ok && rm.Err != nil {
				t.Errorf("%v: %v", m, rm.Err)
			}
		}
		ss, err := msgs(rms).validate()
		if err != nil {
			t.Fatalf("%v: %v", m, err)
		}
		for _, s := range ss {
			t.Log(s)
		}
	}
}
<|endoftext|>