<commit_before>package util

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/skyrings/skyring-common/conf"
	"github.com/skyrings/skyring-common/db"
	"github.com/skyrings/skyring-common/models"
	"github.com/skyrings/skyring-common/monitoring"
	"github.com/skyrings/skyring-common/tools/logger"
	"github.com/skyrings/skyring-common/tools/task"
	"github.com/skyrings/skyring-common/tools/uuid"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"io/ioutil"
	"net/http"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"time"
)

// For testing, bypass HandleCrash.
var ReallyCrash bool

// PanicHandlers is a list of functions which will be invoked when a panic happens.
var PanicHandlers = []func(interface{}){logPanic}

// HandleCrash simply catches a crash and logs an error. Meant to be called via defer.
func HandleCrash() {
	if ReallyCrash {
		return
	}
	if r := recover(); r != nil {
		for _, fn := range PanicHandlers {
			fn(r)
		}
	}
}

// Deprecated. Please use Until and pass NeverStop as the stopCh.
func Forever(f func(), period time.Duration) {
	Until(f, period, nil)
}

// Until loops until stop channel is closed, running f every period.
// Catches any panics, and keeps going. f may not be invoked if
// stop channel is already closed.
func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
	for {
		select {
		case <-stopCh:
			return
		default:
		}
		func() {
			defer HandleCrash()
			f()
		}()
		time.Sleep(period)
	}
}

// logPanic logs the caller tree when a panic occurs.
func logPanic(r interface{}) {
	callers := ""
	for i := 0; true; i++ {
		_, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		callers = callers + fmt.Sprintf("%v:%v\n", file, line)
	}
	logger.Get().Error("Recovered from panic: %#v (%v)\n%v", r, r, callers)
}

func FailTask(msg string, err error, t *task.Task) {
	logger.Get().Error("%s: %v", msg, err)
	t.UpdateStatus("Failed. error: %v", err)
	t.Done(models.TASK_STATUS_FAILURE)
}

func GetString(param interface{}) (string, error) {
	if str, ok := param.(string); ok {
		return str, nil
	}
	return "", fmt.Errorf("Not a string")
}

func HTTPGet(url string) ([]byte, error) {
	response, err := http.Get(url)
	if err != nil {
		return nil, err
	} else {
		defer response.Body.Close()
		contents, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return nil, err
		}
		return contents, nil
	}
}

func Md5FromString(name string) string {
	hash := md5.Sum([]byte(name))
	return hex.EncodeToString(hash[:])
}

func GetMapKeys(inMap interface{}) ([]reflect.Value, error) {
	inMapValue := reflect.ValueOf(inMap)
	if inMapValue.Kind() != reflect.Map {
		return nil, fmt.Errorf("Not a map!!")
	}
	keys := inMapValue.MapKeys()
	return keys, nil
}

func Stringify(keys []reflect.Value) (strings []string) {
	strings = make([]string, len(keys))
	for index, key := range keys {
		strings[index] = key.String()
	}
	return strings
}

func StringifyInterface(keys []interface{}) ([]string, error) {
	var stringKeys []string
	stringKeys = make([]string, len(keys))
	var err error
	var errString string
	for index, key := range keys {
		stringKeys[index], err = GetString(key)
		if err != nil {
			errString = errString + err.Error() + "\n"
		}
	}
	if errString != "" {
		errString = strings.TrimSpace(errString)
		return stringKeys, fmt.Errorf(errString)
	}
	return stringKeys, nil
}

func GenerifyStringArr(keys []string) []interface{} {
	iKeys := make([]interface{}, len(keys))
	for index, key := range keys {
		iKeys[index] = key
	}
	return iKeys
}

func StringSetDiff(keys1 []string, keys2 []string) (diff []string) {
	var unique bool
	for _, key1 := range keys1 {
		unique = true
		for _, key2 := range keys2 {
			if key1 == key2 {
				unique = false
				continue
			}
		}
		if unique {
			diff = append(diff, key1)
		}
	}
	return diff
}

func StringInSlice(value string, slice []string) bool {
	for _, item := range slice {
		if value == item {
			return true
		}
	}
	return false
}

func GetNodes(clusterNodes []models.ClusterNode) (map[uuid.UUID]models.Node, error) {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	var nodes = make(map[uuid.UUID]models.Node)
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	for _, clusterNode := range clusterNodes {
		uuid, err := uuid.Parse(clusterNode.NodeId)
		if err != nil {
			return nodes, errors.New(fmt.Sprintf("Error parsing node id: %v", clusterNode.NodeId))
		}
		var node models.Node
		if err := coll.Find(bson.M{"nodeid": *uuid}).One(&node); err != nil {
			return nodes, err
		}
		nodes[node.NodeId] = node
	}
	return nodes, nil
}

func UpdateThresholdInfoToTable(tEvent models.ThresholdEvent) (err error, isRaiseEvent bool) {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	collection := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_THRESHOLD_BREACHES)
	var tEventInDb models.ThresholdEvent
	selectCriteria := bson.M{
		"entityid":        tEvent.EntityId,
		"clusterid":       tEvent.ClusterId,
		"utilizationtype": tEvent.UtilizationType,
		"entityname":      tEvent.EntityName,
	}
	err = collection.Find(selectCriteria).One(&tEventInDb)
	if err != nil {
		if err == mgo.ErrNotFound {
			if tEvent.ThresholdSeverity == strings.ToUpper(models.STATUS_OK) {
				return nil, false
			}
			if err := collection.Insert(tEvent); err != nil {
				return fmt.Errorf("Failed to persist event %v to db.Error %v",
					tEvent, err), true
			}
			return nil, true
		}
	} else {
		if tEvent.ThresholdSeverity == tEventInDb.ThresholdSeverity {
			return nil, false
		} else if tEvent.ThresholdSeverity == models.STATUS_OK {
			if err = collection.Remove(selectCriteria); err != nil {
				return fmt.Errorf("Failed to update the db, that %v of %v is back to normal.Err %v",
					tEvent.UtilizationType, tEvent.EntityName, err), true
			}
			return nil, true
		} else {
			if err := collection.Update(selectCriteria, tEvent); err != nil {
				return fmt.Errorf("Failed to persist event %v to db.Error %v",
					tEvent, err), true
			}
			return nil, true
		}
	}
	return nil, false
}

func AnalyseThresholdBreach(ctxt string, utilizationType string, resourceName string, resourceUtilization float64, cluster models.Cluster) (models.Event, bool, error) {
	var event models.Event
	timeStamp := time.Now()
	plugin := cluster.Monitoring.Plugins[monitoring.GetPluginIndex(utilizationType, cluster.Monitoring.Plugins)]
	var applicableConfig monitoring.PluginConfig
	var applicableThresholdValue float64
	var message string

	var entityIdentifier string
	entityId, entityIdFetchError := getEntityIdFromNameAndUtilizationType(utilizationType, resourceName, cluster)
	if entityIdFetchError != nil {
		logger.Get().Error("%s - Error fetching the id for %v in cluster %v",
			ctxt, resourceName, cluster.Name)
		return models.Event{}, false, fmt.Errorf("%s - Error fetching the id for %v in cluster %v",
			ctxt, resourceName, cluster.Name)
	}
	entityIdentifier = (*entityId).String()

	for _, config := range plugin.Configs {
		if config.Category == monitoring.THRESHOLD {
			currentThresholdValue, thresholdValError := strconv.ParseFloat(config.Value, 64)
			if thresholdValError != nil {
				logger.Get().Error("%s - %v-%v configuration for %v in cluster %v could not be converted.Err %v\n",
					ctxt, config.Category, config.Type, plugin.Name, cluster.Name, thresholdValError)
			}

			if resourceUtilization > currentThresholdValue && applicableThresholdValue < currentThresholdValue {
				applicableConfig = config
				applicableThresholdValue = currentThresholdValue
			}
		}
	}

	if applicableConfig.Type == "" {
		applicableConfig.Type = models.STATUS_OK
		message = fmt.Sprintf("%v of cluster %v with value %v back to normal",
			plugin.Name, cluster.Name, resourceUtilization)
	}

	tEvent := models.ThresholdEvent{
		ClusterId:         cluster.ClusterId,
		UtilizationType:   plugin.Name,
		ThresholdSeverity: strings.ToUpper(applicableConfig.Type),
		TimeStamp:         timeStamp,
		EntityId:          *entityId,
		EntityName:        resourceName,
	}

	err, isRaiseEvent := UpdateThresholdInfoToTable(tEvent)
	if err != nil {
		logger.Get().Error("%s - %v", ctxt, err)
	}

	if isRaiseEvent {
		event = models.Event{
			Timestamp: timeStamp,
			ClusterId: cluster.ClusterId,
			NodeId:    cluster.ClusterId,
			Tag: fmt.Sprintf("skyring/%v/cluster/%v/threshold/%v/%v",
				cluster.Type, cluster.ClusterId, plugin.Name, strings.ToUpper(applicableConfig.Type)),
			Tags: map[string]string{
				models.CURRENT_VALUE:   strconv.FormatFloat(resourceUtilization, 'E', -1, 64),
				models.ENTITY_ID:       entityIdentifier,
				models.PLUGIN:          plugin.Name,
				models.THRESHOLD_TYPE:  strings.ToUpper(applicableConfig.Type),
				models.THRESHOLD_VALUE: strconv.FormatFloat(applicableThresholdValue, 'E', -1, 64),
				models.ENTITY_NAME:     resourceName,
			},
			Severity: strings.ToUpper(applicableConfig.Type),
		}
		if message == "" {
			message = fmt.Sprintf("%v of cluster %v with value %v breached %v threshold of value %v",
				plugin.Name, cluster.Name, resourceUtilization, strings.ToUpper(applicableConfig.Type), applicableThresholdValue)
		}
		event.Message = message
		return event, true, nil
	}
	return models.Event{}, false, nil
}

func getEntityIdFromNameAndUtilizationType(utilizationType string, resourceName string, cluster models.Cluster) (*uuid.UUID, error) {
	switch utilizationType {
	case monitoring.CLUSTER_UTILIZATION:
		return &(cluster.ClusterId), nil
	case monitoring.SLU_UTILIZATION:
		var slu models.StorageLogicalUnit
		err := getEntity(cluster.ClusterId, resourceName, models.COLL_NAME_STORAGE_LOGICAL_UNITS, &slu)
		if err != nil {
			return nil, fmt.Errorf("Could not fetch osd with name %v in cluster %v.Error %v",
				resourceName, cluster.Name, err)
		}
		return &(slu.SluId), nil
	case monitoring.STORAGE_UTILIZATION:
		var storage models.Storage
		err := getEntity(cluster.ClusterId, resourceName, models.COLL_NAME_STORAGE, &storage)
		if err != nil {
			return nil, fmt.Errorf("Could not fetch pool with name %v in cluster %v",
				storage.Name, cluster.Name)
		}
		return &(storage.StorageId), nil
	case monitoring.STORAGE_PROFILE_UTILIZATION:
		return &(cluster.ClusterId), nil
	}
	return nil, fmt.Errorf("Unsupported utilization type %v", utilizationType)
}

func getEntity(clusterId uuid.UUID, resourceName string, collectionName string, entity interface{}) error {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	collection := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(collectionName)
	if err := collection.Find(bson.M{"clusterid": clusterId, "name": resourceName}).One(entity); err != nil {
		return err
	}
	return nil
}

func GetNodesByIdStr(clusterNodes []models.ClusterNode) (map[string]models.Node, error) {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	var nodes = make(map[string]models.Node)
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	for _, clusterNode := range clusterNodes {
		uuid, err := uuid.Parse(clusterNode.NodeId)
		if err != nil {
			return nodes, errors.New(fmt.Sprintf("Error parsing node id: %v", clusterNode.NodeId))
		}
		var node models.Node
		if err := coll.Find(bson.M{"nodeid": *uuid}).One(&node); err != nil {
			return nodes, err
		}
		nodes[clusterNode.NodeId] = node
	}
	return nodes, nil
}

func GetReadableFloat(str string, ctxt string) (string, error) {
	f, err := strconv.ParseFloat(str, 64)
	if err != nil {
		logger.Get().Error("%s-Could not parse the string: %s", ctxt, str)
		return str, err
	}
	return fmt.Sprintf("%.2f", f), nil
}
<commit_msg>monitoring: Add rbd entity id fetch<commit_after>package util

import (
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/skyrings/skyring-common/conf"
	"github.com/skyrings/skyring-common/db"
	"github.com/skyrings/skyring-common/models"
	"github.com/skyrings/skyring-common/monitoring"
	"github.com/skyrings/skyring-common/tools/logger"
	"github.com/skyrings/skyring-common/tools/task"
	"github.com/skyrings/skyring-common/tools/uuid"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
	"io/ioutil"
	"net/http"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"time"
)

// For testing, bypass HandleCrash.
var ReallyCrash bool

// PanicHandlers is a list of functions which will be invoked when a panic happens.
var PanicHandlers = []func(interface{}){logPanic}

// HandleCrash simply catches a crash and logs an error. Meant to be called via defer.
func HandleCrash() {
	if ReallyCrash {
		return
	}
	if r := recover(); r != nil {
		for _, fn := range PanicHandlers {
			fn(r)
		}
	}
}

// Deprecated. Please use Until and pass NeverStop as the stopCh.
func Forever(f func(), period time.Duration) {
	Until(f, period, nil)
}

// Until loops until stop channel is closed, running f every period.
// Catches any panics, and keeps going. f may not be invoked if
// stop channel is already closed.
func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
	for {
		select {
		case <-stopCh:
			return
		default:
		}
		func() {
			defer HandleCrash()
			f()
		}()
		time.Sleep(period)
	}
}

// logPanic logs the caller tree when a panic occurs.
func logPanic(r interface{}) {
	callers := ""
	for i := 0; true; i++ {
		_, file, line, ok := runtime.Caller(i)
		if !ok {
			break
		}
		callers = callers + fmt.Sprintf("%v:%v\n", file, line)
	}
	logger.Get().Error("Recovered from panic: %#v (%v)\n%v", r, r, callers)
}

func FailTask(msg string, err error, t *task.Task) {
	logger.Get().Error("%s: %v", msg, err)
	t.UpdateStatus("Failed. error: %v", err)
	t.Done(models.TASK_STATUS_FAILURE)
}

func GetString(param interface{}) (string, error) {
	if str, ok := param.(string); ok {
		return str, nil
	}
	return "", fmt.Errorf("Not a string")
}

func HTTPGet(url string) ([]byte, error) {
	response, err := http.Get(url)
	if err != nil {
		return nil, err
	} else {
		defer response.Body.Close()
		contents, err := ioutil.ReadAll(response.Body)
		if err != nil {
			return nil, err
		}
		return contents, nil
	}
}

func Md5FromString(name string) string {
	hash := md5.Sum([]byte(name))
	return hex.EncodeToString(hash[:])
}

func GetMapKeys(inMap interface{}) ([]reflect.Value, error) {
	inMapValue := reflect.ValueOf(inMap)
	if inMapValue.Kind() != reflect.Map {
		return nil, fmt.Errorf("Not a map!!")
	}
	keys := inMapValue.MapKeys()
	return keys, nil
}

func Stringify(keys []reflect.Value) (strings []string) {
	strings = make([]string, len(keys))
	for index, key := range keys {
		strings[index] = key.String()
	}
	return strings
}

func StringifyInterface(keys []interface{}) ([]string, error) {
	var stringKeys []string
	stringKeys = make([]string, len(keys))
	var err error
	var errString string
	for index, key := range keys {
		stringKeys[index], err = GetString(key)
		if err != nil {
			errString = errString + err.Error() + "\n"
		}
	}
	if errString != "" {
		errString = strings.TrimSpace(errString)
		return stringKeys, fmt.Errorf(errString)
	}
	return stringKeys, nil
}

func GenerifyStringArr(keys []string) []interface{} {
	iKeys := make([]interface{}, len(keys))
	for index, key := range keys {
		iKeys[index] = key
	}
	return iKeys
}

func StringSetDiff(keys1 []string, keys2 []string) (diff []string) {
	var unique bool
	for _, key1 := range keys1 {
		unique = true
		for _, key2 := range keys2 {
			if key1 == key2 {
				unique = false
				continue
			}
		}
		if unique {
			diff = append(diff, key1)
		}
	}
	return diff
}

func StringInSlice(value string, slice []string) bool {
	for _, item := range slice {
		if value == item {
			return true
		}
	}
	return false
}

func GetNodes(clusterNodes []models.ClusterNode) (map[uuid.UUID]models.Node, error) {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	var nodes = make(map[uuid.UUID]models.Node)
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	for _, clusterNode := range clusterNodes {
		uuid, err := uuid.Parse(clusterNode.NodeId)
		if err != nil {
			return nodes, errors.New(fmt.Sprintf("Error parsing node id: %v", clusterNode.NodeId))
		}
		var node models.Node
		if err := coll.Find(bson.M{"nodeid": *uuid}).One(&node); err != nil {
			return nodes, err
		}
		nodes[node.NodeId] = node
	}
	return nodes, nil
}

func UpdateThresholdInfoToTable(tEvent models.ThresholdEvent) (err error, isRaiseEvent bool) {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	collection := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_THRESHOLD_BREACHES)
	var tEventInDb models.ThresholdEvent
	selectCriteria := bson.M{
		"entityid":        tEvent.EntityId,
		"clusterid":       tEvent.ClusterId,
		"utilizationtype": tEvent.UtilizationType,
		"entityname":      tEvent.EntityName,
	}
	err = collection.Find(selectCriteria).One(&tEventInDb)
	if err != nil {
		if err == mgo.ErrNotFound {
			if tEvent.ThresholdSeverity == strings.ToUpper(models.STATUS_OK) {
				return nil, false
			}
			if err := collection.Insert(tEvent); err != nil {
				return fmt.Errorf("Failed to persist event %v to db.Error %v",
					tEvent, err), true
			}
			return nil, true
		}
	} else {
		if tEvent.ThresholdSeverity == tEventInDb.ThresholdSeverity {
			return nil, false
		} else if tEvent.ThresholdSeverity == models.STATUS_OK {
			if err = collection.Remove(selectCriteria); err != nil {
				return fmt.Errorf("Failed to update the db, that %v of %v is back to normal.Err %v",
					tEvent.UtilizationType, tEvent.EntityName, err), true
			}
			return nil, true
		} else {
			if err := collection.Update(selectCriteria, tEvent); err != nil {
				return fmt.Errorf("Failed to persist event %v to db.Error %v",
					tEvent, err), true
			}
			return nil, true
		}
	}
	return nil, false
}

func AnalyseThresholdBreach(ctxt string, utilizationType string, resourceName string, resourceUtilization float64, cluster models.Cluster) (models.Event, bool, error) {
	var event models.Event
	timeStamp := time.Now()
	plugin := cluster.Monitoring.Plugins[monitoring.GetPluginIndex(utilizationType, cluster.Monitoring.Plugins)]
	var applicableConfig monitoring.PluginConfig
	var applicableThresholdValue float64
	var message string

	var entityIdentifier string
	entityId, entityIdFetchError := getEntityIdFromNameAndUtilizationType(utilizationType, resourceName, cluster)
	if entityIdFetchError != nil {
		logger.Get().Error("%s - Error fetching the id for %v in cluster %v",
			ctxt, resourceName, cluster.Name)
		return models.Event{}, false, fmt.Errorf("%s - Error fetching the id for %v in cluster %v",
			ctxt, resourceName, cluster.Name)
	}
	entityIdentifier = (*entityId).String()

	for _, config := range plugin.Configs {
		if config.Category == monitoring.THRESHOLD {
			currentThresholdValue, thresholdValError := strconv.ParseFloat(config.Value, 64)
			if thresholdValError != nil {
				logger.Get().Error("%s - %v-%v configuration for %v in cluster %v could not be converted.Err %v\n",
					ctxt, config.Category, config.Type, plugin.Name, cluster.Name, thresholdValError)
			}

			if resourceUtilization > currentThresholdValue && applicableThresholdValue < currentThresholdValue {
				applicableConfig = config
				applicableThresholdValue = currentThresholdValue
			}
		}
	}

	if applicableConfig.Type == "" {
		applicableConfig.Type = models.STATUS_OK
		message = fmt.Sprintf("%v of cluster %v with value %v back to normal",
			plugin.Name, cluster.Name, resourceUtilization)
	}

	tEvent := models.ThresholdEvent{
		ClusterId:         cluster.ClusterId,
		UtilizationType:   plugin.Name,
		ThresholdSeverity: strings.ToUpper(applicableConfig.Type),
		TimeStamp:         timeStamp,
		EntityId:          *entityId,
		EntityName:        resourceName,
	}

	err, isRaiseEvent := UpdateThresholdInfoToTable(tEvent)
	if err != nil {
		logger.Get().Error("%s - %v", ctxt, err)
	}

	if isRaiseEvent {
		event = models.Event{
			Timestamp: timeStamp,
			ClusterId: cluster.ClusterId,
			NodeId:    cluster.ClusterId,
			Tag: fmt.Sprintf("skyring/%v/cluster/%v/threshold/%v/%v",
				cluster.Type, cluster.ClusterId, plugin.Name, strings.ToUpper(applicableConfig.Type)),
			Tags: map[string]string{
				models.CURRENT_VALUE:   strconv.FormatFloat(resourceUtilization, 'E', -1, 64),
				models.ENTITY_ID:       entityIdentifier,
				models.PLUGIN:          plugin.Name,
				models.THRESHOLD_TYPE:  strings.ToUpper(applicableConfig.Type),
				models.THRESHOLD_VALUE: strconv.FormatFloat(applicableThresholdValue, 'E', -1, 64),
				models.ENTITY_NAME:     resourceName,
			},
			Severity: strings.ToUpper(applicableConfig.Type),
		}
		if message == "" {
			message = fmt.Sprintf("%v of cluster %v with value %v breached %v threshold of value %v",
				plugin.Name, cluster.Name, resourceUtilization, strings.ToUpper(applicableConfig.Type), applicableThresholdValue)
		}
		event.Message = message
		return event, true, nil
	}
	return models.Event{}, false, nil
}

func getEntityIdFromNameAndUtilizationType(utilizationType string, resourceName string, cluster models.Cluster) (*uuid.UUID, error) {
	switch utilizationType {
	case monitoring.CLUSTER_UTILIZATION:
		return &(cluster.ClusterId), nil
	case monitoring.SLU_UTILIZATION:
		var slu models.StorageLogicalUnit
		err := getEntity(cluster.ClusterId, resourceName, models.COLL_NAME_STORAGE_LOGICAL_UNITS, &slu)
		if err != nil {
			return nil, fmt.Errorf("Could not fetch osd with name %v in cluster %v.Error %v",
				resourceName, cluster.Name, err)
		}
		return &(slu.SluId), nil
	case monitoring.STORAGE_UTILIZATION:
		var storage models.Storage
		err := getEntity(cluster.ClusterId, resourceName, models.COLL_NAME_STORAGE, &storage)
		if err != nil {
			return nil, fmt.Errorf("Could not fetch pool with name %v in cluster %v",
				storage.Name, cluster.Name)
		}
		return &(storage.StorageId), nil
	case monitoring.STORAGE_PROFILE_UTILIZATION:
		return &(cluster.ClusterId), nil
	case monitoring.BLOCK_DEVICE_UTILIZATION:
		var bDevice models.BlockDevice
		err := getEntity(cluster.ClusterId, resourceName, models.COLL_NAME_BLOCK_DEVICES, &bDevice)
		if err != nil {
			return nil, fmt.Errorf("Could not fetch block device with name %v in cluster %v.Error %v",
				resourceName, cluster.Name, err)
		}
		return &(bDevice.Id), nil
	}
	return nil, fmt.Errorf("Unsupported utilization type %v", utilizationType)
}

func getEntity(clusterId uuid.UUID, resourceName string, collectionName string, entity interface{}) error {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	collection := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(collectionName)
	if err := collection.Find(bson.M{"clusterid": clusterId, "name": resourceName}).One(entity); err != nil {
		return err
	}
	return nil
}

func GetNodesByIdStr(clusterNodes []models.ClusterNode) (map[string]models.Node, error) {
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	var nodes = make(map[string]models.Node)
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	for _, clusterNode := range clusterNodes {
		uuid, err := uuid.Parse(clusterNode.NodeId)
		if err != nil {
			return nodes, errors.New(fmt.Sprintf("Error parsing node id: %v", clusterNode.NodeId))
		}
		var node models.Node
		if err := coll.Find(bson.M{"nodeid": *uuid}).One(&node); err != nil {
			return nodes, err
		}
		nodes[clusterNode.NodeId] = node
	}
	return nodes, nil
}

func GetReadableFloat(str string, ctxt string) (string, error) {
	f, err := strconv.ParseFloat(str, 64)
	if err != nil {
		logger.Get().Error("%s-Could not parse the string: %s", ctxt, str)
		return str, err
	}
	return fmt.Sprintf("%.2f", f), nil
}
<|endoftext|>


<commit_before>package libnetwork

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

	"github.com/docker/libnetwork/driverapi"
	"github.com/docker/libnetwork/types"
)

// EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
type EndpointInfo interface {
	// Iface returns InterfaceInfo, go interface that can be used
	// to get more information on the interface which was assigned to
	// the endpoint by the driver. This can be used after the
	// endpoint has been created.
	Iface() InterfaceInfo

	// Gateway returns the IPv4 gateway assigned by the driver.
	// This will only return a valid value if a container has joined the endpoint.
	Gateway() net.IP

	// GatewayIPv6 returns the IPv6 gateway assigned by the driver.
	// This will only return a valid value if a container has joined the endpoint.
	GatewayIPv6() net.IP

	// Sandbox returns the attached sandbox if there, nil otherwise.
	Sandbox() Sandbox
}

// InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
type InterfaceInfo interface {
	// MacAddress returns the MAC address assigned to the endpoint.
	MacAddress() net.HardwareAddr

	// Address returns the IPv4 address assigned to the endpoint.
	Address() *net.IPNet

	// AddressIPv6 returns the IPv6 address assigned to the endpoint.
	AddressIPv6() *net.IPNet
}

type endpointInterface struct {
	mac       net.HardwareAddr
	addr      *net.IPNet
	addrv6    *net.IPNet
	srcName   string
	dstPrefix string
	routes    []*net.IPNet
	v4PoolID  string
	v6PoolID  string
}

func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
	epMap := make(map[string]interface{})
	if epi.mac != nil {
		epMap["mac"] = epi.mac.String()
	}
	if epi.addr != nil {
		epMap["addr"] = epi.addr.String()
	}
	if epi.addrv6 != nil {
		epMap["addrv6"] = epi.addrv6.String()
	}
	epMap["srcName"] = epi.srcName
	epMap["dstPrefix"] = epi.dstPrefix
	var routes []string
	for _, route := range epi.routes {
		routes = append(routes, route.String())
	}
	epMap["routes"] = routes
	epMap["v4PoolID"] = epi.v4PoolID
	epMap["v6PoolID"] = epi.v6PoolID
	return json.Marshal(epMap)
}

func (epi *endpointInterface) UnmarshalJSON(b []byte) error {
	var (
		err   error
		epMap map[string]interface{}
	)
	if err = json.Unmarshal(b, &epMap); err != nil {
		return err
	}
	if v, ok := epMap["mac"]; ok {
		if epi.mac, err = net.ParseMAC(v.(string)); err != nil {
			return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string))
		}
	}
	if v, ok := epMap["addr"]; ok {
		if epi.addr, err = types.ParseCIDR(v.(string)); err != nil {
			return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err)
		}
	}
	if v, ok := epMap["addrv6"]; ok {
		if epi.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
			return types.InternalErrorf("failed to decode endpoint interface ipv6 address after json unmarshal: %v", err)
		}
	}

	epi.srcName = epMap["srcName"].(string)
	epi.dstPrefix = epMap["dstPrefix"].(string)

	rb, _ := json.Marshal(epMap["routes"])
	var routes []string
	json.Unmarshal(rb, &routes)
	epi.routes = make([]*net.IPNet, 0)
	for _, route := range routes {
		ip, ipr, err := net.ParseCIDR(route)
		if err == nil {
			ipr.IP = ip
			epi.routes = append(epi.routes, ipr)
		}
	}
	epi.v4PoolID = epMap["v4PoolID"].(string)
	epi.v6PoolID = epMap["v6PoolID"].(string)

	return nil
}

func (epi *endpointInterface) CopyTo(dstEpi *endpointInterface) error {
	dstEpi.mac = types.GetMacCopy(epi.mac)
	dstEpi.addr = types.GetIPNetCopy(epi.addr)
	dstEpi.addrv6 = types.GetIPNetCopy(epi.addrv6)
	dstEpi.srcName = epi.srcName
	dstEpi.dstPrefix = epi.dstPrefix
	dstEpi.v4PoolID = epi.v4PoolID
	dstEpi.v6PoolID = epi.v6PoolID

	for _, route := range epi.routes {
		dstEpi.routes = append(dstEpi.routes, types.GetIPNetCopy(route))
	}

	return nil
}

type endpointJoinInfo struct {
	gw           net.IP
	gw6          net.IP
	StaticRoutes []*types.StaticRoute
}

func (ep *endpoint) Info() EndpointInfo {
	n, err := ep.getNetworkFromStore()
	if err != nil {
		return nil
	}

	ep, err = n.getEndpointFromStore(ep.ID())
	if err != nil {
		return nil
	}

	sb, ok := ep.getSandbox()
	if !ok {
		// endpoint hasn't joined any sandbox.
		// Just return the endpoint
		return ep
	}

	return sb.getEndpoint(ep.ID())
}

func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
	ep, err := ep.retrieveFromStore()
	if err != nil {
		return nil, err
	}

	if sb, ok := ep.getSandbox(); ok {
		if gwep := sb.getEndpointInGWNetwork(); gwep != nil && gwep.ID() != ep.ID() {
			return gwep.DriverInfo()
		}
	}

	n, err := ep.getNetworkFromStore()
	if err != nil {
		return nil, fmt.Errorf("could not find network in store for driver info: %v", err)
	}

	driver, err := n.driver()
	if err != nil {
		return nil, fmt.Errorf("failed to get driver info: %v", err)
	}

	return driver.EndpointOperInfo(n.ID(), ep.ID())
}

func (ep *endpoint) Iface() InterfaceInfo {
	ep.Lock()
	defer ep.Unlock()

	if ep.iface != nil {
		return ep.iface
	}

	return nil
}

func (ep *endpoint) Interface() driverapi.InterfaceInfo {
	ep.Lock()
	defer ep.Unlock()

	if ep.iface != nil {
		return ep.iface
	}

	return nil
}

func (epi *endpointInterface) SetMacAddress(mac net.HardwareAddr) error {
	if epi.mac != nil {
		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac)
	}
	if mac == nil {
		return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
	}
	epi.mac = types.GetMacCopy(mac)
	return nil
}

func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error {
	if address.IP == nil {
		return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
	}
	if address.IP.To4() == nil {
		return setAddress(&epi.addrv6, address)
	}
	return setAddress(&epi.addr, address)
}

func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
	if *ifaceAddr != nil {
		return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
	}
	*ifaceAddr = types.GetIPNetCopy(address)
	return nil
}

func (epi *endpointInterface) MacAddress() net.HardwareAddr {
	return types.GetMacCopy(epi.mac)
}

func (epi *endpointInterface) Address() *net.IPNet {
	return types.GetIPNetCopy(epi.addr)
}

func (epi *endpointInterface) AddressIPv6() *net.IPNet {
	return types.GetIPNetCopy(epi.addrv6)
}

func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
	epi.srcName = srcName
	epi.dstPrefix = dstPrefix
	return nil
}

func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo {
	ep.Lock()
	defer ep.Unlock()

	if ep.iface != nil {
		return ep.iface
	}

	return nil
}

func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
	ep.Lock()
	defer ep.Unlock()

	r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop}

	if routeType == types.NEXTHOP {
		// If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface).
		ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &r)
	} else {
		// If the route doesn't specify a next-hop, it must be a connected route, bound to an interface.
		ep.iface.routes = append(ep.iface.routes, r.Destination)
	}
	return nil
}

func (ep *endpoint) Sandbox() Sandbox {
	cnt, ok := ep.getSandbox()
	if !ok {
		return nil
	}
	return cnt
}

func (ep *endpoint) Gateway() net.IP {
	ep.Lock()
	defer ep.Unlock()

	if ep.joinInfo == nil {
		return net.IP{}
	}

	return types.GetIPCopy(ep.joinInfo.gw)
}

func (ep *endpoint) GatewayIPv6() net.IP {
	ep.Lock()
	defer ep.Unlock()

	if ep.joinInfo == nil {
		return net.IP{}
	}

	return types.GetIPCopy(ep.joinInfo.gw6)
}

func (ep *endpoint) SetGateway(gw net.IP) error {
	ep.Lock()
	defer ep.Unlock()

	ep.joinInfo.gw = types.GetIPCopy(gw)
	return nil
}

func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
	ep.Lock()
	defer ep.Unlock()

	ep.joinInfo.gw6 = types.GetIPCopy(gw6)
	return nil
}

func (ep *endpoint) retrieveFromStore() (*endpoint, error) {
	n, err := ep.getNetworkFromStore()
	if err != nil {
		return nil, fmt.Errorf("could not find network in store to get latest endpoint %s: %v", ep.Name(), err)
	}
	return n.getEndpointFromStore(ep.ID())
}
<commit_msg>Fix in endpoint Info() method<commit_after>package libnetwork

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

	"github.com/docker/libnetwork/driverapi"
	"github.com/docker/libnetwork/types"
)

// EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
type EndpointInfo interface {
	// Iface returns InterfaceInfo, go interface that can be used
	// to get more information on the interface which was assigned to
	// the endpoint by the driver. This can be used after the
	// endpoint has been created.
	Iface() InterfaceInfo

	// Gateway returns the IPv4 gateway assigned by the driver.
	// This will only return a valid value if a container has joined the endpoint.
	Gateway() net.IP

	// GatewayIPv6 returns the IPv6 gateway assigned by the driver.
	// This will only return a valid value if a container has joined the endpoint.
	GatewayIPv6() net.IP

	// Sandbox returns the attached sandbox if there, nil otherwise.
	Sandbox() Sandbox
}

// InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
type InterfaceInfo interface {
	// MacAddress returns the MAC address assigned to the endpoint.
	MacAddress() net.HardwareAddr

	// Address returns the IPv4 address assigned to the endpoint.
	Address() *net.IPNet

	// AddressIPv6 returns the IPv6 address assigned to the endpoint.
	AddressIPv6() *net.IPNet
}

type endpointInterface struct {
	mac       net.HardwareAddr
	addr      *net.IPNet
	addrv6    *net.IPNet
	srcName   string
	dstPrefix string
	routes    []*net.IPNet
	v4PoolID  string
	v6PoolID  string
}

func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
	epMap := make(map[string]interface{})
	if epi.mac != nil {
		epMap["mac"] = epi.mac.String()
	}
	if epi.addr != nil {
		epMap["addr"] = epi.addr.String()
	}
	if epi.addrv6 != nil {
		epMap["addrv6"] = epi.addrv6.String()
	}
	epMap["srcName"] = epi.srcName
	epMap["dstPrefix"] = epi.dstPrefix
	var routes []string
	for _, route := range epi.routes {
		routes = append(routes, route.String())
	}
	epMap["routes"] = routes
	epMap["v4PoolID"] = epi.v4PoolID
	epMap["v6PoolID"] = epi.v6PoolID
	return json.Marshal(epMap)
}

func (epi *endpointInterface) UnmarshalJSON(b []byte) error {
	var (
		err   error
		epMap map[string]interface{}
	)
	if err = json.Unmarshal(b, &epMap); err != nil {
		return err
	}
	if v, ok := epMap["mac"]; ok {
		if epi.mac, err = net.ParseMAC(v.(string)); err != nil {
			return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string))
		}
	}
	if v, ok := epMap["addr"]; ok {
		if epi.addr, err = types.ParseCIDR(v.(string)); err != nil {
			return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err)
		}
	}
	if v, ok := epMap["addrv6"]; ok {
		if epi.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
			return types.InternalErrorf("failed to decode endpoint interface ipv6 address after json unmarshal: %v", err)
		}
	}

	epi.srcName = epMap["srcName"].(string)
	epi.dstPrefix = epMap["dstPrefix"].(string)

	rb, _ := json.Marshal(epMap["routes"])
	var routes []string
	json.Unmarshal(rb, &routes)
	epi.routes = make([]*net.IPNet, 0)
	for _, route := range routes {
		ip, ipr, err := net.ParseCIDR(route)
		if err == nil {
			ipr.IP = ip
			epi.routes = append(epi.routes, ipr)
		}
	}
	epi.v4PoolID = epMap["v4PoolID"].(string)
	epi.v6PoolID = epMap["v6PoolID"].(string)

	return nil
}

func (epi *endpointInterface) CopyTo(dstEpi *endpointInterface) error {
	dstEpi.mac = types.GetMacCopy(epi.mac)
	dstEpi.addr = types.GetIPNetCopy(epi.addr)
	dstEpi.addrv6 = types.GetIPNetCopy(epi.addrv6)
	dstEpi.srcName = epi.srcName
	dstEpi.dstPrefix = epi.dstPrefix
	dstEpi.v4PoolID = epi.v4PoolID
	dstEpi.v6PoolID = epi.v6PoolID

	for _, route := range epi.routes {
		dstEpi.routes = append(dstEpi.routes, types.GetIPNetCopy(route))
	}

	return nil
}

type endpointJoinInfo struct {
	gw           net.IP
	gw6          net.IP
	StaticRoutes []*types.StaticRoute
}

func (ep *endpoint) Info() EndpointInfo {
	n, err := ep.getNetworkFromStore()
	if err != nil {
		return nil
	}

	ep, err = n.getEndpointFromStore(ep.ID())
	if err != nil {
		return nil
	}

	sb, ok := ep.getSandbox()
	if !ok {
		// endpoint hasn't joined any sandbox.
		// Just return the endpoint
		return ep
	}

	if epi := sb.getEndpoint(ep.ID()); epi != nil {
		return epi
	}

	return nil
}

func (ep *endpoint) DriverInfo() (map[string]interface{}, error) {
	ep, err := ep.retrieveFromStore()
	if err != nil {
		return nil, err
	}

	if sb, ok := ep.getSandbox(); ok {
		if gwep := sb.getEndpointInGWNetwork(); gwep != nil && gwep.ID() != ep.ID() {
			return gwep.DriverInfo()
		}
	}

	n, err := ep.getNetworkFromStore()
	if err != nil {
		return nil, fmt.Errorf("could not find network in store for driver info: %v", err)
	}

	driver, err := n.driver()
	if err != nil {
		return nil, fmt.Errorf("failed to get driver info: %v", err)
	}

	return driver.EndpointOperInfo(n.ID(), ep.ID())
}

func (ep *endpoint) Iface() InterfaceInfo {
	ep.Lock()
	defer ep.Unlock()

	if ep.iface != nil {
		return ep.iface
	}

	return nil
}

func (ep *endpoint) Interface() driverapi.InterfaceInfo {
	ep.Lock()
	defer ep.Unlock()

	if ep.iface != nil {
		return ep.iface
	}

	return nil
}

func (epi *endpointInterface) SetMacAddress(mac net.HardwareAddr) error {
	if epi.mac != nil {
		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac)
	}
	if mac == nil {
		return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
	}
	epi.mac = types.GetMacCopy(mac)
	return nil
}

func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error {
	if address.IP == nil {
		return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
	}
	if address.IP.To4() == nil {
		return setAddress(&epi.addrv6, address)
	}
	return setAddress(&epi.addr, address)
}

func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
	if *ifaceAddr != nil {
		return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
	}
	*ifaceAddr = types.GetIPNetCopy(address)
	return nil
}

func (epi *endpointInterface) MacAddress() net.HardwareAddr {
	return types.GetMacCopy(epi.mac)
}

func (epi *endpointInterface) Address() *net.IPNet {
	return types.GetIPNetCopy(epi.addr)
}

func (epi *endpointInterface) AddressIPv6() *net.IPNet {
	return types.GetIPNetCopy(epi.addrv6)
}

func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
	epi.srcName = srcName
	epi.dstPrefix = dstPrefix
	return nil
}

func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo {
	ep.Lock()
	defer ep.Unlock()

	if ep.iface != nil {
		return ep.iface
	}

	return nil
}

func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
	ep.Lock()
	defer ep.Unlock()

	r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop}

	if routeType == types.NEXTHOP {
		// If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface).
		ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &r)
	} else {
		// If the route doesn't specify a next-hop, it must be a connected route, bound to an interface.
		ep.iface.routes = append(ep.iface.routes, r.Destination)
	}
	return nil
}

func (ep *endpoint) Sandbox() Sandbox {
	cnt, ok := ep.getSandbox()
	if !ok {
		return nil
	}
	return cnt
}

func (ep *endpoint) Gateway() net.IP {
	ep.Lock()
	defer ep.Unlock()

	if ep.joinInfo == nil {
		return net.IP{}
	}

	return types.GetIPCopy(ep.joinInfo.gw)
}

func (ep *endpoint) GatewayIPv6() net.IP {
	ep.Lock()
	defer ep.Unlock()

	if ep.joinInfo == nil {
		return net.IP{}
	}

	return types.GetIPCopy(ep.joinInfo.gw6)
}

func (ep *endpoint) SetGateway(gw net.IP) error {
	ep.Lock()
	defer ep.Unlock()

	ep.joinInfo.gw = types.GetIPCopy(gw)
	return nil
}

func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
	ep.Lock()
	defer ep.Unlock()

	ep.joinInfo.gw6 = types.GetIPCopy(gw6)
	return nil
}

func (ep *endpoint) retrieveFromStore() (*endpoint, error) {
	n, err := ep.getNetworkFromStore()
	if err != nil {
		return nil, fmt.Errorf("could not find network in store to get latest endpoint %s: %v", ep.Name(), err)
	}
	return n.getEndpointFromStore(ep.ID())
}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker, Inc.

   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 cmd

import (
	"context"
	"fmt"
	"strings"

	"github.com/hashicorp/go-multierror"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"

	"github.com/docker/compose-cli/client"
	"github.com/docker/compose-cli/containers"
	"github.com/docker/compose-cli/errdefs"
)

type rmOpts struct {
	force bool
}

// RmCommand deletes containers
func RmCommand() *cobra.Command {
	var opts rmOpts
	cmd := &cobra.Command{
		Use:     "rm",
		Aliases: []string{"delete"},
		Short:   "Remove containers",
		Args:    cobra.MinimumNArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return runRm(cmd.Context(), args, opts)
		},
	}

	cmd.Flags().BoolVarP(&opts.force, "force", "f", false, "Force removal")

	return cmd
}

func runRm(ctx context.Context, args []string, opts rmOpts) error {
	c, err := client.New(ctx)
	if err != nil {
		return errors.Wrap(err, "cannot connect to backend")
	}

	var errs *multierror.Error
	for _, id := range args {
		err := c.ContainerService().Delete(ctx, id, containers.DeleteRequest{
			Force: opts.force,
		})
		if err != nil {
			if errdefs.IsForbiddenError(err) {
				errs = multierror.Append(errs, fmt.Errorf("you cannot remove a running container %s. Stop the container before attempting removal or force remove", id))
			} else if errdefs.IsNotFoundError(err) {
				errs = multierror.Append(errs, fmt.Errorf("container %s not found", id))
			} else {
				errs = multierror.Append(errs, err)
			}
			continue
		}

		fmt.Println(id)
	}
	if errs != nil {
		errs.ErrorFormat = formatErrors
	}
	return errs.ErrorOrNil()
}

func formatErrors(errs []error) string {
	messages := make([]string, len(errs))
	for i, err := range errs {
		messages[i] = "Error: " + err.Error()
	}
	return strings.Join(messages, "\n")
}
<commit_msg>Remove delete alias, no reason to add this (does not exist in Moby)<commit_after>/*
   Copyright 2020 Docker, Inc.

   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 cmd

import (
	"context"
	"fmt"
	"strings"

	"github.com/hashicorp/go-multierror"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"

	"github.com/docker/compose-cli/client"
	"github.com/docker/compose-cli/containers"
	"github.com/docker/compose-cli/errdefs"
)

type rmOpts struct {
	force bool
}

// RmCommand deletes containers
func RmCommand() *cobra.Command {
	var opts rmOpts
	cmd := &cobra.Command{
		Use:   "rm",
		Short: "Remove containers",
		Args:  cobra.MinimumNArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			return runRm(cmd.Context(), args, opts)
		},
	}

	cmd.Flags().BoolVarP(&opts.force, "force", "f", false, "Force removal")

	return cmd
}

func runRm(ctx context.Context, args []string, opts rmOpts) error {
	c, err := client.New(ctx)
	if err != nil {
		return errors.Wrap(err, "cannot connect to backend")
	}

	var errs *multierror.Error
	for _, id := range args {
		err := c.ContainerService().Delete(ctx, id, containers.DeleteRequest{
			Force: opts.force,
		})
		if err != nil {
			if errdefs.IsForbiddenError(err) {
				errs = multierror.Append(errs, fmt.Errorf("you cannot remove a running container %s. Stop the container before attempting removal or force remove", id))
			} else if errdefs.IsNotFoundError(err) {
				errs = multierror.Append(errs, fmt.Errorf("container %s not found", id))
			} else {
				errs = multierror.Append(errs, err)
			}
			continue
		}

		fmt.Println(id)
	}
	if errs != nil {
		errs.ErrorFormat = formatErrors
	}
	return errs.ErrorOrNil()
}

func formatErrors(errs []error) string {
	messages := make([]string, len(errs))
	for i, err := range errs {
		messages[i] = "Error: " + err.Error()
	}
	return strings.Join(messages, "\n")
}
<|endoftext|>


<commit_before>// Package cli provides a CLI UI for the getstocks command line tool.
package cli

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/mmbros/getstocks/run"
	"github.com/naoina/toml"
)

const (
	// name of the command line parameters
	clConfig    = "c"
	clDebug     = "d"
	clGenConfig = "g"
	clHelp      = "h"
	clOutput    = "o"

	// default values
	defaultConfigFile = "data-crypt/getstocks.cfg"
	defaultOutputFile = "" // if empty use StdOut
)

type clArgs struct {
	config    string
	debug     bool
	genConfig bool
	help      bool
	output    string
}

type configScraper struct {
	Name     string
	Workers  int
	Disabled bool
}

type configStock struct {
	Name        string
	Isin        string
	Description string
	Disabled    bool
	Urls        []string            `toml:"urls"`
	Sources     []configStockSource `toml:"source"`
}

type configStockSource struct {
	Scraper  string
	URL      string
	Disabled bool
}

type config struct {
	Scrapers []*configScraper `toml:"scraper"`
	Stocks   []*configStock   `toml:"stock"`
}

func (cfg *config) Print() {
	for j, s := range cfg.Scrapers {
		fmt.Printf("Scrapers[%d] %v\n", j, s)
	}
	for j, s := range cfg.Stocks {
		fmt.Printf("\nStocks[%d] %v\n", j, s)
	}
}

func unmarshalConfig(data []byte) (*config, error) {
	// parse config file
	var cfg config
	if err := toml.Unmarshal(data, &cfg); err != nil {
		return nil, err
	}

	// check scrapers
	setScrapers := run.NewSet()
	for _, scraper := range cfg.Scrapers {
		if len(scraper.Name) == 0 {
			return nil, errors.New("Invalid scraper: name must be defined")
		}
		if !setScrapers.Add(scraper.Name) {
			return nil, fmt.Errorf("Invalid scraper: name already used: %q", scraper.Name)
		}
	}

	// check stocks
	setStocks := run.NewSet()
	for _, stock := range cfg.Stocks {
		if len(stock.Name) == 0 {
			return nil, errors.New("Invalid stock: name must be defined")
		}
		if !setStocks.Add(stock.Name) {
			return nil, fmt.Errorf("Invalid stock: name already used: %q", stock.Name)
		}

	}

	return &cfg, nil
}

// loadConfigFromFile returns the configuration from a configuration file
func loadConfigFromFile(path string) (*config, error) {
	// open config file
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	// read config file
	buf, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	return unmarshalConfig(buf)
}

func cmdHelp() {
	fmt.Fprintln(os.Stderr, `Usage: getstocks [OPTION]...

getstocks retrives stocks quotes from web sites.
`)
}

func parseArgs() *clArgs {
	var args clArgs

	// command line arguments
	flag.StringVar(&args.config, clConfig, defaultConfigFile, "Configuration file used to generate the package.")
	flag.StringVar(&args.output, clOutput, defaultOutputFile, "Optional output file for package/config file. If empty stdout will be used.")
	flag.BoolVar(&args.debug, clDebug, false, "Debug mode. Do not cache templates and do not format generated code.")
	flag.BoolVar(&args.help, clHelp, false, "Show command usage information.")
	flag.BoolVar(&args.genConfig, clGenConfig, false, "Generate the configuration file instead of the package.")

	flag.Parse()

	return &args
}

// parseConfig returns the configuration from command line parameters,
// config parameters and defaults
func parseConfig(args *clArgs) (*config, error) {

	// init config from the config file
	cfg, err := loadConfigFromFile(args.config)
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

func getRunArgs(cfg *config) ([]*run.Scraper, []*run.Stock, error) {
	disabledScrapers := run.NewSet()
	workers := map[string]int{}
	//usedScrapers := map[string]*run.Scraper{}

	stocks := make([]*run.Stock, 0, len(cfg.Stocks))

	for _, scr := range cfg.Scrapers {
		if scr.Disabled {
			disabledScrapers.Add(scr.Name)
			continue
		}
		workers[scr.Name] = scr.Workers
	}

	// Builds the stock array skipping only the esplicitly disabled stocks.
	// Stocks not disabled will be added even if without any valid source
	// in order to considered in the output result.
	for _, stock := range cfg.Stocks {
		if stock.Disabled {
			continue
		}

		// Builds array of StockSource from urls and sources.
		asrc := make([]*run.StockSource, 0, len(stock.Sources)+len(stock.Urls))

		// Checks stock.sources.
		for _, source := range stock.Sources {
			var err error
			if source.Disabled {
				continue
			}

			// Gets scraper name, if empty.
			if source.Scraper == "" {
				source.Scraper, err = run.GetScraperFromUrl(source.URL)
				//log.Printf("GetScraperFromUrl(%q) -> %s, %v", source.URL, source.Scraper, err)
			}
			// Skip if scraper is disabled.
			if disabledScrapers.Contains(source.Scraper) {
				continue
			}
			// Checks error eventually returned by GetScraperFromUrl.
			if err != nil {
				return nil, nil, err
			}
			// Append the new source to the list.
			asrc = append(asrc, &run.StockSource{
				Scraper: source.Scraper,
				URL:     source.URL,
			})
		}

		// Check stock.urls.
		for _, url := range stock.Urls {
			scraper, err := run.GetScraperFromUrl(url)
			// skip if scraper is disabled
			if disabledScrapers.Contains(scraper) {
				continue
			}
			// Checks error eventually returned by GetScraperFromUrl.
			if err != nil {
				return nil, nil, err
			}
			// append the new source to the list
			asrc = append(asrc, &run.StockSource{
				Scraper: scraper,
				URL:     url,
			})
		}
		// append the stock
		stocks = append(stocks, &run.Stock{
			Name:        stock.Name,
			Isin:        stock.Isin,
			Description: stock.Description,
			Sources:     asrc,
		})
	}

	// build scrapers array (only)
	scrapers := make([]*run.Scraper, 0, len(workers))
	for name, workers := range workers {
		scrapers = append(scrapers, &run.Scraper{
			Name:    name,
			Workers: workers,
		})
	}

	return scrapers, stocks, nil
}

func Run() int {
	const msghelp = "Try 'getstocks -h' for more information."

	args := parseArgs()

	if args.help {
		cmdHelp()
		return 0
	}

	// check config file exists
	if _, err := os.Stat(args.config); os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "Configuration file %q not found.\n%s\n", args.config, msghelp)
		return 2
	}

	// read config file
	cfg, err := parseConfig(args)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		return 2
	}
	cfg.Print()

	scrapers, stocks, err := getRunArgs(cfg)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		return 2
	}

	fmt.Println("**** SCRAPERS *****")
	for i, s := range scrapers {
		fmt.Printf("[%d] %+v\n", i+1, s)
	}
	fmt.Println("**** STOCKS  *****")
	for i, s := range stocks {
		fmt.Printf("[%d] %-20s  (%s)\n", i+1, s.Name, s.Isin)
		for _, src := range s.Sources {
			fmt.Printf("    - %s\n", src.URL)
		}
	}

	ctx := context.Background()
	out, err := run.Execute(ctx, scrapers, stocks)

	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		return 1
	}
	for response := range out {
		fmt.Printf("response = %+v\n", response)
	}

	return 0
}
<commit_msg>changed cli.Run function<commit_after>// Package cli provides a CLI UI for the getstocks command line tool.
package cli

import (
	"context"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os"

	"github.com/mmbros/getstocks/run"
	"github.com/naoina/toml"
)

const (
	// name of the command line parameters
	clConfig    = "c"
	clDebug     = "d"
	clGenConfig = "g"
	clHelp      = "h"
	clOutput    = "o"

	// default values
	defaultConfigFile = "data-crypt/getstocks.cfg"
	defaultOutputFile = "" // if empty use StdOut
)

type clArgs struct {
	config    string
	debug     bool
	genConfig bool
	help      bool
	output    string
}

type configScraper struct {
	Name     string
	Workers  int
	Disabled bool
}

type configStock struct {
	Name        string
	Isin        string
	Description string
	Disabled    bool
	Urls        []string            `toml:"urls"`
	Sources     []configStockSource `toml:"source"`
}

type configStockSource struct {
	Scraper  string
	URL      string
	Disabled bool
}

type config struct {
	Scrapers []*configScraper `toml:"scraper"`
	Stocks   []*configStock   `toml:"stock"`
}

func (cfg *config) Print() {
	for j, s := range cfg.Scrapers {
		fmt.Printf("Scrapers[%d] %v\n", j, s)
	}
	for j, s := range cfg.Stocks {
		fmt.Printf("\nStocks[%d] %v\n", j, s)
	}
}

func unmarshalConfig(data []byte) (*config, error) {
	// parse config file
	var cfg config
	if err := toml.Unmarshal(data, &cfg); err != nil {
		return nil, err
	}

	// check scrapers
	setScrapers := run.NewSet()
	for _, scraper := range cfg.Scrapers {
		if len(scraper.Name) == 0 {
			return nil, errors.New("Invalid scraper: name must be defined")
		}
		if !setScrapers.Add(scraper.Name) {
			return nil, fmt.Errorf("Invalid scraper: name already used: %q", scraper.Name)
		}
	}

	// check stocks
	setStocks := run.NewSet()
	for _, stock := range cfg.Stocks {
		if len(stock.Name) == 0 {
			return nil, errors.New("Invalid stock: name must be defined")
		}
		if !setStocks.Add(stock.Name) {
			return nil, fmt.Errorf("Invalid stock: name already used: %q", stock.Name)
		}

	}

	return &cfg, nil
}

// loadConfigFromFile returns the configuration from a configuration file
func loadConfigFromFile(path string) (*config, error) {
	// open config file
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	// read config file
	buf, err := ioutil.ReadAll(f)
	if err != nil {
		return nil, err
	}
	return unmarshalConfig(buf)
}

func cmdHelp() {
	fmt.Fprintln(os.Stderr, `Usage: getstocks [OPTION]...

getstocks retrives stocks quotes from web sites.
`)
}

func parseArgs() *clArgs {
	var args clArgs

	// command line arguments
	flag.StringVar(&args.config, clConfig, defaultConfigFile, "Configuration file used to generate the package.")
	flag.StringVar(&args.output, clOutput, defaultOutputFile, "Optional output file for package/config file. If empty stdout will be used.")
	flag.BoolVar(&args.debug, clDebug, false, "Debug mode. Do not cache templates and do not format generated code.")
	flag.BoolVar(&args.help, clHelp, false, "Show command usage information.")
	flag.BoolVar(&args.genConfig, clGenConfig, false, "Generate the configuration file instead of the package.")

	flag.Parse()

	return &args
}

// parseConfig returns the configuration from command line parameters,
// config parameters and defaults
func parseConfig(args *clArgs) (*config, error) {

	// init config from the config file
	cfg, err := loadConfigFromFile(args.config)
	if err != nil {
		return nil, err
	}

	return cfg, nil
}

func getRunArgs(cfg *config) ([]*run.Scraper, []*run.Stock, error) {
	disabledScrapers := run.NewSet()
	workers := map[string]int{}
	//usedScrapers := map[string]*run.Scraper{}

	stocks := make([]*run.Stock, 0, len(cfg.Stocks))

	for _, scr := range cfg.Scrapers {
		if scr.Disabled {
			disabledScrapers.Add(scr.Name)
			continue
		}
		workers[scr.Name] = scr.Workers
	}

	// Builds the stock array skipping only the esplicitly disabled stocks.
	// Stocks not disabled will be added even if without any valid source
	// in order to considered in the output result.
	for _, stock := range cfg.Stocks {
		if stock.Disabled {
			continue
		}

		// Builds array of StockSource from urls and sources.
		asrc := make([]*run.StockSource, 0, len(stock.Sources)+len(stock.Urls))

		// Checks stock.sources.
		for _, source := range stock.Sources {
			var err error
			if source.Disabled {
				continue
			}

			// Gets scraper name, if empty.
			if source.Scraper == "" {
				source.Scraper, err = run.GetScraperFromUrl(source.URL)
				//log.Printf("GetScraperFromUrl(%q) -> %s, %v", source.URL, source.Scraper, err)
			}
			// Skip if scraper is disabled.
			if disabledScrapers.Contains(source.Scraper) {
				continue
			}
			// Checks error eventually returned by GetScraperFromUrl.
			if err != nil {
				return nil, nil, err
			}
			// Append the new source to the list.
			asrc = append(asrc, &run.StockSource{
				Scraper: source.Scraper,
				URL:     source.URL,
			})
		}

		// Check stock.urls.
		for _, url := range stock.Urls {
			scraper, err := run.GetScraperFromUrl(url)
			// skip if scraper is disabled
			if disabledScrapers.Contains(scraper) {
				continue
			}
			// Checks error eventually returned by GetScraperFromUrl.
			if err != nil {
				return nil, nil, err
			}
			// append the new source to the list
			asrc = append(asrc, &run.StockSource{
				Scraper: scraper,
				URL:     url,
			})
		}
		// append the stock
		stocks = append(stocks, &run.Stock{
			Name:        stock.Name,
			Isin:        stock.Isin,
			Description: stock.Description,
			Sources:     asrc,
		})
	}

	// build scrapers array (only)
	scrapers := make([]*run.Scraper, 0, len(workers))
	for name, workers := range workers {
		scrapers = append(scrapers, &run.Scraper{
			Name:    name,
			Workers: workers,
		})
	}

	return scrapers, stocks, nil
}

func doJob(scrapers []*run.Scraper, stocks []*run.Stock) error {

	ctx := context.Background()
	out, err := run.Execute(ctx, scrapers, stocks)

	if err != nil {
		return err
	}
	for r := range out {
		fmt.Printf("%-20s  %4.3f %s\n", r.StockName, r.Result.Price, r.Result.Date.Format("02/01/2006"))
	}
	return nil
}

func Run() int {
	const msghelp = "Try 'getstocks -h' for more information."

	args := parseArgs()

	if args.help {
		cmdHelp()
		return 0
	}

	// check config file exists
	if _, err := os.Stat(args.config); os.IsNotExist(err) {
		fmt.Fprintf(os.Stderr, "Configuration file %q not found.\n%s\n", args.config, msghelp)
		return 2
	}

	// read config file
	cfg, err := parseConfig(args)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		return 2
	}
	cfg.Print()

	scrapers, stocks, err := getRunArgs(cfg)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		return 2
	}

	//fmt.Println("**** SCRAPERS *****")
	//for i, s := range scrapers {
	//fmt.Printf("[%d] %+v\n", i+1, s)
	//}
	//fmt.Println("**** STOCKS  *****")
	//for i, s := range stocks {
	//fmt.Printf("[%d] %-20s  (%s)\n", i+1, s.Name, s.Isin)
	//for _, src := range s.Sources {
	//fmt.Printf("    - %s\n", src.URL)
	//}
	//}
	err = doJob(scrapers, stocks)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		return 1
	}

	return 0
}
<|endoftext|>


<commit_before>package cli

import (
	"bytes"
	"errors"
	"fmt"
	"os"
)

// To add a module, implement this interface
// Definition is the command definition
// Exec is the behaviour that you want to implement as a command
type Command interface {
	Definition() string
	Exec() error
}

type Module struct {
	Children   map[string]*Module
	Command    Command
	Definition string
}

func NewModule(name string, definition string) *Module {
	return &Module{Children: make(map[string]*Module, 0), Definition: definition}
}

func NewCommandModule(command Command) *Module {
	return &Module{Command: command}
}

func (m *Module) AddCommand(name string, command Command) *Module {
	child := NewCommandModule(command)
	m.Children[name] = child
	return child
}

func (m *Module) AddModule(name string, definition string) *Module {
	child := NewModule(name, definition)
	m.Children[name] = child
	return child
}

func (m *Module) FindModule(args []string) (*Module, error) {
	moduleWalker := m
	var errStr bytes.Buffer
	for i := 0; i < len(args); i, moduleWalker = i+1, moduleWalker.Children[args[i]] {
		module := moduleWalker.Children[args[i]]
		if module == nil {
			errStr.WriteString(fmt.Sprintf("Command %s not found\n\n", args[i]))
			break
		}
		if module.Command == nil {
			continue
		}
		// command behaves like a subprocess, it will parse arguments again
		// so we re discarding parsed arguments
		temp := os.Args
		os.Args = []string{temp[0]}
		os.Args = append(os.Args, temp[i+2:]...)
		return module, nil
	}
	errStr.WriteString(moduleWalker.printPossibleCommands())
	return nil, errors.New(errStr.String())
}

func (m *Module) printPossibleCommands() string {
	var buffer bytes.Buffer
	buffer.WriteString("Possible commands: \n")
	for n, module := range m.Children {
		buffer.WriteString(fmt.Sprintf("  %-10s  ", n))
		var definition string
		if module.Command != nil {
			definition = module.Command.Definition()
		} else {
			definition = module.Definition
		}
		buffer.WriteString(fmt.Sprintf("%s\n", definition))
	}
	return buffer.String()
}
<commit_msg>treewalker refactored<commit_after>package cli

import (
	"bytes"
	"errors"
	"fmt"
	"os"
)

// To add a module, implement this interface
// Definition is the command definition
// Exec is the behaviour that you want to implement as a command
type Command interface {
	Definition() string
	Exec() error
}

type Module struct {
	Children   map[string]*Module
	Command    Command
	Definition string
}

func NewModule(name string, definition string) *Module {
	return &Module{Children: make(map[string]*Module, 0), Definition: definition}
}

func NewCommandModule(command Command) *Module {
	return &Module{Command: command}
}

func (m *Module) AddCommand(name string, command Command) *Module {
	child := NewCommandModule(command)
	m.Children[name] = child
	return child
}

func (m *Module) AddModule(name string, definition string) *Module {
	child := NewModule(name, definition)
	m.Children[name] = child
	return child
}

func (m *Module) FindModule(args []string) (*Module, error) {
	current := m
	var errStr bytes.Buffer
	for i, arg := range args {
		sub := current.Children[arg]
		if sub == nil {
			errStr.WriteString(fmt.Sprintf("Command %s not found\n\n", arg))
			break
		}
		if sub.Command == nil {
			current = current.Children[arg]
			continue
		}
		// command behaves like a subprocess, it will parse arguments again
		// so we re discarding parsed arguments
		temp := os.Args
		os.Args = []string{temp[0]}
		os.Args = append(os.Args, temp[i+2:]...)
		return sub, nil
	}
	errStr.WriteString(current.printPossibleCommands())
	return nil, errors.New(errStr.String())
}

func (m *Module) printPossibleCommands() string {
	var buffer bytes.Buffer
	buffer.WriteString("Possible commands: \n")
	for n, module := range m.Children {
		buffer.WriteString(fmt.Sprintf("  %-10s  ", n))
		var definition string
		if module.Command != nil {
			definition = module.Command.Definition()
		} else {
			definition = module.Definition
		}
		buffer.WriteString(fmt.Sprintf("%s\n", definition))
	}
	return buffer.String()
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

type option struct {
	field    string
	isFlag   bool
	desc     string
	short    string
	long     string
	required bool
	value    string
	given    bool
}

// Reflect the gathered information into the concrete action instance.
func (o *option) reflectTo(value reflect.Value) (e error) {
	if !o.given && o.value == "" {
		if o.required {
			return fmt.Errorf("option %q is required but not set", o.field)
		}
		return nil
	}

	field := value.FieldByName(o.field)
	if field.Kind() == reflect.Ptr {
		n := reflect.New(field.Type().Elem())
		field.Set(n)
		field = field.Elem()
	}

	switch field.Kind() {
	case reflect.String:
		field.SetString(o.value)
	case reflect.Int, reflect.Int64:
		i, e := strconv.Atoi(o.value)
		if e != nil {
			return e
		}
		field.SetInt(int64(i))
	case reflect.Bool:
		field.SetBool(o.value == "true")
	case reflect.Slice:
		parts := strings.Split(o.value, ",")
		st := field.Type().Elem()
		sl := reflect.MakeSlice(field.Type(), len(parts), len(parts))
		for i := range parts {
			switch st.Kind() {
			case reflect.String:
				sl.Index(i).SetString(parts[i])
			case reflect.Int, reflect.Int64:
				val, e := strconv.Atoi(parts[i])
				if e != nil {
					return e
				}
				sl.Index(i).SetInt(int64(val))
			default:
				return fmt.Errorf("invalid type %q for slice", st.String())
			}
			field.Set(sl)
		}
	default:
		return fmt.Errorf("invalid type %q", field.Type().String())
	}
	return nil
}

func (o *option) description() string {
	desc := "    "
	desc += o.shortDescription(" ")
	desc += fmt.Sprintf("%-*s", 30-len(desc), " ") + o.desc
	if o.value != "" {
		if o.desc != "" {
			desc += " "
		}
		desc += "(default: " + o.value + ")"
	}
	return desc
}

func (o *option) shortDescription(sep string) (desc string) {
	if o.short != "" {
		desc += "-" + o.short
	}
	if o.long != "" {
		if o.short != "" {
			desc += sep
		}
		desc += "--" + o.long
	}

	if !o.isFlag {
		desc += " <" + o.field + ">"
	}

	return desc
}

func (a *action) createOption(field reflect.StructField, value reflect.Value, tagMap map[string]string) (e error) {
	if e := validateTagMap(tagMap, "type", "desc", "short", "long", "required", "default"); e != nil {
		return fmt.Errorf("[option:%s] %s", field.Name, e.Error())
	}
	opt := &option{field: field.Name}

	if field.Type.Kind() == reflect.Bool {
		opt.isFlag = true
	}

	opt.short, e = handleShortIdentifier(tagMap)
	if e != nil {
		return e
	}

	opt.long, e = handleLongIdentifier(tagMap)
	if e != nil {
		return e
	}

	opt.required, e = handleRequired(tagMap)
	if e != nil {
		return e
	}

	if opt.required && opt.isFlag {
		return fmt.Errorf(`field %q is a flag and required, that doesn't make much sense`, field.Name)
	}

	opt.value = handlePresetValue(field, value)

	// Do that for error checking (not necessary if value preset otherwise).
	defaultValue, e := handleDefault(field, tagMap)
	if e != nil {
		return fmt.Errorf(`wrong value for "default" tag: %s`, e.Error())
	}

	if opt.value == "" {
		opt.value = defaultValue
	} else { // With a preset value that value is not required any more.
		opt.required = false
	}

	opt.desc = handleDescription(tagMap)

	if opt.short == "" && opt.long == "" {
		return fmt.Errorf("option %q has neither long nor short accessor set", field.Name)
	}

	if opt.short != "" {
		if o, found := a.params[opt.short]; found {
			return fmt.Errorf("short option %q already used (option %q)", opt.short, o.field)
		}
		a.params[opt.short] = opt
	}
	if opt.long != "" {
		if o, found := a.params[opt.long]; found {
			return fmt.Errorf("long option %q already used (option %q)", opt.long, o.field)
		}
		a.params[opt.long] = opt
	}
	a.opts = append(a.opts, opt)
	return nil
}
<commit_msg>replaces Atoi with ParseInt<commit_after>package cli

import (
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

type option struct {
	field    string
	isFlag   bool
	desc     string
	short    string
	long     string
	required bool
	value    string
	given    bool
}

// Reflect the gathered information into the concrete action instance.
func (o *option) reflectTo(value reflect.Value) (e error) {
	if !o.given && o.value == "" {
		if o.required {
			return fmt.Errorf("option %q is required but not set", o.field)
		}
		return nil
	}

	field := value.FieldByName(o.field)
	if field.Kind() == reflect.Ptr {
		n := reflect.New(field.Type().Elem())
		field.Set(n)
		field = field.Elem()
	}

	switch field.Kind() {
	case reflect.String:
		field.SetString(o.value)
	case reflect.Int, reflect.Int64:
		i, e := strconv.ParseInt(o.value, 10, 64)
		if e != nil {
			return e
		}
		field.SetInt(i)
	case reflect.Bool:
		field.SetBool(o.value == "true")
	case reflect.Slice:
		parts := strings.Split(o.value, ",")
		st := field.Type().Elem()
		sl := reflect.MakeSlice(field.Type(), len(parts), len(parts))
		for i := range parts {
			switch st.Kind() {
			case reflect.String:
				sl.Index(i).SetString(parts[i])
			case reflect.Int, reflect.Int64:
				val, e := strconv.ParseInt(parts[i], 10, 64)
				if e != nil {
					return e
				}

				if e != nil {
					return e
				}
				sl.Index(i).SetInt(val)
			default:
				return fmt.Errorf("invalid type %q for slice", st.String())
			}
			field.Set(sl)
		}
	default:
		return fmt.Errorf("invalid type %q", field.Type().String())
	}
	return nil
}

func (o *option) description() string {
	desc := "    "
	desc += o.shortDescription(" ")
	desc += fmt.Sprintf("%-*s", 30-len(desc), " ") + o.desc
	if o.value != "" {
		if o.desc != "" {
			desc += " "
		}
		desc += "(default: " + o.value + ")"
	}
	return desc
}

func (o *option) shortDescription(sep string) (desc string) {
	if o.short != "" {
		desc += "-" + o.short
	}
	if o.long != "" {
		if o.short != "" {
			desc += sep
		}
		desc += "--" + o.long
	}

	if !o.isFlag {
		desc += " <" + o.field + ">"
	}

	return desc
}

func (a *action) createOption(field reflect.StructField, value reflect.Value, tagMap map[string]string) (e error) {
	if e := validateTagMap(tagMap, "type", "desc", "short", "long", "required", "default"); e != nil {
		return fmt.Errorf("[option:%s] %s", field.Name, e.Error())
	}
	opt := &option{field: field.Name}

	if field.Type.Kind() == reflect.Bool {
		opt.isFlag = true
	}

	opt.short, e = handleShortIdentifier(tagMap)
	if e != nil {
		return e
	}

	opt.long, e = handleLongIdentifier(tagMap)
	if e != nil {
		return e
	}

	opt.required, e = handleRequired(tagMap)
	if e != nil {
		return e
	}

	if opt.required && opt.isFlag {
		return fmt.Errorf(`field %q is a flag and required, that doesn't make much sense`, field.Name)
	}

	opt.value = handlePresetValue(field, value)

	// Do that for error checking (not necessary if value preset otherwise).
	defaultValue, e := handleDefault(field, tagMap)
	if e != nil {
		return fmt.Errorf(`wrong value for "default" tag: %s`, e.Error())
	}

	if opt.value == "" {
		opt.value = defaultValue
	} else { // With a preset value that value is not required any more.
		opt.required = false
	}

	opt.desc = handleDescription(tagMap)

	if opt.short == "" && opt.long == "" {
		return fmt.Errorf("option %q has neither long nor short accessor set", field.Name)
	}

	if opt.short != "" {
		if o, found := a.params[opt.short]; found {
			return fmt.Errorf("short option %q already used (option %q)", opt.short, o.field)
		}
		a.params[opt.short] = opt
	}
	if opt.long != "" {
		if o, found := a.params[opt.long]; found {
			return fmt.Errorf("long option %q already used (option %q)", opt.long, o.field)
		}
		a.params[opt.long] = opt
	}
	a.opts = append(a.opts, opt)
	return nil
}
<|endoftext|>


<commit_before>// This file definse the logOuter interface and several types of logOuter.
//
// emptyOuter = logOuter where both Out and Outf are noops
// lineOuter = logOuter where a newline is inserted after every call to
//			   Out and Outf
// fatalLineOuter = logOuter that logs message with inserted newline then
//					exits with call to os.EXIT(1)

package golog

import (
	"os"
)

type LogOuter interface {
	// Println guarantees a newline and flushes output.
	Println(string)
	FailNow()
}

type fileLogOuter struct {
	*os.File
}

func (f *fileLogOuter) Println(s string) {
	l := len(s)
	if l > 0 {
		if s[l-1] == '\n' {
			f.WriteString(s)
		} else {
			f.WriteString(s + "\n")
		}
	}

	f.Sync()
}

func (f *fileLogOuter) FailNow() {
	f.Close()
	os.Exit(1)
}

// We want to allow an abitrary testing framework.
type TestController interface {
	// We will assume that testers insert newlines in manner similar to
	// the FEATURE of testing.T where it inserts extra newlines. >.<
	Log(...interface{})
	FailNow()
}

type testLogOuter struct {
	TestController
}

func (t* testLogOuter) Println(s string) {
	l := len(s)
	if l > 0 {
		// Since testers insert newlines, we strip the newline
		// in our string.
		if s[l -1] == '\n' {
			t.Log(s[:l-1])
		} else {
			t.Log(s)
		}
	}
}
<commit_msg>Add TODO about mutex<commit_after>// This file definse the logOuter interface and several types of logOuter.
//
// emptyOuter = logOuter where both Out and Outf are noops
// lineOuter = logOuter where a newline is inserted after every call to
//			   Out and Outf
// fatalLineOuter = logOuter that logs message with inserted newline then
//					exits with call to os.EXIT(1)

package golog

import (
	"os"
)

type LogOuter interface {
	// Println guarantees a newline and flushes output.
	Println(string)
	FailNow()
}

type fileLogOuter struct {
	// TODO Insert mutex?
	*os.File
}

func (f *fileLogOuter) Println(s string) {
	// TODO Grab mutex?
	l := len(s)
	if l > 0 {
		if s[l-1] == '\n' {
			f.WriteString(s)
		} else {
			f.WriteString(s + "\n")
		}
	}

	f.Sync()
}

func (f *fileLogOuter) FailNow() {
	// TODO Grab mutex?
	f.Close()
	os.Exit(1)
}

// We want to allow an abitrary testing framework.
type TestController interface {
	// We will assume that testers insert newlines in manner similar to
	// the FEATURE of testing.T where it inserts extra newlines. >.<
	Log(...interface{})
	FailNow()
}

type testLogOuter struct {
	TestController
}

func (t* testLogOuter) Println(s string) {
	l := len(s)
	if l > 0 {
		// Since testers insert newlines, we strip the newline
		// in our string.
		if s[l -1] == '\n' {
			t.Log(s[:l-1])
		} else {
			t.Log(s)
		}
	}
}
<|endoftext|>


<commit_before>package clix

import (
	"errors"
	"strings"

	"github.com/urfave/cli"
)

const (
	FlagPort = "port"

	FlagLogFormat = "log-format"
	FlagLogLevel  = "log-level"
	FlagLogTags   = "log-tags"

	FlagStatsDSN    = "stats-dsn"
	FlagStatsPrefix = "stats-prefix"
	FlagStatsTags   = "stats-tags"

	FlagProfiler     = "profiler"
	FlagProfilerPort = "profiler-port"
)

type defaults struct {
	Port      string
	LogFormat string
	LogLevel  string

	ProfilerPort string
}

var Defaults = defaults{
	Port:      "80",
	LogFormat: "json",
	LogLevel:  "info",

	ProfilerPort: "8081",
}

type Flags []cli.Flag

func (f Flags) Merge(flags Flags) Flags {
	return append(f, flags...)
}

var ServerFlags = Flags{
	cli.StringFlag{
		Name:   FlagPort,
		Value:  Defaults.Port,
		Usage:  "Port for HTTP server to listen on",
		EnvVar: "PORT",
	},
}

var CommonFlags = Flags{
	cli.StringFlag{
		Name:   FlagLogFormat,
		Value:  Defaults.LogFormat,
		Usage:  "Specify the format of logs. Supported formats: 'terminal', 'json'",
		EnvVar: "LOG_FORMAT",
	},
	cli.StringFlag{
		Name:   FlagLogLevel,
		Value:  Defaults.LogLevel,
		Usage:  "Specify the log level. E.g. 'debug', 'warning'.",
		EnvVar: "LOG_LEVEL",
	},
	cli.StringSliceFlag{
		Name:   FlagLogTags,
		Usage:  "A list of tags appended to every log. Format: key=value.",
		EnvVar: "LOG_TAGS",
	},

	cli.StringFlag{
		Name:   FlagStatsDSN,
		Usage:  "The URL of a stats backend.",
		EnvVar: "STATS_DSN",
	},
	cli.StringFlag{
		Name:   FlagStatsPrefix,
		Usage:  "The prefix of the measurements names.",
		EnvVar: "STATS_PREFIX",
	},
	cli.StringSliceFlag{
		Name:   FlagStatsTags,
		Usage:  "A list of tags appended to every measurement. Format: key=value.",
		EnvVar: "STATS_TAGS",
	},
}

var ProfilerFlags = Flags{
	cli.BoolFlag{
		Name:   FlagProfiler,
		Usage:  "Enable profiler server.",
		EnvVar: "PROFILER",
	},
	cli.StringFlag{
		Name:   FlagProfilerPort,
		Value:  Defaults.ProfilerPort,
		Usage:  "Port for the profiler to listen on.",
		EnvVar: "PROFILER_PORT",
	},
}

func SplitTags(slice []string, sep string) ([]interface{}, error) {
	res := make([]interface{}, 2*len(slice))

	for i, str := range slice {
		parts := strings.SplitN(str, sep, 2)
		if len(parts) != 2 {
			return nil, errors.New("invalid tags string")
		}

		res[2*i] = parts[0]
		res[2*i+1] = parts[1]
	}

	return res, nil
}
<commit_msg>Better merge on shared flags and additional flags: Kafka, Redis.<commit_after>package clix

import (
	"errors"
	"strings"

	"github.com/urfave/cli"
)

const (
	FlagPort = "port"

	FlagLogFormat = "log-format"
	FlagLogLevel  = "log-level"
	FlagLogTags   = "log-tags"

	FlagStatsDSN    = "stats-dsn"
	FlagStatsPrefix = "stats-prefix"
	FlagStatsTags   = "stats-tags"

	FlagProfiler     = "profiler"
	FlagProfilerPort = "profiler-port"

	FlagKafkaConsumerBrokers = "kafka-consumer-brokers"
	FlagKafkaConsumerGroupID = "kafka-consumer-group-id"
	FlagKafkaConsumerTopic   = "kafka-consumer-topic"
	FlagKafkaProducerBrokers = "kafka-producer-brokers"
	FlagKafkaProducerTopic   = "kafka-producer-topic"

	FlagRedisDsn = "redis-dsn"
)

type defaults struct {
	Port      string
	LogFormat string
	LogLevel  string

	ProfilerPort string
}

var Defaults = defaults{
	Port:      "80",
	LogFormat: "json",
	LogLevel:  "info",

	ProfilerPort: "8081",
}

type Flags []cli.Flag

func (f Flags) Merge(flags ...Flags) Flags {
	var m Flags
	for _, flag := range flags {
		m = append(f, flag...)
	}

	return m
}

var ServerFlags = Flags{
	cli.StringFlag{
		Name:   FlagPort,
		Value:  Defaults.Port,
		Usage:  "Port for HTTP server to listen on",
		EnvVar: "PORT",
	},
}

var KafkaConsumerFlags = Flags{
	cli.StringSliceFlag{
		Name:   FlagKafkaConsumerBrokers,
		Usage:  "Kafka consumer brokers.",
		EnvVar: "KAFKA_CONSUMER_BROKERS",
	},
	cli.StringFlag{
		Name:   FlagKafkaConsumerGroupID,
		Usage:  "Kafka consumer group id.",
		EnvVar: "KAFKA_CONSUMER_GROUP_ID",
	},
	cli.StringFlag{
		Name:   FlagKafkaConsumerTopic,
		Usage:  "Kafka topic to consume from.",
		EnvVar: "KAFKA_CONSUMER_TOPIC",
	},
}

var KafkaProducerFlags = Flags{
	cli.StringSliceFlag{
		Name:   FlagKafkaProducerBrokers,
		Usage:  "Kafka producer brokers.",
		EnvVar: "KAFKA_PRODUCER_BROKERS",
	},
	cli.StringFlag{
		Name:   FlagKafkaProducerTopic,
		Usage:  "Kafka topic to produce into.",
		EnvVar: "KAFKA_PRODUCER_TOPIC",
	},
}

var RedisFlags = Flags{
	cli.StringFlag{
		Name:   FlagRedisDsn,
		Usage:  "The DSN of Redis.",
		EnvVar: "REDIS_DSN",
	},
}

var CommonFlags = Flags{
	cli.StringFlag{
		Name:   FlagLogFormat,
		Value:  Defaults.LogFormat,
		Usage:  "Specify the format of logs. Supported formats: 'terminal', 'json'",
		EnvVar: "LOG_FORMAT",
	},
	cli.StringFlag{
		Name:   FlagLogLevel,
		Value:  Defaults.LogLevel,
		Usage:  "Specify the log level. E.g. 'debug', 'warning'.",
		EnvVar: "LOG_LEVEL",
	},
	cli.StringSliceFlag{
		Name:   FlagLogTags,
		Usage:  "A list of tags appended to every log. Format: key=value.",
		EnvVar: "LOG_TAGS",
	},

	cli.StringFlag{
		Name:   FlagStatsDSN,
		Usage:  "The URL of a stats backend.",
		EnvVar: "STATS_DSN",
	},
	cli.StringFlag{
		Name:   FlagStatsPrefix,
		Usage:  "The prefix of the measurements names.",
		EnvVar: "STATS_PREFIX",
	},
	cli.StringSliceFlag{
		Name:   FlagStatsTags,
		Usage:  "A list of tags appended to every measurement. Format: key=value.",
		EnvVar: "STATS_TAGS",
	},
}

var ProfilerFlags = Flags{
	cli.BoolFlag{
		Name:   FlagProfiler,
		Usage:  "Enable profiler server.",
		EnvVar: "PROFILER",
	},
	cli.StringFlag{
		Name:   FlagProfilerPort,
		Value:  Defaults.ProfilerPort,
		Usage:  "Port for the profiler to listen on.",
		EnvVar: "PROFILER_PORT",
	},
}

func SplitTags(slice []string, sep string) ([]interface{}, error) {
	res := make([]interface{}, 2*len(slice))

	for i, str := range slice {
		parts := strings.SplitN(str, sep, 2)
		if len(parts) != 2 {
			return nil, errors.New("invalid tags string")
		}

		res[2*i] = parts[0]
		res[2*i+1] = parts[1]
	}

	return res, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"testing"
	"time"

	"github.com/jbenet/go-random"
	"github.com/kylelemons/godebug/diff"
)

// Warning: these tests assume some networking capabilities... sorry

var (
	ipfsPath string
	gitPath  string
)

func init() {
	rand.Seed(time.Now().Unix())
}

// checks for the needed tools
func checkInstalled(t *testing.T) {
	var err error
	ipfsPath, err = exec.LookPath("ipfs")
	if err != nil {
		t.Fatal("ipfs is not installed")
	}
	gitPath, err = exec.LookPath("git")
	if err != nil {
		t.Fatal("git is not installed")
	}
	_, err = exec.LookPath("git-remote-ipfs")
	if err != nil {
		t.Fatal("git-remote-ipfs is not installed")
	}
}

func TestClone(t *testing.T) {
	checkInstalled(t)

	// oh well.. just some rand string
	var buf bytes.Buffer
	if err := random.WriteRandomBytes(20, &buf); err != nil {
		t.Fatalf("get random str: %s", err)
	}
	randStr := fmt.Sprintf("git-remote-ipfs-test-%x", buf.String())

	tmpDir := filepath.Join("/", os.TempDir(), randStr)
	if err := os.MkdirAll(tmpDir, 0700); err != nil {
		t.Fatalf("mkdirAll(%q): %s", tmpDir, err)
	}
	t.Logf("dbg: created %s", tmpDir)

	// pinned by pinbot, prepared with 'git-ipfs-rehost https://github.com/cryptix/git-remote-ipfs-testcase'
	err := exec.Command(gitPath, "clone", "ipfs://QmS5Vauz2G6DVP7NEetJBcHDUNPTRt34D6evNiwrp7Gmsk/git-remote-ipfs-testcase", tmpDir).Run()
	if err != nil { // exit status 0?
		t.Fatalf("git clone ipfs:// failed: %s", err)
	}

	// TODO(cryptix): maybe just use an md5 walker?
	buf.Reset()
	addCmd := exec.Command(ipfsPath, "add", "-q", "-r", tmpDir)
	addCmd.Stdout = &buf
	if err := addCmd.Run(); err != nil {
		t.Fatalf("ipfs add for comparison failed: %s", err)
	}

	// compare cloned hashes against expected ones
	const expected = `QmSS1VNgmPW8yFxYoHEUHDEEz8FYBucMqN8xY92Y9pGq26
QmSKoJo4VSso89bhbiTnVsgC7jKyqdBcB5GYCozYFp7fNs
QmaSPaHCETQmfLo7SigbaqsCHcZgivcWALMhWVnxEaNutj
QmPiW5xxfhVA2YaVoqLXsbMvdLMuVBNL68NPL57aWCAV8X
`
	if diff := diff.Diff(expected, buf.String()); diff != "" {
		t.Fatal(diff)
	}

	if err := os.RemoveAll(tmpDir); err != nil { // cleanup tmpDir
		t.Error(err)
	}
}
<commit_msg>extract 'git clone' test output<commit_after>package main

import (
	"bytes"
	"fmt"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"testing"
	"time"

	"github.com/jbenet/go-random"
	"github.com/kylelemons/godebug/diff"
)

// Warning: these tests assume some networking capabilities... sorry

var (
	ipfsPath string
	gitPath  string
)

func init() {
	rand.Seed(time.Now().Unix())
}

// checks for the needed tools
func checkInstalled(t *testing.T) {
	var err error
	ipfsPath, err = exec.LookPath("ipfs")
	if err != nil {
		t.Fatal("ipfs is not installed")
	}
	gitPath, err = exec.LookPath("git")
	if err != nil {
		t.Fatal("git is not installed")
	}
	_, err = exec.LookPath("git-remote-ipfs")
	if err != nil {
		t.Fatal("git-remote-ipfs is not installed")
	}
}

func TestClone(t *testing.T) {
	checkInstalled(t)

	// oh well.. just some rand string
	var buf bytes.Buffer
	if err := random.WriteRandomBytes(20, &buf); err != nil {
		t.Fatalf("get random str: %s", err)
	}
	randStr := fmt.Sprintf("git-remote-ipfs-test-%x", buf.String())

	tmpDir := filepath.Join("/", os.TempDir(), randStr)
	if err := os.MkdirAll(tmpDir, 0700); err != nil {
		t.Fatalf("mkdirAll(%q): %s", tmpDir, err)
	}
	t.Logf("dbg: created %s", tmpDir)

	// pinned by pinbot, prepared with 'git-ipfs-rehost https://github.com/cryptix/git-remote-ipfs-testcase'
	buf.Reset()
	cloneCmd := exec.Command(gitPath, "clone", "ipfs://QmS5Vauz2G6DVP7NEetJBcHDUNPTRt34D6evNiwrp7Gmsk/git-remote-ipfs-testcase", tmpDir)
	cloneCmd.Stdout = &buf
	cloneCmd.Stderr = &buf
	if err := cloneCmd.Run(); err != nil { // exit status 0?
		t.Log(buf.String())
		t.Fatalf("git clone ipfs:// failed: %s", err)
	}

	// TODO(cryptix): maybe just use an md5 walker?
	buf.Reset()
	addCmd := exec.Command(ipfsPath, "add", "-q", "-r", tmpDir)
	addCmd.Stdout = &buf
	if err := addCmd.Run(); err != nil {
		t.Fatalf("ipfs add for comparison failed: %s", err)
	}

	// compare cloned hashes against expected ones
	const expected = `QmSS1VNgmPW8yFxYoHEUHDEEz8FYBucMqN8xY92Y9pGq26
QmSKoJo4VSso89bhbiTnVsgC7jKyqdBcB5GYCozYFp7fNs
QmaSPaHCETQmfLo7SigbaqsCHcZgivcWALMhWVnxEaNutj
QmPiW5xxfhVA2YaVoqLXsbMvdLMuVBNL68NPL57aWCAV8X
`
	if diff := diff.Diff(expected, buf.String()); diff != "" {
		t.Fatal(diff)
	}

	if err := os.RemoveAll(tmpDir); err != nil { // cleanup tmpDir
		t.Error(err)
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"strings"

	"github.com/nextgearcapital/pepper/pkg/device42"
	"github.com/nextgearcapital/pepper/pkg/log"
	"github.com/nextgearcapital/pepper/pkg/salt"
	"github.com/nextgearcapital/pepper/template/vsphere"

	"github.com/spf13/cobra"
)

var (
	profile    string
	roles      string
	osTemplate string
	ipam       bool
)

func init() {
	RootCmd.AddCommand(deployCmd)

	deployCmd.Flags().StringVarP(&profile, "profile", "p", "", "Profile to generate and output to /etc/salt/cloud.profiles.d for salt-cloud to use")
	deployCmd.Flags().StringVarP(&roles, "roles", "r", "", "List of roles to assign to the host in D42 [eg: dcos,dcos-master]")
	deployCmd.Flags().StringVarP(&osTemplate, "template", "t", "", "Which OS template you want to use [eg: Ubuntu, CentOS, someothertemplatename]")
	deployCmd.Flags().BoolVarP(&ipam, "no-ipam", "", false, "Whether or not to use Device42 IPAM [This is only used internally]")
	deployCmd.Flags().BoolVarP(&log.IsDebugging, "debug", "d", false, "Turn debugging on")
}

var deployCmd = &cobra.Command{
	Use:   "deploy",
	Short: "Deploy VM's via salt-cloud",
	Long: `pepper is a wrapper around salt-cloud that will generate salt-cloud profiles based on information you provide in profile configs.
Profile configs live in "/etc/pepper/config.d/{platform}/{environment}. Pepper is opinionated and looks at the profile you pass in as it's source
of truth. For example: If you pass in "vmware-dev-large" as the profile, it will look for your profile config in "/etc/pepper/config.d/vmware/large.yaml".
This allows for maximum flexibility due to the fact that everyone has different environments and may have some sort of naming scheme associated with them
so Pepper makes no assumptions on that. Pepper does however make assumptions on your instance type. [eg: nano, micro, small, medium, etc] Although these
options are available to you, you are free to override them as you see fit.
For example:

Provision new host web01 (Ubuntu) in the dev environment from the nano profile using vmware as a provider:

$ pepper deploy -p vmware-dev-nano -t Ubuntu web01

Or alternatively:

$ pepper deploy --profile vmware-dev-nano --template Ubuntu web01

Provision new host web02 (CentOS) in the prd environment from the large profile using vmware as a provider:

$ pepper deploy -p vmware-prd-large -t CentOS web02

Provision new host web03 (Ubuntu) in the uat environment from the hyper profile using vmware as a provider:

$ pepper deploy -p vmware-uat-hyper -t Ubuntu web03

Are you getting this yet?

$ pepper deploy -p vmware-prd-mid -t Ubuntu -r dcos,dcos-master dcos01 dcos02 dcos03`,
	Run: func(cmd *cobra.Command, args []string) {
		if profile == "" {
			log.Die("You didn't specify a profile.")
		} else if osTemplate == "" {
			log.Die("You didn't specify an OS template.")
		} else if len(args) == 0 {
			log.Die("You didn't specify any hosts.")
		}

		splitProfile := strings.Split(profile, "-")

		// These will be the basis for how the profile gets generated.
		platform := splitProfile[0]
		environment := splitProfile[1]
		instancetype := splitProfile[2]

		// Nothing really gained here it just makes the code more readable.
		hosts := args

		var ipAddress string
		var serviceLevel string

		for _, host := range hosts {
			if ipam != true {
				if err := device42.ReadConfig(environment); err != nil {
					log.Die("%s", err)
				}
				// Get a new IP
				newIP, err := device42.GetNextIP(device42.IPRange)
				if err != nil {
					log.Die("%s", err)
				}
				ipAddress = newIP
				// Create the Device
				if err := device42.CreateDevice(host, serviceLevel); err != nil {
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				// Reserve IP
				if err := device42.ReserveIP(newIP, host); err != nil {
					if err = device42.MakeIPAvailable(newIP); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				// Update custom fields
				if err := device42.UpdateCustomFields(host, "roles", roles); err != nil {
					if err = device42.MakeIPAvailable(newIP); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
			}
			switch platform {
			case "vmware":
				var vsphere vsphere.ProfileConfig
				if err := vsphere.Prepare(platform, environment, instancetype, osTemplate, ipAddress); err != nil {
					if err = device42.MakeIPAvailable(newIP); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := vsphere.Generate(); err != nil {
					if err = device42.MakeIPAvailable(newIP); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := salt.Provision(profile, host); err != nil {
					if err = device42.MakeIPAvailable(newIP); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := vsphere.Remove(); err != nil {
					log.Die("%s", err)
				}
			default:
				log.Die("I don't recognize this platform!")
			}
		}
	},
}
<commit_msg>Wrong variable<commit_after>package cmd

import (
	"strings"

	"github.com/nextgearcapital/pepper/pkg/device42"
	"github.com/nextgearcapital/pepper/pkg/log"
	"github.com/nextgearcapital/pepper/pkg/salt"
	"github.com/nextgearcapital/pepper/template/vsphere"

	"github.com/spf13/cobra"
)

var (
	profile    string
	roles      string
	osTemplate string
	ipam       bool
)

func init() {
	RootCmd.AddCommand(deployCmd)

	deployCmd.Flags().StringVarP(&profile, "profile", "p", "", "Profile to generate and output to /etc/salt/cloud.profiles.d for salt-cloud to use")
	deployCmd.Flags().StringVarP(&roles, "roles", "r", "", "List of roles to assign to the host in D42 [eg: dcos,dcos-master]")
	deployCmd.Flags().StringVarP(&osTemplate, "template", "t", "", "Which OS template you want to use [eg: Ubuntu, CentOS, someothertemplatename]")
	deployCmd.Flags().BoolVarP(&ipam, "no-ipam", "", false, "Whether or not to use Device42 IPAM [This is only used internally]")
	deployCmd.Flags().BoolVarP(&log.IsDebugging, "debug", "d", false, "Turn debugging on")
}

var deployCmd = &cobra.Command{
	Use:   "deploy",
	Short: "Deploy VM's via salt-cloud",
	Long: `pepper is a wrapper around salt-cloud that will generate salt-cloud profiles based on information you provide in profile configs.
Profile configs live in "/etc/pepper/config.d/{platform}/{environment}. Pepper is opinionated and looks at the profile you pass in as it's source
of truth. For example: If you pass in "vmware-dev-large" as the profile, it will look for your profile config in "/etc/pepper/config.d/vmware/large.yaml".
This allows for maximum flexibility due to the fact that everyone has different environments and may have some sort of naming scheme associated with them
so Pepper makes no assumptions on that. Pepper does however make assumptions on your instance type. [eg: nano, micro, small, medium, etc] Although these
options are available to you, you are free to override them as you see fit.
For example:

Provision new host web01 (Ubuntu) in the dev environment from the nano profile using vmware as a provider:

$ pepper deploy -p vmware-dev-nano -t Ubuntu web01

Or alternatively:

$ pepper deploy --profile vmware-dev-nano --template Ubuntu web01

Provision new host web02 (CentOS) in the prd environment from the large profile using vmware as a provider:

$ pepper deploy -p vmware-prd-large -t CentOS web02

Provision new host web03 (Ubuntu) in the uat environment from the hyper profile using vmware as a provider:

$ pepper deploy -p vmware-uat-hyper -t Ubuntu web03

Are you getting this yet?

$ pepper deploy -p vmware-prd-mid -t Ubuntu -r dcos,dcos-master dcos01 dcos02 dcos03`,
	Run: func(cmd *cobra.Command, args []string) {
		if profile == "" {
			log.Die("You didn't specify a profile.")
		} else if osTemplate == "" {
			log.Die("You didn't specify an OS template.")
		} else if len(args) == 0 {
			log.Die("You didn't specify any hosts.")
		}

		splitProfile := strings.Split(profile, "-")

		// These will be the basis for how the profile gets generated.
		platform := splitProfile[0]
		environment := splitProfile[1]
		instancetype := splitProfile[2]

		// Nothing really gained here it just makes the code more readable.
		hosts := args

		var ipAddress string
		var serviceLevel string

		for _, host := range hosts {
			if ipam != true {
				if err := device42.ReadConfig(environment); err != nil {
					log.Die("%s", err)
				}
				// Get a new IP
				newIP, err := device42.GetNextIP(device42.IPRange)
				if err != nil {
					log.Die("%s", err)
				}
				ipAddress = newIP
				// Create the Device
				if err := device42.CreateDevice(host, serviceLevel); err != nil {
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				// Reserve IP
				if err := device42.ReserveIP(newIP, host); err != nil {
					if err = device42.MakeIPAvailable(newIP); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				// Update custom fields
				if err := device42.UpdateCustomFields(host, "roles", roles); err != nil {
					if err = device42.MakeIPAvailable(newIP); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
			}
			switch platform {
			case "vmware":
				var vsphere vsphere.ProfileConfig
				if err := vsphere.Prepare(platform, environment, instancetype, osTemplate, ipAddress); err != nil {
					if err = device42.MakeIPAvailable(ipAddress); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := vsphere.Generate(); err != nil {
					if err = device42.MakeIPAvailable(ipAddress); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := salt.Provision(profile, host); err != nil {
					if err = device42.MakeIPAvailable(ipAddress); err != nil {
						log.Die("%s", err)
					}
					if err = device42.DeleteDevice(host); err != nil {
						log.Die("%s", err)
					}
					log.Die("%s", err)
				}
				if err := vsphere.Remove(); err != nil {
					log.Die("%s", err)
				}
			default:
				log.Die("I don't recognize this platform!")
			}
		}
	},
}
<|endoftext|>