<commit_before>package daemon

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/execdriver"
	"github.com/docker/docker/pkg/chrootarchive"
	"github.com/docker/docker/pkg/symlink"
	"github.com/docker/docker/volumes"
)

type Mount struct {
	MountToPath string
	container   *Container
	volume      *volumes.Volume
	Writable    bool
	copyData    bool
}

func (mnt *Mount) Export(resource string) (io.ReadCloser, error) {
	var name string
	if resource == mnt.MountToPath[1:] {
		name = filepath.Base(resource)
	}
	path, err := filepath.Rel(mnt.MountToPath[1:], resource)
	if err != nil {
		return nil, err
	}
	return mnt.volume.Export(path, name)
}

func (container *Container) prepareVolumes() error {
	if container.Volumes == nil || len(container.Volumes) == 0 {
		container.Volumes = make(map[string]string)
		container.VolumesRW = make(map[string]bool)
		if err := container.applyVolumesFrom(); err != nil {
			return err
		}
	}

	return container.createVolumes()
}

// sortedVolumeMounts returns the list of container volume mount points sorted in lexicographic order
func (container *Container) sortedVolumeMounts() []string {
	var mountPaths []string
	for path := range container.Volumes {
		mountPaths = append(mountPaths, path)
	}

	sort.Strings(mountPaths)
	return mountPaths
}

func (container *Container) createVolumes() error {
	mounts, err := container.parseVolumeMountConfig()
	if err != nil {
		return err
	}

	for _, mnt := range mounts {
		if err := mnt.initialize(); err != nil {
			return err
		}
	}

	return nil
}

func (m *Mount) initialize() error {
	// No need to initialize anything since it's already been initialized
	if _, exists := m.container.Volumes[m.MountToPath]; exists {
		return nil
	}

	// This is the full path to container fs + mntToPath
	containerMntPath, err := symlink.FollowSymlinkInScope(filepath.Join(m.container.basefs, m.MountToPath), m.container.basefs)
	if err != nil {
		return err
	}
	m.container.VolumesRW[m.MountToPath] = m.Writable
	m.container.Volumes[m.MountToPath] = m.volume.Path
	m.volume.AddContainer(m.container.ID)
	if m.Writable && m.copyData {
		// Copy whatever is in the container at the mntToPath to the volume
		copyExistingContents(containerMntPath, m.volume.Path)
	}

	return nil
}

func (container *Container) VolumePaths() map[string]struct{} {
	var paths = make(map[string]struct{})
	for _, path := range container.Volumes {
		paths[path] = struct{}{}
	}
	return paths
}

func (container *Container) registerVolumes() {
	for _, mnt := range container.VolumeMounts() {
		mnt.volume.AddContainer(container.ID)
	}
}

func (container *Container) derefVolumes() {
	for path := range container.VolumePaths() {
		vol := container.daemon.volumes.Get(path)
		if vol == nil {
			log.Debugf("Volume %s was not found and could not be dereferenced", path)
			continue
		}
		vol.RemoveContainer(container.ID)
	}
}

func (container *Container) parseVolumeMountConfig() (map[string]*Mount, error) {
	var mounts = make(map[string]*Mount)
	// Get all the bind mounts
	for _, spec := range container.hostConfig.Binds {
		path, mountToPath, writable, err := parseBindMountSpec(spec)
		if err != nil {
			return nil, err
		}
		// Check if a volume already exists for this and use it
		vol, err := container.daemon.volumes.FindOrCreateVolume(path, writable)
		if err != nil {
			return nil, err
		}
		mounts[mountToPath] = &Mount{
			container:   container,
			volume:      vol,
			MountToPath: mountToPath,
			Writable:    writable,
		}
	}

	// Get the rest of the volumes
	for path := range container.Config.Volumes {
		// Check if this is already added as a bind-mount
		path = filepath.Clean(path)
		if _, exists := mounts[path]; exists {
			continue
		}

		// Check if this has already been created
		if _, exists := container.Volumes[path]; exists {
			continue
		}

		vol, err := container.daemon.volumes.FindOrCreateVolume("", true)
		if err != nil {
			return nil, err
		}
		mounts[path] = &Mount{
			container:   container,
			MountToPath: path,
			volume:      vol,
			Writable:    true,
			copyData:    true,
		}
	}

	return mounts, nil
}

func parseBindMountSpec(spec string) (string, string, bool, error) {
	var (
		path, mountToPath string
		writable          bool
		arr               = strings.Split(spec, ":")
	)

	switch len(arr) {
	case 2:
		path = arr[0]
		mountToPath = arr[1]
		writable = true
	case 3:
		path = arr[0]
		mountToPath = arr[1]
		writable = validMountMode(arr[2]) && arr[2] == "rw"
	default:
		return "", "", false, fmt.Errorf("Invalid volume specification: %s", spec)
	}

	if !filepath.IsAbs(path) {
		return "", "", false, fmt.Errorf("cannot bind mount volume: %s volume paths must be absolute.", path)
	}

	path = filepath.Clean(path)
	mountToPath = filepath.Clean(mountToPath)
	return path, mountToPath, writable, nil
}

func (container *Container) applyVolumesFrom() error {
	volumesFrom := container.hostConfig.VolumesFrom

	mountGroups := make([]map[string]*Mount, 0, len(volumesFrom))

	for _, spec := range volumesFrom {
		mountGroup, err := parseVolumesFromSpec(container.daemon, spec)
		if err != nil {
			return err
		}
		mountGroups = append(mountGroups, mountGroup)
	}

	for _, mounts := range mountGroups {
		for _, mnt := range mounts {
			mnt.container = container
			if err := mnt.initialize(); err != nil {
				return err
			}
		}
	}
	return nil
}

func validMountMode(mode string) bool {
	validModes := map[string]bool{
		"rw": true,
		"ro": true,
	}

	return validModes[mode]
}

func (container *Container) setupMounts() error {
	mounts := []execdriver.Mount{
		{Source: container.ResolvConfPath, Destination: "/etc/resolv.conf", Writable: true, Private: true},
	}

	if container.HostnamePath != "" {
		mounts = append(mounts, execdriver.Mount{Source: container.HostnamePath, Destination: "/etc/hostname", Writable: true, Private: true})
	}

	if container.HostsPath != "" {
		mounts = append(mounts, execdriver.Mount{Source: container.HostsPath, Destination: "/etc/hosts", Writable: true, Private: true})
	}

	// Mount user specified volumes
	// Note, these are not private because you may want propagation of (un)mounts from host
	// volumes. For instance if you use -v /usr:/usr and the host later mounts /usr/share you
	// want this new mount in the container
	// These mounts must be ordered based on the length of the path that it is being mounted to (lexicographic)
	for _, path := range container.sortedVolumeMounts() {
		mounts = append(mounts, execdriver.Mount{
			Source:      container.Volumes[path],
			Destination: path,
			Writable:    container.VolumesRW[path],
		})
	}

	container.command.Mounts = mounts
	return nil
}

func parseVolumesFromSpec(daemon *Daemon, spec string) (map[string]*Mount, error) {
	specParts := strings.SplitN(spec, ":", 2)
	if len(specParts) == 0 {
		return nil, fmt.Errorf("Malformed volumes-from specification: %s", spec)
	}

	c := daemon.Get(specParts[0])
	if c == nil {
		return nil, fmt.Errorf("Container %s not found. Impossible to mount its volumes", specParts[0])
	}

	mounts := c.VolumeMounts()

	if len(specParts) == 2 {
		mode := specParts[1]
		if !validMountMode(mode) {
			return nil, fmt.Errorf("Invalid mode for volumes-from: %s", mode)
		}

		// Set the mode for the inheritted volume
		for _, mnt := range mounts {
			// Ensure that if the inherited volume is not writable, that we don't make
			// it writable here
			mnt.Writable = mnt.Writable && (mode == "rw")
		}
	}

	return mounts, nil
}

func (container *Container) VolumeMounts() map[string]*Mount {
	mounts := make(map[string]*Mount)

	for mountToPath, path := range container.Volumes {
		if v := container.daemon.volumes.Get(path); v != nil {
			mounts[mountToPath] = &Mount{volume: v, container: container, MountToPath: mountToPath, Writable: container.VolumesRW[mountToPath]}
		}
	}

	return mounts
}

func copyExistingContents(source, destination string) error {
	volList, err := ioutil.ReadDir(source)
	if err != nil {
		return err
	}

	if len(volList) > 0 {
		srcList, err := ioutil.ReadDir(destination)
		if err != nil {
			return err
		}

		if len(srcList) == 0 {
			// If the source volume is empty copy files from the root into the volume
			if err := chrootarchive.CopyWithTar(source, destination); err != nil {
				return err
			}
		}
	}

	return copyOwnership(source, destination)
}

// copyOwnership copies the permissions and uid:gid of the source file
// into the destination file
func copyOwnership(source, destination string) error {
	var stat syscall.Stat_t

	if err := syscall.Stat(source, &stat); err != nil {
		return err
	}

	if err := os.Chown(destination, int(stat.Uid), int(stat.Gid)); err != nil {
		return err
	}

	return os.Chmod(destination, os.FileMode(stat.Mode))
}
<commit_msg>Label content created for containers with the private label<commit_after>package daemon

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"syscall"

	log "github.com/Sirupsen/logrus"
	"github.com/docker/docker/daemon/execdriver"
	"github.com/docker/docker/pkg/chrootarchive"
	"github.com/docker/docker/pkg/symlink"
	"github.com/docker/docker/volumes"
	"github.com/docker/libcontainer/label"
)

type Mount struct {
	MountToPath string
	container   *Container
	volume      *volumes.Volume
	Writable    bool
	copyData    bool
}

func (mnt *Mount) Export(resource string) (io.ReadCloser, error) {
	var name string
	if resource == mnt.MountToPath[1:] {
		name = filepath.Base(resource)
	}
	path, err := filepath.Rel(mnt.MountToPath[1:], resource)
	if err != nil {
		return nil, err
	}
	return mnt.volume.Export(path, name)
}

func (container *Container) prepareVolumes() error {
	if container.Volumes == nil || len(container.Volumes) == 0 {
		container.Volumes = make(map[string]string)
		container.VolumesRW = make(map[string]bool)
		if err := container.applyVolumesFrom(); err != nil {
			return err
		}
	}

	return container.createVolumes()
}

// sortedVolumeMounts returns the list of container volume mount points sorted in lexicographic order
func (container *Container) sortedVolumeMounts() []string {
	var mountPaths []string
	for path := range container.Volumes {
		mountPaths = append(mountPaths, path)
	}

	sort.Strings(mountPaths)
	return mountPaths
}

func (container *Container) createVolumes() error {
	mounts, err := container.parseVolumeMountConfig()
	if err != nil {
		return err
	}

	for _, mnt := range mounts {
		if err := mnt.initialize(); err != nil {
			return err
		}
	}

	return nil
}

func (m *Mount) initialize() error {
	// No need to initialize anything since it's already been initialized
	if _, exists := m.container.Volumes[m.MountToPath]; exists {
		return nil
	}

	// This is the full path to container fs + mntToPath
	containerMntPath, err := symlink.FollowSymlinkInScope(filepath.Join(m.container.basefs, m.MountToPath), m.container.basefs)
	if err != nil {
		return err
	}
	m.container.VolumesRW[m.MountToPath] = m.Writable
	m.container.Volumes[m.MountToPath] = m.volume.Path
	m.volume.AddContainer(m.container.ID)
	if m.Writable && m.copyData {
		// Copy whatever is in the container at the mntToPath to the volume
		copyExistingContents(containerMntPath, m.volume.Path)
	}

	return nil
}

func (container *Container) VolumePaths() map[string]struct{} {
	var paths = make(map[string]struct{})
	for _, path := range container.Volumes {
		paths[path] = struct{}{}
	}
	return paths
}

func (container *Container) registerVolumes() {
	for _, mnt := range container.VolumeMounts() {
		mnt.volume.AddContainer(container.ID)
	}
}

func (container *Container) derefVolumes() {
	for path := range container.VolumePaths() {
		vol := container.daemon.volumes.Get(path)
		if vol == nil {
			log.Debugf("Volume %s was not found and could not be dereferenced", path)
			continue
		}
		vol.RemoveContainer(container.ID)
	}
}

func (container *Container) parseVolumeMountConfig() (map[string]*Mount, error) {
	var mounts = make(map[string]*Mount)
	// Get all the bind mounts
	for _, spec := range container.hostConfig.Binds {
		path, mountToPath, writable, err := parseBindMountSpec(spec)
		if err != nil {
			return nil, err
		}
		// Check if a volume already exists for this and use it
		vol, err := container.daemon.volumes.FindOrCreateVolume(path, writable)
		if err != nil {
			return nil, err
		}
		mounts[mountToPath] = &Mount{
			container:   container,
			volume:      vol,
			MountToPath: mountToPath,
			Writable:    writable,
		}
	}

	// Get the rest of the volumes
	for path := range container.Config.Volumes {
		// Check if this is already added as a bind-mount
		path = filepath.Clean(path)
		if _, exists := mounts[path]; exists {
			continue
		}

		// Check if this has already been created
		if _, exists := container.Volumes[path]; exists {
			continue
		}

		vol, err := container.daemon.volumes.FindOrCreateVolume("", true)
		if err != nil {
			return nil, err
		}
		mounts[path] = &Mount{
			container:   container,
			MountToPath: path,
			volume:      vol,
			Writable:    true,
			copyData:    true,
		}
	}

	return mounts, nil
}

func parseBindMountSpec(spec string) (string, string, bool, error) {
	var (
		path, mountToPath string
		writable          bool
		arr               = strings.Split(spec, ":")
	)

	switch len(arr) {
	case 2:
		path = arr[0]
		mountToPath = arr[1]
		writable = true
	case 3:
		path = arr[0]
		mountToPath = arr[1]
		writable = validMountMode(arr[2]) && arr[2] == "rw"
	default:
		return "", "", false, fmt.Errorf("Invalid volume specification: %s", spec)
	}

	if !filepath.IsAbs(path) {
		return "", "", false, fmt.Errorf("cannot bind mount volume: %s volume paths must be absolute.", path)
	}

	path = filepath.Clean(path)
	mountToPath = filepath.Clean(mountToPath)
	return path, mountToPath, writable, nil
}

func (container *Container) applyVolumesFrom() error {
	volumesFrom := container.hostConfig.VolumesFrom

	mountGroups := make([]map[string]*Mount, 0, len(volumesFrom))

	for _, spec := range volumesFrom {
		mountGroup, err := parseVolumesFromSpec(container.daemon, spec)
		if err != nil {
			return err
		}
		mountGroups = append(mountGroups, mountGroup)
	}

	for _, mounts := range mountGroups {
		for _, mnt := range mounts {
			mnt.container = container
			if err := mnt.initialize(); err != nil {
				return err
			}
		}
	}
	return nil
}

func validMountMode(mode string) bool {
	validModes := map[string]bool{
		"rw": true,
		"ro": true,
	}

	return validModes[mode]
}

func (container *Container) setupMounts() error {
	if err := label.SetFileLabel(container.ResolvConfPath, container.MountLabel); err != nil {
		return err
	}
	mounts := []execdriver.Mount{
		{Source: container.ResolvConfPath, Destination: "/etc/resolv.conf", Writable: true, Private: true},
	}

	if container.HostnamePath != "" {
		if err := label.SetFileLabel(container.HostnamePath, container.MountLabel); err != nil {
			return err
		}
		mounts = append(mounts, execdriver.Mount{Source: container.HostnamePath, Destination: "/etc/hostname", Writable: true, Private: true})
	}

	if container.HostsPath != "" {
		if err := label.SetFileLabel(container.HostsPath, container.MountLabel); err != nil {
			return err
		}
		mounts = append(mounts, execdriver.Mount{Source: container.HostsPath, Destination: "/etc/hosts", Writable: true, Private: true})
	}

	// Mount user specified volumes
	// Note, these are not private because you may want propagation of (un)mounts from host
	// volumes. For instance if you use -v /usr:/usr and the host later mounts /usr/share you
	// want this new mount in the container
	// These mounts must be ordered based on the length of the path that it is being mounted to (lexicographic)
	for _, path := range container.sortedVolumeMounts() {
		mounts = append(mounts, execdriver.Mount{
			Source:      container.Volumes[path],
			Destination: path,
			Writable:    container.VolumesRW[path],
		})
	}

	container.command.Mounts = mounts
	return nil
}

func parseVolumesFromSpec(daemon *Daemon, spec string) (map[string]*Mount, error) {
	specParts := strings.SplitN(spec, ":", 2)
	if len(specParts) == 0 {
		return nil, fmt.Errorf("Malformed volumes-from specification: %s", spec)
	}

	c := daemon.Get(specParts[0])
	if c == nil {
		return nil, fmt.Errorf("Container %s not found. Impossible to mount its volumes", specParts[0])
	}

	mounts := c.VolumeMounts()

	if len(specParts) == 2 {
		mode := specParts[1]
		if !validMountMode(mode) {
			return nil, fmt.Errorf("Invalid mode for volumes-from: %s", mode)
		}

		// Set the mode for the inheritted volume
		for _, mnt := range mounts {
			// Ensure that if the inherited volume is not writable, that we don't make
			// it writable here
			mnt.Writable = mnt.Writable && (mode == "rw")
		}
	}

	return mounts, nil
}

func (container *Container) VolumeMounts() map[string]*Mount {
	mounts := make(map[string]*Mount)

	for mountToPath, path := range container.Volumes {
		if v := container.daemon.volumes.Get(path); v != nil {
			mounts[mountToPath] = &Mount{volume: v, container: container, MountToPath: mountToPath, Writable: container.VolumesRW[mountToPath]}
		}
	}

	return mounts
}

func copyExistingContents(source, destination string) error {
	volList, err := ioutil.ReadDir(source)
	if err != nil {
		return err
	}

	if len(volList) > 0 {
		srcList, err := ioutil.ReadDir(destination)
		if err != nil {
			return err
		}

		if len(srcList) == 0 {
			// If the source volume is empty copy files from the root into the volume
			if err := chrootarchive.CopyWithTar(source, destination); err != nil {
				return err
			}
		}
	}

	return copyOwnership(source, destination)
}

// copyOwnership copies the permissions and uid:gid of the source file
// into the destination file
func copyOwnership(source, destination string) error {
	var stat syscall.Stat_t

	if err := syscall.Stat(source, &stat); err != nil {
		return err
	}

	if err := os.Chown(destination, int(stat.Uid), int(stat.Gid)); err != nil {
		return err
	}

	return os.Chmod(destination, os.FileMode(stat.Mode))
}
<|endoftext|>


<commit_before>// Copyright 2016 CoreOS, Inc.
//
// 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 aws

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/service/ec2"
	"golang.org/x/crypto/ssh"

	"github.com/coreos/mantle/platform"
	"github.com/coreos/mantle/util"
)

type machine struct {
	cluster *cluster
	mach    *ec2.Instance
	dir     string
	journal *platform.Journal
	console string
}

func (am *machine) ID() string {
	return *am.mach.InstanceId
}

func (am *machine) IP() string {
	return *am.mach.PublicIpAddress
}

func (am *machine) PrivateIP() string {
	return *am.mach.PrivateIpAddress
}

func (am *machine) RuntimeConf() platform.RuntimeConfig {
	return am.cluster.RuntimeConf()
}

func (am *machine) SSHClient() (*ssh.Client, error) {
	return am.cluster.SSHClient(am.IP())
}

func (am *machine) PasswordSSHClient(user string, password string) (*ssh.Client, error) {
	return am.cluster.PasswordSSHClient(am.IP(), user, password)
}

func (am *machine) SSH(cmd string) ([]byte, []byte, error) {
	return am.cluster.SSH(am, cmd)
}

func (am *machine) Reboot() error {
	return platform.RebootMachine(am, am.journal)
}

func (am *machine) Destroy() {
	origConsole, err := am.cluster.api.GetConsoleOutput(am.ID())
	if err != nil {
		plog.Warningf("Error retrieving console log for %v: %v", am.ID(), err)
	}

	if err := am.cluster.api.TerminateInstances([]string{am.ID()}); err != nil {
		plog.Errorf("Error terminating instance %v: %v", am.ID(), err)
	}

	if am.journal != nil {
		am.journal.Destroy()
	}

	if err := am.saveConsole(origConsole); err != nil {
		plog.Errorf("Error saving console for instance %v: %v", am.ID(), err)
	}

	am.cluster.DelMach(am)
}

func (am *machine) ConsoleOutput() string {
	return am.console
}

func (am *machine) saveConsole(origConsole string) error {
	// If the instance has e.g. been running for several minutes, the
	// returned output will be non-empty but won't necessarily include
	// the most recent log messages. So we loop until the post-termination
	// logs are different from the pre-termination logs.
	err := util.Retry(60, 5*time.Second, func() error {
		var err error
		am.console, err = am.cluster.api.GetConsoleOutput(am.ID())
		if err != nil {
			return err
		}

		if am.console == origConsole {
			plog.Debugf("waiting for console for %v", am.ID())
			return fmt.Errorf("timed out waiting for console output of %v", am.ID())
		}

		return nil
	})
	if err != nil {
		return err
	}

	// merge the two logs
	overlapLen := 100
	if len(am.console) < overlapLen {
		overlapLen = len(am.console)
	}
	origIdx := strings.LastIndex(origConsole, am.console[0:overlapLen])
	if origIdx != -1 {
		// overlap
		am.console = origConsole[0:origIdx] + am.console
	} else if origConsole != "" {
		// two logs with no overlap; add scissors
		am.console = origConsole + "\n\n8<------------------------\n\n" + am.console
	}

	path := filepath.Join(am.dir, "console.txt")
	f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	f.WriteString(am.console)

	return nil
}
<commit_msg>platform/machine/aws: limit console log timeout to 5 minutes<commit_after>// Copyright 2016 CoreOS, Inc.
//
// 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 aws

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/aws/aws-sdk-go/service/ec2"
	"golang.org/x/crypto/ssh"

	"github.com/coreos/mantle/platform"
	"github.com/coreos/mantle/util"
)

type machine struct {
	cluster *cluster
	mach    *ec2.Instance
	dir     string
	journal *platform.Journal
	console string
}

func (am *machine) ID() string {
	return *am.mach.InstanceId
}

func (am *machine) IP() string {
	return *am.mach.PublicIpAddress
}

func (am *machine) PrivateIP() string {
	return *am.mach.PrivateIpAddress
}

func (am *machine) RuntimeConf() platform.RuntimeConfig {
	return am.cluster.RuntimeConf()
}

func (am *machine) SSHClient() (*ssh.Client, error) {
	return am.cluster.SSHClient(am.IP())
}

func (am *machine) PasswordSSHClient(user string, password string) (*ssh.Client, error) {
	return am.cluster.PasswordSSHClient(am.IP(), user, password)
}

func (am *machine) SSH(cmd string) ([]byte, []byte, error) {
	return am.cluster.SSH(am, cmd)
}

func (am *machine) Reboot() error {
	return platform.RebootMachine(am, am.journal)
}

func (am *machine) Destroy() {
	origConsole, err := am.cluster.api.GetConsoleOutput(am.ID())
	if err != nil {
		plog.Warningf("Error retrieving console log for %v: %v", am.ID(), err)
	}

	if err := am.cluster.api.TerminateInstances([]string{am.ID()}); err != nil {
		plog.Errorf("Error terminating instance %v: %v", am.ID(), err)
	}

	if am.journal != nil {
		am.journal.Destroy()
	}

	if err := am.saveConsole(origConsole); err != nil {
		plog.Errorf("Error saving console for instance %v: %v", am.ID(), err)
	}

	am.cluster.DelMach(am)
}

func (am *machine) ConsoleOutput() string {
	return am.console
}

func (am *machine) saveConsole(origConsole string) error {
	// If the instance has e.g. been running for several minutes, the
	// returned output will be non-empty but won't necessarily include
	// the most recent log messages. So we loop until the post-termination
	// logs are different from the pre-termination logs.
	err := util.WaitUntilReady(5*time.Minute, 5*time.Second, func() (bool, error) {
		var err error
		am.console, err = am.cluster.api.GetConsoleOutput(am.ID())
		if err != nil {
			return false, err
		}

		if am.console == origConsole {
			plog.Debugf("waiting for console for %v", am.ID())
			return false, nil
		}

		return true, nil
	})
	if err != nil {
		return fmt.Errorf("retrieving console output of %v: %v", am.ID(), err)
	}

	// merge the two logs
	overlapLen := 100
	if len(am.console) < overlapLen {
		overlapLen = len(am.console)
	}
	origIdx := strings.LastIndex(origConsole, am.console[0:overlapLen])
	if origIdx != -1 {
		// overlap
		am.console = origConsole[0:origIdx] + am.console
	} else if origConsole != "" {
		// two logs with no overlap; add scissors
		am.console = origConsole + "\n\n8<------------------------\n\n" + am.console
	}

	path := filepath.Join(am.dir, "console.txt")
	f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return err
	}
	defer f.Close()
	f.WriteString(am.console)

	return nil
}
<|endoftext|>


<commit_before>package matchers_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	. "github.com/cloudfoundry/bosh-agent/matchers"

	"fmt"
)

var _ = Describe("matchers", func() {

	var _ = Describe("Match", func() {

		Context("when no sub-matchers match", func() {
			var fakematcher1 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var fakematcher2 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var oneOf = MatchOneOf(fakematcher1, fakematcher2)

			It("calls Match on each sub-matcher", func() {
				success, err := oneOf.Match("Fake Test Value")

				Expect(success).To(BeFalse())
				Expect(err).ToNot(HaveOccurred())

				Expect(fakematcher1.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher2.ReceivedActual).To(Equal("Fake Test Value"))
			})
		})

		Context("when at least one sub-matcher matches", func() {
			var fakematcher1 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var fakematcher2 = &FakeMatcher{
				MatchesToReturn: true,
				ErrToReturn:     nil,
			}
			var fakematcher3 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var oneOf = MatchOneOf(fakematcher1, fakematcher2, fakematcher3)

			It("calls Match on each sub-matcher until a match is found", func() {
				success, err := oneOf.Match("Fake Test Value")

				Expect(success).To(BeTrue())
				Expect(err).ToNot(HaveOccurred())

				Expect(fakematcher1.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher2.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher3.ReceivedActual).To(BeNil())
			})
		})

		Context("when at least one sub-matcher errors", func() {
			var error = fmt.Errorf("Fake Error")
			var fakematcher1 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var fakematcher2 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     error,
			}
			var fakematcher3 = &FakeMatcher{
				MatchesToReturn: true,
				ErrToReturn:     nil,
			}
			var oneOf = MatchOneOf(fakematcher1, fakematcher2, fakematcher3)

			It("calls Match on each sub-matcher until an error is returned", func() {
				success, err := oneOf.Match("Fake Test Value")

				Expect(success).To(BeFalse())
				Expect(err).To(Equal(error))

				Expect(fakematcher1.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher2.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher3.ReceivedActual).To(BeNil())
			})
		})

		Context("when an element is not a matcher", func() {
			var oneOf = MatchOneOf("abc", 123, []string{"x", "y", "z"}, Equal("foo"))

			It("uses an Equal matcher", func() {
				success, err := oneOf.Match("abc")
				Expect(err).ToNot(HaveOccurred())
				Expect(success).To(BeTrue())

				success, err = oneOf.Match(123)
				Expect(err).ToNot(HaveOccurred())
				Expect(success).To(BeTrue())

				success, err = oneOf.Match([]string{"x", "y", "z"})
				Expect(err).ToNot(HaveOccurred())
				Expect(success).To(BeTrue())
			})

			It("matchers still work", func() {
				success, err := oneOf.Match("foo")
				Expect(err).ToNot(HaveOccurred())
				Expect(success).To(BeTrue())
			})
		})
	})

	var _ = Describe("FailureMessage", func() {
		var oneOf = MatchOneOf(Equal("a"), BeNumerically(">", 1))

		It("concatonates the failure message of all matchers", func() {
			msg := oneOf.FailureMessage("Fake Test Value")

			expectedMessagePattern := `Expected
		<string>: Fake Test Value
to match one of
		<\*matchers.EqualMatcher | 0x[[:xdigit:]]+>: {Expected: "a"}
or
		<\*matchers.BeNumericallyMatcher | 0x[[:xdigit:]]+>: {Comparator: ">", CompareTo: \[1\]}`

			Expect(msg).To(MatchRegexp(expectedMessagePattern))
		})
	})

	var _ = Describe("NegatedFailureMessage", func() {
		var oneOf = MatchOneOf("a", BeNumerically(">", 1))

		It("concatonates the failure message of all matchers", func() {
			msg := oneOf.NegatedFailureMessage("Fake Test Value")

			expectedMessagePattern := `Expected
		<string>: Fake Test Value
not to match one of
		<string>: a
or
		<\*matchers\.BeNumericallyMatcher | 0x[[:xdigit:]]+>: {Comparator: ">", CompareTo: \[1\]}`

			Expect(msg).To(MatchRegexp(expectedMessagePattern))
		})
	})
})

type FakeMatcher struct {
	ReceivedActual  interface{}
	MatchesToReturn bool
	ErrToReturn     error
}

func (matcher *FakeMatcher) Match(actual interface{}) (bool, error) {
	matcher.ReceivedActual = actual

	return matcher.MatchesToReturn, matcher.ErrToReturn
}

func (matcher *FakeMatcher) FailureMessage(actual interface{}) string {
	return fmt.Sprintf("positive: %v", actual)
}

func (matcher *FakeMatcher) NegatedFailureMessage(actual interface{}) string {
	return fmt.Sprintf("negative: %v", actual)
}
<commit_msg>Fix unit-tests after dependency bump<commit_after>package matchers_test

import (
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	. "github.com/cloudfoundry/bosh-agent/matchers"

	"fmt"
)

var _ = Describe("matchers", func() {

	var _ = Describe("Match", func() {

		Context("when no sub-matchers match", func() {
			var fakematcher1 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var fakematcher2 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var oneOf = MatchOneOf(fakematcher1, fakematcher2)

			It("calls Match on each sub-matcher", func() {
				success, err := oneOf.Match("Fake Test Value")

				Expect(success).To(BeFalse())
				Expect(err).ToNot(HaveOccurred())

				Expect(fakematcher1.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher2.ReceivedActual).To(Equal("Fake Test Value"))
			})
		})

		Context("when at least one sub-matcher matches", func() {
			var fakematcher1 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var fakematcher2 = &FakeMatcher{
				MatchesToReturn: true,
				ErrToReturn:     nil,
			}
			var fakematcher3 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var oneOf = MatchOneOf(fakematcher1, fakematcher2, fakematcher3)

			It("calls Match on each sub-matcher until a match is found", func() {
				success, err := oneOf.Match("Fake Test Value")

				Expect(success).To(BeTrue())
				Expect(err).ToNot(HaveOccurred())

				Expect(fakematcher1.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher2.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher3.ReceivedActual).To(BeNil())
			})
		})

		Context("when at least one sub-matcher errors", func() {
			var error = fmt.Errorf("Fake Error")
			var fakematcher1 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     nil,
			}
			var fakematcher2 = &FakeMatcher{
				MatchesToReturn: false,
				ErrToReturn:     error,
			}
			var fakematcher3 = &FakeMatcher{
				MatchesToReturn: true,
				ErrToReturn:     nil,
			}
			var oneOf = MatchOneOf(fakematcher1, fakematcher2, fakematcher3)

			It("calls Match on each sub-matcher until an error is returned", func() {
				success, err := oneOf.Match("Fake Test Value")

				Expect(success).To(BeFalse())
				Expect(err).To(Equal(error))

				Expect(fakematcher1.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher2.ReceivedActual).To(Equal("Fake Test Value"))
				Expect(fakematcher3.ReceivedActual).To(BeNil())
			})
		})

		Context("when an element is not a matcher", func() {
			var oneOf = MatchOneOf("abc", 123, []string{"x", "y", "z"}, Equal("foo"))

			It("uses an Equal matcher", func() {
				success, err := oneOf.Match("abc")
				Expect(err).ToNot(HaveOccurred())
				Expect(success).To(BeTrue())

				success, err = oneOf.Match(123)
				Expect(err).ToNot(HaveOccurred())
				Expect(success).To(BeTrue())

				success, err = oneOf.Match([]string{"x", "y", "z"})
				Expect(err).ToNot(HaveOccurred())
				Expect(success).To(BeTrue())
			})

			It("matchers still work", func() {
				success, err := oneOf.Match("foo")
				Expect(err).ToNot(HaveOccurred())
				Expect(success).To(BeTrue())
			})
		})
	})

	var _ = Describe("FailureMessage", func() {
		var oneOf = MatchOneOf(Equal("a"), BeNumerically(">", 1))

		It("concatonates the failure message of all matchers", func() {
			msg := oneOf.FailureMessage("Fake Test Value")

			expectedMessagePattern := `Expected
		<string>: Fake Test Value
to match one of
		<\*matchers.EqualMatcher | 0x[[:xdigit:]]+>: {Expected: "a"}
or
		<\*matchers.BeNumericallyMatcher | 0x[[:xdigit:]]+>: {Comparator: ">", CompareTo: \[<int>1\]}`

			Expect(msg).To(MatchRegexp(expectedMessagePattern))
		})
	})

	var _ = Describe("NegatedFailureMessage", func() {
		var oneOf = MatchOneOf("a", BeNumerically(">", 1))

		It("concatonates the failure message of all matchers", func() {
			msg := oneOf.NegatedFailureMessage("Fake Test Value")

			expectedMessagePattern := `Expected
		<string>: Fake Test Value
not to match one of
		<string>: a
or
		<\*matchers\.BeNumericallyMatcher | 0x[[:xdigit:]]+>: {Comparator: ">", CompareTo: \[<int>1\]}`

			Expect(msg).To(MatchRegexp(expectedMessagePattern))
		})
	})
})

type FakeMatcher struct {
	ReceivedActual  interface{}
	MatchesToReturn bool
	ErrToReturn     error
}

func (matcher *FakeMatcher) Match(actual interface{}) (bool, error) {
	matcher.ReceivedActual = actual

	return matcher.MatchesToReturn, matcher.ErrToReturn
}

func (matcher *FakeMatcher) FailureMessage(actual interface{}) string {
	return fmt.Sprintf("positive: %v", actual)
}

func (matcher *FakeMatcher) NegatedFailureMessage(actual interface{}) string {
	return fmt.Sprintf("negative: %v", actual)
}
<|endoftext|>


<commit_before>package dotquote

func (decoder *Decoder) Values() *DecoderValues {
	decoderValues := DecoderValues{
		decoder:decoder,
	}

	return &decoderValues
}

type DecoderValues struct {
	decoder *Decoder

	hasBegun bool
	iterationCount int

	err error

	valueBegin int
	valueEnd   int
}

func (v DecoderValues) Err() error {
	return v.err
}

func (v *DecoderValues) Next() bool {
	if nil == v {
		panic(errNilReceiver)
	}

	logger := v.decoder.Logger
	if nil == logger {
		logger = internalDiscardLogger{}
	}

	v.hasBegun = true
	if nil != v.err {
		return false
	}
	v.iterationCount++
	logger.Debugf("[VALUES][NEXT] ITERATION COUNT #%d", v.iterationCount)

	values := v.decoder.values
	if nil == values {
		v.err = errInternalError
		return false
	}

	i := v.iterationCount - 1
	if len(values) <= i {
		return false
	}
	currentValue := values[i]

	v.valueBegin = currentValue.valueBegin
	v.valueEnd   = currentValue.valueEnd

	return true
}

func (v DecoderValues) Value() (int, int, error) {
	if !v.hasBegun {
		return -1, -1, errPremature
	}

	return v.valueBegin, v.valueEnd, nil
}

func (v DecoderValues) ValueBytes() ([]byte, error) {
	begin, end, err := v.Value()
	if nil != err {
		return nil, err
	}

	b := v.decoder.Bytes
	if nil == b {
		return nil, errNilBytes
	}
	p := b[begin:end]

	return p, nil
}

func (v DecoderValues) ValueString() (string, error) {
	p, err := v.ValueBytes()
	if nil != err {
		return "", err
	}

	return string(p), nil
}

// MustValue is like Value, expect it panic()s on an error.
func (v DecoderValues) MustValue() (int, int) {
	begin, end, err := v.Value()
	if nil != err {
		panic(err)
	}

	return begin, end
}

// MustValueBytes is like ValueBytes, expect it panic()s on an error.
func (v DecoderValues) MustValueBytes() []byte {
	p, err := v.ValueBytes()
	if nil != err {
		panic(err)
	}

	return p
}

// MustValueString is like ValueString, expect it panic()s on an error.
func (v DecoderValues) MustValueString() string {
	s, err := v.ValueString()
	if nil != err {
		panic(err)
	}

	return s
}
<commit_msg>correction<commit_after>package dotquote

func (decoder *Decoder) Values() *DecoderValues {
	decoderValues := DecoderValues{
		decoder:decoder,
	}

	return &decoderValues
}

type DecoderValues struct {
	decoder *Decoder

	hasBegun bool
	iterationCount int

	err error

	valueBegin int
	valueEnd   int
}

func (v DecoderValues) Err() error {
	return v.err
}

func (v *DecoderValues) Next() bool {
	if nil == v {
		panic(errNilReceiver)
	}

	logger := v.decoder.Logger
	if nil == logger {
		logger = internalDiscardLogger{}
	}

	v.hasBegun = true
	if nil != v.err {
		return false
	}
	v.iterationCount++
	logger.Debugf("[VALUES][NEXT] ITERATION COUNT #%d", v.iterationCount)

	values := v.decoder.values
	if nil == values {
		return false
	}

	i := v.iterationCount - 1
	if len(values) <= i {
		return false
	}
	currentValue := values[i]

	v.valueBegin = currentValue.valueBegin
	v.valueEnd   = currentValue.valueEnd

	return true
}

func (v DecoderValues) Value() (int, int, error) {
	if !v.hasBegun {
		return -1, -1, errPremature
	}

	return v.valueBegin, v.valueEnd, nil
}

func (v DecoderValues) ValueBytes() ([]byte, error) {
	begin, end, err := v.Value()
	if nil != err {
		return nil, err
	}

	b := v.decoder.Bytes
	if nil == b {
		return nil, errNilBytes
	}
	p := b[begin:end]

	return p, nil
}

func (v DecoderValues) ValueString() (string, error) {
	p, err := v.ValueBytes()
	if nil != err {
		return "", err
	}

	return string(p), nil
}

// MustValue is like Value, expect it panic()s on an error.
func (v DecoderValues) MustValue() (int, int) {
	begin, end, err := v.Value()
	if nil != err {
		panic(err)
	}

	return begin, end
}

// MustValueBytes is like ValueBytes, expect it panic()s on an error.
func (v DecoderValues) MustValueBytes() []byte {
	p, err := v.ValueBytes()
	if nil != err {
		panic(err)
	}

	return p
}

// MustValueString is like ValueString, expect it panic()s on an error.
func (v DecoderValues) MustValueString() string {
	s, err := v.ValueString()
	if nil != err {
		panic(err)
	}

	return s
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

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

	"github.com/olivere/elastic/uritemplates"
)

// IndicesForcemergeService allows to force merging of one or more indices.
// The merge relates to the number of segments a Lucene index holds
// within each shard. The force merge operation allows to reduce the number
// of segments by merging them.
//
// See http://www.elastic.co/guide/en/elasticsearch/reference/2.1/indices-forcemerge.html
// for more information.
type IndicesForcemergeService struct {
	client             *Client
	pretty             bool
	index              []string
	allowNoIndices     *bool
	expandWildcards    string
	flush              *bool
	ignoreUnavailable  *bool
	maxNumSegments     interface{}
	onlyExpungeDeletes *bool
	operationThreading interface{}
	waitForMerge       *bool
}

// NewIndicesForcemergeService creates a new IndicesForcemergeService.
func NewIndicesForcemergeService(client *Client) *IndicesForcemergeService {
	return &IndicesForcemergeService{
		client: client,
		index:  make([]string, 0),
	}
}

// Index is a list of index names; use `_all` or empty string to perform
// the operation on all indices.
func (s *IndicesForcemergeService) Index(index ...string) *IndicesForcemergeService {
	if s.index == nil {
		s.index = make([]string, 0)
	}
	s.index = append(s.index, index...)
	return s
}

// AllowNoIndices indicates whether to ignore if a wildcard indices
// expression resolves into no concrete indices.
// (This includes `_all` string or when no indices have been specified).
func (s *IndicesForcemergeService) AllowNoIndices(allowNoIndices bool) *IndicesForcemergeService {
	s.allowNoIndices = &allowNoIndices
	return s
}

// ExpandWildcards indicates whether to expand wildcard expression to
// concrete indices that are open, closed or both..
func (s *IndicesForcemergeService) ExpandWildcards(expandWildcards string) *IndicesForcemergeService {
	s.expandWildcards = expandWildcards
	return s
}

// Flush specifies whether the index should be flushed after performing
// the operation (default: true).
func (s *IndicesForcemergeService) Flush(flush bool) *IndicesForcemergeService {
	s.flush = &flush
	return s
}

// IgnoreUnavailable indicates whether specified concrete indices should
// be ignored when unavailable (missing or closed).
func (s *IndicesForcemergeService) IgnoreUnavailable(ignoreUnavailable bool) *IndicesForcemergeService {
	s.ignoreUnavailable = &ignoreUnavailable
	return s
}

// MaxNumSegments specifies the number of segments the index should be
// merged into (default: dynamic).
func (s *IndicesForcemergeService) MaxNumSegments(maxNumSegments interface{}) *IndicesForcemergeService {
	s.maxNumSegments = maxNumSegments
	return s
}

// OnlyExpungeDeletes specifies whether the operation should only expunge
// deleted documents.
func (s *IndicesForcemergeService) OnlyExpungeDeletes(onlyExpungeDeletes bool) *IndicesForcemergeService {
	s.onlyExpungeDeletes = &onlyExpungeDeletes
	return s
}

func (s *IndicesForcemergeService) OperationThreading(operationThreading interface{}) *IndicesForcemergeService {
	s.operationThreading = operationThreading
	return s
}

// WaitForMerge specifies whether the request should block until the
// merge process is finished (default: true).
func (s *IndicesForcemergeService) WaitForMerge(waitForMerge bool) *IndicesForcemergeService {
	s.waitForMerge = &waitForMerge
	return s
}

// Pretty indicates that the JSON response be indented and human readable.
func (s *IndicesForcemergeService) Pretty(pretty bool) *IndicesForcemergeService {
	s.pretty = pretty
	return s
}

// buildURL builds the URL for the operation.
func (s *IndicesForcemergeService) buildURL() (string, url.Values, error) {
	var err error
	var path string

	// Build URL
	if len(s.index) > 0 {
		path, err = uritemplates.Expand("/{index}/_forcemerge", map[string]string{
			"index": strings.Join(s.index, ","),
		})
	} else {
		path = "/_forcemerge"
	}
	if err != nil {
		return "", url.Values{}, err
	}

	// Add query string parameters
	params := url.Values{}
	if s.pretty {
		params.Set("pretty", "1")
	}
	if s.allowNoIndices != nil {
		params.Set("allow_no_indices", fmt.Sprintf("%v", *s.allowNoIndices))
	}
	if s.expandWildcards != "" {
		params.Set("expand_wildcards", s.expandWildcards)
	}
	if s.flush != nil {
		params.Set("flush", fmt.Sprintf("%v", *s.flush))
	}
	if s.ignoreUnavailable != nil {
		params.Set("ignore_unavailable", fmt.Sprintf("%v", *s.ignoreUnavailable))
	}
	if s.maxNumSegments != nil {
		params.Set("max_num_segments", fmt.Sprintf("%v", s.maxNumSegments))
	}
	if s.onlyExpungeDeletes != nil {
		params.Set("only_expunge_deletes", fmt.Sprintf("%v", *s.onlyExpungeDeletes))
	}
	if s.operationThreading != nil {
		params.Set("operation_threading", fmt.Sprintf("%v", s.operationThreading))
	}
	if s.waitForMerge != nil {
		params.Set("wait_for_merge", fmt.Sprintf("%v", *s.waitForMerge))
	}
	return path, params, nil
}

// Validate checks if the operation is valid.
func (s *IndicesForcemergeService) Validate() error {
	return nil
}

// Do executes the operation.
func (s *IndicesForcemergeService) Do() (*IndicesForcemergeResponse, error) {
	// Check pre-conditions
	if err := s.Validate(); err != nil {
		return nil, err
	}

	// Get URL for request
	path, params, err := s.buildURL()
	if err != nil {
		return nil, err
	}

	// Get HTTP response
	res, err := s.client.PerformRequest("POST", path, params, nil)
	if err != nil {
		return nil, err
	}

	// Return operation response
	ret := new(IndicesForcemergeResponse)
	if err := json.Unmarshal(res.Body, ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// IndicesForcemergeResponse is the response of IndicesForcemergeService.Do.
type IndicesForcemergeResponse struct {
	Shards shardsInfo `json:"_shards"`
}
<commit_msg>Fix wrong import path<commit_after>// Copyright 2012-2015 Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

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

	"gopkg.in/olivere/elastic.v3/uritemplates"
)

// IndicesForcemergeService allows to force merging of one or more indices.
// The merge relates to the number of segments a Lucene index holds
// within each shard. The force merge operation allows to reduce the number
// of segments by merging them.
//
// See http://www.elastic.co/guide/en/elasticsearch/reference/2.1/indices-forcemerge.html
// for more information.
type IndicesForcemergeService struct {
	client             *Client
	pretty             bool
	index              []string
	allowNoIndices     *bool
	expandWildcards    string
	flush              *bool
	ignoreUnavailable  *bool
	maxNumSegments     interface{}
	onlyExpungeDeletes *bool
	operationThreading interface{}
	waitForMerge       *bool
}

// NewIndicesForcemergeService creates a new IndicesForcemergeService.
func NewIndicesForcemergeService(client *Client) *IndicesForcemergeService {
	return &IndicesForcemergeService{
		client: client,
		index:  make([]string, 0),
	}
}

// Index is a list of index names; use `_all` or empty string to perform
// the operation on all indices.
func (s *IndicesForcemergeService) Index(index ...string) *IndicesForcemergeService {
	if s.index == nil {
		s.index = make([]string, 0)
	}
	s.index = append(s.index, index...)
	return s
}

// AllowNoIndices indicates whether to ignore if a wildcard indices
// expression resolves into no concrete indices.
// (This includes `_all` string or when no indices have been specified).
func (s *IndicesForcemergeService) AllowNoIndices(allowNoIndices bool) *IndicesForcemergeService {
	s.allowNoIndices = &allowNoIndices
	return s
}

// ExpandWildcards indicates whether to expand wildcard expression to
// concrete indices that are open, closed or both..
func (s *IndicesForcemergeService) ExpandWildcards(expandWildcards string) *IndicesForcemergeService {
	s.expandWildcards = expandWildcards
	return s
}

// Flush specifies whether the index should be flushed after performing
// the operation (default: true).
func (s *IndicesForcemergeService) Flush(flush bool) *IndicesForcemergeService {
	s.flush = &flush
	return s
}

// IgnoreUnavailable indicates whether specified concrete indices should
// be ignored when unavailable (missing or closed).
func (s *IndicesForcemergeService) IgnoreUnavailable(ignoreUnavailable bool) *IndicesForcemergeService {
	s.ignoreUnavailable = &ignoreUnavailable
	return s
}

// MaxNumSegments specifies the number of segments the index should be
// merged into (default: dynamic).
func (s *IndicesForcemergeService) MaxNumSegments(maxNumSegments interface{}) *IndicesForcemergeService {
	s.maxNumSegments = maxNumSegments
	return s
}

// OnlyExpungeDeletes specifies whether the operation should only expunge
// deleted documents.
func (s *IndicesForcemergeService) OnlyExpungeDeletes(onlyExpungeDeletes bool) *IndicesForcemergeService {
	s.onlyExpungeDeletes = &onlyExpungeDeletes
	return s
}

func (s *IndicesForcemergeService) OperationThreading(operationThreading interface{}) *IndicesForcemergeService {
	s.operationThreading = operationThreading
	return s
}

// WaitForMerge specifies whether the request should block until the
// merge process is finished (default: true).
func (s *IndicesForcemergeService) WaitForMerge(waitForMerge bool) *IndicesForcemergeService {
	s.waitForMerge = &waitForMerge
	return s
}

// Pretty indicates that the JSON response be indented and human readable.
func (s *IndicesForcemergeService) Pretty(pretty bool) *IndicesForcemergeService {
	s.pretty = pretty
	return s
}

// buildURL builds the URL for the operation.
func (s *IndicesForcemergeService) buildURL() (string, url.Values, error) {
	var err error
	var path string

	// Build URL
	if len(s.index) > 0 {
		path, err = uritemplates.Expand("/{index}/_forcemerge", map[string]string{
			"index": strings.Join(s.index, ","),
		})
	} else {
		path = "/_forcemerge"
	}
	if err != nil {
		return "", url.Values{}, err
	}

	// Add query string parameters
	params := url.Values{}
	if s.pretty {
		params.Set("pretty", "1")
	}
	if s.allowNoIndices != nil {
		params.Set("allow_no_indices", fmt.Sprintf("%v", *s.allowNoIndices))
	}
	if s.expandWildcards != "" {
		params.Set("expand_wildcards", s.expandWildcards)
	}
	if s.flush != nil {
		params.Set("flush", fmt.Sprintf("%v", *s.flush))
	}
	if s.ignoreUnavailable != nil {
		params.Set("ignore_unavailable", fmt.Sprintf("%v", *s.ignoreUnavailable))
	}
	if s.maxNumSegments != nil {
		params.Set("max_num_segments", fmt.Sprintf("%v", s.maxNumSegments))
	}
	if s.onlyExpungeDeletes != nil {
		params.Set("only_expunge_deletes", fmt.Sprintf("%v", *s.onlyExpungeDeletes))
	}
	if s.operationThreading != nil {
		params.Set("operation_threading", fmt.Sprintf("%v", s.operationThreading))
	}
	if s.waitForMerge != nil {
		params.Set("wait_for_merge", fmt.Sprintf("%v", *s.waitForMerge))
	}
	return path, params, nil
}

// Validate checks if the operation is valid.
func (s *IndicesForcemergeService) Validate() error {
	return nil
}

// Do executes the operation.
func (s *IndicesForcemergeService) Do() (*IndicesForcemergeResponse, error) {
	// Check pre-conditions
	if err := s.Validate(); err != nil {
		return nil, err
	}

	// Get URL for request
	path, params, err := s.buildURL()
	if err != nil {
		return nil, err
	}

	// Get HTTP response
	res, err := s.client.PerformRequest("POST", path, params, nil)
	if err != nil {
		return nil, err
	}

	// Return operation response
	ret := new(IndicesForcemergeResponse)
	if err := json.Unmarshal(res.Body, ret); err != nil {
		return nil, err
	}
	return ret, nil
}

// IndicesForcemergeResponse is the response of IndicesForcemergeService.Do.
type IndicesForcemergeResponse struct {
	Shards shardsInfo `json:"_shards"`
}
<|endoftext|>


<commit_before>// Copyright 2015 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 gcm

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/gcloud-golang/compute/metadata"
	sink_api "github.com/GoogleCloudPlatform/heapster/sinks/api"
	"github.com/golang/glog"
)

type gcmSink struct {
	// Token to use for authentication.
	token string

	// When the token expires.
	tokenExpiration time.Time

	// TODO(vmarmol): Make this configurable and not only detected.
	// GCE project.
	project string

	// TODO(vmarmol): Also store labels?
	// Map of metrics we currently export.
	exportedMetrics map[string]sink_api.MetricDescriptor
}

func (self *gcmSink) refreshToken() error {
	if time.Now().After(self.tokenExpiration) {
		token, err := getToken()
		if err != nil {
			return nil
		}

		// Expire the token a bit early.
		const earlyRefreshSeconds = 60
		if token.ExpiresIn > earlyRefreshSeconds {
			token.ExpiresIn -= earlyRefreshSeconds
		}
		self.token = token.AccessToken
		self.tokenExpiration = time.Now().Add(time.Duration(token.ExpiresIn) * time.Second)
	}
	return nil
}

// GCM request structures for a MetricDescriptor.
type typeDescriptor struct {
	MetricType string `json:"metricType,omitempty"`
	ValueType  string `json:"valueType,omitempty"`
}

type metricDescriptor struct {
	Name           string                     `json:"name,omitempty"`
	Project        string                     `json:"project,omitempty"`
	Description    string                     `json:"description,omitempty"`
	Labels         []sink_api.LabelDescriptor `json:"labels,omitempty"`
	TypeDescriptor typeDescriptor             `json:"typeDescriptor,omitempty"`
}

const maxNumLabels = 10

// Adds the specified metrics or updates them if they already exist.
func (self *gcmSink) Register(metrics []sink_api.MetricDescriptor) error {
	for _, metric := range metrics {
		// Enforce the most labels that GCM allows.
		if len(metric.Labels) > maxNumLabels {
			return fmt.Errorf("metrics cannot have more than %d labels and %q has %d", maxNumLabels, metric.Name, len(metric.Labels))
		}

		// Ensure all labels are in the correct format.
		for i := range metric.Labels {
			metric.Labels[i].Key = fullLabelName(metric.Labels[i].Key)
		}

		request := metricDescriptor{
			Name:        fullMetricName(metric.Name),
			Project:     self.project,
			Description: metric.Description,
			Labels:      metric.Labels,
			TypeDescriptor: typeDescriptor{
				MetricType: metric.Type.String(),
				ValueType:  metric.ValueType.String(),
			},
		}

		err := sendRequest(fmt.Sprintf("https://www.googleapis.com/cloudmonitoring/v2beta2/projects/%s/metricDescriptors", self.project), self.token, request)
		glog.Infof("[GCM] Adding metric %q: %v", metric.Name, err)
		if err != nil {
			return err
		}

		// Add metric to exportedMetrics.
		self.exportedMetrics[metric.Name] = metric
	}

	return nil
}

// GCM request structures for writing time-series data.
type timeseriesDescriptor struct {
	Project string            `json:"project,omitempty"`
	Metric  string            `json:"metric,omitempty"`
	Labels  map[string]string `json:"labels,omitempty"`
}

type point struct {
	Start      time.Time `json:"start,omitempty"`
	End        time.Time `json:"end,omitempty"`
	Int64Value int64     `json:"int64Value"`
}

type timeseries struct {
	TimeseriesDescriptor timeseriesDescriptor `json:"timeseriesDesc,omitempty"`
	Point                point                `json:"point,omitempty"`
}

type metricWriteRequest struct {
	Timeseries []timeseries `json:"timeseries,omitempty"`
}

// The largest number of timeseries we can write to per request.
const maxTimeseriesPerRequest = 200

// Pushes the specified metric values in input. The metrics must already exist.
func (self *gcmSink) StoreTimeseries(input []sink_api.Timeseries) error {
	// Ensure the metrics exist.
	for _, entry := range input {
		metric := entry.Point
		// TODO: Remove this check if possible.
		if _, ok := self.exportedMetrics[metric.Name]; !ok {
			return fmt.Errorf("unable to push unknown metric %q", metric.Name)
		}
	}

	// Build a map of metrics by name.
	metrics := make(map[string][]timeseries)
	for _, entry := range input {
		metric := entry.Point

		// Use full label names.
		labels := make(map[string]string, len(metric.Labels))
		for key, value := range metric.Labels {
			labels[fullLabelName(key)] = value
		}

		// TODO(vmarmol): Validation and cleanup of data.
		// TODO(vmarmol): Handle non-int64 data types. There is an issue with using omitempty since 0 is a valid value for us.
		if _, ok := metric.Value.(int64); !ok {
			return fmt.Errorf("non-int64 data not implemented. Seen for metric %q", metric.Name)
		}
		metrics[metric.Name] = append(metrics[metric.Name], timeseries{
			TimeseriesDescriptor: timeseriesDescriptor{
				Metric: fullMetricName(metric.Name),
				Labels: labels,
			},
			Point: point{
				Start:      metric.Start,
				End:        metric.End,
				Int64Value: metric.Value.(int64),
			},
		})
	}

	// Only send one metric of each type per request.
	var lastErr error
	for len(metrics) != 0 {
		var request metricWriteRequest
		for name, values := range metrics {
			// Remove metrics with no more values.
			if len(values) == 0 {
				delete(metrics, name)
				continue
			}

			m := values[0]
			metrics[name] = values[1:]
			request.Timeseries = append(request.Timeseries, m)
		}

		err := self.pushMetrics(&request)
		if err != nil {
			lastErr = err
		}
	}

	return lastErr
}

func (self *gcmSink) pushMetrics(request *metricWriteRequest) error {
	if len(request.Timeseries) == 0 {
		return nil
	}
	// TODO(vmarmol): Split requests in this case.
	if len(request.Timeseries) > maxTimeseriesPerRequest {
		return fmt.Errorf("unable to write more than %d metrics at once and %d were provided", maxTimeseriesPerRequest, len(request.Timeseries))
	}

	// Refresh token.
	err := self.refreshToken()
	if err != nil {
		return err
	}

	const requestAttempts = 3
	for i := 0; i < requestAttempts; i++ {
		err = sendRequest(fmt.Sprintf("https://www.googleapis.com/cloudmonitoring/v2beta2/projects/%s/timeseries:write", self.project), self.token, request)
		if err != nil {
			glog.Warningf("[GCM] Push attempt %d failed: %v", i, err)
		} else {
			break
		}
	}
	if err != nil {
		prettyRequest, _ := json.MarshalIndent(request, "", "  ")
		glog.Warningf("[GCM] Pushing %d metrics \n%s\n failed: %v", len(request.Timeseries), string(prettyRequest), err)
	} else {
		glog.V(2).Infof("[GCM] Pushing %d metrics: SUCCESS", len(request.Timeseries))
	}
	return err
}

// Domain for the metrics.
const metricDomain = "kubernetes.io"

func fullLabelName(name string) string {
	if !strings.Contains(name, "custom.cloudmonitoring.googleapis.com/") {
		return fmt.Sprintf("custom.cloudmonitoring.googleapis.com/%s/label/%s", metricDomain, name)
	}
	return name
}

func fullMetricName(name string) string {
	if !strings.Contains(name, "custom.cloudmonitoring.googleapis.com/") {
		return fmt.Sprintf("custom.cloudmonitoring.googleapis.com/%s/%s", metricDomain, name)
	}
	return name
}

func sendRequest(url string, token string, request interface{}) error {
	rawRequest, err := json.Marshal(request)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(rawRequest))
	if err != nil {
		return err
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))

	resp, err := (&http.Client{}).Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	out, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		return fmt.Errorf("request to %q failed with status %q and response: %q", url, resp.Status, string(out))
	}

	return nil
}

func (self *gcmSink) DebugInfo() string {
	return "Sink Type: GCM"
}

// Returns a thread-compatible implementation of GCM interactions.
func NewSink() (sink_api.ExternalSink, error) {
	// TODO: Retry OnGCE call for ~15 seconds before declaring failure.
	time.Sleep(3 * time.Second)
	// Only support GCE for now.
	if !metadata.OnGCE() {
		return nil, fmt.Errorf("the GCM sink is currently only supported on GCE")
	}

	// Detect project.
	project, err := metadata.ProjectID()
	if err != nil {
		return nil, err
	}

	// Check required service accounts
	err = checkServiceAccounts()
	if err != nil {
		return nil, err
	}

	impl := &gcmSink{
		project:         project,
		exportedMetrics: make(map[string]sink_api.MetricDescriptor),
	}

	// Get an initial token.
	err = impl.refreshToken()
	if err != nil {
		return nil, err
	}

	return impl, nil
}
<commit_msg>Compute delta for cumulative metrics in GCM<commit_after>// Copyright 2015 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 gcm

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"github.com/GoogleCloudPlatform/gcloud-golang/compute/metadata"
	sink_api "github.com/GoogleCloudPlatform/heapster/sinks/api"
	"github.com/GoogleCloudPlatform/heapster/util/gcstore"
	"github.com/golang/glog"
)

type gcmSink struct {
	// Token to use for authentication.
	token string

	// When the token expires.
	tokenExpiration time.Time

	// TODO(vmarmol): Make this configurable and not only detected.
	// GCE project.
	project string

	// TODO(vmarmol): Also store labels?
	// Map of metrics we currently export.
	exportedMetrics map[string]sink_api.MetricDescriptor

	// The last value we have pushed for every cumulative metric.
	lastValue gcstore.GCStore
}

func (self *gcmSink) refreshToken() error {
	if time.Now().After(self.tokenExpiration) {
		token, err := getToken()
		if err != nil {
			return nil
		}

		// Expire the token a bit early.
		const earlyRefreshSeconds = 60
		if token.ExpiresIn > earlyRefreshSeconds {
			token.ExpiresIn -= earlyRefreshSeconds
		}
		self.token = token.AccessToken
		self.tokenExpiration = time.Now().Add(time.Duration(token.ExpiresIn) * time.Second)
	}
	return nil
}

// GCM request structures for a MetricDescriptor.
type typeDescriptor struct {
	MetricType string `json:"metricType,omitempty"`
	ValueType  string `json:"valueType,omitempty"`
}

type metricDescriptor struct {
	Name           string                     `json:"name,omitempty"`
	Project        string                     `json:"project,omitempty"`
	Description    string                     `json:"description,omitempty"`
	Labels         []sink_api.LabelDescriptor `json:"labels,omitempty"`
	TypeDescriptor typeDescriptor             `json:"typeDescriptor,omitempty"`
}

const maxNumLabels = 10

// Substitutes any generic description with GCM-specific descriptions
func getDescription(metric sink_api.MetricDescriptor) string {
	descriptions := []struct {
		// Metric names for this description.
		name string

		// Description to use
		description string
	}{
		{
			name:        "uptime",
			description: "Rate of change of time since start in milliseconds per second",
		},
		{
			name:        "cpu/usage",
			description: "Rate of total CPU usage in billionths of a core per second",
		},
		{
			name:        "network/rx",
			description: "Rate of bytes received over the network in bytes per second",
		},
		{
			name:        "network/rx_errors",
			description: "Rate of errors sending over the network in errors per second",
		},
		{
			name:        "network/tx",
			description: "Rate of bytes transmitted over the network in bytes per second",
		},
		{
			name:        "network/tx_errors",
			description: "Rate of errors transmitting over the network in errors per second",
		},
	}

	// Replac the description if we have an alternate one.
	for _, desc := range descriptions {
		if metric.Name == desc.name {
			return desc.description
		}
	}

	return metric.Description
}

// Adds the specified metrics or updates them if they already exist.
func (self *gcmSink) Register(metrics []sink_api.MetricDescriptor) error {
	for _, metric := range metrics {
		// Enforce the most labels that GCM allows.
		if len(metric.Labels) > maxNumLabels {
			return fmt.Errorf("metrics cannot have more than %d labels and %q has %d", maxNumLabels, metric.Name, len(metric.Labels))
		}

		// Ensure all labels are in the correct format.
		for i := range metric.Labels {
			metric.Labels[i].Key = fullLabelName(metric.Labels[i].Key)
		}

		request := metricDescriptor{
			Name:        fullMetricName(metric.Name, metric.Type),
			Project:     self.project,
			Description: getDescription(metric),
			Labels:      metric.Labels,
			TypeDescriptor: typeDescriptor{
				MetricType: sink_api.MetricGauge.String(),
				ValueType:  metric.ValueType.String(),
			},
		}

		err := sendRequest(fmt.Sprintf("https://www.googleapis.com/cloudmonitoring/v2beta2/projects/%s/metricDescriptors", self.project), self.token, request)
		glog.Infof("[GCM] Adding metric %q: %v", metric.Name, err)
		if err != nil {
			return err
		}

		// Add metric to exportedMetrics.
		self.exportedMetrics[metric.Name] = metric
	}

	return nil
}

// GCM request structures for writing time-series data.
type timeseriesDescriptor struct {
	Project string            `json:"project,omitempty"`
	Metric  string            `json:"metric,omitempty"`
	Labels  map[string]string `json:"labels,omitempty"`
}

type point struct {
	Start      time.Time `json:"start,omitempty"`
	End        time.Time `json:"end,omitempty"`
	Int64Value int64     `json:"int64Value"`
}

type timeseries struct {
	TimeseriesDescriptor timeseriesDescriptor `json:"timeseriesDesc,omitempty"`
	Point                point                `json:"point,omitempty"`
}

type metricWriteRequest struct {
	Timeseries []timeseries `json:"timeseries,omitempty"`
}

type lastValueKey struct {
	metricName string
	labels     string
}

type lastValueData struct {
	value     int64
	timestamp time.Time
}

// The largest number of timeseries we can write to per request.
const maxTimeseriesPerRequest = 200

// Pushes the specified metric values in input. The metrics must already exist.
func (self *gcmSink) StoreTimeseries(input []sink_api.Timeseries) error {
	// Ensure the metrics exist.
	for _, entry := range input {
		metric := entry.Point
		// TODO: Remove this check if possible.
		if _, ok := self.exportedMetrics[metric.Name]; !ok {
			return fmt.Errorf("unable to push unknown metric %q", metric.Name)
		}
	}

	// Build a map of metrics by name.
	metrics := make(map[string][]timeseries)
	for _, entry := range input {
		metric := entry.Point

		// Use full label names.
		labels := make(map[string]string, len(metric.Labels))
		for key, value := range metric.Labels {
			labels[fullLabelName(key)] = value
		}

		// TODO(vmarmol): Validation and cleanup of data.
		// TODO(vmarmol): Handle non-int64 data types. There is an issue with using omitempty since 0 is a valid value for us.
		value, ok := metric.Value.(int64)
		if !ok {
			return fmt.Errorf("non-int64 data not implemented. Seen for metric %q", metric.Name)
		}
		fullName := fullMetricName(metric.Name, entry.MetricDescriptor.Type)

		// TODO(vmarmol): Stop doing this when GCM supports graphing cumulative metrics.
		// Translate cumulative to gauge by taking the delta over the time period.
		if entry.MetricDescriptor.Type == sink_api.MetricCumulative {
			key := lastValueKey{
				metricName: fullName,
				labels:     sink_api.LabelsToString(labels, ","),
			}
			lastValueRaw := self.lastValue.Get(key)
			self.lastValue.Put(key, lastValueData{
				value:     value,
				timestamp: metric.End,
			})

			// We need two metrics to do a delta, skip first value.
			if lastValueRaw == nil {
				continue
			}
			lastValue, ok := lastValueRaw.(lastValueData)
			if !ok {
				continue
			}

			value = int64(float64(value-lastValue.value) / float64(metric.End.UnixNano()-lastValue.timestamp.UnixNano()) * float64(time.Second))
			metric.Start = metric.End
		}

		metrics[metric.Name] = append(metrics[metric.Name], timeseries{
			TimeseriesDescriptor: timeseriesDescriptor{
				Metric: fullName,
				Labels: labels,
			},
			Point: point{
				Start:      metric.Start,
				End:        metric.End,
				Int64Value: value,
			},
		})
	}

	// Only send one metric of each type per request.
	var lastErr error
	for len(metrics) != 0 {
		var request metricWriteRequest
		for name, values := range metrics {
			// Remove metrics with no more values.
			if len(values) == 0 {
				delete(metrics, name)
				continue
			}

			m := values[0]
			metrics[name] = values[1:]
			request.Timeseries = append(request.Timeseries, m)
		}

		err := self.pushMetrics(&request)
		if err != nil {
			lastErr = err
		}
	}

	return lastErr
}

func (self *gcmSink) pushMetrics(request *metricWriteRequest) error {
	if len(request.Timeseries) == 0 {
		return nil
	}
	// TODO(vmarmol): Split requests in this case.
	if len(request.Timeseries) > maxTimeseriesPerRequest {
		return fmt.Errorf("unable to write more than %d metrics at once and %d were provided", maxTimeseriesPerRequest, len(request.Timeseries))
	}

	// Refresh token.
	err := self.refreshToken()
	if err != nil {
		return err
	}

	const requestAttempts = 3
	for i := 0; i < requestAttempts; i++ {
		err = sendRequest(fmt.Sprintf("https://www.googleapis.com/cloudmonitoring/v2beta2/projects/%s/timeseries:write", self.project), self.token, request)
		if err != nil {
			glog.Warningf("[GCM] Push attempt %d failed: %v", i, err)
		} else {
			break
		}
	}
	if err != nil {
		prettyRequest, _ := json.MarshalIndent(request, "", "  ")
		glog.Warningf("[GCM] Pushing %d metrics \n%s\n failed: %v", len(request.Timeseries), string(prettyRequest), err)
	} else {
		glog.V(2).Infof("[GCM] Pushing %d metrics: SUCCESS", len(request.Timeseries))
	}
	return err
}

// Domain for the metrics.
const metricDomain = "kubernetes.io"

func fullLabelName(name string) string {
	if !strings.Contains(name, "custom.cloudmonitoring.googleapis.com/") {
		return fmt.Sprintf("custom.cloudmonitoring.googleapis.com/%s/label/%s", metricDomain, name)
	}
	return name
}

func fullMetricName(name string, metricType sink_api.MetricType) string {
	// Suffix cumulative metrics with "_delta" since we're changing them to gauges.
	// This will ease the transition to cumulative metrics when those come.
	suffix := ""
	if metricType == sink_api.MetricCumulative {
		suffix = "_delta"
	}

	if !strings.Contains(name, "custom.cloudmonitoring.googleapis.com/") {
		return fmt.Sprintf("custom.cloudmonitoring.googleapis.com/%s/%s%s", metricDomain, name, suffix)
	}
	return name
}

func sendRequest(url string, token string, request interface{}) error {
	rawRequest, err := json.Marshal(request)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(rawRequest))
	if err != nil {
		return err
	}
	req.Header.Add("Content-Type", "application/json")
	req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))

	resp, err := (&http.Client{}).Do(req)
	if err != nil {
		return err
	}

	defer resp.Body.Close()
	out, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode != 200 {
		return fmt.Errorf("request to %q failed with status %q and response: %q", url, resp.Status, string(out))
	}

	return nil
}

func (self *gcmSink) DebugInfo() string {
	return "Sink Type: GCM"
}

// Returns a thread-compatible implementation of GCM interactions.
func NewSink() (sink_api.ExternalSink, error) {
	// TODO: Retry OnGCE call for ~15 seconds before declaring failure.
	time.Sleep(3 * time.Second)
	// Only support GCE for now.
	if !metadata.OnGCE() {
		return nil, fmt.Errorf("the GCM sink is currently only supported on GCE")
	}

	// Detect project.
	project, err := metadata.ProjectID()
	if err != nil {
		return nil, err
	}

	// Check required service accounts
	err = checkServiceAccounts()
	if err != nil {
		return nil, err
	}

	impl := &gcmSink{
		project:         project,
		exportedMetrics: make(map[string]sink_api.MetricDescriptor),
		lastValue:       gcstore.New(time.Hour),
	}

	// Get an initial token.
	err = impl.refreshToken()
	if err != nil {
		return nil, err
	}

	return impl, nil
}
<|endoftext|>


<commit_before>// Copyright 2016 Stratumn SAS. All rights reserved.
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

// Package batchfossilizer implements a fossilizer that fossilize batches of data using a Merkle tree.
// The evidence will contain the Merkle root and path.
package batchfossilizer

// TODO: save pending leaves to file and recover them on start
// TODO: optimize memory allocation

import (
	"log"
	"sync"
	"time"

	"github.com/stratumn/go/fossilizer"
	"github.com/stratumn/goprivate/merkle"
)

const (
	// Name is the name set in the fossilizer's information.
	Name = "batch"

	// Description is the description set in the fossilizer's information.
	Description = "Stratumn Batch Fossilizer"

	// DefaultInterval is the default interval between batches.
	DefaultInterval = time.Minute

	// DefaultMaxLeaves if the default maximum number of leaves of a Merkle tree.
	DefaultMaxLeaves = 32 * 1024
)

// Config contains configuration options for the fossilizer.
type Config struct {
	// A version string that will set in the store's information.
	Version string

	// Interval between batches.
	Interval time.Duration

	// Maximum number of leaves of a Merkle tree.
	MaxLeaves int
}

type batch struct {
	leaves []merkle.Hash
	meta   [][]byte
}

// BatchFossilizer is the type that implements github.com/stratumn/go/fossilizer.Adapter.
type BatchFossilizer struct {
	config      *Config
	resultChans []chan *fossilizer.Result
	leaves      []merkle.Hash
	meta        [][]byte
	mutex       sync.Mutex
	closeChan   chan struct{}
}

// New creates an instance of a BatchFossilizer.
func New(config *Config) *BatchFossilizer {
	maxLeaves := config.MaxLeaves
	if maxLeaves == 0 {
		maxLeaves = DefaultMaxLeaves
	}

	a := &BatchFossilizer{
		config:    config,
		leaves:    make([]merkle.Hash, 0, maxLeaves),
		meta:      make([][]byte, 0, maxLeaves),
		closeChan: make(chan struct{}),
	}

	return a
}

// Start starts the fossilizer.
func (a *BatchFossilizer) Start() {
	interval := a.config.Interval
	if interval == 0 {
		interval = DefaultInterval
	}

	for {
		select {
		case <-time.After(interval):
			a.mutex.Lock()
			if len(a.leaves) > 0 {
				maxLeaves := a.config.MaxLeaves
				if maxLeaves == 0 {
					maxLeaves = DefaultMaxLeaves
				}
				go a.batch(batch{a.leaves, a.meta})
				a.leaves, a.meta = make([]merkle.Hash, 0, maxLeaves), make([][]byte, 0, maxLeaves)
			}
			a.mutex.Unlock()
		case <-a.closeChan:
			return
		}
	}
}

// Stop stops the fossilizer.
func (a *BatchFossilizer) Stop() {
	a.closeChan <- struct{}{}
}

// GetInfo implements github.com/stratumn/go/fossilizer.Adapter.GetInfo.
func (a *BatchFossilizer) GetInfo() (interface{}, error) {
	return map[string]interface{}{
		"name":        Name,
		"description": Description,
		"version":     a.config.Version,
	}, nil
}

// AddResultChan implements github.com/stratumn/go/fossilizer.Adapter.AddResultChan.
func (a *BatchFossilizer) AddResultChan(resultChan chan *fossilizer.Result) {
	a.resultChans = append(a.resultChans, resultChan)
}

// Fossilize implements github.com/stratumn/go/fossilizer.Adapter.Fossilize.
func (a *BatchFossilizer) Fossilize(data []byte, meta []byte) error {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	var leaf merkle.Hash
	copy(leaf[:], data)
	a.leaves = append(a.leaves, leaf)
	a.meta = append(a.meta, meta)

	maxLeaves := a.config.MaxLeaves
	if maxLeaves == 0 {
		maxLeaves = DefaultMaxLeaves
	}
	if len(a.leaves) >= maxLeaves {
		go a.batch(batch{a.leaves, a.meta})
		a.leaves, a.meta = make([]merkle.Hash, 0, maxLeaves), make([][]byte, 0, maxLeaves)
	}

	return nil
}

type evidence struct {
	Time int64       `json:"time"`
	Root merkle.Hash `json:"merkleRoot"`
	Path merkle.Path `json:"merklePath"`
}

type evidenceWrapper struct {
	Evidence evidence `json:"batch"`
}

func (a *BatchFossilizer) batch(b batch) {
	tree, err := merkle.NewStaticTree(b.leaves)

	// TODO: handle error properly
	if err != nil {
		log.Println(err)
		return
	}

	var (
		meta = b.meta
		ts   = time.Now().UTC().Unix()
		root = tree.Root()
	)

	for i := 0; i < tree.NumLeaves(); i++ {
		leaf := tree.Leaf(i)
		r := &fossilizer.Result{
			Evidence: evidenceWrapper{
				evidence{
					Time: ts,
					Root: root,
					Path: tree.Path(i),
				},
			},
			Data: leaf[:],
			Meta: meta[i],
		}

		go func(chans []chan *fossilizer.Result) {
			for _, c := range chans {
				c <- r
			}
		}(a.resultChans)
	}
}
<commit_msg>batchfossilizer: Add batchfossilizer command<commit_after>// Copyright 2016 Stratumn SAS. All rights reserved.
// Use of this source code is governed by the license
// that can be found in the LICENSE file.

// Package batchfossilizer implements a fossilizer that fossilize batches of data using a Merkle tree.
// The evidence will contain the Merkle root, the Merkle path, and a timestamp.
package batchfossilizer

// TODO: save pending leaves to file and recover them on start
// TODO: optimize memory allocation

import (
	"log"
	"sync"
	"time"

	"github.com/stratumn/go/fossilizer"
	"github.com/stratumn/goprivate/merkle"
)

const (
	// Name is the name set in the fossilizer's information.
	Name = "batch"

	// Description is the description set in the fossilizer's information.
	Description = "Stratumn Batch Fossilizer"

	// DefaultInterval is the default interval between batches.
	DefaultInterval = time.Minute

	// DefaultMaxLeaves if the default maximum number of leaves of a Merkle tree.
	DefaultMaxLeaves = 32 * 1024
)

// Config contains configuration options for the fossilizer.
type Config struct {
	// A version string that will set in the store's information.
	Version string

	// Interval between batches.
	Interval time.Duration

	// Maximum number of leaves of a Merkle tree.
	MaxLeaves int
}

type batch struct {
	leaves []merkle.Hash
	meta   [][]byte
}

// BatchFossilizer is the type that implements github.com/stratumn/go/fossilizer.Adapter.
type BatchFossilizer struct {
	config      *Config
	resultChans []chan *fossilizer.Result
	leaves      []merkle.Hash
	meta        [][]byte
	mutex       sync.Mutex
	closeChan   chan struct{}
}

// New creates an instance of a BatchFossilizer.
func New(config *Config) *BatchFossilizer {
	maxLeaves := config.MaxLeaves
	if maxLeaves == 0 {
		maxLeaves = DefaultMaxLeaves
	}

	a := &BatchFossilizer{
		config:    config,
		leaves:    make([]merkle.Hash, 0, maxLeaves),
		meta:      make([][]byte, 0, maxLeaves),
		closeChan: make(chan struct{}),
	}

	return a
}

// Start starts the fossilizer.
func (a *BatchFossilizer) Start() {
	interval := a.config.Interval
	if interval == 0 {
		interval = DefaultInterval
	}

	for {
		select {
		case <-time.After(interval):
			a.mutex.Lock()
			if len(a.leaves) > 0 {
				maxLeaves := a.config.MaxLeaves
				if maxLeaves == 0 {
					maxLeaves = DefaultMaxLeaves
				}
				go a.batch(batch{a.leaves, a.meta})
				a.leaves, a.meta = make([]merkle.Hash, 0, maxLeaves), make([][]byte, 0, maxLeaves)
			}
			a.mutex.Unlock()
		case <-a.closeChan:
			return
		}
	}
}

// Stop stops the fossilizer.
func (a *BatchFossilizer) Stop() {
	a.closeChan <- struct{}{}
}

// GetInfo implements github.com/stratumn/go/fossilizer.Adapter.GetInfo.
func (a *BatchFossilizer) GetInfo() (interface{}, error) {
	return map[string]interface{}{
		"name":        Name,
		"description": Description,
		"version":     a.config.Version,
	}, nil
}

// AddResultChan implements github.com/stratumn/go/fossilizer.Adapter.AddResultChan.
func (a *BatchFossilizer) AddResultChan(resultChan chan *fossilizer.Result) {
	a.resultChans = append(a.resultChans, resultChan)
}

// Fossilize implements github.com/stratumn/go/fossilizer.Adapter.Fossilize.
func (a *BatchFossilizer) Fossilize(data []byte, meta []byte) error {
	a.mutex.Lock()
	defer a.mutex.Unlock()

	var leaf merkle.Hash
	copy(leaf[:], data)
	a.leaves = append(a.leaves, leaf)
	a.meta = append(a.meta, meta)

	maxLeaves := a.config.MaxLeaves
	if maxLeaves == 0 {
		maxLeaves = DefaultMaxLeaves
	}
	if len(a.leaves) >= maxLeaves {
		go a.batch(batch{a.leaves, a.meta})
		a.leaves, a.meta = make([]merkle.Hash, 0, maxLeaves), make([][]byte, 0, maxLeaves)
	}

	return nil
}

type evidence struct {
	Time int64       `json:"time"`
	Root merkle.Hash `json:"merkleRoot"`
	Path merkle.Path `json:"merklePath"`
}

type evidenceWrapper struct {
	Evidence evidence `json:"batch"`
}

func (a *BatchFossilizer) batch(b batch) {
	tree, err := merkle.NewStaticTree(b.leaves)

	// TODO: handle error properly
	if err != nil {
		log.Println(err)
		return
	}

	var (
		meta = b.meta
		ts   = time.Now().UTC().Unix()
		root = tree.Root()
	)

	for i := 0; i < tree.NumLeaves(); i++ {
		leaf := tree.Leaf(i)
		r := &fossilizer.Result{
			Evidence: evidenceWrapper{
				evidence{
					Time: ts,
					Root: root,
					Path: tree.Path(i),
				},
			},
			Data: leaf[:],
			Meta: meta[i],
		}

		go func(chans []chan *fossilizer.Result) {
			for _, c := range chans {
				c <- r
			}
		}(a.resultChans)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"log"
	"path"
	"strings"

	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
)

type Extracter func(string, string, string, []Type)

func Extract(dir string, extracter Extracter) (types []Type) {
	buildPackage, err := build.Import(dir, "", build.ImportComment)
	if err != nil {
		log.Fatalf("[Tygo][Extract] Cannot import package:\n>>>>%v", err)
		return
	}
	fs := token.NewFileSet()
	for _, filename := range buildPackage.GoFiles {
		file, err := parser.ParseFile(fs, path.Join(buildPackage.Dir, filename), nil, parser.ParseComments)
		if err != nil {
			log.Fatalf("[Tygo][Extract] Cannot parse file:\n>>>>%v", err)
		}
		for _, d := range file.Decls {
			decl, ok := d.(*ast.GenDecl)
			if !ok || decl.Tok != token.IMPORT {
				continue
			}
			for _, s := range decl.Specs {
				spec, ok := s.(*ast.ImportSpec)
				if !ok || strings.Trim(spec.Path.Value, "\"") != TYGO_PATH {
					continue
				}
				imports, typePkg := extractPkgs(file)
				var ts []Type
				if strings.TrimSpace(decl.Doc.Text()) != "" {
					ts = Parse(decl.Doc.Text(), imports, typePkg)
					types = append(types, ts...)
				}
				if extracter != nil {
					extracter(dir, filename, file.Name.Name, ts)
				}
			}
		}
	}
	return
}

func extractPkgs(file *ast.File) (map[string]string, map[string][2]string) {
	imports := make(map[string]string)
	typePkg := make(map[string][2]string)
	for _, importSpec := range file.Imports {
		pkg := strings.Trim(importSpec.Path.Value, "\"")
		if importSpec.Name == nil {
			if p, err := build.Import(pkg, "", build.AllowBinary); err != nil {
				log.Fatalf("[Tygo][Inject] Cannot import package:\n>>>>%v", err)
			} else {
				imports[p.Name] = p.ImportPath
			}
		} else if importSpec.Name.Name == "." {
			if doc := packageDoc(pkg); doc != nil {
				for _, t := range doc.Types {
					typePkg[t.Name] = [2]string{doc.Name, pkg}
				}
			}
		} else {
			imports[importSpec.Name.Name] = pkg
		}
	}
	return imports, typePkg
}
<commit_msg>change little<commit_after>// Copyright 2017 ibelie, Chen Jie, Joungtao. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

package tygo

import (
	"log"
	"path"
	"strings"

	"go/ast"
	"go/build"
	"go/parser"
	"go/token"
)

type Extracter func(string, string, string, []Type)

func Extract(dir string, extracter Extracter) (types []Type) {
	buildPackage, err := build.Import(dir, "", build.ImportComment)
	if err != nil {
		log.Fatalf("[Tygo][Extract] Cannot import package:\n>>>> %v", err)
		return
	}
	fs := token.NewFileSet()
	for _, filename := range buildPackage.GoFiles {
		file, err := parser.ParseFile(fs, path.Join(buildPackage.Dir, filename), nil, parser.ParseComments)
		if err != nil {
			log.Fatalf("[Tygo][Extract] Cannot parse file:\n>>>> %v", err)
		}
		for _, d := range file.Decls {
			decl, ok := d.(*ast.GenDecl)
			if !ok || decl.Tok != token.IMPORT {
				continue
			}
			for _, s := range decl.Specs {
				spec, ok := s.(*ast.ImportSpec)
				if !ok || strings.Trim(spec.Path.Value, "\"") != TYGO_PATH {
					continue
				}
				imports, typePkg := extractPkgs(file)
				var ts []Type
				if strings.TrimSpace(decl.Doc.Text()) != "" {
					ts = Parse(decl.Doc.Text(), imports, typePkg)
					types = append(types, ts...)
				}
				if extracter != nil {
					extracter(dir, filename, file.Name.Name, ts)
				}
			}
		}
	}
	return
}

func extractPkgs(file *ast.File) (map[string]string, map[string][2]string) {
	imports := make(map[string]string)
	typePkg := make(map[string][2]string)
	for _, importSpec := range file.Imports {
		pkg := strings.Trim(importSpec.Path.Value, "\"")
		if importSpec.Name == nil {
			if p, err := build.Import(pkg, "", build.AllowBinary); err != nil {
				log.Fatalf("[Tygo][Inject] Cannot import package:\n>>>> %v", err)
			} else {
				imports[p.Name] = p.ImportPath
			}
		} else if importSpec.Name.Name == "." {
			if doc := packageDoc(pkg); doc != nil {
				for _, t := range doc.Types {
					typePkg[t.Name] = [2]string{doc.Name, pkg}
				}
			}
		} else {
			imports[importSpec.Name.Name] = pkg
		}
	}
	return imports, typePkg
}
<|endoftext|>


<commit_before>package inflator

type Inflatable interface {
	Inflate(s string) <-chan string
}

func Start(f func(chan<- string)) <-chan string {
	c := make(chan string, 1)
	go func() {
		defer close(c)
		f(c)
	}()
	return c
}

////////////////////////////////////////////////////////////////////////////
// Dispatch

type dispatcher struct {
	inflatables []Inflatable
}

func Dispatch(v ...Inflatable) Inflatable {
	return &dispatcher{v}
}

func (d *dispatcher) Inflate(s string) <-chan string {
	return Start(func(c chan<- string) {
		for _, n := range d.inflatables {
			for t := range n.Inflate(s) {
				c <- t
			}
		}
	})
}

////////////////////////////////////////////////////////////////////////////
// Join

type joiner struct {
	first, second Inflatable
}

func Join(first, second Inflatable) Inflatable {
	return &joiner{first, second}
}

func (j *joiner) Inflate(s string) <-chan string {
	return Start(func(c chan<- string) {
		for t := range j.first.Inflate(s) {
			for u := range j.second.Inflate(t) {
				c <- u
			}
		}
	})
}

////////////////////////////////////////////////////////////////////////////
// Echo

type echo struct {
}

func Echo() Inflatable {
	return &echo{}
}

func (e *echo) Inflate(s string) <-chan string {
	return Start(func(c chan<- string) {
		c <- s
	})
}
<commit_msg>impl: Filter, Prefix and Suffix<commit_after>package inflator

type Inflatable interface {
	Inflate(s string) <-chan string
}

func Start(f func(chan<- string)) <-chan string {
	c := make(chan string, 1)
	go func() {
		defer close(c)
		f(c)
	}()
	return c
}

////////////////////////////////////////////////////////////////////////////
// Dispatch

type dispatcher struct {
	inflatables []Inflatable
}

func Dispatch(v ...Inflatable) Inflatable {
	return &dispatcher{v}
}

func (d *dispatcher) Inflate(s string) <-chan string {
	return Start(func(c chan<- string) {
		for _, n := range d.inflatables {
			for t := range n.Inflate(s) {
				c <- t
			}
		}
	})
}

////////////////////////////////////////////////////////////////////////////
// Join

type joiner struct {
	first, second Inflatable
}

func Join(first, second Inflatable) Inflatable {
	return &joiner{first, second}
}

func (j *joiner) Inflate(s string) <-chan string {
	return Start(func(c chan<- string) {
		for t := range j.first.Inflate(s) {
			for u := range j.second.Inflate(t) {
				c <- u
			}
		}
	})
}

////////////////////////////////////////////////////////////////////////////
// Echo

type echo struct {
}

func Echo() Inflatable {
	return &echo{}
}

func (e *echo) Inflate(s string) <-chan string {
	return Start(func(c chan<- string) {
		c <- s
	})
}

////////////////////////////////////////////////////////////////////////////
// Filter

type filter struct {
	check func(string) bool
}

func Filter(check func(string) bool) Inflatable {
	return &filter{check}
}

func (f *filter) Inflate(s string) <-chan string {
	return Start(func(c chan<- string) {
		if f.check(s) {
			c <- s
		}
	})
}

////////////////////////////////////////////////////////////////////////////
// Prefix

type prefixer struct {
	prefixes []string
}

func Prefix(prefixes ...string) Inflatable {
	return &prefixer{prefixes}
}

func (p *prefixer) Inflate(s string) <-chan string {
	return Start(func(c chan<- string) {
		for _, t := range p.prefixes {
			c <- t + s
		}
	})
}

////////////////////////////////////////////////////////////////////////////
// Suffix

type suffixer struct {
	suffixes []string
}

func Suffix(suffixes ...string) Inflatable {
	return &suffixer{suffixes}
}

func (p *suffixer) Inflate(s string) <-chan string {
	return Start(func(c chan<- string) {
		for _, t := range p.suffixes {
			c <- s + t
		}
	})
}
<|endoftext|>


<commit_before>package api

import (
	"bytes"
	"encoding/json"
	"net/http"
)

// IPLookupReq used for rescan body
type IPLookupReq struct {
	Address []string `json:"address"`
}

// IPDetails by file_id
func (api *API) IPDetails(ip string) (string, error) {
	req, _ := http.NewRequest("GET", URL+"ip/"+ip, nil)
	req.Header.Add("Authorization", "apikey "+api.Token)
	return fmtResponse(api.Client.Do(req))
}

// IPsDetails by file_ids
func (api *API) IPsDetails(address []string) (string, error) {
	payload := &IPLookupReq{Address: address}
	j, _ := json.Marshal(payload)
	req, _ := http.NewRequest("POST", api.URL+"ip", bytes.NewBuffer(j))
	req.Header.Add("Authorization", "apikey "+api.Token)
	req.Header.Add("content-type", "application/json")
	return fmtResponse(api.Client.Do(req))
}
<commit_msg>fixes iplookup<commit_after>package api

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

// IPLookupReq used for rescan body
type IPLookupReq struct {
	Address []string `json:"address"`
}

// IPDetails by file_id
func (api *API) IPDetails(ip string) (string, error) {
	url := fmt.Sprintf("%s/ip/%s", api.URL, ip)
	req, _ := http.NewRequest("GET", url, nil)
	req.Header.Add("Authorization", "apikey "+api.Token)
	return fmtResponse(api.Client.Do(req))
}

// IPsDetails by file_ids
func (api *API) IPsDetails(address []string) (string, error) {
	url := fmt.Sprintf("%s/ip", api.URL)
	payload := &IPLookupReq{Address: address}
	j, _ := json.Marshal(payload)
	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(j))
	req.Header.Add("Authorization", "apikey "+api.Token)
	req.Header.Add("content-type", "application/json")
	return fmtResponse(api.Client.Do(req))
}
<|endoftext|>


<commit_before>// Copyright (c) Jeevanandam M (https://github.com/jeevatkm)
// go-aah/log source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

package log

import (
	"fmt"
	"os"

	"aahframework.org/config.v0"
)

var std *Logger

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Logger methods
//_______________________________________

// Error logs message as `ERROR`. Arguments handled in the mananer of `fmt.Print`.
func Error(v ...interface{}) {
	std.output(LevelError, 3, nil, v...)
}

// Errorf logs message as `ERROR`. Arguments handled in the mananer of `fmt.Printf`.
func Errorf(format string, v ...interface{}) {
	std.output(LevelError, 3, &format, v...)
}

// Warn logs message as `WARN`. Arguments handled in the mananer of `fmt.Print`.
func Warn(v ...interface{}) {
	std.output(LevelWarn, 3, nil, v...)
}

// Warnf logs message as `WARN`. Arguments handled in the mananer of `fmt.Printf`.
func Warnf(format string, v ...interface{}) {
	std.output(LevelWarn, 3, &format, v...)
}

// Info logs message as `INFO`. Arguments handled in the mananer of `fmt.Print`.
func Info(v ...interface{}) {
	std.output(LevelInfo, 3, nil, v...)
}

// Infof logs message as `INFO`. Arguments handled in the mananer of `fmt.Printf`.
func Infof(format string, v ...interface{}) {
	std.output(LevelInfo, 3, &format, v...)
}

// Debug logs message as `DEBUG`. Arguments handled in the mananer of `fmt.Print`.
func Debug(v ...interface{}) {
	std.output(LevelDebug, 3, nil, v...)
}

// Debugf logs message as `DEBUG`. Arguments handled in the mananer of `fmt.Printf`.
func Debugf(format string, v ...interface{}) {
	std.output(LevelDebug, 3, &format, v...)
}

// Trace logs message as `TRACE`. Arguments handled in the mananer of `fmt.Print`.
func Trace(v ...interface{}) {
	std.output(LevelTrace, 3, nil, v...)
}

// Tracef logs message as `TRACE`. Arguments handled in the mananer of `fmt.Printf`.
func Tracef(format string, v ...interface{}) {
	std.output(LevelTrace, 3, &format, v...)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Logger methods - Drop-in replacement
// for Go standard logger
//_______________________________________

// Print logs message as `INFO`. Arguments handled in the mananer of `fmt.Print`.
func Print(v ...interface{}) {
	std.output(LevelInfo, 3, nil, v...)
}

// Printf logs message as `INFO`. Arguments handled in the mananer of `fmt.Printf`.
func Printf(format string, v ...interface{}) {
	std.output(LevelInfo, 3, &format, v...)
}

// Println logs message as `INFO`. Arguments handled in the mananer of `fmt.Printf`.
func Println(format string, v ...interface{}) {
	std.output(LevelInfo, 3, &format, v...)
}

// Fatal logs message as `FATAL` and call to os.Exit(1).
func Fatal(v ...interface{}) {
	std.output(levelFatal, 3, nil, v...)
	os.Exit(1)
}

// Fatalf logs message as `FATAL` and call to os.Exit(1).
func Fatalf(format string, v ...interface{}) {
	std.output(levelFatal, 3, &format, v...)
	os.Exit(1)
}

// Fatalln logs message as `FATAL` and call to os.Exit(1).
func Fatalln(format string, v ...interface{}) {
	std.output(levelFatal, 3, &format, v...)
	os.Exit(1)
}

// Panic logs message as `PANIC` and call to panic().
func Panic(v ...interface{}) {
	std.output(levelPanic, 3, nil, v...)
	panic("")
}

// Panicf logs message as `PANIC` and call to panic().
func Panicf(format string, v ...interface{}) {
	std.output(levelPanic, 3, &format, v...)
	panic(fmt.Sprintf(format, v...))
}

// Panicln logs message as `PANIC` and call to panic().
func Panicln(format string, v ...interface{}) {
	std.output(levelPanic, 3, &format, v...)
	panic(fmt.Sprintf(format, v...))
}

// SetDefaultLogger method sets the given logger instance as default logger.
func SetDefaultLogger(l *Logger) {
	std = l
}

// SetLevel method sets log level for default logger.
func SetLevel(level string) error {
	return std.SetLevel(level)
}

// SetPattern method sets the log format pattern for default logger.
func SetPattern(pattern string) error {
	return std.SetPattern(pattern)
}

func init() {
	cfg, _ := config.ParseString("log { }")
	std, _ = New(cfg)
}
<commit_msg>buffer empty check method for default logger<commit_after>// Copyright (c) Jeevanandam M (https://github.com/jeevatkm)
// go-aah/log source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.

package log

import (
	"fmt"
	"os"

	"aahframework.org/config.v0"
)

var std *Logger

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Logger methods
//_______________________________________

// Error logs message as `ERROR`. Arguments handled in the mananer of `fmt.Print`.
func Error(v ...interface{}) {
	std.output(LevelError, 3, nil, v...)
}

// Errorf logs message as `ERROR`. Arguments handled in the mananer of `fmt.Printf`.
func Errorf(format string, v ...interface{}) {
	std.output(LevelError, 3, &format, v...)
}

// Warn logs message as `WARN`. Arguments handled in the mananer of `fmt.Print`.
func Warn(v ...interface{}) {
	std.output(LevelWarn, 3, nil, v...)
}

// Warnf logs message as `WARN`. Arguments handled in the mananer of `fmt.Printf`.
func Warnf(format string, v ...interface{}) {
	std.output(LevelWarn, 3, &format, v...)
}

// Info logs message as `INFO`. Arguments handled in the mananer of `fmt.Print`.
func Info(v ...interface{}) {
	std.output(LevelInfo, 3, nil, v...)
}

// Infof logs message as `INFO`. Arguments handled in the mananer of `fmt.Printf`.
func Infof(format string, v ...interface{}) {
	std.output(LevelInfo, 3, &format, v...)
}

// Debug logs message as `DEBUG`. Arguments handled in the mananer of `fmt.Print`.
func Debug(v ...interface{}) {
	std.output(LevelDebug, 3, nil, v...)
}

// Debugf logs message as `DEBUG`. Arguments handled in the mananer of `fmt.Printf`.
func Debugf(format string, v ...interface{}) {
	std.output(LevelDebug, 3, &format, v...)
}

// Trace logs message as `TRACE`. Arguments handled in the mananer of `fmt.Print`.
func Trace(v ...interface{}) {
	std.output(LevelTrace, 3, nil, v...)
}

// Tracef logs message as `TRACE`. Arguments handled in the mananer of `fmt.Printf`.
func Tracef(format string, v ...interface{}) {
	std.output(LevelTrace, 3, &format, v...)
}

//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
// Logger methods - Drop-in replacement
// for Go standard logger
//_______________________________________

// Print logs message as `INFO`. Arguments handled in the mananer of `fmt.Print`.
func Print(v ...interface{}) {
	std.output(LevelInfo, 3, nil, v...)
}

// Printf logs message as `INFO`. Arguments handled in the mananer of `fmt.Printf`.
func Printf(format string, v ...interface{}) {
	std.output(LevelInfo, 3, &format, v...)
}

// Println logs message as `INFO`. Arguments handled in the mananer of `fmt.Printf`.
func Println(format string, v ...interface{}) {
	std.output(LevelInfo, 3, &format, v...)
}

// Fatal logs message as `FATAL` and call to os.Exit(1).
func Fatal(v ...interface{}) {
	std.output(levelFatal, 3, nil, v...)
	os.Exit(1)
}

// Fatalf logs message as `FATAL` and call to os.Exit(1).
func Fatalf(format string, v ...interface{}) {
	std.output(levelFatal, 3, &format, v...)
	os.Exit(1)
}

// Fatalln logs message as `FATAL` and call to os.Exit(1).
func Fatalln(format string, v ...interface{}) {
	std.output(levelFatal, 3, &format, v...)
	os.Exit(1)
}

// Panic logs message as `PANIC` and call to panic().
func Panic(v ...interface{}) {
	std.output(levelPanic, 3, nil, v...)
	panic("")
}

// Panicf logs message as `PANIC` and call to panic().
func Panicf(format string, v ...interface{}) {
	std.output(levelPanic, 3, &format, v...)
	panic(fmt.Sprintf(format, v...))
}

// Panicln logs message as `PANIC` and call to panic().
func Panicln(format string, v ...interface{}) {
	std.output(levelPanic, 3, &format, v...)
	panic(fmt.Sprintf(format, v...))
}

// SetDefaultLogger method sets the given logger instance as default logger.
func SetDefaultLogger(l *Logger) {
	std = l
}

// SetLevel method sets log level for default logger.
func SetLevel(level string) error {
	return std.SetLevel(level)
}

// SetPattern method sets the log format pattern for default logger.
func SetPattern(pattern string) error {
	return std.SetPattern(pattern)
}

// IsBufferEmpty returns true if logger buffer is empty otherwise false.
// This method can be used to ensure all the log entry is written successfully.
func IsBufferEmpty() bool {
	return std.IsBufferEmpty()
}

func init() {
	cfg, _ := config.ParseString("log { }")
	std, _ = New(cfg)
}
<|endoftext|>