<commit_before>/*
Copyright 2017 The OpenEBS 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 command

import (
	"errors"
	"fmt"
	"os"
	"os/signal"
	"reflect"
	"sort"

	"strings"
	"syscall"
	"time"

	"github.com/golang/glog"

	"github.com/openebs/maya/cmd/maya-apiserver/app/config"
	"github.com/openebs/maya/cmd/maya-apiserver/app/server"
	spc "github.com/openebs/maya/cmd/maya-apiserver/cstor-operator/spc"
	env "github.com/openebs/maya/pkg/env/v1alpha1"
	install "github.com/openebs/maya/pkg/install/v1alpha1"
	"github.com/openebs/maya/pkg/usage"
	"github.com/openebs/maya/pkg/util"
	"github.com/openebs/maya/pkg/version"
	"github.com/spf13/cobra"
)

var (
	helpText = `
Usage: m-apiserver start [options]

  Starts maya-apiserver and runs until an interrupt is received.

  The maya apiserver's configuration primarily comes from the config
  files used, but a subset of the options may also be passed directly
  as CLI arguments, listed below.

General Options :

  -bind=<addr>
    The address the server will bind to for all of its various network
    services. The individual services that run bind to individual
    ports on this address. Defaults to the loopback 127.0.0.1.

  -config=<path>
    The path to either a single config file or a directory of config
    files to use for configuring maya api server. This option may be
    specified multiple times. If multiple config files are used, the
    values from each will be merged together. During merging, values
    from files found later in the list are merged over values from
    previously parsed files.

  -log-level=<level>
    Specify the verbosity level of maya api server's logs. Valid values include
    DEBUG, INFO, and WARN, in decreasing order of verbosity. The
    default is INFO.
 `
)

// gracefulTimeout controls how long we wait before forcefully terminating
const gracefulTimeout = 5 * time.Second

// CmdStartOptions is a cli implementation that runs a maya apiserver.
// The command will not end unless a shutdown message is sent on the
// ShutdownCh. If two messages are sent on the ShutdownCh it will forcibly
// exit.
type CmdStartOptions struct {
	BindAddr   string
	LogLevel   string
	ConfigPath string
	ShutdownCh <-chan struct{}
	args       []string

	// TODO
	// Check if both maya & httpServer instances are required ?
	// Can httpServer or maya embed one of the other ?
	// Need to take care of shuting down & graceful exit scenarios !!
	maya       *server.MayaApiServer
	httpServer *server.HTTPServer
}

// NewCmdStart creates start command for maya-apiserver
func NewCmdStart() *cobra.Command {
	options := CmdStartOptions{}

	cmd := &cobra.Command{
		Use:   "start",
		Short: "start maya-apiserver",
		Long:  helpText,

		Run: func(cmd *cobra.Command, args []string) {
			util.CheckErr(Run(cmd, &options), util.Fatal)
		},
	}

	cmd.Flags().StringVarP(&options.BindAddr, "bind", "", options.BindAddr,
		"IP Address to bind for maya apiserver.")

	cmd.Flags().StringVarP(&options.LogLevel, "log-level", "", options.LogLevel,
		"Log level for maya apiserver DEBUG INFO WARN.")

	cmd.Flags().StringVarP(&options.ConfigPath, "config", "", options.ConfigPath,
		"Path to a single config file or directory.")

	return cmd
}

// Run does tasks related to mayaserver.
func Run(cmd *cobra.Command, c *CmdStartOptions) error {
	glog.Infof("Initializing maya-apiserver...")

	// Read and merge with default configuration
	mconfig := c.readMayaConfig()
	if mconfig == nil {
		return errors.New("Unable to load the configuration")
	}

	//TODO Setup Log Level

	// Setup Maya server
	if err := c.setupMayaServer(mconfig); err != nil {
		return err
	}
	defer c.maya.Shutdown()

	// Check and shut down at the end
	defer func() {
		if c.httpServer != nil {
			c.httpServer.Shutdown()
		}
	}()

	// Compile Maya server information for output later
	info := make(map[string]string)
	info["version"] = fmt.Sprintf("%s%s", mconfig.Version, mconfig.VersionPrerelease)
	info["log level"] = mconfig.LogLevel
	info["region"] = fmt.Sprintf("%s (DC: %s)", mconfig.Region, mconfig.Datacenter)

	// Sort the keys for output
	infoKeys := make([]string, 0, len(info))
	for key := range info {
		infoKeys = append(infoKeys, key)
	}
	sort.Strings(infoKeys)

	// Maya server configuration output
	padding := 18
	glog.Info("Maya api server configuration:\n")
	for _, k := range infoKeys {
		glog.Infof(
			"%s%s: %s",
			strings.Repeat(" ", padding-len(k)),
			strings.Title(k),
			info[k])
	}
	glog.Infof("")

	// Output the header that the server has started
	glog.Info("Maya api server started! Log data will stream in below:\n")

	// start storage pool controller
	go func() {
		err := spc.Start()
		if err != nil {
			glog.Errorf("Failed to start storage pool controller: %s", err.Error())
		}
	}()

	// start webhook controller
	//go func() {
	//	webhook.Start()
	//}()

	if env.Truthy(env.OpenEBSEnableAnalytics) {
		usage.New().Build().InstallBuilder(true).Send()
		go usage.PingCheck()
	}

	// Wait for exit
	if c.handleSignals(mconfig) > 0 {
		return errors.New("Ungraceful exit")
	}

	return nil
}

func (c *CmdStartOptions) readMayaConfig() *config.MayaConfig {
	// Load the configuration
	mconfig := config.DefaultMayaConfig()

	if c.ConfigPath != "" {
		current, err := config.LoadMayaConfig(c.ConfigPath)
		if err != nil {
			glog.Errorf(
				"Error loading configuration from %s: %s", c.ConfigPath, err)
			return nil
		}

		// The user asked us to load some config here but we didn't find any,
		// so we'll complain but continue.
		if current == nil || reflect.DeepEqual(current, &config.MayaConfig{}) {
			glog.Warningf("No configuration loaded from %s", c.ConfigPath)
		}

		if mconfig == nil {
			mconfig = current
		} else {
			mconfig = mconfig.Merge(current)
		}
	}

	// Merge any CLI options over config file options

	// Set the version info
	mconfig.Revision = version.GetGitCommit()
	mconfig.Version = version.GetVersion()
	mconfig.VersionPrerelease = version.GetBuildMeta()

	// Set the details from command line
	if c.BindAddr != "" {
		mconfig.BindAddr = c.BindAddr
	}
	if c.LogLevel != "" {
		mconfig.LogLevel = c.LogLevel
	}

	// Normalize binds, ports, addresses, and advertise
	if err := mconfig.NormalizeAddrs(); err != nil {
		glog.Errorf(err.Error())
		return nil
	}

	return mconfig
}

// setupMayaServer is used to start Maya server
func (c *CmdStartOptions) setupMayaServer(mconfig *config.MayaConfig) error {
	glog.Info("Starting maya api server ...")

	// run maya installer
	installErrs := install.SimpleInstaller().Install()
	if len(installErrs) != 0 {
		glog.Errorf("Install errors were found: %+v", installErrs)
		return fmt.Errorf("Failed to install resources")
	}

	// Setup maya service i.e. maya api server
	maya, err := server.NewMayaApiServer(mconfig, os.Stdout)
	if err != nil {
		glog.Errorf("Error starting maya api server: %s", err)
		return err
	}

	c.maya = maya

	// Setup the HTTP server
	http, err := server.NewHTTPServer(maya, mconfig, os.Stdout)
	if err != nil {
		maya.Shutdown()
		glog.Errorf("Error starting http server: %s", err)
		return err
	}

	c.httpServer = http

	return nil
}

// handleSignals blocks until we get an exit-causing signal
func (c *CmdStartOptions) handleSignals(mconfig *config.MayaConfig) int {
	signalCh := make(chan os.Signal, 4)
	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGPIPE)

	// Wait for a signal
WAIT:
	var sig os.Signal
	select {
	case s := <-signalCh:
		sig = s
	case <-c.ShutdownCh:
		sig = os.Interrupt
	}
	glog.Infof("Caught signal: %v", sig)

	// Skip any SIGPIPE signal (See issue #1798)
	if sig == syscall.SIGPIPE {
		goto WAIT
	}

	// Check if this is a SIGHUP
	if sig == syscall.SIGHUP {
		if conf := c.handleReload(mconfig); conf != nil {
			// Update the value only, not address
			*mconfig = *conf
		}
		goto WAIT
	}

	// Check if we should do a graceful leave
	graceful := false
	if sig == os.Interrupt && mconfig.LeaveOnInt {
		graceful = true
	} else if sig == syscall.SIGTERM && mconfig.LeaveOnTerm {
		graceful = true
	}

	// Bail fast if not doing a graceful leave
	if !graceful {
		return 1
	}

	// Attempt a graceful leave
	gracefulCh := make(chan struct{})
	glog.Info("Gracefully shutting maya api server...")
	go func() {
		if err := c.maya.Leave(); err != nil {
			glog.Errorf("Error: %s", err)
			return
		}
		close(gracefulCh)
	}()

	// Wait for leave or another signal
	select {
	case <-signalCh:
		return 1
	case <-time.After(gracefulTimeout):
		return 1
	case <-gracefulCh:
		return 0
	}
}

// handleReload is invoked when we should reload our configs, e.g. SIGHUP
// TODO
// The current reload code is very basic.
// Add ways to reload the orchestrator & plugins without shuting down the
// process
func (c *CmdStartOptions) handleReload(mconfig *config.MayaConfig) *config.MayaConfig {

	glog.Info("Reloading maya api server configuration...")

	newConf := c.readMayaConfig()
	if newConf == nil {
		glog.Error("Failed to reload config")
		return mconfig
	}

	//TODO Change the log level dynamically
	glog.Infof("Log level is : %s", strings.ToUpper(newConf.LogLevel))

	return newConf
}
<commit_msg>chore(log, install): add log for successful installation of resources (#1240)<commit_after>/*
Copyright 2017 The OpenEBS 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 command

import (
	"fmt"
	"os"
	"os/signal"
	"reflect"
	"sort"

	"strings"
	"syscall"
	"time"

	"github.com/golang/glog"
	"github.com/openebs/maya/cmd/maya-apiserver/app/config"
	"github.com/openebs/maya/cmd/maya-apiserver/app/server"
	spc "github.com/openebs/maya/cmd/maya-apiserver/cstor-operator/spc"
	env "github.com/openebs/maya/pkg/env/v1alpha1"
	errors "github.com/openebs/maya/pkg/errors/v1alpha1"
	install "github.com/openebs/maya/pkg/install/v1alpha1"
	"github.com/openebs/maya/pkg/usage"
	"github.com/openebs/maya/pkg/util"
	"github.com/openebs/maya/pkg/version"
	"github.com/spf13/cobra"
)

var (
	helpText = `
Usage: m-apiserver start [options]

  Starts maya-apiserver and runs until an interrupt is received.

  The maya apiserver's configuration primarily comes from the config
  files used, but a subset of the options may also be passed directly
  as CLI arguments, listed below.

General Options :

  -bind=<addr>
    The address the server will bind to for all of its various network
    services. The individual services that run bind to individual
    ports on this address. Defaults to the loopback 127.0.0.1.

  -config=<path>
    The path to either a single config file or a directory of config
    files to use for configuring maya api server. This option may be
    specified multiple times. If multiple config files are used, the
    values from each will be merged together. During merging, values
    from files found later in the list are merged over values from
    previously parsed files.

  -log-level=<level>
    Specify the verbosity level of maya api server's logs. Valid values include
    DEBUG, INFO, and WARN, in decreasing order of verbosity. The
    default is INFO.
 `
)

// gracefulTimeout controls how long we wait before forcefully terminating
const gracefulTimeout = 5 * time.Second

// CmdStartOptions is a cli implementation that runs a maya apiserver.
// The command will not end unless a shutdown message is sent on the
// ShutdownCh. If two messages are sent on the ShutdownCh it will forcibly
// exit.
type CmdStartOptions struct {
	BindAddr   string
	LogLevel   string
	ConfigPath string
	ShutdownCh <-chan struct{}
	args       []string

	// TODO
	// Check if both maya & httpServer instances are required ?
	// Can httpServer or maya embed one of the other ?
	// Need to take care of shuting down & graceful exit scenarios !!
	maya       *server.MayaApiServer
	httpServer *server.HTTPServer
}

// NewCmdStart creates start command for maya-apiserver
func NewCmdStart() *cobra.Command {
	options := CmdStartOptions{}

	cmd := &cobra.Command{
		Use:   "start",
		Short: "start maya-apiserver",
		Long:  helpText,

		Run: func(cmd *cobra.Command, args []string) {
			util.CheckErr(Run(cmd, &options), util.Fatal)
		},
	}

	cmd.Flags().StringVarP(&options.BindAddr, "bind", "", options.BindAddr,
		"IP Address to bind for maya apiserver.")

	cmd.Flags().StringVarP(&options.LogLevel, "log-level", "", options.LogLevel,
		"Log level for maya apiserver DEBUG INFO WARN.")

	cmd.Flags().StringVarP(&options.ConfigPath, "config", "", options.ConfigPath,
		"Path to a single config file or directory.")

	return cmd
}

// Run does tasks related to mayaserver.
func Run(cmd *cobra.Command, c *CmdStartOptions) error {
	glog.Infof("Initializing maya-apiserver...")

	// Read and merge with default configuration
	mconfig := c.readMayaConfig()
	if mconfig == nil {
		return errors.New("Unable to load the configuration")
	}

	//TODO Setup Log Level

	// Setup Maya server
	if err := c.setupMayaServer(mconfig); err != nil {
		return err
	}
	defer c.maya.Shutdown()

	// Check and shut down at the end
	defer func() {
		if c.httpServer != nil {
			c.httpServer.Shutdown()
		}
	}()

	// Compile Maya server information for output later
	info := make(map[string]string)
	info["version"] = fmt.Sprintf("%s%s", mconfig.Version, mconfig.VersionPrerelease)
	info["log level"] = mconfig.LogLevel
	info["region"] = fmt.Sprintf("%s (DC: %s)", mconfig.Region, mconfig.Datacenter)

	// Sort the keys for output
	infoKeys := make([]string, 0, len(info))
	for key := range info {
		infoKeys = append(infoKeys, key)
	}
	sort.Strings(infoKeys)

	// Maya server configuration output
	padding := 18
	glog.Info("Maya api server configuration:\n")
	for _, k := range infoKeys {
		glog.Infof(
			"%s%s: %s",
			strings.Repeat(" ", padding-len(k)),
			strings.Title(k),
			info[k])
	}
	glog.Infof("")

	// Output the header that the server has started
	glog.Info("Maya api server started! Log data will stream in below:\n")

	// start storage pool controller
	go func() {
		err := spc.Start()
		if err != nil {
			glog.Errorf("Failed to start storage pool controller: %s", err.Error())
		}
	}()

	// start webhook controller
	//go func() {
	//	webhook.Start()
	//}()

	if env.Truthy(env.OpenEBSEnableAnalytics) {
		usage.New().Build().InstallBuilder(true).Send()
		go usage.PingCheck()
	}

	// Wait for exit
	if c.handleSignals(mconfig) > 0 {
		return errors.New("Ungraceful exit")
	}

	return nil
}

func (c *CmdStartOptions) readMayaConfig() *config.MayaConfig {
	// Load the configuration
	mconfig := config.DefaultMayaConfig()

	if c.ConfigPath != "" {
		current, err := config.LoadMayaConfig(c.ConfigPath)
		if err != nil {
			glog.Errorf(
				"Error loading configuration from %s: %s", c.ConfigPath, err)
			return nil
		}

		// The user asked us to load some config here but we didn't find any,
		// so we'll complain but continue.
		if current == nil || reflect.DeepEqual(current, &config.MayaConfig{}) {
			glog.Warningf("No configuration loaded from %s", c.ConfigPath)
		}

		if mconfig == nil {
			mconfig = current
		} else {
			mconfig = mconfig.Merge(current)
		}
	}

	// Merge any CLI options over config file options

	// Set the version info
	mconfig.Revision = version.GetGitCommit()
	mconfig.Version = version.GetVersion()
	mconfig.VersionPrerelease = version.GetBuildMeta()

	// Set the details from command line
	if c.BindAddr != "" {
		mconfig.BindAddr = c.BindAddr
	}
	if c.LogLevel != "" {
		mconfig.LogLevel = c.LogLevel
	}

	// Normalize binds, ports, addresses, and advertise
	if err := mconfig.NormalizeAddrs(); err != nil {
		glog.Errorf(err.Error())
		return nil
	}

	return mconfig
}

// setupMayaServer is used to start Maya server
func (c *CmdStartOptions) setupMayaServer(mconfig *config.MayaConfig) error {
	glog.Info("Starting maya api server ...")

	// run maya installer
	installErrs := install.SimpleInstaller().Install()
	if len(installErrs) != 0 {
		glog.Errorf("failed to apply resources: %+v", installErrs)
		return errors.New("failed to apply resources")
	}

	glog.Info("resources applied successfully by installer")

	// Setup maya service i.e. maya api server
	maya, err := server.NewMayaApiServer(mconfig, os.Stdout)
	if err != nil {
		glog.Errorf("failed to start api server: %+v", err)
		return err
	}

	c.maya = maya

	// Setup the HTTP server
	http, err := server.NewHTTPServer(maya, mconfig, os.Stdout)
	if err != nil {
		maya.Shutdown()
		glog.Errorf("failed to start http server: %+v", err)
		return err
	}

	c.httpServer = http
	return nil
}

// handleSignals blocks until we get an exit-causing signal
func (c *CmdStartOptions) handleSignals(mconfig *config.MayaConfig) int {
	signalCh := make(chan os.Signal, 4)
	signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGPIPE)

	// Wait for a signal
WAIT:
	var sig os.Signal
	select {
	case s := <-signalCh:
		sig = s
	case <-c.ShutdownCh:
		sig = os.Interrupt
	}
	glog.Infof("Caught signal: %v", sig)

	// Skip any SIGPIPE signal (See issue #1798)
	if sig == syscall.SIGPIPE {
		goto WAIT
	}

	// Check if this is a SIGHUP
	if sig == syscall.SIGHUP {
		if conf := c.handleReload(mconfig); conf != nil {
			// Update the value only, not address
			*mconfig = *conf
		}
		goto WAIT
	}

	// Check if we should do a graceful leave
	graceful := false
	if sig == os.Interrupt && mconfig.LeaveOnInt {
		graceful = true
	} else if sig == syscall.SIGTERM && mconfig.LeaveOnTerm {
		graceful = true
	}

	// Bail fast if not doing a graceful leave
	if !graceful {
		return 1
	}

	// Attempt a graceful leave
	gracefulCh := make(chan struct{})
	glog.Info("Gracefully shutting maya api server...")
	go func() {
		if err := c.maya.Leave(); err != nil {
			glog.Errorf("Error: %s", err)
			return
		}
		close(gracefulCh)
	}()

	// Wait for leave or another signal
	select {
	case <-signalCh:
		return 1
	case <-time.After(gracefulTimeout):
		return 1
	case <-gracefulCh:
		return 0
	}
}

// handleReload is invoked when we should reload our configs, e.g. SIGHUP
// TODO
// The current reload code is very basic.
// Add ways to reload the orchestrator & plugins without shuting down the
// process
func (c *CmdStartOptions) handleReload(mconfig *config.MayaConfig) *config.MayaConfig {

	glog.Info("Reloading maya api server configuration...")

	newConf := c.readMayaConfig()
	if newConf == nil {
		glog.Error("Failed to reload config")
		return mconfig
	}

	//TODO Change the log level dynamically
	glog.Infof("Log level is : %s", strings.ToUpper(newConf.LogLevel))

	return newConf
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"strconv"
)

func main() {
	end := flag.Int64("end", 0, "Ending offset")
	lenf := flag.Int64("len", 0, "Length of chunk")
	flag.Usage = func() {
		fmt.Printf(`Usage: %s [OPTIONS] FILENAME OFFSET
where OPTIONS are:
`, os.Args[0])
		flag.PrintDefaults()
		fmt.Println("(Exactly one of -end, -len must be given.)")
	}
	flag.Parse()

	if flag.NArg() != 2 {
		flag.Usage()
		os.Exit(1)
	}
	f, err := os.Open(flag.Arg(0))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer f.Close()
	off, err := strconv.ParseInt(flag.Arg(1), 10, 64)
	if err != nil {
		fmt.Printf("Cannot parse offset: %s\n", err)
		os.Exit(1)
	}

	switch {
	case *end == 0 && *lenf == 0:
		Fatalln("One of -end, -len must be given.")
	case *end != 0 && *lenf != 0:
		Fatalln("Only one of -end, -len may be given.")
	case *end < 0:
		Fatalln("-end cannot be negative.")
	case *end < 0:
		Fatalln("-end cannot be negative.")
	case *end > 0 && *end <= off:
		Fatalln("-end must be greater than the offset.")
	}

	n := *lenf
	if n == 0 {
		n = *end - off
	}
	if _, err := io.Copy(os.Stdout, io.NewSectionReader(f, off, n)); err != nil {
		fmt.Printf("Error while reading chunk: %s\n", err)
		os.Exit(1)
	}
}

func Fatalln(args ...interface{}) {
	fmt.Println(args...)
	os.Exit(1)
}
<commit_msg>Accept more representations of numbers<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"

	"github.com/dustin/go-humanize"
)

func main() {
	var (
		off  Int64
		end  Int64
		lenf Int64
	)
	flag.Var(&end, "end", "Ending offset")
	flag.Var(&lenf, "len", "Length of chunk")
	flag.Usage = func() {
		fmt.Printf(`Usage: %s [OPTIONS] FILENAME OFFSET
where OPTIONS are:
`, os.Args[0])
		flag.PrintDefaults()
		fmt.Println(`Exactly one of -end, -len must be given.
Numbers may be written as 1000, 1e3, or 1kB.`)
	}
	flag.Parse()

	if flag.NArg() != 2 {
		flag.Usage()
		os.Exit(1)
	}
	f, err := os.Open(flag.Arg(0))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer f.Close()
	if err := off.Set(flag.Arg(1)); err != nil {
		Fatalf("Error with offset: %s\n", err)
	}

	switch {
	case end == 0 && lenf == 0:
		Fatalln("One of -end, -len must be given.")
	case end != 0 && lenf != 0:
		Fatalln("Only one of -end, -len may be given.")
	case end < 0:
		Fatalln("-end cannot be negative.")
	case end < 0:
		Fatalln("-end cannot be negative.")
	case end > 0 && end <= off:
		Fatalln("-end must be greater than the offset.")
	}

	n := lenf
	if n == 0 {
		n = end - off
	}
	sr := io.NewSectionReader(f, int64(off), int64(n))
	if _, err := io.Copy(os.Stdout, sr); err != nil {
		fmt.Printf("Error while reading chunk: %s\n", err)
		os.Exit(1)
	}
}

type Int64 int64

func (n *Int64) String() string { return fmt.Sprintf("%d", *n) }
func (n *Int64) Set(s string) error {
	nn, err := strconv.ParseInt(s, 10, 64)
	if err == nil {
		*n = Int64(nn)
		return nil
	}
	f, err := strconv.ParseFloat(s, 64)
	if err == nil {
		if f > float64(math.MaxInt64) {
			return fmt.Errorf("float value too large for float64: %g", f)
		}
		*n = Int64(f)
		return nil
	}
	u, err := humanize.ParseBytes(s)
	if err == nil {
		*n = Int64(u)
		return nil
	}
	return fmt.Errorf("cannot parse %q", s)
}

func Fatalf(format string, args ...interface{}) {
	fmt.Printf(format, args...)
	os.Exit(1)
}

func Fatalln(args ...interface{}) {
	fmt.Println(args...)
	os.Exit(1)
}
<|endoftext|>


<commit_before>package engine

import (
	"errors"
	"strconv"

	garden "github.com/cloudfoundry-incubator/garden/api"
	"github.com/concourse/atc"
	"github.com/concourse/atc/db"
	"github.com/pivotal-golang/lager"
)

var ErrBuildNotActive = errors.New("build not yet active")

//go:generate counterfeiter . BuildDB
type BuildDB interface {
	GetBuild(int) (db.Build, error)
	GetBuildEvents(int, uint) (db.EventSource, error)
	StartBuild(int, string, string) (bool, error)

	AbortBuild(int) error
	AbortNotifier(int) (db.Notifier, error)
}

//go:generate counterfeiter . BuildLocker
type BuildLocker interface {
	AcquireWriteLockImmediately([]db.NamedLock) (db.Lock, error)
}

func NewDBEngine(engine Engine, buildDB BuildDB, locker BuildLocker) Engine {
	return &dbEngine{
		engine: engine,

		db:     buildDB,
		locker: locker,
	}
}

type dbEngine struct {
	engine Engine

	db     BuildDB
	locker BuildLocker
}

func (*dbEngine) Name() string {
	return "db"
}

func (engine *dbEngine) CreateBuild(build db.Build, plan atc.BuildPlan) (Build, error) {
	createdBuild, err := engine.engine.CreateBuild(build, plan)
	if err != nil {
		return nil, err
	}

	started, err := engine.db.StartBuild(build.ID, engine.engine.Name(), createdBuild.Metadata())
	if err != nil {
		return nil, err
	}

	if !started {
		createdBuild.Abort()
	}

	return &dbBuild{
		id: build.ID,

		engine: engine.engine,

		db:     engine.db,
		locker: engine.locker,
	}, nil
}

func (engine *dbEngine) LookupBuild(build db.Build) (Build, error) {
	return &dbBuild{
		id: build.ID,

		engine: engine.engine,

		db:     engine.db,
		locker: engine.locker,
	}, nil
}

type dbBuild struct {
	id int

	engine Engine

	db     BuildDB
	locker BuildLocker
}

func (build *dbBuild) Metadata() string {
	return strconv.Itoa(build.id)
}

func (build *dbBuild) Abort() error {
	// the order below is very important to avoid races with build creation.

	lock, err := build.locker.AcquireWriteLockImmediately([]db.NamedLock{db.BuildTrackingLock(build.id)})
	if err != nil {
		// someone else is tracking the build; abort it, which will notify them
		return build.db.AbortBuild(build.id)
	}

	defer lock.Release()

	// no one is tracking the build; abort it ourselves

	// first save the status so that CreateBuild will see a conflict when it
	// tries to mark the build as started.
	err = build.db.AbortBuild(build.id)
	if err != nil {
		return err
	}

	// reload the model *after* saving the status for the following check to see
	// if it was already started
	model, err := build.db.GetBuild(build.id)
	if err != nil {
		return err
	}

	// if there's an engine, there's a real build to abort
	if model.Engine == "" {
		// otherwise, CreateBuild had not yet tried to start the build, and so it
		// will see the conflict when it tries to transition, and abort itself.
		return nil
	}

	// find the real build to abort...
	engineBuild, err := build.engine.LookupBuild(model)
	if err != nil {
		return err
	}

	// ...and abort it.
	return engineBuild.Abort()
}

func (build *dbBuild) Hijack(spec garden.ProcessSpec, io garden.ProcessIO) (garden.Process, error) {
	model, err := build.db.GetBuild(build.id)
	if err != nil {
		return nil, err
	}

	if model.Engine == "" {
		return nil, ErrBuildNotActive
	}

	engineBuild, err := build.engine.LookupBuild(model)
	if err != nil {
		return nil, err
	}

	return engineBuild.Hijack(spec, io)
}

func (build *dbBuild) Resume(logger lager.Logger) error {
	lock, err := build.locker.AcquireWriteLockImmediately([]db.NamedLock{db.BuildTrackingLock(build.id)})
	if err != nil {
		return nil
	}

	defer lock.Release()

	model, err := build.db.GetBuild(build.id)
	if err != nil {
		return err
	}

	if model.Engine == "" {
		return nil
	}

	engineBuild, err := build.engine.LookupBuild(model)
	if err != nil {
		return err
	}

	aborts, err := build.db.AbortNotifier(build.id)
	if err != nil {
		return err
	}

	defer aborts.Close()

	done := make(chan struct{})
	defer close(done)

	go func() {
		select {
		case <-aborts.Notify():
			engineBuild.Abort()
		case <-done:
		}
	}()

	return engineBuild.Resume(logger)
}
<commit_msg>add logging and comments to db engine<commit_after>package engine

import (
	"errors"
	"strconv"

	garden "github.com/cloudfoundry-incubator/garden/api"
	"github.com/concourse/atc"
	"github.com/concourse/atc/db"
	"github.com/pivotal-golang/lager"
)

var ErrBuildNotActive = errors.New("build not yet active")

//go:generate counterfeiter . BuildDB
type BuildDB interface {
	GetBuild(int) (db.Build, error)
	GetBuildEvents(int, uint) (db.EventSource, error)
	StartBuild(int, string, string) (bool, error)

	AbortBuild(int) error
	AbortNotifier(int) (db.Notifier, error)
}

//go:generate counterfeiter . BuildLocker
type BuildLocker interface {
	AcquireWriteLockImmediately([]db.NamedLock) (db.Lock, error)
}

func NewDBEngine(engine Engine, buildDB BuildDB, locker BuildLocker) Engine {
	return &dbEngine{
		engine: engine,

		db:     buildDB,
		locker: locker,
	}
}

type dbEngine struct {
	engine Engine

	db     BuildDB
	locker BuildLocker
}

func (*dbEngine) Name() string {
	return "db"
}

func (engine *dbEngine) CreateBuild(build db.Build, plan atc.BuildPlan) (Build, error) {
	createdBuild, err := engine.engine.CreateBuild(build, plan)
	if err != nil {
		return nil, err
	}

	started, err := engine.db.StartBuild(build.ID, engine.engine.Name(), createdBuild.Metadata())
	if err != nil {
		return nil, err
	}

	if !started {
		createdBuild.Abort()
	}

	return &dbBuild{
		id: build.ID,

		engine: engine.engine,

		db:     engine.db,
		locker: engine.locker,
	}, nil
}

func (engine *dbEngine) LookupBuild(build db.Build) (Build, error) {
	return &dbBuild{
		id: build.ID,

		engine: engine.engine,

		db:     engine.db,
		locker: engine.locker,
	}, nil
}

type dbBuild struct {
	id int

	engine Engine

	db     BuildDB
	locker BuildLocker
}

func (build *dbBuild) Metadata() string {
	return strconv.Itoa(build.id)
}

func (build *dbBuild) Abort() error {
	// the order below is very important to avoid races with build creation.

	lock, err := build.locker.AcquireWriteLockImmediately([]db.NamedLock{db.BuildTrackingLock(build.id)})
	if err != nil {
		// someone else is tracking the build; abort it, which will notify them
		return build.db.AbortBuild(build.id)
	}

	defer lock.Release()

	// no one is tracking the build; abort it ourselves

	// first save the status so that CreateBuild will see a conflict when it
	// tries to mark the build as started.
	err = build.db.AbortBuild(build.id)
	if err != nil {
		return err
	}

	// reload the model *after* saving the status for the following check to see
	// if it was already started
	model, err := build.db.GetBuild(build.id)
	if err != nil {
		return err
	}

	// if there's an engine, there's a real build to abort
	if model.Engine == "" {
		// otherwise, CreateBuild had not yet tried to start the build, and so it
		// will see the conflict when it tries to transition, and abort itself.
		return nil
	}

	// find the real build to abort...
	engineBuild, err := build.engine.LookupBuild(model)
	if err != nil {
		return err
	}

	// ...and abort it.
	return engineBuild.Abort()
}

func (build *dbBuild) Hijack(spec garden.ProcessSpec, io garden.ProcessIO) (garden.Process, error) {
	model, err := build.db.GetBuild(build.id)
	if err != nil {
		return nil, err
	}

	if model.Engine == "" {
		return nil, ErrBuildNotActive
	}

	engineBuild, err := build.engine.LookupBuild(model)
	if err != nil {
		return nil, err
	}

	return engineBuild.Hijack(spec, io)
}

func (build *dbBuild) Resume(logger lager.Logger) error {
	lock, err := build.locker.AcquireWriteLockImmediately([]db.NamedLock{db.BuildTrackingLock(build.id)})
	if err != nil {
		// already being tracked somewhere; short-circuit
		return nil
	}

	defer lock.Release()

	model, err := build.db.GetBuild(build.id)
	if err != nil {
		logger.Error("failed-to-load-build-from-db", err)
		return err
	}

	if model.Engine == "" {
		logger.Error("build-has-no-engine", err)
		return nil
	}

	engineBuild, err := build.engine.LookupBuild(model)
	if err != nil {
		logger.Error("failed-to-lookup-build-from-engine", err)
		return err
	}

	aborts, err := build.db.AbortNotifier(build.id)
	if err != nil {
		logger.Error("failed-to-listen-for-aborts", err)
		return err
	}

	defer aborts.Close()

	done := make(chan struct{})
	defer close(done)

	go func() {
		select {
		case <-aborts.Notify():
			logger.Info("aborting")

			err := engineBuild.Abort()
			if err != nil {
				logger.Error("failed-to-abort", err)
			}
		case <-done:
		}
	}()

	return engineBuild.Resume(logger)
}
<|endoftext|>


<commit_before>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 6, 1, 0, 0, 0, 0, time.UTC)
	printTargetTime(target)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now()
		now = now.Add(time.Duration(-now.Nanosecond())) // truncate to second
		if now != previous {
			previous = now
			remaining := target.Sub(now)
			printTimeRemaining(now, remaining)
		}
		time.Sleep(50 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent          = "\t"
	highlight_start = "\x1b[1;35m"
	highlight_end   = "\x1b[0m"
)

func printTargetTime(target time.Time) {
	fmt.Print(indent, highlight_start, "Just Go", highlight_end, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printTimeRemaining(now time.Time, remaining time.Duration) {
	var sign string
	if remaining > 0 {
		sign = "-" // countdown is "T minus..."
	} else {
		sign = "+" // count up is "T plus..."
		remaining = -remaining
	}

	var days int
	if remaining >= 24*time.Hour {
		days = int(remaining / (24 * time.Hour))
		remaining = remaining % (24 * time.Hour)
	}

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(remaining, "          \r")
}
<commit_msg>64 day<commit_after>// clock counts down to or up from a target time.
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	target := time.Date(2016, 6, 4, 0, 0, 0, 0, time.UTC)
	printTargetTime(target)
	exitOnEnterKey()

	var previous time.Time
	for {
		now := time.Now()
		now = now.Add(time.Duration(-now.Nanosecond())) // truncate to second
		if now != previous {
			previous = now
			remaining := target.Sub(now)
			printTimeRemaining(now, remaining)
		}
		time.Sleep(50 * time.Millisecond)
	}
}

func exitOnEnterKey() {
	go func() {
		buf := make([]byte, 1)
		_, _ = os.Stdin.Read(buf)
		os.Exit(0)
	}()
}

const (
	indent          = "\t"
	highlight_start = "\x1b[1;35m"
	highlight_end   = "\x1b[0m"
)

func printTargetTime(target time.Time) {
	fmt.Print(indent, highlight_start, "Just Go", highlight_end, "\n")
	fmt.Print(indent, target.Format(time.UnixDate), "\n")
}

func printTimeRemaining(now time.Time, remaining time.Duration) {
	var sign string
	if remaining > 0 {
		sign = "-" // countdown is "T minus..."
	} else {
		sign = "+" // count up is "T plus..."
		remaining = -remaining
	}

	var days int
	if remaining >= 24*time.Hour {
		days = int(remaining / (24 * time.Hour))
		remaining = remaining % (24 * time.Hour)
	}

	fmt.Print(indent, now.Format(time.UnixDate), "  ", sign)
	if days > 0 {
		fmt.Print(days, "d")
	}
	fmt.Print(remaining, "          \r")
}
<|endoftext|>


<commit_before>package srnd

import (
	"errors"
	"io"
	"net"
)

var ErrSpamFilterNotEnabled = errors.New("spam filter access attempted when disabled")

type SpamFilter struct {
	addr    string
	enabled bool
}

func (sp *SpamFilter) Configure(c SpamConfig) {
	sp.enabled = c.enabled
	sp.addr = c.addr
}

func (sp *SpamFilter) Enabled() bool {
	return sp.enabled
}

func (sp *SpamFilter) Rewrite(msg io.Reader, out io.WriteCloser) error {
	var buff [65636]byte
	if !sp.Enabled() {
		return ErrSpamFilterNotEnabled
	}
	addr, err := net.ResolveTCPAddr("tcp", sp.addr)
	if err != nil {
		return err
	}
	c, err := net.DialTCP("tcp", nil, addr)
	if err != nil {
		return err
	}
	io.WriteString(c, "PROCESS SPAMC/1.5\r\n")
	io.CopyBuffer(c, msg, buff[:])
	c.CloseWrite()
	_, err = io.CopyBuffer(out, c, buff[:])
	c.Close()
	out.Close()
	return err
}
<commit_msg>fix sa hook<commit_after>package srnd

import (
	"errors"
	"io"
	"net"
)

var ErrSpamFilterNotEnabled = errors.New("spam filter access attempted when disabled")

type SpamFilter struct {
	addr    string
	enabled bool
}

func (sp *SpamFilter) Configure(c SpamConfig) {
	sp.enabled = c.enabled
	sp.addr = c.addr
}

func (sp *SpamFilter) Enabled() bool {
	return sp.enabled
}

func (sp *SpamFilter) Rewrite(msg io.Reader, out io.WriteCloser) error {
	var buff [65636]byte
	if !sp.Enabled() {
		return ErrSpamFilterNotEnabled
	}
	addr, err := net.ResolveTCPAddr("tcp", sp.addr)
	if err != nil {
		return err
	}
	c, err := net.DialTCP("tcp", nil, addr)
	if err != nil {
		return err
	}
	io.WriteString(c, "PROCESS SPAMC/1.5\r\n\r\n")
	io.CopyBuffer(c, msg, buff[:])
	c.CloseWrite()
	_, err = io.CopyBuffer(out, c, buff[:])
	c.Close()
	out.Close()
	return err
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 config

import (
	"encoding/json"
	"errors"
	"os"
)

// Config represents a configuration passed to the linter.
type Config struct {
	Imports   []BannedAPI `json:"imports"`
	Functions []BannedAPI `json:"functions"`
}

// BannedAPI represents an identifier (e.g. import, function call) that should not be used.
type BannedAPI struct {
	Name       string      `json:"name"` // fully qualified identifier name
	Msg        string      `json:"msg"`  // additional information e.g. rationale for banning
	Exemptions []Exemption `json:"exemptions"`
}

// Exemption represents a location that should be exempted from checking for banned APIs.
type Exemption struct {
	Justification string `json:"justification"`
	AllowedPkg    string `json:"allowedPkg"`
}

// ReadConfigs reads banned APIs from all files.
func ReadConfigs(files []string) (*Config, error) {
	var imports []BannedAPI
	var fns []BannedAPI

	for _, file := range files {
		config, err := readCfg(file)
		if err != nil {
			return nil, err
		}

		imports = append(imports, config.Imports...)
		fns = append(fns, config.Functions...)
	}

	return &Config{Imports: imports, Functions: fns}, nil
}

func readCfg(filename string) (*Config, error) {
	f, err := openFile(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return decodeCfg(f)
}

func openFile(filename string) (*os.File, error) {
	info, err := os.Stat(filename)
	if os.IsNotExist(err) {
		return nil, errors.New("file does not exist")
	}
	if info.IsDir() {
		return nil, errors.New("file is a directory")
	}

	return os.Open(filename)
}

func decodeCfg(f *os.File) (*Config, error) {
	var cfg Config
	err := json.NewDecoder(f).Decode(&cfg)
	if err != nil {
		return nil, err
	}

	return &cfg, nil
}
<commit_msg>Clarify usage instructions for allowed packages.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
// 	https://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 config

import (
	"encoding/json"
	"errors"
	"os"
)

// Config represents a configuration passed to the linter.
type Config struct {
	Imports   []BannedAPI `json:"imports"`
	Functions []BannedAPI `json:"functions"`
}

// BannedAPI represents an identifier (e.g. import, function call) that should not be used.
type BannedAPI struct {
	Name       string      `json:"name"` // fully qualified identifier name
	Msg        string      `json:"msg"`  // additional information e.g. rationale for banning
	Exemptions []Exemption `json:"exemptions"`
}

// Exemption represents a location that should be exempted from checking for banned APIs.
type Exemption struct {
	Justification string `json:"justification"`
	AllowedPkg    string `json:"allowedPkg"` // Uses Go RegExp https://golang.org/pkg/regexp/syntax
}

// ReadConfigs reads banned APIs from all files.
func ReadConfigs(files []string) (*Config, error) {
	var imports []BannedAPI
	var fns []BannedAPI

	for _, file := range files {
		config, err := readCfg(file)
		if err != nil {
			return nil, err
		}

		imports = append(imports, config.Imports...)
		fns = append(fns, config.Functions...)
	}

	return &Config{Imports: imports, Functions: fns}, nil
}

func readCfg(filename string) (*Config, error) {
	f, err := openFile(filename)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return decodeCfg(f)
}

func openFile(filename string) (*os.File, error) {
	info, err := os.Stat(filename)
	if os.IsNotExist(err) {
		return nil, errors.New("file does not exist")
	}
	if info.IsDir() {
		return nil, errors.New("file is a directory")
	}

	return os.Open(filename)
}

func decodeCfg(f *os.File) (*Config, error) {
	var cfg Config
	err := json.NewDecoder(f).Decode(&cfg)
	if err != nil {
		return nil, err
	}

	return &cfg, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
	"testing"
	"time"

	"github.com/docker/docker/integration-cli/cli"
	"gotest.tools/assert"
	"gotest.tools/icmd"
)

// Regression test for https://github.com/docker/docker/issues/7843
func (s *DockerSuite) TestStartAttachReturnsOnError(c *testing.T) {
	// Windows does not support link
	testRequires(c, DaemonIsLinux)
	dockerCmd(c, "run", "--name", "test", "busybox")

	// Expect this to fail because the above container is stopped, this is what we want
	out, _, err := dockerCmdWithError("run", "--name", "test2", "--link", "test:test", "busybox")
	// err shouldn't be nil because container test2 try to link to stopped container
	assert.Assert(c, err != nil, "out: %s", out)

	ch := make(chan error)
	go func() {
		// Attempt to start attached to the container that won't start
		// This should return an error immediately since the container can't be started
		if out, _, err := dockerCmdWithError("start", "-a", "test2"); err == nil {
			ch <- fmt.Errorf("Expected error but got none:\n%s", out)
		}
		close(ch)
	}()

	select {
	case err := <-ch:
		assert.NilError(c, err)
	case <-time.After(5 * time.Second):
		c.Fatalf("Attach did not exit properly")
	}
}

// gh#8555: Exit code should be passed through when using start -a
func (s *DockerSuite) TestStartAttachCorrectExitCode(c *testing.T) {
	testRequires(c, DaemonIsLinux)
	out := cli.DockerCmd(c, "run", "-d", "busybox", "sh", "-c", "sleep 2; exit 1").Stdout()
	out = strings.TrimSpace(out)

	// make sure the container has exited before trying the "start -a"
	cli.DockerCmd(c, "wait", out)

	cli.Docker(cli.Args("start", "-a", out)).Assert(c, icmd.Expected{
		ExitCode: 1,
	})
}

func (s *DockerSuite) TestStartAttachSilent(c *testing.T) {
	name := "teststartattachcorrectexitcode"
	dockerCmd(c, "run", "--name", name, "busybox", "echo", "test")

	// make sure the container has exited before trying the "start -a"
	dockerCmd(c, "wait", name)

	startOut, _ := dockerCmd(c, "start", "-a", name)
	// start -a produced unexpected output
	assert.Equal(c, startOut, "test\n")
}

func (s *DockerSuite) TestStartRecordError(c *testing.T) {
	// TODO Windows CI: Requires further porting work. Should be possible.
	testRequires(c, DaemonIsLinux)
	// when container runs successfully, we should not have state.Error
	dockerCmd(c, "run", "-d", "-p", "9999:9999", "--name", "test", "busybox", "top")
	stateErr := inspectField(c, "test", "State.Error")
	// Expected to not have state error
	assert.Equal(c, stateErr, "")

	// Expect this to fail and records error because of ports conflict
	out, _, err := dockerCmdWithError("run", "-d", "--name", "test2", "-p", "9999:9999", "busybox", "top")
	// err shouldn't be nil because docker run will fail
	assert.Assert(c, err != nil, "out: %s", out)

	stateErr = inspectField(c, "test2", "State.Error")
	assert.Assert(c, strings.Contains(stateErr, "port is already allocated"))
	// Expect the conflict to be resolved when we stop the initial container
	dockerCmd(c, "stop", "test")
	dockerCmd(c, "start", "test2")
	stateErr = inspectField(c, "test2", "State.Error")
	// Expected to not have state error but got one
	assert.Equal(c, stateErr, "")
}

func (s *DockerSuite) TestStartPausedContainer(c *testing.T) {
	// Windows does not support pausing containers
	testRequires(c, IsPausable)

	runSleepingContainer(c, "-d", "--name", "testing")

	dockerCmd(c, "pause", "testing")

	out, _, err := dockerCmdWithError("start", "testing")
	// an error should have been shown that you cannot start paused container
	assert.Assert(c, err != nil, "out: %s", out)
	// an error should have been shown that you cannot start paused container
	assert.Assert(c, strings.Contains(strings.ToLower(out), "cannot start a paused container, try unpause instead"))
}

func (s *DockerSuite) TestStartMultipleContainers(c *testing.T) {
	// Windows does not support --link
	testRequires(c, DaemonIsLinux)
	// run a container named 'parent' and create two container link to `parent`
	dockerCmd(c, "run", "-d", "--name", "parent", "busybox", "top")

	for _, container := range []string{"child_first", "child_second"} {
		dockerCmd(c, "create", "--name", container, "--link", "parent:parent", "busybox", "top")
	}

	// stop 'parent' container
	dockerCmd(c, "stop", "parent")

	out := inspectField(c, "parent", "State.Running")
	// Container should be stopped
	assert.Equal(c, out, "false")

	// start all the three containers, container `child_first` start first which should be failed
	// container 'parent' start second and then start container 'child_second'
	expOut := "Cannot link to a non running container"
	expErr := "failed to start containers: [child_first]"
	out, _, err := dockerCmdWithError("start", "child_first", "parent", "child_second")
	// err shouldn't be nil because start will fail
	assert.Assert(c, err != nil, "out: %s", out)
	// output does not correspond to what was expected
	if !(strings.Contains(out, expOut) || strings.Contains(err.Error(), expErr)) {
		c.Fatalf("Expected out: %v with err: %v  but got out: %v with err: %v", expOut, expErr, out, err)
	}

	for container, expected := range map[string]string{"parent": "true", "child_first": "false", "child_second": "true"} {
		out := inspectField(c, container, "State.Running")
		// Container running state wrong
		assert.Equal(c, out, expected)
	}
}

func (s *DockerSuite) TestStartAttachMultipleContainers(c *testing.T) {
	// run  multiple containers to test
	for _, container := range []string{"test1", "test2", "test3"} {
		runSleepingContainer(c, "--name", container)
	}

	// stop all the containers
	for _, container := range []string{"test1", "test2", "test3"} {
		dockerCmd(c, "stop", container)
	}

	// test start and attach multiple containers at once, expected error
	for _, option := range []string{"-a", "-i", "-ai"} {
		out, _, err := dockerCmdWithError("start", option, "test1", "test2", "test3")
		// err shouldn't be nil because start will fail
		assert.Assert(c, err != nil, "out: %s", out)
		// output does not correspond to what was expected
		assert.Assert(c, strings.Contains(out, "you cannot start and attach multiple containers at once"))
	}

	// confirm the state of all the containers be stopped
	for container, expected := range map[string]string{"test1": "false", "test2": "false", "test3": "false"} {
		out := inspectField(c, container, "State.Running")
		// Container running state wrong
		assert.Equal(c, out, expected)
	}
}

// Test case for #23716
func (s *DockerSuite) TestStartAttachWithRename(c *testing.T) {
	testRequires(c, DaemonIsLinux)
	cli.DockerCmd(c, "create", "-t", "--name", "before", "busybox")
	go func() {
		cli.WaitRun(c, "before")
		cli.DockerCmd(c, "rename", "before", "after")
		cli.DockerCmd(c, "stop", "--time=2", "after")
	}()
	// FIXME(vdemeester) the intent is not clear and potentially racey
	result := cli.Docker(cli.Args("start", "-a", "before")).Assert(c, icmd.Expected{
		ExitCode: 137,
	})
	assert.Assert(c, !strings.Contains(result.Stderr(), "No such container"))
}

func (s *DockerSuite) TestStartReturnCorrectExitCode(c *testing.T) {
	dockerCmd(c, "create", "--restart=on-failure:2", "--name", "withRestart", "busybox", "sh", "-c", "exit 11")
	dockerCmd(c, "create", "--rm", "--name", "withRm", "busybox", "sh", "-c", "exit 12")

	out, exitCode, err := dockerCmdWithError("start", "-a", "withRestart")
	assert.ErrorContains(c, err, "")
	assert.Equal(c, exitCode, 11, fmt.Sprintf("out: %s", out))

	out, exitCode, err = dockerCmdWithError("start", "-a", "withRm")
	assert.ErrorContains(c, err, "")
	assert.Equal(c, exitCode, 12, fmt.Sprintf("out: %s", out))
}
<commit_msg>Windows: disable flaky test TestStartReturnCorrectExitCode<commit_after>package main

import (
	"fmt"
	"runtime"
	"strconv"
	"strings"
	"testing"
	"time"

	"github.com/docker/docker/integration-cli/cli"
	"github.com/docker/docker/pkg/parsers/kernel"
	"gotest.tools/assert"
	"gotest.tools/icmd"
)

// Regression test for https://github.com/docker/docker/issues/7843
func (s *DockerSuite) TestStartAttachReturnsOnError(c *testing.T) {
	// Windows does not support link
	testRequires(c, DaemonIsLinux)
	dockerCmd(c, "run", "--name", "test", "busybox")

	// Expect this to fail because the above container is stopped, this is what we want
	out, _, err := dockerCmdWithError("run", "--name", "test2", "--link", "test:test", "busybox")
	// err shouldn't be nil because container test2 try to link to stopped container
	assert.Assert(c, err != nil, "out: %s", out)

	ch := make(chan error)
	go func() {
		// Attempt to start attached to the container that won't start
		// This should return an error immediately since the container can't be started
		if out, _, err := dockerCmdWithError("start", "-a", "test2"); err == nil {
			ch <- fmt.Errorf("Expected error but got none:\n%s", out)
		}
		close(ch)
	}()

	select {
	case err := <-ch:
		assert.NilError(c, err)
	case <-time.After(5 * time.Second):
		c.Fatalf("Attach did not exit properly")
	}
}

// gh#8555: Exit code should be passed through when using start -a
func (s *DockerSuite) TestStartAttachCorrectExitCode(c *testing.T) {
	testRequires(c, DaemonIsLinux)
	out := cli.DockerCmd(c, "run", "-d", "busybox", "sh", "-c", "sleep 2; exit 1").Stdout()
	out = strings.TrimSpace(out)

	// make sure the container has exited before trying the "start -a"
	cli.DockerCmd(c, "wait", out)

	cli.Docker(cli.Args("start", "-a", out)).Assert(c, icmd.Expected{
		ExitCode: 1,
	})
}

func (s *DockerSuite) TestStartAttachSilent(c *testing.T) {
	name := "teststartattachcorrectexitcode"
	dockerCmd(c, "run", "--name", name, "busybox", "echo", "test")

	// make sure the container has exited before trying the "start -a"
	dockerCmd(c, "wait", name)

	startOut, _ := dockerCmd(c, "start", "-a", name)
	// start -a produced unexpected output
	assert.Equal(c, startOut, "test\n")
}

func (s *DockerSuite) TestStartRecordError(c *testing.T) {
	// TODO Windows CI: Requires further porting work. Should be possible.
	testRequires(c, DaemonIsLinux)
	// when container runs successfully, we should not have state.Error
	dockerCmd(c, "run", "-d", "-p", "9999:9999", "--name", "test", "busybox", "top")
	stateErr := inspectField(c, "test", "State.Error")
	// Expected to not have state error
	assert.Equal(c, stateErr, "")

	// Expect this to fail and records error because of ports conflict
	out, _, err := dockerCmdWithError("run", "-d", "--name", "test2", "-p", "9999:9999", "busybox", "top")
	// err shouldn't be nil because docker run will fail
	assert.Assert(c, err != nil, "out: %s", out)

	stateErr = inspectField(c, "test2", "State.Error")
	assert.Assert(c, strings.Contains(stateErr, "port is already allocated"))
	// Expect the conflict to be resolved when we stop the initial container
	dockerCmd(c, "stop", "test")
	dockerCmd(c, "start", "test2")
	stateErr = inspectField(c, "test2", "State.Error")
	// Expected to not have state error but got one
	assert.Equal(c, stateErr, "")
}

func (s *DockerSuite) TestStartPausedContainer(c *testing.T) {
	// Windows does not support pausing containers
	testRequires(c, IsPausable)

	runSleepingContainer(c, "-d", "--name", "testing")

	dockerCmd(c, "pause", "testing")

	out, _, err := dockerCmdWithError("start", "testing")
	// an error should have been shown that you cannot start paused container
	assert.Assert(c, err != nil, "out: %s", out)
	// an error should have been shown that you cannot start paused container
	assert.Assert(c, strings.Contains(strings.ToLower(out), "cannot start a paused container, try unpause instead"))
}

func (s *DockerSuite) TestStartMultipleContainers(c *testing.T) {
	// Windows does not support --link
	testRequires(c, DaemonIsLinux)
	// run a container named 'parent' and create two container link to `parent`
	dockerCmd(c, "run", "-d", "--name", "parent", "busybox", "top")

	for _, container := range []string{"child_first", "child_second"} {
		dockerCmd(c, "create", "--name", container, "--link", "parent:parent", "busybox", "top")
	}

	// stop 'parent' container
	dockerCmd(c, "stop", "parent")

	out := inspectField(c, "parent", "State.Running")
	// Container should be stopped
	assert.Equal(c, out, "false")

	// start all the three containers, container `child_first` start first which should be failed
	// container 'parent' start second and then start container 'child_second'
	expOut := "Cannot link to a non running container"
	expErr := "failed to start containers: [child_first]"
	out, _, err := dockerCmdWithError("start", "child_first", "parent", "child_second")
	// err shouldn't be nil because start will fail
	assert.Assert(c, err != nil, "out: %s", out)
	// output does not correspond to what was expected
	if !(strings.Contains(out, expOut) || strings.Contains(err.Error(), expErr)) {
		c.Fatalf("Expected out: %v with err: %v  but got out: %v with err: %v", expOut, expErr, out, err)
	}

	for container, expected := range map[string]string{"parent": "true", "child_first": "false", "child_second": "true"} {
		out := inspectField(c, container, "State.Running")
		// Container running state wrong
		assert.Equal(c, out, expected)
	}
}

func (s *DockerSuite) TestStartAttachMultipleContainers(c *testing.T) {
	// run  multiple containers to test
	for _, container := range []string{"test1", "test2", "test3"} {
		runSleepingContainer(c, "--name", container)
	}

	// stop all the containers
	for _, container := range []string{"test1", "test2", "test3"} {
		dockerCmd(c, "stop", container)
	}

	// test start and attach multiple containers at once, expected error
	for _, option := range []string{"-a", "-i", "-ai"} {
		out, _, err := dockerCmdWithError("start", option, "test1", "test2", "test3")
		// err shouldn't be nil because start will fail
		assert.Assert(c, err != nil, "out: %s", out)
		// output does not correspond to what was expected
		assert.Assert(c, strings.Contains(out, "you cannot start and attach multiple containers at once"))
	}

	// confirm the state of all the containers be stopped
	for container, expected := range map[string]string{"test1": "false", "test2": "false", "test3": "false"} {
		out := inspectField(c, container, "State.Running")
		// Container running state wrong
		assert.Equal(c, out, expected)
	}
}

// Test case for #23716
func (s *DockerSuite) TestStartAttachWithRename(c *testing.T) {
	testRequires(c, DaemonIsLinux)
	cli.DockerCmd(c, "create", "-t", "--name", "before", "busybox")
	go func() {
		cli.WaitRun(c, "before")
		cli.DockerCmd(c, "rename", "before", "after")
		cli.DockerCmd(c, "stop", "--time=2", "after")
	}()
	// FIXME(vdemeester) the intent is not clear and potentially racey
	result := cli.Docker(cli.Args("start", "-a", "before")).Assert(c, icmd.Expected{
		ExitCode: 137,
	})
	assert.Assert(c, !strings.Contains(result.Stderr(), "No such container"))
}

func (s *DockerSuite) TestStartReturnCorrectExitCode(c *testing.T) {
	// Note we parse kernel.GetKernelVersion rather than system.GetOSVersion
	// as test binaries aren't manifested, so would otherwise report the wrong
	// build number.
	if runtime.GOOS == "windows" {
		v, err := kernel.GetKernelVersion()
		assert.NilError(c, err)
		build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0])
		if build < 16299 {
			c.Skip("FLAKY on Windows RS1, see #38521")
		}
	}

	dockerCmd(c, "create", "--restart=on-failure:2", "--name", "withRestart", "busybox", "sh", "-c", "exit 11")
	dockerCmd(c, "create", "--rm", "--name", "withRm", "busybox", "sh", "-c", "exit 12")

	out, exitCode, err := dockerCmdWithError("start", "-a", "withRestart")
	assert.ErrorContains(c, err, "")
	assert.Equal(c, exitCode, 11, fmt.Sprintf("out: %s", out))

	out, exitCode, err = dockerCmdWithError("start", "-a", "withRm")
	assert.ErrorContains(c, err, "")
	assert.Equal(c, exitCode, 12, fmt.Sprintf("out: %s", out))
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
)

// Config is the parent configuration struct and includes fields for single
// configurations of a database, cookie, and SMTP connection.
type Config struct {
	HTTPS       bool           `json:"https"`
	Domain      string         `json:"domain"`
	Port        int            `json:"port"`
	TemplateDir string         `json:"templates"`
	StaticDir   string         `json:"static"`
	SecretKey   string         `json:"secret_key"`
	Database    DatabaseConfig `json:"database"`
	Cookie      CookieConfig   `json:"cookie"`
	SMTP        SMTPConfig     `json:"smtp"`
}

// Address returns the domain:port pair.
func (c Config) Address() string {
	return fmt.Sprintf("%s:%d", c.Domain, c.Port)
}

// Parse will create a Config using the file settings.json in the
// current directory.
func Parse() (Config, error) {
	return ParseFile("./settings.json")
}

// ParseFile will create a Config using the file at the given path.
func ParseFile(filename string) (Config, error) {
	f, err := os.Open(filename)
	if err != nil {
		return Config{}, err
	}
	return parse(f)
}

// TODO What about default values other than the cookie? Leave to user?
func parse(f io.Reader) (Config, error) {
	c := Config{
		Cookie: DefaultCookie,
	}
	contents, err := ioutil.ReadAll(f)
	if err != nil {
		return c, err
	}
	if err = json.Unmarshal(contents, &c); err != nil {
		return c, err
	}
	return c, nil
}

func DefaultConfig(key string) Config {
	return Config{
		Cookie:    DefaultCookie,
		Port:      8080,
		SecretKey: key,
	}
}
<commit_msg>Added StaticURL to configuration and default values<commit_after>package config

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
)

// Config is the parent configuration struct and includes fields for single
// configurations of a database, cookie, and SMTP connection.
type Config struct {
	HTTPS       bool           `json:"https"`
	Domain      string         `json:"domain"`
	Port        int            `json:"port"`
	TemplateDir string         `json:"templates"`
	StaticDir   string         `json:"static"`
	StaticURL   string         `json:"static_url"`
	SecretKey   string         `json:"secret_key"`
	Database    DatabaseConfig `json:"database"`
	Cookie      CookieConfig   `json:"cookie"`
	SMTP        SMTPConfig     `json:"smtp"`
}

// Address returns the domain:port pair.
func (c Config) Address() string {
	return fmt.Sprintf("%s:%d", c.Domain, c.Port)
}

// Parse will create a Config using the file settings.json in the
// current directory.
func Parse() (Config, error) {
	return ParseFile("./settings.json")
}

// ParseFile will create a Config using the file at the given path.
func ParseFile(filename string) (Config, error) {
	f, err := os.Open(filename)
	if err != nil {
		return Config{}, err
	}
	return parse(f)
}

// TODO What about default values other than the cookie? Leave to user?
func parse(f io.Reader) (Config, error) {
	c := Config{
		Cookie: DefaultCookie,
	}
	contents, err := ioutil.ReadAll(f)
	if err != nil {
		return c, err
	}
	if err = json.Unmarshal(contents, &c); err != nil {
		return c, err
	}
	return c, nil
}

func DefaultConfig(key string) Config {
	return Config{
		Cookie:    DefaultCookie,
		Port:      8080,
		SecretKey: key,
		StaticURL: "/static/",
	}
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/rvolosatovs/systemgo/system"
	"github.com/spf13/viper"
)

const (
	DEFAULT_PORT   = 8000
	DEFAULT_TARGET = "default.target"
	RESCUE_TARGET  = "rescue.target"
)

var (
	// Default target
	Target string

	// Paths to search for unit files
	Paths []string

	// Port for system daemon to listen on
	Port port

	// Retry specifies the period(in seconds) to wait before
	// restarting the http service if it fails
	Retry time.Duration

	// Wheter to show debugging statements
	Debug bool
)

type port int

func (p port) String() string {
	return fmt.Sprintf(":%v", int(p))
}

func init() {
	viper.SetDefault("port", DEFAULT_PORT)
	viper.SetDefault("target", DEFAULT_TARGET)
	viper.SetDefault("paths", system.DEFAULT_PATHS)
	viper.SetDefault("retry", 1)
	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("systemgo")
	viper.AutomaticEnv()

	viper.SetConfigName("systemgo")

	viper.AddConfigPath(".")
	if os.Getenv("XDG_CONFIG_HOME") != "" {
		viper.AddConfigPath("$XDG_CONFIG_HOME/systemgo")
	}
	viper.AddConfigPath("/etc/systemgo")

	if err := viper.ReadInConfig(); err != nil {
		log.Fatalf("Error reading %s: %s", viper.ConfigFileUsed(), err)
	}
	log.Infof("Found configuration file at %s", viper.ConfigFileUsed())

	Target = viper.GetString("target")
	Paths = viper.GetStringSlice("paths")
	Port = port(viper.GetInt("port"))
	Retry = viper.GetDuration("retry")
	Debug = viper.GetBool("debug")

	if Debug {
		log.SetLevel(log.DebugLevel)
	}
}
<commit_msg>config: don't fail on errors<commit_after>package config

import (
	"fmt"
	"os"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/rvolosatovs/systemgo/system"
	"github.com/spf13/viper"
)

const (
	DEFAULT_PORT   = 8000
	DEFAULT_TARGET = "default.target"
	RESCUE_TARGET  = "rescue.target"
)

var (
	// Default target
	Target string

	// Paths to search for unit files
	Paths []string

	// Port for system daemon to listen on
	Port port

	// Retry specifies the period(in seconds) to wait before
	// restarting the http service if it fails
	Retry time.Duration

	// Wheter to show debugging statements
	Debug bool
)

type port int

func (p port) String() string {
	return fmt.Sprintf(":%v", int(p))
}

func init() {
	viper.SetDefault("port", DEFAULT_PORT)
	viper.SetDefault("target", DEFAULT_TARGET)
	viper.SetDefault("paths", system.DEFAULT_PATHS)
	viper.SetDefault("retry", 1)
	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("systemgo")
	viper.AutomaticEnv()

	viper.SetConfigName("systemgo")
	viper.SetConfigType("yaml")

	viper.AddConfigPath(".")
	if os.Getenv("XDG_CONFIG_HOME") != "" {
		viper.AddConfigPath("$XDG_CONFIG_HOME/systemgo")
	}
	viper.AddConfigPath("/etc/systemgo")

	if err := viper.ReadInConfig(); err != nil {
		switch err.(type) {
		case viper.ConfigFileNotFoundError:
			log.Warn("Config file not found, using defaults")
		case viper.ConfigParseError:
			log.Errorf("Error parsing %s: %s, using defaults", viper.ConfigFileUsed(), err)
		}
	}
	log.Infof("Found configuration file at %s", viper.ConfigFileUsed())

	Target = viper.GetString("target")
	Paths = viper.GetStringSlice("paths")
	Port = port(viper.GetInt("port"))
	Retry = viper.GetDuration("retry")
	Debug = viper.GetBool("debug")

	if Debug {
		log.SetLevel(log.DebugLevel)
	}
}
<|endoftext|>


<commit_before>package config

import (
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/discovery"
	"github.com/docker/docker/pkg/plugingetter"
	"github.com/docker/go-connections/tlsconfig"
	"github.com/docker/libkv/store"
	"github.com/docker/libnetwork/cluster"
	"github.com/docker/libnetwork/datastore"
	"github.com/docker/libnetwork/netlabel"
	"github.com/docker/libnetwork/osl"
)

// Config encapsulates configurations of various Libnetwork components
type Config struct {
	Daemon          DaemonCfg
	Cluster         ClusterCfg
	Scopes          map[string]*datastore.ScopeCfg
	ActiveSandboxes map[string]interface{}
	PluginGetter    plugingetter.PluginGetter
}

// DaemonCfg represents libnetwork core configuration
type DaemonCfg struct {
	Debug                  bool
	Experimental           bool
	DataDir                string
	DefaultNetwork         string
	DefaultDriver          string
	Labels                 []string
	DriverCfg              map[string]interface{}
	ClusterProvider        cluster.Provider
	NetworkControlPlaneMTU int
}

// ClusterCfg represents cluster configuration
type ClusterCfg struct {
	Watcher   discovery.Watcher
	Address   string
	Discovery string
	Heartbeat uint64
}

// LoadDefaultScopes loads default scope configs for scopes which
// doesn't have explicit user specified configs.
func (c *Config) LoadDefaultScopes(dataDir string) {
	for k, v := range datastore.DefaultScopes(dataDir) {
		if _, ok := c.Scopes[k]; !ok {
			c.Scopes[k] = v
		}
	}
}

// ParseConfig parses the libnetwork configuration file
func ParseConfig(tomlCfgFile string) (*Config, error) {
	cfg := &Config{
		Scopes: map[string]*datastore.ScopeCfg{},
	}

	if _, err := toml.DecodeFile(tomlCfgFile, cfg); err != nil {
		return nil, err
	}

	cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
	return cfg, nil
}

// ParseConfigOptions parses the configuration options and returns
// a reference to the corresponding Config structure
func ParseConfigOptions(cfgOptions ...Option) *Config {
	cfg := &Config{
		Daemon: DaemonCfg{
			DriverCfg: make(map[string]interface{}),
		},
		Scopes: make(map[string]*datastore.ScopeCfg),
	}

	cfg.ProcessOptions(cfgOptions...)
	cfg.LoadDefaultScopes(cfg.Daemon.DataDir)

	return cfg
}

// Option is an option setter function type used to pass various configurations
// to the controller
type Option func(c *Config)

// OptionDefaultNetwork function returns an option setter for a default network
func OptionDefaultNetwork(dn string) Option {
	return func(c *Config) {
		logrus.Debugf("Option DefaultNetwork: %s", dn)
		c.Daemon.DefaultNetwork = strings.TrimSpace(dn)
	}
}

// OptionDefaultDriver function returns an option setter for default driver
func OptionDefaultDriver(dd string) Option {
	return func(c *Config) {
		logrus.Debugf("Option DefaultDriver: %s", dd)
		c.Daemon.DefaultDriver = strings.TrimSpace(dd)
	}
}

// OptionDriverConfig returns an option setter for driver configuration.
func OptionDriverConfig(networkType string, config map[string]interface{}) Option {
	return func(c *Config) {
		c.Daemon.DriverCfg[networkType] = config
	}
}

// OptionLabels function returns an option setter for labels
func OptionLabels(labels []string) Option {
	return func(c *Config) {
		for _, label := range labels {
			if strings.HasPrefix(label, netlabel.Prefix) {
				c.Daemon.Labels = append(c.Daemon.Labels, label)
			}
		}
	}
}

// OptionKVProvider function returns an option setter for kvstore provider
func OptionKVProvider(provider string) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionKVProvider: %s", provider)
		if _, ok := c.Scopes[datastore.GlobalScope]; !ok {
			c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.GlobalScope].Client.Provider = strings.TrimSpace(provider)
	}
}

// OptionKVProviderURL function returns an option setter for kvstore url
func OptionKVProviderURL(url string) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionKVProviderURL: %s", url)
		if _, ok := c.Scopes[datastore.GlobalScope]; !ok {
			c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.GlobalScope].Client.Address = strings.TrimSpace(url)
	}
}

// OptionKVOpts function returns an option setter for kvstore options
func OptionKVOpts(opts map[string]string) Option {
	return func(c *Config) {
		if opts["kv.cacertfile"] != "" && opts["kv.certfile"] != "" && opts["kv.keyfile"] != "" {
			logrus.Info("Option Initializing KV with TLS")
			tlsConfig, err := tlsconfig.Client(tlsconfig.Options{
				CAFile:   opts["kv.cacertfile"],
				CertFile: opts["kv.certfile"],
				KeyFile:  opts["kv.keyfile"],
			})
			if err != nil {
				logrus.Errorf("Unable to set up TLS: %s", err)
				return
			}
			if _, ok := c.Scopes[datastore.GlobalScope]; !ok {
				c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{}
			}
			if c.Scopes[datastore.GlobalScope].Client.Config == nil {
				c.Scopes[datastore.GlobalScope].Client.Config = &store.Config{TLS: tlsConfig}
			} else {
				c.Scopes[datastore.GlobalScope].Client.Config.TLS = tlsConfig
			}
			// Workaround libkv/etcd bug for https
			c.Scopes[datastore.GlobalScope].Client.Config.ClientTLS = &store.ClientTLSConfig{
				CACertFile: opts["kv.cacertfile"],
				CertFile:   opts["kv.certfile"],
				KeyFile:    opts["kv.keyfile"],
			}
		} else {
			logrus.Info("Option Initializing KV without TLS")
		}
	}
}

// OptionDiscoveryWatcher function returns an option setter for discovery watcher
func OptionDiscoveryWatcher(watcher discovery.Watcher) Option {
	return func(c *Config) {
		c.Cluster.Watcher = watcher
	}
}

// OptionDiscoveryAddress function returns an option setter for self discovery address
func OptionDiscoveryAddress(address string) Option {
	return func(c *Config) {
		c.Cluster.Address = address
	}
}

// OptionDataDir function returns an option setter for data folder
func OptionDataDir(dataDir string) Option {
	return func(c *Config) {
		c.Daemon.DataDir = dataDir
	}
}

// OptionExecRoot function returns an option setter for exec root folder
func OptionExecRoot(execRoot string) Option {
	return func(c *Config) {
		osl.SetBasePath(execRoot)
	}
}

// OptionPluginGetter returns a plugingetter for remote drivers.
func OptionPluginGetter(pg plugingetter.PluginGetter) Option {
	return func(c *Config) {
		c.PluginGetter = pg
	}
}

// OptionExperimental function returns an option setter for experimental daemon
func OptionExperimental(exp bool) Option {
	return func(c *Config) {
		logrus.Debugf("Option Experimental: %v", exp)
		c.Daemon.Experimental = exp
	}
}

// OptionNetworkControlPlaneMTU function returns an option setter for control plane MTU
func OptionNetworkControlPlaneMTU(exp int) Option {
	return func(c *Config) {
		logrus.Debugf("Network Control Plane MTU: %d", exp)
		if exp < 1500 {
			// if exp == 0 the value won't be used
			logrus.Warnf("Received a MTU of %d, this value is very low,",
				"the network control plane can misbehave", exp)
		}
		c.Daemon.NetworkControlPlaneMTU = exp
	}
}

// ProcessOptions processes options and stores it in config
func (c *Config) ProcessOptions(options ...Option) {
	for _, opt := range options {
		if opt != nil {
			opt(c)
		}
	}
}

// IsValidName validates configuration objects supported by libnetwork
func IsValidName(name string) bool {
	return strings.TrimSpace(name) != ""
}

// OptionLocalKVProvider function returns an option setter for kvstore provider
func OptionLocalKVProvider(provider string) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionLocalKVProvider: %s", provider)
		if _, ok := c.Scopes[datastore.LocalScope]; !ok {
			c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.LocalScope].Client.Provider = strings.TrimSpace(provider)
	}
}

// OptionLocalKVProviderURL function returns an option setter for kvstore url
func OptionLocalKVProviderURL(url string) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionLocalKVProviderURL: %s", url)
		if _, ok := c.Scopes[datastore.LocalScope]; !ok {
			c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.LocalScope].Client.Address = strings.TrimSpace(url)
	}
}

// OptionLocalKVProviderConfig function returns an option setter for kvstore config
func OptionLocalKVProviderConfig(config *store.Config) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionLocalKVProviderConfig: %v", config)
		if _, ok := c.Scopes[datastore.LocalScope]; !ok {
			c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.LocalScope].Client.Config = config
	}
}

// OptionActiveSandboxes function returns an option setter for passing the sandboxes
// which were active during previous daemon life
func OptionActiveSandboxes(sandboxes map[string]interface{}) Option {
	return func(c *Config) {
		c.ActiveSandboxes = sandboxes
	}
}
<commit_msg>Fix warn log<commit_after>package config

import (
	"strings"

	"github.com/BurntSushi/toml"
	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/discovery"
	"github.com/docker/docker/pkg/plugingetter"
	"github.com/docker/go-connections/tlsconfig"
	"github.com/docker/libkv/store"
	"github.com/docker/libnetwork/cluster"
	"github.com/docker/libnetwork/datastore"
	"github.com/docker/libnetwork/netlabel"
	"github.com/docker/libnetwork/osl"
)

// Config encapsulates configurations of various Libnetwork components
type Config struct {
	Daemon          DaemonCfg
	Cluster         ClusterCfg
	Scopes          map[string]*datastore.ScopeCfg
	ActiveSandboxes map[string]interface{}
	PluginGetter    plugingetter.PluginGetter
}

// DaemonCfg represents libnetwork core configuration
type DaemonCfg struct {
	Debug                  bool
	Experimental           bool
	DataDir                string
	DefaultNetwork         string
	DefaultDriver          string
	Labels                 []string
	DriverCfg              map[string]interface{}
	ClusterProvider        cluster.Provider
	NetworkControlPlaneMTU int
}

// ClusterCfg represents cluster configuration
type ClusterCfg struct {
	Watcher   discovery.Watcher
	Address   string
	Discovery string
	Heartbeat uint64
}

// LoadDefaultScopes loads default scope configs for scopes which
// doesn't have explicit user specified configs.
func (c *Config) LoadDefaultScopes(dataDir string) {
	for k, v := range datastore.DefaultScopes(dataDir) {
		if _, ok := c.Scopes[k]; !ok {
			c.Scopes[k] = v
		}
	}
}

// ParseConfig parses the libnetwork configuration file
func ParseConfig(tomlCfgFile string) (*Config, error) {
	cfg := &Config{
		Scopes: map[string]*datastore.ScopeCfg{},
	}

	if _, err := toml.DecodeFile(tomlCfgFile, cfg); err != nil {
		return nil, err
	}

	cfg.LoadDefaultScopes(cfg.Daemon.DataDir)
	return cfg, nil
}

// ParseConfigOptions parses the configuration options and returns
// a reference to the corresponding Config structure
func ParseConfigOptions(cfgOptions ...Option) *Config {
	cfg := &Config{
		Daemon: DaemonCfg{
			DriverCfg: make(map[string]interface{}),
		},
		Scopes: make(map[string]*datastore.ScopeCfg),
	}

	cfg.ProcessOptions(cfgOptions...)
	cfg.LoadDefaultScopes(cfg.Daemon.DataDir)

	return cfg
}

// Option is an option setter function type used to pass various configurations
// to the controller
type Option func(c *Config)

// OptionDefaultNetwork function returns an option setter for a default network
func OptionDefaultNetwork(dn string) Option {
	return func(c *Config) {
		logrus.Debugf("Option DefaultNetwork: %s", dn)
		c.Daemon.DefaultNetwork = strings.TrimSpace(dn)
	}
}

// OptionDefaultDriver function returns an option setter for default driver
func OptionDefaultDriver(dd string) Option {
	return func(c *Config) {
		logrus.Debugf("Option DefaultDriver: %s", dd)
		c.Daemon.DefaultDriver = strings.TrimSpace(dd)
	}
}

// OptionDriverConfig returns an option setter for driver configuration.
func OptionDriverConfig(networkType string, config map[string]interface{}) Option {
	return func(c *Config) {
		c.Daemon.DriverCfg[networkType] = config
	}
}

// OptionLabels function returns an option setter for labels
func OptionLabels(labels []string) Option {
	return func(c *Config) {
		for _, label := range labels {
			if strings.HasPrefix(label, netlabel.Prefix) {
				c.Daemon.Labels = append(c.Daemon.Labels, label)
			}
		}
	}
}

// OptionKVProvider function returns an option setter for kvstore provider
func OptionKVProvider(provider string) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionKVProvider: %s", provider)
		if _, ok := c.Scopes[datastore.GlobalScope]; !ok {
			c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.GlobalScope].Client.Provider = strings.TrimSpace(provider)
	}
}

// OptionKVProviderURL function returns an option setter for kvstore url
func OptionKVProviderURL(url string) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionKVProviderURL: %s", url)
		if _, ok := c.Scopes[datastore.GlobalScope]; !ok {
			c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.GlobalScope].Client.Address = strings.TrimSpace(url)
	}
}

// OptionKVOpts function returns an option setter for kvstore options
func OptionKVOpts(opts map[string]string) Option {
	return func(c *Config) {
		if opts["kv.cacertfile"] != "" && opts["kv.certfile"] != "" && opts["kv.keyfile"] != "" {
			logrus.Info("Option Initializing KV with TLS")
			tlsConfig, err := tlsconfig.Client(tlsconfig.Options{
				CAFile:   opts["kv.cacertfile"],
				CertFile: opts["kv.certfile"],
				KeyFile:  opts["kv.keyfile"],
			})
			if err != nil {
				logrus.Errorf("Unable to set up TLS: %s", err)
				return
			}
			if _, ok := c.Scopes[datastore.GlobalScope]; !ok {
				c.Scopes[datastore.GlobalScope] = &datastore.ScopeCfg{}
			}
			if c.Scopes[datastore.GlobalScope].Client.Config == nil {
				c.Scopes[datastore.GlobalScope].Client.Config = &store.Config{TLS: tlsConfig}
			} else {
				c.Scopes[datastore.GlobalScope].Client.Config.TLS = tlsConfig
			}
			// Workaround libkv/etcd bug for https
			c.Scopes[datastore.GlobalScope].Client.Config.ClientTLS = &store.ClientTLSConfig{
				CACertFile: opts["kv.cacertfile"],
				CertFile:   opts["kv.certfile"],
				KeyFile:    opts["kv.keyfile"],
			}
		} else {
			logrus.Info("Option Initializing KV without TLS")
		}
	}
}

// OptionDiscoveryWatcher function returns an option setter for discovery watcher
func OptionDiscoveryWatcher(watcher discovery.Watcher) Option {
	return func(c *Config) {
		c.Cluster.Watcher = watcher
	}
}

// OptionDiscoveryAddress function returns an option setter for self discovery address
func OptionDiscoveryAddress(address string) Option {
	return func(c *Config) {
		c.Cluster.Address = address
	}
}

// OptionDataDir function returns an option setter for data folder
func OptionDataDir(dataDir string) Option {
	return func(c *Config) {
		c.Daemon.DataDir = dataDir
	}
}

// OptionExecRoot function returns an option setter for exec root folder
func OptionExecRoot(execRoot string) Option {
	return func(c *Config) {
		osl.SetBasePath(execRoot)
	}
}

// OptionPluginGetter returns a plugingetter for remote drivers.
func OptionPluginGetter(pg plugingetter.PluginGetter) Option {
	return func(c *Config) {
		c.PluginGetter = pg
	}
}

// OptionExperimental function returns an option setter for experimental daemon
func OptionExperimental(exp bool) Option {
	return func(c *Config) {
		logrus.Debugf("Option Experimental: %v", exp)
		c.Daemon.Experimental = exp
	}
}

// OptionNetworkControlPlaneMTU function returns an option setter for control plane MTU
func OptionNetworkControlPlaneMTU(exp int) Option {
	return func(c *Config) {
		logrus.Debugf("Network Control Plane MTU: %d", exp)
		if exp < 1500 {
			// if exp == 0 the value won't be used
			logrus.Warnf("Received a MTU of %d, this value is very low, the network control plane can misbehave", exp)
		}
		c.Daemon.NetworkControlPlaneMTU = exp
	}
}

// ProcessOptions processes options and stores it in config
func (c *Config) ProcessOptions(options ...Option) {
	for _, opt := range options {
		if opt != nil {
			opt(c)
		}
	}
}

// IsValidName validates configuration objects supported by libnetwork
func IsValidName(name string) bool {
	return strings.TrimSpace(name) != ""
}

// OptionLocalKVProvider function returns an option setter for kvstore provider
func OptionLocalKVProvider(provider string) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionLocalKVProvider: %s", provider)
		if _, ok := c.Scopes[datastore.LocalScope]; !ok {
			c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.LocalScope].Client.Provider = strings.TrimSpace(provider)
	}
}

// OptionLocalKVProviderURL function returns an option setter for kvstore url
func OptionLocalKVProviderURL(url string) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionLocalKVProviderURL: %s", url)
		if _, ok := c.Scopes[datastore.LocalScope]; !ok {
			c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.LocalScope].Client.Address = strings.TrimSpace(url)
	}
}

// OptionLocalKVProviderConfig function returns an option setter for kvstore config
func OptionLocalKVProviderConfig(config *store.Config) Option {
	return func(c *Config) {
		logrus.Debugf("Option OptionLocalKVProviderConfig: %v", config)
		if _, ok := c.Scopes[datastore.LocalScope]; !ok {
			c.Scopes[datastore.LocalScope] = &datastore.ScopeCfg{}
		}
		c.Scopes[datastore.LocalScope].Client.Config = config
	}
}

// OptionActiveSandboxes function returns an option setter for passing the sandboxes
// which were active during previous daemon life
func OptionActiveSandboxes(sandboxes map[string]interface{}) Option {
	return func(c *Config) {
		c.ActiveSandboxes = sandboxes
	}
}
<|endoftext|>


<commit_before>package config

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/endpoints"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sts"
)

type Config struct {
	Session              *session.Session
	LogPrefix            string
	AccountID            string
	S3Prefix             string
	S3Bucket             string
	Region               string
	IsUTC                bool
	ForceMode            bool
	PreserveGzip         bool
	MaxKeyCount          int64
	StartTime            time.Time
	EndTime              time.Time
	IsELB                bool
	useDefaultCredensial bool
	Debug                bool
	Stdout               bool
}

const (
	usage = `
Usage:
  aloget -o <OutputFilePrefix> -b <S3Bucket> -p <ALBAccessLogPrefix>
         [-s yyyy-MM-ddTHH:mm:ss] [-e yyyy-MM-ddTHH:mm:ss]
         [-r aws-region]
         [-cred] [-gz|-elb] [-utc] [-stdout] [-force] [-debug] [-version]
`

	maxkey          = 10240
	timeFormatInput = "2006-01-02T15:04:05"
	TimeFormatParse = "2006-01-02T15:04:05 MST"
)

var (
	version             = "0"
	ErrOnlyPrintAndExit = errors.New("")
	startTimeInput      = ""
	endTimeInput        = ""
	defaultEndTime      = time.Now()
	defaultStartTime    = defaultEndTime.Add(time.Duration(10) * -time.Minute)
	isVersion           = false
	isHelp              = false
	err                 error
)

func (c *Config) fetchAccountID() error {
	svc := sts.New(c.Session)
	input := &sts.GetCallerIdentityInput{}
	result, err := svc.GetCallerIdentity(input)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			switch aerr.Code() {
			default:
				return fmt.Errorf(aerr.Error())
			}
		} else {
			return fmt.Errorf(err.Error())
		}
	}

	c.AccountID = *result.Account
	return nil
}

func parseFlags(c *Config) {
	flag.StringVar(
		&c.S3Bucket,
		"b",
		"",
		"[Required] S3 Bucket",
	)

	flag.StringVar(
		&c.S3Prefix,
		"p",
		"",
		"[Required] S3 ALB AccessLog Prefix",
	)

	flag.StringVar(
		&c.LogPrefix,
		"o",
		"",
		"[Required] Output file prefix. (ex \"/tmp/alb\")",
	)

	flag.StringVar(
		&startTimeInput,
		"s",
		defaultStartTime.Format(timeFormatInput),
		"Start Time. default 10 minutes ago",
	)

	flag.StringVar(
		&endTimeInput,
		"e",
		defaultEndTime.Format(timeFormatInput),
		"End Time. defalut now ",
	)

	flag.StringVar(
		&c.Region,
		"r",
		"",
		"AWS REGION (ex. us-west-1)",
	)

	flag.BoolVar(
		&c.IsUTC,
		"utc",
		false,
		"-s and -e as UTC",
	)

	flag.BoolVar(
		&c.PreserveGzip,
		"gz",
		false,
		"Don't decompress gzip, preserve gzip format.",
	)

	flag.BoolVar(
		&c.useDefaultCredensial,
		"cred",
		false,
		"Use default credentials (~/.aws/credentials)",
	)

	flag.BoolVar(
		&isVersion,
		"v",
		false,
		"Show version info",
	)

	flag.BoolVar(
		&c.ForceMode,
		"force",
		false,
		"Force mode",
	)

	flag.BoolVar(
		&c.IsELB,
		"elb",
		false,
		"ELB(Classic Load Balancer) mode",
	)

	flag.BoolVar(
		&c.Debug,
		"debug",
		false,
		"Debug mode",
	)

	flag.BoolVar(
		&c.Stdout,
		"stdout",
		false,
		"Write access log to stdout. [Caution] output is not sorted.",
	)

	flag.Parse()
}

func validateOptions(c *Config) error {
	if isVersion {
		fmt.Println("version :", version)
		return ErrOnlyPrintAndExit
	}

	// Check Options
	if len(os.Args) == 1 || isHelp || c.S3Prefix == "" || c.S3Bucket == "" || c.LogPrefix == "" {
		fmt.Println(usage)
		flag.Usage()
		return ErrOnlyPrintAndExit
	}

	if c.IsELB && c.PreserveGzip {
		fmt.Println("-elb can't use with -gz")
		return ErrOnlyPrintAndExit
	}

	// Check Time Inputs
	zone := "UTC"
	if !c.IsUTC {
		zone, _ = time.Now().In(time.Local).Zone()
	}
	c.StartTime, err = time.Parse(
		TimeFormatParse,
		fmt.Sprintf("%s %s", startTimeInput, zone),
	)
	if err != nil {
		return fmt.Errorf("-s time format is %s", timeFormatInput)
	}
	c.EndTime, err = time.Parse(
		TimeFormatParse,
		fmt.Sprintf("%s %s", endTimeInput, zone),
	)
	if err != nil {
		return fmt.Errorf("-e time format is %s", timeFormatInput)
	}
	if c.EndTime.Sub(c.StartTime) < 0 {
		return fmt.Errorf("-s should be before -e")
	}

	if c.Stdout {
		if c.Debug {
			fmt.Println("-stdout can't use with -debug")
			return ErrOnlyPrintAndExit
		}
		c.ForceMode = true
	}

	if c.Region == "" {
		c.Region = os.Getenv("AWS_REGION")
	}
	isValidRegion := false
	for key := range endpoints.AwsPartition().Regions() {
		if c.Region == key {
			isValidRegion = true
			break
		}
	}
	if !isValidRegion {
		if c.Region == "" {
			return fmt.Errorf("No AWS region set, use -r option or os variable AWS_REGION")
		}
		validRegion := ""
		for key := range endpoints.AwsPartition().Regions() {
			validRegion += fmt.Sprintf("%s\n", key)
		}
		return fmt.Errorf("Invalid Region set (%s),it shoud be one of follow.\n%s", c.Region, validRegion)
	}

	if c.useDefaultCredensial {
		c.Session, err = session.NewSession(&aws.Config{
			Credentials: credentials.NewSharedCredentials("", "default"),
			Region:      aws.String(c.Region),
		})
		if err != nil {
			c.Session, err = session.NewSession(&aws.Config{
				Credentials: credentials.NewEnvCredentials(),
				Region:      aws.String(c.Region),
			})
		}
	} else {
		c.Session, err = session.NewSession(&aws.Config{
			Credentials: credentials.NewEnvCredentials(),
			Region:      aws.String(c.Region),
		})
	}
	if err != nil {
		return err
	}

	err = c.fetchAccountID()
	if err != nil {
		return err
	}
	return nil
}

func LoadConfig() (*Config, error) {
	c := new(Config)
	c.MaxKeyCount = maxkey
	parseFlags(c)
	err := validateOptions(c)
	if err != nil {
		return nil, err
	}
	return c, nil
}
<commit_msg>fix bug -stdout with -gz<commit_after>package config

import (
	"errors"
	"flag"
	"fmt"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/endpoints"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/sts"
)

type Config struct {
	Session              *session.Session
	LogPrefix            string
	AccountID            string
	S3Prefix             string
	S3Bucket             string
	Region               string
	IsUTC                bool
	ForceMode            bool
	PreserveGzip         bool
	MaxKeyCount          int64
	StartTime            time.Time
	EndTime              time.Time
	IsELB                bool
	useDefaultCredensial bool
	Debug                bool
	Stdout               bool
}

const (
	usage = `
Usage:
  aloget -o <OutputFilePrefix> -b <S3Bucket> -p <ALBAccessLogPrefix>
         [-s yyyy-MM-ddTHH:mm:ss] [-e yyyy-MM-ddTHH:mm:ss]
         [-r aws-region]
         [-cred] [-gz|-elb] [-utc] [-stdout] [-force] [-debug] [-version]
`

	maxkey          = 10240
	timeFormatInput = "2006-01-02T15:04:05"
	TimeFormatParse = "2006-01-02T15:04:05 MST"
)

var (
	version             = "0"
	ErrOnlyPrintAndExit = errors.New("")
	startTimeInput      = ""
	endTimeInput        = ""
	defaultEndTime      = time.Now()
	defaultStartTime    = defaultEndTime.Add(time.Duration(10) * -time.Minute)
	isVersion           = false
	isHelp              = false
	err                 error
)

func (c *Config) fetchAccountID() error {
	svc := sts.New(c.Session)
	input := &sts.GetCallerIdentityInput{}
	result, err := svc.GetCallerIdentity(input)
	if err != nil {
		if aerr, ok := err.(awserr.Error); ok {
			switch aerr.Code() {
			default:
				return fmt.Errorf(aerr.Error())
			}
		} else {
			return fmt.Errorf(err.Error())
		}
	}

	c.AccountID = *result.Account
	return nil
}

func parseFlags(c *Config) {
	flag.StringVar(
		&c.S3Bucket,
		"b",
		"",
		"[Required] S3 Bucket",
	)

	flag.StringVar(
		&c.S3Prefix,
		"p",
		"",
		"[Required] S3 ALB AccessLog Prefix",
	)

	flag.StringVar(
		&c.LogPrefix,
		"o",
		"",
		"[Required] Output file prefix. (ex \"/tmp/alb\")",
	)

	flag.StringVar(
		&startTimeInput,
		"s",
		defaultStartTime.Format(timeFormatInput),
		"Start Time. default 10 minutes ago",
	)

	flag.StringVar(
		&endTimeInput,
		"e",
		defaultEndTime.Format(timeFormatInput),
		"End Time. defalut now ",
	)

	flag.StringVar(
		&c.Region,
		"r",
		"",
		"AWS REGION (ex. us-west-1)",
	)

	flag.BoolVar(
		&c.IsUTC,
		"utc",
		false,
		"-s and -e as UTC",
	)

	flag.BoolVar(
		&c.PreserveGzip,
		"gz",
		false,
		"Don't decompress gzip, preserve gzip format.",
	)

	flag.BoolVar(
		&c.useDefaultCredensial,
		"cred",
		false,
		"Use default credentials (~/.aws/credentials)",
	)

	flag.BoolVar(
		&isVersion,
		"v",
		false,
		"Show version info",
	)

	flag.BoolVar(
		&c.ForceMode,
		"force",
		false,
		"Force mode",
	)

	flag.BoolVar(
		&c.IsELB,
		"elb",
		false,
		"ELB(Classic Load Balancer) mode",
	)

	flag.BoolVar(
		&c.Debug,
		"debug",
		false,
		"Debug mode",
	)

	flag.BoolVar(
		&c.Stdout,
		"stdout",
		false,
		"Write access log to stdout. [Caution] output is not sorted.",
	)

	flag.Parse()
}

func validateOptions(c *Config) error {
	if isVersion {
		fmt.Println("version :", version)
		return ErrOnlyPrintAndExit
	}

	// Check Options
	if len(os.Args) == 1 || isHelp || c.S3Prefix == "" || c.S3Bucket == "" || c.LogPrefix == "" {
		fmt.Println(usage)
		flag.Usage()
		return ErrOnlyPrintAndExit
	}

	if c.IsELB && c.PreserveGzip {
		fmt.Println("-elb can't use with -gz")
		return ErrOnlyPrintAndExit
	}

	// Check Time Inputs
	zone := "UTC"
	if !c.IsUTC {
		zone, _ = time.Now().In(time.Local).Zone()
	}
	c.StartTime, err = time.Parse(
		TimeFormatParse,
		fmt.Sprintf("%s %s", startTimeInput, zone),
	)
	if err != nil {
		return fmt.Errorf("-s time format is %s", timeFormatInput)
	}
	c.EndTime, err = time.Parse(
		TimeFormatParse,
		fmt.Sprintf("%s %s", endTimeInput, zone),
	)
	if err != nil {
		return fmt.Errorf("-e time format is %s", timeFormatInput)
	}
	if c.EndTime.Sub(c.StartTime) < 0 {
		return fmt.Errorf("-s should be before -e")
	}

	if c.Stdout {
		if c.Debug {
			fmt.Println("-stdout can't use with -debug")
			return ErrOnlyPrintAndExit
		} else if c.PreserveGzip {
			fmt.Println("-stdout can't use with -gz")
			return ErrOnlyPrintAndExit
		}
		c.ForceMode = true
	}

	if c.Region == "" {
		c.Region = os.Getenv("AWS_REGION")
	}
	isValidRegion := false
	for key := range endpoints.AwsPartition().Regions() {
		if c.Region == key {
			isValidRegion = true
			break
		}
	}
	if !isValidRegion {
		if c.Region == "" {
			return fmt.Errorf("No AWS region set, use -r option or os variable AWS_REGION")
		}
		validRegion := ""
		for key := range endpoints.AwsPartition().Regions() {
			validRegion += fmt.Sprintf("%s\n", key)
		}
		return fmt.Errorf("Invalid Region set (%s),it shoud be one of follow.\n%s", c.Region, validRegion)
	}

	if c.useDefaultCredensial {
		c.Session, err = session.NewSession(&aws.Config{
			Credentials: credentials.NewSharedCredentials("", "default"),
			Region:      aws.String(c.Region),
		})
		if err != nil {
			c.Session, err = session.NewSession(&aws.Config{
				Credentials: credentials.NewEnvCredentials(),
				Region:      aws.String(c.Region),
			})
		}
	} else {
		c.Session, err = session.NewSession(&aws.Config{
			Credentials: credentials.NewEnvCredentials(),
			Region:      aws.String(c.Region),
		})
	}
	if err != nil {
		return err
	}

	err = c.fetchAccountID()
	if err != nil {
		return err
	}
	return nil
}

func LoadConfig() (*Config, error) {
	c := new(Config)
	c.MaxKeyCount = maxkey
	parseFlags(c)
	err := validateOptions(c)
	if err != nil {
		return nil, err
	}
	return c, nil
}
<|endoftext|>