<commit_before>package service

import (
	peer "gx/ipfs/QmbyvM8zRFDkbFdYyt1MnevUMJ62SiSGbfDFZ3Z8nkrzr4/go-libp2p-peer"
	"github.com/OpenBazaar/openbazaar-go/pb"
)

type serviceHandler func(peer.ID, *pb.Message) (*pb.Message, error)

func (service *OpenBazaarService) HandlerForMsgType(t pb.Message_MessageType) serviceHandler {
	switch t {
	case pb.Message_PING:
		return service.handlePing
	case pb.Message_FOLLOW:
		return service.handleFollow
	case pb.Message_UNFOLLOW:
		return service.handleUnFollow
	default:
		return nil
	}
}

func (service *OpenBazaarService) handlePing(peer peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Received PING message from %s", peer.Pretty())
	return pmes, nil
}

func (service *OpenBazaarService) handleFollow(peer peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Received FOLLOW message from %s", peer.Pretty())
	err := service.datastore.Followers().Put(peer.Pretty())
	if err != nil {
		return nil, err
	}
	service.broadcast <- []byte(`{"notification": {"follow":"` + peer.Pretty() + `"}}`)
	return nil, nil
}

func (service *OpenBazaarService) handleUnFollow(peer peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Received UNFOLLOW message from %s", peer.Pretty())
	err := service.datastore.Followers().Delete(peer.Pretty())
	if err != nil {
		return nil, err
	}
	service.broadcast <- []byte(`{"notification": {"unfollow":"` + peer.Pretty() + `"}}`)
	return nil, nil
}

func (service *OpenBazaarService) handleOfflineAck(p peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Received OFFLINE_ACK message from %s", p.Pretty())
	pid, err := peer.IDB58Decode(string(pmes.Payload.Value))
	if err != nil {
		return nil, err
	}
	err = service.datastore.Pointers().Delete(pid)
	if err != nil {
		return nil, err
	}
	return nil, nil
}<commit_msg>Add case for OfflineAck handler<commit_after>package service

import (
	peer "gx/ipfs/QmbyvM8zRFDkbFdYyt1MnevUMJ62SiSGbfDFZ3Z8nkrzr4/go-libp2p-peer"
	"github.com/OpenBazaar/openbazaar-go/pb"
)

type serviceHandler func(peer.ID, *pb.Message) (*pb.Message, error)

func (service *OpenBazaarService) HandlerForMsgType(t pb.Message_MessageType) serviceHandler {
	switch t {
	case pb.Message_PING:
		return service.handlePing
	case pb.Message_FOLLOW:
		return service.handleFollow
	case pb.Message_UNFOLLOW:
		return service.handleUnFollow
	case pb.Message_OFFLINE_ACK:
		return service.handleOfflineAck
	default:
		return nil
	}
}

func (service *OpenBazaarService) handlePing(peer peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Received PING message from %s", peer.Pretty())
	return pmes, nil
}

func (service *OpenBazaarService) handleFollow(peer peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Received FOLLOW message from %s", peer.Pretty())
	err := service.datastore.Followers().Put(peer.Pretty())
	if err != nil {
		return nil, err
	}
	service.broadcast <- []byte(`{"notification": {"follow":"` + peer.Pretty() + `"}}`)
	return nil, nil
}

func (service *OpenBazaarService) handleUnFollow(peer peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Received UNFOLLOW message from %s", peer.Pretty())
	err := service.datastore.Followers().Delete(peer.Pretty())
	if err != nil {
		return nil, err
	}
	service.broadcast <- []byte(`{"notification": {"unfollow":"` + peer.Pretty() + `"}}`)
	return nil, nil
}

func (service *OpenBazaarService) handleOfflineAck(p peer.ID, pmes *pb.Message) (*pb.Message, error) {
	log.Debugf("Received OFFLINE_ACK message from %s", p.Pretty())
	pid, err := peer.IDB58Decode(string(pmes.Payload.Value))
	if err != nil {
		return nil, err
	}
	err = service.datastore.Pointers().Delete(pid)
	if err != nil {
		return nil, err
	}
	return nil, nil
}<|endoftext|>


<commit_before>// Copyright (c) 2014 Datacratic. All rights reserved.

package nfork

import (
	"github.com/nativetouch/goklog/klog"

	"net"
	"net/http"
	"sync/atomic"
	"unsafe"
)

// InboundServer wraps an Inbound object into an HTTP server and allows the
// Inbound to be safely manipulated using a copy-on-write scheme.
//
// InboundServer currently assumes that the various management functions are
// synchronized externally.
type InboundServer struct {
	listener net.Listener
	inbound  unsafe.Pointer
}

// NewInboundServer creates and starts a new HTTP server associated with the
// given Inbound.
func NewInboundServer(inbound *Inbound) (*InboundServer, error) {
	server := new(InboundServer)

	if err := inbound.Validate(); err != nil {
		return nil, err
	}
	inbound.Init()

	server.setInbound(inbound)

	listener, err := net.Listen("tcp", inbound.Listen)
	if err != nil {
		klog.KPrintf(klog.Keyf("%s.listen", inbound.Name), "unable to listen on %s: %s", inbound.Listen, err)
		return nil, err
	}
	server.listener = listener

	go func() {
		err := http.Serve(tcpKeepAliveListener{listener.(*net.TCPListener)}, server)
		klog.KPrintf(klog.Keyf("%s.close", server.getInbound().Name), "server closed with: %s", err)
	}()

	return server, nil
}

// Close closes the HTTP server releasing all associated resources.
func (server *InboundServer) Close() {
	server.listener.Close()
}

// ServeHTTP forwards the given HTTP request to the managed inbound.
func (server *InboundServer) ServeHTTP(writer http.ResponseWriter, httpReq *http.Request) {
	server.getInbound().ServeHTTP(writer, httpReq)
}

// List returns the managed inbound.
func (server *InboundServer) List() *Inbound {
	return server.getInbound()
}

// ReadStats calls ReadStats on the managed inbound.
func (server *InboundServer) ReadStats() map[string]*Stats {
	return server.getInbound().ReadStats()
}

// ReadOutboundStats calls ReadOutboundStats on the managed inbound.
func (server *InboundServer) ReadOutboundStats(outbound string) (*Stats, error) {
	return server.getInbound().ReadOutboundStats(outbound)
}

// AddOutbound calls AddOutbound on the managed inbound.
func (server *InboundServer) AddOutbound(outbound, addr, path string) error {
	inbound := server.getInbound().Copy()

	if err := inbound.AddOutbound(outbound, addr, path); err != nil {
		return err
	}

	server.setInbound(inbound)
	return nil
}

// RemoveOutbound calls RemoveOutbound on the managed inbound.
func (server *InboundServer) RemoveOutbound(outbound string) error {
	inbound := server.getInbound().Copy()

	if err := inbound.RemoveOutbound(outbound); err != nil {
		return err
	}

	server.setInbound(inbound)
	return nil
}

// ActivateOutbound calls ActivateOutbound on the managed inbound.
func (server *InboundServer) ActivateOutbound(outbound string) error {
	inbound := server.getInbound().Copy()

	if err := inbound.ActivateOutbound(outbound); err != nil {
		return err
	}

	server.setInbound(inbound)
	return nil
}

func (server *InboundServer) setInbound(inbound *Inbound) {
	atomic.StorePointer(&server.inbound, unsafe.Pointer(inbound))
}

func (server *InboundServer) getInbound() *Inbound {
	return (*Inbound)(atomic.LoadPointer(&server.inbound))
}
<commit_msg>Remove COW unsafe pointer<commit_after>// Copyright (c) 2014 Datacratic. All rights reserved.

package nfork

import (
	"github.com/nativetouch/goklog/klog"

	"net"
	"net/http"
)

// InboundServer wraps an Inbound object into an HTTP server and allows the
// Inbound to be safely manipulated using a copy-on-write scheme.
//
// InboundServer currently assumes that the various management functions are
// synchronized externally.
type InboundServer struct {
	listener net.Listener
	inbound  *Inbound
}

// NewInboundServer creates and starts a new HTTP server associated with the
// given Inbound.
func NewInboundServer(inbound *Inbound) (*InboundServer, error) {
	server := new(InboundServer)

	if err := inbound.Validate(); err != nil {
		return nil, err
	}
	inbound.Init()

	server.setInbound(inbound)

	listener, err := net.Listen("tcp", inbound.Listen)
	if err != nil {
		klog.KPrintf(klog.Keyf("%s.listen", inbound.Name), "unable to listen on %s: %s", inbound.Listen, err)
		return nil, err
	}
	server.listener = listener

	go func() {
		err := http.Serve(tcpKeepAliveListener{listener.(*net.TCPListener)}, server)
		klog.KPrintf(klog.Keyf("%s.close", server.getInbound().Name), "server closed with: %s", err)
	}()

	return server, nil
}

// Close closes the HTTP server releasing all associated resources.
func (server *InboundServer) Close() {
	server.listener.Close()
}

// ServeHTTP forwards the given HTTP request to the managed inbound.
func (server *InboundServer) ServeHTTP(writer http.ResponseWriter, httpReq *http.Request) {
	server.getInbound().ServeHTTP(writer, httpReq)
}

// List returns the managed inbound.
func (server *InboundServer) List() *Inbound {
	return server.getInbound()
}

// ReadStats calls ReadStats on the managed inbound.
func (server *InboundServer) ReadStats() map[string]*Stats {
	return server.getInbound().ReadStats()
}

// ReadOutboundStats calls ReadOutboundStats on the managed inbound.
func (server *InboundServer) ReadOutboundStats(outbound string) (*Stats, error) {
	return server.getInbound().ReadOutboundStats(outbound)
}

// AddOutbound calls AddOutbound on the managed inbound.
func (server *InboundServer) AddOutbound(outbound, addr, path string) error {
	inbound := server.getInbound().Copy()

	if err := inbound.AddOutbound(outbound, addr, path); err != nil {
		return err
	}

	server.setInbound(inbound)
	return nil
}

// RemoveOutbound calls RemoveOutbound on the managed inbound.
func (server *InboundServer) RemoveOutbound(outbound string) error {
	inbound := server.getInbound().Copy()

	if err := inbound.RemoveOutbound(outbound); err != nil {
		return err
	}

	server.setInbound(inbound)
	return nil
}

// ActivateOutbound calls ActivateOutbound on the managed inbound.
func (server *InboundServer) ActivateOutbound(outbound string) error {
	inbound := server.getInbound().Copy()

	if err := inbound.ActivateOutbound(outbound); err != nil {
		return err
	}

	server.setInbound(inbound)
	return nil
}

func (server *InboundServer) setInbound(inbound *Inbound) {
	server.inbound = inbound
}

func (server *InboundServer) getInbound() *Inbound {
	return server.inbound
}
<|endoftext|>


<commit_before>package sqlparser

import (
	"bytes"
	"io"
	"strings"
)

func Parse(doc string) (s *Statement, err error) {
	return NewParser(bytes.NewBufferString(doc)).Parse()
}

// Parser represents a parser.
type Parser struct {
	s   *Scanner
	buf struct {
		tok Token  // last read token
		lit string // last read literal
		n   int    // buffer size (max=1)
	}
}

// NewParser returns a new instance of Parser.
func NewParser(r io.Reader) *Parser {
	return &Parser{s: NewScanner(r)}
}

func (p *Parser) Parse() (s *Statement, err error) {
	tok, _ := p.scanIgnoreWhitespace()
	p.unscan()
	switch tok {
	case SELECT:
		s, err = p.ParseSelect()

	case INSERT:
		s, err = p.ParseInsert()

	case UPDATE:
		s, err = p.ParseUpdate()

	case DELETE:
		s, err = p.ParseDelete()

	case CREATE:
		s, err = p.ParseCreate()

	default:
		panic("sql error, must start with SELECT/INSERT/UPDATE/DELETE")
	}
	if err != nil {
		return nil, err
	}

	if len(s.Fragments) > 0 {
		f := s.Fragments[len(s.Fragments)-1]
		f.Statement = strings.TrimSpace(f.Statement)
	}
	return s, err
}

// scan returns the next token from the underlying scanner.
// If a token has been unscanned then read that instead.
func (p *Parser) scan() (tok Token, lit string) {
	// If we have a token on the buffer, then return it.
	if p.buf.n != 0 {
		p.buf.n = 0
		return p.buf.tok, p.buf.lit
	}

	// Otherwise read the next token from the scanner.
	tok, lit = p.s.Scan()

	// Save it to the buffer in case we unscan later.
	p.buf.tok, p.buf.lit = tok, lit

	return
}

// unscan pushes the previously read token back onto the buffer.
func (p *Parser) unscan() { p.buf.n = 1 }

// scanIgnoreWhitespace scans the next non-whitespace token.
func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
	tok, lit = p.scan()
	if tok == WS {
		tok, lit = p.scan()
	}
	return
}

func (p *Parser) scanVariable() (v string) {
	tok, lit := p.scanIgnoreWhitespace()
	if tok != DOLLAR {
		panic("variable must start with $")
	}
	tok, lit = p.scanIgnoreWhitespace()
	if tok != LEFT_BRACES {
		panic("variable must wraped by ${...}")
	}

	for {
		tok, lit = p.scan()
		switch tok {
		default:
			v += lit
		case WS:
			// ingnore
		case RIGHT_BRACES:
			return
		case EOF:
			panic("expect more words")
		}
	}
}

func (p *Parser) scanReplacer() (v string) {
	tok, lit := p.scanIgnoreWhitespace()
	if tok != POUND {
		panic("replacer must start with #")
	}
	tok, lit = p.scanIgnoreWhitespace()
	if tok != LEFT_BRACES {
		panic("replacer must wraped by #{...}")
	}

	for {
		tok, lit = p.scan()
		switch tok {
		default:
			v += lit
		case WS:
			// ingnore
		case RIGHT_BRACES:
			return
		case EOF:
			panic("expect more words")
		}
	}
}

func (p *Parser) scanCondition() (v string) {
	tok, lit := p.scan()
	if tok != LEFT_BRACES {
		p.unscan()
		return ""
	}

	var buf bytes.Buffer
	for {
		tok, lit = p.scan()
		switch tok {
		default:
			buf.WriteString(lit)
		case WS:
			buf.WriteString(" ")
		case RIGHT_BRACES:
			return buf.String()
		case EOF:
			panic("expect more words")
		}
	}
}

func (p *Parser) scanFragments() (fs []*Fragment) {
	// scan fragment
	for {
		f, lastToken := p.parseFragment()
		if f != nil {
			fs = append(fs, f)
		}
		if lastToken == EOF {
			break
		}
	}
	return fs
}

func (p *Parser) parseFragment() (*Fragment, Token) {
	var inner bool
	var buf bytes.Buffer

	tok, lit := p.scanIgnoreWhitespace()
	if tok == LEFT_BRACKET {
		inner = true
	} else if tok == RIGHT_BRACKET {
		p.unscan()
		return nil, EOF
	} else if tok == ORDER {
		buf.WriteString(strings.ToUpper(lit))
	} else {
		p.unscan()
	}

	f := Fragment{}
	f.Condition = p.scanCondition()
	if f.Condition == "" && inner {
		f.Condition = "-"
	}

	for {
		tok, lit = p.scan()
		switch tok {
		default:
			buf.WriteString(lit)

		case WS:
			buf.WriteByte(SPACE)

		case POUND:
			p.unscan()
			lit = p.scanReplacer()
			f.Replacers = append(f.Replacers, lit)
			buf.WriteString("%v")

		case DOLLAR:
			p.unscan()
			lit = p.scanVariable()
			f.Variables = append(f.Variables, lit)
			buf.WriteByte(QUESTION)

		case LEFT_BRACKET:
			p.unscan()
			if inner {
				stmt := strings.TrimSpace(buf.String())
				buf.Reset()
				if len(stmt) > 0 {
					innerFirst := Fragment{Statement: stmt, Variables: f.Variables}
					f.Variables = nil
					f.Fragments = append(f.Fragments, &innerFirst)
				}
				f.Fragments = append(f.Fragments, p.scanFragments()...)
			}
			goto END

		case RIGHT_BRACKET, ORDER, EOF:
			p.unscan()
			goto END
		}
	}

END:
	tok, lit = p.scanIgnoreWhitespace()
	if inner {
		if tok != RIGHT_BRACKET {
			panic("expect ], but got " + lit + ", " + buf.String())
		}
	} else {
		p.unscan()
		if tok == RIGHT_BRACKET {
			tok = EOF
		}
	}
	f.Statement = strings.TrimSpace(buf.String())
	if len(f.Statement) > 0 {
		f.Statement += " "
	}
	return &f, tok
}
<commit_msg>remove duplicate space<commit_after>package sqlparser

import (
	"bytes"
	"io"
	"strings"
)

func Parse(doc string) (s *Statement, err error) {
	return NewParser(bytes.NewBufferString(doc)).Parse()
}

// Parser represents a parser.
type Parser struct {
	s   *Scanner
	buf struct {
		tok Token  // last read token
		lit string // last read literal
		n   int    // buffer size (max=1)
	}
}

// NewParser returns a new instance of Parser.
func NewParser(r io.Reader) *Parser {
	return &Parser{s: NewScanner(r)}
}

func (p *Parser) Parse() (s *Statement, err error) {
	tok, _ := p.scanIgnoreWhitespace()
	p.unscan()
	switch tok {
	case SELECT:
		s, err = p.ParseSelect()

	case INSERT:
		s, err = p.ParseInsert()

	case UPDATE:
		s, err = p.ParseUpdate()

	case DELETE:
		s, err = p.ParseDelete()

	case CREATE:
		s, err = p.ParseCreate()

	default:
		panic("sql error, must start with SELECT/INSERT/UPDATE/DELETE")
	}
	if err != nil {
		return nil, err
	}

	if len(s.Fragments) > 0 {
		f := s.Fragments[len(s.Fragments)-1]
		f.Statement = strings.TrimSpace(f.Statement)
	}
	return s, err
}

// scan returns the next token from the underlying scanner.
// If a token has been unscanned then read that instead.
func (p *Parser) scan() (tok Token, lit string) {
	// If we have a token on the buffer, then return it.
	if p.buf.n != 0 {
		p.buf.n = 0
		return p.buf.tok, p.buf.lit
	}

	// Otherwise read the next token from the scanner.
	tok, lit = p.s.Scan()

	// Save it to the buffer in case we unscan later.
	p.buf.tok, p.buf.lit = tok, lit

	return
}

// unscan pushes the previously read token back onto the buffer.
func (p *Parser) unscan() { p.buf.n = 1 }

// scanIgnoreWhitespace scans the next non-whitespace token.
func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
	tok, lit = p.scan()
	if tok == WS {
		tok, lit = p.scan()
	}
	return
}

func (p *Parser) scanVariable() (v string) {
	tok, lit := p.scanIgnoreWhitespace()
	if tok != DOLLAR {
		panic("variable must start with $")
	}
	tok, lit = p.scanIgnoreWhitespace()
	if tok != LEFT_BRACES {
		panic("variable must wraped by ${...}")
	}

	for {
		tok, lit = p.scan()
		switch tok {
		default:
			v += lit
		case WS:
			// ingnore
		case RIGHT_BRACES:
			return
		case EOF:
			panic("expect more words")
		}
	}
}

func (p *Parser) scanReplacer() (v string) {
	tok, lit := p.scanIgnoreWhitespace()
	if tok != POUND {
		panic("replacer must start with #")
	}
	tok, lit = p.scanIgnoreWhitespace()
	if tok != LEFT_BRACES {
		panic("replacer must wraped by #{...}")
	}

	for {
		tok, lit = p.scan()
		switch tok {
		default:
			v += lit
		case WS:
			// ingnore
		case RIGHT_BRACES:
			return
		case EOF:
			panic("expect more words")
		}
	}
}

func (p *Parser) scanCondition() (v string) {
	tok, lit := p.scan()
	if tok != LEFT_BRACES {
		p.unscan()
		return ""
	}

	var buf bytes.Buffer
	for {
		tok, lit = p.scan()
		switch tok {
		default:
			buf.WriteString(lit)
		case WS:
			buf.WriteString(" ")
		case RIGHT_BRACES:
			return buf.String()
		case EOF:
			panic("expect more words")
		}
	}
}

func (p *Parser) scanFragments() (fs []*Fragment) {
	// scan fragment
	for {
		f, lastToken := p.parseFragment()
		if f != nil {
			fs = append(fs, f)
		}
		if lastToken == EOF {
			break
		}
	}
	return fs
}

func (p *Parser) parseFragment() (*Fragment, Token) {
	var inner bool
	var buf bytes.Buffer

	tok, lit := p.scanIgnoreWhitespace()
	if tok == LEFT_BRACKET {
		inner = true
	} else if tok == RIGHT_BRACKET {
		p.unscan()
		return nil, EOF
	} else if tok == ORDER {
		buf.WriteString(strings.ToUpper(lit))
	} else {
		p.unscan()
	}

	f := Fragment{}
	f.Condition = p.scanCondition()
	if f.Condition == "" && inner {
		f.Condition = "-"
	}

	for {
		tok, lit = p.scan()
		switch tok {
		default:
			buf.WriteString(lit)

		case WS:
			buf.WriteByte(SPACE)

		case POUND:
			p.unscan()
			lit = p.scanReplacer()
			f.Replacers = append(f.Replacers, lit)
			buf.WriteString("%v")

		case DOLLAR:
			p.unscan()
			lit = p.scanVariable()
			f.Variables = append(f.Variables, lit)
			buf.WriteByte(QUESTION)

		case LEFT_BRACKET:
			p.unscan()
			if inner {
				stmt := strings.TrimSpace(buf.String())
				buf.Reset()
				if len(stmt) > 0 {
					innerFirst := Fragment{Statement: stmt, Variables: f.Variables}
					f.Variables = nil
					f.Fragments = append(f.Fragments, &innerFirst)
				}
				f.Fragments = append(f.Fragments, p.scanFragments()...)
			}
			goto END

		case RIGHT_BRACKET, ORDER, EOF:
			p.unscan()
			goto END
		}
	}

END:
	tok, lit = p.scanIgnoreWhitespace()
	if inner {
		if tok != RIGHT_BRACKET {
			panic("expect ], but got " + lit + ", " + buf.String())
		}
	} else {
		p.unscan()
		if tok == RIGHT_BRACKET {
			tok = EOF
		}
	}
	f.Statement = strings.TrimSpace(buf.String())
	return &f, tok
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"testing"

	"github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
)

func TestNewNova(t *testing.T) {
	n := NewNova()
	if n.machines != nil {
		t.Errorf("'servers' attribute is not nil")
	}
}

func TestInitAndCache(t *testing.T) {
	var err error
	n := NewNova()

	// Remove credential cache file
	os.Remove(n.credentialCachePath())

	// Init
	if err = n.Init(); err != nil {
		t.Errorf("%v", err)
	}

	// Verify credential cache file
	_, err = os.Stat(n.credentialCachePath())
	if err != nil {
		t.Errorf("%v", err)
	}

	strdata, err := ioutil.ReadFile(n.credentialCachePath())
	cred := &Credential{Token: &tokens.Token{}}
	if err = json.Unmarshal(strdata, cred); err != nil {
		t.Errorf("%v", err)
	}
}

func TestInitAndCache2(t *testing.T) {
	// NOTE: Credential cache file has already created by previous test
	n := NewNova()

	// Init() uses it instead of authenticating
	if err := n.Init(); err != nil {
		t.Errorf("%v", err)
	}
}

func TestFind(t *testing.T) {
	n := NewNova()
	n.Init()

	machines, err := n.List()
	if err != nil {
		t.Errorf("%v", err)

	} else if len(machines) == 0 {
		t.Skipf("Skip beause no servers found")
	}

	ss, err := n.Find(machines[0].Name)
	if err != nil {
		t.Errorf("%v", err)

	} else if ss == nil || ss.Name != machines[0].Name {
		t.Errorf("Find() did not return the server: name=%s", machines[0].Name)
	}
}
<commit_msg>インスタンスが無いときのテストを追加<commit_after>package main

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"testing"

	"github.com/rackspace/gophercloud/openstack/identity/v2/tokens"
)

func TestNewNova(t *testing.T) {
	n := NewNova()
	if n.machines != nil {
		t.Errorf("'servers' attribute is not nil")
	}
}

func TestInitAndCache(t *testing.T) {
	var err error
	n := NewNova()

	// Remove credential cache file
	os.Remove(n.credentialCachePath())

	// Init
	if err = n.Init(); err != nil {
		t.Errorf("%v", err)
	}

	// Verify credential cache file
	_, err = os.Stat(n.credentialCachePath())
	if err != nil {
		t.Errorf("%v", err)
	}

	strdata, err := ioutil.ReadFile(n.credentialCachePath())
	cred := &Credential{Token: &tokens.Token{}}
	if err = json.Unmarshal(strdata, cred); err != nil {
		t.Errorf("%v", err)
	}
}

func TestInitAndCache2(t *testing.T) {
	// NOTE: Credential cache file has already created by previous test
	n := NewNova()

	// Init() uses it instead of authenticating
	if err := n.Init(); err != nil {
		t.Errorf("%v", err)
	}
}

func TestFind(t *testing.T) {
	n := NewNova()
	n.Init()

	machines, err := n.List()
	if err != nil {
		t.Errorf("%v", err)

	} else if len(machines) == 0 {
		t.Skipf("Skip beause no servers found")
	}

	ss, err := n.Find(machines[0].Name)
	if err != nil {
		t.Errorf("%v", err)

	} else if ss == nil || ss.Name != machines[0].Name {
		t.Errorf("Find() did not return the server: name=%s", machines[0].Name)
	}
}

func TestFind2(t *testing.T) {
	n := NewNova()
	n.Init()

	ss, err := n.Find("undefinded-instance-name")
	if err != nil {
		t.Errorf("%v", err)

	} else if ss != nil {
		t.Errorf("Find() should return 'nil'")
	}
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Julien Vehent jvehent@mozilla.com [:ulfr]
package agentcontext

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"mig.ninja/mig"
	"mig.ninja/mig/service"
	"os"
	"os/exec"
	"strings"
)

func findHostname(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
	}()

	// get the hostname
	var kernhosterr bool
	kernhostname, err := os.Hostname()
	if err == nil {
		if strings.ContainsAny(kernhostname, ".") {
			ctx.Hostname = kernhostname
			return
		}
	} else {
		kernhostname = "localhost"
		kernhosterr = true
	}
	fqdnhostbuf, err := exec.Command("hostname", "--fqdn").Output()
	if err != nil {
		ctx.Hostname = kernhostname
		err = nil
		return
	}
	fqdnhost := string(fqdnhostbuf)
	fqdnhost = fqdnhost[0 : len(fqdnhost)-1]
	if kernhosterr {
		ctx.Hostname = fqdnhost
		return
	}
	hcomp := strings.Split(fqdnhost, ".")
	if kernhostname == hcomp[0] {
		ctx.Hostname = fqdnhost
		return
	}
	ctx.Hostname = kernhostname
	return
}

func findOSInfo(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findOSInfo() -> %v", e)
		}
		logChan <- mig.Log{Desc: "leaving findOSInfo()"}.Debug()
	}()
	ctx.OSIdent, err = getLSBRelease()
	if err != nil {
		logChan <- mig.Log{Desc: fmt.Sprintf("getLSBRelease() failed: %v", err)}.Info()
		ctx.OSIdent, err = getIssue()
		if err != nil {
			logChan <- mig.Log{Desc: fmt.Sprintf("getIssue() failed: %v", err)}.Info()
		}
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Ident is %s", ctx.OSIdent)}.Debug()

	ctx.Init, err = getInit()
	if err != nil {
		panic(err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Init is %s", ctx.Init)}.Debug()

	return
}

// getLSBRelease reads the linux identity from lsb_release -a
func getLSBRelease() (desc string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getLSBRelease() -> %v", e)
		}
	}()
	path, err := exec.LookPath("lsb_release")
	if err != nil {
		return "", fmt.Errorf("lsb_release is not present")
	}
	out, err := exec.Command(path, "-i", "-r", "-c", "-s").Output()
	if err != nil {
		panic(err)
	}
	desc = fmt.Sprintf("%s", out[0:len(out)-1])
	desc = cleanString(desc)
	return
}

// getIssue parses /etc/issue and returns the first line
func getIssue() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getIssue() -> %v", e)
		}
	}()
	issue, err := ioutil.ReadFile("/etc/issue")
	if err != nil {
		panic(err)
	}
	loc := bytes.IndexAny(issue, "\n")
	if loc < 2 {
		return "", fmt.Errorf("issue string not found")
	}
	initname = fmt.Sprintf("%s", issue[0:loc])
	return
}

// getInit parses /proc/1/cmdline to find out which init system is used
func getInit() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getInit() -> %v", e)
		}
	}()
	itype, err := service.GetFlavor()
	if err != nil {
		panic(err)
	}
	switch itype {
	case service.InitSystemV:
		return "sysvinit", nil
	case service.InitSystemd:
		return "systemd", nil
	case service.InitUpstart:
		return "upstart", nil
	default:
		return "sysvinit-fallback", nil
	}
}

func GetRunDir() string {
	return "/var/lib/mig/"
}
<commit_msg>[minor] in findOSInfo(), dont log normal errors at Info<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Contributor:
// - Julien Vehent jvehent@mozilla.com [:ulfr]
package agentcontext

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"mig.ninja/mig"
	"mig.ninja/mig/service"
	"os"
	"os/exec"
	"strings"
)

func findHostname(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findHostname() -> %v", e)
		}
	}()

	// get the hostname
	var kernhosterr bool
	kernhostname, err := os.Hostname()
	if err == nil {
		if strings.ContainsAny(kernhostname, ".") {
			ctx.Hostname = kernhostname
			return
		}
	} else {
		kernhostname = "localhost"
		kernhosterr = true
	}
	fqdnhostbuf, err := exec.Command("hostname", "--fqdn").Output()
	if err != nil {
		ctx.Hostname = kernhostname
		err = nil
		return
	}
	fqdnhost := string(fqdnhostbuf)
	fqdnhost = fqdnhost[0 : len(fqdnhost)-1]
	if kernhosterr {
		ctx.Hostname = fqdnhost
		return
	}
	hcomp := strings.Split(fqdnhost, ".")
	if kernhostname == hcomp[0] {
		ctx.Hostname = fqdnhost
		return
	}
	ctx.Hostname = kernhostname
	return
}

// findOSInfo gathers information about the Linux distribution if possible, and
// determines the init type of the system.
func findOSInfo(orig_ctx AgentContext) (ctx AgentContext, err error) {
	ctx = orig_ctx
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("findOSInfo() -> %v", e)
		}
		logChan <- mig.Log{Desc: "leaving findOSInfo()"}.Debug()
	}()
	ctx.OSIdent, err = getLSBRelease()
	if err == nil {
		logChan <- mig.Log{Desc: "using lsb release for distribution ident"}.Debug()
		goto haveident
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("getLSBRelease() failed: %v", err)}.Debug()
	ctx.OSIdent, err = getIssue()
	if err == nil {
		logChan <- mig.Log{Desc: "using /etc/issue for distribution ident"}.Debug()
		goto haveident
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("getIssue() failed: %v", err)}.Debug()
	logChan <- mig.Log{Desc: "warning, no valid linux os identification could be found"}.Info()
haveident:
	logChan <- mig.Log{Desc: fmt.Sprintf("Ident is %s", ctx.OSIdent)}.Debug()

	ctx.Init, err = getInit()
	if err != nil {
		panic(err)
	}
	logChan <- mig.Log{Desc: fmt.Sprintf("Init is %s", ctx.Init)}.Debug()

	return
}

// getLSBRelease reads the linux identity from lsb_release -a
func getLSBRelease() (desc string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getLSBRelease() -> %v", e)
		}
	}()
	path, err := exec.LookPath("lsb_release")
	if err != nil {
		return "", fmt.Errorf("lsb_release is not present")
	}
	out, err := exec.Command(path, "-i", "-r", "-c", "-s").Output()
	if err != nil {
		panic(err)
	}
	desc = fmt.Sprintf("%s", out[0:len(out)-1])
	desc = cleanString(desc)
	return
}

// getIssue parses /etc/issue and returns the first line
func getIssue() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getIssue() -> %v", e)
		}
	}()
	issue, err := ioutil.ReadFile("/etc/issue")
	if err != nil {
		panic(err)
	}
	loc := bytes.IndexAny(issue, "\n")
	if loc < 2 {
		return "", fmt.Errorf("issue string not found")
	}
	initname = fmt.Sprintf("%s", issue[0:loc])
	return
}

// getInit parses /proc/1/cmdline to find out which init system is used
func getInit() (initname string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("getInit() -> %v", e)
		}
	}()
	itype, err := service.GetFlavor()
	if err != nil {
		panic(err)
	}
	switch itype {
	case service.InitSystemV:
		return "sysvinit", nil
	case service.InitSystemd:
		return "systemd", nil
	case service.InitUpstart:
		return "upstart", nil
	default:
		return "sysvinit-fallback", nil
	}
}

func GetRunDir() string {
	return "/var/lib/mig/"
}
<|endoftext|>


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

package build

import (
	"crypto/hmac"
	"fmt"
	"http"
	"json"
	"os"

	"appengine"
	"appengine/datastore"
	"cache"
)

const commitsPerPage = 30

// commitHandler retrieves commit data or records a new commit.
//
// For GET requests it returns a Commit value for the specified
// packagePath and hash.
//
// For POST requests it reads a JSON-encoded Commit value from the request
// body and creates a new Commit entity. It also updates the "tip" Tag for
// each new commit at tip.
//
// This handler is used by a gobuilder process in -commit mode.
func commitHandler(r *http.Request) (interface{}, os.Error) {
	c := appengine.NewContext(r)
	com := new(Commit)

	if r.Method == "GET" {
		com.PackagePath = r.FormValue("packagePath")
		com.Hash = r.FormValue("hash")
		if err := datastore.Get(c, com.Key(c), com); err != nil {
			return nil, fmt.Errorf("getting Commit: %v", err)
		}
		return com, nil
	}
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	// POST request
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(com); err != nil {
		return nil, fmt.Errorf("decoding Body: %v", err)
	}
	if len(com.Desc) > maxDatastoreStringLen {
		com.Desc = com.Desc[:maxDatastoreStringLen]
	}
	if err := com.Valid(); err != nil {
		return nil, fmt.Errorf("validating Commit: %v", err)
	}
	defer cache.Tick(c)
	tx := func(c appengine.Context) os.Error {
		return addCommit(c, com)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}

// addCommit adds the Commit entity to the datastore and updates the tip Tag.
// It must be run inside a datastore transaction.
func addCommit(c appengine.Context, com *Commit) os.Error {
	var tc Commit // temp value so we don't clobber com
	err := datastore.Get(c, com.Key(c), &tc)
	if err != datastore.ErrNoSuchEntity {
		// if this commit is already in the datastore, do nothing
		if err == nil {
			return nil
		}
		return fmt.Errorf("getting Commit: %v", err)
	}
	// get the next commit number
	p, err := GetPackage(c, com.PackagePath)
	if err != nil {
		return fmt.Errorf("GetPackage: %v", err)
	}
	com.Num = p.NextNum
	p.NextNum++
	if _, err := datastore.Put(c, p.Key(c), p); err != nil {
		return fmt.Errorf("putting Package: %v", err)
	}
	// if this isn't the first Commit test the parent commit exists
	if com.Num > 0 {
		n, err := datastore.NewQuery("Commit").
			Filter("Hash =", com.ParentHash).
			Ancestor(p.Key(c)).
			Count(c)
		if err != nil {
			return fmt.Errorf("testing for parent Commit: %v", err)
		}
		if n == 0 {
			return os.NewError("parent commit not found")
		}
	}
	// update the tip Tag if this is the Go repo
	if p.Path == "" {
		t := &Tag{Kind: "tip", Hash: com.Hash}
		if _, err = datastore.Put(c, t.Key(c), t); err != nil {
			return fmt.Errorf("putting Tag: %v", err)
		}
	}
	// put the Commit
	if _, err = datastore.Put(c, com.Key(c), com); err != nil {
		return fmt.Errorf("putting Commit: %v", err)
	}
	return nil
}

// tagHandler records a new tag. It reads a JSON-encoded Tag value from the
// request body and updates the Tag entity for the Kind of tag provided.
//
// This handler is used by a gobuilder process in -commit mode.
func tagHandler(r *http.Request) (interface{}, os.Error) {
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	t := new(Tag)
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(t); err != nil {
		return nil, err
	}
	if err := t.Valid(); err != nil {
		return nil, err
	}
	c := appengine.NewContext(r)
	defer cache.Tick(c)
	_, err := datastore.Put(c, t.Key(c), t)
	return nil, err
}

// Todo is a todoHandler response.
type Todo struct {
	Kind string // "build-go-commit" or "build-package"
	Data interface{}
}

// todoHandler returns the next action to be performed by a builder.
// It expects "builder" and "kind" query parameters and returns a *Todo value.
// Multiple "kind" parameters may be specified.
func todoHandler(r *http.Request) (interface{}, os.Error) {
	c := appengine.NewContext(r)
	now := cache.Now(c)
	key := "build-todo-" + r.Form.Encode()
	var todo *Todo
	if cache.Get(r, now, key, &todo) {
		return todo, nil
	}
	var err os.Error
	builder := r.FormValue("builder")
	for _, kind := range r.Form["kind"] {
		var data interface{}
		switch kind {
		case "build-go-commit":
			data, err = buildTodo(c, builder, "", "")
		case "build-package":
			packagePath := r.FormValue("packagePath")
			goHash := r.FormValue("goHash")
			data, err = buildTodo(c, builder, packagePath, goHash)
		}
		if data != nil || err != nil {
			todo = &Todo{Kind: kind, Data: data}
			break
		}
	}
	if err == nil {
		cache.Set(r, now, key, todo)
	}
	return todo, err
}

// buildTodo returns the next Commit to be built (or nil if none available).
//
// If packagePath and goHash are empty, it scans the first 20 Go Commits in
// Num-descending order and returns the first one it finds that doesn't have a
// Result for this builder.
//
// If provided with non-empty packagePath and goHash args, it scans the first
// 20 Commits in Num-descending order for the specified packagePath and
// returns the first that doesn't have a Result for this builder and goHash.
func buildTodo(c appengine.Context, builder, packagePath, goHash string) (interface{}, os.Error) {
	p, err := GetPackage(c, packagePath)
	if err != nil {
		return nil, err
	}

	t := datastore.NewQuery("Commit").
		Ancestor(p.Key(c)).
		Limit(commitsPerPage).
		Order("-Num").
		Run(c)
	for {
		com := new(Commit)
		if _, err := t.Next(com); err == datastore.Done {
			break
		} else if err != nil {
			return nil, err
		}
		if com.Result(builder, goHash) == nil {
			return com, nil
		}
	}

	// Nothing left to do if this is a package (not the Go tree).
	if packagePath != "" {
		return nil, nil
	}

	// If there are no Go tree commits left to build,
	// see if there are any subrepo commits that need to be built at tip.
	// If so, ask the builder to build a go tree at the tip commit.
	// TODO(adg): do the same for "weekly" and "release" tags.
	tag, err := GetTag(c, "tip")
	if err != nil {
		return nil, err
	}
	pkgs, err := Packages(c, "subrepo")
	if err != nil {
		return nil, err
	}
	for _, pkg := range pkgs {
		com, err := pkg.LastCommit(c)
		if err != nil {
			c.Warningf("%v: no Commit found: %v", pkg, err)
			continue
		}
		if com.Result(builder, tag.Hash) == nil {
			return tag.Commit(c)
		}
	}
	return nil, nil
}

// packagesHandler returns a list of the non-Go Packages monitored
// by the dashboard.
func packagesHandler(r *http.Request) (interface{}, os.Error) {
	kind := r.FormValue("kind")
	c := appengine.NewContext(r)
	now := cache.Now(c)
	key := "build-packages-" + kind
	var p []*Package
	if cache.Get(r, now, key, &p) {
		return p, nil
	}
	p, err := Packages(c, kind)
	if err != nil {
		return nil, err
	}
	cache.Set(r, now, key, p)
	return p, nil
}

// resultHandler records a build result.
// It reads a JSON-encoded Result value from the request body,
// creates a new Result entity, and updates the relevant Commit entity.
// If the Log field is not empty, resultHandler creates a new Log entity
// and updates the LogHash field before putting the Commit entity.
func resultHandler(r *http.Request) (interface{}, os.Error) {
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	c := appengine.NewContext(r)
	res := new(Result)
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(res); err != nil {
		return nil, fmt.Errorf("decoding Body: %v", err)
	}
	if err := res.Valid(); err != nil {
		return nil, fmt.Errorf("validating Result: %v", err)
	}
	defer cache.Tick(c)
	// store the Log text if supplied
	if len(res.Log) > 0 {
		hash, err := PutLog(c, res.Log)
		if err != nil {
			return nil, fmt.Errorf("putting Log: %v", err)
		}
		res.LogHash = hash
	}
	tx := func(c appengine.Context) os.Error {
		// check Package exists
		if _, err := GetPackage(c, res.PackagePath); err != nil {
			return fmt.Errorf("GetPackage: %v", err)
		}
		// put Result
		if _, err := datastore.Put(c, res.Key(c), res); err != nil {
			return fmt.Errorf("putting Result: %v", err)
		}
		// add Result to Commit
		com := &Commit{PackagePath: res.PackagePath, Hash: res.Hash}
		if err := com.AddResult(c, res); err != nil {
			return fmt.Errorf("AddResult: %v", err)
		}
		// Send build failure notifications, if necessary.
		// Note this must run after the call AddResult, which
		// populates the Commit's ResultData field.
		return notifyOnFailure(c, com, res.Builder)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}

// logHandler displays log text for a given hash.
// It handles paths like "/log/hash".
func logHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-type", "text/plain")
	c := appengine.NewContext(r)
	hash := r.URL.Path[len("/log/"):]
	key := datastore.NewKey(c, "Log", hash, 0, nil)
	l := new(Log)
	if err := datastore.Get(c, key, l); err != nil {
		logErr(w, r, err)
		return
	}
	b, err := l.Text()
	if err != nil {
		logErr(w, r, err)
		return
	}
	w.Write(b)
}

type dashHandler func(*http.Request) (interface{}, os.Error)

type dashResponse struct {
	Response interface{}
	Error    string
}

// errBadMethod is returned by a dashHandler when
// the request has an unsuitable method.
type errBadMethod string

func (e errBadMethod) String() string {
	return "bad method: " + string(e)
}

// AuthHandler wraps a http.HandlerFunc with a handler that validates the
// supplied key and builder query parameters.
func AuthHandler(h dashHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		c := appengine.NewContext(r)

		// Put the URL Query values into r.Form to avoid parsing the
		// request body when calling r.FormValue.
		r.Form = r.URL.Query()

		var err os.Error
		var resp interface{}

		// Validate key query parameter for POST requests only.
		key := r.FormValue("key")
		builder := r.FormValue("builder")
		if r.Method == "POST" && !validKey(c, key, builder) {
			err = os.NewError("invalid key: " + key)
		}

		// Call the original HandlerFunc and return the response.
		if err == nil {
			resp, err = h(r)
		}

		// Write JSON response.
		dashResp := &dashResponse{Response: resp}
		if err != nil {
			c.Errorf("%v", err)
			dashResp.Error = err.String()
		}
		w.Header().Set("Content-Type", "application/json")
		if err = json.NewEncoder(w).Encode(dashResp); err != nil {
			c.Criticalf("encoding response: %v", err)
		}
	}
}

func keyHandler(w http.ResponseWriter, r *http.Request) {
	builder := r.FormValue("builder")
	if builder == "" {
		logErr(w, r, os.NewError("must supply builder in query string"))
		return
	}
	c := appengine.NewContext(r)
	fmt.Fprint(w, builderKey(c, builder))
}

func init() {
	// admin handlers
	http.HandleFunc("/init", initHandler)
	http.HandleFunc("/key", keyHandler)

	// authenticated handlers
	http.HandleFunc("/commit", AuthHandler(commitHandler))
	http.HandleFunc("/packages", AuthHandler(packagesHandler))
	http.HandleFunc("/result", AuthHandler(resultHandler))
	http.HandleFunc("/tag", AuthHandler(tagHandler))
	http.HandleFunc("/todo", AuthHandler(todoHandler))

	// public handlers
	http.HandleFunc("/log/", logHandler)
}

func validHash(hash string) bool {
	// TODO(adg): correctly validate a hash
	return hash != ""
}

func validKey(c appengine.Context, key, builder string) bool {
	if appengine.IsDevAppServer() {
		return true
	}
	if key == secretKey(c) {
		return true
	}
	return key == builderKey(c, builder)
}

func builderKey(c appengine.Context, builder string) string {
	h := hmac.NewMD5([]byte(secretKey(c)))
	h.Write([]byte(builder))
	return fmt.Sprintf("%x", h.Sum())
}

func logErr(w http.ResponseWriter, r *http.Request, err os.Error) {
	appengine.NewContext(r).Errorf("Error: %v", err)
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprint(w, "Error: ", err)
}
<commit_msg>dashboard: don't send failing Go commits as todos for subrepos<commit_after>// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package build

import (
	"crypto/hmac"
	"fmt"
	"http"
	"json"
	"os"

	"appengine"
	"appengine/datastore"
	"cache"
)

const commitsPerPage = 30

// commitHandler retrieves commit data or records a new commit.
//
// For GET requests it returns a Commit value for the specified
// packagePath and hash.
//
// For POST requests it reads a JSON-encoded Commit value from the request
// body and creates a new Commit entity. It also updates the "tip" Tag for
// each new commit at tip.
//
// This handler is used by a gobuilder process in -commit mode.
func commitHandler(r *http.Request) (interface{}, os.Error) {
	c := appengine.NewContext(r)
	com := new(Commit)

	if r.Method == "GET" {
		com.PackagePath = r.FormValue("packagePath")
		com.Hash = r.FormValue("hash")
		if err := datastore.Get(c, com.Key(c), com); err != nil {
			return nil, fmt.Errorf("getting Commit: %v", err)
		}
		return com, nil
	}
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	// POST request
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(com); err != nil {
		return nil, fmt.Errorf("decoding Body: %v", err)
	}
	if len(com.Desc) > maxDatastoreStringLen {
		com.Desc = com.Desc[:maxDatastoreStringLen]
	}
	if err := com.Valid(); err != nil {
		return nil, fmt.Errorf("validating Commit: %v", err)
	}
	defer cache.Tick(c)
	tx := func(c appengine.Context) os.Error {
		return addCommit(c, com)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}

// addCommit adds the Commit entity to the datastore and updates the tip Tag.
// It must be run inside a datastore transaction.
func addCommit(c appengine.Context, com *Commit) os.Error {
	var tc Commit // temp value so we don't clobber com
	err := datastore.Get(c, com.Key(c), &tc)
	if err != datastore.ErrNoSuchEntity {
		// if this commit is already in the datastore, do nothing
		if err == nil {
			return nil
		}
		return fmt.Errorf("getting Commit: %v", err)
	}
	// get the next commit number
	p, err := GetPackage(c, com.PackagePath)
	if err != nil {
		return fmt.Errorf("GetPackage: %v", err)
	}
	com.Num = p.NextNum
	p.NextNum++
	if _, err := datastore.Put(c, p.Key(c), p); err != nil {
		return fmt.Errorf("putting Package: %v", err)
	}
	// if this isn't the first Commit test the parent commit exists
	if com.Num > 0 {
		n, err := datastore.NewQuery("Commit").
			Filter("Hash =", com.ParentHash).
			Ancestor(p.Key(c)).
			Count(c)
		if err != nil {
			return fmt.Errorf("testing for parent Commit: %v", err)
		}
		if n == 0 {
			return os.NewError("parent commit not found")
		}
	}
	// update the tip Tag if this is the Go repo
	if p.Path == "" {
		t := &Tag{Kind: "tip", Hash: com.Hash}
		if _, err = datastore.Put(c, t.Key(c), t); err != nil {
			return fmt.Errorf("putting Tag: %v", err)
		}
	}
	// put the Commit
	if _, err = datastore.Put(c, com.Key(c), com); err != nil {
		return fmt.Errorf("putting Commit: %v", err)
	}
	return nil
}

// tagHandler records a new tag. It reads a JSON-encoded Tag value from the
// request body and updates the Tag entity for the Kind of tag provided.
//
// This handler is used by a gobuilder process in -commit mode.
func tagHandler(r *http.Request) (interface{}, os.Error) {
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	t := new(Tag)
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(t); err != nil {
		return nil, err
	}
	if err := t.Valid(); err != nil {
		return nil, err
	}
	c := appengine.NewContext(r)
	defer cache.Tick(c)
	_, err := datastore.Put(c, t.Key(c), t)
	return nil, err
}

// Todo is a todoHandler response.
type Todo struct {
	Kind string // "build-go-commit" or "build-package"
	Data interface{}
}

// todoHandler returns the next action to be performed by a builder.
// It expects "builder" and "kind" query parameters and returns a *Todo value.
// Multiple "kind" parameters may be specified.
func todoHandler(r *http.Request) (interface{}, os.Error) {
	c := appengine.NewContext(r)
	now := cache.Now(c)
	key := "build-todo-" + r.Form.Encode()
	var todo *Todo
	if cache.Get(r, now, key, &todo) {
		return todo, nil
	}
	var err os.Error
	builder := r.FormValue("builder")
	for _, kind := range r.Form["kind"] {
		var data interface{}
		switch kind {
		case "build-go-commit":
			data, err = buildTodo(c, builder, "", "")
		case "build-package":
			packagePath := r.FormValue("packagePath")
			goHash := r.FormValue("goHash")
			data, err = buildTodo(c, builder, packagePath, goHash)
		}
		if data != nil || err != nil {
			todo = &Todo{Kind: kind, Data: data}
			break
		}
	}
	if err == nil {
		cache.Set(r, now, key, todo)
	}
	return todo, err
}

// buildTodo returns the next Commit to be built (or nil if none available).
//
// If packagePath and goHash are empty, it scans the first 20 Go Commits in
// Num-descending order and returns the first one it finds that doesn't have a
// Result for this builder.
//
// If provided with non-empty packagePath and goHash args, it scans the first
// 20 Commits in Num-descending order for the specified packagePath and
// returns the first that doesn't have a Result for this builder and goHash.
func buildTodo(c appengine.Context, builder, packagePath, goHash string) (interface{}, os.Error) {
	p, err := GetPackage(c, packagePath)
	if err != nil {
		return nil, err
	}

	t := datastore.NewQuery("Commit").
		Ancestor(p.Key(c)).
		Limit(commitsPerPage).
		Order("-Num").
		Run(c)
	for {
		com := new(Commit)
		if _, err := t.Next(com); err == datastore.Done {
			break
		} else if err != nil {
			return nil, err
		}
		if com.Result(builder, goHash) == nil {
			return com, nil
		}
	}

	// Nothing left to do if this is a package (not the Go tree).
	if packagePath != "" {
		return nil, nil
	}

	// If there are no Go tree commits left to build,
	// see if there are any subrepo commits that need to be built at tip.
	// If so, ask the builder to build a go tree at the tip commit.
	// TODO(adg): do the same for "weekly" and "release" tags.

	tag, err := GetTag(c, "tip")
	if err != nil {
		return nil, err
	}

	// Check that this Go commit builds OK for this builder.
	// If not, don't re-build as the subrepos will never get built anyway.
	com, err := tag.Commit(c)
	if err != nil {
		return nil, err
	}
	if r := com.Result(builder, ""); r != nil && !r.OK {
		return nil, nil
	}

	pkgs, err := Packages(c, "subrepo")
	if err != nil {
		return nil, err
	}
	for _, pkg := range pkgs {
		com, err := pkg.LastCommit(c)
		if err != nil {
			c.Warningf("%v: no Commit found: %v", pkg, err)
			continue
		}
		if com.Result(builder, tag.Hash) == nil {
			return tag.Commit(c)
		}
	}

	return nil, nil
}

// packagesHandler returns a list of the non-Go Packages monitored
// by the dashboard.
func packagesHandler(r *http.Request) (interface{}, os.Error) {
	kind := r.FormValue("kind")
	c := appengine.NewContext(r)
	now := cache.Now(c)
	key := "build-packages-" + kind
	var p []*Package
	if cache.Get(r, now, key, &p) {
		return p, nil
	}
	p, err := Packages(c, kind)
	if err != nil {
		return nil, err
	}
	cache.Set(r, now, key, p)
	return p, nil
}

// resultHandler records a build result.
// It reads a JSON-encoded Result value from the request body,
// creates a new Result entity, and updates the relevant Commit entity.
// If the Log field is not empty, resultHandler creates a new Log entity
// and updates the LogHash field before putting the Commit entity.
func resultHandler(r *http.Request) (interface{}, os.Error) {
	if r.Method != "POST" {
		return nil, errBadMethod(r.Method)
	}

	c := appengine.NewContext(r)
	res := new(Result)
	defer r.Body.Close()
	if err := json.NewDecoder(r.Body).Decode(res); err != nil {
		return nil, fmt.Errorf("decoding Body: %v", err)
	}
	if err := res.Valid(); err != nil {
		return nil, fmt.Errorf("validating Result: %v", err)
	}
	defer cache.Tick(c)
	// store the Log text if supplied
	if len(res.Log) > 0 {
		hash, err := PutLog(c, res.Log)
		if err != nil {
			return nil, fmt.Errorf("putting Log: %v", err)
		}
		res.LogHash = hash
	}
	tx := func(c appengine.Context) os.Error {
		// check Package exists
		if _, err := GetPackage(c, res.PackagePath); err != nil {
			return fmt.Errorf("GetPackage: %v", err)
		}
		// put Result
		if _, err := datastore.Put(c, res.Key(c), res); err != nil {
			return fmt.Errorf("putting Result: %v", err)
		}
		// add Result to Commit
		com := &Commit{PackagePath: res.PackagePath, Hash: res.Hash}
		if err := com.AddResult(c, res); err != nil {
			return fmt.Errorf("AddResult: %v", err)
		}
		// Send build failure notifications, if necessary.
		// Note this must run after the call AddResult, which
		// populates the Commit's ResultData field.
		return notifyOnFailure(c, com, res.Builder)
	}
	return nil, datastore.RunInTransaction(c, tx, nil)
}

// logHandler displays log text for a given hash.
// It handles paths like "/log/hash".
func logHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-type", "text/plain")
	c := appengine.NewContext(r)
	hash := r.URL.Path[len("/log/"):]
	key := datastore.NewKey(c, "Log", hash, 0, nil)
	l := new(Log)
	if err := datastore.Get(c, key, l); err != nil {
		logErr(w, r, err)
		return
	}
	b, err := l.Text()
	if err != nil {
		logErr(w, r, err)
		return
	}
	w.Write(b)
}

type dashHandler func(*http.Request) (interface{}, os.Error)

type dashResponse struct {
	Response interface{}
	Error    string
}

// errBadMethod is returned by a dashHandler when
// the request has an unsuitable method.
type errBadMethod string

func (e errBadMethod) String() string {
	return "bad method: " + string(e)
}

// AuthHandler wraps a http.HandlerFunc with a handler that validates the
// supplied key and builder query parameters.
func AuthHandler(h dashHandler) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		c := appengine.NewContext(r)

		// Put the URL Query values into r.Form to avoid parsing the
		// request body when calling r.FormValue.
		r.Form = r.URL.Query()

		var err os.Error
		var resp interface{}

		// Validate key query parameter for POST requests only.
		key := r.FormValue("key")
		builder := r.FormValue("builder")
		if r.Method == "POST" && !validKey(c, key, builder) {
			err = os.NewError("invalid key: " + key)
		}

		// Call the original HandlerFunc and return the response.
		if err == nil {
			resp, err = h(r)
		}

		// Write JSON response.
		dashResp := &dashResponse{Response: resp}
		if err != nil {
			c.Errorf("%v", err)
			dashResp.Error = err.String()
		}
		w.Header().Set("Content-Type", "application/json")
		if err = json.NewEncoder(w).Encode(dashResp); err != nil {
			c.Criticalf("encoding response: %v", err)
		}
	}
}

func keyHandler(w http.ResponseWriter, r *http.Request) {
	builder := r.FormValue("builder")
	if builder == "" {
		logErr(w, r, os.NewError("must supply builder in query string"))
		return
	}
	c := appengine.NewContext(r)
	fmt.Fprint(w, builderKey(c, builder))
}

func init() {
	// admin handlers
	http.HandleFunc("/init", initHandler)
	http.HandleFunc("/key", keyHandler)

	// authenticated handlers
	http.HandleFunc("/commit", AuthHandler(commitHandler))
	http.HandleFunc("/packages", AuthHandler(packagesHandler))
	http.HandleFunc("/result", AuthHandler(resultHandler))
	http.HandleFunc("/tag", AuthHandler(tagHandler))
	http.HandleFunc("/todo", AuthHandler(todoHandler))

	// public handlers
	http.HandleFunc("/log/", logHandler)
}

func validHash(hash string) bool {
	// TODO(adg): correctly validate a hash
	return hash != ""
}

func validKey(c appengine.Context, key, builder string) bool {
	if appengine.IsDevAppServer() {
		return true
	}
	if key == secretKey(c) {
		return true
	}
	return key == builderKey(c, builder)
}

func builderKey(c appengine.Context, builder string) string {
	h := hmac.NewMD5([]byte(secretKey(c)))
	h.Write([]byte(builder))
	return fmt.Sprintf("%x", h.Sum())
}

func logErr(w http.ResponseWriter, r *http.Request, err os.Error) {
	appengine.NewContext(r).Errorf("Error: %v", err)
	w.WriteHeader(http.StatusInternalServerError)
	fmt.Fprint(w, "Error: ", err)
}
<|endoftext|>


<commit_before>package grpcutil

import (
	"google.golang.org/grpc"
)

type Dialer interface {
	Dial(address string) (*grpc.ClientConn, error)
	CloseConns() error
}

func NewDialer(opts ...grpc.DialOption) Dialer {
	return newDialer(opts...)
}
<commit_msg>Fix linting in grpcutil package<commit_after>package grpcutil

import (
	"google.golang.org/grpc"
)

// Dialer defines a grpc.ClientConn connection dialer.
type Dialer interface {
	Dial(address string) (*grpc.ClientConn, error)
	CloseConns() error
}

// NewDialer creates a Dialer.
func NewDialer(opts ...grpc.DialOption) Dialer {
	return newDialer(opts...)
}
<|endoftext|>


<commit_before>// Copyright 2016 The Upspin 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 dropbox

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"testing"
	"time"

	"golang.org/x/oauth2"

	"upspin.io/cloud/storage"
)

var (
	client      storage.Storage
	testDataStr = fmt.Sprintf("This is test at %v", time.Now())
	testData    = []byte(testDataStr)
	fileName    = fmt.Sprintf("test-file-%d", time.Now().Second())

	authCode   = flag.String("code", "", "dropbox authentication code")
	useDropbox = flag.Bool("use_dropbox", false, "enable to run dropbox tests; requires authentication code")
)

// This is more of a regression test as it uses the running cloud
// storage in prod. However, since Dropbox is always available, we accept
// to rely on it.
func TestPutGetAndDownload(t *testing.T) {
	err := client.Put(fileName, testData)
	if err != nil {
		t.Fatal(err)
	}
	data, err := client.Download(fileName)
	if err != nil {
		t.Fatal(err)
	}
	if string(data) != testDataStr {
		t.Errorf("Expected %q got %q", testDataStr, string(data))
	}
	// Check that Download yields the same data
	bytes, err := client.Download(fileName)
	if err != nil {
		t.Fatal(err)
	}
	if string(bytes) != testDataStr {
		t.Errorf("Expected %q got %q", testDataStr, string(bytes))
	}
}

func TestDelete(t *testing.T) {
	err := client.Put(fileName, testData)
	if err != nil {
		t.Fatal(err)
	}
	err = client.Delete(fileName)
	if err != nil {
		t.Fatalf("Expected no errors, got %v", err)
	}
	// Test the side effect after Delete.
	_, err = client.Download(fileName)
	if err == nil {
		t.Fatal("Expected an error, but got none")
	}
}

func TestMain(m *testing.M) {
	flag.Parse()
	if !*useDropbox {
		log.Printf(`
cloud/storage/dropbox: skipping test as it requires Dropbox access. To enable this test,
on the first run get an authentication code by visiting:

https://www.dropbox.com/oauth2/authorize?client_id=ufhy41x7g4obzqz&response_type=code

Copy the code and pass it by the -code flag. This will get an oAuth2 access token, store
it and reuse it in successive test calls.

`)
		os.Exit(0)
	}

	t, err := token()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error in getting oauth2 token: %v.\n", err)
	}

	// Create client that writes to your Dropbox.
	client, err = storage.Dial("Dropbox",
		storage.WithKeyValue("token", t))
	if err != nil {
		log.Fatalf("cloud/storage/dropbox: couldn't set up client: %v", err)
	}

	code := m.Run()

	os.Exit(code)
}

func token() (string, error) {
	tokenFile := path.Join(os.TempDir(), "upspin-test-token")

	token, _ := ioutil.ReadFile(tokenFile)
	if err == nil {
		return string(token), nil
	}

	conf := &oauth2.Config{
		ClientID:     "ufhy41x7g4obzqz",
		ClientSecret: "vuhgmucmxm93dp5",
		Endpoint: oauth2.Endpoint{
			AuthURL:  "https://www.dropbox.com/oauth2/authorize",
			TokenURL: "https://api.dropboxapi.com/oauth2/token",
		},
	}

	tok, err := conf.Exchange(oauth2.NoContext, *authCode)
	if err != nil {
		return "", err
	}

	if err := ioutil.WriteFile(tokenFile, []byte(tok.AccessToken), 0600); err != nil {
		return "", err
	}

	return tok.AccessToken, nil
}
<commit_msg>cloud/storage/dropbox: fix build<commit_after>// Copyright 2016 The Upspin 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 dropbox

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path"
	"testing"
	"time"

	"golang.org/x/oauth2"

	"upspin.io/cloud/storage"
)

var (
	client      storage.Storage
	testDataStr = fmt.Sprintf("This is test at %v", time.Now())
	testData    = []byte(testDataStr)
	fileName    = fmt.Sprintf("test-file-%d", time.Now().Second())

	authCode   = flag.String("code", "", "dropbox authentication code")
	useDropbox = flag.Bool("use_dropbox", false, "enable to run dropbox tests; requires authentication code")
)

// This is more of a regression test as it uses the running cloud
// storage in prod. However, since Dropbox is always available, we accept
// to rely on it.
func TestPutGetAndDownload(t *testing.T) {
	err := client.Put(fileName, testData)
	if err != nil {
		t.Fatal(err)
	}
	data, err := client.Download(fileName)
	if err != nil {
		t.Fatal(err)
	}
	if string(data) != testDataStr {
		t.Errorf("Expected %q got %q", testDataStr, string(data))
	}
	// Check that Download yields the same data
	bytes, err := client.Download(fileName)
	if err != nil {
		t.Fatal(err)
	}
	if string(bytes) != testDataStr {
		t.Errorf("Expected %q got %q", testDataStr, string(bytes))
	}
}

func TestDelete(t *testing.T) {
	err := client.Put(fileName, testData)
	if err != nil {
		t.Fatal(err)
	}
	err = client.Delete(fileName)
	if err != nil {
		t.Fatalf("Expected no errors, got %v", err)
	}
	// Test the side effect after Delete.
	_, err = client.Download(fileName)
	if err == nil {
		t.Fatal("Expected an error, but got none")
	}
}

func TestMain(m *testing.M) {
	flag.Parse()
	if !*useDropbox {
		log.Printf(`
cloud/storage/dropbox: skipping test as it requires Dropbox access. To enable this test,
on the first run get an authentication code by visiting:

https://www.dropbox.com/oauth2/authorize?client_id=ufhy41x7g4obzqz&response_type=code

Copy the code and pass it by the -code flag. This will get an oAuth2 access token, store
it and reuse it in successive test calls.

`)
		os.Exit(0)
	}

	t, err := token()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error in getting oauth2 token: %v.\n", err)
	}

	// Create client that writes to your Dropbox.
	client, err = storage.Dial("Dropbox",
		storage.WithKeyValue("token", t))
	if err != nil {
		log.Fatalf("cloud/storage/dropbox: couldn't set up client: %v", err)
	}

	code := m.Run()

	os.Exit(code)
}

func token() (string, error) {
	tokenFile := path.Join(os.TempDir(), "upspin-test-token")

	token, err := ioutil.ReadFile(tokenFile)
	if err == nil {
		return string(token), nil
	}

	conf := &oauth2.Config{
		ClientID:     "ufhy41x7g4obzqz",
		ClientSecret: "vuhgmucmxm93dp5",
		Endpoint: oauth2.Endpoint{
			AuthURL:  "https://www.dropbox.com/oauth2/authorize",
			TokenURL: "https://api.dropboxapi.com/oauth2/token",
		},
	}

	tok, err := conf.Exchange(oauth2.NoContext, *authCode)
	if err != nil {
		return "", err
	}

	if err := ioutil.WriteFile(tokenFile, []byte(tok.AccessToken), 0600); err != nil {
		return "", err
	}

	return tok.AccessToken, nil
}
<|endoftext|>


<commit_before>// +build libipmctl

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

package machine

// #cgo pkg-config: libipmctl
// #include <nvm_management.h>
import "C"
import (
	"fmt"

	"k8s.io/klog"
)

// GetNVMAvgPowerBudget retrieves configured power budget
// (in watts)for NVM devices. When libipmct is not available
// zero is returned.
func GetNVMAvgPowerBudget() (uint, error) {
	// Initialize libipmctl library.
	err := C.nvm_init()
	if err != C.NVM_SUCCESS {
		klog.Warningf("libipmctl initialization failed with status %d", err)
		return 0, fmt.Errorf("libipmctl initialization failed with status %d", err)
	}
	defer C.nvm_uninit()

	// Get number of devices on the platform
	// see: https://github.com/intel/ipmctl/blob/v01.00.00.3497/src/os/nvm_api/nvm_management.h#L1478
	var count C.uint
	err = C.nvm_get_number_of_devices(&count)
	if err != C.NVM_SUCCESS {
		klog.Warningf("Unable to get number of NVM devices. Status code: %d", err)
		return uint(0), fmt.Errorf("Unable to get number of NVM devices. Status code: %d", err)
	}

	// Load basic device information for all the devices
	// to obtain UID of the first one.
	var devices = make([]C.struct_device_discovery, count)
	err = C.nvm_get_devices(&devices[0], C.uchar(count))
	if err != C.NVM_SUCCESS {
		klog.Warningf("Unable to get all NVM devices. Status code: %d", err)
		return uint(0), fmt.Errorf("Unable to get all NVM devices. Status code: %d", err)
	}

	// Power budget is same for all the devices
	// so we can rely on any of them.
	var device C.struct_device_details
	err = C.nvm_get_device_details(&devices[0].uid[0], &device)
	if err != C.NVM_SUCCESS {
		uid := C.GoString(&devices[0].uid[0])
		klog.Warningf("Unable to get details of NVM device %q. Status code: %d", uid, err)
		return uint(0), fmt.Errorf("Unable to get details of NVM device %q. Status code: %d", uid, err)
	}

	return uint(device.avg_power_budget / 1000), nil
}
<commit_msg>uint must be returned<commit_after>// +build libipmctl

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

package machine

// #cgo pkg-config: libipmctl
// #include <nvm_management.h>
import "C"
import (
	"fmt"

	"k8s.io/klog"
)

// GetNVMAvgPowerBudget retrieves configured power budget
// (in watts)for NVM devices. When libipmct is not available
// zero is returned.
func GetNVMAvgPowerBudget() (uint, error) {
	// Initialize libipmctl library.
	err := C.nvm_init()
	if err != C.NVM_SUCCESS {
		klog.Warningf("libipmctl initialization failed with status %d", err)
		return uint(0), fmt.Errorf("libipmctl initialization failed with status %d", err)
	}
	defer C.nvm_uninit()

	// Get number of devices on the platform
	// see: https://github.com/intel/ipmctl/blob/v01.00.00.3497/src/os/nvm_api/nvm_management.h#L1478
	var count C.uint
	err = C.nvm_get_number_of_devices(&count)
	if err != C.NVM_SUCCESS {
		klog.Warningf("Unable to get number of NVM devices. Status code: %d", err)
		return uint(0), fmt.Errorf("Unable to get number of NVM devices. Status code: %d", err)
	}

	// Load basic device information for all the devices
	// to obtain UID of the first one.
	var devices = make([]C.struct_device_discovery, count)
	err = C.nvm_get_devices(&devices[0], C.uchar(count))
	if err != C.NVM_SUCCESS {
		klog.Warningf("Unable to get all NVM devices. Status code: %d", err)
		return uint(0), fmt.Errorf("Unable to get all NVM devices. Status code: %d", err)
	}

	// Power budget is same for all the devices
	// so we can rely on any of them.
	var device C.struct_device_details
	err = C.nvm_get_device_details(&devices[0].uid[0], &device)
	if err != C.NVM_SUCCESS {
		uid := C.GoString(&devices[0].uid[0])
		klog.Warningf("Unable to get details of NVM device %q. Status code: %d", uid, err)
		return uint(0), fmt.Errorf("Unable to get details of NVM device %q. Status code: %d", uid, err)
	}

	return uint(device.avg_power_budget / 1000), nil
}
<|endoftext|>


<commit_before>/*
Copyright 2019 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 app

import (
	"testing"
)

func TestGetServiceIPAndRanges(t *testing.T) {
	tests := []struct {
		body                    string
		apiServerServiceIP      string
		primaryServiceIPRange   string
		secondaryServiceIPRange string
		expectedError           bool
	}{
		{"", "10.0.0.1", "10.0.0.0/24", "<nil>", false},
		{"192.0.2.1/24", "192.0.2.1", "192.0.2.0/24", "<nil>", false},
		{"192.0.2.1/24,192.168.128.0/17", "192.0.2.1", "192.0.2.0/24", "192.168.128.0/17", false},
		{"192.0.2.1/30,192.168.128.0/17", "<nil>", "<nil>", "<nil>", true},
	}

	for _, test := range tests {
		apiServerServiceIP, primaryServiceIPRange, secondaryServiceIPRange, err := getServiceIPAndRanges(test.body)

		if apiServerServiceIP.String() != test.apiServerServiceIP {
			t.Errorf("expected apiServerServiceIP: %s, got: %s", test.apiServerServiceIP, apiServerServiceIP.String())
		}

		if primaryServiceIPRange.String() != test.primaryServiceIPRange {
			t.Errorf("expected primaryServiceIPRange: %s, got: %s", test.primaryServiceIPRange, primaryServiceIPRange.String())
		}

		if secondaryServiceIPRange.String() != test.secondaryServiceIPRange {
			t.Errorf("expected secondaryServiceIPRange: %s, got: %s", test.secondaryServiceIPRange, secondaryServiceIPRange.String())
		}

		if (err == nil) == test.expectedError {
			t.Errorf("expected err to be: %t, but it was %t", test.expectedError, !test.expectedError)
		}
	}
}
<commit_msg>test: Add service cluster IP range unit test<commit_after>/*
Copyright 2019 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 app

import (
	"testing"
)

func TestGetServiceIPAndRanges(t *testing.T) {
	tests := []struct {
		body                    string
		apiServerServiceIP      string
		primaryServiceIPRange   string
		secondaryServiceIPRange string
		expectedError           bool
	}{
		{"", "10.0.0.1", "10.0.0.0/24", "<nil>", false},
		{"192.0.2.1/24", "192.0.2.1", "192.0.2.0/24", "<nil>", false},
		{"192.0.2.1/24,192.168.128.0/17", "192.0.2.1", "192.0.2.0/24", "192.168.128.0/17", false},
		// Dual stack IPv4/IPv6
		{"192.0.2.1/24,2001:db2:1:3:4::1/112", "192.0.2.1", "192.0.2.0/24", "2001:db2:1:3:4::/112", false},
		// Dual stack IPv6/IPv4
		{"2001:db2:1:3:4::1/112,192.0.2.1/24", "2001:db2:1:3:4::1", "2001:db2:1:3:4::/112", "192.0.2.0/24", false},

		{"192.0.2.1/30,192.168.128.0/17", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[0] IPv4 mask
		{"192.0.2.1/33,192.168.128.0/17", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[1] IPv4 mask
		{"192.0.2.1/24,192.168.128.0/33", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[0] IPv6 mask
		{"2001:db2:1:3:4::1/129,192.0.2.1/24", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[1] IPv6 mask
		{"192.0.2.1/24,2001:db2:1:3:4::1/129", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[0] missing IPv4 mask
		{"192.0.2.1,192.168.128.0/17", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[1] missing IPv4 mask
		{"192.0.2.1/24,192.168.128.1", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[0] missing IPv6 mask
		{"2001:db2:1:3:4::1,192.0.2.1/24", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[1] missing IPv6 mask
		{"192.0.2.1/24,2001:db2:1:3:4::1", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[0] IP address format
		{"bad.ip.range,192.168.0.2/24", "<nil>", "<nil>", "<nil>", true},
		// Invalid ip range[1] IP address format
		{"192.168.0.2/24,bad.ip.range", "<nil>", "<nil>", "<nil>", true},
	}

	for _, test := range tests {
		apiServerServiceIP, primaryServiceIPRange, secondaryServiceIPRange, err := getServiceIPAndRanges(test.body)

		if apiServerServiceIP.String() != test.apiServerServiceIP {
			t.Errorf("expected apiServerServiceIP: %s, got: %s", test.apiServerServiceIP, apiServerServiceIP.String())
		}

		if primaryServiceIPRange.String() != test.primaryServiceIPRange {
			t.Errorf("expected primaryServiceIPRange: %s, got: %s", test.primaryServiceIPRange, primaryServiceIPRange.String())
		}

		if secondaryServiceIPRange.String() != test.secondaryServiceIPRange {
			t.Errorf("expected secondaryServiceIPRange: %s, got: %s", test.secondaryServiceIPRange, secondaryServiceIPRange.String())
		}

		if (err == nil) == test.expectedError {
			t.Errorf("expected err to be: %t, but it was %t", test.expectedError, !test.expectedError)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The etcd-operator 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 main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"os"

	api "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2"
	"github.com/coreos/etcd-operator/pkg/backup"
	"github.com/coreos/etcd-operator/pkg/backup/env"
	"github.com/coreos/etcd-operator/pkg/util/constants"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil"
	"github.com/coreos/etcd-operator/version"

	"github.com/sirupsen/logrus"
)

var (
	masterHost      string
	clusterName     string
	listenAddr      string
	namespace       string
	serveBackupOnly bool

	printVersion bool
)

func init() {
	flag.StringVar(&masterHost, "master", "", "API Server addr, e.g. ' - NOT RECOMMENDED FOR PRODUCTION - http://127.0.0.1:8080'. Omit parameter to run in on-cluster mode and utilize the service account token.")
	flag.StringVar(&clusterName, "etcd-cluster", "", "")
	flag.StringVar(&listenAddr, "listen", "0.0.0.0:19999", "")
	flag.BoolVar(&printVersion, "version", false, "Show version and quit")
	flag.BoolVar(&serveBackupOnly, "serve-backup-only", false, "feature gate for simpler service to serve backup only")

	flag.Parse()

	namespace = os.Getenv(constants.EnvOperatorPodNamespace)
	if len(namespace) == 0 {
		namespace = "default"
	}
}

func main() {
	if printVersion {
		fmt.Println("etcd-backup", version.Version)
		os.Exit(0)
	}

	if len(clusterName) == 0 {
		panic("clusterName not set")
	}

	bp, tls, err := parseSpecsFromEnv()
	if err != nil {
		logrus.Fatalf("failed to parse specs from environment: %v", err)
	}
	bc := &backup.BackupControllerConfig{
		Kclient:      k8sutil.MustNewKubeClient(),
		ListenAddr:   listenAddr,
		ClusterName:  clusterName,
		Namespace:    namespace,
		TLS:          tls,
		BackupPolicy: bp,
	}

	bk, err := backup.NewBackupController(bc)
	if err != nil {
		logrus.Fatalf("failed to create backup sidecar: %v", err)
	}

	ctx := context.Background()
	go bk.StartHTTP()
	if !serveBackupOnly {
		go bk.Run()
	}

	<-ctx.Done()
}

// parseSpecsFromEnv parses ClusterSpec and BackupSpec from env if any.
func parseSpecsFromEnv() (*api.BackupPolicy, *api.TLSPolicy, error) {
	var (
		bp api.BackupPolicy
		cs api.ClusterSpec
	)

	sps := os.Getenv(env.ClusterSpec)
	if err := json.Unmarshal([]byte(sps), &cs); err != nil {
		return nil, nil, fmt.Errorf("failed to parse cluster spec (%s): %v", sps, err)
	}

	if ebs := os.Getenv(env.BackupSpec); len(ebs) != 0 {
		var bs api.BackupSpec
		if err := json.Unmarshal([]byte(ebs), &bs); err != nil {
			return nil, nil, fmt.Errorf("failed to parse backup spec (%s): %v", ebs, err)
		}
		bp.StorageType = api.BackupStorageType(bs.StorageType)
		switch bp.StorageType {
		case api.BackupStorageTypeS3:
			bp.StorageSource.S3 = bs.BackupStorageSource.S3
		default:
			return nil, nil, fmt.Errorf("unknown backup type (%v)", bp.StorageType)
		}
	} else {
		if cs.Backup == nil {
			return nil, nil, fmt.Errorf("backup policy not found")
		}
		bp = *cs.Backup
	}

	return &bp, cs.TLS, nil
}
<commit_msg>backup: set serveBackupOnly to true only when backup spec exists<commit_after>// Copyright 2016 The etcd-operator 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 main

import (
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"os"

	api "github.com/coreos/etcd-operator/pkg/apis/etcd/v1beta2"
	"github.com/coreos/etcd-operator/pkg/backup"
	"github.com/coreos/etcd-operator/pkg/backup/env"
	"github.com/coreos/etcd-operator/pkg/util/constants"
	"github.com/coreos/etcd-operator/pkg/util/k8sutil"
	"github.com/coreos/etcd-operator/version"

	"github.com/sirupsen/logrus"
)

var (
	masterHost  string
	clusterName string
	listenAddr  string
	namespace   string
	// serveBackupOnly flag indicates that this backup service only serves
	// http backup requests.
	serveBackupOnly bool

	printVersion bool
)

func init() {
	flag.StringVar(&masterHost, "master", "", "API Server addr, e.g. ' - NOT RECOMMENDED FOR PRODUCTION - http://127.0.0.1:8080'. Omit parameter to run in on-cluster mode and utilize the service account token.")
	flag.StringVar(&clusterName, "etcd-cluster", "", "")
	flag.StringVar(&listenAddr, "listen", "0.0.0.0:19999", "")
	flag.BoolVar(&printVersion, "version", false, "Show version and quit")

	flag.Parse()

	namespace = os.Getenv(constants.EnvOperatorPodNamespace)
	if len(namespace) == 0 {
		namespace = "default"
	}
}

func main() {
	if printVersion {
		fmt.Println("etcd-backup", version.Version)
		os.Exit(0)
	}

	if len(clusterName) == 0 {
		panic("clusterName not set")
	}

	bp, tls, err := parseSpecsFromEnv()
	if err != nil {
		logrus.Fatalf("failed to parse specs from environment: %v", err)
	}
	bc := &backup.BackupControllerConfig{
		Kclient:      k8sutil.MustNewKubeClient(),
		ListenAddr:   listenAddr,
		ClusterName:  clusterName,
		Namespace:    namespace,
		TLS:          tls,
		BackupPolicy: bp,
	}

	bk, err := backup.NewBackupController(bc)
	if err != nil {
		logrus.Fatalf("failed to create backup sidecar: %v", err)
	}

	ctx := context.Background()
	go bk.StartHTTP()
	if !serveBackupOnly {
		go bk.Run()
	}

	<-ctx.Done()
}

// parseSpecsFromEnv parses ClusterSpec and BackupSpec from env if any.
func parseSpecsFromEnv() (*api.BackupPolicy, *api.TLSPolicy, error) {
	var (
		bp api.BackupPolicy
		cs api.ClusterSpec
	)

	sps := os.Getenv(env.ClusterSpec)
	if err := json.Unmarshal([]byte(sps), &cs); err != nil {
		return nil, nil, fmt.Errorf("failed to parse cluster spec (%s): %v", sps, err)
	}

	if ebs := os.Getenv(env.BackupSpec); len(ebs) != 0 {
		// set serveBackupOnly to true if backup spec exists.
		serveBackupOnly = true
		var bs api.BackupSpec
		if err := json.Unmarshal([]byte(ebs), &bs); err != nil {
			return nil, nil, fmt.Errorf("failed to parse backup spec (%s): %v", ebs, err)
		}
		bp.StorageType = api.BackupStorageType(bs.StorageType)
		switch bp.StorageType {
		case api.BackupStorageTypeS3:
			bp.StorageSource.S3 = bs.BackupStorageSource.S3
		default:
			return nil, nil, fmt.Errorf("unknown backup type (%v)", bp.StorageType)
		}
	} else {
		if cs.Backup == nil {
			return nil, nil, fmt.Errorf("backup policy not found")
		}
		bp = *cs.Backup
	}

	return &bp, cs.TLS, nil
}
<|endoftext|>


<commit_before>// bootdb bootstraps the database to a minimal functional state
//
//   user
//   auth token
//   project (with membership)
//   admin node
//   manager node (with keys)
//   issuer node (with keys)
//   genesis block
package main

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/btcsuite/btcutil/hdkeychain"
	"golang.org/x/net/context"

	"chain/api/appdb"
	"chain/database/pg"
	"chain/env"
	"chain/errors"
	"chain/fedchain-sandbox/hdkey"
	"chain/fedchain/bc"
	"chain/log"
)

// config vars
var dbURL = env.String("DB_URL", "postgres:///api?sslmode=disable")

var (
	db     *sql.DB
	logbuf bytes.Buffer
)

func main() {
	env.Parse()
	log.SetOutput(&logbuf)

	if len(os.Args) != 3 {
		fatal("usage: bootdb email password")
	}

	sql.Register("schemadb", pg.SchemaDriver("bootdb"))
	db, err := sql.Open("schemadb", *dbURL)
	if err != nil {
		fatal(err)
	}

	appdb.Init(db)
	ctx := pg.NewContext(context.Background(), db)

	u, err := appdb.CreateUser(ctx, os.Args[1], os.Args[2])
	if err != nil {
		fatal(err)
	}

	tok, err := appdb.CreateAuthToken(ctx, u.ID, "api", nil)
	if err != nil {
		fatal(err)
	}

	proj, err := appdb.CreateProject(ctx, "proj", u.ID)
	if err != nil {
		fatal(err)
	}

	adminNode, err := appdb.InsertAdminNode(ctx, proj.ID, "admin")
	if err != nil {
		fatal(err)
	}

	mpub, mpriv := genKey()
	mn, err := appdb.InsertManagerNode(ctx, proj.ID, "manager", mpub, mpriv)
	if err != nil {
		fatal(err)
	}

	ipub, ipriv := genKey()
	in, err := appdb.InsertIssuerNode(ctx, proj.ID, "issuer", ipub, ipriv)
	if err != nil {
		fatal(err)
	}

	block := &bc.Block{
		BlockHeader: bc.BlockHeader{
			Version:   bc.NewBlockVersion,
			Timestamp: uint64(time.Now().Unix()),
		},
	}
	const q = `
		INSERT INTO blocks (block_hash, height, data)
		VALUES ($1, $2, $3)
	`
	_, err = db.Exec(q, block.Hash(), block.Height, block)
	if err != nil {
		fatal(err)
	}

	result, _ := json.MarshalIndent(map[string]string{
		"userID":           u.ID,
		"tokenID":          tok.ID,
		"tokenSecret":      tok.Secret,
		"projectID":        proj.ID,
		"adminNodeID":      adminNode.ID,
		"managerXPRV":      mpriv[0].String(),
		"managerNodeID":    mn.ID,
		"issuerXPRV":       ipriv[0].String(),
		"issuerNodeID":     in.ID,
		"genesisBlockHash": block.Hash().String(),
	}, "", "  ")
	fmt.Printf("%s\n", result)
}

func genKey() (pub, priv []*hdkey.XKey) {
	pk, sk, err := newKey()
	if err != nil {
		fatal(err)
	}
	pub = append(pub, pk)
	priv = append(priv, sk)
	return
}

func newKey() (pub, priv *hdkey.XKey, err error) {
	seed, err := hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen)
	if err != nil {
		return nil, nil, errors.Wrap(err, "generating key seed")
	}
	xprv, err := hdkeychain.NewMaster(seed)
	if err != nil {
		return nil, nil, errors.Wrap(err, "creating root xprv")
	}
	xpub, err := xprv.Neuter()
	if err != nil {
		return nil, nil, errors.Wrap(err, "getting root xpub")
	}
	return &hdkey.XKey{ExtendedKey: *xpub}, &hdkey.XKey{ExtendedKey: *xprv}, nil
}

func fatal(v interface{}) {
	io.Copy(os.Stderr, &logbuf)
	panic(v)
}
<commit_msg>cmd/bootdb: run in a transaction<commit_after>// bootdb bootstraps the database to a minimal functional state
//
//   user
//   auth token
//   project (with membership)
//   admin node
//   manager node (with keys)
//   issuer node (with keys)
//   genesis block
package main

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"time"

	"github.com/btcsuite/btcutil/hdkeychain"
	"golang.org/x/net/context"

	"chain/api/appdb"
	"chain/database/pg"
	"chain/env"
	"chain/errors"
	"chain/fedchain-sandbox/hdkey"
	"chain/fedchain/bc"
	"chain/log"
)

// config vars
var dbURL = env.String("DB_URL", "postgres:///api?sslmode=disable")

var (
	db     *sql.DB
	logbuf bytes.Buffer
)

func main() {
	env.Parse()
	log.SetOutput(&logbuf)

	if len(os.Args) != 3 {
		fatal("usage: bootdb email password")
	}

	sql.Register("schemadb", pg.SchemaDriver("bootdb"))
	db, err := sql.Open("schemadb", *dbURL)
	if err != nil {
		fatal(err)
	}

	appdb.Init(db)
	ctx := pg.NewContext(context.Background(), db)
	dbtx, ctx, err := pg.Begin(ctx)
	if err != nil {
		fatal("begin")
	}
	defer dbtx.Rollback()

	u, err := appdb.CreateUser(ctx, os.Args[1], os.Args[2])
	if err != nil {
		fatal(err)
	}

	tok, err := appdb.CreateAuthToken(ctx, u.ID, "api", nil)
	if err != nil {
		fatal(err)
	}

	proj, err := appdb.CreateProject(ctx, "proj", u.ID)
	if err != nil {
		fatal(err)
	}

	adminNode, err := appdb.InsertAdminNode(ctx, proj.ID, "admin")
	if err != nil {
		fatal(err)
	}

	mpub, mpriv := genKey()
	mn, err := appdb.InsertManagerNode(ctx, proj.ID, "manager", mpub, mpriv)
	if err != nil {
		fatal(err)
	}

	ipub, ipriv := genKey()
	in, err := appdb.InsertIssuerNode(ctx, proj.ID, "issuer", ipub, ipriv)
	if err != nil {
		fatal(err)
	}

	block := &bc.Block{
		BlockHeader: bc.BlockHeader{
			Version:   bc.NewBlockVersion,
			Timestamp: uint64(time.Now().Unix()),
		},
	}
	const q = `
		INSERT INTO blocks (block_hash, height, data)
		VALUES ($1, $2, $3)
	`
	_, err = pg.FromContext(ctx).Exec(q, block.Hash(), block.Height, block)
	if err != nil {
		fatal(err)
	}

	err = dbtx.Commit()
	if err != nil {
		fatal(err)
	}

	result, _ := json.MarshalIndent(map[string]string{
		"userID":           u.ID,
		"tokenID":          tok.ID,
		"tokenSecret":      tok.Secret,
		"projectID":        proj.ID,
		"adminNodeID":      adminNode.ID,
		"managerXPRV":      mpriv[0].String(),
		"managerNodeID":    mn.ID,
		"issuerXPRV":       ipriv[0].String(),
		"issuerNodeID":     in.ID,
		"genesisBlockHash": block.Hash().String(),
	}, "", "  ")
	fmt.Printf("%s\n", result)
}

func genKey() (pub, priv []*hdkey.XKey) {
	pk, sk, err := newKey()
	if err != nil {
		fatal(err)
	}
	pub = append(pub, pk)
	priv = append(priv, sk)
	return
}

func newKey() (pub, priv *hdkey.XKey, err error) {
	seed, err := hdkeychain.GenerateSeed(hdkeychain.RecommendedSeedLen)
	if err != nil {
		return nil, nil, errors.Wrap(err, "generating key seed")
	}
	xprv, err := hdkeychain.NewMaster(seed)
	if err != nil {
		return nil, nil, errors.Wrap(err, "creating root xprv")
	}
	xpub, err := xprv.Neuter()
	if err != nil {
		return nil, nil, errors.Wrap(err, "getting root xpub")
	}
	return &hdkey.XKey{ExtendedKey: *xpub}, &hdkey.XKey{ExtendedKey: *xprv}, nil
}

func fatal(v interface{}) {
	io.Copy(os.Stderr, &logbuf)
	panic(v)
}
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	"github.com/projectatomic/buildah/imagebuildah"
	buildahcli "github.com/projectatomic/buildah/pkg/cli"
	"github.com/projectatomic/buildah/pkg/parse"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

var (
	budDescription = "Builds an OCI image using instructions in one or more Dockerfiles."
	budCommand     = cli.Command{
		Name:                   "build-using-dockerfile",
		Aliases:                []string{"bud"},
		Usage:                  "Build an image using instructions in a Dockerfile",
		Description:            budDescription,
		Flags:                  append(append(buildahcli.BudFlags, buildahcli.LayerFlags...), buildahcli.FromAndBudFlags...),
		Action:                 budCmd,
		ArgsUsage:              "CONTEXT-DIRECTORY | URL",
		SkipArgReorder:         true,
		UseShortOptionHandling: true,
	}
)

func getDockerfiles(files []string) []string {
	var dockerfiles []string
	for _, f := range files {
		if f == "-" {
			dockerfiles = append(dockerfiles, "/dev/stdin")
		} else {
			dockerfiles = append(dockerfiles, f)
		}
	}
	return dockerfiles
}

func budCmd(c *cli.Context) error {
	output := ""
	tags := []string{}
	if c.IsSet("tag") || c.IsSet("t") {
		tags = c.StringSlice("tag")
		if len(tags) > 0 {
			output = tags[0]
			tags = tags[1:]
		}
	}
	pullPolicy := imagebuildah.PullNever
	if c.BoolT("pull") {
		pullPolicy = imagebuildah.PullIfMissing
	}
	if c.Bool("pull-always") {
		pullPolicy = imagebuildah.PullAlways
	}

	args := make(map[string]string)
	if c.IsSet("build-arg") {
		for _, arg := range c.StringSlice("build-arg") {
			av := strings.SplitN(arg, "=", 2)
			if len(av) > 1 {
				args[av[0]] = av[1]
			} else {
				delete(args, av[0])
			}
		}
	}

	dockerfiles := getDockerfiles(c.StringSlice("file"))
	format, err := getFormat(c)
	if err != nil {
		return err
	}
	layers := buildahcli.UseLayers()
	if c.IsSet("layers") {
		layers = c.Bool("layers")
	}
	contextDir := ""
	cliArgs := c.Args()
	if len(cliArgs) == 0 {
		return errors.Errorf("no context directory or URL specified")
	}
	// The context directory could be a URL.  Try to handle that.
	tempDir, subDir, err := imagebuildah.TempDirForURL("", "buildah", cliArgs[0])
	if err != nil {
		return errors.Wrapf(err, "error prepping temporary context directory")
	}
	if tempDir != "" {
		// We had to download it to a temporary directory.
		// Delete it later.
		defer func() {
			if err = os.RemoveAll(tempDir); err != nil {
				logrus.Errorf("error removing temporary directory %q: %v", contextDir, err)
			}
		}()
		contextDir = filepath.Join(tempDir, subDir)
	} else {
		// Nope, it was local.  Use it as is.
		absDir, err := filepath.Abs(cliArgs[0])
		if err != nil {
			return errors.Wrapf(err, "error determining path to directory %q", cliArgs[0])
		}
		contextDir = absDir
	}
	cliArgs = cliArgs.Tail()

	if err := buildahcli.VerifyFlagsArgsOrder(cliArgs); err != nil {
		return err
	}
	if len(dockerfiles) == 0 {
		dockerfiles = append(dockerfiles, filepath.Join(contextDir, "Dockerfile"))
	}
	if err := parse.ValidateFlags(c, buildahcli.BudFlags); err != nil {
		return err
	}
	if err := parse.ValidateFlags(c, buildahcli.LayerFlags); err != nil {
		return err
	}
	if err := parse.ValidateFlags(c, buildahcli.FromAndBudFlags); err != nil {
		return err
	}
	var stdin, stdout, stderr, reporter *os.File
	stdin = os.Stdin
	stdout = os.Stdout
	stderr = os.Stderr
	reporter = os.Stderr
	if c.IsSet("logfile") {
		f, err := os.OpenFile(c.String("logfile"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
		if err != nil {
			return errors.Errorf("error opening logfile %q: %v", c.String("logfile"), err)
		}
		defer f.Close()
		logrus.SetOutput(f)
		stdout = f
		stderr = f
		reporter = f
	}

	store, err := getStore(c)
	if err != nil {
		return err
	}

	systemContext, err := parse.SystemContextFromOptions(c)
	if err != nil {
		return errors.Wrapf(err, "error building system context")
	}

	isolation, err := parse.IsolationOption(c)
	if err != nil {
		return err
	}

	runtimeFlags := []string{}
	for _, arg := range c.StringSlice("runtime-flag") {
		runtimeFlags = append(runtimeFlags, "--"+arg)
	}

	commonOpts, err := parse.CommonBuildOptions(c)
	if err != nil {
		return err
	}

	if c.IsSet("layers") && c.IsSet("no-cache") {
		return errors.Errorf("can only set one of 'layers' or 'no-cache'")
	}

	if (c.IsSet("rm") || c.IsSet("force-rm")) && (!c.IsSet("layers") && !c.IsSet("no-cache")) {
		return errors.Errorf("'rm' and 'force-rm' can only be set with either 'layers' or 'no-cache'")
	}

	if c.IsSet("cache-from") {
		logrus.Debugf("build caching not enabled so --cache-from flag has no effect")
	}

	if c.IsSet("compress") {
		logrus.Debugf("--compress option specified but is ignored")
	}

	if c.IsSet("disable-content-trust") {
		logrus.Debugf("--disable-content-trust option specified but is ignored")
	}

	namespaceOptions, networkPolicy, err := parse.NamespaceOptions(c)
	if err != nil {
		return errors.Wrapf(err, "error parsing namespace-related options")
	}
	usernsOption, idmappingOptions, err := parse.IDMappingOptions(c)
	if err != nil {
		return errors.Wrapf(err, "error parsing ID mapping options")
	}
	namespaceOptions.AddOrReplace(usernsOption...)

	options := imagebuildah.BuildOptions{
		ContextDirectory:        contextDir,
		PullPolicy:              pullPolicy,
		Compression:             imagebuildah.Gzip,
		Quiet:                   c.Bool("quiet"),
		SignaturePolicyPath:     c.String("signature-policy"),
		Args:                    args,
		Output:                  output,
		AdditionalTags:          tags,
		In:                      stdin,
		Out:                     stdout,
		Err:                     stderr,
		ReportWriter:            reporter,
		Runtime:                 c.String("runtime"),
		RuntimeArgs:             runtimeFlags,
		OutputFormat:            format,
		SystemContext:           systemContext,
		Isolation:               isolation,
		NamespaceOptions:        namespaceOptions,
		ConfigureNetwork:        networkPolicy,
		CNIPluginPath:           c.String("cni-plugin-path"),
		CNIConfigDir:            c.String("cni-config-dir"),
		IDMappingOptions:        idmappingOptions,
		AddCapabilities:         c.StringSlice("cap-add"),
		DropCapabilities:        c.StringSlice("cap-drop"),
		CommonBuildOpts:         commonOpts,
		DefaultMountsFilePath:   c.GlobalString("default-mounts-file"),
		IIDFile:                 c.String("iidfile"),
		Squash:                  c.Bool("squash"),
		Labels:                  c.StringSlice("label"),
		Annotations:             c.StringSlice("annotation"),
		Layers:                  layers,
		NoCache:                 c.Bool("no-cache"),
		RemoveIntermediateCtrs:  c.BoolT("rm"),
		ForceRmIntermediateCtrs: c.Bool("force-rm"),
	}

	if c.Bool("quiet") {
		options.ReportWriter = ioutil.Discard
	}

	return imagebuildah.BuildDockerfiles(getContext(), store, options, dockerfiles...)
}
<commit_msg>nitpick: parse.validateFlags loop in bud cli<commit_after>package main

import (
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	"github.com/projectatomic/buildah/imagebuildah"
	buildahcli "github.com/projectatomic/buildah/pkg/cli"
	"github.com/projectatomic/buildah/pkg/parse"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

var (
	budDescription = "Builds an OCI image using instructions in one or more Dockerfiles."
	budCommand     = cli.Command{
		Name:                   "build-using-dockerfile",
		Aliases:                []string{"bud"},
		Usage:                  "Build an image using instructions in a Dockerfile",
		Description:            budDescription,
		Flags:                  append(append(buildahcli.BudFlags, buildahcli.LayerFlags...), buildahcli.FromAndBudFlags...),
		Action:                 budCmd,
		ArgsUsage:              "CONTEXT-DIRECTORY | URL",
		SkipArgReorder:         true,
		UseShortOptionHandling: true,
	}
)

func getDockerfiles(files []string) []string {
	var dockerfiles []string
	for _, f := range files {
		if f == "-" {
			dockerfiles = append(dockerfiles, "/dev/stdin")
		} else {
			dockerfiles = append(dockerfiles, f)
		}
	}
	return dockerfiles
}

func budCmd(c *cli.Context) error {
	output := ""
	tags := []string{}
	if c.IsSet("tag") || c.IsSet("t") {
		tags = c.StringSlice("tag")
		if len(tags) > 0 {
			output = tags[0]
			tags = tags[1:]
		}
	}
	pullPolicy := imagebuildah.PullNever
	if c.BoolT("pull") {
		pullPolicy = imagebuildah.PullIfMissing
	}
	if c.Bool("pull-always") {
		pullPolicy = imagebuildah.PullAlways
	}

	args := make(map[string]string)
	if c.IsSet("build-arg") {
		for _, arg := range c.StringSlice("build-arg") {
			av := strings.SplitN(arg, "=", 2)
			if len(av) > 1 {
				args[av[0]] = av[1]
			} else {
				delete(args, av[0])
			}
		}
	}

	dockerfiles := getDockerfiles(c.StringSlice("file"))
	format, err := getFormat(c)
	if err != nil {
		return err
	}
	layers := buildahcli.UseLayers()
	if c.IsSet("layers") {
		layers = c.Bool("layers")
	}
	contextDir := ""
	cliArgs := c.Args()
	if len(cliArgs) == 0 {
		return errors.Errorf("no context directory or URL specified")
	}
	// The context directory could be a URL.  Try to handle that.
	tempDir, subDir, err := imagebuildah.TempDirForURL("", "buildah", cliArgs[0])
	if err != nil {
		return errors.Wrapf(err, "error prepping temporary context directory")
	}
	if tempDir != "" {
		// We had to download it to a temporary directory.
		// Delete it later.
		defer func() {
			if err = os.RemoveAll(tempDir); err != nil {
				logrus.Errorf("error removing temporary directory %q: %v", contextDir, err)
			}
		}()
		contextDir = filepath.Join(tempDir, subDir)
	} else {
		// Nope, it was local.  Use it as is.
		absDir, err := filepath.Abs(cliArgs[0])
		if err != nil {
			return errors.Wrapf(err, "error determining path to directory %q", cliArgs[0])
		}
		contextDir = absDir
	}
	cliArgs = cliArgs.Tail()

	if err := buildahcli.VerifyFlagsArgsOrder(cliArgs); err != nil {
		return err
	}
	if len(dockerfiles) == 0 {
		dockerfiles = append(dockerfiles, filepath.Join(contextDir, "Dockerfile"))
	}
	for _, flag := range [][]cli.Flag{buildahcli.BudFlags, buildahcli.LayerFlags, buildahcli.FromAndBudFlags} {
		if err := parse.ValidateFlags(c, flag); err != nil {
			return err
		}
	}
	var stdin, stdout, stderr, reporter *os.File
	stdin = os.Stdin
	stdout = os.Stdout
	stderr = os.Stderr
	reporter = os.Stderr
	if c.IsSet("logfile") {
		f, err := os.OpenFile(c.String("logfile"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
		if err != nil {
			return errors.Errorf("error opening logfile %q: %v", c.String("logfile"), err)
		}
		defer f.Close()
		logrus.SetOutput(f)
		stdout = f
		stderr = f
		reporter = f
	}

	store, err := getStore(c)
	if err != nil {
		return err
	}

	systemContext, err := parse.SystemContextFromOptions(c)
	if err != nil {
		return errors.Wrapf(err, "error building system context")
	}

	isolation, err := parse.IsolationOption(c)
	if err != nil {
		return err
	}

	runtimeFlags := []string{}
	for _, arg := range c.StringSlice("runtime-flag") {
		runtimeFlags = append(runtimeFlags, "--"+arg)
	}

	commonOpts, err := parse.CommonBuildOptions(c)
	if err != nil {
		return err
	}

	if c.IsSet("layers") && c.IsSet("no-cache") {
		return errors.Errorf("can only set one of 'layers' or 'no-cache'")
	}

	if (c.IsSet("rm") || c.IsSet("force-rm")) && (!c.IsSet("layers") && !c.IsSet("no-cache")) {
		return errors.Errorf("'rm' and 'force-rm' can only be set with either 'layers' or 'no-cache'")
	}

	if c.IsSet("cache-from") {
		logrus.Debugf("build caching not enabled so --cache-from flag has no effect")
	}

	if c.IsSet("compress") {
		logrus.Debugf("--compress option specified but is ignored")
	}

	if c.IsSet("disable-content-trust") {
		logrus.Debugf("--disable-content-trust option specified but is ignored")
	}

	namespaceOptions, networkPolicy, err := parse.NamespaceOptions(c)
	if err != nil {
		return errors.Wrapf(err, "error parsing namespace-related options")
	}
	usernsOption, idmappingOptions, err := parse.IDMappingOptions(c)
	if err != nil {
		return errors.Wrapf(err, "error parsing ID mapping options")
	}
	namespaceOptions.AddOrReplace(usernsOption...)

	options := imagebuildah.BuildOptions{
		ContextDirectory:        contextDir,
		PullPolicy:              pullPolicy,
		Compression:             imagebuildah.Gzip,
		Quiet:                   c.Bool("quiet"),
		SignaturePolicyPath:     c.String("signature-policy"),
		Args:                    args,
		Output:                  output,
		AdditionalTags:          tags,
		In:                      stdin,
		Out:                     stdout,
		Err:                     stderr,
		ReportWriter:            reporter,
		Runtime:                 c.String("runtime"),
		RuntimeArgs:             runtimeFlags,
		OutputFormat:            format,
		SystemContext:           systemContext,
		Isolation:               isolation,
		NamespaceOptions:        namespaceOptions,
		ConfigureNetwork:        networkPolicy,
		CNIPluginPath:           c.String("cni-plugin-path"),
		CNIConfigDir:            c.String("cni-config-dir"),
		IDMappingOptions:        idmappingOptions,
		AddCapabilities:         c.StringSlice("cap-add"),
		DropCapabilities:        c.StringSlice("cap-drop"),
		CommonBuildOpts:         commonOpts,
		DefaultMountsFilePath:   c.GlobalString("default-mounts-file"),
		IIDFile:                 c.String("iidfile"),
		Squash:                  c.Bool("squash"),
		Labels:                  c.StringSlice("label"),
		Annotations:             c.StringSlice("annotation"),
		Layers:                  layers,
		NoCache:                 c.Bool("no-cache"),
		RemoveIntermediateCtrs:  c.BoolT("rm"),
		ForceRmIntermediateCtrs: c.Bool("force-rm"),
	}

	if c.Bool("quiet") {
		options.ReportWriter = ioutil.Discard
	}

	return imagebuildah.BuildDockerfiles(getContext(), store, options, dockerfiles...)
}
<|endoftext|>