<commit_before>package flow

import (
	"net/http"
	"strconv"

	"github.com/gotgo/chunk"
	"github.com/gotgo/fw/me"
)

const formFileKey = "file"

//flowChunkNumber
//flowChunkSize
//flowCurrentChunkSize
//flowTotalSize
//flowIdentifier
//flowFilename
//flowRelativePath
//flowTotalChunks

const bufferSize = 1024*1024 + 4096

func ChunkAlreadyUploaded(r *http.Request, d chunk.Destination) (bool, int, string) {
	ul, missingField := FlowParse(r)
	if missingField != "" {
		return false, 400, "bad request - missing data " + missingField
	}

	ul.Destination = d

	exists := ul.ChunkAlreadyUploaded()
	if !exists {
		return false, 404, "not found"
	} else {
		return true, 200, "OK"
	}
}

func UploadChunk(r *http.Request, d chunk.Destination) (*chunk.ChunkFolder, int, string) {
	u, missingField := FlowParse(r)
	if missingField != "" {
		return nil, 400, "bad request - missing data " + missingField
	}

	u.Destination = d

	r.ParseMultipartForm(bufferSize)

	if r.MultipartForm == nil {
		return nil, 400, "bad request - no multipart form"
	}

	if r.MultipartForm.File == nil {
		return nil, 400, "no files in multipart form"
	}

	files := r.MultipartForm.File[formFileKey]

	if len(files) > 1 {
		return nil, 400, "more than 1 file present for key " + formFileKey
	} else if len(files) == 0 {
		return nil, 400, "no file found at multipart key:" + formFileKey
	}

	f, err := files[0].Open()
	if err != nil {
		return nil, 500, "failed to open the submitted file"
	}
	f.Close()
	completed, err := u.UploadChunk(f)

	if err != nil {
		return nil, 500, "failed to upload file"
	}

	return completed, 200, "OK"
}

func FlowParse(r *http.Request) (*chunk.ChunkUpload, string) {
	u := new(chunk.ChunkUpload)
	var err error

	u.ChunkSize, err = requireIntValue(r, "flowChunkSize")
	if err != nil {
		return nil, "flowChunkSize"
	}

	u.CurrentChunkNumber, err = requireIntValue(r, "flowChunkNumber")
	if err != nil {
		return nil, "flowchunkNumber"
	}

	u.CurrentChunkSize, err = requireIntValue(r, "flowCurrentChunkSize")
	if err != nil {
		return nil, "flowCurrentChunkSize"
	}

	u.TotalSize, err = requireInt64Value(r, "flowTotalSize")
	if err != nil {
		return nil, "flowTotalSize"
	}

	u.Identifier = r.FormValue("flowIdentifier")
	if u.Identifier == "" {
		return nil, "flowIdentifier"
	}

	u.Filename = r.FormValue("flowFilename")
	u.RelativePath = r.FormValue("flowRelativePath")

	u.TotalChunks, err = requireIntValue(r, "flowTotalChunks")
	if err != nil {
		return nil, "flowTotalChunks"
	}
	return u, ""
}

//http util
func requireIntValue(r *http.Request, name string) (int, error) {
	val := r.FormValue(name)
	if val == "" {
		return 0, me.NewErr(name + " missing")
	}

	v, e := strconv.ParseInt(r.FormValue("flowTotalSize"), 10, 0)
	return int(v), e
}

func requireInt64Value(r *http.Request, name string) (int64, error) {
	val := r.FormValue(name)
	if val == "" {
		return 0, me.NewErr(name + " missing")
	}

	return strconv.ParseInt(r.FormValue("flowTotalSize"), 10, 64)
}
<commit_msg>added error<commit_after>package flow

import (
	"net/http"
	"strconv"

	"github.com/gotgo/chunk"
	"github.com/gotgo/fw/me"
)

const formFileKey = "file"

//flowChunkNumber
//flowChunkSize
//flowCurrentChunkSize
//flowTotalSize
//flowIdentifier
//flowFilename
//flowRelativePath
//flowTotalChunks

const bufferSize = 1024*1024 + 4096

func ChunkAlreadyUploaded(r *http.Request, d chunk.Destination) (bool, int, string) {
	ul, missingField := FlowParse(r)
	if missingField != "" {
		return false, 400, "bad request - missing data " + missingField
	}

	ul.Destination = d

	exists := ul.ChunkAlreadyUploaded()
	if !exists {
		return false, 404, "not found"
	} else {
		return true, 200, "OK"
	}
}

func UploadChunk(r *http.Request, d chunk.Destination) (*chunk.ChunkFolder, int, string, error) {
	u, missingField := FlowParse(r)
	if missingField != "" {
		return nil, 400, "bad request - missing data " + missingField, nil
	}

	u.Destination = d

	r.ParseMultipartForm(bufferSize)

	if r.MultipartForm == nil {
		return nil, 400, "bad request - no multipart form", nil
	}

	if r.MultipartForm.File == nil {
		return nil, 400, "no files in multipart form", nil
	}

	files := r.MultipartForm.File[formFileKey]

	if len(files) > 1 {
		return nil, 400, "more than 1 file present for key " + formFileKey, nil
	} else if len(files) == 0 {
		return nil, 400, "no file found at multipart key:" + formFileKey, nil
	}

	f, err := files[0].Open()
	if err != nil {
		return nil, 500, "failed to open the submitted file", err
	}
	f.Close()
	completed, err := u.UploadChunk(f)

	if err != nil {
		return nil, 500, "failed to upload file", err
	}

	return completed, 200, "OK", nil
}

func FlowParse(r *http.Request) (*chunk.ChunkUpload, string) {
	u := new(chunk.ChunkUpload)
	var err error

	u.ChunkSize, err = requireIntValue(r, "flowChunkSize")
	if err != nil {
		return nil, "flowChunkSize"
	}

	u.CurrentChunkNumber, err = requireIntValue(r, "flowChunkNumber")
	if err != nil {
		return nil, "flowchunkNumber"
	}

	u.CurrentChunkSize, err = requireIntValue(r, "flowCurrentChunkSize")
	if err != nil {
		return nil, "flowCurrentChunkSize"
	}

	u.TotalSize, err = requireInt64Value(r, "flowTotalSize")
	if err != nil {
		return nil, "flowTotalSize"
	}

	u.Identifier = r.FormValue("flowIdentifier")
	if u.Identifier == "" {
		return nil, "flowIdentifier"
	}

	u.Filename = r.FormValue("flowFilename")
	u.RelativePath = r.FormValue("flowRelativePath")

	u.TotalChunks, err = requireIntValue(r, "flowTotalChunks")
	if err != nil {
		return nil, "flowTotalChunks"
	}
	return u, ""
}

//http util
func requireIntValue(r *http.Request, name string) (int, error) {
	val := r.FormValue(name)
	if val == "" {
		return 0, me.NewErr(name + " missing")
	}

	v, e := strconv.ParseInt(r.FormValue("flowTotalSize"), 10, 0)
	return int(v), e
}

func requireInt64Value(r *http.Request, name string) (int64, error) {
	val := r.FormValue(name)
	if val == "" {
		return 0, me.NewErr(name + " missing")
	}

	return strconv.ParseInt(r.FormValue("flowTotalSize"), 10, 64)
}
<|endoftext|>


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

// This file contains the exported entry points for invoking the parser.

package parser

import (
	"bytes"
	"go/ast"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	pathutil "path"
)

// If src != nil, readSource converts src to a []byte if possible;
// otherwise it returns an error. If src == nil, readSource returns
// the result of reading the file specified by filename.
//
func readSource(filename string, src interface{}) ([]byte, os.Error) {
	if src != nil {
		switch s := src.(type) {
		case string:
			return []byte(s), nil
		case []byte:
			return s, nil
		case *bytes.Buffer:
			// is io.Reader, but src is already available in []byte form
			if s != nil {
				return s.Bytes(), nil
			}
		case io.Reader:
			var buf bytes.Buffer
			_, err := io.Copy(&buf, s)
			if err != nil {
				return nil, err
			}
			return buf.Bytes(), nil
		default:
			return nil, os.ErrorString("invalid source")
		}
	}

	return ioutil.ReadFile(filename)
}

func (p *parser) parseEOF() os.Error {
	p.expect(token.EOF)
	return p.GetError(scanner.Sorted)
}

// ParseExpr parses a Go expression and returns the corresponding
// AST node. The filename, src, and scope arguments have the same interpretation
// as for ParseFile. If there is an error, the result expression
// may be nil or contain a partial AST.
//
func ParseExpr(filename string, src interface{}, scope *ast.Scope) (ast.Expr, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(filename, data, scope, 0)
	return p.parseExpr(), p.parseEOF()
}

// ParseStmtList parses a list of Go statements and returns the list
// of corresponding AST nodes. The filename, src, and scope arguments have the same
// interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs.
//
func ParseStmtList(filename string, src interface{}, scope *ast.Scope) ([]ast.Stmt, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(filename, data, scope, 0)
	return p.parseStmtList(), p.parseEOF()
}

// ParseDeclList parses a list of Go declarations and returns the list
// of corresponding AST nodes.  The filename, src, and scope arguments have the same
// interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs.
//
func ParseDeclList(filename string, src interface{}, scope *ast.Scope) ([]ast.Decl, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(filename, data, scope, 0)
	return p.parseDeclList(), p.parseEOF()
}

// ParseFile parses a Go source file and returns a File node.
//
// If src != nil, ParseFile parses the file source from src. src may
// be provided in a variety of formats. At the moment the following types
// are supported: string, []byte, and io.Reader. In this case, filename is
// only used for source position information and error messages.
//
// If src == nil, ParseFile parses the file specified by filename.
//
// If scope != nil, it is the immediately surrounding scope for the file
// (the package scope) and it is used to lookup and declare identifiers.
// When parsing multiple files belonging to a package, the same scope should
// be provided to all files.
//
// The mode parameter controls the amount of source text parsed and other
// optional parser functionality.
//
// If the source couldn't be read, the returned AST is nil and the error
// indicates the specific failure. If the source was read but syntax
// errors were found, the result is a partial AST (with ast.BadX nodes
// representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position.
//
func ParseFile(filename string, src interface{}, scope *ast.Scope, mode uint) (*ast.File, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(filename, data, scope, mode)
	return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
}

// ParseFiles calls ParseFile for each file in the filenames list and returns
// a map of package name -> package AST with all the packages found. The mode
// bits are passed to ParseFile unchanged.
//
// Files with parse errors are ignored. In this case the map of packages may
// be incomplete (missing packages and/or incomplete packages) and the last
// error encountered is returned.
//
func ParseFiles(filenames []string, scope *ast.Scope, mode uint) (map[string]*ast.Package, os.Error) {
	pkgs := make(map[string]*ast.Package)
	var err os.Error
	for _, filename := range filenames {
		var src *ast.File
		src, err = ParseFile(filename, nil, scope, mode)
		if err == nil {
			name := src.Name.Name()
			pkg, found := pkgs[name]
			if !found {
				pkg = &ast.Package{name, scope, make(map[string]*ast.File)}
				pkgs[name] = pkg
			}
			pkg.Files[filename] = src
		}
	}

	return pkgs, err
}

// ParseDir calls ParseFile for the files in the directory specified by path and
// returns a map of package name -> package AST with all the packages found. If
// filter != nil, only the files with os.FileInfo entries passing through the filter
// are considered. The mode bits are passed to ParseFile unchanged.
//
// If the directory couldn't be read, a nil map and the respective error are
// returned. If a parse error occured, a non-nil but incomplete map and the
// error are returned.
//
func ParseDir(path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
	fd, err := os.Open(path, os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}
	defer fd.Close()

	list, err := fd.Readdir(-1)
	if err != nil {
		return nil, err
	}

	filenames := make([]string, len(list))
	n := 0
	for i := 0; i < len(list); i++ {
		d := &list[i]
		if filter == nil || filter(d) {
			filenames[n] = pathutil.Join(path, d.Name)
			n++
		}
	}
	filenames = filenames[0:n]

	var scope *ast.Scope = nil // for now tracking of declarations is disabled
	return ParseFiles(filenames, scope, mode)
}
<commit_msg>go/parser.ParseFiles: don't override error (to nil) if there is one<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains the exported entry points for invoking the parser.

package parser

import (
	"bytes"
	"go/ast"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	pathutil "path"
)

// If src != nil, readSource converts src to a []byte if possible;
// otherwise it returns an error. If src == nil, readSource returns
// the result of reading the file specified by filename.
//
func readSource(filename string, src interface{}) ([]byte, os.Error) {
	if src != nil {
		switch s := src.(type) {
		case string:
			return []byte(s), nil
		case []byte:
			return s, nil
		case *bytes.Buffer:
			// is io.Reader, but src is already available in []byte form
			if s != nil {
				return s.Bytes(), nil
			}
		case io.Reader:
			var buf bytes.Buffer
			_, err := io.Copy(&buf, s)
			if err != nil {
				return nil, err
			}
			return buf.Bytes(), nil
		default:
			return nil, os.ErrorString("invalid source")
		}
	}

	return ioutil.ReadFile(filename)
}

func (p *parser) parseEOF() os.Error {
	p.expect(token.EOF)
	return p.GetError(scanner.Sorted)
}

// ParseExpr parses a Go expression and returns the corresponding
// AST node. The filename, src, and scope arguments have the same interpretation
// as for ParseFile. If there is an error, the result expression
// may be nil or contain a partial AST.
//
func ParseExpr(filename string, src interface{}, scope *ast.Scope) (ast.Expr, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(filename, data, scope, 0)
	return p.parseExpr(), p.parseEOF()
}

// ParseStmtList parses a list of Go statements and returns the list
// of corresponding AST nodes. The filename, src, and scope arguments have the same
// interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs.
//
func ParseStmtList(filename string, src interface{}, scope *ast.Scope) ([]ast.Stmt, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(filename, data, scope, 0)
	return p.parseStmtList(), p.parseEOF()
}

// ParseDeclList parses a list of Go declarations and returns the list
// of corresponding AST nodes.  The filename, src, and scope arguments have the same
// interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs.
//
func ParseDeclList(filename string, src interface{}, scope *ast.Scope) ([]ast.Decl, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(filename, data, scope, 0)
	return p.parseDeclList(), p.parseEOF()
}

// ParseFile parses a Go source file and returns a File node.
//
// If src != nil, ParseFile parses the file source from src. src may
// be provided in a variety of formats. At the moment the following types
// are supported: string, []byte, and io.Reader. In this case, filename is
// only used for source position information and error messages.
//
// If src == nil, ParseFile parses the file specified by filename.
//
// If scope != nil, it is the immediately surrounding scope for the file
// (the package scope) and it is used to lookup and declare identifiers.
// When parsing multiple files belonging to a package, the same scope should
// be provided to all files.
//
// The mode parameter controls the amount of source text parsed and other
// optional parser functionality.
//
// If the source couldn't be read, the returned AST is nil and the error
// indicates the specific failure. If the source was read but syntax
// errors were found, the result is a partial AST (with ast.BadX nodes
// representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position.
//
func ParseFile(filename string, src interface{}, scope *ast.Scope, mode uint) (*ast.File, os.Error) {
	data, err := readSource(filename, src)
	if err != nil {
		return nil, err
	}

	var p parser
	p.init(filename, data, scope, mode)
	return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
}

// ParseFiles calls ParseFile for each file in the filenames list and returns
// a map of package name -> package AST with all the packages found. The mode
// bits are passed to ParseFile unchanged.
//
// Files with parse errors are ignored. In this case the map of packages may
// be incomplete (missing packages and/or incomplete packages) and the first
// error encountered is returned.
//
func ParseFiles(filenames []string, scope *ast.Scope, mode uint) (pkgs map[string]*ast.Package, first os.Error) {
	pkgs = make(map[string]*ast.Package)
	for _, filename := range filenames {
		if src, err := ParseFile(filename, nil, scope, mode); err == nil {
			name := src.Name.Name()
			pkg, found := pkgs[name]
			if !found {
				pkg = &ast.Package{name, scope, make(map[string]*ast.File)}
				pkgs[name] = pkg
			}
			pkg.Files[filename] = src
		} else if first == nil {
			first = err
		}
	}
	return
}

// ParseDir calls ParseFile for the files in the directory specified by path and
// returns a map of package name -> package AST with all the packages found. If
// filter != nil, only the files with os.FileInfo entries passing through the filter
// are considered. The mode bits are passed to ParseFile unchanged.
//
// If the directory couldn't be read, a nil map and the respective error are
// returned. If a parse error occured, a non-nil but incomplete map and the
// error are returned.
//
func ParseDir(path string, filter func(*os.FileInfo) bool, mode uint) (map[string]*ast.Package, os.Error) {
	fd, err := os.Open(path, os.O_RDONLY, 0)
	if err != nil {
		return nil, err
	}
	defer fd.Close()

	list, err := fd.Readdir(-1)
	if err != nil {
		return nil, err
	}

	filenames := make([]string, len(list))
	n := 0
	for i := 0; i < len(list); i++ {
		d := &list[i]
		if filter == nil || filter(d) {
			filenames[n] = pathutil.Join(path, d.Name)
			n++
		}
	}
	filenames = filenames[0:n]

	var scope *ast.Scope = nil // for now tracking of declarations is disabled
	return ParseFiles(filenames, scope, mode)
}
<|endoftext|>


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

package syscall

import (
	"sync"
)

// DLLError describes reasons for DLL load failures.
type DLLError struct {
	Err     error
	ObjName string
	Msg     string
}

func (e *DLLError) Error() string { return e.Msg }

// Implemented in ../runtime/syscall_windows.goc.
func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)

// A DLL implements access to a single DLL.
type DLL struct {
	Name   string
	Handle Handle
}

// LoadDLL loads DLL file into memory.
func LoadDLL(name string) (dll *DLL, err error) {
	namep, err := UTF16PtrFromString(name)
	if err != nil {
		return nil, err
	}
	h, e := loadlibrary(namep)
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to load " + name + ": " + e.Error(),
		}
	}
	d := &DLL{
		Name:   name,
		Handle: Handle(h),
	}
	return d, nil
}

// MustLoadDLL is like LoadDLL but panics if load operation failes.
func MustLoadDLL(name string) *DLL {
	d, e := LoadDLL(name)
	if e != nil {
		panic(e)
	}
	return d
}

// FindProc searches DLL d for procedure named name and returns *Proc
// if found. It returns an error if search fails.
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
	namep, err := BytePtrFromString(name)
	if err != nil {
		return nil, err
	}
	a, e := getprocaddress(uintptr(d.Handle), namep)
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
		}
	}
	p := &Proc{
		Dll:  d,
		Name: name,
		addr: a,
	}
	return p, nil
}

// MustFindProc is like FindProc but panics if search fails.
func (d *DLL) MustFindProc(name string) *Proc {
	p, e := d.FindProc(name)
	if e != nil {
		panic(e)
	}
	return p
}

// Release unloads DLL d from memory.
func (d *DLL) Release() (err error) {
	return FreeLibrary(d.Handle)
}

// A Proc implements access to a procedure inside a DLL.
type Proc struct {
	Dll  *DLL
	Name string
	addr uintptr
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *Proc) Addr() uintptr {
	return p.addr
}

// Call executes procedure p with arguments a.
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	switch len(a) {
	case 0:
		return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
	case 1:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
	case 2:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
	case 3:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
	case 4:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
	case 5:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
	case 6:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
	case 7:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
	case 8:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
	case 9:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
	case 10:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
	case 11:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
	case 12:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
	case 13:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
	case 14:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
	case 15:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
	default:
		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
	}
	return
}

// A LazyDLL implements access to a single DLL.
// It will delay the load of the DLL until the first
// call to its Handle method or to one of its
// LazyProc's Addr method.
type LazyDLL struct {
	mu   sync.Mutex
	dll  *DLL // non nil once DLL is loaded
	Name string
}

// Load loads DLL file d.Name into memory. It returns an error if fails.
// Load will not try to load DLL, if it is already loaded into memory.
func (d *LazyDLL) Load() error {
	if d.dll == nil {
		d.mu.Lock()
		defer d.mu.Unlock()
		if d.dll == nil {
			dll, e := LoadDLL(d.Name)
			if e != nil {
				return e
			}
			d.dll = dll
		}
	}
	return nil
}

// mustLoad is like Load but panics if search fails.
func (d *LazyDLL) mustLoad() {
	e := d.Load()
	if e != nil {
		panic(e)
	}
}

// Handle returns d's module handle.
func (d *LazyDLL) Handle() uintptr {
	d.mustLoad()
	return uintptr(d.dll.Handle)
}

// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
func (d *LazyDLL) NewProc(name string) *LazyProc {
	return &LazyProc{l: d, Name: name}
}

// NewLazyDLL creates new LazyDLL associated with DLL file.
func NewLazyDLL(name string) *LazyDLL {
	return &LazyDLL{Name: name}
}

// A LazyProc implements access to a procedure inside a LazyDLL.
// It delays the lookup until the Addr method is called.
type LazyProc struct {
	mu   sync.Mutex
	Name string
	l    *LazyDLL
	proc *Proc
}

// Find searches DLL for procedure named p.Name. It returns
// an error if search fails. Find will not search procedure,
// if it is already found and loaded into memory.
func (p *LazyProc) Find() error {
	if p.proc == nil {
		p.mu.Lock()
		defer p.mu.Unlock()
		if p.proc == nil {
			e := p.l.Load()
			if e != nil {
				return e
			}
			proc, e := p.l.dll.FindProc(p.Name)
			if e != nil {
				return e
			}
			p.proc = proc
		}
	}
	return nil
}

// mustFind is like Find but panics if search fails.
func (p *LazyProc) mustFind() {
	e := p.Find()
	if e != nil {
		panic(e)
	}
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *LazyProc) Addr() uintptr {
	p.mustFind()
	return p.proc.Addr()
}

// Call executes procedure p with arguments a.
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	p.mustFind()
	return p.proc.Call(a...)
}
<commit_msg>syscall: fix data races in LazyDLL/LazyProc Reincarnation of http://codereview.appspot.com/6817086 (sent from another account). It is ugly because sync.Once will cause allocation of a closure. Fixes issue 4343.<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package syscall

import (
	"sync"
	"sync/atomic"
	"unsafe"
)

// DLLError describes reasons for DLL load failures.
type DLLError struct {
	Err     error
	ObjName string
	Msg     string
}

func (e *DLLError) Error() string { return e.Msg }

// Implemented in ../runtime/syscall_windows.goc.
func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)
func loadlibrary(filename *uint16) (handle uintptr, err Errno)
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)

// A DLL implements access to a single DLL.
type DLL struct {
	Name   string
	Handle Handle
}

// LoadDLL loads DLL file into memory.
func LoadDLL(name string) (dll *DLL, err error) {
	namep, err := UTF16PtrFromString(name)
	if err != nil {
		return nil, err
	}
	h, e := loadlibrary(namep)
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to load " + name + ": " + e.Error(),
		}
	}
	d := &DLL{
		Name:   name,
		Handle: Handle(h),
	}
	return d, nil
}

// MustLoadDLL is like LoadDLL but panics if load operation failes.
func MustLoadDLL(name string) *DLL {
	d, e := LoadDLL(name)
	if e != nil {
		panic(e)
	}
	return d
}

// FindProc searches DLL d for procedure named name and returns *Proc
// if found. It returns an error if search fails.
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
	namep, err := BytePtrFromString(name)
	if err != nil {
		return nil, err
	}
	a, e := getprocaddress(uintptr(d.Handle), namep)
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
		}
	}
	p := &Proc{
		Dll:  d,
		Name: name,
		addr: a,
	}
	return p, nil
}

// MustFindProc is like FindProc but panics if search fails.
func (d *DLL) MustFindProc(name string) *Proc {
	p, e := d.FindProc(name)
	if e != nil {
		panic(e)
	}
	return p
}

// Release unloads DLL d from memory.
func (d *DLL) Release() (err error) {
	return FreeLibrary(d.Handle)
}

// A Proc implements access to a procedure inside a DLL.
type Proc struct {
	Dll  *DLL
	Name string
	addr uintptr
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *Proc) Addr() uintptr {
	return p.addr
}

// Call executes procedure p with arguments a.
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	switch len(a) {
	case 0:
		return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
	case 1:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
	case 2:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
	case 3:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
	case 4:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
	case 5:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
	case 6:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
	case 7:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
	case 8:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
	case 9:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
	case 10:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
	case 11:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
	case 12:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
	case 13:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
	case 14:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
	case 15:
		return Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
	default:
		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
	}
	return
}

// A LazyDLL implements access to a single DLL.
// It will delay the load of the DLL until the first
// call to its Handle method or to one of its
// LazyProc's Addr method.
type LazyDLL struct {
	mu   sync.Mutex
	dll  *DLL // non nil once DLL is loaded
	Name string
}

// Load loads DLL file d.Name into memory. It returns an error if fails.
// Load will not try to load DLL, if it is already loaded into memory.
func (d *LazyDLL) Load() error {
	// Non-racy version of:
	// if d.dll == nil {
	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) == nil {
		d.mu.Lock()
		defer d.mu.Unlock()
		if d.dll == nil {
			dll, e := LoadDLL(d.Name)
			if e != nil {
				return e
			}
			// Non-racy version of:
			// d.dll = dll
			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
		}
	}
	return nil
}

// mustLoad is like Load but panics if search fails.
func (d *LazyDLL) mustLoad() {
	e := d.Load()
	if e != nil {
		panic(e)
	}
}

// Handle returns d's module handle.
func (d *LazyDLL) Handle() uintptr {
	d.mustLoad()
	return uintptr(d.dll.Handle)
}

// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
func (d *LazyDLL) NewProc(name string) *LazyProc {
	return &LazyProc{l: d, Name: name}
}

// NewLazyDLL creates new LazyDLL associated with DLL file.
func NewLazyDLL(name string) *LazyDLL {
	return &LazyDLL{Name: name}
}

// A LazyProc implements access to a procedure inside a LazyDLL.
// It delays the lookup until the Addr method is called.
type LazyProc struct {
	mu   sync.Mutex
	Name string
	l    *LazyDLL
	proc *Proc
}

// Find searches DLL for procedure named p.Name. It returns
// an error if search fails. Find will not search procedure,
// if it is already found and loaded into memory.
func (p *LazyProc) Find() error {
	// Non-racy version of:
	// if p.proc == nil {
	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
		p.mu.Lock()
		defer p.mu.Unlock()
		if p.proc == nil {
			e := p.l.Load()
			if e != nil {
				return e
			}
			proc, e := p.l.dll.FindProc(p.Name)
			if e != nil {
				return e
			}
			// Non-racy version of:
			// p.proc = proc
			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
		}
	}
	return nil
}

// mustFind is like Find but panics if search fails.
func (p *LazyProc) mustFind() {
	e := p.Find()
	if e != nil {
		panic(e)
	}
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *LazyProc) Addr() uintptr {
	p.mustFind()
	return p.proc.Addr()
}

// Call executes procedure p with arguments a.
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	p.mustFind()
	return p.proc.Call(a...)
}
<|endoftext|>


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

package syscall

import (
	"sync"
)

// Errno is the Windows error number.
type Errno uintptr

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

// DLLError describes reasons for DLL load failures.
type DLLError struct {
	Err     error
	ObjName string
	Msg     string
}

func (e *DLLError) Error() string { return e.Msg }

// Implemented in ../runtime/windows/syscall.goc.
func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
func loadlibrary(filename *uint16) (handle, err Errno)
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)

// A DLL implements access to a single DLL.
type DLL struct {
	Name   string
	Handle Handle
}

// LoadDLL loads DLL file into memory.
func LoadDLL(name string) (dll *DLL, err error) {
	h, e := loadlibrary(StringToUTF16Ptr(name))
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to load " + name + ": " + e.Error(),
		}
	}
	d := &DLL{
		Name:   name,
		Handle: Handle(h),
	}
	return d, nil
}

// MustLoadDLL is like LoadDLL but panics if load operation failes.
func MustLoadDLL(name string) *DLL {
	d, e := LoadDLL(name)
	if e != nil {
		panic(e)
	}
	return d
}

// FindProc searches DLL d for procedure named name and returns *Proc
// if found. It returns an error if search fails.
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
	a, e := getprocaddress(uintptr(d.Handle), StringBytePtr(name))
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
		}
	}
	p := &Proc{
		Dll:  d,
		Name: name,
		addr: a,
	}
	return p, nil
}

// MustFindProc is like FindProc but panics if search fails.
func (d *DLL) MustFindProc(name string) *Proc {
	p, e := d.FindProc(name)
	if e != nil {
		panic(e)
	}
	return p
}

// Release unloads DLL d from memory.
func (d *DLL) Release() (err error) {
	return FreeLibrary(d.Handle)
}

// A Proc implements access to a procedure inside a DLL.
type Proc struct {
	Dll  *DLL
	Name string
	addr uintptr
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *Proc) Addr() uintptr {
	return p.addr
}

// Call executes procedure p with arguments a.
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	switch len(a) {
	case 0:
		return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
	case 1:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
	case 2:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
	case 3:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
	case 4:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
	case 5:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
	case 6:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
	case 7:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
	case 8:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
	case 9:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
	case 10:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
	case 11:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
	case 12:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
	default:
		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
	}
	return
}

// A LazyDLL implements access to a single DLL.
// It will delay the load of the DLL until the first
// call to its Handle method or to one of its
// LazyProc's Addr method.
type LazyDLL struct {
	mu   sync.Mutex
	dll  *DLL // non nil once DLL is loaded
	Name string
}

// Load loads DLL file d.Name into memory. It returns an error if fails.
// Load will not try to load DLL, if it is already loaded into memory.
func (d *LazyDLL) Load() error {
	if d.dll == nil {
		d.mu.Lock()
		defer d.mu.Unlock()
		if d.dll == nil {
			dll, e := LoadDLL(d.Name)
			if e != nil {
				return e
			}
			d.dll = dll
		}
	}
	return nil
}

// mustLoad is like Load but panics if search fails.
func (d *LazyDLL) mustLoad() {
	e := d.Load()
	if e != nil {
		panic(e)
	}
}

// Handle returns d's module handle.
func (d *LazyDLL) Handle() uintptr {
	d.mustLoad()
	return uintptr(d.dll.Handle)
}

// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
func (d *LazyDLL) NewProc(name string) *LazyProc {
	return &LazyProc{l: d, Name: name}
}

// NewLazyDLL creates new LazyDLL associated with DLL file.
func NewLazyDLL(name string) *LazyDLL {
	return &LazyDLL{Name: name}
}

// A LazyProc implements access to a procedure inside a LazyDLL.
// It delays the lookup until the Addr method is called.
type LazyProc struct {
	mu   sync.Mutex
	Name string
	l    *LazyDLL
	proc *Proc
}

// Find searches DLL for procedure named p.Name. It returns
// an error if search fails. Find will not search procedure,
// if it is already found and loaded into memory.
func (p *LazyProc) Find() error {
	if p.proc == nil {
		p.mu.Lock()
		defer p.mu.Unlock()
		if p.proc == nil {
			e := p.l.Load()
			if e != nil {
				return e
			}
			proc, e := p.l.dll.FindProc(p.Name)
			if e != nil {
				return e
			}
			p.proc = proc
		}
	}
	return nil
}

// mustFind is like Find but panics if search fails.
func (p *LazyProc) mustFind() {
	e := p.Find()
	if e != nil {
		panic(e)
	}
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *LazyProc) Addr() uintptr {
	p.mustFind()
	return p.proc.Addr()
}

// Call executes procedure p with arguments a.
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	p.mustFind()
	return p.proc.Call(a...)
}
<commit_msg>syscall: make windows Errno implement net.Error (fix build)<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package syscall

import (
	"sync"
)

// Errno is the Windows error number.
type Errno uintptr

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

func (e Errno) Temporary() bool {
	return e == EINTR || e == EMFILE || e.Timeout()
}

func (e Errno) Timeout() bool {
	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
}

// DLLError describes reasons for DLL load failures.
type DLLError struct {
	Err     error
	ObjName string
	Msg     string
}

func (e *DLLError) Error() string { return e.Msg }

// Implemented in ../runtime/windows/syscall.goc.
func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
func loadlibrary(filename *uint16) (handle, err Errno)
func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno)

// A DLL implements access to a single DLL.
type DLL struct {
	Name   string
	Handle Handle
}

// LoadDLL loads DLL file into memory.
func LoadDLL(name string) (dll *DLL, err error) {
	h, e := loadlibrary(StringToUTF16Ptr(name))
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to load " + name + ": " + e.Error(),
		}
	}
	d := &DLL{
		Name:   name,
		Handle: Handle(h),
	}
	return d, nil
}

// MustLoadDLL is like LoadDLL but panics if load operation failes.
func MustLoadDLL(name string) *DLL {
	d, e := LoadDLL(name)
	if e != nil {
		panic(e)
	}
	return d
}

// FindProc searches DLL d for procedure named name and returns *Proc
// if found. It returns an error if search fails.
func (d *DLL) FindProc(name string) (proc *Proc, err error) {
	a, e := getprocaddress(uintptr(d.Handle), StringBytePtr(name))
	if e != 0 {
		return nil, &DLLError{
			Err:     e,
			ObjName: name,
			Msg:     "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
		}
	}
	p := &Proc{
		Dll:  d,
		Name: name,
		addr: a,
	}
	return p, nil
}

// MustFindProc is like FindProc but panics if search fails.
func (d *DLL) MustFindProc(name string) *Proc {
	p, e := d.FindProc(name)
	if e != nil {
		panic(e)
	}
	return p
}

// Release unloads DLL d from memory.
func (d *DLL) Release() (err error) {
	return FreeLibrary(d.Handle)
}

// A Proc implements access to a procedure inside a DLL.
type Proc struct {
	Dll  *DLL
	Name string
	addr uintptr
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *Proc) Addr() uintptr {
	return p.addr
}

// Call executes procedure p with arguments a.
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	switch len(a) {
	case 0:
		return Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
	case 1:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
	case 2:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
	case 3:
		return Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
	case 4:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
	case 5:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
	case 6:
		return Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
	case 7:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
	case 8:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
	case 9:
		return Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
	case 10:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
	case 11:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
	case 12:
		return Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
	default:
		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
	}
	return
}

// A LazyDLL implements access to a single DLL.
// It will delay the load of the DLL until the first
// call to its Handle method or to one of its
// LazyProc's Addr method.
type LazyDLL struct {
	mu   sync.Mutex
	dll  *DLL // non nil once DLL is loaded
	Name string
}

// Load loads DLL file d.Name into memory. It returns an error if fails.
// Load will not try to load DLL, if it is already loaded into memory.
func (d *LazyDLL) Load() error {
	if d.dll == nil {
		d.mu.Lock()
		defer d.mu.Unlock()
		if d.dll == nil {
			dll, e := LoadDLL(d.Name)
			if e != nil {
				return e
			}
			d.dll = dll
		}
	}
	return nil
}

// mustLoad is like Load but panics if search fails.
func (d *LazyDLL) mustLoad() {
	e := d.Load()
	if e != nil {
		panic(e)
	}
}

// Handle returns d's module handle.
func (d *LazyDLL) Handle() uintptr {
	d.mustLoad()
	return uintptr(d.dll.Handle)
}

// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
func (d *LazyDLL) NewProc(name string) *LazyProc {
	return &LazyProc{l: d, Name: name}
}

// NewLazyDLL creates new LazyDLL associated with DLL file.
func NewLazyDLL(name string) *LazyDLL {
	return &LazyDLL{Name: name}
}

// A LazyProc implements access to a procedure inside a LazyDLL.
// It delays the lookup until the Addr method is called.
type LazyProc struct {
	mu   sync.Mutex
	Name string
	l    *LazyDLL
	proc *Proc
}

// Find searches DLL for procedure named p.Name. It returns
// an error if search fails. Find will not search procedure,
// if it is already found and loaded into memory.
func (p *LazyProc) Find() error {
	if p.proc == nil {
		p.mu.Lock()
		defer p.mu.Unlock()
		if p.proc == nil {
			e := p.l.Load()
			if e != nil {
				return e
			}
			proc, e := p.l.dll.FindProc(p.Name)
			if e != nil {
				return e
			}
			p.proc = proc
		}
	}
	return nil
}

// mustFind is like Find but panics if search fails.
func (p *LazyProc) mustFind() {
	e := p.Find()
	if e != nil {
		panic(e)
	}
}

// Addr returns the address of the procedure represented by p.
// The return value can be passed to Syscall to run the procedure.
func (p *LazyProc) Addr() uintptr {
	p.mustFind()
	return p.proc.Addr()
}

// Call executes procedure p with arguments a.
func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, err error) {
	p.mustFind()
	return p.proc.Call(a...)
}
<|endoftext|>


<commit_before>package logfetcher

import "testing"

func TestFetch(t *testing.T) {
	t.Error("not implemented yet")
}
<commit_msg>logfetcher: setup test client<commit_after>package logfetcher

import (
	"log"
	"testing"

	"github.com/koding/klient/Godeps/_workspace/src/github.com/koding/kite"
)

var (
	lf     *kite.Kite
	remote *kite.Client
)

func init() {
	lf := kite.New("logfetcher", "0.0.1")
	lf.Config.DisableAuthentication = true
	lf.Config.Port = 3639
	lf.HandleFunc("fetch", Fetch)

	go lf.Run()
	<-lf.ServerReadyNotify()

	remoteKite := kite.New("remote", "0.0.1")
	remoteKite.Config.Username = "remote"
	remote = remoteKite.NewClient("http://127.0.0.1:3639/kite")
	err := remote.Dial()
	if err != nil {
		log.Fatal("err")
	}
}

func TestFetch(t *testing.T) {
	t.Error("not implemented yet")
}
<|endoftext|>


<commit_before>package KsanaDB
import (
    "fmt"
    "log"
    "encoding/json"
    "strconv"
    "time"
    "errors"
    "strings"
)

var prefix = "KSANADBv1\t"

func SetData(data string) *error {
    InputArray, err := ParseDataJson(data)

    if (err != nil) {
        log.Println(err.Error())
        return &err
    }

    for _, hashdata := range InputArray {
        name := ""
        dataPoints := hashdata.Datapoints

        if hashdata.Name == "" {
            continue
        } else {
            name = hashdata.Name
        }

        if dataPoints == nil {
            value, _ := hashdata.Value.Float64()

            if hashdata.Timestamp == nil {
                log.Println(err.Error())
                continue
            }
            timestamp, err := hashdata.Timestamp.Int64()

            if err != nil {
                log.Println(err.Error())
                continue
            }

            element := make( map[string]interface{})
            keyname, offset := generateTimeSeriesData(prefix, name , timestamp)
            tagSeq := getTagSeq(hashdata.Tags, prefix, name)

            element["timestamp"] = strconv.FormatInt(timestamp, 10)
            element["value"] = strconv.FormatFloat(value, 'f', 6, 64)
            element["tags"] = tagSeq

            jstring, _ := json.Marshal(element)
            input := string(jstring[:])
            SetTimeSeries(keyname, fmt.Sprint(input), offset)
        } else {
            inputData := make(map[string][]interface{})
            tagSeq := getTagSeq(hashdata.Tags, prefix, name)

            for _, data := range dataPoints {
                timestamp, errT := data[0].Int64()
                value, errV := data[1].Float64()

                if errT != nil || errV != nil {
                    log.Println(err.Error())
                    continue
                }

                element := make( map[string]interface{})
                element["timestamp"] = strconv.FormatInt(timestamp, 10)
                element["value"] = strconv.FormatFloat(value, 'f', 6, 64)
                element["tags"] = tagSeq

                jstring, _ := json.Marshal(element)
                input := string(jstring[:])
                keyname, offset := generateTimeSeriesData(prefix, name , timestamp)
                inputData[keyname] = append(inputData[keyname], offset)
                inputData[keyname] = append(inputData[keyname], input)
            }

            for k := range inputData {
                _, err := BulkSetTimeSeries(k, inputData[k])
                if err != nil {
                    log.Println(err.Error())
                    continue
                }
            }

            //fmt.Println(inputData)
        }
    }
    return nil
}

func QueryData(q *Query) (string , error) {
    var start int64
    var end int64
    var err error

    if q.Metric.Name == nil {
        return "", errors.New("Need set Metric name")
    }

    tNow := time.Now()

    if q.StartAbsolute == nil {
        if q.StartRelative == nil {
            return "", errors.New("Need set absolute start time")
        } else {
           start, err = getQueryTime(tNow, q.StartRelative.Unit, q.StartRelative.Value)
           if err != nil {
               return "", err
           }
        }
    } else {
        start, err = q.StartAbsolute.Int64()
        if err != nil {
            return "", err
        }
    }

    if q.EndAbsolute == nil {
        if q.EndRelative == nil {
            return "", errors.New("Need set absolute end time")
        } else {
           end, err = getQueryTime(tNow, q.EndRelative.Unit, q.EndRelative.Value)
           if err != nil {
               return "", err
           }
        }
    } else {
        end, err = q.EndAbsolute.Int64()
        if err != nil {
            return "", err
        }
    }

    if start > end {
        return "", errors.New(fmt.Sprintf("end time(%d) little than start time(%d)", end, start))
    }

    tagFilter := []string{}
    for k, v := range(q.Metric.Tags) {
        tagFilter = append(tagFilter, fmt.Sprintf("%s\t%s", k,v))
    }
    groupByTag := q.Metric.GroupBy
    aggreationFunction := q.Metric.Aggregator.Name
    unit := *q.Metric.Aggregator.Sampling.Unit
    timeRange, err := q.Metric.Aggregator.Sampling.Value.Int64()
    if err != nil {
        return "", err
    }

    ret, err :=  QueryTimeSeriesData(*q.Metric.Name, start, end, tagFilter, groupByTag, aggreationFunction, int(timeRange), unit)
    return ret, err
}

func QueryTimeSeriesData(name string, start int64, stop int64, tagFilter []string, groupByTag []string, aggreationFunction string, timeRange int, unit string) (string , error) {

    groupBy := map[string][]string{}
    var reverseHash map[string]string

    if len(groupByTag) > 0 {
        for _,t := range groupByTag {
            tmp := GetMetricsTagSeq(name, t)
            if len(tmp.Seq[t]) > 0 {
                groupBy[t] = tmp.Seq[t]
            } else {
                return "", errors.New("Input Group by tag(s) not Exist")
            }
            reverseHash = tmp.Val
        }
    }

    tagFilterSeq, err := GetFilterSeq(name, tagFilter)
    if err != nil {
        return "", err
    }

    for _, sq := range (tagFilterSeq) {
        if sq == "" {
            return "", errors.New("Input Filter Tag(s) not Exist")
        }
    }

    rawData, err := queryTimeSeries(prefix , name , start , stop )

    if err != nil {
        return "{}", err
    }

    if len(rawData) == 0 {
        return "{}", nil
    }

    data, err := queryWorker(rawData, start, tagFilterSeq, groupBy, aggreationFunction, unit, timeRange)

    ret, err := generateOutputData(data, reverseHash, name, start, stop, tagFilter, groupByTag, aggreationFunction, timeRange, unit)

    fmt.Print("Find record(s): ")
    fmt.Println(len(rawData))
    return ret, err
}

func GetMetricsTag(name string, target string, keyName string) (string, error)  {
    var ret string
    switch target {
        case "All", "TagKey", "TagValue" :
            ret = getTags(prefix, name, target, keyName)
        default:
            return ret, errors.New("target should be All, TagKey or TagValue")
    }
    return ret, nil
}

func GetMetricsTagSeq(name string, keyName string) (AllTagSeqType)  {
    data := getTags(prefix, name, "TagSeq", keyName)
    var ret AllTagSeqType
    json.Unmarshal([]byte(data), &ret)
    return ret
}

func GetMetric() ([]string)  {
    data := getMetric(prefix)
    var ret []string
    json.Unmarshal([]byte(data), &ret)
    return ret
}

func GetFilterSeq(name string, filterList []string) ([]string, error){
      if len(filterList) == 0 {
          ret := []string{}
          return ret, nil
      }
      d, err := getSeqByKV(prefix, name, filterList)
      return d, err
}

func generateOutputData(result map[string][]map[string]interface{}, reverseHash map[string]string, name string, start int64, stop int64, tagFilter []string, groupByTag []string, aggregationFunction string, timeRange int, unit string) (string , error) {
    resultData := ResultType{}
    resultData.Group = []GroupType{}

    resultData.Name = name
    resultData.GroupBy = groupByTag

    resultData.Start = start
    resultData.End = stop
    resultData.Filter = tagFilter
    resultData.AggregateFunction = aggregationFunction
    resultData.TimeRange = timeRange
    resultData.TimeUnit = unit

    for k,v := range(result) {
       gp := GroupType{}
       gp.Tags = map[string]string{}
       gp.Values = [][]interface{}{}

       if k != "single" {
           ka := strings.Split(k, "\t")
           for _, s := range(ka) {
               tagPair := reverseHash[s]
               tagKV := strings.Split(tagPair, "\t")
               gp.Tags[tagKV[0]] = tagKV[1]
           }
       }

       for _,d := range(v) {
           ele := []interface{}{}
           ele = append(ele, d["timestamp"])
           ele = append(ele, d["value"])
           gp.Values = append(gp.Values, ele)
       }
       resultData.Group = append(resultData.Group, gp)
    }
    jret, err := json.Marshal(resultData)
    return string(jret), err
}
<commit_msg>revert output format<commit_after>package KsanaDB
import (
    "fmt"
    "log"
    "encoding/json"
    "strconv"
    "time"
    "errors"
    "strings"
)

var prefix = "KSANADBv1\t"

func SetData(data string) *error {
    InputArray, err := ParseDataJson(data)

    if (err != nil) {
        log.Println(err.Error())
        return &err
    }

    for _, hashdata := range InputArray {
        name := ""
        dataPoints := hashdata.Datapoints

        if hashdata.Name == "" {
            continue
        } else {
            name = hashdata.Name
        }

        if dataPoints == nil {
            value, _ := hashdata.Value.Float64()

            if hashdata.Timestamp == nil {
                log.Println(err.Error())
                continue
            }
            timestamp, err := hashdata.Timestamp.Int64()

            if err != nil {
                log.Println(err.Error())
                continue
            }

            element := make( map[string]interface{})
            keyname, offset := generateTimeSeriesData(prefix, name , timestamp)
            tagSeq := getTagSeq(hashdata.Tags, prefix, name)

            element["timestamp"] = strconv.FormatInt(timestamp, 10)
            element["value"] = strconv.FormatFloat(value, 'f', 6, 64)
            element["tags"] = tagSeq

            jstring, _ := json.Marshal(element)
            input := string(jstring[:])
            SetTimeSeries(keyname, fmt.Sprint(input), offset)
        } else {
            inputData := make(map[string][]interface{})
            tagSeq := getTagSeq(hashdata.Tags, prefix, name)

            for _, data := range dataPoints {
                timestamp, errT := data[0].Int64()
                value, errV := data[1].Float64()

                if errT != nil || errV != nil {
                    log.Println(err.Error())
                    continue
                }

                element := make( map[string]interface{})
                element["timestamp"] = strconv.FormatInt(timestamp, 10)
                element["value"] = strconv.FormatFloat(value, 'f', 6, 64)
                element["tags"] = tagSeq

                jstring, _ := json.Marshal(element)
                input := string(jstring[:])
                keyname, offset := generateTimeSeriesData(prefix, name , timestamp)
                inputData[keyname] = append(inputData[keyname], offset)
                inputData[keyname] = append(inputData[keyname], input)
            }

            for k := range inputData {
                _, err := BulkSetTimeSeries(k, inputData[k])
                if err != nil {
                    log.Println(err.Error())
                    continue
                }
            }

            //fmt.Println(inputData)
        }
    }
    return nil
}

func QueryData(q *Query) (string , error) {
    var start int64
    var end int64
    var err error

    if q.Metric.Name == nil {
        return "", errors.New("Need set Metric name")
    }

    tNow := time.Now()

    if q.StartAbsolute == nil {
        if q.StartRelative == nil {
            return "", errors.New("Need set absolute start time")
        } else {
           start, err = getQueryTime(tNow, q.StartRelative.Unit, q.StartRelative.Value)
           if err != nil {
               return "", err
           }
        }
    } else {
        start, err = q.StartAbsolute.Int64()
        if err != nil {
            return "", err
        }
    }

    if q.EndAbsolute == nil {
        if q.EndRelative == nil {
            return "", errors.New("Need set absolute end time")
        } else {
           end, err = getQueryTime(tNow, q.EndRelative.Unit, q.EndRelative.Value)
           if err != nil {
               return "", err
           }
        }
    } else {
        end, err = q.EndAbsolute.Int64()
        if err != nil {
            return "", err
        }
    }

    if start > end {
        return "", errors.New(fmt.Sprintf("end time(%d) little than start time(%d)", end, start))
    }

    tagFilter := []string{}
    for k, v := range(q.Metric.Tags) {
        tagFilter = append(tagFilter, fmt.Sprintf("%s\t%s", k,v))
    }
    groupByTag := q.Metric.GroupBy
    aggreationFunction := q.Metric.Aggregator.Name
    unit := *q.Metric.Aggregator.Sampling.Unit
    timeRange, err := q.Metric.Aggregator.Sampling.Value.Int64()
    if err != nil {
        return "", err
    }

    ret, err :=  QueryTimeSeriesData(*q.Metric.Name, start, end, tagFilter, groupByTag, aggreationFunction, int(timeRange), unit)
    return ret, err
}

func QueryTimeSeriesData(name string, start int64, stop int64, tagFilter []string, groupByTag []string, aggreationFunction string, timeRange int, unit string) (string , error) {

    groupBy := map[string][]string{}
    var reverseHash map[string]string

    if len(groupByTag) > 0 {
        for _,t := range groupByTag {
            tmp := GetMetricsTagSeq(name, t)
            if len(tmp.Seq[t]) > 0 {
                groupBy[t] = tmp.Seq[t]
            } else {
                return "", errors.New("Input Group by tag(s) not Exist")
            }
            reverseHash = tmp.Val
        }
    }

    tagFilterSeq, err := GetFilterSeq(name, tagFilter)
    if err != nil {
        return "", err
    }

    for _, sq := range (tagFilterSeq) {
        if sq == "" {
            return "", errors.New("Input Filter Tag(s) not Exist")
        }
    }

    rawData, err := queryTimeSeries(prefix , name , start , stop )

    if err != nil {
        return "{}", err
    }

    if len(rawData) == 0 {
        return "{}", nil
    }

    data, err := queryWorker(rawData, start, tagFilterSeq, groupBy, aggreationFunction, unit, timeRange)

    ret, err := generateOutputData(data, reverseHash, name, start, stop, tagFilter, groupByTag, aggreationFunction, timeRange, unit)

    fmt.Print("Find record(s): ")
    fmt.Println(len(rawData))
    return ret, err
}

func GetMetricsTag(name string, target string, keyName string) (map[string][]string, error)  {
    var ret map[string][]string
    var data string
    switch target {
        case "All", "TagKey", "TagValue" :
            data = getTags(prefix, name, target, keyName)
        default:
            return ret, errors.New("target should be All, TagKey or TagValue")
    }
    json.Unmarshal([]byte(data), &ret)
    return ret, nil
}

func GetMetricsTagSeq(name string, keyName string) (AllTagSeqType)  {
    data := getTags(prefix, name, "TagSeq", keyName)
    var ret AllTagSeqType
    json.Unmarshal([]byte(data), &ret)
    return ret
}

func GetMetric() ([]string)  {
    data := getMetric(prefix)
    var ret []string
    json.Unmarshal([]byte(data), &ret)
    return ret
}

func GetFilterSeq(name string, filterList []string) ([]string, error){
      if len(filterList) == 0 {
          ret := []string{}
          return ret, nil
      }
      d, err := getSeqByKV(prefix, name, filterList)
      return d, err
}

func generateOutputData(result map[string][]map[string]interface{}, reverseHash map[string]string, name string, start int64, stop int64, tagFilter []string, groupByTag []string, aggregationFunction string, timeRange int, unit string) (string , error) {
    resultData := ResultType{}
    resultData.Group = []GroupType{}

    resultData.Name = name
    resultData.GroupBy = groupByTag

    resultData.Start = start
    resultData.End = stop
    resultData.Filter = tagFilter
    resultData.AggregateFunction = aggregationFunction
    resultData.TimeRange = timeRange
    resultData.TimeUnit = unit

    for k,v := range(result) {
       gp := GroupType{}
       gp.Tags = map[string]string{}
       gp.Values = [][]interface{}{}

       if k != "single" {
           ka := strings.Split(k, "\t")
           for _, s := range(ka) {
               tagPair := reverseHash[s]
               tagKV := strings.Split(tagPair, "\t")
               gp.Tags[tagKV[0]] = tagKV[1]
           }
       }

       for _,d := range(v) {
           ele := []interface{}{}
           ele = append(ele, d["timestamp"])
           ele = append(ele, d["value"])
           gp.Values = append(gp.Values, ele)
       }
       resultData.Group = append(resultData.Group, gp)
    }
    jret, err := json.Marshal(resultData)
    return string(jret), err
}
<|endoftext|>


<commit_before>package lifecycle

import (
	"fmt"
	"net/url"

	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/shared/api"
)

// Internal copy of the network zone interface.
type networkZone interface {
	Info() *api.NetworkZone
	Project() string
}

// NetworkZoneAction represents a lifecycle event action for network zones.
type NetworkZoneAction string

// All supported lifecycle events for network zones.
const (
	NetworkZoneCreated = NetworkZoneAction("created")
	NetworkZoneDeleted = NetworkZoneAction("deleted")
	NetworkZoneUpdated = NetworkZoneAction("updated")
)

// Event creates the lifecycle event for an action on a network zone.
func (a NetworkZoneAction) Event(n networkZone, requestor *api.EventLifecycleRequestor, ctx map[string]interface{}) api.EventLifecycle {
	eventType := fmt.Sprintf("network-zone-%s", a)

	u := fmt.Sprintf("/1.0/network-zones/%s", url.PathEscape(n.Info().Name))
	if n.Project() != project.Default {
		u = fmt.Sprintf("%s?project=%s", u, url.QueryEscape(n.Project()))
	}

	return api.EventLifecycle{
		Action:    eventType,
		Source:    u,
		Context:   ctx,
		Requestor: requestor,
	}
}
<commit_msg>lxd/lifecycle: Add network zone record events<commit_after>package lifecycle

import (
	"fmt"
	"net/url"

	"github.com/lxc/lxd/lxd/project"
	"github.com/lxc/lxd/shared/api"
)

// Internal copy of the network zone interface.
type networkZone interface {
	Info() *api.NetworkZone
	Project() string
}

// NetworkZoneAction represents a lifecycle event action for network zones.
type NetworkZoneAction string

// NetworkZoneRecordAction represents a lifecycle event action for network zone records.
type NetworkZoneRecordAction string

// All supported lifecycle events for network zones.
const (
	NetworkZoneCreated = NetworkZoneAction("created")
	NetworkZoneDeleted = NetworkZoneAction("deleted")
	NetworkZoneUpdated = NetworkZoneAction("updated")

	NetworkZoneRecordCreated = NetworkZoneRecordAction("created")
	NetworkZoneRecordDeleted = NetworkZoneRecordAction("deleted")
	NetworkZoneRecordUpdated = NetworkZoneRecordAction("updated")
)

// Event creates the lifecycle event for an action on a network zone.
func (a NetworkZoneAction) Event(n networkZone, requestor *api.EventLifecycleRequestor, ctx map[string]interface{}) api.EventLifecycle {
	eventType := fmt.Sprintf("network-zone-%s", a)

	u := fmt.Sprintf("/1.0/network-zones/%s", url.PathEscape(n.Info().Name))
	if n.Project() != project.Default {
		u = fmt.Sprintf("%s?project=%s", u, url.QueryEscape(n.Project()))
	}

	return api.EventLifecycle{
		Action:    eventType,
		Source:    u,
		Context:   ctx,
		Requestor: requestor,
	}
}

// Event creates the lifecycle event for an action on a network zone record.
func (a NetworkZoneRecordAction) Event(n networkZone, name string, requestor *api.EventLifecycleRequestor, ctx map[string]interface{}) api.EventLifecycle {
	eventType := fmt.Sprintf("network-zone-record-%s", a)

	u := fmt.Sprintf("/1.0/network-zones/%s/records/%s", url.PathEscape(n.Info().Name), url.PathEscape(name))
	if n.Project() != project.Default {
		u = fmt.Sprintf("%s?project=%s", u, url.QueryEscape(n.Project()))
	}

	return api.EventLifecycle{
		Action:    eventType,
		Source:    u,
		Context:   ctx,
		Requestor: requestor,
	}
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"log"

	"github.com/hashicorp/terraform/helper/customdiff"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
	appengine "google.golang.org/api/appengine/v1"
)

func resourceAppEngineApplication() *schema.Resource {
	return &schema.Resource{
		Create: resourceAppEngineApplicationCreate,
		Read:   resourceAppEngineApplicationRead,
		Update: resourceAppEngineApplicationUpdate,
		Delete: resourceAppEngineApplicationDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		CustomizeDiff: customdiff.All(
			appEngineApplicationLocationIDCustomizeDiff,
		),

		Schema: map[string]*schema.Schema{
			"project": {
				Type:         schema.TypeString,
				Optional:     true,
				Computed:     true,
				ForceNew:     true,
				ValidateFunc: validateProjectID(),
			},
			"auth_domain": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"location_id": {
				Type:     schema.TypeString,
				Required: true,
				ValidateFunc: validation.StringInSlice([]string{
					"northamerica-northeast1",
					"us-central",
					"us-west2",
					"us-east1",
					"us-east4",
					"southamerica-east1",
					"europe-west",
					"europe-west2",
					"europe-west3",
					"asia-northeast1",
					"asia-south1",
					"australia-southeast1",
				}, false),
			},
			"serving_status": {
				Type:     schema.TypeString,
				Optional: true,
				ValidateFunc: validation.StringInSlice([]string{
					"UNSPECIFIED",
					"SERVING",
					"USER_DISABLED",
					"SYSTEM_DISABLED",
				}, false),
				Computed: true,
			},
			"feature_settings": {
				Type:     schema.TypeList,
				Optional: true,
				Computed: true,
				MaxItems: 1,
				Elem:     appEngineApplicationFeatureSettingsResource(),
			},
			"name": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"url_dispatch_rule": {
				Type:     schema.TypeList,
				Computed: true,
				Elem:     appEngineApplicationURLDispatchRuleResource(),
			},
			"code_bucket": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"default_hostname": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"default_bucket": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"gcr_domain": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func appEngineApplicationURLDispatchRuleResource() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
			"domain": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"path": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"service": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func appEngineApplicationFeatureSettingsResource() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
			"split_health_checks": {
				Type:     schema.TypeBool,
				Optional: true,
			},
		},
	}
}

func appEngineApplicationLocationIDCustomizeDiff(d *schema.ResourceDiff, meta interface{}) error {
	old, new := d.GetChange("location_id")
	if old != "" && old != new {
		return fmt.Errorf("Cannot change location_id once the resource is created.")
	}
	return nil
}

func resourceAppEngineApplicationCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}
	app, err := expandAppEngineApplication(d, project)
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Creating App Engine App")
	op, err := config.clientAppEngine.Apps.Create(app).Do()
	if err != nil {
		return fmt.Errorf("Error creating App Engine application: %s", err.Error())
	}

	d.SetId(project)

	// Wait for the operation to complete
	waitErr := appEngineOperationWait(config.clientAppEngine, op, project, "App Engine app to create")
	if waitErr != nil {
		d.SetId("")
		return waitErr
	}
	log.Printf("[DEBUG] Created App Engine App")

	return resourceAppEngineApplicationRead(d, meta)
}

func resourceAppEngineApplicationRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	pid := d.Id()

	app, err := config.clientAppEngine.Apps.Get(pid).Do()
	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("App Engine Application %q", pid))
	}
	d.Set("auth_domain", app.AuthDomain)
	d.Set("code_bucket", app.CodeBucket)
	d.Set("default_bucket", app.DefaultBucket)
	d.Set("default_hostname", app.DefaultHostname)
	d.Set("location_id", app.LocationId)
	d.Set("name", app.Name)
	d.Set("serving_status", app.ServingStatus)
	d.Set("gcr_domain", app.GcrDomain)
	d.Set("project", pid)
	dispatchRules, err := flattenAppEngineApplicationDispatchRules(app.DispatchRules)
	if err != nil {
		return err
	}
	err = d.Set("url_dispatch_rule", dispatchRules)
	if err != nil {
		return fmt.Errorf("Error setting dispatch rules in state. This is a bug, please report it at https://github.com/terraform-providers/terraform-provider-google/issues. Error is:\n%s", err.Error())
	}
	featureSettings, err := flattenAppEngineApplicationFeatureSettings(app.FeatureSettings)
	if err != nil {
		return err
	}
	err = d.Set("feature_settings", featureSettings)
	if err != nil {
		return fmt.Errorf("Error setting feature settings in state. This is a bug, please report it at https://github.com/terraform-providers/terraform-provider-google/issues. Error is:\n%s", err.Error())
	}
	return nil
}

func resourceAppEngineApplicationUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	pid := d.Id()
	app, err := expandAppEngineApplication(d, pid)
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Updating App Engine App")
	op, err := config.clientAppEngine.Apps.Patch(pid, app).UpdateMask("authDomain,servingStatus,featureSettings.splitHealthChecks").Do()
	if err != nil {
		return fmt.Errorf("Error updating App Engine application: %s", err.Error())
	}

	// Wait for the operation to complete
	waitErr := appEngineOperationWait(config.clientAppEngine, op, pid, "App Engine app to update")
	if waitErr != nil {
		return waitErr
	}
	log.Printf("[DEBUG] Updated App Engine App")

	return resourceAppEngineApplicationRead(d, meta)
}

func resourceAppEngineApplicationDelete(d *schema.ResourceData, meta interface{}) error {
	log.Println("[WARN] App Engine applications cannot be destroyed once created. The project must be deleted to delete the application.")
	return nil
}

func expandAppEngineApplication(d *schema.ResourceData, project string) (*appengine.Application, error) {
	result := &appengine.Application{
		AuthDomain:    d.Get("auth_domain").(string),
		LocationId:    d.Get("location_id").(string),
		Id:            project,
		GcrDomain:     d.Get("gcr_domain").(string),
		ServingStatus: d.Get("serving_status").(string),
	}
	featureSettings, err := expandAppEngineApplicationFeatureSettings(d)
	if err != nil {
		return nil, err
	}
	result.FeatureSettings = featureSettings
	return result, nil
}

func expandAppEngineApplicationFeatureSettings(d *schema.ResourceData) (*appengine.FeatureSettings, error) {
	blocks := d.Get("feature_settings").([]interface{})
	if len(blocks) < 1 {
		return nil, nil
	}
	return &appengine.FeatureSettings{
		SplitHealthChecks: d.Get("feature_settings.0.split_health_checks").(bool),
		// force send SplitHealthChecks, so if it's set to false it still gets disabled
		ForceSendFields: []string{"SplitHealthChecks"},
	}, nil
}

func flattenAppEngineApplicationFeatureSettings(settings *appengine.FeatureSettings) ([]map[string]interface{}, error) {
	if settings == nil {
		return []map[string]interface{}{}, nil
	}
	result := map[string]interface{}{
		"split_health_checks": settings.SplitHealthChecks,
	}
	return []map[string]interface{}{result}, nil
}

func flattenAppEngineApplicationDispatchRules(rules []*appengine.UrlDispatchRule) ([]map[string]interface{}, error) {
	results := make([]map[string]interface{}, 0, len(rules))
	for _, rule := range rules {
		results = append(results, map[string]interface{}{
			"domain":  rule.Domain,
			"path":    rule.Path,
			"service": rule.Service,
		})
	}
	return results, nil
}
<commit_msg>Remove appengine location validation (#1824)<commit_after>package google

import (
	"fmt"
	"log"

	"github.com/hashicorp/terraform/helper/customdiff"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/hashicorp/terraform/helper/validation"
	appengine "google.golang.org/api/appengine/v1"
)

func resourceAppEngineApplication() *schema.Resource {
	return &schema.Resource{
		Create: resourceAppEngineApplicationCreate,
		Read:   resourceAppEngineApplicationRead,
		Update: resourceAppEngineApplicationUpdate,
		Delete: resourceAppEngineApplicationDelete,

		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		CustomizeDiff: customdiff.All(
			appEngineApplicationLocationIDCustomizeDiff,
		),

		Schema: map[string]*schema.Schema{
			"project": {
				Type:         schema.TypeString,
				Optional:     true,
				Computed:     true,
				ForceNew:     true,
				ValidateFunc: validateProjectID(),
			},
			"auth_domain": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},
			"location_id": {
				Type:     schema.TypeString,
				Required: true,
			},
			"serving_status": {
				Type:     schema.TypeString,
				Optional: true,
				ValidateFunc: validation.StringInSlice([]string{
					"UNSPECIFIED",
					"SERVING",
					"USER_DISABLED",
					"SYSTEM_DISABLED",
				}, false),
				Computed: true,
			},
			"feature_settings": {
				Type:     schema.TypeList,
				Optional: true,
				Computed: true,
				MaxItems: 1,
				Elem:     appEngineApplicationFeatureSettingsResource(),
			},
			"name": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"url_dispatch_rule": {
				Type:     schema.TypeList,
				Computed: true,
				Elem:     appEngineApplicationURLDispatchRuleResource(),
			},
			"code_bucket": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"default_hostname": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"default_bucket": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"gcr_domain": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func appEngineApplicationURLDispatchRuleResource() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
			"domain": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"path": {
				Type:     schema.TypeString,
				Computed: true,
			},
			"service": {
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func appEngineApplicationFeatureSettingsResource() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
			"split_health_checks": {
				Type:     schema.TypeBool,
				Optional: true,
			},
		},
	}
}

func appEngineApplicationLocationIDCustomizeDiff(d *schema.ResourceDiff, meta interface{}) error {
	old, new := d.GetChange("location_id")
	if old != "" && old != new {
		return fmt.Errorf("Cannot change location_id once the resource is created.")
	}
	return nil
}

func resourceAppEngineApplicationCreate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)

	project, err := getProject(d, config)
	if err != nil {
		return err
	}
	app, err := expandAppEngineApplication(d, project)
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Creating App Engine App")
	op, err := config.clientAppEngine.Apps.Create(app).Do()
	if err != nil {
		return fmt.Errorf("Error creating App Engine application: %s", err.Error())
	}

	d.SetId(project)

	// Wait for the operation to complete
	waitErr := appEngineOperationWait(config.clientAppEngine, op, project, "App Engine app to create")
	if waitErr != nil {
		d.SetId("")
		return waitErr
	}
	log.Printf("[DEBUG] Created App Engine App")

	return resourceAppEngineApplicationRead(d, meta)
}

func resourceAppEngineApplicationRead(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	pid := d.Id()

	app, err := config.clientAppEngine.Apps.Get(pid).Do()
	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("App Engine Application %q", pid))
	}
	d.Set("auth_domain", app.AuthDomain)
	d.Set("code_bucket", app.CodeBucket)
	d.Set("default_bucket", app.DefaultBucket)
	d.Set("default_hostname", app.DefaultHostname)
	d.Set("location_id", app.LocationId)
	d.Set("name", app.Name)
	d.Set("serving_status", app.ServingStatus)
	d.Set("gcr_domain", app.GcrDomain)
	d.Set("project", pid)
	dispatchRules, err := flattenAppEngineApplicationDispatchRules(app.DispatchRules)
	if err != nil {
		return err
	}
	err = d.Set("url_dispatch_rule", dispatchRules)
	if err != nil {
		return fmt.Errorf("Error setting dispatch rules in state. This is a bug, please report it at https://github.com/terraform-providers/terraform-provider-google/issues. Error is:\n%s", err.Error())
	}
	featureSettings, err := flattenAppEngineApplicationFeatureSettings(app.FeatureSettings)
	if err != nil {
		return err
	}
	err = d.Set("feature_settings", featureSettings)
	if err != nil {
		return fmt.Errorf("Error setting feature settings in state. This is a bug, please report it at https://github.com/terraform-providers/terraform-provider-google/issues. Error is:\n%s", err.Error())
	}
	return nil
}

func resourceAppEngineApplicationUpdate(d *schema.ResourceData, meta interface{}) error {
	config := meta.(*Config)
	pid := d.Id()
	app, err := expandAppEngineApplication(d, pid)
	if err != nil {
		return err
	}
	log.Printf("[DEBUG] Updating App Engine App")
	op, err := config.clientAppEngine.Apps.Patch(pid, app).UpdateMask("authDomain,servingStatus,featureSettings.splitHealthChecks").Do()
	if err != nil {
		return fmt.Errorf("Error updating App Engine application: %s", err.Error())
	}

	// Wait for the operation to complete
	waitErr := appEngineOperationWait(config.clientAppEngine, op, pid, "App Engine app to update")
	if waitErr != nil {
		return waitErr
	}
	log.Printf("[DEBUG] Updated App Engine App")

	return resourceAppEngineApplicationRead(d, meta)
}

func resourceAppEngineApplicationDelete(d *schema.ResourceData, meta interface{}) error {
	log.Println("[WARN] App Engine applications cannot be destroyed once created. The project must be deleted to delete the application.")
	return nil
}

func expandAppEngineApplication(d *schema.ResourceData, project string) (*appengine.Application, error) {
	result := &appengine.Application{
		AuthDomain:    d.Get("auth_domain").(string),
		LocationId:    d.Get("location_id").(string),
		Id:            project,
		GcrDomain:     d.Get("gcr_domain").(string),
		ServingStatus: d.Get("serving_status").(string),
	}
	featureSettings, err := expandAppEngineApplicationFeatureSettings(d)
	if err != nil {
		return nil, err
	}
	result.FeatureSettings = featureSettings
	return result, nil
}

func expandAppEngineApplicationFeatureSettings(d *schema.ResourceData) (*appengine.FeatureSettings, error) {
	blocks := d.Get("feature_settings").([]interface{})
	if len(blocks) < 1 {
		return nil, nil
	}
	return &appengine.FeatureSettings{
		SplitHealthChecks: d.Get("feature_settings.0.split_health_checks").(bool),
		// force send SplitHealthChecks, so if it's set to false it still gets disabled
		ForceSendFields: []string{"SplitHealthChecks"},
	}, nil
}

func flattenAppEngineApplicationFeatureSettings(settings *appengine.FeatureSettings) ([]map[string]interface{}, error) {
	if settings == nil {
		return []map[string]interface{}{}, nil
	}
	result := map[string]interface{}{
		"split_health_checks": settings.SplitHealthChecks,
	}
	return []map[string]interface{}{result}, nil
}

func flattenAppEngineApplicationDispatchRules(rules []*appengine.UrlDispatchRule) ([]map[string]interface{}, error) {
	results := make([]map[string]interface{}, 0, len(rules))
	for _, rule := range rules {
		results = append(results, map[string]interface{}{
			"domain":  rule.Domain,
			"path":    rule.Path,
			"service": rule.Service,
		})
	}
	return results, nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Gravitational, Inc.

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

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

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

package monitoring

import "github.com/gravitational/satellite/agent/health"

// DefaultPortChecker returns a port range checker with a default set of port ranges
func DefaultPortChecker() health.Checker {
	return NewPortChecker(
		PortRange{Protocol: protoTCP, From: 53, To: 53, Description: "internal cluster DNS"},
		PortRange{Protocol: protoUDP, From: 53, To: 53, Description: "internal cluster DNS"},
		PortRange{Protocol: protoUDP, From: 8472, To: 8472, Description: "overlay network"},
		PortRange{Protocol: protoTCP, From: 7496, To: 7496, Description: "serf (health check agents) peer to peer"},
		PortRange{Protocol: protoTCP, From: 7373, To: 7373, Description: "serf (health check agents) peer to peer"},
		PortRange{Protocol: protoTCP, From: 2379, To: 2380, Description: "etcd"},
		PortRange{Protocol: protoTCP, From: 4001, To: 4001, Description: "etcd"},
		PortRange{Protocol: protoTCP, From: 7001, To: 7001, Description: "etcd"},
		PortRange{Protocol: protoTCP, From: 6443, To: 6443, Description: "kubernetes API server"},
		PortRange{Protocol: protoTCP, From: 10248, To: 10255, Description: "kubernetes internal services range"},
		PortRange{Protocol: protoTCP, From: 5000, To: 5000, Description: "docker registry"},
		PortRange{Protocol: protoTCP, From: 3022, To: 3025, Description: "teleport internal ssh control panel"},
		PortRange{Protocol: protoTCP, From: 3080, To: 3080, Description: "teleport Web UI"},
		PortRange{Protocol: protoTCP, From: 3008, To: 3012, Description: "internal Telekube services"},
		PortRange{Protocol: protoTCP, From: 32009, To: 32009, Description: "telekube OpsCenter control panel"},
		PortRange{Protocol: protoTCP, From: 7575, To: 7575, Description: "telekube RPC agent"},
	)
}

// PreInstallPortChecker validates ports required for installation
func PreInstallPortChecker() health.Checker {
	return NewPortChecker(
		PortRange{Protocol: protoTCP, From: 4242, To: 4242, Description: "bandwidth checker"},
		PortRange{Protocol: protoTCP, From: 61008, To: 61010, Description: "installer agent ports"},
		PortRange{Protocol: protoTCP, From: 61022, To: 61024, Description: "installer agent ports"},
		PortRange{Protocol: protoTCP, From: 61009, To: 61009, Description: "install wizard"},
	)
}

// DefaultProcessChecker returns checker which will ensure no conflicting program is running
func DefaultProcessChecker() health.Checker {
	return &ProcessChecker{[]string{
		"dockerd",
		"docker-current", // Docker daemon name when installed from RHEL repos.
		"lxd",
		"coredns",
		"kube-apiserver",
		"kube-scheduler",
		"kube-controller-manager",
		"kube-proxy",
		"kubelet",
		"planet",
		"teleport",
	}}
}

// BasicCheckers detects common problems preventing k8s cluster from
// functioning properly
func BasicCheckers(checkers ...health.Checker) health.Checker {
	c := &compositeChecker{
		name: "local",
		checkers: []health.Checker{
			NewIPForwardChecker(),
			NewCNIForwardingChecker(),
			NewFlannelForwardingChecker(),
			NewWormholeBridgeForwardingChecker(),
			NewWormholeWgForwardingChecker(),
			NewBridgeNetfilterChecker(),
			NewMayDetachMountsChecker(),
			DefaultProcessChecker(),
			DefaultPortChecker(),
			DefaultBootConfigParams(),
			NewInotifyChecker(),
		},
	}
	c.checkers = append(c.checkers, checkers...)
	return c
}

// PreInstallCheckers are designed to run on a node before installing telekube
func PreInstallCheckers() health.Checker {
	return BasicCheckers(PreInstallPortChecker())
}

// DefaultBootConfigParams returns standard kernel configs required for running kubernetes
func DefaultBootConfigParams() health.Checker {
	return NewBootConfigParamChecker(
		BootConfigParam{Name: "CONFIG_NET_NS"},
		BootConfigParam{Name: "CONFIG_PID_NS"},
		BootConfigParam{Name: "CONFIG_IPC_NS"},
		BootConfigParam{Name: "CONFIG_UTS_NS"},
		BootConfigParam{Name: "CONFIG_CGROUPS"},
		BootConfigParam{Name: "CONFIG_CGROUP_CPUACCT"},
		BootConfigParam{Name: "CONFIG_CGROUP_DEVICE"},
		BootConfigParam{Name: "CONFIG_CGROUP_FREEZER"},
		BootConfigParam{Name: "CONFIG_CGROUP_SCHED"},
		BootConfigParam{Name: "CONFIG_CPUSETS"},
		BootConfigParam{Name: "CONFIG_MEMCG"},
		BootConfigParam{Name: "CONFIG_KEYS"},
		BootConfigParam{Name: "CONFIG_VETH"},
		BootConfigParam{Name: "CONFIG_BRIDGE"},
		BootConfigParam{Name: "CONFIG_BRIDGE_NETFILTER"},
		BootConfigParam{
			// https://cateee.net/lkddb/web-lkddb/NF_NAT_IPV4.html
			// CONFIG_NF_NAT_IPV4 has been removed as of kernel 5.1
			Name:             "CONFIG_NF_NAT_IPV4",
			KernelConstraint: KernelVersionLessThan(KernelVersion{Release: 5, Major: 1}),
		},
		BootConfigParam{Name: "CONFIG_IP_NF_FILTER"},
		BootConfigParam{Name: "CONFIG_IP_NF_TARGET_MASQUERADE"},
		BootConfigParam{Name: "CONFIG_NETFILTER_XT_MATCH_ADDRTYPE"},
		BootConfigParam{Name: "CONFIG_NETFILTER_XT_MATCH_CONNTRACK"},
		BootConfigParam{Name: "CONFIG_NETFILTER_XT_MATCH_IPVS"},
		BootConfigParam{Name: "CONFIG_IP_NF_NAT"},
		BootConfigParam{Name: "CONFIG_NF_NAT"},
		BootConfigParam{
			// https://cateee.net/lkddb/web-lkddb/NF_NAT_NEEDED.html
			// CONFIG_NF_NAT_NEEDED has been removed as of kernel 5.2
			Name:             "CONFIG_NF_NAT_NEEDED",
			KernelConstraint: KernelVersionLessThan(KernelVersion{Release: 5, Major: 2}),
		},
		BootConfigParam{Name: "CONFIG_POSIX_MQUEUE"},
		BootConfigParam{
			// See: https://lists.gt.net/linux/kernel/2465684#2465684
			//  and https://github.com/lxc/lxc/pull/1217
			// CONFIG_DEVPTS_MULTIPLE_INSTANCES has been removed as of kernel 4.7
			Name:             "CONFIG_DEVPTS_MULTIPLE_INSTANCES",
			KernelConstraint: KernelVersionLessThan(KernelVersion{Release: 4, Major: 7}),
		},
	)
}

// NewDNSChecker sends some default queries to monitor DNS / service discovery health
func NewDNSChecker(questionA []string, nameservers ...string) health.Checker {
	return &DNSChecker{
		QuestionA:   questionA,
		Nameservers: nameservers,
	}
}
<commit_msg>Remove CONFIG_NF_NAT_IPV4 check (#285)<commit_after>/*
Copyright 2017 Gravitational, Inc.

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

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

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

package monitoring

import "github.com/gravitational/satellite/agent/health"

// DefaultPortChecker returns a port range checker with a default set of port ranges
func DefaultPortChecker() health.Checker {
	return NewPortChecker(
		PortRange{Protocol: protoTCP, From: 53, To: 53, Description: "internal cluster DNS"},
		PortRange{Protocol: protoUDP, From: 53, To: 53, Description: "internal cluster DNS"},
		PortRange{Protocol: protoUDP, From: 8472, To: 8472, Description: "overlay network"},
		PortRange{Protocol: protoTCP, From: 7496, To: 7496, Description: "serf (health check agents) peer to peer"},
		PortRange{Protocol: protoTCP, From: 7373, To: 7373, Description: "serf (health check agents) peer to peer"},
		PortRange{Protocol: protoTCP, From: 2379, To: 2380, Description: "etcd"},
		PortRange{Protocol: protoTCP, From: 4001, To: 4001, Description: "etcd"},
		PortRange{Protocol: protoTCP, From: 7001, To: 7001, Description: "etcd"},
		PortRange{Protocol: protoTCP, From: 6443, To: 6443, Description: "kubernetes API server"},
		PortRange{Protocol: protoTCP, From: 10248, To: 10255, Description: "kubernetes internal services range"},
		PortRange{Protocol: protoTCP, From: 5000, To: 5000, Description: "docker registry"},
		PortRange{Protocol: protoTCP, From: 3022, To: 3025, Description: "teleport internal ssh control panel"},
		PortRange{Protocol: protoTCP, From: 3080, To: 3080, Description: "teleport Web UI"},
		PortRange{Protocol: protoTCP, From: 3008, To: 3012, Description: "internal Telekube services"},
		PortRange{Protocol: protoTCP, From: 32009, To: 32009, Description: "telekube OpsCenter control panel"},
		PortRange{Protocol: protoTCP, From: 7575, To: 7575, Description: "telekube RPC agent"},
	)
}

// PreInstallPortChecker validates ports required for installation
func PreInstallPortChecker() health.Checker {
	return NewPortChecker(
		PortRange{Protocol: protoTCP, From: 4242, To: 4242, Description: "bandwidth checker"},
		PortRange{Protocol: protoTCP, From: 61008, To: 61010, Description: "installer agent ports"},
		PortRange{Protocol: protoTCP, From: 61022, To: 61024, Description: "installer agent ports"},
		PortRange{Protocol: protoTCP, From: 61009, To: 61009, Description: "install wizard"},
	)
}

// DefaultProcessChecker returns checker which will ensure no conflicting program is running
func DefaultProcessChecker() health.Checker {
	return &ProcessChecker{[]string{
		"dockerd",
		"docker-current", // Docker daemon name when installed from RHEL repos.
		"lxd",
		"coredns",
		"kube-apiserver",
		"kube-scheduler",
		"kube-controller-manager",
		"kube-proxy",
		"kubelet",
		"planet",
		"teleport",
	}}
}

// BasicCheckers detects common problems preventing k8s cluster from
// functioning properly
func BasicCheckers(checkers ...health.Checker) health.Checker {
	c := &compositeChecker{
		name: "local",
		checkers: []health.Checker{
			NewIPForwardChecker(),
			NewCNIForwardingChecker(),
			NewFlannelForwardingChecker(),
			NewWormholeBridgeForwardingChecker(),
			NewWormholeWgForwardingChecker(),
			NewBridgeNetfilterChecker(),
			NewMayDetachMountsChecker(),
			DefaultProcessChecker(),
			DefaultPortChecker(),
			DefaultBootConfigParams(),
			NewInotifyChecker(),
		},
	}
	c.checkers = append(c.checkers, checkers...)
	return c
}

// PreInstallCheckers are designed to run on a node before installing telekube
func PreInstallCheckers() health.Checker {
	return BasicCheckers(PreInstallPortChecker())
}

// DefaultBootConfigParams returns standard kernel configs required for running kubernetes
func DefaultBootConfigParams() health.Checker {
	return NewBootConfigParamChecker(
		BootConfigParam{Name: "CONFIG_NET_NS"},
		BootConfigParam{Name: "CONFIG_PID_NS"},
		BootConfigParam{Name: "CONFIG_IPC_NS"},
		BootConfigParam{Name: "CONFIG_UTS_NS"},
		BootConfigParam{Name: "CONFIG_CGROUPS"},
		BootConfigParam{Name: "CONFIG_CGROUP_CPUACCT"},
		BootConfigParam{Name: "CONFIG_CGROUP_DEVICE"},
		BootConfigParam{Name: "CONFIG_CGROUP_FREEZER"},
		BootConfigParam{Name: "CONFIG_CGROUP_SCHED"},
		BootConfigParam{Name: "CONFIG_CPUSETS"},
		BootConfigParam{Name: "CONFIG_MEMCG"},
		BootConfigParam{Name: "CONFIG_KEYS"},
		BootConfigParam{Name: "CONFIG_VETH"},
		BootConfigParam{Name: "CONFIG_BRIDGE"},
		BootConfigParam{Name: "CONFIG_BRIDGE_NETFILTER"},
		BootConfigParam{Name: "CONFIG_IP_NF_FILTER"},
		BootConfigParam{Name: "CONFIG_IP_NF_TARGET_MASQUERADE"},
		BootConfigParam{Name: "CONFIG_NETFILTER_XT_MATCH_ADDRTYPE"},
		BootConfigParam{Name: "CONFIG_NETFILTER_XT_MATCH_CONNTRACK"},
		BootConfigParam{Name: "CONFIG_NETFILTER_XT_MATCH_IPVS"},
		BootConfigParam{Name: "CONFIG_IP_NF_NAT"},
		BootConfigParam{Name: "CONFIG_NF_NAT"},
		BootConfigParam{
			// https://cateee.net/lkddb/web-lkddb/NF_NAT_NEEDED.html
			// CONFIG_NF_NAT_NEEDED has been removed as of kernel 5.2
			Name:             "CONFIG_NF_NAT_NEEDED",
			KernelConstraint: KernelVersionLessThan(KernelVersion{Release: 5, Major: 2}),
		},
		BootConfigParam{Name: "CONFIG_POSIX_MQUEUE"},
		BootConfigParam{
			// See: https://lists.gt.net/linux/kernel/2465684#2465684
			//  and https://github.com/lxc/lxc/pull/1217
			// CONFIG_DEVPTS_MULTIPLE_INSTANCES has been removed as of kernel 4.7
			Name:             "CONFIG_DEVPTS_MULTIPLE_INSTANCES",
			KernelConstraint: KernelVersionLessThan(KernelVersion{Release: 4, Major: 7}),
		},
	)
}

// NewDNSChecker sends some default queries to monitor DNS / service discovery health
func NewDNSChecker(questionA []string, nameservers ...string) health.Checker {
	return &DNSChecker{
		QuestionA:   questionA,
		Nameservers: nameservers,
	}
}
<|endoftext|>