<commit_before>package ginDoi

import (
	"os/exec"
	"strings"
	"fmt"
	"net/http"
	"io/ioutil"
	"gopkg.in/yaml.v2"
	"log"
	"crypto/md5"
	"encoding/hex"
	"bytes"
	 "regexp"
)

var (
	MS_NOTITLE = "No Title provided"
	MS_NOAUTHORS = "No Authors provided"
	MS_NODESC = ""
	MS_NOLIC = ""
)

type GinDataSource struct {
	GinURL string
}

func hasValues(s *DoiInfo) bool{
	if s.Title == ""{
		s.Missing = append(s.Missing, MS_NOTITLE)
	}
	if len(s.Authors) == 0 {
		s.Missing = append(s.Missing, MS_NOAUTHORS)
	}
	if s.Description == ""{
		//s.Missing = append(s.Missing, MS_NODESC)
	}
	if s.License ==""{
		//s.Missing = append(s.Missing, MS_NOLIC)
	}
	return len(s.Missing)==0
}
// Return true if the specifies URI "has" a doi File containing all nec. information
func validDoiFile(in []byte) (bool, DoiInfo) {
	//Workaround as long as repo does spits out object type and size (and a zero termination...)
	in = bytes.Replace(in,[]byte("\x00"),[]byte(""),-1)
	re := regexp.MustCompile(`blob\W\d+`)
	in = re.ReplaceAll(in, []byte(""))

	doiInfo := DoiInfo{}
	err :=yaml.Unmarshal(in, &doiInfo)
	if err != nil {
		log.Printf("GinDatSource: Could not unmarshal doifile:%v", err)
		return false, DoiInfo{}
	}
	if !hasValues(&doiInfo) {
		log.Printf("GinDatSource validDoiFile: Doi File misses entries: %+v", doiInfo)
		return false, doiInfo
	}
	return true, doiInfo
}

func (s *GinDataSource) GetDoiInfo(URI string) (DoiInfo, error){
	data, err := s.GetDoiFile(URI)
	if err!=nil{
		return DoiInfo{}, err
	}
	valid,info := validDoiFile(data)
	if !valid {
		return info, fmt.Errorf("Not all cloudberry info provided")
	}
	return info, nil
}

func (s *GinDataSource) GetDoiFile(URI string) ([]byte, error){
	//git archive --remote=git://git.foo.com/project.git HEAD:path/to/directory filename
	//https://github.com/go-yaml/yaml.git
	//git@github.com:go-yaml/yaml.git
	fetchRepoPath := ""
	log.Printf("GinDatSourceGetDoiFile: Got URI:%s", URI)
	if splUri:=strings.Split(URI, "/");len(splUri)>1 {
		uname := strings.Split(splUri[0],":")[1]
		repo := splUri[1]
		fetchRepoPath = fmt.Sprintf("/users/%s/repos/%s/browse/master/.cloudberry.yml",uname, repo)
	} else {
		return nil,nil
	}
	log.Printf("GinDatSourceGetDoiFile: Fetching Path: %s", fetchRepoPath)
	resp, err  := http.Get(fmt.Sprintf("%s%s",s.GinURL, fetchRepoPath))
	if err != nil{
		// todo Try to infer what went wrong
		log.Printf("GinDatSourceGetDoiFile: Could not get cloudberry: %v", err)
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err !=nil{
		log.Printf("GinDatSourceGetDoiFile: Could nort read Clodberry: %v", err)
		return nil, err
	}
	return body, nil
}

func (s *GinDataSource)  Get(URI string, To string) (string, error) {
	log.Printf("GinDataSourceGet: Will do a git clone now: %s to:%s", URI, To)
	cmd := exec.Command("git","clone","--depth","1", URI, To)
	out, err :=cmd.CombinedOutput()
	if (err != nil) {
		return string(out), err
	}
	return string(out), nil
}

func (s *GinDataSource)  MakeUUID(URI string) (string, error) {
	fetchRepoPath := ""
	log.Printf("GinDatSourceMakeUUID: Got URI:%s", URI)
	if splUri:=strings.Split(URI, "/");len(splUri)>1 {
		uname := strings.Split(splUri[0],":")[1]
		repo := splUri[1]
		fetchRepoPath = fmt.Sprintf("/users/%s/repos/%s/browse/master",uname, repo)
	}
	log.Printf("GinDatSourceMakeUUID: Fetching Path: %s", fetchRepoPath)
	resp, err  := http.Get(fmt.Sprintf("%s%s",s.GinURL, fetchRepoPath))
	if err != nil{
		return "", err
	}
	if bd,err :=ioutil.ReadAll(resp.Body); err != nil{
		return "", err
	}else {
		currMd5 :=  md5.Sum(bd)
		return hex.EncodeToString(currMd5[:]), nil
	}
}<commit_msg>Add git annex support<commit_after>package ginDoi

import (
	"os/exec"
	"strings"
	"fmt"
	"net/http"
	"io/ioutil"
	"gopkg.in/yaml.v2"
	"log"
	"crypto/md5"
	"encoding/hex"
	"bytes"
	 "regexp"
)

var (
	MS_NOTITLE = "No Title provided."
	MS_NOAUTHORS = "No Authors provided."
	MS_NODESC = "No Description provided."
	MS_NOLIC = "No Liecense provided."
	DSOURCELOGPREFIX= "DSOURCE"
)

type GinDataSource struct {
	GinURL string
}

func hasValues(s *DoiInfo) bool{
	if s.Title == ""{
		s.Missing = append(s.Missing, MS_NOTITLE)
	}
	if len(s.Authors) == 0 {
		s.Missing = append(s.Missing, MS_NOAUTHORS)
	}
	if s.Description == ""{
		s.Missing = append(s.Missing, MS_NODESC)
	}
	if s.License ==""{
		s.Missing = append(s.Missing, MS_NOLIC)
	}
	return len(s.Missing)==0
}
// Return true if the specifies URI "has" a doi File containing all nec. information
func validDoiFile(in []byte) (bool, DoiInfo) {
	//Workaround as long as repo does spits out object type and size (and a zero termination...)
	in = bytes.Replace(in,[]byte("\x00"),[]byte(""),-1)
	re := regexp.MustCompile(`blob\W\d+`)
	in = re.ReplaceAll(in, []byte(""))

	doiInfo := DoiInfo{}
	err :=yaml.Unmarshal(in, &doiInfo)
	if err != nil {
		log.Printf("GinDatSource: Could not unmarshal doifile:%v", err)
		return false, DoiInfo{}
	}
	if !hasValues(&doiInfo) {
		log.Printf("GinDatSource validDoiFile: Doi File misses entries: %+v", doiInfo)
		return false, doiInfo
	}
	return true, doiInfo
}

func (s *GinDataSource) GetDoiInfo(URI string) (DoiInfo, error){
	data, err := s.GetDoiFile(URI)
	if err!=nil{
		return DoiInfo{}, err
	}
	valid,info := validDoiFile(data)
	if !valid {
		return info, fmt.Errorf("Not all cloudberry info provided")
	}
	return info, nil
}

func (s *GinDataSource) GetDoiFile(URI string) ([]byte, error){
	//git archive --remote=git://git.foo.com/project.git HEAD:path/to/directory filename
	//https://github.com/go-yaml/yaml.git
	//git@github.com:go-yaml/yaml.git
	fetchRepoPath := ""
	log.Printf("GinDatSourceGetDoiFile: Got URI:%s", URI)
	if splUri:=strings.Split(URI, "/");len(splUri)>1 {
		uname := strings.Split(splUri[0],":")[1]
		repo := splUri[1]
		fetchRepoPath = fmt.Sprintf("/users/%s/repos/%s/browse/master/.cloudberry.yml",uname, repo)
	} else {
		return nil,nil
	}
	log.Printf("GinDatSourceGetDoiFile: Fetching Path: %s", fetchRepoPath)
	resp, err  := http.Get(fmt.Sprintf("%s%s",s.GinURL, fetchRepoPath))
	if err != nil{
		// todo Try to infer what went wrong
		log.Printf("GinDatSourceGetDoiFile: Could not get cloudberry: %v", err)
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err !=nil{
		log.Printf("GinDatSourceGetDoiFile: Could nort read Clodberry: %v", err)
		return nil, err
	}
	return body, nil
}

func (s *GinDataSource)  Get(URI string, To string) (string, error) {
	log.Printf("GinDataSourceGet: Will do a git clone now: %s to:%s", URI, To)
	cmd := exec.Command("git","clone","--depth","1", URI, To)
	out, err := cmd.CombinedOutput()
	if (err != nil) {
		return string(out), err
	}
	cmd = exec.Command("git", "annex", "sync", "--no-push", "--content")
	out, err = cmd.CombinedOutput()
	if (err != nil) {
		// Workaround for uninitilaizes git annexes (-> return nil)
		// todo
		log.Printf("[%s] Repo was not annexed: %s",DSOURCELOGPREFIX,string(out))
		return string(out), nil
	}
	return string(out), nil
}

func (s *GinDataSource) MakeUUID(URI string) (string, error) {
	fetchRepoPath := ""
	log.Printf("GinDatSourceMakeUUID: Got URI:%s", URI)
	if splUri:=strings.Split(URI, "/");len(splUri)>1 {
		uname := strings.Split(splUri[0],":")[1]
		repo := splUri[1]
		fetchRepoPath = fmt.Sprintf("/users/%s/repos/%s/browse/master",uname, repo)
	}
	log.Printf("GinDatSourceMakeUUID: Fetching Path: %s", fetchRepoPath)
	resp, err  := http.Get(fmt.Sprintf("%s%s",s.GinURL, fetchRepoPath))
	if err != nil{
		return "", err
	}
	if bd,err :=ioutil.ReadAll(resp.Body); err != nil{
		return "", err
	}else {
		currMd5 :=  md5.Sum(bd)
		return hex.EncodeToString(currMd5[:]), nil
	}
}<|endoftext|>


<commit_before>// Package wsdl parses Web Service Definition Language documents.
package wsdl

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"strings"

	"aqwari.net/xml/xmltree"
	"aqwari.net/xml/xsd"
)

const (
	wsdlNS    = "http://schemas.xmlsoap.org/wsdl/"
	soapNS    = "http://schemas.xmlsoap.org/wsdl/soap/"
	soap12NS  = "http://schemas.xmlsoap.org/wsdl/soap12/"
	httpNS    = "http://schemas.xmlsoap.org/wsdl/http/"
	mimeNS    = "http://schemas.xmlsoap.org/wsdl/mime/"
	soapencNS = "http://schemas.xmlsoap.org/soap/encoding/"
	soapenvNS = "http://schemas.xmlsoap.org/soap/envelope/"
	xsiNS     = "http://www.w3.org/2000/10/XMLSchema-instance"
	xsdNS     = "http://www.w3.org/2000/10/XMLSchema"
)

// A Definition contains all information necessary to generate Go code
// from a wsdl document.
type Definition struct {
	Doc      string
	Schema   []xsd.Schema
	Ports    []Port
	Message  map[xml.Name]Message
	TargetNS string
}

func (def *Definition) String() string {
	var buf bytes.Buffer
	fmt.Fprintln(&buf, "Namespace: ", def.TargetNS)
	for _, port := range def.Ports {
		fmt.Fprintf(&buf, "Port %s %s\n", port.Name, port.Address)
		for _, op := range port.Operations {
			input := def.Message[op.Input]
			output := def.Message[op.Output]
			fmt.Fprintf(&buf, "\t%s(%s) -> %s\n",
				op.Name.Local, &input, &output)
		}
	}
	return buf.String()
}

// A Message is a set of zero or more parameters for WSDL
// operations.
type Message struct {
	Name  xml.Name
	Parts []Part
}

func (m *Message) String() string {
	parts := make([]string, 0, len(m.Parts))
	for _, p := range m.Parts {
		parts = append(parts, fmt.Sprintf("%s", p.Type.Local))
	}
	return fmt.Sprintf("%s", strings.Join(parts, ", "))
}

// A Part describes the name and type of a parameter to pass
// to a WSDL endpoint.
type Part struct {
	Name string
	Type xml.Name
}

// An Operation describes an RPC call that can be made against
// the remote server. Its inputs, outputs and transport information
// are parsed from the WSDL definition. Many Operations can be
// defined for a single endpoint.
type Operation struct {
	Doc           string
	Name          xml.Name
	Input, Output xml.Name
}

// A Port describes a set of RPCs and the address to reach them.
type Port struct {
	Name, Address string
	Operations    []Operation
}

// Collect multiple <documentation> children into a newline-separate string
func documentation(el *xmltree.Element) string {
	var docs [][]byte
	for _, doc := range el.Children {
		if doc.Name.Local != "documentation" {
			continue
		}
		docs = append(docs, doc.Content)
	}
	return string(bytes.Join(docs, []byte{'\n'}))
}

func parseMessages(targetNS string, root *xmltree.Element) map[xml.Name]Message {
	messages := make(map[xml.Name]Message)
	for _, msg := range root.Search(wsdlNS, "message") {
		var m Message
		m.Name = msg.ResolveDefault(msg.Attr("", "name"), targetNS)
		for _, part := range msg.Search(wsdlNS, "part") {
			p := Part{
				Name: part.Attr("", "name"),
				Type: part.Resolve(part.Attr("", "type")),
			}
			if len(p.Type.Local) == 0 {
				p.Type = part.Resolve(part.Attr("", "element"))
			}
			m.Parts = append(m.Parts, p)
		}
		messages[m.Name] = m
	}
	return messages
}

func parsePorts(targetNS string, root, svc *xmltree.Element) []Port {
	var ports []Port
	for _, port := range svc.Search(wsdlNS, "port") {
		var p Port
		p.Name = port.Attr("", "name")
		for _, addr := range port.Search(soapNS, "address") {
			p.Address = addr.Attr("", "location")
		}
		for _, addr := range port.Search(soap12NS, "address") {
			p.Address = addr.Attr("", "location")
		}
		p.Operations = parseOperations(targetNS, root, port)
		ports = append(ports, p)
	}
	return ports
}

func parseOperations(targetNS string, root, port *xmltree.Element) []Operation {
	var ops []Operation
	binding := port.Resolve(port.Attr("", "binding"))
	predicate := func(el *xmltree.Element) bool {
		return el.Name.Space == wsdlNS &&
			el.Name.Local == "binding" &&
			el.ResolveDefault(el.Attr("", "name"), targetNS) == binding
	}

	for _, bind := range root.SearchFunc(predicate) {
		portType := bind.Resolve(bind.Attr("", "type"))
		predicate := func(el *xmltree.Element) bool {
			return el.Name.Space == wsdlNS &&
				el.Name.Local == "portType" &&
				el.ResolveDefault(el.Attr("", "name"), targetNS) == portType
		}
		for _, pt := range root.SearchFunc(predicate) {
			for _, op := range pt.Search(wsdlNS, "operation") {
				var oper Operation
				oper.Doc = documentation(op)
				oper.Name = op.ResolveDefault(op.Attr("", "name"), targetNS)
				for _, input := range op.Search(wsdlNS, "input") {
					oper.Input = input.Resolve(input.Attr("", "message"))
				}
				for _, output := range op.Search(wsdlNS, "output") {
					oper.Output = output.Resolve(output.Attr("", "message"))
				}
				ops = append(ops, oper)
			}
		}
	}
	return ops
}

// Parse reads the first WSDL definition from data.
func Parse(data []byte) (*Definition, error) {
	var def Definition
	schema, err := xsd.Parse(data)
	if err != nil {
		return nil, err
	}
	root, err := xmltree.Parse(data)
	if err != nil {
		return nil, err
	}

	def.Schema = schema
	def.TargetNS = root.Attr("", "targetNamespace")
	def.Message = parseMessages(def.TargetNS, root)

	for _, svc := range root.Search(wsdlNS, "service") {
		def.Doc = documentation(svc)
		def.Ports = parsePorts(def.TargetNS, root, svc)
	}
	return &def, nil
}
<commit_msg>Remove xsd Schema from wsdl.Definition, no need<commit_after>// Package wsdl parses Web Service Definition Language documents.
package wsdl

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"strings"

	"aqwari.net/xml/xmltree"
)

const (
	wsdlNS    = "http://schemas.xmlsoap.org/wsdl/"
	soapNS    = "http://schemas.xmlsoap.org/wsdl/soap/"
	soap12NS  = "http://schemas.xmlsoap.org/wsdl/soap12/"
	httpNS    = "http://schemas.xmlsoap.org/wsdl/http/"
	mimeNS    = "http://schemas.xmlsoap.org/wsdl/mime/"
	soapencNS = "http://schemas.xmlsoap.org/soap/encoding/"
	soapenvNS = "http://schemas.xmlsoap.org/soap/envelope/"
	xsiNS     = "http://www.w3.org/2000/10/XMLSchema-instance"
	xsdNS     = "http://www.w3.org/2000/10/XMLSchema"
)

// A Definition contains all information necessary to generate Go code
// from a wsdl document.
type Definition struct {
	Doc      string
	Ports    []Port
	Message  map[xml.Name]Message
	TargetNS string
}

func (def *Definition) String() string {
	var buf bytes.Buffer
	fmt.Fprintln(&buf, "Namespace: ", def.TargetNS)
	for _, port := range def.Ports {
		fmt.Fprintf(&buf, "Port %s %s\n", port.Name, port.Address)
		for _, op := range port.Operations {
			input := def.Message[op.Input]
			output := def.Message[op.Output]
			fmt.Fprintf(&buf, "\t%s(%s) -> %s\n",
				op.Name.Local, &input, &output)
		}
	}
	return buf.String()
}

// A Message is a set of zero or more parameters for WSDL
// operations.
type Message struct {
	Name  xml.Name
	Parts []Part
}

func (m *Message) String() string {
	parts := make([]string, 0, len(m.Parts))
	for _, p := range m.Parts {
		parts = append(parts, fmt.Sprintf("%s", p.Type.Local))
	}
	return fmt.Sprintf("%s", strings.Join(parts, ", "))
}

// A Part describes the name and type of a parameter to pass
// to a WSDL endpoint.
type Part struct {
	Name string
	Type xml.Name
}

// An Operation describes an RPC call that can be made against
// the remote server. Its inputs, outputs and transport information
// are parsed from the WSDL definition. Many Operations can be
// defined for a single endpoint.
type Operation struct {
	Doc           string
	Name          xml.Name
	Input, Output xml.Name
}

// A Port describes a set of RPCs and the address to reach them.
type Port struct {
	Name, Address string
	Operations    []Operation
}

// Collect multiple <documentation> children into a newline-separate string
func documentation(el *xmltree.Element) string {
	var docs [][]byte
	for _, doc := range el.Children {
		if doc.Name.Local != "documentation" {
			continue
		}
		docs = append(docs, doc.Content)
	}
	return string(bytes.Join(docs, []byte{'\n'}))
}

func parseMessages(targetNS string, root *xmltree.Element) map[xml.Name]Message {
	messages := make(map[xml.Name]Message)
	for _, msg := range root.Search(wsdlNS, "message") {
		var m Message
		m.Name = msg.ResolveDefault(msg.Attr("", "name"), targetNS)
		for _, part := range msg.Search(wsdlNS, "part") {
			p := Part{
				Name: part.Attr("", "name"),
				Type: part.Resolve(part.Attr("", "type")),
			}
			if len(p.Type.Local) == 0 {
				p.Type = part.Resolve(part.Attr("", "element"))
			}
			m.Parts = append(m.Parts, p)
		}
		messages[m.Name] = m
	}
	return messages
}

func parsePorts(targetNS string, root, svc *xmltree.Element) []Port {
	var ports []Port
	for _, port := range svc.Search(wsdlNS, "port") {
		var p Port
		p.Name = port.Attr("", "name")
		for _, addr := range port.Search(soapNS, "address") {
			p.Address = addr.Attr("", "location")
		}
		for _, addr := range port.Search(soap12NS, "address") {
			p.Address = addr.Attr("", "location")
		}
		p.Operations = parseOperations(targetNS, root, port)
		ports = append(ports, p)
	}
	return ports
}

func parseOperations(targetNS string, root, port *xmltree.Element) []Operation {
	var ops []Operation
	binding := port.Resolve(port.Attr("", "binding"))
	predicate := func(el *xmltree.Element) bool {
		return el.Name.Space == wsdlNS &&
			el.Name.Local == "binding" &&
			el.ResolveDefault(el.Attr("", "name"), targetNS) == binding
	}

	for _, bind := range root.SearchFunc(predicate) {
		portType := bind.Resolve(bind.Attr("", "type"))
		predicate := func(el *xmltree.Element) bool {
			return el.Name.Space == wsdlNS &&
				el.Name.Local == "portType" &&
				el.ResolveDefault(el.Attr("", "name"), targetNS) == portType
		}
		for _, pt := range root.SearchFunc(predicate) {
			for _, op := range pt.Search(wsdlNS, "operation") {
				var oper Operation
				oper.Doc = documentation(op)
				oper.Name = op.ResolveDefault(op.Attr("", "name"), targetNS)
				for _, input := range op.Search(wsdlNS, "input") {
					oper.Input = input.Resolve(input.Attr("", "message"))
				}
				for _, output := range op.Search(wsdlNS, "output") {
					oper.Output = output.Resolve(output.Attr("", "message"))
				}
				ops = append(ops, oper)
			}
		}
	}
	return ops
}

// Parse reads the first WSDL definition from data.
func Parse(data []byte) (*Definition, error) {
	var def Definition
	root, err := xmltree.Parse(data)
	if err != nil {
		return nil, err
	}

	def.TargetNS = root.Attr("", "targetNamespace")
	def.Message = parseMessages(def.TargetNS, root)

	for _, svc := range root.Search(wsdlNS, "service") {
		def.Doc = documentation(svc)
		def.Ports = parsePorts(def.TargetNS, root, svc)
	}
	return &def, nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"fmt"
	"github.com/slasyz/wundercli/config"
	"github.com/slasyz/wundercli/api"
)

// Gets parameters from command-line arguments or set them empty if not present.
func getParams(count int) (result []string) {
	result = make([]string, count)

	// From command-line arguments
	for i := 0; i < len(os.Args) - 3; i++ {
		result[i] = os.Args[i+2];
	}
	// Empty parameters
	for i := len(os.Args) - 3; i < count; i++ {
		result[i] = ""
	}
	fmt.Println()

	return result
}

func main() {
	exists, err := config.OpenConfig()
	if err != nil {
		fmt.Printf("Error: %s\n", err.Error())
		os.Exit(1)
	}
	if !exists {
		api.DoAuth()
		config.SaveConfig()
	}

	// Parse command-line arguments.
	if len(os.Args) <= 2 {
		cmdHelp()
	}

	switch os.Args[1] {
	case "list":
		switch os.Args[2] {
		case "all":
			err = cmdListAll()
		case "show":
			params := getParams(1)
			err = cmdListShow(params[0])
		case "create":
			params := getParams(1)
			err = cmdListCreate(params[0])
		case "remove":
			params := getParams(1)
			err = cmdListRemove(params[0])
		default:
			cmdHelp()
		}
	case "task":
		switch os.Args[2] {
		case "create":
			params := getParams(2)
			err = cmdTaskCreate(params[0], params[1])
		case "check":
			params := getParams(1)
			err = cmdTaskCheck(params[0])
		case "edit":
			params := getParams(1)
			err = cmdTaskEdit(params[0])
		default:
			cmdHelp()
		}
	default:
		cmdHelp()
	}

	if err != nil {
		fmt.Printf("Error: %s\n\n", err.Error())
		os.Exit(1)
	}

}
<commit_msg>Stupid small fix. Oh my god, why am I so moron?<commit_after>package main

import (
	"os"
	"fmt"
	"github.com/slasyz/wundercli/config"
	"github.com/slasyz/wundercli/api"
)

// Gets parameters from command-line arguments or set them empty if not present.
func getParams(count int) (result []string) {
	result = make([]string, count)

	// From command-line arguments
	for i := 0; i < len(os.Args) - 3; i++ {
		result[i] = os.Args[i+3];
	}
	// Empty parameters
	for i := len(os.Args) - 3; i < count; i++ {
		result[i] = ""
	}
	fmt.Println()

	return result
}

func main() {
	exists, err := config.OpenConfig()
	if err != nil {
		fmt.Printf("Error: %s\n", err.Error())
		os.Exit(1)
	}
	if !exists {
		api.DoAuth()
		config.SaveConfig()
	}

	// Parse command-line arguments.
	if len(os.Args) <= 2 {
		cmdHelp()
	}

	switch os.Args[1] {
	case "list":
		switch os.Args[2] {
		case "all":
			err = cmdListAll()
		case "show":
			params := getParams(1)
			err = cmdListShow(params[0])
		case "create":
			params := getParams(1)
			err = cmdListCreate(params[0])
		case "remove":
			params := getParams(1)
			err = cmdListRemove(params[0])
		default:
			cmdHelp()
		}
	case "task":
		switch os.Args[2] {
		case "create":
			params := getParams(2)
			err = cmdTaskCreate(params[0], params[1])
		case "check":
			params := getParams(1)
			err = cmdTaskCheck(params[0])
		case "edit":
			params := getParams(1)
			err = cmdTaskEdit(params[0])
		default:
			cmdHelp()
		}
	default:
		cmdHelp()
	}

	if err != nil {
		fmt.Printf("Error: %s\n\n", err.Error())
		os.Exit(1)
	}

}
<|endoftext|>


<commit_before>package stats_test

import (
	"math"
	"testing"
	"github.com/mbu/stats"
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/disk"
	"github.com/stretchr/testify/assert"
)

func TestGetAverage_OK(t *testing.T) {

	float32Array := []float32{ 11.904762, 27.5, 5, 2.5, 7.692308, 31.707317, 2.4390242, 7.317073 }

	expected := float32(12.007560525)
	actual := stats.GetAverage(float32Array)
	difference := math.Abs(float64(expected - actual))

	if (difference >= 1) {
		t.Error("Expected a difference less than 1, got: ", difference)
	}
}

func TestGetAverage_NOK_emptyArray(t *testing.T) {

	float32Array := []float32{}

	expected := float32(0)
	actual := stats.GetAverage(float32Array)
	assert.Equal(t, expected, actual)
}

func TestBuildCPUMultipleStat_OK(t *testing.T) {

	float32Array := []float32{ 11.904762, 27.5, 5, 2.5, 7.692308, 31.707317, 2.4390242, 7.317073 }
	cpu := stats.BuildCPUMultipleStat(float32Array)

	assert := assert.New(t)
	assert.NotNil(cpu)
	assert.Equal(stats.GetAverage(float32Array), cpu.AverageUsagePercentage)
	assert.Equal(len(float32Array), len(cpu.UsagePercentagePerCore))
}

func TestBuildCPUMultipleStat_NOK_emptyArray(t *testing.T) {

	float32Array := []float32{}
	cpu := stats.BuildCPUMultipleStat(float32Array)

	assert := assert.New(t)
	assert.NotNil(cpu)
	assert.Equal(stats.GetAverage(float32Array), cpu.AverageUsagePercentage)
	assert.Equal(float32(0), cpu.AverageUsagePercentage)
	assert.Equal(len(float32Array), len(cpu.UsagePercentagePerCore))
	assert.Equal(0, len(cpu.UsagePercentagePerCore))
}

func TestBuildRamStat_OK(t *testing.T) {

	zero := uint64(0)
	total := uint64(100000000000)
	used := uint64(77000000000)
	available := uint64(23000000000)
	usagePercentage := float64(77.00)

	vm := mem.VirtualMemoryStat{ total, available, used, usagePercentage, zero, zero, zero, zero, zero, zero, zero }
	ram := stats.BuildRamStat(vm)

	assert := assert.New(t)
	assert.NotNil(ram)
	assert.Equal(float32(total)/stats.GB, ram.TotalGB)
	assert.Equal(float32(used)/stats.GB, ram.UsedGB)
	assert.Equal(float32(available)/stats.GB, ram.AvailableGB)
	assert.Equal(float32(usagePercentage), ram.UsagePercentage)
}

func TestBuildRamStat_NOK_zeroedRAM(t *testing.T) {

	zero := uint64(0)
	total := uint64(0)
	used := uint64(0)
	available := uint64(0)
	usagePercentage := float64(0.00)

	vm := mem.VirtualMemoryStat{ total, available, used, usagePercentage, zero, zero, zero, zero, zero, zero, zero }
	ram := stats.BuildRamStat(vm)

	assert := assert.New(t)
	assert.NotNil(ram)
	assert.Equal(float32(total)/stats.GB, ram.TotalGB)
	assert.Equal(float32(used)/stats.GB, ram.UsedGB)
	assert.Equal(float32(available)/stats.GB, ram.AvailableGB)
	assert.Equal(float32(usagePercentage), ram.UsagePercentage)
}

func TestBuildDiskStat_OK(t *testing.T) {

	stringValue := ""
	total := uint64(975979800000)
	free := uint64(931929260000)
	used := uint64(44050570000)
	usagePercentage := float64(4.5134716)
	zeroInt := uint64(0)
	zeroFloat := float64(0)

	diskUsage := disk.DiskUsageStat{ stringValue, total, free, used, usagePercentage, zeroInt, zeroInt, zeroInt, zeroFloat }
	disk := stats.BuildDiskStat(diskUsage)

	assert := assert.New(t)
	assert.NotNil(disk)
	assert.Equal(float32(total)/stats.GB, disk.TotalGB)
	assert.Equal(float32(used)/stats.GB, disk.UsedGB)
	assert.Equal(float32(free)/stats.GB, disk.AvailableGB)
	assert.Equal(float32(usagePercentage), disk.UsagePercentage)
}

func TestBuildDiskStat_NOK_zeroedDisk(t *testing.T) {

	stringValue := ""
	total := uint64(0)
	free := uint64(0)
	used := uint64(0)
	usagePercentage := float64(0)
	zeroInt := uint64(0)
	zeroFloat := float64(0)

	diskUsage := disk.DiskUsageStat{ stringValue, total, free, used, usagePercentage, zeroInt, zeroInt, zeroInt, zeroFloat }
	disk := stats.BuildDiskStat(diskUsage)

	assert := assert.New(t)
	assert.NotNil(disk)
	assert.Equal(float32(total)/stats.GB, disk.TotalGB)
	assert.Equal(float32(used)/stats.GB, disk.UsedGB)
	assert.Equal(float32(free)/stats.GB, disk.AvailableGB)
	assert.Equal(float32(usagePercentage), disk.UsagePercentage)
}
<commit_msg>Fix broken tests.<commit_after>package stats_test

import (
	"math"
	"testing"
	"github.com/mbu/stats"
	"github.com/shirou/gopsutil/mem"
	"github.com/shirou/gopsutil/disk"
	"github.com/stretchr/testify/assert"
)

func TestGetAverage_OK(t *testing.T) {

	float64Array := []float64{ 11.904762, 27.5, 5, 2.5, 7.692308, 31.707317, 2.4390242, 7.317073 }

	expected := float64(12.007560525)
	actual := stats.GetAverage(float64Array)
	difference := math.Abs(float64(expected - actual))

	if (difference >= 1) {
		t.Error("Expected a difference less than 1, got: ", difference)
	}
}

func TestGetAverage_NOK_emptyArray(t *testing.T) {

	float64Array := []float64{}

	expected := float64(0)
	actual := stats.GetAverage(float64Array)
	assert.Equal(t, expected, actual)
}

func TestBuildCPUMultipleStat_OK(t *testing.T) {

	float64Array := []float64{ 11.904762, 27.5, 5, 2.5, 7.692308, 31.707317, 2.4390242, 7.317073 }
	cpu := stats.BuildCPUMultipleStat(float64Array)

	assert := assert.New(t)
	assert.NotNil(cpu)
	assert.Equal(stats.GetAverage(float64Array), cpu.AverageUsagePercentage)
	assert.Equal(len(float64Array), len(cpu.UsagePercentagePerCore))
}

func TestBuildCPUMultipleStat_NOK_emptyArray(t *testing.T) {

	float64Array := []float64{}
	cpu := stats.BuildCPUMultipleStat(float64Array)

	assert := assert.New(t)
	assert.NotNil(cpu)
	assert.Equal(stats.GetAverage(float64Array), cpu.AverageUsagePercentage)
	assert.Equal(float64(0), cpu.AverageUsagePercentage)
	assert.Equal(len(float64Array), len(cpu.UsagePercentagePerCore))
	assert.Equal(0, len(cpu.UsagePercentagePerCore))
}

func TestBuildRamStat_OK(t *testing.T) {

	zero := uint64(0)
	total := uint64(100000000000)
	used := uint64(77000000000)
	available := uint64(23000000000)
	usagePercentage := float64(77.00)

	vm := mem.VirtualMemoryStat{ total, available, used, usagePercentage, zero, zero, zero, zero, zero, zero, zero }
	ram := stats.BuildRamStat(vm)

	assert := assert.New(t)
	assert.NotNil(ram)
	assert.Equal(float64(total)/stats.GB, ram.TotalGB)
	assert.Equal(float64(used)/stats.GB, ram.UsedGB)
	assert.Equal(float64(available)/stats.GB, ram.AvailableGB)
	assert.Equal(float64(usagePercentage), ram.UsagePercentage)
}

func TestBuildRamStat_NOK_zeroedRAM(t *testing.T) {

	zero := uint64(0)
	total := uint64(0)
	used := uint64(0)
	available := uint64(0)
	usagePercentage := float64(0.00)

	vm := mem.VirtualMemoryStat{ total, available, used, usagePercentage, zero, zero, zero, zero, zero, zero, zero }
	ram := stats.BuildRamStat(vm)

	assert := assert.New(t)
	assert.NotNil(ram)
	assert.Equal(float64(total)/stats.GB, ram.TotalGB)
	assert.Equal(float64(used)/stats.GB, ram.UsedGB)
	assert.Equal(float64(available)/stats.GB, ram.AvailableGB)
	assert.Equal(float64(usagePercentage), ram.UsagePercentage)
}

func TestBuildDiskStat_OK(t *testing.T) {

	stringValue := ""
	total := uint64(975979800000)
	free := uint64(931929260000)
	used := uint64(44050570000)
	usagePercentage := float64(4.5134716)
	zeroInt := uint64(0)
	zeroFloat := float64(0)

	diskUsage := disk.DiskUsageStat{ stringValue, stringValue, total, free, used, usagePercentage, zeroInt, zeroInt, zeroInt, zeroFloat }
	disk := stats.BuildDiskStat(diskUsage)

	assert := assert.New(t)
	assert.NotNil(disk)
	assert.Equal(float64(total)/stats.GB, disk.TotalGB)
	assert.Equal(float64(used)/stats.GB, disk.UsedGB)
	assert.Equal(float64(free)/stats.GB, disk.AvailableGB)
	assert.Equal(float64(usagePercentage), disk.UsagePercentage)
}

func TestBuildDiskStat_NOK_zeroedDisk(t *testing.T) {

	stringValue := ""
	total := uint64(0)
	free := uint64(0)
	used := uint64(0)
	usagePercentage := float64(0)
	zeroInt := uint64(0)
	zeroFloat := float64(0)

	diskUsage := disk.DiskUsageStat{ stringValue, stringValue, total, free, used, usagePercentage, zeroInt, zeroInt, zeroInt, zeroFloat }
	disk := stats.BuildDiskStat(diskUsage)

	assert := assert.New(t)
	assert.NotNil(disk)
	assert.Equal(float64(total)/stats.GB, disk.TotalGB)
	assert.Equal(float64(used)/stats.GB, disk.UsedGB)
	assert.Equal(float64(free)/stats.GB, disk.AvailableGB)
	assert.Equal(float64(usagePercentage), disk.UsagePercentage)
}
<|endoftext|>


<commit_before>// Package format implements a data format for files in the IPFS filesystem It
// is not the only format in ipfs, but it is the one that the filesystem
// assumes
package unixfs

import (
	"errors"

	dag "github.com/ipfs/go-ipfs/merkledag"
	pb "github.com/ipfs/go-ipfs/unixfs/pb"
	proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
)

const (
	TRaw       = pb.Data_Raw
	TFile      = pb.Data_File
	TDirectory = pb.Data_Directory
	TMetadata  = pb.Data_Metadata
	TSymlink   = pb.Data_Symlink
)

var ErrMalformedFileFormat = errors.New("malformed data in file format")
var ErrInvalidDirLocation = errors.New("found directory node in unexpected place")
var ErrUnrecognizedType = errors.New("unrecognized node type")

func FromBytes(data []byte) (*pb.Data, error) {
	pbdata := new(pb.Data)
	err := proto.Unmarshal(data, pbdata)
	if err != nil {
		return nil, err
	}
	return pbdata, nil
}

func FilePBData(data []byte, totalsize uint64) []byte {
	pbfile := new(pb.Data)
	typ := pb.Data_File
	pbfile.Type = &typ
	pbfile.Data = data
	pbfile.Filesize = proto.Uint64(totalsize)

	data, err := proto.Marshal(pbfile)
	if err != nil {
		// This really shouldnt happen, i promise
		// The only failure case for marshal is if required fields
		// are not filled out, and they all are. If the proto object
		// gets changed and nobody updates this function, the code
		// should panic due to programmer error
		panic(err)
	}
	return data
}

// Returns Bytes that represent a Directory
func FolderPBData() []byte {
	pbfile := new(pb.Data)
	typ := pb.Data_Directory
	pbfile.Type = &typ

	data, err := proto.Marshal(pbfile)
	if err != nil {
		//this really shouldnt happen, i promise
		panic(err)
	}
	return data
}

func WrapData(b []byte) []byte {
	pbdata := new(pb.Data)
	typ := pb.Data_Raw
	pbdata.Data = b
	pbdata.Type = &typ
	pbdata.Filesize = proto.Uint64(uint64(len(b)))

	out, err := proto.Marshal(pbdata)
	if err != nil {
		// This shouldnt happen. seriously.
		panic(err)
	}

	return out
}

func SymlinkData(path string) ([]byte, error) {
	pbdata := new(pb.Data)
	typ := pb.Data_Symlink
	pbdata.Data = []byte(path)
	pbdata.Type = &typ

	out, err := proto.Marshal(pbdata)
	if err != nil {
		return nil, err
	}

	return out, nil
}

func UnwrapData(data []byte) ([]byte, error) {
	pbdata := new(pb.Data)
	err := proto.Unmarshal(data, pbdata)
	if err != nil {
		return nil, err
	}
	return pbdata.GetData(), nil
}

func DataSize(data []byte) (uint64, error) {
	pbdata := new(pb.Data)
	err := proto.Unmarshal(data, pbdata)
	if err != nil {
		return 0, err
	}

	switch pbdata.GetType() {
	case pb.Data_Directory:
		return 0, errors.New("Cant get data size of directory!")
	case pb.Data_File:
		return pbdata.GetFilesize(), nil
	case pb.Data_Raw:
		return uint64(len(pbdata.GetData())), nil
	default:
		return 0, errors.New("Unrecognized node data type!")
	}
}

type FSNode struct {
	Data []byte

	// total data size for each child
	blocksizes []uint64

	// running sum of blocksizes
	subtotal uint64

	// node type of this node
	Type pb.Data_DataType
}

func FSNodeFromBytes(b []byte) (*FSNode, error) {
	pbn := new(pb.Data)
	err := proto.Unmarshal(b, pbn)
	if err != nil {
		return nil, err
	}

	n := new(FSNode)
	n.Data = pbn.Data
	n.blocksizes = pbn.Blocksizes
	n.subtotal = pbn.GetFilesize() - uint64(len(n.Data))
	n.Type = pbn.GetType()
	return n, nil
}

// AddBlockSize adds the size of the next child block of this node
func (n *FSNode) AddBlockSize(s uint64) {
	n.subtotal += s
	n.blocksizes = append(n.blocksizes, s)
}

func (n *FSNode) RemoveBlockSize(i int) {
	n.subtotal -= n.blocksizes[i]
	n.blocksizes = append(n.blocksizes[:i], n.blocksizes[i+1:]...)
}

func (n *FSNode) GetBytes() ([]byte, error) {
	pbn := new(pb.Data)
	pbn.Type = &n.Type
	pbn.Filesize = proto.Uint64(uint64(len(n.Data)) + n.subtotal)
	pbn.Blocksizes = n.blocksizes
	pbn.Data = n.Data
	return proto.Marshal(pbn)
}

func (n *FSNode) FileSize() uint64 {
	return uint64(len(n.Data)) + n.subtotal
}

func (n *FSNode) NumChildren() int {
	return len(n.blocksizes)
}

type Metadata struct {
	MimeType string
	Size     uint64
}

func MetadataFromBytes(b []byte) (*Metadata, error) {
	pbd := new(pb.Data)
	err := proto.Unmarshal(b, pbd)
	if err != nil {
		return nil, err
	}
	if pbd.GetType() != pb.Data_Metadata {
		return nil, errors.New("incorrect node type")
	}

	pbm := new(pb.Metadata)
	err = proto.Unmarshal(pbd.Data, pbm)
	if err != nil {
		return nil, err
	}
	md := new(Metadata)
	md.MimeType = pbm.GetMimeType()
	return md, nil
}

func (m *Metadata) Bytes() ([]byte, error) {
	pbm := new(pb.Metadata)
	pbm.MimeType = &m.MimeType
	return proto.Marshal(pbm)
}

func BytesForMetadata(m *Metadata) ([]byte, error) {
	pbd := new(pb.Data)
	pbd.Filesize = proto.Uint64(m.Size)
	typ := pb.Data_Metadata
	pbd.Type = &typ
	mdd, err := m.Bytes()
	if err != nil {
		return nil, err
	}

	pbd.Data = mdd
	return proto.Marshal(pbd)
}

func EmptyDirNode() *dag.ProtoNode {
	return dag.NodeWithData(FolderPBData())
}
<commit_msg>Add Some Comments to unixfs/format<commit_after>// Package format implements a data format for files in the IPFS filesystem It
// is not the only format in ipfs, but it is the one that the filesystem
// assumes
package unixfs

import (
	"errors"

	dag "github.com/ipfs/go-ipfs/merkledag"
	pb "github.com/ipfs/go-ipfs/unixfs/pb"
	proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
)

const (
	TRaw       = pb.Data_Raw
	TFile      = pb.Data_File
	TDirectory = pb.Data_Directory
	TMetadata  = pb.Data_Metadata
	TSymlink   = pb.Data_Symlink
)

var ErrMalformedFileFormat = errors.New("malformed data in file format")
var ErrInvalidDirLocation = errors.New("found directory node in unexpected place")
var ErrUnrecognizedType = errors.New("unrecognized node type")

func FromBytes(data []byte) (*pb.Data, error) {
	pbdata := new(pb.Data)
	err := proto.Unmarshal(data, pbdata)
	if err != nil {
		return nil, err
	}
	return pbdata, nil
}

func FilePBData(data []byte, totalsize uint64) []byte {
	pbfile := new(pb.Data)
	typ := pb.Data_File
	pbfile.Type = &typ
	pbfile.Data = data
	pbfile.Filesize = proto.Uint64(totalsize)

	data, err := proto.Marshal(pbfile)
	if err != nil {
		// This really shouldnt happen, i promise
		// The only failure case for marshal is if required fields
		// are not filled out, and they all are. If the proto object
		// gets changed and nobody updates this function, the code
		// should panic due to programmer error
		panic(err)
	}
	return data
}

//FolderPBData returns Bytes that represent a Directory.
func FolderPBData() []byte {
	pbfile := new(pb.Data)
	typ := pb.Data_Directory
	pbfile.Type = &typ

	data, err := proto.Marshal(pbfile)
	if err != nil {
		//this really shouldnt happen, i promise
		panic(err)
	}
	return data
}

//WrapData marshals raw bytes into a `Data_Raw` type protobuf message.
func WrapData(b []byte) []byte {
	pbdata := new(pb.Data)
	typ := pb.Data_Raw
	pbdata.Data = b
	pbdata.Type = &typ
	pbdata.Filesize = proto.Uint64(uint64(len(b)))

	out, err := proto.Marshal(pbdata)
	if err != nil {
		// This shouldnt happen. seriously.
		panic(err)
	}

	return out
}

//SymlinkData returns a `Data_Symlink` protobuf message for the path you specify.
func SymlinkData(path string) ([]byte, error) {
	pbdata := new(pb.Data)
	typ := pb.Data_Symlink
	pbdata.Data = []byte(path)
	pbdata.Type = &typ

	out, err := proto.Marshal(pbdata)
	if err != nil {
		return nil, err
	}

	return out, nil
}

func UnwrapData(data []byte) ([]byte, error) {
	pbdata := new(pb.Data)
	err := proto.Unmarshal(data, pbdata)
	if err != nil {
		return nil, err
	}
	return pbdata.GetData(), nil
}

func DataSize(data []byte) (uint64, error) {
	pbdata := new(pb.Data)
	err := proto.Unmarshal(data, pbdata)
	if err != nil {
		return 0, err
	}

	switch pbdata.GetType() {
	case pb.Data_Directory:
		return 0, errors.New("Cant get data size of directory!")
	case pb.Data_File:
		return pbdata.GetFilesize(), nil
	case pb.Data_Raw:
		return uint64(len(pbdata.GetData())), nil
	default:
		return 0, errors.New("Unrecognized node data type!")
	}
}

type FSNode struct {
	Data []byte

	// total data size for each child
	blocksizes []uint64

	// running sum of blocksizes
	subtotal uint64

	// node type of this node
	Type pb.Data_DataType
}

func FSNodeFromBytes(b []byte) (*FSNode, error) {
	pbn := new(pb.Data)
	err := proto.Unmarshal(b, pbn)
	if err != nil {
		return nil, err
	}

	n := new(FSNode)
	n.Data = pbn.Data
	n.blocksizes = pbn.Blocksizes
	n.subtotal = pbn.GetFilesize() - uint64(len(n.Data))
	n.Type = pbn.GetType()
	return n, nil
}

// AddBlockSize adds the size of the next child block of this node
func (n *FSNode) AddBlockSize(s uint64) {
	n.subtotal += s
	n.blocksizes = append(n.blocksizes, s)
}

func (n *FSNode) RemoveBlockSize(i int) {
	n.subtotal -= n.blocksizes[i]
	n.blocksizes = append(n.blocksizes[:i], n.blocksizes[i+1:]...)
}

func (n *FSNode) GetBytes() ([]byte, error) {
	pbn := new(pb.Data)
	pbn.Type = &n.Type
	pbn.Filesize = proto.Uint64(uint64(len(n.Data)) + n.subtotal)
	pbn.Blocksizes = n.blocksizes
	pbn.Data = n.Data
	return proto.Marshal(pbn)
}

func (n *FSNode) FileSize() uint64 {
	return uint64(len(n.Data)) + n.subtotal
}

func (n *FSNode) NumChildren() int {
	return len(n.blocksizes)
}

type Metadata struct {
	MimeType string
	Size     uint64
}

//MetadataFromBytes Unmarshals a protobuf message into Metadata.
func MetadataFromBytes(b []byte) (*Metadata, error) {
	pbd := new(pb.Data)
	err := proto.Unmarshal(b, pbd)
	if err != nil {
		return nil, err
	}
	if pbd.GetType() != pb.Data_Metadata {
		return nil, errors.New("incorrect node type")
	}

	pbm := new(pb.Metadata)
	err = proto.Unmarshal(pbd.Data, pbm)
	if err != nil {
		return nil, err
	}
	md := new(Metadata)
	md.MimeType = pbm.GetMimeType()
	return md, nil
}

func (m *Metadata) Bytes() ([]byte, error) {
	pbm := new(pb.Metadata)
	pbm.MimeType = &m.MimeType
	return proto.Marshal(pbm)
}

func BytesForMetadata(m *Metadata) ([]byte, error) {
	pbd := new(pb.Data)
	pbd.Filesize = proto.Uint64(m.Size)
	typ := pb.Data_Metadata
	pbd.Type = &typ
	mdd, err := m.Bytes()
	if err != nil {
		return nil, err
	}

	pbd.Data = mdd
	return proto.Marshal(pbd)
}

func EmptyDirNode() *dag.ProtoNode {
	return dag.NodeWithData(FolderPBData())
}
<|endoftext|>


<commit_before>package sakuracloud

import (
	"fmt"

	"bytes"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/yamamoto-febc/libsacloud/api"
	"github.com/yamamoto-febc/libsacloud/sacloud"
)

func resourceSakuraCloudVPCRouterFirewall() *schema.Resource {
	return &schema.Resource{
		Create: resourceSakuraCloudVPCRouterFirewallCreate,
		Read:   resourceSakuraCloudVPCRouterFirewallRead,
		Delete: resourceSakuraCloudVPCRouterFirewallDelete,
		Schema: map[string]*schema.Schema{
			"vpc_router_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"direction": &schema.Schema{
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateStringInWord([]string{"send", "receive"}),
			},
			"expressions": &schema.Schema{
				Type:     schema.TypeList,
				Required: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{

						"protocol": &schema.Schema{
							Type:         schema.TypeString,
							Required:     true,
							ForceNew:     true,
							ValidateFunc: validateStringInWord([]string{"tcp", "udp", "icmp", "ip"}),
						},
						"source_nw": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"source_port": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"dest_nw": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"dest_port": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"allow": &schema.Schema{
							Type:     schema.TypeBool,
							Required: true,
							ForceNew: true,
						},
					},
				},
			},

			"zone": &schema.Schema{
				Type:         schema.TypeString,
				Optional:     true,
				Computed:     true,
				ForceNew:     true,
				Description:  "target SakuraCloud zone",
				ValidateFunc: validateStringInWord([]string{"is1a", "is1b", "tk1a", "tk1v"}),
			},
		},
	}
}

func resourceSakuraCloudVPCRouterFirewallCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*api.Client)
	zone, ok := d.GetOk("zone")
	if ok {
		client.Zone = zone.(string)
	}

	routerID := d.Get("vpc_router_id").(string)
	sakuraMutexKV.Lock(routerID)
	defer sakuraMutexKV.Unlock(routerID)

	vpcRouter, err := client.VPCRouter.Read(routerID)
	if err != nil {
		return fmt.Errorf("Couldn't find SakuraCloud VPCRouter resource: %s", err)
	}

	direction := d.Get("direction").(string)

	if vpcRouter.Settings == nil {
		vpcRouter.InitVPCRouterSetting()
	}

	// clear rules
	if vpcRouter.Settings.Router.Firewall != nil && vpcRouter.Settings.Router.Firewall.Config != nil &&
		len(vpcRouter.Settings.Router.Firewall.Config) > 0 {
		switch direction {
		case "send":
			vpcRouter.Settings.Router.Firewall.Config[0].Send = nil
		case "receive":
			vpcRouter.Settings.Router.Firewall.Config[0].Receive = nil
		}

	}

	if rawExpressions, ok := d.GetOk("expressions"); ok {
		expressions := rawExpressions.([]interface{})
		for _, e := range expressions {
			exp := e.(map[string]interface{})

			allow := exp["allow"].(bool)
			protocol := exp["protocol"].(string)
			sourceNW := exp["source_nw"].(string)
			sourcePort := exp["source_port"].(string)
			destNW := exp["dest_nw"].(string)
			destPort := exp["dest_port"].(string)

			switch direction {
			case "send":
				vpcRouter.Settings.Router.AddFirewallRuleSend(allow, protocol, sourceNW, sourcePort, destNW, destPort)
			case "receive":
				vpcRouter.Settings.Router.AddFirewallRuleReceive(allow, protocol, sourceNW, sourcePort, destNW, destPort)
			}
		}
	}

	vpcRouter, err = client.VPCRouter.UpdateSetting(routerID, vpcRouter)
	if err != nil {
		return fmt.Errorf("Failed to enable SakuraCloud VPCRouterFirewall resource: %s", err)
	}

	_, err = client.VPCRouter.Config(routerID)
	if err != nil {
		return fmt.Errorf("Couldn'd apply SakuraCloud VPCRouter config: %s", err)
	}

	d.SetId(vpcRouterFirewallIDHash(routerID, direction))
	return resourceSakuraCloudVPCRouterFirewallRead(d, meta)
}

func resourceSakuraCloudVPCRouterFirewallRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*api.Client)
	zone, ok := d.GetOk("zone")
	if ok {
		client.Zone = zone.(string)
	}

	routerID := d.Get("vpc_router_id").(string)
	vpcRouter, err := client.VPCRouter.Read(routerID)
	if err != nil {
		return fmt.Errorf("Couldn't find SakuraCloud VPCRouter resource: %s", err)
	}

	direction := d.Get("direction").(string)
	if vpcRouter.Settings != nil && vpcRouter.Settings.Router != nil && vpcRouter.Settings.Router.Firewall != nil &&
		vpcRouter.Settings.Router.Firewall.Config != nil {

		expressions := []interface{}{}

		var rules []*sacloud.VPCRouterFirewallRule
		switch direction {
		case "send":
			rules = vpcRouter.Settings.Router.Firewall.Config[0].Send
		case "receive":
			rules = vpcRouter.Settings.Router.Firewall.Config[0].Receive
		}

		for _, rule := range rules {
			expression := map[string]interface{}{}

			expression["source_nw"] = rule.SourceNetwork
			expression["source_port"] = rule.SourcePort
			expression["dest_nw"] = rule.DestinationNetwork
			expression["dest_port"] = rule.DestinationPort
			expression["allow"] = (rule.Action == "allow")
			expression["protocol"] = rule.Protocol

			expressions = append(expressions, expression)
		}
		d.Set("expressions", expressions)
	} else {
		d.Set("expressions", []interface{}{})
	}

	d.Set("zone", client.Zone)

	return nil
}

func resourceSakuraCloudVPCRouterFirewallDelete(d *schema.ResourceData, meta interface{}) error {

	client := meta.(*api.Client)
	zone, ok := d.GetOk("zone")
	if ok {
		client.Zone = zone.(string)
	}

	routerID := d.Get("vpc_router_id").(string)
	sakuraMutexKV.Lock(routerID)
	defer sakuraMutexKV.Unlock(routerID)

	vpcRouter, err := client.VPCRouter.Read(routerID)
	if err != nil {
		return fmt.Errorf("Couldn't find SakuraCloud VPCRouter resource: %s", err)
	}

	if vpcRouter.Settings.Router.Firewall != nil {
		vpcRouter.Settings.Router.Firewall.Config = []*sacloud.VPCRouterFirewallSetting{}
		vpcRouter.Settings.Router.Firewall.Enabled = "False"

		vpcRouter, err = client.VPCRouter.UpdateSetting(routerID, vpcRouter)
		if err != nil {
			return fmt.Errorf("Failed to delete SakuraCloud VPCRouterFirewall resource: %s", err)
		}

		_, err = client.VPCRouter.Config(routerID)
		if err != nil {
			return fmt.Errorf("Couldn'd apply SakuraCloud VPCRouter config: %s", err)
		}
	}

	d.SetId("")
	return nil
}

func vpcRouterFirewallIDHash(routerID string, direction string) string {
	var buf bytes.Buffer
	buf.WriteString(fmt.Sprintf("%s-", routerID))
	buf.WriteString(fmt.Sprintf("%s-", direction))

	return fmt.Sprintf("%d", hashcode.String(buf.String()))
}
<commit_msg>Fix delete vpcrouter firewall rules logic<commit_after>package sakuracloud

import (
	"fmt"

	"bytes"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/yamamoto-febc/libsacloud/api"
	"github.com/yamamoto-febc/libsacloud/sacloud"
)

func resourceSakuraCloudVPCRouterFirewall() *schema.Resource {
	return &schema.Resource{
		Create: resourceSakuraCloudVPCRouterFirewallCreate,
		Read:   resourceSakuraCloudVPCRouterFirewallRead,
		Delete: resourceSakuraCloudVPCRouterFirewallDelete,
		Schema: map[string]*schema.Schema{
			"vpc_router_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"direction": &schema.Schema{
				Type:         schema.TypeString,
				Required:     true,
				ForceNew:     true,
				ValidateFunc: validateStringInWord([]string{"send", "receive"}),
			},
			"expressions": &schema.Schema{
				Type:     schema.TypeList,
				Required: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{

						"protocol": &schema.Schema{
							Type:         schema.TypeString,
							Required:     true,
							ForceNew:     true,
							ValidateFunc: validateStringInWord([]string{"tcp", "udp", "icmp", "ip"}),
						},
						"source_nw": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"source_port": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"dest_nw": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"dest_port": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
							ForceNew: true,
						},
						"allow": &schema.Schema{
							Type:     schema.TypeBool,
							Required: true,
							ForceNew: true,
						},
					},
				},
			},

			"zone": &schema.Schema{
				Type:         schema.TypeString,
				Optional:     true,
				Computed:     true,
				ForceNew:     true,
				Description:  "target SakuraCloud zone",
				ValidateFunc: validateStringInWord([]string{"is1a", "is1b", "tk1a", "tk1v"}),
			},
		},
	}
}

func resourceSakuraCloudVPCRouterFirewallCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*api.Client)
	zone, ok := d.GetOk("zone")
	if ok {
		client.Zone = zone.(string)
	}

	routerID := d.Get("vpc_router_id").(string)
	sakuraMutexKV.Lock(routerID)
	defer sakuraMutexKV.Unlock(routerID)

	vpcRouter, err := client.VPCRouter.Read(routerID)
	if err != nil {
		return fmt.Errorf("Couldn't find SakuraCloud VPCRouter resource: %s", err)
	}

	direction := d.Get("direction").(string)

	if vpcRouter.Settings == nil {
		vpcRouter.InitVPCRouterSetting()
	}

	// clear rules
	if vpcRouter.Settings.Router.Firewall != nil && vpcRouter.Settings.Router.Firewall.Config != nil &&
		len(vpcRouter.Settings.Router.Firewall.Config) > 0 {
		switch direction {
		case "send":
			vpcRouter.Settings.Router.Firewall.Config[0].Send = nil
		case "receive":
			vpcRouter.Settings.Router.Firewall.Config[0].Receive = nil
		}

	}

	if rawExpressions, ok := d.GetOk("expressions"); ok {
		expressions := rawExpressions.([]interface{})
		for _, e := range expressions {
			exp := e.(map[string]interface{})

			allow := exp["allow"].(bool)
			protocol := exp["protocol"].(string)
			sourceNW := exp["source_nw"].(string)
			sourcePort := exp["source_port"].(string)
			destNW := exp["dest_nw"].(string)
			destPort := exp["dest_port"].(string)

			switch direction {
			case "send":
				vpcRouter.Settings.Router.AddFirewallRuleSend(allow, protocol, sourceNW, sourcePort, destNW, destPort)
			case "receive":
				vpcRouter.Settings.Router.AddFirewallRuleReceive(allow, protocol, sourceNW, sourcePort, destNW, destPort)
			}
		}
	}

	vpcRouter, err = client.VPCRouter.UpdateSetting(routerID, vpcRouter)
	if err != nil {
		return fmt.Errorf("Failed to enable SakuraCloud VPCRouterFirewall resource: %s", err)
	}

	_, err = client.VPCRouter.Config(routerID)
	if err != nil {
		return fmt.Errorf("Couldn'd apply SakuraCloud VPCRouter config: %s", err)
	}

	d.SetId(vpcRouterFirewallIDHash(routerID, direction))
	return resourceSakuraCloudVPCRouterFirewallRead(d, meta)
}

func resourceSakuraCloudVPCRouterFirewallRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*api.Client)
	zone, ok := d.GetOk("zone")
	if ok {
		client.Zone = zone.(string)
	}

	routerID := d.Get("vpc_router_id").(string)
	vpcRouter, err := client.VPCRouter.Read(routerID)
	if err != nil {
		return fmt.Errorf("Couldn't find SakuraCloud VPCRouter resource: %s", err)
	}

	direction := d.Get("direction").(string)
	if vpcRouter.Settings != nil && vpcRouter.Settings.Router != nil && vpcRouter.Settings.Router.Firewall != nil &&
		vpcRouter.Settings.Router.Firewall.Config != nil {

		expressions := []interface{}{}

		var rules []*sacloud.VPCRouterFirewallRule
		switch direction {
		case "send":
			rules = vpcRouter.Settings.Router.Firewall.Config[0].Send
		case "receive":
			rules = vpcRouter.Settings.Router.Firewall.Config[0].Receive
		}

		for _, rule := range rules {
			expression := map[string]interface{}{}

			expression["source_nw"] = rule.SourceNetwork
			expression["source_port"] = rule.SourcePort
			expression["dest_nw"] = rule.DestinationNetwork
			expression["dest_port"] = rule.DestinationPort
			expression["allow"] = (rule.Action == "allow")
			expression["protocol"] = rule.Protocol

			expressions = append(expressions, expression)
		}
		d.Set("expressions", expressions)
	} else {
		d.Set("expressions", []interface{}{})
	}

	d.Set("zone", client.Zone)

	return nil
}

func resourceSakuraCloudVPCRouterFirewallDelete(d *schema.ResourceData, meta interface{}) error {

	client := meta.(*api.Client)
	zone, ok := d.GetOk("zone")
	if ok {
		client.Zone = zone.(string)
	}

	routerID := d.Get("vpc_router_id").(string)
	sakuraMutexKV.Lock(routerID)
	defer sakuraMutexKV.Unlock(routerID)

	vpcRouter, err := client.VPCRouter.Read(routerID)
	if err != nil {
		return fmt.Errorf("Couldn't find SakuraCloud VPCRouter resource: %s", err)
	}

	direction := d.Get("direction").(string)
	if vpcRouter.Settings != nil && vpcRouter.Settings.Router != nil && vpcRouter.Settings.Router.Firewall != nil &&
		vpcRouter.Settings.Router.Firewall.Config != nil {

		switch direction {
		case "send":
			vpcRouter.Settings.Router.Firewall.Config[0].Send = nil
		case "receive":
			vpcRouter.Settings.Router.Firewall.Config[0].Receive = nil
		}

		if vpcRouter.Settings.Router.Firewall.Config[0].Send == nil && vpcRouter.Settings.Router.Firewall.Config[0].Receive == nil {
			vpcRouter.Settings.Router.Firewall.Config = nil
			vpcRouter.Settings.Router.Firewall.Enabled = "False"
		}

		vpcRouter, err = client.VPCRouter.UpdateSetting(routerID, vpcRouter)
		if err != nil {
			return fmt.Errorf("Failed to delete SakuraCloud VPCRouterFirewall resource: %s", err)
		}

		_, err = client.VPCRouter.Config(routerID)
		if err != nil {
			return fmt.Errorf("Couldn'd apply SakuraCloud VPCRouter config: %s", err)
		}
	}

	d.SetId("")
	return nil
}

func vpcRouterFirewallIDHash(routerID string, direction string) string {
	var buf bytes.Buffer
	buf.WriteString(fmt.Sprintf("%s-", routerID))
	buf.WriteString(fmt.Sprintf("%s-", direction))

	return fmt.Sprintf("%d", hashcode.String(buf.String()))
}
<|endoftext|>


<commit_before>package psn

import (
	"bufio"
	"bytes"
	"os"
	"os/exec"
	"strings"
	"sync"

	"github.com/kr/pty"
)

// TopStream provides top command output stream.
type TopStream struct {
	cmd *exec.Cmd

	pmu sync.Mutex
	pt  *os.File

	// broadcast updates whenver available available
	wg                sync.WaitGroup
	rcond             *sync.Cond
	rmu               sync.RWMutex // protect results
	queue             []TopCommandRow
	pid2TopCommandRow map[int64]TopCommandRow
	err               error
	errc              chan error
}

// StartStream starts 'top' command stream.
func (cfg *TopConfig) StartStream() (*TopStream, error) {
	if err := cfg.createCmd(); err != nil {
		return nil, err
	}
	pt, err := pty.Start(cfg.cmd)
	if err != nil {
		return nil, err
	}

	str := &TopStream{
		cmd: cfg.cmd,

		pmu: sync.Mutex{},
		pt:  pt,

		wg:  sync.WaitGroup{},
		rmu: sync.RWMutex{},

		// pre-allocate
		queue:             make([]TopCommandRow, 0, 100),
		pid2TopCommandRow: make(map[int64]TopCommandRow, 500),
		err:               nil,
		errc:              make(chan error, 1),
	}
	str.rcond = sync.NewCond(&str.rmu)

	str.wg.Add(1)
	go str.enqueue()
	go str.dequeue()

	return str, nil
}

// ErrChan returns the error from stream.
func (str *TopStream) ErrChan() <-chan error {
	return str.errc
}

func (str *TopStream) noError() (noErr bool) {
	str.rmu.RLock()
	noErr = str.err == nil
	str.rmu.RUnlock()
	return
}

// feed new top results into the queue
func (str *TopStream) enqueue() {
	defer str.wg.Done()
	reader := bufio.NewReader(str.pt)
	for str.noError() {
		// lock for pty
		str.pmu.Lock()
		data, _, lerr := reader.ReadLine()
		str.pmu.Unlock()

		data = bytes.TrimSpace(data)
		if topRowToSkip(data) {
			continue
		}
		line := string(data)

		// lock for results
		str.rmu.Lock()

		str.err = lerr
		if line == "" {
			str.rmu.Unlock()
			continue
		}

		row := strings.Fields(line)
		if len(row) != len(TopRowHeaders) {
			str.rmu.Unlock()
			continue
		}

		r, rerr := parseTopRow(row)
		if rerr != nil {
			str.err = rerr
			str.rmu.Unlock()
			continue
		}

		str.queue = append(str.queue, r)
		if len(str.queue) == 1 {
			// we have a new output; signal!
			str.rcond.Signal()
		}
		str.rmu.Unlock()
	}

	// we got error; signal!
	str.rcond.Signal()
}

// dequeue polls from 'top' process.
// And signals error channel if any.
func (str *TopStream) dequeue() {
	str.rmu.Lock()
	for {
		// wait until there's output
		for len(str.queue) == 0 && str.err == nil {
			str.rcond.Wait()
		}

		// no output; should be error
		if len(str.queue) == 0 {
			break
		}

		row := str.queue[0]
		str.queue = str.queue[1:]

		str.pid2TopCommandRow[row.PID] = row
	}
	if expectedErr(str.err) {
		str.err = nil
	}
	if str.err != nil {
		str.errc <- str.err
	}
	str.rmu.Unlock()
}

func (str *TopStream) close(kill bool) (err error) {
	if str.cmd == nil {
		return str.err
	}
	if kill {
		str.cmd.Process.Kill()
	}

	err = str.cmd.Wait()

	str.pmu.Lock()
	str.pt.Close() // close file
	str.pmu.Unlock()

	str.wg.Wait()

	if err != nil {
		if !kill && strings.Contains(err.Error(), "exit status") {
			err = nil // non-zero exit code
		} else if kill && expectedErr(err) {
			err = nil
		}
	}
	str.cmd = nil
	return err
}

func expectedErr(err error) bool {
	if err == nil {
		return true
	}
	es := err.Error()
	return strings.Contains(es, "signal:") ||
		strings.Contains(es, "/dev/ptmx: input/output error") ||
		strings.Contains(es, "/dev/ptmx: file already closed")
}

// Stop kills the 'top' process and waits for it to exit.
func (str *TopStream) Stop() error {
	return str.close(true)
}

// Wait just waits for the 'top' process to exit.
func (str *TopStream) Wait() error {
	return str.close(false)
}

// Latest returns the latest top command outputs.
func (str *TopStream) Latest() map[int64]TopCommandRow {
	str.rmu.RLock()
	cm := make(map[int64]TopCommandRow, len(str.pid2TopCommandRow))
	for k, v := range str.pid2TopCommandRow {
		cm[k] = v
	}
	str.rmu.RUnlock()
	return cm
}
<commit_msg>top: bump up 'queue' cap<commit_after>package psn

import (
	"bufio"
	"bytes"
	"os"
	"os/exec"
	"strings"
	"sync"

	"github.com/kr/pty"
)

// TopStream provides top command output stream.
type TopStream struct {
	cmd *exec.Cmd

	pmu sync.Mutex
	pt  *os.File

	// broadcast updates whenver available available
	wg                sync.WaitGroup
	rcond             *sync.Cond
	rmu               sync.RWMutex // protect results
	queue             []TopCommandRow
	pid2TopCommandRow map[int64]TopCommandRow
	err               error
	errc              chan error
}

// StartStream starts 'top' command stream.
func (cfg *TopConfig) StartStream() (*TopStream, error) {
	if err := cfg.createCmd(); err != nil {
		return nil, err
	}
	pt, err := pty.Start(cfg.cmd)
	if err != nil {
		return nil, err
	}

	str := &TopStream{
		cmd: cfg.cmd,

		pmu: sync.Mutex{},
		pt:  pt,

		wg:  sync.WaitGroup{},
		rmu: sync.RWMutex{},

		// pre-allocate
		queue:             make([]TopCommandRow, 0, 500),
		pid2TopCommandRow: make(map[int64]TopCommandRow, 500),
		err:               nil,
		errc:              make(chan error, 1),
	}
	str.rcond = sync.NewCond(&str.rmu)

	str.wg.Add(1)
	go str.enqueue()
	go str.dequeue()

	return str, nil
}

// ErrChan returns the error from stream.
func (str *TopStream) ErrChan() <-chan error {
	return str.errc
}

func (str *TopStream) noError() (noErr bool) {
	str.rmu.RLock()
	noErr = str.err == nil
	str.rmu.RUnlock()
	return
}

// feed new top results into the queue
func (str *TopStream) enqueue() {
	defer str.wg.Done()
	reader := bufio.NewReader(str.pt)
	for str.noError() {
		// lock for pty
		str.pmu.Lock()
		data, _, lerr := reader.ReadLine()
		str.pmu.Unlock()

		data = bytes.TrimSpace(data)
		if topRowToSkip(data) {
			continue
		}
		line := string(data)

		// lock for results
		str.rmu.Lock()

		str.err = lerr
		if line == "" {
			str.rmu.Unlock()
			continue
		}

		row := strings.Fields(line)
		if len(row) != len(TopRowHeaders) {
			str.rmu.Unlock()
			continue
		}

		r, rerr := parseTopRow(row)
		if rerr != nil {
			str.err = rerr
			str.rmu.Unlock()
			continue
		}

		str.queue = append(str.queue, r)
		if len(str.queue) == 1 {
			// we have a new output; signal!
			str.rcond.Signal()
		}
		str.rmu.Unlock()
	}

	// we got error; signal!
	str.rcond.Signal()
}

// dequeue polls from 'top' process.
// And signals error channel if any.
func (str *TopStream) dequeue() {
	str.rmu.Lock()
	for {
		// wait until there's output
		for len(str.queue) == 0 && str.err == nil {
			str.rcond.Wait()
		}

		// no output; should be error
		if len(str.queue) == 0 {
			break
		}

		row := str.queue[0]
		str.queue = str.queue[1:]

		str.pid2TopCommandRow[row.PID] = row
	}
	if expectedErr(str.err) {
		str.err = nil
	}
	if str.err != nil {
		str.errc <- str.err
	}
	str.rmu.Unlock()
}

func (str *TopStream) close(kill bool) (err error) {
	if str.cmd == nil {
		return str.err
	}
	if kill {
		str.cmd.Process.Kill()
	}

	err = str.cmd.Wait()

	str.pmu.Lock()
	str.pt.Close() // close file
	str.pmu.Unlock()

	str.wg.Wait()

	if err != nil {
		if !kill && strings.Contains(err.Error(), "exit status") {
			err = nil // non-zero exit code
		} else if kill && expectedErr(err) {
			err = nil
		}
	}
	str.cmd = nil
	return err
}

func expectedErr(err error) bool {
	if err == nil {
		return true
	}
	es := err.Error()
	return strings.Contains(es, "signal:") ||
		strings.Contains(es, "/dev/ptmx: input/output error") ||
		strings.Contains(es, "/dev/ptmx: file already closed")
}

// Stop kills the 'top' process and waits for it to exit.
func (str *TopStream) Stop() error {
	return str.close(true)
}

// Wait just waits for the 'top' process to exit.
func (str *TopStream) Wait() error {
	return str.close(false)
}

// Latest returns the latest top command outputs.
func (str *TopStream) Latest() map[int64]TopCommandRow {
	str.rmu.RLock()
	cm := make(map[int64]TopCommandRow, len(str.pid2TopCommandRow))
	for k, v := range str.pid2TopCommandRow {
		cm[k] = v
	}
	str.rmu.RUnlock()
	return cm
}
<|endoftext|>


<commit_before>package tor

import (
	"fmt"
	"net"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/jfrazelle/onion/vendor/src/github.com/docker/libnetwork/iptables"
	"github.com/vishvananda/netlink"
)

// initBridge creates a bridge if it does not exist
func (n *NetworkState) initBridge(torIP string) error {
	// try to get bridge by name, if it already exists then just exit
	bridgeName := n.BridgeName
	_, err := net.InterfaceByName(bridgeName)
	if err == nil {
		return nil
	}
	if !strings.Contains(err.Error(), "no such network interface") {
		return err
	}

	// create *netlink.Bridge object
	la := netlink.NewLinkAttrs()
	la.Name = bridgeName
	la.MTU = n.MTU
	br := &netlink.Bridge{la}
	if err := netlink.LinkAdd(br); err != nil {
		return fmt.Errorf("Bridge creation failed for bridge %s: %v", bridgeName, err)
	}

	// Set bridge IP
	gatewayIP := n.Gateway + "/" + n.GatewayMask
	if err := setInterfaceIP(bridgeName, gatewayIP); err != nil {
		return fmt.Errorf("Error assigning address: %s on bridge: %s with an error of: %v", gatewayIP, bridgeName, err)
	}

	// Validate that the IPAddress is there!
	_, err = getIfaceAddr(bridgeName)
	if err != nil {
		return fmt.Errorf("No IP address found on bridge %s: %v", bridgeName, err)
	}

	// Bring the bridge up
	if err := interfaceUp(bridgeName); err != nil {
		return fmt.Errorf("Error enabling bridge for %s: %v", bridgeName, err)
	}

	// Setup iptables
	if err := n.setupIPTables(torIP); err != nil {
		return fmt.Errorf("Error setting up iptables for %s: %v", bridgeName, err)
	}

	return nil
}

// deleteBridge deletes the bridge
func (n *NetworkState) deleteBridge(id string) error {
	bridgeName := n.BridgeName

	// get the link
	l, err := netlink.LinkByName(bridgeName)
	if err != nil {
		return fmt.Errorf("Getting link with name %s failed: %v", bridgeName, err)
	}

	// delete the link
	if err := netlink.LinkDel(l); err != nil {
		return fmt.Errorf("Failed to remove bridge interface %s delete: %v", bridgeName, err)
	}

	// delete all relevant iptables rules
	for _, cleanFunc := range n.iptCleanFuncs {
		if err := cleanFunc(); err != nil {
			logrus.Warnf("Failed to clean iptables rules for bridge %s: %v", bridgeName, err)
		}
	}

	// delete all the iptables chains
	if err := iptables.RemoveExistingChain(TorChain, iptables.Nat); err != nil {
		logrus.Warnf("Failed on removing iptables NAT chain on cleanup: %v", err)
	}
	if err := iptables.RemoveExistingChain(TorChain, iptables.Filter); err != nil {
		logrus.Warnf("Failed on removing iptables FILTER chain on cleanup: %v", err)
	}

	return nil
}
<commit_msg>fix go imports<commit_after>package tor

import (
	"fmt"
	"net"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/docker/libnetwork/iptables"
	"github.com/vishvananda/netlink"
)

// initBridge creates a bridge if it does not exist
func (n *NetworkState) initBridge(torIP string) error {
	// try to get bridge by name, if it already exists then just exit
	bridgeName := n.BridgeName
	_, err := net.InterfaceByName(bridgeName)
	if err == nil {
		return nil
	}
	if !strings.Contains(err.Error(), "no such network interface") {
		return err
	}

	// create *netlink.Bridge object
	la := netlink.NewLinkAttrs()
	la.Name = bridgeName
	la.MTU = n.MTU
	br := &netlink.Bridge{la}
	if err := netlink.LinkAdd(br); err != nil {
		return fmt.Errorf("Bridge creation failed for bridge %s: %v", bridgeName, err)
	}

	// Set bridge IP
	gatewayIP := n.Gateway + "/" + n.GatewayMask
	if err := setInterfaceIP(bridgeName, gatewayIP); err != nil {
		return fmt.Errorf("Error assigning address: %s on bridge: %s with an error of: %v", gatewayIP, bridgeName, err)
	}

	// Validate that the IPAddress is there!
	_, err = getIfaceAddr(bridgeName)
	if err != nil {
		return fmt.Errorf("No IP address found on bridge %s: %v", bridgeName, err)
	}

	// Bring the bridge up
	if err := interfaceUp(bridgeName); err != nil {
		return fmt.Errorf("Error enabling bridge for %s: %v", bridgeName, err)
	}

	// Setup iptables
	if err := n.setupIPTables(torIP); err != nil {
		return fmt.Errorf("Error setting up iptables for %s: %v", bridgeName, err)
	}

	return nil
}

// deleteBridge deletes the bridge
func (n *NetworkState) deleteBridge(id string) error {
	bridgeName := n.BridgeName

	// get the link
	l, err := netlink.LinkByName(bridgeName)
	if err != nil {
		return fmt.Errorf("Getting link with name %s failed: %v", bridgeName, err)
	}

	// delete the link
	if err := netlink.LinkDel(l); err != nil {
		return fmt.Errorf("Failed to remove bridge interface %s delete: %v", bridgeName, err)
	}

	// delete all relevant iptables rules
	for _, cleanFunc := range n.iptCleanFuncs {
		if err := cleanFunc(); err != nil {
			logrus.Warnf("Failed to clean iptables rules for bridge %s: %v", bridgeName, err)
		}
	}

	// delete all the iptables chains
	if err := iptables.RemoveExistingChain(TorChain, iptables.Nat); err != nil {
		logrus.Warnf("Failed on removing iptables NAT chain on cleanup: %v", err)
	}
	if err := iptables.RemoveExistingChain(TorChain, iptables.Filter); err != nil {
		logrus.Warnf("Failed on removing iptables FILTER chain on cleanup: %v", err)
	}

	return nil
}
<|endoftext|>


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

package tls

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"math/big"
	"net"
	"os"
	"time"

	"github.com/fastly/go-utils/vlog"
)

// CertCreator generates client or server public/private RSA keypairs signed by
// a generated self-signed certificate authority (CA). It will reload the CA
// cert from disk if present, and will not overwrite a keypair if either the
// key or cert exists on disk, so a cert generation program can be safely
// re-run after adding new certs. All keys are granted the minimal set of
// extended key usages for their purpose.
//
// The default values described below are not for the zero value, but rather
// those returned by NewCertCreator().
//
// Example:
//
//	cc := tls.NewCertCreator()
//	root := cc.GenerateRootKeyPair("my-ca", "My CA")
//	host := "*.mydomain.com"
//	cc.GenerateKeyPair(CLIENT, root, "proxy-client", host, host)
//	cc.GenerateKeyPair(SERVER, root, "proxy-server", host, host)
type CertCreator struct {
	// Serial number, defaults to 1.
	Serial int64
	// Time period in which the cert if valid, defaults to the current time
	// until the maximum of 2049-12-13.
	NotBefore, NotAfter time.Time
	// Key size in bytes, defaults to 4096.
	KeySize int
	// Descriptive names for the organization creating the CA. Defaults to
	// empty.
	Country, State, City, Organization string
}

// NewCertCreator returns a CertCreator with default values.
func NewCertCreator() *CertCreator {
	return &CertCreator{
		Serial:    1,
		NotBefore: time.Now(),
		NotAfter:  time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC), // end of ASN.1 time
		KeySize:   4096,
	}
}

type Purpose int

const (
	// CA certs are used only for signing other certs.
	CA Purpose = iota
	// CLIENT certs are presented by clients which initiate TLS connections.
	CLIENT
	// SERVER certs are presented by servers which accept TLS connections.
	SERVER
)

type KeyPair struct {
	Cert    *x509.Certificate
	PrivKey *rsa.PrivateKey
}

// GenerateRootKeyPair creates or reloads a self-signed CA cert.
func (cc *CertCreator) GenerateRootKeyPair(name string, commonName string, hosts ...string) (*KeyPair, error) {
	return cc.GenerateKeyPair(CA, nil, name, commonName, hosts...)
}

// GenerateKeyPair generates or reloads an RSA keypair with key usages
// determined by `purpose`. The disk files that are generated or reused are
// named `name`-key.pem and `name`-cert.pem for the private and public halves,
// respectively. `commonName` and `hosts` are the corresponding fields in the
// certificate.
//
// cc.Serial is incremented for each key that is freshly generated.
func (cc *CertCreator) GenerateKeyPair(purpose Purpose, parent *KeyPair, name string, commonName string, hosts ...string) (*KeyPair, error) {
	if pair, err := LoadKeyPairFromDisk(name); err == nil {
		return pair, nil
	}

	keyFile, certFile := name+"-key.pem", name+"-cert.pem"
	if _, err := os.Open(keyFile); !os.IsNotExist(err) {
		return nil, fmt.Errorf("Key file %q already exists", keyFile)
	}
	if _, err := os.Open(certFile); !os.IsNotExist(err) {
		return nil, fmt.Errorf("Cert file %q already exists", keyFile)
	}

	var extUsages []x509.ExtKeyUsage
	if purpose == CA {
		extUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
	} else if purpose == SERVER {
		extUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
	} else {
		extUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
	}

	serial := new(big.Int).SetInt64(cc.Serial)
	cc.Serial++
	template := x509.Certificate{
		Subject: pkix.Name{
			Country:      []string{cc.Country},
			Province:     []string{cc.State},
			Locality:     []string{cc.City},
			Organization: []string{cc.Organization},
			CommonName:   commonName,
			SerialNumber: serial.String(),
		},

		NotBefore:    cc.NotBefore,
		NotAfter:     cc.NotAfter,
		SerialNumber: serial,

		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           extUsages,
		BasicConstraintsValid: true, // enforces IsCA and KeyUsage
	}
	if purpose == CA {
		template.IsCA = true
		template.KeyUsage = x509.KeyUsageCertSign
	} else {
		template.MaxPathLen = 1
	}

	// generate IP and DNS SANs
	for _, h := range hosts {
		if ip := net.ParseIP(h); ip != nil {
			template.IPAddresses = append(template.IPAddresses, ip)
		} else {
			template.DNSNames = append(template.DNSNames, h)
		}
	}

	if parent == nil {
		privkey, err := rsa.GenerateKey(rand.Reader, cc.KeySize)
		if err != nil {
			return nil, fmt.Errorf("Failed to generate private key: %s", err)
		}
		parent = &KeyPair{&template, privkey}
	}

	// sign the key
	derBytes, err := x509.CreateCertificate(rand.Reader, &template, parent.Cert, &parent.PrivKey.PublicKey, parent.PrivKey)
	if err != nil {
		return nil, err
	}

	// check that the cert verifies against its own CA
	cert, err := x509.ParseCertificate(derBytes)
	if err != nil {
		return nil, fmt.Errorf("Cert doesn't veryfiy against its CA: %s", err)
	}

	roots := x509.NewCertPool()
	if purpose == CA {
		roots.AddCert(cert)
	} else {
		roots.AddCert(parent.Cert)
	}
	_, err = cert.Verify(x509.VerifyOptions{Roots: roots, KeyUsages: extUsages})
	if err != nil {
		return nil, fmt.Errorf("Couldn't verify %q against its own CA: %s", name, err)
	}

	// write key and cert to disk
	keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return nil, fmt.Errorf("Failed to open %q for writing: %s", keyFile, err)
	}
	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(parent.PrivKey)})
	keyOut.Close()
	vlog.VLogf("Wrote key %q\n", keyFile)

	certOut, err := os.Create(certFile)
	if err != nil {
		return nil, fmt.Errorf("Failed to open %q for writing: %s", certFile, err)
	}
	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()
	vlog.VLogf("Wrote cert %q\n", certFile)

	return LoadKeyPairFromDisk(name)
}

// LoadKeyPairFromDisk returns a KeyPair from disk files based on the given
// name.
func LoadKeyPairFromDisk(name string) (*KeyPair, error) {
	// cert
	certFile := name + "-cert.pem"
	b, err := ioutil.ReadFile(certFile)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(b)
	if block == nil {
		return nil, fmt.Errorf("No PEM data found in %q", certFile)
	}

	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, err
	}

	vlog.VLogf("Loaded cert from %s", certFile)

	// private key
	keyFile := name + "-key.pem"
	b, err = ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, err
	}

	block, _ = pem.Decode(b)
	if block == nil {
		return nil, fmt.Errorf("No PEM data found in %q", keyFile)
	}

	key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	vlog.VLogf("Loaded key from %s", keyFile)

	return &KeyPair{cert, key}, nil
}
<commit_msg>Fix error message typos<commit_after>// Portions Copyright 2009 The Go Authors. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in the
// LICENSE file.
//
// Portions Copyright 2014 Fastly, Inc.

package tls

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"math/big"
	"net"
	"os"
	"time"

	"github.com/fastly/go-utils/vlog"
)

// CertCreator generates client or server public/private RSA keypairs signed by
// a generated self-signed certificate authority (CA). It will reload the CA
// cert from disk if present, and will not overwrite a keypair if either the
// key or cert exists on disk, so a cert generation program can be safely
// re-run after adding new certs. All keys are granted the minimal set of
// extended key usages for their purpose.
//
// The default values described below are not for the zero value, but rather
// those returned by NewCertCreator().
//
// Example:
//
//	cc := tls.NewCertCreator()
//	root := cc.GenerateRootKeyPair("my-ca", "My CA")
//	host := "*.mydomain.com"
//	cc.GenerateKeyPair(CLIENT, root, "proxy-client", host, host)
//	cc.GenerateKeyPair(SERVER, root, "proxy-server", host, host)
type CertCreator struct {
	// Serial number, defaults to 1.
	Serial int64
	// Time period in which the cert if valid, defaults to the current time
	// until the maximum of 2049-12-13.
	NotBefore, NotAfter time.Time
	// Key size in bytes, defaults to 4096.
	KeySize int
	// Descriptive names for the organization creating the CA. Defaults to
	// empty.
	Country, State, City, Organization string
}

// NewCertCreator returns a CertCreator with default values.
func NewCertCreator() *CertCreator {
	return &CertCreator{
		Serial:    1,
		NotBefore: time.Now(),
		NotAfter:  time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC), // end of ASN.1 time
		KeySize:   4096,
	}
}

type Purpose int

const (
	// CA certs are used only for signing other certs.
	CA Purpose = iota
	// CLIENT certs are presented by clients which initiate TLS connections.
	CLIENT
	// SERVER certs are presented by servers which accept TLS connections.
	SERVER
)

type KeyPair struct {
	Cert    *x509.Certificate
	PrivKey *rsa.PrivateKey
}

// GenerateRootKeyPair creates or reloads a self-signed CA cert.
func (cc *CertCreator) GenerateRootKeyPair(name string, commonName string, hosts ...string) (*KeyPair, error) {
	return cc.GenerateKeyPair(CA, nil, name, commonName, hosts...)
}

// GenerateKeyPair generates or reloads an RSA keypair with key usages
// determined by `purpose`. The disk files that are generated or reused are
// named `name`-key.pem and `name`-cert.pem for the private and public halves,
// respectively. `commonName` and `hosts` are the corresponding fields in the
// certificate.
//
// cc.Serial is incremented for each key that is freshly generated.
func (cc *CertCreator) GenerateKeyPair(purpose Purpose, parent *KeyPair, name string, commonName string, hosts ...string) (*KeyPair, error) {
	if pair, err := LoadKeyPairFromDisk(name); err == nil {
		return pair, nil
	}

	keyFile, certFile := name+"-key.pem", name+"-cert.pem"
	if _, err := os.Open(keyFile); !os.IsNotExist(err) {
		return nil, fmt.Errorf("Key file %q already exists", keyFile)
	}
	if _, err := os.Open(certFile); !os.IsNotExist(err) {
		return nil, fmt.Errorf("Cert file %q already exists", certFile)
	}

	var extUsages []x509.ExtKeyUsage
	if purpose == CA {
		extUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
	} else if purpose == SERVER {
		extUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
	} else {
		extUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}
	}

	serial := new(big.Int).SetInt64(cc.Serial)
	cc.Serial++
	template := x509.Certificate{
		Subject: pkix.Name{
			Country:      []string{cc.Country},
			Province:     []string{cc.State},
			Locality:     []string{cc.City},
			Organization: []string{cc.Organization},
			CommonName:   commonName,
			SerialNumber: serial.String(),
		},

		NotBefore:    cc.NotBefore,
		NotAfter:     cc.NotAfter,
		SerialNumber: serial,

		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           extUsages,
		BasicConstraintsValid: true, // enforces IsCA and KeyUsage
	}
	if purpose == CA {
		template.IsCA = true
		template.KeyUsage = x509.KeyUsageCertSign
	} else {
		template.MaxPathLen = 1
	}

	// generate IP and DNS SANs
	for _, h := range hosts {
		if ip := net.ParseIP(h); ip != nil {
			template.IPAddresses = append(template.IPAddresses, ip)
		} else {
			template.DNSNames = append(template.DNSNames, h)
		}
	}

	if parent == nil {
		privkey, err := rsa.GenerateKey(rand.Reader, cc.KeySize)
		if err != nil {
			return nil, fmt.Errorf("Failed to generate private key: %s", err)
		}
		parent = &KeyPair{&template, privkey}
	}

	// sign the key
	derBytes, err := x509.CreateCertificate(rand.Reader, &template, parent.Cert, &parent.PrivKey.PublicKey, parent.PrivKey)
	if err != nil {
		return nil, err
	}

	// check that the cert verifies against its own CA
	cert, err := x509.ParseCertificate(derBytes)
	if err != nil {
		return nil, fmt.Errorf("Cert doesn't verify against its CA: %s", err)
	}

	roots := x509.NewCertPool()
	if purpose == CA {
		roots.AddCert(cert)
	} else {
		roots.AddCert(parent.Cert)
	}
	_, err = cert.Verify(x509.VerifyOptions{Roots: roots, KeyUsages: extUsages})
	if err != nil {
		return nil, fmt.Errorf("Couldn't verify %q against its own CA: %s", name, err)
	}

	// write key and cert to disk
	keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return nil, fmt.Errorf("Failed to open %q for writing: %s", keyFile, err)
	}
	pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(parent.PrivKey)})
	keyOut.Close()
	vlog.VLogf("Wrote key %q\n", keyFile)

	certOut, err := os.Create(certFile)
	if err != nil {
		return nil, fmt.Errorf("Failed to open %q for writing: %s", certFile, err)
	}
	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()
	vlog.VLogf("Wrote cert %q\n", certFile)

	return LoadKeyPairFromDisk(name)
}

// LoadKeyPairFromDisk returns a KeyPair from disk files based on the given
// name.
func LoadKeyPairFromDisk(name string) (*KeyPair, error) {
	// cert
	certFile := name + "-cert.pem"
	b, err := ioutil.ReadFile(certFile)
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(b)
	if block == nil {
		return nil, fmt.Errorf("No PEM data found in %q", certFile)
	}

	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return nil, err
	}

	vlog.VLogf("Loaded cert from %s", certFile)

	// private key
	keyFile := name + "-key.pem"
	b, err = ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, err
	}

	block, _ = pem.Decode(b)
	if block == nil {
		return nil, fmt.Errorf("No PEM data found in %q", keyFile)
	}

	key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	vlog.VLogf("Loaded key from %s", keyFile)

	return &KeyPair{cert, key}, nil
}
<|endoftext|>


<commit_before>package tlsconfig

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"sort"
	"strings"
)

// Create creates a new tls.Config object from the given certs, key, and CA files.
func Create(
	SSLCA, SSLCert, SSLKey string,
	InsecureSkipVerify bool,
) (*tls.Config, error) {
	t := &tls.Config{
		InsecureSkipVerify: InsecureSkipVerify,
	}
	if SSLCert != "" && SSLKey != "" {
		cert, err := tls.LoadX509KeyPair(SSLCert, SSLKey)
		if err != nil {
			return nil, fmt.Errorf(
				"Could not load TLS client key/certificate: %s",
				err)
		}
		t.Certificates = []tls.Certificate{cert}
	} else if SSLCert != "" {
		return nil, errors.New("Must provide both key and cert files: only cert file provided.")
	} else if SSLKey != "" {
		return nil, errors.New("Must provide both key and cert files: only key file provided.")
	}

	if SSLCA != "" {
		caCert, err := ioutil.ReadFile(SSLCA)
		if err != nil {
			return nil, fmt.Errorf("Could not load TLS CA: %s",
				err)
		}
		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)
		t.RootCAs = caCertPool
	}
	return t, nil
}

type Config struct {
	Ciphers    []string `toml:"ciphers"`
	MinVersion string   `toml:"min-version"`
	MaxVersion string   `toml:"max-version"`
}

func NewConfig() Config {
	return Config{}
}

func (c Config) Validate() error {
	_, err := c.Parse()
	return err
}

func (c Config) Parse() (out *tls.Config, err error) {
	if len(c.Ciphers) > 0 {
		if out == nil {
			out = new(tls.Config)
		}

		for _, name := range c.Ciphers {
			cipher, ok := ciphersMap[strings.ToUpper(name)]
			if !ok {
				return nil, unknownCipher(name)
			}
			out.CipherSuites = append(out.CipherSuites, cipher)
		}
	}

	if c.MinVersion != "" {
		if out == nil {
			out = new(tls.Config)
		}

		version, ok := versionsMap[strings.ToUpper(c.MinVersion)]
		if !ok {
			return nil, unknownVersion(c.MinVersion)
		}
		out.MinVersion = version
	}

	if c.MaxVersion != "" {
		if out == nil {
			out = new(tls.Config)
		}

		version, ok := versionsMap[strings.ToUpper(c.MaxVersion)]
		if !ok {
			return nil, unknownVersion(c.MaxVersion)
		}
		out.MaxVersion = version
	}

	return out, nil
}

var ciphersMap = map[string]uint16{
	"TLS_RSA_WITH_RC4_128_SHA":                tls.TLS_RSA_WITH_RC4_128_SHA,
	"TLS_RSA_WITH_3DES_EDE_CBC_SHA":           tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
	"TLS_RSA_WITH_AES_128_CBC_SHA":            tls.TLS_RSA_WITH_AES_128_CBC_SHA,
	"TLS_RSA_WITH_AES_256_CBC_SHA":            tls.TLS_RSA_WITH_AES_256_CBC_SHA,
	"TLS_RSA_WITH_AES_128_CBC_SHA256":         tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
	"TLS_RSA_WITH_AES_128_GCM_SHA256":         tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
	"TLS_RSA_WITH_AES_256_GCM_SHA384":         tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":        tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_RC4_128_SHA":          tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA":     tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":      tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":      tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
	"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256":   tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
	"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":   tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
	"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
	"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":   tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305":    tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
	"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305":  tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,

	// TLS1.3 cypher suites
	"TLS_AES_128_GCM_SHA256":       tls.TLS_AES_128_GCM_SHA256,
	"TLS_AES_256_GCM_SHA384":       tls.TLS_AES_256_GCM_SHA384,
	"TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256,
}

func unknownCipher(name string) error {
	available := make([]string, 0, len(ciphersMap))
	for name := range ciphersMap {
		available = append(available, name)
	}
	sort.Strings(available)

	return fmt.Errorf("unknown cipher suite: %q. available ciphers: %s",
		name, strings.Join(available, ", "))
}

var versionsMap = map[string]uint16{
	"SSL3.0": tls.VersionSSL30,
	"TLS1.0": tls.VersionTLS10,
	"1.0":    tls.VersionTLS10,
	"TLS1.1": tls.VersionTLS11,
	"1.1":    tls.VersionTLS11,
	"TLS1.2": tls.VersionTLS12,
	"1.2":    tls.VersionTLS12,
	"TLS1.3": tls.VersionTLS13,
	"1.3":    tls.VersionTLS13,
}

func unknownVersion(name string) error {
	available := make([]string, 0, len(versionsMap))
	for name := range versionsMap {
		// skip the ones that just begin with a number. they may be confusing
		// due to the duplication, and just help if the user specifies without
		// the TLS part.
		if name[0] == '1' {
			continue
		}
		available = append(available, name)
	}
	sort.Strings(available)

	return fmt.Errorf("unknown tls version: %q. available versions: %s",
		name, strings.Join(available, ", "))
}
<commit_msg>fix(tls): deprecations in response to sweet32 (#2644)<commit_after>package tlsconfig

import (
	"crypto/tls"
	"crypto/x509"
	"errors"
	"fmt"
	"io/ioutil"
	"sort"
	"strings"
)

// Create creates a new tls.Config object from the given certs, key, and CA files.
func Create(
	SSLCA, SSLCert, SSLKey string,
	InsecureSkipVerify bool,
) (*tls.Config, error) {
	t := &tls.Config{
		InsecureSkipVerify: InsecureSkipVerify,
	}
	if SSLCert != "" && SSLKey != "" {
		cert, err := tls.LoadX509KeyPair(SSLCert, SSLKey)
		if err != nil {
			return nil, fmt.Errorf(
				"Could not load TLS client key/certificate: %s",
				err)
		}
		t.Certificates = []tls.Certificate{cert}
	} else if SSLCert != "" {
		return nil, errors.New("Must provide both key and cert files: only cert file provided.")
	} else if SSLKey != "" {
		return nil, errors.New("Must provide both key and cert files: only key file provided.")
	}

	if SSLCA != "" {
		caCert, err := ioutil.ReadFile(SSLCA)
		if err != nil {
			return nil, fmt.Errorf("Could not load TLS CA: %s",
				err)
		}
		caCertPool := x509.NewCertPool()
		caCertPool.AppendCertsFromPEM(caCert)
		t.RootCAs = caCertPool
	}
	return t, nil
}

type Config struct {
	Ciphers    []string `toml:"ciphers"`
	MinVersion string   `toml:"min-version"`
	MaxVersion string   `toml:"max-version"`
}

func NewConfig() Config {
	return Config{}
}

func (c Config) Validate() error {
	_, err := c.Parse()
	return err
}

func (c Config) Parse() (out *tls.Config, err error) {
	if len(c.Ciphers) > 0 {
		if out == nil {
			out = new(tls.Config)
		}

		for _, name := range c.Ciphers {
			strUpperName := strings.ToUpper(name)
			cipher, ok := ciphers[strUpperName]
			if !ok {
				return nil, badCipher(name)
			}
			out.CipherSuites = append(out.CipherSuites, cipher)
		}
	}

	if c.MinVersion != "" {
		if out == nil {
			out = new(tls.Config)
		}

		version, ok := versionsMap[strings.ToUpper(c.MinVersion)]
		if !ok {
			return nil, badVersion(c.MinVersion)
		}
		out.MinVersion = version
	}

	if c.MaxVersion != "" {
		if out == nil {
			out = new(tls.Config)
		}

		version, ok := versionsMap[strings.ToUpper(c.MaxVersion)]
		if !ok {
			return nil, badVersion(c.MaxVersion)
		}
		out.MaxVersion = version
	}

	return out, nil
}

var ciphers = map[string]uint16{
	"TLS_RSA_WITH_RC4_128_SHA":                tls.TLS_RSA_WITH_RC4_128_SHA,
	"TLS_RSA_WITH_AES_128_CBC_SHA":            tls.TLS_RSA_WITH_AES_128_CBC_SHA,
	"TLS_RSA_WITH_AES_256_CBC_SHA":            tls.TLS_RSA_WITH_AES_256_CBC_SHA,
	"TLS_RSA_WITH_AES_128_CBC_SHA256":         tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
	"TLS_RSA_WITH_AES_128_GCM_SHA256":         tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
	"TLS_RSA_WITH_AES_256_GCM_SHA384":         tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA":        tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA":    tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_RC4_128_SHA":          tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
	"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA":      tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA":      tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
	"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256":   tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
	"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256":   tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
	"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
	"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384":   tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
	"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305":    tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
	"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305":  tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,

	// TLS1.3 cypher suites
	"TLS_AES_128_GCM_SHA256":       tls.TLS_AES_128_GCM_SHA256,
	"TLS_AES_256_GCM_SHA384":       tls.TLS_AES_256_GCM_SHA384,
	"TLS_CHACHA20_POLY1305_SHA256": tls.TLS_CHACHA20_POLY1305_SHA256,
}

var availableCiphers = func() string {
	available := make([]string, 0, len(versionsMap))
	for name := range ciphers {
		if name[0] == '1' {
			continue
		}
		available = append(available, name)
	}
	sort.Strings(available)
	return strings.Join(available, ", ")
}()

// we do not use these because they are insecure
var deprecatedCiphers = map[string]struct{}{
	"TLS_RSA_WITH_3DES_EDE_CBC_SHA":       struct{}{}, // broken by sweet32 https://sweet32.info/
	"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": struct{}{}, // broken by sweet32 https://sweet32.info/
}

func badCipher(name string) error {
	if _, ok := deprecatedCiphers[name]; ok {
		return fmt.Errorf("deprecated cipher suite: %q. available versions: %s", name, availableCiphers)
	}
	return fmt.Errorf("unknown cipher suite: %q. available ciphers: %s", name, availableCiphers)
}

var versionsMap = map[string]uint16{
	"TLS1.1": tls.VersionTLS11,
	"1.1":    tls.VersionTLS11,
	"TLS1.2": tls.VersionTLS12,
	"1.2":    tls.VersionTLS12,
	"TLS1.3": tls.VersionTLS13,
	"1.3":    tls.VersionTLS13,
}

var availableVersions = func() string {
	available := make([]string, 0, len(versionsMap))
	for name := range versionsMap {
		// skip the ones that just begin with a number. they may be confusing
		// due to the duplication, and just help if the user specifies without
		// the TLS part.
		if name[0] == '1' {
			continue
		}
		available = append(available, name)
	}
	sort.Strings(available)
	return strings.Join(available, ", ")
}()

var deprecatedVersions = map[string]struct{}{
	"SSL3.0": struct{}{},
	"TLS1.0": struct{}{},
	"1.0":    struct{}{},
}

func badVersion(name string) error {
	if _, ok := deprecatedVersions[name]; ok {
		return fmt.Errorf("deprecated tls version: %q. available versions: %s", name, availableVersions)
	}
	return fmt.Errorf("unknown tls version: %q. available versions: %s", name, availableVersions)
}
<|endoftext|>


<commit_before>package token_test

import (
	"testing"

	"github.com/goccy/go-yaml/token"
)

func TestToken(t *testing.T) {
	pos := &token.Position{}
	tokens := token.Tokens{
		token.SequenceEntry("-", pos),
		token.MappingKey(pos),
		token.MappingValue(pos),
		token.CollectEntry(",", pos),
		token.SequenceStart("[", pos),
		token.SequenceEnd("]", pos),
		token.MappingStart("{", pos),
		token.MappingEnd("}", pos),
		token.Comment("#", "#", pos),
		token.Anchor("&", pos),
		token.Alias("*", pos),
		token.Literal("|", "|", pos),
		token.Folded(">", ">", pos),
		token.SingleQuote("'", "'", pos),
		token.DoubleQuote(`"`, `"`, pos),
		token.Directive(pos),
		token.Space(pos),
		token.MergeKey("<<", pos),
		token.DocumentHeader(pos),
		token.DocumentEnd(pos),
		token.New("1", "1", pos),
		token.New("3.14", "3.14", pos),
		token.New("-0b101010", "-0b101010", pos),
		token.New("0xA", "0xA", pos),
		token.New("685.230_15e+03", "685.230_15e+03", pos),
		token.New("02472256", "02472256", pos),
		token.New("0o2472256", "0o2472256", pos),
		token.New("", "", pos),
		token.New("_1", "_1", pos),
		token.New("1.1.1.1", "1.1.1.1", pos),
		token.New("+", "+", pos),
		token.New("-", "-", pos),
		token.New("_", "_", pos),
		token.New("true", "true", pos),
		token.New("false", "false", pos),
		token.New(".nan", ".nan", pos),
		token.New(".inf", ".inf", pos),
		token.New("-.inf", "-.inf", pos),
		token.New("null", "null", pos),
		token.Tag("!!null", "!!null", pos),
		token.Tag("!!map", "!!map", pos),
		token.Tag("!!str", "!!str", pos),
		token.Tag("!!seq", "!!seq", pos),
		token.Tag("!!binary", "!!binary", pos),
		token.Tag("!!omap", "!!omap", pos),
		token.Tag("!!set", "!!set", pos),
		token.Tag("!!int", "!!int", pos),
		token.Tag("!!float", "!!float", pos),
		token.Tag("!hoge", "!hoge", pos),
	}
	tokens.Dump()
	tokens.Add(token.New("hoge", "hoge", pos))
	if tokens[len(tokens)-1].PreviousType() != token.TagType {
		t.Fatal("invalid previous token type")
	}
	if tokens[0].PreviousType() != token.UnknownType {
		t.Fatal("invalid previous token type")
	}
	if tokens[len(tokens)-2].NextType() != token.StringType {
		t.Fatal("invalid next token type")
	}
	if tokens[len(tokens)-1].NextType() != token.UnknownType {
		t.Fatal("invalid next token type")
	}
}

func TestIsNeedQuoted(t *testing.T) {
	if !token.IsNeedQuoted("") {
		t.Fatal("failed to quoted judge for empty string")
	}
	if !token.IsNeedQuoted("true") {
		t.Fatal("failed to quoted judge for boolean")
	}
	if !token.IsNeedQuoted("1.234") {
		t.Fatal("failed to quoted judge for number")
	}
	if !token.IsNeedQuoted("1:1") {
		t.Fatal("failed to quoted judge for time")
	}
	if !token.IsNeedQuoted("hoge # comment") {
		t.Fatal("failed to quoted judge for comment")
	}
	if !token.IsNeedQuoted("\\0") {
		t.Fatal("failed to quoted judge for escaped token")
	}
	if token.IsNeedQuoted("Hello World") {
		t.Fatal("failed to unquoted judge")
	}
}
<commit_msg>Add test case for token package<commit_after>package token_test

import (
	"testing"

	"github.com/goccy/go-yaml/token"
)

func TestToken(t *testing.T) {
	pos := &token.Position{}
	tokens := token.Tokens{
		token.SequenceEntry("-", pos),
		token.MappingKey(pos),
		token.MappingValue(pos),
		token.CollectEntry(",", pos),
		token.SequenceStart("[", pos),
		token.SequenceEnd("]", pos),
		token.MappingStart("{", pos),
		token.MappingEnd("}", pos),
		token.Comment("#", "#", pos),
		token.Anchor("&", pos),
		token.Alias("*", pos),
		token.Literal("|", "|", pos),
		token.Folded(">", ">", pos),
		token.SingleQuote("'", "'", pos),
		token.DoubleQuote(`"`, `"`, pos),
		token.Directive(pos),
		token.Space(pos),
		token.MergeKey("<<", pos),
		token.DocumentHeader(pos),
		token.DocumentEnd(pos),
		token.New("1", "1", pos),
		token.New("3.14", "3.14", pos),
		token.New("-0b101010", "-0b101010", pos),
		token.New("0xA", "0xA", pos),
		token.New("685.230_15e+03", "685.230_15e+03", pos),
		token.New("02472256", "02472256", pos),
		token.New("0o2472256", "0o2472256", pos),
		token.New("", "", pos),
		token.New("_1", "_1", pos),
		token.New("1.1.1.1", "1.1.1.1", pos),
		token.New("+", "+", pos),
		token.New("-", "-", pos),
		token.New("_", "_", pos),
		token.New("~", "~", pos),
		token.New("true", "true", pos),
		token.New("false", "false", pos),
		token.New(".nan", ".nan", pos),
		token.New(".inf", ".inf", pos),
		token.New("-.inf", "-.inf", pos),
		token.New("null", "null", pos),
		token.Tag("!!null", "!!null", pos),
		token.Tag("!!map", "!!map", pos),
		token.Tag("!!str", "!!str", pos),
		token.Tag("!!seq", "!!seq", pos),
		token.Tag("!!binary", "!!binary", pos),
		token.Tag("!!omap", "!!omap", pos),
		token.Tag("!!set", "!!set", pos),
		token.Tag("!!int", "!!int", pos),
		token.Tag("!!float", "!!float", pos),
		token.Tag("!hoge", "!hoge", pos),
	}
	tokens.Dump()
	tokens.Add(token.New("hoge", "hoge", pos))
	if tokens[len(tokens)-1].PreviousType() != token.TagType {
		t.Fatal("invalid previous token type")
	}
	if tokens[0].PreviousType() != token.UnknownType {
		t.Fatal("invalid previous token type")
	}
	if tokens[len(tokens)-2].NextType() != token.StringType {
		t.Fatal("invalid next token type")
	}
	if tokens[len(tokens)-1].NextType() != token.UnknownType {
		t.Fatal("invalid next token type")
	}
}

func TestIsNeedQuoted(t *testing.T) {
	if !token.IsNeedQuoted("") {
		t.Fatal("failed to quoted judge for empty string")
	}
	if !token.IsNeedQuoted("true") {
		t.Fatal("failed to quoted judge for boolean")
	}
	if !token.IsNeedQuoted("1.234") {
		t.Fatal("failed to quoted judge for number")
	}
	if !token.IsNeedQuoted("1:1") {
		t.Fatal("failed to quoted judge for time")
	}
	if !token.IsNeedQuoted("hoge # comment") {
		t.Fatal("failed to quoted judge for comment")
	}
	if !token.IsNeedQuoted("\\0") {
		t.Fatal("failed to quoted judge for escaped token")
	}
	if token.IsNeedQuoted("Hello World") {
		t.Fatal("failed to unquoted judge")
	}
}
<|endoftext|>