<commit_before>package cmd

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os/exec"
)

var update = flag.Bool("update", false, "update .golden files")

func init() {
	// Mute commands.
	addCmd.SetOutput(new(bytes.Buffer))
	initCmd.SetOutput(new(bytes.Buffer))
}

// compareFiles compares the content of files with pathA and pathB.
// If contents are equal, it returns nil.
// If not, it returns which files are not equal
// and diff (if system has diff command) between these files.
func compareFiles(pathA, pathB string) error {
	contentA, err := ioutil.ReadFile(pathA)
	if err != nil {
		return err
	}
	contentB, err := ioutil.ReadFile(pathB)
	if err != nil {
		return err
	}
	if !bytes.Equal(contentA, contentB) {
		output := new(bytes.Buffer)
		output.WriteString(fmt.Sprintf("%q and %q are not equal!\n\n", pathA, pathB))

		diffPath, err := exec.LookPath("diff")
		if err != nil {
			// Don't execute diff if it can't be found.
			return nil
		}
		diffCmd := exec.Command(diffPath, pathA, pathB)
		diffCmd.Stdout = output
		diffCmd.Stderr = output

		output.WriteString("$ diff " + pathA + " " + pathB + "\n")
		if err := diffCmd.Run(); err != nil {
			output.WriteString("\n" + err.Error())
		}
		return errors.New(output.String())
	}
	return nil
}

// checkLackFiles checks if all elements of expected are in got.
func checkLackFiles(expected, got []string) error {
	lacks := make([]string, 0, len(expected))
	for _, ev := range expected {
		if !stringInStringSlice(ev, got) {
			lacks = append(lacks, ev)
		}
	}
	if len(lacks) > 0 {
		return fmt.Errorf("Lack %v file(s): %v", len(lacks), lacks)
	}
	return nil
}

// stringInStringSlice checks if s is an element of slice.
func stringInStringSlice(s string, slice []string) bool {
	for _, v := range slice {
		if s == v {
			return true
		}
	}
	return false
}
<commit_msg>cmd: Add "-u" to output unified diff in golden tests<commit_after>package cmd

import (
	"bytes"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"os/exec"
)

var update = flag.Bool("update", false, "update .golden files")

func init() {
	// Mute commands.
	addCmd.SetOutput(new(bytes.Buffer))
	initCmd.SetOutput(new(bytes.Buffer))
}

// compareFiles compares the content of files with pathA and pathB.
// If contents are equal, it returns nil.
// If not, it returns which files are not equal
// and diff (if system has diff command) between these files.
func compareFiles(pathA, pathB string) error {
	contentA, err := ioutil.ReadFile(pathA)
	if err != nil {
		return err
	}
	contentB, err := ioutil.ReadFile(pathB)
	if err != nil {
		return err
	}
	if !bytes.Equal(contentA, contentB) {
		output := new(bytes.Buffer)
		output.WriteString(fmt.Sprintf("%q and %q are not equal!\n\n", pathA, pathB))

		diffPath, err := exec.LookPath("diff")
		if err != nil {
			// Don't execute diff if it can't be found.
			return nil
		}
		diffCmd := exec.Command(diffPath, "-u", pathA, pathB)
		diffCmd.Stdout = output
		diffCmd.Stderr = output

		output.WriteString("$ diff -u " + pathA + " " + pathB + "\n")
		if err := diffCmd.Run(); err != nil {
			output.WriteString("\n" + err.Error())
		}
		return errors.New(output.String())
	}
	return nil
}

// checkLackFiles checks if all elements of expected are in got.
func checkLackFiles(expected, got []string) error {
	lacks := make([]string, 0, len(expected))
	for _, ev := range expected {
		if !stringInStringSlice(ev, got) {
			lacks = append(lacks, ev)
		}
	}
	if len(lacks) > 0 {
		return fmt.Errorf("Lack %v file(s): %v", len(lacks), lacks)
	}
	return nil
}

// stringInStringSlice checks if s is an element of slice.
func stringInStringSlice(s string, slice []string) bool {
	for _, v := range slice {
		if s == v {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package gcpce

import (
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"

	"google.golang.org/api/monitoring/v3"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

const zuluFormat string = "2006-01-02T15:4:05Z"
const duration string = "3m0s"
const computeDomain string = "compute.googleapis.com"

// ComputeEnginePlugin is mackerel plugin for Google Compute Engine
type ComputeEnginePlugin struct {
	Project           string
	InstanceName      string
	MonitoringService *monitoring.Service
	Option            *Option
	Tempfile          string
}

// Option is optional argument to an API call
type Option struct {
	Key string
}

// Get returns key and value
func (c Option) Get() (string, string) {
	return "key", c.Key
}

var graphdef = map[string]mp.Graphs{
	"Firewall.DroppedBytesCount": mp.Graphs{
		Label: "FireWall Dropped Bytes Count",
		Unit:  "bytes",
		Metrics: []mp.Metrics{
			{Name: "dropped_bytes_count", Label: "Dropped Bytes Count", Type: "uint64"},
		},
	},
	"Firewall.DroppedPacketsCount": mp.Graphs{
		Label: "FireWall Dropped Packets Count",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "dropped_packets_count", Label: "Dropped Packets Count", Type: "uint64"},
		},
	},
	"Cpu.Utilization": mp.Graphs{
		Label: "CPU Utilization",
		Unit:  "percentage",
		Metrics: []mp.Metrics{
			{Name: "utilization", Label: "Utilization"},
		},
	},
	"Disk.BytesCount": mp.Graphs{
		Label: "Disk Read Bytes Count",
		Unit:  "bytes",
		Metrics: []mp.Metrics{
			{Name: "read_bytes_count", Label: "Read Bytes Count", Type: "uint64"},
			{Name: "write_bytes_count", Label: "Write Bytes Count", Type: "uint64"},
		},
	},
	"Disk.OpsCount": mp.Graphs{
		Label: "Disk Read Ops Count",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "read_ops_count", Label: "Read Ops Count", Type: "uint64"},
			{Name: "write_ops_count", Label: "Write Ops Count", Type: "uint64"},
		},
	},
	"Network.BytesCount": mp.Graphs{
		Label: "Network Received Bytes Count",
		Unit:  "bytes",
		Metrics: []mp.Metrics{
			{Name: "received_bytes_count", Label: "Received Bytes Count", Type: "uint64"},
			{Name: "sent_bytes_count", Label: "Sent Bytes Count", Type: "uint64"},
		},
	},
	"Network.PacketsCount": mp.Graphs{
		Label: "Network Received Packets Count",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "received_packets_count", Label: "Received Packets Count", Type: "uint64"},
			{Name: "sent_packets_count", Label: "Sent Packets Count", Type: "uint64"},
		},
	},
}

// GraphDefinition is return graphdef
func (p ComputeEnginePlugin) GraphDefinition() map[string]mp.Graphs {
	return graphdef
}

func getLatestValue(listCall *monitoring.ProjectsTimeSeriesListCall, filter string, startTime string, endTime string, opts *Option) (interface{}, error) {
	res, err := listCall.Filter(filter).IntervalEndTime(endTime).IntervalStartTime(startTime).Do(*opts)

	if err != nil || res == nil {
		return 0, err
	}

	var sum interface{}
	p := res.TimeSeries[0].Points[0].Value
	if p.Int64Value != nil {
		sum = uint64(0)
	} else if p.DoubleValue != nil {
		sum = float64(0)
	}

	for _, series := range res.TimeSeries {
		valuePtr := series.Points[0].Value
		if valuePtr.Int64Value != nil {
			sum = sum.(uint64) + uint64(*valuePtr.Int64Value)
		} else if valuePtr.DoubleValue != nil {
			sum = sum.(float64) + *valuePtr.DoubleValue
		}
	}

	return sum, nil
}

func mkFilter(domain string, metricName string, instance string) string {
	filter := `metric.type = "` + domain + metricName + `"`
	switch domain {
	case computeDomain:
		filter += " AND metric.label.instance_name = " + instance
	}

	return filter
}

// FetchMetrics fetches metrics from Google Monitoring API
func (p ComputeEnginePlugin) FetchMetrics() (map[string]interface{}, error) {
	now := time.Now()
	formattedEnd := now.Format(zuluFormat)
	m, _ := time.ParseDuration(duration)
	formattedStart := now.Add(-m).Format(zuluFormat)
	listCall := p.MonitoringService.Projects.TimeSeries.List(p.Project)

	stat := map[string]interface{}{}
	for _, metricName := range []string{
		"/firewall/dropped_bytes_count",
		"/firewall/dropped_packets_count",
		"/instance/cpu/utilization",
		"/instance/disk/read_bytes_count",
		"/instance/disk/read_ops_count",
		"/instance/disk/write_bytes_count",
		"/instance/disk/write_ops_count",
		"/instance/network/received_bytes_count",
		"/instance/network/received_packets_count",
		"/instance/network/sent_bytes_count",
		"/instance/network/sent_packets_count",
	} {
		value, err := getLatestValue(listCall, mkFilter(computeDomain, metricName, p.InstanceName), formattedStart, formattedEnd, p.Option)
		if err != nil {
			continue
		}
		splited := strings.Split(metricName, "/")
		stat[splited[len(splited)-1]] = value
	}

	return stat, nil
}

func getMetaData(url string) string {
	httpClient := &http.Client{Timeout: time.Duration(10) * time.Second}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return ""
	}
	req.Header.Add("Metadata-Flavor", "Google")

	res, err := httpClient.Do(req)
	if err != nil {
		return ""
	}

	b, _ := ioutil.ReadAll(res.Body)
	return string(b)
}

func getProjectID() string {
	projectID := getMetaData("http://metadata.google.internal/computeMetadata/v1/project/project-id")

	if projectID == "" {
		return ""
	}

	return projectID
}

func getInstanceName() string {
	hostName := getMetaData("http://metadata.google.internal/computeMetadata/v1/instance/hostname")

	if hostName == "" {
		return ""
	}

	return strings.Split(hostName, ".")[0]
}

// Do the plugin
func Do() {
	optProject := flag.String("project", "", "Project No")
	optInstanceName := flag.String("instance-name", "", "Instance Name")

	optAPIKey := flag.String("api-key", "", "API key")
	optTempfile := flag.String("tempfile", "", "Temp file name")

	flag.Parse()

	if *optAPIKey == "" {
		fmt.Println("Errors:", errors.New("api-key is required"))
		return
	}

	// Auto detect projectID/instanceName unless specified
	projectID := *optProject
	instanceName := *optInstanceName
	if projectID == "" {
		projectID = getProjectID()
	}
	if instanceName == "" {
		instanceName = getInstanceName()
	}

	if projectID == "" || instanceName == "" {
		fmt.Println("Errors:", errors.New("can not get project id or instance name"))
	}

	ctx := context.Background()

	client, err := google.DefaultClient(ctx, monitoring.CloudPlatformScope)
	if err != nil {
		return
	}

	service, err := monitoring.New(client)
	if err != nil {
		return
	}

	var computeEngine = ComputeEnginePlugin{
		MonitoringService: service,
		Project:           "projects/" + projectID,
		InstanceName:      instanceName,
		Option:            &Option{Key: *optAPIKey},
	}

	helper := mp.NewMackerelPlugin(computeEngine)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-gcp-compute-engine-%s", computeEngine.InstanceName)
	}

	helper.Run()
}
<commit_msg>use Log package and exit by Log.Fatal*<commit_after>package gcpce

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"

	"golang.org/x/net/context"
	"golang.org/x/oauth2/google"

	"google.golang.org/api/monitoring/v3"

	mp "github.com/mackerelio/go-mackerel-plugin-helper"
)

const zuluFormat string = "2006-01-02T15:4:05Z"
const duration string = "3m0s"
const computeDomain string = "compute.googleapis.com"

// ComputeEnginePlugin is mackerel plugin for Google Compute Engine
type ComputeEnginePlugin struct {
	Project           string
	InstanceName      string
	MonitoringService *monitoring.Service
	Option            *Option
	Tempfile          string
}

// Option is optional argument to an API call
type Option struct {
	Key string
}

// Get returns key and value
func (c Option) Get() (string, string) {
	return "key", c.Key
}

var graphdef = map[string]mp.Graphs{
	"Firewall.DroppedBytesCount": mp.Graphs{
		Label: "FireWall Dropped Bytes Count",
		Unit:  "bytes",
		Metrics: []mp.Metrics{
			{Name: "dropped_bytes_count", Label: "Dropped Bytes Count", Type: "uint64"},
		},
	},
	"Firewall.DroppedPacketsCount": mp.Graphs{
		Label: "FireWall Dropped Packets Count",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "dropped_packets_count", Label: "Dropped Packets Count", Type: "uint64"},
		},
	},
	"Cpu.Utilization": mp.Graphs{
		Label: "CPU Utilization",
		Unit:  "percentage",
		Metrics: []mp.Metrics{
			{Name: "utilization", Label: "Utilization"},
		},
	},
	"Disk.BytesCount": mp.Graphs{
		Label: "Disk Read Bytes Count",
		Unit:  "bytes",
		Metrics: []mp.Metrics{
			{Name: "read_bytes_count", Label: "Read Bytes Count", Type: "uint64"},
			{Name: "write_bytes_count", Label: "Write Bytes Count", Type: "uint64"},
		},
	},
	"Disk.OpsCount": mp.Graphs{
		Label: "Disk Read Ops Count",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "read_ops_count", Label: "Read Ops Count", Type: "uint64"},
			{Name: "write_ops_count", Label: "Write Ops Count", Type: "uint64"},
		},
	},
	"Network.BytesCount": mp.Graphs{
		Label: "Network Received Bytes Count",
		Unit:  "bytes",
		Metrics: []mp.Metrics{
			{Name: "received_bytes_count", Label: "Received Bytes Count", Type: "uint64"},
			{Name: "sent_bytes_count", Label: "Sent Bytes Count", Type: "uint64"},
		},
	},
	"Network.PacketsCount": mp.Graphs{
		Label: "Network Received Packets Count",
		Unit:  "integer",
		Metrics: []mp.Metrics{
			{Name: "received_packets_count", Label: "Received Packets Count", Type: "uint64"},
			{Name: "sent_packets_count", Label: "Sent Packets Count", Type: "uint64"},
		},
	},
}

// GraphDefinition is return graphdef
func (p ComputeEnginePlugin) GraphDefinition() map[string]mp.Graphs {
	return graphdef
}

func getLatestValue(listCall *monitoring.ProjectsTimeSeriesListCall, filter string, startTime string, endTime string, opts *Option) (interface{}, error) {
	res, err := listCall.Filter(filter).IntervalEndTime(endTime).IntervalStartTime(startTime).Do(*opts)

	if err != nil || res == nil {
		return 0, err
	}

	var sum interface{}
	p := res.TimeSeries[0].Points[0].Value
	if p.Int64Value != nil {
		sum = uint64(0)
	} else if p.DoubleValue != nil {
		sum = float64(0)
	}

	for _, series := range res.TimeSeries {
		valuePtr := series.Points[0].Value
		if valuePtr.Int64Value != nil {
			sum = sum.(uint64) + uint64(*valuePtr.Int64Value)
		} else if valuePtr.DoubleValue != nil {
			sum = sum.(float64) + *valuePtr.DoubleValue
		}
	}

	return sum, nil
}

func mkFilter(domain string, metricName string, instance string) string {
	filter := `metric.type = "` + domain + metricName + `"`
	switch domain {
	case computeDomain:
		filter += " AND metric.label.instance_name = " + instance
	}

	return filter
}

// FetchMetrics fetches metrics from Google Monitoring API
func (p ComputeEnginePlugin) FetchMetrics() (map[string]interface{}, error) {
	now := time.Now()
	formattedEnd := now.Format(zuluFormat)
	m, _ := time.ParseDuration(duration)
	formattedStart := now.Add(-m).Format(zuluFormat)
	listCall := p.MonitoringService.Projects.TimeSeries.List(p.Project)

	stat := map[string]interface{}{}
	for _, metricName := range []string{
		"/firewall/dropped_bytes_count",
		"/firewall/dropped_packets_count",
		"/instance/cpu/utilization",
		"/instance/disk/read_bytes_count",
		"/instance/disk/read_ops_count",
		"/instance/disk/write_bytes_count",
		"/instance/disk/write_ops_count",
		"/instance/network/received_bytes_count",
		"/instance/network/received_packets_count",
		"/instance/network/sent_bytes_count",
		"/instance/network/sent_packets_count",
	} {
		value, err := getLatestValue(listCall, mkFilter(computeDomain, metricName, p.InstanceName), formattedStart, formattedEnd, p.Option)
		if err != nil {
			continue
		}
		splited := strings.Split(metricName, "/")
		stat[splited[len(splited)-1]] = value
	}

	return stat, nil
}

func getMetaData(url string) string {
	httpClient := &http.Client{Timeout: time.Duration(10) * time.Second}

	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return ""
	}
	req.Header.Add("Metadata-Flavor", "Google")

	res, err := httpClient.Do(req)
	if err != nil {
		return ""
	}

	b, _ := ioutil.ReadAll(res.Body)
	return string(b)
}

func getProjectID() string {
	projectID := getMetaData("http://metadata.google.internal/computeMetadata/v1/project/project-id")

	if projectID == "" {
		return ""
	}

	return projectID
}

func getInstanceName() string {
	hostName := getMetaData("http://metadata.google.internal/computeMetadata/v1/instance/hostname")

	if hostName == "" {
		return ""
	}

	return strings.Split(hostName, ".")[0]
}

// Do the plugin
func Do() {
	optProject := flag.String("project", "", "Project No")
	optInstanceName := flag.String("instance-name", "", "Instance Name")

	optAPIKey := flag.String("api-key", "", "API key")
	optTempfile := flag.String("tempfile", "", "Temp file name")

	flag.Parse()

	if *optAPIKey == "" {
		log.Fatalln("-api-key is required")
	}

	// Auto detect projectID/instanceName unless specified
	projectID := *optProject
	instanceName := *optInstanceName
	if projectID == "" {
		projectID = getProjectID()
	}
	if instanceName == "" {
		instanceName = getInstanceName()
	}

	if projectID == "" || instanceName == "" {
		log.Fatalln("Could not get project id and/or instance name")
	}

	ctx := context.Background()

	client, err := google.DefaultClient(ctx, monitoring.CloudPlatformScope)
	if err != nil {
		log.Fatalln("Error while preparing Google OAuth client:", err)
	}

	service, err := monitoring.New(client)
	if err != nil {
		log.Fatalln("Error while preparing monitoring client:", err)
	}

	var computeEngine = ComputeEnginePlugin{
		MonitoringService: service,
		Project:           "projects/" + projectID,
		InstanceName:      instanceName,
		Option:            &Option{Key: *optAPIKey},
	}

	helper := mp.NewMackerelPlugin(computeEngine)
	if *optTempfile != "" {
		helper.Tempfile = *optTempfile
	} else {
		helper.Tempfile = fmt.Sprintf("/tmp/mackerel-plugin-gcp-compute-engine-%s", computeEngine.InstanceName)
	}

	helper.Run()
}
<|endoftext|>


<commit_before>package daemon // import "github.com/docker/docker/daemon"

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

	containertypes "github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/docker/container"
	"github.com/docker/docker/daemon/network"
	"github.com/docker/docker/errdefs"
	"github.com/docker/docker/image"
	"github.com/docker/docker/opts"
	"github.com/docker/docker/pkg/signal"
	"github.com/docker/docker/pkg/system"
	"github.com/docker/docker/pkg/truncindex"
	"github.com/docker/docker/runconfig"
	volumemounts "github.com/docker/docker/volume/mounts"
	"github.com/docker/go-connections/nat"
	"github.com/opencontainers/selinux/go-selinux/label"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// GetContainer looks for a container using the provided information, which could be
// one of the following inputs from the caller:
//  - A full container ID, which will exact match a container in daemon's list
//  - A container name, which will only exact match via the GetByName() function
//  - A partial container ID prefix (e.g. short ID) of any length that is
//    unique enough to only return a single container object
//  If none of these searches succeed, an error is returned
func (daemon *Daemon) GetContainer(prefixOrName string) (*container.Container, error) {
	if len(prefixOrName) == 0 {
		return nil, errors.WithStack(invalidIdentifier(prefixOrName))
	}

	if containerByID := daemon.containers.Get(prefixOrName); containerByID != nil {
		// prefix is an exact match to a full container ID
		return containerByID, nil
	}

	// GetByName will match only an exact name provided; we ignore errors
	if containerByName, _ := daemon.GetByName(prefixOrName); containerByName != nil {
		// prefix is an exact match to a full container Name
		return containerByName, nil
	}

	containerID, indexError := daemon.idIndex.Get(prefixOrName)
	if indexError != nil {
		// When truncindex defines an error type, use that instead
		if indexError == truncindex.ErrNotExist {
			return nil, containerNotFound(prefixOrName)
		}
		return nil, errdefs.System(indexError)
	}
	return daemon.containers.Get(containerID), nil
}

// checkContainer make sure the specified container validates the specified conditions
func (daemon *Daemon) checkContainer(container *container.Container, conditions ...func(*container.Container) error) error {
	for _, condition := range conditions {
		if err := condition(container); err != nil {
			return err
		}
	}
	return nil
}

// Exists returns a true if a container of the specified ID or name exists,
// false otherwise.
func (daemon *Daemon) Exists(id string) bool {
	c, _ := daemon.GetContainer(id)
	return c != nil
}

// IsPaused returns a bool indicating if the specified container is paused.
func (daemon *Daemon) IsPaused(id string) bool {
	c, _ := daemon.GetContainer(id)
	return c.State.IsPaused()
}

func (daemon *Daemon) containerRoot(id string) string {
	return filepath.Join(daemon.repository, id)
}

// Load reads the contents of a container from disk
// This is typically done at startup.
func (daemon *Daemon) load(id string) (*container.Container, error) {
	container := daemon.newBaseContainer(id)

	if err := container.FromDisk(); err != nil {
		return nil, err
	}
	if err := label.ReserveLabel(container.ProcessLabel); err != nil {
		return nil, err
	}

	if container.ID != id {
		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
	}

	return container, nil
}

// Register makes a container object usable by the daemon as <container.ID>
func (daemon *Daemon) Register(c *container.Container) error {
	// Attach to stdout and stderr
	if c.Config.OpenStdin {
		c.StreamConfig.NewInputPipes()
	} else {
		c.StreamConfig.NewNopInputPipe()
	}

	// once in the memory store it is visible to other goroutines
	// grab a Lock until it has been checkpointed to avoid races
	c.Lock()
	defer c.Unlock()

	daemon.containers.Add(c.ID, c)
	daemon.idIndex.Add(c.ID)
	return c.CheckpointTo(daemon.containersReplica)
}

func (daemon *Daemon) newContainer(name string, operatingSystem string, config *containertypes.Config, hostConfig *containertypes.HostConfig, imgID image.ID, managed bool) (*container.Container, error) {
	var (
		id             string
		err            error
		noExplicitName = name == ""
	)
	id, name, err = daemon.generateIDAndName(name)
	if err != nil {
		return nil, err
	}

	if hostConfig.NetworkMode.IsHost() {
		if config.Hostname == "" {
			config.Hostname, err = os.Hostname()
			if err != nil {
				return nil, errdefs.System(err)
			}
		}
	} else {
		daemon.generateHostname(id, config)
	}
	entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd)

	base := daemon.newBaseContainer(id)
	base.Created = time.Now().UTC()
	base.Managed = managed
	base.Path = entrypoint
	base.Args = args //FIXME: de-duplicate from config
	base.Config = config
	base.HostConfig = &containertypes.HostConfig{}
	base.ImageID = imgID
	base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
	base.Name = name
	base.Driver = daemon.imageService.GraphDriverForOS(operatingSystem)
	base.OS = operatingSystem
	return base, err
}

// GetByName returns a container given a name.
func (daemon *Daemon) GetByName(name string) (*container.Container, error) {
	if len(name) == 0 {
		return nil, fmt.Errorf("No container name supplied")
	}
	fullName := name
	if name[0] != '/' {
		fullName = "/" + name
	}
	id, err := daemon.containersReplica.Snapshot().GetID(fullName)
	if err != nil {
		return nil, fmt.Errorf("Could not find entity for %s", name)
	}
	e := daemon.containers.Get(id)
	if e == nil {
		return nil, fmt.Errorf("Could not find container for entity id %s", id)
	}
	return e, nil
}

// newBaseContainer creates a new container with its initial
// configuration based on the root storage from the daemon.
func (daemon *Daemon) newBaseContainer(id string) *container.Container {
	return container.NewBaseContainer(id, daemon.containerRoot(id))
}

func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint strslice.StrSlice, configCmd strslice.StrSlice) (string, []string) {
	if len(configEntrypoint) != 0 {
		return configEntrypoint[0], append(configEntrypoint[1:], configCmd...)
	}
	return configCmd[0], configCmd[1:]
}

func (daemon *Daemon) generateHostname(id string, config *containertypes.Config) {
	// Generate default hostname
	if config.Hostname == "" {
		config.Hostname = id[:12]
	}
}

func (daemon *Daemon) setSecurityOptions(container *container.Container, hostConfig *containertypes.HostConfig) error {
	container.Lock()
	defer container.Unlock()
	return daemon.parseSecurityOpt(container, hostConfig)
}

func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *containertypes.HostConfig) error {
	// Do not lock while creating volumes since this could be calling out to external plugins
	// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
	if err := daemon.registerMountPoints(container, hostConfig); err != nil {
		return err
	}

	container.Lock()
	defer container.Unlock()

	// Register any links from the host config before starting the container
	if err := daemon.registerLinks(container, hostConfig); err != nil {
		return err
	}

	runconfig.SetDefaultNetModeIfBlank(hostConfig)
	container.HostConfig = hostConfig
	return container.CheckpointTo(daemon.containersReplica)
}

// verifyContainerSettings performs validation of the hostconfig and config
// structures.
func (daemon *Daemon) verifyContainerSettings(platform string, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) (warnings []string, err error) {
	// First perform verification of settings common across all platforms.
	if config != nil {
		if config.WorkingDir != "" {
			wdInvalid := false
			if runtime.GOOS == platform {
				config.WorkingDir = filepath.FromSlash(config.WorkingDir) // Ensure in platform semantics
				if !system.IsAbs(config.WorkingDir) {
					wdInvalid = true
				}
			} else {
				// LCOW. Force Unix semantics
				config.WorkingDir = strings.Replace(config.WorkingDir, string(os.PathSeparator), "/", -1)
				if !path.IsAbs(config.WorkingDir) {
					wdInvalid = true
				}
			}
			if wdInvalid {
				return nil, fmt.Errorf("the working directory '%s' is invalid, it needs to be an absolute path", config.WorkingDir)
			}
		}

		if len(config.StopSignal) > 0 {
			_, err := signal.ParseSignal(config.StopSignal)
			if err != nil {
				return nil, err
			}
		}

		// Validate if Env contains empty variable or not (e.g., ``, `=foo`)
		for _, env := range config.Env {
			if _, err := opts.ValidateEnv(env); err != nil {
				return nil, err
			}
		}

		if err := validateHealthCheck(config.Healthcheck); err != nil {
			return nil, err
		}
	}

	if hostConfig == nil {
		return nil, nil
	}

	if hostConfig.AutoRemove && !hostConfig.RestartPolicy.IsNone() {
		return nil, errors.Errorf("can't create 'AutoRemove' container with restart policy")
	}

	// Validate mounts; check if host directories still exist
	parser := volumemounts.NewParser(platform)
	for _, cfg := range hostConfig.Mounts {
		if err := parser.ValidateMountConfig(&cfg); err != nil {
			return nil, err
		}
	}

	for _, extraHost := range hostConfig.ExtraHosts {
		if _, err := opts.ValidateExtraHost(extraHost); err != nil {
			return nil, err
		}
	}

	for port := range hostConfig.PortBindings {
		_, portStr := nat.SplitProtoPort(string(port))
		if _, err := nat.ParsePort(portStr); err != nil {
			return nil, errors.Errorf("invalid port specification: %q", portStr)
		}
		for _, pb := range hostConfig.PortBindings[port] {
			_, err := nat.NewPort(nat.SplitProtoPort(pb.HostPort))
			if err != nil {
				return nil, errors.Errorf("invalid port specification: %q", pb.HostPort)
			}
		}
	}

	p := hostConfig.RestartPolicy

	switch p.Name {
	case "always", "unless-stopped", "no":
		if p.MaximumRetryCount != 0 {
			return nil, errors.Errorf("maximum retry count cannot be used with restart policy '%s'", p.Name)
		}
	case "on-failure":
		if p.MaximumRetryCount < 0 {
			return nil, errors.Errorf("maximum retry count cannot be negative")
		}
	case "":
		// do nothing
	default:
		return nil, errors.Errorf("invalid restart policy '%s'", p.Name)
	}

	if !hostConfig.Isolation.IsValid() {
		return nil, errors.Errorf("invalid isolation '%s' on %s", hostConfig.Isolation, runtime.GOOS)
	}

	// Now do platform-specific verification
	warnings, err = verifyPlatformContainerSettings(daemon, hostConfig, update)
	for _, w := range warnings {
		logrus.Warn(w)
	}
	return warnings, err
}

// validateHealthCheck validates the healthcheck params of Config
func validateHealthCheck(healthConfig *containertypes.HealthConfig) error {
	if healthConfig == nil {
		return nil
	}
	if healthConfig.Interval != 0 && healthConfig.Interval < containertypes.MinimumDuration {
		return errors.Errorf("Interval in Healthcheck cannot be less than %s", containertypes.MinimumDuration)
	}
	if healthConfig.Timeout != 0 && healthConfig.Timeout < containertypes.MinimumDuration {
		return errors.Errorf("Timeout in Healthcheck cannot be less than %s", containertypes.MinimumDuration)
	}
	if healthConfig.Retries < 0 {
		return errors.Errorf("Retries in Healthcheck cannot be negative")
	}
	if healthConfig.StartPeriod != 0 && healthConfig.StartPeriod < containertypes.MinimumDuration {
		return errors.Errorf("StartPeriod in Healthcheck cannot be less than %s", containertypes.MinimumDuration)
	}
	return nil
}
<commit_msg>Extract restart-policy-validation to a function<commit_after>package daemon // import "github.com/docker/docker/daemon"

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

	containertypes "github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/strslice"
	"github.com/docker/docker/container"
	"github.com/docker/docker/daemon/network"
	"github.com/docker/docker/errdefs"
	"github.com/docker/docker/image"
	"github.com/docker/docker/opts"
	"github.com/docker/docker/pkg/signal"
	"github.com/docker/docker/pkg/system"
	"github.com/docker/docker/pkg/truncindex"
	"github.com/docker/docker/runconfig"
	volumemounts "github.com/docker/docker/volume/mounts"
	"github.com/docker/go-connections/nat"
	"github.com/opencontainers/selinux/go-selinux/label"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// GetContainer looks for a container using the provided information, which could be
// one of the following inputs from the caller:
//  - A full container ID, which will exact match a container in daemon's list
//  - A container name, which will only exact match via the GetByName() function
//  - A partial container ID prefix (e.g. short ID) of any length that is
//    unique enough to only return a single container object
//  If none of these searches succeed, an error is returned
func (daemon *Daemon) GetContainer(prefixOrName string) (*container.Container, error) {
	if len(prefixOrName) == 0 {
		return nil, errors.WithStack(invalidIdentifier(prefixOrName))
	}

	if containerByID := daemon.containers.Get(prefixOrName); containerByID != nil {
		// prefix is an exact match to a full container ID
		return containerByID, nil
	}

	// GetByName will match only an exact name provided; we ignore errors
	if containerByName, _ := daemon.GetByName(prefixOrName); containerByName != nil {
		// prefix is an exact match to a full container Name
		return containerByName, nil
	}

	containerID, indexError := daemon.idIndex.Get(prefixOrName)
	if indexError != nil {
		// When truncindex defines an error type, use that instead
		if indexError == truncindex.ErrNotExist {
			return nil, containerNotFound(prefixOrName)
		}
		return nil, errdefs.System(indexError)
	}
	return daemon.containers.Get(containerID), nil
}

// checkContainer make sure the specified container validates the specified conditions
func (daemon *Daemon) checkContainer(container *container.Container, conditions ...func(*container.Container) error) error {
	for _, condition := range conditions {
		if err := condition(container); err != nil {
			return err
		}
	}
	return nil
}

// Exists returns a true if a container of the specified ID or name exists,
// false otherwise.
func (daemon *Daemon) Exists(id string) bool {
	c, _ := daemon.GetContainer(id)
	return c != nil
}

// IsPaused returns a bool indicating if the specified container is paused.
func (daemon *Daemon) IsPaused(id string) bool {
	c, _ := daemon.GetContainer(id)
	return c.State.IsPaused()
}

func (daemon *Daemon) containerRoot(id string) string {
	return filepath.Join(daemon.repository, id)
}

// Load reads the contents of a container from disk
// This is typically done at startup.
func (daemon *Daemon) load(id string) (*container.Container, error) {
	container := daemon.newBaseContainer(id)

	if err := container.FromDisk(); err != nil {
		return nil, err
	}
	if err := label.ReserveLabel(container.ProcessLabel); err != nil {
		return nil, err
	}

	if container.ID != id {
		return container, fmt.Errorf("Container %s is stored at %s", container.ID, id)
	}

	return container, nil
}

// Register makes a container object usable by the daemon as <container.ID>
func (daemon *Daemon) Register(c *container.Container) error {
	// Attach to stdout and stderr
	if c.Config.OpenStdin {
		c.StreamConfig.NewInputPipes()
	} else {
		c.StreamConfig.NewNopInputPipe()
	}

	// once in the memory store it is visible to other goroutines
	// grab a Lock until it has been checkpointed to avoid races
	c.Lock()
	defer c.Unlock()

	daemon.containers.Add(c.ID, c)
	daemon.idIndex.Add(c.ID)
	return c.CheckpointTo(daemon.containersReplica)
}

func (daemon *Daemon) newContainer(name string, operatingSystem string, config *containertypes.Config, hostConfig *containertypes.HostConfig, imgID image.ID, managed bool) (*container.Container, error) {
	var (
		id             string
		err            error
		noExplicitName = name == ""
	)
	id, name, err = daemon.generateIDAndName(name)
	if err != nil {
		return nil, err
	}

	if hostConfig.NetworkMode.IsHost() {
		if config.Hostname == "" {
			config.Hostname, err = os.Hostname()
			if err != nil {
				return nil, errdefs.System(err)
			}
		}
	} else {
		daemon.generateHostname(id, config)
	}
	entrypoint, args := daemon.getEntrypointAndArgs(config.Entrypoint, config.Cmd)

	base := daemon.newBaseContainer(id)
	base.Created = time.Now().UTC()
	base.Managed = managed
	base.Path = entrypoint
	base.Args = args //FIXME: de-duplicate from config
	base.Config = config
	base.HostConfig = &containertypes.HostConfig{}
	base.ImageID = imgID
	base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
	base.Name = name
	base.Driver = daemon.imageService.GraphDriverForOS(operatingSystem)
	base.OS = operatingSystem
	return base, err
}

// GetByName returns a container given a name.
func (daemon *Daemon) GetByName(name string) (*container.Container, error) {
	if len(name) == 0 {
		return nil, fmt.Errorf("No container name supplied")
	}
	fullName := name
	if name[0] != '/' {
		fullName = "/" + name
	}
	id, err := daemon.containersReplica.Snapshot().GetID(fullName)
	if err != nil {
		return nil, fmt.Errorf("Could not find entity for %s", name)
	}
	e := daemon.containers.Get(id)
	if e == nil {
		return nil, fmt.Errorf("Could not find container for entity id %s", id)
	}
	return e, nil
}

// newBaseContainer creates a new container with its initial
// configuration based on the root storage from the daemon.
func (daemon *Daemon) newBaseContainer(id string) *container.Container {
	return container.NewBaseContainer(id, daemon.containerRoot(id))
}

func (daemon *Daemon) getEntrypointAndArgs(configEntrypoint strslice.StrSlice, configCmd strslice.StrSlice) (string, []string) {
	if len(configEntrypoint) != 0 {
		return configEntrypoint[0], append(configEntrypoint[1:], configCmd...)
	}
	return configCmd[0], configCmd[1:]
}

func (daemon *Daemon) generateHostname(id string, config *containertypes.Config) {
	// Generate default hostname
	if config.Hostname == "" {
		config.Hostname = id[:12]
	}
}

func (daemon *Daemon) setSecurityOptions(container *container.Container, hostConfig *containertypes.HostConfig) error {
	container.Lock()
	defer container.Unlock()
	return daemon.parseSecurityOpt(container, hostConfig)
}

func (daemon *Daemon) setHostConfig(container *container.Container, hostConfig *containertypes.HostConfig) error {
	// Do not lock while creating volumes since this could be calling out to external plugins
	// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
	if err := daemon.registerMountPoints(container, hostConfig); err != nil {
		return err
	}

	container.Lock()
	defer container.Unlock()

	// Register any links from the host config before starting the container
	if err := daemon.registerLinks(container, hostConfig); err != nil {
		return err
	}

	runconfig.SetDefaultNetModeIfBlank(hostConfig)
	container.HostConfig = hostConfig
	return container.CheckpointTo(daemon.containersReplica)
}

// verifyContainerSettings performs validation of the hostconfig and config
// structures.
func (daemon *Daemon) verifyContainerSettings(platform string, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) (warnings []string, err error) {
	// First perform verification of settings common across all platforms.
	if config != nil {
		if config.WorkingDir != "" {
			wdInvalid := false
			if runtime.GOOS == platform {
				config.WorkingDir = filepath.FromSlash(config.WorkingDir) // Ensure in platform semantics
				if !system.IsAbs(config.WorkingDir) {
					wdInvalid = true
				}
			} else {
				// LCOW. Force Unix semantics
				config.WorkingDir = strings.Replace(config.WorkingDir, string(os.PathSeparator), "/", -1)
				if !path.IsAbs(config.WorkingDir) {
					wdInvalid = true
				}
			}
			if wdInvalid {
				return nil, fmt.Errorf("the working directory '%s' is invalid, it needs to be an absolute path", config.WorkingDir)
			}
		}

		if len(config.StopSignal) > 0 {
			_, err := signal.ParseSignal(config.StopSignal)
			if err != nil {
				return nil, err
			}
		}

		// Validate if Env contains empty variable or not (e.g., ``, `=foo`)
		for _, env := range config.Env {
			if _, err := opts.ValidateEnv(env); err != nil {
				return nil, err
			}
		}

		if err := validateHealthCheck(config.Healthcheck); err != nil {
			return nil, err
		}
	}

	if hostConfig == nil {
		return nil, nil
	}

	if hostConfig.AutoRemove && !hostConfig.RestartPolicy.IsNone() {
		return nil, errors.Errorf("can't create 'AutoRemove' container with restart policy")
	}

	// Validate mounts; check if host directories still exist
	parser := volumemounts.NewParser(platform)
	for _, cfg := range hostConfig.Mounts {
		if err := parser.ValidateMountConfig(&cfg); err != nil {
			return nil, err
		}
	}

	for _, extraHost := range hostConfig.ExtraHosts {
		if _, err := opts.ValidateExtraHost(extraHost); err != nil {
			return nil, err
		}
	}

	for port := range hostConfig.PortBindings {
		_, portStr := nat.SplitProtoPort(string(port))
		if _, err := nat.ParsePort(portStr); err != nil {
			return nil, errors.Errorf("invalid port specification: %q", portStr)
		}
		for _, pb := range hostConfig.PortBindings[port] {
			_, err := nat.NewPort(nat.SplitProtoPort(pb.HostPort))
			if err != nil {
				return nil, errors.Errorf("invalid port specification: %q", pb.HostPort)
			}
		}
	}

	if err := validateRestartPolicy(hostConfig.RestartPolicy); err != nil {
		return nil, err
	}
	if !hostConfig.Isolation.IsValid() {
		return nil, errors.Errorf("invalid isolation '%s' on %s", hostConfig.Isolation, runtime.GOOS)
	}

	// Now do platform-specific verification
	warnings, err = verifyPlatformContainerSettings(daemon, hostConfig, update)
	for _, w := range warnings {
		logrus.Warn(w)
	}
	return warnings, err
}

// validateHealthCheck validates the healthcheck params of Config
func validateHealthCheck(healthConfig *containertypes.HealthConfig) error {
	if healthConfig == nil {
		return nil
	}
	if healthConfig.Interval != 0 && healthConfig.Interval < containertypes.MinimumDuration {
		return errors.Errorf("Interval in Healthcheck cannot be less than %s", containertypes.MinimumDuration)
	}
	if healthConfig.Timeout != 0 && healthConfig.Timeout < containertypes.MinimumDuration {
		return errors.Errorf("Timeout in Healthcheck cannot be less than %s", containertypes.MinimumDuration)
	}
	if healthConfig.Retries < 0 {
		return errors.Errorf("Retries in Healthcheck cannot be negative")
	}
	if healthConfig.StartPeriod != 0 && healthConfig.StartPeriod < containertypes.MinimumDuration {
		return errors.Errorf("StartPeriod in Healthcheck cannot be less than %s", containertypes.MinimumDuration)
	}
	return nil
}

func validateRestartPolicy(policy containertypes.RestartPolicy) error {
	switch policy.Name {
	case "always", "unless-stopped", "no":
		if policy.MaximumRetryCount != 0 {
			return errors.Errorf("maximum retry count cannot be used with restart policy '%s'", policy.Name)
		}
	case "on-failure":
		if policy.MaximumRetryCount < 0 {
			return errors.Errorf("maximum retry count cannot be negative")
		}
	case "":
		// do nothing
		return nil
	default:
		return errors.Errorf("invalid restart policy '%s'", policy.Name)
	}
	return nil
}
<|endoftext|>


<commit_before>// +build !windows

package daemon // import "github.com/docker/docker/daemon"

import (
	"context"
	"fmt"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/docker/docker/api/types"
	containertypes "github.com/docker/docker/api/types/container"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/sysinfo"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// fillPlatformInfo fills the platform related info.
func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
	v.CgroupDriver = daemon.getCgroupDriver()
	v.CgroupVersion = "1"
	if sysInfo.CgroupUnified {
		v.CgroupVersion = "2"
	}

	v.MemoryLimit = sysInfo.MemoryLimit
	v.SwapLimit = sysInfo.SwapLimit
	v.KernelMemory = sysInfo.KernelMemory
	v.KernelMemoryTCP = sysInfo.KernelMemoryTCP
	v.OomKillDisable = sysInfo.OomKillDisable
	v.CPUCfsPeriod = sysInfo.CPUCfsPeriod
	v.CPUCfsQuota = sysInfo.CPUCfsQuota
	v.CPUShares = sysInfo.CPUShares
	v.CPUSet = sysInfo.Cpuset
	v.PidsLimit = sysInfo.PidsLimit
	v.Runtimes = daemon.configStore.GetAllRuntimes()
	v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName()
	v.InitBinary = daemon.configStore.GetInitPath()

	defaultRuntimeBinary := daemon.configStore.GetRuntime(v.DefaultRuntime).Path
	if rv, err := exec.Command(defaultRuntimeBinary, "--version").Output(); err == nil {
		if _, _, commit, err := parseRuntimeVersion(string(rv)); err != nil {
			logrus.Warnf("failed to parse %s version: %v", defaultRuntimeBinary, err)
			v.RuncCommit.ID = "N/A"
		} else {
			v.RuncCommit.ID = commit
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %v", defaultRuntimeBinary, err)
		v.RuncCommit.ID = "N/A"
	}

	// runc is now shipped as a separate package. Set "expected" to same value
	// as "ID" to prevent clients from reporting a version-mismatch
	v.RuncCommit.Expected = v.RuncCommit.ID

	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
		v.ContainerdCommit.ID = rv.Revision
	} else {
		logrus.Warnf("failed to retrieve containerd version: %v", err)
		v.ContainerdCommit.ID = "N/A"
	}

	// containerd is now shipped as a separate package. Set "expected" to same
	// value as "ID" to prevent clients from reporting a version-mismatch
	v.ContainerdCommit.Expected = v.ContainerdCommit.ID

	// TODO is there still a need to check the expected version for tini?
	// if not, we can change this, and just set "Expected" to v.InitCommit.ID
	v.InitCommit.Expected = dockerversion.InitCommitID

	defaultInitBinary := daemon.configStore.GetInitPath()
	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
		if _, commit, err := parseInitVersion(string(rv)); err != nil {
			logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err)
			v.InitCommit.ID = "N/A"
		} else {
			v.InitCommit.ID = commit
			if len(dockerversion.InitCommitID) > len(commit) {
				v.InitCommit.Expected = dockerversion.InitCommitID[0:len(commit)]
			}
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
		v.InitCommit.ID = "N/A"
	}

	if v.CgroupDriver == cgroupNoneDriver {
		if v.CgroupVersion == "2" {
			v.Warnings = append(v.Warnings, "WARNING: Running in rootless-mode without cgroup. To enable cgroup in rootless-mode, you need to set exec-opt \"native.cgroupdriver=systemd\".")
		} else {
			v.Warnings = append(v.Warnings, "WARNING: Running in rootless-mode without cgroup. To enable cgroup in rootless-mode, you need to boot the system in cgroup v2 mode and set exec-opt \"native.cgroupdriver=systemd\".")
		}
	} else {
		if !v.MemoryLimit {
			v.Warnings = append(v.Warnings, "WARNING: No memory limit support")
		}
		if !v.SwapLimit {
			v.Warnings = append(v.Warnings, "WARNING: No swap limit support")
		}
		if !v.KernelMemory {
			v.Warnings = append(v.Warnings, "WARNING: No kernel memory limit support")
		}
		if !v.KernelMemoryTCP {
			v.Warnings = append(v.Warnings, "WARNING: No kernel memory TCP limit support")
		}
		if !v.OomKillDisable {
			v.Warnings = append(v.Warnings, "WARNING: No oom kill disable support")
		}
		if !v.CPUCfsQuota {
			v.Warnings = append(v.Warnings, "WARNING: No cpu cfs quota support")
		}
		if !v.CPUCfsPeriod {
			v.Warnings = append(v.Warnings, "WARNING: No cpu cfs period support")
		}
		if !v.CPUShares {
			v.Warnings = append(v.Warnings, "WARNING: No cpu shares support")
		}
		if !v.CPUSet {
			v.Warnings = append(v.Warnings, "WARNING: No cpuset support")
		}
		if v.CgroupVersion == "2" {
			v.Warnings = append(v.Warnings, "WARNING: Support for cgroup v2 is experimental")
		}
	}
	if !v.IPv4Forwarding {
		v.Warnings = append(v.Warnings, "WARNING: IPv4 forwarding is disabled")
	}
	if !v.BridgeNfIptables {
		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-iptables is disabled")
	}
	if !v.BridgeNfIP6tables {
		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-ip6tables is disabled")
	}
}

func (daemon *Daemon) fillPlatformVersion(v *types.Version) {
	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
		v.Components = append(v.Components, types.ComponentVersion{
			Name:    "containerd",
			Version: rv.Version,
			Details: map[string]string{
				"GitCommit": rv.Revision,
			},
		})
	}

	defaultRuntime := daemon.configStore.GetDefaultRuntimeName()
	defaultRuntimeBinary := daemon.configStore.GetRuntime(defaultRuntime).Path
	if rv, err := exec.Command(defaultRuntimeBinary, "--version").Output(); err == nil {
		if _, ver, commit, err := parseRuntimeVersion(string(rv)); err != nil {
			logrus.Warnf("failed to parse %s version: %v", defaultRuntimeBinary, err)
		} else {
			v.Components = append(v.Components, types.ComponentVersion{
				Name:    defaultRuntime,
				Version: ver,
				Details: map[string]string{
					"GitCommit": commit,
				},
			})
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %v", defaultRuntimeBinary, err)
	}

	defaultInitBinary := daemon.configStore.GetInitPath()
	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
		if ver, commit, err := parseInitVersion(string(rv)); err != nil {
			logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err)
		} else {
			v.Components = append(v.Components, types.ComponentVersion{
				Name:    filepath.Base(defaultInitBinary),
				Version: ver,
				Details: map[string]string{
					"GitCommit": commit,
				},
			})
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
	}
}

func fillDriverWarnings(v *types.Info) {
	for _, pair := range v.DriverStatus {
		if pair[0] == "Data loop file" {
			msg := fmt.Sprintf("WARNING: %s: usage of loopback devices is "+
				"strongly discouraged for production use.\n         "+
				"Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.", v.Driver)

			v.Warnings = append(v.Warnings, msg)
			continue
		}
		if pair[0] == "Supports d_type" && pair[1] == "false" {
			backingFs := getBackingFs(v)

			msg := fmt.Sprintf("WARNING: %s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.\n", v.Driver, backingFs)
			if backingFs == "xfs" {
				msg += "         Reformat the filesystem with ftype=1 to enable d_type support.\n"
			}
			msg += "         Running without d_type support will not be supported in future releases."

			v.Warnings = append(v.Warnings, msg)
			continue
		}
	}
}

func getBackingFs(v *types.Info) string {
	for _, pair := range v.DriverStatus {
		if pair[0] == "Backing Filesystem" {
			return pair[1]
		}
	}
	return ""
}

// parseInitVersion parses a Tini version string, and extracts the "version"
// and "git commit" from the output.
//
// Output example from `docker-init --version`:
//
//     tini version 0.18.0 - git.fec3683
func parseInitVersion(v string) (version string, commit string, err error) {
	parts := strings.Split(v, " - ")

	if len(parts) >= 2 {
		gitParts := strings.Split(strings.TrimSpace(parts[1]), ".")
		if len(gitParts) == 2 && gitParts[0] == "git" {
			commit = gitParts[1]
		}
	}
	parts[0] = strings.TrimSpace(parts[0])
	if strings.HasPrefix(parts[0], "tini version ") {
		version = strings.TrimPrefix(parts[0], "tini version ")
	}
	if version == "" && commit == "" {
		err = errors.Errorf("unknown output format: %s", v)
	}
	return version, commit, err
}

// parseRuntimeVersion parses the output of `[runtime] --version` and extracts the
// "name", "version" and "git commit" from the output.
//
// Output example from `runc --version`:
//
//   runc version 1.0.0-rc5+dev
//   commit: 69663f0bd4b60df09991c08812a60108003fa340
//   spec: 1.0.0
func parseRuntimeVersion(v string) (runtime string, version string, commit string, err error) {
	lines := strings.Split(strings.TrimSpace(v), "\n")
	for _, line := range lines {
		if strings.Contains(line, "version") {
			s := strings.Split(line, "version")
			runtime = strings.TrimSpace(s[0])
			version = strings.TrimSpace(s[len(s)-1])
			continue
		}
		if strings.HasPrefix(line, "commit:") {
			commit = strings.TrimSpace(strings.TrimPrefix(line, "commit:"))
			continue
		}
	}
	if version == "" && commit == "" {
		err = errors.Errorf("unknown output format: %s", v)
	}
	return runtime, version, commit, err
}

func (daemon *Daemon) cgroupNamespacesEnabled(sysInfo *sysinfo.SysInfo) bool {
	return sysInfo.CgroupNamespaces && containertypes.CgroupnsMode(daemon.configStore.CgroupNamespaceMode).IsPrivate()
}

// Rootless returns true if daemon is running in rootless mode
func (daemon *Daemon) Rootless() bool {
	return daemon.configStore.Rootless
}
<commit_msg>info: improve "WARNING: Running in rootless-mode without cgroup"<commit_after>// +build !windows

package daemon // import "github.com/docker/docker/daemon"

import (
	"context"
	"fmt"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/docker/docker/api/types"
	containertypes "github.com/docker/docker/api/types/container"
	"github.com/docker/docker/dockerversion"
	"github.com/docker/docker/pkg/sysinfo"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
)

// fillPlatformInfo fills the platform related info.
func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
	v.CgroupDriver = daemon.getCgroupDriver()
	v.CgroupVersion = "1"
	if sysInfo.CgroupUnified {
		v.CgroupVersion = "2"
	}

	v.MemoryLimit = sysInfo.MemoryLimit
	v.SwapLimit = sysInfo.SwapLimit
	v.KernelMemory = sysInfo.KernelMemory
	v.KernelMemoryTCP = sysInfo.KernelMemoryTCP
	v.OomKillDisable = sysInfo.OomKillDisable
	v.CPUCfsPeriod = sysInfo.CPUCfsPeriod
	v.CPUCfsQuota = sysInfo.CPUCfsQuota
	v.CPUShares = sysInfo.CPUShares
	v.CPUSet = sysInfo.Cpuset
	v.PidsLimit = sysInfo.PidsLimit
	v.Runtimes = daemon.configStore.GetAllRuntimes()
	v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName()
	v.InitBinary = daemon.configStore.GetInitPath()

	defaultRuntimeBinary := daemon.configStore.GetRuntime(v.DefaultRuntime).Path
	if rv, err := exec.Command(defaultRuntimeBinary, "--version").Output(); err == nil {
		if _, _, commit, err := parseRuntimeVersion(string(rv)); err != nil {
			logrus.Warnf("failed to parse %s version: %v", defaultRuntimeBinary, err)
			v.RuncCommit.ID = "N/A"
		} else {
			v.RuncCommit.ID = commit
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %v", defaultRuntimeBinary, err)
		v.RuncCommit.ID = "N/A"
	}

	// runc is now shipped as a separate package. Set "expected" to same value
	// as "ID" to prevent clients from reporting a version-mismatch
	v.RuncCommit.Expected = v.RuncCommit.ID

	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
		v.ContainerdCommit.ID = rv.Revision
	} else {
		logrus.Warnf("failed to retrieve containerd version: %v", err)
		v.ContainerdCommit.ID = "N/A"
	}

	// containerd is now shipped as a separate package. Set "expected" to same
	// value as "ID" to prevent clients from reporting a version-mismatch
	v.ContainerdCommit.Expected = v.ContainerdCommit.ID

	// TODO is there still a need to check the expected version for tini?
	// if not, we can change this, and just set "Expected" to v.InitCommit.ID
	v.InitCommit.Expected = dockerversion.InitCommitID

	defaultInitBinary := daemon.configStore.GetInitPath()
	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
		if _, commit, err := parseInitVersion(string(rv)); err != nil {
			logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err)
			v.InitCommit.ID = "N/A"
		} else {
			v.InitCommit.ID = commit
			if len(dockerversion.InitCommitID) > len(commit) {
				v.InitCommit.Expected = dockerversion.InitCommitID[0:len(commit)]
			}
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
		v.InitCommit.ID = "N/A"
	}

	if v.CgroupDriver == cgroupNoneDriver {
		if v.CgroupVersion == "2" {
			v.Warnings = append(v.Warnings, "WARNING: Running in rootless-mode without cgroups. Systemd is required to enable cgroups in rootless-mode.")
		} else {
			v.Warnings = append(v.Warnings, "WARNING: Running in rootless-mode without cgroups. To enable cgroups in rootless-mode, you need to boot the system in cgroup v2 mode.")
		}
	} else {
		if !v.MemoryLimit {
			v.Warnings = append(v.Warnings, "WARNING: No memory limit support")
		}
		if !v.SwapLimit {
			v.Warnings = append(v.Warnings, "WARNING: No swap limit support")
		}
		if !v.KernelMemory {
			v.Warnings = append(v.Warnings, "WARNING: No kernel memory limit support")
		}
		if !v.KernelMemoryTCP {
			v.Warnings = append(v.Warnings, "WARNING: No kernel memory TCP limit support")
		}
		if !v.OomKillDisable {
			v.Warnings = append(v.Warnings, "WARNING: No oom kill disable support")
		}
		if !v.CPUCfsQuota {
			v.Warnings = append(v.Warnings, "WARNING: No cpu cfs quota support")
		}
		if !v.CPUCfsPeriod {
			v.Warnings = append(v.Warnings, "WARNING: No cpu cfs period support")
		}
		if !v.CPUShares {
			v.Warnings = append(v.Warnings, "WARNING: No cpu shares support")
		}
		if !v.CPUSet {
			v.Warnings = append(v.Warnings, "WARNING: No cpuset support")
		}
		if v.CgroupVersion == "2" {
			v.Warnings = append(v.Warnings, "WARNING: Support for cgroup v2 is experimental")
		}
	}
	if !v.IPv4Forwarding {
		v.Warnings = append(v.Warnings, "WARNING: IPv4 forwarding is disabled")
	}
	if !v.BridgeNfIptables {
		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-iptables is disabled")
	}
	if !v.BridgeNfIP6tables {
		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-ip6tables is disabled")
	}
}

func (daemon *Daemon) fillPlatformVersion(v *types.Version) {
	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
		v.Components = append(v.Components, types.ComponentVersion{
			Name:    "containerd",
			Version: rv.Version,
			Details: map[string]string{
				"GitCommit": rv.Revision,
			},
		})
	}

	defaultRuntime := daemon.configStore.GetDefaultRuntimeName()
	defaultRuntimeBinary := daemon.configStore.GetRuntime(defaultRuntime).Path
	if rv, err := exec.Command(defaultRuntimeBinary, "--version").Output(); err == nil {
		if _, ver, commit, err := parseRuntimeVersion(string(rv)); err != nil {
			logrus.Warnf("failed to parse %s version: %v", defaultRuntimeBinary, err)
		} else {
			v.Components = append(v.Components, types.ComponentVersion{
				Name:    defaultRuntime,
				Version: ver,
				Details: map[string]string{
					"GitCommit": commit,
				},
			})
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %v", defaultRuntimeBinary, err)
	}

	defaultInitBinary := daemon.configStore.GetInitPath()
	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
		if ver, commit, err := parseInitVersion(string(rv)); err != nil {
			logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err)
		} else {
			v.Components = append(v.Components, types.ComponentVersion{
				Name:    filepath.Base(defaultInitBinary),
				Version: ver,
				Details: map[string]string{
					"GitCommit": commit,
				},
			})
		}
	} else {
		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
	}
}

func fillDriverWarnings(v *types.Info) {
	for _, pair := range v.DriverStatus {
		if pair[0] == "Data loop file" {
			msg := fmt.Sprintf("WARNING: %s: usage of loopback devices is "+
				"strongly discouraged for production use.\n         "+
				"Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.", v.Driver)

			v.Warnings = append(v.Warnings, msg)
			continue
		}
		if pair[0] == "Supports d_type" && pair[1] == "false" {
			backingFs := getBackingFs(v)

			msg := fmt.Sprintf("WARNING: %s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.\n", v.Driver, backingFs)
			if backingFs == "xfs" {
				msg += "         Reformat the filesystem with ftype=1 to enable d_type support.\n"
			}
			msg += "         Running without d_type support will not be supported in future releases."

			v.Warnings = append(v.Warnings, msg)
			continue
		}
	}
}

func getBackingFs(v *types.Info) string {
	for _, pair := range v.DriverStatus {
		if pair[0] == "Backing Filesystem" {
			return pair[1]
		}
	}
	return ""
}

// parseInitVersion parses a Tini version string, and extracts the "version"
// and "git commit" from the output.
//
// Output example from `docker-init --version`:
//
//     tini version 0.18.0 - git.fec3683
func parseInitVersion(v string) (version string, commit string, err error) {
	parts := strings.Split(v, " - ")

	if len(parts) >= 2 {
		gitParts := strings.Split(strings.TrimSpace(parts[1]), ".")
		if len(gitParts) == 2 && gitParts[0] == "git" {
			commit = gitParts[1]
		}
	}
	parts[0] = strings.TrimSpace(parts[0])
	if strings.HasPrefix(parts[0], "tini version ") {
		version = strings.TrimPrefix(parts[0], "tini version ")
	}
	if version == "" && commit == "" {
		err = errors.Errorf("unknown output format: %s", v)
	}
	return version, commit, err
}

// parseRuntimeVersion parses the output of `[runtime] --version` and extracts the
// "name", "version" and "git commit" from the output.
//
// Output example from `runc --version`:
//
//   runc version 1.0.0-rc5+dev
//   commit: 69663f0bd4b60df09991c08812a60108003fa340
//   spec: 1.0.0
func parseRuntimeVersion(v string) (runtime string, version string, commit string, err error) {
	lines := strings.Split(strings.TrimSpace(v), "\n")
	for _, line := range lines {
		if strings.Contains(line, "version") {
			s := strings.Split(line, "version")
			runtime = strings.TrimSpace(s[0])
			version = strings.TrimSpace(s[len(s)-1])
			continue
		}
		if strings.HasPrefix(line, "commit:") {
			commit = strings.TrimSpace(strings.TrimPrefix(line, "commit:"))
			continue
		}
	}
	if version == "" && commit == "" {
		err = errors.Errorf("unknown output format: %s", v)
	}
	return runtime, version, commit, err
}

func (daemon *Daemon) cgroupNamespacesEnabled(sysInfo *sysinfo.SysInfo) bool {
	return sysInfo.CgroupNamespaces && containertypes.CgroupnsMode(daemon.configStore.CgroupNamespaceMode).IsPrivate()
}

// Rootless returns true if daemon is running in rootless mode
func (daemon *Daemon) Rootless() bool {
	return daemon.configStore.Rootless
}
<|endoftext|>


<commit_before>package dao

import (
	"encoding/json"
	"errors"
	"github.com/resourced/resourced-master/libstring"
	resourcedmaster_storage "github.com/resourced/resourced-master/storage"
	"time"
)

// NewAccessToken is constructor for NewAccessToken struct.
func NewAccessToken(store resourcedmaster_storage.Storer, app *Application) (*AccessToken, error) {
	a := &AccessToken{}
	a.store = store
	a.Token = ""
	a.Level = "basic"
	a.Enabled = true
	a.CreatedUnixNano = time.Now().UnixNano()
	a.Id = a.CreatedUnixNano
	a.ApplicationId = app.Id

	accessToken, err := libstring.GeneratePassword(32)
	if err != nil {
		return nil, err
	}
	a.Token = accessToken

	return a, nil
}

type AccessToken struct {
	Id              int64
	ApplicationId   int64
	Token           string
	Level           string
	Enabled         bool
	CreatedUnixNano int64
	store           resourcedmaster_storage.Storer
}

// validateBeforeSave checks various conditions before saving.
func (a *AccessToken) validateBeforeSave() error {
	if a.Id <= 0 {
		return errors.New("Id must not be empty.")
	}
	if a.Token == "" {
		return errors.New("Token must not be empty.")
	}
	return nil
}

// Save application in JSON format.
func (a *AccessToken) Save() error {
	err := a.validateBeforeSave()
	if err != nil {
		return err
	}

	jsonBytes, err := json.Marshal(a)
	if err != nil {
		return err
	}

	err = CommonSaveById(a.store, "access-tokens", a.Id, jsonBytes)
	if err != nil {
		return err
	}

	return nil
}

func (a *AccessToken) Delete() error {
	err := CommonDeleteById(a.store, "access-tokens", a.Id)
	if err != nil {
		return err
	}

	err = a.store.Delete("/applications/access-token/" + a.Token)
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Able to get list of all access tokens.<commit_after>package dao

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/resourced/resourced-master/libstring"
	resourcedmaster_storage "github.com/resourced/resourced-master/storage"
	"strconv"
	"time"
)

// AllAccessTokens returns slice of all AccessToken
func AllAccessTokens(store resourcedmaster_storage.Storer) ([]*AccessToken, error) {
	ids, err := store.List("/access-tokens/id")
	if err != nil {
		return nil, err
	}

	accessTokens := make([]*AccessToken, 0)

	for _, idString := range ids {
		id, err := strconv.ParseInt(idString, 10, 0)
		if err != nil {
			continue
		}

		access, err := GetAccessTokenById(store, id)
		if err != nil {
			continue
		}

		accessTokens = append(accessTokens, access)
	}

	return accessTokens, nil
}

// GetApplicationById returns AccessToken struct with name as key.
func GetAccessTokenById(store resourcedmaster_storage.Storer, id int64) (*AccessToken, error) {
	jsonBytes, err := store.Get(fmt.Sprintf("/access-tokens/id/%v", id))
	if err != nil {
		return nil, err
	}

	a := &AccessToken{}

	err = json.Unmarshal(jsonBytes, a)
	if err != nil {
		return nil, err
	}

	a.store = store

	return a, nil
}

// NewAccessToken is constructor for NewAccessToken struct.
func NewAccessToken(store resourcedmaster_storage.Storer, app *Application) (*AccessToken, error) {
	a := &AccessToken{}
	a.store = store
	a.Token = ""
	a.Level = "basic"
	a.Enabled = true
	a.CreatedUnixNano = time.Now().UnixNano()
	a.Id = a.CreatedUnixNano
	a.ApplicationId = app.Id

	accessToken, err := libstring.GeneratePassword(32)
	if err != nil {
		return nil, err
	}
	a.Token = accessToken

	return a, nil
}

type AccessToken struct {
	Id              int64
	ApplicationId   int64
	Token           string
	Level           string
	Enabled         bool
	CreatedUnixNano int64
	store           resourcedmaster_storage.Storer
}

// validateBeforeSave checks various conditions before saving.
func (a *AccessToken) validateBeforeSave() error {
	if a.Id <= 0 {
		return errors.New("Id must not be empty.")
	}
	if a.Token == "" {
		return errors.New("Token must not be empty.")
	}
	return nil
}

// Save application in JSON format.
func (a *AccessToken) Save() error {
	err := a.validateBeforeSave()
	if err != nil {
		return err
	}

	jsonBytes, err := json.Marshal(a)
	if err != nil {
		return err
	}

	err = CommonSaveById(a.store, "access-tokens", a.Id, jsonBytes)
	if err != nil {
		return err
	}

	return nil
}

func (a *AccessToken) Delete() error {
	err := CommonDeleteById(a.store, "access-tokens", a.Id)
	if err != nil {
		return err
	}

	err = a.store.Delete("/applications/access-token/" + a.Token)
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package downloader

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/kkdai/youtube/v2"
	"github.com/vbauerster/mpb/v5"
	"github.com/vbauerster/mpb/v5/decor"
)

// Downloader offers high level functions to download videos into files
type Downloader struct {
	youtube.Client
	OutputDir string // optional directory to store the files
}

func (dl *Downloader) getOutputFile(v *youtube.Video, format *youtube.Format, outputFile string) (string, error) {
	if outputFile == "" {
		outputFile = SanitizeFilename(v.Title)
		outputFile += pickIdealFileExtension(format.MimeType)
	}

	if dl.OutputDir != "" {
		if err := os.MkdirAll(dl.OutputDir, 0o755); err != nil {
			return "", err
		}
		outputFile = filepath.Join(dl.OutputDir, outputFile)
	}

	return outputFile, nil
}

// Download : Starting download video by arguments.
func (dl *Downloader) Download(ctx context.Context, v *youtube.Video, format *youtube.Format, outputFile string) error {
	destFile, err := dl.getOutputFile(v, format, outputFile)
	if err != nil {
		return err
	}

	// Create output file
	out, err := os.Create(destFile)
	if err != nil {
		return err
	}
	defer out.Close()

	dl.logf("Download to file=%s", destFile)
	return dl.videoDLWorker(ctx, out, v, format)
}

// DownloadWithHighQuality : Starting downloading video with high quality (>720p).
func (dl *Downloader) DownloadWithHighQuality(ctx context.Context, outputFile string, v *youtube.Video, quality string) error {
	var videoFormat, audioFormat *youtube.Format

	switch quality {
	case "hd1080":
		videoFormat = v.Formats.FindByItag(137)
		audioFormat = v.Formats.FindByItag(140)
	default:
		return fmt.Errorf("unknown quality: %s", quality)
	}

	if videoFormat == nil {
		return fmt.Errorf("no format video/mp4 for %s found", quality)
	}
	if audioFormat == nil {
		return fmt.Errorf("no format audio/mp4 for %s found", quality)
	}

	destFile, err := dl.getOutputFile(v, videoFormat, outputFile)
	if err != nil {
		return err
	}
	outputDir := filepath.Dir(destFile)

	// Create temporary video file
	videoFile, err := ioutil.TempFile(outputDir, "youtube_*.m4v")
	if err != nil {
		return err
	}
	defer os.Remove(videoFile.Name())

	// Create temporary audio file
	audioFile, err := ioutil.TempFile(outputDir, "youtube_*.m4a")
	if err != nil {
		return err
	}
	defer os.Remove(audioFile.Name())

	dl.logf("Downloading video file...")
	err = dl.videoDLWorker(ctx, videoFile, v, videoFormat)
	if err != nil {
		return err
	}

	dl.logf("Downloading audio file...")
	err = dl.videoDLWorker(ctx, audioFile, v, audioFormat)
	if err != nil {
		return err
	}

	ffmpegVersionCmd := exec.Command("ffmpeg", "-y",
		"-i", videoFile.Name(),
		"-i", audioFile.Name(),
		"-c", "copy", // Just copy without re-encoding
		"-shortest", // Finish encoding when the shortest input stream ends
		destFile,
		"-loglevel", "warning",
	)
	ffmpegVersionCmd.Stderr = os.Stderr
	ffmpegVersionCmd.Stdout = os.Stdout
	dl.logf("merging video and audio to %s", destFile)

	return ffmpegVersionCmd.Run()
}

func (dl *Downloader) videoDLWorker(ctx context.Context, out *os.File, video *youtube.Video, format *youtube.Format) error {
	resp, err := dl.GetStreamContext(ctx, video, format)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	prog := &progress{
		contentLength: float64(resp.ContentLength),
	}

	// create progress bar
	progress := mpb.New(mpb.WithWidth(64))
	bar := progress.AddBar(
		int64(prog.contentLength),

		mpb.PrependDecorators(
			decor.CountersKibiByte("% .2f / % .2f"),
			decor.Percentage(decor.WCSyncSpace),
		),
		mpb.AppendDecorators(
			decor.EwmaETA(decor.ET_STYLE_GO, 90),
			decor.Name(" ] "),
			decor.EwmaSpeed(decor.UnitKiB, "% .2f", 60),
		),
	)

	reader := bar.ProxyReader(resp.Body)
	mw := io.MultiWriter(out, prog)
	_, err = io.Copy(mw, reader)
	if err != nil {
		return err
	}

	progress.Wait()
	return nil
}

func (dl *Downloader) logf(format string, v ...interface{}) {
	if dl.Debug {
		log.Printf(format, v...)
	}
}
<commit_msg>Add more high quality formats<commit_after>package downloader

import (
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"

	"github.com/kkdai/youtube/v2"
	"github.com/vbauerster/mpb/v5"
	"github.com/vbauerster/mpb/v5/decor"
)

// Downloader offers high level functions to download videos into files
type Downloader struct {
	youtube.Client
	OutputDir string // optional directory to store the files
}

func (dl *Downloader) getOutputFile(v *youtube.Video, format *youtube.Format, outputFile string) (string, error) {
	if outputFile == "" {
		outputFile = SanitizeFilename(v.Title)
		outputFile += pickIdealFileExtension(format.MimeType)
	}

	if dl.OutputDir != "" {
		if err := os.MkdirAll(dl.OutputDir, 0o755); err != nil {
			return "", err
		}
		outputFile = filepath.Join(dl.OutputDir, outputFile)
	}

	return outputFile, nil
}

// Download : Starting download video by arguments.
func (dl *Downloader) Download(ctx context.Context, v *youtube.Video, format *youtube.Format, outputFile string) error {
	destFile, err := dl.getOutputFile(v, format, outputFile)
	if err != nil {
		return err
	}

	// Create output file
	out, err := os.Create(destFile)
	if err != nil {
		return err
	}
	defer out.Close()

	dl.logf("Download to file=%s", destFile)
	return dl.videoDLWorker(ctx, out, v, format)
}

// DownloadWithHighQuality : Starting downloading video with high quality (>720p).
func (dl *Downloader) DownloadWithHighQuality(ctx context.Context, outputFile string, v *youtube.Video, quality string) error {
	var videoFormat, audioFormat *youtube.Format

	switch quality {
	case "hdr2060":
		videoFormat = v.Formats.FindByItag(401)
	case "hdr1080":
		videoFormat = v.Formats.FindByItag(399)
	case "hd1080":
		videoFormat = v.Formats.FindByItag(137)
	case "hdr720":
		videoFormat = v.Formats.FindByItag(398)
	case "hd720":
		videoFormat = v.Formats.FindByItag(136)
	default:
		return fmt.Errorf("unknown quality: %s", quality)
	}

	audioFormat = v.Formats.FindByItag(140)

	if videoFormat == nil {
		return fmt.Errorf("no format video/mp4 for %s found", quality)
	}
	if audioFormat == nil {
		return fmt.Errorf("no format audio/mp4 for %s found", quality)
	}

	destFile, err := dl.getOutputFile(v, videoFormat, outputFile)
	if err != nil {
		return err
	}
	outputDir := filepath.Dir(destFile)

	// Create temporary video file
	videoFile, err := ioutil.TempFile(outputDir, "youtube_*.m4v")
	if err != nil {
		return err
	}
	defer os.Remove(videoFile.Name())

	// Create temporary audio file
	audioFile, err := ioutil.TempFile(outputDir, "youtube_*.m4a")
	if err != nil {
		return err
	}
	defer os.Remove(audioFile.Name())

	dl.logf("Downloading video file...")
	err = dl.videoDLWorker(ctx, videoFile, v, videoFormat)
	if err != nil {
		return err
	}

	dl.logf("Downloading audio file...")
	err = dl.videoDLWorker(ctx, audioFile, v, audioFormat)
	if err != nil {
		return err
	}

	ffmpegVersionCmd := exec.Command("ffmpeg", "-y",
		"-i", videoFile.Name(),
		"-i", audioFile.Name(),
		"-c", "copy", // Just copy without re-encoding
		"-shortest", // Finish encoding when the shortest input stream ends
		destFile,
		"-loglevel", "warning",
	)
	ffmpegVersionCmd.Stderr = os.Stderr
	ffmpegVersionCmd.Stdout = os.Stdout
	dl.logf("merging video and audio to %s", destFile)

	return ffmpegVersionCmd.Run()
}

func (dl *Downloader) videoDLWorker(ctx context.Context, out *os.File, video *youtube.Video, format *youtube.Format) error {
	resp, err := dl.GetStreamContext(ctx, video, format)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	prog := &progress{
		contentLength: float64(resp.ContentLength),
	}

	// create progress bar
	progress := mpb.New(mpb.WithWidth(64))
	bar := progress.AddBar(
		int64(prog.contentLength),

		mpb.PrependDecorators(
			decor.CountersKibiByte("% .2f / % .2f"),
			decor.Percentage(decor.WCSyncSpace),
		),
		mpb.AppendDecorators(
			decor.EwmaETA(decor.ET_STYLE_GO, 90),
			decor.Name(" ] "),
			decor.EwmaSpeed(decor.UnitKiB, "% .2f", 60),
		),
	)

	reader := bar.ProxyReader(resp.Body)
	mw := io.MultiWriter(out, prog)
	_, err = io.Copy(mw, reader)
	if err != nil {
		return err
	}

	progress.Wait()
	return nil
}

func (dl *Downloader) logf(format string, v ...interface{}) {
	if dl.Debug {
		log.Printf(format, v...)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/micanzhang/gohosts"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

const VERSION = "1.0@dev"
const PLATFORM = runtime.GOOS

var pathMap map[string]string = map[string]string{
	"windows": "C:\\Windows\\System32\\drivers\\etc\\hosts",
	"darwin":  "/etc/hosts",
	"linux":   "/etc/hosts",
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [options]\n", os.Args[0])
	flag.PrintDefaults()
	os.Exit(2)
}

func help() {
	usage()
}

func version() {
	fmt.Printf("%s version %s\n", os.Args[0], VERSION)
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	parseCMD()
}

func edit() {
	hostFile := "/etc/hosts"
	if PLATFORM == "win" {
		hostFile = "C:/Windows/System32/driver/etc/hosts"
	}
	cmd := exec.Command("emacs", hostFile)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		fmt.Println(err)
	}
}

func listHosts(params map[string]string) {
	groups := getHost()
	if group, ok := params["group"]; ok {
		groups = groups.FindByName(group)
	}

	if ip, ok := params["ip"]; ok {
		groups = groups.FilterByIp(ip)
	}

	if domain, ok := params["domain"]; ok {
		groups = groups.FilterByDomain(domain)
	}

	fmt.Println(groups)
}

func switchHosts(params map[string]string, enable bool) {
	groups := getHost()
	if name, ok := params["group"]; ok {
		if ip, ok := params["ip"]; ok {
			groups.SwitchByIp(ip, enable)
		} else if domain, ok := params["domain"]; ok {
			groups.SwitchByDomain(domain, enable)
		} else {
			groups.SwitchByName(name, enable)
		}
	} else {

	}

	if ip, ok := params["ip"]; ok {
		groups.SwitchByIp(ip, enable)
	}

	if domain, ok := params["domain"]; ok {
		groups.SwitchByDomain(domain, enable)
	}

	if groups != nil {
		content := groups.String()
		if err := updateHostString(content); err != nil {
			fmt.Printf("Error: %v\n", err)
		} else {
			fmt.Println(content)
		}
	} else {

	}
}

func parseCMD() {
	args := os.Args
	params := make(map[string]string)
	if len(args) == 1 {
		usage()
	}

	key := ""
	action := ""
	//support list, edit, disable, enable, help, version
	for _, arg := range args[1:] {
		if len(key) > 0 {
			params[key] = arg
			key = ""
		} else {
			switch arg {
			case "-h", "--help":
				action = "help"
				help()
				break
			case "-v", "--version":
				action = "version"
				version()
				break
			case "-l", "--list", "list":
				if len(action) == 0 {
					action = "list"
				} else if action != "list" {
					usage()
				}
				break
			case "-e", "--edit":
				action = "edit"
				edit()
				os.Exit(0)
			case "-r", "--remove", "remove":
				if len(action) == 0 {
					action = "disable"
				} else if action != "disable" {
					usage()
				}
				break
			case "-s", "--switch", "switch":
				if len(action) == 0 {
					action = "enable"
				} else if action != "enable" {
					usage()
				}
				break
			case "-g", "--group":
				key = "group"
				break
			case "-d", "--domain":
				key = "domain"
				break
			case "-i", "--ip":
				key = "ip"
				break
			default:
				if action != "" {
					params["group"] = arg
				} else {
					usage()
				}
				break
			}
		}
	}

	if action == "disable" {
		switchHosts(params, false)
	} else if action == "enable" {
		switchHosts(params, true)
	} else {
		listHosts(params)
	}
}

func listHost(params map[string]string) {
	groups := getHost()
	fmt.Println(groups)
	//list all
	//list by group
	// list by domain
	// list by ip
}

// Build Groups object
func getHost() *hosts.Groups {
	hostStr, err := loadHostString()
	if err != nil {
		panic(err)
	}
	lines := strings.Split(hostStr, "\n")
	groups := new(hosts.Groups)
	group := new(hosts.Group)
	inGroup := false
	for _, line := range lines {
		line = strings.TrimSpace(line)
		length := len(line)
		if length == 5 && inGroup {
			*groups = append(*groups, *group)
			group = new(hosts.Group)
			inGroup = false
		} else if length > 5 {
			if !inGroup && string(line[:5]) == "#====" {
				inGroup = true
				group.Name = strings.TrimSpace(string(line[5:]))
			} else if inGroup {
				host := new(hosts.Host)
				if line[0] == '#' {
					line = string(line[1:])
					host.Enable = false
				} else {
					host.Enable = true
				}
				items := strings.Fields(line)
				if len(items) > 0 {
					host.Ip = items[0]
					host.Domain = items[1:]
				}

				group.Items = append(group.Items, *host)
			}
		}
	}
	return groups
}

// Read host of supported platform
func loadHostString() (string, error) {
	paltform := runtime.GOOS
	if hostPath, ok := pathMap[paltform]; ok {
		bytes, err := ioutil.ReadFile(hostPath)
		if err != nil {
			return "", err
		}
		return string(bytes), nil
	} else {
		return "", errors.New("unsupported PLATFORM!")
	}

}

func updateHostString(hosts string) error {
	hostFile := "/etc/hosts"
	return ioutil.WriteFile(hostFile, []byte(hosts), 0777)
}
<commit_msg>get hostFile by call a function, and make hm works at windows 8<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"github.com/micanzhang/gohosts"
	"io/ioutil"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

const VERSION = "1.0@dev"
const PLATFORM = runtime.GOOS

var pathMap map[string]string = map[string]string{
	"windows": "C:\\Windows\\System32\\drivers\\etc\\hosts",
	"darwin":  "/etc/hosts",
	"linux":   "/etc/hosts",
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [options]\n", os.Args[0])
	flag.PrintDefaults()
	os.Exit(2)
}

func help() {
	usage()
}

func version() {
	fmt.Printf("%s version %s\n", os.Args[0], VERSION)
	flag.PrintDefaults()
	os.Exit(2)
}

func main() {
	parseCMD()
}

func edit() {
	if hostFile, err := getHostFile(); err == nil {
		cmd := exec.Command("emacs", hostFile)
		cmd.Stdin = os.Stdin
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err := cmd.Run(); err != nil {
			fmt.Println(err)
		}
	} else {
		fmt.Println(err)
		os.Exit(2)
	}
}

func listHosts(params map[string]string) {
	groups := getHost()
	if group, ok := params["group"]; ok {
		groups = groups.FindByName(group)
	}

	if ip, ok := params["ip"]; ok {
		groups = groups.FilterByIp(ip)
	}

	if domain, ok := params["domain"]; ok {
		groups = groups.FilterByDomain(domain)
	}

	fmt.Println(groups)
}

func switchHosts(params map[string]string, enable bool) {
	groups := getHost()
	if name, ok := params["group"]; ok {
		if ip, ok := params["ip"]; ok {
			groups.SwitchByIp(ip, enable)
		} else if domain, ok := params["domain"]; ok {
			groups.SwitchByDomain(domain, enable)
		} else {
			groups.SwitchByName(name, enable)
		}
	} else {

	}

	if ip, ok := params["ip"]; ok {
		groups.SwitchByIp(ip, enable)
	}

	if domain, ok := params["domain"]; ok {
		groups.SwitchByDomain(domain, enable)
	}

	if groups != nil {
		content := groups.String()
		if err := updateHostString(content); err != nil {
			fmt.Printf("Error: %v\n", err)
		} else {
			fmt.Println(content)
		}
	} else {

	}
}

func parseCMD() {
	args := os.Args
	params := make(map[string]string)
	if len(args) == 1 {
		usage()
	}

	key := ""
	action := ""
	//support list, edit, disable, enable, help, version
	for _, arg := range args[1:] {
		if len(key) > 0 {
			params[key] = arg
			key = ""
		} else {
			switch arg {
			case "-h", "--help":
				action = "help"
				help()
				break
			case "-v", "--version":
				action = "version"
				version()
				break
			case "-l", "--list", "list":
				if len(action) == 0 {
					action = "list"
				} else if action != "list" {
					usage()
				}
				break
			case "-e", "--edit":
				action = "edit"
				edit()
				os.Exit(0)
			case "-r", "--remove", "remove":
				if len(action) == 0 {
					action = "disable"
				} else if action != "disable" {
					usage()
				}
				break
			case "-s", "--switch", "switch":
				if len(action) == 0 {
					action = "enable"
				} else if action != "enable" {
					usage()
				}
				break
			case "-g", "--group":
				key = "group"
				break
			case "-d", "--domain":
				key = "domain"
				break
			case "-i", "--ip":
				key = "ip"
				break
			default:
				if action != "" {
					params["group"] = arg
				} else {
					usage()
				}
				break
			}
		}
	}

	if action == "disable" {
		switchHosts(params, false)
	} else if action == "enable" {
		switchHosts(params, true)
	} else {
		listHosts(params)
	}
}

// Build Groups object
func getHost() *hosts.Groups {
	hostStr, err := loadHostString()
	if err != nil {
		panic(err)
	}
	lines := strings.Split(hostStr, "\n")
	groups := new(hosts.Groups)
	group := new(hosts.Group)
	inGroup := false
	for _, line := range lines {
		line = strings.TrimSpace(line)
		length := len(line)
		if length == 5 && inGroup {
			*groups = append(*groups, *group)
			group = new(hosts.Group)
			inGroup = false
		} else if length > 5 {
			if !inGroup && string(line[:5]) == "#====" {
				inGroup = true
				group.Name = strings.TrimSpace(string(line[5:]))
			} else if inGroup {
				host := new(hosts.Host)
				if line[0] == '#' {
					line = string(line[1:])
					host.Enable = false
				} else {
					host.Enable = true
				}
				items := strings.Fields(line)
				if len(items) > 0 {
					host.Ip = items[0]
					host.Domain = items[1:]
				}

				group.Items = append(group.Items, *host)
			}
		}
	}
	return groups
}

// Read host of supported platform
func loadHostString() (string, error) {
	if hostFile, err := getHostFile(); err == nil {
		bytes, err := ioutil.ReadFile(hostFile)
		if err != nil {
			return "", err
		}
		return string(bytes), nil
	} else {
		return "", err
	}

}

//write hosts config to system hosts config file
func updateHostString(hosts string) error {
	if hostFile, err := getHostFile(); err == nil {
		return ioutil.WriteFile(hostFile, []byte(hosts), 0777)
	} else {
		return err
	}
}

//Get host file by current os
func getHostFile() (string, error) {
	paltform := runtime.GOOS
	if hostFile, ok := pathMap[paltform]; ok {
		return hostFile, nil
	} else {
		return "", errors.New("unsupported PLATFORM!")
	}
}
<|endoftext|>


<commit_before>package crc32c

import "hash/crc32"

// Table is a crc32 table based on the Castagnoli polynomial, and can be used
// to compute CRC32-C hashes, which are used on Google Cloud Storage for example.
var Table = crc32.MakeTable(crc32.Castagnoli)
<commit_msg>Remove crc32c tables<commit_after><|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"strconv"
)

type session struct {
	name        string
	ipVersion   int
	established int
	imported    int64
	exported    int64
}

const version string = "0.1"

var (
	protoRegex    *regexp.Regexp
	routeRegex    *regexp.Regexp
	showVersion   = flag.Bool("version", false, "Print version information.")
	listenAddress = flag.String("web.listen-address", ":9200", "Address on which to expose metrics and web interface.")
	metricsPath   = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
	birdClient    = flag.String("bird.client", "birdc", "Binary to communicate with the bird routing daemon")
)

func main() {
	initRegexes()
	flag.Parse()

	if *showVersion {
		printVersion()
		os.Exit(0)
	}

	startServer()
}

func printVersion() {
	fmt.Println("bird_bgp_exporter")
	fmt.Printf("Version: %s\n", version)
	fmt.Println("BGP exporter for bird routing daemon")
}

func startServer() {
	fmt.Printf("Starting bird BGP exporter (Version: %s)\n", version)
	http.HandleFunc(*metricsPath, handleMetricsRequest)

	fmt.Printf("Listening for %s on %s\n", *metricsPath, *listenAddress)
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}

func initRegexes() {
	protoRegex, _ = regexp.Compile("^([^\\s]+)\\s+BGP\\s+([^\\s]+)\\s+([^\\s]+)\\s+([\\d]+)\\s+(.*?)\\s*$")
	routeRegex, _ = regexp.Compile("^\\s+Routes:\\s+(\\d+) imported, \\d+ filtered, (\\d+) exported")
}

func handleMetricsRequest(w http.ResponseWriter, r *http.Request) {
	sessions := getSessions()

	for _, s := range sessions {
		writeLineForSession(s, w)
	}
}

func writeLineForSession(s *session, w io.Writer) {
	fmt.Fprintf(w, "bgp%d_session_up{name=\"%s\"} %d\n", s.ipVersion, s.name, s.established)
	fmt.Fprintf(w, "bgp%d_session_prefix_count_import{name=\"%s\"} %d\n", s.ipVersion, s.name, s.imported)
	fmt.Fprintf(w, "bgp%d_session_prefix_count_export{name=\"%s\"} %d\n", s.ipVersion, s.name, s.exported)
}

func getSessions() []*session {
	birdSessions := getSessionsFromBird(4)
	bird6Sessions := getSessionsFromBird(6)

	return append(birdSessions, bird6Sessions...)
}

func getSessionsFromBird(ipVersion int) []*session {
	client := *birdClient

	if ipVersion == 6 {
		client += "6"
	}

	output := getBirdOutput(client)
	return parseOutput(output, ipVersion)
}

func getBirdOutput(birdClient string) []byte {
	b, err := exec.Command(birdClient, "show", "protocols", "all").Output()

	if err != nil {
		b = make([]byte, 0)
		log.Println(err)
	}

	return b
}

func parseOutput(data []byte, ipVersion int) []*session {
	sessions := make([]*session, 0)

	reader := bytes.NewReader(data)
	scanner := bufio.NewScanner(reader)
	var current *session = nil

	for scanner.Scan() {
		line := scanner.Text()
		if session, res := parseLineForSession(line, ipVersion); res == true {
			current = session
			sessions = append(sessions, current)
		}

		if current != nil {
			parseLineForRoutes(line, current)
		}

		if line == "" {
			current = nil
		}
	}

	return sessions
}

func parseLineForSession(line string, ipVersion int) (*session, bool) {
	match := protoRegex.FindStringSubmatch(line)

	if match != nil {
		session := session{name: match[1], ipVersion: ipVersion, established: parseState(match[5])}
		return &session, true
	}

	return nil, false
}

func parseLineForRoutes(line string, session *session) {
	match := routeRegex.FindStringSubmatch(line)

	if match != nil {
		session.imported, _ = strconv.ParseInt(match[1], 0, 64)
		session.exported, _ = strconv.ParseInt(match[2], 0, 64)
	}
}

func parseState(state string) int {
	if state == "Established" {
		return 1
	} else {
		return 0
	}
}
<commit_msg>style: prefere early return<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"regexp"
	"strconv"
)

type session struct {
	name        string
	ipVersion   int
	established int
	imported    int64
	exported    int64
}

const version string = "0.1"

var (
	protoRegex    *regexp.Regexp
	routeRegex    *regexp.Regexp
	showVersion   = flag.Bool("version", false, "Print version information.")
	listenAddress = flag.String("web.listen-address", ":9200", "Address on which to expose metrics and web interface.")
	metricsPath   = flag.String("web.telemetry-path", "/metrics", "Path under which to expose metrics.")
	birdClient    = flag.String("bird.client", "birdc", "Binary to communicate with the bird routing daemon")
)

func main() {
	initRegexes()
	flag.Parse()

	if *showVersion {
		printVersion()
		os.Exit(0)
	}

	startServer()
}

func printVersion() {
	fmt.Println("bird_bgp_exporter")
	fmt.Printf("Version: %s\n", version)
	fmt.Println("BGP exporter for bird routing daemon")
}

func startServer() {
	fmt.Printf("Starting bird BGP exporter (Version: %s)\n", version)
	http.HandleFunc(*metricsPath, handleMetricsRequest)

	fmt.Printf("Listening for %s on %s\n", *metricsPath, *listenAddress)
	log.Fatal(http.ListenAndServe(*listenAddress, nil))
}

func initRegexes() {
	protoRegex, _ = regexp.Compile("^([^\\s]+)\\s+BGP\\s+([^\\s]+)\\s+([^\\s]+)\\s+([\\d]+)\\s+(.*?)\\s*$")
	routeRegex, _ = regexp.Compile("^\\s+Routes:\\s+(\\d+) imported, \\d+ filtered, (\\d+) exported")
}

func handleMetricsRequest(w http.ResponseWriter, r *http.Request) {
	sessions := getSessions()

	for _, s := range sessions {
		writeLineForSession(s, w)
	}
}

func writeLineForSession(s *session, w io.Writer) {
	fmt.Fprintf(w, "bgp%d_session_up{name=\"%s\"} %d\n", s.ipVersion, s.name, s.established)
	fmt.Fprintf(w, "bgp%d_session_prefix_count_import{name=\"%s\"} %d\n", s.ipVersion, s.name, s.imported)
	fmt.Fprintf(w, "bgp%d_session_prefix_count_export{name=\"%s\"} %d\n", s.ipVersion, s.name, s.exported)
}

func getSessions() []*session {
	birdSessions := getSessionsFromBird(4)
	bird6Sessions := getSessionsFromBird(6)

	return append(birdSessions, bird6Sessions...)
}

func getSessionsFromBird(ipVersion int) []*session {
	client := *birdClient

	if ipVersion == 6 {
		client += "6"
	}

	output := getBirdOutput(client)
	return parseOutput(output, ipVersion)
}

func getBirdOutput(birdClient string) []byte {
	b, err := exec.Command(birdClient, "show", "protocols", "all").Output()

	if err != nil {
		b = make([]byte, 0)
		log.Println(err)
	}

	return b
}

func parseOutput(data []byte, ipVersion int) []*session {
	sessions := make([]*session, 0)

	reader := bytes.NewReader(data)
	scanner := bufio.NewScanner(reader)
	var current *session = nil

	for scanner.Scan() {
		line := scanner.Text()
		if session, res := parseLineForSession(line, ipVersion); res == true {
			current = session
			sessions = append(sessions, current)
		}

		if current != nil {
			parseLineForRoutes(line, current)
		}

		if line == "" {
			current = nil
		}
	}

	return sessions
}

func parseLineForSession(line string, ipVersion int) (*session, bool) {
	match := protoRegex.FindStringSubmatch(line)

	if match == nil {
		return nil, false
	}

	session := session{name: match[1], ipVersion: ipVersion, established: parseState(match[5])}
	return &session, true
}

func parseLineForRoutes(line string, session *session) {
	match := routeRegex.FindStringSubmatch(line)

	if match != nil {
		session.imported, _ = strconv.ParseInt(match[1], 0, 64)
		session.exported, _ = strconv.ParseInt(match[2], 0, 64)
	}
}

func parseState(state string) int {
	if state == "Established" {
		return 1
	} else {
		return 0
	}
}
<|endoftext|>