<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.

package ast

import "fmt"

// A Visitor's Visit method is invoked for each node encountered by Walk.
// If the result visitor w is not nil, Walk visits each of the children
// of node with the visitor w, followed by a call of w.Visit(nil).
type Visitor interface {
	Visit(node Node) (w Visitor)
}

// Helper functions for common node lists. They may be empty.

func walkIdentList(v Visitor, list []*Ident) {
	for _, x := range list {
		Walk(v, x)
	}
}

func walkExprList(v Visitor, list []Expr) {
	for _, x := range list {
		Walk(v, x)
	}
}

func walkStmtList(v Visitor, list []Stmt) {
	for _, x := range list {
		Walk(v, x)
	}
}

func walkDeclList(v Visitor, list []Decl) {
	for _, x := range list {
		Walk(v, x)
	}
}

// TODO(gri): Investigate if providing a closure to Walk leads to
//            simpler use (and may help eliminate Inspect in turn).

// Walk traverses an AST in depth-first order: It starts by calling
// v.Visit(node); node must not be nil. If the visitor w returned by
// v.Visit(node) is not nil, Walk is invoked recursively with visitor
// w for each of the non-nil children of node, followed by a call of
// w.Visit(nil).
//
func Walk(v Visitor, node Node) {
	if v = v.Visit(node); v == nil {
		return
	}

	// walk children
	// (the order of the cases matches the order
	// of the corresponding node types in ast.go)
	switch n := node.(type) {
	// Comments and fields
	case *Comment:
		// nothing to do

	case *CommentGroup:
		for _, c := range n.List {
			Walk(v, c)
		}

	case *Field:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		walkIdentList(v, n.Names)
		Walk(v, n.Type)
		if n.Tag != nil {
			Walk(v, n.Tag)
		}
		if n.Comment != nil {
			Walk(v, n.Comment)
		}

	case *FieldList:
		for _, f := range n.List {
			Walk(v, f)
		}

	// Expressions
	case *BadExpr, *Ident, *BasicLit:
		// nothing to do

	case *Ellipsis:
		if n.Elt != nil {
			Walk(v, n.Elt)
		}

	case *FuncLit:
		Walk(v, n.Type)
		Walk(v, n.Body)

	case *CompositeLit:
		if n.Type != nil {
			Walk(v, n.Type)
		}
		walkExprList(v, n.Elts)

	case *ParenExpr:
		Walk(v, n.X)

	case *SelectorExpr:
		Walk(v, n.X)
		Walk(v, n.Sel)

	case *IndexExpr:
		Walk(v, n.X)
		Walk(v, n.Index)

	case *SliceExpr:
		Walk(v, n.X)
		if n.Low != nil {
			Walk(v, n.Low)
		}
		if n.High != nil {
			Walk(v, n.High)
		}

	case *TypeAssertExpr:
		Walk(v, n.X)
		if n.Type != nil {
			Walk(v, n.Type)
		}

	case *CallExpr:
		Walk(v, n.Fun)
		walkExprList(v, n.Args)

	case *StarExpr:
		Walk(v, n.X)

	case *UnaryExpr:
		Walk(v, n.X)

	case *BinaryExpr:
		Walk(v, n.X)
		Walk(v, n.Y)

	case *KeyValueExpr:
		Walk(v, n.Key)
		Walk(v, n.Value)

	// Types
	case *ArrayType:
		if n.Len != nil {
			Walk(v, n.Len)
		}
		Walk(v, n.Elt)

	case *StructType:
		Walk(v, n.Fields)

	case *FuncType:
		Walk(v, n.Params)
		if n.Results != nil {
			Walk(v, n.Results)
		}

	case *InterfaceType:
		Walk(v, n.Methods)

	case *MapType:
		Walk(v, n.Key)
		Walk(v, n.Value)

	case *ChanType:
		Walk(v, n.Value)

	// Statements
	case *BadStmt:
		// nothing to do

	case *DeclStmt:
		Walk(v, n.Decl)

	case *EmptyStmt:
		// nothing to do

	case *LabeledStmt:
		Walk(v, n.Label)
		Walk(v, n.Stmt)

	case *ExprStmt:
		Walk(v, n.X)

	case *IncDecStmt:
		Walk(v, n.X)

	case *AssignStmt:
		walkExprList(v, n.Lhs)
		walkExprList(v, n.Rhs)

	case *GoStmt:
		Walk(v, n.Call)

	case *DeferStmt:
		Walk(v, n.Call)

	case *ReturnStmt:
		walkExprList(v, n.Results)

	case *BranchStmt:
		if n.Label != nil {
			Walk(v, n.Label)
		}

	case *BlockStmt:
		walkStmtList(v, n.List)

	case *IfStmt:
		if n.Init != nil {
			Walk(v, n.Init)
		}
		if n.Cond != nil {
			Walk(v, n.Cond)
		}
		Walk(v, n.Body)
		if n.Else != nil {
			Walk(v, n.Else)
		}

	case *CaseClause:
		walkExprList(v, n.Values)
		walkStmtList(v, n.Body)

	case *SwitchStmt:
		if n.Init != nil {
			Walk(v, n.Init)
		}
		if n.Tag != nil {
			Walk(v, n.Tag)
		}
		Walk(v, n.Body)

	case *TypeCaseClause:
		for _, x := range n.Types {
			Walk(v, x)
		}
		walkStmtList(v, n.Body)

	case *TypeSwitchStmt:
		if n.Init != nil {
			Walk(v, n.Init)
		}
		Walk(v, n.Assign)
		Walk(v, n.Body)

	case *CommClause:
		if n.Comm != nil {
			Walk(v, n.Comm)
		}
		walkStmtList(v, n.Body)

	case *SelectStmt:
		Walk(v, n.Body)

	case *ForStmt:
		if n.Init != nil {
			Walk(v, n.Init)
		}
		if n.Cond != nil {
			Walk(v, n.Cond)
		}
		if n.Post != nil {
			Walk(v, n.Post)
		}
		Walk(v, n.Body)

	case *RangeStmt:
		Walk(v, n.Key)
		if n.Value != nil {
			Walk(v, n.Value)
		}
		Walk(v, n.X)
		Walk(v, n.Body)

	// Declarations
	case *ImportSpec:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		if n.Name != nil {
			Walk(v, n.Name)
		}
		Walk(v, n.Path)
		if n.Comment != nil {
			Walk(v, n.Comment)
		}

	case *ValueSpec:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		walkIdentList(v, n.Names)
		if n.Type != nil {
			Walk(v, n.Type)
		}
		walkExprList(v, n.Values)
		if n.Comment != nil {
			Walk(v, n.Comment)
		}

	case *TypeSpec:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		Walk(v, n.Name)
		Walk(v, n.Type)
		if n.Comment != nil {
			Walk(v, n.Comment)
		}

	case *BadDecl:
		// nothing to do

	case *GenDecl:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		for _, s := range n.Specs {
			Walk(v, s)
		}

	case *FuncDecl:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		if n.Recv != nil {
			Walk(v, n.Recv)
		}
		Walk(v, n.Name)
		Walk(v, n.Type)
		if n.Body != nil {
			Walk(v, n.Body)
		}

	// Files and packages
	case *File:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		Walk(v, n.Name)
		walkDeclList(v, n.Decls)
		for _, g := range n.Comments {
			Walk(v, g)
		}
		// don't walk n.Comments - they have been
		// visited already through the individual
		// nodes

	case *Package:
		for _, f := range n.Files {
			Walk(v, f)
		}

	default:
		fmt.Printf("ast.Walk: unexpected node type %T", n)
		panic("ast.Walk")
	}

	v.Visit(nil)
}

type inspector func(Node) bool

func (f inspector) Visit(node Node) Visitor {
	if f(node) {
		return f
	}
	return nil
}

// Inspect traverses an AST in depth-first order: It starts by calling
// f(node); node must not be nil. If f returns true, Inspect invokes f
// for all the non-nil children of node, recursively.
//
func Inspect(node Node, f func(Node) bool) {
	Walk(inspector(f), node)
}
<commit_msg>go/ast: add missing handling of SendStmt to ast.Walk<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.

package ast

import "fmt"

// A Visitor's Visit method is invoked for each node encountered by Walk.
// If the result visitor w is not nil, Walk visits each of the children
// of node with the visitor w, followed by a call of w.Visit(nil).
type Visitor interface {
	Visit(node Node) (w Visitor)
}

// Helper functions for common node lists. They may be empty.

func walkIdentList(v Visitor, list []*Ident) {
	for _, x := range list {
		Walk(v, x)
	}
}

func walkExprList(v Visitor, list []Expr) {
	for _, x := range list {
		Walk(v, x)
	}
}

func walkStmtList(v Visitor, list []Stmt) {
	for _, x := range list {
		Walk(v, x)
	}
}

func walkDeclList(v Visitor, list []Decl) {
	for _, x := range list {
		Walk(v, x)
	}
}

// TODO(gri): Investigate if providing a closure to Walk leads to
//            simpler use (and may help eliminate Inspect in turn).

// Walk traverses an AST in depth-first order: It starts by calling
// v.Visit(node); node must not be nil. If the visitor w returned by
// v.Visit(node) is not nil, Walk is invoked recursively with visitor
// w for each of the non-nil children of node, followed by a call of
// w.Visit(nil).
//
func Walk(v Visitor, node Node) {
	if v = v.Visit(node); v == nil {
		return
	}

	// walk children
	// (the order of the cases matches the order
	// of the corresponding node types in ast.go)
	switch n := node.(type) {
	// Comments and fields
	case *Comment:
		// nothing to do

	case *CommentGroup:
		for _, c := range n.List {
			Walk(v, c)
		}

	case *Field:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		walkIdentList(v, n.Names)
		Walk(v, n.Type)
		if n.Tag != nil {
			Walk(v, n.Tag)
		}
		if n.Comment != nil {
			Walk(v, n.Comment)
		}

	case *FieldList:
		for _, f := range n.List {
			Walk(v, f)
		}

	// Expressions
	case *BadExpr, *Ident, *BasicLit:
		// nothing to do

	case *Ellipsis:
		if n.Elt != nil {
			Walk(v, n.Elt)
		}

	case *FuncLit:
		Walk(v, n.Type)
		Walk(v, n.Body)

	case *CompositeLit:
		if n.Type != nil {
			Walk(v, n.Type)
		}
		walkExprList(v, n.Elts)

	case *ParenExpr:
		Walk(v, n.X)

	case *SelectorExpr:
		Walk(v, n.X)
		Walk(v, n.Sel)

	case *IndexExpr:
		Walk(v, n.X)
		Walk(v, n.Index)

	case *SliceExpr:
		Walk(v, n.X)
		if n.Low != nil {
			Walk(v, n.Low)
		}
		if n.High != nil {
			Walk(v, n.High)
		}

	case *TypeAssertExpr:
		Walk(v, n.X)
		if n.Type != nil {
			Walk(v, n.Type)
		}

	case *CallExpr:
		Walk(v, n.Fun)
		walkExprList(v, n.Args)

	case *StarExpr:
		Walk(v, n.X)

	case *UnaryExpr:
		Walk(v, n.X)

	case *BinaryExpr:
		Walk(v, n.X)
		Walk(v, n.Y)

	case *KeyValueExpr:
		Walk(v, n.Key)
		Walk(v, n.Value)

	// Types
	case *ArrayType:
		if n.Len != nil {
			Walk(v, n.Len)
		}
		Walk(v, n.Elt)

	case *StructType:
		Walk(v, n.Fields)

	case *FuncType:
		Walk(v, n.Params)
		if n.Results != nil {
			Walk(v, n.Results)
		}

	case *InterfaceType:
		Walk(v, n.Methods)

	case *MapType:
		Walk(v, n.Key)
		Walk(v, n.Value)

	case *ChanType:
		Walk(v, n.Value)

	// Statements
	case *BadStmt:
		// nothing to do

	case *DeclStmt:
		Walk(v, n.Decl)

	case *EmptyStmt:
		// nothing to do

	case *LabeledStmt:
		Walk(v, n.Label)
		Walk(v, n.Stmt)

	case *ExprStmt:
		Walk(v, n.X)

	case *SendStmt:
		Walk(v, n.Chan)
		Walk(v, n.Value)

	case *IncDecStmt:
		Walk(v, n.X)

	case *AssignStmt:
		walkExprList(v, n.Lhs)
		walkExprList(v, n.Rhs)

	case *GoStmt:
		Walk(v, n.Call)

	case *DeferStmt:
		Walk(v, n.Call)

	case *ReturnStmt:
		walkExprList(v, n.Results)

	case *BranchStmt:
		if n.Label != nil {
			Walk(v, n.Label)
		}

	case *BlockStmt:
		walkStmtList(v, n.List)

	case *IfStmt:
		if n.Init != nil {
			Walk(v, n.Init)
		}
		if n.Cond != nil {
			Walk(v, n.Cond)
		}
		Walk(v, n.Body)
		if n.Else != nil {
			Walk(v, n.Else)
		}

	case *CaseClause:
		walkExprList(v, n.Values)
		walkStmtList(v, n.Body)

	case *SwitchStmt:
		if n.Init != nil {
			Walk(v, n.Init)
		}
		if n.Tag != nil {
			Walk(v, n.Tag)
		}
		Walk(v, n.Body)

	case *TypeCaseClause:
		for _, x := range n.Types {
			Walk(v, x)
		}
		walkStmtList(v, n.Body)

	case *TypeSwitchStmt:
		if n.Init != nil {
			Walk(v, n.Init)
		}
		Walk(v, n.Assign)
		Walk(v, n.Body)

	case *CommClause:
		if n.Comm != nil {
			Walk(v, n.Comm)
		}
		walkStmtList(v, n.Body)

	case *SelectStmt:
		Walk(v, n.Body)

	case *ForStmt:
		if n.Init != nil {
			Walk(v, n.Init)
		}
		if n.Cond != nil {
			Walk(v, n.Cond)
		}
		if n.Post != nil {
			Walk(v, n.Post)
		}
		Walk(v, n.Body)

	case *RangeStmt:
		Walk(v, n.Key)
		if n.Value != nil {
			Walk(v, n.Value)
		}
		Walk(v, n.X)
		Walk(v, n.Body)

	// Declarations
	case *ImportSpec:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		if n.Name != nil {
			Walk(v, n.Name)
		}
		Walk(v, n.Path)
		if n.Comment != nil {
			Walk(v, n.Comment)
		}

	case *ValueSpec:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		walkIdentList(v, n.Names)
		if n.Type != nil {
			Walk(v, n.Type)
		}
		walkExprList(v, n.Values)
		if n.Comment != nil {
			Walk(v, n.Comment)
		}

	case *TypeSpec:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		Walk(v, n.Name)
		Walk(v, n.Type)
		if n.Comment != nil {
			Walk(v, n.Comment)
		}

	case *BadDecl:
		// nothing to do

	case *GenDecl:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		for _, s := range n.Specs {
			Walk(v, s)
		}

	case *FuncDecl:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		if n.Recv != nil {
			Walk(v, n.Recv)
		}
		Walk(v, n.Name)
		Walk(v, n.Type)
		if n.Body != nil {
			Walk(v, n.Body)
		}

	// Files and packages
	case *File:
		if n.Doc != nil {
			Walk(v, n.Doc)
		}
		Walk(v, n.Name)
		walkDeclList(v, n.Decls)
		for _, g := range n.Comments {
			Walk(v, g)
		}
		// don't walk n.Comments - they have been
		// visited already through the individual
		// nodes

	case *Package:
		for _, f := range n.Files {
			Walk(v, f)
		}

	default:
		fmt.Printf("ast.Walk: unexpected node type %T", n)
		panic("ast.Walk")
	}

	v.Visit(nil)
}

type inspector func(Node) bool

func (f inspector) Visit(node Node) Visitor {
	if f(node) {
		return f
	}
	return nil
}

// Inspect traverses an AST in depth-first order: It starts by calling
// f(node); node must not be nil. If f returns true, Inspect invokes f
// for all the non-nil children of node, recursively.
//
func Inspect(node Node, f func(Node) bool) {
	Walk(inspector(f), node)
}
<|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.

// Represents JSON data structure using native Go types: booleans, floats,
// strings, arrays, and maps.

package json

import (
	"container/vector"
	"os"
)

// Decode a JSON string

// Decode parses the string s as a JSON-syntax string and returns the
// generic JSON object representation.  The object representation is a tree
// of Go data types.  The data return value may be one of float64, string,
// bool, nil, []interface{} or map[string]interface{}.  The array and map
// elements may in turn contain any of the types listed above and so on.

// If Decode encounters a syntax error, it returns with err set to an
// instance of ParseError.  See ParseError documentation for details.
func Decode(s string) (data interface{}, err os.Error) {
	jb := newDecoder(nil, nil)
	ok, errPos, errTok := Parse(s, jb)
	if ok {
		data = jb.Data()
	} else {
		err = &ParseError{Index: errPos, Token: errTok}
	}
	return
}

type decoder struct {
	// A value being constructed.
	value interface{}
	// Container entity to flush into.  Can be either vector.Vector or
	// map[string]interface{}.
	container interface{}
	// The index into the container interface.  Either int or string.
	index interface{}
}

func newDecoder(container interface{}, key interface{}) *decoder {
	return &decoder{container: container, index: key}
}

func (j *decoder) Int64(i int64) { j.value = float64(i) }

func (j *decoder) Uint64(i uint64) { j.value = float64(i) }

func (j *decoder) Float64(f float64) { j.value = float64(f) }

func (j *decoder) String(s string) { j.value = s }

func (j *decoder) Bool(b bool) { j.value = b }

func (j *decoder) Null() { j.value = nil }

func (j *decoder) Array() { j.value = new(vector.Vector) }

func (j *decoder) Map() { j.value = make(map[string]interface{}) }

func (j *decoder) Elem(i int) Builder {
	v, ok := j.value.(*vector.Vector)
	if !ok {
		v = new(vector.Vector)
		j.value = v
	}
	if v.Len() <= i {
		v.Resize(i+1, (i+1)*2)
	}
	return newDecoder(v, i)
}

func (j *decoder) Key(s string) Builder {
	m, ok := j.value.(map[string]interface{})
	if !ok {
		m = make(map[string]interface{})
		j.value = m
	}
	return newDecoder(m, s)
}

func (j *decoder) Flush() {
	switch c := j.container.(type) {
	case *vector.Vector:
		index := j.index.(int)
		c.Set(index, j.Data())
	case map[string]interface{}:
		index := j.index.(string)
		c[index] = j.Data()
	}
}

// Get the value built by this builder.
func (j *decoder) Data() interface{} {
	switch v := j.value.(type) {
	case *vector.Vector:
		return v.Data()
	}
	return j.value
}
<commit_msg>json: fix doc comment<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.

// Represents JSON data structure using native Go types: booleans, floats,
// strings, arrays, and maps.

package json

import (
	"container/vector"
	"os"
)

// Decode a JSON string

// Decode parses the string s as a JSON-syntax string and returns the
// generic JSON object representation.  The object representation is a tree
// of Go data types.  The data return value may be one of float64, string,
// bool, nil, []interface{} or map[string]interface{}.  The array and map
// elements may in turn contain any of the types listed above and so on.
//
// If Decode encounters a syntax error, it returns with err set to an
// instance of ParseError.  See ParseError documentation for details.
func Decode(s string) (data interface{}, err os.Error) {
	jb := newDecoder(nil, nil)
	ok, errPos, errTok := Parse(s, jb)
	if ok {
		data = jb.Data()
	} else {
		err = &ParseError{Index: errPos, Token: errTok}
	}
	return
}

type decoder struct {
	// A value being constructed.
	value interface{}
	// Container entity to flush into.  Can be either vector.Vector or
	// map[string]interface{}.
	container interface{}
	// The index into the container interface.  Either int or string.
	index interface{}
}

func newDecoder(container interface{}, key interface{}) *decoder {
	return &decoder{container: container, index: key}
}

func (j *decoder) Int64(i int64) { j.value = float64(i) }

func (j *decoder) Uint64(i uint64) { j.value = float64(i) }

func (j *decoder) Float64(f float64) { j.value = float64(f) }

func (j *decoder) String(s string) { j.value = s }

func (j *decoder) Bool(b bool) { j.value = b }

func (j *decoder) Null() { j.value = nil }

func (j *decoder) Array() { j.value = new(vector.Vector) }

func (j *decoder) Map() { j.value = make(map[string]interface{}) }

func (j *decoder) Elem(i int) Builder {
	v, ok := j.value.(*vector.Vector)
	if !ok {
		v = new(vector.Vector)
		j.value = v
	}
	if v.Len() <= i {
		v.Resize(i+1, (i+1)*2)
	}
	return newDecoder(v, i)
}

func (j *decoder) Key(s string) Builder {
	m, ok := j.value.(map[string]interface{})
	if !ok {
		m = make(map[string]interface{})
		j.value = m
	}
	return newDecoder(m, s)
}

func (j *decoder) Flush() {
	switch c := j.container.(type) {
	case *vector.Vector:
		index := j.index.(int)
		c.Set(index, j.Data())
	case map[string]interface{}:
		index := j.index.(string)
		c[index] = j.Data()
	}
}

// Get the value built by this builder.
func (j *decoder) Data() interface{} {
	switch v := j.value.(type) {
	case *vector.Vector:
		return v.Data()
	}
	return j.value
}
<|endoftext|>


<commit_before>package provision

import (
	"fmt"
	"net/url"
	"strings"

	"github.com/docker/machine/libmachine/auth"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcndockerclient"
	"github.com/docker/machine/libmachine/swarm"
	"github.com/samalba/dockerclient"
)

func configureSwarm(p Provisioner, swarmOptions swarm.Options, authOptions auth.Options) error {
	if !swarmOptions.IsSwarm {
		return nil
	}

	log.Info("Configuring swarm...")

	ip, err := p.GetDriver().GetIP()
	if err != nil {
		return err
	}

	u, err := url.Parse(swarmOptions.Host)
	if err != nil {
		return err
	}

	parts := strings.Split(u.Host, ":")
	port := parts[1]

	dockerPort := "2376"
	dockerDir := p.GetDockerOptionsDir()
	dockerHost := fmt.Sprintf("tcp://%s:%s", ip, dockerPort)
	dockerClient := mcndockerclient.RemoteDocker{
		HostURL:    dockerHost,
		AuthOption: &authOptions,
	}
	advertiseInfo := fmt.Sprintf("%s:%s", ip, dockerPort)

	if swarmOptions.Master {
		cmd := fmt.Sprintf("manage --tlsverify --tlscacert=%s --tlscert=%s --tlskey=%s -H %s --strategy %s --advertise %s",
			authOptions.CaCertRemotePath,
			authOptions.ServerCertRemotePath,
			authOptions.ServerKeyRemotePath,
			swarmOptions.Host,
			swarmOptions.Strategy,
			advertiseInfo,
		)

		cmdMaster := strings.Fields(cmd)
		for _, option := range swarmOptions.ArbitraryFlags {
			cmdMaster = append(cmdMaster, "--"+option)
		}

		//Discovery must be at end of command
		cmdMaster = append(cmdMaster, swarmOptions.Discovery)

		hostBind := fmt.Sprintf("%s:%s", dockerDir, dockerDir)
		masterHostConfig := dockerclient.HostConfig{
			RestartPolicy: dockerclient.RestartPolicy{
				Name:              "Always",
				MaximumRetryCount: 0,
			},
			Binds:        []string{hostBind},
			PortBindings: map[string][]dockerclient.PortBinding{"3376/tcp": {{"", port}}},
			NetworkMode:  "host",
		}

		swarmMasterConfig := &dockerclient.ContainerConfig{
			Image: swarmOptions.Image,
			Env:   swarmOptions.Env,
			ExposedPorts: map[string]struct{}{
				"2375/tcp": {},
				"3376/tcp": {},
			},
			Cmd:        cmdMaster,
			HostConfig: masterHostConfig,
		}

		err = mcndockerclient.CreateContainer(dockerClient, swarmMasterConfig, "swarm-agent-master")
		if err != nil {
			return err
		}
	}

	workerHostConfig := dockerclient.HostConfig{
		RestartPolicy: dockerclient.RestartPolicy{
			Name:              "Always",
			MaximumRetryCount: 0,
		},
		NetworkMode: "host",
	}

	swarmWorkerConfig := &dockerclient.ContainerConfig{
		Image: swarmOptions.Image,
		Env:   swarmOptions.Env,
		Cmd: []string{
			"join",
			"--advertise",
			advertiseInfo,
			swarmOptions.Discovery,
		},
		HostConfig: workerHostConfig,
	}

	return mcndockerclient.CreateContainer(dockerClient, swarmWorkerConfig, "swarm-agent")
}
<commit_msg>fix swarm provision issue #2715: invalid restart policy<commit_after>package provision

import (
	"fmt"
	"net/url"
	"strings"

	"github.com/docker/machine/libmachine/auth"
	"github.com/docker/machine/libmachine/log"
	"github.com/docker/machine/libmachine/mcndockerclient"
	"github.com/docker/machine/libmachine/swarm"
	"github.com/samalba/dockerclient"
)

func configureSwarm(p Provisioner, swarmOptions swarm.Options, authOptions auth.Options) error {
	if !swarmOptions.IsSwarm {
		return nil
	}

	log.Info("Configuring swarm...")

	ip, err := p.GetDriver().GetIP()
	if err != nil {
		return err
	}

	u, err := url.Parse(swarmOptions.Host)
	if err != nil {
		return err
	}

	parts := strings.Split(u.Host, ":")
	port := parts[1]

	dockerPort := "2376"
	dockerDir := p.GetDockerOptionsDir()
	dockerHost := fmt.Sprintf("tcp://%s:%s", ip, dockerPort)
	dockerClient := mcndockerclient.RemoteDocker{
		HostURL:    dockerHost,
		AuthOption: &authOptions,
	}
	advertiseInfo := fmt.Sprintf("%s:%s", ip, dockerPort)

	if swarmOptions.Master {
		cmd := fmt.Sprintf("manage --tlsverify --tlscacert=%s --tlscert=%s --tlskey=%s -H %s --strategy %s --advertise %s",
			authOptions.CaCertRemotePath,
			authOptions.ServerCertRemotePath,
			authOptions.ServerKeyRemotePath,
			swarmOptions.Host,
			swarmOptions.Strategy,
			advertiseInfo,
		)

		cmdMaster := strings.Fields(cmd)
		for _, option := range swarmOptions.ArbitraryFlags {
			cmdMaster = append(cmdMaster, "--"+option)
		}

		//Discovery must be at end of command
		cmdMaster = append(cmdMaster, swarmOptions.Discovery)

		hostBind := fmt.Sprintf("%s:%s", dockerDir, dockerDir)
		masterHostConfig := dockerclient.HostConfig{
			RestartPolicy: dockerclient.RestartPolicy{
				Name:              "always",
				MaximumRetryCount: 0,
			},
			Binds:        []string{hostBind},
			PortBindings: map[string][]dockerclient.PortBinding{"3376/tcp": {{"", port}}},
			NetworkMode:  "host",
		}

		swarmMasterConfig := &dockerclient.ContainerConfig{
			Image: swarmOptions.Image,
			Env:   swarmOptions.Env,
			ExposedPorts: map[string]struct{}{
				"2375/tcp": {},
				"3376/tcp": {},
			},
			Cmd:        cmdMaster,
			HostConfig: masterHostConfig,
		}

		err = mcndockerclient.CreateContainer(dockerClient, swarmMasterConfig, "swarm-agent-master")
		if err != nil {
			return err
		}
	}

	workerHostConfig := dockerclient.HostConfig{
		RestartPolicy: dockerclient.RestartPolicy{
			Name:              "always",
			MaximumRetryCount: 0,
		},
		NetworkMode: "host",
	}

	swarmWorkerConfig := &dockerclient.ContainerConfig{
		Image: swarmOptions.Image,
		Env:   swarmOptions.Env,
		Cmd: []string{
			"join",
			"--advertise",
			advertiseInfo,
			swarmOptions.Discovery,
		},
		HostConfig: workerHostConfig,
	}

	return mcndockerclient.CreateContainer(dockerClient, swarmWorkerConfig, "swarm-agent")
}
<|endoftext|>


<commit_before>package charm

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
)

// InfoResponse is sent by the charm store in response to charm-info requests.
type InfoResponse struct {
	Revision int      `json:"revision"` // Zero is valid. Can't omitempty.
	Sha256   string   `json:"sha256,omitempty"`
	Digest   string   `json:"digest,omitempty"`
	Errors   []string `json:"errors,omitempty"`
	Warnings []string `json:"warnings,omitempty"`
}

// EventResponse is sent by the charm store in response to charm-event requests.
type EventResponse struct {
	Kind     string   `json:"kind"`
	Revision int      `json:"revision"` // Zero is valid. Can't omitempty.
	Digest   string   `json:"digest,omitempty"`
	Errors   []string `json:"errors,omitempty"`
	Warnings []string `json:"warnings,omitempty"`
	Time     string   `json:"time,omitempty"`
}

// Repository respresents a collection of charms.
type Repository interface {
	Get(curl *URL) (Charm, error)
	Latest(curl *URL) (int, error)
}

// NotFoundError represents an error indicating that the requested data wasn't found.
type NotFoundError struct {
	msg string
}

func (e *NotFoundError) Error() string {
	return e.msg
}

// CharmStore is a Repository that provides access to the public juju charm store.
type CharmStore struct {
	baseURL   string
}

//var Store = &CharmStore{"https://store.juju.ubuntu.com"}
var Store = &CharmStore{"http://localhost:8080"}

// Info returns details for a charm in the charm store.
func (s *CharmStore) Info(curl *URL) (*InfoResponse, error) {
	key := curl.String()
	resp, err := http.Get(s.baseURL + "/charm-info?charms=" + url.QueryEscape(key))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	infos := make(map[string]*InfoResponse)
	if err = json.Unmarshal(body, &infos); err != nil {
		return nil, err
	}
	info, found := infos[key]
	if !found {
		return nil, fmt.Errorf("charm: charm store returned response without charm %q", key)
	}
	if len(info.Errors) == 1 && info.Errors[0] == "entry not found" {
		return nil, &NotFoundError{fmt.Sprintf("charm not found: %s", curl)}
	}
	return info, nil
}

// Event returns details for a charm event in the charm store.
//
// If digest is empty, the latest event is returned.
func (s *CharmStore) Event(curl *URL, digest string) (*EventResponse, error) {
	key := curl.String()
	query := key
	if digest != "" {
		query += "@" + digest
	}
	resp, err := http.Get(s.baseURL + "/charm-event?charms=" + url.QueryEscape(query))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	events := make(map[string]*EventResponse)
	if err = json.Unmarshal(body, &events); err != nil {
		return nil, err
	}
	event, found := events[key]
	if !found {
		return nil, fmt.Errorf("charm: charm store returned response without charm %q", key)
	}
	if len(event.Errors) == 1 && event.Errors[0] == "entry not found" {
		if digest == "" {
			return nil, &NotFoundError{fmt.Sprintf("charm event not found for %q", curl)}
		} else {
			return nil, &NotFoundError{fmt.Sprintf("charm event not found for %q with digest %q", curl, digest)}
		}
	}
	return event, nil
}

// revision returns the revision and SHA256 digest of the charm referenced by curl.
func (s *CharmStore) revision(curl *URL) (revision int, digest string, err error) {
	info, err := s.Info(curl)
	if err != nil {
		return 0, "", err
	}
	for _, w := range info.Warnings {
		log.Warningf("charm: charm store reports for %q: %s", curl, w)
	}
	if info.Errors != nil {
		return 0, "", fmt.Errorf("charm info errors for %q: %s", curl, strings.Join(info.Errors, "; "))
	}
	return info.Revision, info.Sha256, nil
}

// Latest returns the latest revision of the charm referenced by curl, regardless
// of the revision set on curl itself.
func (s *CharmStore) Latest(curl *URL) (int, error) {
	rev, _, err := s.revision(curl.WithRevision(-1))
	return rev, err
}

// verify returns an error unless a file exists at path with a hex-encoded
// SHA256 matching digest.
func verify(path, digest string) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()
	h := sha256.New()
	if _, err := io.Copy(h, f); err != nil {
		return err
	}
	if hex.EncodeToString(h.Sum(nil)) != digest {
		return fmt.Errorf("bad SHA256 of %q", path)
	}
	return nil
}

// Get returns the charm referenced by curl.
func (s *CharmStore) Get(curl *URL) (Charm, error) {
	cachePath := config.JujuHomePath("cache")
	if err := os.MkdirAll(cachePath, 0755); err != nil {
		return nil, err
	}
	rev, digest, err := s.revision(curl)
	if err != nil {
		return nil, err
	}
	if curl.Revision == -1 {
		curl = curl.WithRevision(rev)
	} else if curl.Revision != rev {
		return nil, fmt.Errorf("charm: store returned charm with wrong revision for %q", curl.String())
	}
	path := filepath.Join(cachePath, Quote(curl.String())+".charm")
	if verify(path, digest) != nil {
		resp, err := http.Get(s.baseURL + "/charm/" + url.QueryEscape(curl.Path()))
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()
		f, err := ioutil.TempFile(cachePath, "charm-download")
		if err != nil {
			return nil, err
		}
		dlPath := f.Name()
		_, err = io.Copy(f, resp.Body)
		if cerr := f.Close(); err == nil {
			err = cerr
		}
		if err != nil {
			os.Remove(dlPath)
			return nil, err
		}
		if err := os.Rename(dlPath, path); err != nil {
			return nil, err
		}
	}
	if err := verify(path, digest); err != nil {
		return nil, err
	}
	return ReadBundle(path)
}

// LocalRepository represents a local directory containing subdirectories
// named after an Ubuntu series, each of which contains charms targeted for
// that series. For example:
//
//   /path/to/repository/oneiric/mongodb/
//   /path/to/repository/precise/mongodb.charm
//   /path/to/repository/precise/wordpress/
type LocalRepository struct {
	Path string
}

// Latest returns the latest revision of the charm referenced by curl, regardless
// of the revision set on curl itself.
func (r *LocalRepository) Latest(curl *URL) (int, error) {
	ch, err := r.Get(curl.WithRevision(-1))
	if err != nil {
		return 0, err
	}
	return ch.Revision(), nil
}

func repoNotFound(path string) error {
	return &NotFoundError{fmt.Sprintf("no repository found at %q", path)}
}

func charmNotFound(curl *URL, repoPath string) error {
	return &NotFoundError{fmt.Sprintf("no charms found matching %q in %s", curl, repoPath)}
}

func mightBeCharm(info os.FileInfo) bool {
	if info.IsDir() {
		return !strings.HasPrefix(info.Name(), ".")
	}
	return strings.HasSuffix(info.Name(), ".charm")
}

// Get returns a charm matching curl, if one exists. If curl has a revision of
// -1, it returns the latest charm that matches curl. If multiple candidates
// satisfy the foregoing, the first one encountered will be returned.
func (r *LocalRepository) Get(curl *URL) (Charm, error) {
	if curl.Schema != "local" {
		return nil, fmt.Errorf("local repository got URL with non-local schema: %q", curl)
	}
	info, err := os.Stat(r.Path)
	if err != nil {
		if os.IsNotExist(err) {
			err = repoNotFound(r.Path)
		}
		return nil, err
	}
	if !info.IsDir() {
		return nil, repoNotFound(r.Path)
	}
	path := filepath.Join(r.Path, curl.Series)
	infos, err := ioutil.ReadDir(path)
	if err != nil {
		return nil, charmNotFound(curl, r.Path)
	}
	var latest Charm
	for _, info := range infos {
		if !mightBeCharm(info) {
			continue
		}
		chPath := filepath.Join(path, info.Name())
		if ch, err := Read(chPath); err != nil {
			log.Warningf("charm: failed to load charm at %q: %s", chPath, err)
		} else if ch.Meta().Name == curl.Name {
			if ch.Revision() == curl.Revision {
				return ch, nil
			}
			if latest == nil || ch.Revision() > latest.Revision() {
				latest = ch
			}
		}
	}
	if curl.Revision == -1 && latest != nil {
		return latest, nil
	}
	return nil, charmNotFound(curl, r.Path)
}
<commit_msg>go fmt<commit_after>package charm

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/log"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
)

// InfoResponse is sent by the charm store in response to charm-info requests.
type InfoResponse struct {
	Revision int      `json:"revision"` // Zero is valid. Can't omitempty.
	Sha256   string   `json:"sha256,omitempty"`
	Digest   string   `json:"digest,omitempty"`
	Errors   []string `json:"errors,omitempty"`
	Warnings []string `json:"warnings,omitempty"`
}

// EventResponse is sent by the charm store in response to charm-event requests.
type EventResponse struct {
	Kind     string   `json:"kind"`
	Revision int      `json:"revision"` // Zero is valid. Can't omitempty.
	Digest   string   `json:"digest,omitempty"`
	Errors   []string `json:"errors,omitempty"`
	Warnings []string `json:"warnings,omitempty"`
	Time     string   `json:"time,omitempty"`
}

// Repository respresents a collection of charms.
type Repository interface {
	Get(curl *URL) (Charm, error)
	Latest(curl *URL) (int, error)
}

// NotFoundError represents an error indicating that the requested data wasn't found.
type NotFoundError struct {
	msg string
}

func (e *NotFoundError) Error() string {
	return e.msg
}

// CharmStore is a Repository that provides access to the public juju charm store.
type CharmStore struct {
	baseURL string
}

//var Store = &CharmStore{"https://store.juju.ubuntu.com"}
var Store = &CharmStore{"http://localhost:8080"}

// Info returns details for a charm in the charm store.
func (s *CharmStore) Info(curl *URL) (*InfoResponse, error) {
	key := curl.String()
	resp, err := http.Get(s.baseURL + "/charm-info?charms=" + url.QueryEscape(key))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	infos := make(map[string]*InfoResponse)
	if err = json.Unmarshal(body, &infos); err != nil {
		return nil, err
	}
	info, found := infos[key]
	if !found {
		return nil, fmt.Errorf("charm: charm store returned response without charm %q", key)
	}
	if len(info.Errors) == 1 && info.Errors[0] == "entry not found" {
		return nil, &NotFoundError{fmt.Sprintf("charm not found: %s", curl)}
	}
	return info, nil
}

// Event returns details for a charm event in the charm store.
//
// If digest is empty, the latest event is returned.
func (s *CharmStore) Event(curl *URL, digest string) (*EventResponse, error) {
	key := curl.String()
	query := key
	if digest != "" {
		query += "@" + digest
	}
	resp, err := http.Get(s.baseURL + "/charm-event?charms=" + url.QueryEscape(query))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	events := make(map[string]*EventResponse)
	if err = json.Unmarshal(body, &events); err != nil {
		return nil, err
	}
	event, found := events[key]
	if !found {
		return nil, fmt.Errorf("charm: charm store returned response without charm %q", key)
	}
	if len(event.Errors) == 1 && event.Errors[0] == "entry not found" {
		if digest == "" {
			return nil, &NotFoundError{fmt.Sprintf("charm event not found for %q", curl)}
		} else {
			return nil, &NotFoundError{fmt.Sprintf("charm event not found for %q with digest %q", curl, digest)}
		}
	}
	return event, nil
}

// revision returns the revision and SHA256 digest of the charm referenced by curl.
func (s *CharmStore) revision(curl *URL) (revision int, digest string, err error) {
	info, err := s.Info(curl)
	if err != nil {
		return 0, "", err
	}
	for _, w := range info.Warnings {
		log.Warningf("charm: charm store reports for %q: %s", curl, w)
	}
	if info.Errors != nil {
		return 0, "", fmt.Errorf("charm info errors for %q: %s", curl, strings.Join(info.Errors, "; "))
	}
	return info.Revision, info.Sha256, nil
}

// Latest returns the latest revision of the charm referenced by curl, regardless
// of the revision set on curl itself.
func (s *CharmStore) Latest(curl *URL) (int, error) {
	rev, _, err := s.revision(curl.WithRevision(-1))
	return rev, err
}

// verify returns an error unless a file exists at path with a hex-encoded
// SHA256 matching digest.
func verify(path, digest string) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()
	h := sha256.New()
	if _, err := io.Copy(h, f); err != nil {
		return err
	}
	if hex.EncodeToString(h.Sum(nil)) != digest {
		return fmt.Errorf("bad SHA256 of %q", path)
	}
	return nil
}

// Get returns the charm referenced by curl.
func (s *CharmStore) Get(curl *URL) (Charm, error) {
	cachePath := config.JujuHomePath("cache")
	if err := os.MkdirAll(cachePath, 0755); err != nil {
		return nil, err
	}
	rev, digest, err := s.revision(curl)
	if err != nil {
		return nil, err
	}
	if curl.Revision == -1 {
		curl = curl.WithRevision(rev)
	} else if curl.Revision != rev {
		return nil, fmt.Errorf("charm: store returned charm with wrong revision for %q", curl.String())
	}
	path := filepath.Join(cachePath, Quote(curl.String())+".charm")
	if verify(path, digest) != nil {
		resp, err := http.Get(s.baseURL + "/charm/" + url.QueryEscape(curl.Path()))
		if err != nil {
			return nil, err
		}
		defer resp.Body.Close()
		f, err := ioutil.TempFile(cachePath, "charm-download")
		if err != nil {
			return nil, err
		}
		dlPath := f.Name()
		_, err = io.Copy(f, resp.Body)
		if cerr := f.Close(); err == nil {
			err = cerr
		}
		if err != nil {
			os.Remove(dlPath)
			return nil, err
		}
		if err := os.Rename(dlPath, path); err != nil {
			return nil, err
		}
	}
	if err := verify(path, digest); err != nil {
		return nil, err
	}
	return ReadBundle(path)
}

// LocalRepository represents a local directory containing subdirectories
// named after an Ubuntu series, each of which contains charms targeted for
// that series. For example:
//
//   /path/to/repository/oneiric/mongodb/
//   /path/to/repository/precise/mongodb.charm
//   /path/to/repository/precise/wordpress/
type LocalRepository struct {
	Path string
}

// Latest returns the latest revision of the charm referenced by curl, regardless
// of the revision set on curl itself.
func (r *LocalRepository) Latest(curl *URL) (int, error) {
	ch, err := r.Get(curl.WithRevision(-1))
	if err != nil {
		return 0, err
	}
	return ch.Revision(), nil
}

func repoNotFound(path string) error {
	return &NotFoundError{fmt.Sprintf("no repository found at %q", path)}
}

func charmNotFound(curl *URL, repoPath string) error {
	return &NotFoundError{fmt.Sprintf("no charms found matching %q in %s", curl, repoPath)}
}

func mightBeCharm(info os.FileInfo) bool {
	if info.IsDir() {
		return !strings.HasPrefix(info.Name(), ".")
	}
	return strings.HasSuffix(info.Name(), ".charm")
}

// Get returns a charm matching curl, if one exists. If curl has a revision of
// -1, it returns the latest charm that matches curl. If multiple candidates
// satisfy the foregoing, the first one encountered will be returned.
func (r *LocalRepository) Get(curl *URL) (Charm, error) {
	if curl.Schema != "local" {
		return nil, fmt.Errorf("local repository got URL with non-local schema: %q", curl)
	}
	info, err := os.Stat(r.Path)
	if err != nil {
		if os.IsNotExist(err) {
			err = repoNotFound(r.Path)
		}
		return nil, err
	}
	if !info.IsDir() {
		return nil, repoNotFound(r.Path)
	}
	path := filepath.Join(r.Path, curl.Series)
	infos, err := ioutil.ReadDir(path)
	if err != nil {
		return nil, charmNotFound(curl, r.Path)
	}
	var latest Charm
	for _, info := range infos {
		if !mightBeCharm(info) {
			continue
		}
		chPath := filepath.Join(path, info.Name())
		if ch, err := Read(chPath); err != nil {
			log.Warningf("charm: failed to load charm at %q: %s", chPath, err)
		} else if ch.Meta().Name == curl.Name {
			if ch.Revision() == curl.Revision {
				return ch, nil
			}
			if latest == nil || ch.Revision() > latest.Revision() {
				latest = ch
			}
		}
	}
	if curl.Revision == -1 && latest != nil {
		return latest, nil
	}
	return nil, charmNotFound(curl, r.Path)
}
<|endoftext|>


<commit_before>package charneoapo

import (
	"io"
	"net/url"
	"os"
	"regexp"
	"strings"
	"time"

	gq "github.com/PuerkitoBio/goquery"
	"github.com/ikeikeikeike/go-bracmeister"
	"github.com/ikeikeikeike/gopkg/convert"
	behavior "github.com/ikeikeikeike/gopkg/net/http"
	"github.com/ikeikeikeike/gopkg/str"
)

const EndPoint = "http://neoapo.com/characters"

func tee(r io.Reader, debug bool) io.Reader {
	if !debug {
		return r
	}
	return io.TeeReader(r, os.Stdout)
}

type Neoapo struct {
	*behavior.UserBehavior
	doc *gq.Document

	Unit  string
	Debug bool
}

func NewNeoapo() *Neoapo {
	return &Neoapo{
		UserBehavior: behavior.NewUserBehavior(),
		Unit:         "cm",
		Debug:        false,
	}
}

func (w *Neoapo) Doc(page string) (*gq.Document, error) {
	resp, err := w.Behave(EndPoint + "/" + url.QueryEscape(page))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return gq.NewDocumentFromResponse(resp)
}

func (w *Neoapo) Do(page string) error {
	doc, err := w.Doc(page)

	if err != nil {
		return err
	}

	w.doc = doc
	return nil
}

func (w *Neoapo) Name() (r string) {
	w.doc.Find(`dl dt:contains(名前)`).Each(func(i int, s *gq.Selection) {
		r = str.Clean(s.Next().Text())
	})
	return
}

func (w *Neoapo) Kana() (r string) {
	w.doc.Find(`dl dt:contains(名前)`).Each(func(i int, s *gq.Selection) {
		r, _ = s.Next().Attr("title")
		r = str.Clean(r)
	})
	return
}

func (w *Neoapo) Product() (r string) {
	var ok bool
	w.doc.Find(`.profile_related a`).Each(func(i int, s *gq.Selection) {
		if r != "" {
			return
		}
		r, ok = s.ChildrenFiltered("img").Attr("title")
		if !ok {
			return
		}
		r = str.Clean(r)
	})
	return
}

func (w *Neoapo) Birthday() (r time.Time) {
	w.doc.Find(`dl dt:contains(誕生日)`).Each(func(i int, s *gq.Selection) {
		r, _ = time.Parse("2006年1月2日", str.MustClean(s.Next().Text()))
	})
	return
}

func (w *Neoapo) Blood() (r string) {
	w.doc.Find(`dl dt:contains(血液型)`).Each(func(i int, s *gq.Selection) {
		r = str.Clean(strings.Replace(s.Next().Text(), "型", "", -1))
	})
	return
}

var reNum = regexp.MustCompile(`(\d+)`)

func (w *Neoapo) Height() (r int) {
	w.doc.Find(`dl dt:contains(身長)`).Each(func(i int, s *gq.Selection) {
		text := s.Next().Text()
		if strings.Contains(text, w.Unit) {
			r, _ = convert.StrTo(str.Clean(reNum.FindString(text))).Int()
		}
	})
	return
}

func (w *Neoapo) Weight() (r int) {
	var err error
	w.doc.Find(`dl dt:contains(体重)`).Each(func(i int, s *gq.Selection) {
		text := s.Next().Text()
		if strings.Contains(text, "kg") {
			text = str.Clean(strings.Replace(text, "kg", "", -1))
			r, err = convert.StrTo(text).Int()
			if err != nil {
				f, _ := convert.StrTo(text).Float32()
				r = int(f)
			}
		}
	})
	return
}

func (w *Neoapo) BWH() (r string) {
	w.doc.Find(`dl dt:contains(ｽﾘｰｻｲｽﾞ)`).Each(func(i int, s *gq.Selection) {
		text := s.Next().Text()
		if strings.Contains(text, "B") {
			r = str.Clean(text)
		}
	})
	return
}

func (w *Neoapo) Bust() (r int) {
	bhw := strings.Split(w.BWH(), "/")
	if len(bhw) > 0 {
		r, _ = convert.StrTo(str.Clean(reNum.FindString(bhw[0]))).Int()
	}
	return
}

func (w *Neoapo) Waist() (r int) {
	bhw := strings.Split(w.BWH(), "/")
	if len(bhw) > 1 {
		r, _ = convert.StrTo(str.Clean(reNum.FindString(bhw[1]))).Int()
	}
	return
}

func (w *Neoapo) Hip() (r int) {
	bhw := strings.Split(w.BWH(), "/")
	if len(bhw) > 2 {
		r, _ = convert.StrTo(str.Clean(reNum.FindString(bhw[2]))).Int()
	}
	return
}

func (w *Neoapo) Bracup() (r string) {
	var re = regexp.MustCompile(`\(\w\)`)

	bhw := strings.Split(w.BWH(), "/")
	if len(bhw) > 0 {
		r = re.FindString(bhw[0])
		r = strings.Replace(strings.Replace(r, "(", "", -1), ")", "", -1)
	}

	if r == "" {
		h, b, w := w.Height(), w.Bust(), w.Waist()
		if h > 10 && b > 10 && w > 10 {
			r = bracmeister.Calc(h, b, w, true).Cup
		}
	}

	r = strings.ToUpper(str.Clean(r))
	return
}

func (w *Neoapo) Comment() (r string) {
	w.doc.Find(`dl dt:contains(コメント)`).Each(func(i int, s *gq.Selection) {
		r = str.Clean(s.Next().Next().Text())
	})
	return
}
<commit_msg>Added both endpoint<commit_after>package charneoapo

import (
	"io"
	"net/url"
	"os"
	"regexp"
	"strings"
	"time"

	gq "github.com/PuerkitoBio/goquery"
	"github.com/ikeikeikeike/go-bracmeister"
	"github.com/ikeikeikeike/gopkg/convert"
	behavior "github.com/ikeikeikeike/gopkg/net/http"
	"github.com/ikeikeikeike/gopkg/str"
)

const EndPoint = "http://neoapo.com"

func tee(r io.Reader, debug bool) io.Reader {
	if !debug {
		return r
	}
	return io.TeeReader(r, os.Stdout)
}

type Neoapo struct {
	*behavior.UserBehavior
	doc *gq.Document

	Unit  string
	Debug bool
}

func NewNeoapo() *Neoapo {
	return &Neoapo{
		UserBehavior: behavior.NewUserBehavior(),
		Unit:         "cm",
		Debug:        false,
	}
}

func (w *Neoapo) Doc(url string) (*gq.Document, error) {
	resp, err := w.Behave(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return gq.NewDocumentFromResponse(resp)
}

func (w *Neoapo) Do(path, page string) error {
	doc, err := w.Doc(EndPoint + "/" + path + "/" + url.QueryEscape(page))

	if err != nil {
		return err
	}

	w.doc = doc
	return nil
}

func (w *Neoapo) Name() (r string) {
	w.doc.Find(`dl dt:contains(名前)`).Each(func(i int, s *gq.Selection) {
		r = str.Clean(s.Next().Text())
	})
	return
}

func (w *Neoapo) Kana() (r string) {
	w.doc.Find(`dl dt:contains(名前)`).Each(func(i int, s *gq.Selection) {
		r, _ = s.Next().Attr("title")
		r = str.Clean(r)
	})
	return
}

func (w *Neoapo) Product() (r string) {
	var ok bool
	w.doc.Find(`.profile_related a`).Each(func(i int, s *gq.Selection) {
		if r != "" {
			return
		}
		r, ok = s.ChildrenFiltered("img").Attr("title")
		if !ok {
			return
		}
		r = str.Clean(r)
	})
	return
}

func (w *Neoapo) Birthday() (r time.Time) {
	w.doc.Find(`dl dt:contains(誕生日)`).Each(func(i int, s *gq.Selection) {
		r, _ = time.Parse("2006年1月2日", str.MustClean(s.Next().Text()))
	})
	return
}

func (w *Neoapo) Blood() (r string) {
	w.doc.Find(`dl dt:contains(血液型)`).Each(func(i int, s *gq.Selection) {
		r = str.Clean(strings.Replace(s.Next().Text(), "型", "", -1))
	})
	return
}

var reNum = regexp.MustCompile(`(\d+)`)

func (w *Neoapo) Height() (r int) {
	w.doc.Find(`dl dt:contains(身長)`).Each(func(i int, s *gq.Selection) {
		text := s.Next().Text()
		if strings.Contains(text, w.Unit) {
			r, _ = convert.StrTo(str.Clean(reNum.FindString(text))).Int()
		}
	})
	return
}

func (w *Neoapo) Weight() (r int) {
	var err error
	w.doc.Find(`dl dt:contains(体重)`).Each(func(i int, s *gq.Selection) {
		text := s.Next().Text()
		if strings.Contains(text, "kg") {
			text = str.Clean(strings.Replace(text, "kg", "", -1))
			r, err = convert.StrTo(text).Int()
			if err != nil {
				f, _ := convert.StrTo(text).Float32()
				r = int(f)
			}
		}
	})
	return
}

func (w *Neoapo) BWH() (r string) {
	w.doc.Find(`dl dt:contains(ｽﾘｰｻｲｽﾞ)`).Each(func(i int, s *gq.Selection) {
		text := s.Next().Text()
		if strings.Contains(text, "B") {
			r = str.Clean(text)
		}
	})
	return
}

func (w *Neoapo) Bust() (r int) {
	bhw := strings.Split(w.BWH(), "/")
	if len(bhw) > 0 {
		r, _ = convert.StrTo(str.Clean(reNum.FindString(bhw[0]))).Int()
	}
	return
}

func (w *Neoapo) Waist() (r int) {
	bhw := strings.Split(w.BWH(), "/")
	if len(bhw) > 1 {
		r, _ = convert.StrTo(str.Clean(reNum.FindString(bhw[1]))).Int()
	}
	return
}

func (w *Neoapo) Hip() (r int) {
	bhw := strings.Split(w.BWH(), "/")
	if len(bhw) > 2 {
		r, _ = convert.StrTo(str.Clean(reNum.FindString(bhw[2]))).Int()
	}
	return
}

func (w *Neoapo) Bracup() (r string) {
	var re = regexp.MustCompile(`\(\w\)`)

	bhw := strings.Split(w.BWH(), "/")
	if len(bhw) > 0 {
		r = re.FindString(bhw[0])
		r = strings.Replace(strings.Replace(r, "(", "", -1), ")", "", -1)
	}

	if r == "" {
		h, b, w := w.Height(), w.Bust(), w.Waist()
		if h > 10 && b > 10 && w > 10 {
			r = bracmeister.Calc(h, b, w, true).Cup
		}
	}

	r = strings.ToUpper(str.Clean(r))
	return
}

func (w *Neoapo) Comment() (r string) {
	w.doc.Find(`dl dt:contains(コメント)`).Each(func(i int, s *gq.Selection) {
		r = str.Clean(s.Next().Next().Text())
	})
	return
}
<|endoftext|>


<commit_before>package chlib

import (
	"github.com/containerum/chkit/chlib/dbconfig"
	"github.com/containerum/chkit/helpers"

	jww "github.com/spf13/jwalterweatherman"
)

func UserLogin(db *dbconfig.ConfigDB, login, password string, np *jww.Notepad) (token string, err error) {
	info, err := db.GetUserInfo()
	if err != nil {
		return
	}
	client, err := NewClient(db, helpers.CurrentClientVersion, helpers.UuidV4(), np)
	if err != nil {
		return
	}
	token, err = client.Login(login, password)
	if err != nil {
		return
	}
	info.Token = token
	err = db.UpdateUserInfo(info)
	return
}

func UserLogout(db *dbconfig.ConfigDB) error {
	info, err := db.GetUserInfo()
	if err != nil {
		return err
	}
	info.Token = ""
	err = db.UpdateUserInfo(info)
	return err
}
<commit_msg>Set namespace on login<commit_after>package chlib

import (
	"github.com/containerum/chkit/chlib/dbconfig"
	"github.com/containerum/chkit/helpers"

	jww "github.com/spf13/jwalterweatherman"
)

func UserLogin(db *dbconfig.ConfigDB, login, password string, np *jww.Notepad) (token string, err error) {
	info, err := db.GetUserInfo()
	if err != nil {
		return
	}
	client, err := NewClient(db, helpers.CurrentClientVersion, helpers.UuidV4(), np)
	if err != nil {
		return
	}
	token, err = client.Login(login, password)
	if err != nil {
		return
	}
	info.Token = token
	// get namespaces and set default namespace
	nsResult, err := GetCmdRequestJson(client, KindNamespaces, "", "")
	if err != nil {
		return
	}
	info.Namespace = nsResult[0]["data"].(map[string]interface{})["metadata"].(map[string]interface{})["namespace"].(string)
	np.FEEDBACK.Printf("Chosen namespace: %v", info.Namespace)
	err = db.UpdateUserInfo(info)
	return
}

func UserLogout(db *dbconfig.ConfigDB) error {
	info, err := db.GetUserInfo()
	if err != nil {
		return err
	}
	info.Token = ""
	err = db.UpdateUserInfo(info)
	return err
}
<|endoftext|>


<commit_before>package cli

import (
	"bytes"
	"encoding/json"
	"fmt"
	"os"
	"os/user"
	"reflect"
	"strconv"
	"strings"
)

var defaultConfig = `{
	"ping" : {
		"timeout" : "2s",
		"interval": "1s",
		"count":	4
	},
	"hping" : {
		"timeout"  : "2s",
		"method"   : "HEAD",
		"data"	   : "mylg",
		"count"	   : 5
	},
	"web" : {
		"port"	   : 8080,
		"address"  : "127.0.0.1"
	},
	"scan" : {
		"port"     : "1-500"
	},
	"trace" : {
		"wait"  : "2s",
		"theme" : "dark"
	},
	"snmp" : {
		"community"     : "public",
		"timeout"       : "1s",
		"version"       : "2c",
		"retries"       : 1,
		"port"          : 161,
		"securitylevel" : "noauthnopriv",
		"authpass"      : "nopass",
		"authproto"     : "sha",
		"Privacypass"   : "nopass",
		"Privacyproto"  : "aes"
	}
}`

// Config represents configuration
type Config struct {
	Ping  Ping  `json:"ping"`
	Hping HPing `json:"hping"`
	Web   Web   `json:"web"`
	Scan  Scan  `json:"scan"`
	Trace Trace `json:"trace"`
	Snmp  SNMP  `json:"snmp"`
}

// Ping represents ping command options
type Ping struct {
	Timeout  string `json:"timeout"`
	Interval string `json:"interval"`
	Count    int    `json:"count"`
}

// HPing represents ping command options
type HPing struct {
	Timeout string `json:"timeout"`
	Method  string `json:"method"`
	Data    string `json:"data"`
	Count   int    `json:"count"`
}

// Web represents web command options
type Web struct {
	Port    int    `json:"port"`
	Address string `json:"address"`
}

// Scan represents scan command options
type Scan struct {
	Port string `json:"port"`
}

// Trace represents trace command options
type Trace struct {
	Wait  string `json:"wait"`
	Theme string `json:"theme"`
}

// SNMP represents nms command options
type SNMP struct {
	Community     string `json:"community"`
	Timeout       string `json:"timeout"`
	Version       string `json:"version"`
	Retries       int    `json:"retries"`
	Port          int    `json:"port"`
	Securitylevel string `json:"securitylevel"`
	Authpass      string `json:"authpass"`
	Authproto     string `json:"authproto"`
	Privacypass   string `json:"privacypass"`
	Privacyproto  string `json:"privacyproto"`
}

// WriteConfig write config to disk
func WriteConfig(cfg Config) error {
	f, err := cfgFile()
	if err != nil {
		return err
	}

	h, err := os.Create(f)
	if err != nil {
		return err
	}

	b, err := json.Marshal(cfg)
	if err != nil {
		return err
	}
	_, err = h.Write(bytes.ToLower(b))
	if err != nil {
		return err
	}
	h.Close()

	return nil
}

// GetOptions returns option(s)/value(s) for specific command
func GetOptions(s interface{}, key string) ([]string, []interface{}) {
	var (
		opts []string
		vals []interface{}
	)
	v := reflect.ValueOf(s)
	t := v.Type()

	for i := 0; i < v.NumField(); i++ {
		if t.Field(i).Name == key {
			f := v.Field(i)
			ft := f.Type()
			for j := 0; j < f.NumField(); j++ {
				vals = append(vals, f.Field(j))
				opts = append(opts, ft.Field(j).Name)
			}
			break
		}
	}
	return opts, vals
}

// GetCMDNames returns command line names
func GetCMDNames(s interface{}) []string {
	var fields []string

	v := reflect.ValueOf(s)
	t := v.Type()

	for i := 0; i < t.NumField(); i++ {
		fields = append(fields, t.Field(i).Name)
	}
	return fields
}

// UpgradeConfig adds / removes new command(s)/option(s)
func UpgradeConfig(cfg *Config) error {
	var (
		conf  map[string]interface{}
		cConf Config
	)

	b := make([]byte, 2048)
	f, err := cfgFile()
	if err != nil {
		return err
	}

	h, err := os.Open(f)
	if err != nil {
		return err
	}
	n, _ := h.Read(b)
	b = b[:n]
	// load saved/old config to conf
	json.Unmarshal(b, &conf)
	// load default config to cConf
	json.Unmarshal([]byte(defaultConfig), &cConf)

	for _, cmd := range GetCMDNames(cConf) {
		opts, vals := GetOptions(cConf, cmd)
		for i, opt := range opts {
			if v, ok := conf[strings.ToLower(cmd)].(interface{}); ok {
				if _, ok = v.(map[string]interface{})[strings.ToLower(opt)]; !ok {
					args := fmt.Sprintf("%s %s %v", cmd, opt, vals[i])
					SetConfig(args, cfg)
				}
			} else {
				// there is new command
				args := fmt.Sprintf("%s %s %v", cmd, opt, vals[i])
				SetConfig(args, cfg)
			}
		}
	}
	return nil
}

// LoadConfig loads configuration
func LoadConfig() Config {
	var cfg Config

	cfg = ReadConfig()
	UpgradeConfig(&cfg)
	return cfg
}

// InitConfig creates new config file
func InitConfig(f string) ([]byte, error) {
	h, err := os.Create(f)
	if err != nil {
		return []byte(""), err
	}

	h.Chmod(os.FileMode(int(0600)))
	h.WriteString(defaultConfig)
	h.Close()

	return []byte(defaultConfig), nil
}

// ReadConfig reads configuration from existing
// or default configuration
func ReadConfig() Config {
	var (
		b    = make([]byte, 2048)
		conf Config
		err  error
	)
	f, err := cfgFile()
	if err != nil {

	}

	h, err := os.Open(f)

	if err != nil {
		switch {
		case os.IsNotExist(err):
			if b, err = InitConfig(f); err != nil {
				println(err.Error())
			}
		case os.IsPermission(err):
			println("cannot read configuration file due to insufficient permissions")
			b = []byte(defaultConfig)
		default:
			println(err.Error())
			b = []byte(defaultConfig)
		}
	} else {
		n, _ := h.Read(b)
		b = b[:n]
	}

	err = json.Unmarshal(b, &conf)
	if err != nil {
		println(err.Error())
		b = []byte(defaultConfig)
		json.Unmarshal(b, &conf)
	}

	return conf
}

// ReadDefaultConfig returns default configuration
func ReadDefaultConfig() (Config, error) {
	var (
		b    = make([]byte, 2048)
		conf Config
	)
	b = []byte(defaultConfig)
	err := json.Unmarshal(b, &conf)
	return conf, err
}

// cfgFile returns config file
func cfgFile() (string, error) {
	user, err := user.Current()
	if err != nil {
		return "", err
	}
	return user.HomeDir + "/.mylg.config", nil
}

//
func optionType(v reflect.Value, opt string) string {
	opt = strings.Title(opt)
	for i := 0; i < v.NumField(); i++ {
		if v.Type().Field(i).Name == opt {
			return v.Type().Field(i).Type.Name()
		}
	}
	return "nan"
}

// SetConfig handles update option's value
func SetConfig(args string, s *Config) error {
	var (
		v       reflect.Value
		integer int64
		float   float64
		err     error
	)

	args = strings.ToLower(args)
	f := strings.Fields(args)
	if len(f) < 3 {
		helpSet()
		return fmt.Errorf("syntax error")
	}

	cmd, opt, val := f[0], f[1], f[2]
	opt = strings.Title(opt)

	v = reflect.ValueOf(s)
	v = reflect.Indirect(v)
	v = v.FieldByName(strings.Title(cmd))

	if !v.IsValid() {
		return fmt.Errorf("invalid command")
	}

	switch optionType(v, opt) {
	case "string":
		// string
		err = SetValue(v.Addr(), opt, fmt.Sprintf("%v", val))
	case "int":
		// integer
		if integer, err = strconv.ParseInt(val, 10, 64); err == nil {
			err = SetValue(v.Addr(), strings.Title(opt), integer)
		} else {
			err = fmt.Errorf("the value should be integer")
		}
	case "float":
		// float
		if float, err = strconv.ParseFloat(val, 64); err == nil {
			err = SetValue(v.Addr(), opt, float)
		} else {
			err = fmt.Errorf("the value should be float")
		}
	default:
		err = fmt.Errorf("invalid option")
	}

	if err != nil {
		return err
	}

	// save config
	err = WriteConfig(*s)
	return err
}

// SetValue set optioni's value
func SetValue(v reflect.Value, rec string, val interface{}) error {

	if v.Kind() != reflect.Ptr {
		return fmt.Errorf("not a pointer value")
	}

	v = reflect.Indirect(v)
	switch v.Kind() {
	case reflect.Int:
		if value, ok := val.(int64); ok {
			v.SetInt(value)
		} else {
			return fmt.Errorf("the value should be integer")
		}
	case reflect.Float64:
		if value, ok := val.(float64); ok {
			v.SetFloat(value)
		} else {
			return fmt.Errorf("the value should be float")
		}
	case reflect.String:
		if value, ok := val.(string); ok {
			v.SetString(value)
		} else {
			return fmt.Errorf("the value shouldn't be number")
		}
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			if v.Type().Field(i).Name == rec {
				err := SetValue(v.Field(i).Addr(), rec, val)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// ShowConfig prints the configuration
func ShowConfig(s *Config) {
	var v reflect.Value

	v = reflect.ValueOf(s)
	v = reflect.Indirect(v)

	for i := 0; i < v.NumField(); i++ {
		cmd := v.Type().Field(i).Name
		cmd = strings.ToLower(cmd)

		vv := v.Field(i).Addr()
		vv = reflect.Indirect(vv)

		for j := 0; j < vv.NumField(); j++ {
			subCmd := vv.Type().Field(j).Name
			subCmd = strings.ToLower(subCmd)
			value := vv.Field(j)
			fmt.Printf("set %-8s %-15s %v\n", cmd, subCmd, value)
		}
	}
}

// helpSet shows set command
func helpSet() {
	println(`
          usage:
               set command option value
          example:
               set ping timeout 2s
	`)

}
<commit_msg>config lowercase issue - fixed #49<commit_after>package cli

import (
	"encoding/json"
	"fmt"
	"os"
	"os/user"
	"reflect"
	"strconv"
	"strings"
)

var defaultConfig = `{
	"ping" : {
		"timeout" : "2s",
		"interval": "1s",
		"count":	4
	},
	"hping" : {
		"timeout"  : "2s",
		"method"   : "HEAD",
		"data"	   : "mylg",
		"count"	   : 5
	},
	"web" : {
		"port"	   : 8080,
		"address"  : "127.0.0.1"
	},
	"scan" : {
		"port"     : "1-500"
	},
	"trace" : {
		"wait"  : "2s",
		"theme" : "dark"
	},
	"snmp" : {
		"community"     : "public",
		"timeout"       : "1s",
		"version"       : "2c",
		"retries"       : 1,
		"port"          : 161,
		"securitylevel" : "noauthnopriv",
		"authpass"      : "nopass",
		"authproto"     : "sha",
		"Privacypass"   : "nopass",
		"Privacyproto"  : "aes"
	}
}`

// Config represents configuration
type Config struct {
	Ping  Ping  `json:"ping"`
	Hping HPing `json:"hping"`
	Web   Web   `json:"web"`
	Scan  Scan  `json:"scan"`
	Trace Trace `json:"trace"`
	Snmp  SNMP  `json:"snmp"`
}

// Ping represents ping command options
type Ping struct {
	Timeout  string `json:"timeout" tag:"lower"`
	Interval string `json:"interval" tag:"lower"`
	Count    int    `json:"count"`
}

// HPing represents ping command options
type HPing struct {
	Timeout string `json:"timeout" tag:"lower"`
	Method  string `json:"method" tag:"upper"`
	Data    string `json:"data"`
	Count   int    `json:"count"`
}

// Web represents web command options
type Web struct {
	Port    int    `json:"port"`
	Address string `json:"address"`
}

// Scan represents scan command options
type Scan struct {
	Port string `json:"port"`
}

// Trace represents trace command options
type Trace struct {
	Wait  string `json:"wait" tag:"lower"`
	Theme string `json:"theme" tag:"lower"`
}

// SNMP represents nms command options
type SNMP struct {
	Community     string `json:"community"`
	Timeout       string `json:"timeout" tag:"lower"`
	Version       string `json:"version" tag:"lower"`
	Retries       int    `json:"retries"`
	Port          int    `json:"port"`
	Securitylevel string `json:"securitylevel"`
	Authpass      string `json:"authpass"`
	Authproto     string `json:"authproto" tag:"lower"`
	Privacypass   string `json:"privacypass"`
	Privacyproto  string `json:"privacyproto" tag:"lower"`
}

// WriteConfig write config to disk
func WriteConfig(cfg Config) error {
	f, err := cfgFile()
	if err != nil {
		return err
	}

	h, err := os.Create(f)
	if err != nil {
		return err
	}

	b, err := json.Marshal(cfg)
	if err != nil {
		return err
	}
	_, err = h.Write(b)
	if err != nil {
		return err
	}
	h.Close()

	return nil
}

// GetOptions returns option(s)/value(s) for specific command
func GetOptions(s interface{}, key string) ([]string, []interface{}) {
	var (
		opts []string
		vals []interface{}
	)
	v := reflect.ValueOf(s)
	t := v.Type()

	for i := 0; i < v.NumField(); i++ {
		if t.Field(i).Name == key {
			f := v.Field(i)
			ft := f.Type()
			for j := 0; j < f.NumField(); j++ {
				vals = append(vals, f.Field(j))
				opts = append(opts, ft.Field(j).Name)
			}
			break
		}
	}
	return opts, vals
}

// GetCMDNames returns command line names
func GetCMDNames(s interface{}) []string {
	var fields []string

	v := reflect.ValueOf(s)
	t := v.Type()

	for i := 0; i < t.NumField(); i++ {
		fields = append(fields, t.Field(i).Name)
	}
	return fields
}

// UpgradeConfig adds / removes new command(s)/option(s)
func UpgradeConfig(cfg *Config) error {
	var (
		conf  map[string]interface{}
		cConf Config
	)

	b := make([]byte, 2048)
	f, err := cfgFile()
	if err != nil {
		return err
	}

	h, err := os.Open(f)
	if err != nil {
		return err
	}
	n, _ := h.Read(b)
	b = b[:n]
	// load saved/old config to conf
	json.Unmarshal(b, &conf)
	// load default config to cConf
	json.Unmarshal([]byte(defaultConfig), &cConf)

	for _, cmd := range GetCMDNames(cConf) {
		opts, vals := GetOptions(cConf, cmd)
		for i, opt := range opts {
			if v, ok := conf[strings.ToLower(cmd)].(interface{}); ok {
				if _, ok = v.(map[string]interface{})[strings.ToLower(opt)]; !ok {
					args := fmt.Sprintf("%s %s %v", cmd, opt, vals[i])
					SetConfig(args, cfg)
				}
			} else {
				// there is new command
				args := fmt.Sprintf("%s %s %v", cmd, opt, vals[i])
				SetConfig(args, cfg)
			}
		}
	}
	return nil
}

// LoadConfig loads configuration
func LoadConfig() Config {
	var cfg Config

	cfg = ReadConfig()
	UpgradeConfig(&cfg)
	return cfg
}

// InitConfig creates new config file
func InitConfig(f string) ([]byte, error) {
	h, err := os.Create(f)
	if err != nil {
		return []byte(""), err
	}

	h.Chmod(os.FileMode(int(0600)))
	h.WriteString(defaultConfig)
	h.Close()

	return []byte(defaultConfig), nil
}

// ReadConfig reads configuration from existing
// or default configuration
func ReadConfig() Config {
	var (
		b    = make([]byte, 2048)
		conf Config
		err  error
	)
	f, err := cfgFile()
	if err != nil {

	}

	h, err := os.Open(f)

	if err != nil {
		switch {
		case os.IsNotExist(err):
			if b, err = InitConfig(f); err != nil {
				println(err.Error())
			}
		case os.IsPermission(err):
			println("cannot read configuration file due to insufficient permissions")
			b = []byte(defaultConfig)
		default:
			println(err.Error())
			b = []byte(defaultConfig)
		}
	} else {
		n, _ := h.Read(b)
		b = b[:n]
	}

	err = json.Unmarshal(b, &conf)
	if err != nil {
		println(err.Error())
		b = []byte(defaultConfig)
		json.Unmarshal(b, &conf)
	}

	return conf
}

// ReadDefaultConfig returns default configuration
func ReadDefaultConfig() (Config, error) {
	var (
		b    = make([]byte, 2048)
		conf Config
	)
	b = []byte(defaultConfig)
	err := json.Unmarshal(b, &conf)
	return conf, err
}

// cfgFile returns config file
func cfgFile() (string, error) {
	user, err := user.Current()
	if err != nil {
		return "", err
	}
	return user.HomeDir + "/.mylg.config", nil
}

//
func optionProp(v reflect.Value, opt string) (string, string) {
	opt = strings.Title(opt)
	for i := 0; i < v.NumField(); i++ {
		if v.Type().Field(i).Name == opt {
			field := v.Type().Field(i)
			return field.Tag.Get("tag"), field.Type.Name()
		}
	}
	return "", "nan"
}

// SetConfig handles update option's value
func SetConfig(args string, s *Config) error {
	var (
		v       reflect.Value
		integer int64
		float   float64
		err     error
	)

	//args = strings.ToLower(args)
	f := strings.Fields(args)
	if len(f) < 3 {
		helpSet()
		return fmt.Errorf("syntax error")
	}

	cmd, opt, val := f[0], f[1], f[2]
	opt = strings.Title(opt)

	v = reflect.ValueOf(s)
	v = reflect.Indirect(v)
	v = v.FieldByName(strings.Title(cmd))

	if !v.IsValid() {
		return fmt.Errorf("invalid command")
	}

	tags, valType := optionProp(v, opt)
	val = applyTag(val, tags)

	switch valType {
	case "string":
		// string
		err = SetValue(v.Addr(), opt, fmt.Sprintf("%v", val))
	case "int":
		// integer
		if integer, err = strconv.ParseInt(val, 10, 64); err == nil {
			err = SetValue(v.Addr(), strings.Title(opt), integer)
		} else {
			err = fmt.Errorf("the value should be integer")
		}
	case "float":
		// float
		if float, err = strconv.ParseFloat(val, 64); err == nil {
			err = SetValue(v.Addr(), opt, float)
		} else {
			err = fmt.Errorf("the value should be float")
		}
	default:
		err = fmt.Errorf("invalid option")
	}

	if err != nil {
		return err
	}

	// save config
	err = WriteConfig(*s)
	return err
}

// SetValue set optioni's value
func SetValue(v reflect.Value, rec string, val interface{}) error {

	if v.Kind() != reflect.Ptr {
		return fmt.Errorf("not a pointer value")
	}

	v = reflect.Indirect(v)
	switch v.Kind() {
	case reflect.Int:
		if value, ok := val.(int64); ok {
			v.SetInt(value)
		} else {
			return fmt.Errorf("the value should be integer")
		}
	case reflect.Float64:
		if value, ok := val.(float64); ok {
			v.SetFloat(value)
		} else {
			return fmt.Errorf("the value should be float")
		}
	case reflect.String:
		if value, ok := val.(string); ok {
			v.SetString(value)
		} else {
			return fmt.Errorf("the value shouldn't be number")
		}
	case reflect.Struct:
		for i := 0; i < v.NumField(); i++ {
			if v.Type().Field(i).Name == rec {
				err := SetValue(v.Field(i).Addr(), rec, val)
				if err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// ShowConfig prints the configuration
func ShowConfig(s *Config) {
	var v reflect.Value

	v = reflect.ValueOf(s)
	v = reflect.Indirect(v)

	for i := 0; i < v.NumField(); i++ {
		cmd := v.Type().Field(i).Name
		cmd = strings.ToLower(cmd)

		vv := v.Field(i).Addr()
		vv = reflect.Indirect(vv)

		for j := 0; j < vv.NumField(); j++ {
			subCmd := vv.Type().Field(j).Name
			subCmd = strings.ToLower(subCmd)
			value := vv.Field(j)
			fmt.Printf("set %-8s %-15s %v\n", cmd, subCmd, value)
		}
	}
}

func applyTag(val string, typ string) string {
	switch {
	case strings.Contains(typ, "lower"):
		return strings.ToLower(val)
	case strings.Contains(typ, "upper"):
		return strings.ToUpper(val)
	default:
		return val
	}

}

// helpSet shows set command
func helpSet() {
	println(`
          usage:
               set command option value
          example:
               set ping timeout 2s
	`)

}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"os"
)

type Command interface {
	Help() string
	Exec() error
}

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

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

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

func (m *Module) AddModule(name string, definition string) *Module {
	child := &Module{Children: make(map[string]*Module, 0), Definition: definition}
	m.Children[name] = child
	return child
}

func (m *Module) FindModule(args []string) *Module {
	moduleWalker := m

	for i := 0; i < len(args); i, moduleWalker = i+1, moduleWalker.Children[args[i]] {
		module := moduleWalker.Children[args[i]]
		if module == nil {
			fmt.Printf("Command %s not found\n\n", args[i])
			break
		}
		if module.Command == nil {
			continue
		}
		// command behaves like a subprocess, it will parse arguments again
		// so we re discarding parsed arguments
		temp := os.Args
		os.Args = []string{temp[0]}
		os.Args = append(os.Args, temp[i+2:]...)
		return module
	}
	printPossibleCommands(moduleWalker)
	return nil
}

func printPossibleCommands(module *Module) {
	fmt.Println("Possible commands: ")
	for n, m := range module.Children {
		fmt.Printf("%s - ", n)
		if m.Command != nil {
			fmt.Printf("%s\n", m.Command.Help())
		} else {
			fmt.Printf("%s\n", m.Definition)
		}
	}
}
<commit_msg>refactored module instantiation<commit_after>package cli

import (
	"fmt"
	"os"
)

type Command interface {
	Help() string
	Exec() error
}

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

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

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

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

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

func (m *Module) FindModule(args []string) *Module {
	moduleWalker := m

	for i := 0; i < len(args); i, moduleWalker = i+1, moduleWalker.Children[args[i]] {
		module := moduleWalker.Children[args[i]]
		if module == nil {
			fmt.Printf("Command %s not found\n\n", args[i])
			break
		}
		if module.Command == nil {
			continue
		}
		// command behaves like a subprocess, it will parse arguments again
		// so we re discarding parsed arguments
		temp := os.Args
		os.Args = []string{temp[0]}
		os.Args = append(os.Args, temp[i+2:]...)
		return module
	}
	printPossibleCommands(moduleWalker)
	return nil
}

func printPossibleCommands(module *Module) {
	fmt.Println("Possible commands: ")
	for n, m := range module.Children {
		fmt.Printf("%s - ", n)
		if m.Command != nil {
			fmt.Printf("%s\n", m.Command.Help())
		} else {
			fmt.Printf("%s\n", m.Definition)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

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

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

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

package node

import (
	"encoding/json"
	"fmt"
	"net"
	"os"
	"strings"
	"time"

	"github.com/golang/glog"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/v1"
	"k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
	kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
)

const (
	// The reason and message set on a pod when its state cannot be confirmed as kubelet is unresponsive
	// on the node it is (was) running.
	NodeUnreachablePodReason  = "NodeLost"
	NodeUnreachablePodMessage = "Node %v which was running pod %v is unresponsive"
)

func GetHostname(hostnameOverride string) string {
	var hostname string = hostnameOverride
	if hostname == "" {
		nodename, err := os.Hostname()
		if err != nil {
			glog.Fatalf("Couldn't determine hostname: %v", err)
		}
		hostname = nodename
	}
	return strings.ToLower(strings.TrimSpace(hostname))
}

// GetPreferredNodeAddress returns the address of the provided node, using the provided preference order.
// If none of the preferred address types are found, an error is returned.
func GetPreferredNodeAddress(node *v1.Node, preferredAddressTypes []v1.NodeAddressType) (string, error) {
	for _, addressType := range preferredAddressTypes {
		for _, address := range node.Status.Addresses {
			if address.Type == addressType {
				return address.Address, nil
			}
		}
		// If hostname was requested and no Hostname address was registered...
		if addressType == v1.NodeHostName {
			// ...fall back to the kubernetes.io/hostname label for compatibility with kubelets before 1.5
			if hostname, ok := node.Labels[kubeletapis.LabelHostname]; ok && len(hostname) > 0 {
				return hostname, nil
			}
		}
	}
	return "", fmt.Errorf("no preferred addresses found; known addresses: %v", node.Status.Addresses)
}

// GetNodeHostIP returns the provided node's IP, based on the priority:
// 1. NodeInternalIP
// 2. NodeExternalIP
func GetNodeHostIP(node *v1.Node) (net.IP, error) {
	addresses := node.Status.Addresses
	addressMap := make(map[v1.NodeAddressType][]v1.NodeAddress)
	for i := range addresses {
		addressMap[addresses[i].Type] = append(addressMap[addresses[i].Type], addresses[i])
	}
	if addresses, ok := addressMap[v1.NodeInternalIP]; ok {
		return net.ParseIP(addresses[0].Address), nil
	}
	if addresses, ok := addressMap[v1.NodeExternalIP]; ok {
		return net.ParseIP(addresses[0].Address), nil
	}
	return nil, fmt.Errorf("host IP unknown; known addresses: %v", addresses)
}

// InternalGetNodeHostIP returns the provided node's IP, based on the priority:
// 1. NodeInternalIP
// 2. NodeExternalIP
func InternalGetNodeHostIP(node *api.Node) (net.IP, error) {
	addresses := node.Status.Addresses
	addressMap := make(map[api.NodeAddressType][]api.NodeAddress)
	for i := range addresses {
		addressMap[addresses[i].Type] = append(addressMap[addresses[i].Type], addresses[i])
	}
	if addresses, ok := addressMap[api.NodeInternalIP]; ok {
		return net.ParseIP(addresses[0].Address), nil
	}
	if addresses, ok := addressMap[api.NodeExternalIP]; ok {
		return net.ParseIP(addresses[0].Address), nil
	}
	return nil, fmt.Errorf("host IP unknown; known addresses: %v", addresses)
}

// Helper function that builds a string identifier that is unique per failure-zone
// Returns empty-string for no zone
func GetZoneKey(node *v1.Node) string {
	labels := node.Labels
	if labels == nil {
		return ""
	}

	region, _ := labels[kubeletapis.LabelZoneRegion]
	failureDomain, _ := labels[kubeletapis.LabelZoneFailureDomain]

	if region == "" && failureDomain == "" {
		return ""
	}

	// We include the null character just in case region or failureDomain has a colon
	// (We do assume there's no null characters in a region or failureDomain)
	// As a nice side-benefit, the null character is not printed by fmt.Print or glog
	return region + ":\x00:" + failureDomain
}

// SetNodeCondition updates specific node condition with patch operation.
func SetNodeCondition(c clientset.Interface, node types.NodeName, condition v1.NodeCondition) error {
	generatePatch := func(condition v1.NodeCondition) ([]byte, error) {
		raw, err := json.Marshal(&[]v1.NodeCondition{condition})
		if err != nil {
			return nil, err
		}
		return []byte(fmt.Sprintf(`{"status":{"conditions":%s}}`, raw)), nil
	}
	condition.LastHeartbeatTime = metav1.NewTime(time.Now())
	patch, err := generatePatch(condition)
	if err != nil {
		return nil
	}
	_, err = c.Core().Nodes().PatchStatus(string(node), patch)
	return err
}

// PatchNodeStatus patches node status.
func PatchNodeStatus(c clientset.Interface, nodeName types.NodeName, oldNode *v1.Node, newNode *v1.Node) (*v1.Node, error) {
	oldData, err := json.Marshal(oldNode)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal old node %#v for node %q: %v", oldNode, nodeName, err)
	}

	// Reset spec to make sure only patch for Status or ObjectMeta is generated.
	// Note that we don't reset ObjectMeta here, because:
	// 1. This aligns with Nodes().UpdateStatus().
	// 2. Some component does use this to update node annotations.
	newNode.Spec = oldNode.Spec
	newData, err := json.Marshal(newNode)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal new node %#v for node %q: %v", newNode, nodeName, err)
	}

	patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Node{})
	if err != nil {
		return nil, fmt.Errorf("failed to create patch for node %q: %v", nodeName, err)
	}

	updatedNode, err := c.Core().Nodes().Patch(string(nodeName), types.StrategicMergePatchType, patchBytes, "status")
	if err != nil {
		return nil, fmt.Errorf("failed to patch status %q for node %q: %v", patchBytes, nodeName, err)
	}
	return updatedNode, nil
}
<commit_msg>Use govendor to replace godep<commit_after><|endoftext|>


<commit_before>package cmd

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// Params currently used:
// token - an OAuth 2.0 bearer token to use when authenticating
// username - the default username to use - if not present, $USER
// endpoint - the default endpoint to use - if not present, https://uk0.bigv.io
// auth-endpoint - the default auth API endpoint to use - if not present, https://auth.bytemark.co.uk

// A Config determines the configuration of the bigv client.
// It's responsible for handling things like the credentials to use and what endpoints to talk to.
//
// Each configuration item is read from the following places, falling back to successive places:
//
// Per-command command-line flags, global command-line flags, environment variables, configuration directory, hard-coded defaults
//
//The location of the configuration directory is read from global command-line flags, or is otherwise ~/.go-bigv
//
type Config struct {
	Dir         string
	Memo        map[string]string
	Definitions map[string]string
}

// Do I really need to have the flags passed in here?
// Yes. Doing commands will be sorted out in a different place, and I don't want to touch it here.

// NewConfig sets up a new config struct. Pass in an empty string to default to ~/.go-bigv
func NewConfig(configDir string, flags *flag.FlagSet) (config *Config) {
	config = new(Config)
	config.Memo = make(map[string]string)
	config.Dir = filepath.Join(os.Getenv("HOME"), "/.go-bigv")
	if os.Getenv("BIGV_CONFIG_DIR") != "" {
		config.Dir = os.Getenv("BIGV_CONFIG_DIR")
	}

	if configDir != "" {
		err := os.MkdirAll(configDir, 0600)
		if err != nil {
			// TODO(telyn): Better error handling here

			panic(err)
		}

		stat, err := os.Stat(configDir)
		if err != nil {
			// TODO(telyn): Better error handling here
			panic(err)
		}

		if !stat.IsDir() {
			fmt.Printf("%s is not a directory", configDir)
			panic("Cannot continue")
		}
		config.Dir = configDir
	}

	if flags != nil {
		// dump all the flags into the memo
		// should be reet...reet?
		flags.Visit(func(f *flag.Flag) {
			config.Memo[f.Name] = f.Value.String()
		})
	}
	return config
}

// GetPath joins the given string onto the end of the Config.Dir path
func (config *Config) GetPath(name string) string {
	return filepath.Join(config.Dir, name)
}
func (config *Config) GetUrl(path ...string) *url.URL {
	url, err := url.Parse(config.Get("endpoint"))
	if err != nil {
		panic("Endpoint is not a valid URL")
	}
	url.Parse("/" + strings.Join([]string(path), "/"))
	return url
}

func (config *Config) LoadDefinitions() {
	stat, err := os.Stat(config.GetPath("definitions"))

	if err != nil || time.Since(stat.ModTime()) > 24*time.Hour {
		// TODO(telyn): grab it off the internet
		//		url := config.GetUrl("definitions.json")
	} else {
		_, err := ioutil.ReadFile(config.GetPath("definitions"))
		if err != nil {
			panic("Couldn't load definitions")
		}
	}

}

func (config *Config) Get(name string) string {
	// try to read the Memo
	if val, ok := config.Memo[name]; ok {
		return val
	} else {
		return config.Read(name)
	}
	return ""
}

func (config *Config) GetDefault(name string) string {
	// ideally most of these should just be	os.Getenv("BIGV_"+name.Upcase().Replace("-","_"))
	switch name {
	case "user":
		return FirstNotEmpty(os.Getenv("BIGV_USER"), os.Getenv("USER"))
	case "endpoint":
		return FirstNotEmpty(os.Getenv("BIGV_ENDPOINT"), "https://uk0.bigv.io")
	case "auth-endpoint":
		return FirstNotEmpty(os.Getenv("BIGV_AUTH_ENDPOINT"), "https://auth.bytemark.co.uk")
	case "account":
		return FirstNotEmpty(os.Getenv("BIGV_ACCOUNT"), os.Getenv("BIGV_USER"), os.Getenv("USER"))
	case "debug-level":
		return FirstNotEmpty(os.Getenv("BIGV_DEBUG_LEVEL"), "0")
	}
	return ""
}

func (config *Config) Read(name string) string {
	contents, err := ioutil.ReadFile(config.GetPath(name))
	if err != nil {
		if os.IsNotExist(err) {
			return config.GetDefault(name)
		}
		fmt.Printf("Couldn't read config for %s", name)
		panic(err)
	}

	return string(contents)
}

// Set stores the given key-value pair in config's Memo. This storage does not persist once the program terminates.
func (config *Config) Set(name string, value string) {
	config.Memo[name] = value
}

// SetPersistent writes a file to the config directory for the given key-value pair.
func (config *Config) SetPersistent(name, value string) {
	config.Set(name, value)
	err := ioutil.WriteFile(config.GetPath("user"), []byte(value), 0600)
	if err != nil {
		fmt.Println("Couldn't write to config directory " + config.Dir)
		panic(err)
	}
}
<commit_msg>Now creates the config dir if it doesn't exist. With the right permissions, too.<commit_after>package cmd

import (
	"flag"
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

// Params currently used:
// token - an OAuth 2.0 bearer token to use when authenticating
// username - the default username to use - if not present, $USER
// endpoint - the default endpoint to use - if not present, https://uk0.bigv.io
// auth-endpoint - the default auth API endpoint to use - if not present, https://auth.bytemark.co.uk

// A Config determines the configuration of the bigv client.
// It's responsible for handling things like the credentials to use and what endpoints to talk to.
//
// Each configuration item is read from the following places, falling back to successive places:
//
// Per-command command-line flags, global command-line flags, environment variables, configuration directory, hard-coded defaults
//
//The location of the configuration directory is read from global command-line flags, or is otherwise ~/.go-bigv
//
type Config struct {
	Dir         string
	Memo        map[string]string
	Definitions map[string]string
}

// Do I really need to have the flags passed in here?
// Yes. Doing commands will be sorted out in a different place, and I don't want to touch it here.

// NewConfig sets up a new config struct. Pass in an empty string to default to ~/.go-bigv
func NewConfig(configDir string, flags *flag.FlagSet) (config *Config) {
	config = new(Config)
	config.Memo = make(map[string]string)
	config.Dir = filepath.Join(os.Getenv("HOME"), "/.go-bigv")
	if os.Getenv("BIGV_CONFIG_DIR") != "" {
		config.Dir = os.Getenv("BIGV_CONFIG_DIR")
	}

	if configDir != "" {
		config.Dir = configDir
	}

	err := os.MkdirAll(config.Dir, 0700)
	if err != nil {
		// TODO(telyn): Better error handling here

		panic(err)
	}

	stat, err := os.Stat(config.Dir)
	if err != nil {
		// TODO(telyn): Better error handling here
		panic(err)
	}

	if !stat.IsDir() {
		fmt.Printf("%s is not a directory", config.Dir)
		panic("Cannot continue")
	}

	if flags != nil {
		// dump all the flags into the memo
		// should be reet...reet?
		flags.Visit(func(f *flag.Flag) {
			config.Memo[f.Name] = f.Value.String()
		})
	}
	return config
}

// GetPath joins the given string onto the end of the Config.Dir path
func (config *Config) GetPath(name string) string {
	return filepath.Join(config.Dir, name)
}
func (config *Config) GetUrl(path ...string) *url.URL {
	url, err := url.Parse(config.Get("endpoint"))
	if err != nil {
		panic("Endpoint is not a valid URL")
	}
	url.Parse("/" + strings.Join([]string(path), "/"))
	return url
}

func (config *Config) LoadDefinitions() {
	stat, err := os.Stat(config.GetPath("definitions"))

	if err != nil || time.Since(stat.ModTime()) > 24*time.Hour {
		// TODO(telyn): grab it off the internet
		//		url := config.GetUrl("definitions.json")
	} else {
		_, err := ioutil.ReadFile(config.GetPath("definitions"))
		if err != nil {
			panic("Couldn't load definitions")
		}
	}

}

func (config *Config) Get(name string) string {
	// try to read the Memo
	if val, ok := config.Memo[name]; ok {
		return val
	} else {
		return config.Read(name)
	}
	return ""
}

func (config *Config) GetDefault(name string) string {
	// ideally most of these should just be	os.Getenv("BIGV_"+name.Upcase().Replace("-","_"))
	switch name {
	case "user":
		return FirstNotEmpty(os.Getenv("BIGV_USER"), os.Getenv("USER"))
	case "endpoint":
		return FirstNotEmpty(os.Getenv("BIGV_ENDPOINT"), "https://uk0.bigv.io")
	case "auth-endpoint":
		return FirstNotEmpty(os.Getenv("BIGV_AUTH_ENDPOINT"), "https://auth.bytemark.co.uk")
	case "account":
		return FirstNotEmpty(os.Getenv("BIGV_ACCOUNT"), os.Getenv("BIGV_USER"), os.Getenv("USER"))
	case "debug-level":
		return FirstNotEmpty(os.Getenv("BIGV_DEBUG_LEVEL"), "0")
	}
	return ""
}

func (config *Config) Read(name string) string {
	contents, err := ioutil.ReadFile(config.GetPath(name))
	if err != nil {
		if os.IsNotExist(err) {
			return config.GetDefault(name)
		}
		fmt.Printf("Couldn't read config for %s", name)
		panic(err)
	}

	return string(contents)
}

// Set stores the given key-value pair in config's Memo. This storage does not persist once the program terminates.
func (config *Config) Set(name string, value string) {
	config.Memo[name] = value
}

// SetPersistent writes a file to the config directory for the given key-value pair.
func (config *Config) SetPersistent(name, value string) {
	config.Set(name, value)
	err := ioutil.WriteFile(config.GetPath("user"), []byte(value), 0600)
	if err != nil {
		fmt.Println("Couldn't write to config directory " + config.Dir)
		panic(err)
	}
}
<|endoftext|>


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

package cmd

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"net/http"
	"sync"

	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
	"github.com/karimra/gnmic/outputs"
	nokiasros "github.com/karimra/sros-dialout"
	"github.com/openconfig/gnmi/proto/gnmi"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/peer"
)

// listenCmd represents the listen command
var listenCmd = &cobra.Command{
	Use:   "listen",
	Short: "listens for telemetry dialout updates from the node",

	RunE: func(cmd *cobra.Command, args []string) error {
		server := new(dialoutTelemetryServer)
		address := viper.GetStringSlice("address")
		if len(address) == 0 {
			return fmt.Errorf("no address specified")
		}
		if len(address) > 1 {
			fmt.Printf("multiple addresses specified, listening only on %s\n", address[0])
		}
		var err error
		server.Outputs, err = getOutputs()
		if err != nil {
			return err
		}

		defer func() {
			for _, o := range server.Outputs {
				o.Close()
			}
		}()
		server.listener, err = net.Listen("tcp", address[0])
		if err != nil {
			return err
		}
		logger.Printf("waiting for connections on %s", address[0])
		var opts []grpc.ServerOption
		if viper.GetInt("max-msg-size") > 0 {
			opts = append(opts, grpc.MaxRecvMsgSize(viper.GetInt("max-msg-size")))
		}
		opts = append(opts,
			grpc.MaxConcurrentStreams(viper.GetUint32("max-concurrent-streams")),
			grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor))

		if viper.GetString("tls-key") != "" && viper.GetString("tls-cert") != "" {
			tlsConfig := &tls.Config{
				Renegotiation:      tls.RenegotiateNever,
				InsecureSkipVerify: viper.GetBool("skip-verify"),
			}
			err := loadCerts(tlsConfig)
			if err != nil {
				logger.Printf("failed loading certificates: %v", err)
			}

			err = loadCACerts(tlsConfig)
			if err != nil {
				logger.Printf("failed loading CA certificates: %v", err)
			}
			opts = append(opts, grpc.Creds(credentials.NewTLS(tlsConfig)))
		}

		server.grpcServer = grpc.NewServer(opts...)
		nokiasros.RegisterDialoutTelemetryServer(server.grpcServer, server)
		grpc_prometheus.Register(server.grpcServer)

		httpServer := &http.Server{
			Handler: promhttp.Handler(),
			Addr:    viper.GetString("prometheus-address"),
		}
		go func() {
			if err := httpServer.ListenAndServe(); err != nil {
				logger.Printf("Unable to start prometheus http server.")
			}
		}()
		defer httpServer.Close()
		server.grpcServer.Serve(server.listener)
		defer server.grpcServer.Stop()
		return nil
	},
}

func init() {
	rootCmd.AddCommand(listenCmd)

	listenCmd.Flags().Uint32P("max-concurrent-streams", "", 256, "max concurrent streams gnmic can receive per transport")

	viper.BindPFlag("listen-max-concurrent-streams", listenCmd.LocalFlags().Lookup("max-concurrent-streams"))
}

type dialoutTelemetryServer struct {
	listener   net.Listener
	grpcServer *grpc.Server
	Outputs    []outputs.Output
}

func (s *dialoutTelemetryServer) Publish(stream nokiasros.DialoutTelemetry_PublishServer) error {
	peer, ok := peer.FromContext(stream.Context())
	if ok && viper.GetBool("debug") {
		b, err := json.Marshal(peer)
		if err != nil {
			logger.Printf("failed to marshal peer data: %v", err)
		} else {
			logger.Printf("received Publish RPC from peer=%s", string(b))
		}
	}
	md, ok := metadata.FromIncomingContext(stream.Context())
	if ok && viper.GetBool("debug") {
		b, err := json.Marshal(md)
		if err != nil {
			logger.Printf("failed to marshal context metadata: %v", err)
		} else {
			logger.Printf("received http2_header=%s", string(b))
		}
	}
	outMeta := outputs.Meta{}
	meta := make(map[string]interface{})
	if sn, ok := md["subscription-name"]; ok {
		if len(sn) > 0 {
			meta["subscription-name"] = sn[0]
			outMeta["subscription-name"] = sn[0]
		}
	} else {
		logger.Println("could not find subscription-name in http2 headers")
	}
	meta["source"] = peer.Addr.String()
	outMeta["source"] = peer.Addr.String()
	if systemName, ok := md["system-name"]; ok {
		if len(systemName) > 0 {
			meta["system-name"] = systemName[0]
		}
	} else {
		logger.Println("could not find system-name in http2 headers")
	}
	lock := new(sync.Mutex)
	for {
		subResp, err := stream.Recv()
		if err != nil {
			if err != io.EOF {
				logger.Printf("gRPC dialout receive error: %v", err)
			}
			break
		}
		err = stream.Send(&nokiasros.PublishResponse{})
		if err != nil {
			logger.Printf("error sending publish response to server: %v", err)
		}
		switch resp := subResp.Response.(type) {
		case *gnmi.SubscribeResponse_Update:
			b, err := formatSubscribeResponse(meta, subResp)
			if err != nil {
				logger.Printf("failed to format subscribe response: %v", err)
				continue
			}
			for _, o := range s.Outputs {
				go o.Write(b, outMeta)
			}
			buff := new(bytes.Buffer)
			err = json.Indent(buff, b, "", "  ")
			if err != nil {
				logger.Printf("failed to indent msg: err=%v, msg=%s", err, string(b))
				continue
			}
			lock.Lock()
			fmt.Println(buff.String())
			lock.Unlock()
		case *gnmi.SubscribeResponse_SyncResponse:
			logger.Printf("received sync response=%+v from %s\n", resp.SyncResponse, meta["source"])
		}
	}
	return nil
}
<commit_msg>change outputs to map, rather than list<commit_after>// Copyright © 2020 Karim Radhouani <medkarimrdi@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"net"
	"net/http"
	"sync"

	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
	"github.com/karimra/gnmic/outputs"
	nokiasros "github.com/karimra/sros-dialout"
	"github.com/openconfig/gnmi/proto/gnmi"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/peer"
)

// listenCmd represents the listen command
var listenCmd = &cobra.Command{
	Use:   "listen",
	Short: "listens for telemetry dialout updates from the node",

	RunE: func(cmd *cobra.Command, args []string) error {
		server := new(dialoutTelemetryServer)
		address := viper.GetStringSlice("address")
		if len(address) == 0 {
			return fmt.Errorf("no address specified")
		}
		if len(address) > 1 {
			fmt.Printf("multiple addresses specified, listening only on %s\n", address[0])
		}
		var err error
		server.Outputs, err = getOutputs()
		if err != nil {
			return err
		}

		defer func() {
			for _, o := range server.Outputs {
				o.Close()
			}
		}()
		server.listener, err = net.Listen("tcp", address[0])
		if err != nil {
			return err
		}
		logger.Printf("waiting for connections on %s", address[0])
		var opts []grpc.ServerOption
		if viper.GetInt("max-msg-size") > 0 {
			opts = append(opts, grpc.MaxRecvMsgSize(viper.GetInt("max-msg-size")))
		}
		opts = append(opts,
			grpc.MaxConcurrentStreams(viper.GetUint32("max-concurrent-streams")),
			grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor))

		if viper.GetString("tls-key") != "" && viper.GetString("tls-cert") != "" {
			tlsConfig := &tls.Config{
				Renegotiation:      tls.RenegotiateNever,
				InsecureSkipVerify: viper.GetBool("skip-verify"),
			}
			err := loadCerts(tlsConfig)
			if err != nil {
				logger.Printf("failed loading certificates: %v", err)
			}

			err = loadCACerts(tlsConfig)
			if err != nil {
				logger.Printf("failed loading CA certificates: %v", err)
			}
			opts = append(opts, grpc.Creds(credentials.NewTLS(tlsConfig)))
		}

		server.grpcServer = grpc.NewServer(opts...)
		nokiasros.RegisterDialoutTelemetryServer(server.grpcServer, server)
		grpc_prometheus.Register(server.grpcServer)

		httpServer := &http.Server{
			Handler: promhttp.Handler(),
			Addr:    viper.GetString("prometheus-address"),
		}
		go func() {
			if err := httpServer.ListenAndServe(); err != nil {
				logger.Printf("Unable to start prometheus http server.")
			}
		}()
		defer httpServer.Close()
		server.grpcServer.Serve(server.listener)
		defer server.grpcServer.Stop()
		return nil
	},
}

func init() {
	rootCmd.AddCommand(listenCmd)

	listenCmd.Flags().Uint32P("max-concurrent-streams", "", 256, "max concurrent streams gnmic can receive per transport")

	viper.BindPFlag("listen-max-concurrent-streams", listenCmd.LocalFlags().Lookup("max-concurrent-streams"))
}

type dialoutTelemetryServer struct {
	listener   net.Listener
	grpcServer *grpc.Server
	Outputs    map[string]outputs.Output
}

func (s *dialoutTelemetryServer) Publish(stream nokiasros.DialoutTelemetry_PublishServer) error {
	peer, ok := peer.FromContext(stream.Context())
	if ok && viper.GetBool("debug") {
		b, err := json.Marshal(peer)
		if err != nil {
			logger.Printf("failed to marshal peer data: %v", err)
		} else {
			logger.Printf("received Publish RPC from peer=%s", string(b))
		}
	}
	md, ok := metadata.FromIncomingContext(stream.Context())
	if ok && viper.GetBool("debug") {
		b, err := json.Marshal(md)
		if err != nil {
			logger.Printf("failed to marshal context metadata: %v", err)
		} else {
			logger.Printf("received http2_header=%s", string(b))
		}
	}
	outMeta := outputs.Meta{}
	meta := make(map[string]interface{})
	if sn, ok := md["subscription-name"]; ok {
		if len(sn) > 0 {
			meta["subscription-name"] = sn[0]
			outMeta["subscription-name"] = sn[0]
		}
	} else {
		logger.Println("could not find subscription-name in http2 headers")
	}
	meta["source"] = peer.Addr.String()
	outMeta["source"] = peer.Addr.String()
	if systemName, ok := md["system-name"]; ok {
		if len(systemName) > 0 {
			meta["system-name"] = systemName[0]
		}
	} else {
		logger.Println("could not find system-name in http2 headers")
	}
	lock := new(sync.Mutex)
	for {
		subResp, err := stream.Recv()
		if err != nil {
			if err != io.EOF {
				logger.Printf("gRPC dialout receive error: %v", err)
			}
			break
		}
		err = stream.Send(&nokiasros.PublishResponse{})
		if err != nil {
			logger.Printf("error sending publish response to server: %v", err)
		}
		switch resp := subResp.Response.(type) {
		case *gnmi.SubscribeResponse_Update:
			b, err := formatSubscribeResponse(meta, subResp)
			if err != nil {
				logger.Printf("failed to format subscribe response: %v", err)
				continue
			}
			for _, o := range s.Outputs {
				go o.Write(b, outMeta)
			}
			buff := new(bytes.Buffer)
			err = json.Indent(buff, b, "", "  ")
			if err != nil {
				logger.Printf("failed to indent msg: err=%v, msg=%s", err, string(b))
				continue
			}
			lock.Lock()
			fmt.Println(buff.String())
			lock.Unlock()
		case *gnmi.SubscribeResponse_SyncResponse:
			logger.Printf("received sync response=%+v from %s\n", resp.SyncResponse, meta["source"])
		}
	}
	return nil
}
<|endoftext|>