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

// +build !noethtool

// The hard work of collecting data from the kernel via the ethtool interfaces is done by
// https://github.com/safchain/ethtool/
// by Sylvain Afchain. Used under the Apache license.

package collector

import (
	"errors"
	"fmt"
	"os"
	"regexp"
	"sort"
	"syscall"

	"github.com/go-kit/log"
	"github.com/go-kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/procfs/sysfs"
	"github.com/safchain/ethtool"
	"golang.org/x/sys/unix"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	ethtoolIgnoredDevices = kingpin.Flag("collector.ethtool.ignored-devices", "Regexp of net devices to ignore for ethtool collector.").Default("^$").String()
	receivedRegex         = regexp.MustCompile(`_rx_`)
	transmittedRegex      = regexp.MustCompile(`_tx_`)
)

type EthtoolStats interface {
	Stats(string) (map[string]uint64, error)
}

type ethtoolStats struct {
}

func (e *ethtoolStats) Stats(intf string) (map[string]uint64, error) {
	return ethtool.Stats(intf)
}

type ethtoolCollector struct {
	fs                    sysfs.FS
	entries               map[string]*prometheus.Desc
	ignoredDevicesPattern *regexp.Regexp
	logger                log.Logger
	stats                 EthtoolStats
}

// makeEthtoolCollector is the internal constructor for EthtoolCollector.
// This allows NewEthtoolTestCollector to override its .stats interface
// for testing.
func makeEthtoolCollector(logger log.Logger) (*ethtoolCollector, error) {
	fs, err := sysfs.NewFS(*sysPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open sysfs: %w", err)
	}

	// Pre-populate some common ethtool metrics.
	return &ethtoolCollector{
		fs:                    fs,
		ignoredDevicesPattern: regexp.MustCompile(*ethtoolIgnoredDevices),
		logger:                logger,
		stats:                 &ethtoolStats{},
		entries: map[string]*prometheus.Desc{
			"rx_bytes": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "received_bytes_total"),
				"Network interface bytes received",
				[]string{"device"}, nil,
			),
			"rx_dropped": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "received_dropped_total"),
				"Number of received frames dropped",
				[]string{"device"}, nil,
			),
			"rx_errors": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "received_errors_total"),
				"Number of received frames with errors",
				[]string{"device"}, nil,
			),
			"rx_packets": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "received_packets_total"),
				"Network interface packets received",
				[]string{"device"}, nil,
			),
			"tx_bytes": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "transmitted_bytes_total"),
				"Network interface bytes sent",
				[]string{"device"}, nil,
			),
			"tx_errors": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "transmitted_errors_total"),
				"Number of sent frames with errors",
				[]string{"device"}, nil,
			),
			"tx_packets": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "transmitted_packets_total"),
				"Network interface packets sent",
				[]string{"device"}, nil,
			),
		},
	}, nil
}

func init() {
	registerCollector("ethtool", defaultDisabled, NewEthtoolCollector)
}

// NewEthtoolCollector returns a new Collector exposing ethtool stats.
func NewEthtoolCollector(logger log.Logger) (Collector, error) {
	return makeEthtoolCollector(logger)
}

func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
	netClass, err := c.fs.NetClass()
	if err != nil {
		if errors.Is(err, os.ErrNotExist) || errors.Is(err, os.ErrPermission) {
			level.Debug(c.logger).Log("msg", "Could not read netclass file", "err", err)
			return ErrNoData
		}
		return fmt.Errorf("could not get net class info: %w", err)
	}

	if len(netClass) == 0 {
		return fmt.Errorf("no network devices found")
	}

	for device := range netClass {
		var stats map[string]uint64
		var err error

		if c.ignoredDevicesPattern.MatchString(device) {
			continue
		}

		stats, err = c.stats.Stats(device)

		// If Stats() returns EOPNOTSUPP it doesn't support ethtool stats. Log that only at Debug level.
		// Otherwise log it at Error level.
		if err != nil {
			if errno, ok := err.(syscall.Errno); ok {
				if err == unix.EOPNOTSUPP {
					level.Debug(c.logger).Log("msg", "ethtool stats error", "err", err, "device", device, "errno", uint(errno))
				} else if errno != 0 {
					level.Error(c.logger).Log("msg", "ethtool stats error", "err", err, "device", device, "errno", uint(errno))
				}
			} else {
				level.Error(c.logger).Log("msg", "ethtool stats error", "err", err, "device", device)
			}
		}

		if stats == nil || len(stats) < 1 {
			// No stats returned; device does not support ethtool stats.
			continue
		}

		// Sort metric names so that the test fixtures will match up
		keys := make([]string, 0, len(stats))
		for k := range stats {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		for _, metric := range keys {
			val := stats[metric]
			metricFQName := prometheus.BuildFQName(namespace, "ethtool", metric)
			metricFQName = receivedRegex.ReplaceAllString(metricFQName, "_received_")
			metricFQName = transmittedRegex.ReplaceAllString(metricFQName, "_transmitted_")

			// Check to see if this metric exists; if not then create it and store it in c.entries.
			entry, exists := c.entries[metric]
			if !exists {
				entry = prometheus.NewDesc(
					metricFQName,
					fmt.Sprintf("Network interface %s", metric),
					[]string{"device"}, nil,
				)
				c.entries[metric] = entry
			}
			ch <- prometheus.MustNewConstMetric(
				entry, prometheus.UntypedValue, float64(val), device)
		}
	}

	return nil
}
<commit_msg>Add collector.ethtool.metrics-include<commit_after>// Copyright 2021 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build !noethtool

// The hard work of collecting data from the kernel via the ethtool interfaces is done by
// https://github.com/safchain/ethtool/
// by Sylvain Afchain. Used under the Apache license.

package collector

import (
	"errors"
	"fmt"
	"os"
	"regexp"
	"sort"
	"syscall"

	"github.com/go-kit/log"
	"github.com/go-kit/log/level"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/procfs/sysfs"
	"github.com/safchain/ethtool"
	"golang.org/x/sys/unix"
	"gopkg.in/alecthomas/kingpin.v2"
)

var (
	ethtoolIgnoredDevices  = kingpin.Flag("collector.ethtool.ignored-devices", "Regexp of net devices to ignore for ethtool collector.").Default("^$").String()
	ethtoolIncludedMetrics = kingpin.Flag("collector.ethtool.metrics-include", "Regexp of ethtool stats to include.").Default(".*").String()
	receivedRegex          = regexp.MustCompile(`_rx_`)
	transmittedRegex       = regexp.MustCompile(`_tx_`)
)

type EthtoolStats interface {
	Stats(string) (map[string]uint64, error)
}

type ethtoolStats struct {
}

func (e *ethtoolStats) Stats(intf string) (map[string]uint64, error) {
	return ethtool.Stats(intf)
}

type ethtoolCollector struct {
	fs                    sysfs.FS
	entries               map[string]*prometheus.Desc
	ignoredDevicesPattern *regexp.Regexp
	metricsPattern        *regexp.Regexp
	logger                log.Logger
	stats                 EthtoolStats
}

// makeEthtoolCollector is the internal constructor for EthtoolCollector.
// This allows NewEthtoolTestCollector to override its .stats interface
// for testing.
func makeEthtoolCollector(logger log.Logger) (*ethtoolCollector, error) {
	fs, err := sysfs.NewFS(*sysPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open sysfs: %w", err)
	}

	// Pre-populate some common ethtool metrics.
	return &ethtoolCollector{
		fs:                    fs,
		ignoredDevicesPattern: regexp.MustCompile(*ethtoolIgnoredDevices),
		metricsPattern:        regexp.MustCompile(*ethtoolIncludedMetrics),
		logger:                logger,
		stats:                 &ethtoolStats{},
		entries: map[string]*prometheus.Desc{
			"rx_bytes": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "received_bytes_total"),
				"Network interface bytes received",
				[]string{"device"}, nil,
			),
			"rx_dropped": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "received_dropped_total"),
				"Number of received frames dropped",
				[]string{"device"}, nil,
			),
			"rx_errors": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "received_errors_total"),
				"Number of received frames with errors",
				[]string{"device"}, nil,
			),
			"rx_packets": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "received_packets_total"),
				"Network interface packets received",
				[]string{"device"}, nil,
			),
			"tx_bytes": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "transmitted_bytes_total"),
				"Network interface bytes sent",
				[]string{"device"}, nil,
			),
			"tx_errors": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "transmitted_errors_total"),
				"Number of sent frames with errors",
				[]string{"device"}, nil,
			),
			"tx_packets": prometheus.NewDesc(
				prometheus.BuildFQName(namespace, "ethtool", "transmitted_packets_total"),
				"Network interface packets sent",
				[]string{"device"}, nil,
			),
		},
	}, nil
}

func init() {
	registerCollector("ethtool", defaultDisabled, NewEthtoolCollector)
}

// NewEthtoolCollector returns a new Collector exposing ethtool stats.
func NewEthtoolCollector(logger log.Logger) (Collector, error) {
	return makeEthtoolCollector(logger)
}

func (c *ethtoolCollector) Update(ch chan<- prometheus.Metric) error {
	netClass, err := c.fs.NetClass()
	if err != nil {
		if errors.Is(err, os.ErrNotExist) || errors.Is(err, os.ErrPermission) {
			level.Debug(c.logger).Log("msg", "Could not read netclass file", "err", err)
			return ErrNoData
		}
		return fmt.Errorf("could not get net class info: %w", err)
	}

	if len(netClass) == 0 {
		return fmt.Errorf("no network devices found")
	}

	for device := range netClass {
		var stats map[string]uint64
		var err error

		if c.ignoredDevicesPattern.MatchString(device) {
			continue
		}

		stats, err = c.stats.Stats(device)

		// If Stats() returns EOPNOTSUPP it doesn't support ethtool stats. Log that only at Debug level.
		// Otherwise log it at Error level.
		if err != nil {
			if errno, ok := err.(syscall.Errno); ok {
				if err == unix.EOPNOTSUPP {
					level.Debug(c.logger).Log("msg", "ethtool stats error", "err", err, "device", device, "errno", uint(errno))
				} else if errno != 0 {
					level.Error(c.logger).Log("msg", "ethtool stats error", "err", err, "device", device, "errno", uint(errno))
				}
			} else {
				level.Error(c.logger).Log("msg", "ethtool stats error", "err", err, "device", device)
			}
		}

		if stats == nil || len(stats) < 1 {
			// No stats returned; device does not support ethtool stats.
			continue
		}

		// Sort metric names so that the test fixtures will match up
		keys := make([]string, 0, len(stats))
		for k := range stats {
			keys = append(keys, k)
		}
		sort.Strings(keys)

		for _, metric := range keys {
			if !c.metricsPattern.MatchString(metric) {
				continue
			}
			val := stats[metric]
			metricFQName := prometheus.BuildFQName(namespace, "ethtool", metric)
			metricFQName = receivedRegex.ReplaceAllString(metricFQName, "_received_")
			metricFQName = transmittedRegex.ReplaceAllString(metricFQName, "_transmitted_")

			// Check to see if this metric exists; if not then create it and store it in c.entries.
			entry, exists := c.entries[metric]
			if !exists {
				entry = prometheus.NewDesc(
					metricFQName,
					fmt.Sprintf("Network interface %s", metric),
					[]string{"device"}, nil,
				)
				c.entries[metric] = entry
			}
			ch <- prometheus.MustNewConstMetric(
				entry, prometheus.UntypedValue, float64(val), device)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package commands

import (
	"github.com/github/git-media/gitmedia"
	"github.com/github/git-media/scanner"
	"github.com/spf13/cobra"
)

var (
	statusCmd = &cobra.Command{
		Use:   "status",
		Short: "Show information about git media files that would be pushed",
		Run:   statusCommand,
	}
)

func statusCommand(cmd *cobra.Command, args []string) {
	ref, err := gitmedia.CurrentRef()
	if err != nil {
		Panic(err, "Could not ls-files")
	}

	pointers, err := scanner.Scan(ref, "^origin/HEAD")
	if err != nil {
		Panic(err, "Could not scan for git media files")
	}

	for _, p := range pointers {
		Print(p.Name)
	}
}

func init() {
	RootCmd.AddCommand(statusCmd)
}
<commit_msg>ララララー ラララー ララ<commit_after>package commands

import (
	"github.com/github/git-media/gitmedia"
	"github.com/github/git-media/scanner"
	"github.com/spf13/cobra"
)

var (
	statusCmd = &cobra.Command{
		Use:   "status",
		Short: "Show information about git media files that would be pushed",
		Run:   statusCommand,
	}
)

func statusCommand(cmd *cobra.Command, args []string) {
	ref, err := gitmedia.CurrentRef()
	if err != nil {
		Panic(err, "Could not calculate status")
	}

	pointers, err := scanner.Scan(ref, "^origin/HEAD")
	if err != nil {
		Panic(err, "Could not scan for git media files")
	}

	for _, p := range pointers {
		Print(p.Name)
	}
}

func init() {
	RootCmd.AddCommand(statusCmd)
}
<|endoftext|>


<commit_before>package logutils

import (
	"fmt"
	"os"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/facebookgo/stack"
)

const TIME_FORMAT = "2006-01-02 15:04:05"

func SetGlobalLogger(logger *logrus.Logger) {
	logrus.SetFormatter(logger.Formatter)
}

type StandardFormatter struct {
	Name string
}

func NewStandardLogger(name string) *logrus.Logger {
	logger := &logrus.Logger{
		Out:       os.Stderr,
		Formatter: &StandardFormatter{Name: name},
		Hooks:     make(logrus.LevelHooks),
		Level:     logrus.GetLevel(),
	}

	return logger
}

func (this *StandardFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	time := entry.Time.Format(TIME_FORMAT)
	level := strings.ToUpper(entry.Level.String())
	if level == "WARNING" {
		level = "WARN"
	}

	content := fmt.Sprintf("%v [%s] %-5s: %s\n", time, this.Name, level, entry.Message)
	return []byte(content), nil
}

type CLIFormatter struct{}

func (c *CLIFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	level := strings.ToUpper(entry.Level.String())
	content := fmt.Sprintf("[%s] %s\n", level, entry.Message)
	return []byte(content), nil
}

type StackTraceFormatter struct {
	*StandardFormatter
}

func NewStackTraceLogger(name string) *logrus.Logger {
	logger := NewStandardLogger(name)
	logger.Formatter = &StackTraceFormatter{logger.Formatter.(*StandardFormatter)}

	return logger
}

func (this *StackTraceFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	// logrus levels go backwards: Panic=0, Debug=5
	if entry.Level > logrus.ErrorLevel || logrus.GetLevel() != logrus.DebugLevel {
		return this.StandardFormatter.Format(entry)
	}

	content, err := this.StandardFormatter.Format(entry)
	if err != nil {
		return nil, err
	}

	// find the first caller that isn't in the logrus package
	var skip int
	for i, caller := range stack.Callers(1) {
		if !strings.Contains(caller.File, "/Sirupsen/logrus/") {
			skip = i + 1
			break
		}
	}

	trace := fmt.Sprintf("%s\n", stack.Callers(skip))
	content = append(content, []byte(trace)...)

	return content, nil
}

type SilentLogger struct{}

func (SilentLogger) Print(v ...interface{})                 {}
func (SilentLogger) Printf(format string, v ...interface{}) {}
<commit_msg>Add compatibility with 'tftest.Logger'<commit_after>package logutils

import (
	"fmt"
	"os"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/facebookgo/stack"
)

const TIME_FORMAT = "2006-01-02 15:04:05"

func SetGlobalLogger(logger *logrus.Logger) {
	logrus.SetFormatter(logger.Formatter)
}

type StandardFormatter struct {
	Name string
}

func (this *StandardFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	time := entry.Time.Format(TIME_FORMAT)
	level := strings.ToUpper(entry.Level.String())
	if level == "WARNING" {
		level = "WARN"
	}

	content := fmt.Sprintf("%v [%s] %-5s: %s\n", time, this.Name, level, entry.Message)
	return []byte(content), nil
}

type StandardLogger struct {
	*logrus.Logger
}

func NewStandardLogger(name string) *StandardLogger {
	return &StandardLogger{
		&logrus.Logger{
			Out:       os.Stderr,
			Formatter: &StandardFormatter{Name: name},
			Hooks:     make(logrus.LevelHooks),
			Level:     logrus.GetLevel(),
		},
	}
}

func (s *StandardLogger) Log(tokens ...interface{}) {
	s.Logger.Info(tokens...)
}

func (s *StandardLogger) Logf(format string, tokens ...interface{}) {
	s.Logger.Infof(format, tokens...)
}

type CLIFormatter struct{}

func (c *CLIFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	level := strings.ToUpper(entry.Level.String())
	content := fmt.Sprintf("[%s] %s\n", level, entry.Message)
	return []byte(content), nil
}

type StackTraceFormatter struct {
	*StandardFormatter
}

func NewStackTraceLogger(name string) *logrus.Logger {
	logger := NewStandardLogger(name)
	logger.Formatter = &StackTraceFormatter{logger.Formatter.(*StandardFormatter)}

	return logger.Logger
}

func (this *StackTraceFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	// logrus levels go backwards: Panic=0, Debug=5
	if entry.Level > logrus.ErrorLevel || logrus.GetLevel() != logrus.DebugLevel {
		return this.StandardFormatter.Format(entry)
	}

	content, err := this.StandardFormatter.Format(entry)
	if err != nil {
		return nil, err
	}

	// find the first caller that isn't in the logrus package
	var skip int
	for i, caller := range stack.Callers(1) {
		if !strings.Contains(caller.File, "/Sirupsen/logrus/") {
			skip = i + 1
			break
		}
	}

	trace := fmt.Sprintf("%s\n", stack.Callers(skip))
	content = append(content, []byte(trace)...)

	return content, nil
}

type SilentLogger struct{}

func (SilentLogger) Print(v ...interface{})                 {}
func (SilentLogger) Printf(format string, v ...interface{}) {}
<|endoftext|>


<commit_before>// Copyright 2021 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.

// Provides integration tests for file operations with implicit_dir flag set.
package implicitdir_test

import (
	"io"
	"os"
	"path"
	"testing"
	"time"
)

func TestRenameFile(t *testing.T) {
	fileName := createTempFile()
	err := clearKernelCache()
	if err != nil {
		t.Errorf("Clear Kernel Cache: %v", err)
	}
	content, err := os.ReadFile(fileName)
	if err != nil {
		t.Errorf("Read: %v", err)
	}
	newFileName := fileName + "Rename"
	if _, err := os.Stat(newFileName); err == nil {
		t.Errorf("Renamed file %s already present", newFileName)
	}

	if err := os.Rename(fileName, newFileName); err != nil {
		t.Errorf("Rename unsuccessful: %v", err)
	}

	if _, err := os.Stat(fileName); err == nil {
		t.Errorf("Original file %s still exists", fileName)
	}
	if _, err := os.Stat(newFileName); err != nil {
		t.Errorf("Renamed file %s not found", newFileName)
	}
	// Check if the data in the file is the same after renaming.
	compareFileContents(t, newFileName, string(content))
}

func TestFileAttributes(t *testing.T) {
	preCreateTime := time.Now()
	fileName := createTempFile()
	postCreateTime := time.Now()

	fStat, err := os.Stat(fileName)

	if err != nil {
		t.Errorf("os.Stat error: %s, %v", fileName, err)
	}
	statFileName := path.Join(tmpDir, fStat.Name())
	if fileName != statFileName {
		t.Errorf("File name not matched in os.Stat, found: %s, expected: %s", statFileName, fileName)
	}
	if (preCreateTime.After(fStat.ModTime())) || (postCreateTime.Before(fStat.ModTime())) {
		t.Errorf("File modification time not in the expected time-range")
	}
	// The file size in createTempFile() is 14 bytes
	if fStat.Size() != 14 {
		t.Errorf("File size is not 14 bytes, found size: %d bytes", fStat.Size())
	}
}

func TestCopyFile(t *testing.T) {
	fileName := createTempFile()
	err := clearKernelCache()
	if err != nil {
		t.Errorf("Clear Kernel Cache: %v", err)
	}
	content, err := os.ReadFile(fileName)
	if err != nil {
		t.Errorf("Read: %v", err)
	}
	newFileName := fileName + "Copy"
	if _, err := os.Stat(newFileName); err == nil {
		t.Errorf("Copied file %s already present", newFileName)
	}

	// File copying with io.Copy() utility.
	source, err := os.Open(fileName)
	if err != nil {
		t.Errorf("File %s opening error: %v", fileName, err)
	}
	defer source.Close()
	destination, err := os.Create(newFileName)
	if err != nil {
		t.Errorf("Copied file creation error: %v", err)
	}
	defer destination.Close()
	_, err = io.Copy(destination, source)
	if err != nil {
		t.Errorf("Error in file copying: %v", err)
	}

	// Checks on old and new file.
	if _, err := os.Stat(fileName); os.IsExist(err) {
		t.Errorf("Old file %s not found", fileName)
	}
	if _, err := os.Stat(newFileName); os.IsNotExist(err) {
		t.Errorf("Copied file %s not found", newFileName)
	}
	// Check if the data in the copied file matches the original file.
	compareFileContents(t, newFileName, string(content))
}
<commit_msg>Minor fixes in file_operations_test<commit_after>// Copyright 2021 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.

// Provides integration tests for file operations with implicit_dir flag set.
package implicitdir_test

import (
	"io"
	"os"
	"path"
	"testing"
	"time"
)

func TestRenameFile(t *testing.T) {
	fileName := createTempFile()
	err := clearKernelCache()
	if err != nil {
		t.Errorf("Clear Kernel Cache: %v", err)
	}
	content, err := os.ReadFile(fileName)
	if err != nil {
		t.Errorf("Read: %v", err)
	}
	newFileName := fileName + "Rename"
	if _, err := os.Stat(newFileName); err == nil {
		t.Errorf("Renamed file %s already present", newFileName)
	}

	if err := os.Rename(fileName, newFileName); err != nil {
		t.Errorf("Rename unsuccessful: %v", err)
	}

	if _, err := os.Stat(fileName); err == nil {
		t.Errorf("Original file %s still exists", fileName)
	}
	if _, err := os.Stat(newFileName); err != nil {
		t.Errorf("Renamed file %s not found", newFileName)
	}
	// Check if the data in the file is the same after renaming.
	compareFileContents(t, newFileName, string(content))
}

func TestFileAttributes(t *testing.T) {
	preCreateTime := time.Now()
	fileName := createTempFile()
	postCreateTime := time.Now()

	fStat, err := os.Stat(fileName)

	if err != nil {
		t.Errorf("os.Stat error: %s, %v", fileName, err)
	}
	statFileName := path.Join(tmpDir, fStat.Name())
	if fileName != statFileName {
		t.Errorf("File name not matched in os.Stat, found: %s, expected: %s", statFileName, fileName)
	}
	if (preCreateTime.After(fStat.ModTime())) || (postCreateTime.Before(fStat.ModTime())) {
		t.Errorf("File modification time not in the expected time-range")
	}
	// The file size in createTempFile() is 14 bytes
	if fStat.Size() != 14 {
		t.Errorf("File size is not 14 bytes, found size: %d bytes", fStat.Size())
	}
}

func TestCopyFile(t *testing.T) {
	fileName := createTempFile()
	err := clearKernelCache()
	if err != nil {
		t.Errorf("Clear Kernel Cache: %v", err)
	}
	content, err := os.ReadFile(fileName)
	if err != nil {
		t.Errorf("Read: %v", err)
	}
	newFileName := fileName + "Copy"
	if _, err := os.Stat(newFileName); err == nil {
		t.Errorf("Copied file %s already present", newFileName)
	}

	// File copying with io.Copy() utility.
	source, err := os.Open(fileName)
	if err != nil {
		t.Errorf("File %s opening error: %v", fileName, err)
	}
	defer source.Close()
	destination, err := os.Create(newFileName)
	if err != nil {
		t.Errorf("Copied file creation error: %v", err)
	}
	defer destination.Close()
	_, err = io.Copy(destination, source)
	if err != nil {
		t.Errorf("Error in file copying: %v", err)
	}

	// Check if the data in the copied file matches the original file,
	// and the data in original file is unchanged.
	compareFileContents(t, newFileName, string(content))
	compareFileContents(t, fileName, string(content))
}
<|endoftext|>


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

package test

import (
	"math/rand"
	"reflect"
	"testing"
	"time"

	"github.com/google/cadvisor/info"
	"github.com/google/cadvisor/storage"
)

func buildTrace(cpu, mem []uint64, duration time.Duration) []*info.ContainerStats {
	if len(cpu) != len(mem) {
		panic("len(cpu) != len(mem)")
	}

	ret := make([]*info.ContainerStats, len(cpu))
	currentTime := time.Now()

	var cpuTotalUsage uint64 = 0
	for i, cpuUsage := range cpu {
		cpuTotalUsage += cpuUsage
		stats := new(info.ContainerStats)
		stats.Cpu = new(info.CpuStats)
		stats.Memory = new(info.MemoryStats)
		stats.Timestamp = currentTime
		currentTime = currentTime.Add(duration)

		stats.Cpu.Usage.Total = cpuTotalUsage
		stats.Cpu.Usage.User = stats.Cpu.Usage.Total
		stats.Cpu.Usage.System = 0

		stats.Memory.Usage = mem[i]

		ret[i] = stats
	}
	return ret
}

// The underlying driver must be able to hold more than 10 samples.
func StorageDriverTestSampleCpuUsage(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 10
	cpuTrace := make([]uint64, 0, N)
	memTrace := make([]uint64, 0, N)

	// We need N+1 observations to get N samples
	for i := 0; i < N+1; i++ {
		cpuTrace = append(cpuTrace, uint64(rand.Intn(1000)))
		memTrace = append(memTrace, uint64(rand.Intn(1000)))
	}

	samplePeriod := 1 * time.Second

	ref := info.ContainerReference{
		Name: "container",
	}

	trace := buildTrace(cpuTrace, memTrace, samplePeriod)

	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}

	samples, err := driver.Samples(ref.Name, N)
	if err != nil {
		t.Errorf("unable to sample stats: %v", err)
	}
	for _, sample := range samples {
		if sample.Duration != samplePeriod {
			t.Errorf("sample duration is %v, not %v", sample.Duration, samplePeriod)
		}
		cpuUsage := sample.Cpu.Usage
		found := false
		for _, u := range cpuTrace {
			if u == cpuUsage {
				found = true
			}
		}
		if !found {
			t.Errorf("unable to find cpu usage %v", cpuUsage)
		}
	}
}

func StorageDriverTestMaxMemoryUsage(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 100
	memTrace := make([]uint64, N)
	cpuTrace := make([]uint64, N)
	for i := 0; i < N; i++ {
		memTrace[i] = uint64(i + 1)
		cpuTrace[i] = uint64(1)
	}

	ref := info.ContainerReference{
		Name: "container",
	}

	trace := buildTrace(cpuTrace, memTrace, 1*time.Second)

	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}

	percentiles, err := driver.Percentiles(ref.Name, []int{50}, []int{50})
	if err != nil {
		t.Errorf("unable to call Percentiles(): %v", err)
	}
	maxUsage := uint64(N)
	if percentiles.MaxMemoryUsage != maxUsage {
		t.Fatalf("Max memory usage should be %v; received %v", maxUsage, percentiles.MaxMemoryUsage)
	}
}

func StorageDriverTestSamplesWithoutSample(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	trace := buildTrace(
		[]uint64{10},
		[]uint64{10},
		1*time.Second)
	ref := info.ContainerReference{
		Name: "container",
	}
	driver.AddStats(ref, trace[0])
	samples, err := driver.Samples(ref.Name, -1)
	if err != nil {
		t.Fatal(err)
	}
	if len(samples) != 0 {
		t.Errorf("There should be no sample")
	}
}

func StorageDriverTestPercentilesWithoutSample(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	trace := buildTrace(
		[]uint64{10},
		[]uint64{10},
		1*time.Second)
	ref := info.ContainerReference{
		Name: "container",
	}
	driver.AddStats(ref, trace[0])
	percentiles, err := driver.Percentiles(
		ref.Name,
		[]int{50},
		[]int{50},
	)
	if err != nil {
		t.Fatal(err)
	}
	if percentiles != nil {
		t.Errorf("There should be no percentiles")
	}
}

// The driver must be able to hold more than 100 samples
func StorageDriverTestPercentiles(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 100
	cpuTrace := make([]uint64, N)
	memTrace := make([]uint64, N)
	for i := 1; i < N+1; i++ {
		cpuTrace[i-1] = uint64(i)
		memTrace[i-1] = uint64(i)
	}

	trace := buildTrace(cpuTrace, memTrace, 1*time.Second)

	ref := info.ContainerReference{
		Name: "container",
	}
	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}
	percentages := []int{
		80,
		90,
		50,
	}
	percentiles, err := driver.Percentiles(ref.Name, percentages, percentages)
	if err != nil {
		t.Fatal(err)
	}
	for _, s := range percentiles.CpuUsagePercentiles {
		// The value is out of the range of tolerance..
		if s.Value > uint64(s.Percentage+1) || s.Value < uint64(s.Percentage-1) {
			t.Errorf("%v percentile data should be %v, but got %v", s.Percentage, s.Percentage, s.Value)
		}
	}
	for _, s := range percentiles.MemoryUsagePercentiles {
		// The value is out of the range of tolerance..
		if s.Value > uint64(s.Percentage+1) || s.Value < uint64(s.Percentage-1) {
			t.Errorf("%v percentile data should be %v, but got %v", s.Percentage, s.Percentage, s.Value)
		}
	}
}

// The driver must be albe to hold more than 10 stats
func StorageDriverTestRetrievePartialRecentStats(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 100
	memTrace := make([]uint64, N)
	cpuTrace := make([]uint64, N)
	for i := 0; i < N; i++ {
		memTrace[i] = uint64(i + 1)
		cpuTrace[i] = uint64(1)
	}

	ref := info.ContainerReference{
		Name: "container",
	}

	trace := buildTrace(cpuTrace, memTrace, 1*time.Second)

	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}

	recentStats, err := driver.RecentStats(ref.Name, 10)
	if err != nil {
		t.Fatal(err)
	}

	if len(recentStats) != 10 {
		t.Fatalf("returned %v stats, not 10.", len(recentStats))
	}

	for _, r := range recentStats {
		found := false
		for _, s := range trace[len(trace)-10:] {
			if reflect.DeepEqual(s, r) {
				found = true
			}
		}
		if !found {
			t.Errorf("returned unexpected stats: %+v; %v", r, r.Memory.Usage)
		}
	}
}

// The driver must be albe to hold more than 10 stats
func StorageDriverTestRetrieveAllRecentStats(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 100
	memTrace := make([]uint64, N)
	cpuTrace := make([]uint64, N)
	for i := 0; i < N; i++ {
		memTrace[i] = uint64(i + 1)
		cpuTrace[i] = uint64(1)
	}

	ref := info.ContainerReference{
		Name: "container",
	}

	trace := buildTrace(cpuTrace, memTrace, 1*time.Second)

	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}

	recentStats, err := driver.RecentStats(ref.Name, -1)
	if err != nil {
		t.Fatal(err)
	}

	for _, r := range recentStats {
		found := false
		for _, s := range trace {
			if reflect.DeepEqual(s, r) {
				found = true
			}
		}
		if !found {
			t.Errorf("returned unexpected stats: %+v; %v", r, r.Memory.Usage)
		}
	}
}
<commit_msg>defines the order of the returned recent stats<commit_after>// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package test

import (
	"math/rand"
	"reflect"
	"testing"
	"time"

	"github.com/google/cadvisor/info"
	"github.com/google/cadvisor/storage"
)

func buildTrace(cpu, mem []uint64, duration time.Duration) []*info.ContainerStats {
	if len(cpu) != len(mem) {
		panic("len(cpu) != len(mem)")
	}

	ret := make([]*info.ContainerStats, len(cpu))
	currentTime := time.Now()

	var cpuTotalUsage uint64 = 0
	for i, cpuUsage := range cpu {
		cpuTotalUsage += cpuUsage
		stats := new(info.ContainerStats)
		stats.Cpu = new(info.CpuStats)
		stats.Memory = new(info.MemoryStats)
		stats.Timestamp = currentTime
		currentTime = currentTime.Add(duration)

		stats.Cpu.Usage.Total = cpuTotalUsage
		stats.Cpu.Usage.User = stats.Cpu.Usage.Total
		stats.Cpu.Usage.System = 0

		stats.Memory.Usage = mem[i]

		ret[i] = stats
	}
	return ret
}

// The underlying driver must be able to hold more than 10 samples.
func StorageDriverTestSampleCpuUsage(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 10
	cpuTrace := make([]uint64, 0, N)
	memTrace := make([]uint64, 0, N)

	// We need N+1 observations to get N samples
	for i := 0; i < N+1; i++ {
		cpuTrace = append(cpuTrace, uint64(rand.Intn(1000)))
		memTrace = append(memTrace, uint64(rand.Intn(1000)))
	}

	samplePeriod := 1 * time.Second

	ref := info.ContainerReference{
		Name: "container",
	}

	trace := buildTrace(cpuTrace, memTrace, samplePeriod)

	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}

	samples, err := driver.Samples(ref.Name, N)
	if err != nil {
		t.Errorf("unable to sample stats: %v", err)
	}
	for _, sample := range samples {
		if sample.Duration != samplePeriod {
			t.Errorf("sample duration is %v, not %v", sample.Duration, samplePeriod)
		}
		cpuUsage := sample.Cpu.Usage
		found := false
		for _, u := range cpuTrace {
			if u == cpuUsage {
				found = true
			}
		}
		if !found {
			t.Errorf("unable to find cpu usage %v", cpuUsage)
		}
	}
}

func StorageDriverTestMaxMemoryUsage(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 100
	memTrace := make([]uint64, N)
	cpuTrace := make([]uint64, N)
	for i := 0; i < N; i++ {
		memTrace[i] = uint64(i + 1)
		cpuTrace[i] = uint64(1)
	}

	ref := info.ContainerReference{
		Name: "container",
	}

	trace := buildTrace(cpuTrace, memTrace, 1*time.Second)

	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}

	percentiles, err := driver.Percentiles(ref.Name, []int{50}, []int{50})
	if err != nil {
		t.Errorf("unable to call Percentiles(): %v", err)
	}
	maxUsage := uint64(N)
	if percentiles.MaxMemoryUsage != maxUsage {
		t.Fatalf("Max memory usage should be %v; received %v", maxUsage, percentiles.MaxMemoryUsage)
	}
}

func StorageDriverTestSamplesWithoutSample(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	trace := buildTrace(
		[]uint64{10},
		[]uint64{10},
		1*time.Second)
	ref := info.ContainerReference{
		Name: "container",
	}
	driver.AddStats(ref, trace[0])
	samples, err := driver.Samples(ref.Name, -1)
	if err != nil {
		t.Fatal(err)
	}
	if len(samples) != 0 {
		t.Errorf("There should be no sample")
	}
}

func StorageDriverTestPercentilesWithoutSample(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	trace := buildTrace(
		[]uint64{10},
		[]uint64{10},
		1*time.Second)
	ref := info.ContainerReference{
		Name: "container",
	}
	driver.AddStats(ref, trace[0])
	percentiles, err := driver.Percentiles(
		ref.Name,
		[]int{50},
		[]int{50},
	)
	if err != nil {
		t.Fatal(err)
	}
	if percentiles != nil {
		t.Errorf("There should be no percentiles")
	}
}

// The driver must be able to hold more than 100 samples
func StorageDriverTestPercentiles(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 100
	cpuTrace := make([]uint64, N)
	memTrace := make([]uint64, N)
	for i := 1; i < N+1; i++ {
		cpuTrace[i-1] = uint64(i)
		memTrace[i-1] = uint64(i)
	}

	trace := buildTrace(cpuTrace, memTrace, 1*time.Second)

	ref := info.ContainerReference{
		Name: "container",
	}
	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}
	percentages := []int{
		80,
		90,
		50,
	}
	percentiles, err := driver.Percentiles(ref.Name, percentages, percentages)
	if err != nil {
		t.Fatal(err)
	}
	for _, s := range percentiles.CpuUsagePercentiles {
		// The value is out of the range of tolerance..
		if s.Value > uint64(s.Percentage+1) || s.Value < uint64(s.Percentage-1) {
			t.Errorf("%v percentile data should be %v, but got %v", s.Percentage, s.Percentage, s.Value)
		}
	}
	for _, s := range percentiles.MemoryUsagePercentiles {
		// The value is out of the range of tolerance..
		if s.Value > uint64(s.Percentage+1) || s.Value < uint64(s.Percentage-1) {
			t.Errorf("%v percentile data should be %v, but got %v", s.Percentage, s.Percentage, s.Value)
		}
	}
}

// The driver must be albe to hold more than 10 stats
func StorageDriverTestRetrievePartialRecentStats(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 100
	memTrace := make([]uint64, N)
	cpuTrace := make([]uint64, N)
	for i := 0; i < N; i++ {
		memTrace[i] = uint64(i + 1)
		cpuTrace[i] = uint64(1)
	}

	ref := info.ContainerReference{
		Name: "container",
	}

	trace := buildTrace(cpuTrace, memTrace, 1*time.Second)

	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}

	recentStats, err := driver.RecentStats(ref.Name, 10)
	if err != nil {
		t.Fatal(err)
	}

	if len(recentStats) != 10 {
		t.Fatalf("returned %v stats, not 10.", len(recentStats))
	}

	traceIdx := len(trace) - 1
	// Latest stats come first
	for i := 0; i < 10; i++ {
		r := recentStats[i]
		s := trace[traceIdx]
		traceIdx--
		if !reflect.DeepEqual(s, r) {
			t.Errorf("The %vth item should be %+v with memory usage %v; got item %+v with memory usage %v", i, s, s.Memory.Usage, r, r.Memory.Usage)
		}
	}
}

// The driver must be albe to hold more than 10 stats
func StorageDriverTestRetrieveAllRecentStats(driver storage.StorageDriver, t *testing.T) {
	defer driver.Close()
	N := 100
	memTrace := make([]uint64, N)
	cpuTrace := make([]uint64, N)
	for i := 0; i < N; i++ {
		memTrace[i] = uint64(i + 1)
		cpuTrace[i] = uint64(1)
	}

	ref := info.ContainerReference{
		Name: "container",
	}

	trace := buildTrace(cpuTrace, memTrace, 1*time.Second)

	for _, stats := range trace {
		driver.AddStats(ref, stats)
	}

	recentStats, err := driver.RecentStats(ref.Name, -1)
	if err != nil {
		t.Fatal(err)
	}

	traceIdx := len(trace) - 1
	for i, r := range recentStats {
		s := trace[traceIdx]
		traceIdx--
		if !reflect.DeepEqual(s, r) {
			t.Errorf("The %vth item should be %+v with memory usage %v; got item %+v with memory usage %v", i, s, s.Memory.Usage, r, r.Memory.Usage)
		}
	}
}
<|endoftext|>


<commit_before><commit_msg>Be a bit more strict when parsing booleans<commit_after><|endoftext|>


<commit_before>package types

import (
	"time"

	"github.com/docker/docker/daemon/network"
	"github.com/docker/docker/pkg/version"
	"github.com/docker/docker/runconfig"
)

// ContainerCreateResponse contains the information returned to a client on the
// creation of a new container.
type ContainerCreateResponse struct {
	// ID is the ID of the created container.
	ID string `json:"Id"`

	// Warnings are any warnings encountered during the creation of the container.
	Warnings []string `json:"Warnings"`
}

// POST /containers/{name:.*}/exec
type ContainerExecCreateResponse struct {
	// ID is the exec ID.
	ID string `json:"Id"`
}

// POST /auth
type AuthResponse struct {
	// Status is the authentication status
	Status string `json:"Status"`
}

// POST "/containers/"+containerID+"/wait"
type ContainerWaitResponse struct {
	// StatusCode is the status code of the wait job
	StatusCode int `json:"StatusCode"`
}

// POST "/commit?container="+containerID
type ContainerCommitResponse struct {
	ID string `json:"Id"`
}

// GET "/containers/{name:.*}/changes"
type ContainerChange struct {
	Kind int
	Path string
}

// GET "/images/{name:.*}/history"
type ImageHistory struct {
	ID        string `json:"Id"`
	Created   int64
	CreatedBy string
	Tags      []string
	Size      int64
	Comment   string
}

// DELETE "/images/{name:.*}"
type ImageDelete struct {
	Untagged string `json:",omitempty"`
	Deleted  string `json:",omitempty"`
}

// GET "/images/json"
type Image struct {
	ID          string `json:"Id"`
	ParentId    string
	RepoTags    []string
	RepoDigests []string
	Created     int
	Size        int
	VirtualSize int
	Labels      map[string]string
}

// GET "/images/{name:.*}/json"
type ImageInspect struct {
	Id              string
	Parent          string
	Comment         string
	Created         time.Time
	Container       string
	ContainerConfig *runconfig.Config
	DockerVersion   string
	Author          string
	Config          *runconfig.Config
	Architecture    string
	Os              string
	Size            int64
	VirtualSize     int64
}

// GET  "/containers/json"
type Port struct {
	IP          string
	PrivatePort int
	PublicPort  int
	Type        string
}

type Container struct {
	ID         string            `json:"Id"`
	Names      []string          `json:",omitempty"`
	Image      string            `json:",omitempty"`
	Command    string            `json:",omitempty"`
	Created    int               `json:",omitempty"`
	Ports      []Port            `json:",omitempty"`
	SizeRw     int               `json:",omitempty"`
	SizeRootFs int               `json:",omitempty"`
	Labels     map[string]string `json:",omitempty"`
	Status     string            `json:",omitempty"`
}

// POST "/containers/"+containerID+"/copy"
type CopyConfig struct {
	Resource string
}

// GET "/containers/{name:.*}/top"
type ContainerProcessList struct {
	Processes [][]string
	Titles    []string
}

type Version struct {
	Version       string
	ApiVersion    version.Version
	GitCommit     string
	GoVersion     string
	Os            string
	Arch          string
	KernelVersion string `json:",omitempty"`
}

// GET "/info"
type Info struct {
	ID                 string
	Containers         int
	Images             int
	Driver             string
	DriverStatus       [][2]string
	MemoryLimit        bool
	SwapLimit          bool
	CpuCfsPeriod       bool
	CpuCfsQuota        bool
	IPv4Forwarding     bool
	Debug              bool
	NFd                int
	OomKillDisable     bool
	NGoroutines        int
	SystemTime         string
	ExecutionDriver    string
	LoggingDriver      string
	NEventsListener    int
	KernelVersion      string
	OperatingSystem    string
	IndexServerAddress string
	RegistryConfig     interface{}
	InitSha1           string
	InitPath           string
	NCPU               int
	MemTotal           int64
	DockerRootDir      string
	HttpProxy          string
	HttpsProxy         string
	NoProxy            string
	Name               string
	Labels             []string
	ExperimentalBuild  bool
}

// This struct is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartCheck struct {
	// ExecStart will first check if it's detached
	Detach bool
	// Check if there's a tty
	Tty bool
}

type ContainerState struct {
	Running    bool
	Paused     bool
	Restarting bool
	OOMKilled  bool
	Dead       bool
	Pid        int
	ExitCode   int
	Error      string
	StartedAt  time.Time
	FinishedAt time.Time
}

// GET "/containers/{name:.*}/json"
type ContainerJSON struct {
	Id              string
	Created         time.Time
	Path            string
	Args            []string
	Config          *runconfig.Config
	State           *ContainerState
	Image           string
	NetworkSettings *network.Settings
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Name            string
	RestartCount    int
	Driver          string
	ExecDriver      string
	MountLabel      string
	ProcessLabel    string
	Volumes         map[string]string
	VolumesRW       map[string]bool
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      *runconfig.HostConfig
}
<commit_msg>fix experimental version and release script<commit_after>package types

import (
	"time"

	"github.com/docker/docker/daemon/network"
	"github.com/docker/docker/pkg/version"
	"github.com/docker/docker/runconfig"
)

// ContainerCreateResponse contains the information returned to a client on the
// creation of a new container.
type ContainerCreateResponse struct {
	// ID is the ID of the created container.
	ID string `json:"Id"`

	// Warnings are any warnings encountered during the creation of the container.
	Warnings []string `json:"Warnings"`
}

// POST /containers/{name:.*}/exec
type ContainerExecCreateResponse struct {
	// ID is the exec ID.
	ID string `json:"Id"`
}

// POST /auth
type AuthResponse struct {
	// Status is the authentication status
	Status string `json:"Status"`
}

// POST "/containers/"+containerID+"/wait"
type ContainerWaitResponse struct {
	// StatusCode is the status code of the wait job
	StatusCode int `json:"StatusCode"`
}

// POST "/commit?container="+containerID
type ContainerCommitResponse struct {
	ID string `json:"Id"`
}

// GET "/containers/{name:.*}/changes"
type ContainerChange struct {
	Kind int
	Path string
}

// GET "/images/{name:.*}/history"
type ImageHistory struct {
	ID        string `json:"Id"`
	Created   int64
	CreatedBy string
	Tags      []string
	Size      int64
	Comment   string
}

// DELETE "/images/{name:.*}"
type ImageDelete struct {
	Untagged string `json:",omitempty"`
	Deleted  string `json:",omitempty"`
}

// GET "/images/json"
type Image struct {
	ID          string `json:"Id"`
	ParentId    string
	RepoTags    []string
	RepoDigests []string
	Created     int
	Size        int
	VirtualSize int
	Labels      map[string]string
}

// GET "/images/{name:.*}/json"
type ImageInspect struct {
	Id              string
	Parent          string
	Comment         string
	Created         time.Time
	Container       string
	ContainerConfig *runconfig.Config
	DockerVersion   string
	Author          string
	Config          *runconfig.Config
	Architecture    string
	Os              string
	Size            int64
	VirtualSize     int64
}

// GET  "/containers/json"
type Port struct {
	IP          string
	PrivatePort int
	PublicPort  int
	Type        string
}

type Container struct {
	ID         string            `json:"Id"`
	Names      []string          `json:",omitempty"`
	Image      string            `json:",omitempty"`
	Command    string            `json:",omitempty"`
	Created    int               `json:",omitempty"`
	Ports      []Port            `json:",omitempty"`
	SizeRw     int               `json:",omitempty"`
	SizeRootFs int               `json:",omitempty"`
	Labels     map[string]string `json:",omitempty"`
	Status     string            `json:",omitempty"`
}

// POST "/containers/"+containerID+"/copy"
type CopyConfig struct {
	Resource string
}

// GET "/containers/{name:.*}/top"
type ContainerProcessList struct {
	Processes [][]string
	Titles    []string
}

type Version struct {
	Version       string
	ApiVersion    version.Version
	GitCommit     string
	GoVersion     string
	Os            string
	Arch          string
	KernelVersion string `json:",omitempty"`
	Experimental  bool
}

// GET "/info"
type Info struct {
	ID                 string
	Containers         int
	Images             int
	Driver             string
	DriverStatus       [][2]string
	MemoryLimit        bool
	SwapLimit          bool
	CpuCfsPeriod       bool
	CpuCfsQuota        bool
	IPv4Forwarding     bool
	Debug              bool
	NFd                int
	OomKillDisable     bool
	NGoroutines        int
	SystemTime         string
	ExecutionDriver    string
	LoggingDriver      string
	NEventsListener    int
	KernelVersion      string
	OperatingSystem    string
	IndexServerAddress string
	RegistryConfig     interface{}
	InitSha1           string
	InitPath           string
	NCPU               int
	MemTotal           int64
	DockerRootDir      string
	HttpProxy          string
	HttpsProxy         string
	NoProxy            string
	Name               string
	Labels             []string
	ExperimentalBuild  bool
}

// This struct is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartCheck struct {
	// ExecStart will first check if it's detached
	Detach bool
	// Check if there's a tty
	Tty bool
}

type ContainerState struct {
	Running    bool
	Paused     bool
	Restarting bool
	OOMKilled  bool
	Dead       bool
	Pid        int
	ExitCode   int
	Error      string
	StartedAt  time.Time
	FinishedAt time.Time
}

// GET "/containers/{name:.*}/json"
type ContainerJSON struct {
	Id              string
	Created         time.Time
	Path            string
	Args            []string
	Config          *runconfig.Config
	State           *ContainerState
	Image           string
	NetworkSettings *network.Settings
	ResolvConfPath  string
	HostnamePath    string
	HostsPath       string
	LogPath         string
	Name            string
	RestartCount    int
	Driver          string
	ExecDriver      string
	MountLabel      string
	ProcessLabel    string
	Volumes         map[string]string
	VolumesRW       map[string]bool
	AppArmorProfile string
	ExecIDs         []string
	HostConfig      *runconfig.HostConfig
}
<|endoftext|>


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

package auth

import (
	"context"
	"fmt"
	"net"

	"golang.org/x/oauth2"

	"go.chromium.org/luci/auth/identity"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/server/auth/authdb"
	"go.chromium.org/luci/server/auth/realms"
)

// State is stored in the context when handling an incoming request. It
// contains authentication related state of the current request.
type State interface {
	// Authenticator is an Authenticator used to authenticate the request.
	Authenticator() *Authenticator

	// DB is authdb.DB snapshot with authorization information to use when
	// processing this request.
	//
	// Use directly only when you know what your are doing. Prefer to use wrapping
	// functions (e.g. IsMember) instead.
	DB() authdb.DB

	// Method returns an authentication method used for the current request or nil
	// if the request is anonymous.
	//
	// If non-nil, its one of the methods in Authenticator.Methods.
	Method() Method

	// User holds the identity and profile of the current caller.
	//
	// User.Identity usually matches PeerIdentity(), but can be different if
	// the delegation is used.
	//
	// This field is never nil. For anonymous call it contains User with identity
	// AnonymousIdentity.
	//
	// Do not modify it.
	User() *User

	// Session is the session object produced by the authentication method.
	//
	// It may hold some extra information pertaining to the request. It may be nil
	// if there's no extra information. The session can be used to transfer
	// information from the authentication method to other parts of the auth
	// stack that execute later.
	Session() Session

	// PeerIdentity identifies whoever is making the request.
	//
	// It's an identity directly extracted from user credentials (ignoring
	// delegation tokens).
	PeerIdentity() identity.Identity

	// PeerIP is IP address (IPv4 or IPv6) of whoever is making the request or
	// nil if not available.
	PeerIP() net.IP

	// UserCredentials is an end-user credentials as they were received if they
	// are allowed to be forwarded.
	//
	// Includes the primary OAuth token and any extra LUCI-specific headers.
	UserCredentials() (*oauth2.Token, map[string]string, error)
}

type stateContextKey int

// WithState injects State into the context.
//
// Mostly useful from tests. Must not be normally used from production code,
// 'Authenticate' sets the state itself.
func WithState(ctx context.Context, s State) context.Context {
	return context.WithValue(ctx, stateContextKey(0), s)
}

// GetState return State stored in the context by 'Authenticate' call, the
// background state if 'Authenticate' wasn't used or nil if the auth library
// wasn't configured.
//
// The background state roughly is similar to the state of anonymous call.
// Various background non user-facing handlers (crons, task queues) that do not
// use 'Authenticate' see this state by default. Its most important role is to
// provide access to authdb.DB (and all functionality that depends on it) to
// background handlers.
func GetState(ctx context.Context) State {
	if s, ok := ctx.Value(stateContextKey(0)).(State); ok && s != nil {
		return s
	}
	if getConfig(ctx) != nil {
		return backgroundState{ctx}
	}
	return nil
}

// CurrentUser represents the current caller.
//
// Shortcut for GetState(ctx).User(). Returns user with AnonymousIdentity if
// the context doesn't have State.
func CurrentUser(ctx context.Context) *User {
	if s := GetState(ctx); s != nil {
		return s.User()
	}
	return &User{Identity: identity.AnonymousIdentity}
}

// CurrentIdentity return identity of the current caller.
//
// Shortcut for GetState(ctx).User().Identity(). Returns AnonymousIdentity if
// the context doesn't have State.
func CurrentIdentity(ctx context.Context) identity.Identity {
	if s := GetState(ctx); s != nil {
		return s.User().Identity
	}
	return identity.AnonymousIdentity
}

// IsMember returns true if the current caller is in any of the given groups.
//
// Unknown groups are considered empty (the function returns false).
//
// May return errors if the check can not be performed (e.g. on datastore
// issues).
func IsMember(ctx context.Context, groups ...string) (bool, error) {
	if s := GetState(ctx); s != nil {
		return s.DB().IsMember(ctx, s.User().Identity, groups)
	}
	return false, ErrNotConfigured
}

// HasPermission returns true if the current caller has the given permission
// in the realm.
//
// A non-existing realm is replaced with the corresponding root realm (e.g. if
// "projectA:some/realm" doesn't exist, "projectA:@root" will be used in its
// place). If the project doesn't exist or is not using realms yet, all its
// realms (including the root realm) are considered empty. HasPermission returns
// false in this case.
//
// Attributes are the context of this particular permission check and are used
// as inputs to `conditions` predicates in conditional bindings. If a service
// supports conditional bindings, it must document what attributes it passes
// with each permission it checks.
//
// Returns an error only if the check itself failed due to a misconfiguration
// or transient issues. This should usually result in an Internal error.
func HasPermission(ctx context.Context, perm realms.Permission, realm string, attrs realms.Attrs) (bool, error) {
	if s := GetState(ctx); s != nil {
		return s.DB().HasPermission(ctx, s.User().Identity, perm, realm, attrs)
	}
	return false, ErrNotConfigured
}

// HasPermissionDryRun compares result of HasPermission to 'expected'.
//
// Intended to be used during the migration between the old and new ACL models.
type HasPermissionDryRun struct {
	ExpectedResult bool   // the expected result of this dry run
	TrackingBug    string // identifier of a particular migration, for logs
	AdminGroup     string // if given, implicitly grant all permissions to its members
}

// Execute calls HasPermission and compares the result to the expectations.
//
// Logs information about the call and any errors or discrepancies found.
//
// Accepts same arguments as HasPermission. Intentionally returns nothing.
func (dr HasPermissionDryRun) Execute(ctx context.Context, perm realms.Permission, realm string, attrs realms.Attrs) {
	s := GetState(ctx)
	if s == nil { // this should not really be happening at all
		logging.Errorf(ctx, "HasPermissionDryRun: no state in the context")
		return
	}

	db := s.DB()
	ident := s.User().Identity

	// We use python naming convention in the log to make Go and Python dry run
	// logs look identical in case we want to parse them.
	logPfx := fmt.Sprintf("has_permission_dryrun(%q, %q, %q), authdb=%d", perm, realm, ident, authdb.Revision(db))
	if dr.TrackingBug != "" {
		logPfx = dr.TrackingBug + ": " + logPfx
	}

	allowDeny := func(b bool) string {
		if b {
			return "ALLOW"
		}
		return "DENY"
	}

	switch result, err := db.HasPermission(ctx, ident, perm, realm, attrs); {
	case err != nil:
		logging.Errorf(ctx, "%s: error - want %s, got: %s", logPfx, allowDeny(dr.ExpectedResult), err)
	case result == dr.ExpectedResult:
		logging.Infof(ctx, "%s: match - %s", logPfx, allowDeny(result))
	case dr.AdminGroup == "" || !dr.ExpectedResult:
		logging.Warningf(ctx, "%s: mismatch - got %s, want %s", logPfx, allowDeny(result), allowDeny(dr.ExpectedResult))
	default:
		// We expected ALLOW, but got DENY. Maybe the legacy ACL check relied on
		// the admin group. Check this separately.
		switch admin, err := db.IsMember(ctx, ident, []string{dr.AdminGroup}); {
		case err != nil:
			logging.Errorf(ctx, "%s: error - want ALLOW, got: %s", logPfx, err)
		case admin:
			logging.Infof(ctx, "%s: match - ADMIN_ALLOW", logPfx)
		default:
			logging.Warningf(ctx, "%s: mismatch - got DENY, want ALLOW", logPfx)
		}
	}
}

// QueryRealms returns a list of realms where the current caller has the given
// permission.
//
// If `project` is not empty, restricts the check only to the realms in this
// project, otherwise checks all realms across all projects. Either way, the
// returned realm names have form `<some-project>:<some-realm>`. The list is
// returned in some arbitrary order.
//
// Semantically it is equivalent to visiting all explicitly defined realms
// (plus "<project>:@root" and "<project>:@legacy") in the requested project or
// all projects, and calling HasPermission(perm, realm, attr) for each of them.
//
// The permission `perm` should be flagged in the process with UsedInQueryRealms
// flag, which lets the runtime know it must prepare indexes for the
// corresponding QueryRealms call.
//
// Returns an error only if the check itself failed due to a misconfiguration
// or transient issues. This should usually result in an Internal error.
func QueryRealms(ctx context.Context, id identity.Identity, perm realms.Permission, project string, attrs realms.Attrs) ([]string, error) {
	if s := GetState(ctx); s != nil {
		return s.DB().QueryRealms(ctx, s.User().Identity, perm, project, attrs)
	}
	return nil, ErrNotConfigured
}

// ShouldEnforceRealmACL is true if the service should enforce the realm's ACLs.
//
// Based on `enforce_in_service` realm data. Exists temporarily during the
// realms migration.
//
// TODO(crbug.com/1051724): Remove when no longer used.
func ShouldEnforceRealmACL(ctx context.Context, realm string) (bool, error) {
	s := GetState(ctx)
	if s == nil {
		return false, ErrNotConfigured
	}

	data, err := s.DB().GetRealmData(ctx, realm)
	switch {
	case err != nil:
		return false, errors.Annotate(err, "failed to load realm data").Err()
	case data == nil:
		return false, nil // no realms.cfg in the project at all
	case len(data.EnforceInService) == 0:
		return false, nil // enforced nowhere
	}

	info, err := GetSigner(ctx).ServiceInfo(ctx)
	if err != nil {
		return false, errors.Annotate(err, "failed to get our own service info").Err()
	}

	for _, id := range data.EnforceInService {
		if id == info.AppID {
			return true, nil
		}
	}
	return false, nil
}

// IsInWhitelist returns true if the current caller is in the given IP
// whitelist.
//
// Unknown whitelists are considered empty (the function returns false).
//
// May return errors if the check can not be performed (e.g. on datastore
// issues).
func IsInWhitelist(ctx context.Context, whitelist string) (bool, error) {
	if s := GetState(ctx); s != nil {
		return s.DB().IsInWhitelist(ctx, s.PeerIP(), whitelist)
	}
	return false, ErrNotConfigured
}

// LoginURL returns a URL that, when visited, prompts the user to sign in,
// then redirects the user to the URL specified by dest.
//
// Shortcut for GetState(ctx).Authenticator().LoginURL(...).
func LoginURL(ctx context.Context, dest string) (string, error) {
	if s := GetState(ctx); s != nil {
		return s.Authenticator().LoginURL(ctx, dest)
	}
	return "", ErrNotConfigured
}

// LogoutURL returns a URL that, when visited, signs the user out, then
// redirects the user to the URL specified by dest.
//
// Shortcut for GetState(ctx).Authenticator().LogoutURL(...).
func LogoutURL(ctx context.Context, dest string) (string, error) {
	if s := GetState(ctx); s != nil {
		return s.Authenticator().LogoutURL(ctx, dest)
	}
	return "", ErrNotConfigured
}

///

// state implements State. Immutable.
type state struct {
	authenticator *Authenticator
	db            authdb.DB
	method        Method
	user          *User
	session       Session
	peerIdent     identity.Identity
	peerIP        net.IP

	// For AsCredentialsForwarder. 'endUserErr' (if not nil) would be returned by
	// GetRPCTransport when attempting to forward the credentials.
	endUserTok          *oauth2.Token
	endUserExtraHeaders map[string]string
	endUserErr          error
}

func (s *state) Authenticator() *Authenticator   { return s.authenticator }
func (s *state) DB() authdb.DB                   { return s.db }
func (s *state) Method() Method                  { return s.method }
func (s *state) User() *User                     { return s.user }
func (s *state) Session() Session                { return s.session }
func (s *state) PeerIdentity() identity.Identity { return s.peerIdent }
func (s *state) PeerIP() net.IP                  { return s.peerIP }
func (s *state) UserCredentials() (*oauth2.Token, map[string]string, error) {
	return s.endUserTok, s.endUserExtraHeaders, s.endUserErr
}

///

// backgroundState corresponds to the state of auth library before any
// authentication is performed.
type backgroundState struct {
	ctx context.Context
}

func isBackgroundState(s State) bool {
	_, yes := s.(backgroundState)
	return yes
}

func (s backgroundState) DB() authdb.DB {
	db, err := GetDB(s.ctx)
	if err != nil {
		return authdb.ErroringDB{Error: err}
	}
	return db
}

func (s backgroundState) Authenticator() *Authenticator   { return nil }
func (s backgroundState) Method() Method                  { return nil }
func (s backgroundState) User() *User                     { return &User{Identity: identity.AnonymousIdentity} }
func (s backgroundState) Session() Session                { return nil }
func (s backgroundState) PeerIdentity() identity.Identity { return identity.AnonymousIdentity }
func (s backgroundState) PeerIP() net.IP                  { return nil }
func (s backgroundState) UserCredentials() (*oauth2.Token, map[string]string, error) {
	return nil, nil, ErrNoForwardableCreds
}
<commit_msg>[server][auth] fix QueryRealms requires identity<commit_after>// Copyright 2015 The LUCI Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package auth

import (
	"context"
	"fmt"
	"net"

	"golang.org/x/oauth2"

	"go.chromium.org/luci/auth/identity"
	"go.chromium.org/luci/common/errors"
	"go.chromium.org/luci/common/logging"
	"go.chromium.org/luci/server/auth/authdb"
	"go.chromium.org/luci/server/auth/realms"
)

// State is stored in the context when handling an incoming request. It
// contains authentication related state of the current request.
type State interface {
	// Authenticator is an Authenticator used to authenticate the request.
	Authenticator() *Authenticator

	// DB is authdb.DB snapshot with authorization information to use when
	// processing this request.
	//
	// Use directly only when you know what your are doing. Prefer to use wrapping
	// functions (e.g. IsMember) instead.
	DB() authdb.DB

	// Method returns an authentication method used for the current request or nil
	// if the request is anonymous.
	//
	// If non-nil, its one of the methods in Authenticator.Methods.
	Method() Method

	// User holds the identity and profile of the current caller.
	//
	// User.Identity usually matches PeerIdentity(), but can be different if
	// the delegation is used.
	//
	// This field is never nil. For anonymous call it contains User with identity
	// AnonymousIdentity.
	//
	// Do not modify it.
	User() *User

	// Session is the session object produced by the authentication method.
	//
	// It may hold some extra information pertaining to the request. It may be nil
	// if there's no extra information. The session can be used to transfer
	// information from the authentication method to other parts of the auth
	// stack that execute later.
	Session() Session

	// PeerIdentity identifies whoever is making the request.
	//
	// It's an identity directly extracted from user credentials (ignoring
	// delegation tokens).
	PeerIdentity() identity.Identity

	// PeerIP is IP address (IPv4 or IPv6) of whoever is making the request or
	// nil if not available.
	PeerIP() net.IP

	// UserCredentials is an end-user credentials as they were received if they
	// are allowed to be forwarded.
	//
	// Includes the primary OAuth token and any extra LUCI-specific headers.
	UserCredentials() (*oauth2.Token, map[string]string, error)
}

type stateContextKey int

// WithState injects State into the context.
//
// Mostly useful from tests. Must not be normally used from production code,
// 'Authenticate' sets the state itself.
func WithState(ctx context.Context, s State) context.Context {
	return context.WithValue(ctx, stateContextKey(0), s)
}

// GetState return State stored in the context by 'Authenticate' call, the
// background state if 'Authenticate' wasn't used or nil if the auth library
// wasn't configured.
//
// The background state roughly is similar to the state of anonymous call.
// Various background non user-facing handlers (crons, task queues) that do not
// use 'Authenticate' see this state by default. Its most important role is to
// provide access to authdb.DB (and all functionality that depends on it) to
// background handlers.
func GetState(ctx context.Context) State {
	if s, ok := ctx.Value(stateContextKey(0)).(State); ok && s != nil {
		return s
	}
	if getConfig(ctx) != nil {
		return backgroundState{ctx}
	}
	return nil
}

// CurrentUser represents the current caller.
//
// Shortcut for GetState(ctx).User(). Returns user with AnonymousIdentity if
// the context doesn't have State.
func CurrentUser(ctx context.Context) *User {
	if s := GetState(ctx); s != nil {
		return s.User()
	}
	return &User{Identity: identity.AnonymousIdentity}
}

// CurrentIdentity return identity of the current caller.
//
// Shortcut for GetState(ctx).User().Identity(). Returns AnonymousIdentity if
// the context doesn't have State.
func CurrentIdentity(ctx context.Context) identity.Identity {
	if s := GetState(ctx); s != nil {
		return s.User().Identity
	}
	return identity.AnonymousIdentity
}

// IsMember returns true if the current caller is in any of the given groups.
//
// Unknown groups are considered empty (the function returns false).
//
// May return errors if the check can not be performed (e.g. on datastore
// issues).
func IsMember(ctx context.Context, groups ...string) (bool, error) {
	if s := GetState(ctx); s != nil {
		return s.DB().IsMember(ctx, s.User().Identity, groups)
	}
	return false, ErrNotConfigured
}

// HasPermission returns true if the current caller has the given permission
// in the realm.
//
// A non-existing realm is replaced with the corresponding root realm (e.g. if
// "projectA:some/realm" doesn't exist, "projectA:@root" will be used in its
// place). If the project doesn't exist or is not using realms yet, all its
// realms (including the root realm) are considered empty. HasPermission returns
// false in this case.
//
// Attributes are the context of this particular permission check and are used
// as inputs to `conditions` predicates in conditional bindings. If a service
// supports conditional bindings, it must document what attributes it passes
// with each permission it checks.
//
// Returns an error only if the check itself failed due to a misconfiguration
// or transient issues. This should usually result in an Internal error.
func HasPermission(ctx context.Context, perm realms.Permission, realm string, attrs realms.Attrs) (bool, error) {
	if s := GetState(ctx); s != nil {
		return s.DB().HasPermission(ctx, s.User().Identity, perm, realm, attrs)
	}
	return false, ErrNotConfigured
}

// HasPermissionDryRun compares result of HasPermission to 'expected'.
//
// Intended to be used during the migration between the old and new ACL models.
type HasPermissionDryRun struct {
	ExpectedResult bool   // the expected result of this dry run
	TrackingBug    string // identifier of a particular migration, for logs
	AdminGroup     string // if given, implicitly grant all permissions to its members
}

// Execute calls HasPermission and compares the result to the expectations.
//
// Logs information about the call and any errors or discrepancies found.
//
// Accepts same arguments as HasPermission. Intentionally returns nothing.
func (dr HasPermissionDryRun) Execute(ctx context.Context, perm realms.Permission, realm string, attrs realms.Attrs) {
	s := GetState(ctx)
	if s == nil { // this should not really be happening at all
		logging.Errorf(ctx, "HasPermissionDryRun: no state in the context")
		return
	}

	db := s.DB()
	ident := s.User().Identity

	// We use python naming convention in the log to make Go and Python dry run
	// logs look identical in case we want to parse them.
	logPfx := fmt.Sprintf("has_permission_dryrun(%q, %q, %q), authdb=%d", perm, realm, ident, authdb.Revision(db))
	if dr.TrackingBug != "" {
		logPfx = dr.TrackingBug + ": " + logPfx
	}

	allowDeny := func(b bool) string {
		if b {
			return "ALLOW"
		}
		return "DENY"
	}

	switch result, err := db.HasPermission(ctx, ident, perm, realm, attrs); {
	case err != nil:
		logging.Errorf(ctx, "%s: error - want %s, got: %s", logPfx, allowDeny(dr.ExpectedResult), err)
	case result == dr.ExpectedResult:
		logging.Infof(ctx, "%s: match - %s", logPfx, allowDeny(result))
	case dr.AdminGroup == "" || !dr.ExpectedResult:
		logging.Warningf(ctx, "%s: mismatch - got %s, want %s", logPfx, allowDeny(result), allowDeny(dr.ExpectedResult))
	default:
		// We expected ALLOW, but got DENY. Maybe the legacy ACL check relied on
		// the admin group. Check this separately.
		switch admin, err := db.IsMember(ctx, ident, []string{dr.AdminGroup}); {
		case err != nil:
			logging.Errorf(ctx, "%s: error - want ALLOW, got: %s", logPfx, err)
		case admin:
			logging.Infof(ctx, "%s: match - ADMIN_ALLOW", logPfx)
		default:
			logging.Warningf(ctx, "%s: mismatch - got DENY, want ALLOW", logPfx)
		}
	}
}

// QueryRealms returns a list of realms where the current caller has the given
// permission.
//
// If `project` is not empty, restricts the check only to the realms in this
// project, otherwise checks all realms across all projects. Either way, the
// returned realm names have form `<some-project>:<some-realm>`. The list is
// returned in some arbitrary order.
//
// Semantically it is equivalent to visiting all explicitly defined realms
// (plus "<project>:@root" and "<project>:@legacy") in the requested project or
// all projects, and calling HasPermission(perm, realm, attr) for each of them.
//
// The permission `perm` should be flagged in the process with UsedInQueryRealms
// flag, which lets the runtime know it must prepare indexes for the
// corresponding QueryRealms call.
//
// Returns an error only if the check itself failed due to a misconfiguration
// or transient issues. This should usually result in an Internal error.
func QueryRealms(ctx context.Context, perm realms.Permission, project string, attrs realms.Attrs) ([]string, error) {
	if s := GetState(ctx); s != nil {
		return s.DB().QueryRealms(ctx, s.User().Identity, perm, project, attrs)
	}
	return nil, ErrNotConfigured
}

// ShouldEnforceRealmACL is true if the service should enforce the realm's ACLs.
//
// Based on `enforce_in_service` realm data. Exists temporarily during the
// realms migration.
//
// TODO(crbug.com/1051724): Remove when no longer used.
func ShouldEnforceRealmACL(ctx context.Context, realm string) (bool, error) {
	s := GetState(ctx)
	if s == nil {
		return false, ErrNotConfigured
	}

	data, err := s.DB().GetRealmData(ctx, realm)
	switch {
	case err != nil:
		return false, errors.Annotate(err, "failed to load realm data").Err()
	case data == nil:
		return false, nil // no realms.cfg in the project at all
	case len(data.EnforceInService) == 0:
		return false, nil // enforced nowhere
	}

	info, err := GetSigner(ctx).ServiceInfo(ctx)
	if err != nil {
		return false, errors.Annotate(err, "failed to get our own service info").Err()
	}

	for _, id := range data.EnforceInService {
		if id == info.AppID {
			return true, nil
		}
	}
	return false, nil
}

// IsInWhitelist returns true if the current caller is in the given IP
// whitelist.
//
// Unknown whitelists are considered empty (the function returns false).
//
// May return errors if the check can not be performed (e.g. on datastore
// issues).
func IsInWhitelist(ctx context.Context, whitelist string) (bool, error) {
	if s := GetState(ctx); s != nil {
		return s.DB().IsInWhitelist(ctx, s.PeerIP(), whitelist)
	}
	return false, ErrNotConfigured
}

// LoginURL returns a URL that, when visited, prompts the user to sign in,
// then redirects the user to the URL specified by dest.
//
// Shortcut for GetState(ctx).Authenticator().LoginURL(...).
func LoginURL(ctx context.Context, dest string) (string, error) {
	if s := GetState(ctx); s != nil {
		return s.Authenticator().LoginURL(ctx, dest)
	}
	return "", ErrNotConfigured
}

// LogoutURL returns a URL that, when visited, signs the user out, then
// redirects the user to the URL specified by dest.
//
// Shortcut for GetState(ctx).Authenticator().LogoutURL(...).
func LogoutURL(ctx context.Context, dest string) (string, error) {
	if s := GetState(ctx); s != nil {
		return s.Authenticator().LogoutURL(ctx, dest)
	}
	return "", ErrNotConfigured
}

///

// state implements State. Immutable.
type state struct {
	authenticator *Authenticator
	db            authdb.DB
	method        Method
	user          *User
	session       Session
	peerIdent     identity.Identity
	peerIP        net.IP

	// For AsCredentialsForwarder. 'endUserErr' (if not nil) would be returned by
	// GetRPCTransport when attempting to forward the credentials.
	endUserTok          *oauth2.Token
	endUserExtraHeaders map[string]string
	endUserErr          error
}

func (s *state) Authenticator() *Authenticator   { return s.authenticator }
func (s *state) DB() authdb.DB                   { return s.db }
func (s *state) Method() Method                  { return s.method }
func (s *state) User() *User                     { return s.user }
func (s *state) Session() Session                { return s.session }
func (s *state) PeerIdentity() identity.Identity { return s.peerIdent }
func (s *state) PeerIP() net.IP                  { return s.peerIP }
func (s *state) UserCredentials() (*oauth2.Token, map[string]string, error) {
	return s.endUserTok, s.endUserExtraHeaders, s.endUserErr
}

///

// backgroundState corresponds to the state of auth library before any
// authentication is performed.
type backgroundState struct {
	ctx context.Context
}

func isBackgroundState(s State) bool {
	_, yes := s.(backgroundState)
	return yes
}

func (s backgroundState) DB() authdb.DB {
	db, err := GetDB(s.ctx)
	if err != nil {
		return authdb.ErroringDB{Error: err}
	}
	return db
}

func (s backgroundState) Authenticator() *Authenticator   { return nil }
func (s backgroundState) Method() Method                  { return nil }
func (s backgroundState) User() *User                     { return &User{Identity: identity.AnonymousIdentity} }
func (s backgroundState) Session() Session                { return nil }
func (s backgroundState) PeerIdentity() identity.Identity { return identity.AnonymousIdentity }
func (s backgroundState) PeerIP() net.IP                  { return nil }
func (s backgroundState) UserCredentials() (*oauth2.Token, map[string]string, error) {
	return nil, nil, ErrNoForwardableCreds
}
<|endoftext|>


<commit_before>package main

import (
	"meowtrics/model"

	log "github.com/Sirupsen/logrus"
)

func StoreEvent(event model.ClientEventData, logger *log.Logger) error {

	if event.GetEventId() == "" {
		log.Warningln("Event Id is nil, returning error")
		return InvalidParametersError
	}

	eventMap[event.GetEventId()] = event
	return nil
}

func RetrieveEvent(eventId string) (*model.ClientEventData, error) {

	if eventId == "" {
		return nil, InvalidParametersError
	}

	if event, ok := eventMap[eventId]; ok {
		return &event, nil
	}

	return nil, RecordNotFoundError
}

/*
func GetDbConnection() (conn *bolt.DB, error){
	filename := viper.GetString("boltDbFilePath")
	mode := 0600
	timeout := 1 * time.Second
	return bolt.Open(filename, mode, &bolt.Options{Timeout: timeout})
}

func StoreEvent(b *bolt.Bucket, event *model.ClientEventData) error {

}

func RetrieveEvent(b *bolt.Bucket, eventId *string) (*ClientEventData, error) {

}
*/
<commit_msg>Changed signature StoreEvent method<commit_after>package main

import "meowtrics/model"

func StoreEvent(event model.ClientEventData) error {

	if event.GetEventId() == "" {
		return InvalidParametersError
	}

	eventMap[event.GetEventId()] = event
	return nil
}

func RetrieveEvent(eventId string) (*model.ClientEventData, error) {

	if eventId == "" {
		return nil, InvalidParametersError
	}

	if event, ok := eventMap[eventId]; ok {
		return &event, nil
	}

	return nil, RecordNotFoundError
}

/*
func GetDbConnection() (conn *bolt.DB, error){
	filename := viper.GetString("boltDbFilePath")
	mode := 0600
	timeout := 1 * time.Second
	return bolt.Open(filename, mode, &bolt.Options{Timeout: timeout})
}

func StoreEvent(b *bolt.Bucket, event *model.ClientEventData) error {

}

func RetrieveEvent(b *bolt.Bucket, eventId *string) (*ClientEventData, error) {

}
*/
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
)

type GameState struct {
	Time        uint64                 `json:"time"`
	Ships       map[string]*Ship       `json:"ships"`
	Projectiles map[string]*Projectile `json:"projectiles"`
	Asteroids   map[string]*Asteroid   `json:"asteroids"`
}

func CreateGameState(t uint64) *GameState {
	return &GameState{
		Time:        t,
		Ships:       make(map[string]*Ship),
		Projectiles: make(map[string]*Projectile),
		Asteroids:   make(map[string]*Asteroid),
	}
}

func (s *GameState) Tick(t uint64) *GameState {
	if t < s.Time {
		log.Fatalf("Tried to call tick with timestamp lower than previous tick: %d, %d", s.Time, t)
		return nil
	}

	// TODO: If t == s.Time, do a clone of game objects and return, since no time will have elapsed?

	// create new state
	state := CreateGameState(t)

	for _, o := range s.Ships {
		p := o.Tick(t, s)
		if p != nil {
			state.Ships[p.Id] = p
		}
	}

	for _, o := range s.Projectiles {
		p := o.Tick(t, s)
		if p != nil {
			state.Projectiles[p.Id] = p
		}
	}

	for _, o := range s.Asteroids {
		p := o.Tick(t, s)
		if p != nil {
			state.Asteroids[p.Id] = p
		}
	}

	// TODO: Come up with a better way to look up collisions.
	// From https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

	for _, s := range state.Ships {
		if !s.Alive {
			continue
		}

		// check for ship-ship collisions
		for _, os := range state.Ships {
			if !s.Alive || !os.Alive || s.Id == os.Id {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, os.Position, settings.constants.ShipRadius) {
				log.Println(fmt.Sprintf("Ship %v collided with Ship %v", s.Id, os.Id))
				s.Alive = false
				s.Died = t
				os.Alive = false
				os.Died = t
			}
		}

		if !s.Alive {
			continue
		}

		// check for ship-projectile collisions
		for _, p := range state.Projectiles {
			if !s.Alive || !p.Alive || s.Id == p.Owner {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, p.Position, settings.constants.ProjectileRadius) {
				log.Println(fmt.Sprintf("Ship %v collided with Projectile %v", s.Id, p.Id))
				s.Alive = false
				s.Died = t
				p.Alive = false
				p.Died = t
			}
		}
	}

	return state
}
<commit_msg>Added ship/asteroid collisions.<commit_after>package main

import (
	"fmt"
	"log"
)

type GameState struct {
	Time        uint64                 `json:"time"`
	Ships       map[string]*Ship       `json:"ships"`
	Projectiles map[string]*Projectile `json:"projectiles"`
	Asteroids   map[string]*Asteroid   `json:"asteroids"`
}

func CreateGameState(t uint64) *GameState {
	return &GameState{
		Time:        t,
		Ships:       make(map[string]*Ship),
		Projectiles: make(map[string]*Projectile),
		Asteroids:   make(map[string]*Asteroid),
	}
}

func (s *GameState) Tick(t uint64) *GameState {
	if t < s.Time {
		log.Fatalf("Tried to call tick with timestamp lower than previous tick: %d, %d", s.Time, t)
		return nil
	}

	// TODO: If t == s.Time, do a clone of game objects and return, since no time will have elapsed?

	// create new state
	state := CreateGameState(t)

	for _, o := range s.Ships {
		p := o.Tick(t, s)
		if p != nil {
			state.Ships[p.Id] = p
		}
	}

	for _, o := range s.Projectiles {
		p := o.Tick(t, s)
		if p != nil {
			state.Projectiles[p.Id] = p
		}
	}

	for _, o := range s.Asteroids {
		p := o.Tick(t, s)
		if p != nil {
			state.Asteroids[p.Id] = p
		}
	}

	// TODO: Come up with a better way to look up collisions.
	// From https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

	for _, s := range state.Ships {
		if !s.Alive {
			continue
		}

		// check for ship-ship collisions
		for _, os := range state.Ships {
			if !s.Alive || !os.Alive || s.Id == os.Id {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, os.Position, settings.constants.ShipRadius) {
				log.Println(fmt.Sprintf("Ship %v collided with Ship %v", s.Id, os.Id))
				s.Alive = false
				s.Died = t
				os.Alive = false
				os.Died = t
			}
		}

		if !s.Alive {
			continue
		}

		// check for ship-projectile collisions
		for _, p := range state.Projectiles {
			if !s.Alive || !p.Alive || s.Id == p.Owner {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, p.Position, settings.constants.ProjectileRadius) {
				log.Println(fmt.Sprintf("Ship %v collided with Projectile %v", s.Id, p.Id))
				s.Alive = false
				s.Died = t
				p.Alive = false
				p.Died = t
			}
		}

		if !s.Alive {
			continue
		}

		// check for ship-asteroid collisions
		for _, a := range state.Asteroids {
			if !s.Alive || !a.Alive {
				continue
			}

			if IsColliding(s.Position, settings.constants.ShipRadius, a.Position, a.Radius) {
				log.Println(fmt.Sprintf("Ship %v collided with Asteroid %v", s.Id, a.Id))
				s.Alive = false
				s.Died = t
			}
		}
	}

	return state
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/APTrust/exchange/partner_apps/common"
	"github.com/APTrust/exchange/util/fileutil"
	"github.com/APTrust/exchange/util/storage"
	"github.com/APTrust/exchange/validation"
	"os"
	"path/filepath"
)

func main() {
	pathToConfigFile, pathToOutFile, preserveAttrs := parseCommandLine()
	configAbsPath, err := filepath.Abs(pathToConfigFile)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
	pathToBag, err := filepath.Abs(flag.Arg(0))
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}
	conf, errors := validation.LoadBagValidationConfig(configAbsPath)
	if errors != nil && len(errors) > 0 {
		fmt.Fprintln(os.Stderr, "Could not load bag validation config: ", errors[0])
		os.Exit(1)
	}
	validator, err := validation.NewValidator(pathToBag, conf, preserveAttrs)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error creating validator: ", err.Error())
		os.Exit(1)
	}
	summary, err := validator.Validate()
	if err != nil {
		fmt.Fprintln(os.Stderr, "The validator encountered an error: ", err.Error())
		os.Exit(1)
	}
	exitCode := 0
	if summary.HasErrors() {
		cleanup(validator.DBName())
		fmt.Println("Bag is not valid")
		fmt.Println(summary.AllErrorsAsString())
		exitCode = 2
	} else {
		fmt.Println("Bag is valid")
	}
	if pathToOutFile != "" {
		printOutput(validator, pathToOutFile)
	}
	cleanup(validator.DBName())
	os.Exit(exitCode)
}

func printOutput(validator *validation.Validator, pathToOutFile string) {
	file, err := os.Create(pathToOutFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Can't open output file: %v\n", err)
		return
	}
	defer file.Close()

	db, err := storage.NewBoltDB(validator.DBName())
	if err != nil {
		fmt.Fprintf(os.Stderr, "Can't open db: %v\n", err)
		return
	}

	db.DumpJson(file)
}

func cleanup(filePath string) {
	if fileutil.LooksSafeToDelete(filePath, 12, 3) {
		os.Remove(filePath)
	}
}

func parseCommandLine() (pathToConfigFile, pathToOutFile string, preserveAttrs bool) {
	var help bool
	var version bool
	flag.StringVar(&pathToConfigFile, "config", "", "Path to bag validation config file")
	flag.StringVar(&pathToOutFile, "outfile", "", "Path to file for dumping JSON output")
	flag.BoolVar(&preserveAttrs, "attrs", false, "Preserve attributes")
	flag.BoolVar(&help, "help", false, "Show help")
	flag.BoolVar(&version, "version", false, "Show version")

	flag.Parse()

	if version {
		fmt.Println(common.GetVersion())
		os.Exit(100)
	}
	if help || pathToConfigFile == "" || flag.Arg(0) == "" {
		printUsage()
		os.Exit(0)
	}
	return pathToConfigFile, pathToOutFile, preserveAttrs
}

// Tell the user about the program.
func printUsage() {
	message := `
apt_validate validates bags according to the specified config file.

Usage:

apt_validate --config=<config_file> \
		--attrs=<true|false> \
		--outfile=<path_to_output_file> \
        [--version] \
		path_to_bag

The path_to_bag parameter is required. It should be the absolute path
to the directory containing the untarred bag, or to a tarred bag file.

The --config option is required and should be the path to a bag validation
config file that describes the validation rules. Examples can be found at
https://github.com/APTrust/exchange/blob/master/config/aptrust_bag_validation_config.json
or https://github.com/APTrust/exchange/blob/master/config/dpn_bag_validation_config.json,
but the config file must exist on the local drive.

The --attrs option is not required. It indicates whether you want to preserve
detailed information when parsing the bag. This uses more memory, and is generally
necessary only for APTrust ingest.

The --outfile option is not required. If specified, the validator will dump
JSON information about the bag and its contents to this file. That info may be
useful, especially when combined with --attrs=true, in cases where you're trying
to debug your bagging process.

Option --version prints version info and exits.

Exit codes:

0 - Bag is valid
1 - Validation could not be completed, typically because of a problem
	finding or reading the config file, or finding or reading the bag.
2 - Validation completed and bag is invalid.

`
	fmt.Println(message)
}
<commit_msg>Updated doc and standardized exit codes in apt_validate<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/APTrust/exchange/partner_apps/common"
	"github.com/APTrust/exchange/util/fileutil"
	"github.com/APTrust/exchange/util/storage"
	"github.com/APTrust/exchange/validation"
	"os"
	"path/filepath"
)

func main() {
	pathToConfigFile, pathToOutFile, preserveAttrs := parseCommandLine()
	configAbsPath, err := filepath.Abs(pathToConfigFile)
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(common.EXIT_RUNTIME_ERR)
	}
	pathToBag, err := filepath.Abs(flag.Arg(0))
	if err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(common.EXIT_RUNTIME_ERR)
	}
	conf, errors := validation.LoadBagValidationConfig(configAbsPath)
	if errors != nil && len(errors) > 0 {
		fmt.Fprintln(os.Stderr, "Could not load bag validation config: ", errors[0])
		os.Exit(common.EXIT_RUNTIME_ERR)
	}
	validator, err := validation.NewValidator(pathToBag, conf, preserveAttrs)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error creating validator: ", err.Error())
		os.Exit(common.EXIT_RUNTIME_ERR)
	}
	summary, err := validator.Validate()
	if err != nil {
		fmt.Fprintln(os.Stderr, "The validator encountered an error: ", err.Error())
		os.Exit(common.EXIT_RUNTIME_ERR)
	}
	exitCode := common.EXIT_OK
	if summary.HasErrors() {
		cleanup(validator.DBName())
		fmt.Println("Bag is not valid")
		fmt.Println(summary.AllErrorsAsString())
		exitCode = common.EXIT_BAG_INVALID
	} else {
		fmt.Println("Bag is valid")
	}
	if pathToOutFile != "" {
		printOutput(validator, pathToOutFile)
	}
	cleanup(validator.DBName())
	os.Exit(exitCode)
}

func printOutput(validator *validation.Validator, pathToOutFile string) {
	file, err := os.Create(pathToOutFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Can't open output file: %v\n", err)
		return
	}
	defer file.Close()

	db, err := storage.NewBoltDB(validator.DBName())
	if err != nil {
		fmt.Fprintf(os.Stderr, "Can't open db: %v\n", err)
		return
	}

	db.DumpJson(file)
}

func cleanup(filePath string) {
	if fileutil.LooksSafeToDelete(filePath, 12, 3) {
		os.Remove(filePath)
	}
}

func parseCommandLine() (pathToConfigFile, pathToOutFile string, preserveAttrs bool) {
	var help bool
	var version bool
	flag.StringVar(&pathToConfigFile, "config", "", "Path to bag validation config file")
	flag.StringVar(&pathToOutFile, "outfile", "", "Path to file for dumping JSON output")
	flag.BoolVar(&preserveAttrs, "attrs", false, "Preserve attributes")
	flag.BoolVar(&help, "help", false, "Show help")
	flag.BoolVar(&version, "version", false, "Show version")

	flag.Parse()

	if version {
		fmt.Println(common.GetVersion())
		os.Exit(common.EXIT_NO_OP)
	}
	if help || pathToConfigFile == "" || flag.Arg(0) == "" {
		printUsage()
		os.Exit(common.EXIT_USER_ERR)
	}
	return pathToConfigFile, pathToOutFile, preserveAttrs
}

// Tell the user about the program.
func printUsage() {
	message := `
apt_validate validates bags according to the specified config file.

Usage:

apt_validate --config=<config_file> \
             [--attrs=<true|false>] \
             [--outfile=<path_to_output_file>] \
             path_to_bag

apt_validate --help
apt_validate --version

Options

--attrs option is not required. It indicates whether you want to preserve
detailed information in the JSON output when parsing the bag. This uses
more memory, and is generally not useful to users outside of APTrust.
The additional information generated by the --attrs flag is used by APTrust
during the ingest proces. Timestamps and UUIDs change each time you run
the validator.

--config is required and should be the path to a bag validation
config file that describes the validation rules. Examples can be found at
https://github.com/APTrust/exchange/blob/master/config/aptrust_bag_validation_config.json
or https://github.com/APTrust/exchange/blob/master/config/dpn_bag_validation_config.json,
but the config file must exist on the local drive.

--help prints this help message and exits.

--outfile option is not required. If specified, the validator will dump
JSON information about the bag and its contents to this file. That info may be
useful, especially when combined with --attrs=true, in cases where you're trying
to debug your bagging process.

--version prints version info and exits.

Arguments

The path_to_bag parameter is required. It should be the absolute path
to the directory containing the untarred bag, or to a tarred bag file.

Exit codes:

0 - Bag is valid
1 - Validation could not be completed, typically because of a problem
	finding or reading the config file, or finding or reading the bag.
2 - Validation completed and bag is invalid.
3 - Operation could not be completed due to usage error (e.g. missing params)

`
	fmt.Println(message)
}
<|endoftext|>