<commit_before>package machine

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/Sirupsen/logrus"

	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/docker"
)

type machineProvider struct {
	machine     docker_helpers.Machine
	details     machinesDetails
	lock        sync.RWMutex
	acquireLock sync.Mutex
	// provider stores a real executor that is used to start run the builds
	provider common.ExecutorProvider
}

func (m *machineProvider) machineDetails(name string, acquire bool) *machineDetails {
	m.lock.Lock()
	defer m.lock.Unlock()

	details, ok := m.details[name]
	if !ok {
		details = &machineDetails{
			Name:      name,
			Created:   time.Now(),
			Used:      time.Now(),
			UsedCount: 1, // any machine that we find we mark as already used
			State:     machineStateIdle,
		}
		m.details[name] = details
	}

	if acquire {
		if details.isUsed() {
			return nil
		}
		details.State = machineStateAcquired
	}

	return details
}

func (m *machineProvider) create(config *common.RunnerConfig, state machineState) (details *machineDetails, errCh chan error) {
	name := newMachineName(machineFilter(config))
	details = m.machineDetails(name, true)
	details.State = machineStateCreating
	details.UsedCount = 0
	errCh = make(chan error, 1)

	// Create machine asynchronously
	go func() {
		started := time.Now()
		err := m.machine.Create(config.Machine.MachineDriver, details.Name, config.Machine.MachineOptions...)
		for i := 0; i < 3 && err != nil; i++ {
			logrus.WithField("name", details.Name).WithError(err).
				Warningln("Machine creation failed, trying to provision")
			time.Sleep(provisionRetryInterval)
			err = m.machine.Provision(details.Name)
		}

		if err != nil {
			logrus.WithField("name", details.Name).
				WithField("time", time.Since(started)).
				WithError(err).
				Errorln("Machine creation failed")
			m.remove(details.Name, "Failed to create")
		} else {
			details.State = state
			details.Used = time.Now()
			logrus.WithField("time", time.Since(started)).
				WithField("name", details.Name).
				Infoln("Machine created")
		}
		errCh <- err
	}()
	return
}

func (m *machineProvider) findFreeMachine(machines ...string) (details *machineDetails) {
	// Enumerate all machines
	for _, name := range machines {
		details := m.machineDetails(name, true)
		if details == nil {
			continue
		}

		// Check if node is running
		canConnect := m.machine.CanConnect(name)
		if !canConnect {
			m.remove(name, "machine is unavailable")
			continue
		}
		return details
	}

	return nil
}

func (m *machineProvider) useMachine(config *common.RunnerConfig) (details *machineDetails, err error) {
	machines, err := m.loadMachines(config)
	if err != nil {
		return
	}
	details = m.findFreeMachine(machines...)
	if details == nil {
		var errCh chan error
		details, errCh = m.create(config, machineStateAcquired)
		err = <-errCh
	}
	return
}

func (m *machineProvider) retryUseMachine(config *common.RunnerConfig) (details *machineDetails, err error) {
	// Try to find a machine
	for i := 0; i < 3; i++ {
		details, err = m.useMachine(config)
		if err == nil {
			break
		}
		time.Sleep(provisionRetryInterval)
	}
	return
}

func (m *machineProvider) finalizeRemoval(details *machineDetails) {
	for {
		if !m.machine.Exist(details.Name) {
			logrus.WithField("name", details.Name).
				WithField("created", time.Since(details.Created)).
				WithField("used", time.Since(details.Used)).
				WithField("reason", details.Reason).
				Warningln("Skipping machine removal, because it doesn't exist")
			break
		}

		err := m.machine.Remove(details.Name)
		if err == nil {
			break
		}
		time.Sleep(30 * time.Second)
		logrus.WithField("name", details.Name).
			WithField("created", time.Since(details.Created)).
			WithField("used", time.Since(details.Used)).
			WithField("reason", details.Reason).
			Warningln("Retrying removal")
	}

	m.lock.Lock()
	defer m.lock.Unlock()
	delete(m.details, details.Name)

	logrus.WithField("name", details.Name).
		WithField("created", time.Since(details.Created)).
		WithField("used", time.Since(details.Used)).
		WithField("reason", details.Reason).
		Infoln("Machine removed")
}

func (m *machineProvider) remove(machineName string, reason ...interface{}) {
	m.lock.Lock()
	defer m.lock.Unlock()

	details, _ := m.details[machineName]
	if details == nil {
		return
	}

	details.Reason = fmt.Sprint(reason...)
	details.State = machineStateRemoving
	logrus.WithField("name", machineName).
		WithField("created", time.Since(details.Created)).
		WithField("used", time.Since(details.Used)).
		WithField("reason", details.Reason).
		Warningln("Removing machine")
	details.Used = time.Now()
	details.writeDebugInformation()

	go m.finalizeRemoval(details)
}

func (m *machineProvider) updateMachine(config *common.RunnerConfig, data *machinesData, details *machineDetails) error {
	if details.State != machineStateIdle {
		return nil
	}

	if config.Machine.MaxBuilds > 0 && details.UsedCount >= config.Machine.MaxBuilds {
		// Limit number of builds
		return errors.New("Too many builds")
	}

	if data.Total() >= config.Limit && config.Limit > 0 {
		// Limit maximum number of machines
		return errors.New("Too many machines")
	}

	if time.Since(details.Used) > time.Second*time.Duration(config.Machine.IdleTime) {
		if data.Idle >= config.Machine.IdleCount {
			// Remove machine that are way over the idle time
			return errors.New("Too many idle machines")
		}
	}
	return nil
}

func (m *machineProvider) updateMachines(machines []string, config *common.RunnerConfig) (data machinesData) {
	data.Runner = config.ShortDescription()

	for _, name := range machines {
		details := m.machineDetails(name, false)
		err := m.updateMachine(config, &data, details)
		if err != nil {
			m.remove(details.Name, err)
		}

		data.Add(details.State)
	}
	return
}

func (m *machineProvider) createMachines(config *common.RunnerConfig, data *machinesData) {
	// Create a new machines and mark them as Idle
	for {
		if data.Available() >= config.Machine.IdleCount {
			// Limit maximum number of idle machines
			break
		}
		if data.Total() >= config.Limit && config.Limit > 0 {
			// Limit maximum number of machines
			break
		}
		m.create(config, machineStateIdle)
		data.Creating++
	}
}

func (m *machineProvider) loadMachines(config *common.RunnerConfig) ([]string, error) {
	// Find a new machine
	return m.machine.List(machineFilter(config))
}

func (m *machineProvider) Acquire(config *common.RunnerConfig) (data common.ExecutorData, err error) {
	if config.Machine == nil || config.Machine.MachineName == "" {
		err = fmt.Errorf("Missing Machine options")
		return
	}

	machines, err := m.loadMachines(config)
	if err != nil {
		return
	}

	// Lock updating machines, because two Acquires can be run at the same time
	m.acquireLock.Lock()

	// Update a list of currently configured machines
	machinesData := m.updateMachines(machines, config)

	// Pre-create machines
	m.createMachines(config, &machinesData)

	m.acquireLock.Unlock()

	logrus.WithFields(machinesData.Fields()).
		WithField("runner", config.ShortDescription()).
		WithField("minIdleCount", config.Machine.IdleCount).
		WithField("maxMachines", config.Limit).
		WithField("time", time.Now()).
		Debugln("Docker Machine Details")
	machinesData.writeDebugInformation()

	// Try to find a free machine
	details := m.findFreeMachine(machines...)
	if details != nil {
		data = details
		return
	}

	// If we have a free machines we can process a build
	if config.Machine.IdleCount != 0 && machinesData.Idle == 0 {
		err = errors.New("No free machines that can process builds")
	}
	return
}

func (m *machineProvider) Use(config *common.RunnerConfig, data common.ExecutorData) (newConfig common.RunnerConfig, newData common.ExecutorData, err error) {
	// Find a new machine
	details, _ := data.(*machineDetails)
	if details == nil {
		details, err = m.retryUseMachine(config)
		if err != nil {
			return
		}

		// Return details only if this is a new instance
		newData = details
	}

	// Get machine credentials
	dc, err := m.machine.Credentials(details.Name)
	if err != nil {
		if newData != nil {
			m.Release(config, newData)
		}
		return
	}

	// Create shallow copy of config and store in it docker credentials
	newConfig = *config
	newConfig.Docker = &common.DockerConfig{}
	if config.Docker != nil {
		*newConfig.Docker = *config.Docker
	}
	newConfig.Docker.DockerCredentials = dc

	// Mark machine as used
	details.State = machineStateUsed
	return
}

func (m *machineProvider) Release(config *common.RunnerConfig, data common.ExecutorData) error {
	// Release machine
	details, ok := data.(*machineDetails)
	if ok {
		// Mark last used time when is Used
		if details.State == machineStateUsed {
			details.Used = time.Now()
			details.UsedCount++
		}
		details.State = machineStateIdle
	}
	return nil
}

func (m *machineProvider) CanCreate() bool {
	return m.provider.CanCreate()
}

func (m *machineProvider) GetFeatures(features *common.FeaturesInfo) {
	m.provider.GetFeatures(features)
}

func (m *machineProvider) Create() common.Executor {
	return &machineExecutor{
		provider: m,
	}
}

func newMachineProvider(executor string) *machineProvider {
	provider := common.GetExecutor(executor)
	if provider == nil {
		logrus.Panicln("Missing", executor)
	}

	return &machineProvider{
		details:  make(machinesDetails),
		machine:  docker_helpers.NewMachineCommand(),
		provider: provider,
	}
}
<commit_msg>Find free machines by going from the back to use a new provisioned ones<commit_after>package machine

import (
	"errors"
	"fmt"
	"sync"
	"time"

	"github.com/Sirupsen/logrus"

	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/common"
	"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers/docker"
)

type machineProvider struct {
	machine     docker_helpers.Machine
	details     machinesDetails
	lock        sync.RWMutex
	acquireLock sync.Mutex
	// provider stores a real executor that is used to start run the builds
	provider common.ExecutorProvider
}

func (m *machineProvider) machineDetails(name string, acquire bool) *machineDetails {
	m.lock.Lock()
	defer m.lock.Unlock()

	details, ok := m.details[name]
	if !ok {
		details = &machineDetails{
			Name:      name,
			Created:   time.Now(),
			Used:      time.Now(),
			UsedCount: 1, // any machine that we find we mark as already used
			State:     machineStateIdle,
		}
		m.details[name] = details
	}

	if acquire {
		if details.isUsed() {
			return nil
		}
		details.State = machineStateAcquired
	}

	return details
}

func (m *machineProvider) create(config *common.RunnerConfig, state machineState) (details *machineDetails, errCh chan error) {
	name := newMachineName(machineFilter(config))
	details = m.machineDetails(name, true)
	details.State = machineStateCreating
	details.UsedCount = 0
	errCh = make(chan error, 1)

	// Create machine asynchronously
	go func() {
		started := time.Now()
		err := m.machine.Create(config.Machine.MachineDriver, details.Name, config.Machine.MachineOptions...)
		for i := 0; i < 3 && err != nil; i++ {
			logrus.WithField("name", details.Name).WithError(err).
				Warningln("Machine creation failed, trying to provision")
			time.Sleep(provisionRetryInterval)
			err = m.machine.Provision(details.Name)
		}

		if err != nil {
			logrus.WithField("name", details.Name).
				WithField("time", time.Since(started)).
				WithError(err).
				Errorln("Machine creation failed")
			m.remove(details.Name, "Failed to create")
		} else {
			details.State = state
			details.Used = time.Now()
			logrus.WithField("time", time.Since(started)).
				WithField("name", details.Name).
				Infoln("Machine created")
		}
		errCh <- err
	}()
	return
}

func (m *machineProvider) findFreeMachine(machines ...string) (details *machineDetails) {
	// Enumerate all machines in reverse order, to always take the newest machines first
	for idx := range machines {
		name := machines[len(machines)-idx-1]
		details := m.machineDetails(name, true)
		if details == nil {
			continue
		}

		// Check if node is running
		canConnect := m.machine.CanConnect(name)
		if !canConnect {
			m.remove(name, "machine is unavailable")
			continue
		}
		return details
	}

	return nil
}

func (m *machineProvider) useMachine(config *common.RunnerConfig) (details *machineDetails, err error) {
	machines, err := m.loadMachines(config)
	if err != nil {
		return
	}
	details = m.findFreeMachine(machines...)
	if details == nil {
		var errCh chan error
		details, errCh = m.create(config, machineStateAcquired)
		err = <-errCh
	}
	return
}

func (m *machineProvider) retryUseMachine(config *common.RunnerConfig) (details *machineDetails, err error) {
	// Try to find a machine
	for i := 0; i < 3; i++ {
		details, err = m.useMachine(config)
		if err == nil {
			break
		}
		time.Sleep(provisionRetryInterval)
	}
	return
}

func (m *machineProvider) finalizeRemoval(details *machineDetails) {
	for {
		if !m.machine.Exist(details.Name) {
			logrus.WithField("name", details.Name).
				WithField("created", time.Since(details.Created)).
				WithField("used", time.Since(details.Used)).
				WithField("reason", details.Reason).
				Warningln("Skipping machine removal, because it doesn't exist")
			break
		}

		err := m.machine.Remove(details.Name)
		if err == nil {
			break
		}
		time.Sleep(30 * time.Second)
		logrus.WithField("name", details.Name).
			WithField("created", time.Since(details.Created)).
			WithField("used", time.Since(details.Used)).
			WithField("reason", details.Reason).
			Warningln("Retrying removal")
	}

	m.lock.Lock()
	defer m.lock.Unlock()
	delete(m.details, details.Name)

	logrus.WithField("name", details.Name).
		WithField("created", time.Since(details.Created)).
		WithField("used", time.Since(details.Used)).
		WithField("reason", details.Reason).
		Infoln("Machine removed")
}

func (m *machineProvider) remove(machineName string, reason ...interface{}) {
	m.lock.Lock()
	defer m.lock.Unlock()

	details, _ := m.details[machineName]
	if details == nil {
		return
	}

	details.Reason = fmt.Sprint(reason...)
	details.State = machineStateRemoving
	logrus.WithField("name", machineName).
		WithField("created", time.Since(details.Created)).
		WithField("used", time.Since(details.Used)).
		WithField("reason", details.Reason).
		Warningln("Removing machine")
	details.Used = time.Now()
	details.writeDebugInformation()

	go m.finalizeRemoval(details)
}

func (m *machineProvider) updateMachine(config *common.RunnerConfig, data *machinesData, details *machineDetails) error {
	if details.State != machineStateIdle {
		return nil
	}

	if config.Machine.MaxBuilds > 0 && details.UsedCount >= config.Machine.MaxBuilds {
		// Limit number of builds
		return errors.New("Too many builds")
	}

	if data.Total() >= config.Limit && config.Limit > 0 {
		// Limit maximum number of machines
		return errors.New("Too many machines")
	}

	if time.Since(details.Used) > time.Second*time.Duration(config.Machine.IdleTime) {
		if data.Idle >= config.Machine.IdleCount {
			// Remove machine that are way over the idle time
			return errors.New("Too many idle machines")
		}
	}
	return nil
}

func (m *machineProvider) updateMachines(machines []string, config *common.RunnerConfig) (data machinesData) {
	data.Runner = config.ShortDescription()

	for _, name := range machines {
		details := m.machineDetails(name, false)
		err := m.updateMachine(config, &data, details)
		if err != nil {
			m.remove(details.Name, err)
		}

		data.Add(details.State)
	}
	return
}

func (m *machineProvider) createMachines(config *common.RunnerConfig, data *machinesData) {
	// Create a new machines and mark them as Idle
	for {
		if data.Available() >= config.Machine.IdleCount {
			// Limit maximum number of idle machines
			break
		}
		if data.Total() >= config.Limit && config.Limit > 0 {
			// Limit maximum number of machines
			break
		}
		m.create(config, machineStateIdle)
		data.Creating++
	}
}

func (m *machineProvider) loadMachines(config *common.RunnerConfig) ([]string, error) {
	// Find a new machine
	return m.machine.List(machineFilter(config))
}

func (m *machineProvider) Acquire(config *common.RunnerConfig) (data common.ExecutorData, err error) {
	if config.Machine == nil || config.Machine.MachineName == "" {
		err = fmt.Errorf("Missing Machine options")
		return
	}

	machines, err := m.loadMachines(config)
	if err != nil {
		return
	}

	// Lock updating machines, because two Acquires can be run at the same time
	m.acquireLock.Lock()

	// Update a list of currently configured machines
	machinesData := m.updateMachines(machines, config)

	// Pre-create machines
	m.createMachines(config, &machinesData)

	m.acquireLock.Unlock()

	logrus.WithFields(machinesData.Fields()).
		WithField("runner", config.ShortDescription()).
		WithField("minIdleCount", config.Machine.IdleCount).
		WithField("maxMachines", config.Limit).
		WithField("time", time.Now()).
		Debugln("Docker Machine Details")
	machinesData.writeDebugInformation()

	// Try to find a free machine
	details := m.findFreeMachine(machines...)
	if details != nil {
		data = details
		return
	}

	// If we have a free machines we can process a build
	if config.Machine.IdleCount != 0 && machinesData.Idle == 0 {
		err = errors.New("No free machines that can process builds")
	}
	return
}

func (m *machineProvider) Use(config *common.RunnerConfig, data common.ExecutorData) (newConfig common.RunnerConfig, newData common.ExecutorData, err error) {
	// Find a new machine
	details, _ := data.(*machineDetails)
	if details == nil {
		details, err = m.retryUseMachine(config)
		if err != nil {
			return
		}

		// Return details only if this is a new instance
		newData = details
	}

	// Get machine credentials
	dc, err := m.machine.Credentials(details.Name)
	if err != nil {
		if newData != nil {
			m.Release(config, newData)
		}
		return
	}

	// Create shallow copy of config and store in it docker credentials
	newConfig = *config
	newConfig.Docker = &common.DockerConfig{}
	if config.Docker != nil {
		*newConfig.Docker = *config.Docker
	}
	newConfig.Docker.DockerCredentials = dc

	// Mark machine as used
	details.State = machineStateUsed
	return
}

func (m *machineProvider) Release(config *common.RunnerConfig, data common.ExecutorData) error {
	// Release machine
	details, ok := data.(*machineDetails)
	if ok {
		// Mark last used time when is Used
		if details.State == machineStateUsed {
			details.Used = time.Now()
			details.UsedCount++
		}
		details.State = machineStateIdle
	}
	return nil
}

func (m *machineProvider) CanCreate() bool {
	return m.provider.CanCreate()
}

func (m *machineProvider) GetFeatures(features *common.FeaturesInfo) {
	m.provider.GetFeatures(features)
}

func (m *machineProvider) Create() common.Executor {
	return &machineExecutor{
		provider: m,
	}
}

func newMachineProvider(executor string) *machineProvider {
	provider := common.GetExecutor(executor)
	if provider == nil {
		logrus.Panicln("Missing", executor)
	}

	return &machineProvider{
		details:  make(machinesDetails),
		machine:  docker_helpers.NewMachineCommand(),
		provider: provider,
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"strconv"
	"syscall"
)

var (
	flagNomadEnable = flag.Bool("nomad-enable", false, "Whether Nomad engine should be started. "+
		"Overrides the NOMAD_ENABLE environment variable if set. "+flagDefault(strconv.FormatBool(defaultConfig.NomadEnable)))

	flagNomadSkipVerify = flag.Bool("nomad-skip-verify", false, "Whether Hashi-UI should skip TLS verification, not recommended. "+
		"Overrides the NOMAD_SKIP_VERIFY environment variable if set. "+flagDefault(strconv.FormatBool(defaultConfig.NomadSkipVerify)))

	flagNomadReadOnly = flag.Bool("nomad-read-only", false, "Whether Hashi-UI should be allowed to modify Nomad state. "+
		"Overrides the NOMAD_READ_ONLY environment variable if set. "+flagDefault(strconv.FormatBool(defaultConfig.NomadReadOnly)))

	flagNomadAddress = flag.String("nomad-address", "", "The address of the Nomad server. "+
		"Overrides the NOMAD_ADDR environment variable if set. "+flagDefault(defaultConfig.NomadAddress))

	flagNomadCACert = flag.String("nomad-ca-cert", "", "Path to the Nomad TLS CA Cert File. "+
		"Overrides the NOMAD_CACERT environment variable if set. "+flagDefault(defaultConfig.NomadCACert))

	flagNomadClientCert = flag.String("nomad-client-cert", "", "Path to the Nomad Client Cert File. "+
		"Overrides the NOMAD_CLIENT_CERT environment variable if set. "+flagDefault(defaultConfig.NomadClientCert))

	flagNomadClientKey = flag.String("nomad-client-key", "", "Path to the Nomad Client Key File. "+
		"Overrides the NOMAD_CLIENT_KEY environment variable if set. "+flagDefault(defaultConfig.NomadClientKey))
 )
// ParseNomadEnvConfig ...
func ParseNomadEnvConfig(c *Config) {
	nomadEnable, ok := syscall.Getenv("NOMAD_ENABLE")
	if ok {
		c.NomadEnable = nomadEnable != "0"
	}

	nomadReadOnly, ok := syscall.Getenv("NOMAD_READ_ONLY")
	if ok {
		c.NomadReadOnly = nomadReadOnly != "0"
	}

	nomadAddress, ok := syscall.Getenv("NOMAD_ADDR")
	if ok {
		c.NomadAddress = nomadAddress
	}

	listenPort, ok := syscall.Getenv("NOMAD_PORT_http")
	if ok {
		c.ListenAddress = fmt.Sprintf("0.0.0.0:%s", listenPort)
	}

	proxyAddress, ok := syscall.Getenv("NOMAD_PROXY_ADDRESS")
	if ok {
		c.ProxyAddress = proxyAddress
	}

	nomadCACert, ok := syscall.Getenv("NOMAD_CACERT")
	if ok {
		c.NomadCACert = nomadCACert
	}

	nomadClientCert, ok := syscall.Getenv("NOMAD_CLIENT_CERT")
	if ok {
		c.NomadClientCert = nomadClientCert
	}

	nomadClientKey, ok := syscall.Getenv("NOMAD_CLIENT_KEY")
	if ok {
		c.NomadClientKey = nomadClientKey
	}
	nomadSkipVerify, ok := syscall.Getenv("NOMAD_SKIP_VERIFY")
	if ok {
		c.NomadSkipVerify = nomadSkipVerify != "false"
	}
}

// ParseNomadFlagConfig ...
func ParseNomadFlagConfig(c *Config) {
	if *flagNomadEnable {
		c.NomadEnable = *flagNomadEnable
	}

	if *flagNomadReadOnly {
		c.NomadReadOnly = *flagNomadReadOnly
	}

	if *flagNomadAddress != "" {
		c.NomadAddress = *flagNomadAddress
	}

	if *flagNomadCACert != "" {
		c.NomadCACert = *flagNomadCACert
	}

	if *flagNomadClientCert != "" {
		c.NomadClientCert = *flagNomadClientCert
	}

	if *flagNomadClientKey != "" {
		c.NomadClientKey = *flagNomadClientKey
	}
}
<commit_msg>updating formatting<commit_after>package main

import (
	"flag"
	"fmt"
	"strconv"
	"syscall"
)

var (
	flagNomadEnable = flag.Bool("nomad-enable", false, "Whether Nomad engine should be started. "+
		"Overrides the NOMAD_ENABLE environment variable if set. "+flagDefault(strconv.FormatBool(defaultConfig.NomadEnable)))

	flagNomadSkipVerify = flag.Bool("nomad-skip-verify", false, "Whether Hashi-UI should skip TLS verification, not recommended. "+
		"Overrides the NOMAD_SKIP_VERIFY environment variable if set. "+flagDefault(strconv.FormatBool(defaultConfig.NomadSkipVerify)))

	flagNomadReadOnly = flag.Bool("nomad-read-only", false, "Whether Hashi-UI should be allowed to modify Nomad state. "+
		"Overrides the NOMAD_READ_ONLY environment variable if set. "+flagDefault(strconv.FormatBool(defaultConfig.NomadReadOnly)))

	flagNomadAddress = flag.String("nomad-address", "", "The address of the Nomad server. "+
		"Overrides the NOMAD_ADDR environment variable if set. "+flagDefault(defaultConfig.NomadAddress))

	flagNomadCACert = flag.String("nomad-ca-cert", "", "Path to the Nomad TLS CA Cert File. "+
		"Overrides the NOMAD_CACERT environment variable if set. "+flagDefault(defaultConfig.NomadCACert))

	flagNomadClientCert = flag.String("nomad-client-cert", "", "Path to the Nomad Client Cert File. "+
		"Overrides the NOMAD_CLIENT_CERT environment variable if set. "+flagDefault(defaultConfig.NomadClientCert))

	flagNomadClientKey = flag.String("nomad-client-key", "", "Path to the Nomad Client Key File. "+
		"Overrides the NOMAD_CLIENT_KEY environment variable if set. "+flagDefault(defaultConfig.NomadClientKey))
)

// ParseNomadEnvConfig ...
func ParseNomadEnvConfig(c *Config) {
	nomadEnable, ok := syscall.Getenv("NOMAD_ENABLE")
	if ok {
		c.NomadEnable = nomadEnable != "0"
	}

	nomadReadOnly, ok := syscall.Getenv("NOMAD_READ_ONLY")
	if ok {
		c.NomadReadOnly = nomadReadOnly != "0"
	}

	nomadAddress, ok := syscall.Getenv("NOMAD_ADDR")
	if ok {
		c.NomadAddress = nomadAddress
	}

	listenPort, ok := syscall.Getenv("NOMAD_PORT_http")
	if ok {
		c.ListenAddress = fmt.Sprintf("0.0.0.0:%s", listenPort)
	}

	proxyAddress, ok := syscall.Getenv("NOMAD_PROXY_ADDRESS")
	if ok {
		c.ProxyAddress = proxyAddress
	}

	nomadCACert, ok := syscall.Getenv("NOMAD_CACERT")
	if ok {
		c.NomadCACert = nomadCACert
	}

	nomadClientCert, ok := syscall.Getenv("NOMAD_CLIENT_CERT")
	if ok {
		c.NomadClientCert = nomadClientCert
	}

	nomadClientKey, ok := syscall.Getenv("NOMAD_CLIENT_KEY")
	if ok {
		c.NomadClientKey = nomadClientKey
	}
	nomadSkipVerify, ok := syscall.Getenv("NOMAD_SKIP_VERIFY")
	if ok {
		c.NomadSkipVerify = nomadSkipVerify != "false"
	}
}

// ParseNomadFlagConfig ...
func ParseNomadFlagConfig(c *Config) {
	if *flagNomadEnable {
		c.NomadEnable = *flagNomadEnable
	}

	if *flagNomadReadOnly {
		c.NomadReadOnly = *flagNomadReadOnly
	}

	if *flagNomadAddress != "" {
		c.NomadAddress = *flagNomadAddress
	}

	if *flagNomadCACert != "" {
		c.NomadCACert = *flagNomadCACert
	}

	if *flagNomadClientCert != "" {
		c.NomadClientCert = *flagNomadClientCert
	}

	if *flagNomadClientKey != "" {
		c.NomadClientKey = *flagNomadClientKey
	}
}
<|endoftext|>


<commit_before>package bytecode

import (
	"bytecode/ir"
	"emacs/lisp"
	"fmt"
	"sexp"
	"tu"
)

// #FIXME: either make compiler object reusable,
// or make it private type and expose Compile as a
// free standing function.

// Compiler converts Sexp forms into bytecode objects.
type Compiler struct {
	code      *code
	constPool ConstPool
	stack     stack
}

func NewCompiler() *Compiler {
	return &Compiler{code: newCode()}
}

func (cl *Compiler) CompileFunc(f *tu.Func) *Func {
	for _, param := range f.Params {
		cl.stack.pushVar(param)
	}

	cl.compileStmtList(f.Body)
	cl.ensureTrailingReturn()

	return &Func{
		Object:   cl.createObject(),
		ArgsDesc: argsDescriptor(len(f.Params), f.Variadic),
	}
}

// Insert trailing "return" opcode if its not already there.
func (cl *Compiler) ensureTrailingReturn() {
	code := cl.code

	lastInstr := ir.Empty
	for i := len(code.blocks) - 1; i >= 0; i-- {
		bb := code.blocks[i]
		if len(bb.Instrs) == 0 {
			continue // Empty block
		}
		lastInstr = bb.Instrs[len(bb.Instrs)-1]
	}

	if lastInstr.Op == ir.OpEmpty || lastInstr.Op != ir.OpReturn {
		cl.emit(ir.Return())
	}
}

func (cl *Compiler) compileStmt(form sexp.Form) {
	switch form := form.(type) {
	case *sexp.Return:
		cl.compileReturn(form)
	case *sexp.If:
		cl.compileIf(form)
	case *sexp.Block:
		cl.compileBlock(form)
	case *sexp.FormList:
		cl.compileStmtList(form.Forms)
	case *sexp.Bind:
		cl.compileBind(form)
	case *sexp.Rebind:
		cl.compileRebind(form)
	case *sexp.MapSet:
		cl.compileMapSet(form)
	case sexp.ExprStmt:
		cl.compileExprStmt(form.Form)
	case *sexp.Panic:
		cl.compilePanic(form)

	default:
		panic(fmt.Sprintf("unexpected stmt: %#v\n", form))
	}
}

func (cl *Compiler) compileExpr(form sexp.Form) {
	switch form := form.(type) {
	case *sexp.NumAdd:
		cl.compileOp(ir.OpNumAdd, form.Args)
	case *sexp.NumSub:
		cl.compileOp(ir.OpNumSub, form.Args)
	case *sexp.NumMul:
		cl.compileOp(ir.OpNumMul, form.Args)
	case *sexp.NumQuo:
		cl.compileOp(ir.OpNumQuo, form.Args)
	case *sexp.NumGt:
		cl.compileOp(ir.OpNumGt, form.Args)
	case *sexp.NumLt:
		cl.compileOp(ir.OpNumLt, form.Args)
	case *sexp.NumEq:
		cl.compileOp(ir.OpNumEq, form.Args)

	case sexp.Int:
		cl.emitConst(cl.constPool.InsertInt(form.Val))
	case sexp.Float:
		cl.emitConst(cl.constPool.InsertFloat(form.Val))
	case sexp.String:
		cl.emitConst(cl.constPool.InsertString(form.Val))
	case sexp.Var:
		cl.emitVar(form.Name, cl.stack.findVar(form.Name))
	case sexp.Symbol:
		cl.emitConst(cl.constPool.InsertSym(form.Val))

	case *sexp.Call:
		cl.compileCall(lisp.Symbol(form.Fn), form.Args...)

	case sexp.MakeMap:
		cl.compileMakeMap(form)

	default:
		panic(fmt.Sprintf("unexpected expr: %#v\n", form))
	}
}

func (cl *Compiler) compileOp(op ir.Opcode, args []sexp.Form) {
	if len(args) == 2 {
		cl.compileExprList(args)
		cl.emit(ir.Instr{Op: op})
	} else {
		cl.compileCall(instrSpecs[op].fn, args...)
	}
}

func (cl *Compiler) compileInstr(instr ir.Instr, argc int, args []sexp.Form) {
	if len(args) != argc {
		// #FIXME: need better error handling here.
		panic(fmt.Sprintf("%s expected %d args, got %d",
			instr.Op, argc, len(args)))
	}
	cl.compileExprList(args)
	cl.emit(instr)
}

func (cl *Compiler) compileCall(fn lisp.Symbol, args ...sexp.Form) {
	switch fn {
	case "cons":
		cl.compileInstr(ir.MakeCons(), 2, args)
	case "car":
		cl.compileInstr(ir.Car(), 1, args)
	case "cdr":
		cl.compileInstr(ir.Cdr(), 1, args)

	default:
		cpIndex := cl.constPool.InsertSym(fn)
		cl.emitConst(cpIndex)
		cl.compileExprList(args)
		cl.emitCall(len(args))
	}
}

func (cl *Compiler) compileReturn(form *sexp.Return) {
	if len(form.Results) > 1 {
		panic("unimplemented") // #REFS: 1
	}
	if len(form.Results) != 0 {
		cl.compileExpr(form.Results[0])
	}
	cl.emit(ir.Return())
}

func (cl *Compiler) compileIf(form *sexp.If) {
	cl.compileExpr(form.Test)
	jmpRef := cl.emitJmp(ir.OpJmpNil)
	cl.pushBlock("then")
	cl.compileStmtList(form.Then.Forms)
	cl.pushBlock("else")
	jmpRef.bind()
	if form.Else != nil {
		cl.compileStmt(form.Else)
	}
}

func (cl *Compiler) compileBlock(form *sexp.Block) {
	cl.compileStmtList(form.Forms)
	cl.stack.drop(form.Scope.Len())
}

func (cl *Compiler) compileBind(form *sexp.Bind) {
	cl.compileExpr(form.Init)
	cl.stack.vals[len(cl.stack.vals)-1] = form.Name
}

func (cl *Compiler) compileRebind(form *sexp.Rebind) {
	cl.compileExpr(form.Expr)
	stIndex := cl.stack.findVar(form.Name)
	cl.emit(ir.StackSet(stIndex))
}

func (cl *Compiler) compileMakeMap(form sexp.MakeMap) {
	cl.compileCall(
		"make-hash-table",
		sym(":size"), form.SizeHint,
		sym(":test"), sym("equal"),
	)
}

func (cl *Compiler) compileMapSet(form *sexp.MapSet) {
	cl.compileCall("puthash", form.Key, form.Val, form.Map)
	cl.emit(ir.Drop(1))
}

func (cl *Compiler) compilePanic(form *sexp.Panic) {
	cl.compileCall("Go-panic", form.ErrorData)
	cl.code.pushBlock("panic")
}

func (cl *Compiler) compileExprStmt(form sexp.Form) {
	cl.compileExpr(form)
	cl.emit(ir.Drop(1)) // Discard expression result.
}

func (cl *Compiler) compileStmtList(forms []sexp.Form) {
	for _, form := range forms {
		cl.compileStmt(form)
	}
}

func (cl *Compiler) compileExprList(forms []sexp.Form) {
	for _, form := range forms {
		cl.compileExpr(form)
	}
}

func (cl *Compiler) emit(instr ir.Instr) {
	spec := instrSpecs[instr.Op]

	cl.stack.drop(spec.argc)
	cl.code.pushInstr(instr)

	switch spec.mode {
	case omTmp:
		cl.stack.pushTmp()

	case omDiscard:
		cl.stack.pushTmp()
		cl.emit(ir.Drop(1))

	case omVoid:
		/* Do nothing */
	}
}

func (cl *Compiler) emitJmp(op ir.Opcode) jmpRef {
	if op != ir.OpJmp {
		cl.stack.drop(1)
	}
	return cl.code.pushJmp(op)
}

func (cl *Compiler) emitConst(cpIndex int) {
	cl.code.pushInstr(ir.ConstRef(cpIndex))
	cl.stack.pushConst(cpIndex)
}

func (cl *Compiler) emitVar(name string, stIndex int) {
	cl.code.pushInstr(ir.StackRef(stIndex))
	cl.stack.pushVar(name)
}

func (cl *Compiler) emitCall(argc int) {
	cl.stack.drop(argc + 1)
	cl.code.pushInstr(ir.Call(argc))
	cl.stack.pushTmp()
}

func (cl *Compiler) pushBlock(name string) {
	cl.code.pushBlock(name)
}

func (cl *Compiler) createObject() Object {
	return Object{
		Blocks:     cl.code.blocks,
		ConstPool:  cl.constPool,
		StackUsage: cl.stack.maxSize,
	}
}

func sym(val lisp.Symbol) sexp.Symbol {
	return sexp.Symbol{Val: val}
}

func argsDescriptor(arity int, variadic bool) uint32 {
	if arity > 127 {
		panic("can not have more than 127 positional parameters")
	}

	positionalArgs := uint32(arity) // First 7 bits: required args
	const variadicBit = 128         // 8-th bit: "rest" arg
	totalArgs := uint32(arity << 8) // Other bits

	if variadic {
		return positionalArgs + variadicBit + totalArgs
	}
	return positionalArgs + totalArgs
}
<commit_msg>fix CL bug: insertion of duplicative 'return' due to incorrect lastInstr lookup<commit_after>package bytecode

import (
	"bytecode/ir"
	"emacs/lisp"
	"fmt"
	"sexp"
	"tu"
)

// #FIXME: either make compiler object reusable,
// or make it private type and expose Compile as a
// free standing function.

// Compiler converts Sexp forms into bytecode objects.
type Compiler struct {
	code      *code
	constPool ConstPool
	stack     stack
}

func NewCompiler() *Compiler {
	return &Compiler{code: newCode()}
}

func (cl *Compiler) CompileFunc(f *tu.Func) *Func {
	for _, param := range f.Params {
		cl.stack.pushVar(param)
	}

	cl.compileStmtList(f.Body)
	cl.ensureTrailingReturn()

	return &Func{
		Object:   cl.createObject(),
		ArgsDesc: argsDescriptor(len(f.Params), f.Variadic),
	}
}

// Insert trailing "return" opcode if its not already there.
func (cl *Compiler) ensureTrailingReturn() {
	code := cl.code

	lastInstr := ir.Empty
	for i := len(code.blocks) - 1; i >= 0; i-- {
		bb := code.blocks[i]
		if len(bb.Instrs) == 0 {
			continue // Empty block
		}
		lastInstr = bb.Instrs[len(bb.Instrs)-1]
		break
	}

	if lastInstr.Op == ir.OpEmpty || lastInstr.Op != ir.OpReturn {
		cl.emit(ir.Return())
	}
}

func (cl *Compiler) compileStmt(form sexp.Form) {
	switch form := form.(type) {
	case *sexp.Return:
		cl.compileReturn(form)
	case *sexp.If:
		cl.compileIf(form)
	case *sexp.Block:
		cl.compileBlock(form)
	case *sexp.FormList:
		cl.compileStmtList(form.Forms)
	case *sexp.Bind:
		cl.compileBind(form)
	case *sexp.Rebind:
		cl.compileRebind(form)
	case *sexp.MapSet:
		cl.compileMapSet(form)
	case sexp.ExprStmt:
		cl.compileExprStmt(form.Form)
	case *sexp.Panic:
		cl.compilePanic(form)

	default:
		panic(fmt.Sprintf("unexpected stmt: %#v\n", form))
	}
}

func (cl *Compiler) compileExpr(form sexp.Form) {
	switch form := form.(type) {
	case *sexp.NumAdd:
		cl.compileOp(ir.OpNumAdd, form.Args)
	case *sexp.NumSub:
		cl.compileOp(ir.OpNumSub, form.Args)
	case *sexp.NumMul:
		cl.compileOp(ir.OpNumMul, form.Args)
	case *sexp.NumQuo:
		cl.compileOp(ir.OpNumQuo, form.Args)
	case *sexp.NumGt:
		cl.compileOp(ir.OpNumGt, form.Args)
	case *sexp.NumLt:
		cl.compileOp(ir.OpNumLt, form.Args)
	case *sexp.NumEq:
		cl.compileOp(ir.OpNumEq, form.Args)

	case sexp.Int:
		cl.emitConst(cl.constPool.InsertInt(form.Val))
	case sexp.Float:
		cl.emitConst(cl.constPool.InsertFloat(form.Val))
	case sexp.String:
		cl.emitConst(cl.constPool.InsertString(form.Val))
	case sexp.Var:
		cl.emitVar(form.Name, cl.stack.findVar(form.Name))
	case sexp.Symbol:
		cl.emitConst(cl.constPool.InsertSym(form.Val))

	case *sexp.Call:
		cl.compileCall(lisp.Symbol(form.Fn), form.Args...)

	case sexp.MakeMap:
		cl.compileMakeMap(form)

	default:
		panic(fmt.Sprintf("unexpected expr: %#v\n", form))
	}
}

func (cl *Compiler) compileOp(op ir.Opcode, args []sexp.Form) {
	if len(args) == 2 {
		cl.compileExprList(args)
		cl.emit(ir.Instr{Op: op})
	} else {
		cl.compileCall(instrSpecs[op].fn, args...)
	}
}

func (cl *Compiler) compileInstr(instr ir.Instr, argc int, args []sexp.Form) {
	if len(args) != argc {
		// #FIXME: need better error handling here.
		panic(fmt.Sprintf("%s expected %d args, got %d",
			instr.Op, argc, len(args)))
	}
	cl.compileExprList(args)
	cl.emit(instr)
}

func (cl *Compiler) compileCall(fn lisp.Symbol, args ...sexp.Form) {
	switch fn {
	case "cons":
		cl.compileInstr(ir.MakeCons(), 2, args)
	case "car":
		cl.compileInstr(ir.Car(), 1, args)
	case "cdr":
		cl.compileInstr(ir.Cdr(), 1, args)

	default:
		cpIndex := cl.constPool.InsertSym(fn)
		cl.emitConst(cpIndex)
		cl.compileExprList(args)
		cl.emitCall(len(args))
	}
}

func (cl *Compiler) compileReturn(form *sexp.Return) {
	if len(form.Results) > 1 {
		panic("unimplemented") // #REFS: 1
	}
	if len(form.Results) != 0 {
		cl.compileExpr(form.Results[0])
	}
	cl.emit(ir.Return())
}

func (cl *Compiler) compileIf(form *sexp.If) {
	cl.compileExpr(form.Test)
	jmpRef := cl.emitJmp(ir.OpJmpNil)
	cl.pushBlock("then")
	cl.compileStmtList(form.Then.Forms)
	cl.pushBlock("else")
	jmpRef.bind()
	if form.Else != nil {
		cl.compileStmt(form.Else)
	}
}

func (cl *Compiler) compileBlock(form *sexp.Block) {
	cl.compileStmtList(form.Forms)
	cl.stack.drop(form.Scope.Len())
}

func (cl *Compiler) compileBind(form *sexp.Bind) {
	cl.compileExpr(form.Init)
	cl.stack.vals[len(cl.stack.vals)-1] = form.Name
}

func (cl *Compiler) compileRebind(form *sexp.Rebind) {
	cl.compileExpr(form.Expr)
	stIndex := cl.stack.findVar(form.Name)
	cl.emit(ir.StackSet(stIndex))
}

func (cl *Compiler) compileMakeMap(form sexp.MakeMap) {
	cl.compileCall(
		"make-hash-table",
		sym(":size"), form.SizeHint,
		sym(":test"), sym("equal"),
	)
}

func (cl *Compiler) compileMapSet(form *sexp.MapSet) {
	cl.compileCall("puthash", form.Key, form.Val, form.Map)
	cl.emit(ir.Drop(1))
}

func (cl *Compiler) compilePanic(form *sexp.Panic) {
	cl.compileCall("Go-panic", form.ErrorData)
	cl.code.pushBlock("panic")
}

func (cl *Compiler) compileExprStmt(form sexp.Form) {
	cl.compileExpr(form)
	cl.emit(ir.Drop(1)) // Discard expression result.
}

func (cl *Compiler) compileStmtList(forms []sexp.Form) {
	for _, form := range forms {
		cl.compileStmt(form)
	}
}

func (cl *Compiler) compileExprList(forms []sexp.Form) {
	for _, form := range forms {
		cl.compileExpr(form)
	}
}

func (cl *Compiler) emit(instr ir.Instr) {
	spec := instrSpecs[instr.Op]

	cl.stack.drop(spec.argc)
	cl.code.pushInstr(instr)

	switch spec.mode {
	case omTmp:
		cl.stack.pushTmp()

	case omDiscard:
		cl.stack.pushTmp()
		cl.emit(ir.Drop(1))

	case omVoid:
		/* Do nothing */
	}
}

func (cl *Compiler) emitJmp(op ir.Opcode) jmpRef {
	if op != ir.OpJmp {
		cl.stack.drop(1)
	}
	return cl.code.pushJmp(op)
}

func (cl *Compiler) emitConst(cpIndex int) {
	cl.code.pushInstr(ir.ConstRef(cpIndex))
	cl.stack.pushConst(cpIndex)
}

func (cl *Compiler) emitVar(name string, stIndex int) {
	cl.code.pushInstr(ir.StackRef(stIndex))
	cl.stack.pushVar(name)
}

func (cl *Compiler) emitCall(argc int) {
	cl.stack.drop(argc + 1)
	cl.code.pushInstr(ir.Call(argc))
	cl.stack.pushTmp()
}

func (cl *Compiler) pushBlock(name string) {
	cl.code.pushBlock(name)
}

func (cl *Compiler) createObject() Object {
	return Object{
		Blocks:     cl.code.blocks,
		ConstPool:  cl.constPool,
		StackUsage: cl.stack.maxSize,
	}
}

func sym(val lisp.Symbol) sexp.Symbol {
	return sexp.Symbol{Val: val}
}

func argsDescriptor(arity int, variadic bool) uint32 {
	if arity > 127 {
		panic("can not have more than 127 positional parameters")
	}

	positionalArgs := uint32(arity) // First 7 bits: required args
	const variadicBit = 128         // 8-th bit: "rest" arg
	totalArgs := uint32(arity << 8) // Other bits

	if variadic {
		return positionalArgs + variadicBit + totalArgs
	}
	return positionalArgs + totalArgs
}
<|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
//
//      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 acceptance

import (
	"testing"

	"github.com/GoogleCloudPlatform/buildpacks/internal/acceptance"
)

func init() {
	acceptance.DefineFlags()
}

func TestAcceptance(t *testing.T) {
	t.Skip("Disable ruby30")

	builder, cleanup := acceptance.CreateBuilder(t)
	t.Cleanup(cleanup)

	// TODO(b/193272221): Remove when stack images are published.
	//if acceptance.PullImages() {
	//t.Skip("Disabled for continuous builds")
	//}

	testCases := []acceptance.Test{
		{
			Name: "function with dependencies",
			App:  "with_dependencies",
		},
		{
			Name: "function with platform-specific dependencies",
			App:  "with_platform_dependencies",
		},
		{
			Name:   "function with runtime env var",
			App:    "with_env_var",
			RunEnv: []string{"FOO=foo"},
		},
		{
			Name: "function in fn_source file",
			App:  "with_fn_source",
			Env:  []string{"GOOGLE_FUNCTION_SOURCE=sub_dir/custom_file.rb"},
		},
		{
			Name: "function using framework older than 0.7",
			App:  "with_legacy_framework",
		},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.Name, func(t *testing.T) {
			t.Parallel()

			tc.Path = "/testFunction"
			tc.Env = append(tc.Env,
				"GOOGLE_FUNCTION_TARGET=testFunction",
				"GOOGLE_RUNTIME=ruby30",
				"X_GOOGLE_TARGET_PLATFORM=gcf",
			)
			tc.FilesMustExist = append(tc.FilesMustExist,
				"/layers/google.utils.archive-source/src/source-code.tar.gz",
				"/workspace/.googlebuild/source-code.tar.gz",
			)

			acceptance.TestApp(t, builder, tc)
		})
	}
}

func TestFailures(t *testing.T) {
	t.Skip("Disable ruby30")

	builder, cleanup := acceptance.CreateBuilder(t)
	t.Cleanup(cleanup)

	// TODO(b/193272221): Remove when stack images are published.
	//if acceptance.PullImages() {
	//t.Skip("Disabled for continuous builds")
	//}

	testCases := []acceptance.FailureTest{
		{
			App:       "fail_ruby_version",
			MustMatch: "Could not find gem",
		},
		{
			App:       "fail_framework_missing",
			MustMatch: "unable to execute functions-framework-ruby",
		},
		{
			Name:      "must fail due to missing source file",
			App:       "with_dependencies",
			Env:       []string{"GOOGLE_FUNCTION_SOURCE=missing_file.rb"},
			MustMatch: `GOOGLE_FUNCTION_SOURCE specified file "missing_file.rb" but it does not exist`,
		},
		{
			Name:      "must fail due to incorrect signature",
			App:       "with_dependencies",
			Env:       []string{"GOOGLE_FUNCTION_SIGNATURE_TYPE=cloudevent"},
			MustMatch: `failed to verify function target "testFunction" in source "app.rb": Function "testFunction" does not match type cloudevent`,
		},
		{
			App:       "fail_syntax_error",
			MustMatch: "syntax error",
		},
		{
			App:       "fail_source_missing",
			MustMatch: `expected source file "app.rb" does not exist`,
		},
		{
			App:       "fail_target_missing",
			MustMatch: `failed to verify function target "testFunction" in source "app.rb": Undefined function`,
		},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.App, func(t *testing.T) {
			t.Parallel()

			tc.Env = append(tc.Env,
				"GOOGLE_FUNCTION_TARGET=testFunction",
				"GOOGLE_RUNTIME=ruby30",
				"X_GOOGLE_TARGET_PLATFORM=gcf",
			)

			acceptance.TestBuildFailure(t, builder, tc)
		})
	}
}
<commit_msg>Enable ruby30 gcf buildpack test.<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
//
//      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 acceptance

import (
	"testing"

	"github.com/GoogleCloudPlatform/buildpacks/internal/acceptance"
)

func init() {
	acceptance.DefineFlags()
}

func TestAcceptance(t *testing.T) {
	builder, cleanup := acceptance.CreateBuilder(t)
	t.Cleanup(cleanup)

	if acceptance.PullImages() {
		t.Skip("Disabled for continuous builds")
	}

	testCases := []acceptance.Test{
		{
			Name: "function with dependencies",
			App:  "with_dependencies",
		},
		{
			Name: "function with platform-specific dependencies",
			App:  "with_platform_dependencies",
		},
		{
			Name:   "function with runtime env var",
			App:    "with_env_var",
			RunEnv: []string{"FOO=foo"},
		},
		{
			Name: "function in fn_source file",
			App:  "with_fn_source",
			Env:  []string{"GOOGLE_FUNCTION_SOURCE=sub_dir/custom_file.rb"},
		},
		{
			Name: "function using framework older than 0.7",
			App:  "with_legacy_framework",
		},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.Name, func(t *testing.T) {
			t.Parallel()

			tc.Path = "/testFunction"
			tc.Env = append(tc.Env,
				"GOOGLE_FUNCTION_TARGET=testFunction",
				"GOOGLE_RUNTIME=ruby30",
				"X_GOOGLE_TARGET_PLATFORM=gcf",
			)
			tc.FilesMustExist = append(tc.FilesMustExist,
				"/layers/google.utils.archive-source/src/source-code.tar.gz",
				"/workspace/.googlebuild/source-code.tar.gz",
			)

			acceptance.TestApp(t, builder, tc)
		})
	}
}

func TestFailures(t *testing.T) {
	t.Skip("Disable ruby30")

	builder, cleanup := acceptance.CreateBuilder(t)
	t.Cleanup(cleanup)

	// TODO(b/193272221): Remove when stack images are published.
	//if acceptance.PullImages() {
	//t.Skip("Disabled for continuous builds")
	//}

	testCases := []acceptance.FailureTest{
		{
			App:       "fail_ruby_version",
			MustMatch: "Could not find gem",
		},
		{
			App:       "fail_framework_missing",
			MustMatch: "unable to execute functions-framework-ruby",
		},
		{
			Name:      "must fail due to missing source file",
			App:       "with_dependencies",
			Env:       []string{"GOOGLE_FUNCTION_SOURCE=missing_file.rb"},
			MustMatch: `GOOGLE_FUNCTION_SOURCE specified file "missing_file.rb" but it does not exist`,
		},
		{
			Name:      "must fail due to incorrect signature",
			App:       "with_dependencies",
			Env:       []string{"GOOGLE_FUNCTION_SIGNATURE_TYPE=cloudevent"},
			MustMatch: `failed to verify function target "testFunction" in source "app.rb": Function "testFunction" does not match type cloudevent`,
		},
		{
			App:       "fail_syntax_error",
			MustMatch: "syntax error",
		},
		{
			App:       "fail_source_missing",
			MustMatch: `expected source file "app.rb" does not exist`,
		},
		{
			App:       "fail_target_missing",
			MustMatch: `failed to verify function target "testFunction" in source "app.rb": Undefined function`,
		},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.App, func(t *testing.T) {
			t.Parallel()

			tc.Env = append(tc.Env,
				"GOOGLE_FUNCTION_TARGET=testFunction",
				"GOOGLE_RUNTIME=ruby30",
				"X_GOOGLE_TARGET_PLATFORM=gcf",
			)

			acceptance.TestBuildFailure(t, builder, tc)
		})
	}
}
<|endoftext|>


<commit_before>package queenattack

import "testing"

// Arguments to CanQueenAttack are in algebraic notation.
// See http://en.wikipedia.org/wiki/Algebraic_notation_(chess)

const targetTestVersion = 2

var tests = []struct {
	w, b   string
	attack bool
	ok     bool
}{
	{"b4", "b4", false, false}, // same square
	{"a8", "b9", false, false}, // off board
	{"a0", "b1", false, false},
	{"g3", "i5", false, false},
	{"here", "there", false, false}, // invalid
	{"", "", false, false},

	{"b3", "d7", false, true}, // no attack
	{"a1", "f8", false, true},
	{"b4", "b7", true, true}, // same file
	{"e4", "b4", true, true}, // same rank
	{"a1", "f6", true, true}, // common diagonals
	{"a6", "b7", true, true},
	{"d1", "f3", true, true},
	{"f1", "a6", true, true},
	{"a1", "h8", true, true},
	{"a8", "h1", true, true},
}

func TestTestVersion(t *testing.T) {
	if testVersion != targetTestVersion {
		t.Errorf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
	}
}

func TestCanQueenAttack(t *testing.T) {
	for _, test := range tests {
		switch attack, err := CanQueenAttack(test.w, test.b); {
		case err != nil:
			var _ error = err
			if test.ok {
				t.Fatalf("CanQueenAttack(%s, %s) returned error %q.  "+
					"Error not expected.",
					test.w, test.b, err)
			}
		case !test.ok:
			t.Fatalf("CanQueenAttack(%s, %s) = %t, %v.  Expected error.",
				test.w, test.b, attack, err)
		case attack != test.attack:
			t.Fatalf("CanQueenAttack(%s, %s) = %t, want %t.",
				test.w, test.b, attack, test.attack)
		}
	}
}

// Benchmark combined time for all test cases
func BenchmarkCanQueenAttack(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, test := range tests {
			CanQueenAttack(test.w, test.b)
		}
	}
}
<commit_msg>queen-attack: Ensure test versioning consistency with other exercises (#577)<commit_after>package queenattack

import "testing"

// Arguments to CanQueenAttack are in algebraic notation.
// See http://en.wikipedia.org/wiki/Algebraic_notation_(chess)

const targetTestVersion = 2

var tests = []struct {
	w, b   string
	attack bool
	ok     bool
}{
	{"b4", "b4", false, false}, // same square
	{"a8", "b9", false, false}, // off board
	{"a0", "b1", false, false},
	{"g3", "i5", false, false},
	{"here", "there", false, false}, // invalid
	{"", "", false, false},

	{"b3", "d7", false, true}, // no attack
	{"a1", "f8", false, true},
	{"b4", "b7", true, true}, // same file
	{"e4", "b4", true, true}, // same rank
	{"a1", "f6", true, true}, // common diagonals
	{"a6", "b7", true, true},
	{"d1", "f3", true, true},
	{"f1", "a6", true, true},
	{"a1", "h8", true, true},
	{"a8", "h1", true, true},
}

func TestTestVersion(t *testing.T) {
	if testVersion != targetTestVersion {
		t.Fatalf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
	}
}

func TestCanQueenAttack(t *testing.T) {
	for _, test := range tests {
		switch attack, err := CanQueenAttack(test.w, test.b); {
		case err != nil:
			var _ error = err
			if test.ok {
				t.Fatalf("CanQueenAttack(%s, %s) returned error %q.  "+
					"Error not expected.",
					test.w, test.b, err)
			}
		case !test.ok:
			t.Fatalf("CanQueenAttack(%s, %s) = %t, %v.  Expected error.",
				test.w, test.b, attack, err)
		case attack != test.attack:
			t.Fatalf("CanQueenAttack(%s, %s) = %t, want %t.",
				test.w, test.b, attack, test.attack)
		}
	}
}

// Benchmark combined time for all test cases
func BenchmarkCanQueenAttack(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, test := range tests {
			CanQueenAttack(test.w, test.b)
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rand"
	"encoding/base64"
	"flag"
	"fmt"
	"time"

	"github.com/dronemill/eventsocket-client-go"
)

var ticker = flag.Bool("ticker", false, "Do we write to the websocket connection as we tick?")
var requester = flag.Bool("requester", false, "Do we write to the websocket connection?")
var requestClientId = flag.String("requestClientId", "", "The clientId to send a request to")

func main() {
	flag.Parse()

	client, err := eventsocketclient.NewClient("127.0.0.1:8080")
	if err != nil {
		panic(err)
	}

	if err := client.DialWs(); err != nil {
		panic(err)
	}

	fmt.Printf("Connected! ClientId: %s\n", client.Id)

	if *ticker {
		go tick(client)
	}

	if *requester {
		go makeRequest(client)
	}

	go client.Recv()

	subChan, err := client.Suscribe("foo")
	if err != nil {
		panic(err)
	}

	for {
		select {
		case m := <-client.RecvBroadcast:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("BROADCAST err:%v :: %+v\n", m.Err, m.Message.Payload)
		case m := <-subChan:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("Foo: err:%v :: %+v\n", m.Err, m.Message.Payload)
		case m := <-client.RecvRequest:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("REQUEST err:%v :: %+v\n", m.Err, m.Message.Payload)
			p := eventsocketclient.NewPayload()
			p["I_SEE_YOU"] = randomString(32)
			if err := client.Reply(m.Message.RequestId, m.Message.ReplyClientId, &p); err != nil {
				panic(err)
			}
		case err := <-client.RecvError:
			panic(err)
		}
	}
}

func makeRequest(client *eventsocketclient.Client) {
	p := eventsocketclient.NewPayload()
	p["PEEK_ABOO"] = randomString(32)

	res, err := client.Request(*requestClientId, &p)
	if err != nil {
		panic(err)
	}

	m := <-res

	fmt.Printf("REPLY err:%v :: %+v\n", m.Err, m.Message.Payload)
}

func tick(client *eventsocketclient.Client) {
	tickChan := time.NewTicker(time.Second).C

	for {
		select {
		case <-tickChan:
			p := eventsocketclient.NewPayload()
			p["awesomeValue"] = randomString(32)

			if err := client.Emit("foo", &p); err != nil {
				panic(err)
			}

			p = make(eventsocketclient.Payload)
			p["value"] = randomString(32)

			if err := client.Broadcast(&p); err != nil {
				panic(err)
			}
		}
	}
}

func randomString(size int) string {
	rb := make([]byte, size)
	_, err := rand.Read(rb)

	if err != nil {
		fmt.Println(err)
	}

	return base64.URLEncoding.EncodeToString(rb)
}
<commit_msg>examples.basic.client: set the max message size<commit_after>package main

import (
	"crypto/rand"
	"encoding/base64"
	"flag"
	"fmt"
	"time"

	"github.com/dronemill/eventsocket-client-go"
)

var ticker = flag.Bool("ticker", false, "Do we write to the websocket connection as we tick?")
var requester = flag.Bool("requester", false, "Do we write to the websocket connection?")
var requestClientId = flag.String("requestClientId", "", "The clientId to send a request to")

func main() {
	flag.Parse()

	client, err := eventsocketclient.NewClient("127.0.0.1:8080")
	if err != nil {
		panic(err)
	}

	if err := client.DialWs(); err != nil {
		panic(err)
	}

	// set the max mesage that can be received
	client.SetMaxMessageSize(10240)

	fmt.Printf("Connected! ClientId: %s\n", client.Id)

	if *ticker {
		go tick(client)
	}

	if *requester {
		go makeRequest(client)
	}

	go client.Recv()

	subChan, err := client.Suscribe("foo")
	if err != nil {
		panic(err)
	}

	for {
		select {
		case m := <-client.RecvBroadcast:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("BROADCAST err:%v :: %+v\n", m.Err, m.Message.Payload)
		case m := <-subChan:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("Foo: err:%v :: %+v\n", m.Err, m.Message.Payload)
		case m := <-client.RecvRequest:
			if m.Err != nil {
				panic(m.Err)
			}
			fmt.Printf("REQUEST err:%v :: %+v\n", m.Err, m.Message.Payload)
			p := eventsocketclient.NewPayload()
			p["I_SEE_YOU"] = randomString(32)
			if err := client.Reply(m.Message.RequestId, m.Message.ReplyClientId, &p); err != nil {
				panic(err)
			}
		case err := <-client.RecvError:
			panic(err)
		}
	}
}

func makeRequest(client *eventsocketclient.Client) {
	p := eventsocketclient.NewPayload()
	p["PEEK_ABOO"] = randomString(32)

	res, err := client.Request(*requestClientId, &p)
	if err != nil {
		panic(err)
	}

	m := <-res

	fmt.Printf("REPLY err:%v :: %+v\n", m.Err, m.Message.Payload)
}

func tick(client *eventsocketclient.Client) {
	tickChan := time.NewTicker(time.Second).C

	for {
		select {
		case <-tickChan:
			p := eventsocketclient.NewPayload()
			p["awesomeValue"] = randomString(32)

			if err := client.Emit("foo", &p); err != nil {
				panic(err)
			}

			p = make(eventsocketclient.Payload)
			p["value"] = randomString(320)

			if err := client.Broadcast(&p); err != nil {
				panic(err)
			}
		}
	}
}

func randomString(size int) string {
	rb := make([]byte, size)
	_, err := rand.Read(rb)

	if err != nil {
		fmt.Println(err)
	}

	return base64.URLEncoding.EncodeToString(rb)
}
<|endoftext|>


<commit_before>package cf_test

import (
	. "cf"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"path/filepath"
)

var _ = Describe("AppFiles", func() {
	fixturePath := filepath.Join("..", "fixtures", "applications")

	Describe("AppFilesInDir", func() {
		It("all files have '/' path separators", func() {
			files, err := AppFilesInDir(fixturePath)
			Expect(err).ShouldNot(HaveOccurred())

			for _, afile := range files {
				Expect(afile.Path).Should(Equal(filepath.ToSlash(afile.Path)))
			}
		})

		It("excludes files based on the .cfignore file", func() {
			appPath := filepath.Join(fixturePath, "app-with-cfignore")
			files, err := AppFilesInDir(appPath)
			Expect(err).ShouldNot(HaveOccurred())

			paths := []string{}
			for _, file := range files {
				paths = append(paths, file.Path)
			}

			Expect(paths).To(Equal([]string{
				filepath.Join("dir1", "child-dir", "file3.txt"),
				filepath.Join("dir1", "file1.txt"),
			}))
		})
	})
})
<commit_msg>Fix app files test on windows<commit_after>package cf_test

import (
	. "cf"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	"path/filepath"
	"path"
)

var _ = Describe("AppFiles", func() {
	fixturePath := filepath.Join("..", "fixtures", "applications")

	Describe("AppFilesInDir", func() {
		It("all files have '/' path separators", func() {
			files, err := AppFilesInDir(fixturePath)
			Expect(err).ShouldNot(HaveOccurred())

			for _, afile := range files {
				Expect(afile.Path).Should(Equal(filepath.ToSlash(afile.Path)))
			}
		})

		It("excludes files based on the .cfignore file", func() {
			appPath := filepath.Join(fixturePath, "app-with-cfignore")
			files, err := AppFilesInDir(appPath)
			Expect(err).ShouldNot(HaveOccurred())

			paths := []string{}
			for _, file := range files {
				paths = append(paths, file.Path)
			}

			Expect(paths).To(Equal([]string{
				path.Join("dir1", "child-dir", "file3.txt"),
				path.Join("dir1", "file1.txt"),
			}))
		})
	})
})
<|endoftext|>


<commit_before>package ui

import (
	"fmt"
	"net"
	"net/http"
	"path/filepath"
	"runtime"
	"time"

	"github.com/getlantern/flashlight/packaged"
	"github.com/getlantern/golog"
	"github.com/getlantern/tarfs"
	"github.com/skratchdot/open-golang/open"
)

const (
	LocalUIDir = "../../../lantern-ui/app"
)

var (
	log = golog.LoggerFor("flashlight.ui")

	l            net.Listener
	fs           *tarfs.FileSystem
	Translations *tarfs.FileSystem
	server       *http.Server
	uiaddr       string

	openedExternal = false
	r              = http.NewServeMux()
)

func init() {
	// Assume the default directory containing UI assets is
	// a sibling directory to this file's directory.
	localResourcesPath := ""
	_, curDir, _, ok := runtime.Caller(1)
	if !ok {
		log.Errorf("Unable to determine caller directory")
	} else {
		localResourcesPath = filepath.Join(curDir, LocalUIDir)
		absLocalResourcesPath, err := filepath.Abs(localResourcesPath)
		if err != nil {
			absLocalResourcesPath = localResourcesPath
		}
		log.Debugf("Creating tarfs filesystem that prefers local resources at %v", absLocalResourcesPath)
	}

	var err error
	fs, err = tarfs.New(Resources, localResourcesPath)
	if err != nil {
		// Panicking here because this shouldn't happen at runtime unless the
		// resources were incorrectly embedded.
		panic(fmt.Errorf("Unable to open tarfs filesystem: %v", err))
	}
	Translations = fs.SubDir("locale")
}

func Handle(p string, handler http.Handler) string {
	r.Handle(p, handler)
	return uiaddr + p
}

func Start(tcpAddr *net.TCPAddr, allowRemote bool) (err error) {
	addr := tcpAddr
	if allowRemote {
		// If we want to allow remote connections, we have to bind all interfaces
		addr = &net.TCPAddr{Port: tcpAddr.Port}
	}
	if l, err = net.ListenTCP("tcp4", addr); err != nil {
		return fmt.Errorf("Unable to listen at %v: %v. Error is: %v", addr, l, err)
	}

	// This allows a second Lantern running on the system to trigger the existing
	// Lantern to show the UI, or at least try to
	handler := func(resp http.ResponseWriter, req *http.Request) {
		// If we're allowing remote, we're in practice not showing the UI on this
		// typically headless system, so don't allow triggering of the UI.
		if !allowRemote {
			Show()
		}
		resp.WriteHeader(http.StatusOK)
	}
	r.Handle("/startup", http.HandlerFunc(handler))
	r.Handle("/", http.FileServer(fs))

	server = &http.Server{
		Handler:  r,
		ErrorLog: log.AsStdLogger(),
	}
	go func() {
		err := server.Serve(l)
		if err != nil {
			log.Errorf("Error serving: %v", err)
		}
	}()
	uiaddr = fmt.Sprintf("http://%v", l.Addr().String())
	log.Debugf("UI available at %v", uiaddr)

	return nil
}

// Show opens the UI in a browser. Note we know the UI server is
// *listening* at this point as long as Start is correctly called prior
// to this method. It may not be reading yet, but since we're the only
// ones reading from those incoming sockets the fact that reading starts
// asynchronously is not a problem.
func Show() {
	go func() {
		err := open.Run(uiaddr)
		if err != nil {
			log.Errorf("Error opening page to `%v`: %v", uiaddr, err)
		}
		openExternalUrl()
	}()
}

// openExternalUrl opens an external URL of one of our partners automatically
// at startup if configured to do so. It should only open the first time in
// a given session that Lantern is opened.
func openExternalUrl() {
	if openedExternal {
		log.Debugf("Not opening external URL again")
		return
	}
	defer func() {
		openedExternal = true
	}()

	path, s, err := packaged.ReadSettings()
	if err != nil {
		log.Errorf("Could not read yaml from %v: %v", path, err)
		return
	}

	time.Sleep(4 * time.Second)
	err = open.Run(s.StartupUrl)
	if err != nil {
		log.Errorf("Error opening external page to `%v`: %v", uiaddr, err)
	}
}
<commit_msg>Change logging closes #2898<commit_after>package ui

import (
	"fmt"
	"net"
	"net/http"
	"path/filepath"
	"runtime"
	"time"

	"github.com/getlantern/flashlight/packaged"
	"github.com/getlantern/golog"
	"github.com/getlantern/tarfs"
	"github.com/skratchdot/open-golang/open"
)

const (
	LocalUIDir = "../../../lantern-ui/app"
)

var (
	log = golog.LoggerFor("flashlight.ui")

	l            net.Listener
	fs           *tarfs.FileSystem
	Translations *tarfs.FileSystem
	server       *http.Server
	uiaddr       string

	openedExternal = false
	r              = http.NewServeMux()
)

func init() {
	// Assume the default directory containing UI assets is
	// a sibling directory to this file's directory.
	localResourcesPath := ""
	_, curDir, _, ok := runtime.Caller(1)
	if !ok {
		log.Errorf("Unable to determine caller directory")
	} else {
		localResourcesPath = filepath.Join(curDir, LocalUIDir)
		absLocalResourcesPath, err := filepath.Abs(localResourcesPath)
		if err != nil {
			absLocalResourcesPath = localResourcesPath
		}
		log.Debugf("Creating tarfs filesystem that prefers local resources at %v", absLocalResourcesPath)
	}

	var err error
	fs, err = tarfs.New(Resources, localResourcesPath)
	if err != nil {
		// Panicking here because this shouldn't happen at runtime unless the
		// resources were incorrectly embedded.
		panic(fmt.Errorf("Unable to open tarfs filesystem: %v", err))
	}
	Translations = fs.SubDir("locale")
}

func Handle(p string, handler http.Handler) string {
	r.Handle(p, handler)
	return uiaddr + p
}

func Start(tcpAddr *net.TCPAddr, allowRemote bool) (err error) {
	addr := tcpAddr
	if allowRemote {
		// If we want to allow remote connections, we have to bind all interfaces
		addr = &net.TCPAddr{Port: tcpAddr.Port}
	}
	if l, err = net.ListenTCP("tcp4", addr); err != nil {
		return fmt.Errorf("Unable to listen at %v: %v. Error is: %v", addr, l, err)
	}

	// This allows a second Lantern running on the system to trigger the existing
	// Lantern to show the UI, or at least try to
	handler := func(resp http.ResponseWriter, req *http.Request) {
		// If we're allowing remote, we're in practice not showing the UI on this
		// typically headless system, so don't allow triggering of the UI.
		if !allowRemote {
			Show()
		}
		resp.WriteHeader(http.StatusOK)
	}
	r.Handle("/startup", http.HandlerFunc(handler))
	r.Handle("/", http.FileServer(fs))

	server = &http.Server{
		Handler:  r,
		ErrorLog: log.AsStdLogger(),
	}
	go func() {
		err := server.Serve(l)
		if err != nil {
			log.Errorf("Error serving: %v", err)
		}
	}()
	uiaddr = fmt.Sprintf("http://%v", l.Addr().String())
	log.Debugf("UI available at %v", uiaddr)

	return nil
}

// Show opens the UI in a browser. Note we know the UI server is
// *listening* at this point as long as Start is correctly called prior
// to this method. It may not be reading yet, but since we're the only
// ones reading from those incoming sockets the fact that reading starts
// asynchronously is not a problem.
func Show() {
	go func() {
		err := open.Run(uiaddr)
		if err != nil {
			log.Errorf("Error opening page to `%v`: %v", uiaddr, err)
		}
		openExternalUrl()
	}()
}

// openExternalUrl opens an external URL of one of our partners automatically
// at startup if configured to do so. It should only open the first time in
// a given session that Lantern is opened.
func openExternalUrl() {
	if openedExternal {
		log.Debugf("Not opening external URL again")
		return
	}
	defer func() {
		openedExternal = true
	}()

	path, s, err := packaged.ReadSettings()
	if err != nil {
		// Let packaged itself log errors as necessary.
		log.Debugf("Could not read yaml from %v: %v", path, err)
		return
	}

	time.Sleep(4 * time.Second)
	err = open.Run(s.StartupUrl)
	if err != nil {
		log.Errorf("Error opening external page to `%v`: %v", uiaddr, err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Istio 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 kube

import (
	"fmt"
	"sort"
	"strconv"
	"strings"

	multierror "github.com/hashicorp/go-multierror"
	"k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"

	"istio.io/pilot/model"
)

const (
	// IngressClassAnnotation is the annotation on ingress resources for the class of controllers
	// responsible for it
	IngressClassAnnotation = "kubernetes.io/ingress.class"

	// KubeServiceAccountsOnVMAnnotation is to specify the K8s service accounts that are allowed to run
	// this service on the VMs
	KubeServiceAccountsOnVMAnnotation = "alpha.istio.io/serviceaccounts/kubernetes"

	// CanonicalServiceAccountsOnVMAnnotation is to specify the non-Kubernetes service accounts that
	// are allowed to run this service on the VMs
	CanonicalServiceAccountsOnVMAnnotation = "alpha.istio.io/serviceaccounts/canonical"

	// IstioURIPrefix is the URI prefix in the Istio service account scheme
	IstioURIPrefix = "spiffe"
)

func convertTags(obj meta_v1.ObjectMeta) model.Tags {
	out := make(model.Tags, len(obj.Labels))
	for k, v := range obj.Labels {
		out[k] = v
	}
	return out
}

func convertPort(port v1.ServicePort) *model.Port {
	return &model.Port{
		Name:     port.Name,
		Port:     int(port.Port),
		Protocol: convertProtocol(port.Name, port.Protocol),
	}
}

func convertService(svc v1.Service, domainSuffix string) *model.Service {
	addr, external := "", ""
	if svc.Spec.ClusterIP != "" && svc.Spec.ClusterIP != v1.ClusterIPNone {
		addr = svc.Spec.ClusterIP
	}

	if svc.Spec.Type == v1.ServiceTypeExternalName && svc.Spec.ExternalName != "" {
		external = svc.Spec.ExternalName
	}

	// must have address or be external (but not both)
	if (addr == "" && external == "") || (addr != "" && external != "") {
		return nil
	}

	ports := make([]*model.Port, 0, len(svc.Spec.Ports))
	for _, port := range svc.Spec.Ports {
		ports = append(ports, convertPort(port))
	}

	serviceaccounts := make([]string, 0)
	if svc.Annotations != nil {
		for _, csa := range strings.Split(svc.Annotations[CanonicalServiceAccountsOnVMAnnotation], ",") {
			serviceaccounts = append(serviceaccounts, canonicalToIstioServiceAccount(csa))
		}
		for _, ksa := range strings.Split(svc.Annotations[KubeServiceAccountsOnVMAnnotation], ",") {
			serviceaccounts = append(serviceaccounts, kubeToIstioServiceAccount(ksa, svc.Namespace, domainSuffix))
		}
	}
	sort.Sort(sort.StringSlice(serviceaccounts))

	return &model.Service{
		Hostname:        serviceHostname(svc.Name, svc.Namespace, domainSuffix),
		Ports:           ports,
		Address:         addr,
		ExternalName:    external,
		ServiceAccounts: serviceaccounts,
	}
}

// serviceHostname produces FQDN for a k8s service
func serviceHostname(name, namespace, domainSuffix string) string {
	return fmt.Sprintf("%s.%s.svc.%s", name, namespace, domainSuffix)
}

// canonicalToIstioServiceAccount converts a Canonical service account to an Istio service account
func canonicalToIstioServiceAccount(saname string) string {
	return fmt.Sprintf("%v://%v", IstioURIPrefix, saname)
}

// kubeToIstioServiceAccount converts a K8s service account to an Istio service account
func kubeToIstioServiceAccount(saname string, ns string, domain string) string {
	return fmt.Sprintf("%v://%v/ns/%v/sa/%v", IstioURIPrefix, domain, ns, saname)
}

// KeyFunc is the internal API key function that returns "namespace"/"name" or
// "name" if "namespace" is empty
func KeyFunc(name, namespace string) string {
	if len(namespace) == 0 {
		return name
	}
	return namespace + "/" + name
}

// parseHostname extracts service name and namespace from the service hostnamei
func parseHostname(hostname string) (name string, namespace string, err error) {
	parts := strings.Split(hostname, ".")
	if len(parts) < 2 {
		err = fmt.Errorf("missing service name and namespace from the service hostname %q", hostname)
		return
	}
	name = parts[0]
	namespace = parts[1]
	return
}

func convertProtocol(name string, proto v1.Protocol) model.Protocol {
	out := model.ProtocolTCP
	switch proto {
	case v1.ProtocolUDP:
		out = model.ProtocolUDP
	case v1.ProtocolTCP:
		prefix := name
		i := strings.Index(name, "-")
		if i >= 0 {
			prefix = name[:i]
		}
		switch prefix {
		case "grpc":
			out = model.ProtocolGRPC
		case "http":
			out = model.ProtocolHTTP
		case "http2":
			out = model.ProtocolHTTP2
		case "https":
			out = model.ProtocolHTTPS
		}
	}
	return out
}

func convertProbePort(c v1.Container, handler *v1.Handler) (*model.Port, error) {
	if handler == nil {
		return nil, nil
	}

	var protocol model.Protocol
	var portVal intstr.IntOrString
	var port int

	// Only one type of handler is allowed by Kubernetes (HTTPGet or TCPSocket)
	if handler.HTTPGet != nil {
		portVal = handler.HTTPGet.Port
		protocol = model.ProtocolHTTP
	} else if handler.TCPSocket != nil {
		portVal = handler.TCPSocket.Port
		protocol = model.ProtocolTCP
	} else {
		return nil, nil
	}

	switch portVal.Type {
	case intstr.Int:
		port = portVal.IntValue()
		return &model.Port{
			Name:     "mgmt-" + strconv.Itoa(port),
			Port:     port,
			Protocol: protocol,
		}, nil
	case intstr.String:
		for _, named := range c.Ports {
			if named.Name == portVal.String() {
				port = int(named.ContainerPort)
				return &model.Port{
					Name:     "mgmt-" + strconv.Itoa(port),
					Port:     port,
					Protocol: protocol,
				}, nil
			}
		}
		return nil, fmt.Errorf("missing named port %q", portVal)
	default:
		return nil, fmt.Errorf("incorrect port type %q", portVal)
	}
}

// convertProbesToPorts returns a PortList consisting of the ports where the
// pod is configured to do Liveness and Readiness probes
func convertProbesToPorts(t *v1.PodSpec) (model.PortList, error) {
	set := make(map[string]*model.Port)
	var errs error
	for _, container := range t.Containers {
		for _, probe := range []*v1.Probe{container.LivenessProbe, container.ReadinessProbe} {
			if probe == nil {
				continue
			}

			p, err := convertProbePort(container, &probe.Handler)
			if err != nil {
				errs = multierror.Append(errs, err)
			} else if p != nil && set[p.Name] == nil {
				// Deduplicate along the way. We don't differentiate between HTTP vs TCP mgmt ports
				set[p.Name] = p
			}
		}
	}

	mgmtPorts := make(model.PortList, 0, len(set))
	for _, p := range set {
		mgmtPorts = append(mgmtPorts, p)
	}
	sort.Slice(mgmtPorts, func(i, j int) bool { return mgmtPorts[i].Port < mgmtPorts[j].Port })

	return mgmtPorts, errs
}
<commit_msg>Change secure naming annotation signature. (#1102)<commit_after>// Copyright 2017 Istio 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 kube

import (
	"fmt"
	"sort"
	"strconv"
	"strings"

	multierror "github.com/hashicorp/go-multierror"
	"k8s.io/api/core/v1"
	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"

	"istio.io/pilot/model"
)

const (
	// IngressClassAnnotation is the annotation on ingress resources for the class of controllers
	// responsible for it
	IngressClassAnnotation = "kubernetes.io/ingress.class"

	// KubeServiceAccountsOnVMAnnotation is to specify the K8s service accounts that are allowed to run
	// this service on the VMs
	KubeServiceAccountsOnVMAnnotation = "alpha.istio.io/kubernetes-serviceaccounts"

	// CanonicalServiceAccountsOnVMAnnotation is to specify the non-Kubernetes service accounts that
	// are allowed to run this service on the VMs
	CanonicalServiceAccountsOnVMAnnotation = "alpha.istio.io/canonical-serviceaccounts"

	// IstioURIPrefix is the URI prefix in the Istio service account scheme
	IstioURIPrefix = "spiffe"
)

func convertTags(obj meta_v1.ObjectMeta) model.Tags {
	out := make(model.Tags, len(obj.Labels))
	for k, v := range obj.Labels {
		out[k] = v
	}
	return out
}

func convertPort(port v1.ServicePort) *model.Port {
	return &model.Port{
		Name:     port.Name,
		Port:     int(port.Port),
		Protocol: convertProtocol(port.Name, port.Protocol),
	}
}

func convertService(svc v1.Service, domainSuffix string) *model.Service {
	addr, external := "", ""
	if svc.Spec.ClusterIP != "" && svc.Spec.ClusterIP != v1.ClusterIPNone {
		addr = svc.Spec.ClusterIP
	}

	if svc.Spec.Type == v1.ServiceTypeExternalName && svc.Spec.ExternalName != "" {
		external = svc.Spec.ExternalName
	}

	// must have address or be external (but not both)
	if (addr == "" && external == "") || (addr != "" && external != "") {
		return nil
	}

	ports := make([]*model.Port, 0, len(svc.Spec.Ports))
	for _, port := range svc.Spec.Ports {
		ports = append(ports, convertPort(port))
	}

	serviceaccounts := make([]string, 0)
	if svc.Annotations != nil {
		for _, csa := range strings.Split(svc.Annotations[CanonicalServiceAccountsOnVMAnnotation], ",") {
			serviceaccounts = append(serviceaccounts, canonicalToIstioServiceAccount(csa))
		}
		for _, ksa := range strings.Split(svc.Annotations[KubeServiceAccountsOnVMAnnotation], ",") {
			serviceaccounts = append(serviceaccounts, kubeToIstioServiceAccount(ksa, svc.Namespace, domainSuffix))
		}
	}
	sort.Sort(sort.StringSlice(serviceaccounts))

	return &model.Service{
		Hostname:        serviceHostname(svc.Name, svc.Namespace, domainSuffix),
		Ports:           ports,
		Address:         addr,
		ExternalName:    external,
		ServiceAccounts: serviceaccounts,
	}
}

// serviceHostname produces FQDN for a k8s service
func serviceHostname(name, namespace, domainSuffix string) string {
	return fmt.Sprintf("%s.%s.svc.%s", name, namespace, domainSuffix)
}

// canonicalToIstioServiceAccount converts a Canonical service account to an Istio service account
func canonicalToIstioServiceAccount(saname string) string {
	return fmt.Sprintf("%v://%v", IstioURIPrefix, saname)
}

// kubeToIstioServiceAccount converts a K8s service account to an Istio service account
func kubeToIstioServiceAccount(saname string, ns string, domain string) string {
	return fmt.Sprintf("%v://%v/ns/%v/sa/%v", IstioURIPrefix, domain, ns, saname)
}

// KeyFunc is the internal API key function that returns "namespace"/"name" or
// "name" if "namespace" is empty
func KeyFunc(name, namespace string) string {
	if len(namespace) == 0 {
		return name
	}
	return namespace + "/" + name
}

// parseHostname extracts service name and namespace from the service hostnamei
func parseHostname(hostname string) (name string, namespace string, err error) {
	parts := strings.Split(hostname, ".")
	if len(parts) < 2 {
		err = fmt.Errorf("missing service name and namespace from the service hostname %q", hostname)
		return
	}
	name = parts[0]
	namespace = parts[1]
	return
}

func convertProtocol(name string, proto v1.Protocol) model.Protocol {
	out := model.ProtocolTCP
	switch proto {
	case v1.ProtocolUDP:
		out = model.ProtocolUDP
	case v1.ProtocolTCP:
		prefix := name
		i := strings.Index(name, "-")
		if i >= 0 {
			prefix = name[:i]
		}
		switch prefix {
		case "grpc":
			out = model.ProtocolGRPC
		case "http":
			out = model.ProtocolHTTP
		case "http2":
			out = model.ProtocolHTTP2
		case "https":
			out = model.ProtocolHTTPS
		}
	}
	return out
}

func convertProbePort(c v1.Container, handler *v1.Handler) (*model.Port, error) {
	if handler == nil {
		return nil, nil
	}

	var protocol model.Protocol
	var portVal intstr.IntOrString
	var port int

	// Only one type of handler is allowed by Kubernetes (HTTPGet or TCPSocket)
	if handler.HTTPGet != nil {
		portVal = handler.HTTPGet.Port
		protocol = model.ProtocolHTTP
	} else if handler.TCPSocket != nil {
		portVal = handler.TCPSocket.Port
		protocol = model.ProtocolTCP
	} else {
		return nil, nil
	}

	switch portVal.Type {
	case intstr.Int:
		port = portVal.IntValue()
		return &model.Port{
			Name:     "mgmt-" + strconv.Itoa(port),
			Port:     port,
			Protocol: protocol,
		}, nil
	case intstr.String:
		for _, named := range c.Ports {
			if named.Name == portVal.String() {
				port = int(named.ContainerPort)
				return &model.Port{
					Name:     "mgmt-" + strconv.Itoa(port),
					Port:     port,
					Protocol: protocol,
				}, nil
			}
		}
		return nil, fmt.Errorf("missing named port %q", portVal)
	default:
		return nil, fmt.Errorf("incorrect port type %q", portVal)
	}
}

// convertProbesToPorts returns a PortList consisting of the ports where the
// pod is configured to do Liveness and Readiness probes
func convertProbesToPorts(t *v1.PodSpec) (model.PortList, error) {
	set := make(map[string]*model.Port)
	var errs error
	for _, container := range t.Containers {
		for _, probe := range []*v1.Probe{container.LivenessProbe, container.ReadinessProbe} {
			if probe == nil {
				continue
			}

			p, err := convertProbePort(container, &probe.Handler)
			if err != nil {
				errs = multierror.Append(errs, err)
			} else if p != nil && set[p.Name] == nil {
				// Deduplicate along the way. We don't differentiate between HTTP vs TCP mgmt ports
				set[p.Name] = p
			}
		}
	}

	mgmtPorts := make(model.PortList, 0, len(set))
	for _, p := range set {
		mgmtPorts = append(mgmtPorts, p)
	}
	sort.Slice(mgmtPorts, func(i, j int) bool { return mgmtPorts[i].Port < mgmtPorts[j].Port })

	return mgmtPorts, errs
}
<|endoftext|>


<commit_before>package acsengine

import (
	"strconv"
	"strings"

	"github.com/Azure/acs-engine/pkg/api"
	"github.com/Azure/acs-engine/pkg/api/common"
	"github.com/Azure/acs-engine/pkg/helpers"
)

func setKubeletConfig(cs *api.ContainerService) {
	o := cs.Properties.OrchestratorProfile
	cloudSpecConfig := getCloudSpecConfig(cs.Location)
	staticLinuxKubeletConfig := map[string]string{
		"--address":                     "0.0.0.0",
		"--allow-privileged":            "true",
		"--anonymous-auth":              "false",
		"--authorization-mode":          "Webhook",
		"--client-ca-file":              "/etc/kubernetes/certs/ca.crt",
		"--pod-manifest-path":           "/etc/kubernetes/manifests",
		"--cluster-dns":                 o.KubernetesConfig.DNSServiceIP,
		"--cgroups-per-qos":             "true",
		"--enforce-node-allocatable":    "pods",
		"--kubeconfig":                  "/var/lib/kubelet/kubeconfig",
		"--keep-terminated-pod-volumes": "false",
	}

	staticWindowsKubeletConfig := make(map[string]string)
	for key, val := range staticLinuxKubeletConfig {
		staticWindowsKubeletConfig[key] = val
	}

	// Default Kubelet config
	defaultKubeletConfig := map[string]string{
		"--cluster-domain":                  "cluster.local",
		"--network-plugin":                  "cni",
		"--pod-infra-container-image":       cloudSpecConfig.KubernetesSpecConfig.KubernetesImageBase + KubeConfigs[o.OrchestratorVersion]["pause"],
		"--max-pods":                        strconv.Itoa(DefaultKubernetesMaxPods),
		"--eviction-hard":                   DefaultKubernetesHardEvictionThreshold,
		"--node-status-update-frequency":    KubeConfigs[o.OrchestratorVersion]["nodestatusfreq"],
		"--image-gc-high-threshold":         strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"--image-gc-low-threshold":          strconv.Itoa(DefaultKubernetesGCLowThreshold),
		"--non-masquerade-cidr":             o.KubernetesConfig.ClusterSubnet,
		"--cloud-provider":                  "azure",
		"--cloud-config":                    "/etc/kubernetes/azure.json",
		"--azure-container-registry-config": "/etc/kubernetes/azure.json",
		"--event-qps":                       DefaultKubeletEventQPS,
		"--cadvisor-port":                   DefaultKubeletCadvisorPort,
		"--pod-max-pids":                    strconv.Itoa(DefaultKubeletPodMaxPIDs),
		"--image-pull-progress-deadline":    "30m",
	}

	// Apply Azure CNI-specific --max-pods value
	if o.KubernetesConfig.NetworkPlugin == NetworkPluginAzure {
		defaultKubeletConfig["--max-pods"] = strconv.Itoa(DefaultKubernetesMaxPodsVNETIntegrated)
	}

	// If no user-configurable kubelet config values exists, use the defaults
	setMissingKubeletValues(o.KubernetesConfig, defaultKubeletConfig)
	addDefaultFeatureGates(o.KubernetesConfig.KubeletConfig, o.OrchestratorVersion, "", "")

	// Override default cloud-provider?
	if helpers.IsTrueBoolPointer(o.KubernetesConfig.UseCloudControllerManager) {
		staticLinuxKubeletConfig["--cloud-provider"] = "external"
	}

	// Override default --network-plugin?
	if o.KubernetesConfig.NetworkPlugin == NetworkPluginKubenet {
		if o.KubernetesConfig.NetworkPolicy != NetworkPolicyCalico {
			o.KubernetesConfig.KubeletConfig["--network-plugin"] = NetworkPluginKubenet
		}
	}

	// We don't support user-configurable values for the following,
	// so any of the value assignments below will override user-provided values
	var overrideKubeletConfig map[string]string
	if cs.Properties.HasWindows() {
		overrideKubeletConfig = staticWindowsKubeletConfig
	} else {
		overrideKubeletConfig = staticLinuxKubeletConfig
	}
	for key, val := range overrideKubeletConfig {
		o.KubernetesConfig.KubeletConfig[key] = val
	}

	// Get rid of values not supported in v1.5 clusters
	if !common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.6.0") {
		for _, key := range []string{"--non-masquerade-cidr", "--cgroups-per-qos", "--enforce-node-allocatable"} {
			delete(o.KubernetesConfig.KubeletConfig, key)
		}
	}

	// Get rid of values not supported in v1.10 clusters
	if !common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.10.0") {
		for _, key := range []string{"--pod-max-pids"} {
			delete(o.KubernetesConfig.KubeletConfig, key)
		}
	}

	// Get rid of values not supported in v1.12 and up
	if common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.12.0-alpha.1") {
		for _, key := range []string{"--cadvisor-port"} {
			delete(o.KubernetesConfig.KubeletConfig, key)
		}
	}

	// Remove secure kubelet flags, if configured
	if !helpers.IsTrueBoolPointer(o.KubernetesConfig.EnableSecureKubelet) {
		for _, key := range []string{"--anonymous-auth", "--client-ca-file"} {
			delete(o.KubernetesConfig.KubeletConfig, key)
		}
	}

	// Master-specific kubelet config changes go here
	if cs.Properties.MasterProfile != nil {
		if cs.Properties.MasterProfile.KubernetesConfig == nil {
			cs.Properties.MasterProfile.KubernetesConfig = &api.KubernetesConfig{}
			cs.Properties.MasterProfile.KubernetesConfig.KubeletConfig = copyMap(cs.Properties.MasterProfile.KubernetesConfig.KubeletConfig)
		}
		setMissingKubeletValues(cs.Properties.MasterProfile.KubernetesConfig, o.KubernetesConfig.KubeletConfig)
		addDefaultFeatureGates(cs.Properties.MasterProfile.KubernetesConfig.KubeletConfig, o.OrchestratorVersion, "", "")
	}

	// Agent-specific kubelet config changes go here
	for _, profile := range cs.Properties.AgentPoolProfiles {
		if profile.KubernetesConfig == nil {
			profile.KubernetesConfig = &api.KubernetesConfig{}
			profile.KubernetesConfig.KubeletConfig = copyMap(profile.KubernetesConfig.KubeletConfig)
		}
		setMissingKubeletValues(profile.KubernetesConfig, o.KubernetesConfig.KubeletConfig)

		// For N Series (GPU) VMs
		if strings.Contains(profile.VMSize, "Standard_N") {
			if !cs.Properties.IsNVIDIADevicePluginEnabled() && !common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.11.0") {
				// enabling accelerators for Kubernetes >= 1.6 to <= 1.9
				addDefaultFeatureGates(profile.KubernetesConfig.KubeletConfig, o.OrchestratorVersion, "1.6.0", "Accelerators=true")
			}
		}
	}
}

func setMissingKubeletValues(p *api.KubernetesConfig, d map[string]string) {
	if p.KubeletConfig == nil {
		p.KubeletConfig = d
	} else {
		for key, val := range d {
			// If we don't have a user-configurable value for each option
			if _, ok := p.KubeletConfig[key]; !ok {
				// then assign the default value
				p.KubeletConfig[key] = val
			}
		}
	}
}
func copyMap(input map[string]string) map[string]string {
	copy := map[string]string{}
	for key, value := range input {
		copy[key] = value
	}
	return copy
}
<commit_msg>Fixing #3246 - Windows kubelet configs shouldn't overwrite Linux configs in hybrid cluster (#3651)<commit_after>package acsengine

import (
	"strconv"
	"strings"

	"github.com/Azure/acs-engine/pkg/api"
	"github.com/Azure/acs-engine/pkg/api/common"
	"github.com/Azure/acs-engine/pkg/helpers"
)

func setKubeletConfig(cs *api.ContainerService) {
	o := cs.Properties.OrchestratorProfile
	cloudSpecConfig := getCloudSpecConfig(cs.Location)
	staticLinuxKubeletConfig := map[string]string{
		"--address":                     "0.0.0.0",
		"--allow-privileged":            "true",
		"--anonymous-auth":              "false",
		"--authorization-mode":          "Webhook",
		"--client-ca-file":              "/etc/kubernetes/certs/ca.crt",
		"--pod-manifest-path":           "/etc/kubernetes/manifests",
		"--cluster-dns":                 o.KubernetesConfig.DNSServiceIP,
		"--cgroups-per-qos":             "true",
		"--enforce-node-allocatable":    "pods",
		"--kubeconfig":                  "/var/lib/kubelet/kubeconfig",
		"--keep-terminated-pod-volumes": "false",
	}

	staticWindowsKubeletConfig := make(map[string]string)
	for key, val := range staticLinuxKubeletConfig {
		staticWindowsKubeletConfig[key] = val
	}
	staticWindowsKubeletConfig["--azure-container-registry-config"] = "c:\\k\\azure.json"
	staticWindowsKubeletConfig["--pod-infra-container-image"] = "kubletwin/pause"
	staticWindowsKubeletConfig["--kubeconfig"] = "c:\\k\\config"
	staticWindowsKubeletConfig["--cloud-config"] = "c:\\k\\azure.json"
	staticWindowsKubeletConfig["--cgroups-per-qos"] = "false"
	staticWindowsKubeletConfig["--enforce-node-allocatable"] = "\"\""

	// Default Kubelet config
	defaultKubeletConfig := map[string]string{
		"--cluster-domain":                  "cluster.local",
		"--network-plugin":                  "cni",
		"--pod-infra-container-image":       cloudSpecConfig.KubernetesSpecConfig.KubernetesImageBase + KubeConfigs[o.OrchestratorVersion]["pause"],
		"--max-pods":                        strconv.Itoa(DefaultKubernetesMaxPods),
		"--eviction-hard":                   DefaultKubernetesHardEvictionThreshold,
		"--node-status-update-frequency":    KubeConfigs[o.OrchestratorVersion]["nodestatusfreq"],
		"--image-gc-high-threshold":         strconv.Itoa(DefaultKubernetesGCHighThreshold),
		"--image-gc-low-threshold":          strconv.Itoa(DefaultKubernetesGCLowThreshold),
		"--non-masquerade-cidr":             o.KubernetesConfig.ClusterSubnet,
		"--cloud-provider":                  "azure",
		"--cloud-config":                    "/etc/kubernetes/azure.json",
		"--azure-container-registry-config": "/etc/kubernetes/azure.json",
		"--event-qps":                       DefaultKubeletEventQPS,
		"--cadvisor-port":                   DefaultKubeletCadvisorPort,
		"--pod-max-pids":                    strconv.Itoa(DefaultKubeletPodMaxPIDs),
		"--image-pull-progress-deadline":    "30m",
	}

	// Apply Azure CNI-specific --max-pods value
	if o.KubernetesConfig.NetworkPlugin == NetworkPluginAzure {
		defaultKubeletConfig["--max-pods"] = strconv.Itoa(DefaultKubernetesMaxPodsVNETIntegrated)
	}

	// If no user-configurable kubelet config values exists, use the defaults
	setMissingKubeletValues(o.KubernetesConfig, defaultKubeletConfig)
	addDefaultFeatureGates(o.KubernetesConfig.KubeletConfig, o.OrchestratorVersion, "", "")

	// Override default cloud-provider?
	if helpers.IsTrueBoolPointer(o.KubernetesConfig.UseCloudControllerManager) {
		staticLinuxKubeletConfig["--cloud-provider"] = "external"
	}

	// Override default --network-plugin?
	if o.KubernetesConfig.NetworkPlugin == NetworkPluginKubenet {
		if o.KubernetesConfig.NetworkPolicy != NetworkPolicyCalico {
			o.KubernetesConfig.KubeletConfig["--network-plugin"] = NetworkPluginKubenet
		}
	}

	// We don't support user-configurable values for the following,
	// so any of the value assignments below will override user-provided values
	for key, val := range staticLinuxKubeletConfig {
		o.KubernetesConfig.KubeletConfig[key] = val
	}

	// Get rid of values not supported in v1.5 clusters
	if !common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.6.0") {
		for _, key := range []string{"--non-masquerade-cidr", "--cgroups-per-qos", "--enforce-node-allocatable"} {
			delete(o.KubernetesConfig.KubeletConfig, key)
		}
	}

	// Get rid of values not supported in v1.10 clusters
	if !common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.10.0") {
		for _, key := range []string{"--pod-max-pids"} {
			delete(o.KubernetesConfig.KubeletConfig, key)
		}
	}

	// Get rid of values not supported in v1.12 and up
	if common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.12.0-alpha.1") {
		for _, key := range []string{"--cadvisor-port"} {
			delete(o.KubernetesConfig.KubeletConfig, key)
		}
	}

	// Remove secure kubelet flags, if configured
	if !helpers.IsTrueBoolPointer(o.KubernetesConfig.EnableSecureKubelet) {
		for _, key := range []string{"--anonymous-auth", "--client-ca-file"} {
			delete(o.KubernetesConfig.KubeletConfig, key)
		}
	}

	// Master-specific kubelet config changes go here
	if cs.Properties.MasterProfile != nil {
		if cs.Properties.MasterProfile.KubernetesConfig == nil {
			cs.Properties.MasterProfile.KubernetesConfig = &api.KubernetesConfig{}
			cs.Properties.MasterProfile.KubernetesConfig.KubeletConfig = copyMap(cs.Properties.MasterProfile.KubernetesConfig.KubeletConfig)
		}
		setMissingKubeletValues(cs.Properties.MasterProfile.KubernetesConfig, o.KubernetesConfig.KubeletConfig)
		addDefaultFeatureGates(cs.Properties.MasterProfile.KubernetesConfig.KubeletConfig, o.OrchestratorVersion, "", "")
	}

	// Agent-specific kubelet config changes go here
	for _, profile := range cs.Properties.AgentPoolProfiles {
		if profile.KubernetesConfig == nil {
			profile.KubernetesConfig = &api.KubernetesConfig{}
			profile.KubernetesConfig.KubeletConfig = copyMap(profile.KubernetesConfig.KubeletConfig)
			if profile.OSType == "Windows" {
				for key, val := range staticWindowsKubeletConfig {
					profile.KubernetesConfig.KubeletConfig[key] = val
				}
			}
		}
		setMissingKubeletValues(profile.KubernetesConfig, o.KubernetesConfig.KubeletConfig)

		// For N Series (GPU) VMs
		if strings.Contains(profile.VMSize, "Standard_N") {
			if !cs.Properties.IsNVIDIADevicePluginEnabled() && !common.IsKubernetesVersionGe(o.OrchestratorVersion, "1.11.0") {
				// enabling accelerators for Kubernetes >= 1.6 to <= 1.9
				addDefaultFeatureGates(profile.KubernetesConfig.KubeletConfig, o.OrchestratorVersion, "1.6.0", "Accelerators=true")
			}
		}
	}
}

func setMissingKubeletValues(p *api.KubernetesConfig, d map[string]string) {
	if p.KubeletConfig == nil {
		p.KubeletConfig = d
	} else {
		for key, val := range d {
			// If we don't have a user-configurable value for each option
			if _, ok := p.KubeletConfig[key]; !ok {
				// then assign the default value
				p.KubeletConfig[key] = val
			}
		}
	}
}
func copyMap(input map[string]string) map[string]string {
	copy := map[string]string{}
	for key, value := range input {
		copy[key] = value
	}
	return copy
}
<|endoftext|>


<commit_before>// Copyright 2017-2020 The Usacloud 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 cflag

type OutputParameter struct {
	OutputType string `cli:",short=o,aliases=out,category=output,desc=Output format: one of the following [table/json/yaml]"`
	Quiet      bool   `cli:",short=q,category=output,desc=Output IDs only"`
	Format     string `cli:",aliases=fmt,category=output,desc=Output format in Go templates"`
	FormatFile string `cli:",category=output,desc=Output format in Go templates(from file)"`
	Query      string `cli:",category=output,desc=JMESPath query"`
	QueryFile  string `cli:",category=output,desc=JMESPath query(from file)"`
}

func (p *OutputParameter) OutputTypeFlagValue() string {
	return p.OutputType
}

func (p *OutputParameter) QuietFlagValue() bool {
	return p.Quiet
}

func (p *OutputParameter) FormatFlagValue() string {
	return p.Format
}

func (p *OutputParameter) QueryFlagValue() string {
	return p.Query
}
<commit_msg>Validate --output-type<commit_after>// Copyright 2017-2020 The Usacloud 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 cflag

type OutputParameter struct {
	OutputType string `cli:",short=o,aliases=out,category=output,desc=Output format: one of the following [table/json/yaml]" validate:"omitempty,output_type"`
	Quiet      bool   `cli:",short=q,category=output,desc=Output IDs only"`
	Format     string `cli:",aliases=fmt,category=output,desc=Output format in Go templates"`
	FormatFile string `cli:",category=output,desc=Output format in Go templates(from file)"`
	Query      string `cli:",category=output,desc=JMESPath query"`
	QueryFile  string `cli:",category=output,desc=JMESPath query(from file)"`
}

func (p *OutputParameter) OutputTypeFlagValue() string {
	return p.OutputType
}

func (p *OutputParameter) QuietFlagValue() bool {
	return p.Quiet
}

func (p *OutputParameter) FormatFlagValue() string {
	return p.Format
}

func (p *OutputParameter) QueryFlagValue() string {
	return p.Query
}
<|endoftext|>