<commit_before>package cwl

import (
	"fmt"
	"os"
	"path"
	"reflect"

	shock "github.com/MG-RAST/go-shock-client"
	"github.com/davecgh/go-spew/spew"

	//"github.com/davecgh/go-spew/spew"
	"net/url"
	"strings"

	"github.com/mitchellh/mapstructure"
)

// http://www.commonwl.org/v1.0/Workflow.html#File
type File struct {
	CWLType_Impl `yaml:",inline" json:",inline" bson:",inline" mapstructure:",squash"` // Provides: Id, Class, Type
	//Type           CWLType_Type  `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
	Location string `yaml:"location,omitempty" json:"location,omitempty" bson:"location,omitempty" mapstructure:"location,omitempty"` // An IRI that identifies the file resource.
	//Location_url   *url.URL      `yaml:"-" json:"-" bson:"-" mapstructure:"-"`                                                                     // only for internal purposes
	Path           string        `yaml:"path,omitempty" json:"path,omitempty" bson:"path,omitempty" mapstructure:"path,omitempty"`                 // dirname + '/' + basename == path This field must be set by the implementation.
	Basename       string        `yaml:"basename,omitempty" json:"basename,omitempty" bson:"basename,omitempty" mapstructure:"basename,omitempty"` // dirname + '/' + basename == path // if not defined, take from location
	Dirname        string        `yaml:"dirname,omitempty" json:"dirname,omitempty" bson:"dirname,omitempty" mapstructure:"dirname,omitempty"`     // dirname + '/' + basename == path
	Nameroot       string        `yaml:"nameroot,omitempty" json:"nameroot,omitempty" bson:"nameroot,omitempty" mapstructure:"nameroot,omitempty"`
	Nameext        string        `yaml:"nameext,omitempty" json:"nameext,omitempty" bson:"nameext,omitempty" mapstructure:"nameext,omitempty"`
	Checksum       string        `yaml:"checksum,omitempty" json:"checksum,omitempty" bson:"checksum,omitempty" mapstructure:"checksum,omitempty"`
	Size           *int32        `yaml:"size,omitempty" json:"size,omitempty" bson:"size,omitempty" mapstructure:"size,omitempty"`
	SecondaryFiles []interface{} `yaml:"secondaryFiles,omitempty" json:"secondaryFiles,omitempty" bson:"secondaryFiles,omitempty" mapstructure:"secondaryFiles,omitempty"`
	Format         string        `yaml:"format,omitempty" json:"format,omitempty" bson:"format,omitempty" mapstructure:"format,omitempty"`
	Contents       string        `yaml:"contents,omitempty" json:"contents,omitempty" bson:"contents,omitempty" mapstructure:"contents,omitempty"`
	// Shock node
	Host   string `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
	Node   string `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
	Bearer string `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
	Token  string `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
}

func (f *File) IsCWLMinimal() {}
func (f *File) Is_CWLType()   {}

//func (f *File) GetClass() string      { return "File" }
func (f *File) GetType() CWLType_Type { return CWLFile }

//func (f *File) GetID() string       { return f.Id }
//func (f *File) SetID(id string)     { f.Id = id }
func (f *File) String() string { return f.Path }

//func (f *File) Is_Array() bool      { return false }

//func (f *File) Is_CommandInputParameterType() {} // for CommandInputParameterType

func NewFile() (f *File) {
	f = &File{}
	f.CWLType_Impl = CWLType_Impl{}
	f.Class = string(CWLFile)
	f.Type = CWLFile
	return
}

func NewFileFromInterface(obj interface{}, context *WorkflowContext, external_id string) (file File, err error) {

	file, err = MakeFile(obj, context, external_id)

	return
}

func MakeFile(obj interface{}, context *WorkflowContext, external_id string) (file File, err error) {

	// external_id is used to add File to context, not to set the Id or Name field!

	//fmt.Println("MakeFile:")
	//spew.Dump(obj)

	obj_map, ok := obj.(map[string]interface{})

	if !ok {
		err = fmt.Errorf("(MakeFile) File is not a map[string]interface{} (File is %s)", reflect.TypeOf(obj))
		return
	}

	secondaryFiles, has_secondaryFiles := obj_map["secondaryFiles"]
	if has_secondaryFiles {
		obj_map["secondaryFiles"], err = GetSecondaryFilesArray(secondaryFiles, context)
		if err != nil {
			err = fmt.Errorf("(MakeFile) GetSecondaryFilesArray returned: %s", err.Error())
			return
		}

	}

	// format, has_format := obj_map["format"]
	// if has_format {
	// 	switch format.(type) {
	// 	case []interface{}:
	// 		// ok
	// 	case interface{}:
	// 		// put element into array
	// 		obj_map["format"] = []interface{}{format}
	// 	default:
	// 		err = fmt.Errorf("(MakeFile) format type not supported: %s", reflect.TypeOf(format))
	// 		return
	// 	}

	// }

	file = *NewFile()
	err = mapstructure.Decode(obj_map, &file)
	if err != nil {
		spew.Dump(obj)
		err = fmt.Errorf("(MakeFile) Could not convert File object: %s", err.Error())
		return
	}
	//file.Class = string(CWLFile)
	//file.Type = CWLFile

	//fmt.Println("MakeFile input:")
	//spew.Dump(obj)
	//fmt.Println("MakeFile output:")
	//fmt.Printf("%+v\n", file)

	components_updated := false

	if file.Location != "" {

		// example shock://shock.metagenomics.anl.gov/node/92a76f64-d221-4947-9fd0-7106c3b9163a
		file_url, xerr := url.Parse(file.Location)
		if xerr != nil {
			err = fmt.Errorf("(MakeFile) Error parsing url %s %s", file.Location, xerr.Error())

			return
		}

		//file.Location_url = file_url
		scheme := strings.ToLower(file_url.Scheme)
		values := file_url.Query()

		// TODO add "node/uuid" matching to detect shock

		switch scheme {

		case "http", "https":
			_, has_download := values["download"]
			//extract filename ?
			if has_download && false {

				array := strings.Split(file_url.Path, "/")
				if len(array) != 3 {
					err = fmt.Errorf("(MakeFile) shock url cannot be parsed")
					return
				}
				if array[1] != "node" {
					err = fmt.Errorf("(MakeFile) node missing in shock url")
					return
				}
				file.Node = array[2]

				file.Host = scheme + "://" + file_url.Host
				shock_client := shock.ShockClient{Host: file.Host} // TODO Token: datatoken
				node, xerr := shock_client.GetNode(file.Node)

				if xerr != nil {
					err = fmt.Errorf("(MakeFile) Could not get shock node (%s, %s): %s", file.Host, file.Node, xerr.Error())
					return
				}
				//fmt.Println("---node:")
				//spew.Dump(node)

				if file.Basename == "" {
					// use filename from shocknode
					if node.File.Name != "" {
						//fmt.Printf("(MakeFile) node.File.Name: %s\n", node.File.Name)
						//file.Basename = node.File.Name
						file.UpdateComponents(node.File.Name)
					} else {
						// if user does not specify a filename and shock does not, use node_id
						//file.Basename =
						file.UpdateComponents(file.Node)
					}
					components_updated = true
				}
			}
		case "file":

			file.UpdateComponents(file_url.Path)
		case "":

		default:
			err = fmt.Errorf("(MakeFile) scheme %s not supported yet", scheme)
			return
		}
	}

	if context != nil && context.Initialzing && external_id != "" {

		err = context.Add(external_id, &file, "MakeFile")
		if err != nil {
			err = fmt.Errorf("(MakeFile) (external_id: %s) context.Add returned: %s", external_id, err.Error())
			return
		}
	}

	// used to set Basename, Nameroot and Nameext
	if (!components_updated) && file.Path != "" {
		file.UpdateComponents(file.Path)
	}
	return
}

func (file *File) UpdateComponents(filename string) {
	file.Basename = path.Base(filename)

	file.Nameext = path.Ext(filename)
	file.Nameroot = strings.TrimSuffix(file.Basename, file.Nameext)
	//fmt.Printf("file.Basename: %s\n", file.Basename)
	//fmt.Printf("file.Nameext: %s\n", file.Nameext)
	//fmt.Printf("file.Nameroot: %s\n", file.Nameroot)

}

func (file *File) SetPath(path_str string) {
	oldPath := file.Path
	file.Path = path_str

	if path_str == "" {
		file.UpdateComponents(oldPath)
		file.Path = ""
		// on upload to Shock we loose path, but need to keep basename

		//file.Basename = ""

		//file.Nameext = ""
		//file.Nameroot = ""
	} else {
		file.UpdateComponents(path_str)

	}
	//fmt.Printf("file.Path: %s\n", file.Path)

}

// returns array<File | Directory>
func GetSecondaryFilesArray(original interface{}, context *WorkflowContext) (array []interface{}, err error) {

	array = []interface{}{}

	switch original.(type) {
	case []interface{}:
		original_array := original.([]interface{})
		for i, _ := range original_array {
			var obj CWLType
			obj, err = NewCWLType("", original_array[i], context)
			if err != nil {
				err = fmt.Errorf("(GetSecondaryFilesArray) NewCWLType returned: %s", err.Error())
				return
			}

			obj_class := obj.GetClass()

			if obj_class != "File" && obj_class != "Directory" {
				err = fmt.Errorf("(GetSecondaryFilesArray) Object class %s not supported", obj_class)
				return
			}
			array = append(array, obj)

		}
		return
	}

	err = fmt.Errorf("(GetSecondaryFilesArray) type %s not supported", reflect.TypeOf(original))

	return
}

func (file *File) Exists(inputfile_path string) (ok bool, err error) {
	if file.Contents != "" {
		ok = true
		return
	}

	//fmt.Printf("file.Path: %s\n", file.Path)
	//fmt.Printf("file.Location: %s\n", file.Location)

	if file.Path != "" {
		file_path := file.Path
		file_path = strings.TrimPrefix(file_path, "file://")

		if !path.IsAbs(file_path) {
			file_path = path.Join(inputfile_path, file_path)
		}

		//var file_info os.FileInfo
		_, err = os.Stat(file_path)
		if err != nil {
			err = nil
			ok = false
			//err = fmt.Errorf("(UploadFile) os.Stat returned: %s (file.Path: %s)", err.Error(), file.Path)
			return
		}
		ok = true
		return
	}

	if file.Location != "" {

		file_path := strings.TrimPrefix(file.Location, "file://")

		if strings.HasPrefix(file.Location, "http:") {
			err = fmt.Errorf("(File/Exists) schema http not yet supported (%s)", file.Location)
			return
		}
		if strings.HasPrefix(file.Location, "https:") {
			err = fmt.Errorf("(File/Exists) schema https not yet supported")
			return
		}
		if strings.HasPrefix(file.Location, "ftp:") {
			err = fmt.Errorf("(File/Exists) schema https not yet supported")
			return
		}

		if !path.IsAbs(file_path) {
			file_path = path.Join(inputfile_path, file_path)
		}

		//var file_info os.FileInfo
		_, err = os.Stat(file_path)
		if err != nil {
			err = nil
			ok = false
			//err = fmt.Errorf("(UploadFile) os.Stat returned: %s (file.Path: %s)", err.Error(), file.Path)
			return
		}
		ok = true
		return
	}
	return
}

//type FileArray struct {
//	CWLType_Impl
//	Id   string `yaml:"id" json:"id"`
//	Data []File
//}

//func (f *FileArray) GetClass() string { return "array" }

//func (f *FileArray) Is_Array() bool   { return true }

//func (f *FileArray) IsArrayType() {}
//func (f *FileArray) Get_Array() *[]File {
//	return &f.Data
//}

//func (f *FileArray) GetID() string   { return f.Id }
//func (f *FileArray) SetID(id string) { f.Id = id }

//func (f *FileArray) String() string      { return f.Path }
//func (f *FileArray) GetLocation() string { return f.Location } // for CWL_location

//func (s *FileArray) Is_CommandInputParameterType() {} // for CommandInputParameterType
<commit_msg>golint fix<commit_after>package cwl

import (
	"fmt"
	"os"
	"path"
	"reflect"

	shock "github.com/MG-RAST/go-shock-client"
	"github.com/davecgh/go-spew/spew"

	//"github.com/davecgh/go-spew/spew"
	"net/url"
	"strings"

	"github.com/mitchellh/mapstructure"
)

// File http://www.commonwl.org/v1.0/Workflow.html#File
type File struct {
	CWLType_Impl `yaml:",inline" json:",inline" bson:",inline" mapstructure:",squash"` // Provides: Id, Class, Type
	//Type           CWLType_Type  `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
	Location string `yaml:"location,omitempty" json:"location,omitempty" bson:"location,omitempty" mapstructure:"location,omitempty"` // An IRI that identifies the file resource.
	//Location_url   *url.URL      `yaml:"-" json:"-" bson:"-" mapstructure:"-"`                                                                     // only for internal purposes
	Path           string        `yaml:"path,omitempty" json:"path,omitempty" bson:"path,omitempty" mapstructure:"path,omitempty"`                 // dirname + '/' + basename == path This field must be set by the implementation.
	Basename       string        `yaml:"basename,omitempty" json:"basename,omitempty" bson:"basename,omitempty" mapstructure:"basename,omitempty"` // dirname + '/' + basename == path // if not defined, take from location
	Dirname        string        `yaml:"dirname,omitempty" json:"dirname,omitempty" bson:"dirname,omitempty" mapstructure:"dirname,omitempty"`     // dirname + '/' + basename == path
	Nameroot       string        `yaml:"nameroot,omitempty" json:"nameroot,omitempty" bson:"nameroot,omitempty" mapstructure:"nameroot,omitempty"`
	Nameext        string        `yaml:"nameext,omitempty" json:"nameext,omitempty" bson:"nameext,omitempty" mapstructure:"nameext,omitempty"`
	Checksum       string        `yaml:"checksum,omitempty" json:"checksum,omitempty" bson:"checksum,omitempty" mapstructure:"checksum,omitempty"`
	Size           *int32        `yaml:"size,omitempty" json:"size,omitempty" bson:"size,omitempty" mapstructure:"size,omitempty"`
	SecondaryFiles []interface{} `yaml:"secondaryFiles,omitempty" json:"secondaryFiles,omitempty" bson:"secondaryFiles,omitempty" mapstructure:"secondaryFiles,omitempty"`
	Format         string        `yaml:"format,omitempty" json:"format,omitempty" bson:"format,omitempty" mapstructure:"format,omitempty"`
	Contents       string        `yaml:"contents,omitempty" json:"contents,omitempty" bson:"contents,omitempty" mapstructure:"contents,omitempty"`
	// Shock node
	Host   string `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
	Node   string `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
	Bearer string `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
	Token  string `yaml:"-" json:"-" bson:"-" mapstructure:"-"`
}

// IsCWLMinimal _
func (file *File) IsCWLMinimal() {}

// Is_CWLType _
func (file *File) Is_CWLType() {}

//func (f *File) GetClass() string      { return "File" }

// GetType _
func (file *File) GetType() CWLType_Type { return CWLFile }

//func (f *File) GetID() string       { return f.Id }
//func (f *File) SetID(id string)     { f.Id = id }
func (file *File) String() string { return file.Path }

//func (f *File) Is_Array() bool      { return false }

//func (f *File) Is_CommandInputParameterType() {} // for CommandInputParameterType

// NewFile _
func NewFile() (file *File) {
	file = &File{}
	file.CWLType_Impl = CWLType_Impl{}
	file.Class = string(CWLFile)
	file.Type = CWLFile
	return
}

// NewFileFromInterface _
func NewFileFromInterface(obj interface{}, context *WorkflowContext, external_id string) (file File, err error) {

	file, err = MakeFile(obj, context, external_id)

	return
}

// MakeFile _
func MakeFile(obj interface{}, context *WorkflowContext, external_id string) (file File, err error) {

	// external_id is used to add File to context, not to set the Id or Name field!

	//fmt.Println("MakeFile:")
	//spew.Dump(obj)

	objMap, ok := obj.(map[string]interface{})

	if !ok {
		err = fmt.Errorf("(MakeFile) File is not a map[string]interface{} (File is %s)", reflect.TypeOf(obj))
		return
	}

	secondaryFiles, hasSecondaryFiles := objMap["secondaryFiles"]
	if hasSecondaryFiles {
		objMap["secondaryFiles"], err = GetSecondaryFilesArray(secondaryFiles, context)
		if err != nil {
			err = fmt.Errorf("(MakeFile) GetSecondaryFilesArray returned: %s", err.Error())
			return
		}

	}

	// format, has_format := obj_map["format"]
	// if has_format {
	// 	switch format.(type) {
	// 	case []interface{}:
	// 		// ok
	// 	case interface{}:
	// 		// put element into array
	// 		obj_map["format"] = []interface{}{format}
	// 	default:
	// 		err = fmt.Errorf("(MakeFile) format type not supported: %s", reflect.TypeOf(format))
	// 		return
	// 	}

	// }

	file = *NewFile()
	err = mapstructure.Decode(objMap, &file)
	if err != nil {
		spew.Dump(obj)
		err = fmt.Errorf("(MakeFile) Could not convert File object: %s", err.Error())
		return
	}
	//file.Class = string(CWLFile)
	//file.Type = CWLFile

	//fmt.Println("MakeFile input:")
	//spew.Dump(obj)
	//fmt.Println("MakeFile output:")
	//fmt.Printf("%+v\n", file)

	componentsUpdated := false

	if file.Location != "" {

		// example shock://shock.metagenomics.anl.gov/node/92a76f64-d221-4947-9fd0-7106c3b9163a
		fileURL, xerr := url.Parse(file.Location)
		if xerr != nil {
			err = fmt.Errorf("(MakeFile) Error parsing url file.Location=%s : %s", file.Location, xerr.Error())

			return
		}

		//file.Location_url = file_url
		scheme := strings.ToLower(fileURL.Scheme)
		values := fileURL.Query()

		// TODO add "node/uuid" matching to detect shock

		switch scheme {

		case "http", "https":
			_, hasDownload := values["download"]
			//extract filename ?
			if hasDownload && false {

				array := strings.Split(fileURL.Path, "/")
				if len(array) != 3 {
					err = fmt.Errorf("(MakeFile) shock url cannot be parsed")
					return
				}
				if array[1] != "node" {
					err = fmt.Errorf("(MakeFile) node missing in shock url")
					return
				}
				file.Node = array[2]

				file.Host = scheme + "://" + fileURL.Host
				shockClient := shock.ShockClient{Host: file.Host} // TODO Token: datatoken
				node, xerr := shockClient.GetNode(file.Node)

				if xerr != nil {
					err = fmt.Errorf("(MakeFile) Could not get shock node (%s, %s): %s", file.Host, file.Node, xerr.Error())
					return
				}
				//fmt.Println("---node:")
				//spew.Dump(node)

				if file.Basename == "" {
					// use filename from shocknode
					if node.File.Name != "" {
						//fmt.Printf("(MakeFile) node.File.Name: %s\n", node.File.Name)
						//file.Basename = node.File.Name
						file.UpdateComponents(node.File.Name)
					} else {
						// if user does not specify a filename and shock does not, use node_id
						//file.Basename =
						file.UpdateComponents(file.Node)
					}
					componentsUpdated = true
				}
			}
		case "file":

			file.UpdateComponents(fileURL.Path)
		case "":

		default:
			err = fmt.Errorf("(MakeFile) scheme %s not supported yet", scheme)
			return
		}
	}

	if context != nil && context.Initialzing && external_id != "" {

		err = context.Add(external_id, &file, "MakeFile")
		if err != nil {
			err = fmt.Errorf("(MakeFile) (external_id: %s) context.Add returned: %s", external_id, err.Error())
			return
		}
	}

	// used to set Basename, Nameroot and Nameext
	if (!componentsUpdated) && file.Path != "" {
		file.UpdateComponents(file.Path)
	}
	return
}

// UpdateComponents _
func (file *File) UpdateComponents(filename string) {
	file.Basename = path.Base(filename)

	file.Nameext = path.Ext(filename)
	file.Nameroot = strings.TrimSuffix(file.Basename, file.Nameext)
	//fmt.Printf("file.Basename: %s\n", file.Basename)
	//fmt.Printf("file.Nameext: %s\n", file.Nameext)
	//fmt.Printf("file.Nameroot: %s\n", file.Nameroot)

}

// SetPath _
func (file *File) SetPath(pathStr string) {
	oldPath := file.Path
	file.Path = pathStr

	if pathStr == "" {
		file.UpdateComponents(oldPath)
		file.Path = ""
		// on upload to Shock we loose path, but need to keep basename

		//file.Basename = ""

		//file.Nameext = ""
		//file.Nameroot = ""
	} else {
		file.UpdateComponents(pathStr)

	}
	//fmt.Printf("file.Path: %s\n", file.Path)

}

// GetSecondaryFilesArray returns array<File | Directory>
func GetSecondaryFilesArray(original interface{}, context *WorkflowContext) (array []interface{}, err error) {

	array = []interface{}{}

	switch original.(type) {
	case []interface{}:
		originalArray := original.([]interface{})
		for i := range originalArray {
			var obj CWLType
			obj, err = NewCWLType("", originalArray[i], context)
			if err != nil {
				err = fmt.Errorf("(GetSecondaryFilesArray) NewCWLType returned: %s", err.Error())
				return
			}

			objClass := obj.GetClass()

			if objClass != "File" && objClass != "Directory" {
				err = fmt.Errorf("(GetSecondaryFilesArray) Object class %s not supported", objClass)
				return
			}
			array = append(array, obj)

		}
		return
	}

	err = fmt.Errorf("(GetSecondaryFilesArray) type %s not supported", reflect.TypeOf(original))

	return
}

// Exists _
func (file *File) Exists(inputfilePath string) (ok bool, err error) {
	if file.Contents != "" {
		ok = true
		return
	}

	//fmt.Printf("file.Path: %s\n", file.Path)
	//fmt.Printf("file.Location: %s\n", file.Location)

	if file.Path != "" {
		filePath := file.Path
		filePath = strings.TrimPrefix(filePath, "file://")

		if !path.IsAbs(filePath) {
			filePath = path.Join(inputfilePath, filePath)
		}

		//var file_info os.FileInfo
		_, err = os.Stat(filePath)
		if err != nil {
			err = nil
			ok = false
			//err = fmt.Errorf("(UploadFile) os.Stat returned: %s (file.Path: %s)", err.Error(), file.Path)
			return
		}
		ok = true
		return
	}

	if file.Location != "" {

		filePath := strings.TrimPrefix(file.Location, "file://")

		if strings.HasPrefix(file.Location, "http:") {
			err = fmt.Errorf("(File/Exists) schema http not yet supported (%s)", file.Location)
			return
		}
		if strings.HasPrefix(file.Location, "https:") {
			err = fmt.Errorf("(File/Exists) schema https not yet supported")
			return
		}
		if strings.HasPrefix(file.Location, "ftp:") {
			err = fmt.Errorf("(File/Exists) schema https not yet supported")
			return
		}

		if !path.IsAbs(filePath) {
			filePath = path.Join(inputfilePath, filePath)
		}

		//var file_info os.FileInfo
		_, err = os.Stat(filePath)
		if err != nil {
			err = nil
			ok = false
			//err = fmt.Errorf("(UploadFile) os.Stat returned: %s (file.Path: %s)", err.Error(), file.Path)
			return
		}
		ok = true

	}
	return
}

//type FileArray struct {
//	CWLType_Impl
//	Id   string `yaml:"id" json:"id"`
//	Data []File
//}

//func (f *FileArray) GetClass() string { return "array" }

//func (f *FileArray) Is_Array() bool   { return true }

//func (f *FileArray) IsArrayType() {}
//func (f *FileArray) Get_Array() *[]File {
//	return &f.Data
//}

//func (f *FileArray) GetID() string   { return f.Id }
//func (f *FileArray) SetID(id string) { f.Id = id }

//func (f *FileArray) String() string      { return f.Path }
//func (f *FileArray) GetLocation() string { return f.Location } // for CWL_location

//func (s *FileArray) Is_CommandInputParameterType() {} // for CommandInputParameterType
<|endoftext|>


<commit_before>package testintegration

import (
	"github.com/smancke/guble/client"
	"github.com/smancke/guble/gubled"
	"github.com/smancke/guble/server"
	"github.com/stretchr/testify/assert"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	"testing"
	"time"
	"github.com/smancke/guble/testutil"
)

func createService(storagePath, nodeID, nodePort, listenPort string, remotes string) *server.Service {
	os.Args = []string{os.Args[0],
		"--log", "debug",
		"--listen", listenPort,
		"--storage-path", storagePath,
		"--node-id", nodeID,
		"--health", "",
		"--node-port", nodePort,
		remotes,
	}

	kingpin.Parse()
	service := gubled.StartService()
	return service
}

func Test_Cluster(t *testing.T) {
	a := assert.New(t)
	defer testutil.EnableDebugForMethod()()

	service1 := createService("/tmp/s1", "1", "10000", "127.0.0.1:8080", "tcp://127.0.0.1:10000")
	a.NotNil(service1)

	service2 := createService("/tmp/s2", "2", "10001", "127.0.0.1:8081", "tcp://127.0.0.1:10000")
	a.NotNil(service2)

	client1, err := client.Open("ws://127.0.0.1:8081/stream/user/user1", "http://localhost", 1, false)
	assert.NoError(t, err)

	client2, err := client.Open("ws://127.0.0.1:8080/stream/user/user2", "http://localhost", 1, false)
	assert.NoError(t, err)

	err = client1.Subscribe("/foo")
	a.Nil(err)

	err = client2.Subscribe("/barbazzMarian35")
	a.Nil(err)

	err = client1.Send("/barbazzMarian35", "", "{}")
	a.Nil(err)

	time.Sleep(time.Millisecond * 10)
	//
	err = service1.Stop()
	//err = service2.Stop()
	time.Sleep(time.Second * 2)
	a.Nil(err)
}
<commit_msg>Added client testing for services<commit_after>package testintegration

import (
	"github.com/smancke/guble/client"
	"github.com/smancke/guble/gubled"
	"github.com/smancke/guble/server"
	"github.com/stretchr/testify/assert"
	"gopkg.in/alecthomas/kingpin.v2"
	"os"
	"testing"
	"time"
	//"github.com/smancke/guble/testutil"
	"fmt"
)

func createService(storagePath, nodeID, nodePort, listenPort string, remotes string) *server.Service {
	os.Args = []string{os.Args[0],
		"--log", "debug",
		"--listen", listenPort,
		"--storage-path", storagePath,
		"--node-id", nodeID,
		"--health", "",
		"--node-port", nodePort,
		remotes,
	}

	kingpin.Parse()
	service := gubled.StartService()
	return service
}

func Test_Cluster(t *testing.T) {
	a := assert.New(t)
	//defer testutil.EnableDebugForMethod()()

	service1 := createService("/tmp/s1", "1", "10000", "127.0.0.1:8080", "tcp://127.0.0.1:10000")
	a.NotNil(service1)

	service2 := createService("/tmp/s2", "2", "10001", "127.0.0.1:8081", "tcp://127.0.0.1:10000")
	a.NotNil(service2)

	client1, err := client.Open("ws://127.0.0.1:8081/stream/user/user1", "http://localhost", 1, false)
	assert.NoError(t, err)

	client2, err := client.Open("ws://127.0.0.1:8080/stream/user/user2", "http://localhost", 1, false)
	assert.NoError(t, err)

	err = client1.Subscribe("/foo")
	a.Nil(err)

	err = client2.Subscribe("/testTopic")
	a.Nil(err)

	err = client1.Send("/testTopic", "", "{}")
	a.Nil(err)

	//see if the message arrived at the other  client
	select {
	case incomingMessage := <-client2.Messages():
		fmt.Printf("+++%v: %v\n", incomingMessage.UserID, incomingMessage.BodyAsString())
	case <-time.After(time.Second):
		a.FailNow("No Message was received on second client in 1 second")
	}

	time.Sleep(time.Millisecond * 10)
	//
	err = service1.Stop()
	err2 := service2.Stop()
	time.Sleep(time.Second * 2)
	a.Nil(err)
	a.Nil(err2)
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package e2e

import (
	"fmt"
	"io/ioutil"
	"net"
	"strings"
	"sync"
)

type command struct {
	cmd       string
	component string
}

func CoreDump(dir string) {
	c, err := loadClient()
	if err != nil {
		fmt.Printf("Error creating client: %v", err)
		return
	}
	provider := testContext.Provider

	// requires ssh to master machine
	if !providerIs(providersWithMasterSSH...) {
		fmt.Printf("Skipping SSH core dump, which is not implemented for %s", provider)
		return
	}

	// I wish there was a better way to get the master IP...
	config, err := loadConfig()
	if err != nil {
		fmt.Printf("Error loading config: %v", err)
	}
	ix := strings.LastIndex(config.Host, "/")
	master := net.JoinHostPort(config.Host[ix+1:], "22")

	cmds := []command{
		{"cat /var/log/kube-apiserver.log", "kube-apiserver"},
		{"cat /var/log/kube-scheduler.log", "kube-scheduler"},
		{"cat /var/log/kube-controller-manager.log", "kube-controller-manager"},
		{"cat /var/log/etcd.log", "kube-etcd"},
	}
	if isUsingSystemdKubelet(provider, master) {
		cmds = append(cmds, command{"sudo journalctl --output=cat -u kubelet.service", "kubelet"})
	} else {
		cmds = append(cmds, []command{
			{"cat /var/log/kubelet.log", "kubelet"},
			{"cat /var/log/supervisor/supervisord.log", "supervisord"},
			{"cat /var/log/supervisor/kubelet-stdout.log", "supervisord-kubelet-stdout"},
			{"cat /var/log/supervisor/kubelet-stderr.log", "supervisord-kubelet-stderr"},
			{"cat /var/log/kern.log", "kern.log"},
		}...)
	}

	logCore(cmds, []string{master}, dir, provider)

	// requires ssh
	if !providerIs(providersWithSSH...) {
		fmt.Printf("Skipping SSH core dump for nodes, which is not implemented for %s", provider)
		return
	}

	// Get all nodes' external IPs.
	hosts, err := NodeSSHHosts(c)
	if err != nil {
		fmt.Printf("Error getting node hostnames: %v", err)
		return
	}

	cmds = []command{{"cat /var/log/kube-proxy.log", "kube-proxy"}}
	if isUsingSystemdKubelet(provider, hosts...) {
		cmds = append(cmds, command{"sudo journalctl --output=cat -u kubelet.service", "kubelet"})
	} else {
		cmds = append(cmds, []command{
			{"cat /var/log/kubelet.log", "kubelet"},
			{"cat /var/log/supervisor/supervisord.log", "supervisord"},
			{"cat /var/log/supervisor/kubelet-stdout.log", "supervisord-kubelet-stdout"},
			{"cat /var/log/supervisor/kubelet-stderr.log", "supervisord-kubelet-stderr"},
			{"cat /var/log/kern.log", "kern.log"},
		}...)
	}

	logCore(cmds, hosts, dir, provider)
}

func logCore(cmds []command, hosts []string, dir, provider string) {
	wg := &sync.WaitGroup{}
	// Run commands on all nodes via SSH.
	for _, cmd := range cmds {
		fmt.Printf("SSH'ing to all nodes and running %s\n", cmd.cmd)
		for _, host := range hosts {
			wg.Add(1)
			go func(cmd command, host string) {
				defer wg.Done()
				logfile := fmt.Sprintf("%s/%s-%s.log", dir, host, cmd.component)
				fmt.Printf("Writing to %s.\n", logfile)
				result, err := SSH(cmd.cmd, host, provider)
				if err != nil {
					fmt.Printf("Error running command: %v\n", err)
				}
				if err := ioutil.WriteFile(logfile, []byte(result.Stdout+result.Stderr), 0777); err != nil {
					fmt.Printf("Error writing logfile: %v\n", err)
				}
			}(cmd, host)
		}
	}
	wg.Wait()
}

func isUsingSystemdKubelet(provider string, hosts ...string) bool {
	wg := &sync.WaitGroup{}
	results := make([]bool, len(hosts))
	cmd := "sudo systemctl status kubelet.service"

	wg.Add(len(hosts))
	for i := range hosts {
		go func(i int) {
			defer wg.Done()
			result, err := SSH(cmd, hosts[i], provider)
			if err != nil {
				fmt.Printf("Error running command: %v\n", err)
				return
			}
			if result.Code == 0 {
				results[i] = true
			}
		}(i)
	}
	wg.Wait()

	for _, r := range results {
		if r {
			return true
		}
	}
	return false
}
<commit_msg>collect docker.log<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

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

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

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

package e2e

import (
	"fmt"
	"io/ioutil"
	"net"
	"strings"
	"sync"
)

type command struct {
	cmd       string
	component string
}

func CoreDump(dir string) {
	c, err := loadClient()
	if err != nil {
		fmt.Printf("Error creating client: %v", err)
		return
	}
	provider := testContext.Provider

	// requires ssh to master machine
	if !providerIs(providersWithMasterSSH...) {
		fmt.Printf("Skipping SSH core dump, which is not implemented for %s", provider)
		return
	}

	// I wish there was a better way to get the master IP...
	config, err := loadConfig()
	if err != nil {
		fmt.Printf("Error loading config: %v", err)
	}
	ix := strings.LastIndex(config.Host, "/")
	master := net.JoinHostPort(config.Host[ix+1:], "22")

	cmds := []command{
		{"cat /var/log/kube-apiserver.log", "kube-apiserver"},
		{"cat /var/log/kube-scheduler.log", "kube-scheduler"},
		{"cat /var/log/kube-controller-manager.log", "kube-controller-manager"},
		{"cat /var/log/etcd.log", "kube-etcd"},
	}
	if isUsingSystemdKubelet(provider, master) {
		cmds = append(cmds, command{"sudo journalctl --output=cat -u kubelet.service", "kubelet"})
	} else {
		cmds = append(cmds, []command{
			{"cat /var/log/kubelet.log", "kubelet"},
			{"cat /var/log/supervisor/supervisord.log", "supervisord"},
			{"cat /var/log/supervisor/kubelet-stdout.log", "supervisord-kubelet-stdout"},
			{"cat /var/log/supervisor/kubelet-stderr.log", "supervisord-kubelet-stderr"},
			{"cat /var/log/kern.log", "kern.log"},
			{"cat /var/log/docker.log", "docker.log"},
		}...)
	}

	logCore(cmds, []string{master}, dir, provider)

	// requires ssh
	if !providerIs(providersWithSSH...) {
		fmt.Printf("Skipping SSH core dump for nodes, which is not implemented for %s", provider)
		return
	}

	// Get all nodes' external IPs.
	hosts, err := NodeSSHHosts(c)
	if err != nil {
		fmt.Printf("Error getting node hostnames: %v", err)
		return
	}

	cmds = []command{{"cat /var/log/kube-proxy.log", "kube-proxy"}}
	if isUsingSystemdKubelet(provider, hosts...) {
		cmds = append(cmds, command{"sudo journalctl --output=cat -u kubelet.service", "kubelet"})
	} else {
		cmds = append(cmds, []command{
			{"cat /var/log/kubelet.log", "kubelet"},
			{"cat /var/log/supervisor/supervisord.log", "supervisord"},
			{"cat /var/log/supervisor/kubelet-stdout.log", "supervisord-kubelet-stdout"},
			{"cat /var/log/supervisor/kubelet-stderr.log", "supervisord-kubelet-stderr"},
			{"cat /var/log/kern.log", "kern.log"},
			{"cat /var/log/docker.log", "docker.log"},
		}...)
	}

	logCore(cmds, hosts, dir, provider)
}

func logCore(cmds []command, hosts []string, dir, provider string) {
	wg := &sync.WaitGroup{}
	// Run commands on all nodes via SSH.
	for _, cmd := range cmds {
		fmt.Printf("SSH'ing to all nodes and running %s\n", cmd.cmd)
		for _, host := range hosts {
			wg.Add(1)
			go func(cmd command, host string) {
				defer wg.Done()
				logfile := fmt.Sprintf("%s/%s-%s.log", dir, host, cmd.component)
				fmt.Printf("Writing to %s.\n", logfile)
				result, err := SSH(cmd.cmd, host, provider)
				if err != nil {
					fmt.Printf("Error running command: %v\n", err)
				}
				if err := ioutil.WriteFile(logfile, []byte(result.Stdout+result.Stderr), 0777); err != nil {
					fmt.Printf("Error writing logfile: %v\n", err)
				}
			}(cmd, host)
		}
	}
	wg.Wait()
}

func isUsingSystemdKubelet(provider string, hosts ...string) bool {
	wg := &sync.WaitGroup{}
	results := make([]bool, len(hosts))
	cmd := "sudo systemctl status kubelet.service"

	wg.Add(len(hosts))
	for i := range hosts {
		go func(i int) {
			defer wg.Done()
			result, err := SSH(cmd, hosts[i], provider)
			if err != nil {
				fmt.Printf("Error running command: %v\n", err)
				return
			}
			if result.Code == 0 {
				results[i] = true
			}
		}(i)
	}
	wg.Wait()

	for _, r := range results {
		if r {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/util"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
	"strings"
)

func init() {
	commands = append(commands, cli.Command{
		Name:      "delete",
		Usage:     "delete a given server, disc, group, account or key",
		UsageText: "bytemark delete account|disc|group|key|server",
		Description: `delete a given server, disc, group, account or key

   Only empty groups and accounts can be deleted.

   The restore server command may be used to restore a deleted (but not purged) server to its state prior to deletion.`,
		Action: cli.ShowSubcommandHelp,
		Subcommands: []cli.Command{{
			Name:        "disc",
			Usage:       "delete the given disc",
			UsageText:   "bytemark delete disc <virtual machine name> <disc label>",
			Description: "Deletes the given disc. To find out a disc's label you can use the `bytemark show server` command or `bytemark list discs` command.",
			Flags:       []cli.Flag{forceFlag},
			Aliases:     []string{"disk"},
			Action: With(VirtualMachineNameProvider, DiscLabelProvider, AuthProvider, func(c *Context) (err error) {
				if !c.Bool("force") && !util.PromptYesNo("Are you sure you wish to delete this disc? It is impossible to recover.") {
					return util.UserRequestedExit{}
				}

				return global.Client.DeleteDisc(c.VirtualMachineName, *c.DiscLabel)
			}),
		}, {
			Name:      "group",
			Usage:     "deletes the given group",
			UsageText: "bytemark delete group [--force] [--recursive] <group name>",
			Description: `Deletes the given group.
If --recursive is specified, all servers in the group will be purged. Otherwise, if there are servers in the group, will return an error.`,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "recursive",
					Usage: "If set, all servers in the group will be irrevocably deleted.",
				},
				forceFlag,
			},
			Action: With(GroupProvider, deleteGroup),
		}, {
			Name:        "key",
			Usage:       "deletes the specified key",
			UsageText:   "bytemark delete key [--user <user>] <key>",
			Description: "Keys may be specified as just the comment part or as the whole key. If there are multiple keys with the comment given, an error will be returned",
			Action: With(func(c *Context) (err error) {
				user := global.Config.GetIgnoreErr("user")

				key := strings.Join(c.Args(), " ")
				if key == "" {
					return c.Help("You must specify a key to delete.\r\n")
				}

				err = EnsureAuth()
				if err != nil {
					return
				}

				err = global.Client.DeleteUserAuthorizedKey(user, key)
				if err == nil {
					log.Log("Key deleted successfullly")
				}
				return
			}),
		}, {
			Name:        "server",
			Usage:       "delete the given server",
			UsageText:   `bytemark delete server [--purge] <server name>`,
			Description: "Deletes the given server. Deleted servers still exist and can be restored. To ensure a server is fully deleted, use the --purge flag.",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "purge",
					Usage: "If set, the server will be irrevocably deleted.",
				},
				forceFlag,
			},
			Action: With(VirtualMachineProvider, deleteServer),
		}},
	})
}

func deleteServer(c *Context) (err error) {
	purge := c.Bool("purge")
	vm := c.VirtualMachine

	if vm.Deleted && !purge {
		log.Errorf("Server %s has already been deleted.\r\nIf you wish to permanently delete it, add --purge\r\n", vm.Hostname)
		// we don't return an error because we want a 0 exit code - the deletion request has happened, just not now.
		return
	}
	fstr := fmt.Sprintf("Are you certain you wish to delete %s?", vm.Hostname)
	if purge {
		fstr = fmt.Sprintf("Are you certain you wish to permanently delete %s? You will not be able to un-delete it.", vm.Hostname)

	}

	if !c.Bool("force") && !util.PromptYesNo(fstr) {
		err = util.UserRequestedExit{}
		return
	}

	err = global.Client.DeleteVirtualMachine(c.VirtualMachineName, purge)
	if err != nil {
		return
	}
	if purge {
		log.Logf("Server %s purged successfully.\r\n", vm.Hostname)
	} else {
		log.Logf("Server %s deleted successfully.\r\n", vm.Hostname)
	}
	return
}

func countRunning(group *brain.Group) (running int) {
	for _, vm := range group.VirtualMachines {
		if vm.PowerOn {
			running++
		}
	}
	return running
}

func deleteGroup(c *Context) (err error) {
	recursive := c.Bool("recursive")
	if len(c.Group.VirtualMachines) > 0 && recursive {
		prompt := fmt.Sprintf("The group '%s' has %d servers in it, these servers will be irrevocably deleted", c.GroupName.Group, len(c.Group.VirtualMachines))
		running := countRunning(c.Group)
		if running != 0 {
			prompt = fmt.Sprintf("The group '%s' has %d currently-running servers in it, these servers will be forcibly stopped and irrevocably deleted", c.GroupName.Group, running)
		}

		if !c.Bool("force") && !util.PromptYesNo(prompt+" - are you sure you wish to delete this group?") {
			return util.UserRequestedExit{}
		}
		err = recursiveDeleteGroup(c.GroupName, c.Group)
		if err != nil {
			return
		}
	} else if !recursive {
		err = &util.WontDeleteNonEmptyGroupError{Group: c.GroupName}
		return
	}
	err = global.Client.DeleteGroup(c.GroupName)
	if err != nil {
		log.Logf("Group %s deleted successfully.\r\n", c.GroupName.String())
	}
	return
}

func recursiveDeleteGroup(name *lib.GroupName, group *brain.Group) error {
	log.Log("", "")
	vmn := lib.VirtualMachineName{Group: name.Group, Account: name.Account}
	for _, vm := range group.VirtualMachines {
		vmn.VirtualMachine = vm.Name
		err := global.Client.DeleteVirtualMachine(&vmn, true)
		if err != nil {
			return err
		}
		log.Logf("%s\r\n", vm.Name)

	}
	log.Log()
	return nil
}

/*log.Log("usage: bytemark delete account <account>")
	log.Log("       bytemark delete disc <server> <label>")
	log.Log("       bytemark delete group [--recursive] <group>")
	//log.Log("       bytemark delete user <user>")
	log.Log("       bytemark delete key [--user=<user>] <public key identifier>")
	log.Log("       bytemark delete server [--force] [---purge] <server>")
	log.Log("       bytemark undelete server <server>")
}*/
<commit_msg>delete group --recusive: add stopped count,<commit_after>package main

import (
	"fmt"
	"github.com/BytemarkHosting/bytemark-client/cmd/bytemark/util"
	"github.com/BytemarkHosting/bytemark-client/lib"
	"github.com/BytemarkHosting/bytemark-client/lib/brain"
	"github.com/BytemarkHosting/bytemark-client/util/log"
	"github.com/urfave/cli"
	"strings"
)

func init() {
	commands = append(commands, cli.Command{
		Name:      "delete",
		Usage:     "delete a given server, disc, group, account or key",
		UsageText: "bytemark delete account|disc|group|key|server",
		Description: `delete a given server, disc, group, account or key

   Only empty groups and accounts can be deleted.

   The restore server command may be used to restore a deleted (but not purged) server to its state prior to deletion.`,
		Action: cli.ShowSubcommandHelp,
		Subcommands: []cli.Command{{
			Name:        "disc",
			Usage:       "delete the given disc",
			UsageText:   "bytemark delete disc <virtual machine name> <disc label>",
			Description: "Deletes the given disc. To find out a disc's label you can use the `bytemark show server` command or `bytemark list discs` command.",
			Flags:       []cli.Flag{forceFlag},
			Aliases:     []string{"disk"},
			Action: With(VirtualMachineNameProvider, DiscLabelProvider, AuthProvider, func(c *Context) (err error) {
				if !c.Bool("force") && !util.PromptYesNo("Are you sure you wish to delete this disc? It is impossible to recover.") {
					return util.UserRequestedExit{}
				}

				return global.Client.DeleteDisc(c.VirtualMachineName, *c.DiscLabel)
			}),
		}, {
			Name:      "group",
			Usage:     "deletes the given group",
			UsageText: "bytemark delete group [--force] [--recursive] <group name>",
			Description: `Deletes the given group.
If --recursive is specified, all servers in the group will be purged. Otherwise, if there are servers in the group, will return an error.`,
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "recursive",
					Usage: "If set, all servers in the group will be irrevocably deleted.",
				},
				forceFlag,
			},
			Action: With(GroupProvider, deleteGroup),
		}, {
			Name:        "key",
			Usage:       "deletes the specified key",
			UsageText:   "bytemark delete key [--user <user>] <key>",
			Description: "Keys may be specified as just the comment part or as the whole key. If there are multiple keys with the comment given, an error will be returned",
			Action: With(func(c *Context) (err error) {
				user := global.Config.GetIgnoreErr("user")

				key := strings.Join(c.Args(), " ")
				if key == "" {
					return c.Help("You must specify a key to delete.\r\n")
				}

				err = EnsureAuth()
				if err != nil {
					return
				}

				err = global.Client.DeleteUserAuthorizedKey(user, key)
				if err == nil {
					log.Log("Key deleted successfullly")
				}
				return
			}),
		}, {
			Name:        "server",
			Usage:       "delete the given server",
			UsageText:   `bytemark delete server [--purge] <server name>`,
			Description: "Deletes the given server. Deleted servers still exist and can be restored. To ensure a server is fully deleted, use the --purge flag.",
			Flags: []cli.Flag{
				cli.BoolFlag{
					Name:  "purge",
					Usage: "If set, the server will be irrevocably deleted.",
				},
				forceFlag,
			},
			Action: With(VirtualMachineProvider, deleteServer),
		}},
	})
}

func deleteServer(c *Context) (err error) {
	purge := c.Bool("purge")
	vm := c.VirtualMachine

	if vm.Deleted && !purge {
		log.Errorf("Server %s has already been deleted.\r\nIf you wish to permanently delete it, add --purge\r\n", vm.Hostname)
		// we don't return an error because we want a 0 exit code - the deletion request has happened, just not now.
		return
	}
	fstr := fmt.Sprintf("Are you certain you wish to delete %s?", vm.Hostname)
	if purge {
		fstr = fmt.Sprintf("Are you certain you wish to permanently delete %s? You will not be able to un-delete it.", vm.Hostname)

	}

	if !c.Bool("force") && !util.PromptYesNo(fstr) {
		err = util.UserRequestedExit{}
		return
	}

	err = global.Client.DeleteVirtualMachine(c.VirtualMachineName, purge)
	if err != nil {
		return
	}
	if purge {
		log.Logf("Server %s purged successfully.\r\n", vm.Hostname)
	} else {
		log.Logf("Server %s deleted successfully.\r\n", vm.Hostname)
	}
	return
}

func countRunning(group *brain.Group) (running int) {
	for _, vm := range group.VirtualMachines {
		if vm.PowerOn {
			running++
		}
	}
	return running
}

func deleteGroup(c *Context) (err error) {
	recursive := c.Bool("recursive")
	if len(c.Group.VirtualMachines) > 0 && recursive {
		prompt := fmt.Sprintf("The group '%s' has %d servers in it which will be irrevocably deleted", c.GroupName.Group, len(c.Group.VirtualMachines))
		running := countRunning(c.Group)
		if running != 0 {
			stopped := len(c.Group.VirtualMachines) - running
			andStopped := ""
			if stopped > 0 {
				andStopped = fmt.Sprintf("and %d stopped ", stopped)
			}
			prompt = fmt.Sprintf("The group '%s' has %d currently-running %sservers in it which will be forcibly stopped and irrevocably deleted", c.GroupName.Group, running, andStopped)
		}

		if !c.Bool("force") && !util.PromptYesNo(prompt+" - are you sure you wish to delete this group?") {
			return util.UserRequestedExit{}
		}
		err = recursiveDeleteGroup(c.GroupName, c.Group)
		if err != nil {
			return
		}
	} else if !recursive {
		err = &util.WontDeleteNonEmptyGroupError{Group: c.GroupName}
		return
	}
	err = global.Client.DeleteGroup(c.GroupName)
	if err == nil {
		log.Logf("Group %s deleted successfully.\r\n", c.GroupName.String())
	}
	return
}

func recursiveDeleteGroup(name *lib.GroupName, group *brain.Group) error {
	log.Log("", "")
	vmn := lib.VirtualMachineName{Group: name.Group, Account: name.Account}
	for _, vm := range group.VirtualMachines {
		vmn.VirtualMachine = vm.Name
		err := global.Client.DeleteVirtualMachine(&vmn, true)
		if err != nil {
			return err
		}
		log.Logf("%s\r\n", vm.Name)

	}
	log.Log()
	return nil
}

/*log.Log("usage: bytemark delete account <account>")
	log.Log("       bytemark delete disc <server> <label>")
	log.Log("       bytemark delete group [--recursive] <group>")
	//log.Log("       bytemark delete user <user>")
	log.Log("       bytemark delete key [--user=<user>] <public key identifier>")
	log.Log("       bytemark delete server [--force] [---purge] <server>")
	log.Log("       bytemark undelete server <server>")
}*/
<|endoftext|>


<commit_before>package cmd_member

import (
	"flag"
	"github.com/watermint/toolbox/app/app_report"
	"github.com/watermint/toolbox/cmd"
	"github.com/watermint/toolbox/domain/infra/api_auth_impl"
	"github.com/watermint/toolbox/domain/service/sv_member"
)

type CmdMemberList struct {
	*cmd.SimpleCommandlet

	optIncludeRemoved bool
	report            app_report.Factory
}

func (z *CmdMemberList) Name() string {
	return "list"
}

func (z *CmdMemberList) Desc() string {
	return "cmd.member.list.desc"
}

func (CmdMemberList) Usage() func(cmd.CommandUsage) {
	return nil
}

func (z *CmdMemberList) FlagConfig(f *flag.FlagSet) {
	z.report.ExecContext = z.ExecContext
	z.report.FlagConfig(f)

	descCsv := "Include removed members"
	f.BoolVar(&z.optIncludeRemoved, "include-removed", false, descCsv)
}

func (z *CmdMemberList) Exec(args []string) {
	ctx, err := api_auth_impl.Auth(z.ExecContext, api_auth_impl.BusinessInfo())
	if err != nil {
		return
	}

	z.report.Init(z.ExecContext)
	defer z.report.Close()

	svc := sv_member.New(ctx)
	members, err := svc.List()
	if err != nil {
		ctx.ErrorMsg(err).TellError()
		return
	}

	for _, m := range members {
		z.report.Report(m)
	}
}
<commit_msg>temporarily replace auth type of `member list`<commit_after>package cmd_member

import (
	"flag"
	"github.com/watermint/toolbox/app/app_report"
	"github.com/watermint/toolbox/cmd"
	"github.com/watermint/toolbox/domain/infra/api_auth_impl"
	"github.com/watermint/toolbox/domain/service/sv_member"
)

type CmdMemberList struct {
	*cmd.SimpleCommandlet

	optIncludeRemoved bool
	report            app_report.Factory
}

func (z *CmdMemberList) Name() string {
	return "list"
}

func (z *CmdMemberList) Desc() string {
	return "cmd.member.list.desc"
}

func (CmdMemberList) Usage() func(cmd.CommandUsage) {
	return nil
}

func (z *CmdMemberList) FlagConfig(f *flag.FlagSet) {
	z.report.ExecContext = z.ExecContext
	z.report.FlagConfig(f)

	descCsv := "Include removed members"
	f.BoolVar(&z.optIncludeRemoved, "include-removed", false, descCsv)
}

func (z *CmdMemberList) Exec(args []string) {
	//	ctx, err := api_auth_impl.Auth(z.ExecContext, api_auth_impl.BusinessInfo())
	ctx, err := api_auth_impl.Auth(z.ExecContext, api_auth_impl.BusinessManagement())
	if err != nil {
		return
	}

	z.report.Init(z.ExecContext)
	defer z.report.Close()

	svc := sv_member.New(ctx)
	members, err := svc.List()
	if err != nil {
		ctx.ErrorMsg(err).TellError()
		return
	}

	for _, m := range members {
		z.report.Report(m)
	}
}
<|endoftext|>


<commit_before>/*
   Copyright 2020 Docker Compose CLI authors

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

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

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

package compose

import (
	"fmt"
	"strings"

	"github.com/docker/compose/v2/cmd/formatter"

	"github.com/spf13/cobra"

	"github.com/docker/compose/v2/internal"
)

type versionOptions struct {
	format string
	short  bool
}

func versionCommand() *cobra.Command {
	opts := versionOptions{}
	cmd := &cobra.Command{
		Use:   "version",
		Short: "Show the Docker Compose version information",
		Args:  cobra.MaximumNArgs(0),
		RunE: func(cmd *cobra.Command, _ []string) error {
			runVersion(opts)
			return nil
		},
	}
	// define flags for backward compatibility with com.docker.cli
	flags := cmd.Flags()
	flags.StringVarP(&opts.format, "format", "f", "", "Format the output. Values: [pretty | json]. (Default: pretty)")
	flags.BoolVar(&opts.short, "short", false, "Shows only Compose's version number.")

	return cmd
}

func runVersion(opts versionOptions) {
	if opts.short {
		fmt.Println(strings.TrimPrefix(internal.Version, "v"))
		return
	}
	if opts.format == formatter.JSON {
		fmt.Printf("{\"version\":%q}\n", internal.Version)
		return
	}
	fmt.Println("Docker Compose version", internal.Version)
}
<commit_msg>Overwrite parent commands PreRun code for `compose version`<commit_after>/*
   Copyright 2020 Docker Compose CLI authors

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

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

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

package compose

import (
	"fmt"
	"strings"

	"github.com/docker/compose/v2/cmd/formatter"

	"github.com/spf13/cobra"

	"github.com/docker/compose/v2/internal"
)

type versionOptions struct {
	format string
	short  bool
}

func versionCommand() *cobra.Command {
	opts := versionOptions{}
	cmd := &cobra.Command{
		Use:   "version",
		Short: "Show the Docker Compose version information",
		Args:  cobra.MaximumNArgs(0),
		RunE: func(cmd *cobra.Command, _ []string) error {
			runVersion(opts)
			return nil
		},
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			// overwrite parent PersistentPreRunE to avoid trying to load
			// compose file on version command if COMPOSE_FILE is set
			return nil
		},
	}
	// define flags for backward compatibility with com.docker.cli
	flags := cmd.Flags()
	flags.StringVarP(&opts.format, "format", "f", "", "Format the output. Values: [pretty | json]. (Default: pretty)")
	flags.BoolVar(&opts.short, "short", false, "Shows only Compose's version number.")

	return cmd
}

func runVersion(opts versionOptions) {
	if opts.short {
		fmt.Println(strings.TrimPrefix(internal.Version, "v"))
		return
	}
	if opts.format == formatter.JSON {
		fmt.Printf("{\"version\":%q}\n", internal.Version)
		return
	}
	fmt.Println("Docker Compose version", internal.Version)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"github.com/datawire/teleproxy/pkg/k8s"
	"github.com/datawire/teleproxy/pkg/supervisor"
	"github.com/datawire/teleproxy/pkg/watt"
	"github.com/spf13/cobra"
	"net/http"
	"os"
	"strings"
	"sync"
)

var kubernetesNamespace string
var initialSources = make([]string, 0)
var port int

var rootCmd = &cobra.Command{
	Use:              "watt",
	Short:            "watt",
	Long:             "watt - watch all the things",
	PersistentPreRun: func(cmd *cobra.Command, args []string) {},
	Run:              runWatt,
}

type getSnapshotRequest struct {
	snapshot chan string
}

func init() {
	rootCmd.Flags().StringVarP(&kubernetesNamespace, "namespace", "", "", "namespace to watch (default: all)")
	rootCmd.Flags().StringSliceVarP(&initialSources, "source", "s", []string{}, "configure an initial static source")
	rootCmd.Flags().IntVarP(&port, "port", "p", 7000, "configure the snapshot server port")
}

// determine if we're dealing with a potential piece of Ambassador configuration. Right now that comes through in
// annotations of a Service. In the future it will likely be done via CRD. For this PoC I use a ConfigMap as pseudo-CRD.
func isAmbassadorConfiguration(r k8s.Resource) (string, bool) {
	kind := strings.ToLower(r.Kind())

	switch kind {
	case "service":
		// this is terribly hacky and not particularly important atm
		a := r.Metadata().Annotations()
		if _, ok := a["getambassador.io/config"]; ok {
			return "mapping", true
		}
	case "configmap":
		a := r.Metadata().Annotations()
		if _, ok := a["getambassador.io/consul-resolver"]; ok {
			return "consul-resolver", true
		}
	default:
		return "", false
	}

	return "", false
}

// this thing here would extract Ambassador annotation data from the metadata and then do something useful with it...
// let's pretend this is not important right now.
func extractAmbassadorAnnotation(r k8s.Resource) string {
	return ""
}

// makeKubeWatcher returns a function that sets up a series of watches to the Kubernetes API for different
// kubernetes resources. When a change occurs the function gets the state of all resources that are being watched
// and sends a message to the watchman and assembler channels for further processing.
func makeKubeWatcher(namespace string,
	kinds []string,
	watchman chan<- []k8s.Resource,
	assembler chan<- []k8s.Resource) func(p *supervisor.Process) error {

	return func(p *supervisor.Process) error {
		kubeWatcher := k8s.NewClient(nil).Watcher()

		for _, kind := range kinds {
			p.Logf("adding watch for %q", kind)
			err := kubeWatcher.WatchNamespace(namespace, kind, func(watcher *k8s.Watcher) {
				k := kinds
				p.Logf("change in watched resources")

				resources := make([]k8s.Resource, 0)
				for _, kind := range k {
					resources = append(resources, watcher.List(kind)...)
				}

				watchman <- resources
				assembler <- resources
			})

			if err != nil {
				p.Logf("failed to add watch for %q", kind)
				return err
			}

			p.Logf("added watch for %q", kind)
		}

		kubeWatcher.Start()

		for {
			select {
			case <-p.Shutdown():
				p.Logf("shutdown initiated\n")
				kubeWatcher.Stop()
				return nil
			}
		}
	}
}

func makeConsulWatcher(config k8s.Resource, assembler chan<- []k8s.Resource) (string, *supervisor.Worker) {
	data := config.Data()
	cwm := &watt.ConsulServiceNodeWatchMaker{
		Service:     data["service"].(string),
		Datacenter:  data["datacenter"].(string),
		OnlyHealthy: true,
	}

	cwmFunc, _ := cwm.Make(assembler)
	return cwm.ID(), &supervisor.Worker{
		Name:  cwm.ID(),
		Work:  cwmFunc,
		Retry: false,
	}
}

func makeWatchman(resourcesChan <-chan []k8s.Resource, assembler chan<- []k8s.Resource) func(p *supervisor.Process) error {
	return func(p *supervisor.Process) error {
		p.Ready()

		watched := make(map[string]*supervisor.Worker)

		for {
			select {
			case resources := <-resourcesChan:
				reported := make(map[string]*supervisor.Worker, 0)
				for _, r := range resources {
					rType, _ := isAmbassadorConfiguration(r)
					if rType == "consul-resolver" {
						ID, worker := makeConsulWatcher(r, assembler)
						if _, exists := watched[ID]; !exists {
							p.Logf("add consul watcher %s\n", ID)
							p.Supervisor().Supervise(worker)
							watched[ID] = worker
						}

						reported[ID] = worker
					}
				}

				// purge the watches that no longer are needed because they did not come through the in the latest
				// report
				for k, worker := range watched {
					if _, exists := reported[k]; !exists {
						p.Logf("remove consul watcher %s\n", k)
						worker.Shutdown()
					}
				}

				watched = reported
			case <-p.Shutdown():
				return nil
			}
		}
	}
}

func makeAssembler(getSnapshotCh <-chan *getSnapshotRequest, recordsCh <-chan []k8s.Resource) func(p *supervisor.Process) error {
	return func(p *supervisor.Process) error {
		p.Ready()
		snapshots := make([]watt.Snapshot, 0)

		for {
			select {
			case req := <-getSnapshotCh:
				p.Logf("returning snapshot")
				req.snapshot <- "{ }" // ignore this for now.

			case <-recordsCh:
				p.Logf("creating snapshot")
				if len(snapshots) > 10 {
					snapshots = snapshots[1:]
				}
			case <-p.Shutdown():
				return nil
			}
		}
	}
}

func runWatt(_ *cobra.Command, _ []string) {
	fmt.Println("Watt - Watch All The Things! Starting...")

	// 1. construct an initial list of things to watch
	// 2. feed them to the watch controller
	watchman := make(chan []k8s.Resource)
	assembler := make(chan []k8s.Resource)

	fmt.Println(initialSources)

	ctx := context.Background()

	s := supervisor.WithContext(ctx)
	s.Supervise(&supervisor.Worker{
		Name:     "kubewatcher",
		Work:     makeKubeWatcher(kubernetesNamespace, initialSources, watchman, assembler),
		Requires: []string{"watchman"},
		Retry:    false,
	})

	s.Supervise(&supervisor.Worker{
		Name:     "watchman",
		Work:     makeWatchman(watchman, assembler),
		Requires: []string{"assembler"},
		Retry:    false,
	})

	getSnapshotChan := make(chan *getSnapshotRequest)
	s.Supervise(&supervisor.Worker{
		Name:  "assembler",
		Work:  makeAssembler(getSnapshotChan, assembler),
		Retry: false,
	})

	s.Supervise(&supervisor.Worker{
		Name:     "snapshot server",
		Requires: []string{"assembler"},
		Work: func(p *supervisor.Process) error {
			http.HandleFunc("/snapshot", func(w http.ResponseWriter, r *http.Request) {
				wg := &sync.WaitGroup{}
				snapshot := make(chan string)
				getSnapshotChan <- &getSnapshotRequest{snapshot: snapshot}

				res := ""
				wg.Add(1)
				go func(replyChan chan string) {
					defer wg.Done()
					for v := range snapshot {
						res = v
						close(snapshot)
					}
				}(snapshot)

				wg.Wait()
				if _, err := w.Write([]byte(res)); err != nil {
					p.Logf("write snapshot errored: %v", err)
				}
			})
			listenHostAndPort := fmt.Sprintf(":%d", port)
			p.Logf("snapshot server listening on: %s", listenHostAndPort)
			return http.ListenAndServe(listenHostAndPort, nil)
		},
	})

	if errs := s.Run(); len(errs) > 0 {
		for _, err := range errs {
			fmt.Println(err)
		}
	}
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<commit_msg>working-ish<commit_after>package main

import (
	"context"
	"fmt"
	"github.com/datawire/teleproxy/pkg/k8s"
	"github.com/datawire/teleproxy/pkg/supervisor"
	"github.com/datawire/teleproxy/pkg/watt"
	"github.com/spf13/cobra"
	"net/http"
	"os"
	"strings"
	"sync"
)

var kubernetesNamespace string
var initialSources = make([]string, 0)
var port int

var rootCmd = &cobra.Command{
	Use:              "watt",
	Short:            "watt",
	Long:             "watt - watch all the things",
	PersistentPreRun: func(cmd *cobra.Command, args []string) {},
	Run:              runWatt,
}

type getSnapshotRequest struct {
	snapshot chan string
}

func init() {
	rootCmd.Flags().StringVarP(&kubernetesNamespace, "namespace", "", "", "namespace to watch (default: all)")
	rootCmd.Flags().StringSliceVarP(&initialSources, "source", "s", []string{}, "configure an initial static source")
	rootCmd.Flags().IntVarP(&port, "port", "p", 7000, "configure the snapshot server port")
}

// determine if we're dealing with a potential piece of Ambassador configuration. Right now that comes through in
// annotations of a Service. In the future it will likely be done via CRD. For this PoC I use a ConfigMap as pseudo-CRD.
func isAmbassadorConfiguration(r k8s.Resource) (string, bool) {
	kind := strings.ToLower(r.Kind())

	switch kind {
	case "service":
		// this is terribly hacky and not particularly important atm
		a := r.Metadata().Annotations()
		if _, ok := a["getambassador.io/config"]; ok {
			return "mapping", true
		}
	case "configmap":
		a := r.Metadata().Annotations()
		if _, ok := a["getambassador.io/consul-resolver"]; ok {
			return "consul-resolver", true
		}
	default:
		return "", false
	}

	return "", false
}

// this thing here would extract Ambassador annotation data from the metadata and then do something useful with it...
// let's pretend this is not important right now.
func extractAmbassadorAnnotation(r k8s.Resource) string {
	return ""
}

// makeKubeWatcher returns a function that sets up a series of watches to the Kubernetes API for different
// kubernetes resources. When a change occurs the function gets the state of all resources that are being watched
// and sends a message to the watchman and assembler channels for further processing.
func makeKubeWatcher(namespace string,
	kinds []string,
	watchman chan<- []k8s.Resource,
	assembler chan<- []k8s.Resource) func(p *supervisor.Process) error {

	return func(p *supervisor.Process) error {
		kubeWatcher := k8s.NewClient(nil).Watcher()

		for _, kind := range kinds {
			p.Logf("adding watch for %q", kind)
			err := kubeWatcher.WatchNamespace(namespace, kind, func(watcher *k8s.Watcher) {
				k := kinds
				p.Logf("change in watched resources")

				resources := make([]k8s.Resource, 0)
				for _, kind := range k {
					resources = append(resources, watcher.List(kind)...)
				}

				watchman <- resources
				assembler <- resources
			})

			if err != nil {
				p.Logf("failed to add watch for %q", kind)
				return err
			}

			p.Logf("added watch for %q", kind)
		}

		kubeWatcher.Start()

		for {
			select {
			case <-p.Shutdown():
				p.Logf("shutdown initiated\n")
				kubeWatcher.Stop()
				return nil
			}
		}
	}
}

func makeConsulWatcher(config k8s.Resource, assembler chan<- []k8s.Resource) (string, *supervisor.Worker) {
	data := config.Data()
	cwm := &watt.ConsulServiceNodeWatchMaker{
		Service:     data["service"].(string),
		Datacenter:  data["datacenter"].(string),
		OnlyHealthy: true,
	}

	cwmFunc, _ := cwm.Make(assembler)
	return cwm.ID(), &supervisor.Worker{
		Name:  cwm.ID(),
		Work:  cwmFunc,
		Retry: false,
	}
}

func makeWatchman(resourcesChan <-chan []k8s.Resource, assembler chan<- []k8s.Resource) func(p *supervisor.Process) error {
	return func(p *supervisor.Process) error {
		p.Ready()

		watched := make(map[string]*supervisor.Worker)

		for {
			select {
			case resources := <-resourcesChan:
				reported := make(map[string]*supervisor.Worker, 0)
				for _, r := range resources {
					rType, _ := isAmbassadorConfiguration(r)
					if rType == "consul-resolver" {
						ID, worker := makeConsulWatcher(r, assembler)
						if _, exists := watched[ID]; !exists {
							p.Logf("add consul watcher %s\n", ID)
							p.Supervisor().Supervise(worker)
							watched[ID] = worker
						}

						reported[ID] = worker
					}
				}

				// purge the watches that no longer are needed because they did not come through the in the latest
				// report
				for k, worker := range watched {
					if _, exists := reported[k]; !exists {
						p.Logf("remove consul watcher %s\n", k)
						worker.Shutdown()
					}
				}

				watched = reported
			case <-p.Shutdown():
				return nil
			}
		}
	}
}

func makeAssembler(getSnapshotCh <-chan *getSnapshotRequest, recordsCh <-chan []k8s.Resource) func(p *supervisor.Process) error {
	return func(p *supervisor.Process) error {
		p.Ready()
		snapshots := make([][]k8s.Resource, 0)

		for {
			select {
			case req := <-getSnapshotCh:
				p.Logf("returning snapshot")
				if len(snapshots) != 0 {
					snapshotBytes, _ := k8s.MarshalResources(snapshots[len(snapshots) - 1])
					req.snapshot <- string(snapshotBytes)
				} else {
					req.snapshot <- ""
				}

			case resources := <-recordsCh:
				p.Logf("creating snapshot")
				snapshots = append(snapshots, resources)
				if len(snapshots) > 10 {
					snapshots = snapshots[1:]
				}
			case <-p.Shutdown():
				return nil
			}
		}
	}
}

func runWatt(_ *cobra.Command, _ []string) {
	fmt.Println("Watt - Watch All The Things! Starting...")

	// 1. construct an initial list of things to watch
	// 2. feed them to the watch controller
	watchman := make(chan []k8s.Resource)
	assembler := make(chan []k8s.Resource)

	fmt.Println(initialSources)

	ctx := context.Background()

	s := supervisor.WithContext(ctx)
	s.Supervise(&supervisor.Worker{
		Name:     "kubewatcher",
		Work:     makeKubeWatcher(kubernetesNamespace, initialSources, watchman, assembler),
		Requires: []string{"watchman"},
		Retry:    false,
	})

	s.Supervise(&supervisor.Worker{
		Name:     "watchman",
		Work:     makeWatchman(watchman, assembler),
		Requires: []string{"assembler"},
		Retry:    false,
	})

	getSnapshotChan := make(chan *getSnapshotRequest)
	s.Supervise(&supervisor.Worker{
		Name:  "assembler",
		Work:  makeAssembler(getSnapshotChan, assembler),
		Retry: false,
	})

	s.Supervise(&supervisor.Worker{
		Name:     "snapshot server",
		Requires: []string{"assembler"},
		Work: func(p *supervisor.Process) error {
			http.HandleFunc("/snapshot", func(w http.ResponseWriter, r *http.Request) {
				wg := &sync.WaitGroup{}
				snapshot := make(chan string)
				getSnapshotChan <- &getSnapshotRequest{snapshot: snapshot}

				res := ""
				wg.Add(1)
				go func(replyChan chan string) {
					defer wg.Done()
					for v := range snapshot {
						res = v
						close(snapshot)
					}
				}(snapshot)

				wg.Wait()
				if _, err := w.Write([]byte(res)); err != nil {
					p.Logf("write snapshot errored: %v", err)
				}
			})
			listenHostAndPort := fmt.Sprintf(":%d", port)
			p.Logf("snapshot server listening on: %s", listenHostAndPort)
			return http.ListenAndServe(listenHostAndPort, nil)
		},
	})

	if errs := s.Run(); len(errs) > 0 {
		for _, err := range errs {
			fmt.Println(err)
		}
	}
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package prereqs

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/itchio/butler/butlerd"
	"github.com/itchio/butler/redist"
	"github.com/itchio/ox"
	"github.com/itchio/wharf/eos"
	"github.com/itchio/wharf/eos/option"
	"github.com/itchio/wharf/state"
	"github.com/pkg/errors"
)

type PrereqsContext struct {
	RequestContext *butlerd.RequestContext
	Credentials    *butlerd.GameCredentials
	Runtime        *ox.Runtime
	Consumer       *state.Consumer
	PrereqsDir     string
	Force          bool

	library  Library
	registry *redist.RedistRegistry
}

func (pc *PrereqsContext) GetLibrary() (Library, error) {
	if pc.library == nil {
		library, err := NewLibrary(pc.RequestContext, pc.Credentials)
		if err != nil {
			return nil, errors.Wrap(err, "opening prereqs library")
		}

		pc.library = library
	}
	return pc.library, nil
}

func (pc *PrereqsContext) GetRegistry() (*redist.RedistRegistry, error) {
	if pc.registry == nil {
		beforeFetch := time.Now()

		consumer := pc.Consumer

		consumer.Infof("Fetching prereqs registry...")
		registry := &redist.RedistRegistry{}

		needFetch := false
		wantFetch := false

		cachedRegistryPath := filepath.Join(pc.PrereqsDir, "info.json")
		stats, err := os.Stat(cachedRegistryPath)
		if err != nil {
			needFetch = true
		} else {
			sinceLastFetch := time.Since(stats.ModTime())
			if sinceLastFetch > 24*time.Hour {
				consumer.Infof("It's been %s since we fetched the redist registry, let's do it now", sinceLastFetch)
				wantFetch = true
			}
		}
		if pc.Force {
			needFetch = true
		}

		if needFetch || wantFetch {
			err := func() error {
				src, err := eos.Open("https://broth.itch.ovh/itch-redists/info/LATEST/unpacked", option.WithConsumer(pc.Consumer))
				if err != nil {
					return errors.Wrap(err, "opening remote registry file")
				}
				defer src.Close()

				dst, err := os.Create(cachedRegistryPath)
				if err != nil {
					return errors.WithMessage(err, "creating local registry cache")
				}
				defer dst.Close()

				_, err = io.Copy(dst, src)
				if err != nil {
					return errors.WithMessage(err, "downloading registry")
				}
				return nil
			}()
			if err != nil {
				if needFetch {
					return nil, errors.Wrap(err, "fetching prereqs registry")
				} else {
					consumer.Warnf("while fetching prereqs registry: %v", err)
				}
			}
		}

		registryBytes, err := ioutil.ReadFile(cachedRegistryPath)
		if err != nil {
			return nil, errors.WithMessage(err, "while reading registry from disk")
		}

		err = json.Unmarshal(registryBytes, registry)
		if err != nil {
			return nil, errors.WithMessage(err, "decoding redist registry")
		}

		registryFetchDuration := time.Since(beforeFetch)
		consumer.Infof("✓ Fetched %d entries in %s", len(registry.Entries), registryFetchDuration)

		pc.registry = registry
	}

	return pc.registry, nil
}

func (pc *PrereqsContext) GetEntry(name string) (*redist.RedistEntry, error) {
	r, err := pc.GetRegistry()
	if err != nil {
		return nil, errors.Wrap(err, "opening prereqs registry")
	}

	return r.Entries[name], nil
}

func (pc *PrereqsContext) GetEntryDir(name string) string {
	return filepath.Join(pc.PrereqsDir, name)
}
<commit_msg>Closes https://github.com/itchio/itch/issues/1813<commit_after>package prereqs

import (
	"encoding/json"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	"github.com/itchio/butler/butlerd"
	"github.com/itchio/butler/redist"
	"github.com/itchio/ox"
	"github.com/itchio/wharf/eos"
	"github.com/itchio/wharf/eos/option"
	"github.com/itchio/wharf/state"
	"github.com/pkg/errors"
)

type PrereqsContext struct {
	RequestContext *butlerd.RequestContext
	Credentials    *butlerd.GameCredentials
	Runtime        *ox.Runtime
	Consumer       *state.Consumer
	PrereqsDir     string
	Force          bool

	library  Library
	registry *redist.RedistRegistry
}

func (pc *PrereqsContext) GetLibrary() (Library, error) {
	if pc.library == nil {
		library, err := NewLibrary(pc.RequestContext, pc.Credentials)
		if err != nil {
			return nil, errors.Wrap(err, "opening prereqs library")
		}

		pc.library = library
	}
	return pc.library, nil
}

func (pc *PrereqsContext) GetRegistry() (*redist.RedistRegistry, error) {
	if pc.registry == nil {
		beforeFetch := time.Now()

		consumer := pc.Consumer

		consumer.Infof("Fetching prereqs registry...")
		registry := &redist.RedistRegistry{}

		needFetch := false
		wantFetch := false

		err := os.MkdirAll(pc.PrereqsDir, 0755)
		if err != nil {
			return nil, err
		}

		cachedRegistryPath := filepath.Join(pc.PrereqsDir, "info.json")
		stats, err := os.Stat(cachedRegistryPath)
		if err != nil {
			needFetch = true
		} else {
			sinceLastFetch := time.Since(stats.ModTime())
			if sinceLastFetch > 24*time.Hour {
				consumer.Infof("It's been %s since we fetched the redist registry, let's do it now", sinceLastFetch)
				wantFetch = true
			}
		}
		if pc.Force {
			needFetch = true
		}

		if needFetch || wantFetch {
			err := func() error {
				src, err := eos.Open("https://broth.itch.ovh/itch-redists/info/LATEST/unpacked", option.WithConsumer(pc.Consumer))
				if err != nil {
					return errors.Wrap(err, "opening remote registry file")
				}
				defer src.Close()

				dst, err := os.Create(cachedRegistryPath)
				if err != nil {
					return errors.WithMessage(err, "creating local registry cache")
				}
				defer dst.Close()

				_, err = io.Copy(dst, src)
				if err != nil {
					return errors.WithMessage(err, "downloading registry")
				}
				return nil
			}()
			if err != nil {
				if needFetch {
					return nil, errors.Wrap(err, "fetching prereqs registry")
				} else {
					consumer.Warnf("while fetching prereqs registry: %v", err)
				}
			}
		}

		registryBytes, err := ioutil.ReadFile(cachedRegistryPath)
		if err != nil {
			return nil, errors.WithMessage(err, "while reading registry from disk")
		}

		err = json.Unmarshal(registryBytes, registry)
		if err != nil {
			return nil, errors.WithMessage(err, "decoding redist registry")
		}

		registryFetchDuration := time.Since(beforeFetch)
		consumer.Infof("✓ Fetched %d entries in %s", len(registry.Entries), registryFetchDuration)

		pc.registry = registry
	}

	return pc.registry, nil
}

func (pc *PrereqsContext) GetEntry(name string) (*redist.RedistEntry, error) {
	r, err := pc.GetRegistry()
	if err != nil {
		return nil, errors.Wrap(err, "opening prereqs registry")
	}

	return r.Entries[name], nil
}

func (pc *PrereqsContext) GetEntryDir(name string) string {
	return filepath.Join(pc.PrereqsDir, name)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	cfg "github.com/tendermint/tendermint/config"
	tmcfg "github.com/tendermint/tendermint/config/tendermint"
	"github.com/tendermint/tendermint/node"
)

func main() {

	args := os.Args[1:]
	if len(args) == 0 {
		fmt.Println(`Tendermint

Commands:
    node            Run the tendermint node
    show_validator  Show this node's validator info
    gen_account     Generate new account keypair
    gen_validator   Generate new validator keypair
    get_account     Get account balance
    send_tx         Sign and publish a SendTx
    probe_upnp      Test UPnP functionality
    version         Show version info
`)
		return
	}

	// Get configuration
	config := tmcfg.GetConfig("")
	parseFlags(config, args[1:]) // Command line overrides
	cfg.ApplyConfig(config)      // Notify modules of new config

	switch args[0] {
	case "node":
		node.RunNode()
	case "show_validator":
		show_validator()
	case "gen_account":
		gen_account()
	case "gen_validator":
		gen_validator()
	case "get_account":
		get_account()
	case "send_tx":
		send_tx()
	case "probe_upnp":
		probe_upnp()
	case "unsafe_reset_priv_validator":
		reset_priv_validator()
	case "version":
		fmt.Println(node.Version)
	default:
		Exit(Fmt("Unknown command %v\n", args[0]))
	}
}
<commit_msg>fix main compile bug<commit_after>package main

import (
	"fmt"
	"os"

	. "github.com/tendermint/tendermint/common"
	cfg "github.com/tendermint/tendermint/config"
	tmcfg "github.com/tendermint/tendermint/config/tendermint"
	"github.com/tendermint/tendermint/node"
)

func main() {

	args := os.Args[1:]
	if len(args) == 0 {
		fmt.Println(`Tendermint

Commands:
    node            Run the tendermint node
    show_validator  Show this node's validator info
    gen_account     Generate new account keypair
    gen_validator   Generate new validator keypair
    get_account     Get account balance
    send_tx         Sign and publish a SendTx
    probe_upnp      Test UPnP functionality
    version         Show version info
`)
		return
	}

	// Get configuration
	config := tmcfg.GetConfig("")
	parseFlags(config, args[1:]) // Command line overrides
	cfg.ApplyConfig(config)      // Notify modules of new config

	switch args[0] {
	case "node":
		node.RunNode()
	case "show_validator":
		show_validator()
	case "gen_account":
		gen_account()
	case "gen_validator":
		gen_validator()
	case "get_account":
		get_account()
	case "send_tx":
		send_tx()
	case "probe_upnp":
		probe_upnp()
	case "unsafe_reset_priv_validator":
		reset_priv_validator()
	case "version":
		fmt.Println(node.Version)
	default:
		Exit(Fmt("Unknown command %v\n", args[0]))
	}
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Michał Matczuk
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"os"
	"strings"

	"golang.org/x/net/http2"

	"github.com/mmatczuk/go-http-tunnel"
	"github.com/mmatczuk/go-http-tunnel/id"
	"github.com/mmatczuk/go-http-tunnel/log"
)

func main() {
	opts := parseArgs()

	if opts.version {
		fmt.Println(version)
		return
	}

	logger, err := log.NewLogger(opts.logTo, opts.logLevel)
	if err != nil {
		fatal("failed to init logger: %s", err)
	}

	// load certs
	cert, err := tls.LoadX509KeyPair(opts.tlsCrt, opts.tlsKey)
	if err != nil {
		fatal("failed to load certificate: %s", err)
	}

	// setup server
	server, err := tunnel.NewServer(&tunnel.ServerConfig{
		Addr:      opts.tunnelAddr,
		TLSConfig: tlsConfig(cert),
		Logger:    logger,
	})
	if err != nil {
		fatal("failed to create server: %s", err)
	}

	if opts.clients == "" {
		logger.Log(
			"level", 0,
			"msg", "No clients",
		)
	} else {
		for _, c := range strings.Split(opts.clients, ",") {
			if c == "" {
				fatal("empty client id")
			}
			identifier := id.ID{}
			err := identifier.UnmarshalText([]byte(c))
			if err != nil {
				fatal("invalid identifier %q: %s", c, err)
			}
			server.Subscribe(identifier)
		}
	}

	// start HTTP
	if opts.httpAddr != "" {
		go func() {
			logger.Log(
				"level", 1,
				"action", "start http",
				"addr", opts.httpAddr,
			)

			fatal("failed to start HTTP: %s", http.ListenAndServe(opts.httpAddr, server))
		}()
	}

	// start HTTPS
	if opts.httpsAddr != "" {
		go func() {
			logger.Log(
				"level", 1,
				"action", "start https",
				"addr", opts.httpsAddr,
			)

			s := &http.Server{
				Addr:    opts.httpsAddr,
				Handler: server,
			}
			http2.ConfigureServer(s, nil)

			fatal("failed to start HTTPS: %s", s.ListenAndServeTLS(opts.tlsCrt, opts.tlsKey))
		}()
	}

	server.Start()
}

func tlsConfig(cert tls.Certificate) *tls.Config {
	return &tls.Config{
		Certificates:             []tls.Certificate{cert},
		ClientAuth:               tls.RequestClientCert,
		SessionTicketsDisabled:   true,
		MinVersion:               tls.VersionTLS12,
		CipherSuites:             []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
		PreferServerCipherSuites: true,
		NextProtos:               []string{"h2"},
	}
}

func fatal(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
	fmt.Fprint(os.Stderr, "\n")
	os.Exit(1)
}
<commit_msg>tunneld: Require all clients to have a certificate<commit_after>// Copyright (C) 2017 Michał Matczuk
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"crypto/tls"
	"fmt"
	"net/http"
	"os"
	"strings"

	"golang.org/x/net/http2"

	"github.com/mmatczuk/go-http-tunnel"
	"github.com/mmatczuk/go-http-tunnel/id"
	"github.com/mmatczuk/go-http-tunnel/log"
)

func main() {
	opts := parseArgs()

	if opts.version {
		fmt.Println(version)
		return
	}

	logger, err := log.NewLogger(opts.logTo, opts.logLevel)
	if err != nil {
		fatal("failed to init logger: %s", err)
	}

	// load certs
	cert, err := tls.LoadX509KeyPair(opts.tlsCrt, opts.tlsKey)
	if err != nil {
		fatal("failed to load certificate: %s", err)
	}

	// setup server
	server, err := tunnel.NewServer(&tunnel.ServerConfig{
		Addr:      opts.tunnelAddr,
		TLSConfig: tlsConfig(cert),
		Logger:    logger,
	})
	if err != nil {
		fatal("failed to create server: %s", err)
	}

	if opts.clients == "" {
		logger.Log(
			"level", 0,
			"msg", "No clients",
		)
	} else {
		for _, c := range strings.Split(opts.clients, ",") {
			if c == "" {
				fatal("empty client id")
			}
			identifier := id.ID{}
			err := identifier.UnmarshalText([]byte(c))
			if err != nil {
				fatal("invalid identifier %q: %s", c, err)
			}
			server.Subscribe(identifier)
		}
	}

	// start HTTP
	if opts.httpAddr != "" {
		go func() {
			logger.Log(
				"level", 1,
				"action", "start http",
				"addr", opts.httpAddr,
			)

			fatal("failed to start HTTP: %s", http.ListenAndServe(opts.httpAddr, server))
		}()
	}

	// start HTTPS
	if opts.httpsAddr != "" {
		go func() {
			logger.Log(
				"level", 1,
				"action", "start https",
				"addr", opts.httpsAddr,
			)

			s := &http.Server{
				Addr:    opts.httpsAddr,
				Handler: server,
			}
			http2.ConfigureServer(s, nil)

			fatal("failed to start HTTPS: %s", s.ListenAndServeTLS(opts.tlsCrt, opts.tlsKey))
		}()
	}

	server.Start()
}

func tlsConfig(cert tls.Certificate) *tls.Config {
	return &tls.Config{
		Certificates:             []tls.Certificate{cert},
		ClientAuth:               tls.RequireAnyClientCert,
		SessionTicketsDisabled:   true,
		MinVersion:               tls.VersionTLS12,
		CipherSuites:             []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
		PreferServerCipherSuites: true,
		NextProtos:               []string{"h2"},
	}
}

func fatal(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
	fmt.Fprint(os.Stderr, "\n")
	os.Exit(1)
}
<|endoftext|>


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

// assumptions
// we've been booted into a ramfs with all this stuff unpacked and ready.
// we don't need a loop device mount because it's all there.
// So we run /go/bin/go build installcommand
// and then exec /buildbin/sh

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"syscall"

	"github.com/u-root/u-root/pkg/libinit"
	"github.com/u-root/u-root/pkg/ulog"
	"github.com/u-root/u-root/pkg/upath"
)

var (
	verbose  = flag.Bool("v", false, "print all build commands")
	test     = flag.Bool("test", false, "Test mode: don't try to set control tty")
	debug    = func(string, ...interface{}) {}
	osInitGo = func() {}
	cmdList  []string
	cmdCount int
	envs     []string
)

func init() {
	r := upath.UrootPath
	cmdList = []string{
		r("/inito"),

		r("/bbin/uinit"),
		r("/bin/uinit"),
		r("/buildbin/uinit"),

		r("/bin/defaultsh"),
		r("/bin/sh"),
	}
}

func main() {
	flag.Parse()

	log.Printf("Welcome to u-root!")
	fmt.Println(`                              _`)
	fmt.Println(`   _   _      _ __ ___   ___ | |_`)
	fmt.Println(`  | | | |____| '__/ _ \ / _ \| __|`)
	fmt.Println(`  | |_| |____| | | (_) | (_) | |_`)
	fmt.Println(`   \__,_|    |_|  \___/ \___/ \__|`)
	fmt.Println()

	log.SetPrefix("init: ")

	if *verbose {
		debug = log.Printf
	}

	// Before entering an interactive shell, decrease the loglevel because
	// spamming non-critical logs onto the shell frustrates users. The logs
	// are still accessible through dmesg.
	if !*verbose {
		// Only messages more severe than "notice" are printed.
		if err := ulog.KernelLog.SetConsoleLogLevel(ulog.KLogNotice); err != nil {
			log.Printf("Could not set log level: %v", err)
		}
	}

	libinit.SetEnv()
	// Create the root file systems.
	libinit.CreateRootfs()

	envs = os.Environ()
	debug("envs %v", envs)

	// Start background build.
	if isBgBuildEnabled() {
		go startBgBuild()
	}

	osInitGo()

	for _, v := range cmdList {
		debug("Trying to run %v", v)
		if _, err := os.Stat(v); os.IsNotExist(err) {
			debug("%v", err)
			continue
		}

		// I *love* special cases. Evaluate just the top-most symlink.
		//
		// In source mode, this would be a symlink like
		// /buildbin/defaultsh -> /buildbin/elvish ->
		// /buildbin/installcommand.
		//
		// To actually get the command to build, argv[0] has to end
		// with /elvish, so we resolve one level of symlink.
		if path.Base(v) == "defaultsh" {
			s, err := os.Readlink(v)
			if err == nil {
				v = s
			}
			debug("readlink of %v returns %v", v, s)
			// and, well, it might be a relative link.
			// We must go deeper.
			d, b := filepath.Split(v)
			d = filepath.Base(d)
			v = filepath.Join("/", os.Getenv("UROOT_ROOT"), d, b)
			debug("is now %v", v)
		}

		// inito is (optionally) created by the u-root command when the
		// u-root initramfs is merged with an existing initramfs that
		// has a /init. The name inito means "original /init" There may
		// be an inito if we are building on an existing initramfs. All
		// initos need their own pid space.
		var cloneFlags uintptr
		if v == "/inito" {
			cloneFlags = uintptr(syscall.CLONE_NEWPID)
		}

		cmdCount++
		cmd := exec.Command(v)
		cmd.Env = envs
		cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
		if *test {
			cmd.SysProcAttr = &syscall.SysProcAttr{Cloneflags: cloneFlags}
		} else {
			cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true, Cloneflags: cloneFlags}
		}
		debug("running %v", cmd)
		if err := cmd.Start(); err != nil {
			log.Printf("Error starting %v: %v", v, err)
			continue
		}
		for {
			var s syscall.WaitStatus
			var r syscall.Rusage
			if p, err := syscall.Wait4(-1, &s, 0, &r); p == cmd.Process.Pid {
				debug("Shell exited, exit status %d", s.ExitStatus())
				break
			} else if p != -1 {
				debug("Reaped PID %d, exit status %d", p, s.ExitStatus())
			} else {
				debug("Error from Wait4 for orphaned child: %v", err)
				break
			}
		}
		if err := cmd.Process.Release(); err != nil {
			log.Printf("Error releasing process %v: %v", v, err)
		}
	}
	if cmdCount == 0 {
		log.Printf("No suitable executable found in %+v", cmdList)
	}

	// We need to reap all children before exiting.
	log.Printf("Waiting for orphaned children")
	for {
		var s syscall.WaitStatus
		var r syscall.Rusage
		p, err := syscall.Wait4(-1, &s, 0, &r)
		if p == -1 {
			break
		}
		log.Printf("%v: exited with %v, status %v, rusage %v", p, err, s, r)
	}
	log.Printf("All commands exited")
	log.Printf("Syncing filesystems")
	syscall.Sync()
	log.Printf("Exiting...")
}
<commit_msg>init: remove defaultsh special case<commit_after>// Copyright 2012-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// assumptions
// we've been booted into a ramfs with all this stuff unpacked and ready.
// we don't need a loop device mount because it's all there.
// So we run /go/bin/go build installcommand
// and then exec /buildbin/sh

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"syscall"

	"github.com/u-root/u-root/pkg/libinit"
	"github.com/u-root/u-root/pkg/ulog"
	"github.com/u-root/u-root/pkg/upath"
)

var (
	verbose  = flag.Bool("v", false, "print all build commands")
	test     = flag.Bool("test", false, "Test mode: don't try to set control tty")
	debug    = func(string, ...interface{}) {}
	osInitGo = func() {}
	cmdList  []string
	cmdCount int
	envs     []string
)

func init() {
	r := upath.UrootPath
	cmdList = []string{
		r("/inito"),

		r("/bbin/uinit"),
		r("/bin/uinit"),
		r("/buildbin/uinit"),

		r("/bin/defaultsh"),
		r("/bin/sh"),
	}
}

func main() {
	flag.Parse()

	log.Printf("Welcome to u-root!")
	fmt.Println(`                              _`)
	fmt.Println(`   _   _      _ __ ___   ___ | |_`)
	fmt.Println(`  | | | |____| '__/ _ \ / _ \| __|`)
	fmt.Println(`  | |_| |____| | | (_) | (_) | |_`)
	fmt.Println(`   \__,_|    |_|  \___/ \___/ \__|`)
	fmt.Println()

	log.SetPrefix("init: ")

	if *verbose {
		debug = log.Printf
	}

	// Before entering an interactive shell, decrease the loglevel because
	// spamming non-critical logs onto the shell frustrates users. The logs
	// are still accessible through dmesg.
	if !*verbose {
		// Only messages more severe than "notice" are printed.
		if err := ulog.KernelLog.SetConsoleLogLevel(ulog.KLogNotice); err != nil {
			log.Printf("Could not set log level: %v", err)
		}
	}

	libinit.SetEnv()
	// Create the root file systems.
	libinit.CreateRootfs()

	envs = os.Environ()
	debug("envs %v", envs)

	// Start background build.
	if isBgBuildEnabled() {
		go startBgBuild()
	}

	osInitGo()

	for _, v := range cmdList {
		debug("Trying to run %v", v)
		if _, err := os.Stat(v); os.IsNotExist(err) {
			debug("%v", err)
			continue
		}

		// inito is (optionally) created by the u-root command when the
		// u-root initramfs is merged with an existing initramfs that
		// has a /init. The name inito means "original /init" There may
		// be an inito if we are building on an existing initramfs. All
		// initos need their own pid space.
		var cloneFlags uintptr
		if v == "/inito" {
			cloneFlags = uintptr(syscall.CLONE_NEWPID)
		}

		cmdCount++
		cmd := exec.Command(v)
		cmd.Env = envs
		cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
		if *test {
			cmd.SysProcAttr = &syscall.SysProcAttr{Cloneflags: cloneFlags}
		} else {
			cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true, Cloneflags: cloneFlags}
		}
		debug("running %v", cmd)
		if err := cmd.Start(); err != nil {
			log.Printf("Error starting %v: %v", v, err)
			continue
		}
		for {
			var s syscall.WaitStatus
			var r syscall.Rusage
			if p, err := syscall.Wait4(-1, &s, 0, &r); p == cmd.Process.Pid {
				debug("Shell exited, exit status %d", s.ExitStatus())
				break
			} else if p != -1 {
				debug("Reaped PID %d, exit status %d", p, s.ExitStatus())
			} else {
				debug("Error from Wait4 for orphaned child: %v", err)
				break
			}
		}
		if err := cmd.Process.Release(); err != nil {
			log.Printf("Error releasing process %v: %v", v, err)
		}
	}
	if cmdCount == 0 {
		log.Printf("No suitable executable found in %+v", cmdList)
	}

	// We need to reap all children before exiting.
	log.Printf("Waiting for orphaned children")
	for {
		var s syscall.WaitStatus
		var r syscall.Rusage
		p, err := syscall.Wait4(-1, &s, 0, &r)
		if p == -1 {
			break
		}
		log.Printf("%v: exited with %v, status %v, rusage %v", p, err, s, r)
	}
	log.Printf("All commands exited")
	log.Printf("Syncing filesystems")
	syscall.Sync()
	log.Printf("Exiting...")
}
<|endoftext|>


<commit_before>// Copyright 2015 CoreOS, 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 main

import (
	"flag"
	"net/http"
	"strings"

	"github.com/coreos/pkg/capnslog"
	"github.com/prometheus/client_golang/prometheus"
)

var plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "etcd-tester")

func main() {
	endpointStr := flag.String("agent-endpoints", "localhost:9027", "HTTP RPC endpoints of agents. Do not specify the schema.")
	datadir := flag.String("data-dir", "agent.etcd", "etcd data directory location on agent machine.")
	stressKeySize := flag.Int("stress-key-size", 100, "the size of each key written into etcd.")
	stressKeySuffixRange := flag.Int("stress-key-count", 250000, "the count of key range written into etcd.")
	limit := flag.Int("limit", 3, "the limit of rounds to run failure set.")
	isV2Only := flag.Bool("v2-only", false, "'true' to run V2 only tester.")
	flag.Parse()

	endpoints := strings.Split(*endpointStr, ",")
	c, err := newCluster(endpoints, *datadir, *stressKeySize, *stressKeySuffixRange, *isV2Only)
	if err != nil {
		plog.Fatal(err)
	}
	defer c.Terminate()

	t := &tester{
		failures: []failure{
			newFailureKillAll(),
			newFailureKillMajority(),
			newFailureKillOne(),
			newFailureKillLeader(),
			newFailureKillOneForLongTime(),
			newFailureKillLeaderForLongTime(),
			newFailureIsolate(),
			newFailureIsolateAll(),
		},
		cluster: c,
		limit:   *limit,
	}

	sh := statusHandler{status: &t.status}
	http.Handle("/status", sh)
	http.Handle("/metrics", prometheus.Handler())
	go func() { plog.Fatal(http.ListenAndServe(":9028", nil)) }()

	t.runLoop()
}
<commit_msg>tools/functional-tester: --schedule-cases flag<commit_after>// Copyright 2015 CoreOS, 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 main

import (
	"flag"
	"fmt"
	"net/http"
	"strings"

	"github.com/coreos/pkg/capnslog"
	"github.com/prometheus/client_golang/prometheus"
)

var plog = capnslog.NewPackageLogger("github.com/coreos/etcd", "etcd-tester")

func main() {
	endpointStr := flag.String("agent-endpoints", "localhost:9027", "HTTP RPC endpoints of agents. Do not specify the schema.")
	datadir := flag.String("data-dir", "agent.etcd", "etcd data directory location on agent machine.")
	stressKeySize := flag.Int("stress-key-size", 100, "the size of each key written into etcd.")
	stressKeySuffixRange := flag.Int("stress-key-count", 250000, "the count of key range written into etcd.")
	limit := flag.Int("limit", 3, "the limit of rounds to run failure set.")
	schedCases := flag.String("schedule-cases", "", "test case schedule")

	isV2Only := flag.Bool("v2-only", false, "'true' to run V2 only tester.")
	flag.Parse()

	endpoints := strings.Split(*endpointStr, ",")
	c, err := newCluster(endpoints, *datadir, *stressKeySize, *stressKeySuffixRange, *isV2Only)
	if err != nil {
		plog.Fatal(err)
	}
	defer c.Terminate()

	failures := []failure{
		newFailureKillAll(),
		newFailureKillMajority(),
		newFailureKillOne(),
		newFailureKillLeader(),
		newFailureKillOneForLongTime(),
		newFailureKillLeaderForLongTime(),
		newFailureIsolate(),
		newFailureIsolateAll(),
	}

	schedule := failures
	if schedCases != nil && *schedCases != "" {
		cases := strings.Split(*schedCases, " ")
		schedule = make([]failure, len(cases))
		for i := range cases {
			caseNum := 0
			n, err := fmt.Sscanf(cases[i], "%d", &caseNum)
			if n == 0 || err != nil {
				plog.Fatalf(`couldn't parse case "%s" (%v)`, cases[i], err)
			}
			schedule[i] = failures[caseNum]
		}
	}

	t := &tester{
		failures: schedule,
		cluster:  c,
		limit:    *limit,
	}

	sh := statusHandler{status: &t.status}
	http.Handle("/status", sh)
	http.Handle("/metrics", prometheus.Handler())
	go func() { plog.Fatal(http.ListenAndServe(":9028", nil)) }()

	t.runLoop()
}
<|endoftext|>