<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

import (
	"fmt"
	"net"
	"os"
	"os/user"
	"syscall"

	"github.com/juju/loggo"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju/osenv"
	"launchpad.net/juju-core/provider"
	"launchpad.net/juju-core/utils"
	"launchpad.net/juju-core/version"
)

var logger = loggo.GetLogger("juju.provider.local")

var _ environs.EnvironProvider = (*environProvider)(nil)

type environProvider struct{}

var providerInstance = &environProvider{}

func init() {
	environs.RegisterProvider(provider.Local, providerInstance)
}

var userCurrent = user.Current

// Open implements environs.EnvironProvider.Open.
func (environProvider) Open(cfg *config.Config) (environs.Environ, error) {
	logger.Infof("opening environment %q", cfg.Name())
	if _, ok := cfg.AgentVersion(); !ok {
		newCfg, err := cfg.Apply(map[string]interface{}{
			"agent-version": version.Current.Number.String(),
		})
		if err != nil {
			return nil, err
		}
		cfg = newCfg
	}
	// Set the "namespace" attribute. We do this here, and not in Prepare,
	// for backwards compatibility: older versions did not store the namespace
	// in config.
	if namespace, _ := cfg.UnknownAttrs()["namespace"].(string); namespace == "" {
		username := os.Getenv("USER")
		if username == "" {
			u, err := userCurrent()
			if err != nil {
				return nil, fmt.Errorf("failed to determine username for namespace: %v", err)
			}
			username = u.Username
		}
		var err error
		namespace = fmt.Sprintf("%s-%s", username, cfg.Name())
		cfg, err = cfg.Apply(map[string]interface{}{"namespace": namespace})
		if err != nil {
			return nil, fmt.Errorf("failed to create namespace: %v", err)
		}
	}
	// Do the initial validation on the config.
	localConfig, err := providerInstance.newConfig(cfg)
	if err != nil {
		return nil, err
	}
	if err := VerifyPrerequisites(localConfig.container()); err != nil {
		logger.Errorf("failed verification of local provider prerequisites: %v", err)
		return nil, err
	}
	environ := &localEnviron{name: cfg.Name()}
	if err := environ.SetConfig(cfg); err != nil {
		logger.Errorf("failure setting config: %v", err)
		return nil, err
	}
	return environ, nil
}

var detectAptProxies = utils.DetectAptProxies

// Prepare implements environs.EnvironProvider.Prepare.
func (p environProvider) Prepare(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
	// The user must not set bootstrap-ip; this is determined by the provider,
	// and its presence used to determine whether the environment has yet been
	// bootstrapped.
	if _, ok := cfg.UnknownAttrs()["bootstrap-ip"]; ok {
		return nil, fmt.Errorf("bootstrap-ip must not be specified")
	}
	err := checkLocalPort(cfg.StatePort(), "state port")
	if err != nil {
		return nil, err
	}
	err = checkLocalPort(cfg.APIPort(), "API port")
	if err != nil {
		return nil, err
	}
	// If the user has specified no values for any of the three normal
	// proxies, then look in the environment and set them.
	attrs := map[string]interface{}{
		// We must not proxy SSH through the API server in a
		// local provider environment. Besides not being useful,
		// it may not work; there is no requirement for sshd to
		// be available on machine-0.
		"proxy-ssh": false,
	}
	setIfNotBlank := func(key, value string) {
		if value != "" {
			attrs[key] = value
		}
	}
	logger.Tracef("Look for proxies?")
	if cfg.HttpProxy() == "" &&
		cfg.HttpsProxy() == "" &&
		cfg.FtpProxy() == "" &&
		cfg.NoProxy() == "" {
		proxy := osenv.DetectProxies()
		logger.Tracef("Proxies detected %#v", proxy)
		setIfNotBlank("http-proxy", proxy.Http)
		setIfNotBlank("https-proxy", proxy.Https)
		setIfNotBlank("ftp-proxy", proxy.Ftp)
		setIfNotBlank("no-proxy", proxy.NoProxy)
	}
	if cfg.AptHttpProxy() == "" &&
		cfg.AptHttpsProxy() == "" &&
		cfg.AptFtpProxy() == "" {
		proxy, err := detectAptProxies()
		if err != nil {
			return nil, err
		}
		setIfNotBlank("apt-http-proxy", proxy.Http)
		setIfNotBlank("apt-https-proxy", proxy.Https)
		setIfNotBlank("apt-ftp-proxy", proxy.Ftp)
	}
	if len(attrs) > 0 {
		cfg, err = cfg.Apply(attrs)
		if err != nil {
			return nil, err
		}
	}

	return p.Open(cfg)
}

// checkLocalPort checks that the passed port is not used so far.
var checkLocalPort = func(port int, description string) error {
	logger.Infof("checking %s", description)
	// Try to connect the port on localhost.
	address := fmt.Sprintf("localhost:%d", port)
	// TODO(mue) Add a timeout?
	conn, err := net.Dial("tcp", address)
	if err != nil {
		if nerr, ok := err.(*net.OpError); ok {
			if nerr.Err == syscall.ECONNREFUSED {
				// No connection, so everything is fine.
				return nil
			}
		}
		return err
	}
	// Connected, so port is in use.
	err = conn.Close()
	if err != nil {
		return err
	}
	return fmt.Errorf("cannot use %d as %s, already in use", port, description)
}

// Validate implements environs.EnvironProvider.Validate.
func (provider environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
	// Check for valid changes for the base config values.
	if err := config.Validate(cfg, old); err != nil {
		return nil, err
	}
	validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults)
	if err != nil {
		logger.Errorf("failed to validate unknown attrs: %v", err)
		return nil, err
	}
	localConfig := newEnvironConfig(cfg, validated)
	// Before potentially creating directories, make sure that the
	// root directory has not changed.
	containerType := localConfig.container()
	if old != nil {
		oldLocalConfig, err := provider.newConfig(old)
		if err != nil {
			return nil, fmt.Errorf("old config is not a valid local config: %v", old)
		}
		if containerType != oldLocalConfig.container() {
			return nil, fmt.Errorf("cannot change container from %q to %q",
				oldLocalConfig.container(), containerType)
		}
		if localConfig.rootDir() != oldLocalConfig.rootDir() {
			return nil, fmt.Errorf("cannot change root-dir from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
		if localConfig.networkBridge() != oldLocalConfig.networkBridge() {
			return nil, fmt.Errorf("cannot change network-bridge from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
		if localConfig.storagePort() != oldLocalConfig.storagePort() {
			return nil, fmt.Errorf("cannot change storage-port from %v to %v",
				oldLocalConfig.storagePort(),
				localConfig.storagePort())
		}
	}
	// Currently only supported containers are "lxc" and "kvm".
	if containerType != instance.LXC && containerType != instance.KVM {
		return nil, fmt.Errorf("unsupported container type: %q", containerType)
	}
	dir, err := utils.NormalizePath(localConfig.rootDir())
	if err != nil {
		return nil, err
	}
	if dir == "." {
		dir = osenv.JujuHomePath(cfg.Name())
	}
	// Always assign the normalized path.
	localConfig.attrs["root-dir"] = dir

	if containerType != instance.KVM {
		fastOptionAvailable := useFastLXC(containerType)
		if _, found := localConfig.attrs["lxc-clone"]; !found {
			localConfig.attrs["lxc-clone"] = fastOptionAvailable
		}
	}

	// Apply the coerced unknown values back into the config.
	return cfg.Apply(localConfig.attrs)
}

// BoilerplateConfig implements environs.EnvironProvider.BoilerplateConfig.
func (environProvider) BoilerplateConfig() string {
	return `
# https://juju.ubuntu.com/docs/config-local.html
local:
    type: local

    # root-dir holds the directory that is used for the storage files and
    # database. The default location is $JUJU_HOME/<env-name>.
    # $JUJU_HOME defaults to ~/.juju. Override if needed.
    #
    # root-dir: ~/.juju/local

    # storage-port holds the port where the local provider starts the
    # HTTP file server. Override the value if you have multiple local
    # providers, or if the default port is used by another program.
    #
    # storage-port: 8040

    # network-bridge holds the name of the LXC network bridge to use.
    # Override if the default LXC network bridge is different.
    #
    #
    # network-bridge: lxcbr0

`[1:]
}

// SecretAttrs implements environs.EnvironProvider.SecretAttrs.
func (environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
	// don't have any secret attrs
	return nil, nil
}

func (p environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
	valid, err := p.Validate(cfg, nil)
	if err != nil {
		return nil, err
	}
	return newEnvironConfig(valid, valid.UnknownAttrs()), nil
}
<commit_msg>Add default-series: example to local provider boilerplate.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package local

import (
	"fmt"
	"net"
	"os"
	"os/user"
	"syscall"

	"github.com/juju/loggo"

	"launchpad.net/juju-core/environs"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju/osenv"
	"launchpad.net/juju-core/provider"
	"launchpad.net/juju-core/utils"
	"launchpad.net/juju-core/version"
)

var logger = loggo.GetLogger("juju.provider.local")

var _ environs.EnvironProvider = (*environProvider)(nil)

type environProvider struct{}

var providerInstance = &environProvider{}

func init() {
	environs.RegisterProvider(provider.Local, providerInstance)
}

var userCurrent = user.Current

// Open implements environs.EnvironProvider.Open.
func (environProvider) Open(cfg *config.Config) (environs.Environ, error) {
	logger.Infof("opening environment %q", cfg.Name())
	if _, ok := cfg.AgentVersion(); !ok {
		newCfg, err := cfg.Apply(map[string]interface{}{
			"agent-version": version.Current.Number.String(),
		})
		if err != nil {
			return nil, err
		}
		cfg = newCfg
	}
	// Set the "namespace" attribute. We do this here, and not in Prepare,
	// for backwards compatibility: older versions did not store the namespace
	// in config.
	if namespace, _ := cfg.UnknownAttrs()["namespace"].(string); namespace == "" {
		username := os.Getenv("USER")
		if username == "" {
			u, err := userCurrent()
			if err != nil {
				return nil, fmt.Errorf("failed to determine username for namespace: %v", err)
			}
			username = u.Username
		}
		var err error
		namespace = fmt.Sprintf("%s-%s", username, cfg.Name())
		cfg, err = cfg.Apply(map[string]interface{}{"namespace": namespace})
		if err != nil {
			return nil, fmt.Errorf("failed to create namespace: %v", err)
		}
	}
	// Do the initial validation on the config.
	localConfig, err := providerInstance.newConfig(cfg)
	if err != nil {
		return nil, err
	}
	if err := VerifyPrerequisites(localConfig.container()); err != nil {
		logger.Errorf("failed verification of local provider prerequisites: %v", err)
		return nil, err
	}
	environ := &localEnviron{name: cfg.Name()}
	if err := environ.SetConfig(cfg); err != nil {
		logger.Errorf("failure setting config: %v", err)
		return nil, err
	}
	return environ, nil
}

var detectAptProxies = utils.DetectAptProxies

// Prepare implements environs.EnvironProvider.Prepare.
func (p environProvider) Prepare(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
	// The user must not set bootstrap-ip; this is determined by the provider,
	// and its presence used to determine whether the environment has yet been
	// bootstrapped.
	if _, ok := cfg.UnknownAttrs()["bootstrap-ip"]; ok {
		return nil, fmt.Errorf("bootstrap-ip must not be specified")
	}
	err := checkLocalPort(cfg.StatePort(), "state port")
	if err != nil {
		return nil, err
	}
	err = checkLocalPort(cfg.APIPort(), "API port")
	if err != nil {
		return nil, err
	}
	// If the user has specified no values for any of the three normal
	// proxies, then look in the environment and set them.
	attrs := map[string]interface{}{
		// We must not proxy SSH through the API server in a
		// local provider environment. Besides not being useful,
		// it may not work; there is no requirement for sshd to
		// be available on machine-0.
		"proxy-ssh": false,
	}
	setIfNotBlank := func(key, value string) {
		if value != "" {
			attrs[key] = value
		}
	}
	logger.Tracef("Look for proxies?")
	if cfg.HttpProxy() == "" &&
		cfg.HttpsProxy() == "" &&
		cfg.FtpProxy() == "" &&
		cfg.NoProxy() == "" {
		proxy := osenv.DetectProxies()
		logger.Tracef("Proxies detected %#v", proxy)
		setIfNotBlank("http-proxy", proxy.Http)
		setIfNotBlank("https-proxy", proxy.Https)
		setIfNotBlank("ftp-proxy", proxy.Ftp)
		setIfNotBlank("no-proxy", proxy.NoProxy)
	}
	if cfg.AptHttpProxy() == "" &&
		cfg.AptHttpsProxy() == "" &&
		cfg.AptFtpProxy() == "" {
		proxy, err := detectAptProxies()
		if err != nil {
			return nil, err
		}
		setIfNotBlank("apt-http-proxy", proxy.Http)
		setIfNotBlank("apt-https-proxy", proxy.Https)
		setIfNotBlank("apt-ftp-proxy", proxy.Ftp)
	}
	if len(attrs) > 0 {
		cfg, err = cfg.Apply(attrs)
		if err != nil {
			return nil, err
		}
	}

	return p.Open(cfg)
}

// checkLocalPort checks that the passed port is not used so far.
var checkLocalPort = func(port int, description string) error {
	logger.Infof("checking %s", description)
	// Try to connect the port on localhost.
	address := fmt.Sprintf("localhost:%d", port)
	// TODO(mue) Add a timeout?
	conn, err := net.Dial("tcp", address)
	if err != nil {
		if nerr, ok := err.(*net.OpError); ok {
			if nerr.Err == syscall.ECONNREFUSED {
				// No connection, so everything is fine.
				return nil
			}
		}
		return err
	}
	// Connected, so port is in use.
	err = conn.Close()
	if err != nil {
		return err
	}
	return fmt.Errorf("cannot use %d as %s, already in use", port, description)
}

// Validate implements environs.EnvironProvider.Validate.
func (provider environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
	// Check for valid changes for the base config values.
	if err := config.Validate(cfg, old); err != nil {
		return nil, err
	}
	validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults)
	if err != nil {
		logger.Errorf("failed to validate unknown attrs: %v", err)
		return nil, err
	}
	localConfig := newEnvironConfig(cfg, validated)
	// Before potentially creating directories, make sure that the
	// root directory has not changed.
	containerType := localConfig.container()
	if old != nil {
		oldLocalConfig, err := provider.newConfig(old)
		if err != nil {
			return nil, fmt.Errorf("old config is not a valid local config: %v", old)
		}
		if containerType != oldLocalConfig.container() {
			return nil, fmt.Errorf("cannot change container from %q to %q",
				oldLocalConfig.container(), containerType)
		}
		if localConfig.rootDir() != oldLocalConfig.rootDir() {
			return nil, fmt.Errorf("cannot change root-dir from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
		if localConfig.networkBridge() != oldLocalConfig.networkBridge() {
			return nil, fmt.Errorf("cannot change network-bridge from %q to %q",
				oldLocalConfig.rootDir(),
				localConfig.rootDir())
		}
		if localConfig.storagePort() != oldLocalConfig.storagePort() {
			return nil, fmt.Errorf("cannot change storage-port from %v to %v",
				oldLocalConfig.storagePort(),
				localConfig.storagePort())
		}
	}
	// Currently only supported containers are "lxc" and "kvm".
	if containerType != instance.LXC && containerType != instance.KVM {
		return nil, fmt.Errorf("unsupported container type: %q", containerType)
	}
	dir, err := utils.NormalizePath(localConfig.rootDir())
	if err != nil {
		return nil, err
	}
	if dir == "." {
		dir = osenv.JujuHomePath(cfg.Name())
	}
	// Always assign the normalized path.
	localConfig.attrs["root-dir"] = dir

	if containerType != instance.KVM {
		fastOptionAvailable := useFastLXC(containerType)
		if _, found := localConfig.attrs["lxc-clone"]; !found {
			localConfig.attrs["lxc-clone"] = fastOptionAvailable
		}
	}

	// Apply the coerced unknown values back into the config.
	return cfg.Apply(localConfig.attrs)
}

// BoilerplateConfig implements environs.EnvironProvider.BoilerplateConfig.
func (environProvider) BoilerplateConfig() string {
	return `
# https://juju.ubuntu.com/docs/config-local.html
local:
    type: local

    # root-dir holds the directory that is used for the storage files and
    # database. The default location is $JUJU_HOME/<env-name>.
    # $JUJU_HOME defaults to ~/.juju. Override if needed.
    #
    # root-dir: ~/.juju/local

    # storage-port holds the port where the local provider starts the
    # HTTP file server. Override the value if you have multiple local
    # providers, or if the default port is used by another program.
    #
    # storage-port: 8040

    # network-bridge holds the name of the LXC network bridge to use.
    # Override if the default LXC network bridge is different.
    #
    #
    # network-bridge: lxcbr0

    # The default series to deploy the state-server and charms on.
    #
    # default-series: precise

`[1:]
}

// SecretAttrs implements environs.EnvironProvider.SecretAttrs.
func (environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
	// don't have any secret attrs
	return nil, nil
}

func (p environProvider) newConfig(cfg *config.Config) (*environConfig, error) {
	valid, err := p.Validate(cfg, nil)
	if err != nil {
		return nil, err
	}
	return newEnvironConfig(valid, valid.UnknownAttrs()), nil
}
<|endoftext|>


<commit_before>package client

import (
	"syscall"
	"unsafe"
)

type Termios struct {
	Iflag  uintptr
	Oflag  uintptr
	Cflag  uintptr
	Lflag  uintptr
	Cc     [20]byte
	Ispeed uintptr
	Ospeed uintptr
}

const (
	// Input flags
	inpck  = 0x010
	istrip = 0x020
	icrnl  = 0x100
	ixon   = 0x200

	// Output flags
	opost = 0x1

	// Control flags
	cs8 = 0x300

	// Local flags
	icanon = 0x100
	iexten = 0x400
)

const (
        HUPCL                             = 0x4000
        ICANON                            = 0x100
        ICRNL                             = 0x100
        IEXTEN                            = 0x400
        BRKINT                            = 0x2
        CFLUSH                            = 0xf
        CLOCAL                            = 0x8000
        CREAD                             = 0x800
        CS5                               = 0x0
        CS6                               = 0x100
        CS7                               = 0x200
        CS8                               = 0x300
        CSIZE                             = 0x300
        CSTART                            = 0x11
        CSTATUS                           = 0x14
        CSTOP                             = 0x13
        CSTOPB                            = 0x400
        CSUSP                             = 0x1a
        IGNBRK                            = 0x1
        IGNCR                             = 0x80
        IGNPAR                            = 0x4
        IMAXBEL                           = 0x2000
        INLCR                             = 0x40
        INPCK                             = 0x10
        ISIG                              = 0x80
        ISTRIP                            = 0x20
        IUTF8                             = 0x4000
        IXANY                             = 0x800
        IXOFF                             = 0x400
        IXON                              = 0x200
        NOFLSH                            = 0x80000000
        OCRNL                             = 0x10
        OFDEL                             = 0x20000
        OFILL                             = 0x80
        ONLCR                             = 0x2
        ONLRET                            = 0x40
        ONOCR                             = 0x20
        ONOEOT                            = 0x8
        OPOST                             = 0x1
RENB                            = 0x1000
        PARMRK                            = 0x8
        PARODD                            = 0x2000

        TOSTOP                            = 0x400000
        VDISCARD                          = 0xf
        VDSUSP                            = 0xb
        VEOF                              = 0x0
        VEOL                              = 0x1
        VEOL2                             = 0x2
        VERASE                            = 0x3
        VINTR                             = 0x8
        VKILL                             = 0x5
        VLNEXT                            = 0xe
        VMIN                              = 0x10
        VQUIT                             = 0x9
        VREPRINT                          = 0x6
        VSTART                            = 0xc
        VSTATUS                           = 0x12
        VSTOP                             = 0xd
        VSUSP                             = 0xa
        VT0                               = 0x0
        VT1                               = 0x10000
        VTDLY                             = 0x10000
        VTIME                             = 0x11
	ECHO				  = 0x00000008

        PENDIN                            = 0x20000000
)

type State struct {
       termios Termios
}

// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
        var termios Termios
        _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
        return err == 0
}

// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
        var oldState State
        if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
                return nil, err
        }

        newState := oldState.termios
        newState.Iflag &^= istrip | INLCR | ICRNL | IGNCR | IXON | IXOFF
        newState.Lflag &^= ECHO | ICANON | ISIG
        if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
                return nil, err
        }

        return &oldState, nil
}

// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
        _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
        return err
}

<commit_msg>make sure the standard "replace input carriage returns with line feeds" and "replace output line feeds with carriage return and line feed" flags are set, even on raw (I dont think it should actually be raw)<commit_after>package client

import (
	"syscall"
	"unsafe"
)

type Termios struct {
	Iflag  uintptr
	Oflag  uintptr
	Cflag  uintptr
	Lflag  uintptr
	Cc     [20]byte
	Ispeed uintptr
	Ospeed uintptr
}

const (
	// Input flags
	inpck  = 0x010
	istrip = 0x020
	icrnl  = 0x100
	ixon   = 0x200

	// Output flags
	opost = 0x1

	// Control flags
	cs8 = 0x300

	// Local flags
	icanon = 0x100
	iexten = 0x400
)

const (
        HUPCL                             = 0x4000
        ICANON                            = 0x100
        ICRNL                             = 0x100
        IEXTEN                            = 0x400
        BRKINT                            = 0x2
        CFLUSH                            = 0xf
        CLOCAL                            = 0x8000
        CREAD                             = 0x800
        CS5                               = 0x0
        CS6                               = 0x100
        CS7                               = 0x200
        CS8                               = 0x300
        CSIZE                             = 0x300
        CSTART                            = 0x11
        CSTATUS                           = 0x14
        CSTOP                             = 0x13
        CSTOPB                            = 0x400
        CSUSP                             = 0x1a
        IGNBRK                            = 0x1
        IGNCR                             = 0x80
        IGNPAR                            = 0x4
        IMAXBEL                           = 0x2000
        INLCR                             = 0x40
        INPCK                             = 0x10
        ISIG                              = 0x80
        ISTRIP                            = 0x20
        IUTF8                             = 0x4000
        IXANY                             = 0x800
        IXOFF                             = 0x400
        IXON                              = 0x200
        NOFLSH                            = 0x80000000
        OCRNL                             = 0x10
        OFDEL                             = 0x20000
        OFILL                             = 0x80
        ONLCR                             = 0x2
        ONLRET                            = 0x40
        ONOCR                             = 0x20
        ONOEOT                            = 0x8
        OPOST                             = 0x1
RENB                            = 0x1000
        PARMRK                            = 0x8
        PARODD                            = 0x2000

        TOSTOP                            = 0x400000
        VDISCARD                          = 0xf
        VDSUSP                            = 0xb
        VEOF                              = 0x0
        VEOL                              = 0x1
        VEOL2                             = 0x2
        VERASE                            = 0x3
        VINTR                             = 0x8
        VKILL                             = 0x5
        VLNEXT                            = 0xe
        VMIN                              = 0x10
        VQUIT                             = 0x9
        VREPRINT                          = 0x6
        VSTART                            = 0xc
        VSTATUS                           = 0x12
        VSTOP                             = 0xd
        VSUSP                             = 0xa
        VT0                               = 0x0
        VT1                               = 0x10000
        VTDLY                             = 0x10000
        VTIME                             = 0x11
	ECHO				  = 0x00000008

        PENDIN                            = 0x20000000
)

type State struct {
       termios Termios
}

// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
        var termios Termios
        _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
        return err == 0
}

// MakeRaw put the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd int) (*State, error) {
        var oldState State
        if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
                return nil, err
        }

        newState := oldState.termios
        newState.Iflag &^= ISTRIP | INLCR | IGNCR | IXON | IXOFF
	newState.Iflag |= ICRNL
	newState.Oflag |= ONLCR
        newState.Lflag &^= ECHO | ICANON | ISIG
        if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
                return nil, err
        }

        return &oldState, nil
}

// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func Restore(fd int, state *State) error {
        _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
        return err
}

<|endoftext|>


<commit_before>package haproxy

func ExampleHAProxyClient_Stats() {
	client := &HAProxyClient{
		Addr: "unix:///var/run/haproxy.sock",
	}
	stats, err := client.Stats()
	for _, s := range stats {
		fmt.Printf("%s: %s\n", s.SvName, s.Status)
	}
	// Output:
	//	static: DOWN
	//	app1: UP
	//	app2: UP
	//	...
}

func ExampleHAProxyClient_Info() {
	client := &HAProxyClient{
		Addr: "unix:///var/run/haproxy.sock",
	}
	info, err := client.Info()
	fmt.Printf("%s version %s\n", info.Name, info.Version)
	// Output:
	//	HAProxy version 1.6.3
}

func ExampleHAProxyClient_RunCommand() {
	client := &HAProxyClient{
		Addr: "unix:///var/run/haproxy.sock",
	}
	result, err := h.RunCommand("show info")
	fmt.Println(result.String())
	// Output:
	//	Name: HAProxy
	//	Version: 1.6.3
	//	Release_date: 2015/12/25
	//	Nbproc: 1
	//	...
}
<commit_msg>fix examples<commit_after>package haproxy

import (
	"fmt"
)

func ExampleHAProxyClient_Stats() {
	client := &HAProxyClient{
		Addr: "unix:///var/run/haproxy.sock",
	}
	stats, err := client.Stats()
	if err != nil {
		fmt.Println(err)
		return
	}
	for _, s := range stats {
		fmt.Printf("%s: %s\n", s.SvName, s.Status)
	}
	// Output:
	//static: DOWN
	//app1: UP
	//app2: UP
	//...
}

func ExampleHAProxyClient_Info() {
	client := &HAProxyClient{
		Addr: "unix:///var/run/haproxy.sock",
	}
	info, err := client.Info()
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%s version %s\n", info.Name, info.Version)
	// Output:
	//HAProxy version 1.6.3
}

func ExampleHAProxyClient_RunCommand() {
	client := &HAProxyClient{
		Addr: "unix:///var/run/haproxy.sock",
	}
	result, err := client.RunCommand("show info")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(result.String())
}
<|endoftext|>


<commit_before>package juggler

import (
	"bytes"
	"encoding/json"
	"io"
	"sync"
	"testing"
	"time"

	"github.com/PuerkitoBio/exp/juggler/internal/wstest"
	"github.com/PuerkitoBio/exp/juggler/msg"
	"github.com/gorilla/websocket"
	"github.com/pborman/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestClient(t *testing.T) {
	var buf bytes.Buffer
	done := make(chan bool, 1)
	srv := wstest.StartRecordingServer(t, done, &buf)
	defer srv.Close()

	// the only received message should be EXP
	var (
		mu         sync.Mutex
		cnt        int
		expForUUID uuid.UUID
		wg         sync.WaitGroup
	)
	h := MsgHandlerFunc(func(m msg.Msg) {
		defer wg.Done()

		mu.Lock()
		cnt++
		if assert.Equal(t, msg.ExpMsg, m.Type(), "Expects EXP message") {
			expForUUID = m.(*msg.Exp).Payload.For
		}
		mu.Unlock()
	})

	cli, err := Dial(&websocket.Dialer{}, srv.URL, nil, h)
	require.NoError(t, err, "Dial")
	cli.CallTimeout = time.Millisecond
	cli.LogFunc = (&debugLog{t: t}).Printf

	// call
	wg.Add(1)
	type expected struct {
		uid uuid.UUID
		mt  msg.MessageType
	}
	var expectedResults []expected
	callUUID, err := cli.Call("a", "call", 0)
	require.NoError(t, err, "Call")
	expectedResults = append(expectedResults, expected{callUUID, msg.CallMsg})

	uid, err := cli.Pub("b", "pub")
	require.NoError(t, err, "Pub")
	expectedResults = append(expectedResults, expected{uid, msg.PubMsg})

	uid, err = cli.Sub("c", false)
	require.NoError(t, err, "Sub")
	expectedResults = append(expectedResults, expected{uid, msg.SubMsg})

	uid, err = cli.Unsb("d", true)
	require.NoError(t, err, "Unsb")
	expectedResults = append(expectedResults, expected{uid, msg.UnsbMsg})

	// wait for any pending handlers
	wg.Wait()

	cli.Close()
	<-done

	mu.Lock()
	defer mu.Unlock()
	assert.Equal(t, 1, cnt, "Expected calls to Handler")
	assert.Equal(t, callUUID, expForUUID, "Expired message should be for the Call message")

	// read the messages received by the server
	var p json.RawMessage
	r := bytes.NewReader(buf.Bytes())
	dec := json.NewDecoder(r)
	for i, exp := range expectedResults {
		require.NoError(t, dec.Decode(&p), "Decode %d", i)
		m, err := msg.Unmarshal(bytes.NewReader(p))
		require.NoError(t, err, "Unmarshal %d", i)
		assert.Equal(t, exp.uid, m.UUID(), "%d: uuid", i)
		assert.Equal(t, exp.mt, m.Type(), "%d: type", i)
	}

	// no superfluous bytes
	finalErr := dec.Decode(&p)
	if assert.Error(t, finalErr, "Decode after expected results") {
		assert.Equal(t, io.EOF, finalErr, "EOF")
	}
}
<commit_msg>juggler: fix race when running TestClient with TestUpgrade<commit_after>package juggler

import (
	"bytes"
	"encoding/json"
	"io"
	"sync"
	"testing"
	"time"

	"github.com/PuerkitoBio/exp/juggler/internal/wstest"
	"github.com/PuerkitoBio/exp/juggler/msg"
	"github.com/gorilla/websocket"
	"github.com/pborman/uuid"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestClient(t *testing.T) {
	var buf bytes.Buffer
	done := make(chan bool, 1)
	srv := wstest.StartRecordingServer(t, done, &buf)
	defer srv.Close()

	// the only received message should be EXP
	var (
		mu         sync.Mutex
		cnt        int
		expForUUID uuid.UUID
		wg         sync.WaitGroup
	)
	h := MsgHandlerFunc(func(m msg.Msg) {
		defer wg.Done()

		mu.Lock()
		cnt++
		if assert.Equal(t, msg.ExpMsg, m.Type(), "Expects EXP message") {
			expForUUID = m.(*msg.Exp).Payload.For
		}
		mu.Unlock()
	})

	closed := make(chan bool)
	dbgClientClosed = func(c *Client) { closed <- true }
	defer func() { dbgClientClosed = nil }()

	cli, err := Dial(&websocket.Dialer{}, srv.URL, nil, h)
	require.NoError(t, err, "Dial")
	cli.CallTimeout = time.Millisecond
	cli.LogFunc = (&debugLog{t: t}).Printf

	// call
	wg.Add(1)
	type expected struct {
		uid uuid.UUID
		mt  msg.MessageType
	}
	var expectedResults []expected
	callUUID, err := cli.Call("a", "call", 0)
	require.NoError(t, err, "Call")
	expectedResults = append(expectedResults, expected{callUUID, msg.CallMsg})

	uid, err := cli.Pub("b", "pub")
	require.NoError(t, err, "Pub")
	expectedResults = append(expectedResults, expected{uid, msg.PubMsg})

	uid, err = cli.Sub("c", false)
	require.NoError(t, err, "Sub")
	expectedResults = append(expectedResults, expected{uid, msg.SubMsg})

	uid, err = cli.Unsb("d", true)
	require.NoError(t, err, "Unsb")
	expectedResults = append(expectedResults, expected{uid, msg.UnsbMsg})

	// wait for any pending handlers
	wg.Wait()

	cli.Close()
	<-done
	<-closed

	mu.Lock()
	defer mu.Unlock()
	assert.Equal(t, 1, cnt, "Expected calls to Handler")
	assert.Equal(t, callUUID, expForUUID, "Expired message should be for the Call message")

	// read the messages received by the server
	var p json.RawMessage
	r := bytes.NewReader(buf.Bytes())
	dec := json.NewDecoder(r)
	for i, exp := range expectedResults {
		require.NoError(t, dec.Decode(&p), "Decode %d", i)
		m, err := msg.Unmarshal(bytes.NewReader(p))
		require.NoError(t, err, "Unmarshal %d", i)
		assert.Equal(t, exp.uid, m.UUID(), "%d: uuid", i)
		assert.Equal(t, exp.mt, m.Type(), "%d: type", i)
	}

	// no superfluous bytes
	finalErr := dec.Decode(&p)
	if assert.Error(t, finalErr, "Decode after expected results") {
		assert.Equal(t, io.EOF, finalErr, "EOF")
	}
}
<|endoftext|>


<commit_before>package harmony

import (
	"bytes"
	"io"
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"testing"
)

func TestNewClient_badURL(t *testing.T) {
	_, err := NewClient("")
	if err == nil {
		t.Fatal("expected error, but nothing was returned")
	}

	expected := "client: missing url"
	if !strings.Contains(err.Error(), expected) {
		t.Fatalf("expected %q to contain %q", err.Error(), expected)
	}
}

func TestNewClient_parsesURL(t *testing.T) {
	client, err := NewClient("https://example.com/foo/bar")
	if err != nil {
		t.Fatal(err)
	}

	expected := &url.URL{
		Scheme: "https",
		Host:   "example.com",
		Path:   "/foo/bar",
	}
	if !reflect.DeepEqual(client.URL, expected) {
		t.Fatalf("expected %q to equal %q", client.URL, expected)
	}
}

func TestNewClient_setsDefaultHTTPClient(t *testing.T) {
	client, err := NewClient("https://example.com/foo/bar")
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(client.HTTPClient, http.DefaultClient) {
		t.Fatalf("expected %q to equal %q", client.HTTPClient, http.DefaultClient)
	}
}

func TestLogin_missingUsername(t *testing.T) {
	client, err := NewClient("https://example.com/foo/bar")
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.Login("", "")
	if err == nil {
		t.Fatal("expected error, but nothing was returned")
	}

	expected := "client: missing username"
	if !strings.Contains(err.Error(), expected) {
		t.Fatalf("expected %q to contain %q", err.Error(), expected)
	}
}

func TestLogin_missingPassword(t *testing.T) {
	client, err := NewClient("https://example.com/foo/bar")
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.Login("username", "")
	if err == nil {
		t.Fatal("expected error, but nothing was returned")
	}

	expected := "client: missing password"
	if !strings.Contains(err.Error(), expected) {
		t.Fatalf("expected %q to contain %q", err.Error(), expected)
	}
}

func TestRequest_getsData(t *testing.T) {
	server := newTestHarmonyServer(t)
	defer server.Stop()

	client, err := NewClient(server.URL.String())
	if err != nil {
		t.Fatal(err)
	}

	response, err := client.request("get", "/_status/200")
	if err != nil {
		t.Fatal(err)
	}

	var body bytes.Buffer
	io.Copy(&body, response.Body)

	expected := "Status code: 200"
	if body.String() != expected {
		t.Fatalf("expected %q to equal %q", body.String(), expected)
	}
}

func TestRequest_returnsError(t *testing.T) {
	server := newTestHarmonyServer(t)
	defer server.Stop()

	client, err := NewClient(server.URL.String())
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.request("get", "/_status/404")
	if err == nil {
		t.Fatal("expected error, but nothing was returned")
	}

	expected := "Status code: 404"
	if !strings.Contains(err.Error(), expected) {
		t.Fatalf("expected %q to contain %q", err.Error(), expected)
	}
}

func TestRequestJSON_decodesData(t *testing.T) {
	server := newTestHarmonyServer(t)
	defer server.Stop()

	client, err := NewClient(server.URL.String())
	if err != nil {
		t.Fatal(err)
	}

	var response struct{ Ok bool }
	err = client.requestJSON("get", "/_json", &response)
	if err != nil {
		t.Fatal(err)
	}

	if !response.Ok {
		t.Fatal("expected response to be Ok, but was not")
	}
}
<commit_msg>Update tests for login<commit_after>package harmony

import (
	"net/http"
	"net/url"
	"reflect"
	"strings"
	"testing"
)

func TestNewClient_badURL(t *testing.T) {
	_, err := NewClient("")
	if err == nil {
		t.Fatal("expected error, but nothing was returned")
	}

	expected := "client: missing url"
	if !strings.Contains(err.Error(), expected) {
		t.Fatalf("expected %q to contain %q", err.Error(), expected)
	}
}

func TestNewClient_parsesURL(t *testing.T) {
	client, err := NewClient("https://example.com/foo/bar")
	if err != nil {
		t.Fatal(err)
	}

	expected := &url.URL{
		Scheme: "https",
		Host:   "example.com",
		Path:   "/foo/bar",
	}
	if !reflect.DeepEqual(client.URL, expected) {
		t.Fatalf("expected %q to equal %q", client.URL, expected)
	}
}

func TestNewClient_setsDefaultHTTPClient(t *testing.T) {
	client, err := NewClient("https://example.com/foo/bar")
	if err != nil {
		t.Fatal(err)
	}

	if !reflect.DeepEqual(client.HTTPClient, http.DefaultClient) {
		t.Fatalf("expected %q to equal %q", client.HTTPClient, http.DefaultClient)
	}
}

func TestLogin_missingUsername(t *testing.T) {
	client, err := NewClient("https://example.com/foo/bar")
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.Login("", "")
	if err == nil {
		t.Fatal("expected error, but nothing was returned")
	}

	expected := "client: missing username"
	if !strings.Contains(err.Error(), expected) {
		t.Fatalf("expected %q to contain %q", err.Error(), expected)
	}
}

func TestLogin_missingPassword(t *testing.T) {
	client, err := NewClient("https://example.com/foo/bar")
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.Login("username", "")
	if err == nil {
		t.Fatal("expected error, but nothing was returned")
	}

	expected := "client: missing password"
	if !strings.Contains(err.Error(), expected) {
		t.Fatalf("expected %q to contain %q", err.Error(), expected)
	}
}

func TestLogin_serverErrorMessage(t *testing.T) {
	server := newTestHarmonyServer(t)
	defer server.Stop()

	client, err := NewClient(server.URL.String())
	if err != nil {
		t.Fatal(err)
	}

	_, err = client.Login("username", "password")
	if err == nil {
		t.Fatal("expected error, but nothing was returned")
	}

	expected := "error: Bad login details"
	if !strings.Contains(err.Error(), expected) {
		t.Fatal("expected %q to contain %q", err.Error(), expected)
	}
}

func TestLogin_success(t *testing.T) {
	server := newTestHarmonyServer(t)
	defer server.Stop()

	client, err := NewClient(server.URL.String())
	if err != nil {
		t.Fatal(err)
	}

	token, err := client.Login("sethloves", "bacon")
	if err != nil {
		t.Fatal(err)
	}

	if client.Token == "" {
		t.Fatal("expected client token to be set")
	}

	if token == "" {
		t.Fatal("expected token to be returned")
	}
}

func TestRequest_getsData(t *testing.T) {
	server := newTestHarmonyServer(t)
	defer server.Stop()

	client, err := NewClient(server.URL.String())
	if err != nil {
		t.Fatal(err)
	}

	request, err := client.NewRequest("GET", "/_status/200", nil)
	if err != nil {
		t.Fatal(err)
	}

	if _, err := checkResp(client.HTTPClient.Do(request)); err != nil {
		t.Fatal(err)
	}
}

func TestRequest_returnsError(t *testing.T) {
	server := newTestHarmonyServer(t)
	defer server.Stop()

	client, err := NewClient(server.URL.String())
	if err != nil {
		t.Fatal(err)
	}

	request, err := client.NewRequest("GET", "/_status/404", nil)
	if err != nil {
		t.Fatal(err)
	}

	_, err = checkResp(client.HTTPClient.Do(request))
	if err == nil {
		t.Fatal("expected error, but nothing was returned")
	}

	expected := "404 Not Found"
	if !strings.Contains(err.Error(), expected) {
		t.Fatalf("expected %q to contain %q", err.Error(), expected)
	}
}

func TestRequestJSON_decodesData(t *testing.T) {
	server := newTestHarmonyServer(t)
	defer server.Stop()

	client, err := NewClient(server.URL.String())
	if err != nil {
		t.Fatal(err)
	}

	request, err := client.NewRequest("GET", "/_json", nil)
	if err != nil {
		t.Fatal(err)
	}

	response, err := checkResp(client.HTTPClient.Do(request))
	if err != nil {
		t.Fatal(err)
	}

	var decoded struct{ Ok bool }
	if err := decodeBody(response, &decoded); err != nil {
		t.Fatal(err)
	}

	if !decoded.Ok {
		t.Fatal("expected decoded response to be Ok, but was not")
	}
}
<|endoftext|>


<commit_before>/*
Copyright The Pharmer 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 cloud

import (
	"encoding/json"
	"fmt"
	"time"

	api "pharmer.dev/pharmer/apis/v1alpha1"
	"pharmer.dev/pharmer/cloud/utils/kube"

	"github.com/pkg/errors"
	semver "gomodules.xyz/version"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/clusterclient"
	clusterapi "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
)

func Apply(scope *Scope) error {
	if scope.Cluster.DeletionTimestamp == nil {
		scope.Logger = scope.Logger.WithName("[apply-cluster]")
	} else {
		scope.Logger = scope.Logger.WithName("[delete-cluster]")
	}
	log := scope.Logger

	log.Info("applying cluster")

	cluster := scope.Cluster
	if cluster.Status.Phase == "" {
		log.Info("cluster is in unknown phase")
		return errors.Errorf("Cluster `%s` is in unknown phase", cluster.Name)
	}
	if cluster.Status.Phase == api.ClusterDeleted {
		log.Info("cluster is already deleted, ignoring")
		return nil
	}

	if cluster.Status.Phase == api.ClusterUpgrading {
		log.Info("cluster is upgrading")
		return errors.Errorf("Cluster `%s` is upgrading. Retry after Cluster returns to Ready state", cluster.Name)
	}

	_, err := scope.GetCloudManager()
	if err != nil {
		log.Error(err, "failed to get cloud manager")
		return err
	}
	err = scope.CloudManager.SetCloudConnector()
	if err != nil {
		log.Error(err, "failed to set cloud-connector")
		return err
	}

	if cluster.Status.Phase == api.ClusterPending {
		err := ApplyCreate(scope)
		if err != nil {
			log.Error(err, "failed in applycreate")
			return err
		}
		err = ApplyScale(scope)
		if err != nil {
			log.Error(err, "failed to scale cluster")
			return err
		}
	}

	if cluster.DeletionTimestamp != nil && cluster.Status.Phase != api.ClusterDeleted {
		machineSets, err := scope.StoreProvider.MachineSet(cluster.Name).List(metav1.ListOptions{})
		if err != nil {
			log.Error(err, "failed to list machinesets from store")
			return err
		}
		var replica int32 = 0
		for _, ng := range machineSets {
			ng.Spec.Replicas = &replica
			ng.DeletionTimestamp = &metav1.Time{Time: time.Now()}
			_, err := scope.StoreProvider.MachineSet(cluster.Name).Update(ng)
			if err != nil {
				log.Error(err, "failed to update machinesets in store")
				return err
			}
		}

		err = ApplyDelete(scope)
		if err != nil {
			log.Error(err, "failed in ApplyDelete")
			return err
		}
	}

	log.Info("successfully applied cluster")

	return nil
}

func ApplyCreate(scope *Scope) error {
	log := scope.Logger
	cm, err := scope.GetCloudManager()
	if err != nil {
		return err
	}

	err = cm.PrepareCloud()
	if err != nil {
		log.Error(err, "failed to prepare cloud infrastructure")
		return err
	}

	if !api.ManagedProviders.Has(cm.GetCluster().Spec.Config.Cloud.CloudProvider) {
		err = setMasterSKU(scope)
		if err != nil {
			log.Error(err, "failed to set default master sku")
			return err
		}

		machine, err := getLeaderMachine(scope.StoreProvider.Machine(scope.Cluster.Name), scope.Cluster.Name)
		if err != nil {
			log.Error(err, "failed to get leader machine")
			return err
		}

		err = cm.EnsureMaster(machine)
		if err != nil {
			log.Error(err, "failed to create master machine")
			return err
		}
	}

	cluster := cm.GetCluster()

	kubeClient, err := cm.GetAdminClient()
	if err != nil {
		log.Error(err, "failed to get admin client")
		return err
	}

	if err = kube.WaitForReadyMaster(log, kubeClient); err != nil {
		log.Error(err, "failed waiting for master to be ready")
		return err
	}

	// create ccm credential
	err = cm.CreateCredentials(kubeClient)
	if err != nil {
		log.Error(err, "failed to create ccm-credential")
		return err
	}

	if !api.ManagedProviders.Has(cluster.Spec.Config.Cloud.CloudProvider) {
		err = applyClusterAPI(scope)
		if err != nil {
			log.Error(err, "failed to create cluster api components")
			return err
		}
	}

	ns, err := scope.AdminClient.CoreV1().Namespaces().Get(metav1.NamespaceSystem, metav1.GetOptions{})
	if err != nil {
		log.Error(err, "failed to get `kube-system` namespace")
		return err
	}
	if cluster, err = scope.StoreProvider.Clusters().UpdateUUID(cluster, string(ns.UID)); err != nil {
		log.Error(err, "failed to update cluster uuid in store")
		return err
	}

	cluster.Status.Phase = api.ClusterReady
	if _, err = scope.StoreProvider.Clusters().UpdateStatus(cluster); err != nil {
		log.Error(err, "failed to update cluster status in store")
		return err
	}

	log.Info("successful")

	return nil
}

func applyClusterAPI(s *Scope) error {
	cluster := s.Cluster
	ca, err := NewClusterAPI(s, "cloud-provider-system")
	if err != nil {
		s.Logger.Error(err, "failed to create cluster-api clients")
		return err
	}
	ca.Logger = s.Logger.WithName("[cluster-api]")
	log := ca.Logger

	clusterAPIcomponents, err := s.CloudManager.GetClusterAPIComponents()
	if err != nil {
		log.Error(err, "failed to get clusterAPI components")
		return err
	}

	if err := ca.Apply(clusterAPIcomponents); err != nil {
		log.Error(err, "failed to apply cluster api components")
		return err
	}

	log.Info("adding other master machines")

	clusterEndpoint := s.Cluster.APIServerURL()
	if clusterEndpoint == "" {
		return errors.Errorf("failed to detect api server url for Cluster %s", s.Cluster.Name)
	}

	capiClient, err := kube.GetClusterAPIClient(s.StoreProvider.Certificates(cluster.Name), clusterEndpoint)
	if err != nil {
		log.Error(err, "failed to get cluster api client")
		return err
	}

	machines, err := s.StoreProvider.Machine(cluster.Name).List(metav1.ListOptions{})
	if err != nil {
		log.Error(err, "failed to list master machines")
		return err
	}

	for _, m := range machines {
		_, err := capiClient.ClusterV1alpha1().Machines(cluster.Spec.ClusterAPI.Namespace).Create(m)
		if err != nil && !api.ErrObjectModified(err) && !api.ErrAlreadyExist(err) {
			log.Error(err, "failed ot create machine", "namespace", cluster.Spec.ClusterAPI.Namespace, "machine-name", m.Name)
			return err
		}
	}

	return nil
}

func setMasterSKU(scope *Scope) error {
	log := scope.Logger

	clusterName := scope.Cluster.Name
	cm := scope.CloudManager

	machines, err := scope.StoreProvider.Machine(clusterName).List(metav1.ListOptions{})
	if err != nil {
		log.Error(err, "failed to list machines from store")
		return err
	}

	machineSets, err := scope.StoreProvider.MachineSet(clusterName).List(metav1.ListOptions{})
	if err != nil {
		log.Error(err, "failed to list machinesets from store")
		return err
	}

	totalNodes := nodeCount(machineSets)

	sku := cm.GetMasterSKU(totalNodes)

	// update all the master machines
	for _, m := range machines {
		providerspec, err := cm.GetDefaultMachineProviderSpec(sku, api.MasterMachineRole)
		if err != nil {
			log.Error(err, "failed to get default provider spec")
			return err
		}
		m.Spec.ProviderSpec = providerspec

		_, err = scope.StoreProvider.Machine(clusterName).Update(m)
		if err != nil {
			log.Error(err, "failed to update machine to store", "machine-name", m.Name)
			return err
		}
	}

	return nil
}

func ApplyScale(s *Scope) error {
	log := s.Logger

	log.Info("scaling Machine Sets")

	if api.ManagedProviders.Has(s.Cluster.CloudProvider()) {
		return s.CloudManager.ApplyScale()
	}

	cluster := s.Cluster
	machineSets, err := s.StoreProvider.MachineSet(cluster.Name).List(metav1.ListOptions{})
	if err != nil {
		log.Error(err, "failed to list machineset")
		return err
	}

	bc, err := kube.GetBooststrapClient(s.StoreProvider.Certificates(s.Cluster.Name), s.Cluster, s.GetCaCertPair())
	if err != nil {
		log.Error(err, "failed to get bootstrap clients")
		return err
	}

	clusterEndpoint := s.Cluster.APIServerURL()
	if clusterEndpoint == "" {
		return errors.Errorf("failed to detect api server url for Cluster %s", s.Cluster.Name)
	}

	clusterClient, err := kube.GetClusterAPIClient(s.StoreProvider.Certificates(s.Cluster.Name), clusterEndpoint)
	if err != nil {
		log.Error(err, "failed to get cluster api client")
		return err
	}

	for _, machineSet := range machineSets {
		if machineSet.DeletionTimestamp != nil {
			err = clusterClient.ClusterV1alpha1().MachineSets(machineSet.Namespace).Delete(machineSet.Name, nil)
			if err != nil {
				log.Error(err, "failed to delete machinesets")
				return err
			}
			if err = s.StoreProvider.MachineSet(cluster.Name).Delete(machineSet.Name); err != nil {
				log.Error(err, "failed to delete machinesets")
				return err
			}
			continue
		}

		data, err := json.Marshal(machineSet)
		if err != nil {
			log.Error(err, "failed to json marshal machineset")
			return err
		}
		if err = bc.Apply(string(data)); err != nil {
			log.Error(err, "failed to apply machineset")
			return err
		}
	}

	log.Info("successfully scaled machineset")

	return nil
}

func ApplyUpgrade(s *Scope) error {
	s.Logger = s.Logger.WithName("[apply-upgrade]")

	kc, err := s.GetAdminClient()
	if err != nil {
		return err
	}

	Cluster := s.Cluster
	var masterMachine *clusterapi.Machine
	masterName := fmt.Sprintf("%v-master", Cluster.Name)
	masterMachine, err = s.StoreProvider.Machine(Cluster.Name).Get(masterName)
	if err != nil {
		return err
	}

	masterMachine.Spec.Versions.ControlPlane = Cluster.Spec.Config.KubernetesVersion
	masterMachine.Spec.Versions.Kubelet = Cluster.Spec.Config.KubernetesVersion

	var bc clusterclient.Client
	bc, err = kube.GetBooststrapClient(s.StoreProvider.Certificates(s.Cluster.Name), s.Cluster, s.GetCaCertPair())
	if err != nil {
		return err
	}

	var data []byte
	if data, err = json.Marshal(masterMachine); err != nil {
		return err
	}
	if err = bc.Apply(string(data)); err != nil {
		return err
	}

	// Wait until masterMachine is updated
	desiredVersion, _ := semver.NewVersion(s.Cluster.ClusterConfig().KubernetesVersion)
	if err = kube.WaitForReadyMasterVersion(kc, desiredVersion); err != nil {
		return err
	}

	var machineSets []*clusterapi.MachineSet
	machineSets, err = s.StoreProvider.MachineSet(Cluster.Name).List(metav1.ListOptions{})
	if err != nil {
		return err
	}

	for _, machineSet := range machineSets {
		machineSet.Spec.Template.Spec.Versions.Kubelet = Cluster.Spec.Config.KubernetesVersion
		if data, err = json.Marshal(machineSet); err != nil {
			return err
		}

		if err = bc.Apply(string(data)); err != nil {
			return err
		}
	}

	Cluster.Status.Phase = api.ClusterReady
	if _, err = s.StoreProvider.Clusters().UpdateStatus(Cluster); err != nil {
		return err
	}

	return err
}

func nodeCount(machineSets []*clusterapi.MachineSet) int32 {
	var count int32
	for _, machineSet := range machineSets {
		count += *machineSet.Spec.Replicas
	}
	return count
}
<commit_msg>Fix kubeClient being nil (#514)<commit_after>/*
Copyright The Pharmer 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 cloud

import (
	"encoding/json"
	"fmt"
	"time"

	api "pharmer.dev/pharmer/apis/v1alpha1"
	"pharmer.dev/pharmer/cloud/utils/kube"

	"github.com/pkg/errors"
	semver "gomodules.xyz/version"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/cluster-api/cmd/clusterctl/clusterdeployer/clusterclient"
	clusterapi "sigs.k8s.io/cluster-api/pkg/apis/cluster/v1alpha1"
)

func Apply(scope *Scope) error {
	if scope.Cluster.DeletionTimestamp == nil {
		scope.Logger = scope.Logger.WithName("[apply-cluster]")
	} else {
		scope.Logger = scope.Logger.WithName("[delete-cluster]")
	}
	log := scope.Logger

	log.Info("applying cluster")

	cluster := scope.Cluster
	if cluster.Status.Phase == "" {
		log.Info("cluster is in unknown phase")
		return errors.Errorf("Cluster `%s` is in unknown phase", cluster.Name)
	}
	if cluster.Status.Phase == api.ClusterDeleted {
		log.Info("cluster is already deleted, ignoring")
		return nil
	}

	if cluster.Status.Phase == api.ClusterUpgrading {
		log.Info("cluster is upgrading")
		return errors.Errorf("Cluster `%s` is upgrading. Retry after Cluster returns to Ready state", cluster.Name)
	}

	_, err := scope.GetCloudManager()
	if err != nil {
		log.Error(err, "failed to get cloud manager")
		return err
	}
	err = scope.CloudManager.SetCloudConnector()
	if err != nil {
		log.Error(err, "failed to set cloud-connector")
		return err
	}

	if cluster.Status.Phase == api.ClusterPending {
		err := ApplyCreate(scope)
		if err != nil {
			log.Error(err, "failed in applycreate")
			return err
		}
		err = ApplyScale(scope)
		if err != nil {
			log.Error(err, "failed to scale cluster")
			return err
		}
	}

	if cluster.DeletionTimestamp != nil && cluster.Status.Phase != api.ClusterDeleted {
		machineSets, err := scope.StoreProvider.MachineSet(cluster.Name).List(metav1.ListOptions{})
		if err != nil {
			log.Error(err, "failed to list machinesets from store")
			return err
		}
		var replica int32 = 0
		for _, ng := range machineSets {
			ng.Spec.Replicas = &replica
			ng.DeletionTimestamp = &metav1.Time{Time: time.Now()}
			_, err := scope.StoreProvider.MachineSet(cluster.Name).Update(ng)
			if err != nil {
				log.Error(err, "failed to update machinesets in store")
				return err
			}
		}

		err = ApplyDelete(scope)
		if err != nil {
			log.Error(err, "failed in ApplyDelete")
			return err
		}
	}

	log.Info("successfully applied cluster")

	return nil
}

func ApplyCreate(scope *Scope) error {
	log := scope.Logger
	cm, err := scope.GetCloudManager()
	if err != nil {
		return err
	}

	err = cm.PrepareCloud()
	if err != nil {
		log.Error(err, "failed to prepare cloud infrastructure")
		return err
	}

	if !api.ManagedProviders.Has(cm.GetCluster().Spec.Config.Cloud.CloudProvider) {
		err = setMasterSKU(scope)
		if err != nil {
			log.Error(err, "failed to set default master sku")
			return err
		}

		machine, err := getLeaderMachine(scope.StoreProvider.Machine(scope.Cluster.Name), scope.Cluster.Name)
		if err != nil {
			log.Error(err, "failed to get leader machine")
			return err
		}

		err = cm.EnsureMaster(machine)
		if err != nil {
			log.Error(err, "failed to create master machine")
			return err
		}
	}

	cluster := cm.GetCluster()

	kubeClient, err := cm.GetAdminClient()
	if err != nil {
		log.Error(err, "failed to get admin client")
		return err
	}

	if err = kube.WaitForReadyMaster(log, kubeClient); err != nil {
		log.Error(err, "failed waiting for master to be ready")
		return err
	}

	// create ccm credential
	err = cm.CreateCredentials(kubeClient)
	if err != nil {
		log.Error(err, "failed to create ccm-credential")
		return err
	}

	if !api.ManagedProviders.Has(cluster.Spec.Config.Cloud.CloudProvider) {
		err = applyClusterAPI(scope)
		if err != nil {
			log.Error(err, "failed to create cluster api components")
			return err
		}
	}

	ns, err := kubeClient.CoreV1().Namespaces().Get(metav1.NamespaceSystem, metav1.GetOptions{})
	if err != nil {
		log.Error(err, "failed to get `kube-system` namespace")
		return err
	}
	if cluster, err = scope.StoreProvider.Clusters().UpdateUUID(cluster, string(ns.UID)); err != nil {
		log.Error(err, "failed to update cluster uuid in store")
		return err
	}

	cluster.Status.Phase = api.ClusterReady
	if _, err = scope.StoreProvider.Clusters().UpdateStatus(cluster); err != nil {
		log.Error(err, "failed to update cluster status in store")
		return err
	}

	log.Info("successful")

	return nil
}

func applyClusterAPI(s *Scope) error {
	cluster := s.Cluster
	ca, err := NewClusterAPI(s, "cloud-provider-system")
	if err != nil {
		s.Logger.Error(err, "failed to create cluster-api clients")
		return err
	}
	ca.Logger = s.Logger.WithName("[cluster-api]")
	log := ca.Logger

	clusterAPIcomponents, err := s.CloudManager.GetClusterAPIComponents()
	if err != nil {
		log.Error(err, "failed to get clusterAPI components")
		return err
	}

	if err := ca.Apply(clusterAPIcomponents); err != nil {
		log.Error(err, "failed to apply cluster api components")
		return err
	}

	log.Info("adding other master machines")

	clusterEndpoint := s.Cluster.APIServerURL()
	if clusterEndpoint == "" {
		return errors.Errorf("failed to detect api server url for Cluster %s", s.Cluster.Name)
	}

	capiClient, err := kube.GetClusterAPIClient(s.StoreProvider.Certificates(cluster.Name), clusterEndpoint)
	if err != nil {
		log.Error(err, "failed to get cluster api client")
		return err
	}

	machines, err := s.StoreProvider.Machine(cluster.Name).List(metav1.ListOptions{})
	if err != nil {
		log.Error(err, "failed to list master machines")
		return err
	}

	for _, m := range machines {
		_, err := capiClient.ClusterV1alpha1().Machines(cluster.Spec.ClusterAPI.Namespace).Create(m)
		if err != nil && !api.ErrObjectModified(err) && !api.ErrAlreadyExist(err) {
			log.Error(err, "failed ot create machine", "namespace", cluster.Spec.ClusterAPI.Namespace, "machine-name", m.Name)
			return err
		}
	}

	return nil
}

func setMasterSKU(scope *Scope) error {
	log := scope.Logger

	clusterName := scope.Cluster.Name
	cm := scope.CloudManager

	machines, err := scope.StoreProvider.Machine(clusterName).List(metav1.ListOptions{})
	if err != nil {
		log.Error(err, "failed to list machines from store")
		return err
	}

	machineSets, err := scope.StoreProvider.MachineSet(clusterName).List(metav1.ListOptions{})
	if err != nil {
		log.Error(err, "failed to list machinesets from store")
		return err
	}

	totalNodes := nodeCount(machineSets)

	sku := cm.GetMasterSKU(totalNodes)

	// update all the master machines
	for _, m := range machines {
		providerspec, err := cm.GetDefaultMachineProviderSpec(sku, api.MasterMachineRole)
		if err != nil {
			log.Error(err, "failed to get default provider spec")
			return err
		}
		m.Spec.ProviderSpec = providerspec

		_, err = scope.StoreProvider.Machine(clusterName).Update(m)
		if err != nil {
			log.Error(err, "failed to update machine to store", "machine-name", m.Name)
			return err
		}
	}

	return nil
}

func ApplyScale(s *Scope) error {
	log := s.Logger

	log.Info("scaling Machine Sets")

	if api.ManagedProviders.Has(s.Cluster.CloudProvider()) {
		return s.CloudManager.ApplyScale()
	}

	cluster := s.Cluster
	machineSets, err := s.StoreProvider.MachineSet(cluster.Name).List(metav1.ListOptions{})
	if err != nil {
		log.Error(err, "failed to list machineset")
		return err
	}

	bc, err := kube.GetBooststrapClient(s.StoreProvider.Certificates(s.Cluster.Name), s.Cluster, s.GetCaCertPair())
	if err != nil {
		log.Error(err, "failed to get bootstrap clients")
		return err
	}

	clusterEndpoint := s.Cluster.APIServerURL()
	if clusterEndpoint == "" {
		return errors.Errorf("failed to detect api server url for Cluster %s", s.Cluster.Name)
	}

	clusterClient, err := kube.GetClusterAPIClient(s.StoreProvider.Certificates(s.Cluster.Name), clusterEndpoint)
	if err != nil {
		log.Error(err, "failed to get cluster api client")
		return err
	}

	for _, machineSet := range machineSets {
		if machineSet.DeletionTimestamp != nil {
			err = clusterClient.ClusterV1alpha1().MachineSets(machineSet.Namespace).Delete(machineSet.Name, nil)
			if err != nil {
				log.Error(err, "failed to delete machinesets")
				return err
			}
			if err = s.StoreProvider.MachineSet(cluster.Name).Delete(machineSet.Name); err != nil {
				log.Error(err, "failed to delete machinesets")
				return err
			}
			continue
		}

		data, err := json.Marshal(machineSet)
		if err != nil {
			log.Error(err, "failed to json marshal machineset")
			return err
		}
		if err = bc.Apply(string(data)); err != nil {
			log.Error(err, "failed to apply machineset")
			return err
		}
	}

	log.Info("successfully scaled machineset")

	return nil
}

func ApplyUpgrade(s *Scope) error {
	s.Logger = s.Logger.WithName("[apply-upgrade]")

	kc, err := s.GetAdminClient()
	if err != nil {
		return err
	}

	Cluster := s.Cluster
	var masterMachine *clusterapi.Machine
	masterName := fmt.Sprintf("%v-master", Cluster.Name)
	masterMachine, err = s.StoreProvider.Machine(Cluster.Name).Get(masterName)
	if err != nil {
		return err
	}

	masterMachine.Spec.Versions.ControlPlane = Cluster.Spec.Config.KubernetesVersion
	masterMachine.Spec.Versions.Kubelet = Cluster.Spec.Config.KubernetesVersion

	var bc clusterclient.Client
	bc, err = kube.GetBooststrapClient(s.StoreProvider.Certificates(s.Cluster.Name), s.Cluster, s.GetCaCertPair())
	if err != nil {
		return err
	}

	var data []byte
	if data, err = json.Marshal(masterMachine); err != nil {
		return err
	}
	if err = bc.Apply(string(data)); err != nil {
		return err
	}

	// Wait until masterMachine is updated
	desiredVersion, _ := semver.NewVersion(s.Cluster.ClusterConfig().KubernetesVersion)
	if err = kube.WaitForReadyMasterVersion(kc, desiredVersion); err != nil {
		return err
	}

	var machineSets []*clusterapi.MachineSet
	machineSets, err = s.StoreProvider.MachineSet(Cluster.Name).List(metav1.ListOptions{})
	if err != nil {
		return err
	}

	for _, machineSet := range machineSets {
		machineSet.Spec.Template.Spec.Versions.Kubelet = Cluster.Spec.Config.KubernetesVersion
		if data, err = json.Marshal(machineSet); err != nil {
			return err
		}

		if err = bc.Apply(string(data)); err != nil {
			return err
		}
	}

	Cluster.Status.Phase = api.ClusterReady
	if _, err = s.StoreProvider.Clusters().UpdateStatus(Cluster); err != nil {
		return err
	}

	return err
}

func nodeCount(machineSets []*clusterapi.MachineSet) int32 {
	var count int32
	for _, machineSet := range machineSets {
		count += *machineSet.Spec.Replicas
	}
	return count
}
<|endoftext|>


<commit_before>package conf

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
)

// Config contains the application configuration settings
type Config struct {
	// RootURLPath gets just the path portion of the base application url.
	// E.g., if the app sits at http://www.example.com/path/to/gomp,
	// this setting would be "/path/to/gomp"
	RootURLPath string `json:"root_url_path"`

	// Port gets the port number under which the site is being hosted.
	Port int `json:"port"`

	// UploadDriver is used to select which backend data store is used for file uploads.
	// Available choises are: fs, s3
	UploadDriver string `json:"upload_driver"`

	// UploadPath gets the path (full or relative) under which to store uploads.
	// When using Amazon S3, this should be set to the bucket name.
	UploadPath string `json:"upload_path"`

	// IsDevelopment defines whether to run the application in "development mode".
	// Development mode turns on additional features, such as logging, that may
	// not be desirable in a production environment.
	IsDevelopment bool `json:"is_development"`

	// SecretKey is used to keep data safe.
	SecretKey string `json:"secret_key"`

	// ApplicationTitle is used where the application name (title) is displayed on screen.
	ApplicationTitle string `json:"application_title"`

	// DatabaseDriver gets which database/sql driver to use.
	// Supported drivers: sqlite3, postgres
	DatabaseDriver string `json:"database_driver"`

	// DatabaseUrl gets the url (or path, connection string, etc) to use with the associated
	// database driver when opening the database connection.
	DatabaseURL string `json:"database_url"`

	// AwsRegion defines the region to use for the S3 upload driver.
	AwsRegion string `json:"aws_region"`

	// AwsAccessKeyID defines the Access Key to use for S3 upload driver.
	AwsAccessKeyID string `json:"aws_access_key_id"`

	// AwsRegion defines the Secret Access Key to use for the S3 upload driver.
	AwsSecretAccessKey string `json:"aws_secret_access_key"`
}

// Load reads the configuration file from the specified path
func Load(path string) *Config {
	c := Config{
		RootURLPath:      "",
		Port:             4000,
		UploadDriver:     "fs",
		UploadPath:       filepath.Join("data", "uploads"),
		IsDevelopment:    false,
		SecretKey:        "Secret123",
		ApplicationTitle: "GOMP: Go Meal Planner",
		DatabaseDriver:   "sqlite3",
		DatabaseURL:      "sqlite3://data/gomp.db",
	}

	// If environment variables are set, use them.
	loadEnv("GOMP_ROOT_URL_PATH").fillString(&c.RootURLPath)
	loadEnv("PORT").fillInt(&c.Port)
	loadEnv("GOMP_UPLOAD_DRIVER").fillString(&c.UploadDriver)
	loadEnv("GOMP_UPLOAD_PATH").fillString(&c.UploadPath)
	loadEnv("GOMP_IS_DEVELOPMENT").fillBool(&c.IsDevelopment)
	loadEnv("GOMP_SECRET_KEY").fillString(&c.SecretKey)
	loadEnv("GOMP_APPLICATION_TITLE").fillString(&c.ApplicationTitle)
	loadEnv("DATABASE_DRIVER").fillString(&c.DatabaseDriver)
	loadEnv("DATABASE_URL").fillString(&c.DatabaseURL)

	// If a config file exists, use it and override anything that came from environment variables
	file, err := ioutil.ReadFile(path)
	if err == nil {
		err = json.Unmarshal(file, &c)
		if err != nil {
			log.Fatalf("Failed to marshal configuration settings. Error = %s", err)
		}
	} else if !os.IsNotExist(err) {
		log.Fatalf("Failed to read in app.json. Error = %s", err)
	}

	if c.IsDevelopment {
		log.Printf("[config] RootUrlPath=%s", c.RootURLPath)
		log.Printf("[config] Port=%d", c.Port)
		log.Printf("[config] UploadDriver=%s", c.UploadDriver)
		log.Printf("[config] UploadPath=%s", c.UploadPath)
		log.Printf("[config] IsDevelopment=%t", c.IsDevelopment)
		log.Printf("[config] SecretKey=%s", c.SecretKey)
		log.Printf("[config] ApplicationTitle=%s", c.ApplicationTitle)
		log.Printf("[config] DatabaseDriver=%s", c.DatabaseDriver)
		log.Printf("[config] DatabaseURL=%s", c.DatabaseURL)
	}

	return &c
}

// Validate checks whether the current configuration settings are valid.
func (c *Config) Validate() error {
	_, err := url.Parse(c.RootURLPath)
	if err != nil {
		return errors.New("GOMP_ROOT_URL_PATH is invalid")
	}

	if c.Port <= 0 {
		return errors.New("PORT must be a positive integer")
	}

	if c.UploadDriver != "fs" && c.UploadDriver != "s3" {
		return errors.New("UPLOAD_DRIVER must be one of ('fs', 's3')")
	}

	if c.UploadPath == "" {
		return errors.New("UPLOAD_PATH must be specified")
	}

	if c.SecretKey == "" {
		return errors.New("GOMP_SECRET_KEY must be specified")
	}

	if c.ApplicationTitle == "" {
		return errors.New("GOMP_APPLICATION_TITLE must be specified")
	}

	if c.DatabaseDriver != "sqlite3" && c.UploadDriver != "postgres" {
		return errors.New("DATABASE_DRIVER must be one of ('sqlite3', 'postgres')")
	}

	_, err = url.Parse(c.DatabaseURL)
	if err != nil {
		return errors.New("DATABASE_URL is invalid")
	}

	return nil
}

type environmentVar struct {
	Name  string
	Value string
	IsSet bool
}

func loadEnv(name string) *environmentVar {
	if envStr := os.Getenv(name); envStr != "" {
		return &environmentVar{Name: name, Value: envStr, IsSet: true}
	}

	return &environmentVar{Name: name, IsSet: false}
}

func (e *environmentVar) fillString(value *string) {
	if e.IsSet {
		*value = e.Value
	}
}

func (e *environmentVar) fillInt(value *int) {
	if e.IsSet {
		var err error
		*value, err = strconv.Atoi(e.Value)
		if err != nil {
			log.Fatalf("[config] Failed to convert %s environment variable to an integer. Value = %s, Error = %s",
				e.Name, e.Value, err)
		}
	}
}

func (e *environmentVar) fillBool(value *bool) {
	if e.IsSet {
		*value = e.Value != "0"
	}
}
<commit_msg>Fixed a bug in config validation where the wrong value was checked for db drivers<commit_after>package conf

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
)

// Config contains the application configuration settings
type Config struct {
	// RootURLPath gets just the path portion of the base application url.
	// E.g., if the app sits at http://www.example.com/path/to/gomp,
	// this setting would be "/path/to/gomp"
	RootURLPath string `json:"root_url_path"`

	// Port gets the port number under which the site is being hosted.
	Port int `json:"port"`

	// UploadDriver is used to select which backend data store is used for file uploads.
	// Available choises are: fs, s3
	UploadDriver string `json:"upload_driver"`

	// UploadPath gets the path (full or relative) under which to store uploads.
	// When using Amazon S3, this should be set to the bucket name.
	UploadPath string `json:"upload_path"`

	// IsDevelopment defines whether to run the application in "development mode".
	// Development mode turns on additional features, such as logging, that may
	// not be desirable in a production environment.
	IsDevelopment bool `json:"is_development"`

	// SecretKey is used to keep data safe.
	SecretKey string `json:"secret_key"`

	// ApplicationTitle is used where the application name (title) is displayed on screen.
	ApplicationTitle string `json:"application_title"`

	// DatabaseDriver gets which database/sql driver to use.
	// Supported drivers: sqlite3, postgres
	DatabaseDriver string `json:"database_driver"`

	// DatabaseUrl gets the url (or path, connection string, etc) to use with the associated
	// database driver when opening the database connection.
	DatabaseURL string `json:"database_url"`

	// AwsRegion defines the region to use for the S3 upload driver.
	AwsRegion string `json:"aws_region"`

	// AwsAccessKeyID defines the Access Key to use for S3 upload driver.
	AwsAccessKeyID string `json:"aws_access_key_id"`

	// AwsRegion defines the Secret Access Key to use for the S3 upload driver.
	AwsSecretAccessKey string `json:"aws_secret_access_key"`
}

// Load reads the configuration file from the specified path
func Load(path string) *Config {
	c := Config{
		RootURLPath:      "",
		Port:             4000,
		UploadDriver:     "fs",
		UploadPath:       filepath.Join("data", "uploads"),
		IsDevelopment:    false,
		SecretKey:        "Secret123",
		ApplicationTitle: "GOMP: Go Meal Planner",
		DatabaseDriver:   "sqlite3",
		DatabaseURL:      "sqlite3://data/gomp.db",
	}

	// If environment variables are set, use them.
	loadEnv("GOMP_ROOT_URL_PATH").fillString(&c.RootURLPath)
	loadEnv("PORT").fillInt(&c.Port)
	loadEnv("GOMP_UPLOAD_DRIVER").fillString(&c.UploadDriver)
	loadEnv("GOMP_UPLOAD_PATH").fillString(&c.UploadPath)
	loadEnv("GOMP_IS_DEVELOPMENT").fillBool(&c.IsDevelopment)
	loadEnv("GOMP_SECRET_KEY").fillString(&c.SecretKey)
	loadEnv("GOMP_APPLICATION_TITLE").fillString(&c.ApplicationTitle)
	loadEnv("DATABASE_DRIVER").fillString(&c.DatabaseDriver)
	loadEnv("DATABASE_URL").fillString(&c.DatabaseURL)

	// If a config file exists, use it and override anything that came from environment variables
	file, err := ioutil.ReadFile(path)
	if err == nil {
		err = json.Unmarshal(file, &c)
		if err != nil {
			log.Fatalf("Failed to marshal configuration settings. Error = %s", err)
		}
	} else if !os.IsNotExist(err) {
		log.Fatalf("Failed to read in app.json. Error = %s", err)
	}

	if c.IsDevelopment {
		log.Printf("[config] RootUrlPath=%s", c.RootURLPath)
		log.Printf("[config] Port=%d", c.Port)
		log.Printf("[config] UploadDriver=%s", c.UploadDriver)
		log.Printf("[config] UploadPath=%s", c.UploadPath)
		log.Printf("[config] IsDevelopment=%t", c.IsDevelopment)
		log.Printf("[config] SecretKey=%s", c.SecretKey)
		log.Printf("[config] ApplicationTitle=%s", c.ApplicationTitle)
		log.Printf("[config] DatabaseDriver=%s", c.DatabaseDriver)
		log.Printf("[config] DatabaseURL=%s", c.DatabaseURL)
	}

	return &c
}

// Validate checks whether the current configuration settings are valid.
func (c *Config) Validate() error {
	_, err := url.Parse(c.RootURLPath)
	if err != nil {
		return errors.New("GOMP_ROOT_URL_PATH is invalid")
	}

	if c.Port <= 0 {
		return errors.New("PORT must be a positive integer")
	}

	if c.UploadDriver != "fs" && c.UploadDriver != "s3" {
		return errors.New("UPLOAD_DRIVER must be one of ('fs', 's3')")
	}

	if c.UploadPath == "" {
		return errors.New("UPLOAD_PATH must be specified")
	}

	if c.SecretKey == "" {
		return errors.New("GOMP_SECRET_KEY must be specified")
	}

	if c.ApplicationTitle == "" {
		return errors.New("GOMP_APPLICATION_TITLE must be specified")
	}

	if c.DatabaseDriver != "sqlite3" && c.DatabaseDriver != "postgres" {
		return errors.New("DATABASE_DRIVER must be one of ('sqlite3', 'postgres')")
	}

	_, err = url.Parse(c.DatabaseURL)
	if err != nil {
		return errors.New("DATABASE_URL is invalid")
	}

	return nil
}

type environmentVar struct {
	Name  string
	Value string
	IsSet bool
}

func loadEnv(name string) *environmentVar {
	if envStr := os.Getenv(name); envStr != "" {
		return &environmentVar{Name: name, Value: envStr, IsSet: true}
	}

	return &environmentVar{Name: name, IsSet: false}
}

func (e *environmentVar) fillString(value *string) {
	if e.IsSet {
		*value = e.Value
	}
}

func (e *environmentVar) fillInt(value *int) {
	if e.IsSet {
		var err error
		*value, err = strconv.Atoi(e.Value)
		if err != nil {
			log.Fatalf("[config] Failed to convert %s environment variable to an integer. Value = %s, Error = %s",
				e.Name, e.Value, err)
		}
	}
}

func (e *environmentVar) fillBool(value *bool) {
	if e.IsSet {
		*value = e.Value != "0"
	}
}
<|endoftext|>


<commit_before>package arn

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path"

	"github.com/aerogo/nano"
	"github.com/animenotifier/arn/video"
)

// AMV is an anime music video.
type AMV struct {
	File           string     `json:"file" editable:"true" type:"upload" filetype:"video" endpoint:"/api/upload/amv/:id/file"`
	Title          AMVTitle   `json:"title" editable:"true"`
	MainAnimeID    string     `json:"mainAnimeId" editable:"true"`
	ExtraAnimeIDs  []string   `json:"extraAnimeIds" editable:"true"`
	VideoEditorIDs []string   `json:"videoEditorIds" editable:"true"`
	Links          []Link     `json:"links" editable:"true"`
	Tags           []string   `json:"tags" editable:"true"`
	Info           video.Info `json:"info"`

	HasID
	HasPosts
	HasCreator
	HasEditor
	HasLikes
	HasDraft
}

// Link returns the permalink for the AMV.
func (amv *AMV) Link() string {
	return "/amv/" + amv.ID
}

// TitleByUser returns the preferred title for the given user.
func (amv *AMV) TitleByUser(user *User) string {
	return amv.Title.ByUser(user)
}

// SetVideoBytes sets the bytes for the video file.
func (amv *AMV) SetVideoBytes(data []byte) error {
	fileName := amv.ID + ".webm"
	filePath := path.Join(Root, "videos", "amvs", fileName)
	err := ioutil.WriteFile(filePath, data, 0644)

	if err != nil {
		return err
	}

	amv.File = fileName
	amv.RefreshInfo()
	return nil
}

// RefreshInfo refreshes the information about the video file.
func (amv *AMV) RefreshInfo() error {
	if amv.File == "" {
		return fmt.Errorf("Video file has not been uploaded yet for AMV %s", amv.ID)
	}

	info, err := video.GetInfo(path.Join(Root, "videos", "amvs", amv.File))

	if err != nil {
		return err
	}

	amv.Info = *info
	return nil
}

// MainAnime returns main anime for the AMV, if available.
func (amv *AMV) MainAnime() *Anime {
	mainAnime, _ := GetAnime(amv.MainAnimeID)
	return mainAnime
}

// ExtraAnime returns main anime for the AMV, if available.
func (amv *AMV) ExtraAnime() []*Anime {
	objects := DB.GetMany("Anime", amv.ExtraAnimeIDs)
	animes := []*Anime{}

	for _, obj := range objects {
		if obj == nil {
			continue
		}

		animes = append(animes, obj.(*Anime))
	}

	return animes
}

// VideoEditors returns a slice of all the users involved in creating the AMV.
func (amv *AMV) VideoEditors() []*User {
	objects := DB.GetMany("User", amv.VideoEditorIDs)
	editors := []*User{}

	for _, obj := range objects {
		if obj == nil {
			continue
		}

		editors = append(editors, obj.(*User))
	}

	return editors
}

// Publish turns the draft into a published object.
func (amv *AMV) Publish() error {
	// No title
	if amv.Title.String() == "" {
		return errors.New("AMV doesn't have a title")
	}

	// No anime found
	if amv.MainAnimeID == "" && len(amv.ExtraAnimeIDs) == 0 {
		return errors.New("Need to specify at least one anime")
	}

	// No file uploaded
	if amv.File == "" {
		return errors.New("You need to upload a WebM file for this AMV")
	}

	if _, err := os.Stat(path.Join(Root, "videos", "amvs", amv.File)); os.IsNotExist(err) {
		return errors.New("You need to upload a WebM file for this AMV")
	}

	return publish(amv)
}

// Unpublish turns the object back into a draft.
func (amv *AMV) Unpublish() error {
	return unpublish(amv)
}

// OnLike is called when the AMV receives a like.
func (amv *AMV) OnLike(likedBy *User) {
	if likedBy.ID == amv.CreatedBy {
		return
	}

	go func() {
		amv.Creator().SendNotification(&PushNotification{
			Title:   likedBy.Nick + " liked your AMV " + amv.Title.ByUser(amv.Creator()),
			Message: likedBy.Nick + " liked your AMV " + amv.Title.ByUser(amv.Creator()) + ".",
			Icon:    "https:" + likedBy.AvatarLink("large"),
			Link:    "https://notify.moe" + likedBy.Link(),
			Type:    NotificationTypeLike,
		})
	}()
}

// String implements the default string serialization.
func (amv *AMV) String() string {
	return amv.Title.ByUser(nil)
}

// GetAMV returns the AMV with the given ID.
func GetAMV(id string) (*AMV, error) {
	obj, err := DB.Get("AMV", id)

	if err != nil {
		return nil, err
	}

	return obj.(*AMV), nil
}

// StreamAMVs returns a stream of all AMVs.
func StreamAMVs() chan *AMV {
	channel := make(chan *AMV, nano.ChannelBufferSize)

	go func() {
		for obj := range DB.All("AMV") {
			channel <- obj.(*AMV)
		}

		close(channel)
	}()

	return channel
}

// AllAMVs returns a slice of all AMVs.
func AllAMVs() []*AMV {
	var all []*AMV

	stream := StreamAMVs()

	for obj := range stream {
		all = append(all, obj)
	}

	return all
}

// FilterAMVs filters all AMVs by a custom function.
func FilterAMVs(filter func(*AMV) bool) []*AMV {
	var filtered []*AMV

	channel := DB.All("AMV")

	for obj := range channel {
		realObject := obj.(*AMV)

		if filter(realObject) {
			filtered = append(filtered, realObject)
		}
	}

	return filtered
}
<commit_msg>Optimize webm files on upload<commit_after>package arn

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"

	"github.com/aerogo/nano"
	"github.com/animenotifier/arn/video"
)

// AMV is an anime music video.
type AMV struct {
	File           string     `json:"file" editable:"true" type:"upload" filetype:"video" endpoint:"/api/upload/amv/:id/file"`
	Title          AMVTitle   `json:"title" editable:"true"`
	MainAnimeID    string     `json:"mainAnimeId" editable:"true"`
	ExtraAnimeIDs  []string   `json:"extraAnimeIds" editable:"true"`
	VideoEditorIDs []string   `json:"videoEditorIds" editable:"true"`
	Links          []Link     `json:"links" editable:"true"`
	Tags           []string   `json:"tags" editable:"true"`
	Info           video.Info `json:"info"`

	HasID
	HasPosts
	HasCreator
	HasEditor
	HasLikes
	HasDraft
}

// Link returns the permalink for the AMV.
func (amv *AMV) Link() string {
	return "/amv/" + amv.ID
}

// TitleByUser returns the preferred title for the given user.
func (amv *AMV) TitleByUser(user *User) string {
	return amv.Title.ByUser(user)
}

// SetVideoBytes sets the bytes for the video file.
func (amv *AMV) SetVideoBytes(data []byte) error {
	fileName := amv.ID + ".webm"
	filePath := path.Join(Root, "videos", "amvs", fileName)
	err := ioutil.WriteFile(filePath, data, 0644)

	if err != nil {
		return err
	}

	// Run mkclean
	optimizedFile := filePath + ".optimized"

	cmd := exec.Command(
		"mkclean",
		"--doctype", "4",
		"--keep-cues",
		"--optimize",
		filePath,
		optimizedFile,
	)

	err = cmd.Start()

	if err != nil {
		return err
	}

	err = cmd.Wait()

	if err != nil {
		return err
	}

	// Now delete the original file and replace it with the optimized file
	err = os.Remove(filePath)

	if err != nil {
		return err
	}

	err = os.Rename(optimizedFile, filePath)

	if err != nil {
		return err
	}

	// Refresh video file info
	amv.File = fileName
	amv.RefreshInfo()
	return nil
}

// RefreshInfo refreshes the information about the video file.
func (amv *AMV) RefreshInfo() error {
	if amv.File == "" {
		return fmt.Errorf("Video file has not been uploaded yet for AMV %s", amv.ID)
	}

	info, err := video.GetInfo(path.Join(Root, "videos", "amvs", amv.File))

	if err != nil {
		return err
	}

	amv.Info = *info
	return nil
}

// MainAnime returns main anime for the AMV, if available.
func (amv *AMV) MainAnime() *Anime {
	mainAnime, _ := GetAnime(amv.MainAnimeID)
	return mainAnime
}

// ExtraAnime returns main anime for the AMV, if available.
func (amv *AMV) ExtraAnime() []*Anime {
	objects := DB.GetMany("Anime", amv.ExtraAnimeIDs)
	animes := []*Anime{}

	for _, obj := range objects {
		if obj == nil {
			continue
		}

		animes = append(animes, obj.(*Anime))
	}

	return animes
}

// VideoEditors returns a slice of all the users involved in creating the AMV.
func (amv *AMV) VideoEditors() []*User {
	objects := DB.GetMany("User", amv.VideoEditorIDs)
	editors := []*User{}

	for _, obj := range objects {
		if obj == nil {
			continue
		}

		editors = append(editors, obj.(*User))
	}

	return editors
}

// Publish turns the draft into a published object.
func (amv *AMV) Publish() error {
	// No title
	if amv.Title.String() == "" {
		return errors.New("AMV doesn't have a title")
	}

	// No anime found
	if amv.MainAnimeID == "" && len(amv.ExtraAnimeIDs) == 0 {
		return errors.New("Need to specify at least one anime")
	}

	// No file uploaded
	if amv.File == "" {
		return errors.New("You need to upload a WebM file for this AMV")
	}

	if _, err := os.Stat(path.Join(Root, "videos", "amvs", amv.File)); os.IsNotExist(err) {
		return errors.New("You need to upload a WebM file for this AMV")
	}

	return publish(amv)
}

// Unpublish turns the object back into a draft.
func (amv *AMV) Unpublish() error {
	return unpublish(amv)
}

// OnLike is called when the AMV receives a like.
func (amv *AMV) OnLike(likedBy *User) {
	if likedBy.ID == amv.CreatedBy {
		return
	}

	go func() {
		amv.Creator().SendNotification(&PushNotification{
			Title:   likedBy.Nick + " liked your AMV " + amv.Title.ByUser(amv.Creator()),
			Message: likedBy.Nick + " liked your AMV " + amv.Title.ByUser(amv.Creator()) + ".",
			Icon:    "https:" + likedBy.AvatarLink("large"),
			Link:    "https://notify.moe" + likedBy.Link(),
			Type:    NotificationTypeLike,
		})
	}()
}

// String implements the default string serialization.
func (amv *AMV) String() string {
	return amv.Title.ByUser(nil)
}

// GetAMV returns the AMV with the given ID.
func GetAMV(id string) (*AMV, error) {
	obj, err := DB.Get("AMV", id)

	if err != nil {
		return nil, err
	}

	return obj.(*AMV), nil
}

// StreamAMVs returns a stream of all AMVs.
func StreamAMVs() chan *AMV {
	channel := make(chan *AMV, nano.ChannelBufferSize)

	go func() {
		for obj := range DB.All("AMV") {
			channel <- obj.(*AMV)
		}

		close(channel)
	}()

	return channel
}

// AllAMVs returns a slice of all AMVs.
func AllAMVs() []*AMV {
	var all []*AMV

	stream := StreamAMVs()

	for obj := range stream {
		all = append(all, obj)
	}

	return all
}

// FilterAMVs filters all AMVs by a custom function.
func FilterAMVs(filter func(*AMV) bool) []*AMV {
	var filtered []*AMV

	channel := DB.All("AMV")

	for obj := range channel {
		realObject := obj.(*AMV)

		if filter(realObject) {
			filtered = append(filtered, realObject)
		}
	}

	return filtered
}
<|endoftext|>


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

// Package cmd contains all the global variables and constants. ONLY TO BE ACCESSED VIA GET/SET FUNCTIONS.
package cmd

import (
	"crypto/x509"

	"github.com/minio/cli"
	"github.com/minio/mc/pkg/console"
)

// mc configuration related constants.
const (
	minGoVersion = ">= 1.7.5" // mc requires at least Go v1.7.5
)

const (
	globalMCConfigVersion = "8"

	globalMCConfigDir        = ".mc/"
	globalMCConfigWindowsDir = "mc\\"
	globalMCConfigFile       = "config.json"
	globalMCCertsDir         = "certs"
	globalMCCAsDir           = "CAs"

	// session config and shared urls related constants
	globalSessionDir           = "session"
	globalSharedURLsDataDir    = "share"
	globalSessionConfigVersion = "8"

	// Profile directory for dumping profiler outputs.
	globalProfileDir = "profile"

	// Global error exit status.
	globalErrorExitStatus = 1
)

var (
	globalQuiet    = false // Quiet flag set via command line
	globalJSON     = false // Json flag set via command line
	globalDebug    = false // Debug flag set via command line
	globalNoColor  = false // No Color flag set via command line
	globalInsecure = false // Insecure flag set via command line
	// WHEN YOU ADD NEXT GLOBAL FLAG, MAKE SURE TO ALSO UPDATE SESSION CODE AND CODE BELOW.
)

var (
	// Terminal width
	globalTermWidth int

	// CA root certificates, a nil value means system certs pool will be used
	globalRootCAs *x509.CertPool
)

// Set global states. NOTE: It is deliberately kept monolithic to ensure we dont miss out any flags.
func setGlobals(quiet, debug, json, noColor, insecure bool) {
	globalQuiet = globalQuiet || quiet
	globalDebug = globalDebug || debug
	globalJSON = globalJSON || json
	globalNoColor = globalNoColor || noColor
	globalInsecure = globalInsecure || insecure

	// Enable debug messages if requested.
	if globalDebug {
		console.DebugPrint = true
	}

	// Disable colorified messages if requested.
	if globalNoColor {
		console.SetColorOff()
	}
}

// Set global states. NOTE: It is deliberately kept monolithic to ensure we dont miss out any flags.
func setGlobalsFromContext(ctx *cli.Context) error {
	quiet := ctx.IsSet("quiet")
	debug := ctx.IsSet("debug")
	json := ctx.IsSet("json")
	noColor := ctx.IsSet("no-color")
	insecure := ctx.IsSet("insecure")
	setGlobals(quiet, debug, json, noColor, insecure)
	return nil
}
<commit_msg>Skip color theme for quiet mode (#2313)<commit_after>/*
 * Minio Client (C) 2015 Minio, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Package cmd contains all the global variables and constants. ONLY TO BE ACCESSED VIA GET/SET FUNCTIONS.
package cmd

import (
	"crypto/x509"

	"github.com/minio/cli"
	"github.com/minio/mc/pkg/console"
)

// mc configuration related constants.
const (
	minGoVersion = ">= 1.7.5" // mc requires at least Go v1.7.5
)

const (
	globalMCConfigVersion = "8"

	globalMCConfigDir        = ".mc/"
	globalMCConfigWindowsDir = "mc\\"
	globalMCConfigFile       = "config.json"
	globalMCCertsDir         = "certs"
	globalMCCAsDir           = "CAs"

	// session config and shared urls related constants
	globalSessionDir           = "session"
	globalSharedURLsDataDir    = "share"
	globalSessionConfigVersion = "8"

	// Profile directory for dumping profiler outputs.
	globalProfileDir = "profile"

	// Global error exit status.
	globalErrorExitStatus = 1
)

var (
	globalQuiet    = false // Quiet flag set via command line
	globalJSON     = false // Json flag set via command line
	globalDebug    = false // Debug flag set via command line
	globalNoColor  = false // No Color flag set via command line
	globalInsecure = false // Insecure flag set via command line
	// WHEN YOU ADD NEXT GLOBAL FLAG, MAKE SURE TO ALSO UPDATE SESSION CODE AND CODE BELOW.
)

var (
	// Terminal width
	globalTermWidth int

	// CA root certificates, a nil value means system certs pool will be used
	globalRootCAs *x509.CertPool
)

// Set global states. NOTE: It is deliberately kept monolithic to ensure we dont miss out any flags.
func setGlobals(quiet, debug, json, noColor, insecure bool) {
	globalQuiet = globalQuiet || quiet
	globalDebug = globalDebug || debug
	globalJSON = globalJSON || json
	globalNoColor = globalNoColor || noColor
	globalInsecure = globalInsecure || insecure

	// Enable debug messages if requested.
	if globalDebug {
		console.DebugPrint = true
	}

	// Disable colorified messages if requested.
	if globalNoColor || globalQuiet {
		console.SetColorOff()
	}
}

// Set global states. NOTE: It is deliberately kept monolithic to ensure we dont miss out any flags.
func setGlobalsFromContext(ctx *cli.Context) error {
	quiet := ctx.IsSet("quiet")
	debug := ctx.IsSet("debug")
	json := ctx.IsSet("json")
	noColor := ctx.IsSet("no-color")
	insecure := ctx.IsSet("insecure")
	setGlobals(quiet, debug, json, noColor, insecure)
	return nil
}
<|endoftext|>