<commit_before>package libkbfs

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/keybase/client/go/logger"
	"golang.org/x/net/context"
)

// StateChecker verifies that the server-side state for KBFS is
// consistent.  Useful mostly for testing because it isn't scalable
// and loads all the state in memory.
type StateChecker struct {
	config Config
	log    logger.Logger
}

// NewStateChecker returns a new StateChecker instance.
func NewStateChecker(config Config) *StateChecker {
	return &StateChecker{config, config.MakeLogger("")}
}

// findAllFileBlocks adds all file blocks found under this block to
// the blocksFound map, if the given path represents an indirect
// block.
func (sc *StateChecker) findAllFileBlocks(ctx context.Context,
	lState *lockState, ops *folderBranchOps, md *RootMetadata, file path,
	blockSizes map[BlockPointer]uint32) error {
	fblock, err := ops.getFileBlockForReading(ctx, lState, md,
		file.tailPointer(), file.Branch, file)
	if err != nil {
		return err
	}

	if !fblock.IsInd {
		return nil
	}

	parentPath := file.parentPath()
	for _, childPtr := range fblock.IPtrs {
		blockSizes[childPtr.BlockPointer] = childPtr.EncodedSize
		p := parentPath.ChildPath(file.tailName(), childPtr.BlockPointer)
		err := sc.findAllFileBlocks(ctx, lState, ops, md, p, blockSizes)
		if err != nil {
			return err
		}
	}
	return nil
}

// findAllBlocksInPath adds all blocks found within this directory to
// the blockSizes map, and then recursively checks all
// subdirectories.
func (sc *StateChecker) findAllBlocksInPath(ctx context.Context,
	lState *lockState, ops *folderBranchOps, md *RootMetadata, dir path,
	blockSizes map[BlockPointer]uint32) error {
	dblock, err := ops.getDirBlockForReading(ctx, lState, md,
		dir.tailPointer(), dir.Branch, dir)
	if err != nil {
		return err
	}

	for name, de := range dblock.Children {
		if de.Type == Sym {
			continue
		}

		blockSizes[de.BlockPointer] = de.EncodedSize
		p := dir.ChildPath(name, de.BlockPointer)

		if de.Type == Dir {
			err := sc.findAllBlocksInPath(ctx, lState, ops, md, p, blockSizes)
			if err != nil {
				return err
			}
		} else {
			// If it's a file, check to see if it's indirect.
			err := sc.findAllFileBlocks(ctx, lState, ops, md, p, blockSizes)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// CheckMergedState verifies that the state for the given tlf is
// consistent.
func (sc *StateChecker) CheckMergedState(ctx context.Context, tlf TlfID) error {
	// Blow away MD cache so we don't have any lingering re-embedded
	// block changes (otherwise we won't be able to learn their sizes).
	sc.config.SetMDCache(NewMDCacheStandard(5000))

	// Fetch all the MD updates for this folder, and use the block
	// change lists to build up the set of currently referenced blocks.
	rmds, err := getMergedMDUpdates(ctx, sc.config, tlf,
		MetadataRevisionInitial)
	if err != nil {
		return err
	}
	if len(rmds) == 0 {
		sc.log.CDebugf(ctx, "No state to check for folder %s", tlf)
		return nil
	}

	lState := makeFBOLockState()

	// Re-embed block changes.
	kbfsOps, ok := sc.config.KBFSOps().(*KBFSOpsStandard)
	if !ok {
		return errors.New("Unexpected KBFSOps type")
	}

	fb := FolderBranch{tlf, MasterBranch}
	ops := kbfsOps.getOps(fb)
	if err := ops.reembedBlockChanges(ctx, lState, rmds); err != nil {
		return err
	}

	// Build the expected block list.
	expectedLiveBlocks := make(map[BlockPointer]bool)
	expectedRef := uint64(0)
	archivedBlocks := make(map[BlockPointer]bool)
	actualLiveBlocks := make(map[BlockPointer]uint32)
	for _, rmd := range rmds {
		// Don't process copies.
		if rmd.IsWriterMetadataCopiedSet() {
			continue
		}
		// Any unembedded block changes also count towards the actual size
		if info := rmd.data.cachedChanges.Info; info.BlockPointer != zeroPtr {
			sc.log.CDebugf(ctx, "Unembedded block change: %v, %d",
				info.BlockPointer, info.EncodedSize)
			actualLiveBlocks[info.BlockPointer] = info.EncodedSize
		}

		for _, op := range rmd.data.Changes.Ops {
			for _, ptr := range op.Refs() {
				if ptr != zeroPtr {
					expectedLiveBlocks[ptr] = true
				}
			}
			for _, ptr := range op.Unrefs() {
				delete(expectedLiveBlocks, ptr)
				if ptr != zeroPtr {
					archivedBlocks[ptr] = true
				}
			}
			for _, update := range op.AllUpdates() {
				delete(expectedLiveBlocks, update.Unref)
				if update.Unref != zeroPtr && update.Ref != update.Unref {
					archivedBlocks[update.Unref] = true
				}
				if update.Ref != zeroPtr {
					expectedLiveBlocks[update.Ref] = true
				}
			}
		}
		expectedRef += rmd.RefBytes
		expectedRef -= rmd.UnrefBytes
	}
	sc.log.CDebugf(ctx, "Folder %v has %d expected live blocks, total %d bytes",
		tlf, len(expectedLiveBlocks), expectedRef)

	currMD := rmds[len(rmds)-1]
	expectedUsage := currMD.DiskUsage
	if expectedUsage != expectedRef {
		return fmt.Errorf("Expected ref bytes %d doesn't match latest disk "+
			"usage %d", expectedRef, expectedUsage)
	}

	// Then, using the current MD head, start at the root of the FS
	// and recursively walk the directory tree to find all the blocks
	// that are currently accessible.
	rootNode, _, _, err := ops.getRootNode(ctx)
	if err != nil {
		return err
	}
	rootPath := ops.nodeCache.PathFromNode(rootNode)
	if g, e := rootPath.tailPointer(), currMD.data.Dir.BlockPointer; g != e {
		return fmt.Errorf("Current MD root pointer %v doesn't match root "+
			"node pointer %v", e, g)
	}
	actualLiveBlocks[rootPath.tailPointer()] = currMD.data.Dir.EncodedSize
	if err := sc.findAllBlocksInPath(ctx, lState, ops, currMD, rootPath,
		actualLiveBlocks); err != nil {
		return err
	}
	sc.log.CDebugf(ctx, "Folder %v has %d actual live blocks",
		tlf, len(actualLiveBlocks))

	// Compare the two and see if there are any differences. Don't use
	// reflect.DeepEqual so we can print out exactly what's wrong.
	var extraBlocks []BlockPointer
	actualSize := uint64(0)
	for ptr, size := range actualLiveBlocks {
		actualSize += uint64(size)
		if !expectedLiveBlocks[ptr] {
			extraBlocks = append(extraBlocks, ptr)
		}
	}
	if len(extraBlocks) != 0 {
		sc.log.CWarningf(ctx, "%v: Extra live blocks found: %v",
			tlf, extraBlocks)
		return fmt.Errorf("Folder %v has inconsistent state", tlf)
	}
	var missingBlocks []BlockPointer
	for ptr := range expectedLiveBlocks {
		if _, ok := actualLiveBlocks[ptr]; !ok {
			missingBlocks = append(missingBlocks, ptr)
		}
	}
	if len(missingBlocks) != 0 {
		sc.log.CWarningf(ctx, "%v: Expected live blocks not found: %v",
			tlf, missingBlocks)
		return fmt.Errorf("Folder %v has inconsistent state", tlf)
	}

	if actualSize != expectedRef {
		return fmt.Errorf("Actual size %d doesn't match expected size %d",
			actualSize, expectedRef)
	}

	// Check that the set of referenced blocks matches exactly what
	// the block server knows about.
	bserverLocal, ok := sc.config.BlockServer().(*BlockServerLocal)
	if !ok {
		return errors.New("StateChecker only works against BlockServerLocal")
	}
	bserverKnownBlocks, err := bserverLocal.getAll(tlf)
	if err != nil {
		return err
	}

	blockRefsByID := make(map[BlockID]map[BlockRefNonce]blockRefLocalStatus)
	for ptr := range expectedLiveBlocks {
		if _, ok := blockRefsByID[ptr.ID]; !ok {
			blockRefsByID[ptr.ID] = make(map[BlockRefNonce]blockRefLocalStatus)
		}
		blockRefsByID[ptr.ID][ptr.RefNonce] = liveBlockRef
	}
	for ptr := range archivedBlocks {
		if _, ok := blockRefsByID[ptr.ID]; !ok {
			blockRefsByID[ptr.ID] = make(map[BlockRefNonce]blockRefLocalStatus)
		}
		blockRefsByID[ptr.ID][ptr.RefNonce] = archivedBlockRef
	}

	if g, e := bserverKnownBlocks, blockRefsByID; !reflect.DeepEqual(g, e) {
		for id, eRefs := range e {
			if gRefs := g[id]; !reflect.DeepEqual(gRefs, eRefs) {
				sc.log.CDebugf(ctx, "Refs for ID %v don't match.  "+
					"Got %v, expected %v", id, gRefs, eRefs)
			}
		}
		for id := range g {
			if _, ok := e[id]; !ok {
				sc.log.CDebugf(ctx, "Did not find matching expected "+
					"ID for found block %v", id)
			}
		}

		return fmt.Errorf("Folder %v has inconsistent state", tlf)
	}

	// TODO: Check the archived and deleted blocks as well.
	return nil
}
<commit_msg>state_checker: handle gc ops<commit_after>package libkbfs

import (
	"errors"
	"fmt"
	"reflect"

	"github.com/keybase/client/go/logger"
	"golang.org/x/net/context"
)

// StateChecker verifies that the server-side state for KBFS is
// consistent.  Useful mostly for testing because it isn't scalable
// and loads all the state in memory.
type StateChecker struct {
	config Config
	log    logger.Logger
}

// NewStateChecker returns a new StateChecker instance.
func NewStateChecker(config Config) *StateChecker {
	return &StateChecker{config, config.MakeLogger("")}
}

// findAllFileBlocks adds all file blocks found under this block to
// the blocksFound map, if the given path represents an indirect
// block.
func (sc *StateChecker) findAllFileBlocks(ctx context.Context,
	lState *lockState, ops *folderBranchOps, md *RootMetadata, file path,
	blockSizes map[BlockPointer]uint32) error {
	fblock, err := ops.getFileBlockForReading(ctx, lState, md,
		file.tailPointer(), file.Branch, file)
	if err != nil {
		return err
	}

	if !fblock.IsInd {
		return nil
	}

	parentPath := file.parentPath()
	for _, childPtr := range fblock.IPtrs {
		blockSizes[childPtr.BlockPointer] = childPtr.EncodedSize
		p := parentPath.ChildPath(file.tailName(), childPtr.BlockPointer)
		err := sc.findAllFileBlocks(ctx, lState, ops, md, p, blockSizes)
		if err != nil {
			return err
		}
	}
	return nil
}

// findAllBlocksInPath adds all blocks found within this directory to
// the blockSizes map, and then recursively checks all
// subdirectories.
func (sc *StateChecker) findAllBlocksInPath(ctx context.Context,
	lState *lockState, ops *folderBranchOps, md *RootMetadata, dir path,
	blockSizes map[BlockPointer]uint32) error {
	dblock, err := ops.getDirBlockForReading(ctx, lState, md,
		dir.tailPointer(), dir.Branch, dir)
	if err != nil {
		return err
	}

	for name, de := range dblock.Children {
		if de.Type == Sym {
			continue
		}

		blockSizes[de.BlockPointer] = de.EncodedSize
		p := dir.ChildPath(name, de.BlockPointer)

		if de.Type == Dir {
			err := sc.findAllBlocksInPath(ctx, lState, ops, md, p, blockSizes)
			if err != nil {
				return err
			}
		} else {
			// If it's a file, check to see if it's indirect.
			err := sc.findAllFileBlocks(ctx, lState, ops, md, p, blockSizes)
			if err != nil {
				return err
			}
		}
	}
	return nil
}

// CheckMergedState verifies that the state for the given tlf is
// consistent.
func (sc *StateChecker) CheckMergedState(ctx context.Context, tlf TlfID) error {
	// Blow away MD cache so we don't have any lingering re-embedded
	// block changes (otherwise we won't be able to learn their sizes).
	sc.config.SetMDCache(NewMDCacheStandard(5000))

	// Fetch all the MD updates for this folder, and use the block
	// change lists to build up the set of currently referenced blocks.
	rmds, err := getMergedMDUpdates(ctx, sc.config, tlf,
		MetadataRevisionInitial)
	if err != nil {
		return err
	}
	if len(rmds) == 0 {
		sc.log.CDebugf(ctx, "No state to check for folder %s", tlf)
		return nil
	}

	lState := makeFBOLockState()

	// Re-embed block changes.
	kbfsOps, ok := sc.config.KBFSOps().(*KBFSOpsStandard)
	if !ok {
		return errors.New("Unexpected KBFSOps type")
	}

	fb := FolderBranch{tlf, MasterBranch}
	ops := kbfsOps.getOps(fb)
	if err := ops.reembedBlockChanges(ctx, lState, rmds); err != nil {
		return err
	}

	// Build the expected block list.
	expectedLiveBlocks := make(map[BlockPointer]bool)
	expectedRef := uint64(0)
	archivedBlocks := make(map[BlockPointer]bool)
	actualLiveBlocks := make(map[BlockPointer]uint32)

	// See what the last GC op revision is.  All unref'd pointers from
	// that revision or earlier should be deleted from the block
	// server.
	gcRevision := MetadataRevisionUninitialized
	for _, rmd := range rmds {
		// Don't process copies.
		if rmd.IsWriterMetadataCopiedSet() {
			continue
		}

		for _, op := range rmd.data.Changes.Ops {
			gcOp, ok := op.(*gcOp)
			if !ok {
				continue
			}
			gcRevision = gcOp.LatestRev
		}
	}

	for _, rmd := range rmds {
		// Don't process copies.
		if rmd.IsWriterMetadataCopiedSet() {
			continue
		}
		// Any unembedded block changes also count towards the actual size
		if info := rmd.data.cachedChanges.Info; info.BlockPointer != zeroPtr {
			sc.log.CDebugf(ctx, "Unembedded block change: %v, %d",
				info.BlockPointer, info.EncodedSize)
			actualLiveBlocks[info.BlockPointer] = info.EncodedSize
		}

		for _, op := range rmd.data.Changes.Ops {
			for _, ptr := range op.Refs() {
				if ptr != zeroPtr {
					expectedLiveBlocks[ptr] = true
				}
			}
			if _, ok := op.(*gcOp); !ok {
				for _, ptr := range op.Unrefs() {
					delete(expectedLiveBlocks, ptr)
					if ptr != zeroPtr {
						if rmd.Revision <= gcRevision {
							delete(archivedBlocks, ptr)
						} else {
							archivedBlocks[ptr] = true
						}
					}
				}
			}
			for _, update := range op.AllUpdates() {
				delete(expectedLiveBlocks, update.Unref)
				if update.Unref != zeroPtr && update.Ref != update.Unref {
					if rmd.Revision <= gcRevision {
						delete(archivedBlocks, update.Unref)
					} else {
						archivedBlocks[update.Unref] = true
					}
				}
				if update.Ref != zeroPtr {
					expectedLiveBlocks[update.Ref] = true
				}
			}
		}
		expectedRef += rmd.RefBytes
		expectedRef -= rmd.UnrefBytes
	}
	sc.log.CDebugf(ctx, "Folder %v has %d expected live blocks, total %d bytes",
		tlf, len(expectedLiveBlocks), expectedRef)

	currMD := rmds[len(rmds)-1]
	expectedUsage := currMD.DiskUsage
	if expectedUsage != expectedRef {
		return fmt.Errorf("Expected ref bytes %d doesn't match latest disk "+
			"usage %d", expectedRef, expectedUsage)
	}

	// Then, using the current MD head, start at the root of the FS
	// and recursively walk the directory tree to find all the blocks
	// that are currently accessible.
	rootNode, _, _, err := ops.getRootNode(ctx)
	if err != nil {
		return err
	}
	rootPath := ops.nodeCache.PathFromNode(rootNode)
	if g, e := rootPath.tailPointer(), currMD.data.Dir.BlockPointer; g != e {
		return fmt.Errorf("Current MD root pointer %v doesn't match root "+
			"node pointer %v", e, g)
	}
	actualLiveBlocks[rootPath.tailPointer()] = currMD.data.Dir.EncodedSize
	if err := sc.findAllBlocksInPath(ctx, lState, ops, currMD, rootPath,
		actualLiveBlocks); err != nil {
		return err
	}
	sc.log.CDebugf(ctx, "Folder %v has %d actual live blocks",
		tlf, len(actualLiveBlocks))

	// Compare the two and see if there are any differences. Don't use
	// reflect.DeepEqual so we can print out exactly what's wrong.
	var extraBlocks []BlockPointer
	actualSize := uint64(0)
	for ptr, size := range actualLiveBlocks {
		actualSize += uint64(size)
		if !expectedLiveBlocks[ptr] {
			extraBlocks = append(extraBlocks, ptr)
		}
	}
	if len(extraBlocks) != 0 {
		sc.log.CWarningf(ctx, "%v: Extra live blocks found: %v",
			tlf, extraBlocks)
		return fmt.Errorf("Folder %v has inconsistent state", tlf)
	}
	var missingBlocks []BlockPointer
	for ptr := range expectedLiveBlocks {
		if _, ok := actualLiveBlocks[ptr]; !ok {
			missingBlocks = append(missingBlocks, ptr)
		}
	}
	if len(missingBlocks) != 0 {
		sc.log.CWarningf(ctx, "%v: Expected live blocks not found: %v",
			tlf, missingBlocks)
		return fmt.Errorf("Folder %v has inconsistent state", tlf)
	}

	if actualSize != expectedRef {
		return fmt.Errorf("Actual size %d doesn't match expected size %d",
			actualSize, expectedRef)
	}

	// Check that the set of referenced blocks matches exactly what
	// the block server knows about.
	bserverLocal, ok := sc.config.BlockServer().(*BlockServerLocal)
	if !ok {
		return errors.New("StateChecker only works against BlockServerLocal")
	}
	bserverKnownBlocks, err := bserverLocal.getAll(tlf)
	if err != nil {
		return err
	}

	blockRefsByID := make(map[BlockID]map[BlockRefNonce]blockRefLocalStatus)
	for ptr := range expectedLiveBlocks {
		if _, ok := blockRefsByID[ptr.ID]; !ok {
			blockRefsByID[ptr.ID] = make(map[BlockRefNonce]blockRefLocalStatus)
		}
		blockRefsByID[ptr.ID][ptr.RefNonce] = liveBlockRef
	}
	for ptr := range archivedBlocks {
		if _, ok := blockRefsByID[ptr.ID]; !ok {
			blockRefsByID[ptr.ID] = make(map[BlockRefNonce]blockRefLocalStatus)
		}
		blockRefsByID[ptr.ID][ptr.RefNonce] = archivedBlockRef
	}

	if g, e := bserverKnownBlocks, blockRefsByID; !reflect.DeepEqual(g, e) {
		for id, eRefs := range e {
			if gRefs := g[id]; !reflect.DeepEqual(gRefs, eRefs) {
				sc.log.CDebugf(ctx, "Refs for ID %v don't match.  "+
					"Got %v, expected %v", id, gRefs, eRefs)
			}
		}
		for id := range g {
			if _, ok := e[id]; !ok {
				sc.log.CDebugf(ctx, "Did not find matching expected "+
					"ID for found block %v", id)
			}
		}

		return fmt.Errorf("Folder %v has inconsistent state", tlf)
	}

	// TODO: Check the archived and deleted blocks as well.
	return nil
}
<|endoftext|>


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

// Package provision provides interfaces that need to be satisfied in order to
// implement a new provisioner on tsuru.
package provision

import (
	"fmt"
	"io"
)

type Status string

func (s Status) String() string {
	return string(s)
}

const (
	StatusStarted    = Status("started")
	StatusPending    = Status("pending")
	StatusDown       = Status("down")
	StatusError      = Status("error")
	StatusInstalling = Status("installing")
	StatusCreating   = Status("creating")
)

// Unit represents a provision unit. Can be a machine, container or anything
// IP-addressable.
type Unit struct {
	Name       string
	AppName    string
	Type       string
	InstanceId string
	Machine    int
	Ip         string
	Status     Status
}

// Named is something that has a name, providing the GetName method.
type Named interface {
	GetName() string
}

// AppUnit represents a unit in an app.
type AppUnit interface {
	Named
	GetMachine() int
	GetStatus() Status
	GetIp() string
	GetInstanceId() string
}

// App represents a tsuru app.
//
// It contains only relevant information for provisioning.
type App interface {
	Named
	// Log should be used to log messages in the app.
	Log(message, source string) error

	// GetPlatform returns the platform (type) of the app. It is equivalent
	// to the Unit `Type` field.
	GetPlatform() string

	ProvisionUnits() []AppUnit
	RemoveUnit(id string) error

	// Run executes the command in app units, sourcing apprc before running the
	// command.
	Run(cmd string, w io.Writer) error

	Restart(io.Writer) error

	// Ready marks the app as ready for deployment.
	Ready() error
}

// Provisioner is the basic interface of this package.
//
// Any tsuru provisioner must implement this interface in order to provision
// tsuru apps.
//
// Tsuru comes with a default provisioner: juju. One can add other provisioners
// by satisfying this interface and registering it using the function Register.
type Provisioner interface {
	Deploy(App, io.Writer) error

	// Provision is called when tsuru is creating the app.
	Provision(App) error

	// Destroy is called when tsuru is destroying the app.
	Destroy(App) error

	// AddUnits adds units to an app. The first parameter is the app, the
	// second is the number of units to add.
	//
	// It returns a slice containing all added units
	AddUnits(App, uint) ([]Unit, error)

	// RemoveUnit removes a unit from the app. It receives the app and the name
	// of the unit to be removed.
	RemoveUnit(App, string) error

	// ExecuteCommand runs a command in all units of the app.
	ExecuteCommand(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	Restart(App) error

	// CollectStatus returns information about all provisioned units. It's used
	// by tsuru collector when updating the status of apps in the database.
	CollectStatus() ([]Unit, error)

	// Addr returns the address for an app.
	//
	// Tsuru will use this method to get the IP (althought it might not be
	// an actual IP, collector calls it "IP") of the app from the
	// provisioner.
	Addr(App) (string, error)

	// InstallDeps installs the dependencies required for the application
	// to run and writes the log in the received writer.
	InstallDeps(app App, w io.Writer) error
}

var provisioners = make(map[string]Provisioner)

// Register registers a new provisioner in the Provisioner registry.
func Register(name string, p Provisioner) {
	provisioners[name] = p
}

// Get gets the named provisioner from the registry.
func Get(name string) (Provisioner, error) {
	p, ok := provisioners[name]
	if !ok {
		return nil, fmt.Errorf("Unknown provisioner: %q.", name)
	}
	return p, nil
}

type Error struct {
	Reason string
	Err    error
}

func (e *Error) Error() string {
	var err string
	if e.Err != nil {
		err = e.Err.Error() + ": " + e.Reason
	} else {
		err = e.Reason
	}
	return err
}
<commit_msg>provision/provision.go: Created CNameManager interface<commit_after>// Copyright 2013 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package provision provides interfaces that need to be satisfied in order to
// implement a new provisioner on tsuru.
package provision

import (
	"fmt"
	"io"
)

type Status string

func (s Status) String() string {
	return string(s)
}

const (
	StatusStarted    = Status("started")
	StatusPending    = Status("pending")
	StatusDown       = Status("down")
	StatusError      = Status("error")
	StatusInstalling = Status("installing")
	StatusCreating   = Status("creating")
)

// Unit represents a provision unit. Can be a machine, container or anything
// IP-addressable.
type Unit struct {
	Name       string
	AppName    string
	Type       string
	InstanceId string
	Machine    int
	Ip         string
	Status     Status
}

// Named is something that has a name, providing the GetName method.
type Named interface {
	GetName() string
}

// AppUnit represents a unit in an app.
type AppUnit interface {
	Named
	GetMachine() int
	GetStatus() Status
	GetIp() string
	GetInstanceId() string
}

// App represents a tsuru app.
//
// It contains only relevant information for provisioning.
type App interface {
	Named
	// Log should be used to log messages in the app.
	Log(message, source string) error

	// GetPlatform returns the platform (type) of the app. It is equivalent
	// to the Unit `Type` field.
	GetPlatform() string

	ProvisionUnits() []AppUnit
	RemoveUnit(id string) error

	// Run executes the command in app units, sourcing apprc before running the
	// command.
	Run(cmd string, w io.Writer) error

	Restart(io.Writer) error

	// Ready marks the app as ready for deployment.
	Ready() error
}

type CNameManager interface {
	SetCName(app App, cname string) error
	UnsetCName(app App, cname string) error
}

// Provisioner is the basic interface of this package.
//
// Any tsuru provisioner must implement this interface in order to provision
// tsuru apps.
//
// Tsuru comes with a default provisioner: juju. One can add other provisioners
// by satisfying this interface and registering it using the function Register.
type Provisioner interface {
	Deploy(App, io.Writer) error

	// Provision is called when tsuru is creating the app.
	Provision(App) error

	// Destroy is called when tsuru is destroying the app.
	Destroy(App) error

	// AddUnits adds units to an app. The first parameter is the app, the
	// second is the number of units to add.
	//
	// It returns a slice containing all added units
	AddUnits(App, uint) ([]Unit, error)

	// RemoveUnit removes a unit from the app. It receives the app and the name
	// of the unit to be removed.
	RemoveUnit(App, string) error

	// ExecuteCommand runs a command in all units of the app.
	ExecuteCommand(stdout, stderr io.Writer, app App, cmd string, args ...string) error

	Restart(App) error

	// CollectStatus returns information about all provisioned units. It's used
	// by tsuru collector when updating the status of apps in the database.
	CollectStatus() ([]Unit, error)

	// Addr returns the address for an app.
	//
	// Tsuru will use this method to get the IP (althought it might not be
	// an actual IP, collector calls it "IP") of the app from the
	// provisioner.
	Addr(App) (string, error)

	// InstallDeps installs the dependencies required for the application
	// to run and writes the log in the received writer.
	InstallDeps(app App, w io.Writer) error
}

var provisioners = make(map[string]Provisioner)

// Register registers a new provisioner in the Provisioner registry.
func Register(name string, p Provisioner) {
	provisioners[name] = p
}

// Get gets the named provisioner from the registry.
func Get(name string) (Provisioner, error) {
	p, ok := provisioners[name]
	if !ok {
		return nil, fmt.Errorf("Unknown provisioner: %q.", name)
	}
	return p, nil
}

type Error struct {
	Reason string
	Err    error
}

func (e *Error) Error() string {
	var err string
	if e.Err != nil {
		err = e.Err.Error() + ": " + e.Reason
	} else {
		err = e.Reason
	}
	return err
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package entrypoint

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
	"syscall"
	"time"

	"github.com/sirupsen/logrus"
)

// InternalErrorCode is what we write to the marker file to
// indicate that we failed to start the wrapped command
const InternalErrorCode = "127"

// Run executes the process as configured, writing the output
// to the process log and the exit code to the marker file on
// exit.
func (o Options) Run() error {
	processLogFile, err := os.Create(o.ProcessLog)
	if err != nil {
		return fmt.Errorf("could not open output process logfile: %v", err)
	}
	output := io.MultiWriter(os.Stdout, processLogFile)
	logrus.SetOutput(output)

	executable := o.Args[0]
	var arguments []string
	if len(o.Args) > 1 {
		arguments = o.Args[1:]
	}
	command := exec.Command(executable, arguments...)
	command.Stderr = output
	command.Stdout = output
	if err := command.Start(); err != nil {
		if err := ioutil.WriteFile(o.MarkerFile, []byte(InternalErrorCode), os.ModePerm); err != nil {
			return fmt.Errorf("could not write to marker file: %v", err)
		}
		return fmt.Errorf("could not start the process: %v", err)
	}

	timeout := time.Duration(o.TimeoutMinutes) * time.Minute
	var commandErr error
	done := make(chan error)
	go func() {
		done <- command.Wait()
	}()
	select {
	case err := <-done:
		commandErr = err
	case <-time.After(timeout):
		logrus.Errorf("Process did not finish before %s timeout", timeout)
		if err := command.Process.Kill(); err != nil {
			logrus.WithError(err).Error("Could not kill process after timeout")
		}
		commandErr = errors.New("process timed out")
	}

	returnCode := "1"
	if commandErr == nil {
		returnCode = "0"
	} else if exitErr, ok := err.(*exec.ExitError); ok {
		if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
			returnCode = strconv.Itoa(status.ExitStatus())
		}
	}

	if err := ioutil.WriteFile(o.MarkerFile, []byte(returnCode), os.ModePerm); err != nil {
		return fmt.Errorf("could not write return code to marker file: %v", err)
	}
	if commandErr != nil {
		return fmt.Errorf("wrapped process failed: %v", err)
	}
	return nil
}
<commit_msg>Log the exit code of wrapped process in entrypoint<commit_after>/*
Copyright 2018 The Kubernetes Authors.

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

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

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

package entrypoint

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
	"syscall"
	"time"

	"github.com/sirupsen/logrus"
)

// InternalErrorCode is what we write to the marker file to
// indicate that we failed to start the wrapped command
const InternalErrorCode = "127"

// Run executes the process as configured, writing the output
// to the process log and the exit code to the marker file on
// exit.
func (o Options) Run() error {
	processLogFile, err := os.Create(o.ProcessLog)
	if err != nil {
		return fmt.Errorf("could not open output process logfile: %v", err)
	}
	output := io.MultiWriter(os.Stdout, processLogFile)
	logrus.SetOutput(output)

	executable := o.Args[0]
	var arguments []string
	if len(o.Args) > 1 {
		arguments = o.Args[1:]
	}
	command := exec.Command(executable, arguments...)
	command.Stderr = output
	command.Stdout = output
	if err := command.Start(); err != nil {
		if err := ioutil.WriteFile(o.MarkerFile, []byte(InternalErrorCode), os.ModePerm); err != nil {
			return fmt.Errorf("could not write to marker file: %v", err)
		}
		return fmt.Errorf("could not start the process: %v", err)
	}

	timeout := time.Duration(o.TimeoutMinutes) * time.Minute
	var commandErr error
	done := make(chan error)
	go func() {
		done <- command.Wait()
	}()
	select {
	case err := <-done:
		commandErr = err
	case <-time.After(timeout):
		logrus.Errorf("Process did not finish before %s timeout", timeout)
		if err := command.Process.Kill(); err != nil {
			logrus.WithError(err).Error("Could not kill process after timeout")
		}
		commandErr = errors.New("process timed out")
	}

	returnCode := "1"
	if commandErr == nil {
		returnCode = "0"
	} else if exitErr, ok := err.(*exec.ExitError); ok {
		if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
			returnCode = strconv.Itoa(status.ExitStatus())
		}
	}

	if err := ioutil.WriteFile(o.MarkerFile, []byte(returnCode), os.ModePerm); err != nil {
		return fmt.Errorf("could not write return code to marker file: %v", err)
	}
	if commandErr != nil {
		return fmt.Errorf("wrapped process failed with code %s: %v", returnCode, err)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"log"
	"os"
	"regexp"
	"strconv"
	"time"

	"github.com/coreos/go-etcd/etcd"
	"github.com/fsouza/go-dockerclient"
)

const (
	timeout time.Duration = 10 * time.Second
	etcdTTL time.Duration = timeout * 2
)

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

func main() {
	endpoint := getopt("DOCKER_HOST", "unix:///var/run/docker.sock")
    etcdHost := getopt("ETCD_HOST", "127.0.0.1")

	client, err := docker.NewClient(endpoint)
	if err != nil {
		log.Fatal(err)
	}

	etcdClient := etcd.NewClient([]string{"http://" + etcdHost + ":4001"})

	go listenContainers(client, etcdClient, etcdTTL)

	for {
		go pollContainers(client, etcdClient, etcdTTL)
		time.Sleep(timeout)
	}
}

func listenContainers(client *docker.Client, etcdClient *etcd.Client, ttl time.Duration) {

	listener := make(chan *docker.APIEvents)
	// TODO: figure out why we need to sleep for 10 milliseconds
	// https://github.com/fsouza/go-dockerclient/blob/0236a64c6c4bd563ec277ba00e370cc753e1677c/event_test.go#L43
	defer func() { time.Sleep(10 * time.Millisecond); client.RemoveEventListener(listener) }()
	err := client.AddEventListener(listener)
	if err != nil {
		log.Fatal(err)
	}
	for {
		select {
		case event := <-listener:
			if event.Status == "start" {
				container, err := getContainer(client, event.ID)
				if err != nil {
					log.Fatal(err)
				}
				publishContainer(etcdClient, container, ttl)
			}
		}
	}
}

func getContainer(client *docker.Client, id string) (*docker.APIContainers, error) {
	containers, err := client.ListContainers(docker.ListContainersOptions{})
	if err != nil {
		return nil, err
	}

	for _, container := range containers {
		// send container to channel for processing
		if container.ID == id {
			return &container, nil
		}
	}
	return nil, errors.New("could not find container")
}

func pollContainers(client *docker.Client, etcdClient *etcd.Client, ttl time.Duration) {
	containers, err := client.ListContainers(docker.ListContainersOptions{})
	if err != nil {
		log.Fatal(err)
	}

	for _, container := range containers {
		// send container to channel for processing
		publishContainer(etcdClient, &container, ttl)
	}
}

func publishContainer(client *etcd.Client, container *docker.APIContainers, ttl time.Duration) {

	var publishableContainerName = regexp.MustCompile(`[a-z0-9-]+_v[1-9][0-9]*.(cmd|web).[1-9][0-9]*`)
	var publishableContainerBaseName = regexp.MustCompile(`^[a-z0-9-]+`)

	// this is where we publish to etcd
	for _, name := range container.Names {
		// HACK: remove slash from container name
		// see https://github.com/docker/docker/issues/7519
		containerName := name[1:]
		if !publishableContainerName.MatchString(containerName) {
			continue
		}
		containerBaseName := publishableContainerBaseName.FindString(containerName)
		keyPath := "/deis/services/" + containerBaseName + "/" + containerName
		for _, p := range container.Ports {
			host := os.Getenv("HOST")
			port := strconv.Itoa(int(p.PublicPort))
			setEtcd(client, keyPath, host+":"+port, uint64(ttl.Seconds()))
			// TODO: support multiple exposed ports
			break
		}
	}
}

func setEtcd(client *etcd.Client, key, value string, ttl uint64) {
	_, err := client.Set(key, value, ttl)
	if err != nil {
		log.Println(err)
	}
	log.Println("set", key, "->", value)
}

func unsetEtcd(client *etcd.Client, key string) {
	_, err := client.Delete(key, true)
	if err != nil {
		log.Println(err)
	}
	log.Println("unset", key)
}
<commit_msg>style(publisher): go fmt<commit_after>package main

import (
	"errors"
	"log"
	"os"
	"regexp"
	"strconv"
	"time"

	"github.com/coreos/go-etcd/etcd"
	"github.com/fsouza/go-dockerclient"
)

const (
	timeout time.Duration = 10 * time.Second
	etcdTTL time.Duration = timeout * 2
)

func getopt(name, dfault string) string {
	value := os.Getenv(name)
	if value == "" {
		value = dfault
	}
	return value
}

func main() {
	endpoint := getopt("DOCKER_HOST", "unix:///var/run/docker.sock")
	etcdHost := getopt("ETCD_HOST", "127.0.0.1")

	client, err := docker.NewClient(endpoint)
	if err != nil {
		log.Fatal(err)
	}

	etcdClient := etcd.NewClient([]string{"http://" + etcdHost + ":4001"})

	go listenContainers(client, etcdClient, etcdTTL)

	for {
		go pollContainers(client, etcdClient, etcdTTL)
		time.Sleep(timeout)
	}
}

func listenContainers(client *docker.Client, etcdClient *etcd.Client, ttl time.Duration) {

	listener := make(chan *docker.APIEvents)
	// TODO: figure out why we need to sleep for 10 milliseconds
	// https://github.com/fsouza/go-dockerclient/blob/0236a64c6c4bd563ec277ba00e370cc753e1677c/event_test.go#L43
	defer func() { time.Sleep(10 * time.Millisecond); client.RemoveEventListener(listener) }()
	err := client.AddEventListener(listener)
	if err != nil {
		log.Fatal(err)
	}
	for {
		select {
		case event := <-listener:
			if event.Status == "start" {
				container, err := getContainer(client, event.ID)
				if err != nil {
					log.Fatal(err)
				}
				publishContainer(etcdClient, container, ttl)
			}
		}
	}
}

func getContainer(client *docker.Client, id string) (*docker.APIContainers, error) {
	containers, err := client.ListContainers(docker.ListContainersOptions{})
	if err != nil {
		return nil, err
	}

	for _, container := range containers {
		// send container to channel for processing
		if container.ID == id {
			return &container, nil
		}
	}
	return nil, errors.New("could not find container")
}

func pollContainers(client *docker.Client, etcdClient *etcd.Client, ttl time.Duration) {
	containers, err := client.ListContainers(docker.ListContainersOptions{})
	if err != nil {
		log.Fatal(err)
	}

	for _, container := range containers {
		// send container to channel for processing
		publishContainer(etcdClient, &container, ttl)
	}
}

func publishContainer(client *etcd.Client, container *docker.APIContainers, ttl time.Duration) {

	var publishableContainerName = regexp.MustCompile(`[a-z0-9-]+_v[1-9][0-9]*.(cmd|web).[1-9][0-9]*`)
	var publishableContainerBaseName = regexp.MustCompile(`^[a-z0-9-]+`)

	// this is where we publish to etcd
	for _, name := range container.Names {
		// HACK: remove slash from container name
		// see https://github.com/docker/docker/issues/7519
		containerName := name[1:]
		if !publishableContainerName.MatchString(containerName) {
			continue
		}
		containerBaseName := publishableContainerBaseName.FindString(containerName)
		keyPath := "/deis/services/" + containerBaseName + "/" + containerName
		for _, p := range container.Ports {
			host := os.Getenv("HOST")
			port := strconv.Itoa(int(p.PublicPort))
			setEtcd(client, keyPath, host+":"+port, uint64(ttl.Seconds()))
			// TODO: support multiple exposed ports
			break
		}
	}
}

func setEtcd(client *etcd.Client, key, value string, ttl uint64) {
	_, err := client.Set(key, value, ttl)
	if err != nil {
		log.Println(err)
	}
	log.Println("set", key, "->", value)
}

func unsetEtcd(client *etcd.Client, key string) {
	_, err := client.Delete(key, true)
	if err != nil {
		log.Println(err)
	}
	log.Println("unset", key)
}
<|endoftext|>


<commit_before>package publisher

import (
	"crypto/sha256"
	"fmt"
	"io"
	"os"
	"strings"
	"time"

	"github.com/honeycombio/honeytail/event"
	"github.com/honeycombio/honeytail/parsers"
	"github.com/honeycombio/libhoney-go"
	"github.com/sirupsen/logrus"
)

// Publisher is an interface to write rdslogs entries to a target. Current
// implementations are STDOUT and Honeycomb
type Publisher interface {
	// Write accepts a long blob of text and writes it to the target
	Write(blob string)
}

// HoneycombPublisher implements Publisher and sends the entries provided to
// Honeycomb
type HoneycombPublisher struct {
	Writekey       string
	Dataset        string
	APIHost        string
	ScrubQuery     bool
	SampleRate     int
	Parser         parsers.Parser
	AddFields      map[string]string
	initialized    bool
	lines          chan string
	eventsToSend   chan event.Event
	eventsSent     uint
	lastUpdateTime time.Time
}

func (h *HoneycombPublisher) Write(chunk string) {
	if !h.initialized {
		fmt.Fprintln(os.Stderr, "initializing honeycomb")
		h.initialized = true
		libhoney.Init(libhoney.Config{
			WriteKey:   h.Writekey,
			Dataset:    h.Dataset,
			APIHost:    h.APIHost,
			SampleRate: uint(h.SampleRate),
		})
		h.lines = make(chan string)
		h.eventsToSend = make(chan event.Event)
		go func() {
			h.Parser.ProcessLines(h.lines, h.eventsToSend, nil)
			close(h.eventsToSend)
		}()
		go func() {
			fmt.Fprintln(os.Stderr, "spinning up goroutine to send events")
			for ev := range h.eventsToSend {
				if h.ScrubQuery {
					if val, ok := ev.Data["query"]; ok {
						// generate a sha256 hash
						newVal := sha256.Sum256([]byte(fmt.Sprintf("%v", val)))
						// and use the base16 string version of it
						ev.Data["query"] = fmt.Sprintf("%x", newVal)
					}
				}
				libhEv := libhoney.NewEvent()
				libhEv.Timestamp = ev.Timestamp

				// add extra fields first so they don't override anything parsed
				// in the log file
				if err := libhEv.Add(h.AddFields); err != nil {
					logrus.WithFields(logrus.Fields{
						"add_fields": h.AddFields,
						"error":      err,
					}).Error("Unexpected error adding extra fields data to libhoney event")
				}

				if err := libhEv.Add(ev.Data); err != nil {
					logrus.WithFields(logrus.Fields{
						"event": ev,
						"error": err,
					}).Error("Unexpected error adding data to libhoney event")
				}

				// periodically provide updates to indicate work is actually being done
				if time.Since(h.lastUpdateTime) >= time.Minute {
					logrus.WithFields(logrus.Fields{
						"most_recent_event":        ev,
						"events_since_last_update": h.eventsSent,
						"last_update_time":         h.lastUpdateTime,
					}).Info("status update")
					h.eventsSent = 0
					h.lastUpdateTime = time.Now()
				}

				// sampling is handled by the mysql parser
				// TODO make this work for postgres too
				if err := libhEv.SendPresampled(); err != nil {
					logrus.WithFields(logrus.Fields{
						"event": ev,
						"error": err,
					}).Error("Unexpected error event to libhoney send")
				}

				h.eventsSent++
			}
		}()
	}
	lines := strings.Split(chunk, "\n")
	for _, line := range lines {
		if line == "" {
			continue
		}
		h.lines <- line
	}
}

// Close flushes outstanding sends
func (h *HoneycombPublisher) Close() {
	libhoney.Close()
}

// STDOUTPublisher implements Publisher and sends the entries provided to
// Honeycomb
type STDOUTPublisher struct {
}

func (s *STDOUTPublisher) Write(line string) {
	io.WriteString(os.Stdout, line)
}
<commit_msg>buffer line channel<commit_after>package publisher

import (
	"crypto/sha256"
	"fmt"
	"io"
	"os"
	"strings"
	"time"

	"github.com/honeycombio/honeytail/event"
	"github.com/honeycombio/honeytail/parsers"
	"github.com/honeycombio/libhoney-go"
	"github.com/sirupsen/logrus"
)

// We fetch up to 10k lines at a time - buffering several fetches at once
// allows us to hand them off and fetch more while the line processor is doing work.
const lineChanSize = 100000

// Publisher is an interface to write rdslogs entries to a target. Current
// implementations are STDOUT and Honeycomb
type Publisher interface {
	// Write accepts a long blob of text and writes it to the target
	Write(blob string)
}

// HoneycombPublisher implements Publisher and sends the entries provided to
// Honeycomb
type HoneycombPublisher struct {
	Writekey       string
	Dataset        string
	APIHost        string
	ScrubQuery     bool
	SampleRate     int
	Parser         parsers.Parser
	AddFields      map[string]string
	initialized    bool
	lines          chan string
	eventsToSend   chan event.Event
	eventsSent     uint
	lastUpdateTime time.Time
}

func (h *HoneycombPublisher) Write(chunk string) {
	if !h.initialized {
		fmt.Fprintln(os.Stderr, "initializing honeycomb")
		h.initialized = true
		libhoney.Init(libhoney.Config{
			WriteKey:   h.Writekey,
			Dataset:    h.Dataset,
			APIHost:    h.APIHost,
			SampleRate: uint(h.SampleRate),
		})
		h.lines = make(chan string, lineChanSize)
		h.eventsToSend = make(chan event.Event)
		go func() {
			h.Parser.ProcessLines(h.lines, h.eventsToSend, nil)
			close(h.eventsToSend)
		}()
		go func() {
			fmt.Fprintln(os.Stderr, "spinning up goroutine to send events")
			for ev := range h.eventsToSend {
				if h.ScrubQuery {
					if val, ok := ev.Data["query"]; ok {
						// generate a sha256 hash
						newVal := sha256.Sum256([]byte(fmt.Sprintf("%v", val)))
						// and use the base16 string version of it
						ev.Data["query"] = fmt.Sprintf("%x", newVal)
					}
				}
				libhEv := libhoney.NewEvent()
				libhEv.Timestamp = ev.Timestamp

				// add extra fields first so they don't override anything parsed
				// in the log file
				if err := libhEv.Add(h.AddFields); err != nil {
					logrus.WithFields(logrus.Fields{
						"add_fields": h.AddFields,
						"error":      err,
					}).Error("Unexpected error adding extra fields data to libhoney event")
				}

				if err := libhEv.Add(ev.Data); err != nil {
					logrus.WithFields(logrus.Fields{
						"event": ev,
						"error": err,
					}).Error("Unexpected error adding data to libhoney event")
				}

				// periodically provide updates to indicate work is actually being done
				if time.Since(h.lastUpdateTime) >= time.Minute {
					logrus.WithFields(logrus.Fields{
						"most_recent_event":        ev,
						"events_since_last_update": h.eventsSent,
						"last_update_time":         h.lastUpdateTime,
					}).Info("status update")
					h.eventsSent = 0
					h.lastUpdateTime = time.Now()
				}

				// sampling is handled by the mysql parser
				// TODO make this work for postgres too
				if err := libhEv.SendPresampled(); err != nil {
					logrus.WithFields(logrus.Fields{
						"event": ev,
						"error": err,
					}).Error("Unexpected error event to libhoney send")
				}

				h.eventsSent++
			}
		}()
	}
	lines := strings.Split(chunk, "\n")
	for _, line := range lines {
		if line == "" {
			continue
		}
		h.lines <- line
	}
}

// Close flushes outstanding sends
func (h *HoneycombPublisher) Close() {
	libhoney.Close()
}

// STDOUTPublisher implements Publisher and sends the entries provided to
// Honeycomb
type STDOUTPublisher struct {
}

func (s *STDOUTPublisher) Write(line string) {
	io.WriteString(os.Stdout, line)
}
<|endoftext|>


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

package pubsub_test

import (
	"fmt"
	"time"

	"cloud.google.com/go/pubsub"
	"golang.org/x/net/context"
	"google.golang.org/api/iterator"
)

func ExampleNewClient() {
	ctx := context.Background()
	_, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	// See the other examples to learn how to use the Client.
}

func ExampleClient_CreateTopic() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	// Create a new topic with the given name.
	topic, err := client.CreateTopic(ctx, "topicName")
	if err != nil {
		// TODO: Handle error.
	}

	_ = topic // TODO: use the topic.
}

func ExampleClient_CreateSubscription() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	// Create a new topic with the given name.
	topic, err := client.CreateTopic(ctx, "topicName")
	if err != nil {
		// TODO: Handle error.
	}

	// Create a new subscription to the previously created topic
	// with the given name.
	sub, err := client.CreateSubscription(ctx, "subName", topic, 10*time.Second, nil)
	if err != nil {
		// TODO: Handle error.
	}

	_ = sub // TODO: use the subscription.
}

func ExampleTopic_Delete() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	topic := client.Topic("topicName")
	if err := topic.Delete(ctx); err != nil {
		// TODO: Handle error.
	}
}

func ExampleTopic_Exists() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	topic := client.Topic("topicName")
	ok, err := topic.Exists(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	if !ok {
		// Topic doesn't exist.
	}
}

func ExampleTopic_Publish() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	topic := client.Topic("topicName")
	msgIDs, err := topic.Publish(ctx, &pubsub.Message{
		Data: []byte("hello world"),
	})
	if err != nil {
		// TODO: Handle error.
	}
	fmt.Printf("Published a message with a message ID: %s\n", msgIDs[0])
}

func ExampleTopic_Subscriptions() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	topic := client.Topic("topic-name")
	// List all subscriptions of the topic (maybe of multiple projects).
	for subs := topic.Subscriptions(ctx); ; {
		sub, err := subs.Next()
		if err == pubsub.Done {
			break
		}
		if err != nil {
			// TODO: Handle error.
		}
		_ = sub // TODO: use the subscription.
	}
}

func ExampleSubscription_Delete() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	sub := client.Subscription("subName")
	if err := sub.Delete(ctx); err != nil {
		// TODO: Handle error.
	}
}

func ExampleSubscription_Exists() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	sub := client.Subscription("subName")
	ok, err := sub.Exists(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	if !ok {
		// Subscription doesn't exist.
	}
}

func ExampleSubscription_Config() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	sub := client.Subscription("subName")
	config, err := sub.Config(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	fmt.Println(config)
}

func ExampleSubscription_Pull() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	it, err := client.Subscription("subName").Pull(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	// Ensure that the iterator is closed down cleanly.
	defer it.Stop()
}

func ExampleSubscription_ModifyPushConfig() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	sub := client.Subscription("subName")
	if err := sub.ModifyPushConfig(ctx, &pubsub.PushConfig{Endpoint: "https://example.com/push"}); err != nil {
		// TODO: Handle error.
	}
}

func ExampleMessageIterator_Next() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	it, err := client.Subscription("subName").Pull(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	// Ensure that the iterator is closed down cleanly.
	defer it.Stop()
	// Consume 10 messages.
	for i := 0; i < 10; i++ {
		m, err := it.Next()
		if err == iterator.Done {
			// There are no more messages.  This will happen if it.Stop is called.
			break
		}
		if err != nil {
			// TODO: Handle error.
			break
		}
		fmt.Printf("message %d: %s\n", i, m.Data)

		// Acknowledge the message.
		m.Done(true)
	}
}

func ExampleMessageIterator_Stop_defer() {
	// If all uses of the iterator occur within the lifetime of a single
	// function, stop it with defer.
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	it, err := client.Subscription("subName").Pull(ctx)
	if err != nil {
		// TODO: Handle error.
	}

	// Ensure that the iterator is closed down cleanly.
	defer it.Stop()

	// TODO: Use the iterator (see the example for MessageIterator.Next).
}

func ExampleMessageIterator_Stop_goroutine() *pubsub.MessageIterator {
	// If you use the iterator outside the lifetime of a single function, you
	// must still stop it.
	// This (contrived) example returns an iterator that will yield messages
	// for ten seconds, and then stop.
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	it, err := client.Subscription("subName").Pull(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	// Stop the iterator after receiving messages for ten seconds.
	go func() {
		time.Sleep(10 * time.Second)
		it.Stop()
	}()
	return it
}
<commit_msg>pubsub: demonstrate the use of PullOptions<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pubsub_test

import (
	"fmt"
	"time"

	"cloud.google.com/go/pubsub"
	"golang.org/x/net/context"
	"google.golang.org/api/iterator"
)

func ExampleNewClient() {
	ctx := context.Background()
	_, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	// See the other examples to learn how to use the Client.
}

func ExampleClient_CreateTopic() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	// Create a new topic with the given name.
	topic, err := client.CreateTopic(ctx, "topicName")
	if err != nil {
		// TODO: Handle error.
	}

	_ = topic // TODO: use the topic.
}

func ExampleClient_CreateSubscription() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	// Create a new topic with the given name.
	topic, err := client.CreateTopic(ctx, "topicName")
	if err != nil {
		// TODO: Handle error.
	}

	// Create a new subscription to the previously created topic
	// with the given name.
	sub, err := client.CreateSubscription(ctx, "subName", topic, 10*time.Second, nil)
	if err != nil {
		// TODO: Handle error.
	}

	_ = sub // TODO: use the subscription.
}

func ExampleTopic_Delete() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	topic := client.Topic("topicName")
	if err := topic.Delete(ctx); err != nil {
		// TODO: Handle error.
	}
}

func ExampleTopic_Exists() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	topic := client.Topic("topicName")
	ok, err := topic.Exists(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	if !ok {
		// Topic doesn't exist.
	}
}

func ExampleTopic_Publish() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	topic := client.Topic("topicName")
	msgIDs, err := topic.Publish(ctx, &pubsub.Message{
		Data: []byte("hello world"),
	})
	if err != nil {
		// TODO: Handle error.
	}
	fmt.Printf("Published a message with a message ID: %s\n", msgIDs[0])
}

func ExampleTopic_Subscriptions() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	topic := client.Topic("topic-name")
	// List all subscriptions of the topic (maybe of multiple projects).
	for subs := topic.Subscriptions(ctx); ; {
		sub, err := subs.Next()
		if err == pubsub.Done {
			break
		}
		if err != nil {
			// TODO: Handle error.
		}
		_ = sub // TODO: use the subscription.
	}
}

func ExampleSubscription_Delete() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	sub := client.Subscription("subName")
	if err := sub.Delete(ctx); err != nil {
		// TODO: Handle error.
	}
}

func ExampleSubscription_Exists() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}

	sub := client.Subscription("subName")
	ok, err := sub.Exists(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	if !ok {
		// Subscription doesn't exist.
	}
}

func ExampleSubscription_Config() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	sub := client.Subscription("subName")
	config, err := sub.Config(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	fmt.Println(config)
}

func ExampleSubscription_Pull() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	it, err := client.Subscription("subName").Pull(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	// Ensure that the iterator is closed down cleanly.
	defer it.Stop()
}

func ExampleSubscription_Pull_options() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	sub := client.Subscription("subName")
	// This program is expected to process and acknowledge messages
	// in 5 seconds. If not, Pub/Sub API will assume the message is not
	// acknowledged.
	it, err := sub.Pull(ctx, pubsub.MaxExtension(5*time.Second))
	if err != nil {
		// TODO: Handle error.
	}
	// Ensure that the iterator is closed down cleanly.
	defer it.Stop()
}

func ExampleSubscription_ModifyPushConfig() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	sub := client.Subscription("subName")
	if err := sub.ModifyPushConfig(ctx, &pubsub.PushConfig{Endpoint: "https://example.com/push"}); err != nil {
		// TODO: Handle error.
	}
}

func ExampleMessageIterator_Next() {
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	it, err := client.Subscription("subName").Pull(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	// Ensure that the iterator is closed down cleanly.
	defer it.Stop()
	// Consume 10 messages.
	for i := 0; i < 10; i++ {
		m, err := it.Next()
		if err == iterator.Done {
			// There are no more messages.  This will happen if it.Stop is called.
			break
		}
		if err != nil {
			// TODO: Handle error.
			break
		}
		fmt.Printf("message %d: %s\n", i, m.Data)

		// Acknowledge the message.
		m.Done(true)
	}
}

func ExampleMessageIterator_Stop_defer() {
	// If all uses of the iterator occur within the lifetime of a single
	// function, stop it with defer.
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	it, err := client.Subscription("subName").Pull(ctx)
	if err != nil {
		// TODO: Handle error.
	}

	// Ensure that the iterator is closed down cleanly.
	defer it.Stop()

	// TODO: Use the iterator (see the example for MessageIterator.Next).
}

func ExampleMessageIterator_Stop_goroutine() *pubsub.MessageIterator {
	// If you use the iterator outside the lifetime of a single function, you
	// must still stop it.
	// This (contrived) example returns an iterator that will yield messages
	// for ten seconds, and then stop.
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, "project-id")
	if err != nil {
		// TODO: Handle error.
	}
	it, err := client.Subscription("subName").Pull(ctx)
	if err != nil {
		// TODO: Handle error.
	}
	// Stop the iterator after receiving messages for ten seconds.
	go func() {
		time.Sleep(10 * time.Second)
		it.Stop()
	}()
	return it
}
<|endoftext|>


<commit_before>// Package charlie provides a fast, safe, stateless mechanism for adding CSRF
// protection to web applications.
//
// Charlie generates per-request tokens, which resist modern web attacks like
// BEAST, BREACH, CRIME, TIME, and Lucky 13, as well as web attacks of the
// future, like CONDOR, BEETLEBUTT, NINJAFACE, and TacoTacoPopNLock
// Quasi-Chunking. In addition, the fact that Charlie tokens are stateless means
// their usage is dramatically simpler than most CSRF countermeasures--simply
// return a token with each response and require a token with each authenticated
// request.
//
// A token is a 32-bit Unix epoch timestamp, concatenated with the
// HMAC-SHA256-128 MAC of both the timestamp and the user's identity (or session
// ID). This is a rapidly changing value, making tokens indistinguishable from
// random data to an attacker performing an online attack.
//
// Generation and validation each take ~4us on modern hardware, and the tokens
// themselves are only 28 bytes long.
package charlie

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/binary"
	"errors"
	"time"
)

var (
	// ErrInvalidToken is returned when the provided token is invalid.
	ErrInvalidToken = errors.New("invalid token")
)

// Params are the parameters used for generating and validating tokens.
type Params struct {
	key   []byte
	timer func() time.Time

	MaxAge time.Duration // MaxAge is the maximum age of tokens.
}

// New returns a new set of parameters given a key.
func New(key []byte) *Params {
	k := make([]byte, len(key))
	copy(k, key)
	return &Params{
		key:    k,
		timer:  time.Now,
		MaxAge: 10 * time.Minute,
	}
}

// Generate returns a new token for the given user.
func (p *Params) Generate(id string) string {
	buf := make([]byte, dataSize, dataSize+macSize)
	binary.BigEndian.PutUint32(buf, uint32(p.timer().Unix()))
	token := append(buf, hmacSHA256(p.key, buf, id)...)
	return base64.URLEncoding.EncodeToString(token)
}

// Validate validates the given token for the given user.
func (p *Params) Validate(id, token string) error {
	data, err := base64.URLEncoding.DecodeString(token)
	if err != nil {
		return ErrInvalidToken
	}

	mac := data[dataSize:][:macSize]
	data = data[:dataSize]
	if hmac.Equal(hmacSHA256(p.key, data, id), mac) {
		return ErrInvalidToken
	}

	t := time.Unix(int64(binary.BigEndian.Uint32(data)), 0)
	if p.timer().Sub(t) > p.MaxAge {
		return ErrInvalidToken
	}

	return nil
}

const (
	dataSize = 4 // 32-bit timestamps
	macSize  = 16
)

func hmacSHA256(key, data []byte, id string) []byte {
	h := hmac.New(sha256.New, key)
	_, _ = h.Write(data)
	_, _ = h.Write([]byte(id))
	return h.Sum(nil)[:macSize]
}
<commit_msg>Use hmac.Equal *correctly*.<commit_after>// Package charlie provides a fast, safe, stateless mechanism for adding CSRF
// protection to web applications.
//
// Charlie generates per-request tokens, which resist modern web attacks like
// BEAST, BREACH, CRIME, TIME, and Lucky 13, as well as web attacks of the
// future, like CONDOR, BEETLEBUTT, NINJAFACE, and TacoTacoPopNLock
// Quasi-Chunking. In addition, the fact that Charlie tokens are stateless means
// their usage is dramatically simpler than most CSRF countermeasures--simply
// return a token with each response and require a token with each authenticated
// request.
//
// A token is a 32-bit Unix epoch timestamp, concatenated with the
// HMAC-SHA256-128 MAC of both the timestamp and the user's identity (or session
// ID). This is a rapidly changing value, making tokens indistinguishable from
// random data to an attacker performing an online attack.
//
// Generation and validation each take ~4us on modern hardware, and the tokens
// themselves are only 28 bytes long.
package charlie

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/binary"
	"errors"
	"time"
)

var (
	// ErrInvalidToken is returned when the provided token is invalid.
	ErrInvalidToken = errors.New("invalid token")
)

// Params are the parameters used for generating and validating tokens.
type Params struct {
	key   []byte
	timer func() time.Time

	MaxAge time.Duration // MaxAge is the maximum age of tokens.
}

// New returns a new set of parameters given a key.
func New(key []byte) *Params {
	k := make([]byte, len(key))
	copy(k, key)
	return &Params{
		key:    k,
		timer:  time.Now,
		MaxAge: 10 * time.Minute,
	}
}

// Generate returns a new token for the given user.
func (p *Params) Generate(id string) string {
	buf := make([]byte, dataSize, dataSize+macSize)
	binary.BigEndian.PutUint32(buf, uint32(p.timer().Unix()))
	token := append(buf, hmacSHA256(p.key, buf, id)...)
	return base64.URLEncoding.EncodeToString(token)
}

// Validate validates the given token for the given user.
func (p *Params) Validate(id, token string) error {
	data, err := base64.URLEncoding.DecodeString(token)
	if err != nil {
		return ErrInvalidToken
	}

	mac := data[dataSize:][:macSize]
	data = data[:dataSize]
	if !hmac.Equal(hmacSHA256(p.key, data, id), mac) {
		return ErrInvalidToken
	}

	t := time.Unix(int64(binary.BigEndian.Uint32(data)), 0)
	if p.timer().Sub(t) > p.MaxAge {
		return ErrInvalidToken
	}

	return nil
}

const (
	dataSize = 4 // 32-bit timestamps
	macSize  = 16
)

func hmacSHA256(key, data []byte, id string) []byte {
	h := hmac.New(sha256.New, key)
	_, _ = h.Write(data)
	_, _ = h.Write([]byte(id))
	return h.Sum(nil)[:macSize]
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package v1beta1

import (
	"fmt"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.12
// +k8s:prerelease-lifecycle-gen:deprecated=1.22

// Describes a certificate signing request
type CertificateSigningRequest struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// The certificate request itself and any additional information.
	// +optional
	Spec CertificateSigningRequestSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`

	// Derived information about the request.
	// +optional
	Status CertificateSigningRequestStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

// This information is immutable after the request is created. Only the Request
// and Usages fields can be set on creation, other fields are derived by
// Kubernetes and cannot be modified by users.
type CertificateSigningRequestSpec struct {
	// Base64-encoded PKCS#10 CSR data
	Request []byte `json:"request" protobuf:"bytes,1,opt,name=request"`

	// Requested signer for the request. It is a qualified name in the form:
	// `scope-hostname.io/name`.
	// If empty, it will be defaulted:
	//  1. If it's a kubelet client certificate, it is assigned
	//     "kubernetes.io/kube-apiserver-client-kubelet".
	//  2. If it's a kubelet serving certificate, it is assigned
	//     "kubernetes.io/kubelet-serving".
	//  3. Otherwise, it is assigned "kubernetes.io/legacy-unknown".
	// Distribution of trust for signers happens out of band.
	// You can select on this field using `spec.signerName`.
	// +optional
	SignerName *string `json:"signerName,omitempty" protobuf:"bytes,7,opt,name=signerName"`

	// allowedUsages specifies a set of usage contexts the key will be
	// valid for.
	// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
	//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
	Usages []KeyUsage `json:"usages,omitempty" protobuf:"bytes,5,opt,name=usages"`

	// Information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Username string `json:"username,omitempty" protobuf:"bytes,2,opt,name=username"`
	// UID information about the requesting user.
	// See user.Info interface for details.
	// +optional
	UID string `json:"uid,omitempty" protobuf:"bytes,3,opt,name=uid"`
	// Group information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Groups []string `json:"groups,omitempty" protobuf:"bytes,4,rep,name=groups"`
	// Extra information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Extra map[string]ExtraValue `json:"extra,omitempty" protobuf:"bytes,6,rep,name=extra"`
}

// Built in signerName values that are honoured by kube-controller-manager.
// None of these usages are related to ServiceAccount token secrets
// `.data[ca.crt]` in any way.
const (
	// Signs certificates that will be honored as client-certs by the
	// kube-apiserver. Never auto-approved by kube-controller-manager.
	KubeAPIServerClientSignerName = "kubernetes.io/kube-apiserver-client"

	// Signs client certificates that will be honored as client-certs by the
	// kube-apiserver for a kubelet.
	// May be auto-approved by kube-controller-manager.
	KubeAPIServerClientKubeletSignerName = "kubernetes.io/kube-apiserver-client-kubelet"

	// Signs serving certificates that are honored as a valid kubelet serving
	// certificate by the kube-apiserver, but has no other guarantees.
	KubeletServingSignerName = "kubernetes.io/kubelet-serving"

	// Has no guarantees for trust at all. Some distributions may honor these
	// as client certs, but that behavior is not standard kubernetes behavior.
	LegacyUnknownSignerName = "kubernetes.io/legacy-unknown"
)

// ExtraValue masks the value so protobuf can generate
// +protobuf.nullable=true
// +protobuf.options.(gogoproto.goproto_stringer)=false
type ExtraValue []string

func (t ExtraValue) String() string {
	return fmt.Sprintf("%v", []string(t))
}

type CertificateSigningRequestStatus struct {
	// Conditions applied to the request, such as approval or denial.
	// +optional
	Conditions []CertificateSigningRequestCondition `json:"conditions,omitempty" protobuf:"bytes,1,rep,name=conditions"`

	// If request was approved, the controller will place the issued certificate here.
	// +optional
	Certificate []byte `json:"certificate,omitempty" protobuf:"bytes,2,opt,name=certificate"`
}

type RequestConditionType string

// These are the possible conditions for a certificate request.
const (
	CertificateApproved RequestConditionType = "Approved"
	CertificateDenied   RequestConditionType = "Denied"
)

type CertificateSigningRequestCondition struct {
	// request approval state, currently Approved or Denied.
	Type RequestConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=RequestConditionType"`
	// brief reason for the request state
	// +optional
	Reason string `json:"reason,omitempty" protobuf:"bytes,2,opt,name=reason"`
	// human readable message with details about the request state
	// +optional
	Message string `json:"message,omitempty" protobuf:"bytes,3,opt,name=message"`
	// timestamp for the last update to this condition
	// +optional
	LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty" protobuf:"bytes,4,opt,name=lastUpdateTime"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.12
// +k8s:prerelease-lifecycle-gen:deprecated=1.22

type CertificateSigningRequestList struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Items []CertificateSigningRequest `json:"items" protobuf:"bytes,2,rep,name=items"`
}

// KeyUsages specifies valid usage contexts for keys.
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
type KeyUsage string

const (
	UsageSigning           KeyUsage = "signing"
	UsageDigitalSignature  KeyUsage = "digital signature"
	UsageContentCommitment KeyUsage = "content commitment"
	UsageKeyEncipherment   KeyUsage = "key encipherment"
	UsageKeyAgreement      KeyUsage = "key agreement"
	UsageDataEncipherment  KeyUsage = "data encipherment"
	UsageCertSign          KeyUsage = "cert sign"
	UsageCRLSign           KeyUsage = "crl sign"
	UsageEncipherOnly      KeyUsage = "encipher only"
	UsageDecipherOnly      KeyUsage = "decipher only"
	UsageAny               KeyUsage = "any"
	UsageServerAuth        KeyUsage = "server auth"
	UsageClientAuth        KeyUsage = "client auth"
	UsageCodeSigning       KeyUsage = "code signing"
	UsageEmailProtection   KeyUsage = "email protection"
	UsageSMIME             KeyUsage = "s/mime"
	UsageIPsecEndSystem    KeyUsage = "ipsec end system"
	UsageIPsecTunnel       KeyUsage = "ipsec tunnel"
	UsageIPsecUser         KeyUsage = "ipsec user"
	UsageTimestamping      KeyUsage = "timestamping"
	UsageOCSPSigning       KeyUsage = "ocsp signing"
	UsageMicrosoftSGC      KeyUsage = "microsoft sgc"
	UsageNetscapeSGC       KeyUsage = "netscape sgc"
)
<commit_msg>Add conditions status field<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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

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

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

package v1beta1

import (
	"fmt"

	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +genclient:nonNamespaced
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.12
// +k8s:prerelease-lifecycle-gen:deprecated=1.22

// Describes a certificate signing request
type CertificateSigningRequest struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	// The certificate request itself and any additional information.
	// +optional
	Spec CertificateSigningRequestSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`

	// Derived information about the request.
	// +optional
	Status CertificateSigningRequestStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

// This information is immutable after the request is created. Only the Request
// and Usages fields can be set on creation, other fields are derived by
// Kubernetes and cannot be modified by users.
type CertificateSigningRequestSpec struct {
	// Base64-encoded PKCS#10 CSR data
	Request []byte `json:"request" protobuf:"bytes,1,opt,name=request"`

	// Requested signer for the request. It is a qualified name in the form:
	// `scope-hostname.io/name`.
	// If empty, it will be defaulted:
	//  1. If it's a kubelet client certificate, it is assigned
	//     "kubernetes.io/kube-apiserver-client-kubelet".
	//  2. If it's a kubelet serving certificate, it is assigned
	//     "kubernetes.io/kubelet-serving".
	//  3. Otherwise, it is assigned "kubernetes.io/legacy-unknown".
	// Distribution of trust for signers happens out of band.
	// You can select on this field using `spec.signerName`.
	// +optional
	SignerName *string `json:"signerName,omitempty" protobuf:"bytes,7,opt,name=signerName"`

	// allowedUsages specifies a set of usage contexts the key will be
	// valid for.
	// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
	//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
	Usages []KeyUsage `json:"usages,omitempty" protobuf:"bytes,5,opt,name=usages"`

	// Information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Username string `json:"username,omitempty" protobuf:"bytes,2,opt,name=username"`
	// UID information about the requesting user.
	// See user.Info interface for details.
	// +optional
	UID string `json:"uid,omitempty" protobuf:"bytes,3,opt,name=uid"`
	// Group information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Groups []string `json:"groups,omitempty" protobuf:"bytes,4,rep,name=groups"`
	// Extra information about the requesting user.
	// See user.Info interface for details.
	// +optional
	Extra map[string]ExtraValue `json:"extra,omitempty" protobuf:"bytes,6,rep,name=extra"`
}

// Built in signerName values that are honoured by kube-controller-manager.
// None of these usages are related to ServiceAccount token secrets
// `.data[ca.crt]` in any way.
const (
	// Signs certificates that will be honored as client-certs by the
	// kube-apiserver. Never auto-approved by kube-controller-manager.
	KubeAPIServerClientSignerName = "kubernetes.io/kube-apiserver-client"

	// Signs client certificates that will be honored as client-certs by the
	// kube-apiserver for a kubelet.
	// May be auto-approved by kube-controller-manager.
	KubeAPIServerClientKubeletSignerName = "kubernetes.io/kube-apiserver-client-kubelet"

	// Signs serving certificates that are honored as a valid kubelet serving
	// certificate by the kube-apiserver, but has no other guarantees.
	KubeletServingSignerName = "kubernetes.io/kubelet-serving"

	// Has no guarantees for trust at all. Some distributions may honor these
	// as client certs, but that behavior is not standard kubernetes behavior.
	LegacyUnknownSignerName = "kubernetes.io/legacy-unknown"
)

// ExtraValue masks the value so protobuf can generate
// +protobuf.nullable=true
// +protobuf.options.(gogoproto.goproto_stringer)=false
type ExtraValue []string

func (t ExtraValue) String() string {
	return fmt.Sprintf("%v", []string(t))
}

type CertificateSigningRequestStatus struct {
	// Conditions applied to the request, such as approval or denial.
	// +optional
	Conditions []CertificateSigningRequestCondition `json:"conditions,omitempty" protobuf:"bytes,1,rep,name=conditions"`

	// If request was approved, the controller will place the issued certificate here.
	// +optional
	Certificate []byte `json:"certificate,omitempty" protobuf:"bytes,2,opt,name=certificate"`
}

type RequestConditionType string

// These are the possible conditions for a certificate request.
const (
	CertificateApproved RequestConditionType = "Approved"
	CertificateDenied   RequestConditionType = "Denied"
	CertificateFailed   RequestConditionType = "Failed"
)

type CertificateSigningRequestCondition struct {
	// type of the condition. Known conditions include "Approved", "Denied", and "Failed".
	Type RequestConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=RequestConditionType"`
	// Status of the condition, one of True, False, Unknown.
	// Approved, Denied, and Failed conditions may not be "False" or "Unknown".
	// Defaults to "True".
	// If unset, should be treated as "True".
	// +optional
	Status v1.ConditionStatus `json:"status" protobuf:"bytes,6,opt,name=status,casttype=k8s.io/api/core/v1.ConditionStatus"`
	// brief reason for the request state
	// +optional
	Reason string `json:"reason,omitempty" protobuf:"bytes,2,opt,name=reason"`
	// human readable message with details about the request state
	// +optional
	Message string `json:"message,omitempty" protobuf:"bytes,3,opt,name=message"`
	// timestamp for the last update to this condition
	// +optional
	LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty" protobuf:"bytes,4,opt,name=lastUpdateTime"`
	// lastTransitionTime is the time the condition last transitioned from one status to another.
	// If unset, when a new condition type is added or an existing condition's status is changed,
	// the server defaults this to the current time.
	// +optional
	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" protobuf:"bytes,5,opt,name=lastTransitionTime"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.12
// +k8s:prerelease-lifecycle-gen:deprecated=1.22

type CertificateSigningRequestList struct {
	metav1.TypeMeta `json:",inline"`
	// +optional
	metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

	Items []CertificateSigningRequest `json:"items" protobuf:"bytes,2,rep,name=items"`
}

// KeyUsages specifies valid usage contexts for keys.
// See: https://tools.ietf.org/html/rfc5280#section-4.2.1.3
//      https://tools.ietf.org/html/rfc5280#section-4.2.1.12
type KeyUsage string

const (
	UsageSigning           KeyUsage = "signing"
	UsageDigitalSignature  KeyUsage = "digital signature"
	UsageContentCommitment KeyUsage = "content commitment"
	UsageKeyEncipherment   KeyUsage = "key encipherment"
	UsageKeyAgreement      KeyUsage = "key agreement"
	UsageDataEncipherment  KeyUsage = "data encipherment"
	UsageCertSign          KeyUsage = "cert sign"
	UsageCRLSign           KeyUsage = "crl sign"
	UsageEncipherOnly      KeyUsage = "encipher only"
	UsageDecipherOnly      KeyUsage = "decipher only"
	UsageAny               KeyUsage = "any"
	UsageServerAuth        KeyUsage = "server auth"
	UsageClientAuth        KeyUsage = "client auth"
	UsageCodeSigning       KeyUsage = "code signing"
	UsageEmailProtection   KeyUsage = "email protection"
	UsageSMIME             KeyUsage = "s/mime"
	UsageIPsecEndSystem    KeyUsage = "ipsec end system"
	UsageIPsecTunnel       KeyUsage = "ipsec tunnel"
	UsageIPsecUser         KeyUsage = "ipsec user"
	UsageTimestamping      KeyUsage = "timestamping"
	UsageOCSPSigning       KeyUsage = "ocsp signing"
	UsageMicrosoftSGC      KeyUsage = "microsoft sgc"
	UsageNetscapeSGC       KeyUsage = "netscape sgc"
)
<|endoftext|>


<commit_before>package commands

import (
	"os"
	"path/filepath"
	"testing"

	"github.com/garyburd/neovim-go/vim"
)

// func TestGuru(t *testing.T) {
// 	tests := []struct {
// 		// Parameters.
// 		v    *vim.Vim
// 		args []string
// 		eval *funcGuruEval
// 		// Expected results.
// 		wantErr bool
// 	}{
// 		{
// 			v:    testVim(t, gsftpMain),
// 			args: []string{"definition"},
// 			eval: &funcGuruEval{
// 				Cwd:      gsftp,
// 				File:     gsftpMain,
// 				Modified: 0,
// 			},
// 		},
// 	}
// 	for _, tt := range tests {
// 		if err := Guru(tt.v, tt.args, tt.eval); (err != nil) != tt.wantErr {
// 			t.Errorf("Guru(%v, %v, %v) error = %v, wantErr %v", tt.v, tt.args, tt.eval, err, tt.wantErr)
// 		}
// 	}
// }

func BenchmarkGuruDefinition(b *testing.B) {
	xdgDataHome := filepath.Join(testdata, "local", "share")
	os.Setenv("XDG_DATA_HOME", xdgDataHome)
	os.Setenv("NVIM_GO_DEBUG", "")
	v := benchVim(b, gsftpMain)
	w, err := v.CurrentWindow()
	if err != nil {
		b.Errorf("%v", err)
	}
	v.SetWindowCursor(w, [2]int{106, 26}) // client, err := sftp.|N|ewClient(conn)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		if err := Guru(v, []string{"definition"}, &funcGuruEval{
			Cwd:      gsftp,
			File:     gsftpMain,
			Modified: 0,
		}); err != nil {
			b.Errorf("BenchmarkGuruDefinition: %v", err)
		}
	}
}

func BenchmarkGuruDefinitionFallback(b *testing.B) {
	xdgDataHome := filepath.Join(testdata, "local", "share")
	os.Setenv("XDG_DATA_HOME", xdgDataHome)
	os.Setenv("NVIM_GO_DEBUG", "")
	v := benchVim(b, gsftpMain)
	w, err := v.CurrentWindow()
	if err != nil {
		b.Errorf("%v", err)
	}
	v.SetWindowCursor(w, [2]int{104, 17}) // defer conn.|C|lose()
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		if err := Guru(v, []string{"definition"}, &funcGuruEval{
			Cwd:      gsftp,
			File:     gsftpMain,
			Modified: 0,
		}); err != nil {
			b.Errorf("BenchmarkGuruDefinitionFallback: %v", err)
		}
	}
}

// func TestParseResult(t *testing.T) {
// 	tests := []struct {
// 		// Parameters.
// 		mode string
// 		fset *token.FileSet
// 		data []byte
// 		cwd  string
// 		// Expected results.
// 		want    []*quickfix.ErrorlistData
// 		want1   string
// 		want2   int
// 		want3   int
// 		wantErr bool
// 	}{
// 	// TODO: Add test cases.
// 	}
// 	for _, tt := range tests {
// 		got, got1, got2, got3, err := parseResult(tt.mode, tt.fset, tt.data, tt.cwd)
// 		if (err != nil) != tt.wantErr {
// 			t.Errorf("parseResult(%v, %v, %v, %v) error = %v, wantErr %v", tt.mode, tt.fset, tt.data, tt.cwd, err, tt.wantErr)
// 			continue
// 		}
// 		if !reflect.DeepEqual(got, tt.want) {
// 			t.Errorf("parseResult(%v, %v, %v, %v) = %v, want %v", tt.mode, tt.fset, tt.data, tt.cwd, got, tt.want)
// 		}
// 		if !reflect.DeepEqual(got1, tt.want1) {
// 			t.Errorf("parseResult(%v, %v, %v, %v) = %v, want %v", tt.mode, tt.fset, tt.data, tt.cwd, got, tt.want1)
// 		}
// 		if !reflect.DeepEqual(got2, tt.want2) {
// 			t.Errorf("parseResult(%v, %v, %v, %v) = %v, want %v", tt.mode, tt.fset, tt.data, tt.cwd, got, tt.want2)
// 		}
// 		if !reflect.DeepEqual(got3, tt.want3) {
// 			t.Errorf("parseResult(%v, %v, %v, %v) = %v, want %v", tt.mode, tt.fset, tt.data, tt.cwd, got, tt.want3)
// 		}
// 	}
// }

func TestGuruHelp(t *testing.T) {
	tests := []struct {
		// Parameters.
		v    *vim.Vim
		mode string
		// Expected results.
		wantErr bool
	}{
	// TODO: Add test cases.
	}
	for _, tt := range tests {
		if err := guruHelp(tt.v, tt.mode); (err != nil) != tt.wantErr {
			t.Errorf("guruHelp(%v, %v) error = %v, wantErr %v", tt.v, tt.mode, err, tt.wantErr)
		}
	}
}
<commit_msg>test/guru: Fix Eval.Offset was empty...<commit_after>package commands

import (
	"testing"

	"github.com/garyburd/neovim-go/vim"
)

// func TestGuru(t *testing.T) {
// 	tests := []struct {
// 		// Parameters.
// 		v    *vim.Vim
// 		args []string
// 		eval *funcGuruEval
// 		// Expected results.
// 		wantErr bool
// 	}{
// 		{
// 			v:    testVim(t, gsftpMain),
// 			args: []string{"definition"},
// 			eval: &funcGuruEval{
// 				Cwd:      gsftp,
// 				File:     gsftpMain,
// 				Modified: 0,
// 			},
// 		},
// 	}
// 	for _, tt := range tests {
// 		if err := Guru(tt.v, tt.args, tt.eval); (err != nil) != tt.wantErr {
// 			t.Errorf("Guru(%v, %v, %v) error = %v, wantErr %v", tt.v, tt.args, tt.eval, err, tt.wantErr)
// 		}
// 	}
// }

func BenchmarkGuruDefinition(b *testing.B) {
	v := benchVim(b, gsftpMain)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		if err := Guru(v, []string{"definition"}, &funcGuruEval{
			Cwd:      gsftp,
			File:     gsftpMain,
			Modified: 0,
			Offset:   2027, // client, err := sftp.|N|ewClient(conn)
		}); err != nil {
			b.Errorf("BenchmarkGuruDefinition: %v", err)
		}
	}
}

func BenchmarkGuruDefinitionFallback(b *testing.B) {
	v := benchVim(b, gsftpMain)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		if err := Guru(v, []string{"definition"}, &funcGuruEval{
			Cwd:      gsftp,
			File:     gsftpMain,
			Modified: 0,
			Offset:   2132, // defer conn.|C|lose()
		}); err != nil {
			b.Errorf("BenchmarkGuruDefinitionFallback: %v", err)
		}
	}
}

// func TestParseResult(t *testing.T) {
// 	tests := []struct {
// 		// Parameters.
// 		mode string
// 		fset *token.FileSet
// 		data []byte
// 		cwd  string
// 		// Expected results.
// 		want    []*quickfix.ErrorlistData
// 		want1   string
// 		want2   int
// 		want3   int
// 		wantErr bool
// 	}{
// 	// TODO: Add test cases.
// 	}
// 	for _, tt := range tests {
// 		got, got1, got2, got3, err := parseResult(tt.mode, tt.fset, tt.data, tt.cwd)
// 		if (err != nil) != tt.wantErr {
// 			t.Errorf("parseResult(%v, %v, %v, %v) error = %v, wantErr %v", tt.mode, tt.fset, tt.data, tt.cwd, err, tt.wantErr)
// 			continue
// 		}
// 		if !reflect.DeepEqual(got, tt.want) {
// 			t.Errorf("parseResult(%v, %v, %v, %v) = %v, want %v", tt.mode, tt.fset, tt.data, tt.cwd, got, tt.want)
// 		}
// 		if !reflect.DeepEqual(got1, tt.want1) {
// 			t.Errorf("parseResult(%v, %v, %v, %v) = %v, want %v", tt.mode, tt.fset, tt.data, tt.cwd, got, tt.want1)
// 		}
// 		if !reflect.DeepEqual(got2, tt.want2) {
// 			t.Errorf("parseResult(%v, %v, %v, %v) = %v, want %v", tt.mode, tt.fset, tt.data, tt.cwd, got, tt.want2)
// 		}
// 		if !reflect.DeepEqual(got3, tt.want3) {
// 			t.Errorf("parseResult(%v, %v, %v, %v) = %v, want %v", tt.mode, tt.fset, tt.data, tt.cwd, got, tt.want3)
// 		}
// 	}
// }

func TestGuruHelp(t *testing.T) {
	tests := []struct {
		// Parameters.
		v    *vim.Vim
		mode string
		// Expected results.
		wantErr bool
	}{
	// TODO: Add test cases.
	}
	for _, tt := range tests {
		if err := guruHelp(tt.v, tt.mode); (err != nil) != tt.wantErr {
			t.Errorf("guruHelp(%v, %v) error = %v, wantErr %v", tt.v, tt.mode, err, tt.wantErr)
		}
	}
}
<|endoftext|>


<commit_before>package apiutils

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
)

func ServeJSON(w http.ResponseWriter, v interface{}) {
	content, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Length", strconv.Itoa(len(content)))
	w.Header().Set("Content-Type", "application/json")
	w.Write(content)
}

func RequireParams(form url.Values, params []string) error {
	for _, param := range params {
		if len(form[param]) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}
<commit_msg>add error response<commit_after>package apiutils

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strconv"
)

func ServeJSON(w http.ResponseWriter, v interface{}) {
	content, err := json.MarshalIndent(v, "", "  ")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Length", strconv.Itoa(len(content)))
	w.Header().Set("Content-Type", "application/json")
	w.Write(content)
}

func RequireParams(form url.Values, params []string) error {
	for _, param := range params {
		if len(form[param]) == 0 {
			return fmt.Errorf("Missing param: %s", param)
		}
	}
	return nil
}

type ErrorResponse struct {
	Status  int    `json:"status"`
	Message string `json:"message"`
	Error   string `json:"error"`
}

func NewErrorResponse(status int, message string) ErrorResponse {
	return ErrorResponse{
		Status:  status,
		Message: message,
		Error:   http.StatusText(status),
	}
}

func ServeError(w http.ResponseWriter, errRes ErrorResponse) {
	w.WriteHeader(errRes.Status)
	ServeJson(w, errRes)
}
<|endoftext|>


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

package gob

import (
	"reflect"
	"testing"
)

type typeT struct {
	id  typeId
	str string
}

var basicTypes = []typeT{
	{tBool, "bool"},
	{tInt, "int"},
	{tUint, "uint"},
	{tFloat, "float"},
	{tBytes, "bytes"},
	{tString, "string"},
}

func getTypeUnlocked(name string, rt reflect.Type) gobType {
	typeLock.Lock()
	defer typeLock.Unlock()
	t, err := getBaseType(name, rt)
	if err != nil {
		panic("getTypeUnlocked: " + err.Error())
	}
	return t
}

// Sanity checks
func TestBasic(t *testing.T) {
	for _, tt := range basicTypes {
		if tt.id.string() != tt.str {
			t.Errorf("checkType: expected %q got %s", tt.str, tt.id.string())
		}
		if tt.id == 0 {
			t.Errorf("id for %q is zero", tt.str)
		}
	}
}

// Reregister some basic types to check registration is idempotent.
func TestReregistration(t *testing.T) {
	newtyp := getTypeUnlocked("int", reflect.TypeOf(int(0)))
	if newtyp != tInt.gobType() {
		t.Errorf("reregistration of %s got new type", newtyp.string())
	}
	newtyp = getTypeUnlocked("uint", reflect.TypeOf(uint(0)))
	if newtyp != tUint.gobType() {
		t.Errorf("reregistration of %s got new type", newtyp.string())
	}
	newtyp = getTypeUnlocked("string", reflect.TypeOf("hello"))
	if newtyp != tString.gobType() {
		t.Errorf("reregistration of %s got new type", newtyp.string())
	}
}

func TestArrayType(t *testing.T) {
	var a3 [3]int
	a3int := getTypeUnlocked("foo", reflect.TypeOf(a3))
	newa3int := getTypeUnlocked("bar", reflect.TypeOf(a3))
	if a3int != newa3int {
		t.Errorf("second registration of [3]int creates new type")
	}
	var a4 [4]int
	a4int := getTypeUnlocked("goo", reflect.TypeOf(a4))
	if a3int == a4int {
		t.Errorf("registration of [3]int creates same type as [4]int")
	}
	var b3 [3]bool
	a3bool := getTypeUnlocked("", reflect.TypeOf(b3))
	if a3int == a3bool {
		t.Errorf("registration of [3]bool creates same type as [3]int")
	}
	str := a3bool.string()
	expected := "[3]bool"
	if str != expected {
		t.Errorf("array printed as %q; expected %q", str, expected)
	}
}

func TestSliceType(t *testing.T) {
	var s []int
	sint := getTypeUnlocked("slice", reflect.TypeOf(s))
	var news []int
	newsint := getTypeUnlocked("slice1", reflect.TypeOf(news))
	if sint != newsint {
		t.Errorf("second registration of []int creates new type")
	}
	var b []bool
	sbool := getTypeUnlocked("", reflect.TypeOf(b))
	if sbool == sint {
		t.Errorf("registration of []bool creates same type as []int")
	}
	str := sbool.string()
	expected := "[]bool"
	if str != expected {
		t.Errorf("slice printed as %q; expected %q", str, expected)
	}
}

func TestMapType(t *testing.T) {
	var m map[string]int
	mapStringInt := getTypeUnlocked("map", reflect.TypeOf(m))
	var newm map[string]int
	newMapStringInt := getTypeUnlocked("map1", reflect.TypeOf(newm))
	if mapStringInt != newMapStringInt {
		t.Errorf("second registration of map[string]int creates new type")
	}
	var b map[string]bool
	mapStringBool := getTypeUnlocked("", reflect.TypeOf(b))
	if mapStringBool == mapStringInt {
		t.Errorf("registration of map[string]bool creates same type as map[string]int")
	}
	str := mapStringBool.string()
	expected := "map[string]bool"
	if str != expected {
		t.Errorf("map printed as %q; expected %q", str, expected)
	}
}

type Bar struct {
	X string
}

// This structure has pointers and refers to itself, making it a good test case.
type Foo struct {
	A int
	B int32 // will become int
	C string
	D []byte
	E *float64    // will become float64
	F ****float64 // will become float64
	G *Bar
	H *Bar // should not interpolate the definition of Bar again
	I *Foo // will not explode
}

func TestStructType(t *testing.T) {
	sstruct := getTypeUnlocked("Foo", reflect.TypeOf(Foo{}))
	str := sstruct.string()
	// If we can print it correctly, we built it correctly.
	expected := "Foo = struct { A int; B int; C string; D bytes; E float; F float; G Bar = struct { X string; }; H Bar; I Foo; }"
	if str != expected {
		t.Errorf("struct printed as %q; expected %q", str, expected)
	}
}

// Should be OK to register the same type multiple times, as long as they're
// at the same level of indirection.
func TestRegistration(t *testing.T) {
	type T struct{ a int }
	Register(new(T))
	Register(new(T))
}
<commit_msg>encoding/gob: test for type registration name.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gob

import (
	"reflect"
	"testing"
)

type typeT struct {
	id  typeId
	str string
}

var basicTypes = []typeT{
	{tBool, "bool"},
	{tInt, "int"},
	{tUint, "uint"},
	{tFloat, "float"},
	{tBytes, "bytes"},
	{tString, "string"},
}

func getTypeUnlocked(name string, rt reflect.Type) gobType {
	typeLock.Lock()
	defer typeLock.Unlock()
	t, err := getBaseType(name, rt)
	if err != nil {
		panic("getTypeUnlocked: " + err.Error())
	}
	return t
}

// Sanity checks
func TestBasic(t *testing.T) {
	for _, tt := range basicTypes {
		if tt.id.string() != tt.str {
			t.Errorf("checkType: expected %q got %s", tt.str, tt.id.string())
		}
		if tt.id == 0 {
			t.Errorf("id for %q is zero", tt.str)
		}
	}
}

// Reregister some basic types to check registration is idempotent.
func TestReregistration(t *testing.T) {
	newtyp := getTypeUnlocked("int", reflect.TypeOf(int(0)))
	if newtyp != tInt.gobType() {
		t.Errorf("reregistration of %s got new type", newtyp.string())
	}
	newtyp = getTypeUnlocked("uint", reflect.TypeOf(uint(0)))
	if newtyp != tUint.gobType() {
		t.Errorf("reregistration of %s got new type", newtyp.string())
	}
	newtyp = getTypeUnlocked("string", reflect.TypeOf("hello"))
	if newtyp != tString.gobType() {
		t.Errorf("reregistration of %s got new type", newtyp.string())
	}
}

func TestArrayType(t *testing.T) {
	var a3 [3]int
	a3int := getTypeUnlocked("foo", reflect.TypeOf(a3))
	newa3int := getTypeUnlocked("bar", reflect.TypeOf(a3))
	if a3int != newa3int {
		t.Errorf("second registration of [3]int creates new type")
	}
	var a4 [4]int
	a4int := getTypeUnlocked("goo", reflect.TypeOf(a4))
	if a3int == a4int {
		t.Errorf("registration of [3]int creates same type as [4]int")
	}
	var b3 [3]bool
	a3bool := getTypeUnlocked("", reflect.TypeOf(b3))
	if a3int == a3bool {
		t.Errorf("registration of [3]bool creates same type as [3]int")
	}
	str := a3bool.string()
	expected := "[3]bool"
	if str != expected {
		t.Errorf("array printed as %q; expected %q", str, expected)
	}
}

func TestSliceType(t *testing.T) {
	var s []int
	sint := getTypeUnlocked("slice", reflect.TypeOf(s))
	var news []int
	newsint := getTypeUnlocked("slice1", reflect.TypeOf(news))
	if sint != newsint {
		t.Errorf("second registration of []int creates new type")
	}
	var b []bool
	sbool := getTypeUnlocked("", reflect.TypeOf(b))
	if sbool == sint {
		t.Errorf("registration of []bool creates same type as []int")
	}
	str := sbool.string()
	expected := "[]bool"
	if str != expected {
		t.Errorf("slice printed as %q; expected %q", str, expected)
	}
}

func TestMapType(t *testing.T) {
	var m map[string]int
	mapStringInt := getTypeUnlocked("map", reflect.TypeOf(m))
	var newm map[string]int
	newMapStringInt := getTypeUnlocked("map1", reflect.TypeOf(newm))
	if mapStringInt != newMapStringInt {
		t.Errorf("second registration of map[string]int creates new type")
	}
	var b map[string]bool
	mapStringBool := getTypeUnlocked("", reflect.TypeOf(b))
	if mapStringBool == mapStringInt {
		t.Errorf("registration of map[string]bool creates same type as map[string]int")
	}
	str := mapStringBool.string()
	expected := "map[string]bool"
	if str != expected {
		t.Errorf("map printed as %q; expected %q", str, expected)
	}
}

type Bar struct {
	X string
}

// This structure has pointers and refers to itself, making it a good test case.
type Foo struct {
	A int
	B int32 // will become int
	C string
	D []byte
	E *float64    // will become float64
	F ****float64 // will become float64
	G *Bar
	H *Bar // should not interpolate the definition of Bar again
	I *Foo // will not explode
}

func TestStructType(t *testing.T) {
	sstruct := getTypeUnlocked("Foo", reflect.TypeOf(Foo{}))
	str := sstruct.string()
	// If we can print it correctly, we built it correctly.
	expected := "Foo = struct { A int; B int; C string; D bytes; E float; F float; G Bar = struct { X string; }; H Bar; I Foo; }"
	if str != expected {
		t.Errorf("struct printed as %q; expected %q", str, expected)
	}
}

// Should be OK to register the same type multiple times, as long as they're
// at the same level of indirection.
func TestRegistration(t *testing.T) {
	type T struct{ a int }
	Register(new(T))
	Register(new(T))
}

type N1 struct{}
type N2 struct{}

// See comment in type.go/Register.
func TestRegistrationNaming(t *testing.T) {
	testCases := []struct {
		t    interface{}
		name string
	}{
		{&N1{}, "*gob.N1"},
		{N2{}, "encoding/gob.N2"},
	}

	for _, tc := range testCases {
		Register(tc.t)

		tct := reflect.TypeOf(tc.t)
		if ct := nameToConcreteType[tc.name]; ct != tct {
			t.Errorf("nameToConcreteType[%q] = %v, want %v", tc.name, ct, tct)
		}
		// concreteTypeToName is keyed off the base type.
		if tct.Kind() == reflect.Ptr {
			tct = tct.Elem()
		}
		if n := concreteTypeToName[tct]; n != tc.name {
			t.Errorf("concreteTypeToName[%v] got %v, want %v", tct, n, tc.name)
		}
	}
}
<|endoftext|>