<commit_before>// Copyright (c) 2018 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package ticketbuyer

import (
	"context"
	"sync"

	"github.com/decred/dcrd/chaincfg/chainhash"
	"github.com/decred/dcrd/dcrutil"
	"github.com/decred/dcrwallet/errors"
	"github.com/decred/dcrwallet/wallet"
)

const minconf = 1

// Config modifies the behavior of TB.
type Config struct {
	// Account to buy tickets from
	Account uint32

	// Account to derive voting addresses from; overridden by VotingAddr
	VotingAccount uint32

	// Minimum amount to maintain in purchasing account
	Maintain dcrutil.Amount

	// Address to assign voting rights; overrides VotingAccount
	VotingAddr dcrutil.Address

	// Commitment address for stakepool fees
	PoolFeeAddr dcrutil.Address

	// Stakepool fee percentage (between 0-100)
	PoolFees float64
}

// TB is an automated ticket buyer, buying as many tickets as possible given an
// account's available balance.  TB may be configured to buy tickets for any
// arbitrary voting address or (optional) stakepool.
type TB struct {
	wallet *wallet.Wallet

	cfg Config
	mu  sync.Mutex
}

// New returns a new TB to buy tickets from a wallet using the default config.
func New(w *wallet.Wallet) *TB {
	return &TB{wallet: w}
}

// Run executes the ticket buyer.  If the private passphrase is incorrect, or
// ever becomes incorrect due to a wallet passphrase change, Run exits with an
// errors.Passphrase error.
func (tb *TB) Run(ctx context.Context, passphrase []byte) error {
	err := tb.wallet.Unlock(passphrase, nil)
	if err != nil {
		return err
	}

	c := tb.wallet.NtfnServer.MainTipChangedNotifications()
	defer c.Done()

	var mu sync.Mutex
	var done bool
	var errc = make(chan error, 1)
	for {
		select {
		case <-ctx.Done():
			mu.Lock()
			done = true
			mu.Unlock()
			return ctx.Err()
		case n := <-c.C:
			if len(n.AttachedBlocks) == 0 {
				continue
			}
			go func() {
				defer mu.Unlock()
				mu.Lock()
				if done {
					return
				}
				b := n.AttachedBlocks[len(n.AttachedBlocks)-1]
				err := tb.buy(ctx, passphrase, b)
				if err != nil {
					log.Errorf("Ticket purchasing failed: %v", err)
					if errors.Is(errors.Passphrase, err) {
						errc <- err
						done = true
					}
				}
			}()
		case err := <-errc:
			return err
		}
	}
}

func (tb *TB) buy(ctx context.Context, passphrase []byte, tip *chainhash.Hash) error {
	w := tb.wallet

	// Don't buy tickets for this attached block when transactions are not
	// synced through the tip block.
	rp, err := w.RescanPoint()
	if err != nil {
		return err
	}
	if rp != nil {
		log.Debugf("Skipping purchase: transactions are not synced")
		return nil
	}

	// Unable to publish any transactions if the network backend is unset.
	_, err = w.NetworkBackend()
	if err != nil {
		return err
	}

	// Ensure wallet is unlocked with the current passphrase.  If the passphase
	// is changed, the Run exits and TB must be restarted with the new
	// passphrase.
	err = w.Unlock(passphrase, nil)
	if err != nil {
		return err
	}

	header, err := w.BlockHeader(tip)
	if err != nil {
		return err
	}
	height := int32(header.Height)

	intervalSize := int32(w.ChainParams().StakeDiffWindowSize)
	currentInterval := height / intervalSize
	nextIntervalStart := (currentInterval + 1) * intervalSize
	// Skip purchase when no more tickets may be purchased in this interval and
	// the next sdiff is unknown.  The earliest any ticket may be mined is two
	// blocks from now, with the next block containing the split transaction
	// that the ticket purchase spends.
	if height+2 == nextIntervalStart {
		log.Debugf("Skipping purchase: next sdiff interval starts soon")
		return nil
	}
	// Set expiry to prevent tickets from being mined in the next
	// sdiff interval.  When the next block begins the new interval,
	// the ticket is being purchased for the next interval; therefore
	// increment expiry by a full sdiff window size to prevent it
	// being mined in the interval after the next.
	expiry := nextIntervalStart
	if height+1 == nextIntervalStart {
		expiry += intervalSize
	}

	// Read config
	tb.mu.Lock()
	account := tb.cfg.Account
	votingAccount := tb.cfg.VotingAccount
	maintain := tb.cfg.Maintain
	votingAddr := tb.cfg.VotingAddr
	poolFeeAddr := tb.cfg.PoolFeeAddr
	poolFees := tb.cfg.PoolFees
	tb.mu.Unlock()

	// Determine how many tickets to buy
	bal, err := w.CalculateAccountBalance(account, minconf)
	if err != nil {
		return err
	}
	spendable := bal.Spendable
	if spendable < maintain {
		log.Debugf("Skipping purchase: low available balance")
		return nil
	}
	spendable -= maintain
	sdiff, err := w.NextStakeDifficultyAfterHeader(header)
	if err != nil {
		return err
	}
	buy := int(spendable / sdiff)
	if buy == 0 {
		log.Debugf("Skipping purchase: low available balance")
		return nil
	}
	if max := int(w.ChainParams().TicketsPerBlock); buy > max {
		buy = max
	}

	// Derive a voting address from voting account when address is unset.
	if votingAddr == nil {
		votingAddr, err = w.NewInternalAddress(votingAccount, wallet.WithGapPolicyWrap())
		if err != nil {
			return err
		}
	}

	feeRate := w.RelayFee()
	tix, err := w.PurchaseTickets(maintain, -1, minconf, votingAddr, account,
		buy, poolFeeAddr, poolFees, expiry, feeRate, feeRate)
	for _, hash := range tix {
		log.Infof("Purchased ticket %v at stake difficulty %v", hash, sdiff)
	}
	if err != nil {
		// Invalid passphrase errors must be returned so Run exits.
		if errors.Is(errors.Passphrase, err) {
			return err
		}
		log.Errorf("One or more tickets could not be purchased: %v", err)
	}
	return nil
}

// AccessConfig runs f with the current config passed as a parameter.  The
// config is protected by a mutex and this function is safe for concurrent
// access to read or modify the config.  It is unsafe to leak a pointer to the
// config, but a copy of *cfg is legal.
func (tb *TB) AccessConfig(f func(cfg *Config)) {
	tb.mu.Lock()
	f(&tb.cfg)
	tb.mu.Unlock()
}
<commit_msg>Buy max tickets mineable per block.<commit_after>// Copyright (c) 2018 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package ticketbuyer

import (
	"context"
	"sync"

	"github.com/decred/dcrd/chaincfg/chainhash"
	"github.com/decred/dcrd/dcrutil"
	"github.com/decred/dcrwallet/errors"
	"github.com/decred/dcrwallet/wallet"
)

const minconf = 1

// Config modifies the behavior of TB.
type Config struct {
	// Account to buy tickets from
	Account uint32

	// Account to derive voting addresses from; overridden by VotingAddr
	VotingAccount uint32

	// Minimum amount to maintain in purchasing account
	Maintain dcrutil.Amount

	// Address to assign voting rights; overrides VotingAccount
	VotingAddr dcrutil.Address

	// Commitment address for stakepool fees
	PoolFeeAddr dcrutil.Address

	// Stakepool fee percentage (between 0-100)
	PoolFees float64
}

// TB is an automated ticket buyer, buying as many tickets as possible given an
// account's available balance.  TB may be configured to buy tickets for any
// arbitrary voting address or (optional) stakepool.
type TB struct {
	wallet *wallet.Wallet

	cfg Config
	mu  sync.Mutex
}

// New returns a new TB to buy tickets from a wallet using the default config.
func New(w *wallet.Wallet) *TB {
	return &TB{wallet: w}
}

// Run executes the ticket buyer.  If the private passphrase is incorrect, or
// ever becomes incorrect due to a wallet passphrase change, Run exits with an
// errors.Passphrase error.
func (tb *TB) Run(ctx context.Context, passphrase []byte) error {
	err := tb.wallet.Unlock(passphrase, nil)
	if err != nil {
		return err
	}

	c := tb.wallet.NtfnServer.MainTipChangedNotifications()
	defer c.Done()

	var mu sync.Mutex
	var done bool
	var errc = make(chan error, 1)
	for {
		select {
		case <-ctx.Done():
			mu.Lock()
			done = true
			mu.Unlock()
			return ctx.Err()
		case n := <-c.C:
			if len(n.AttachedBlocks) == 0 {
				continue
			}
			go func() {
				defer mu.Unlock()
				mu.Lock()
				if done {
					return
				}
				b := n.AttachedBlocks[len(n.AttachedBlocks)-1]
				err := tb.buy(ctx, passphrase, b)
				if err != nil {
					log.Errorf("Ticket purchasing failed: %v", err)
					if errors.Is(errors.Passphrase, err) {
						errc <- err
						done = true
					}
				}
			}()
		case err := <-errc:
			return err
		}
	}
}

func (tb *TB) buy(ctx context.Context, passphrase []byte, tip *chainhash.Hash) error {
	w := tb.wallet

	// Don't buy tickets for this attached block when transactions are not
	// synced through the tip block.
	rp, err := w.RescanPoint()
	if err != nil {
		return err
	}
	if rp != nil {
		log.Debugf("Skipping purchase: transactions are not synced")
		return nil
	}

	// Unable to publish any transactions if the network backend is unset.
	_, err = w.NetworkBackend()
	if err != nil {
		return err
	}

	// Ensure wallet is unlocked with the current passphrase.  If the passphase
	// is changed, the Run exits and TB must be restarted with the new
	// passphrase.
	err = w.Unlock(passphrase, nil)
	if err != nil {
		return err
	}

	header, err := w.BlockHeader(tip)
	if err != nil {
		return err
	}
	height := int32(header.Height)

	intervalSize := int32(w.ChainParams().StakeDiffWindowSize)
	currentInterval := height / intervalSize
	nextIntervalStart := (currentInterval + 1) * intervalSize
	// Skip purchase when no more tickets may be purchased in this interval and
	// the next sdiff is unknown.  The earliest any ticket may be mined is two
	// blocks from now, with the next block containing the split transaction
	// that the ticket purchase spends.
	if height+2 == nextIntervalStart {
		log.Debugf("Skipping purchase: next sdiff interval starts soon")
		return nil
	}
	// Set expiry to prevent tickets from being mined in the next
	// sdiff interval.  When the next block begins the new interval,
	// the ticket is being purchased for the next interval; therefore
	// increment expiry by a full sdiff window size to prevent it
	// being mined in the interval after the next.
	expiry := nextIntervalStart
	if height+1 == nextIntervalStart {
		expiry += intervalSize
	}

	// Read config
	tb.mu.Lock()
	account := tb.cfg.Account
	votingAccount := tb.cfg.VotingAccount
	maintain := tb.cfg.Maintain
	votingAddr := tb.cfg.VotingAddr
	poolFeeAddr := tb.cfg.PoolFeeAddr
	poolFees := tb.cfg.PoolFees
	tb.mu.Unlock()

	// Determine how many tickets to buy
	bal, err := w.CalculateAccountBalance(account, minconf)
	if err != nil {
		return err
	}
	spendable := bal.Spendable
	if spendable < maintain {
		log.Debugf("Skipping purchase: low available balance")
		return nil
	}
	spendable -= maintain
	sdiff, err := w.NextStakeDifficultyAfterHeader(header)
	if err != nil {
		return err
	}
	buy := int(spendable / sdiff)
	if buy == 0 {
		log.Debugf("Skipping purchase: low available balance")
		return nil
	}
	if max := int(w.ChainParams().MaxFreshStakePerBlock); buy > max {
		buy = max
	}

	// Derive a voting address from voting account when address is unset.
	if votingAddr == nil {
		votingAddr, err = w.NewInternalAddress(votingAccount, wallet.WithGapPolicyWrap())
		if err != nil {
			return err
		}
	}

	feeRate := w.RelayFee()
	tix, err := w.PurchaseTickets(maintain, -1, minconf, votingAddr, account,
		buy, poolFeeAddr, poolFees, expiry, feeRate, feeRate)
	for _, hash := range tix {
		log.Infof("Purchased ticket %v at stake difficulty %v", hash, sdiff)
	}
	if err != nil {
		// Invalid passphrase errors must be returned so Run exits.
		if errors.Is(errors.Passphrase, err) {
			return err
		}
		log.Errorf("One or more tickets could not be purchased: %v", err)
	}
	return nil
}

// AccessConfig runs f with the current config passed as a parameter.  The
// config is protected by a mutex and this function is safe for concurrent
// access to read or modify the config.  It is unsafe to leak a pointer to the
// config, but a copy of *cfg is legal.
func (tb *TB) AccessConfig(f func(cfg *Config)) {
	tb.mu.Lock()
	f(&tb.cfg)
	tb.mu.Unlock()
}
<|endoftext|>


<commit_before>package terraform

import (
	"fmt"
)

// NodeOutputOrphan represents an output that is an orphan.
type NodeOutputOrphan struct {
	OutputName string
	PathValue  []string
}

func (n *NodeOutputOrphan) Name() string {
	result := fmt.Sprintf("output.%s (orphan)", n.OutputName)
	if len(n.PathValue) > 1 {
		result = fmt.Sprintf("%s.%s", modulePrefixStr(n.PathValue), result)
	}

	return result
}

// GraphNodeSubPath
func (n *NodeOutputOrphan) Path() []string {
	return n.PathValue
}

// GraphNodeEvalable
func (n *NodeOutputOrphan) EvalTree() EvalNode {
	return &EvalOpFilter{
		Ops: []walkOperation{walkRefresh, walkApply, walkDestroy},
		Node: &EvalDeleteOutput{
			Name: n.OutputName,
		},
	}
}
<commit_msg>make NodeOutputOrphan referenceable<commit_after>package terraform

import (
	"fmt"
)

// NodeOutputOrphan represents an output that is an orphan.
type NodeOutputOrphan struct {
	OutputName string
	PathValue  []string
}

func (n *NodeOutputOrphan) Name() string {
	result := fmt.Sprintf("output.%s (orphan)", n.OutputName)
	if len(n.PathValue) > 1 {
		result = fmt.Sprintf("%s.%s", modulePrefixStr(n.PathValue), result)
	}

	return result
}

// GraphNodeReferenceable
func (n *NodeOutputOrphan) ReferenceableName() []string {
	return []string{"output." + n.OutputName}
}

// GraphNodeSubPath
func (n *NodeOutputOrphan) Path() []string {
	return n.PathValue
}

// GraphNodeEvalable
func (n *NodeOutputOrphan) EvalTree() EvalNode {
	return &EvalOpFilter{
		Ops: []walkOperation{walkRefresh, walkApply, walkDestroy},
		Node: &EvalDeleteOutput{
			Name: n.OutputName,
		},
	}
}
<|endoftext|>


<commit_before>package transport

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/LUSHDigital/microservice-core-golang/transport/config"
	"github.com/LUSHDigital/microservice-core-golang/transport/domain"
)

// Resource - Useful for defining a remote resource without an attached transport.
type Resource struct {
	Branch         string        // VCS branch the service is built from.
	CurrentRequest *http.Request // Current HTTP request being actioned.
	Environment    string        // CI environment the service operates in.
	Namespace      string        // Namespace of the service.
	Name           string        // Name of the service.
	Version        int           // Major API version of the service.
}

// DNSPath returns internal dns path for the resource
func (r *Resource) DNSPath() string {
	// Make any alterations based upon the namespace.
	switch r.Namespace {
	case "aggregators":
		if !strings.HasPrefix(r.Name, config.AggregatorDomainPrefix) {
			r.Name = strings.Join([]string{config.AggregatorDomainPrefix, r.Name}, "-")
		}
	}
	// Determine the service namespace to use based on the service version.
	serviceNamespace := r.Name
	if r.Version != 0 {
		serviceNamespace = fmt.Sprintf("%r-%d", serviceNamespace, r.Version)
	}
	return serviceNamespace
}

// Service - Responsible for communication with a service.
type Service struct {
	Resource
	Client *http.Client // http client implementation
}

// NewService - prepares a new service with the provided parameters and client.
func NewService(client *http.Client, branch, env, namespace, name string) *Service {
	return &Service{
		Resource: Resource{
			Branch:      branch,
			Name:        name,
			Environment: env,
			Namespace:   namespace,
		},
		Client: client,
	}
}

// Call - Do the current service request.
func (s *Service) Call() (*http.Response, error) {
	return s.Client.Do(s.CurrentRequest)
}

// Dial - Create a request to a service resource.
func (s *Service) Dial(request *Request) error {
	var err error

	serviceNamespace := s.DNSPath()
	// Get the name of the service.
	dnsName := domain.BuildServiceDNSName(s.Name, s.Branch, s.Environment, serviceNamespace)

	// Build the resource URL.
	resourceURL := fmt.Sprintf("%s://%s/%s", request.getProtocol(), dnsName, request.Resource)

	// Append the query string if we have any.
	if len(request.Query) > 0 {
		resourceURL = fmt.Sprintf("%s?%s", resourceURL, request.Query.Encode())
	}

	// Create the request.
	s.CurrentRequest, err = http.NewRequest(request.Method, resourceURL, request.Body)

	// Add the headers.
	for key, value := range request.Headers {
		s.CurrentRequest.Header.Set(key, value)
	}

	return err
}

// GetName - Get the name of the service
func (s *Service) GetName() string {
	return s.Name
}
<commit_msg>fix incorrect printf verb<commit_after>package transport

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/LUSHDigital/microservice-core-golang/transport/config"
	"github.com/LUSHDigital/microservice-core-golang/transport/domain"
)

// Resource - Useful for defining a remote resource without an attached transport.
type Resource struct {
	Branch         string        // VCS branch the service is built from.
	CurrentRequest *http.Request // Current HTTP request being actioned.
	Environment    string        // CI environment the service operates in.
	Namespace      string        // Namespace of the service.
	Name           string        // Name of the service.
	Version        int           // Major API version of the service.
}

// DNSPath returns internal dns path for the resource
func (r *Resource) DNSPath() string {
	// Make any alterations based upon the namespace.
	switch r.Namespace {
	case "aggregators":
		if !strings.HasPrefix(r.Name, config.AggregatorDomainPrefix) {
			r.Name = strings.Join([]string{config.AggregatorDomainPrefix, r.Name}, "-")
		}
	}
	// Determine the service namespace to use based on the service version.
	serviceNamespace := r.Name
	if r.Version != 0 {
		serviceNamespace = fmt.Sprintf("%s-%d", serviceNamespace, r.Version)
	}
	return serviceNamespace
}

// Service - Responsible for communication with a service.
type Service struct {
	Resource
	Client *http.Client // http client implementation
}

// NewService - prepares a new service with the provided parameters and client.
func NewService(client *http.Client, branch, env, namespace, name string) *Service {
	return &Service{
		Resource: Resource{
			Branch:      branch,
			Name:        name,
			Environment: env,
			Namespace:   namespace,
		},
		Client: client,
	}
}

// Call - Do the current service request.
func (s *Service) Call() (*http.Response, error) {
	return s.Client.Do(s.CurrentRequest)
}

// Dial - Create a request to a service resource.
func (s *Service) Dial(request *Request) error {
	var err error

	serviceNamespace := s.DNSPath()
	// Get the name of the service.
	dnsName := domain.BuildServiceDNSName(s.Name, s.Branch, s.Environment, serviceNamespace)

	// Build the resource URL.
	resourceURL := fmt.Sprintf("%s://%s/%s", request.getProtocol(), dnsName, request.Resource)

	// Append the query string if we have any.
	if len(request.Query) > 0 {
		resourceURL = fmt.Sprintf("%s?%s", resourceURL, request.Query.Encode())
	}

	// Create the request.
	s.CurrentRequest, err = http.NewRequest(request.Method, resourceURL, request.Body)

	// Add the headers.
	for key, value := range request.Headers {
		s.CurrentRequest.Header.Set(key, value)
	}

	return err
}

// GetName - Get the name of the service
func (s *Service) GetName() string {
	return s.Name
}
<|endoftext|>


<commit_before>package transport

import (
	"sync"

	"code.google.com/p/go-uuid/uuid"
)

// InProc is the InProc implementation of the
// Transport interface.
//
// The InProc transport implements everything using in-process
// communication methods. This is useful for creating a
// service style system inside a single application for
// initial development and testing. When ready, it requires
// minimal effort to split each service into separate
// processes.
type InProc struct {
	id string
}

var callbacks = map[string]map[string][]MessageFunc{}
var queue = make(chan *BinaryMessage)
var kill = make(chan struct{})
var lock sync.RWMutex
var once sync.Once

func processMessages() {
	once.Do(func() {
		go func() {
			for {
				select {
				case bm := <-queue:
					lock.RLock()
					for _, instance := range callbacks {
						for _, cb := range instance[bm.topic] {
							cb(bm)
						}
					}
					lock.RUnlock()
				}
			}
		}()
	})
}

func init() {
	processMessages()
}

func NewInProc() *InProc {
	return &InProc{id: uuid.New()}
}

// ListenFor instructs InProc to deliver a message for the given topic
func (r *InProc) ListenFor(topic string, callback MessageFunc) error {
	lock.Lock()
	if _, ok := callbacks[r.id]; !ok {
		callbacks[r.id] = map[string][]MessageFunc{}
	}
	callbacks[r.id][topic] = append(callbacks[r.id][topic], callback)
	lock.Unlock()
	return nil
}

// Send sends a message out to InProc
func (r *InProc) Send(message *BinaryMessage) error {
	queue <- message
	return nil
}

// Start is a no-op for the InProc transport.
func (r *InProc) Start() {
}

// Stop removes all callbacks for this instance of InProc
func (r *InProc) Stop() {
	lock.Lock()
	callbacks[r.id] = map[string][]MessageFunc{}
	lock.Unlock()
}
<commit_msg>Remove leftover sync code<commit_after>package transport

import (
	"sync"

	"code.google.com/p/go-uuid/uuid"
)

// InProc is the InProc implementation of the
// Transport interface.
//
// The InProc transport implements everything using in-process
// communication methods. This is useful for creating a
// service style system inside a single application for
// initial development and testing. When ready, it requires
// minimal effort to split each service into separate
// processes.
type InProc struct {
	id string
}

var callbacks = map[string]map[string][]MessageFunc{}
var queue = make(chan *BinaryMessage)
var lock sync.RWMutex

func processMessages() {
	go func() {
		for {
			select {
			case bm := <-queue:
				lock.RLock()
				for _, instance := range callbacks {
					for _, cb := range instance[bm.topic] {
						cb(bm)
					}
				}
				lock.RUnlock()
			}
		}
	}()
}

func init() {
	processMessages()
}

func NewInProc() *InProc {
	return &InProc{id: uuid.New()}
}

// ListenFor instructs InProc to deliver a message for the given topic
func (r *InProc) ListenFor(topic string, callback MessageFunc) error {
	lock.Lock()
	if _, ok := callbacks[r.id]; !ok {
		callbacks[r.id] = map[string][]MessageFunc{}
	}
	callbacks[r.id][topic] = append(callbacks[r.id][topic], callback)
	lock.Unlock()
	return nil
}

// Send sends a message into the transport
func (r *InProc) Send(message *BinaryMessage) error {
	queue <- message
	return nil
}

// Start is a no-op for the InProc transport.
func (r *InProc) Start() {
}

// Stop removes all callbacks for this instance of InProc
func (r *InProc) Stop() {
	lock.Lock()
	callbacks[r.id] = map[string][]MessageFunc{}
	lock.Unlock()
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 keyval

import (
	"bytes"

	"github.com/gogo/protobuf/jsonpb"
	"github.com/gogo/protobuf/proto"
)

// DefaultMarshaler is the marshaler used for JSON encoding.
// It uses original names (from .proto by default).
var DefaultMarshaler = &jsonpb.Marshaler{
	OrigName: true,
}

// Serializer is used to make conversions between raw and formatted data.
// Currently supported formats are JSON and protobuf.
type Serializer interface {
	Unmarshal(data []byte, protoData proto.Message) error
	Marshal(message proto.Message) ([]byte, error)
}

// SerializerProto serializes proto message using proto serializer.
type SerializerProto struct{}

// Unmarshal deserializes data from slice of bytes into the provided protobuf
// message using proto marshaller.
func (sp *SerializerProto) Unmarshal(data []byte, protoData proto.Message) error {
	return proto.Unmarshal(data, protoData)
}

// Marshal serializes data from proto message to the slice of bytes using proto
// marshaller.
func (sp *SerializerProto) Marshal(message proto.Message) ([]byte, error) {
	return proto.Marshal(message)
}

// SerializerJSON serializes proto message using JSON serializer.
type SerializerJSON struct{}

// Unmarshal deserializes data from slice of bytes into the provided protobuf
// message using jsonpb marshaller to correctly unmarshal protobuf data.
func (sj *SerializerJSON) Unmarshal(data []byte, protoData proto.Message) error {
	return jsonpb.Unmarshal(bytes.NewBuffer(data), protoData)
}

// Marshal serializes proto message to the slice of bytes using
// jsonpb marshaller to correctly marshal protobuf data.
func (sj *SerializerJSON) Marshal(message proto.Message) ([]byte, error) {
	var buf bytes.Buffer
	if err := DefaultMarshaler.Marshal(&buf, message); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
<commit_msg>Handle nil message in json serializer<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// 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 keyval

import (
	"bytes"

	"github.com/gogo/protobuf/jsonpb"
	"github.com/gogo/protobuf/proto"
)

// DefaultMarshaler is the marshaler used for JSON encoding.
// It uses original names (from .proto by default).
var DefaultMarshaler = &jsonpb.Marshaler{
	OrigName: true,
}

// Serializer is used to make conversions between raw and formatted data.
// Currently supported formats are JSON and protobuf.
type Serializer interface {
	Unmarshal(data []byte, protoData proto.Message) error
	Marshal(message proto.Message) ([]byte, error)
}

// SerializerProto serializes proto message using proto serializer.
type SerializerProto struct{}

// Unmarshal deserializes data from slice of bytes into the provided protobuf
// message using proto marshaller.
func (sp *SerializerProto) Unmarshal(data []byte, protoData proto.Message) error {
	return proto.Unmarshal(data, protoData)
}

// Marshal serializes data from proto message to the slice of bytes using proto
// marshaller.
func (sp *SerializerProto) Marshal(message proto.Message) ([]byte, error) {
	return proto.Marshal(message)
}

// SerializerJSON serializes proto message using JSON serializer.
type SerializerJSON struct{}

// Unmarshal deserializes data from slice of bytes into the provided protobuf
// message using jsonpb marshaller to correctly unmarshal protobuf data.
func (sj *SerializerJSON) Unmarshal(data []byte, protoData proto.Message) error {
	return jsonpb.Unmarshal(bytes.NewBuffer(data), protoData)
}

// Marshal serializes proto message to the slice of bytes using
// jsonpb marshaller to correctly marshal protobuf data.
func (sj *SerializerJSON) Marshal(message proto.Message) ([]byte, error) {
	if message == nil {
		return []byte("null"), nil
	}
	var buf bytes.Buffer
	if err := DefaultMarshaler.Marshal(&buf, message); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"strconv"
	"strings"

	"github.com/ajm188/advent_of_code/pkg/cli"
)

type coordinate struct{ row, col int }

func neighbors(c *coordinate) []*coordinate {
	return []*coordinate{
		{c.row - 1, c.col},
		{c.row + 1, c.col},
		{c.row, c.col - 1},
		{c.row, c.col + 1},
		{c.row - 1, c.col - 1},
		{c.row - 1, c.col + 1},
		{c.row + 1, c.col - 1},
		{c.row + 1, c.col + 1},
	}
}

func main() {
	path := flag.String("path", "input.txt", "")
	steps := flag.Int("steps", 100, "")
	debug := flag.Bool("debug", false, "")
	flag.Parse()

	data, err := cli.GetInput(*path)
	cli.ExitOnError(err)

	var grid [][]int
	for i, line := range strings.Split(string(data), "\n") {
		if line == "" {
			continue
		}

		if len(line) != 10 {
			cli.ExitOnError(fmt.Errorf("malformed input: line %d is not length 10 (have length=%d)", i, len(line)))
		}

		var row []int
		for j, d := range line {
			num, err := strconv.ParseInt(string(d), 10, 64)
			cli.ExitOnErrorf(err, "%s on line %d:%d", err, i, j)

			row = append(row, int(num))
		}

		grid = append(grid, row)
	}

	if len(grid) != 10 {
		cli.ExitOnError(fmt.Errorf("malformed input: did not receive 10x10 grid as input"))
	}

	var flashes int
	for step := 1; step <= *steps; step++ {
		var (
			stepFlashes  int
			chainFlashes []*coordinate
		)
		for i := 0; i < len(grid); i++ {
			for j := 0; j < len(grid[i]); j++ {
				grid[i][j]++
				if grid[i][j] > 9 {
					stepFlashes++
					chainFlashes = append(chainFlashes, neighbors(&coordinate{i, j})...)
				}
			}
		}

		for len(chainFlashes) != 0 {
			var chain []*coordinate
			for _, c := range chainFlashes {
				if c.row < 0 || c.row >= len(grid) {
					continue
				}

				if c.col < 0 || c.col >= len(grid[c.row]) {
					continue
				}

				grid[c.row][c.col]++
				if grid[c.row][c.col] == 10 { // if we're above 10, we've already flashed once this step
					chain = append(chain, neighbors(c)...)
					stepFlashes++
				}
			}

			chainFlashes = chain
		}

		flashes += stepFlashes
		if *debug {
			fmt.Printf("after step %d: %d flashes\n", step, flashes)
			for _, row := range grid {
				fmt.Printf("\t%v\n", row)
			}
		}

		for i := 0; i < len(grid); i++ {
			for j := 0; j < len(grid); j++ {
				if grid[i][j] > 9 {
					grid[i][j] = 0
				}
			}
		}
	}

	fmt.Println(flashes)
}
<commit_msg>day11, part2<commit_after>package main

import (
	"flag"
	"fmt"
	"strconv"
	"strings"

	"github.com/ajm188/advent_of_code/pkg/cli"
)

type coordinate struct{ row, col int }

func neighbors(c *coordinate) []*coordinate {
	return []*coordinate{
		{c.row - 1, c.col},
		{c.row + 1, c.col},
		{c.row, c.col - 1},
		{c.row, c.col + 1},
		{c.row - 1, c.col - 1},
		{c.row - 1, c.col + 1},
		{c.row + 1, c.col - 1},
		{c.row + 1, c.col + 1},
	}
}

func main() {
	path := flag.String("path", "input.txt", "")
	steps := flag.Int("steps", 100, "")
	debug := flag.Bool("debug", false, "")
	flag.Parse()

	data, err := cli.GetInput(*path)
	cli.ExitOnError(err)

	var grid [][]int
	for i, line := range strings.Split(string(data), "\n") {
		if line == "" {
			continue
		}

		if len(line) != 10 {
			cli.ExitOnError(fmt.Errorf("malformed input: line %d is not length 10 (have length=%d)", i, len(line)))
		}

		var row []int
		for j, d := range line {
			num, err := strconv.ParseInt(string(d), 10, 64)
			cli.ExitOnErrorf(err, "%s on line %d:%d", err, i, j)

			row = append(row, int(num))
		}

		grid = append(grid, row)
	}

	if len(grid) != 10 {
		cli.ExitOnError(fmt.Errorf("malformed input: did not receive 10x10 grid as input"))
	}

	var (
		flashes   int
		firstSync *int
	)

	doStep := func(step int) {
		var (
			stepFlashes  int
			chainFlashes []*coordinate
		)
		for i := 0; i < len(grid); i++ {
			for j := 0; j < len(grid[i]); j++ {
				grid[i][j]++
				if grid[i][j] > 9 {
					stepFlashes++
					chainFlashes = append(chainFlashes, neighbors(&coordinate{i, j})...)
				}
			}
		}

		for len(chainFlashes) != 0 {
			var chain []*coordinate
			for _, c := range chainFlashes {
				if c.row < 0 || c.row >= len(grid) {
					continue
				}

				if c.col < 0 || c.col >= len(grid[c.row]) {
					continue
				}

				grid[c.row][c.col]++
				if grid[c.row][c.col] == 10 { // if we're above 10, we've already flashed once this step
					chain = append(chain, neighbors(c)...)
					stepFlashes++
				}
			}

			chainFlashes = chain
		}

		flashes += stepFlashes
		if *debug {
			fmt.Printf("after step %d: %d flashes\n", step, flashes)
			for _, row := range grid {
				fmt.Printf("\t%v\n", row)
			}
		}

		if firstSync == nil && stepFlashes == len(grid)*len(grid) {
			s := step + 1
			firstSync = &s
			if *debug {
				fmt.Printf("first synchronization after step %d", s)
			}
		}

		for i := 0; i < len(grid); i++ {
			for j := 0; j < len(grid); j++ {
				if grid[i][j] > 9 {
					grid[i][j] = 0
				}
			}
		}
	}
	for step := 1; step <= *steps; step++ {
		doStep(step)
	}

	fmt.Println(flashes)

	for step := *steps; firstSync == nil; step++ {
		doStep(step)
	}
	fmt.Println(*firstSync)
}
<|endoftext|>


<commit_before>package rules

import (
	"k8s.io/client-go/pkg/apis/apps/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"testing"
	"gopkg.in/yaml.v2"
	"github.com/magiconair/properties/assert"
)

func TestDeploymentRuleReplicas_FindNonConformingDeployment(t *testing.T) {
	deployment1 := newDeploymentWithReplicas("default", "one", int32(1))
	deployment2 := newDeploymentWithReplicas("default", "two", int32(2))
	deployments := []v1beta1.Deployment{deployment1, deployment2}

	rule := DeploymentRuleReplicasMinimum{
		MinimumReplicas: 2,
	}

	ruleResult := rule.FindNonConformingDeployment(deployments)
	assert.Equal(t, len(ruleResult.Deployments), 1)
	assert.Equal(t, ruleResult.Deployments[0].Name, "one")
}

func TestDeploymentRuleReplicas_UnmarshalYAML(t *testing.T) {
	string := `
name: minimum replicas 2
minimum_replicas: 2`

	rule := DeploymentRuleReplicasMinimum{}

	err := yaml.Unmarshal([]byte(string), &rule)

	if err != nil {
		t.Fail()
	}
	assert.Equal(t, int32(2), rule.MinimumReplicas)
}

func TestDeploymentRuleReplicas_UnmarshalYAML_NameNotFilledIn(t *testing.T) {
	string := `
minimum_replicas: 2`

	rule := DeploymentRuleReplicasMinimum{}

	err := yaml.Unmarshal([]byte(string), &rule)

	if err == nil {
		t.Fail()
	}
}

func TestDeploymentRuleReplicas_UnmarshalYAML_MinimumReplicasNotFilledIn(t *testing.T) {
	string := `
name: minimum replicas 2`

	rule := DeploymentRuleReplicasMinimum{}

	err := yaml.Unmarshal([]byte(string), &rule)

	if err == nil {
		t.Fail()
	}
}

func newDeploymentWithReplicas(namespace, name string, replicas int32) v1beta1.Deployment {
	return v1beta1.Deployment{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: namespace,
			Name:      name,
		},
		Spec: v1beta1.DeploymentSpec{
			Replicas: &replicas,
		},
	}
}
<commit_msg>Fix to tests<commit_after>package rules

import (
	"k8s.io/client-go/pkg/apis/apps/v1beta1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"testing"
	"gopkg.in/yaml.v2"
	"github.com/stretchr/testify/assert"
)

func TestDeploymentRuleReplicas_FindNonConformingDeployment(t *testing.T) {
	deployment1 := newDeploymentWithReplicas("default", "one", int32(1))
	deployment2 := newDeploymentWithReplicas("default", "two", int32(2))
	deployments := []v1beta1.Deployment{deployment1, deployment2}

	rule := DeploymentRuleReplicasMinimum{
		MinimumReplicas: 2,
	}

	ruleResult := rule.FindNonConformingDeployment(deployments)
	assert.Equal(t, len(ruleResult.Deployments), 1)
	assert.Equal(t, ruleResult.Deployments[0].Name, "one")
}

func TestDeploymentRuleReplicas_UnmarshalYAML(t *testing.T) {
	string := `
name: minimum replicas 2
minimum_replicas: 2`

	rule := DeploymentRuleReplicasMinimum{}

	err := yaml.Unmarshal([]byte(string), &rule)

	if err != nil {
		t.Fail()
	}
	assert.Equal(t, int32(2), rule.MinimumReplicas)
}

func TestDeploymentRuleReplicas_UnmarshalYAML_NameNotFilledIn(t *testing.T) {
	string := `
minimum_replicas: 2`

	rule := DeploymentRuleReplicasMinimum{}

	err := yaml.Unmarshal([]byte(string), &rule)

	if err == nil {
		t.Fail()
	}
}

func TestDeploymentRuleReplicas_UnmarshalYAML_MinimumReplicasNotFilledIn(t *testing.T) {
	string := `
name: minimum replicas 2`

	rule := DeploymentRuleReplicasMinimum{}

	err := yaml.Unmarshal([]byte(string), &rule)

	if err == nil {
		t.Fail()
	}
}

func newDeploymentWithReplicas(namespace, name string, replicas int32) v1beta1.Deployment {
	return v1beta1.Deployment{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: namespace,
			Name:      name,
		},
		Spec: v1beta1.DeploymentSpec{
			Replicas: &replicas,
		},
	}
}
<|endoftext|>


<commit_before>package tsacmd

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

	"code.cloudfoundry.org/lager"
	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/tsa"
	"github.com/concourse/flag"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"golang.org/x/crypto/ssh"
)

type TSACommand struct {
	Logger flag.Lager

	BindIP      flag.IP `long:"bind-ip"   default:"0.0.0.0" description:"IP address on which to listen for SSH."`
	PeerAddress string  `long:"peer-address" default:"127.0.0.1" description:"Network address of this web node, reachable by other web nodes. Used for forwarded worker addresses."`
	BindPort    uint16  `long:"bind-port" default:"2222"    description:"Port on which to listen for SSH."`

	DebugBindIP   flag.IP `long:"debug-bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the pprof debugger endpoints."`
	DebugBindPort uint16  `long:"debug-bind-port" default:"2221"      description:"Port on which to listen for the pprof debugger endpoints."`

	HostKey            *flag.PrivateKey               `long:"host-key"        required:"true" description:"Path to private key to use for the SSH server."`
	AuthorizedKeys     flag.AuthorizedKeys            `long:"authorized-keys" description:"Path to file containing keys to authorize, in SSH authorized_keys format (one public key per line)."`
	TeamAuthorizedKeys map[string]flag.AuthorizedKeys `long:"team-authorized-keys" value-name:"NAME:PATH" description:"Path to file containing keys to authorize, in SSH authorized_keys format (one public key per line)."`

	ATCURLs []flag.URL `long:"atc-url" required:"true" description:"ATC API endpoints to which workers will be registered."`

	SessionSigningKey *flag.PrivateKey `long:"session-signing-key" required:"true" description:"Path to private key to use when signing tokens in reqests to the ATC during registration."`

	HeartbeatInterval time.Duration `long:"heartbeat-interval" default:"30s" description:"interval on which to heartbeat workers to the ATC"`

	ClusterName    string `long:"cluster-name" description:"A name for this Concourse cluster, to be displayed on the dashboard page."`
	LogClusterName bool   `long:"log-cluster-name" description:"Log cluster name."`
}

type TeamAuthKeys struct {
	Team     string
	AuthKeys []ssh.PublicKey
}

func (cmd *TSACommand) Execute(args []string) error {
	runner, err := cmd.Runner(args)
	if err != nil {
		return err
	}

	tsaServerMember := grouper.Member{
		Name:   "tsa-server",
		Runner: sigmon.New(runner),
	}

	tsaDebugMember := grouper.Member{
		Name: "debug-server",
		Runner: http_server.New(
			cmd.debugBindAddr(),
			http.DefaultServeMux,
		)}

	members := []grouper.Member{
		tsaDebugMember,
		tsaServerMember,
	}

	group := grouper.NewParallel(os.Interrupt, members)
	return <-ifrit.Invoke(group).Wait()
}

func (cmd *TSACommand) Runner(args []string) (ifrit.Runner, error) {
	logger, _ := cmd.constructLogger()

	atcEndpointPicker := tsa.NewRandomATCEndpointPicker(cmd.ATCURLs)

	teamAuthorizedKeys, err := cmd.loadTeamAuthorizedKeys()
	if err != nil {
		return nil, fmt.Errorf("failed to load team authorized keys: %s", err)
	}

	if len(cmd.AuthorizedKeys.Keys)+len(cmd.TeamAuthorizedKeys) == 0 {
		logger.Info("starting-tsa-without-authorized-keys")
	}

	sessionAuthTeam := &sessionTeam{
		sessionTeams: make(map[string]string),
		lock:         &sync.RWMutex{},
	}

	config, err := cmd.configureSSHServer(sessionAuthTeam, cmd.AuthorizedKeys.Keys, teamAuthorizedKeys)
	if err != nil {
		return nil, fmt.Errorf("failed to configure SSH server: %s", err)
	}

	listenAddr := fmt.Sprintf("%s:%d", cmd.BindIP, cmd.BindPort)

	if cmd.SessionSigningKey == nil {
		return nil, fmt.Errorf("missing session signing key")
	}

	tokenGenerator := tsa.NewTokenGenerator(cmd.SessionSigningKey.PrivateKey)

	server := &server{
		logger:            logger,
		heartbeatInterval: cmd.HeartbeatInterval,
		cprInterval:       1 * time.Second,
		atcEndpointPicker: atcEndpointPicker,
		tokenGenerator:    tokenGenerator,
		forwardHost:       cmd.PeerAddress,
		config:            config,
		httpClient:        http.DefaultClient,
		sessionTeam:       sessionAuthTeam,
	}

	return serverRunner{logger, server, listenAddr}, nil
}

func (cmd *TSACommand) constructLogger() (lager.Logger, *lager.ReconfigurableSink) {
	logger, reconfigurableSink := cmd.Logger.Logger("tsa")
	if cmd.LogClusterName {
		logger = logger.WithData(lager.Data{
			"cluster": cmd.ClusterName,
		})
	}

	return logger, reconfigurableSink
}

func (cmd *TSACommand) loadTeamAuthorizedKeys() ([]TeamAuthKeys, error) {
	var teamKeys []TeamAuthKeys

	for teamName, keys := range cmd.TeamAuthorizedKeys {
		teamKeys = append(teamKeys, TeamAuthKeys{
			Team:     teamName,
			AuthKeys: keys.Keys,
		})
	}

	return teamKeys, nil
}

func (cmd *TSACommand) configureSSHServer(sessionAuthTeam *sessionTeam, authorizedKeys []ssh.PublicKey, teamAuthorizedKeys []TeamAuthKeys) (*ssh.ServerConfig, error) {
	certChecker := &ssh.CertChecker{
		IsUserAuthority: func(key ssh.PublicKey) bool {
			return false
		},

		IsHostAuthority: func(key ssh.PublicKey, address string) bool {
			return false
		},

		UserKeyFallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			for _, k := range authorizedKeys {
				if bytes.Equal(k.Marshal(), key.Marshal()) {
					return nil, nil
				}
			}

			for _, teamKeys := range teamAuthorizedKeys {
				for _, k := range teamKeys.AuthKeys {
					if bytes.Equal(k.Marshal(), key.Marshal()) {
						sessionAuthTeam.AuthorizeTeam(string(conn.SessionID()), teamKeys.Team)
						return nil, nil
					}
				}
			}

			return nil, fmt.Errorf("unknown public key")
		},
	}

	config := &ssh.ServerConfig{
		Config: atc.DefaultSSHConfig(),
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			return certChecker.Authenticate(conn, key)
		},
	}

	signer, err := ssh.NewSignerFromKey(cmd.HostKey)
	if err != nil {
		return nil, fmt.Errorf("failed to create signer from host key: %s", err)
	}

	config.AddHostKey(signer)

	return config, nil
}

func (cmd *TSACommand) debugBindAddr() string {
	return fmt.Sprintf("%s:%d", cmd.DebugBindIP, cmd.DebugBindPort)
}
<commit_msg>Add new yaml-team-authorized-keys flag to provide authorized team key in one yaml file<commit_after>package tsacmd

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

	"io/ioutil"
	yaml "gopkg.in/yaml.v2"

	"code.cloudfoundry.org/lager"
	"github.com/concourse/concourse/atc"
	"github.com/concourse/concourse/tsa"
	"github.com/concourse/flag"
	"github.com/tedsuo/ifrit"
	"github.com/tedsuo/ifrit/grouper"
	"github.com/tedsuo/ifrit/http_server"
	"github.com/tedsuo/ifrit/sigmon"
	"golang.org/x/crypto/ssh"
)

type TSACommand struct {
	Logger flag.Lager

	BindIP      flag.IP `long:"bind-ip"   default:"0.0.0.0" description:"IP address on which to listen for SSH."`
	PeerAddress string  `long:"peer-address" default:"127.0.0.1" description:"Network address of this web node, reachable by other web nodes. Used for forwarded worker addresses."`
	BindPort    uint16  `long:"bind-port" default:"2222"    description:"Port on which to listen for SSH."`

	DebugBindIP   flag.IP `long:"debug-bind-ip"   default:"127.0.0.1" description:"IP address on which to listen for the pprof debugger endpoints."`
	DebugBindPort uint16  `long:"debug-bind-port" default:"2221"      description:"Port on which to listen for the pprof debugger endpoints."`

	HostKey                *flag.PrivateKey               `long:"host-key"        required:"true" description:"Path to private key to use for the SSH server."`
	AuthorizedKeys         flag.AuthorizedKeys            `long:"authorized-keys" description:"Path to file containing keys to authorize, in SSH authorized_keys format (one public key per line)."`
	TeamAuthorizedKeys     map[string]flag.AuthorizedKeys `long:"team-authorized-keys" value-name:"NAME:PATH" description:"Path to file containing keys to authorize, in SSH authorized_keys format (one public key per line)."`
	TeamAuthorizedKeysFile flag.File                      `long:"team-authorized-keys-file" description:"Path to file containing a YAML array of teams and their authorized SSH keys, e.g. [{team:foo,ssh_keys:[key1,key2]}]."`

	ATCURLs []flag.URL `long:"atc-url" required:"true" description:"ATC API endpoints to which workers will be registered."`

	SessionSigningKey *flag.PrivateKey `long:"session-signing-key" required:"true" description:"Path to private key to use when signing tokens in reqests to the ATC during registration."`

	HeartbeatInterval time.Duration `long:"heartbeat-interval" default:"30s" description:"interval on which to heartbeat workers to the ATC"`

	ClusterName    string `long:"cluster-name" description:"A name for this Concourse cluster, to be displayed on the dashboard page."`
	LogClusterName bool   `long:"log-cluster-name" description:"Log cluster name."`
}

type TeamAuthKeys struct {
	Team     string
	AuthKeys []ssh.PublicKey
}

type yamlTeamAuthorizedKey struct {
	Team string   `yaml:"team"`
	Keys []string `yaml:"ssh_keys,flow"`
}

func (cmd *TSACommand) Execute(args []string) error {
	runner, err := cmd.Runner(args)
	if err != nil {
		return err
	}

	tsaServerMember := grouper.Member{
		Name:   "tsa-server",
		Runner: sigmon.New(runner),
	}

	tsaDebugMember := grouper.Member{
		Name: "debug-server",
		Runner: http_server.New(
			cmd.debugBindAddr(),
			http.DefaultServeMux,
		)}

	members := []grouper.Member{
		tsaDebugMember,
		tsaServerMember,
	}

	group := grouper.NewParallel(os.Interrupt, members)
	return <-ifrit.Invoke(group).Wait()
}

func (cmd *TSACommand) Runner(args []string) (ifrit.Runner, error) {
	logger, _ := cmd.constructLogger()

	atcEndpointPicker := tsa.NewRandomATCEndpointPicker(cmd.ATCURLs)

	teamAuthorizedKeys, err := cmd.loadTeamAuthorizedKeys()
	if err != nil {
		return nil, fmt.Errorf("failed to load team authorized keys: %s", err)
	}

	if len(cmd.AuthorizedKeys.Keys)+len(cmd.TeamAuthorizedKeys) == 0 {
		logger.Info("starting-tsa-without-authorized-keys")
	}

	sessionAuthTeam := &sessionTeam{
		sessionTeams: make(map[string]string),
		lock:         &sync.RWMutex{},
	}

	config, err := cmd.configureSSHServer(sessionAuthTeam, cmd.AuthorizedKeys.Keys, teamAuthorizedKeys)
	if err != nil {
		return nil, fmt.Errorf("failed to configure SSH server: %s", err)
	}

	listenAddr := fmt.Sprintf("%s:%d", cmd.BindIP, cmd.BindPort)

	if cmd.SessionSigningKey == nil {
		return nil, fmt.Errorf("missing session signing key")
	}

	tokenGenerator := tsa.NewTokenGenerator(cmd.SessionSigningKey.PrivateKey)

	server := &server{
		logger:            logger,
		heartbeatInterval: cmd.HeartbeatInterval,
		cprInterval:       1 * time.Second,
		atcEndpointPicker: atcEndpointPicker,
		tokenGenerator:    tokenGenerator,
		forwardHost:       cmd.PeerAddress,
		config:            config,
		httpClient:        http.DefaultClient,
		sessionTeam:       sessionAuthTeam,
	}

	return serverRunner{logger, server, listenAddr}, nil
}

func (cmd *TSACommand) constructLogger() (lager.Logger, *lager.ReconfigurableSink) {
	logger, reconfigurableSink := cmd.Logger.Logger("tsa")
	if cmd.LogClusterName {
		logger = logger.WithData(lager.Data{
			"cluster": cmd.ClusterName,
		})
	}

	return logger, reconfigurableSink
}

func (cmd *TSACommand) loadTeamAuthorizedKeys() ([]TeamAuthKeys, error) {
	var teamKeys []TeamAuthKeys

	for teamName, keys := range cmd.TeamAuthorizedKeys {
		teamKeys = append(teamKeys, TeamAuthKeys{
			Team:     teamName,
			AuthKeys: keys.Keys,
		})
	}

	// load TeamAuthorizedKeysFile
	if cmd.TeamAuthorizedKeysFile != "" {
		logger, _ := cmd.constructLogger()
		var rawTeamAuthorizedKeys []yamlTeamAuthorizedKey

		authorizedKeysBytes, err := ioutil.ReadFile(cmd.TeamAuthorizedKeysFile.Path())
		if err != nil {
			return nil, fmt.Errorf("failed to read yaml authorized keys file: %s", err)
		}
		err = yaml.Unmarshal([]byte(authorizedKeysBytes), &rawTeamAuthorizedKeys)
		if err != nil {
			return nil, fmt.Errorf("failed to parse yaml authorized keys file: %s", err)
		}

		for _, t := range rawTeamAuthorizedKeys {
			var teamAuthorizedKeys []ssh.PublicKey
			for _, k := range t.Keys {
				key, _, _, _, err := ssh.ParseAuthorizedKey([]byte(k))
				if err != nil {
					logger.Error("load-team-authorized-keys-parse", fmt.Errorf("Invalid format, ignoring (%s): %s", k, err.Error()))
					continue
				}
				logger.Info("load-team-authorized-keys-loaded", lager.Data{"team": t.Team, "key": k})
				teamAuthorizedKeys = append(teamAuthorizedKeys, key)
			}
			teamKeys = append(teamKeys, TeamAuthKeys{Team: t.Team, AuthKeys: teamAuthorizedKeys})
		}
	}

	return teamKeys, nil
}

func (cmd *TSACommand) configureSSHServer(sessionAuthTeam *sessionTeam, authorizedKeys []ssh.PublicKey, teamAuthorizedKeys []TeamAuthKeys) (*ssh.ServerConfig, error) {
	certChecker := &ssh.CertChecker{
		IsUserAuthority: func(key ssh.PublicKey) bool {
			return false
		},

		IsHostAuthority: func(key ssh.PublicKey, address string) bool {
			return false
		},

		UserKeyFallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			for _, k := range authorizedKeys {
				if bytes.Equal(k.Marshal(), key.Marshal()) {
					return nil, nil
				}
			}

			for _, teamKeys := range teamAuthorizedKeys {
				for _, k := range teamKeys.AuthKeys {
					if bytes.Equal(k.Marshal(), key.Marshal()) {
						sessionAuthTeam.AuthorizeTeam(string(conn.SessionID()), teamKeys.Team)
						return nil, nil
					}
				}
			}

			return nil, fmt.Errorf("unknown public key")
		},
	}

	config := &ssh.ServerConfig{
		Config: atc.DefaultSSHConfig(),
		PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
			return certChecker.Authenticate(conn, key)
		},
	}

	signer, err := ssh.NewSignerFromKey(cmd.HostKey)
	if err != nil {
		return nil, fmt.Errorf("failed to create signer from host key: %s", err)
	}

	config.AddHostKey(signer)

	return config, nil
}

func (cmd *TSACommand) debugBindAddr() string {
	return fmt.Sprintf("%s:%d", cmd.DebugBindIP, cmd.DebugBindPort)
}
<|endoftext|>


<commit_before>package adds

import "syscall"

var (
	modnetapi32 = syscall.NewLazyDLL("netapi32.dll")

	procDsAddressToSiteNamesW             = modnetapi32.NewProc("DsAddressToSiteNamesW")
	procDsAddressToSiteNamesExW           = modnetapi32.NewProc("DsAddressToSiteNamesExW")
	procDsDeregisterDnsHostRecordsW       = modnetapi32.NewProc("DsDeregisterDnsHostRecordsW")
	procDsEnumerateDomainTrustsW          = modnetapi32.NewProc("DsEnumerateDomainTrustsW")
	procDsGetDcCloseW                     = modnetapi32.NewProc("DsGetDcCloseW")
	procDsGetDcNameW                      = modnetapi32.NewProc("DsGetDcNameW")
	procDsGetDcNextW                      = modnetapi32.NewProc("DsGetDcNextW")
	procDsGetDcOpenW                      = modnetapi32.NewProc("DsGetDcOpenW")
	procDsGetDcSiteCoverageW              = modnetapi32.NewProc("DsGetDcSiteCoverageW")
	procDsGetForestTrustInformationW      = modnetapi32.NewProc("DsGetForestTrustInformationW")
	procDsGetSiteNameW                    = modnetapi32.NewProc("DsGetSiteNameW")
	procDsMergeForestTrustInformationW    = modnetapi32.NewProc("DsMergeForestTrustInformationW")
	procDsRoleFreeMemory                  = modnetapi32.NewProc("DsRoleFreeMemory")
	procDsRoleGetPrimaryDomainInformation = modnetapi32.NewProc("DsRoleGetPrimaryDomainInformation")
	procDsValidateSubnetNameW             = modnetapi32.NewProc("DsValidateSubnetNameW")
)
<commit_msg>Added DsGetSiteName API support<commit_after>package adds

import (
	"syscall"
	"unsafe"
)

var (
	modnetapi32 = syscall.NewLazyDLL("netapi32.dll")

	procDsAddressToSiteNamesW             = modnetapi32.NewProc("DsAddressToSiteNamesW")
	procDsAddressToSiteNamesExW           = modnetapi32.NewProc("DsAddressToSiteNamesExW")
	procDsDeregisterDnsHostRecordsW       = modnetapi32.NewProc("DsDeregisterDnsHostRecordsW")
	procDsEnumerateDomainTrustsW          = modnetapi32.NewProc("DsEnumerateDomainTrustsW")
	procDsGetDcCloseW                     = modnetapi32.NewProc("DsGetDcCloseW")
	procDsGetDcNameW                      = modnetapi32.NewProc("DsGetDcNameW")
	procDsGetDcNextW                      = modnetapi32.NewProc("DsGetDcNextW")
	procDsGetDcOpenW                      = modnetapi32.NewProc("DsGetDcOpenW")
	procDsGetDcSiteCoverageW              = modnetapi32.NewProc("DsGetDcSiteCoverageW")
	procDsGetForestTrustInformationW      = modnetapi32.NewProc("DsGetForestTrustInformationW")
	procDsGetSiteNameW                    = modnetapi32.NewProc("DsGetSiteNameW")
	procDsMergeForestTrustInformationW    = modnetapi32.NewProc("DsMergeForestTrustInformationW")
	procDsRoleFreeMemory                  = modnetapi32.NewProc("DsRoleFreeMemory")
	procDsRoleGetPrimaryDomainInformation = modnetapi32.NewProc("DsRoleGetPrimaryDomainInformation")
	procDsValidateSubnetNameW             = modnetapi32.NewProc("DsValidateSubnetNameW")
)

func GetSiteName(computerName string) (siteName string, err error) {
	var cnp, snp *uint16
	if len(siteName) == 0 {
		cnp = nil
	} else {
		cnp, err = syscall.UTF16PtrFromString(computerName)
		if err != nil {
			return
		}
	}
	snp, err = DsGetSiteName(cnp)
	if err != nil {

		panic(err)
		return
	}
	defer syscall.NetApiBufferFree((*byte)(unsafe.Pointer(snp)))
	siteName = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(snp))[:]) // Assumes max site name length of 256 characters
	return
}

func DsGetSiteName(computerName *uint16) (siteName *uint16, err error) {
	// See https://msdn.microsoft.com/en-us/library/ms675992
	r1, _, e1 := syscall.Syscall(procDsGetSiteNameW.Addr(), 2, uintptr(unsafe.Pointer(computerName)), uintptr(unsafe.Pointer(&siteName)), 0)
	if r1 != 0 {
		if e1 != 0 {
			err = error(e1)
		} else {
			err = syscall.EINVAL
		}
	}
	return
}
<|endoftext|>


<commit_before>package proxy

import (
	"math/rand"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
	host "github.com/jbenet/go-ipfs/p2p/host"
	inet "github.com/jbenet/go-ipfs/p2p/net"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	dhtpb "github.com/jbenet/go-ipfs/routing/dht/pb"
	eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog"
	errors "github.com/jbenet/go-ipfs/util/debugerror"
)

const ProtocolGCR = "/ipfs/grandcentral"

var log = eventlog.Logger("grandcentral/proxy")

type Proxy interface {
	HandleStream(inet.Stream)
	SendMessage(ctx context.Context, m *dhtpb.Message) error
	SendRequest(ctx context.Context, m *dhtpb.Message) (*dhtpb.Message, error)
}

type standard struct {
	Host    host.Host
	Remotes []peer.ID
}

func Standard(h host.Host, remotes []peer.ID) Proxy {
	return &standard{h, remotes}
}

func (p *standard) HandleStream(s inet.Stream) {
	panic("client received a GCR message")
}

func (px *standard) SendMessage(ctx context.Context, m *dhtpb.Message) error {
	var err error
	for _, i := range rand.Perm(len(px.Remotes)) {
		remote := px.Remotes[i]
		if err = px.sendMessage(ctx, m, remote); err != nil { // careful don't re-declare err!
			continue
		}
		return nil // success
	}
	return err // NB: returns the last error
}

func (px *standard) sendMessage(ctx context.Context, m *dhtpb.Message, remote peer.ID) (err error) {
	e := log.EventBegin(ctx, "sendRoutingMessage", px.Host.ID(), remote, m)
	defer func() {
		if err != nil {
			e.SetError(err)
		}
		e.Done()
	}()
	if err = px.Host.Connect(ctx, peer.PeerInfo{ID: remote}); err != nil {
		return err
	}
	s, err := px.Host.NewStream(ProtocolGCR, remote)
	if err != nil {
		return err
	}
	defer s.Close()
	pbw := ggio.NewDelimitedWriter(s)
	if err := pbw.WriteMsg(m); err != nil {
		return errors.Wrap(err)
	}
	return nil
}

func (px *standard) SendRequest(ctx context.Context, m *dhtpb.Message) (*dhtpb.Message, error) {
	var err error
	for _, i := range rand.Perm(len(px.Remotes)) {
		remote := px.Remotes[i]
		var reply *dhtpb.Message
		reply, err = px.sendRequest(ctx, m, remote) // careful don't redeclare err!
		if err != nil {
			continue
		}
		return reply, nil // success
	}
	return nil, err // NB: returns the last error
}

func (px *standard) sendRequest(ctx context.Context, m *dhtpb.Message, remote peer.ID) (_ *dhtpb.Message, err error) {
	e := log.EventBegin(ctx, "sendRoutingRequest", px.Host.ID(), remote, m)
	defer func() {
		if err != nil {
			e.SetError(err)
		}
		e.Done()
	}()
	if err = px.Host.Connect(ctx, peer.PeerInfo{ID: remote}); err != nil {
		return nil, err
	}
	s, err := px.Host.NewStream(ProtocolGCR, remote)
	if err != nil {
		return nil, err
	}
	defer s.Close()
	r := ggio.NewDelimitedReader(s, inet.MessageSizeMax)
	w := ggio.NewDelimitedWriter(s)
	if err = w.WriteMsg(m); err != nil {
		return nil, err
	}

	var reply dhtpb.Message
	if err = r.ReadMsg(&reply); err != nil {
		return nil, err
	}
	// need ctx expiration?
	if &reply == nil {
		return nil, errors.New("no response to request")
	}
	return &reply, nil
}
<commit_msg>fix(gcr/c) print a loud error when clients receive routing messages, but don't panic<commit_after>package proxy

import (
	"math/rand"

	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
	ggio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/gogoprotobuf/io"
	host "github.com/jbenet/go-ipfs/p2p/host"
	inet "github.com/jbenet/go-ipfs/p2p/net"
	peer "github.com/jbenet/go-ipfs/p2p/peer"
	dhtpb "github.com/jbenet/go-ipfs/routing/dht/pb"
	eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog"
	errors "github.com/jbenet/go-ipfs/util/debugerror"
)

const ProtocolGCR = "/ipfs/grandcentral"

var log = eventlog.Logger("grandcentral/proxy")

type Proxy interface {
	HandleStream(inet.Stream)
	SendMessage(ctx context.Context, m *dhtpb.Message) error
	SendRequest(ctx context.Context, m *dhtpb.Message) (*dhtpb.Message, error)
}

type standard struct {
	Host    host.Host
	Remotes []peer.ID
}

func Standard(h host.Host, remotes []peer.ID) Proxy {
	return &standard{h, remotes}
}

func (p *standard) HandleStream(s inet.Stream) {
	// TODO(brian): Should clients be able to satisfy requests?
	log.Error("grandcentral client received (dropped) a routing message from", s.Conn().RemotePeer())
	s.Close()
}

func (px *standard) SendMessage(ctx context.Context, m *dhtpb.Message) error {
	var err error
	for _, i := range rand.Perm(len(px.Remotes)) {
		remote := px.Remotes[i]
		if err = px.sendMessage(ctx, m, remote); err != nil { // careful don't re-declare err!
			continue
		}
		return nil // success
	}
	return err // NB: returns the last error
}

func (px *standard) sendMessage(ctx context.Context, m *dhtpb.Message, remote peer.ID) (err error) {
	e := log.EventBegin(ctx, "sendRoutingMessage", px.Host.ID(), remote, m)
	defer func() {
		if err != nil {
			e.SetError(err)
		}
		e.Done()
	}()
	if err = px.Host.Connect(ctx, peer.PeerInfo{ID: remote}); err != nil {
		return err
	}
	s, err := px.Host.NewStream(ProtocolGCR, remote)
	if err != nil {
		return err
	}
	defer s.Close()
	pbw := ggio.NewDelimitedWriter(s)
	if err := pbw.WriteMsg(m); err != nil {
		return errors.Wrap(err)
	}
	return nil
}

func (px *standard) SendRequest(ctx context.Context, m *dhtpb.Message) (*dhtpb.Message, error) {
	var err error
	for _, i := range rand.Perm(len(px.Remotes)) {
		remote := px.Remotes[i]
		var reply *dhtpb.Message
		reply, err = px.sendRequest(ctx, m, remote) // careful don't redeclare err!
		if err != nil {
			continue
		}
		return reply, nil // success
	}
	return nil, err // NB: returns the last error
}

func (px *standard) sendRequest(ctx context.Context, m *dhtpb.Message, remote peer.ID) (_ *dhtpb.Message, err error) {
	e := log.EventBegin(ctx, "sendRoutingRequest", px.Host.ID(), remote, m)
	defer func() {
		if err != nil {
			e.SetError(err)
		}
		e.Done()
	}()
	if err = px.Host.Connect(ctx, peer.PeerInfo{ID: remote}); err != nil {
		return nil, err
	}
	s, err := px.Host.NewStream(ProtocolGCR, remote)
	if err != nil {
		return nil, err
	}
	defer s.Close()
	r := ggio.NewDelimitedReader(s, inet.MessageSizeMax)
	w := ggio.NewDelimitedWriter(s)
	if err = w.WriteMsg(m); err != nil {
		return nil, err
	}

	var reply dhtpb.Message
	if err = r.ReadMsg(&reply); err != nil {
		return nil, err
	}
	// need ctx expiration?
	if &reply == nil {
		return nil, errors.New("no response to request")
	}
	return &reply, nil
}
<|endoftext|>


<commit_before>// +build !windows

package collectors

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/StackExchange/scollector/metadata"
	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/scollector/util"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_ntp_peers_unix})
}

var ntpNtpqPeerFields = []string{
	"remote",
	"refid",
	"st",
	"t",
	"when",
	"poll",
	"reach",
	"delay",
	"offset",
	"jitter",
}

// ntUnPretty reverses human formating for poll and when, see prettyinterval in ntpq/ntpq-subs.c
func ntpUnPretty(s string) (int64, error) {
	if len(s) < 1 {
		return 0, fmt.Errorf("Zero length string passed to ntpUnPretty")
	}
	var multiplier int64 = 1
	shift := 1
	switch s[len(s)-1] {
	case 'm':
		multiplier = 60
	case 'h':
		multiplier = 60 * 60
	case 'd':
		multiplier = 60 * 60 * 24
	default:
		shift = 0
	}
	i, err := strconv.ParseInt(s[0:len(s)-shift], 10, 64)
	return i * multiplier, err
}

func c_ntp_peers_unix() (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	const metric = "ntp."
	util.ReadCommand(func(line string) error {
		fields := strings.Fields(line)
		if len(fields) != len(ntpNtpqPeerFields) || fields[0] == "remote" {
			return nil
		}
		tags := opentsdb.TagSet{"remote": fields[0], "refid": fields[1]}
		var current_source int
		if strings.HasPrefix(fields[0], "*") {
			current_source = 1
		}
		Add(&md, metric+"current_source", current_source, tags, metadata.Gauge, metadata.Bool, "")
		Add(&md, metric+"stratum", fields[2], tags, metadata.Gauge, "Stratum", "")
		if when, err := ntpUnPretty(fields[4]); err != nil {
			return err
		} else {
			Add(&md, metric+"when", when, tags, metadata.Gauge, metadata.Second, "")
		}
		if poll, err := ntpUnPretty(fields[5]); err != nil {
			return err
		} else {
			Add(&md, metric+"poll", poll, tags, metadata.Gauge, metadata.Second, "")
		}
		Add(&md, metric+"reach", fields[6], tags, metadata.Gauge, "Code", "")
		Add(&md, metric+"delay", fields[7], tags, metadata.Gauge, metadata.MilliSecond, "")
		Add(&md, metric+"offset", fields[8], tags, metadata.Gauge, metadata.MilliSecond, "")
		Add(&md, metric+"jitter", fields[9], tags, metadata.Gauge, metadata.MilliSecond, "")
		return nil
	}, "ntpq", "-pn")
	return md, nil
}
<commit_msg>cmd/scollector: Fix ntp parsing<commit_after>// +build !windows

package collectors

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/StackExchange/scollector/metadata"
	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/scollector/util"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_ntp_peers_unix})
}

var ntpNtpqPeerFields = []string{
	"remote",
	"refid",
	"st",
	"t",
	"when",
	"poll",
	"reach",
	"delay",
	"offset",
	"jitter",
}

// ntUnPretty reverses human formating for poll and when, see prettyinterval in ntpq/ntpq-subs.c
func ntpUnPretty(s string) (int64, error) {
	if len(s) < 1 {
		return 0, fmt.Errorf("Zero length string passed to ntpUnPretty")
	}
	var multiplier int64 = 1
	shift := 1
	switch s[len(s)-1] {
	case 'm':
		multiplier = 60
	case 'h':
		multiplier = 60 * 60
	case 'd':
		multiplier = 60 * 60 * 24
	default:
		shift = 0
	}
	i, err := strconv.ParseInt(s[0:len(s)-shift], 10, 64)
	return i * multiplier, err
}

func c_ntp_peers_unix() (opentsdb.MultiDataPoint, error) {
	var md opentsdb.MultiDataPoint
	const metric = "ntp."
	util.ReadCommand(func(line string) error {
		fields := strings.Fields(line)
		if len(fields) != len(ntpNtpqPeerFields) || fields[0] == "remote" {
			return nil
		}
		r := []rune(line)
		if len(r) < 2 {
			return nil, fmt.Errorf("unexpected length of line ")
		}
		fl := string(r[0])
		rest := string(r[1:])
		remote := strings.Fields(rest)[0]
		tags := opentsdb.TagSet{"remote": remote, "refid": fields[1]}
		var current_source int
		if fl == "*" {
			current_source = 1
		}
		Add(&md, metric+"current_source", current_source, tags, metadata.Gauge, metadata.Bool, "")
		Add(&md, metric+"stratum", fields[2], tags, metadata.Gauge, "Stratum", "")
		if when, err := ntpUnPretty(fields[4]); err != nil {
			return err
		} else {
			Add(&md, metric+"when", when, tags, metadata.Gauge, metadata.Second, "")
		}
		if poll, err := ntpUnPretty(fields[5]); err != nil {
			return err
		} else {
			Add(&md, metric+"poll", poll, tags, metadata.Gauge, metadata.Second, "")
		}
		Add(&md, metric+"reach", fields[6], tags, metadata.Gauge, "Code", "")
		Add(&md, metric+"delay", fields[7], tags, metadata.Gauge, metadata.MilliSecond, "")
		Add(&md, metric+"offset", fields[8], tags, metadata.Gauge, metadata.MilliSecond, "")
		Add(&md, metric+"jitter", fields[9], tags, metadata.Gauge, metadata.MilliSecond, "")
		return nil
	}, "ntpq", "-pn")
	return md, nil
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 *
 * 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.
 *
 * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @license 	Apache-2.0
 */

package oauth2_test

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"
	"time"

	"github.com/google/uuid"
	"github.com/tidwall/gjson"

	"github.com/ory/hydra/internal/testhelpers"
	"github.com/ory/x/httpx"
	"github.com/ory/x/ioutilx"

	"github.com/dgrijalva/jwt-go"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	goauth2 "golang.org/x/oauth2"
	"golang.org/x/oauth2/clientcredentials"

	"github.com/ory/viper"

	hc "github.com/ory/hydra/client"
	"github.com/ory/hydra/driver/configuration"
	"github.com/ory/hydra/internal"
	. "github.com/ory/hydra/oauth2"
	"github.com/ory/hydra/x"
)

func TestClientCredentials(t *testing.T) {
	reg := internal.NewMockedRegistry(t)
	viper.Set(configuration.ViperKeyAccessTokenStrategy, "opaque")
	public, admin := testhelpers.NewOAuth2Server(t, reg)

	var newClient = func(t *testing.T) (*hc.Client, clientcredentials.Config) {
		secret := uuid.New().String()
		c := &hc.Client{
			OutfacingID:   uuid.New().String(),
			Secret:        secret,
			RedirectURIs:  []string{public.URL + "/callback"},
			ResponseTypes: []string{"token"},
			GrantTypes:    []string{"client_credentials"},
			Scope:         "foobar",
			Audience:      []string{"https://api.ory.sh/"},
		}
		require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), c))
		return c, clientcredentials.Config{
			ClientID:       c.OutfacingID,
			ClientSecret:   secret,
			TokenURL:       reg.Config().OAuth2TokenURL().String(),
			Scopes:         strings.Split(c.Scope, " "),
			EndpointParams: url.Values{"audience": c.Audience},
		}
	}

	var getToken = func(t *testing.T, conf clientcredentials.Config) (*goauth2.Token, error) {
		conf.AuthStyle = goauth2.AuthStyleInHeader
		return conf.Token(context.Background())
	}

	var encodeOr = func(t *testing.T, val interface{}, or string) string {
		out, err := json.Marshal(val)
		require.NoError(t, err)
		if string(out) == "null" {
			return or
		}

		return string(out)
	}

	var inspectToken = func(t *testing.T, token *goauth2.Token, cl *hc.Client, conf clientcredentials.Config, strategy string) {
		require.NotEmpty(t, token.AccessToken)

		req := httpx.MustNewRequest("POST", admin.URL+IntrospectPath,
			strings.NewReader((url.Values{"token": {token.AccessToken}}).Encode()),
			"application/x-www-form-urlencoded")
		req.SetBasicAuth(cl.OutfacingID, conf.ClientSecret)
		res, err := public.Client().Do(req)
		require.NoError(t, err)
		defer res.Body.Close()

		check := func(res gjson.Result) {
			assert.EqualValues(t, cl.OutfacingID, res.Get("client_id").String(), "%s", res.Raw)
			assert.EqualValues(t, cl.OutfacingID, res.Get("sub").String(), "%s", res.Raw)
			assert.EqualValues(t, reg.Config().IssuerURL().String(), res.Get("iss").String(), "%s", res.Raw)

			assert.EqualValues(t, res.Get("nbf").Int(), res.Get("iat").Int(), "%s", res.Raw)
			assert.True(t, res.Get("exp").Int() >= res.Get("iat").Int()+int64(reg.Config().AccessTokenLifespan().Seconds()), "%s", res.Raw)

			assert.EqualValues(t, encodeOr(t, conf.EndpointParams["audience"], "[]"), res.Get("aud").Raw, "%s", res.Raw)
		}

		introspection := gjson.ParseBytes(ioutilx.MustReadAll(res.Body))
		check(introspection)
		assert.True(t, introspection.Get("active").Bool())
		assert.EqualValues(t, "access_token", introspection.Get("token_use").String())
		assert.EqualValues(t, "Bearer", introspection.Get("token_type").String())
		assert.EqualValues(t, strings.Join(conf.Scopes, " "), introspection.Get("scope").String(), "%s", introspection.Raw)

		if strategy != "jwt" {
			return
		}

		body, err := jwt.DecodeSegment(strings.Split(token.AccessToken, ".")[1])
		require.NoError(t, err)

		jwtClaims := gjson.ParseBytes(body)
		assert.NotEmpty(t, jwtClaims.Get("jti").String())
		assert.EqualValues(t, encodeOr(t, conf.Scopes, "[]"), jwtClaims.Get("scp").Raw, "%s", introspection.Raw)
		check(jwtClaims)
	}

	var getAndInspectToken = func(t *testing.T, cl *hc.Client, conf clientcredentials.Config, strategy string) {
		token, err := getToken(t, conf)
		require.NoError(t, err)
		inspectToken(t, token, cl, conf, strategy)
	}

	t.Run("case=should fail because audience is not allowed", func(t *testing.T) {
		_, conf := newClient(t)
		conf.EndpointParams = url.Values{"audience": {"https://not-api.ory.sh/"}}
		_, err := getToken(t, conf)
		require.Error(t, err)
	})

	t.Run("case=should fail because scope is not allowed", func(t *testing.T) {
		_, conf := newClient(t)
		conf.Scopes = []string{"not-allowed-scope"}
		_, err := getToken(t, conf)
		require.Error(t, err)
	})

	t.Run("case=should pass with audience", func(t *testing.T) {
		run := func(strategy string) func(t *testing.T) {
			return func(t *testing.T) {
				viper.Set(configuration.ViperKeyAccessTokenStrategy, strategy)

				cl, conf := newClient(t)
				getAndInspectToken(t, cl, conf, strategy)
			}
		}

		t.Run("strategy=opaque", run("opaque"))
		t.Run("strategy=jwt", run("jwt"))
	})

	t.Run("case=should pass without audience", func(t *testing.T) {
		run := func(strategy string) func(t *testing.T) {
			return func(t *testing.T) {
				viper.Set(configuration.ViperKeyAccessTokenStrategy, strategy)

				cl, conf := newClient(t)
				conf.EndpointParams = url.Values{}
				getAndInspectToken(t, cl, conf, strategy)
			}
		}

		t.Run("strategy=opaque", run("opaque"))
		t.Run("strategy=jwt", run("jwt"))
	})

	t.Run("case=should pass without scope", func(t *testing.T) {
		run := func(strategy string) func(t *testing.T) {
			return func(t *testing.T) {
				viper.Set(configuration.ViperKeyAccessTokenStrategy, strategy)

				cl, conf := newClient(t)
				conf.Scopes = []string{}
				getAndInspectToken(t, cl, conf, strategy)
			}
		}

		t.Run("strategy=opaque", run("opaque"))
		t.Run("strategy=jwt", run("jwt"))
	})
}

func TestClientCredentialsGrantAllScopes(t *testing.T) {
	for _, tc := range []struct{ d string }{{d: "opaque"}, {d: "jwt"}} {
		t.Run("tc="+tc.d, func(t *testing.T) {
			conf := internal.NewConfigurationWithDefaults()
			viper.Set(configuration.ViperKeyAccessTokenLifespan, time.Second)
			viper.Set(configuration.ViperKeyAccessTokenStrategy, tc.d)
			viper.Set(configuration.ViperKeyGrantAllClientCredentialsScopesPerDefault, true)

			reg := internal.NewRegistryMemory(t, conf)

			router := x.NewRouterPublic()
			ts := httptest.NewServer(router)
			defer ts.Close()
			viper.Set(configuration.ViperKeyIssuerURL, ts.URL)

			handler := NewHandler(reg, conf)
			handler.SetRoutes(router.RouterAdmin(), router, func(h http.Handler) http.Handler {
				return h
			})

			require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), &hc.Client{
				OutfacingID:   "app-client",
				Secret:        "secret",
				RedirectURIs:  []string{ts.URL + "/callback"},
				ResponseTypes: []string{"token"},
				GrantTypes:    []string{"client_credentials"},
				Scope:         "foobar foo2bar",
				Audience:      []string{"https://api.ory.sh/"},
			}))

			for k, ccc := range []struct {
				d                 string
				c                 *clientcredentials.Config
				assertAccessToken func(*testing.T, string)
				expectAccessToken bool
				expectError       bool
			}{
				{
					d: "should pass with multiple scopes",
					c: &clientcredentials.Config{
						ClientID:     "app-client",
						ClientSecret: "secret",
						TokenURL:     ts.URL + "/oauth2/token",
						Scopes:       []string{},
					},
					assertAccessToken: func(t *testing.T, token string) {
						if tc.d != "jwt" {
							return
						}
						body, err := jwt.DecodeSegment(strings.Split(token, ".")[1])
						require.NoError(t, err)

						data := map[string]interface{}{}
						require.NoError(t, json.Unmarshal(body, &data))
						assert.EqualValues(t, "app-client", data["client_id"])
						assert.EqualValues(t, []interface{}{"foobar", "foo2bar"}, data["scp"])
					},
					expectAccessToken: true,
					expectError:       false,
				},
			} {
				t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) {
					ccc.c.AuthStyle = goauth2.AuthStyleInHeader
					tok, err := ccc.c.Token(context.Background())

					if ccc.expectError {
						require.Error(t, err)
					} else {
						require.NoError(t, err)
					}

					if ccc.expectAccessToken {
						assert.NotEmpty(t, tok.AccessToken)
						assert.Empty(t, tok.RefreshToken)
						assert.Empty(t, tok.Extra("id_token"))
					} else {
						assert.Nil(t, tok)
					}

					if ccc.assertAccessToken != nil {
						ccc.assertAccessToken(t, tok.AccessToken)
					}
				})
			}
		})
	}
}
<commit_msg>test: improve TestClientCredentialsGrantAllScopes<commit_after>/*
 * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 *
 * 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.
 *
 * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
 * @license 	Apache-2.0
 */

package oauth2_test

import (
	"context"
	"encoding/json"
	"github.com/google/uuid"
	"github.com/tidwall/gjson"
	"net/url"
	"strings"
	"testing"

	"github.com/ory/hydra/internal/testhelpers"
	"github.com/ory/x/httpx"
	"github.com/ory/x/ioutilx"

	"github.com/dgrijalva/jwt-go"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	goauth2 "golang.org/x/oauth2"
	"golang.org/x/oauth2/clientcredentials"

	"github.com/ory/viper"

	hc "github.com/ory/hydra/client"
	"github.com/ory/hydra/driver/configuration"
	"github.com/ory/hydra/internal"
	. "github.com/ory/hydra/oauth2"
)

func TestClientCredentials(t *testing.T) {
	reg := internal.NewMockedRegistry(t)
	viper.Set(configuration.ViperKeyAccessTokenStrategy, "opaque")
	public, admin := testhelpers.NewOAuth2Server(t, reg)

	var newClient = func(t *testing.T) (*hc.Client, clientcredentials.Config) {
		secret := uuid.New().String()
		c := &hc.Client{
			OutfacingID:   uuid.New().String(),
			Secret:        secret,
			RedirectURIs:  []string{public.URL + "/callback"},
			ResponseTypes: []string{"token"},
			GrantTypes:    []string{"client_credentials"},
			Scope:         "foobar",
			Audience:      []string{"https://api.ory.sh/"},
		}
		require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), c))
		return c, clientcredentials.Config{
			ClientID:       c.OutfacingID,
			ClientSecret:   secret,
			TokenURL:       reg.Config().OAuth2TokenURL().String(),
			Scopes:         strings.Split(c.Scope, " "),
			EndpointParams: url.Values{"audience": c.Audience},
		}
	}

	var getToken = func(t *testing.T, conf clientcredentials.Config) (*goauth2.Token, error) {
		conf.AuthStyle = goauth2.AuthStyleInHeader
		return conf.Token(context.Background())
	}

	var encodeOr = func(t *testing.T, val interface{}, or string) string {
		out, err := json.Marshal(val)
		require.NoError(t, err)
		if string(out) == "null" {
			return or
		}

		return string(out)
	}

	var inspectToken = func(t *testing.T, token *goauth2.Token, cl *hc.Client, conf clientcredentials.Config, strategy string) {
		require.NotEmpty(t, token.AccessToken)

		req := httpx.MustNewRequest("POST", admin.URL+IntrospectPath,
			strings.NewReader((url.Values{"token": {token.AccessToken}}).Encode()),
			"application/x-www-form-urlencoded")
		req.SetBasicAuth(cl.OutfacingID, conf.ClientSecret)
		res, err := public.Client().Do(req)
		require.NoError(t, err)
		defer res.Body.Close()

		check := func(res gjson.Result) {
			assert.EqualValues(t, cl.OutfacingID, res.Get("client_id").String(), "%s", res.Raw)
			assert.EqualValues(t, cl.OutfacingID, res.Get("sub").String(), "%s", res.Raw)
			assert.EqualValues(t, reg.Config().IssuerURL().String(), res.Get("iss").String(), "%s", res.Raw)

			assert.EqualValues(t, res.Get("nbf").Int(), res.Get("iat").Int(), "%s", res.Raw)
			assert.True(t, res.Get("exp").Int() >= res.Get("iat").Int()+int64(reg.Config().AccessTokenLifespan().Seconds()), "%s", res.Raw)

			assert.EqualValues(t, encodeOr(t, conf.EndpointParams["audience"], "[]"), res.Get("aud").Raw, "%s", res.Raw)
		}

		introspection := gjson.ParseBytes(ioutilx.MustReadAll(res.Body))
		check(introspection)
		assert.True(t, introspection.Get("active").Bool())
		assert.EqualValues(t, "access_token", introspection.Get("token_use").String())
		assert.EqualValues(t, "Bearer", introspection.Get("token_type").String())
		assert.EqualValues(t, strings.Join(conf.Scopes, " "), introspection.Get("scope").String(), "%s", introspection.Raw)

		if strategy != "jwt" {
			return
		}

		body, err := jwt.DecodeSegment(strings.Split(token.AccessToken, ".")[1])
		require.NoError(t, err)

		jwtClaims := gjson.ParseBytes(body)
		assert.NotEmpty(t, jwtClaims.Get("jti").String())
		assert.EqualValues(t, encodeOr(t, conf.Scopes, "[]"), jwtClaims.Get("scp").Raw, "%s", introspection.Raw)
		check(jwtClaims)
	}

	var getAndInspectToken = func(t *testing.T, cl *hc.Client, conf clientcredentials.Config, strategy string) {
		token, err := getToken(t, conf)
		require.NoError(t, err)
		inspectToken(t, token, cl, conf, strategy)
	}

	t.Run("case=should fail because audience is not allowed", func(t *testing.T) {
		_, conf := newClient(t)
		conf.EndpointParams = url.Values{"audience": {"https://not-api.ory.sh/"}}
		_, err := getToken(t, conf)
		require.Error(t, err)
	})

	t.Run("case=should fail because scope is not allowed", func(t *testing.T) {
		_, conf := newClient(t)
		conf.Scopes = []string{"not-allowed-scope"}
		_, err := getToken(t, conf)
		require.Error(t, err)
	})

	t.Run("case=should pass with audience", func(t *testing.T) {
		run := func(strategy string) func(t *testing.T) {
			return func(t *testing.T) {
				viper.Set(configuration.ViperKeyAccessTokenStrategy, strategy)

				cl, conf := newClient(t)
				getAndInspectToken(t, cl, conf, strategy)
			}
		}

		t.Run("strategy=opaque", run("opaque"))
		t.Run("strategy=jwt", run("jwt"))
	})

	t.Run("case=should pass without audience", func(t *testing.T) {
		run := func(strategy string) func(t *testing.T) {
			return func(t *testing.T) {
				viper.Set(configuration.ViperKeyAccessTokenStrategy, strategy)

				cl, conf := newClient(t)
				conf.EndpointParams = url.Values{}
				getAndInspectToken(t, cl, conf, strategy)
			}
		}

		t.Run("strategy=opaque", run("opaque"))
		t.Run("strategy=jwt", run("jwt"))
	})

	t.Run("case=should pass without scope", func(t *testing.T) {
		run := func(strategy string) func(t *testing.T) {
			return func(t *testing.T) {
				viper.Set(configuration.ViperKeyAccessTokenStrategy, strategy)

				cl, conf := newClient(t)
				conf.Scopes = []string{}
				getAndInspectToken(t, cl, conf, strategy)
			}
		}

		t.Run("strategy=opaque", run("opaque"))
		t.Run("strategy=jwt", run("jwt"))
	})

	t.Run("case=should grant default scopes if configured to do ", func(t *testing.T) {
		viper.Set(configuration.ViperKeyGrantAllClientCredentialsScopesPerDefault, true)

		run := func(strategy string) func(t *testing.T) {
			return func(t *testing.T) {
				viper.Set(configuration.ViperKeyAccessTokenStrategy, strategy)

				cl, conf := newClient(t)
				defaultScope := conf.Scopes
				conf.Scopes = []string{}

				token, err := getToken(t, conf)
				require.NoError(t, err)

				// We reset this so that introspectToken is going to check for the default scope.
				conf.Scopes = defaultScope
				inspectToken(t, token, cl, conf, strategy)
			}
		}

		t.Run("strategy=opaque", run("opaque"))
		t.Run("strategy=jwt", run("jwt"))
	})
}
<|endoftext|>


<commit_before>package google

import (
	"fmt"
	"strconv"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"google.golang.org/api/compute/v1"
)

func resourceComputeSslCertificate() *schema.Resource {
	return &schema.Resource{
		Create: resourceComputeSslCertificateCreate,
		Read:   resourceComputeSslCertificateRead,
		Delete: resourceComputeSslCertificateDelete,

		Schema: map[string]*schema.Schema{
			"certificate": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
				ValidateFunc:  validateGCPName,
			},

			"name_prefix": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					// https://cloud.google.com/compute/docs/reference/latest/sslCertificates#resource
					// uuid is 26 characters, limit the prefix to 37.
					value := v.(string)
					if len(value) > 37 {
						errors = append(errors, fmt.Errorf(
							"%q cannot be longer than 37 characters, name is limited to 63", k))
					}
					return
				},
			},

			"private_key": &schema.Schema{
				Type:      schema.TypeString,
				Required:  true,
				ForceNew:  true,
				Sensitive: true,
			},

			"description": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"project": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"self_link": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

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

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	var certName string
	if v, ok := d.GetOk("name"); ok {
		certName = v.(string)
	} else if v, ok := d.GetOk("name_prefix"); ok {
		certName = resource.PrefixedUniqueId(v.(string))
	} else {
		certName = resource.UniqueId()
	}

	// Build the certificate parameter
	cert := &compute.SslCertificate{
		Name:        certName,
		Certificate: d.Get("certificate").(string),
		PrivateKey:  d.Get("private_key").(string),
	}

	if v, ok := d.GetOk("description"); ok {
		cert.Description = v.(string)
	}

	op, err := config.clientCompute.SslCertificates.Insert(
		project, cert).Do()

	if err != nil {
		return fmt.Errorf("Error creating ssl certificate: %s", err)
	}

	err = computeOperationWait(config, op, project, "Creating SslCertificate")
	if err != nil {
		return err
	}

	d.SetId(cert.Name)

	return resourceComputeSslCertificateRead(d, meta)
}

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

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	cert, err := config.clientCompute.SslCertificates.Get(
		project, d.Id()).Do()
	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("SSL Certificate %q", d.Get("name").(string)))
	}

	d.Set("self_link", cert.SelfLink)
	d.Set("id", strconv.FormatUint(cert.Id, 10))

	return nil
}

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

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	op, err := config.clientCompute.SslCertificates.Delete(
		project, d.Id()).Do()
	if err != nil {
		return fmt.Errorf("Error deleting ssl certificate: %s", err)
	}

	err = computeOperationWait(config, op, project, "Deleting SslCertificate")
	if err != nil {
		return err
	}

	d.SetId("")
	return nil
}
<commit_msg>Mark certificate as sensitive within `google_compute_ssl_certificate` (#490)<commit_after>package google

import (
	"fmt"
	"strconv"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"google.golang.org/api/compute/v1"
)

func resourceComputeSslCertificate() *schema.Resource {
	return &schema.Resource{
		Create: resourceComputeSslCertificateCreate,
		Read:   resourceComputeSslCertificateRead,
		Delete: resourceComputeSslCertificateDelete,

		Schema: map[string]*schema.Schema{
			"certificate": &schema.Schema{
				Type:      schema.TypeString,
				Required:  true,
				ForceNew:  true,
				Sensitive: true,
			},

			"name": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				Computed:      true,
				ForceNew:      true,
				ConflictsWith: []string{"name_prefix"},
				ValidateFunc:  validateGCPName,
			},

			"name_prefix": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
					// https://cloud.google.com/compute/docs/reference/latest/sslCertificates#resource
					// uuid is 26 characters, limit the prefix to 37.
					value := v.(string)
					if len(value) > 37 {
						errors = append(errors, fmt.Errorf(
							"%q cannot be longer than 37 characters, name is limited to 63", k))
					}
					return
				},
			},

			"private_key": &schema.Schema{
				Type:      schema.TypeString,
				Required:  true,
				ForceNew:  true,
				Sensitive: true,
			},

			"description": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"id": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"project": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"self_link": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

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

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	var certName string
	if v, ok := d.GetOk("name"); ok {
		certName = v.(string)
	} else if v, ok := d.GetOk("name_prefix"); ok {
		certName = resource.PrefixedUniqueId(v.(string))
	} else {
		certName = resource.UniqueId()
	}

	// Build the certificate parameter
	cert := &compute.SslCertificate{
		Name:        certName,
		Certificate: d.Get("certificate").(string),
		PrivateKey:  d.Get("private_key").(string),
	}

	if v, ok := d.GetOk("description"); ok {
		cert.Description = v.(string)
	}

	op, err := config.clientCompute.SslCertificates.Insert(
		project, cert).Do()

	if err != nil {
		return fmt.Errorf("Error creating ssl certificate: %s", err)
	}

	err = computeOperationWait(config, op, project, "Creating SslCertificate")
	if err != nil {
		return err
	}

	d.SetId(cert.Name)

	return resourceComputeSslCertificateRead(d, meta)
}

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

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	cert, err := config.clientCompute.SslCertificates.Get(
		project, d.Id()).Do()
	if err != nil {
		return handleNotFoundError(err, d, fmt.Sprintf("SSL Certificate %q", d.Get("name").(string)))
	}

	d.Set("self_link", cert.SelfLink)
	d.Set("id", strconv.FormatUint(cert.Id, 10))

	return nil
}

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

	project, err := getProject(d, config)
	if err != nil {
		return err
	}

	op, err := config.clientCompute.SslCertificates.Delete(
		project, d.Id()).Do()
	if err != nil {
		return fmt.Errorf("Error deleting ssl certificate: %s", err)
	}

	err = computeOperationWait(config, op, project, "Deleting SslCertificate")
	if err != nil {
		return err
	}

	d.SetId("")
	return nil
}
<|endoftext|>


<commit_before>package bongo

import (
	"encoding/json"
	"strings"

	"github.com/koding/redis"
)

// A generic key value storage interface. Implementations must be thread safe.
// The storage can be anything.
type Cache interface {
	// Get retrieves data from the storage.
	Get(key string) (string, error)

	// Set puts data into the storage.
	Set(key string, item string) error

	// TODO implement Delete, MultiGet, MultiSet
}

// Basic requirements for a model for working with caching system
type Cacher interface {
	CachePrefix(id int64) string
	GetForCache(id int64) (string, error)
	Cacheable
}

type Cacheable interface {
	GetCacheId() int64
}

func (b *Bongo) GetFromBest(i Modellable, data Cacher, id int64) error {
	var d string
	var err error

	// check if cache is enabled
	if b.Cache == nil {
		// try to get data from getter func
		d, err = data.GetForCache(id)
		if err != nil {
			return err
		}
	} else {
		// get data from cache
		d, err = b.getFromCacheHelper(data, id)
		if err != nil {
			return err
		}
	}

	// marshall it to the `modellable`
	err = json.NewDecoder(strings.NewReader(d)).Decode(i)
	if err != nil {
		return err
	}

	return nil
}

func (b *Bongo) SetToCache(data Cacher) error {
	// check if  cache is enabled
	if b.Cache == nil {
		return ErrCacheIsNotEnabled
	}

	return b.setToCacheHelper(data, data.GetCacheId())

}

func (b *Bongo) getFromCacheHelper(service Cacher, id int64) (string, error) {
	data, err := b.Cache.Get(service.CachePrefix(id))
	// if not err, return early
	if err == nil {
		return data, nil
	}

	// if error isnt nilErr, return
	// TODO this redis err should not be here
	if err != redis.ErrNil {
		return "", err
	}

	// try to get data from getter func
	d, err := service.GetForCache(id)
	if err != nil {
		return "", err
	}

	// after getting data, set it to cache
	// since we have the data, no need to handle error here
	err = b.putHelper(service.CachePrefix(id), d)
	if err != nil {
		b.log.Error("Error occurred while setting data to cache %v", err.Error())
	}

	return d, nil
}

func (b *Bongo) setToCacheHelper(service Cacher, id int64) error {
	// try to get data from getter func
	d, err := service.GetForCache(id)
	if err != nil {
		return err
	}

	// after getting data, set it to cache
	// since we have the data, no need to handle error here
	return b.putHelper(service.CachePrefix(id), d)
}

func (b *Bongo) putHelper(id, data string) error {
	return b.Cache.Set(id, data)
}
<commit_msg>Bongo: remove unnecessary code<commit_after>package bongo

import (
	"encoding/json"
	"strings"

	"github.com/koding/redis"
)

// A generic key value storage interface. Implementations must be thread safe.
// The storage can be anything.
type Cache interface {
	// Get retrieves data from the storage.
	Get(key string) (string, error)

	// Set puts data into the storage.
	Set(key string, item string) error

	// TODO implement Delete, MultiGet, MultiSet
}

// Basic requirements for a model for working with caching system
type Cacher interface {
	CachePrefix(id int64) string
	GetForCache(id int64) (string, error)
	Cacheable
}

type Cacheable interface {
	GetCacheId() int64
}

func (b *Bongo) GetFromBest(i Modellable, data Cacher, id int64) error {
	var d string
	var err error

	// check if cache is enabled
	if b.Cache == nil {
		// try to get data from getter func
		d, err = data.GetForCache(id)
		if err != nil {
			return err
		}
	} else {
		// get data from cache
		d, err = b.getFromCacheHelper(data, id)
		if err != nil {
			return err
		}
	}

	// marshall it to the `modellable`
	return json.NewDecoder(strings.NewReader(d)).Decode(i)
}

func (b *Bongo) SetToCache(data Cacher) error {
	// check if  cache is enabled
	if b.Cache == nil {
		return ErrCacheIsNotEnabled
	}

	return b.setToCacheHelper(data, data.GetCacheId())

}

func (b *Bongo) getFromCacheHelper(service Cacher, id int64) (string, error) {
	data, err := b.Cache.Get(service.CachePrefix(id))
	// if not err, return early
	if err == nil {
		return data, nil
	}

	// if error isnt nilErr, return
	// TODO this redis err should not be here
	if err != redis.ErrNil {
		return "", err
	}

	// try to get data from getter func
	d, err := service.GetForCache(id)
	if err != nil {
		return "", err
	}

	// after getting data, set it to cache
	// since we have the data, no need to handle error here
	err = b.putHelper(service.CachePrefix(id), d)
	if err != nil {
		b.log.Error("Error occurred while setting data to cache %v", err.Error())
	}

	return d, nil
}

func (b *Bongo) setToCacheHelper(service Cacher, id int64) error {
	// try to get data from getter func
	d, err := service.GetForCache(id)
	if err != nil {
		return err
	}

	// after getting data, set it to cache
	// since we have the data, no need to handle error here
	return b.putHelper(service.CachePrefix(id), d)
}

func (b *Bongo) putHelper(id, data string) error {
	return b.Cache.Set(id, data)
}
<|endoftext|>