<commit_before>package ls

import "fmt"
import "io"
import "os"
import "path/filepath"
import "regexp"
import "sort"
import "strings"
import "time"

import "../box"
import "../dos"
import "../exename"

const (
	O_STRIP_DIR = 1
	O_LONG      = 2
	O_INDICATOR = 4
	O_COLOR     = 8
	O_ALL       = 16
	O_TIME      = 32
	O_REVERSE   = 64
	O_RECURSIVE = 128
)

type fileInfoT struct {
	name string
	info os.FileInfo
}

const (
	ANSI_EXEC     = "\x1B[1;35m"
	ANSI_DIR      = "\x1B[1;32m"
	ANSI_NORM     = "\x1B[1;37m"
	ANSI_READONLY = "\x1B[1;33m"
	ANSI_END      = "\x1B[39m"
)

func (this fileInfoT) Name() string       { return this.name }
func (this fileInfoT) Size() int64        { return this.info.Size() }
func (this fileInfoT) Mode() os.FileMode  { return this.info.Mode() }
func (this fileInfoT) ModTime() time.Time { return this.info.ModTime() }
func (this fileInfoT) IsDir() bool        { return this.info.IsDir() }
func (this fileInfoT) Sys() interface{}   { return this.info.Sys() }

func newMyFileInfoT(name string, info os.FileInfo) *fileInfoT {
	return &fileInfoT{
		name: name,
		info: info,
	}
}

func lsOneLong(status os.FileInfo, flag int, out io.Writer) {
	indicator := " "
	prefix := ""
	postfix := ""
	if status.IsDir() {
		io.WriteString(out, "d")
		indicator = "/"
		if (flag & O_COLOR) != 0 {
			prefix = ANSI_DIR
			postfix = ANSI_END
		}
	} else {
		io.WriteString(out, "-")
	}
	mode := status.Mode()
	perm := mode.Perm()
	name := status.Name()
	if (perm & 4) > 0 {
		io.WriteString(out, "r")
	} else {
		io.WriteString(out, "-")
	}
	if (perm & 2) > 0 {
		io.WriteString(out, "w")
	} else {
		if (flag & O_COLOR) != 0 {
			prefix = ANSI_READONLY
			postfix = ANSI_END
		}
		io.WriteString(out, "-")
	}
	if (perm & 1) > 0 {
		io.WriteString(out, "x")
	} else if exename.Suffixes[strings.ToLower(filepath.Ext(name))] {
		io.WriteString(out, "x")
		indicator = "*"
		if (flag & O_COLOR) != 0 {
			prefix = ANSI_EXEC
			postfix = ANSI_END
		}
	} else {
		io.WriteString(out, "-")
	}
	if (flag & O_STRIP_DIR) > 0 {
		name = filepath.Base(name)
	}
	stamp := status.ModTime()
	fmt.Fprintf(out, " %8d %04d-%02d-%02d %02d:%02d %s%s%s",
		status.Size(),
		stamp.Year(),
		stamp.Month(),
		stamp.Day(),
		stamp.Hour(),
		stamp.Minute(),
		prefix,
		name,
		postfix)
	if (flag & O_INDICATOR) > 0 {
		io.WriteString(out, indicator)
	}
	io.WriteString(out, "\n")
}

func lsBox(nodes []os.FileInfo, flag int, out io.Writer) {
	nodes_ := make([]string, len(nodes))
	for key, val := range nodes {
		prefix := ""
		postfix := ""
		if val.IsDir() {
			if (flag & O_COLOR) != 0 {
				prefix = ANSI_DIR
				postfix = ANSI_END
			}
			if (flag & O_INDICATOR) != 0 {
				postfix += "/"
			}
		} else if (val.Mode().Perm() & 2) == 0 {
			if (flag & O_COLOR) != 0 {
				prefix = ANSI_READONLY
				postfix = ANSI_END
			}
		} else if exename.Suffixes[strings.ToLower(filepath.Ext(val.Name()))] {
			if (flag & O_COLOR) != 0 {
				prefix = ANSI_EXEC
				postfix = ANSI_END
			}
			if (flag & O_INDICATOR) != 0 {
				postfix += "*"
			}
		}
		nodes_[key] = prefix + val.Name() + postfix
	}
	box.Print(nodes_, 80, out)
}

func lsLong(nodes []os.FileInfo, flag int, out io.Writer) {
	for _, finfo := range nodes {
		lsOneLong(finfo, flag, out)
	}
}

type fileInfoCollection struct {
	flag  int
	nodes []os.FileInfo
}

func (this fileInfoCollection) Len() int {
	return len(this.nodes)
}
func (this fileInfoCollection) Less(i, j int) bool {
	var result bool
	if (this.flag & O_TIME) != 0 {
		result = this.nodes[i].ModTime().After(this.nodes[j].ModTime())
		if !result && !this.nodes[i].ModTime().Before(this.nodes[j].ModTime()) {
			result = (this.nodes[i].Name() < this.nodes[j].Name())
		}
	} else {
		result = (this.nodes[i].Name() < this.nodes[j].Name())
	}
	if (this.flag & O_REVERSE) != 0 {
		result = !result
	}
	return result
}
func (this fileInfoCollection) Swap(i, j int) {
	tmp := this.nodes[i]
	this.nodes[i] = this.nodes[j]
	this.nodes[j] = tmp
}

func lsFolder(folder string, flag int, out io.Writer) error {
	var folder_ string
	if rxDriveOnly.MatchString(folder) {
		folder_ = folder + "."
	} else {
		folder_ = folder
	}
	fd, err := os.Open(folder_)
	if err != nil {
		return err
	}
	var nodesArray fileInfoCollection
	nodesArray.nodes, err = fd.Readdir(-1)
	fd.Close()
	nodesArray.flag = flag
	if err != nil {
		return err
	}
	tmp := make([]os.FileInfo, 0)
	var folders []string = nil
	if (flag & O_RECURSIVE) != 0 {
		folders = make([]string, 0)
	}
	for _, f := range nodesArray.nodes {
		attr := dos.NewFileAttr(dos.Join(folder_, f.Name()))
		if (strings.HasPrefix(f.Name(), ".") || attr.IsHidden()) && (flag&O_ALL) == 0 {
			continue
		}
		if f.IsDir() && folders != nil {
			folders = append(folders, f.Name())
		} else {
			tmp = append(tmp, f)
		}
	}
	nodesArray.nodes = tmp
	sort.Sort(nodesArray)
	if (flag & O_LONG) > 0 {
		lsLong(nodesArray.nodes, O_STRIP_DIR|flag, out)
	} else {
		lsBox(nodesArray.nodes, O_STRIP_DIR|flag, out)
	}
	if folders != nil && len(folders) > 0 {
		for _, f1 := range folders {
			f1fullpath := dos.Join(folder, f1)
			fmt.Fprintf(out, "\n%s:\n", f1fullpath)
			lsFolder(f1fullpath, flag, out)
		}
	}
	return nil
}

var rxDriveOnly = regexp.MustCompile("^[a-zA-Z]:$")

func lsCore(paths []string, flag int, out io.Writer) error {
	if len(paths) <= 0 {
		return lsFolder(".", flag, out)
	}
	dirs := make([]string, 0)
	printCount := 0
	files := make([]os.FileInfo, 0)
	for _, name := range paths {
		var nameStat string
		if rxDriveOnly.MatchString(name) {
			nameStat = name + "."
		} else {
			nameStat = name
		}
		status, err := os.Stat(nameStat)
		if err != nil {
			continue
		} else if status.IsDir() {
			dirs = append(dirs, name)
		} else if (flag & O_LONG) != 0 {
			lsOneLong(newMyFileInfoT(name, status), flag, out)
			printCount += 1
		} else {
			files = append(files, newMyFileInfoT(name, status))
		}
	}
	if len(files) > 0 {
		lsBox(files, flag, out)
		printCount = len(files)
	}
	for _, name := range dirs {
		if len(paths) > 1 {
			if printCount > 0 {
				io.WriteString(out, "\n")
			}
			io.WriteString(out, name)
			io.WriteString(out, ":\n")
		}
		err := lsFolder(name, flag, out)
		if err != nil {
			return err
		}
		printCount++
	}
	return nil
}

var option = map[rune](func(*int) error){
	'l': func(flag *int) error {
		*flag |= O_LONG
		return nil
	},
	'F': func(flag *int) error {
		*flag |= O_INDICATOR
		return nil
	},
	'o': func(flag *int) error {
		*flag |= O_COLOR
		return nil
	},
	'a': func(flag *int) error {
		*flag |= O_ALL
		return nil
	},
	't': func(flag *int) error {
		*flag |= O_TIME
		return nil
	},
	'r': func(flag *int) error {
		*flag |= O_REVERSE
		return nil
	},
	'R': func(flag *int) error {
		*flag |= O_RECURSIVE
		return nil
	},
}

// 存在しないオプションに関するエラー
type OptionError struct {
	Option rune
}

func (this OptionError) Error() string {
	return fmt.Sprintf("-%c: No such option", this.Option)
}

// ls 機能のエントリ:引数をオプションとパスに分離する
func Main(args []string, out io.Writer) error {
	flag := 0
	paths := make([]string, 0)
	for _, arg := range args {
		if strings.HasPrefix(arg, "-") {
			for _, o := range arg[1:] {
				setter, ok := option[o]
				if !ok {
					var err OptionError
					err.Option = o
					return err
				}
				err := setter(&flag)
				if err != nil {
					return err
				}
			}
		} else {
			paths = append(paths, arg)
		}
	}
	return lsCore(paths, flag, out)
}

// vim:set fenc=utf8 ts=4 sw=4 noet:
<commit_msg>ls: use anonymous field.<commit_after>package ls

import "fmt"
import "io"
import "os"
import "path/filepath"
import "regexp"
import "sort"
import "strings"

import "../box"
import "../dos"
import "../exename"

const (
	O_STRIP_DIR = 1
	O_LONG      = 2
	O_INDICATOR = 4
	O_COLOR     = 8
	O_ALL       = 16
	O_TIME      = 32
	O_REVERSE   = 64
	O_RECURSIVE = 128
)

type fileInfoT struct {
	name        string
	os.FileInfo // anonymous
}

const (
	ANSI_EXEC     = "\x1B[1;35m"
	ANSI_DIR      = "\x1B[1;32m"
	ANSI_NORM     = "\x1B[1;37m"
	ANSI_READONLY = "\x1B[1;33m"
	ANSI_END      = "\x1B[39m"
)

func (this fileInfoT) Name() string { return this.name }

func newMyFileInfoT(name string, info os.FileInfo) *fileInfoT {
	return &fileInfoT{name, info}
}

func lsOneLong(status os.FileInfo, flag int, out io.Writer) {
	indicator := " "
	prefix := ""
	postfix := ""
	if status.IsDir() {
		io.WriteString(out, "d")
		indicator = "/"
		if (flag & O_COLOR) != 0 {
			prefix = ANSI_DIR
			postfix = ANSI_END
		}
	} else {
		io.WriteString(out, "-")
	}
	mode := status.Mode()
	perm := mode.Perm()
	name := status.Name()
	if (perm & 4) > 0 {
		io.WriteString(out, "r")
	} else {
		io.WriteString(out, "-")
	}
	if (perm & 2) > 0 {
		io.WriteString(out, "w")
	} else {
		if (flag & O_COLOR) != 0 {
			prefix = ANSI_READONLY
			postfix = ANSI_END
		}
		io.WriteString(out, "-")
	}
	if (perm & 1) > 0 {
		io.WriteString(out, "x")
	} else if exename.Suffixes[strings.ToLower(filepath.Ext(name))] {
		io.WriteString(out, "x")
		indicator = "*"
		if (flag & O_COLOR) != 0 {
			prefix = ANSI_EXEC
			postfix = ANSI_END
		}
	} else {
		io.WriteString(out, "-")
	}
	if (flag & O_STRIP_DIR) > 0 {
		name = filepath.Base(name)
	}
	stamp := status.ModTime()
	fmt.Fprintf(out, " %8d %04d-%02d-%02d %02d:%02d %s%s%s",
		status.Size(),
		stamp.Year(),
		stamp.Month(),
		stamp.Day(),
		stamp.Hour(),
		stamp.Minute(),
		prefix,
		name,
		postfix)
	if (flag & O_INDICATOR) > 0 {
		io.WriteString(out, indicator)
	}
	io.WriteString(out, "\n")
}

func lsBox(nodes []os.FileInfo, flag int, out io.Writer) {
	nodes_ := make([]string, len(nodes))
	for key, val := range nodes {
		prefix := ""
		postfix := ""
		if val.IsDir() {
			if (flag & O_COLOR) != 0 {
				prefix = ANSI_DIR
				postfix = ANSI_END
			}
			if (flag & O_INDICATOR) != 0 {
				postfix += "/"
			}
		} else if (val.Mode().Perm() & 2) == 0 {
			if (flag & O_COLOR) != 0 {
				prefix = ANSI_READONLY
				postfix = ANSI_END
			}
		} else if exename.Suffixes[strings.ToLower(filepath.Ext(val.Name()))] {
			if (flag & O_COLOR) != 0 {
				prefix = ANSI_EXEC
				postfix = ANSI_END
			}
			if (flag & O_INDICATOR) != 0 {
				postfix += "*"
			}
		}
		nodes_[key] = prefix + val.Name() + postfix
	}
	box.Print(nodes_, 80, out)
}

func lsLong(nodes []os.FileInfo, flag int, out io.Writer) {
	for _, finfo := range nodes {
		lsOneLong(finfo, flag, out)
	}
}

type fileInfoCollection struct {
	flag  int
	nodes []os.FileInfo
}

func (this fileInfoCollection) Len() int {
	return len(this.nodes)
}
func (this fileInfoCollection) Less(i, j int) bool {
	var result bool
	if (this.flag & O_TIME) != 0 {
		result = this.nodes[i].ModTime().After(this.nodes[j].ModTime())
		if !result && !this.nodes[i].ModTime().Before(this.nodes[j].ModTime()) {
			result = (this.nodes[i].Name() < this.nodes[j].Name())
		}
	} else {
		result = (this.nodes[i].Name() < this.nodes[j].Name())
	}
	if (this.flag & O_REVERSE) != 0 {
		result = !result
	}
	return result
}
func (this fileInfoCollection) Swap(i, j int) {
	tmp := this.nodes[i]
	this.nodes[i] = this.nodes[j]
	this.nodes[j] = tmp
}

func lsFolder(folder string, flag int, out io.Writer) error {
	var folder_ string
	if rxDriveOnly.MatchString(folder) {
		folder_ = folder + "."
	} else {
		folder_ = folder
	}
	fd, err := os.Open(folder_)
	if err != nil {
		return err
	}
	var nodesArray fileInfoCollection
	nodesArray.nodes, err = fd.Readdir(-1)
	fd.Close()
	nodesArray.flag = flag
	if err != nil {
		return err
	}
	tmp := make([]os.FileInfo, 0)
	var folders []string = nil
	if (flag & O_RECURSIVE) != 0 {
		folders = make([]string, 0)
	}
	for _, f := range nodesArray.nodes {
		attr := dos.NewFileAttr(dos.Join(folder_, f.Name()))
		if (strings.HasPrefix(f.Name(), ".") || attr.IsHidden()) && (flag&O_ALL) == 0 {
			continue
		}
		if f.IsDir() && folders != nil {
			folders = append(folders, f.Name())
		} else {
			tmp = append(tmp, f)
		}
	}
	nodesArray.nodes = tmp
	sort.Sort(nodesArray)
	if (flag & O_LONG) > 0 {
		lsLong(nodesArray.nodes, O_STRIP_DIR|flag, out)
	} else {
		lsBox(nodesArray.nodes, O_STRIP_DIR|flag, out)
	}
	if folders != nil && len(folders) > 0 {
		for _, f1 := range folders {
			f1fullpath := dos.Join(folder, f1)
			fmt.Fprintf(out, "\n%s:\n", f1fullpath)
			lsFolder(f1fullpath, flag, out)
		}
	}
	return nil
}

var rxDriveOnly = regexp.MustCompile("^[a-zA-Z]:$")

func lsCore(paths []string, flag int, out io.Writer) error {
	if len(paths) <= 0 {
		return lsFolder(".", flag, out)
	}
	dirs := make([]string, 0)
	printCount := 0
	files := make([]os.FileInfo, 0)
	for _, name := range paths {
		var nameStat string
		if rxDriveOnly.MatchString(name) {
			nameStat = name + "."
		} else {
			nameStat = name
		}
		status, err := os.Stat(nameStat)
		if err != nil {
			continue
		} else if status.IsDir() {
			dirs = append(dirs, name)
		} else if (flag & O_LONG) != 0 {
			lsOneLong(newMyFileInfoT(name, status), flag, out)
			printCount += 1
		} else {
			files = append(files, newMyFileInfoT(name, status))
		}
	}
	if len(files) > 0 {
		lsBox(files, flag, out)
		printCount = len(files)
	}
	for _, name := range dirs {
		if len(paths) > 1 {
			if printCount > 0 {
				io.WriteString(out, "\n")
			}
			io.WriteString(out, name)
			io.WriteString(out, ":\n")
		}
		err := lsFolder(name, flag, out)
		if err != nil {
			return err
		}
		printCount++
	}
	return nil
}

var option = map[rune](func(*int) error){
	'l': func(flag *int) error {
		*flag |= O_LONG
		return nil
	},
	'F': func(flag *int) error {
		*flag |= O_INDICATOR
		return nil
	},
	'o': func(flag *int) error {
		*flag |= O_COLOR
		return nil
	},
	'a': func(flag *int) error {
		*flag |= O_ALL
		return nil
	},
	't': func(flag *int) error {
		*flag |= O_TIME
		return nil
	},
	'r': func(flag *int) error {
		*flag |= O_REVERSE
		return nil
	},
	'R': func(flag *int) error {
		*flag |= O_RECURSIVE
		return nil
	},
}

// 存在しないオプションに関するエラー
type OptionError struct {
	Option rune
}

func (this OptionError) Error() string {
	return fmt.Sprintf("-%c: No such option", this.Option)
}

// ls 機能のエントリ:引数をオプションとパスに分離する
func Main(args []string, out io.Writer) error {
	flag := 0
	paths := make([]string, 0)
	for _, arg := range args {
		if strings.HasPrefix(arg, "-") {
			for _, o := range arg[1:] {
				setter, ok := option[o]
				if !ok {
					var err OptionError
					err.Option = o
					return err
				}
				err := setter(&flag)
				if err != nil {
					return err
				}
			}
		} else {
			paths = append(paths, arg)
		}
	}
	return lsCore(paths, flag, out)
}

// vim:set fenc=utf8 ts=4 sw=4 noet:
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package generator

type Wsdl struct {
	Name            string          `xml:"name,attr"`
	TargetNamespace string          `xml:"targetNamespace,attr"`
	Imports         []*WsdlImport   `xml:"import"`
	Doc             string          `xml:"documentation"`
	Types           WsdlType        `xml:"types"`
	Messages        []*WsdlMessage  `xml:"message"`
	PortTypes       []*WsdlPortType `xml:"portType"`
	Binding         []*WsdlBinding  `xml:"binding"`
	Service         []*WsdlService  `xml:"service"`
}

type WsdlImport struct {
	Namespace string `xml:"namespace,attr"`
	Location  string `xml:"location,attr"`
}

type WsdlType struct {
	Doc     string       `xml:"documentation"`
	Schemas []*XsdSchema `xml:"schema"`
}

type WsdlPart struct {
	Name    string `xml:"name,attr"`
	Element string `xml:"element,attr"`
	Type    string `xml:"type,attr"`
}

type WsdlMessage struct {
	Name  string      `xml:"name,attr"`
	Doc   string      `xml:"documentation"`
	Parts []*WsdlPart `xml:"part"`
}

type WsdlFault struct {
	Name      string        `xml:"name,attr"`
	Message   string        `xml:"message,attr"`
	Doc       string        `xml:"documentation"`
	SoapFault WsdlSoapFault `xml:"fault"`
}

type WsdlInput struct {
	Name       string            `xml:"name,attr"`
	Message    string            `xml:"message,attr"`
	Doc        string            `xml:"documentation"`
	SoapBody   WsdlSoapBody      `xml:"body"`
	SoapHeader []*WsdlSoapHeader `xml:"header"`
	//Mime       MimeBinding
}

type WsdlOutput struct {
	Name       string            `xml:"name,attr"`
	Message    string            `xml:"message,attr"`
	Doc        string            `xml:"documentation"`
	SoapBody   WsdlSoapBody      `xml:"body"`
	SoapHeader []*WsdlSoapHeader `xml:"header"`
	//Mime       MimeBinding
}

type WsdlOperation struct {
	Name          string            `xml:"name,attr"`
	Doc           string            `xml:"documentation"`
	Input         WsdlInput         `xml:"input"`
	Output        WsdlOutput        `xml:"output"`
	Faults        []*WsdlFault      `xml:"fault"`
	SoapOperation WsdlSoapOperation `xml:"http://schemas.xmlsoap.org/wsdl/soap/ operation"`
	HttpOperation WsdlHttpOperation `xml:"http://schemas.xmlsoap.org/wsdl/http/ operation"`
}

type WsdlPortType struct {
	Name       string           `xml:"name,attr"`
	Doc        string           `xml:"documentation"`
	Operations []*WsdlOperation `xml:"operation"`
}

type WsdlHttpBinding struct {
	Verb string `xml:"verb,attr"`
}

type WsdlSoapBinding struct {
	Style     string `xml:"style,attr"`
	Transport string `xml:"transport,attr"`
}

type WsdlSoapOperation struct {
	SoapAction string `xml:"soapAction,attr"`
	Style      string `xml:"style,attr"`
}

type WsdlSoapHeader struct {
	Message       string                 `xml:"message,attr"`
	Part          string                 `xml:"part,attr"`
	Use           string                 `xml:"use,attr"`
	EncodingStyle string                 `xml:"encodingStyle,attr"`
	Namespace     string                 `xml:"namespace,attr"`
	HeadersFault  []*WsdlSoapHeaderFault `xml:"headerfault"`
}

type WsdlSoapHeaderFault struct {
	Message       string `xml:"message,attr"`
	Part          string `xml:"part,attr"`
	Use           string `xml:"use,attr"`
	EncodingStyle string `xml:"encodingStyle,attr"`
	Namespace     string `xml:"namespace,attr"`
}

type WsdlSoapBody struct {
	Parts         string `xml:"parts,attr"`
	Use           string `xml:"use,attr"`
	EncodingStyle string `xml:"encodingStyle,attr"`
	Namespace     string `xml:"namespace,attr"`
}

type WsdlSoapFault struct {
	Parts         string `xml:"parts,attr"`
	Use           string `xml:"use,attr"`
	EncodingStyle string `xml:"encodingStyle,attr"`
	Namespace     string `xml:"namespace,attr"`
}

type WsdlSoapAddress struct {
	Location string `xml:"location,attr"`
}

type WsdlHttpOperation struct {
	Location string `xml:"location,attr"`
}

type WsdlBinding struct {
	Name        string           `xml:"name,attr"`
	Type        string           `xml:"type,attr"`
	Doc         string           `xml:"documentation"`
	HttpBinding WsdlHttpBinding  `xml:"http://schemas.xmlsoap.org/wsdl/http/ binding"`
	SoapBinding WsdlSoapBinding  `xml:"http://schemas.xmlsoap.org/wsdl/soap/ binding"`
	Operations  []*WsdlOperation `xml:"operation"`
}

type WsdlPort struct {
	Name        string          `xml:"name,attr"`
	Binding     string          `xml:"binding,attr"`
	Doc         string          `xml:"documentation"`
	SoapAddress WsdlSoapAddress `xml:"address"`
}

type WsdlService struct {
	Name  string      `xml:"name,attr"`
	Doc   string      `xml:"documentation"`
	Ports []*WsdlPort `xml:"port"`
}
<commit_msg>Takes back namespaces for WSDL tags<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package generator

type Wsdl struct {
	Name            string          `xml:"name,attr"`
	TargetNamespace string          `xml:"targetNamespace,attr"`
	Imports         []*WsdlImport   `xml:"import"`
	Doc             string          `xml:"documentation"`
	Types           WsdlType        `xml:"http://schemas.xmlsoap.org/wsdl/ types"`
	Messages        []*WsdlMessage  `xml:"http://schemas.xmlsoap.org/wsdl/ message"`
	PortTypes       []*WsdlPortType `xml:"http://schemas.xmlsoap.org/wsdl/ portType"`
	Binding         []*WsdlBinding  `xml:"http://schemas.xmlsoap.org/wsdl/ binding"`
	Service         []*WsdlService  `xml:"http://schemas.xmlsoap.org/wsdl/ service"`
}

type WsdlImport struct {
	Namespace string `xml:"namespace,attr"`
	Location  string `xml:"location,attr"`
}

type WsdlType struct {
	Doc     string       `xml:"documentation"`
	Schemas []*XsdSchema `xml:"schema"`
}

type WsdlPart struct {
	Name    string `xml:"name,attr"`
	Element string `xml:"element,attr"`
	Type    string `xml:"type,attr"`
}

type WsdlMessage struct {
	Name  string      `xml:"name,attr"`
	Doc   string      `xml:"documentation"`
	Parts []*WsdlPart `xml:"http://schemas.xmlsoap.org/wsdl/ part"`
}

type WsdlFault struct {
	Name      string        `xml:"name,attr"`
	Message   string        `xml:"message,attr"`
	Doc       string        `xml:"documentation"`
	SoapFault WsdlSoapFault `xml:"http://schemas.xmlsoap.org/wsdl/soap/ fault"`
}

type WsdlInput struct {
	Name       string            `xml:"name,attr"`
	Message    string            `xml:"message,attr"`
	Doc        string            `xml:"documentation"`
	SoapBody   WsdlSoapBody      `xml:"http://schemas.xmlsoap.org/wsdl/soap/ body"`
	SoapHeader []*WsdlSoapHeader `xml:"http://schemas.xmlsoap.org/wsdl/soap/ header"`
}

type WsdlOutput struct {
	Name       string            `xml:"name,attr"`
	Message    string            `xml:"message,attr"`
	Doc        string            `xml:"documentation"`
	SoapBody   WsdlSoapBody      `xml:"http://schemas.xmlsoap.org/wsdl/soap/ body"`
	SoapHeader []*WsdlSoapHeader `xml:"http://schemas.xmlsoap.org/wsdl/soap/ header"`
}

type WsdlOperation struct {
	Name          string            `xml:"name,attr"`
	Doc           string            `xml:"documentation"`
	Input         WsdlInput         `xml:"input"`
	Output        WsdlOutput        `xml:"output"`
	Faults        []*WsdlFault      `xml:"fault"`
	SoapOperation WsdlSoapOperation `xml:"http://schemas.xmlsoap.org/wsdl/soap/ operation"`
}

type WsdlPortType struct {
	Name       string           `xml:"name,attr"`
	Doc        string           `xml:"documentation"`
	Operations []*WsdlOperation `xml:"http://schemas.xmlsoap.org/wsdl/ operation"`
}

type WsdlSoapBinding struct {
	Style     string `xml:"style,attr"`
	Transport string `xml:"transport,attr"`
}

type WsdlSoapOperation struct {
	SoapAction string `xml:"soapAction,attr"`
	Style      string `xml:"style,attr"`
}

type WsdlSoapHeader struct {
	Message       string                 `xml:"message,attr"`
	Part          string                 `xml:"part,attr"`
	Use           string                 `xml:"use,attr"`
	EncodingStyle string                 `xml:"encodingStyle,attr"`
	Namespace     string                 `xml:"namespace,attr"`
	HeadersFault  []*WsdlSoapHeaderFault `xml:"headerfault"`
}

type WsdlSoapHeaderFault struct {
	Message       string `xml:"message,attr"`
	Part          string `xml:"part,attr"`
	Use           string `xml:"use,attr"`
	EncodingStyle string `xml:"encodingStyle,attr"`
	Namespace     string `xml:"namespace,attr"`
}

type WsdlSoapBody struct {
	Parts         string `xml:"parts,attr"`
	Use           string `xml:"use,attr"`
	EncodingStyle string `xml:"encodingStyle,attr"`
	Namespace     string `xml:"namespace,attr"`
}

type WsdlSoapFault struct {
	Parts         string `xml:"parts,attr"`
	Use           string `xml:"use,attr"`
	EncodingStyle string `xml:"encodingStyle,attr"`
	Namespace     string `xml:"namespace,attr"`
}

type WsdlSoapAddress struct {
	Location string `xml:"location,attr"`
}

type WsdlBinding struct {
	Name        string           `xml:"name,attr"`
	Type        string           `xml:"type,attr"`
	Doc         string           `xml:"documentation"`
	SoapBinding WsdlSoapBinding  `xml:"http://schemas.xmlsoap.org/wsdl/soap/ binding"`
	Operations  []*WsdlOperation `xml:"http://schemas.xmlsoap.org/wsdl/ operation"`
}

type WsdlPort struct {
	Name        string          `xml:"name,attr"`
	Binding     string          `xml:"binding,attr"`
	Doc         string          `xml:"documentation"`
	SoapAddress WsdlSoapAddress `xml:"http://schemas.xmlsoap.org/wsdl/soap/ address"`
}

type WsdlService struct {
	Name  string      `xml:"name,attr"`
	Doc   string      `xml:"documentation"`
	Ports []*WsdlPort `xml:"http://schemas.xmlsoap.org/wsdl/ port"`
}
<|endoftext|>


<commit_before>package geos

/*
#cgo LDFLAGS: -lgeos_c
#include "geos_c.h"
#include <stdlib.h>

extern void goLogString(char *msg);
extern void debug_wrap(const char *fmt, ...);
extern GEOSContextHandle_t initGEOS_r_debug();
extern void initGEOS_debug();
*/
import "C"

import (
	"errors"
	"runtime"
	"unsafe"

	"github.com/omniscale/imposm3/logging"
)

var log = logging.NewLogger("GEOS")

//export goLogString
func goLogString(msg *C.char) {
	log.Printf(C.GoString(msg))
}

type Geos struct {
	v    C.GEOSContextHandle_t
	srid int
}

type Geom struct {
	v *C.GEOSGeometry
}

type CreateError string
type Error string

func (e Error) Error() string {
	return string(e)
}

func (e CreateError) Error() string {
	return string(e)
}

func NewGeos() *Geos {
	geos := &Geos{}
	geos.v = C.initGEOS_r_debug()
	return geos
}

func (this *Geos) Finish() {
	if this.v != nil {
		C.finishGEOS_r(this.v)
		this.v = nil
	}
}

func init() {
	/*
		Init global GEOS handle for non _r calls.
		In theory we need to always call the _r functions
		with a thread/goroutine-local GEOS instance to get thread
		safe behaviour. Some functions don't need a GEOS instance though
		and we can make use of that e.g. to call GEOSGeom_destroy in
		finalizer.
	*/
	C.initGEOS_debug()
}

func (this *Geos) Destroy(geom *Geom) {
	runtime.SetFinalizer(geom, nil)
	if geom.v != nil {
		C.GEOSGeom_destroy_r(this.v, geom.v)
		geom.v = nil
	} else {
		log.Printf("double free?")
	}
}

func destroyGeom(geom *Geom) {
	C.GEOSGeom_destroy(geom.v)
}

func (this *Geos) DestroyLater(geom *Geom) {
	runtime.SetFinalizer(geom, destroyGeom)
}

func (this *Geos) Clone(geom *Geom) *Geom {
	if geom == nil || geom.v == nil {
		return nil
	}

	result := C.GEOSGeom_clone_r(this.v, geom.v)
	if result == nil {
		return nil
	}
	return &Geom{result}
}

func (this *Geos) SetHandleSrid(srid int) {
	this.srid = srid
}

func (this *Geos) NumGeoms(geom *Geom) int32 {
	count := int32(C.GEOSGetNumGeometries_r(this.v, geom.v))
	return count
}

func (this *Geos) Geoms(geom *Geom) []*Geom {
	count := this.NumGeoms(geom)
	var result []*Geom
	for i := 0; int32(i) < count; i++ {
		part := C.GEOSGetGeometryN_r(this.v, geom.v, C.int(i))
		if part == nil {
			return nil
		}
		result = append(result, &Geom{part})
	}
	return result
}

func (this *Geos) ExteriorRing(geom *Geom) *Geom {
	ring := C.GEOSGetExteriorRing_r(this.v, geom.v)
	if ring == nil {
		return nil
	}
	return &Geom{ring}
}

func (this *Geos) BoundsPolygon(bounds Bounds) *Geom {
	coordSeq, err := this.CreateCoordSeq(5, 2)
	if err != nil {
		return nil
	}
	// coordSeq inherited by LineString, no destroy

	if err := coordSeq.SetXY(this, 0, bounds.MinX, bounds.MinY); err != nil {
		return nil
	}
	if err := coordSeq.SetXY(this, 1, bounds.MaxX, bounds.MinY); err != nil {
		return nil
	}
	if err := coordSeq.SetXY(this, 2, bounds.MaxX, bounds.MaxY); err != nil {
		return nil
	}
	if err := coordSeq.SetXY(this, 3, bounds.MinX, bounds.MaxY); err != nil {
		return nil
	}
	if err := coordSeq.SetXY(this, 4, bounds.MinX, bounds.MinY); err != nil {
		return nil
	}

	geom, err := coordSeq.AsLinearRing(this)
	if err != nil {
		return nil
	}
	// geom inherited by Polygon, no destroy

	geom = this.Polygon(geom, nil)
	return geom

}

func (this *Geos) Point(x, y float64) *Geom {
	coordSeq, err := this.CreateCoordSeq(1, 2)
	if err != nil {
		return nil
	}
	// coordSeq inherited by LineString
	coordSeq.SetXY(this, 0, x, y)
	geom, err := coordSeq.AsPoint(this)
	if err != nil {
		return nil
	}
	return geom
}

func (this *Geos) Polygon(exterior *Geom, interiors []*Geom) *Geom {
	if len(interiors) == 0 {
		geom := C.GEOSGeom_createPolygon_r(this.v, exterior.v, nil, C.uint(0))
		if geom == nil {
			return nil
		}
		err := C.GEOSNormalize_r(this.v, geom)
		if err != 0 {
			C.GEOSGeom_destroy(geom)
			return nil
		}
		return &Geom{geom}
	}

	interiorPtr := make([]*C.GEOSGeometry, len(interiors))
	for i, geom := range interiors {
		interiorPtr[i] = geom.v
	}
	geom := C.GEOSGeom_createPolygon_r(this.v, exterior.v, &interiorPtr[0], C.uint(len(interiors)))
	if geom == nil {
		return nil
	}
	err := C.GEOSNormalize_r(this.v, geom)
	if err != 0 {
		C.GEOSGeom_destroy(geom)
		return nil
	}
	return &Geom{geom}
}

func (this *Geos) MultiPolygon(polygons []*Geom) *Geom {
	if len(polygons) == 0 {
		return nil
	}
	polygonPtr := make([]*C.GEOSGeometry, len(polygons))
	for i, geom := range polygons {
		polygonPtr[i] = geom.v
	}
	geom := C.GEOSGeom_createCollection_r(this.v, C.GEOS_MULTIPOLYGON, &polygonPtr[0], C.uint(len(polygons)))
	if geom == nil {
		return nil
	}
	return &Geom{geom}
}
func (this *Geos) MultiLineString(lines []*Geom) *Geom {
	if len(lines) == 0 {
		return nil
	}
	linePtr := make([]*C.GEOSGeometry, len(lines))
	for i, geom := range lines {
		linePtr[i] = geom.v
	}
	geom := C.GEOSGeom_createCollection_r(this.v, C.GEOS_MULTILINESTRING, &linePtr[0], C.uint(len(lines)))
	if geom == nil {
		return nil
	}
	return &Geom{geom}
}

func (this *Geos) IsValid(geom *Geom) bool {
	if C.GEOSisValid_r(this.v, geom.v) == 1 {
		return true
	}
	return false
}

func (this *Geos) IsSimple(geom *Geom) bool {
	if C.GEOSisSimple_r(this.v, geom.v) == 1 {
		return true
	}
	return false
}

func (this *Geos) IsEmpty(geom *Geom) bool {
	if C.GEOSisEmpty_r(this.v, geom.v) == 1 {
		return true
	}
	return false
}

func (this *Geos) Type(geom *Geom) string {
	geomType := C.GEOSGeomType_r(this.v, geom.v)
	if geomType == nil {
		return "Unknown"
	}
	defer C.free(unsafe.Pointer(geomType))
	return C.GoString(geomType)
}

func (this *Geos) Equals(a, b *Geom) bool {
	result := C.GEOSEquals_r(this.v, a.v, b.v)
	if result == 1 {
		return true
	}
	return false
}

func (g *Geos) MakeValid(geom *Geom) (*Geom, error) {
	if g.IsValid(geom) {
		return geom, nil
	}
	fixed := g.Buffer(geom, 0)
	if fixed == nil {
		return nil, errors.New("Error while fixing geom with buffer(0)")
	}
	g.Destroy(geom)

	return fixed, nil
}

func (this *Geom) Area() float64 {
	var area C.double
	if ret := C.GEOSArea(this.v, &area); ret == 1 {
		return float64(area)
	} else {
		return 0
	}
}

func (this *Geom) Length() float64 {
	var length C.double
	if ret := C.GEOSLength(this.v, &length); ret == 1 {
		return float64(length)
	} else {
		return 0
	}
}

type Bounds struct {
	MinX float64
	MinY float64
	MaxX float64
	MaxY float64
}

var NilBounds = Bounds{1e20, 1e20, -1e20, -1e20}

func (this *Geom) Bounds() Bounds {
	geom := C.GEOSEnvelope(this.v)
	if geom == nil {
		return NilBounds
	}
	extRing := C.GEOSGetExteriorRing(geom)
	if extRing == nil {
		return NilBounds
	}
	cs := C.GEOSGeom_getCoordSeq(extRing)
	var csLen C.uint
	C.GEOSCoordSeq_getSize(cs, &csLen)
	minx := 1.e+20
	maxx := -1e+20
	miny := 1.e+20
	maxy := -1e+20
	var temp C.double
	for i := 0; i < int(csLen); i++ {
		C.GEOSCoordSeq_getX(cs, C.uint(i), &temp)
		x := float64(temp)
		if x < minx {
			minx = x
		}
		if x > maxx {
			maxx = x
		}
		C.GEOSCoordSeq_getY(cs, C.uint(i), &temp)
		y := float64(temp)
		if y < miny {
			miny = y
		}
		if y > maxy {
			maxy = y
		}
	}

	return Bounds{minx, miny, maxx, maxy}
}
<commit_msg>fix memory leak in Geom.Bounds<commit_after>package geos

/*
#cgo LDFLAGS: -lgeos_c
#include "geos_c.h"
#include <stdlib.h>

extern void goLogString(char *msg);
extern void debug_wrap(const char *fmt, ...);
extern GEOSContextHandle_t initGEOS_r_debug();
extern void initGEOS_debug();
*/
import "C"

import (
	"errors"
	"runtime"
	"unsafe"

	"github.com/omniscale/imposm3/logging"
)

var log = logging.NewLogger("GEOS")

//export goLogString
func goLogString(msg *C.char) {
	log.Printf(C.GoString(msg))
}

type Geos struct {
	v    C.GEOSContextHandle_t
	srid int
}

type Geom struct {
	v *C.GEOSGeometry
}

type CreateError string
type Error string

func (e Error) Error() string {
	return string(e)
}

func (e CreateError) Error() string {
	return string(e)
}

func NewGeos() *Geos {
	geos := &Geos{}
	geos.v = C.initGEOS_r_debug()
	return geos
}

func (this *Geos) Finish() {
	if this.v != nil {
		C.finishGEOS_r(this.v)
		this.v = nil
	}
}

func init() {
	/*
		Init global GEOS handle for non _r calls.
		In theory we need to always call the _r functions
		with a thread/goroutine-local GEOS instance to get thread
		safe behaviour. Some functions don't need a GEOS instance though
		and we can make use of that e.g. to call GEOSGeom_destroy in
		finalizer.
	*/
	C.initGEOS_debug()
}

func (this *Geos) Destroy(geom *Geom) {
	runtime.SetFinalizer(geom, nil)
	if geom.v != nil {
		C.GEOSGeom_destroy_r(this.v, geom.v)
		geom.v = nil
	} else {
		log.Printf("double free?")
	}
}

func destroyGeom(geom *Geom) {
	C.GEOSGeom_destroy(geom.v)
}

func (this *Geos) DestroyLater(geom *Geom) {
	runtime.SetFinalizer(geom, destroyGeom)
}

func (this *Geos) Clone(geom *Geom) *Geom {
	if geom == nil || geom.v == nil {
		return nil
	}

	result := C.GEOSGeom_clone_r(this.v, geom.v)
	if result == nil {
		return nil
	}
	return &Geom{result}
}

func (this *Geos) SetHandleSrid(srid int) {
	this.srid = srid
}

func (this *Geos) NumGeoms(geom *Geom) int32 {
	count := int32(C.GEOSGetNumGeometries_r(this.v, geom.v))
	return count
}

func (this *Geos) Geoms(geom *Geom) []*Geom {
	count := this.NumGeoms(geom)
	var result []*Geom
	for i := 0; int32(i) < count; i++ {
		part := C.GEOSGetGeometryN_r(this.v, geom.v, C.int(i))
		if part == nil {
			return nil
		}
		result = append(result, &Geom{part})
	}
	return result
}

func (this *Geos) ExteriorRing(geom *Geom) *Geom {
	ring := C.GEOSGetExteriorRing_r(this.v, geom.v)
	if ring == nil {
		return nil
	}
	return &Geom{ring}
}

func (this *Geos) BoundsPolygon(bounds Bounds) *Geom {
	coordSeq, err := this.CreateCoordSeq(5, 2)
	if err != nil {
		return nil
	}
	// coordSeq inherited by LineString, no destroy

	if err := coordSeq.SetXY(this, 0, bounds.MinX, bounds.MinY); err != nil {
		return nil
	}
	if err := coordSeq.SetXY(this, 1, bounds.MaxX, bounds.MinY); err != nil {
		return nil
	}
	if err := coordSeq.SetXY(this, 2, bounds.MaxX, bounds.MaxY); err != nil {
		return nil
	}
	if err := coordSeq.SetXY(this, 3, bounds.MinX, bounds.MaxY); err != nil {
		return nil
	}
	if err := coordSeq.SetXY(this, 4, bounds.MinX, bounds.MinY); err != nil {
		return nil
	}

	geom, err := coordSeq.AsLinearRing(this)
	if err != nil {
		return nil
	}
	// geom inherited by Polygon, no destroy

	geom = this.Polygon(geom, nil)
	return geom

}

func (this *Geos) Point(x, y float64) *Geom {
	coordSeq, err := this.CreateCoordSeq(1, 2)
	if err != nil {
		return nil
	}
	// coordSeq inherited by LineString
	coordSeq.SetXY(this, 0, x, y)
	geom, err := coordSeq.AsPoint(this)
	if err != nil {
		return nil
	}
	return geom
}

func (this *Geos) Polygon(exterior *Geom, interiors []*Geom) *Geom {
	if len(interiors) == 0 {
		geom := C.GEOSGeom_createPolygon_r(this.v, exterior.v, nil, C.uint(0))
		if geom == nil {
			return nil
		}
		err := C.GEOSNormalize_r(this.v, geom)
		if err != 0 {
			C.GEOSGeom_destroy(geom)
			return nil
		}
		return &Geom{geom}
	}

	interiorPtr := make([]*C.GEOSGeometry, len(interiors))
	for i, geom := range interiors {
		interiorPtr[i] = geom.v
	}
	geom := C.GEOSGeom_createPolygon_r(this.v, exterior.v, &interiorPtr[0], C.uint(len(interiors)))
	if geom == nil {
		return nil
	}
	err := C.GEOSNormalize_r(this.v, geom)
	if err != 0 {
		C.GEOSGeom_destroy(geom)
		return nil
	}
	return &Geom{geom}
}

func (this *Geos) MultiPolygon(polygons []*Geom) *Geom {
	if len(polygons) == 0 {
		return nil
	}
	polygonPtr := make([]*C.GEOSGeometry, len(polygons))
	for i, geom := range polygons {
		polygonPtr[i] = geom.v
	}
	geom := C.GEOSGeom_createCollection_r(this.v, C.GEOS_MULTIPOLYGON, &polygonPtr[0], C.uint(len(polygons)))
	if geom == nil {
		return nil
	}
	return &Geom{geom}
}
func (this *Geos) MultiLineString(lines []*Geom) *Geom {
	if len(lines) == 0 {
		return nil
	}
	linePtr := make([]*C.GEOSGeometry, len(lines))
	for i, geom := range lines {
		linePtr[i] = geom.v
	}
	geom := C.GEOSGeom_createCollection_r(this.v, C.GEOS_MULTILINESTRING, &linePtr[0], C.uint(len(lines)))
	if geom == nil {
		return nil
	}
	return &Geom{geom}
}

func (this *Geos) IsValid(geom *Geom) bool {
	if C.GEOSisValid_r(this.v, geom.v) == 1 {
		return true
	}
	return false
}

func (this *Geos) IsSimple(geom *Geom) bool {
	if C.GEOSisSimple_r(this.v, geom.v) == 1 {
		return true
	}
	return false
}

func (this *Geos) IsEmpty(geom *Geom) bool {
	if C.GEOSisEmpty_r(this.v, geom.v) == 1 {
		return true
	}
	return false
}

func (this *Geos) Type(geom *Geom) string {
	geomType := C.GEOSGeomType_r(this.v, geom.v)
	if geomType == nil {
		return "Unknown"
	}
	defer C.free(unsafe.Pointer(geomType))
	return C.GoString(geomType)
}

func (this *Geos) Equals(a, b *Geom) bool {
	result := C.GEOSEquals_r(this.v, a.v, b.v)
	if result == 1 {
		return true
	}
	return false
}

func (g *Geos) MakeValid(geom *Geom) (*Geom, error) {
	if g.IsValid(geom) {
		return geom, nil
	}
	fixed := g.Buffer(geom, 0)
	if fixed == nil {
		return nil, errors.New("Error while fixing geom with buffer(0)")
	}
	g.Destroy(geom)

	return fixed, nil
}

func (this *Geom) Area() float64 {
	var area C.double
	if ret := C.GEOSArea(this.v, &area); ret == 1 {
		return float64(area)
	} else {
		return 0
	}
}

func (this *Geom) Length() float64 {
	var length C.double
	if ret := C.GEOSLength(this.v, &length); ret == 1 {
		return float64(length)
	} else {
		return 0
	}
}

type Bounds struct {
	MinX float64
	MinY float64
	MaxX float64
	MaxY float64
}

var NilBounds = Bounds{1e20, 1e20, -1e20, -1e20}

func (this *Geom) Bounds() Bounds {
	geom := C.GEOSEnvelope(this.v)
	if geom == nil {
		return NilBounds
	}
	defer C.GEOSGeom_destroy(geom)
	extRing := C.GEOSGetExteriorRing(geom)
	if extRing == nil {
		return NilBounds
	}
	cs := C.GEOSGeom_getCoordSeq(extRing)
	var csLen C.uint
	C.GEOSCoordSeq_getSize(cs, &csLen)
	minx := 1.e+20
	maxx := -1e+20
	miny := 1.e+20
	maxy := -1e+20
	var temp C.double
	for i := 0; i < int(csLen); i++ {
		C.GEOSCoordSeq_getX(cs, C.uint(i), &temp)
		x := float64(temp)
		if x < minx {
			minx = x
		}
		if x > maxx {
			maxx = x
		}
		C.GEOSCoordSeq_getY(cs, C.uint(i), &temp)
		y := float64(temp)
		if y < miny {
			miny = y
		}
		if y > maxy {
			maxy = y
		}
	}

	return Bounds{minx, miny, maxx, maxy}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
)

func main() {
	var showVersion bool
	flag.BoolVar(&showVersion, "version", false, "Print version information.")
	flag.BoolVar(&showVersion, "v", false, "Print version information.")
	flag.Parse()

	// Show version and exit
	if showVersion {
		fmt.Println("version: 1.0.0")
		os.Exit(0)
	}

	fmt.Println("try -h to get more information")
}
<commit_msg>udpate flag command line.<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"os"
)

// HelloWorld for hello world
func HelloWorld() string {
	return "Hello World, golang workshop!"
}

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s, I love %s!", HelloWorld(), r.URL.Path[1:])
}

func main() {
	var showVersion bool
	var port string
	flag.BoolVar(&showVersion, "version", false, "Print version information.")
	flag.BoolVar(&showVersion, "v", false, "Print version information.")
	flag.StringVar(&port, "port", "8080", "server port")
	flag.StringVar(&port, "p", "8080", "server port")
	flag.Parse()

	// Show version and exit
	if showVersion {
		fmt.Println("version: 1.0.0")
		os.Exit(0)
	}

	if p, ok := os.LookupEnv("PORT"); ok {
		port = p
	}
	flag.Parse()
	http.HandleFunc("/", handler)
	log.Println("http server run on " + port + " port")
	log.Fatal(http.ListenAndServe(":"+port, nil))
}
<|endoftext|>


<commit_before>package rope

import (
	"crypto/rand"
	"testing"
)

func BenchmarkNew(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.SetBytes(int64(len(bytes)))
		NewFromBytes(bytes)
	}
}

func BenchmarkIndex(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Index(300000)
	}
}

func BenchmarkLen(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Len()
	}
}

func BenchmarkSplit(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Split(300000)
	}
}

func BenchmarkInsert(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Insert(300000, []byte("foobar"))
	}
}

func BenchmarkDelete(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Delete(300000, 400000)
	}
}

func BenchmarkSub(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Sub(300000, 128)
	}
}
<commit_msg>add NewRuneReader benchmark<commit_after>package rope

import (
	"crypto/rand"
	"testing"
)

func BenchmarkNew(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		b.SetBytes(int64(len(bytes)))
		NewFromBytes(bytes)
	}
}

func BenchmarkIndex(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Index(300000)
	}
}

func BenchmarkLen(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Len()
	}
}

func BenchmarkSplit(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Split(300000)
	}
}

func BenchmarkInsert(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Insert(300000, []byte("foobar"))
	}
}

func BenchmarkDelete(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Delete(300000, 400000)
	}
}

func BenchmarkSub(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.Sub(300000, 128)
	}
}

func BenchmarkNewRuneReader(b *testing.B) {
	bytes := make([]byte, 409600)
	n, err := rand.Read(bytes)
	if n != len(bytes) || err != nil {
		b.Fatalf("%d %v", n, err)
	}
	r := NewFromBytes(bytes)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		r.NewRuneReader()
	}
}
<|endoftext|>


<commit_before>package encode

import (
	"fmt"
	"strconv"
)

func RunLengthEncode(s string) string {
	count := 1
	var output string
	for i, c := range s {
		if i != 0 {
			if rune(s[i-1]) == c {
				count++
			} else {
				count, output = encode(count, i, s, output)
			}
		}
	}
	if len(s) != 0 {
		count, output = encode(count, len(s), s, output)
	}
	return output
}

func RunLengthDecode(s string) string {
	count := 1
	var stringCount, output string
	for _, c := range s {
		if _, err := strconv.Atoi(string(c)); err == nil {
			stringCount += string(c)
		} else {
			if stringCount != "" {
				count, _ = strconv.Atoi(stringCount)
			}
			for j := 0; j < count; j++ {
				output += string(c)
			}
			count = 1
			stringCount = ""
		}
	}
	return output
}

func encode(count, i int, s, output string) (int, string) {
	if count > 1 {
		output += fmt.Sprintf("%d%c", count, s[i-1])
		return 1, output
	}
	output += fmt.Sprintf("%c", s[i-1])
	return 1, output
}
<commit_msg>run-length-encoding: updates for golangci-lint<commit_after>package encode

import (
	"fmt"
	"strconv"
)

func RunLengthEncode(s string) string {
	count := 1
	var output string
	for i, c := range s {
		if i != 0 {
			if rune(s[i-1]) == c {
				count++
			} else {
				count, output = encode(count, i, s, output)
			}
		}
	}
	if len(s) != 0 {
		_, output = encode(count, len(s), s, output)
	}
	return output
}

func RunLengthDecode(s string) string {
	count := 1
	var stringCount, output string
	for _, c := range s {
		if _, err := strconv.Atoi(string(c)); err == nil {
			stringCount += string(c)
		} else {
			if stringCount != "" {
				count, _ = strconv.Atoi(stringCount)
			}
			for j := 0; j < count; j++ {
				output += string(c)
			}
			count = 1
			stringCount = ""
		}
	}
	return output
}

func encode(count, i int, s, output string) (int, string) {
	if count > 1 {
		output += fmt.Sprintf("%d%c", count, s[i-1])
		return 1, output
	}
	output += fmt.Sprintf("%c", s[i-1])
	return 1, output
}
<|endoftext|>


<commit_before>package rkenodeconfigserver

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	v32 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/controllers/dashboard/clusterregistrationtoken"
	"github.com/rancher/rancher/pkg/tunnelserver/mcmauthorizer"

	rketypes "github.com/rancher/rke/types"

	"github.com/pkg/errors"
	util "github.com/rancher/rancher/pkg/cluster"
	kd "github.com/rancher/rancher/pkg/controllers/management/kontainerdrivermetadata"
	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/image"
	"github.com/rancher/rancher/pkg/librke"
	"github.com/rancher/rancher/pkg/rkeworker"
	"github.com/rancher/rancher/pkg/settings"
	"github.com/rancher/rancher/pkg/systemaccount"
	"github.com/rancher/rancher/pkg/taints"
	"github.com/rancher/rancher/pkg/types/config"
	rkepki "github.com/rancher/rke/pki"
	rkeservices "github.com/rancher/rke/services"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
)

const (
	DefaultAgentCheckInterval       = 120
	AgentCheckIntervalDuringUpgrade = 35
	AgentCheckIntervalDuringCreate  = 15
)

type RKENodeConfigServer struct {
	auth                 *mcmauthorizer.Authorizer
	lookup               *BundleLookup
	systemAccountManager *systemaccount.Manager
	serviceOptionsLister v3.RkeK8sServiceOptionLister
	serviceOptions       v3.RkeK8sServiceOptionInterface
	sysImagesLister      v3.RkeK8sSystemImageLister
	sysImages            v3.RkeK8sSystemImageInterface
	nodes                v3.NodeInterface
}

func Handler(auth *mcmauthorizer.Authorizer, scaledContext *config.ScaledContext) http.Handler {
	return &RKENodeConfigServer{
		auth:                 auth,
		lookup:               NewLookup(scaledContext.Core.Namespaces(""), scaledContext.Core),
		systemAccountManager: systemaccount.NewManagerFromScale(scaledContext),
		serviceOptionsLister: scaledContext.Management.RkeK8sServiceOptions("").Controller().Lister(),
		serviceOptions:       scaledContext.Management.RkeK8sServiceOptions(""),
		sysImagesLister:      scaledContext.Management.RkeK8sSystemImages("").Controller().Lister(),
		sysImages:            scaledContext.Management.RkeK8sSystemImages(""),
		nodes:                scaledContext.Management.Nodes(""),
	}
}

func (n *RKENodeConfigServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// 404 tells the client to continue without plan
	// 5xx tells the client to try again later for plan

	client, ok, err := n.auth.Authorize(req)
	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte(err.Error()))
		return
	}

	if !ok {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if client.Node == nil {
		rw.WriteHeader(http.StatusNotFound)
		return
	}

	if client.Cluster.Status.Driver == "" {
		rw.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	if client.Cluster.Status.Driver != v32.ClusterDriverRKE {
		rw.WriteHeader(http.StatusNotFound)
		return
	}

	if client.Node.Status.NodeConfig == nil {
		rw.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	var nodeConfig *rkeworker.NodeConfig
	if IsNonWorker(client.Node.Status.NodeConfig.Role) {
		nodeConfig, err = n.nonWorkerConfig(req.Context(), client.Cluster, client.Node)
	} else {
		if client.Cluster.Status.AppliedSpec.RancherKubernetesEngineConfig == nil {
			rw.WriteHeader(http.StatusServiceUnavailable)
			return
		}
		if client.NodeVersion != 0 {
			logrus.Debugf("cluster [%s] worker-upgrade: received node-version [%v] for node [%s]", client.Cluster.Name,
				client.NodeVersion, client.Node.Name)

			if client.Node.Status.AppliedNodeVersion != client.NodeVersion {
				nodeCopy := client.Node.DeepCopy()
				logrus.Infof("cluster [%s] worker-upgrade: updating node [%s] with node-version %v", client.Cluster.Name,
					client.Node.Name, client.NodeVersion)

				nodeCopy.Status.AppliedNodeVersion = client.NodeVersion

				_, err = n.nodes.Update(nodeCopy)
				if err != nil {
					logrus.Infof("cluster [%s] worker-upgrade: error updating node [%s] with node-version [%v]: %v", client.Cluster.Name,
						client.Node.Name, client.NodeVersion, err)
				}
			}
		}

		nodeConfig, err = n.nodeConfig(req.Context(), client.Cluster, client.Node)
	}

	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Failed to construct node config. Error: " + err.Error()))
		return
	}

	rw.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(rw).Encode(nodeConfig); err != nil {
		logrus.Errorf("failed to write nodeConfig to agent: %v", err)
	}
}

func IsNonWorker(roles []string) bool {
	for _, role := range roles {
		if role == rkeservices.ETCDRole {
			return true
		}
		if role == rkeservices.ControlRole {
			return true
		}
	}
	return false
}

func (n *RKENodeConfigServer) nonWorkerConfig(ctx context.Context, cluster *v3.Cluster, node *v3.Node) (*rkeworker.NodeConfig, error) {
	nodePlan := node.Status.NodePlan
	nc := &rkeworker.NodeConfig{
		ClusterName: cluster.Name,
	}

	if nodePlan == nil {
		logrus.Tracef("cluster [%s]: node [%s] doesn't have node plan yet", cluster.Name, node.Name)
		nc.AgentCheckInterval = AgentCheckIntervalDuringCreate
		return nc, nil
	}

	nc.Processes = nodePlan.Plan.Processes
	nc.AgentCheckInterval = nodePlan.AgentCheckInterval

	return nc, nil
}

func (n *RKENodeConfigServer) nodeConfig(ctx context.Context, cluster *v3.Cluster, node *v3.Node) (*rkeworker.NodeConfig, error) {
	status := cluster.Status.AppliedSpec.DeepCopy()
	rkeConfig := status.RancherKubernetesEngineConfig

	nodePlan := node.Status.NodePlan
	hostAddress := node.Status.NodeConfig.Address

	nc := &rkeworker.NodeConfig{
		ClusterName: cluster.Name,
	}

	if nodePlan == nil {
		logrus.Tracef("cluster [%s]: node [%s] %s doesn't have node plan yet", cluster.Name, node.Name, hostAddress)
		nc.AgentCheckInterval = AgentCheckIntervalDuringCreate
		return nc, nil
	}

	infos, err := librke.GetDockerInfo(node)
	if err != nil {
		return nil, err
	}

	bundle, err := n.lookup.Lookup(cluster)
	if err != nil {
		return nil, err
	}

	hostDockerInfo := infos[hostAddress]
	if hostDockerInfo.OSType == "windows" { // compatible with Windows
		bundle = bundle.ForWindowsNode(rkeConfig, hostAddress)
	} else {
		bundle = bundle.ForNode(rkeConfig, hostAddress)
	}

	if rkepki.IsKubeletGenerateServingCertificateEnabledinConfig(rkeConfig) {
		logrus.Debugf("nodeConfig: VerifyKubeletCAEnabled is true, generating kubelet certificate for [%s]", hostAddress)
		err := rkepki.GenerateKubeletCertificate(ctx, bundle.Certs(), *rkeConfig, "", "", false)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to generate kubelet certificate")
		}
	}
	certString, err := bundle.SafeMarshal()
	if err != nil {
		return nil, errors.Wrapf(err, "failed to marshal certificates bundle")
	}
	nc.Certs = certString
	np := nodePlan.Plan
	nc.Processes = np.Processes
	nc.Files = np.Files
	if nodePlan.AgentCheckInterval != 0 {
		nc.AgentCheckInterval = nodePlan.AgentCheckInterval
	}

	if node.Status.AppliedNodeVersion != cluster.Status.NodeVersion {
		if nodePlan.Version == cluster.Status.NodeVersion {
			nc.NodeVersion = cluster.Status.NodeVersion
			logrus.Infof("cluster [%s] worker-upgrade: sending node-version for node [%s] version %v", cluster.Name, node.Status.NodeName, nc.NodeVersion)
		} else if v32.ClusterConditionUpgraded.IsUnknown(cluster) {
			if nc.AgentCheckInterval != AgentCheckIntervalDuringUpgrade {
				nodeCopy := node.DeepCopy()
				nodeCopy.Status.NodePlan.AgentCheckInterval = AgentCheckIntervalDuringUpgrade

				n.nodes.Update(nodeCopy)

				logrus.Infof("cluster [%s] worker-upgrade: updating [%s] with agent-interval [%v]", cluster.Name, node.Status.NodeName, AgentCheckIntervalDuringUpgrade)
				nc.AgentCheckInterval = AgentCheckIntervalDuringUpgrade
			}
		}
	}
	return nc, nil
}

func FilterHostForSpec(spec *rketypes.RancherKubernetesEngineConfig, n *v3.Node) {
	nodeList := make([]rketypes.RKEConfigNode, 0)
	for _, node := range spec.Nodes {
		if IsNonWorker(node.Role) || node.NodeName == n.Status.NodeConfig.NodeName {
			nodeList = append(nodeList, node)
		}
	}
	spec.Nodes = nodeList
}

func AugmentProcesses(token string, processes map[string]rketypes.Process, worker bool, nodeName string,
	cluster *v3.Cluster) (map[string]rketypes.Process, error) {
	var shared bool

OuterLoop:
	for _, process := range processes {
		for _, bind := range process.Binds {
			parts := strings.Split(bind, ":")
			if len(parts) > 2 && strings.Contains(parts[2], "shared") {
				shared = true
				break OuterLoop
			}
		}
	}

	if shared {
		agentImage := settings.AgentImage.Get()
		nodeCommand, err := clusterregistrationtoken.ShareMntCommand(nodeName, token, cluster)
		if err != nil {
			return nil, err
		}
		privateRegistryConfig, _ := util.GenerateClusterPrivateRegistryDockerConfig(cluster)
		processes["share-mnt"] = rketypes.Process{
			Name:  "share-mnt",
			Args:  nodeCommand,
			Image: image.ResolveWithCluster(agentImage, cluster),
			Binds: []string{
				"/var/run:/var/run",
				"/etc/kubernetes:/etc/kubernetes",
			},
			NetworkMode:             "host",
			RestartPolicy:           "always",
			Privileged:              true,
			ImageRegistryAuthConfig: privateRegistryConfig,
		}
	}

	if worker {
		// not sure if we really need this anymore
		delete(processes, "etcd")
	} else {
		if p, ok := processes["share-mnt"]; ok {
			processes = map[string]rketypes.Process{
				"share-mnt": p,
			}
		} else {
			processes = nil
		}
	}

	for _, p := range processes {
		for i, bind := range p.Binds {
			parts := strings.Split(bind, ":")
			if len(parts) > 1 && parts[1] == "/etc/kubernetes" {
				parts[0] = parts[1]
				p.Binds[i] = strings.Join(parts, ":")
			}
		}
	}

	return processes, nil
}

func EnhanceWindowsProcesses(processes map[string]rketypes.Process) map[string]rketypes.Process {
	newProcesses := make(map[string]rketypes.Process, len(processes))
	for k, p := range processes {
		p.Binds = append(p.Binds,
			"//./pipe/rancher_wins://./pipe/rancher_wins",
		)
		newProcesses[k] = p
	}

	return newProcesses
}

func AppendTaintsToKubeletArgs(processes map[string]rketypes.Process, nodeConfigTaints []rketypes.RKETaint) map[string]rketypes.Process {
	if kubelet, ok := processes["kubelet"]; ok && len(nodeConfigTaints) != 0 {
		initialTaints := taints.GetTaintsFromStrings(taints.GetStringsFromRKETaint(nodeConfigTaints))
		var currentTaints []v1.Taint
		foundArgs := ""
		for i, arg := range kubelet.Command {
			if strings.HasPrefix(arg, "--register-with-taints=") {
				foundArgs = strings.TrimPrefix(arg, "--register-with-taints=")
				kubelet.Command = append(kubelet.Command[:i], kubelet.Command[i+1:]...)
				break
			}
		}
		if foundArgs != "" {
			currentTaints = taints.GetTaintsFromStrings(strings.Split(foundArgs, ","))
		}

		// The initial taints are from node pool and node template. They should override the taints from kubelet args.
		mergedTaints := taints.MergeTaints(currentTaints, initialTaints)

		taintArgs := fmt.Sprintf("--register-with-taints=%s", strings.Join(taints.GetStringsFromTaint(mergedTaints), ","))
		kubelet.Command = append(kubelet.Command, taintArgs)
		processes["kubelet"] = kubelet
	}
	return processes
}

func (n *RKENodeConfigServer) getServiceOptions(k8sVersion string, osType string) (map[string]interface{}, error) {
	data := map[string]interface{}{}
	svcOptions, err := kd.GetRKEK8sServiceOptions(k8sVersion, n.serviceOptionsLister, n.serviceOptions, n.sysImagesLister, n.sysImages, kd.Linux)
	if err != nil {
		logrus.Errorf("getK8sServiceOptions: k8sVersion %s [%v]", k8sVersion, err)
		return data, err
	}
	if svcOptions != nil {
		data["k8s-service-options"] = svcOptions
	}
	if osType == "windows" {
		svcOptionsWindows, err := kd.GetRKEK8sServiceOptions(k8sVersion, n.serviceOptionsLister, n.serviceOptions, n.sysImagesLister, n.sysImages, kd.Windows)
		if err != nil {
			logrus.Errorf("getK8sServiceOptionsWindows: k8sVersion %s [%v]", k8sVersion, err)
			return data, err
		}
		if svcOptionsWindows != nil {
			data["k8s-windows-service-options"] = svcOptionsWindows
		}
	}
	return data, nil
}
<commit_msg>Return err to node if no applied cluster config<commit_after>package rkenodeconfigserver

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	v32 "github.com/rancher/rancher/pkg/apis/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/controllers/dashboard/clusterregistrationtoken"
	"github.com/rancher/rancher/pkg/tunnelserver/mcmauthorizer"

	rketypes "github.com/rancher/rke/types"

	"github.com/pkg/errors"
	util "github.com/rancher/rancher/pkg/cluster"
	kd "github.com/rancher/rancher/pkg/controllers/management/kontainerdrivermetadata"
	v3 "github.com/rancher/rancher/pkg/generated/norman/management.cattle.io/v3"
	"github.com/rancher/rancher/pkg/image"
	"github.com/rancher/rancher/pkg/librke"
	"github.com/rancher/rancher/pkg/rkeworker"
	"github.com/rancher/rancher/pkg/settings"
	"github.com/rancher/rancher/pkg/systemaccount"
	"github.com/rancher/rancher/pkg/taints"
	"github.com/rancher/rancher/pkg/types/config"
	rkepki "github.com/rancher/rke/pki"
	rkeservices "github.com/rancher/rke/services"
	"github.com/sirupsen/logrus"
	v1 "k8s.io/api/core/v1"
)

const (
	DefaultAgentCheckInterval       = 120
	AgentCheckIntervalDuringUpgrade = 35
	AgentCheckIntervalDuringCreate  = 15
)

type RKENodeConfigServer struct {
	auth                 *mcmauthorizer.Authorizer
	lookup               *BundleLookup
	systemAccountManager *systemaccount.Manager
	serviceOptionsLister v3.RkeK8sServiceOptionLister
	serviceOptions       v3.RkeK8sServiceOptionInterface
	sysImagesLister      v3.RkeK8sSystemImageLister
	sysImages            v3.RkeK8sSystemImageInterface
	nodes                v3.NodeInterface
}

func Handler(auth *mcmauthorizer.Authorizer, scaledContext *config.ScaledContext) http.Handler {
	return &RKENodeConfigServer{
		auth:                 auth,
		lookup:               NewLookup(scaledContext.Core.Namespaces(""), scaledContext.Core),
		systemAccountManager: systemaccount.NewManagerFromScale(scaledContext),
		serviceOptionsLister: scaledContext.Management.RkeK8sServiceOptions("").Controller().Lister(),
		serviceOptions:       scaledContext.Management.RkeK8sServiceOptions(""),
		sysImagesLister:      scaledContext.Management.RkeK8sSystemImages("").Controller().Lister(),
		sysImages:            scaledContext.Management.RkeK8sSystemImages(""),
		nodes:                scaledContext.Management.Nodes(""),
	}
}

func (n *RKENodeConfigServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	// 404 tells the client to continue without plan
	// 5xx tells the client to try again later for plan

	client, ok, err := n.auth.Authorize(req)
	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte(err.Error()))
		return
	}

	if !ok {
		rw.WriteHeader(http.StatusUnauthorized)
		return
	}

	if client.Node == nil {
		rw.WriteHeader(http.StatusNotFound)
		return
	}

	if client.Cluster.Status.Driver == "" {
		rw.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	if client.Cluster.Status.Driver != v32.ClusterDriverRKE {
		rw.WriteHeader(http.StatusNotFound)
		return
	}

	if client.Node.Status.NodeConfig == nil {
		rw.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	if client.Cluster.Status.AppliedSpec.RancherKubernetesEngineConfig == nil {
		rw.WriteHeader(http.StatusServiceUnavailable)
		return
	}

	var nodeConfig *rkeworker.NodeConfig
	if IsNonWorker(client.Node.Status.NodeConfig.Role) {
		nodeConfig, err = n.nonWorkerConfig(req.Context(), client.Cluster, client.Node)
	} else {
		if client.NodeVersion != 0 {
			logrus.Debugf("cluster [%s] worker-upgrade: received node-version [%v] for node [%s]", client.Cluster.Name,
				client.NodeVersion, client.Node.Name)

			if client.Node.Status.AppliedNodeVersion != client.NodeVersion {
				nodeCopy := client.Node.DeepCopy()
				logrus.Infof("cluster [%s] worker-upgrade: updating node [%s] with node-version %v", client.Cluster.Name,
					client.Node.Name, client.NodeVersion)

				nodeCopy.Status.AppliedNodeVersion = client.NodeVersion

				_, err = n.nodes.Update(nodeCopy)
				if err != nil {
					logrus.Infof("cluster [%s] worker-upgrade: error updating node [%s] with node-version [%v]: %v", client.Cluster.Name,
						client.Node.Name, client.NodeVersion, err)
				}
			}
		}

		nodeConfig, err = n.nodeConfig(req.Context(), client.Cluster, client.Node)
	}

	if err != nil {
		rw.WriteHeader(http.StatusInternalServerError)
		rw.Write([]byte("Failed to construct node config. Error: " + err.Error()))
		return
	}

	rw.Header().Set("Content-Type", "application/json")

	if err := json.NewEncoder(rw).Encode(nodeConfig); err != nil {
		logrus.Errorf("failed to write nodeConfig to agent: %v", err)
	}
}

func IsNonWorker(roles []string) bool {
	for _, role := range roles {
		if role == rkeservices.ETCDRole {
			return true
		}
		if role == rkeservices.ControlRole {
			return true
		}
	}
	return false
}

func (n *RKENodeConfigServer) nonWorkerConfig(ctx context.Context, cluster *v3.Cluster, node *v3.Node) (*rkeworker.NodeConfig, error) {
	nodePlan := node.Status.NodePlan
	nc := &rkeworker.NodeConfig{
		ClusterName: cluster.Name,
	}

	if nodePlan == nil {
		logrus.Tracef("cluster [%s]: node [%s] doesn't have node plan yet", cluster.Name, node.Name)
		nc.AgentCheckInterval = AgentCheckIntervalDuringCreate
		return nc, nil
	}

	nc.Processes = nodePlan.Plan.Processes
	nc.AgentCheckInterval = nodePlan.AgentCheckInterval

	return nc, nil
}

func (n *RKENodeConfigServer) nodeConfig(ctx context.Context, cluster *v3.Cluster, node *v3.Node) (*rkeworker.NodeConfig, error) {
	status := cluster.Status.AppliedSpec.DeepCopy()
	rkeConfig := status.RancherKubernetesEngineConfig

	nodePlan := node.Status.NodePlan
	hostAddress := node.Status.NodeConfig.Address

	nc := &rkeworker.NodeConfig{
		ClusterName: cluster.Name,
	}

	if nodePlan == nil {
		logrus.Tracef("cluster [%s]: node [%s] %s doesn't have node plan yet", cluster.Name, node.Name, hostAddress)
		nc.AgentCheckInterval = AgentCheckIntervalDuringCreate
		return nc, nil
	}

	infos, err := librke.GetDockerInfo(node)
	if err != nil {
		return nil, err
	}

	bundle, err := n.lookup.Lookup(cluster)
	if err != nil {
		return nil, err
	}

	hostDockerInfo := infos[hostAddress]
	if hostDockerInfo.OSType == "windows" { // compatible with Windows
		bundle = bundle.ForWindowsNode(rkeConfig, hostAddress)
	} else {
		bundle = bundle.ForNode(rkeConfig, hostAddress)
	}

	if rkepki.IsKubeletGenerateServingCertificateEnabledinConfig(rkeConfig) {
		logrus.Debugf("nodeConfig: VerifyKubeletCAEnabled is true, generating kubelet certificate for [%s]", hostAddress)
		err := rkepki.GenerateKubeletCertificate(ctx, bundle.Certs(), *rkeConfig, "", "", false)
		if err != nil {
			return nil, errors.Wrapf(err, "failed to generate kubelet certificate")
		}
	}
	certString, err := bundle.SafeMarshal()
	if err != nil {
		return nil, errors.Wrapf(err, "failed to marshal certificates bundle")
	}
	nc.Certs = certString
	np := nodePlan.Plan
	nc.Processes = np.Processes
	nc.Files = np.Files
	if nodePlan.AgentCheckInterval != 0 {
		nc.AgentCheckInterval = nodePlan.AgentCheckInterval
	}

	if node.Status.AppliedNodeVersion != cluster.Status.NodeVersion {
		if nodePlan.Version == cluster.Status.NodeVersion {
			nc.NodeVersion = cluster.Status.NodeVersion
			logrus.Infof("cluster [%s] worker-upgrade: sending node-version for node [%s] version %v", cluster.Name, node.Status.NodeName, nc.NodeVersion)
		} else if v32.ClusterConditionUpgraded.IsUnknown(cluster) {
			if nc.AgentCheckInterval != AgentCheckIntervalDuringUpgrade {
				nodeCopy := node.DeepCopy()
				nodeCopy.Status.NodePlan.AgentCheckInterval = AgentCheckIntervalDuringUpgrade

				n.nodes.Update(nodeCopy)

				logrus.Infof("cluster [%s] worker-upgrade: updating [%s] with agent-interval [%v]", cluster.Name, node.Status.NodeName, AgentCheckIntervalDuringUpgrade)
				nc.AgentCheckInterval = AgentCheckIntervalDuringUpgrade
			}
		}
	}
	return nc, nil
}

func FilterHostForSpec(spec *rketypes.RancherKubernetesEngineConfig, n *v3.Node) {
	nodeList := make([]rketypes.RKEConfigNode, 0)
	for _, node := range spec.Nodes {
		if IsNonWorker(node.Role) || node.NodeName == n.Status.NodeConfig.NodeName {
			nodeList = append(nodeList, node)
		}
	}
	spec.Nodes = nodeList
}

func AugmentProcesses(token string, processes map[string]rketypes.Process, worker bool, nodeName string,
	cluster *v3.Cluster) (map[string]rketypes.Process, error) {
	var shared bool

OuterLoop:
	for _, process := range processes {
		for _, bind := range process.Binds {
			parts := strings.Split(bind, ":")
			if len(parts) > 2 && strings.Contains(parts[2], "shared") {
				shared = true
				break OuterLoop
			}
		}
	}

	if shared {
		agentImage := settings.AgentImage.Get()
		nodeCommand, err := clusterregistrationtoken.ShareMntCommand(nodeName, token, cluster)
		if err != nil {
			return nil, err
		}
		privateRegistryConfig, _ := util.GenerateClusterPrivateRegistryDockerConfig(cluster)
		processes["share-mnt"] = rketypes.Process{
			Name:  "share-mnt",
			Args:  nodeCommand,
			Image: image.ResolveWithCluster(agentImage, cluster),
			Binds: []string{
				"/var/run:/var/run",
				"/etc/kubernetes:/etc/kubernetes",
			},
			NetworkMode:             "host",
			RestartPolicy:           "always",
			Privileged:              true,
			ImageRegistryAuthConfig: privateRegistryConfig,
		}
	}

	if worker {
		// not sure if we really need this anymore
		delete(processes, "etcd")
	} else {
		if p, ok := processes["share-mnt"]; ok {
			processes = map[string]rketypes.Process{
				"share-mnt": p,
			}
		} else {
			processes = nil
		}
	}

	for _, p := range processes {
		for i, bind := range p.Binds {
			parts := strings.Split(bind, ":")
			if len(parts) > 1 && parts[1] == "/etc/kubernetes" {
				parts[0] = parts[1]
				p.Binds[i] = strings.Join(parts, ":")
			}
		}
	}

	return processes, nil
}

func EnhanceWindowsProcesses(processes map[string]rketypes.Process) map[string]rketypes.Process {
	newProcesses := make(map[string]rketypes.Process, len(processes))
	for k, p := range processes {
		p.Binds = append(p.Binds,
			"//./pipe/rancher_wins://./pipe/rancher_wins",
		)
		newProcesses[k] = p
	}

	return newProcesses
}

func AppendTaintsToKubeletArgs(processes map[string]rketypes.Process, nodeConfigTaints []rketypes.RKETaint) map[string]rketypes.Process {
	if kubelet, ok := processes["kubelet"]; ok && len(nodeConfigTaints) != 0 {
		initialTaints := taints.GetTaintsFromStrings(taints.GetStringsFromRKETaint(nodeConfigTaints))
		var currentTaints []v1.Taint
		foundArgs := ""
		for i, arg := range kubelet.Command {
			if strings.HasPrefix(arg, "--register-with-taints=") {
				foundArgs = strings.TrimPrefix(arg, "--register-with-taints=")
				kubelet.Command = append(kubelet.Command[:i], kubelet.Command[i+1:]...)
				break
			}
		}
		if foundArgs != "" {
			currentTaints = taints.GetTaintsFromStrings(strings.Split(foundArgs, ","))
		}

		// The initial taints are from node pool and node template. They should override the taints from kubelet args.
		mergedTaints := taints.MergeTaints(currentTaints, initialTaints)

		taintArgs := fmt.Sprintf("--register-with-taints=%s", strings.Join(taints.GetStringsFromTaint(mergedTaints), ","))
		kubelet.Command = append(kubelet.Command, taintArgs)
		processes["kubelet"] = kubelet
	}
	return processes
}

func (n *RKENodeConfigServer) getServiceOptions(k8sVersion string, osType string) (map[string]interface{}, error) {
	data := map[string]interface{}{}
	svcOptions, err := kd.GetRKEK8sServiceOptions(k8sVersion, n.serviceOptionsLister, n.serviceOptions, n.sysImagesLister, n.sysImages, kd.Linux)
	if err != nil {
		logrus.Errorf("getK8sServiceOptions: k8sVersion %s [%v]", k8sVersion, err)
		return data, err
	}
	if svcOptions != nil {
		data["k8s-service-options"] = svcOptions
	}
	if osType == "windows" {
		svcOptionsWindows, err := kd.GetRKEK8sServiceOptions(k8sVersion, n.serviceOptionsLister, n.serviceOptions, n.sysImagesLister, n.sysImages, kd.Windows)
		if err != nil {
			logrus.Errorf("getK8sServiceOptionsWindows: k8sVersion %s [%v]", k8sVersion, err)
			return data, err
		}
		if svcOptionsWindows != nil {
			data["k8s-windows-service-options"] = svcOptionsWindows
		}
	}
	return data, nil
}
<|endoftext|>


<commit_before>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package auth

import (
	"gvisor.googlesource.com/gvisor/pkg/abi/linux"
	"gvisor.googlesource.com/gvisor/pkg/syserror"
)

// Credentials contains information required to authorize privileged operations
// in a user namespace.
//
// +stateify savable
type Credentials struct {
	// Real/effective/saved user/group IDs in the root user namespace. None of
	// these should ever be NoID.
	RealKUID      KUID
	EffectiveKUID KUID
	SavedKUID     KUID
	RealKGID      KGID
	EffectiveKGID KGID
	SavedKGID     KGID

	// Filesystem user/group IDs are not implemented. "... setfsuid() is
	// nowadays unneeded and should be avoided in new applications (likewise
	// for setfsgid(2))." - setfsuid(2)

	// Supplementary groups used by set/getgroups.
	//
	// ExtraKGIDs slices are immutable, allowing multiple Credentials with the
	// same ExtraKGIDs to share the same slice.
	ExtraKGIDs []KGID

	// The capability sets applicable to this set of credentials.
	PermittedCaps   CapabilitySet
	InheritableCaps CapabilitySet
	EffectiveCaps   CapabilitySet
	BoundingCaps    CapabilitySet
	// Ambient capabilities are not introduced until Linux 4.3.

	// KeepCaps is the flag for PR_SET_KEEPCAPS which allow capabilities to be
	// maintained after a switch from root user to non-root user via setuid().
	KeepCaps bool

	// The user namespace associated with the owner of the credentials.
	UserNamespace *UserNamespace
}

// NewAnonymousCredentials returns a set of credentials with no capabilities in
// any user namespace.
func NewAnonymousCredentials() *Credentials {
	// Create a new root user namespace. Since the new namespace's owner is
	// KUID 0 and the returned credentials have non-zero KUID/KGID, the
	// returned credentials do not have any capabilities in the new namespace.
	// Since the new namespace is not part of any existing user namespace
	// hierarchy, the returned credentials do not have any capabilities in any
	// other namespace.
	return &Credentials{
		RealKUID:      NobodyKUID,
		EffectiveKUID: NobodyKUID,
		SavedKUID:     NobodyKUID,
		RealKGID:      NobodyKGID,
		EffectiveKGID: NobodyKGID,
		SavedKGID:     NobodyKGID,
		UserNamespace: NewRootUserNamespace(),
	}
}

// NewRootCredentials returns a set of credentials with KUID and KGID 0 (i.e.
// global root) in user namespace ns.
func NewRootCredentials(ns *UserNamespace) *Credentials {
	// I can't find documentation for this anywhere, but it's correct for the
	// inheritable capability set to be initially empty (the capabilities test
	// checks for this property).
	return &Credentials{
		RealKUID:      RootKUID,
		EffectiveKUID: RootKUID,
		SavedKUID:     RootKUID,
		RealKGID:      RootKGID,
		EffectiveKGID: RootKGID,
		SavedKGID:     RootKGID,
		PermittedCaps: AllCapabilities,
		EffectiveCaps: AllCapabilities,
		BoundingCaps:  AllCapabilities,
		UserNamespace: ns,
	}
}

// NewUserCredentials returns a set of credentials based on the given UID, GIDs,
// and capabilities in a given namespace. If all arguments are their zero
// values, this returns the same credentials as NewRootCredentials.
func NewUserCredentials(kuid KUID, kgid KGID, extraKGIDs []KGID, capabilities *TaskCapabilities, ns *UserNamespace) *Credentials {
	creds := NewRootCredentials(ns)

	// Set the UID.
	uid := kuid
	creds.RealKUID = uid
	creds.EffectiveKUID = uid
	creds.SavedKUID = uid

	// Set GID.
	gid := kgid
	creds.RealKGID = gid
	creds.EffectiveKGID = gid
	creds.SavedKGID = gid

	// Set additional GIDs.
	creds.ExtraKGIDs = append(creds.ExtraKGIDs, extraKGIDs...)

	// Set capabilities. If capabilities aren't specified, we default to
	// all capabilities.
	if capabilities != nil {
		creds.PermittedCaps = capabilities.PermittedCaps
		creds.EffectiveCaps = capabilities.EffectiveCaps
		creds.BoundingCaps = capabilities.BoundingCaps
		creds.InheritableCaps = capabilities.InheritableCaps
		// // TODO: Support ambient capabilities.
	} else {
		// If no capabilities are specified, grant the same capabilities
		// that NewRootCredentials does.
		creds.PermittedCaps = AllCapabilities
		creds.EffectiveCaps = AllCapabilities
		creds.BoundingCaps = AllCapabilities
	}

	return creds
}

// Fork generates an identical copy of a set of credentials.
func (c *Credentials) Fork() *Credentials {
	nc := new(Credentials)
	*nc = *c // Copy-by-value; this is legal for all fields.
	return nc
}

// InGroup returns true if c is in group kgid. Compare Linux's
// kernel/groups.c:in_group_p().
func (c *Credentials) InGroup(kgid KGID) bool {
	if c.EffectiveKGID == kgid {
		return true
	}
	for _, extraKGID := range c.ExtraKGIDs {
		if extraKGID == kgid {
			return true
		}
	}
	return false
}

// HasCapabilityIn returns true if c has capability cp in ns.
func (c *Credentials) HasCapabilityIn(cp linux.Capability, ns *UserNamespace) bool {
	for {
		// "1. A process has a capability inside a user namespace if it is a member
		// of that namespace and it has the capability in its effective capability
		// set." - user_namespaces(7)
		if c.UserNamespace == ns {
			return CapabilitySetOf(cp)&c.EffectiveCaps != 0
		}
		// "3. ... A process that resides in the parent of the user namespace and
		// whose effective user ID matches the owner of the namespace has all
		// capabilities in the namespace."
		if c.UserNamespace == ns.parent && c.EffectiveKUID == ns.owner {
			return true
		}
		// "2. If a process has a capability in a user namespace, then it has that
		// capability in all child (and further removed descendant) namespaces as
		// well."
		if ns.parent == nil {
			return false
		}
		ns = ns.parent
	}
}

// HasCapability returns true if c has capability cp in its user namespace.
func (c *Credentials) HasCapability(cp linux.Capability) bool {
	return c.HasCapabilityIn(cp, c.UserNamespace)
}

// UseUID checks that c can use uid in its user namespace, then translates it
// to the root user namespace.
//
// The checks UseUID does are common, but you should verify that it's doing
// exactly what you want.
func (c *Credentials) UseUID(uid UID) (KUID, error) {
	// uid must be mapped.
	kuid := c.UserNamespace.MapToKUID(uid)
	if !kuid.Ok() {
		return NoID, syserror.EINVAL
	}
	// If c has CAP_SETUID, then it can use any UID in its user namespace.
	if c.HasCapability(linux.CAP_SETUID) {
		return kuid, nil
	}
	// Otherwise, c must already have the UID as its real, effective, or saved
	// set-user-ID.
	if kuid == c.RealKUID || kuid == c.EffectiveKUID || kuid == c.SavedKUID {
		return kuid, nil
	}
	return NoID, syserror.EPERM
}

// UseGID checks that c can use gid in its user namespace, then translates it
// to the root user namespace.
func (c *Credentials) UseGID(gid GID) (KGID, error) {
	kgid := c.UserNamespace.MapToKGID(gid)
	if !kgid.Ok() {
		return NoID, syserror.EINVAL
	}
	if c.HasCapability(linux.CAP_SETGID) {
		return kgid, nil
	}
	if kgid == c.RealKGID || kgid == c.EffectiveKGID || kgid == c.SavedKGID {
		return kgid, nil
	}
	return NoID, syserror.EPERM
}
<commit_msg>Grant no initial capabilities to non-root UIDs.<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package auth

import (
	"gvisor.googlesource.com/gvisor/pkg/abi/linux"
	"gvisor.googlesource.com/gvisor/pkg/syserror"
)

// Credentials contains information required to authorize privileged operations
// in a user namespace.
//
// +stateify savable
type Credentials struct {
	// Real/effective/saved user/group IDs in the root user namespace. None of
	// these should ever be NoID.
	RealKUID      KUID
	EffectiveKUID KUID
	SavedKUID     KUID
	RealKGID      KGID
	EffectiveKGID KGID
	SavedKGID     KGID

	// Filesystem user/group IDs are not implemented. "... setfsuid() is
	// nowadays unneeded and should be avoided in new applications (likewise
	// for setfsgid(2))." - setfsuid(2)

	// Supplementary groups used by set/getgroups.
	//
	// ExtraKGIDs slices are immutable, allowing multiple Credentials with the
	// same ExtraKGIDs to share the same slice.
	ExtraKGIDs []KGID

	// The capability sets applicable to this set of credentials.
	PermittedCaps   CapabilitySet
	InheritableCaps CapabilitySet
	EffectiveCaps   CapabilitySet
	BoundingCaps    CapabilitySet
	// Ambient capabilities are not introduced until Linux 4.3.

	// KeepCaps is the flag for PR_SET_KEEPCAPS which allow capabilities to be
	// maintained after a switch from root user to non-root user via setuid().
	KeepCaps bool

	// The user namespace associated with the owner of the credentials.
	UserNamespace *UserNamespace
}

// NewAnonymousCredentials returns a set of credentials with no capabilities in
// any user namespace.
func NewAnonymousCredentials() *Credentials {
	// Create a new root user namespace. Since the new namespace's owner is
	// KUID 0 and the returned credentials have non-zero KUID/KGID, the
	// returned credentials do not have any capabilities in the new namespace.
	// Since the new namespace is not part of any existing user namespace
	// hierarchy, the returned credentials do not have any capabilities in any
	// other namespace.
	return &Credentials{
		RealKUID:      NobodyKUID,
		EffectiveKUID: NobodyKUID,
		SavedKUID:     NobodyKUID,
		RealKGID:      NobodyKGID,
		EffectiveKGID: NobodyKGID,
		SavedKGID:     NobodyKGID,
		UserNamespace: NewRootUserNamespace(),
	}
}

// NewRootCredentials returns a set of credentials with KUID and KGID 0 (i.e.
// global root) in user namespace ns.
func NewRootCredentials(ns *UserNamespace) *Credentials {
	// I can't find documentation for this anywhere, but it's correct for the
	// inheritable capability set to be initially empty (the capabilities test
	// checks for this property).
	return &Credentials{
		RealKUID:      RootKUID,
		EffectiveKUID: RootKUID,
		SavedKUID:     RootKUID,
		RealKGID:      RootKGID,
		EffectiveKGID: RootKGID,
		SavedKGID:     RootKGID,
		PermittedCaps: AllCapabilities,
		EffectiveCaps: AllCapabilities,
		BoundingCaps:  AllCapabilities,
		UserNamespace: ns,
	}
}

// NewUserCredentials returns a set of credentials based on the given UID, GIDs,
// and capabilities in a given namespace. If all arguments are their zero
// values, this returns the same credentials as NewRootCredentials.
func NewUserCredentials(kuid KUID, kgid KGID, extraKGIDs []KGID, capabilities *TaskCapabilities, ns *UserNamespace) *Credentials {
	creds := NewRootCredentials(ns)

	// Set the UID.
	uid := kuid
	creds.RealKUID = uid
	creds.EffectiveKUID = uid
	creds.SavedKUID = uid

	// Set GID.
	gid := kgid
	creds.RealKGID = gid
	creds.EffectiveKGID = gid
	creds.SavedKGID = gid

	// Set additional GIDs.
	creds.ExtraKGIDs = append(creds.ExtraKGIDs, extraKGIDs...)

	// Set capabilities.
	if capabilities != nil {
		creds.PermittedCaps = capabilities.PermittedCaps
		creds.EffectiveCaps = capabilities.EffectiveCaps
		creds.BoundingCaps = capabilities.BoundingCaps
		creds.InheritableCaps = capabilities.InheritableCaps
		// TODO: Support ambient capabilities.
	} else {
		// If no capabilities are specified, grant capabilities consistent with
		// setresuid + setresgid from NewRootCredentials to the given uid and
		// gid.
		if kuid == RootKUID {
			creds.PermittedCaps = AllCapabilities
			creds.EffectiveCaps = AllCapabilities
		} else {
			creds.PermittedCaps = 0
			creds.EffectiveCaps = 0
		}
		creds.BoundingCaps = AllCapabilities
	}

	return creds
}

// Fork generates an identical copy of a set of credentials.
func (c *Credentials) Fork() *Credentials {
	nc := new(Credentials)
	*nc = *c // Copy-by-value; this is legal for all fields.
	return nc
}

// InGroup returns true if c is in group kgid. Compare Linux's
// kernel/groups.c:in_group_p().
func (c *Credentials) InGroup(kgid KGID) bool {
	if c.EffectiveKGID == kgid {
		return true
	}
	for _, extraKGID := range c.ExtraKGIDs {
		if extraKGID == kgid {
			return true
		}
	}
	return false
}

// HasCapabilityIn returns true if c has capability cp in ns.
func (c *Credentials) HasCapabilityIn(cp linux.Capability, ns *UserNamespace) bool {
	for {
		// "1. A process has a capability inside a user namespace if it is a member
		// of that namespace and it has the capability in its effective capability
		// set." - user_namespaces(7)
		if c.UserNamespace == ns {
			return CapabilitySetOf(cp)&c.EffectiveCaps != 0
		}
		// "3. ... A process that resides in the parent of the user namespace and
		// whose effective user ID matches the owner of the namespace has all
		// capabilities in the namespace."
		if c.UserNamespace == ns.parent && c.EffectiveKUID == ns.owner {
			return true
		}
		// "2. If a process has a capability in a user namespace, then it has that
		// capability in all child (and further removed descendant) namespaces as
		// well."
		if ns.parent == nil {
			return false
		}
		ns = ns.parent
	}
}

// HasCapability returns true if c has capability cp in its user namespace.
func (c *Credentials) HasCapability(cp linux.Capability) bool {
	return c.HasCapabilityIn(cp, c.UserNamespace)
}

// UseUID checks that c can use uid in its user namespace, then translates it
// to the root user namespace.
//
// The checks UseUID does are common, but you should verify that it's doing
// exactly what you want.
func (c *Credentials) UseUID(uid UID) (KUID, error) {
	// uid must be mapped.
	kuid := c.UserNamespace.MapToKUID(uid)
	if !kuid.Ok() {
		return NoID, syserror.EINVAL
	}
	// If c has CAP_SETUID, then it can use any UID in its user namespace.
	if c.HasCapability(linux.CAP_SETUID) {
		return kuid, nil
	}
	// Otherwise, c must already have the UID as its real, effective, or saved
	// set-user-ID.
	if kuid == c.RealKUID || kuid == c.EffectiveKUID || kuid == c.SavedKUID {
		return kuid, nil
	}
	return NoID, syserror.EPERM
}

// UseGID checks that c can use gid in its user namespace, then translates it
// to the root user namespace.
func (c *Credentials) UseGID(gid GID) (KGID, error) {
	kgid := c.UserNamespace.MapToKGID(gid)
	if !kgid.Ok() {
		return NoID, syserror.EINVAL
	}
	if c.HasCapability(linux.CAP_SETGID) {
		return kgid, nil
	}
	if kgid == c.RealKGID || kgid == c.EffectiveKGID || kgid == c.SavedKGID {
		return kgid, nil
	}
	return NoID, syserror.EPERM
}
<|endoftext|>


<commit_before>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2017 Red Hat, Inc.
 *
 */

package cmdclient

//go:generate mockgen -source $GOFILE -package=$GOPACKAGE -destination=generated_mock_$GOFILE

/*
 ATTENTION: Rerun code generators when interface signatures are modified.
*/

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/rpc"
	"os"
	"path/filepath"
	"syscall"

	"kubevirt.io/kubevirt/pkg/api/v1"
	diskutils "kubevirt.io/kubevirt/pkg/ephemeral-disk-utils"
	"kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
)

type Reply struct {
	Success bool
	Message string
	Domain  *api.Domain
}

type Args struct {
	// used for domain management
	VMI *v1.VirtualMachineInstance
}

type LauncherClient interface {
	SyncVirtualMachine(vmi *v1.VirtualMachineInstance) error
	SyncMigrationTarget(vmi *v1.VirtualMachineInstance) error
	ShutdownVirtualMachine(vmi *v1.VirtualMachineInstance) error
	KillVirtualMachine(vmi *v1.VirtualMachineInstance) error
	MigrateVirtualMachine(vmi *v1.VirtualMachineInstance) error
	DeleteDomain(vmi *v1.VirtualMachineInstance) error
	GetDomain() (*api.Domain, bool, error)
	Ping() error
	Close()
}

type VirtLauncherClient struct {
	client *rpc.Client
}

func ListAllSockets(baseDir string) ([]string, error) {
	var socketFiles []string

	fileDir := filepath.Join(baseDir, "sockets")
	exists, err := diskutils.FileExists(fileDir)
	if err != nil {
		return nil, err
	}

	if exists == false {
		return socketFiles, nil
	}

	files, err := ioutil.ReadDir(fileDir)
	if err != nil {
		return nil, err
	}
	for _, file := range files {
		socketFiles = append(socketFiles, filepath.Join(fileDir, file.Name()))
	}
	return socketFiles, nil
}

func SocketsDirectory(baseDir string) string {
	return filepath.Join(baseDir, "sockets")
}

func SocketFromUID(baseDir string, uid string) string {
	sockFile := uid + "_sock"
	return filepath.Join(SocketsDirectory(baseDir), sockFile)
}

func GetClient(socketPath string) (LauncherClient, error) {
	conn, err := rpc.Dial("unix", socketPath)
	if err != nil {
		return nil, err
	}

	return &VirtLauncherClient{client: conn}, nil
}

func (c *VirtLauncherClient) Close() {
	c.client.Close()
}

func (c *VirtLauncherClient) genericSendCmd(args *Args, cmd string) (*Reply, error) {
	reply := &Reply{}

	err := c.client.Call(cmd, args, reply)
	if IsDisconnected(err) {
		return reply, err
	} else if err != nil {
		msg := fmt.Sprintf("unknown error encountered sending command %s: %s", cmd, err.Error())
		return reply, fmt.Errorf(msg)
	} else if reply.Success != true {
		msg := fmt.Sprintf("server error. command %s failed: %s", cmd, reply.Message)
		return reply, fmt.Errorf(msg)
	}
	return reply, nil
}

func (c *VirtLauncherClient) ShutdownVirtualMachine(vmi *v1.VirtualMachineInstance) error {
	cmd := "Launcher.Shutdown"

	args := &Args{
		VMI: vmi,
	}
	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) MigrateVirtualMachine(vmi *v1.VirtualMachineInstance) error {
	cmd := "Launcher.Migrate"

	args := &Args{
		VMI: vmi,
	}
	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) KillVirtualMachine(vmi *v1.VirtualMachineInstance) error {
	cmd := "Launcher.Kill"

	args := &Args{
		VMI: vmi,
	}
	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) DeleteDomain(vmi *v1.VirtualMachineInstance) error {
	cmd := "Launcher.Delete"

	args := &Args{
		VMI: vmi,
	}
	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) GetDomain() (*api.Domain, bool, error) {
	domain := &api.Domain{}
	cmd := "Launcher.GetDomain"
	exists := false

	args := &Args{}

	reply, err := c.genericSendCmd(args, cmd)
	if err != nil {
		return nil, exists, err
	}

	if reply.Domain != nil {
		domain = reply.Domain
		exists = true
	}
	return domain, exists, nil

}
func (c *VirtLauncherClient) SyncVirtualMachine(vmi *v1.VirtualMachineInstance) error {

	cmd := "Launcher.Sync"

	args := &Args{
		VMI: vmi,
	}

	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) SyncMigrationTarget(vmi *v1.VirtualMachineInstance) error {

	cmd := "Launcher.SyncMigrationTarget"

	args := &Args{
		VMI: vmi,
	}

	_, err := c.genericSendCmd(args, cmd)

	return err
}

func IsDisconnected(err error) bool {
	if err == nil {
		return false
	}
	if err == rpc.ErrShutdown || err == io.ErrUnexpectedEOF || err == io.EOF {
		return true
	}

	if opErr, ok := err.(*net.OpError); ok {
		if syscallErr, ok := opErr.Err.(*os.SyscallError); ok {
			// catches "connection reset by peer"
			if syscallErr.Err == syscall.ECONNRESET {
				return true
			}
		}
	}

	return false
}

func (c *VirtLauncherClient) Ping() error {
	cmd := "Launcher.Ping"
	args := &Args{}
	_, err := c.genericSendCmd(args, cmd)

	return err
}
<commit_msg>Fixed error message formatting<commit_after>/*
 * This file is part of the KubeVirt project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2017 Red Hat, Inc.
 *
 */

package cmdclient

//go:generate mockgen -source $GOFILE -package=$GOPACKAGE -destination=generated_mock_$GOFILE

/*
 ATTENTION: Rerun code generators when interface signatures are modified.
*/

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/rpc"
	"os"
	"path/filepath"
	"syscall"

	"kubevirt.io/kubevirt/pkg/api/v1"
	diskutils "kubevirt.io/kubevirt/pkg/ephemeral-disk-utils"
	"kubevirt.io/kubevirt/pkg/virt-launcher/virtwrap/api"
)

type Reply struct {
	Success bool
	Message string
	Domain  *api.Domain
}

type Args struct {
	// used for domain management
	VMI *v1.VirtualMachineInstance
}

type LauncherClient interface {
	SyncVirtualMachine(vmi *v1.VirtualMachineInstance) error
	SyncMigrationTarget(vmi *v1.VirtualMachineInstance) error
	ShutdownVirtualMachine(vmi *v1.VirtualMachineInstance) error
	KillVirtualMachine(vmi *v1.VirtualMachineInstance) error
	MigrateVirtualMachine(vmi *v1.VirtualMachineInstance) error
	DeleteDomain(vmi *v1.VirtualMachineInstance) error
	GetDomain() (*api.Domain, bool, error)
	Ping() error
	Close()
}

type VirtLauncherClient struct {
	client *rpc.Client
}

func ListAllSockets(baseDir string) ([]string, error) {
	var socketFiles []string

	fileDir := filepath.Join(baseDir, "sockets")
	exists, err := diskutils.FileExists(fileDir)
	if err != nil {
		return nil, err
	}

	if exists == false {
		return socketFiles, nil
	}

	files, err := ioutil.ReadDir(fileDir)
	if err != nil {
		return nil, err
	}
	for _, file := range files {
		socketFiles = append(socketFiles, filepath.Join(fileDir, file.Name()))
	}
	return socketFiles, nil
}

func SocketsDirectory(baseDir string) string {
	return filepath.Join(baseDir, "sockets")
}

func SocketFromUID(baseDir string, uid string) string {
	sockFile := uid + "_sock"
	return filepath.Join(SocketsDirectory(baseDir), sockFile)
}

func GetClient(socketPath string) (LauncherClient, error) {
	conn, err := rpc.Dial("unix", socketPath)
	if err != nil {
		return nil, err
	}

	return &VirtLauncherClient{client: conn}, nil
}

func (c *VirtLauncherClient) Close() {
	c.client.Close()
}

func (c *VirtLauncherClient) genericSendCmd(args *Args, cmd string) (*Reply, error) {
	reply := &Reply{}

	err := c.client.Call(cmd, args, reply)
	if IsDisconnected(err) {
		return reply, err
	} else if err != nil {
		msg := fmt.Sprintf("unknown error encountered sending command %s: %s", cmd, err.Error())
		return reply, fmt.Errorf(msg)
	} else if reply.Success != true {
		return reply, fmt.Errorf("server error. command %s failed: %q", cmd, reply.Message)
	}
	return reply, nil
}

func (c *VirtLauncherClient) ShutdownVirtualMachine(vmi *v1.VirtualMachineInstance) error {
	cmd := "Launcher.Shutdown"

	args := &Args{
		VMI: vmi,
	}
	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) MigrateVirtualMachine(vmi *v1.VirtualMachineInstance) error {
	cmd := "Launcher.Migrate"

	args := &Args{
		VMI: vmi,
	}
	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) KillVirtualMachine(vmi *v1.VirtualMachineInstance) error {
	cmd := "Launcher.Kill"

	args := &Args{
		VMI: vmi,
	}
	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) DeleteDomain(vmi *v1.VirtualMachineInstance) error {
	cmd := "Launcher.Delete"

	args := &Args{
		VMI: vmi,
	}
	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) GetDomain() (*api.Domain, bool, error) {
	domain := &api.Domain{}
	cmd := "Launcher.GetDomain"
	exists := false

	args := &Args{}

	reply, err := c.genericSendCmd(args, cmd)
	if err != nil {
		return nil, exists, err
	}

	if reply.Domain != nil {
		domain = reply.Domain
		exists = true
	}
	return domain, exists, nil

}
func (c *VirtLauncherClient) SyncVirtualMachine(vmi *v1.VirtualMachineInstance) error {

	cmd := "Launcher.Sync"

	args := &Args{
		VMI: vmi,
	}

	_, err := c.genericSendCmd(args, cmd)

	return err
}

func (c *VirtLauncherClient) SyncMigrationTarget(vmi *v1.VirtualMachineInstance) error {

	cmd := "Launcher.SyncMigrationTarget"

	args := &Args{
		VMI: vmi,
	}

	_, err := c.genericSendCmd(args, cmd)

	return err
}

func IsDisconnected(err error) bool {
	if err == nil {
		return false
	}
	if err == rpc.ErrShutdown || err == io.ErrUnexpectedEOF || err == io.EOF {
		return true
	}

	if opErr, ok := err.(*net.OpError); ok {
		if syscallErr, ok := opErr.Err.(*os.SyscallError); ok {
			// catches "connection reset by peer"
			if syscallErr.Err == syscall.ECONNRESET {
				return true
			}
		}
	}

	return false
}

func (c *VirtLauncherClient) Ping() error {
	cmd := "Launcher.Ping"
	args := &Args{}
	_, err := c.genericSendCmd(args, cmd)

	return err
}
<|endoftext|>