<commit_before>// Package digitalocean implements a DNS provider for solving the DNS-01
// challenge using digitalocean DNS.
package digitalocean

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"sync"
	"time"

	"github.com/xenolf/lego/acme"
)

// DNSProvider is an implementation of the acme.ChallengeProvider interface
// that uses DigitalOcean's REST API to manage TXT records for a domain.
type DNSProvider struct {
	apiAuthToken string
	recordIDs    map[string]int
	recordIDsMu  sync.Mutex
}

// NewDNSProvider returns a DNSProvider instance configured for Digital
// Ocean. Credentials must be passed in the environment variable:
// DO_AUTH_TOKEN.
func NewDNSProvider() (*DNSProvider, error) {
	apiAuthToken := os.Getenv("DO_AUTH_TOKEN")
	return NewDNSProviderCredentials(apiAuthToken)
}

// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for Digital Ocean.
func NewDNSProviderCredentials(apiAuthToken string) (*DNSProvider, error) {
	if apiAuthToken == "" {
		return nil, fmt.Errorf("DigitalOcean credentials missing")
	}
	return &DNSProvider{
		apiAuthToken: apiAuthToken,
		recordIDs:    make(map[string]int),
	}, nil
}

// Present creates a TXT record using the specified parameters
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
	// txtRecordRequest represents the request body to DO's API to make a TXT record
	type txtRecordRequest struct {
		RecordType string `json:"type"`
		Name       string `json:"name"`
		Data       string `json:"data"`
	}

	// txtRecordResponse represents a response from DO's API after making a TXT record
	type txtRecordResponse struct {
		DomainRecord struct {
			ID   int    `json:"id"`
			Type string `json:"type"`
			Name string `json:"name"`
			Data string `json:"data"`
		} `json:"domain_record"`
	}

	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

	reqURL := fmt.Sprintf("%s/v2/domains/%s/records", digitalOceanBaseURL, domain)
	reqData := txtRecordRequest{RecordType: "TXT", Name: fqdn, Data: value}
	body, err := json.Marshal(reqData)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", reqURL, bytes.NewReader(body))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.apiAuthToken))

	client := http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		var errInfo digitalOceanAPIError
		json.NewDecoder(resp.Body).Decode(&errInfo)
		return fmt.Errorf("HTTP %d: %s: %s", resp.StatusCode, errInfo.ID, errInfo.Message)
	}

	// Everything looks good; but we'll need the ID later to delete the record
	var respData txtRecordResponse
	err = json.NewDecoder(resp.Body).Decode(&respData)
	if err != nil {
		return err
	}
	d.recordIDsMu.Lock()
	d.recordIDs[fqdn] = respData.DomainRecord.ID
	d.recordIDsMu.Unlock()

	return nil
}

// CleanUp removes the TXT record matching the specified parameters
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _, _ := acme.DNS01Record(domain, keyAuth)

	// get the record's unique ID from when we created it
	d.recordIDsMu.Lock()
	recordID, ok := d.recordIDs[fqdn]
	d.recordIDsMu.Unlock()
	if !ok {
		return fmt.Errorf("unknown record ID for '%s'", fqdn)
	}

	reqURL := fmt.Sprintf("%s/v2/domains/%s/records/%d", digitalOceanBaseURL, domain, recordID)
	req, err := http.NewRequest("DELETE", reqURL, nil)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.apiAuthToken))

	client := http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		var errInfo digitalOceanAPIError
		json.NewDecoder(resp.Body).Decode(&errInfo)
		return fmt.Errorf("HTTP %d: %s: %s", resp.StatusCode, errInfo.ID, errInfo.Message)
	}

	// Delete record ID from map
	d.recordIDsMu.Lock()
	delete(d.recordIDs, fqdn)
	d.recordIDsMu.Unlock()

	return nil
}

type digitalOceanAPIError struct {
	ID      string `json:"id"`
	Message string `json:"message"`
}

var digitalOceanBaseURL = "https://api.digitalocean.com"
<commit_msg>digital ocean uses FindZoneByFqdn<commit_after>// Package digitalocean implements a DNS provider for solving the DNS-01
// challenge using digitalocean DNS.
package digitalocean

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"sync"
	"time"

	"github.com/xenolf/lego/acme"
)

// DNSProvider is an implementation of the acme.ChallengeProvider interface
// that uses DigitalOcean's REST API to manage TXT records for a domain.
type DNSProvider struct {
	apiAuthToken string
	recordIDs    map[string]int
	recordIDsMu  sync.Mutex
}

// NewDNSProvider returns a DNSProvider instance configured for Digital
// Ocean. Credentials must be passed in the environment variable:
// DO_AUTH_TOKEN.
func NewDNSProvider() (*DNSProvider, error) {
	apiAuthToken := os.Getenv("DO_AUTH_TOKEN")
	return NewDNSProviderCredentials(apiAuthToken)
}

// NewDNSProviderCredentials uses the supplied credentials to return a
// DNSProvider instance configured for Digital Ocean.
func NewDNSProviderCredentials(apiAuthToken string) (*DNSProvider, error) {
	if apiAuthToken == "" {
		return nil, fmt.Errorf("DigitalOcean credentials missing")
	}
	return &DNSProvider{
		apiAuthToken: apiAuthToken,
		recordIDs:    make(map[string]int),
	}, nil
}

// Present creates a TXT record using the specified parameters
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
	// txtRecordRequest represents the request body to DO's API to make a TXT record
	type txtRecordRequest struct {
		RecordType string `json:"type"`
		Name       string `json:"name"`
		Data       string `json:"data"`
	}

	// txtRecordResponse represents a response from DO's API after making a TXT record
	type txtRecordResponse struct {
		DomainRecord struct {
			ID   int    `json:"id"`
			Type string `json:"type"`
			Name string `json:"name"`
			Data string `json:"data"`
		} `json:"domain_record"`
	}

	fqdn, value, _ := acme.DNS01Record(domain, keyAuth)

	authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameserver)
	if err != nil {
		return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err)
	}

	authZone = acme.UnFqdn(authZone)

	reqURL := fmt.Sprintf("%s/v2/domains/%s/records", digitalOceanBaseURL, authZone)
	reqData := txtRecordRequest{RecordType: "TXT", Name: fqdn, Data: value}
	body, err := json.Marshal(reqData)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", reqURL, bytes.NewReader(body))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.apiAuthToken))

	client := http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		var errInfo digitalOceanAPIError
		json.NewDecoder(resp.Body).Decode(&errInfo)
		return fmt.Errorf("HTTP %d: %s: %s", resp.StatusCode, errInfo.ID, errInfo.Message)
	}

	// Everything looks good; but we'll need the ID later to delete the record
	var respData txtRecordResponse
	err = json.NewDecoder(resp.Body).Decode(&respData)
	if err != nil {
		return err
	}
	d.recordIDsMu.Lock()
	d.recordIDs[fqdn] = respData.DomainRecord.ID
	d.recordIDsMu.Unlock()

	return nil
}

// CleanUp removes the TXT record matching the specified parameters
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
	fqdn, _, _ := acme.DNS01Record(domain, keyAuth)

	// get the record's unique ID from when we created it
	d.recordIDsMu.Lock()
	recordID, ok := d.recordIDs[fqdn]
	d.recordIDsMu.Unlock()
	if !ok {
		return fmt.Errorf("unknown record ID for '%s'", fqdn)
	}

	authZone, err := acme.FindZoneByFqdn(acme.ToFqdn(domain), acme.RecursiveNameserver)
	if err != nil {
		return fmt.Errorf("Could not determine zone for domain: '%s'. %s", domain, err)
	}

	authZone = acme.UnFqdn(authZone)

	reqURL := fmt.Sprintf("%s/v2/domains/%s/records/%d", digitalOceanBaseURL, authZone, recordID)
	req, err := http.NewRequest("DELETE", reqURL, nil)
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", d.apiAuthToken))

	client := http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		var errInfo digitalOceanAPIError
		json.NewDecoder(resp.Body).Decode(&errInfo)
		return fmt.Errorf("HTTP %d: %s: %s", resp.StatusCode, errInfo.ID, errInfo.Message)
	}

	// Delete record ID from map
	d.recordIDsMu.Lock()
	delete(d.recordIDs, fqdn)
	d.recordIDsMu.Unlock()

	return nil
}

type digitalOceanAPIError struct {
	ID      string `json:"id"`
	Message string `json:"message"`
}

var digitalOceanBaseURL = "https://api.digitalocean.com"
<|endoftext|>


<commit_before>// Copyright 2010 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 math

// Logb returns the binary exponent of x.
//
// Special cases are:
//
//	Logb(±Inf) = +Inf
//	Logb(0) = -Inf
//	Logb(NaN) = NaN
func Logb(x float64) float64 {
	// special cases
	switch {
	case x == 0:
		return Inf(-1)
	case IsInf(x, 0):
		return Inf(1)
	case IsNaN(x):
		return x
	}
	return float64(ilogb(x))
}

// Ilogb returns the binary exponent of x as an integer.
//
// Special cases are:
//
//	Ilogb(±Inf) = MaxInt32
//	Ilogb(0) = MinInt32
//	Ilogb(NaN) = MaxInt32
func Ilogb(x float64) int {
	// special cases
	switch {
	case x == 0:
		return MinInt32
	case IsNaN(x):
		return MaxInt32
	case IsInf(x, 0):
		return MaxInt32
	}
	return ilogb(x)
}

// logb returns the binary exponent of x. It assumes x is finite and
// non-zero.
func ilogb(x float64) int {
	x, exp := normalize(x)
	return int((Float64bits(x)>>shift)&mask) - bias + exp
}
<commit_msg>math: fix function name in comment<commit_after>// Copyright 2010 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 math

// Logb returns the binary exponent of x.
//
// Special cases are:
//
//	Logb(±Inf) = +Inf
//	Logb(0) = -Inf
//	Logb(NaN) = NaN
func Logb(x float64) float64 {
	// special cases
	switch {
	case x == 0:
		return Inf(-1)
	case IsInf(x, 0):
		return Inf(1)
	case IsNaN(x):
		return x
	}
	return float64(ilogb(x))
}

// Ilogb returns the binary exponent of x as an integer.
//
// Special cases are:
//
//	Ilogb(±Inf) = MaxInt32
//	Ilogb(0) = MinInt32
//	Ilogb(NaN) = MaxInt32
func Ilogb(x float64) int {
	// special cases
	switch {
	case x == 0:
		return MinInt32
	case IsNaN(x):
		return MaxInt32
	case IsInf(x, 0):
		return MaxInt32
	}
	return ilogb(x)
}

// ilogb returns the binary exponent of x. It assumes x is finite and
// non-zero.
func ilogb(x float64) int {
	x, exp := normalize(x)
	return int((Float64bits(x)>>shift)&mask) - bias + exp
}
<|endoftext|>


<commit_before>package eio

import (
	"errors"
	"fmt"
	"net/http"
	"sync"
	"sync/atomic"
	"time"

	"log"
)

var (
	protocolVersion = struct {
		n uint8
		s string
	}{3, "3",}
)

type engineOptions struct {
	allowUpgrades  bool
	cookie         bool
	cookiePath     string
	cookieHTTPOnly bool
	pingInterval   uint32
	pingTimeout    uint32
	handleAsync    bool
}

type engineImpl struct {
	logInfo         *log.Logger
	logWarn         *log.Logger
	logErr          *log.Logger
	allowTransports []TransportType
	sidGen          func(seq uint32) string
	sequence        uint32
	path            string
	options         *engineOptions
	onSockets       []func(Socket)
	sockets         *socketMap
	junkKiller      chan struct{}
	junkTicker      *time.Ticker
	allowRequest    func(*http.Request) error
}

func (p *engineImpl) Router() func(http.ResponseWriter, *http.Request) {
	p.ensureCleaner()
	return func(writer http.ResponseWriter, request *http.Request) {
		if request.Method == http.MethodOptions {
			writer.Header().Set("Access-Control-Allow-Headers", "Content-Type")
			writer.WriteHeader(http.StatusOK)
			return
		}
		if !(request.Method == http.MethodGet || request.Method == http.MethodPost) {
			writer.WriteHeader(http.StatusMethodNotAllowed)
			return
		}
		query := request.URL.Query()
		var err error
		// check protocol version
		if err = p.checkVersion(query.Get("EIO")); err != nil {
			sendError(writer, err, http.StatusBadRequest)
			return
		}

		// check transport
		var ttype TransportType
		if ttype, err = p.checkTransport(query.Get("transport")); err != nil {
			sendError(writer, errors.New("transprot error"), http.StatusBadRequest, 0)
			return
		}

		// check allow request
		if p.allowRequest != nil {
			if err := p.allowRequest(request); err != nil {
				sendError(writer, err, http.StatusNotAcceptable, 0)
				return
			}
		}

		var sid = query.Get("sid")
		var isNew = len(sid) < 1

		var socket *socketImpl
		var tp Transport

		if isNew {
			sid = p.generateID()
			tp, socket = newTransport(p, ttype), newSocket(sid, p)
			socket.setTransport(tp)
			tp.setSocket(socket)
			if err = tp.ready(writer, request); err != nil {
				sendError(writer, err)
				return
			}
			socket.OnClose(func(reason string) {
				p.sockets.Remove(socket)
			})
			p.sockets.Put(socket)
			p.socketCreated(socket)
		} else if socket0, ok := p.sockets.Get(sid); !ok {
			sendError(writer, fmt.Errorf("%s:socket#%s doesn't exist", request.Method, sid))
			return
		} else {
			socket = socket0
			tp0 := socket0.getTransport()
			ttype0 := tp0.GetType()
			if ttype > ttype0 {
				tp = newTransport(p, ttype)
				tp.setSocket(socket)
				socket.setTransport(tp)
			} else if ttype < ttype0 {
				tp = socket0.getTransportOld()
			} else {
				tp = tp0
			}
		}
		tp.doReq(writer, request)
	}
}

func (p *engineImpl) Close() {
	close(p.junkKiller)
}

func (p *engineImpl) Listen(addr string) error {
	http.HandleFunc(p.path, p.Router())
	return http.ListenAndServe(addr, nil)
}

func (p *engineImpl) GetProtocol() uint8 {
	return protocolVersion.n
}

func (p *engineImpl) GetClients() map[string]Socket {
	m := make(map[string]Socket)
	for _, it := range p.sockets.List(nil) {
		m[it.ID()] = it
	}
	return m
}

func (p *engineImpl) CountClients() int {
	return p.sockets.Count()
}

func (p *engineImpl) OnConnect(onConn func(socket Socket)) Engine {
	p.onSockets = append(p.onSockets, onConn)
	return p
}

func (p *engineImpl) checkVersion(v string) error {
	if v != protocolVersion.s {
		return fmt.Errorf("illegal protocol version: EIO=%s", v)
	}
	return nil
}

func (p *engineImpl) checkTransport(qTransport string) (TransportType, error) {
	var t TransportType
	switch qTransport {
	default:
		return -1, fmt.Errorf("invalid transport '%s'", qTransport)
	case "polling":
		t = POLLING
	case "websocket":
		t = WEBSOCKET
	}
	for _, it := range p.allowTransports {
		if t == it {
			return t, nil
		}
	}
	return -1, fmt.Errorf("transport '%s' is forbiden", qTransport)
}

func (p *engineImpl) generateID() string {
	if atomic.CompareAndSwapUint32(&(p.sequence), 0xFFFF, 0) {
		return p.sidGen(0)
	}
	return p.sidGen(atomic.AddUint32(&(p.sequence), 1))
}

func (p *engineImpl) ensureCleaner() {
	if p.junkTicker != nil {
		return
	}
	p.junkTicker = time.NewTicker(time.Millisecond * time.Duration(p.options.pingTimeout))
	// cron: check and kill lost socket.
	go func() {
		for {
			select {
			case <-p.junkTicker.C:
				losts := p.sockets.List(func(val *socketImpl) bool {
					return val.isLost()
				})
				if len(losts) > 0 {
					for _, it := range losts {
						it.Close()
					}
					if p.logInfo != nil {
						p.logInfo.Printf("***** kill %d DEAD sockets *****\n", len(losts))
					}
				}
				break
			case <-p.junkKiller:
				p.junkTicker.Stop()
				return
			}
		}
	}()
}

func (p *engineImpl) socketCreated(socket *socketImpl) {
	if p.onSockets == nil {
		return
	}
	for _, fn := range p.onSockets {
		fn(socket)
	}
}

type socketMap struct {
	store *sync.Map
}

func (p *socketMap) Get(id string) (*socketImpl, bool) {
	val, ok := p.store.Load(id)
	if ok {
		return val.(*socketImpl), ok
	}
	return nil, ok
}

func (p *socketMap) Put(socket *socketImpl) {
	if _, ok := p.store.LoadOrStore(socket.ID(), socket); ok {
		panic(fmt.Errorf("socket#%s exists already", socket.ID()))
	}
}

func (p *socketMap) Remove(socket *socketImpl) {
	p.store.Delete(socket.ID())
}

func (p *socketMap) Count() int {
	var c int
	p.store.Range(func(_, _ interface{}) bool {
		c++
		return true
	})
	return c
}

func (p *socketMap) List(filter func(impl *socketImpl) bool) []*socketImpl {
	ret := make([]*socketImpl, 0)
	p.store.Range(func(key, value interface{}) bool {
		it := value.(*socketImpl)
		if filter == nil || filter(it) {
			ret = append(ret, it)
		}
		return true
	})
	return ret
}
<commit_msg>fix bug<commit_after>package eio

import (
	"errors"
	"fmt"
	"net/http"
	"sync"
	"sync/atomic"
	"time"

	"log"
)

var (
	protocolVersion = struct {
		n uint8
		s string
	}{3, "3",}
)

type engineOptions struct {
	allowUpgrades  bool
	cookie         bool
	cookiePath     string
	cookieHTTPOnly bool
	pingInterval   uint32
	pingTimeout    uint32
	handleAsync    bool
}

type engineImpl struct {
	logInfo         *log.Logger
	logWarn         *log.Logger
	logErr          *log.Logger
	allowTransports []TransportType
	sidGen          func(seq uint32) string
	sequence        uint32
	path            string
	options         *engineOptions
	onSockets       []func(Socket)
	sockets         *socketMap
	junkKiller      chan struct{}
	junkTicker      *time.Ticker
	allowRequest    func(*http.Request) error
}

func (p *engineImpl) Router() func(http.ResponseWriter, *http.Request) {
	p.ensureCleaner()
	return func(writer http.ResponseWriter, request *http.Request) {
		if request.Method == http.MethodOptions {
			writer.Header().Set("Access-Control-Allow-Headers", "Content-Type")
			writer.WriteHeader(http.StatusOK)
			return
		}
		if !(request.Method == http.MethodGet || request.Method == http.MethodPost) {
			writer.WriteHeader(http.StatusMethodNotAllowed)
			return
		}
		query := request.URL.Query()
		var err error
		// check protocol version
		if err = p.checkVersion(query.Get("EIO")); err != nil {
			sendError(writer, err, http.StatusBadRequest)
			return
		}

		// check transport
		var ttype TransportType
		if ttype, err = p.checkTransport(query.Get("transport")); err != nil {
			sendError(writer, errors.New("transprot error"), http.StatusBadRequest, 0)
			return
		}

		// check allow request
		if p.allowRequest != nil {
			if err := p.allowRequest(request); err != nil {
				sendError(writer, err, http.StatusNotAcceptable, 0)
				return
			}
		}

		var sid = query.Get("sid")
		var isNew = len(sid) < 1

		var socket *socketImpl
		var tp Transport

		if isNew {
			sid = p.generateID()
			tp, socket = newTransport(p, ttype), newSocket(sid, p)
			socket.setTransport(tp)
			tp.setSocket(socket)
			if err = tp.ready(writer, request); err != nil {
				sendError(writer, err)
				return
			}
			socket.OnClose(func(reason string) {
				p.sockets.Remove(socket)
			})
			p.sockets.Put(socket)
			p.socketCreated(socket)
		} else if socket0, ok := p.sockets.Get(sid); !ok {
			sendError(writer, fmt.Errorf("%s:socket#%s doesn't exist", request.Method, sid))
			return
		} else {
			socket = socket0
			tp0 := socket0.getTransport()
			ttype0 := tp0.GetType()
			if ttype > ttype0 {
				tp = newTransport(p, ttype)
				tp.setSocket(socket)
				socket.setTransport(tp)
			} else if ttype < ttype0 {
				tp = socket0.getTransportOld()
			} else {
				tp = tp0
			}
		}
		tp.doReq(writer, request)
	}
}

func (p *engineImpl) Close() {
	close(p.junkKiller)
}

func (p *engineImpl) Listen(addr string) error {
	http.HandleFunc(p.path, p.Router())
	return http.ListenAndServe(addr, nil)
}

func (p *engineImpl) GetProtocol() uint8 {
	return protocolVersion.n
}

func (p *engineImpl) GetClients() map[string]Socket {
	m := make(map[string]Socket)
	for _, it := range p.sockets.List(nil) {
		m[it.ID()] = it
	}
	return m
}

func (p *engineImpl) CountClients() int {
	return p.sockets.Count()
}

func (p *engineImpl) OnConnect(onConn func(socket Socket)) Engine {
	p.onSockets = append(p.onSockets, onConn)
	return p
}

func (p *engineImpl) checkVersion(v string) error {
	if v != protocolVersion.s {
		return fmt.Errorf("illegal protocol version: EIO=%s", v)
	}
	return nil
}

func (p *engineImpl) checkTransport(qTransport string) (TransportType, error) {
	var t TransportType
	switch qTransport {
	default:
		return -1, fmt.Errorf("invalid transport '%s'", qTransport)
	case "polling":
		t = POLLING
	case "websocket":
		t = WEBSOCKET
	}
	for _, it := range p.allowTransports {
		if t == it {
			return t, nil
		}
	}
	return -1, fmt.Errorf("transport '%s' is forbiden", qTransport)
}

func (p *engineImpl) generateID() string {
	if atomic.CompareAndSwapUint32(&(p.sequence), 0xFFFF, 0) {
		return p.sidGen(0)
	}
	return p.sidGen(atomic.AddUint32(&(p.sequence), 1))
}

func (p *engineImpl) ensureCleaner() {
	if p.junkTicker != nil {
		return
	}
	p.junkTicker = time.NewTicker(time.Millisecond * time.Duration(p.options.pingTimeout))
	// cron: check and kill lost socket.
	go func() {
		var end bool
		for {
			if end {
				break
			}
			select {
			case <-p.junkTicker.C:
				losts := p.sockets.List(func(val *socketImpl) bool {
					return val.isLost()
				})
				if len(losts) > 0 {
					for _, it := range losts {
						it.Close()
					}
					if p.logInfo != nil {
						p.logInfo.Printf("***** kill %d DEAD sockets *****\n", len(losts))
					}
				}
				break
			case <-p.junkKiller:
				p.junkTicker.Stop()
				end = true
				return
			}
		}
	}()
}

func (p *engineImpl) socketCreated(socket *socketImpl) {
	if p.onSockets == nil {
		return
	}
	for _, fn := range p.onSockets {
		fn(socket)
	}
}

type socketMap struct {
	store *sync.Map
}

func (p *socketMap) Get(id string) (*socketImpl, bool) {
	val, ok := p.store.Load(id)
	if ok {
		return val.(*socketImpl), ok
	}
	return nil, ok
}

func (p *socketMap) Put(socket *socketImpl) {
	if _, ok := p.store.LoadOrStore(socket.ID(), socket); ok {
		panic(fmt.Errorf("socket#%s exists already", socket.ID()))
	}
}

func (p *socketMap) Remove(socket *socketImpl) {
	p.store.Delete(socket.ID())
}

func (p *socketMap) Count() int {
	var c int
	p.store.Range(func(_, _ interface{}) bool {
		c++
		return true
	})
	return c
}

func (p *socketMap) List(filter func(impl *socketImpl) bool) []*socketImpl {
	ret := make([]*socketImpl, 0)
	p.store.Range(func(key, value interface{}) bool {
		it := value.(*socketImpl)
		if filter == nil || filter(it) {
			ret = append(ret, it)
		}
		return true
	})
	return ret
}
<|endoftext|>


<commit_before>package qb

import "database/sql"

// NewEngine generates a new engine and returns it as an engine pointer
func NewEngine(driver string, dsn string) (*Engine, error) {

	conn, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}

	return &Engine{
		driver: driver,
		dsn:    dsn,
		db:     conn,
	}, err
}

// Engine is the generic struct for handling db connections
type Engine struct {
	driver string
	dsn    string
	db     *sql.DB
}

// Exec executes insert & update type queries and returns sql.Result and error
func (e *Engine) Exec(query *Query) (sql.Result, error) {

	stmt, err := e.db.Prepare(query.SQL())
	if err != nil {
		return nil, err
	}

	res, err := stmt.Exec(query.Bindings())
	if err != nil {
		return nil, err
	}

	return res, nil
}

// DB returns sql.DB of wrapped engine connection
func (e *Engine) DB() *sql.DB {
	return e.db
}

// Ping pings the db using connection and returns error if connectivity is not present
func (e *Engine) Ping() error {
	return e.db.Ping()
}

// Driver returns the driver as string
func (e *Engine) Driver() string {
	return e.driver
}

// Dsn returns the connection dsn
func (e *Engine) Dsn() string {
	return e.dsn
}
<commit_msg>fix Exec() function bindings not passing correctly<commit_after>package qb

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/lib/pq"
	_ "github.com/mattn/go-sqlite3"
)

// NewEngine generates a new engine and returns it as an engine pointer
func NewEngine(driver string, dsn string) (*Engine, error) {

	conn, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}

	return &Engine{
		driver: driver,
		dsn:    dsn,
		db:     conn,
	}, err
}

// Engine is the generic struct for handling db connections
type Engine struct {
	driver string
	dsn    string
	db     *sql.DB
}

// Exec executes insert & update type queries and returns sql.Result and error
func (e *Engine) Exec(query *Query) (sql.Result, error) {

	stmt, err := e.db.Prepare(query.SQL())
	if err != nil {
		return nil, err
	}

	res, err := stmt.Exec(query.Bindings()...)
	if err != nil {
		return nil, err
	}

	return res, nil
}

// DB returns sql.DB of wrapped engine connection
func (e *Engine) DB() *sql.DB {
	return e.db
}

// Ping pings the db using connection and returns error if connectivity is not present
func (e *Engine) Ping() error {
	return e.db.Ping()
}

// Driver returns the driver as string
func (e *Engine) Driver() string {
	return e.driver
}

// Dsn returns the connection dsn
func (e *Engine) Dsn() string {
	return e.dsn
}
<|endoftext|>


<commit_before>package qbit

import "database/sql"

func NewEngine(driver string, dsn string) (*Engine, error) {

	conn, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}

	return &Engine{
		driver: driver,
		dsn:    dsn,
		db:     conn,
	}, err
}

type Engine struct {
	driver string
	dsn    string
	db     *sql.DB
}

func (e *Engine) Exec(sql string, bindings []interface{}) (sql.Result, error) {

	stmt, err := e.db.Prepare(sql)
	if err != nil {
		return nil, err
	}

	res, err := stmt.Exec(bindings)
	if err != nil {
		return nil, err
	}

	return res, nil
}

func (e *Engine) DB() *sql.DB {
	return e.db
}

func (e *Engine) Ping() error {
	return e.db.Ping()
}

func (e *Engine) Driver() string {
	return e.driver
}

func (e *Engine) Dsn() string {
	return e.dsn
}
<commit_msg>add comments, fix engine lint errors<commit_after>package qbit

import "database/sql"

// NewEngine generates a new engine and returns it as an engine pointer
func NewEngine(driver string, dsn string) (*Engine, error) {

	conn, err := sql.Open(driver, dsn)
	if err != nil {
		return nil, err
	}

	return &Engine{
		driver: driver,
		dsn:    dsn,
		db:     conn,
	}, err
}

// Engine is the generic struct for handling db connections
type Engine struct {
	driver string
	dsn    string
	db     *sql.DB
}

// Exec executes insert & update type queries and returns sql.Result and error
func (e *Engine) Exec(sql string, bindings []interface{}) (sql.Result, error) {

	stmt, err := e.db.Prepare(sql)
	if err != nil {
		return nil, err
	}

	res, err := stmt.Exec(bindings)
	if err != nil {
		return nil, err
	}

	return res, nil
}

// DB returns sql.DB of wrapped engine connection
func (e *Engine) DB() *sql.DB {
	return e.db
}

// Ping pings the db using connection and returns error if connectivity is not present
func (e *Engine) Ping() error {
	return e.db.Ping()
}

// Driver returns the driver as string
func (e *Engine) Driver() string {
	return e.driver
}

// Dsn returns the connection dsn
func (e *Engine) Dsn() string {
	return e.dsn
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (s *DockerSuite) TestStatsNoStream(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), checker.IsNil)

	statsCmd := exec.Command(dockerBinary, "stats", "--no-stream", id)
	type output struct {
		out []byte
		err error
	}

	ch := make(chan output)
	go func() {
		out, err := statsCmd.Output()
		ch <- output{out, err}
	}()

	select {
	case outerr := <-ch:
		c.Assert(outerr.err, checker.IsNil, check.Commentf("Error running stats: %v", outerr.err))
		c.Assert(string(outerr.out), checker.Contains, id) //running container wasn't present in output
	case <-time.After(3 * time.Second):
		statsCmd.Process.Kill()
		c.Fatalf("stats did not return immediately when not streaming")
	}
}

func (s *DockerSuite) TestStatsContainerNotFound(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)

	out, _, err := dockerCmdWithError("stats", "notfound")
	c.Assert(err, checker.NotNil)
	c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats, got %q instead", out))

	out, _, err = dockerCmdWithError("stats", "--no-stream", "notfound")
	c.Assert(err, checker.NotNil)
	c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats with --no-stream, got %q instead", out))
}

func (s *DockerSuite) TestStatsAllRunningNoStream(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id1 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id1), check.IsNil)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id2 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id2), check.IsNil)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id3 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id3), check.IsNil)
	dockerCmd(c, "stop", id3)

	out, _ = dockerCmd(c, "stats", "--no-stream")
	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
	}
	if strings.Contains(out, id3) {
		c.Fatalf("Did not expect %s in stats, got %s", id3, out)
	}
}

func (s *DockerSuite) TestStatsAllNoStream(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id1 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id1), check.IsNil)
	dockerCmd(c, "stop", id1)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id2 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id2), check.IsNil)

	out, _ = dockerCmd(c, "stats", "--all", "--no-stream")
	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
	}
}

func (s *DockerSuite) TestStatsAllNewContainersAdded(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)

	id := make(chan string)
	addedChan := make(chan struct{})

	dockerCmd(c, "run", "-d", "busybox", "top")
	statsCmd := exec.Command(dockerBinary, "stats")
	stdout, err := statsCmd.StdoutPipe()
	c.Assert(err, check.IsNil)
	c.Assert(statsCmd.Start(), check.IsNil)
	defer statsCmd.Process.Kill()

	go func() {
		containerID := <-id
		matchID := regexp.MustCompile(containerID)

		scanner := bufio.NewScanner(stdout)
		for scanner.Scan() {
			switch {
			case matchID.MatchString(scanner.Text()):
				close(addedChan)
			}
		}
	}()

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	c.Assert(waitRun(strings.TrimSpace(out)), check.IsNil)
	id <- strings.TrimSpace(out)[:12]

	select {
	case <-time.After(10 * time.Second):
		c.Fatal("failed to observe new container created added to stats")
	case <-addedChan:
		// ignore, done
	}
}
<commit_msg>Fix flakey TestStatsAllNewContainersAdded<commit_after>package main

import (
	"bufio"
	"os/exec"
	"regexp"
	"strings"
	"time"

	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (s *DockerSuite) TestStatsNoStream(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)
	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id := strings.TrimSpace(out)
	c.Assert(waitRun(id), checker.IsNil)

	statsCmd := exec.Command(dockerBinary, "stats", "--no-stream", id)
	type output struct {
		out []byte
		err error
	}

	ch := make(chan output)
	go func() {
		out, err := statsCmd.Output()
		ch <- output{out, err}
	}()

	select {
	case outerr := <-ch:
		c.Assert(outerr.err, checker.IsNil, check.Commentf("Error running stats: %v", outerr.err))
		c.Assert(string(outerr.out), checker.Contains, id) //running container wasn't present in output
	case <-time.After(3 * time.Second):
		statsCmd.Process.Kill()
		c.Fatalf("stats did not return immediately when not streaming")
	}
}

func (s *DockerSuite) TestStatsContainerNotFound(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)

	out, _, err := dockerCmdWithError("stats", "notfound")
	c.Assert(err, checker.NotNil)
	c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats, got %q instead", out))

	out, _, err = dockerCmdWithError("stats", "--no-stream", "notfound")
	c.Assert(err, checker.NotNil)
	c.Assert(out, checker.Contains, "No such container: notfound", check.Commentf("Expected to fail on not found container stats with --no-stream, got %q instead", out))
}

func (s *DockerSuite) TestStatsAllRunningNoStream(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id1 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id1), check.IsNil)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id2 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id2), check.IsNil)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id3 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id3), check.IsNil)
	dockerCmd(c, "stop", id3)

	out, _ = dockerCmd(c, "stats", "--no-stream")
	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
	}
	if strings.Contains(out, id3) {
		c.Fatalf("Did not expect %s in stats, got %s", id3, out)
	}
}

func (s *DockerSuite) TestStatsAllNoStream(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)

	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
	id1 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id1), check.IsNil)
	dockerCmd(c, "stop", id1)
	out, _ = dockerCmd(c, "run", "-d", "busybox", "top")
	id2 := strings.TrimSpace(out)[:12]
	c.Assert(waitRun(id2), check.IsNil)

	out, _ = dockerCmd(c, "stats", "--all", "--no-stream")
	if !strings.Contains(out, id1) || !strings.Contains(out, id2) {
		c.Fatalf("Expected stats output to contain both %s and %s, got %s", id1, id2, out)
	}
}

func (s *DockerSuite) TestStatsAllNewContainersAdded(c *check.C) {
	// Windows does not support stats
	testRequires(c, DaemonIsLinux)

	id := make(chan string)
	addedChan := make(chan struct{})

	runSleepingContainer(c, "-d")
	statsCmd := exec.Command(dockerBinary, "stats")
	stdout, err := statsCmd.StdoutPipe()
	c.Assert(err, check.IsNil)
	c.Assert(statsCmd.Start(), check.IsNil)
	defer statsCmd.Process.Kill()

	go func() {
		containerID := <-id
		matchID := regexp.MustCompile(containerID)

		scanner := bufio.NewScanner(stdout)
		for scanner.Scan() {
			switch {
			case matchID.MatchString(scanner.Text()):
				close(addedChan)
				return
			}
		}
	}()

	out, _ := runSleepingContainer(c, "-d")
	c.Assert(waitRun(strings.TrimSpace(out)), check.IsNil)
	id <- strings.TrimSpace(out)[:12]

	select {
	case <-time.After(30 * time.Second):
		c.Fatal("failed to observe new container created added to stats")
	case <-addedChan:
		// ignore, done
	}
}
<|endoftext|>


<commit_before>package utils

const VERSION = "0.6.1"
<commit_msg>Update version to 0.7.0-beta<commit_after>package utils

const VERSION = "0.7.0-beta"
<|endoftext|>


<commit_before>package push

import (
	"fmt"
	"path"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	"github.com/onsi/ginkgo/config"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("random route", func() {
	var (
		appName string
	)

	BeforeEach(func() {
		appName = fmt.Sprintf("app%d", config.GinkgoConfig.ParallelNode)
	})

	When("passed the --random-route flag", func() {
		When("the app does not already exist", func() {
			It("generates a random route for the app", func() {
				helpers.WithHelloWorldApp(func(dir string) {
					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--random-route", "--no-manifest", "--no-start")
					Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
					Eventually(session).Should(Exit(0))
				})

				appSession := helpers.CF("app", appName)
				Eventually(appSession).Should(Say(`name:\s+%s`, appName))
				Eventually(appSession).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
				Eventually(appSession).Should(Exit(0))
			})
		})

		When("the app exists and has an existing route", func() {
			BeforeEach(func() {
				helpers.WithHelloWorldApp(func(dir string) {
					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-manifest", "--no-start")
					Eventually(session).Should(Exit(0))
				})
			})

			It("does not generate a random route for the app", func() {
				helpers.WithHelloWorldApp(func(dir string) {
					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--random-route", "--no-manifest", "--no-start")
					Eventually(session).Should(Say(`(?m)routes:\s+%s.%s$`, appName, helpers.DefaultSharedDomain()))
					Eventually(session).Should(Exit(0))
				})
			})
		})
	})

	When("passed the random-route manifest property as 'true' and no --random-route flag", func() {
		var manifest map[string]interface{}

		BeforeEach(func() {
			manifest = map[string]interface{}{
				"applications": []map[string]interface{}{
					{
						"name":         appName,
						"random-route": true,
					},
				},
			}
			helpers.WithHelloWorldApp(func(dir string) {
				helpers.WriteManifest(path.Join(dir, "manifest.yml"), manifest)
				session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")
				Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
				Eventually(session).Should(Exit(0))
			})
		})

		It("generates a random route for the app", func() {
			session := helpers.CF("app", appName)
			Eventually(session).Should(Say(`name:\s+%s`, appName))
			Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
			Eventually(session).Should(Exit(0))
		})

		When("the app has an existing route", func() {
			It("does not generate a random route for the app", func() {
				helpers.WithHelloWorldApp(func(dir string) {
					helpers.WriteManifest(path.Join(dir, "manifest.yml"), manifest)

					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")
					Eventually(session).ShouldNot(Say(`\+\s+%s-[\w]+`, appName))
					Eventually(session).Should(Exit(0))
				})
			})
		})
	})

	When("passed the random-route manifest property as 'false' and with --random-route flag", func() {
		var manifest map[string]interface{}

		BeforeEach(func() {
			manifest = map[string]interface{}{
				"applications": []map[string]interface{}{
					{
						"name":         appName,
						"random-route": false,
					},
				},
			}

			helpers.WithHelloWorldApp(func(dir string) {
				helpers.WriteManifest(path.Join(dir, "manifest.yml"), manifest)
				session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start", "--random-route")
				Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
				Eventually(session).Should(Exit(0))
			})
		})

		It("generates a random route for the app", func() {
			session := helpers.CF("app", appName)
			Eventually(session).Should(Say(`name:\s+%s`, appName))
			Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
			Eventually(session).Should(Exit(0))
		})
	})
})
<commit_msg>Use the time to get a more random appName<commit_after>package push

import (
	"fmt"
	"path"
	"time"

	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("random route", func() {
	var (
		appName string
	)

	BeforeEach(func() {
		appName = fmt.Sprintf("app%d", time.Now().Nanosecond())
	})

	When("passed the --random-route flag", func() {
		When("the app does not already exist", func() {
			It("generates a random route for the app", func() {
				helpers.WithHelloWorldApp(func(dir string) {
					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--random-route", "--no-manifest", "--no-start")
					Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
					Eventually(session).Should(Exit(0))
				})

				appSession := helpers.CF("app", appName)
				Eventually(appSession).Should(Say(`name:\s+%s`, appName))
				Eventually(appSession).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
				Eventually(appSession).Should(Exit(0))
			})
		})

		When("the app exists and has an existing route", func() {
			BeforeEach(func() {
				helpers.WithHelloWorldApp(func(dir string) {
					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-manifest", "--no-start")
					Eventually(session).Should(Exit(0))
				})
			})

			It("does not generate a random route for the app", func() {
				helpers.WithHelloWorldApp(func(dir string) {
					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--random-route", "--no-manifest", "--no-start")
					Eventually(session).Should(Say(`(?m)routes:\s+%s.%s$`, appName, helpers.DefaultSharedDomain()))
					Eventually(session).Should(Exit(0))
				})
			})
		})
	})

	When("passed the random-route manifest property as 'true' and no --random-route flag", func() {
		var manifest map[string]interface{}

		BeforeEach(func() {
			manifest = map[string]interface{}{
				"applications": []map[string]interface{}{
					{
						"name":         appName,
						"random-route": true,
					},
				},
			}
			helpers.WithHelloWorldApp(func(dir string) {
				helpers.WriteManifest(path.Join(dir, "manifest.yml"), manifest)
				session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")
				Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
				Eventually(session).Should(Exit(0))
			})
		})

		It("generates a random route for the app", func() {
			session := helpers.CF("app", appName)
			Eventually(session).Should(Say(`name:\s+%s`, appName))
			Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
			Eventually(session).Should(Exit(0))
		})

		When("the app has an existing route", func() {
			It("does not generate a random route for the app", func() {
				helpers.WithHelloWorldApp(func(dir string) {
					helpers.WriteManifest(path.Join(dir, "manifest.yml"), manifest)

					session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start")
					Eventually(session).ShouldNot(Say(`\+\s+%s-[\w]+`, appName))
					Eventually(session).Should(Exit(0))
				})
			})
		})
	})

	When("passed the random-route manifest property as 'false' and with --random-route flag", func() {
		var manifest map[string]interface{}

		BeforeEach(func() {
			manifest = map[string]interface{}{
				"applications": []map[string]interface{}{
					{
						"name":         appName,
						"random-route": false,
					},
				},
			}

			helpers.WithHelloWorldApp(func(dir string) {
				helpers.WriteManifest(path.Join(dir, "manifest.yml"), manifest)
				session := helpers.CustomCF(helpers.CFEnv{WorkingDirectory: dir}, PushCommandName, appName, "--no-start", "--random-route")
				Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
				Eventually(session).Should(Exit(0))
			})
		})

		It("generates a random route for the app", func() {
			session := helpers.CF("app", appName)
			Eventually(session).Should(Say(`name:\s+%s`, appName))
			Eventually(session).Should(Say(`(?m)routes:\s+%s-[\w]+-[\w]+.%s$`, appName, helpers.DefaultSharedDomain()))
			Eventually(session).Should(Exit(0))
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"testing"
	"time"
)

// Should serve a known static error page if all backend servers are down
// and object isn't in cache/stale.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestFailoverErrorPageAllServersDown(t *testing.T) {

	originServer.Stop()
	backupServer1.Stop()
	backupServer2.Stop()

	sourceUrl := fmt.Sprintf("https://%s/?cache-bust=%s", *edgeHost, NewUUID())
	req, err := http.NewRequest("GET", sourceUrl, nil)
	if err != nil {
		t.Fatal(err)
	}
	resp, err := client.RoundTrip(req)
	if err != nil {
		t.Fatal(err)
	}

	if resp.StatusCode != 503 {
		t.Errorf("Invalid StatusCode received. Expected 503, got %d", resp.StatusCode)
	}

	err = StartBackendsInOrder(*edgeHost)
	if err != nil {
		// Bomb out - we do not have a consistent backend, so subsequent tests
		// would fail in unexpected ways.
		log.Fatal(err)
	}

}

// Should serve a known static error page if all backend servers return a
// 5xx response and object isn't in cache/stale.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestFailoverErrorPageAllServers5xx(t *testing.T) {
	t.Error("Not implemented")
}

// Should back off requests against origin for a very short period of time
// if origin returns a 5xx response so as not to overwhelm it.
func TestFailoverOrigin5xxBackOff(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	const expectedResponseStale = "going off like stilton"
	const expectedResponseFresh = "as fresh as daisies"

	const respTTL = time.Duration(2 * time.Second)
	const respTTLWithBuffer = 5 * respTTL
	// Allow varnish's beresp.saintmode to expire.
	const waitSaintMode = time.Duration(5 * time.Second)
	headerValue := fmt.Sprintf("max-age=%.0f", respTTL.Seconds())

	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		t.Errorf("Server %s received request and it shouldn't have", name)
		w.Write([]byte(name))
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		t.Errorf("Server %s received request and it shouldn't have", name)
		w.Write([]byte(name))
	})

	req := NewUniqueEdgeGET(t)

	var expectedBody string
	for requestCount := 1; requestCount < 6; requestCount++ {
		switch requestCount {
		case 1: // Request 1 populates cache.
			expectedBody = expectedResponseStale

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.Header().Set("Cache-Control", headerValue)
				w.Write([]byte(expectedBody))
			})
		case 2: // Requests 2,3,4 come from stale.
			time.Sleep(respTTLWithBuffer)
			expectedBody = expectedResponseStale

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusServiceUnavailable)
				w.Write([]byte(originServer.Name))
			})
		case 5: // Last request comes directly from origin again.
			time.Sleep(waitSaintMode)
			expectedBody = expectedResponseFresh

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.Write([]byte(expectedBody))
			})
		}

		resp := RoundTripCheckError(t, req)

		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatal(err)
		}
		if bodyStr := string(body); bodyStr != expectedBody {
			t.Errorf(
				"Request %d received incorrect response body. Expected %q, got %q",
				requestCount,
				expectedBody,
				bodyStr,
			)
		}
	}
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	expectedBody := "lucky golden ticket"
	expectedStatus := http.StatusOK
	backendsSawRequest := map[string]bool{}

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := originServer.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		if !backendsSawRequest[name] {
			w.Write([]byte(expectedBody))
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
			w.Write([]byte(name))
		}
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		t.Errorf("Server %s received a request and it shouldn't have", name)
		w.Write([]byte(name))
	})

	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)

	if resp.StatusCode != expectedStatus {
		t.Errorf(
			"Received incorrect status code. Expected %d, got %d",
			expectedStatus,
			resp.StatusCode,
		)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if bodyStr := string(body); bodyStr != expectedBody {
		t.Errorf(
			"Received incorrect response body. Expected %q, got %q",
			expectedBody,
			bodyStr,
		)
	}
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	expectedBody := "lucky golden ticket"
	expectedStatus := http.StatusOK
	backendsSawRequest := map[string]bool{}

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := originServer.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		if !backendsSawRequest[name] {
			w.Write([]byte(expectedBody))
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
			w.Write([]byte(name))
		}
	})

	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)

	if resp.StatusCode != expectedStatus {
		t.Errorf(
			"Received incorrect status code. Expected %d, got %d",
			expectedStatus,
			resp.StatusCode,
		)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if bodyStr := string(body); bodyStr != expectedBody {
		t.Errorf(
			"Received incorrect response body. Expected %q, got %q",
			expectedBody,
			bodyStr,
		)
	}
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}
<commit_msg>Use request helpers in ErrorPageAllServersDown<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"testing"
	"time"
)

// Should serve a known static error page if all backend servers are down
// and object isn't in cache/stale.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestFailoverErrorPageAllServersDown(t *testing.T) {

	originServer.Stop()
	backupServer1.Stop()
	backupServer2.Stop()

	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)

	if resp.StatusCode != 503 {
		t.Errorf("Invalid StatusCode received. Expected 503, got %d", resp.StatusCode)
	}

	err := StartBackendsInOrder(*edgeHost)
	if err != nil {
		// Bomb out - we do not have a consistent backend, so subsequent tests
		// would fail in unexpected ways.
		log.Fatal(err)
	}

}

// Should serve a known static error page if all backend servers return a
// 5xx response and object isn't in cache/stale.
// NB: ideally this should be a page that we control that has a mechanism
//     to alert us that it has been served.
func TestFailoverErrorPageAllServers5xx(t *testing.T) {
	t.Error("Not implemented")
}

// Should back off requests against origin for a very short period of time
// if origin returns a 5xx response so as not to overwhelm it.
func TestFailoverOrigin5xxBackOff(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	const expectedResponseStale = "going off like stilton"
	const expectedResponseFresh = "as fresh as daisies"

	const respTTL = time.Duration(2 * time.Second)
	const respTTLWithBuffer = 5 * respTTL
	// Allow varnish's beresp.saintmode to expire.
	const waitSaintMode = time.Duration(5 * time.Second)
	headerValue := fmt.Sprintf("max-age=%.0f", respTTL.Seconds())

	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		t.Errorf("Server %s received request and it shouldn't have", name)
		w.Write([]byte(name))
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		t.Errorf("Server %s received request and it shouldn't have", name)
		w.Write([]byte(name))
	})

	req := NewUniqueEdgeGET(t)

	var expectedBody string
	for requestCount := 1; requestCount < 6; requestCount++ {
		switch requestCount {
		case 1: // Request 1 populates cache.
			expectedBody = expectedResponseStale

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.Header().Set("Cache-Control", headerValue)
				w.Write([]byte(expectedBody))
			})
		case 2: // Requests 2,3,4 come from stale.
			time.Sleep(respTTLWithBuffer)
			expectedBody = expectedResponseStale

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.WriteHeader(http.StatusServiceUnavailable)
				w.Write([]byte(originServer.Name))
			})
		case 5: // Last request comes directly from origin again.
			time.Sleep(waitSaintMode)
			expectedBody = expectedResponseFresh

			originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
				w.Write([]byte(expectedBody))
			})
		}

		resp := RoundTripCheckError(t, req)

		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			t.Fatal(err)
		}
		if bodyStr := string(body); bodyStr != expectedBody {
			t.Errorf(
				"Request %d received incorrect response body. Expected %q, got %q",
				requestCount,
				expectedBody,
				bodyStr,
			)
		}
	}
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	expectedBody := "lucky golden ticket"
	expectedStatus := http.StatusOK
	backendsSawRequest := map[string]bool{}

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := originServer.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		if !backendsSawRequest[name] {
			w.Write([]byte(expectedBody))
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
			w.Write([]byte(name))
		}
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		t.Errorf("Server %s received a request and it shouldn't have", name)
		w.Write([]byte(name))
	})

	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)

	if resp.StatusCode != expectedStatus {
		t.Errorf(
			"Received incorrect status code. Expected %d, got %d",
			expectedStatus,
			resp.StatusCode,
		)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if bodyStr := string(body); bodyStr != expectedBody {
		t.Errorf(
			"Received incorrect response body. Expected %q, got %q",
			expectedBody,
			bodyStr,
		)
	}
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	expectedBody := "lucky golden ticket"
	expectedStatus := http.StatusOK
	backendsSawRequest := map[string]bool{}

	originServer.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := originServer.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer1.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer1.Name
		if !backendsSawRequest[name] {
			w.WriteHeader(http.StatusServiceUnavailable)
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
		}
		w.Write([]byte(name))
	})
	backupServer2.SwitchHandler(func(w http.ResponseWriter, r *http.Request) {
		name := backupServer2.Name
		if !backendsSawRequest[name] {
			w.Write([]byte(expectedBody))
			backendsSawRequest[name] = true
		} else {
			t.Errorf("Server %s received more than one request", name)
			w.Write([]byte(name))
		}
	})

	req := NewUniqueEdgeGET(t)
	resp := RoundTripCheckError(t, req)

	if resp.StatusCode != expectedStatus {
		t.Errorf(
			"Received incorrect status code. Expected %d, got %d",
			expectedStatus,
			resp.StatusCode,
		)
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		t.Fatal(err)
	}
	if bodyStr := string(body); bodyStr != expectedBody {
		t.Errorf(
			"Received incorrect response body. Expected %q, got %q",
			expectedBody,
			bodyStr,
		)
	}
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}
<|endoftext|>


<commit_before>package epochs

import (
	"math/big"
	"time"
)

// Epoch gets a Unix time of the given x after dividing by q and
// adding s.
func epoch(x, q, s *big.Int) time.Time {
	z := new(big.Int)
	m := new(big.Int)
	z.DivMod(x, q, m)
	z.Add(z, s)
	r := m.Mul(m, big.NewInt(1e9)).Div(m, q)
	return time.Unix(z.Int64(), r.Int64()).UTC()
}

// Chrome time is the number of microseconds since 1601-01-01, which
// is 11,644,473,600 seconds before the Unix epoch.
func Chrome(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1e6), big.NewInt(-11644473600))
}

// Unix time is the number of seconds since 1970-01-01.
func Unix(num int64) time.Time {
	return time.Unix(num, 0).UTC()
}
<commit_msg>add cocoa time<commit_after>package epochs

import (
	"math/big"
	"time"
)

// Epoch gets a Unix time of the given x after dividing by q and
// adding s.
func epoch(x, q, s *big.Int) time.Time {
	z := new(big.Int)
	m := new(big.Int)
	z.DivMod(x, q, m)
	z.Add(z, s)
	r := m.Mul(m, big.NewInt(1e9)).Div(m, q)
	return time.Unix(z.Int64(), r.Int64()).UTC()
}

// Chrome time is the number of microseconds since 1601-01-01, which
// is 11,644,473,600 seconds before the Unix epoch.
func Chrome(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1e6), big.NewInt(-11644473600))
}

// Cocoa time is the number of seconds since 2001-01-01, which
// is 978,307,200 seconds after the Unix epoch.
func Cocoa(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1), big.NewInt(978307200))
}

// Unix time is the number of seconds since 1970-01-01.
func Unix(num int64) time.Time {
	return time.Unix(num, 0).UTC()
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package api

// TODO(ericsnow) Eliminate the params import if possible.

import (
	"github.com/juju/errors"

	"github.com/juju/juju/apiserver/params"
)

// BulkFailure indicates that at least one arg failed.
var BulkFailure = errors.Errorf("at least one bulk arg has an error")

// RegisterProcessArgs are the arguments for the RegisterProcesses endpoint.
type RegisterProcessesArgs struct {
	// Processes is the list of Processes to register
	Processes []Process
}

// ProcessResults is the result for a call that makes one or more requests
// about processes.
type ProcessResults struct {
	// Results is the list of results.
	Results []ProcessResult
	// Error is the error (if any) for the call as a whole.
	Error *params.Error
}

// ProcessResult contains the result for a single call.
type ProcessResult struct {
	// ID is the id of the process referenced in the call..
	ID string
	// Error is the error (if any) for the call referring to ID.
	Error *params.Error
}

// ListProcessesesArgs are the arguments for the ListProcesses endpoint.
type ListProcessesArgs struct {
	// IDs is the list of IDs of the processes you want information on.
	IDs []string
}

// ListProcessesResults contains the results for a call to ListProcesses.
type ListProcessesResults struct {
	// Results is the list of process results.
	Results []ListProcessResult
	// Error is the error (if any) for the call as a whole.
	Error *params.Error
}

// ListProcessResult contains the results for a single call to ListProcess.
type ListProcessResult struct {
	// ID is the id of the process this result applies to.
	ID string
	// Info holds the details of the process.
	Info Process
	// NotFound indicates that the process was not found in state.
	NotFound bool
	// Error holds the error retrieving this information (if any).
	Error *params.Error
}

// ListDefinitionsResults contains the results for a call to ListDefinitions.
type ListDefinitionsResults struct {
	// Results is the list of definition results.
	Results []ProcessDefinition
	// Error is the error (if any) for the call as a whole.
	Error *params.Error
}

// SetProcessesStatusArgs are the arguments for the SetProcessesStatus endpoint.
type SetProcessesStatusArgs struct {
	// Args is the list of arguments to pass to this function.
	Args []SetProcessStatusArg
}

// SetProcessStatusArg are the arguments for a single call to the
// SetProcessStatus endpoint.
type SetProcessStatusArg struct {
	// ID is the ID of the process.
	ID string
	// Status is the status of the process.
	Status ProcessStatus
	// PluginStatus is the plugin-provided status of the process.
	PluginStatus PluginStatus
}

// UnregisterProcessesArgs are the arguments for the UnregisterProcesses endpoint.
type UnregisterProcessesArgs struct {
	// IDs is a list of IDs of processes.
	IDs []string
}

// Process contains information about a workload process.
type Process struct {
	// Process is information about the process itself.
	Definition ProcessDefinition
	// Status is the Juju-level status for the process.
	Status ProcessStatus
	// Details are the information returned from starting the process.
	Details ProcessDetails
}

// ProcessDefinition is the static definition of a workload process in a charm.
type ProcessDefinition struct {
	// Name is the name of the process.
	Name string
	// Description is a brief description of the process.
	Description string
	// Type is the name of the process type.
	Type string
	// TypeOptions is a map of arguments for the process type.
	TypeOptions map[string]string
	// Command is use command executed used by the process, if any.
	Command string
	// Image is the image used by the process, if any.
	Image string
	// Ports is a list of ProcessPort.
	Ports []ProcessPort
	// Volumes is a list of ProcessVolume.
	Volumes []ProcessVolume
	// EnvVars is map of environment variables used by the process.
	EnvVars map[string]string
}

// ProcessPort is network port information for a workload process.
type ProcessPort struct {
	// External is the port on the host.
	External int
	// Internal is the port on the process.
	Internal int
	// Endpoint is the unit-relation endpoint matching the external
	// port, if any.
	Endpoint string
}

// ProcessVolume is storage volume information for a workload process.
type ProcessVolume struct {
	// ExternalMount is the path on the host.
	ExternalMount string
	// InternalMount is the path on the process.
	InternalMount string
	// Mode is the "ro" OR "rw"
	Mode string
	// Name is the name of the storage metadata entry, if any.
	Name string
}

// ProcessStatus represents the Juju-level status of the process.
type ProcessStatus struct {
	// State is the Juju-defined state the process is in.
	State string
	// Blocker identifies the kind of blocker preventing interaction
	// with the process.
	Blocker string
	// Message is the human-readable information about the status of
	// the process.
	Message string
}

// ProcessDetails represents information about a process launched by a plugin.
type ProcessDetails struct {
	// ID is a unique string identifying the process to the plugin.
	ID string
	// Status is the status of the process after launch.
	Status PluginStatus
}

// PluginStatus represents the plugin-defined status for the process.
type PluginStatus struct {
	// State represents the human-readable label returned by the plugin for
	// the process that represents the status of the workload process.
	State string
}
<commit_msg>more rename<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package api

// TODO(ericsnow) Eliminate the params import if possible.

import (
	"github.com/juju/errors"

	"github.com/juju/juju/apiserver/params"
)

// BulkFailure indicates that at least one arg failed.
var BulkFailure = errors.Errorf("at least one bulk arg has an error")

// RegisterProcessArgs are the arguments for the RegisterProcesses endpoint.
type RegisterProcessesArgs struct {
	// Processes is the list of Processes to register
	Processes []Process
}

// ProcessResults is the result for a call that makes one or more requests
// about processes.
type ProcessResults struct {
	// Results is the list of results.
	Results []ProcessResult
	// Error is the error (if any) for the call as a whole.
	Error *params.Error
}

// ProcessResult contains the result for a single call.
type ProcessResult struct {
	// ID is the id of the process referenced in the call..
	ID string
	// Error is the error (if any) for the call referring to ID.
	Error *params.Error
}

// ListProcessesesArgs are the arguments for the ListProcesses endpoint.
type ListProcessesArgs struct {
	// IDs is the list of IDs of the processes you want information on.
	IDs []string
}

// ListProcessesResults contains the results for a call to ListProcesses.
type ListProcessesResults struct {
	// Results is the list of process results.
	Results []ListProcessResult
	// Error is the error (if any) for the call as a whole.
	Error *params.Error
}

// ListProcessResult contains the results for a single call to ListProcess.
type ListProcessResult struct {
	// ID is the id of the process this result applies to.
	ID string
	// Info holds the details of the process.
	Info Process
	// NotFound indicates that the process was not found in state.
	NotFound bool
	// Error holds the error retrieving this information (if any).
	Error *params.Error
}

// ListDefinitionsResults contains the results for a call to ListDefinitions.
type ListDefinitionsResults struct {
	// Results is the list of definition results.
	Results []ProcessDefinition
	// Error is the error (if any) for the call as a whole.
	Error *params.Error
}

// SetProcessesStatusArgs are the arguments for the SetProcessesStatus endpoint.
type SetProcessesStatusArgs struct {
	// Args is the list of arguments to pass to this function.
	Args []SetProcessStatusArg
}

// SetProcessStatusArg are the arguments for a single call to the
// SetProcessStatus endpoint.
type SetProcessStatusArg struct {
	// ID is the ID of the process.
	ID string
	// Status is the status of the process.
	Status ProcessStatus
	// PluginStatus is the plugin-provided status of the process.
	PluginStatus PluginStatus
}

// UntrackArgs are the arguments for the Untrack endpoint.
type UntrackArgs struct {
	// IDs is a list of IDs of processes.
	IDs []string
}

// Process contains information about a workload process.
type Process struct {
	// Process is information about the process itself.
	Definition ProcessDefinition
	// Status is the Juju-level status for the process.
	Status ProcessStatus
	// Details are the information returned from starting the process.
	Details ProcessDetails
}

// ProcessDefinition is the static definition of a workload process in a charm.
type ProcessDefinition struct {
	// Name is the name of the process.
	Name string
	// Description is a brief description of the process.
	Description string
	// Type is the name of the process type.
	Type string
	// TypeOptions is a map of arguments for the process type.
	TypeOptions map[string]string
	// Command is use command executed used by the process, if any.
	Command string
	// Image is the image used by the process, if any.
	Image string
	// Ports is a list of ProcessPort.
	Ports []ProcessPort
	// Volumes is a list of ProcessVolume.
	Volumes []ProcessVolume
	// EnvVars is map of environment variables used by the process.
	EnvVars map[string]string
}

// ProcessPort is network port information for a workload process.
type ProcessPort struct {
	// External is the port on the host.
	External int
	// Internal is the port on the process.
	Internal int
	// Endpoint is the unit-relation endpoint matching the external
	// port, if any.
	Endpoint string
}

// ProcessVolume is storage volume information for a workload process.
type ProcessVolume struct {
	// ExternalMount is the path on the host.
	ExternalMount string
	// InternalMount is the path on the process.
	InternalMount string
	// Mode is the "ro" OR "rw"
	Mode string
	// Name is the name of the storage metadata entry, if any.
	Name string
}

// ProcessStatus represents the Juju-level status of the process.
type ProcessStatus struct {
	// State is the Juju-defined state the process is in.
	State string
	// Blocker identifies the kind of blocker preventing interaction
	// with the process.
	Blocker string
	// Message is the human-readable information about the status of
	// the process.
	Message string
}

// ProcessDetails represents information about a process launched by a plugin.
type ProcessDetails struct {
	// ID is a unique string identifying the process to the plugin.
	ID string
	// Status is the status of the process after launch.
	Status PluginStatus
}

// PluginStatus represents the plugin-defined status for the process.
type PluginStatus struct {
	// State represents the human-readable label returned by the plugin for
	// the process that represents the status of the workload process.
	State string
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 inspectors

import (
	"flag"
	"time"

	log "github.com/cihub/seelog"
	"github.com/mitchellh/cli"

	inspector "github.com/osrg/earthquake/earthquake/inspector/proc"
)

type procFlags struct {
	commonFlags
	RootPID       int
	WatchInterval time.Duration
}

var (
	procFlagset = flag.NewFlagSet("proc", flag.ExitOnError)
	_procFlags  = procFlags{}
)

func init() {
	initCommon(procFlagset, &_procFlags.commonFlags, "_earthquake_proc_inspector")
	procFlagset.IntVar(&_procFlags.RootPID, "root-pid", -1, "PID for the target process tree")
	procFlagset.DurationVar(&_procFlags.WatchInterval, "watch-interval", 1*time.Second, "Watching interval")
}

type procCmd struct {
}

func ProcCommandFactory() (cli.Command, error) {
	return procCmd{}, nil
}

func (cmd procCmd) Help() string {
	return "Please run `earthquake --help inspectors` instead"
}

func (cmd procCmd) Synopsis() string {
	return "Start process inspector"
}

func (cmd procCmd) Run(args []string) int {
	if err := procFlagset.Parse(args); err != nil {
		log.Critical(err)
		return 1
	}

	if _procFlags.RootPID <= 0 {
		log.Critical("root-pid is not set (or set to non-positive value)")
		return 1
	}

	autopilot, err := conditionalStartAutopilotOrchestrator(_fsFlags.commonFlags)
	if err != nil {
		log.Critical(err)
		return 1
	}
	log.Infof("Autopilot-mode: %t", autopilot)

	procInspector := &inspector.ProcInspector{
		OrchestratorURL: _procFlags.OrchestratorURL,
		EntityID:        _procFlags.EntityID,
		RootPID:         _procFlags.RootPID,
		WatchInterval:   _procFlags.WatchInterval,
	}

	if err := procInspector.Serve(); err != nil {
		panic(log.Critical(err))
	}

	// NOTREACHED
	return 0
}
<commit_msg>cli: fix typo<commit_after>// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
//
// 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 inspectors

import (
	"flag"
	"time"

	log "github.com/cihub/seelog"
	"github.com/mitchellh/cli"

	inspector "github.com/osrg/earthquake/earthquake/inspector/proc"
)

type procFlags struct {
	commonFlags
	RootPID       int
	WatchInterval time.Duration
}

var (
	procFlagset = flag.NewFlagSet("proc", flag.ExitOnError)
	_procFlags  = procFlags{}
)

func init() {
	initCommon(procFlagset, &_procFlags.commonFlags, "_earthquake_proc_inspector")
	procFlagset.IntVar(&_procFlags.RootPID, "root-pid", -1, "PID for the target process tree")
	procFlagset.DurationVar(&_procFlags.WatchInterval, "watch-interval", 1*time.Second, "Watching interval")
}

type procCmd struct {
}

func ProcCommandFactory() (cli.Command, error) {
	return procCmd{}, nil
}

func (cmd procCmd) Help() string {
	return "Please run `earthquake --help inspectors` instead"
}

func (cmd procCmd) Synopsis() string {
	return "Start process inspector"
}

func (cmd procCmd) Run(args []string) int {
	if err := procFlagset.Parse(args); err != nil {
		log.Critical(err)
		return 1
	}

	if _procFlags.RootPID <= 0 {
		log.Critical("root-pid is not set (or set to non-positive value)")
		return 1
	}

	autopilot, err := conditionalStartAutopilotOrchestrator(_procFlags.commonFlags)
	if err != nil {
		log.Critical(err)
		return 1
	}
	log.Infof("Autopilot-mode: %t", autopilot)

	procInspector := &inspector.ProcInspector{
		OrchestratorURL: _procFlags.OrchestratorURL,
		EntityID:        _procFlags.EntityID,
		RootPID:         _procFlags.RootPID,
		WatchInterval:   _procFlags.WatchInterval,
	}

	if err := procInspector.Serve(); err != nil {
		panic(log.Critical(err))
	}

	// NOTREACHED
	return 0
}
<|endoftext|>


<commit_before>// Package rtc provides interface to nRF5 real time counters.
package rtc

import (
	"mmio"
	"unsafe"

	"nrf5/hal/internal/mmap"
	"nrf5/hal/te"
)

// Periph represents Real Time Counter peripheral.
type Periph struct {
	te.Regs

	_         [65]mmio.U32
	counter   mmio.U32
	prescaler mmio.U32
	_         [13]mmio.U32
	cc        [4]mmio.U32
}

//emgo:const
var (
	RTC0 = (*Periph)(unsafe.Pointer(mmap.APB_BASE + 0x0b000))
	RTC1 = (*Periph)(unsafe.Pointer(mmap.APB_BASE + 0x11000))
	RTC2 = (*Periph)(unsafe.Pointer(mmap.APB_BASE + 0x24000))
)

type Task byte

const (
	START      Task = 0 // Start RTC COUNTER.
	STOP       Task = 1 // Stop RTC COUNTER.
	CLEAR      Task = 2 // Clear RTC COUNTER.
	TRIGOVRFLW Task = 3 // Store COUNTER to 0xFFFFF0.
)

type Event byte

const (
	TICK     Event = 0  // Event on COUNTER increment.
	OVRFLW   Event = 1  // Event on COUNTER overflow.
	COMPARE0 Event = 16 // Compare event on CC[0] match.
	COMPARE1 Event = 17 // Compare event on CC[1] match.
	COMPARE2 Event = 18 // Compare event on CC[2] match.
	COMPARE3 Event = 19 // Compare event on CC[3] match.
)

func (p *Periph) Task(t Task) *te.Task    { return p.Regs.Task(int(t)) }
func (p *Periph) Event(e Event) *te.Event { return p.Regs.Event(int(e)) }

// LoadCOUNTER returns value of counter register.
func (p *Periph) LoadCOUNTER() uint32 {
	return p.counter.Bits(0xffffff)
}

// StoreCOUNTER stores value of counter register.
func (p *Periph) StoreCOUNTER(c uint32) {
	p.counter.Store(c)
}

// LoadPRESCALER returns value of prescaler register.
func (p *Periph) LoadPRESCALER() uint32 {
	return p.counter.Bits(0xfff)
}

// StorePRESCALER stores prescaler to pr (freq = 32768Hz/(pr+1)). Must only be used
// when the timer is stopped.
func (p *Periph) StorePRESCALER(pr int) {
	p.prescaler.Store(uint32(pr))
}

// LoadCC returns value of n-th compare register.
func (p *Periph) LoadCC(n int) uint32 {
	return p.cc[n].Bits(0xffffff)
}

// StoreCC stores n-th compare register to cc.
func (p *Periph) StoreCC(n int, cc uint32) {
	p.cc[n].Store(cc)
}
<commit_msg>nrf5/hal/rtc: Fix bug in Periph.LoadPRESCALER.<commit_after>// Package rtc provides interface to nRF5 real time counters.
package rtc

import (
	"mmio"
	"unsafe"

	"nrf5/hal/internal/mmap"
	"nrf5/hal/te"
)

// Periph represents Real Time Counter peripheral.
type Periph struct {
	te.Regs

	_         [65]mmio.U32
	counter   mmio.U32
	prescaler mmio.U32
	_         [13]mmio.U32
	cc        [4]mmio.U32
}

//emgo:const
var (
	RTC0 = (*Periph)(unsafe.Pointer(mmap.APB_BASE + 0x0b000))
	RTC1 = (*Periph)(unsafe.Pointer(mmap.APB_BASE + 0x11000))
	RTC2 = (*Periph)(unsafe.Pointer(mmap.APB_BASE + 0x24000))
)

type Task byte

const (
	START      Task = 0 // Start RTC COUNTER.
	STOP       Task = 1 // Stop RTC COUNTER.
	CLEAR      Task = 2 // Clear RTC COUNTER.
	TRIGOVRFLW Task = 3 // Store COUNTER to 0xFFFFF0.
)

type Event byte

const (
	TICK     Event = 0  // Event on COUNTER increment.
	OVRFLW   Event = 1  // Event on COUNTER overflow.
	COMPARE0 Event = 16 // Compare event on CC[0] match.
	COMPARE1 Event = 17 // Compare event on CC[1] match.
	COMPARE2 Event = 18 // Compare event on CC[2] match.
	COMPARE3 Event = 19 // Compare event on CC[3] match.
)

func (p *Periph) Task(t Task) *te.Task    { return p.Regs.Task(int(t)) }
func (p *Periph) Event(e Event) *te.Event { return p.Regs.Event(int(e)) }

// LoadCOUNTER returns value of counter register.
func (p *Periph) LoadCOUNTER() uint32 {
	return p.counter.Bits(0xffffff)
}

// StoreCOUNTER stores value of counter register.
func (p *Periph) StoreCOUNTER(c uint32) {
	p.counter.Store(c)
}

// LoadPRESCALER returns value of prescaler register.
func (p *Periph) LoadPRESCALER() uint32 {
	return p.prescaler.Bits(0xfff)
}

// StorePRESCALER stores prescaler to pr (freq = 32768Hz/(pr+1)). Must only be used
// when the timer is stopped.
func (p *Periph) StorePRESCALER(pr int) {
	p.prescaler.Store(uint32(pr))
}

// LoadCC returns value of n-th compare register.
func (p *Periph) LoadCC(n int) uint32 {
	return p.cc[n].Bits(0xffffff)
}

// StoreCC stores n-th compare register to cc.
func (p *Periph) StoreCC(n int, cc uint32) {
	p.cc[n].Store(cc)
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/log"
)

func runArtifactUpload(w *currentWorker) BuiltInAction {
	if w.currentJob.wJob == nil {
		return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
			res := sdk.Result{Status: sdk.StatusSuccess.String()}

			pipeline := sdk.ParameterValue(*params, "cds.pipeline")
			project := sdk.ParameterValue(*params, "cds.project")
			application := sdk.ParameterValue(*params, "cds.application")
			environment := sdk.ParameterValue(*params, "cds.environment")
			buildNumberString := sdk.ParameterValue(*params, "cds.buildNumber")

			path := sdk.ParameterValue(a.Parameters, "path")
			if path == "" {
				path = "."
			}

			tag := sdk.ParameterFind(a.Parameters, "tag")
			if tag == nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("tag variable is empty. aborting")
				sendLog(res.Reason)
				return res
			}
			tag.Value = strings.Replace(tag.Value, "/", "-", -1)
			tag.Value = url.QueryEscape(tag.Value)

			// Global all files matching filePath
			filesPath, err := filepath.Glob(path)
			if err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("cannot perform globbing of pattern '%s': %s", path, err)
				sendLog(res.Reason)
				return res
			}

			if len(filesPath) == 0 {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("Pattern '%s' matched no file", path)
				sendLog(res.Reason)
				return res
			}

			buildNumber, errBN := strconv.Atoi(buildNumberString)
			if errBN != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("BuilNumber is not an integer %s\n", errBN)
				sendLog(res.Reason)
				return res
			}

			for _, filePath := range filesPath {
				filename := filepath.Base(filePath)
				sendLog(fmt.Sprintf("Uploading '%s'", filename))
				if err := sdk.UploadArtifact(project, pipeline, application, tag.Value, filePath, buildNumber, environment); err != nil {
					res.Status = sdk.StatusFail.String()
					res.Reason = fmt.Sprintf("Error while uploading artefact: %s\n", err)
					sendLog(res.Reason)
					return res
				}
			}

			return res
		}
	}

	return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
		res := sdk.Result{Status: sdk.StatusSuccess.String()}

		path := sdk.ParameterValue(a.Parameters, "path")
		if path == "" {
			path = "."
		}

		tag := sdk.ParameterFind(a.Parameters, "tag")
		if tag == nil {
			res.Status = sdk.StatusFail.String()
			res.Reason = fmt.Sprintf("tag variable is empty. aborting")
			sendLog(res.Reason)
			return res
		}
		tag.Value = strings.Replace(tag.Value, "/", "-", -1)
		tag.Value = url.QueryEscape(tag.Value)

		// Global all files matching filePath
		filesPath, err := filepath.Glob(path)
		if err != nil {
			res.Status = sdk.StatusFail.String()
			res.Reason = fmt.Sprintf("cannot perform globbing of pattern '%s': %s", path, err)
			sendLog(res.Reason)
			return res
		}

		if len(filesPath) == 0 {
			res.Status = sdk.StatusFail.String()
			res.Reason = fmt.Sprintf("Pattern '%s' matched no file", path)
			sendLog(res.Reason)
			return res
		}

		for _, filePath := range filesPath {
			filename := filepath.Base(filePath)
			sendLog(fmt.Sprintf("Uploading '%s'\n", filename))
			if err := w.client.QueueArtifactUpload(buildID, tag.Value, filePath); err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("Error while uploading artefact: %s\n", err)
				sendLog(res.Reason)
				return res
			}
		}

		return res
	}
}

func runArtifactDownload(w *currentWorker) BuiltInAction {
	if w.currentJob.wJob == nil {
		return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
			res := sdk.Result{Status: sdk.StatusSuccess.String()}

			project := sdk.ParameterValue(*params, "cds.project")
			environment := sdk.ParameterValue(*params, "cds.environment")
			enabled := sdk.ParameterValue(*params, "enabled") != "false"

			application := sdk.ParameterValue(a.Parameters, "application")
			pipeline := sdk.ParameterValue(a.Parameters, "pipeline")
			path := sdk.ParameterValue(a.Parameters, "path")
			tag := sdk.ParameterValue(a.Parameters, "tag")

			if !enabled {
				sendLog("Artifact Download is disabled.")
				return res
			}

			if tag == "" {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("tag variable is empty. aborting")
				sendLog(res.Reason)
				return res
			}
			tag = strings.Replace(tag, "/", "-", -1)
			tag = url.QueryEscape(tag)

			if pipeline == "" {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("pipeline variable is empty. aborting\n")
				sendLog(res.Reason)
				return res
			}

			sendLog(fmt.Sprintf("Downloading artifacts from into '%s'...", path))
			if err := sdk.DownloadArtifacts(project, application, pipeline, tag, path, environment); err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = err.Error()
				log.Warning("Cannot download artifacts: %s", err)
				sendLog(res.Reason)
				return res
			}

			return res
		}
	}

	return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
		res := sdk.Result{Status: sdk.StatusSuccess.String()}

		project := sdk.ParameterValue(*params, "cds.project")
		workflow := sdk.ParameterValue(*params, "cds.workflow")
		number := sdk.ParameterValue(*params, "cds.run.number")
		enabled := sdk.ParameterValue(*params, "enabled") != "false"

		path := sdk.ParameterValue(a.Parameters, "path")
		tag := sdk.ParameterValue(a.Parameters, "tag")

		if !enabled {
			sendLog("Artifact Download is disabled.")
			return res
		}

		if tag != "" {
			sendLog("tag variable can not be used with CDS Workflow. Please remove-it")
		}

		sendLog(fmt.Sprintf("Downloading artifacts from workflow into '%s'...", path))

		n, err := strconv.ParseInt(number, 10, 64)
		if err != nil {
			res.Status = sdk.StatusFail.String()
			res.Reason = fmt.Sprintf("cds.run.nubmer variable is not valid. aborting")
			sendLog(res.Reason)
			return res
		}
		artifacts, err := w.client.WorkflowRunArtifacts(project, workflow, n)
		if err != nil {
			res.Status = sdk.StatusFail.String()
			res.Reason = err.Error()
			log.Warning("Cannot download artifacts: %s", err)
			sendLog(res.Reason)
			return res
		}

		for _, a := range artifacts {
			f, err := os.OpenFile(a.Name, os.O_RDWR|os.O_CREATE, os.FileMode(a.Perm))
			if err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = err.Error()
				log.Warning("Cannot download artifacts (OpenFile): %s", err)
				sendLog(res.Reason)
				return res
			}
			if err := w.client.WorkflowNodeRunArtifactDownload(project, workflow, a.ID, f); err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = err.Error()
				log.Warning("Cannot download artifacts: %s", err)
				sendLog(res.Reason)
				return res
			}
			if err := f.Close(); err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = err.Error()
				log.Warning("Cannot download artifacts: %s", err)
				sendLog(res.Reason)
				return res
			}
		}

		return res
	}
}
<commit_msg>feat (worker): more logs on artifact download (#1088)<commit_after>package main

import (
	"context"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/ovh/cds/sdk"
	"github.com/ovh/cds/sdk/log"
)

func runArtifactUpload(w *currentWorker) BuiltInAction {
	if w.currentJob.wJob == nil {
		return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
			res := sdk.Result{Status: sdk.StatusSuccess.String()}

			pipeline := sdk.ParameterValue(*params, "cds.pipeline")
			project := sdk.ParameterValue(*params, "cds.project")
			application := sdk.ParameterValue(*params, "cds.application")
			environment := sdk.ParameterValue(*params, "cds.environment")
			buildNumberString := sdk.ParameterValue(*params, "cds.buildNumber")

			path := sdk.ParameterValue(a.Parameters, "path")
			if path == "" {
				path = "."
			}

			tag := sdk.ParameterFind(a.Parameters, "tag")
			if tag == nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("tag variable is empty. aborting")
				sendLog(res.Reason)
				return res
			}
			tag.Value = strings.Replace(tag.Value, "/", "-", -1)
			tag.Value = url.QueryEscape(tag.Value)

			// Global all files matching filePath
			filesPath, err := filepath.Glob(path)
			if err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("cannot perform globbing of pattern '%s': %s", path, err)
				sendLog(res.Reason)
				return res
			}

			if len(filesPath) == 0 {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("Pattern '%s' matched no file", path)
				sendLog(res.Reason)
				return res
			}

			buildNumber, errBN := strconv.Atoi(buildNumberString)
			if errBN != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("BuilNumber is not an integer %s\n", errBN)
				sendLog(res.Reason)
				return res
			}

			for _, filePath := range filesPath {
				filename := filepath.Base(filePath)
				sendLog(fmt.Sprintf("Uploading '%s'", filename))
				if err := sdk.UploadArtifact(project, pipeline, application, tag.Value, filePath, buildNumber, environment); err != nil {
					res.Status = sdk.StatusFail.String()
					res.Reason = fmt.Sprintf("Error while uploading artefact: %s\n", err)
					sendLog(res.Reason)
					return res
				}
			}

			return res
		}
	}

	return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
		res := sdk.Result{Status: sdk.StatusSuccess.String()}

		path := sdk.ParameterValue(a.Parameters, "path")
		if path == "" {
			path = "."
		}

		tag := sdk.ParameterFind(a.Parameters, "tag")
		if tag == nil {
			res.Status = sdk.StatusFail.String()
			res.Reason = fmt.Sprintf("tag variable is empty. aborting")
			sendLog(res.Reason)
			return res
		}
		tag.Value = strings.Replace(tag.Value, "/", "-", -1)
		tag.Value = url.QueryEscape(tag.Value)

		// Global all files matching filePath
		filesPath, err := filepath.Glob(path)
		if err != nil {
			res.Status = sdk.StatusFail.String()
			res.Reason = fmt.Sprintf("cannot perform globbing of pattern '%s': %s", path, err)
			sendLog(res.Reason)
			return res
		}

		if len(filesPath) == 0 {
			res.Status = sdk.StatusFail.String()
			res.Reason = fmt.Sprintf("Pattern '%s' matched no file", path)
			sendLog(res.Reason)
			return res
		}

		for _, filePath := range filesPath {
			filename := filepath.Base(filePath)
			sendLog(fmt.Sprintf("Uploading '%s'\n", filename))
			if err := w.client.QueueArtifactUpload(buildID, tag.Value, filePath); err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("Error while uploading artefact: %s\n", err)
				sendLog(res.Reason)
				return res
			}
		}

		return res
	}
}

func runArtifactDownload(w *currentWorker) BuiltInAction {
	if w.currentJob.wJob == nil {
		return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
			res := sdk.Result{Status: sdk.StatusSuccess.String()}

			project := sdk.ParameterValue(*params, "cds.project")
			environment := sdk.ParameterValue(*params, "cds.environment")
			enabled := sdk.ParameterValue(*params, "enabled") != "false"

			application := sdk.ParameterValue(a.Parameters, "application")
			pipeline := sdk.ParameterValue(a.Parameters, "pipeline")
			path := sdk.ParameterValue(a.Parameters, "path")
			tag := sdk.ParameterValue(a.Parameters, "tag")

			if !enabled {
				sendLog("Artifact Download is disabled.")
				return res
			}

			if tag == "" {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("tag variable is empty. aborting")
				sendLog(res.Reason)
				return res
			}
			tag = strings.Replace(tag, "/", "-", -1)
			tag = url.QueryEscape(tag)

			if pipeline == "" {
				res.Status = sdk.StatusFail.String()
				res.Reason = fmt.Sprintf("pipeline variable is empty. aborting\n")
				sendLog(res.Reason)
				return res
			}

			sendLog(fmt.Sprintf("Downloading artifacts from into '%s'...", path))
			if err := sdk.DownloadArtifacts(project, application, pipeline, tag, path, environment); err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = err.Error()
				log.Warning("Cannot download artifacts: %s", err)
				sendLog(res.Reason)
				return res
			}

			return res
		}
	}

	return func(ctx context.Context, a *sdk.Action, buildID int64, params *[]sdk.Parameter, sendLog LoggerFunc) sdk.Result {
		res := sdk.Result{Status: sdk.StatusSuccess.String()}

		project := sdk.ParameterValue(*params, "cds.project")
		workflow := sdk.ParameterValue(*params, "cds.workflow")
		number := sdk.ParameterValue(*params, "cds.run.number")
		enabled := sdk.ParameterValue(*params, "enabled") != "false"

		path := sdk.ParameterValue(a.Parameters, "path")
		tag := sdk.ParameterValue(a.Parameters, "tag")

		if !enabled {
			sendLog("Artifact Download is disabled.")
			return res
		}

		if tag != "" {
			sendLog("tag variable can not be used with CDS Workflow - ignored.")
		}

		sendLog(fmt.Sprintf("Downloading artifacts from workflow into '%s'...", path))

		n, err := strconv.ParseInt(number, 10, 64)
		if err != nil {
			res.Status = sdk.StatusFail.String()
			res.Reason = fmt.Sprintf("cds.run.number variable is not valid. aborting")
			sendLog(res.Reason)
			return res
		}
		artifacts, err := w.client.WorkflowRunArtifacts(project, workflow, n)
		if err != nil {
			res.Status = sdk.StatusFail.String()
			res.Reason = err.Error()
			log.Warning("Cannot download artifacts: %s", err)
			sendLog(res.Reason)
			return res
		}

		for _, a := range artifacts {
			f, err := os.OpenFile(a.Name, os.O_RDWR|os.O_CREATE, os.FileMode(a.Perm))
			if err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = err.Error()
				log.Warning("Cannot download artifact (OpenFile) %s: %s", a.Name, err)
				sendLog(res.Reason)
				return res
			}
			sendLog(fmt.Sprintf("downloading artifact %s from workflow %s/%s on run %d...", a.Name, project, workflow, n))
			if err := w.client.WorkflowNodeRunArtifactDownload(project, workflow, a.ID, f); err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = err.Error()
				log.Warning("Cannot download artifact %s: %s", a.Name, err)
				sendLog(res.Reason)
				return res
			}
			if err := f.Close(); err != nil {
				res.Status = sdk.StatusFail.String()
				res.Reason = err.Error()
				log.Warning("Cannot download artifact %s: %s", a.Name, err)
				sendLog(res.Reason)
				return res
			}
		}

		return res
	}
}
<|endoftext|>