<commit_before>package QesyGo

import (
	"math/rand"
	"strconv"
	"time"
)

func Array_merge(arr ...[]string) []string {
	var retArr []string
	for _, n := range arr {
		for _, v := range n {
			retArr = append(retArr, v)
		}
	}
	return retArr
}

func Array_merge_int(arr ...[]int) []int {
	var retArr []int
	for _, n := range arr {
		for _, v := range n {
			retArr = append(retArr, v)
		}
	}
	return retArr
}

func InArray(Arr interface{}, str string) bool {
	strArr, ok := Arr.([]string)
	if ok {
		for _, v := range strArr {
			if v == str {
				return true
			}
		}
		return false
	}
	mapArr, ok := Arr.(map[string]string)
	if ok {
		for _, v := range mapArr {
			if v == str {
				return true
			}
		}
		return false
	}
	intArr, ok := Arr.([]int)
	if ok {
		for _, v := range intArr {
			if strconv.Itoa(v) == str {
				return true
			}
		}
		return false
	}
	return false

}

func Array_Rand(num int) []int {
	rand.Seed(time.Now().UnixNano())
	return rand.Perm(num)
}

func Array_Diff(Arr1 []int, Arr2 []int) []int {
	BigArr, SmallArr := Arr1, Arr2
	if len(Arr2) > len(Arr1) {
		BigArr = Arr2
		SmallArr = Arr1
	}
	TempArr := []int{}
	for _, v := range BigArr {
		if !InArray(SmallArr, strconv.Itoa(v)) {
			TempArr = append(TempArr, v)
		}
	}
	return TempArr
}

func Array_Diff_String(Arr1 []string, Arr2 []string) []string {
	BigArr, SmallArr := Arr1, Arr2
	if len(Arr2) > len(Arr1) {
		BigArr = Arr2
		SmallArr = Arr1
	}
	TempArr := []string{}
	for _, v := range BigArr {
		if !InArray(SmallArr, v) {
			TempArr = append(TempArr, v)
		}
	}
	return TempArr
}

func Array_Mixed(Arr1 []int, Arr2 []int) []int {
	BigArr, SmallArr := Arr1, Arr2
	if len(Arr2) > len(Arr1) {
		BigArr = Arr2
		SmallArr = Arr1
	}
	TempArr := []int{}
	for _, v := range BigArr {
		if InArray(SmallArr, strconv.Itoa(v)) {
			TempArr = append(TempArr, v)
		}
	}
	return TempArr
}
<commit_msg>fix inarray<commit_after>package QesyGo

import (
	"math/rand"
	"strconv"
	"time"
)

func Array_merge(arr ...[]string) []string {
	var retArr []string
	for _, n := range arr {
		for _, v := range n {
			retArr = append(retArr, v)
		}
	}
	return retArr
}

func Array_merge_int(arr ...[]int) []int {
	var retArr []int
	for _, n := range arr {
		for _, v := range n {
			retArr = append(retArr, v)
		}
	}
	return retArr
}

func InArray(Arr interface{}, str string) bool {
	if strArr, ok := Arr.([]string); ok {
		for _, v := range strArr {
			if v == str {
				return true
			}
		}
		return false
	}
	if mapArr, ok := Arr.(map[string]string); ok {
		for _, v := range mapArr {
			if v == str {
				return true
			}
		}
		return false
	}
	if intArr, ok := Arr.([]int); ok {
		for _, v := range intArr {
			if strconv.Itoa(v) == str {
				return true
			}
		}
		return false
	}
	if intArr, ok := Arr.([]int32); ok {
		for _, v := range intArr {
			if IntToStr(v) == str {
				return true
			}
		}
		return false
	}
	return false

}

func Array_Rand(num int) []int {
	rand.Seed(time.Now().UnixNano())
	return rand.Perm(num)
}

func Array_Diff(Arr1 []int, Arr2 []int) []int {
	BigArr, SmallArr := Arr1, Arr2
	if len(Arr2) > len(Arr1) {
		BigArr = Arr2
		SmallArr = Arr1
	}
	TempArr := []int{}
	for _, v := range BigArr {
		if !InArray(SmallArr, strconv.Itoa(v)) {
			TempArr = append(TempArr, v)
		}
	}
	return TempArr
}

func Array_Diff_String(Arr1 []string, Arr2 []string) []string {
	BigArr, SmallArr := Arr1, Arr2
	if len(Arr2) > len(Arr1) {
		BigArr = Arr2
		SmallArr = Arr1
	}
	TempArr := []string{}
	for _, v := range BigArr {
		if !InArray(SmallArr, v) {
			TempArr = append(TempArr, v)
		}
	}
	return TempArr
}

func Array_Mixed(Arr1 []int, Arr2 []int) []int {
	BigArr, SmallArr := Arr1, Arr2
	if len(Arr2) > len(Arr1) {
		BigArr = Arr2
		SmallArr = Arr1
	}
	TempArr := []int{}
	for _, v := range BigArr {
		if InArray(SmallArr, strconv.Itoa(v)) {
			TempArr = append(TempArr, v)
		}
	}
	return TempArr
}
<|endoftext|>


<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package lib

import (
	"context"
	"encoding/json"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/loadimpact/k6/stats"
	"github.com/loadimpact/k6/ui/pb"
	"github.com/sirupsen/logrus"
	null "gopkg.in/guregu/null.v3"
)

//TODO: remove globals and use some type of explicit dependency injection?
//nolint:gochecknoglobals
var (
	executorConfigTypesMutex   sync.RWMutex
	executorConfigConstructors = make(map[string]ExecutorConfigConstructor)
)

// ExecutionStep is used by different executors to specify the planned number of
// VUs they will need at a particular time. The times are relative to their
// StartTime, i.e. they don't take into account the specific starting time of
// the executor, as that will be considered by the external execution executor
// separately.
//
// A slice [{t1, v1}, {t2, v2}, {t3, v3}, ..., {tn, vn}] of execution steps
// means that an executor will need 0 VUs until t1, it will need v1 number of
// VUs from time t1 until t2, need v2 number of VUs from time t2 to t3, and so
// on. t1 is usually 0, tn is usually the same as GetMaxDuration() and vn is
// usually 0.
//
// Keep in mind that t(i) may be exactly equal to t(i+i), when there's an abrupt
// transition in the number of VUs required by an executor. For example, the
// variable-looping-vus executor may have 0-duration stages, or it may scale up
// VUs in its last stage right until the end. These immediate transitions cannot
// be ignored, since the gracefulStop/gracefulRampDown options potentially allow
// any started iterations to finish.
//
// []ExecutionStep is also used by the ExecutorConfigMap, to represent the
// amount of needed VUs among all executors, during the whole execution of a
// test script. In that context, each executor's StartTime is accounted for and
// included in the offsets.
type ExecutionStep struct {
	TimeOffset      time.Duration
	PlannedVUs      uint64
	MaxUnplannedVUs uint64
}

//TODO: make []ExecutionStep or []ExecutorConfig their own type?

// ExecutorConfig is an interface that should be implemented by all executor config types
type ExecutorConfig interface {
	Validate() []error

	GetName() string
	GetType() string
	GetStartTime() time.Duration
	GetGracefulStop() time.Duration

	// This is used to validate whether a particular script can run in the cloud
	// or, in the future, in the native k6 distributed execution. Currently only
	// the externally-controlled executor should return false.
	IsDistributable() bool

	GetEnv() map[string]string
	// Allows us to get the non-default function the executor should run, if it
	// has been specified.
	//
	// TODO: use interface{} so plain http requests can be specified?
	GetExec() null.String

	// Calculates the VU requirements in different stages of the executor's
	// execution, including any extensions caused by waiting for iterations to
	// finish with graceful stops or ramp-downs.
	GetExecutionRequirements(*ExecutionSegment) []ExecutionStep

	// Return a human-readable description of the executor
	GetDescription(es *ExecutionSegment) string

	NewExecutor(*ExecutionState, *logrus.Entry) (Executor, error)

	// HasWork reports whether there is any work for the executor to do with a given segment.
	HasWork(*ExecutionSegment) bool
}

// InitVUFunc is just a shorthand so we don't have to type the function
// signature every time.
type InitVUFunc func(context.Context, *logrus.Entry) (VU, error)

// Executor is the interface all executors should implement
type Executor interface {
	GetConfig() ExecutorConfig
	GetProgress() *pb.ProgressBar
	GetLogger() *logrus.Entry

	Init(ctx context.Context) error //TODO: remove, since it's currently unused?
	Run(ctx context.Context, engineOut chan<- stats.SampleContainer) error
}

// PausableExecutor should be implemented by the executors that can be paused
// and resumed in the middle of the test execution. Currently, only the
// externally controlled executor implements it.
type PausableExecutor interface {
	SetPaused(bool) error
}

// LiveUpdatableExecutor should be implemented for the executors whose
// configuration can be modified in the middle of the test execution. Currently,
// only the manual execution executor implements it.
type LiveUpdatableExecutor interface {
	UpdateConfig(ctx context.Context, newConfig interface{}) error
}

// ExecutorConfigConstructor is a simple function that returns a concrete
// Config instance with the specified name and all default values correctly
// initialized
type ExecutorConfigConstructor func(name string, rawJSON []byte) (ExecutorConfig, error)

// RegisterExecutorConfigType adds the supplied ExecutorConfigConstructor as
// the constructor for its type in the configConstructors map, in a thread-safe
// manner
func RegisterExecutorConfigType(configType string, constructor ExecutorConfigConstructor) {
	executorConfigTypesMutex.Lock()
	defer executorConfigTypesMutex.Unlock()

	if constructor == nil {
		panic("executor configs: constructor is nil")
	}
	if _, configTypeExists := executorConfigConstructors[configType]; configTypeExists {
		panic("executor configs: lib.RegisterExecutorConfigType called twice for  " + configType)
	}

	executorConfigConstructors[configType] = constructor
}

// ExecutorConfigMap can contain mixed executor config types
type ExecutorConfigMap map[string]ExecutorConfig

// UnmarshalJSON implements the json.Unmarshaler interface in a two-step manner,
// creating the correct type of configs based on the `type` property.
func (scs *ExecutorConfigMap) UnmarshalJSON(data []byte) error {
	if len(data) == 0 {
		return nil
	}

	if len(data) == 4 && string(data) == "null" {
		return nil
	}

	//TODO: use a more sophisticated combination of dec.Token() and dec.More(),
	// which would allow us to support both arrays and maps for this config?
	var protoConfigs map[string]protoExecutorConfig
	if err := StrictJSONUnmarshal(data, &protoConfigs); err != nil {
		return err
	}

	result := make(ExecutorConfigMap, len(protoConfigs))
	for k, v := range protoConfigs {
		if v.configType == "" {
			return fmt.Errorf("execution config '%s' doesn't have a type value", k)
		}
		config, err := GetParsedExecutorConfig(k, v.configType, v.rawJSON)
		if err != nil {
			return err
		}
		result[k] = config
	}

	*scs = result

	return nil
}

// Validate checks if all of the specified executor options make sense
func (scs ExecutorConfigMap) Validate() (errors []error) {
	for name, exec := range scs {
		if execErr := exec.Validate(); len(execErr) != 0 {
			errors = append(errors,
				fmt.Errorf("executor %s has errors: %s", name, ConcatErrors(execErr, ", ")))
		}
	}
	return errors
}

// GetSortedConfigs returns a slice with the executor configurations,
// sorted in a consistent and predictable manner. It is useful when we want or
// have to avoid using maps with string keys (and tons of string lookups in
// them) and avoid the unpredictable iterations over Go maps. Slices allow us
// constant-time lookups and ordered iterations.
//
// The configs in the returned slice will be sorted by their start times in an
// ascending order, and alphabetically by their names (which are unique) if
// there are ties.
func (scs ExecutorConfigMap) GetSortedConfigs() []ExecutorConfig {
	configs := make([]ExecutorConfig, len(scs))

	// Populate the configs slice with sorted executor configs
	i := 0
	for _, config := range scs {
		configs[i] = config // populate the slice in an unordered manner
		i++
	}
	sort.Slice(configs, func(a, b int) bool { // sort by (start time, name)
		switch {
		case configs[a].GetStartTime() < configs[b].GetStartTime():
			return true
		case configs[a].GetStartTime() == configs[b].GetStartTime():
			return strings.Compare(configs[a].GetName(), configs[b].GetName()) < 0
		default:
			return false
		}
	})

	return configs
}

// GetFullExecutionRequirements combines the execution requirements from all of
// the configured executors. It takes into account their start times and their
// individual VU requirements and calculates the total VU requirements for each
// moment in the test execution.
func (scs ExecutorConfigMap) GetFullExecutionRequirements(executionSegment *ExecutionSegment) []ExecutionStep {
	sortedConfigs := scs.GetSortedConfigs()

	// Combine the steps and requirements from all different executors, and
	// sort them by their time offset, counting the executors' startTimes as
	// well.
	type trackedStep struct {
		ExecutionStep
		configID int
	}
	trackedSteps := []trackedStep{}
	for configID, config := range sortedConfigs { // orderly iteration over a slice
		configStartTime := config.GetStartTime()
		configSteps := config.GetExecutionRequirements(executionSegment)
		for _, cs := range configSteps {
			cs.TimeOffset += configStartTime // add the executor start time to the step time offset
			trackedSteps = append(trackedSteps, trackedStep{cs, configID})
		}
	}
	// Sort by (time offset, config id). It's important that we use stable
	// sorting algorithm, since there could be steps with the same time from
	// the same executor and their order is important.
	sort.SliceStable(trackedSteps, func(a, b int) bool {
		switch {
		case trackedSteps[a].TimeOffset < trackedSteps[b].TimeOffset:
			return true
		case trackedSteps[a].TimeOffset == trackedSteps[b].TimeOffset:
			if trackedSteps[a].configID == trackedSteps[b].configID {
				return trackedSteps[a].PlannedVUs < trackedSteps[b].PlannedVUs
			}
			return trackedSteps[a].configID < trackedSteps[b].configID
		default:
			return false
		}
	})

	// Go through all of the sorted steps from all of the executors, and
	// build a new list of execution steps that consolidates all of their
	// requirements. If multiple executors have an execution step at exactly
	// the same time offset, they will be combined into a single new execution
	// step with the sum of the values from the previous ones.
	currentTimeOffset := time.Duration(0)
	currentPlannedVUs := make([]uint64, len(scs))
	currentMaxUnplannedVUs := make([]uint64, len(scs))
	sum := func(data []uint64) (result uint64) { // sigh...
		for _, val := range data {
			result += val
		}
		return result
	}
	consolidatedSteps := []ExecutionStep{}
	addCurrentStepIfDifferent := func() {
		newPlannedVUs := sum(currentPlannedVUs)
		newMaxUnplannedVUs := sum(currentMaxUnplannedVUs)
		stepsLen := len(consolidatedSteps)
		if stepsLen == 0 ||
			consolidatedSteps[stepsLen-1].PlannedVUs != newPlannedVUs ||
			consolidatedSteps[stepsLen-1].MaxUnplannedVUs != newMaxUnplannedVUs {
			consolidatedSteps = append(consolidatedSteps, ExecutionStep{
				TimeOffset:      currentTimeOffset,
				PlannedVUs:      newPlannedVUs,
				MaxUnplannedVUs: newMaxUnplannedVUs,
			})
		}
	}
	for _, step := range trackedSteps {
		// If the time offset is different, create a new step with the current values
		if step.TimeOffset != currentTimeOffset {
			addCurrentStepIfDifferent()
			currentTimeOffset = step.TimeOffset
		}
		currentPlannedVUs[step.configID] = step.PlannedVUs
		currentMaxUnplannedVUs[step.configID] = step.MaxUnplannedVUs
	}
	addCurrentStepIfDifferent() // Add the last step
	return consolidatedSteps
}

// GetParsedExecutorConfig returns a struct instance corresponding to the supplied
// config type. It will be fully initialized - with both the default values of
// the type, as well as with whatever the user had specified in the JSON
func GetParsedExecutorConfig(name, configType string, rawJSON []byte) (result ExecutorConfig, err error) {
	executorConfigTypesMutex.Lock()
	defer executorConfigTypesMutex.Unlock()

	constructor, exists := executorConfigConstructors[configType]
	if !exists {
		return nil, fmt.Errorf("unknown executor type '%s'", configType)
	}
	return constructor(name, rawJSON)
}

type protoExecutorConfig struct {
	configType string
	rawJSON    json.RawMessage
}

// UnmarshalJSON unmarshals the base config (to get the type), but it also
// stores the unprocessed JSON so we can parse the full config in the next step
func (pc *protoExecutorConfig) UnmarshalJSON(b []byte) error {
	var tmp struct {
		ConfigType string `json:"type"`
	}
	err := json.Unmarshal(b, &tmp)
	*pc = protoExecutorConfig{tmp.ConfigType, b}
	return err
}
<commit_msg>Don't skip steps in GetFullExecutionRequirements<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2019 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package lib

import (
	"context"
	"encoding/json"
	"fmt"
	"sort"
	"strings"
	"sync"
	"time"

	"github.com/loadimpact/k6/stats"
	"github.com/loadimpact/k6/ui/pb"
	"github.com/sirupsen/logrus"
	null "gopkg.in/guregu/null.v3"
)

//TODO: remove globals and use some type of explicit dependency injection?
//nolint:gochecknoglobals
var (
	executorConfigTypesMutex   sync.RWMutex
	executorConfigConstructors = make(map[string]ExecutorConfigConstructor)
)

// ExecutionStep is used by different executors to specify the planned number of
// VUs they will need at a particular time. The times are relative to their
// StartTime, i.e. they don't take into account the specific starting time of
// the executor, as that will be considered by the external execution executor
// separately.
//
// A slice [{t1, v1}, {t2, v2}, {t3, v3}, ..., {tn, vn}] of execution steps
// means that an executor will need 0 VUs until t1, it will need v1 number of
// VUs from time t1 until t2, need v2 number of VUs from time t2 to t3, and so
// on. t1 is usually 0, tn is usually the same as GetMaxDuration() and vn is
// usually 0.
//
// Keep in mind that t(i) may be exactly equal to t(i+i), when there's an abrupt
// transition in the number of VUs required by an executor. For example, the
// variable-looping-vus executor may have 0-duration stages, or it may scale up
// VUs in its last stage right until the end. These immediate transitions cannot
// be ignored, since the gracefulStop/gracefulRampDown options potentially allow
// any started iterations to finish.
//
// []ExecutionStep is also used by the ExecutorConfigMap, to represent the
// amount of needed VUs among all executors, during the whole execution of a
// test script. In that context, each executor's StartTime is accounted for and
// included in the offsets.
type ExecutionStep struct {
	TimeOffset      time.Duration
	PlannedVUs      uint64
	MaxUnplannedVUs uint64
}

//TODO: make []ExecutionStep or []ExecutorConfig their own type?

// ExecutorConfig is an interface that should be implemented by all executor config types
type ExecutorConfig interface {
	Validate() []error

	GetName() string
	GetType() string
	GetStartTime() time.Duration
	GetGracefulStop() time.Duration

	// This is used to validate whether a particular script can run in the cloud
	// or, in the future, in the native k6 distributed execution. Currently only
	// the externally-controlled executor should return false.
	IsDistributable() bool

	GetEnv() map[string]string
	// Allows us to get the non-default function the executor should run, if it
	// has been specified.
	//
	// TODO: use interface{} so plain http requests can be specified?
	GetExec() null.String

	// Calculates the VU requirements in different stages of the executor's
	// execution, including any extensions caused by waiting for iterations to
	// finish with graceful stops or ramp-downs.
	GetExecutionRequirements(*ExecutionSegment) []ExecutionStep

	// Return a human-readable description of the executor
	GetDescription(es *ExecutionSegment) string

	NewExecutor(*ExecutionState, *logrus.Entry) (Executor, error)

	// HasWork reports whether there is any work for the executor to do with a given segment.
	HasWork(*ExecutionSegment) bool
}

// InitVUFunc is just a shorthand so we don't have to type the function
// signature every time.
type InitVUFunc func(context.Context, *logrus.Entry) (VU, error)

// Executor is the interface all executors should implement
type Executor interface {
	GetConfig() ExecutorConfig
	GetProgress() *pb.ProgressBar
	GetLogger() *logrus.Entry

	Init(ctx context.Context) error //TODO: remove, since it's currently unused?
	Run(ctx context.Context, engineOut chan<- stats.SampleContainer) error
}

// PausableExecutor should be implemented by the executors that can be paused
// and resumed in the middle of the test execution. Currently, only the
// externally controlled executor implements it.
type PausableExecutor interface {
	SetPaused(bool) error
}

// LiveUpdatableExecutor should be implemented for the executors whose
// configuration can be modified in the middle of the test execution. Currently,
// only the manual execution executor implements it.
type LiveUpdatableExecutor interface {
	UpdateConfig(ctx context.Context, newConfig interface{}) error
}

// ExecutorConfigConstructor is a simple function that returns a concrete
// Config instance with the specified name and all default values correctly
// initialized
type ExecutorConfigConstructor func(name string, rawJSON []byte) (ExecutorConfig, error)

// RegisterExecutorConfigType adds the supplied ExecutorConfigConstructor as
// the constructor for its type in the configConstructors map, in a thread-safe
// manner
func RegisterExecutorConfigType(configType string, constructor ExecutorConfigConstructor) {
	executorConfigTypesMutex.Lock()
	defer executorConfigTypesMutex.Unlock()

	if constructor == nil {
		panic("executor configs: constructor is nil")
	}
	if _, configTypeExists := executorConfigConstructors[configType]; configTypeExists {
		panic("executor configs: lib.RegisterExecutorConfigType called twice for  " + configType)
	}

	executorConfigConstructors[configType] = constructor
}

// ExecutorConfigMap can contain mixed executor config types
type ExecutorConfigMap map[string]ExecutorConfig

// UnmarshalJSON implements the json.Unmarshaler interface in a two-step manner,
// creating the correct type of configs based on the `type` property.
func (scs *ExecutorConfigMap) UnmarshalJSON(data []byte) error {
	if len(data) == 0 {
		return nil
	}

	if len(data) == 4 && string(data) == "null" {
		return nil
	}

	//TODO: use a more sophisticated combination of dec.Token() and dec.More(),
	// which would allow us to support both arrays and maps for this config?
	var protoConfigs map[string]protoExecutorConfig
	if err := StrictJSONUnmarshal(data, &protoConfigs); err != nil {
		return err
	}

	result := make(ExecutorConfigMap, len(protoConfigs))
	for k, v := range protoConfigs {
		if v.configType == "" {
			return fmt.Errorf("execution config '%s' doesn't have a type value", k)
		}
		config, err := GetParsedExecutorConfig(k, v.configType, v.rawJSON)
		if err != nil {
			return err
		}
		result[k] = config
	}

	*scs = result

	return nil
}

// Validate checks if all of the specified executor options make sense
func (scs ExecutorConfigMap) Validate() (errors []error) {
	for name, exec := range scs {
		if execErr := exec.Validate(); len(execErr) != 0 {
			errors = append(errors,
				fmt.Errorf("executor %s has errors: %s", name, ConcatErrors(execErr, ", ")))
		}
	}
	return errors
}

// GetSortedConfigs returns a slice with the executor configurations,
// sorted in a consistent and predictable manner. It is useful when we want or
// have to avoid using maps with string keys (and tons of string lookups in
// them) and avoid the unpredictable iterations over Go maps. Slices allow us
// constant-time lookups and ordered iterations.
//
// The configs in the returned slice will be sorted by their start times in an
// ascending order, and alphabetically by their names (which are unique) if
// there are ties.
func (scs ExecutorConfigMap) GetSortedConfigs() []ExecutorConfig {
	configs := make([]ExecutorConfig, len(scs))

	// Populate the configs slice with sorted executor configs
	i := 0
	for _, config := range scs {
		configs[i] = config // populate the slice in an unordered manner
		i++
	}
	sort.Slice(configs, func(a, b int) bool { // sort by (start time, name)
		switch {
		case configs[a].GetStartTime() < configs[b].GetStartTime():
			return true
		case configs[a].GetStartTime() == configs[b].GetStartTime():
			return strings.Compare(configs[a].GetName(), configs[b].GetName()) < 0
		default:
			return false
		}
	})

	return configs
}

// GetFullExecutionRequirements combines the execution requirements from all of
// the configured executors. It takes into account their start times and their
// individual VU requirements and calculates the total VU requirements for each
// moment in the test execution.
func (scs ExecutorConfigMap) GetFullExecutionRequirements(executionSegment *ExecutionSegment) []ExecutionStep {
	sortedConfigs := scs.GetSortedConfigs()

	// Combine the steps and requirements from all different executors, and
	// sort them by their time offset, counting the executors' startTimes as
	// well.
	type trackedStep struct {
		ExecutionStep
		configID int
	}
	trackedSteps := []trackedStep{}
	for configID, config := range sortedConfigs { // orderly iteration over a slice
		configStartTime := config.GetStartTime()
		configSteps := config.GetExecutionRequirements(executionSegment)
		for _, cs := range configSteps {
			cs.TimeOffset += configStartTime // add the executor start time to the step time offset
			trackedSteps = append(trackedSteps, trackedStep{cs, configID})
		}
	}
	// Sort by (time offset, config id). It's important that we use stable
	// sorting algorithm, since there could be steps with the same time from
	// the same executor and their order is important.
	sort.SliceStable(trackedSteps, func(a, b int) bool {
		if trackedSteps[a].TimeOffset == trackedSteps[b].TimeOffset {
			return trackedSteps[a].configID < trackedSteps[b].configID
		}

		return trackedSteps[a].TimeOffset < trackedSteps[b].TimeOffset
	})

	// Go through all of the sorted steps from all of the executors, and
	// build a new list of execution steps that consolidates all of their
	// requirements. If multiple executors have an execution step at exactly
	// the same time offset, they will be combined into a single new execution
	// step with the sum of the values from the previous ones.
	currentTimeOffset := time.Duration(0)
	currentPlannedVUs := make([]uint64, len(scs))
	currentMaxUnplannedVUs := make([]uint64, len(scs))
	sum := func(data []uint64) (result uint64) { // sigh...
		for _, val := range data {
			result += val
		}
		return result
	}
	consolidatedSteps := []ExecutionStep{}
	addCurrentStepIfDifferent := func() {
		newPlannedVUs := sum(currentPlannedVUs)
		newMaxUnplannedVUs := sum(currentMaxUnplannedVUs)
		stepsLen := len(consolidatedSteps)
		if stepsLen == 0 ||
			consolidatedSteps[stepsLen-1].PlannedVUs != newPlannedVUs ||
			consolidatedSteps[stepsLen-1].MaxUnplannedVUs != newMaxUnplannedVUs {
			consolidatedSteps = append(consolidatedSteps, ExecutionStep{
				TimeOffset:      currentTimeOffset,
				PlannedVUs:      newPlannedVUs,
				MaxUnplannedVUs: newMaxUnplannedVUs,
			})
		}
	}
	for _, step := range trackedSteps {
		// TODO: optimize by skipping some steps
		// If the time offset is different, create a new step with the current values

		currentTimeOffset = step.TimeOffset
		currentPlannedVUs[step.configID] = step.PlannedVUs
		currentMaxUnplannedVUs[step.configID] = step.MaxUnplannedVUs
		addCurrentStepIfDifferent()
	}
	return consolidatedSteps
}

// GetParsedExecutorConfig returns a struct instance corresponding to the supplied
// config type. It will be fully initialized - with both the default values of
// the type, as well as with whatever the user had specified in the JSON
func GetParsedExecutorConfig(name, configType string, rawJSON []byte) (result ExecutorConfig, err error) {
	executorConfigTypesMutex.Lock()
	defer executorConfigTypesMutex.Unlock()

	constructor, exists := executorConfigConstructors[configType]
	if !exists {
		return nil, fmt.Errorf("unknown executor type '%s'", configType)
	}
	return constructor(name, rawJSON)
}

type protoExecutorConfig struct {
	configType string
	rawJSON    json.RawMessage
}

// UnmarshalJSON unmarshals the base config (to get the type), but it also
// stores the unprocessed JSON so we can parse the full config in the next step
func (pc *protoExecutorConfig) UnmarshalJSON(b []byte) error {
	var tmp struct {
		ConfigType string `json:"type"`
	}
	err := json.Unmarshal(b, &tmp)
	*pc = protoExecutorConfig{tmp.ConfigType, b}
	return err
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"github.com/caiofilipini/encurtador/url"
	"net/http"
	"os"
	"strings"
)

var (
	porta   string
	urlBase string
	ids     chan string
)

func init() {
	dominio := lerConfig("DOMINIO", "localhost")
	porta = lerConfig("PORTA", "8888")
	urlBase = fmt.Sprintf("http://%s:%s", dominio, porta)
}

type Headers map[string]string

func Encurtador(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		responderCom(w, http.StatusMethodNotAllowed, Headers{"Allow": "POST"})
		return
	}

	url, nova, err := url.BuscarOuCriarNovaUrl(extrairUrl(r))

	if err != nil {
		responderCom(w, http.StatusBadRequest, nil)
		return
	}

	var status int
	if nova {
		status = http.StatusCreated
	} else {
		status = http.StatusOK
	}

	responderCom(w, status, Headers{
		"Location": fmt.Sprintf("%s/r/%s", urlBase, url.Id),
		"Link":     fmt.Sprintf("<%s/api/stats/%s>; rel=\"stats\"", urlBase, url.Id),
	})
}

func Redirecionador(w http.ResponseWriter, r *http.Request) {
	buscarUrlEExecutar(w, r, func(url *url.Url) {
		http.Redirect(w, r, url.Destino, http.StatusMovedPermanently)
		ids <- url.Id
	})
}

func Visualizador(w http.ResponseWriter, r *http.Request) {
	buscarUrlEExecutar(w, r, func(url *url.Url) {
		json, err := json.Marshal(url.Stats())

		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		responderComJSON(w, string(json))
	})
}

func buscarUrlEExecutar(w http.ResponseWriter, r *http.Request, executor func(*url.Url)) {
	caminho := strings.Split(r.URL.Path, "/")
	id := caminho[len(caminho)-1]

	if url := url.Buscar(id); url != nil {
		executor(url)
	} else {
		http.NotFound(w, r)
	}
}

func responderCom(w http.ResponseWriter, status int, headers Headers) {
	for k, v := range headers {
		w.Header().Set(k, v)
	}
	w.WriteHeader(status)
}

func responderComJSON(w http.ResponseWriter, resposta string) {
	responderCom(w, http.StatusOK, Headers{"Content-Type": "application/json"})
	fmt.Fprintf(w, resposta)
}

func lerConfig(config string, valorPadrao string) string {
	if d := os.Getenv(config); d != "" {
		return d
	}
	return valorPadrao
}

func extrairUrl(r *http.Request) string {
	rawBody := make([]byte, r.ContentLength, r.ContentLength)
	r.Body.Read(rawBody)
	return string(rawBody)
}

func registrarEstatisticas(ids chan string) {
	for id := range ids {
		url.RegistrarClick(id)
		fmt.Printf("Click registrado com sucesso para %s.\n", id)
	}
}

func main() {
	ids = make(chan string)
	defer close(ids)
	go registrarEstatisticas(ids)

	http.HandleFunc("/r/", Redirecionador)
	http.HandleFunc("/api/encurtar", Encurtador)
	http.HandleFunc("/api/stats/", Visualizador)

	http.ListenAndServe(":"+porta, nil)
}
<commit_msg>Substituir canal global por contexto.<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"github.com/caiofilipini/encurtador/url"
	"net/http"
	"os"
	"strings"
)

var (
	porta   string
	urlBase string
)

func init() {
	dominio := lerConfig("DOMINIO", "localhost")
	porta = lerConfig("PORTA", "8888")
	urlBase = fmt.Sprintf("http://%s:%s", dominio, porta)
}

type Headers map[string]string

type Redirecionador struct {
	stats chan string
}

func (r *Redirecionador) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	buscarUrlEExecutar(w, req, func(url *url.Url) {
		http.Redirect(w, req, url.Destino, http.StatusMovedPermanently)
		r.stats <- url.Id
	})
}

func Encurtador(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		responderCom(w, http.StatusMethodNotAllowed, Headers{"Allow": "POST"})
		return
	}

	url, nova, err := url.BuscarOuCriarNovaUrl(extrairUrl(r))

	if err != nil {
		responderCom(w, http.StatusBadRequest, nil)
		return
	}

	var status int
	if nova {
		status = http.StatusCreated
	} else {
		status = http.StatusOK
	}

	responderCom(w, status, Headers{
		"Location": fmt.Sprintf("%s/r/%s", urlBase, url.Id),
		"Link":     fmt.Sprintf("<%s/api/stats/%s>; rel=\"stats\"", urlBase, url.Id),
	})
}

func Visualizador(w http.ResponseWriter, r *http.Request) {
	buscarUrlEExecutar(w, r, func(url *url.Url) {
		json, err := json.Marshal(url.Stats())

		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		responderComJSON(w, string(json))
	})
}

func buscarUrlEExecutar(w http.ResponseWriter, r *http.Request, executor func(*url.Url)) {
	caminho := strings.Split(r.URL.Path, "/")
	id := caminho[len(caminho)-1]

	if url := url.Buscar(id); url != nil {
		executor(url)
	} else {
		http.NotFound(w, r)
	}
}

func responderCom(w http.ResponseWriter, status int, headers Headers) {
	for k, v := range headers {
		w.Header().Set(k, v)
	}
	w.WriteHeader(status)
}

func responderComJSON(w http.ResponseWriter, resposta string) {
	responderCom(w, http.StatusOK, Headers{"Content-Type": "application/json"})
	fmt.Fprintf(w, resposta)
}

func lerConfig(config string, valorPadrao string) string {
	if d := os.Getenv(config); d != "" {
		return d
	}
	return valorPadrao
}

func extrairUrl(r *http.Request) string {
	rawBody := make([]byte, r.ContentLength, r.ContentLength)
	r.Body.Read(rawBody)
	return string(rawBody)
}

func registrarEstatisticas(ids chan string) {
	for id := range ids {
		url.RegistrarClick(id)
		fmt.Printf("Click registrado com sucesso para %s.\n", id)
	}
}

func main() {
	stats := make(chan string)
	defer close(stats)
	go registrarEstatisticas(stats)

	http.Handle("/r/", &Redirecionador{stats})
	http.HandleFunc("/api/encurtar", Encurtador)
	http.HandleFunc("/api/stats/", Visualizador)

	http.ListenAndServe(":"+porta, nil)
}
<|endoftext|>


<commit_before>package utils

import (
	"errors"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

func Fatal(err error) {
	log.Fatal(err)
}

func Check(err error) {
	if err != nil {
		log.Fatalf("fatal: %v", err)
	}
}

func ConcatPaths(paths ...string) string {
	return strings.Join(paths, "/")
}

func BrowserLauncher() ([]string, error) {
	browser := os.Getenv("BROWSER")
	if browser == "" {
		browser = searchBrowserLauncher(runtime.GOOS)
	}

	if browser == "" {
		return nil, errors.New("Please set $BROWSER to a web launcher")
	}

	return strings.Split(browser, " "), nil
}

func searchBrowserLauncher(goos string) (browser string) {
	switch goos {
	case "darwin":
		browser = "open"
	case "windows":
		browser = "cmd /c start"
	default:
		candidates := []string{"xdg-open", "cygstart", "x-www-browser", "firefox",
			"opera", "mozilla", "netscape"}
		for _, b := range candidates {
			path, err := exec.LookPath(b)
			if err == nil {
				browser = path
				break
			}
		}
	}

	return browser
}
<commit_msg>Fix utils<commit_after>package utils

import (
	"errors"
	"log"
	"os"
	"os/exec"
	"runtime"
	"strings"
)

func Fatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func Check(err error) {
	if err != nil {
		log.Fatalf("fatal: %v", err)
	}
}

func ConcatPaths(paths ...string) string {
	return strings.Join(paths, "/")
}

func BrowserLauncher() ([]string, error) {
	browser := os.Getenv("BROWSER")
	if browser == "" {
		browser = searchBrowserLauncher(runtime.GOOS)
	}

	if browser == "" {
		return nil, errors.New("Please set $BROWSER to a web launcher")
	}

	return strings.Split(browser, " "), nil
}

func searchBrowserLauncher(goos string) (browser string) {
	switch goos {
	case "darwin":
		browser = "open"
	case "windows":
		browser = "cmd /c start"
	default:
		candidates := []string{"xdg-open", "cygstart", "x-www-browser", "firefox",
			"opera", "mozilla", "netscape"}
		for _, b := range candidates {
			path, err := exec.LookPath(b)
			if err == nil {
				browser = path
				break
			}
		}
	}

	return browser
}
<|endoftext|>


<commit_before>// Package utils - 套件所需的公用工具
//
package utils

import (
	"regexp"
	"strconv"
	"time"
)

// ExchangeMap is simple to check tse or otc.
var ExchangeMap = map[string]bool{"tse": true, "otc": true}

// TaipeiTimeZone is for time.Data() setting.
var TaipeiTimeZone = time.FixedZone("Asia/Taipei", 8*3600)

// TWSE base url.
const (
	TWSEURL     string = "http://mis.tse.com.tw"
	TWSEHOST    string = "http://www.twse.com.tw"
	OTCHOST     string = "http://www.tpex.org.tw"
	OTCCSV      string = "/ch/stock/aftertrading/daily_trading_info/st43_download.php?d=%d/%02d&stkno=%s&r=%d" // year, mon, stock, rand
	TWSECSV     string = "/ch/trading/exchange/STOCK_DAY/STOCK_DAY_print.php?genpage=genpage/Report%d%02d/%d%02d_F3_1_8_%s.php&type=csv&r=%d"
	TWSELISTCSV string = "/ch/trading/exchange/MI_INDEX/MI_INDEX.php" // year, mon, day, type
	TWSEREAL    string = "/stock/api/getStockInfo.jsp?ex_ch=%s_%s.tw_%s&json=1&delay=0&_=%d"
)

// RandInt return random int.
func RandInt() int {
	return time.Now().Nanosecond()
}

//func RandInt() int64 {
//	result, _ := rand.Int(rand.Reader, big.NewInt(102400))
//	return result.Int64()
//}

//func RandInt() int64 {
//	r := rand.New(rand.NewSource(time.Now().UnixNano()))
//	return r.Int63n(100000)
//}

var dateReg = regexp.MustCompile(`([\d]{2,})/([\d]{1,2})/([\d]{1,2})`)

// ParseDate is to parse "104/01/13" format.
func ParseDate(strDate string) time.Time {
	p := dateReg.FindStringSubmatch(strDate)
	year, _ := strconv.Atoi(p[1])
	mon, _ := strconv.Atoi(p[2])
	day, _ := strconv.Atoi(p[3])
	return time.Date(year+1911, time.Month(mon), day, 0, 0, 0, 0, TaipeiTimeZone)
}

// SumFloat64 計算總和（float64）
func SumFloat64(data []float64) float64 {
	var result float64
	for _, v := range data {
		result += v
	}
	return result
}

// AvgFlast64 計算平均（float64）
func AvgFlast64(data []float64) float64 {
	return float64(int(SumFloat64(data)*100)/len(data)) / 100
}

// SumUint64 計算總和（uint64）
func SumUint64(data []uint64) uint64 {
	var result uint64
	for _, v := range data {
		result += v
	}
	return result
}

// AvgUint64 計算平均（uint64）
func AvgUint64(data []uint64) uint64 {
	return SumUint64(data) / uint64(len(data))
}

// ThanPastUint64 計算最後一個數值是否為過去幾天最大或最小（uint64）
func ThanPastUint64(data []uint64, days int, max bool) bool {
	var dataFloat64 = make([]float64, days+1)
	for i, v := range data[len(data)-1-days:] {
		dataFloat64[i] = float64(v)
	}
	return thanPast(dataFloat64, max)
}

// ThanPastFloat64 計算最後一個數值是否為過去幾天最大或最小（float64）
func ThanPastFloat64(data []float64, days int, max bool) bool {
	return thanPast(data[len(data)-1-days:], max)
}

func thanPast(data []float64, max bool) bool {
	//var dataFloat64 []float64
	//dataFloat64 = make([]float64, days+1)
	//for i, v := range data[len(data)-1-days : len(data)-1] {
	//	switch v.(type) {
	//	case int64:
	//		dataFloat64[i] = float64(v.(int64))
	//	case float64:
	//		dataFloat64[i] = v.(float64)
	//	}
	//}

	var base = data[len(data)-1]
	var condition func(b float64) bool

	if max {
		condition = func(b float64) bool { return base > b }
	} else {
		condition = func(b float64) bool { return base < b }
	}

	for _, v := range data[:len(data)-1] {
		if condition(v) {
			continue
		} else {
			return false
		}
	}
	return true
}

// ThanSumPastFloat64 計算最後一個數值是否為過去幾天的總和大或小（float64）
func ThanSumPastFloat64(data []float64, days int, max bool) bool {
	return thanSumPast(data[len(data)-1-days:], max)
}

func thanSumPast(data []float64, max bool) bool {
	var result = data[len(data)-1] > SumFloat64(data[:len(data)-1])
	if max {
		return result
	}
	return !result
}
<commit_msg>Add `ThanSumPastUint64`.<commit_after>// Package utils - 套件所需的公用工具
//
package utils

import (
	"regexp"
	"strconv"
	"time"
)

// ExchangeMap is simple to check tse or otc.
var ExchangeMap = map[string]bool{"tse": true, "otc": true}

// TaipeiTimeZone is for time.Data() setting.
var TaipeiTimeZone = time.FixedZone("Asia/Taipei", 8*3600)

// TWSE base url.
const (
	TWSEURL     string = "http://mis.tse.com.tw"
	TWSEHOST    string = "http://www.twse.com.tw"
	OTCHOST     string = "http://www.tpex.org.tw"
	OTCCSV      string = "/ch/stock/aftertrading/daily_trading_info/st43_download.php?d=%d/%02d&stkno=%s&r=%d" // year, mon, stock, rand
	TWSECSV     string = "/ch/trading/exchange/STOCK_DAY/STOCK_DAY_print.php?genpage=genpage/Report%d%02d/%d%02d_F3_1_8_%s.php&type=csv&r=%d"
	TWSELISTCSV string = "/ch/trading/exchange/MI_INDEX/MI_INDEX.php" // year, mon, day, type
	TWSEREAL    string = "/stock/api/getStockInfo.jsp?ex_ch=%s_%s.tw_%s&json=1&delay=0&_=%d"
)

// RandInt return random int.
func RandInt() int {
	return time.Now().Nanosecond()
}

//func RandInt() int64 {
//	result, _ := rand.Int(rand.Reader, big.NewInt(102400))
//	return result.Int64()
//}

//func RandInt() int64 {
//	r := rand.New(rand.NewSource(time.Now().UnixNano()))
//	return r.Int63n(100000)
//}

var dateReg = regexp.MustCompile(`([\d]{2,})/([\d]{1,2})/([\d]{1,2})`)

// ParseDate is to parse "104/01/13" format.
func ParseDate(strDate string) time.Time {
	p := dateReg.FindStringSubmatch(strDate)
	year, _ := strconv.Atoi(p[1])
	mon, _ := strconv.Atoi(p[2])
	day, _ := strconv.Atoi(p[3])
	return time.Date(year+1911, time.Month(mon), day, 0, 0, 0, 0, TaipeiTimeZone)
}

// SumFloat64 計算總和（float64）
func SumFloat64(data []float64) float64 {
	var result float64
	for _, v := range data {
		result += v
	}
	return result
}

// AvgFlast64 計算平均（float64）
func AvgFlast64(data []float64) float64 {
	return float64(int(SumFloat64(data)*100)/len(data)) / 100
}

// SumUint64 計算總和（uint64）
func SumUint64(data []uint64) uint64 {
	var result uint64
	for _, v := range data {
		result += v
	}
	return result
}

// AvgUint64 計算平均（uint64）
func AvgUint64(data []uint64) uint64 {
	return SumUint64(data) / uint64(len(data))
}

// ThanPastUint64 計算最後一個數值是否為過去幾天最大或最小（uint64）
func ThanPastUint64(data []uint64, days int, max bool) bool {
	var dataFloat64 = make([]float64, days+1)
	for i, v := range data[len(data)-1-days:] {
		dataFloat64[i] = float64(v)
	}
	return thanPast(dataFloat64, max)
}

// ThanPastFloat64 計算最後一個數值是否為過去幾天最大或最小（float64）
func ThanPastFloat64(data []float64, days int, max bool) bool {
	return thanPast(data[len(data)-1-days:], max)
}

func thanPast(data []float64, max bool) bool {
	//var dataFloat64 []float64
	//dataFloat64 = make([]float64, days+1)
	//for i, v := range data[len(data)-1-days : len(data)-1] {
	//	switch v.(type) {
	//	case int64:
	//		dataFloat64[i] = float64(v.(int64))
	//	case float64:
	//		dataFloat64[i] = v.(float64)
	//	}
	//}

	var base = data[len(data)-1]
	var condition func(b float64) bool

	if max {
		condition = func(b float64) bool { return base > b }
	} else {
		condition = func(b float64) bool { return base < b }
	}

	for _, v := range data[:len(data)-1] {
		if condition(v) {
			continue
		} else {
			return false
		}
	}
	return true
}

// ThanSumPastFloat64 計算最後一個數值是否為過去幾天的總和大或小（float64）
func ThanSumPastFloat64(data []float64, days int, max bool) bool {
	return thanSumPast(data[len(data)-1-days:], max)
}

// ThanSumPastUint64 計算最後一個數值是否為過去幾天的總和大或小（uint64）
func ThanSumPastUint64(data []uint64, days int, max bool) bool {
	var dataFloat64 = make([]float64, days+1)
	for i, v := range data[len(data)-1-days:] {
		dataFloat64[i] = float64(v)
	}
	return thanSumPast(dataFloat64, max)
}

func thanSumPast(data []float64, max bool) bool {
	var result = data[len(data)-1] > SumFloat64(data[:len(data)-1])
	if max {
		return result
	}
	return !result
}
<|endoftext|>


<commit_before>// Package upgrade fetches the latest Apex binary, if any, for the current platform.
package upgrade

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"github.com/apex/log"
	"github.com/google/go-github/github"
)

// Upgrade the current `version` of apex to the latest.
func Upgrade(version string) error {
	log.Infof("current release is v%s", version)

	// fetch releases
	gh := github.NewClient(nil)
	releases, _, err := gh.Repositories.ListReleases("apex", "apex", nil)
	if err != nil {
		return err
	}

	// see if it's new
	latest := releases[0]
	log.Infof("latest release is %s", *latest.TagName)

	if (*latest.TagName)[1:] == version {
		log.Infof("you're up to date :)")
		return nil
	}

	asset := findAsset(latest)
	if asset == nil {
		return errors.New("cannot find binary for your system")
	}

	// create tmp file
	tmpPath := filepath.Join(os.TempDir(), "apex-upgrade")
	f, err := os.OpenFile(tmpPath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0755)
	if err != nil {
		return err
	}

	// download binary
	log.Infof("downloading %s", *asset.BrowserDownloadURL)
	res, err := http.Get(*asset.BrowserDownloadURL)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	// copy it down
	_, err = io.Copy(f, res.Body)
	if err != nil {
		return err
	}

	// replace it
	cmdPath, err := exec.LookPath("apex")
	if err != nil {
		return err
	}

	log.Infof("replacing %s", cmdPath)
	err = os.Rename(tmpPath, cmdPath)
	if err != nil {
		return err
	}

	log.Infof("visit https://github.com/apex/apex/releases for the changelog")
	return nil
}

// findAsset returns the binary for this platform.
func findAsset(release *github.RepositoryRelease) *github.ReleaseAsset {
	for _, asset := range release.Assets {
		if *asset.Name == fmt.Sprintf("apex_%s_%s", runtime.GOOS, runtime.GOARCH) {
			return &asset
		}
	}
	return nil
}
<commit_msg>Use executable's path as the temp path (#488)<commit_after>// Package upgrade fetches the latest Apex binary, if any, for the current platform.
package upgrade

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"

	"github.com/apex/log"
	"github.com/google/go-github/github"
)

// Upgrade the current `version` of apex to the latest.
func Upgrade(version string) error {
	log.Infof("current release is v%s", version)

	// fetch releases
	gh := github.NewClient(nil)
	releases, _, err := gh.Repositories.ListReleases("apex", "apex", nil)
	if err != nil {
		return err
	}

	// see if it's new
	latest := releases[0]
	log.Infof("latest release is %s", *latest.TagName)

	if (*latest.TagName)[1:] == version {
		log.Infof("you're up to date :)")
		return nil
	}

	asset := findAsset(latest)
	if asset == nil {
		return errors.New("cannot find binary for your system")
	}

	// get the executable's path
	cmdPath, err := exec.LookPath("apex")
	if err != nil {
		return err
	}
	cmdDir := filepath.Dir(cmdPath)

	// create tmp file
	tmpPath := filepath.Join(cmdDir, "apex-upgrade")
	f, err := os.OpenFile(tmpPath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0755)
	if err != nil {
		return err
	}

	// download binary
	log.Infof("downloading %s", *asset.BrowserDownloadURL)
	res, err := http.Get(*asset.BrowserDownloadURL)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	// copy it down
	_, err = io.Copy(f, res.Body)
	if err != nil {
		return err
	}

	// replace it
	log.Infof("replacing %s", cmdPath)
	err = os.Rename(tmpPath, cmdPath)
	if err != nil {
		return err
	}

	log.Infof("visit https://github.com/apex/apex/releases for the changelog")
	return nil
}

// findAsset returns the binary for this platform.
func findAsset(release *github.RepositoryRelease) *github.ReleaseAsset {
	for _, asset := range release.Assets {
		if *asset.Name == fmt.Sprintf("apex_%s_%s", runtime.GOOS, runtime.GOARCH) {
			return &asset
		}
	}
	return nil
}
<|endoftext|>


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

package upstart

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"regexp"
	"text/template"
	"time"

	"github.com/juju/utils"
)

var startedRE = regexp.MustCompile(`^.* start/running, process (\d+)\n$`)

// InitDir holds the default init directory name.
var InitDir = "/etc/init"

var InstallStartRetryAttempts = utils.AttemptStrategy{
	Total: 1 * time.Second,
	Delay: 250 * time.Millisecond,
}

// Service provides visibility into and control over an upstart service.
type Service struct {
	Name    string
	InitDir string // defaults to "/etc/init"
}

func NewService(name string) *Service {
	return &Service{Name: name, InitDir: InitDir}
}

// confPath returns the path to the service's configuration file.
func (s *Service) confPath() string {
	return path.Join(s.InitDir, s.Name+".conf")
}

// Installed returns whether the service configuration exists in the
// init directory.
func (s *Service) Installed() bool {
	_, err := os.Stat(s.confPath())
	return err == nil
}

// Running returns true if the Service appears to be running.
func (s *Service) Running() bool {
	cmd := exec.Command("status", "--system", s.Name)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return false
	}
	return startedRE.Match(out)
}

// Start starts the service.
func (s *Service) Start() error {
	if s.Running() {
		return nil
	}
	err := runCommand("start", "--system", s.Name)
	if err != nil {
		// Double check to see if we were started before our command ran.
		if s.Running() {
			return nil
		}
	}
	return err
}

func runCommand(args ...string) error {
	out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
	if err == nil {
		return nil
	}
	out = bytes.TrimSpace(out)
	if len(out) > 0 {
		return fmt.Errorf("exec %q: %v (%s)", args, err, out)
	}
	return fmt.Errorf("exec %q: %v", args, err)
}

// Stop stops the service.
func (s *Service) Stop() error {
	if !s.Running() {
		return nil
	}
	return runCommand("stop", "--system", s.Name)
}

// StopAndRemove stops the service and then deletes the service
// configuration from the init directory.
func (s *Service) StopAndRemove() error {
	if !s.Installed() {
		return nil
	}
	if err := s.Stop(); err != nil {
		return err
	}
	return os.Remove(s.confPath())
}

// Remove deletes the service configuration from the init directory.
func (s *Service) Remove() error {
	if !s.Installed() {
		return nil
	}
	return os.Remove(s.confPath())
}

// BUG: %q quoting does not necessarily match libnih quoting rules
// (as used by upstart); this may become an issue in the future.
var confT = template.Must(template.New("").Parse(`
description "{{.Desc}}"
author "Juju Team <juju@lists.ubuntu.com>"
start on runlevel [2345]
stop on runlevel [!2345]
respawn
normal exit 0
{{range $k, $v := .Env}}env {{$k}}={{$v|printf "%q"}}
{{end}}
{{range $k, $v := .Limit}}limit {{$k}} {{$v}}
{{end}}
{{if .Out}}
# Ensure log files are properly protected
exec touch {{.Out}} && chmod 0600 {{.Out}}
{{end}}
exec {{.Cmd}}{{if .Out}} >> {{.Out}} 2>&1{{end}}
`[1:]))

// Conf is responsible for defining and installing upstart services. Its fields
// represent elements of an upstart service configuration file.
type Conf struct {
	Service
	// Desc is the upstart service's description.
	Desc string
	// Env holds the environment variables that will be set when the command runs.
	Env map[string]string
	// Limit holds the ulimit values that will be set when the command runs.
	Limit map[string]string
	// Cmd is the command (with arguments) that will be run.
	// The command will be restarted if it exits with a non-zero exit code.
	Cmd string
	// Out, if set, will redirect output to that path.
	Out string
}

// validate returns an error if the service is not adequately defined.
func (c *Conf) validate() error {
	if c.Name == "" {
		return errors.New("missing Name")
	}
	if c.InitDir == "" {
		return errors.New("missing InitDir")
	}
	if c.Desc == "" {
		return errors.New("missing Desc")
	}
	if c.Cmd == "" {
		return errors.New("missing Cmd")
	}
	return nil
}

// render returns the upstart configuration for the service as a slice of bytes.
func (c *Conf) render() ([]byte, error) {
	if err := c.validate(); err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	if err := confT.Execute(&buf, c); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// Install installs and starts the service.
func (c *Conf) Install() error {
	conf, err := c.render()
	if err != nil {
		return err
	}

	exists, err := c.removeOld(conf)
	if err != nil {
		return err
	}
	if !exists {
		if err := ioutil.WriteFile(c.confPath(), conf, 0644); err != nil {
			return err
		}
	}

	// On slower disks, upstart may take a short time to realise
	// that there is a service there.
	for attempt := InstallStartRetryAttempts.Start(); attempt.Next(); {
		if err = c.Start(); err == nil {
			break
		}
	}
	return err
}

func (c *Conf) removeOld(expected []byte) (exists bool, err error) {
	current, err := ioutil.ReadFile(c.confPath())
	if os.IsNotExist(err) {
		// no existing config
		return false, nil
	}
	if err != nil {
		return false, fmt.Errorf("upstart: could not read existing service config: %v", err)
	}

	// if we have a current config on disk, check to see if it's different
	if bytes.Equal(current, expected) {
		return true, nil
	}
	if err := c.StopAndRemove(); err != nil {
		return false, fmt.Errorf("upstart: could not remove installed service: %s", err)
	}
	return false, nil
}

// InstallCommands returns shell commands to install and start the service.
func (c *Conf) InstallCommands() ([]string, error) {
	conf, err := c.render()
	if err != nil {
		return nil, err
	}
	return []string{
		fmt.Sprintf("cat >> %s << 'EOF'\n%sEOF\n", c.confPath(), conf),
		"start " + c.Name,
	}, nil
}
<commit_msg>Modified Upstart config to grant correct permissions to agent logs.<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package upstart

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"regexp"
	"text/template"
	"time"

	"github.com/juju/utils"
)

var startedRE = regexp.MustCompile(`^.* start/running, process (\d+)\n$`)

// InitDir holds the default init directory name.
var InitDir = "/etc/init"

var InstallStartRetryAttempts = utils.AttemptStrategy{
	Total: 1 * time.Second,
	Delay: 250 * time.Millisecond,
}

// Service provides visibility into and control over an upstart service.
type Service struct {
	Name    string
	InitDir string // defaults to "/etc/init"
}

func NewService(name string) *Service {
	return &Service{Name: name, InitDir: InitDir}
}

// confPath returns the path to the service's configuration file.
func (s *Service) confPath() string {
	return path.Join(s.InitDir, s.Name+".conf")
}

// Installed returns whether the service configuration exists in the
// init directory.
func (s *Service) Installed() bool {
	_, err := os.Stat(s.confPath())
	return err == nil
}

// Running returns true if the Service appears to be running.
func (s *Service) Running() bool {
	cmd := exec.Command("status", "--system", s.Name)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return false
	}
	return startedRE.Match(out)
}

// Start starts the service.
func (s *Service) Start() error {
	if s.Running() {
		return nil
	}
	err := runCommand("start", "--system", s.Name)
	if err != nil {
		// Double check to see if we were started before our command ran.
		if s.Running() {
			return nil
		}
	}
	return err
}

func runCommand(args ...string) error {
	out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
	if err == nil {
		return nil
	}
	out = bytes.TrimSpace(out)
	if len(out) > 0 {
		return fmt.Errorf("exec %q: %v (%s)", args, err, out)
	}
	return fmt.Errorf("exec %q: %v", args, err)
}

// Stop stops the service.
func (s *Service) Stop() error {
	if !s.Running() {
		return nil
	}
	return runCommand("stop", "--system", s.Name)
}

// StopAndRemove stops the service and then deletes the service
// configuration from the init directory.
func (s *Service) StopAndRemove() error {
	if !s.Installed() {
		return nil
	}
	if err := s.Stop(); err != nil {
		return err
	}
	return os.Remove(s.confPath())
}

// Remove deletes the service configuration from the init directory.
func (s *Service) Remove() error {
	if !s.Installed() {
		return nil
	}
	return os.Remove(s.confPath())
}

// BUG: %q quoting does not necessarily match libnih quoting rules
// (as used by upstart); this may become an issue in the future.
var confT = template.Must(template.New("").Parse(`
description "{{.Desc}}"
author "Juju Team <juju@lists.ubuntu.com>"
start on runlevel [2345]
stop on runlevel [!2345]
respawn
normal exit 0
{{range $k, $v := .Env}}env {{$k}}={{$v|printf "%q"}}
{{end}}
{{range $k, $v := .Limit}}limit {{$k}} {{$v}}
{{end}}
script
{{if .Out}}
  # Ensure log files are properly protected
  touch {{.Out}}
  chmod 0600 {{.Out}}
{{end}}
  exec {{.Cmd}}{{if .Out}} >> {{.Out}} 2>&1{{end}}
end script
`[1:]))

// Conf is responsible for defining and installing upstart services. Its fields
// represent elements of an upstart service configuration file.
type Conf struct {
	Service
	// Desc is the upstart service's description.
	Desc string
	// Env holds the environment variables that will be set when the command runs.
	Env map[string]string
	// Limit holds the ulimit values that will be set when the command runs.
	Limit map[string]string
	// Cmd is the command (with arguments) that will be run.
	// The command will be restarted if it exits with a non-zero exit code.
	Cmd string
	// Out, if set, will redirect output to that path.
	Out string
}

// validate returns an error if the service is not adequately defined.
func (c *Conf) validate() error {
	if c.Name == "" {
		return errors.New("missing Name")
	}
	if c.InitDir == "" {
		return errors.New("missing InitDir")
	}
	if c.Desc == "" {
		return errors.New("missing Desc")
	}
	if c.Cmd == "" {
		return errors.New("missing Cmd")
	}
	return nil
}

// render returns the upstart configuration for the service as a slice of bytes.
func (c *Conf) render() ([]byte, error) {
	if err := c.validate(); err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	if err := confT.Execute(&buf, c); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}

// Install installs and starts the service.
func (c *Conf) Install() error {
	conf, err := c.render()
	if err != nil {
		return err
	}

	exists, err := c.removeOld(conf)
	if err != nil {
		return err
	}
	if !exists {
		if err := ioutil.WriteFile(c.confPath(), conf, 0644); err != nil {
			return err
		}
	}

	// On slower disks, upstart may take a short time to realise
	// that there is a service there.
	for attempt := InstallStartRetryAttempts.Start(); attempt.Next(); {
		if err = c.Start(); err == nil {
			break
		}
	}
	return err
}

func (c *Conf) removeOld(expected []byte) (exists bool, err error) {
	current, err := ioutil.ReadFile(c.confPath())
	if os.IsNotExist(err) {
		// no existing config
		return false, nil
	}
	if err != nil {
		return false, fmt.Errorf("upstart: could not read existing service config: %v", err)
	}

	// if we have a current config on disk, check to see if it's different
	if bytes.Equal(current, expected) {
		return true, nil
	}
	if err := c.StopAndRemove(); err != nil {
		return false, fmt.Errorf("upstart: could not remove installed service: %s", err)
	}
	return false, nil
}

// InstallCommands returns shell commands to install and start the service.
func (c *Conf) InstallCommands() ([]string, error) {
	conf, err := c.render()
	if err != nil {
		return nil, err
	}
	return []string{
		fmt.Sprintf("cat >> %s << 'EOF'\n%sEOF\n", c.confPath(), conf),
		"start " + c.Name,
	}, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/cloudfoundry-incubator/guardian/guardiancmd"
	"github.com/concourse/atc"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/concourse/baggageclaim/fs"
	"github.com/concourse/bin/bindata"
	"github.com/jessevdk/go-flags"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
)

const btrfsFSType = 0x9123683e

type GardenBackend guardiancmd.GuardianCommand

func (cmd WorkerCommand) lessenRequirements(command *flags.Command) {
	command.FindOptionByLongName("garden-depot").Required = false
	command.FindOptionByLongName("garden-graph").Required = false
	command.FindOptionByLongName("garden-runc-bin").Required = false
	command.FindOptionByLongName("garden-dadoo-bin").Required = false
	command.FindOptionByLongName("garden-init-bin").Required = false
	command.FindOptionByLongName("garden-iodaemon-bin").Required = false
	command.FindOptionByLongName("garden-kawasaki-bin").Required = false
	command.FindOptionByLongName("garden-nstar-bin").Required = false
	command.FindOptionByLongName("garden-tar-bin").Required = false
}

func (cmd *WorkerCommand) gardenRunner(logger lager.Logger, args []string) (atc.Worker, ifrit.Runner, error) {
	err := cmd.checkRoot()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	err = bindata.RestoreAssets(cmd.WorkDir, "linux")
	if err != nil {
		return atc.Worker{}, nil, err
	}

	linux := filepath.Join(cmd.WorkDir, "linux")

	btrfsToolsDir := filepath.Join(linux, "btrfs")
	iptablesDir := filepath.Join(linux, "iptables")

	err = os.Setenv(
		"PATH",
		strings.Join(
			[]string{
				btrfsToolsDir,
				filepath.Join(iptablesDir, "sbin"),
				filepath.Join(iptablesDir, "bin"),
				os.Getenv("PATH"),
			},
			string(os.PathListSeparator),
		),
	)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	busyboxDir, err := cmd.extractBusybox(linux)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	depotDir := filepath.Join(linux, "depot")

	// must be readable by other users so unprivileged containers can run their
	// own `initc' process
	err = os.MkdirAll(depotDir, 0755)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	cmd.Garden.Server.BindIP = guardiancmd.IPFlag(cmd.BindIP)

	cmd.Garden.Containers.Dir = guardiancmd.DirFlag(depotDir)
	cmd.Garden.Containers.DefaultRootFSDir = guardiancmd.DirFlag(busyboxDir)

	cmd.Garden.Bin.Runc = filepath.Join(linux, "bin", "runc")
	cmd.Garden.Bin.Dadoo = guardiancmd.FileFlag(filepath.Join(linux, "bin", "dadoo"))
	cmd.Garden.Bin.Init = guardiancmd.FileFlag(filepath.Join(linux, "bin", "init"))
	cmd.Garden.Bin.IODaemon = guardiancmd.FileFlag(filepath.Join(linux, "bin", "iodaemon"))
	cmd.Garden.Bin.Kawasaki = guardiancmd.FileFlag(filepath.Join(linux, "bin", "kawasaki"))
	cmd.Garden.Bin.NSTar = guardiancmd.FileFlag(filepath.Join(linux, "bin", "nstar"))
	cmd.Garden.Bin.Tar = guardiancmd.FileFlag(filepath.Join(linux, "bin", "tar"))

	cmd.Garden.Network.AllowHostAccess = true

	worker := atc.Worker{
		Platform: "linux",
		Tags:     cmd.Tags,

		HTTPProxyURL:  cmd.HTTPProxy.String(),
		HTTPSProxyURL: cmd.HTTPSProxy.String(),
		NoProxy:       strings.Join(cmd.NoProxy, ","),
	}

	worker.ResourceTypes, err = cmd.extractResources(linux)

	worker.Name, err = cmd.workerName()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	runner := guardiancmd.GuardianCommand(cmd.Garden)
	return worker, &runner, nil
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger) (ifrit.Runner, error) {
	volumesImage := filepath.Join(cmd.WorkDir, "volumes.img")
	volumesDir := filepath.Join(cmd.WorkDir, "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	var fsStat syscall.Statfs_t
	err = syscall.Statfs(volumesDir, &fsStat)
	if err != nil {
		return nil, fmt.Errorf("failed to stat volumes filesystem: %s", err)
	}

	if fsStat.Type != btrfsFSType {
		filesystem := fs.New(logger.Session("fs"), volumesImage, volumesDir)

		err = filesystem.Create(fsStat.Blocks * uint64(fsStat.Bsize))
		if err != nil {
			logger.Error("falling-back-on-naive-driver", error)
			return cmd.naiveBaggageclaimRunner(logger)
		}
	}

	bc := &baggageclaimcmd.BaggageclaimCommand{
		BindIP:   baggageclaimcmd.IPFlag(cmd.Baggageclaim.BindIP.IP().String()),
		BindPort: cmd.Baggageclaim.BindPort,

		VolumesDir: baggageclaimcmd.DirFlag(volumesDir),

		Driver: "btrfs",

		ReapInterval: cmd.Baggageclaim.ReapInterval,

		Metrics: cmd.Metrics,
	}

	return bc.Runner(nil)
}

func (cmd *WorkerCommand) extractBusybox(linux string) (string, error) {
	archive := filepath.Join(linux, "busybox.tar.gz")

	busyboxDir := filepath.Join(linux, "busybox")
	err := os.MkdirAll(busyboxDir, 0755)
	if err != nil {
		return "", err
	}

	tarBin := filepath.Join(linux, "bin", "tar")
	tar := exec.Command(tarBin, "-zxf", archive, "-C", busyboxDir)
	tar.Stdout = os.Stdout
	tar.Stderr = os.Stderr

	err = tar.Run()
	if err != nil {
		return "", err
	}

	return busyboxDir, nil
}

func (cmd *WorkerCommand) extractResources(linux string) ([]atc.WorkerResourceType, error) {
	var resourceTypes []atc.WorkerResourceType

	binDir := filepath.Join(linux, "bin")
	resourcesDir := filepath.Join(linux, "resources")
	resourceImagesDir := filepath.Join(linux, "resource-images")

	tarBin := filepath.Join(binDir, "tar")

	infos, err := ioutil.ReadDir(resourcesDir)
	if err == nil {
		for _, info := range infos {
			archive := filepath.Join(resourcesDir, info.Name())
			resourceType := info.Name()

			imageDir := filepath.Join(resourceImagesDir, resourceType)

			err := os.RemoveAll(imageDir)
			if err != nil {
				return nil, err
			}

			err = os.MkdirAll(imageDir, 0755)
			if err != nil {
				return nil, err
			}

			tar := exec.Command(tarBin, "-zxf", archive, "-C", imageDir)
			tar.Stdout = os.Stdout
			tar.Stderr = os.Stderr

			err = tar.Run()
			if err != nil {
				return nil, err
			}

			resourceTypes = append(resourceTypes, atc.WorkerResourceType{
				Type:  resourceType,
				Image: imageDir,
			})
		}
	}

	return resourceTypes, nil
}
<commit_msg>fix word<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/cloudfoundry-incubator/guardian/guardiancmd"
	"github.com/concourse/atc"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/concourse/baggageclaim/fs"
	"github.com/concourse/bin/bindata"
	"github.com/jessevdk/go-flags"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
)

const btrfsFSType = 0x9123683e

type GardenBackend guardiancmd.GuardianCommand

func (cmd WorkerCommand) lessenRequirements(command *flags.Command) {
	command.FindOptionByLongName("garden-depot").Required = false
	command.FindOptionByLongName("garden-graph").Required = false
	command.FindOptionByLongName("garden-runc-bin").Required = false
	command.FindOptionByLongName("garden-dadoo-bin").Required = false
	command.FindOptionByLongName("garden-init-bin").Required = false
	command.FindOptionByLongName("garden-iodaemon-bin").Required = false
	command.FindOptionByLongName("garden-kawasaki-bin").Required = false
	command.FindOptionByLongName("garden-nstar-bin").Required = false
	command.FindOptionByLongName("garden-tar-bin").Required = false
}

func (cmd *WorkerCommand) gardenRunner(logger lager.Logger, args []string) (atc.Worker, ifrit.Runner, error) {
	err := cmd.checkRoot()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	err = bindata.RestoreAssets(cmd.WorkDir, "linux")
	if err != nil {
		return atc.Worker{}, nil, err
	}

	linux := filepath.Join(cmd.WorkDir, "linux")

	btrfsToolsDir := filepath.Join(linux, "btrfs")
	iptablesDir := filepath.Join(linux, "iptables")

	err = os.Setenv(
		"PATH",
		strings.Join(
			[]string{
				btrfsToolsDir,
				filepath.Join(iptablesDir, "sbin"),
				filepath.Join(iptablesDir, "bin"),
				os.Getenv("PATH"),
			},
			string(os.PathListSeparator),
		),
	)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	busyboxDir, err := cmd.extractBusybox(linux)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	depotDir := filepath.Join(linux, "depot")

	// must be readable by other users so unprivileged containers can run their
	// own `initc' process
	err = os.MkdirAll(depotDir, 0755)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	cmd.Garden.Server.BindIP = guardiancmd.IPFlag(cmd.BindIP)

	cmd.Garden.Containers.Dir = guardiancmd.DirFlag(depotDir)
	cmd.Garden.Containers.DefaultRootFSDir = guardiancmd.DirFlag(busyboxDir)

	cmd.Garden.Bin.Runc = filepath.Join(linux, "bin", "runc")
	cmd.Garden.Bin.Dadoo = guardiancmd.FileFlag(filepath.Join(linux, "bin", "dadoo"))
	cmd.Garden.Bin.Init = guardiancmd.FileFlag(filepath.Join(linux, "bin", "init"))
	cmd.Garden.Bin.IODaemon = guardiancmd.FileFlag(filepath.Join(linux, "bin", "iodaemon"))
	cmd.Garden.Bin.Kawasaki = guardiancmd.FileFlag(filepath.Join(linux, "bin", "kawasaki"))
	cmd.Garden.Bin.NSTar = guardiancmd.FileFlag(filepath.Join(linux, "bin", "nstar"))
	cmd.Garden.Bin.Tar = guardiancmd.FileFlag(filepath.Join(linux, "bin", "tar"))

	cmd.Garden.Network.AllowHostAccess = true

	worker := atc.Worker{
		Platform: "linux",
		Tags:     cmd.Tags,

		HTTPProxyURL:  cmd.HTTPProxy.String(),
		HTTPSProxyURL: cmd.HTTPSProxy.String(),
		NoProxy:       strings.Join(cmd.NoProxy, ","),
	}

	worker.ResourceTypes, err = cmd.extractResources(linux)

	worker.Name, err = cmd.workerName()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	runner := guardiancmd.GuardianCommand(cmd.Garden)
	return worker, &runner, nil
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger) (ifrit.Runner, error) {
	volumesImage := filepath.Join(cmd.WorkDir, "volumes.img")
	volumesDir := filepath.Join(cmd.WorkDir, "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	var fsStat syscall.Statfs_t
	err = syscall.Statfs(volumesDir, &fsStat)
	if err != nil {
		return nil, fmt.Errorf("failed to stat volumes filesystem: %s", err)
	}

	if fsStat.Type != btrfsFSType {
		filesystem := fs.New(logger.Session("fs"), volumesImage, volumesDir)

		err = filesystem.Create(fsStat.Blocks * uint64(fsStat.Bsize))
		if err != nil {
			logger.Error("falling-back-on-naive-driver", err)
			return cmd.naiveBaggageclaimRunner(logger)
		}
	}

	bc := &baggageclaimcmd.BaggageclaimCommand{
		BindIP:   baggageclaimcmd.IPFlag(cmd.Baggageclaim.BindIP.IP().String()),
		BindPort: cmd.Baggageclaim.BindPort,

		VolumesDir: baggageclaimcmd.DirFlag(volumesDir),

		Driver: "btrfs",

		ReapInterval: cmd.Baggageclaim.ReapInterval,

		Metrics: cmd.Metrics,
	}

	return bc.Runner(nil)
}

func (cmd *WorkerCommand) extractBusybox(linux string) (string, error) {
	archive := filepath.Join(linux, "busybox.tar.gz")

	busyboxDir := filepath.Join(linux, "busybox")
	err := os.MkdirAll(busyboxDir, 0755)
	if err != nil {
		return "", err
	}

	tarBin := filepath.Join(linux, "bin", "tar")
	tar := exec.Command(tarBin, "-zxf", archive, "-C", busyboxDir)
	tar.Stdout = os.Stdout
	tar.Stderr = os.Stderr

	err = tar.Run()
	if err != nil {
		return "", err
	}

	return busyboxDir, nil
}

func (cmd *WorkerCommand) extractResources(linux string) ([]atc.WorkerResourceType, error) {
	var resourceTypes []atc.WorkerResourceType

	binDir := filepath.Join(linux, "bin")
	resourcesDir := filepath.Join(linux, "resources")
	resourceImagesDir := filepath.Join(linux, "resource-images")

	tarBin := filepath.Join(binDir, "tar")

	infos, err := ioutil.ReadDir(resourcesDir)
	if err == nil {
		for _, info := range infos {
			archive := filepath.Join(resourcesDir, info.Name())
			resourceType := info.Name()

			imageDir := filepath.Join(resourceImagesDir, resourceType)

			err := os.RemoveAll(imageDir)
			if err != nil {
				return nil, err
			}

			err = os.MkdirAll(imageDir, 0755)
			if err != nil {
				return nil, err
			}

			tar := exec.Command(tarBin, "-zxf", archive, "-C", imageDir)
			tar.Stdout = os.Stdout
			tar.Stderr = os.Stderr

			err = tar.Run()
			if err != nil {
				return nil, err
			}

			resourceTypes = append(resourceTypes, atc.WorkerResourceType{
				Type:  resourceType,
				Image: imageDir,
			})
		}
	}

	return resourceTypes, nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/cloudfoundry-incubator/guardian/guardiancmd"
	"github.com/concourse/atc"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/concourse/baggageclaim/fs"
	"github.com/concourse/bin/bindata"
	"github.com/jessevdk/go-flags"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
)

const btrfsFSType = 0x9123683e

type GardenBackend guardiancmd.GuardianCommand

func (cmd WorkerCommand) lessenRequirements(command *flags.Command) {
	command.FindOptionByLongName("garden-depot").Required = false
	command.FindOptionByLongName("garden-graph").Required = false
	command.FindOptionByLongName("garden-runc-bin").Required = false
	command.FindOptionByLongName("garden-dadoo-bin").Required = false
	command.FindOptionByLongName("garden-init-bin").Required = false
	command.FindOptionByLongName("garden-iodaemon-bin").Required = false
	command.FindOptionByLongName("garden-kawasaki-bin").Required = false
	command.FindOptionByLongName("garden-nstar-bin").Required = false
	command.FindOptionByLongName("garden-tar-bin").Required = false
}

func (cmd *WorkerCommand) gardenRunner(logger lager.Logger, args []string) (atc.Worker, ifrit.Runner, error) {
	err := cmd.checkRoot()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	assetsDir, err := cmd.restoreVersionedAssets()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	btrfsToolsDir := filepath.Join(assetsDir, "btrfs")
	iptablesDir := filepath.Join(assetsDir, "iptables")

	err = os.Setenv(
		"PATH",
		strings.Join(
			[]string{
				btrfsToolsDir,
				filepath.Join(iptablesDir, "sbin"),
				filepath.Join(iptablesDir, "bin"),
				os.Getenv("PATH"),
			},
			string(os.PathListSeparator),
		),
	)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	depotDir := filepath.Join(cmd.WorkDir, "depot")

	// must be readable by other users so unprivileged containers can run their
	// own `initc' process
	err = os.MkdirAll(depotDir, 0755)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	cmd.Garden.Server.BindIP = guardiancmd.IPFlag(cmd.BindIP)

	cmd.Garden.Containers.Dir = guardiancmd.DirFlag(depotDir)

	cmd.Garden.Bin.Runc = filepath.Join(assetsDir, "bin", "runc")
	cmd.Garden.Bin.Dadoo = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "dadoo"))
	cmd.Garden.Bin.Init = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "init"))
	cmd.Garden.Bin.IODaemon = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "iodaemon"))
	cmd.Garden.Bin.Kawasaki = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "kawasaki"))
	cmd.Garden.Bin.NSTar = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "nstar"))
	cmd.Garden.Bin.Tar = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "tar"))

	cmd.Garden.Network.AllowHostAccess = true

	worker := atc.Worker{
		Platform: "linux",
		Tags:     cmd.Tags,

		HTTPProxyURL:  cmd.HTTPProxy.String(),
		HTTPSProxyURL: cmd.HTTPSProxy.String(),
		NoProxy:       strings.Join(cmd.NoProxy, ","),
	}

	worker.ResourceTypes, err = cmd.extractResources(assetsDir)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	worker.Name, err = cmd.workerName()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	runner := guardiancmd.GuardianCommand(cmd.Garden)
	return worker, &runner, nil
}

func (cmd *WorkerCommand) restoreVersionedAssets() (string, error) {
	assetsDir := filepath.Join(cmd.WorkDir, Version)

	okMarker := filepath.Join(assetsDir, "ok")

	_, err := os.Stat(okMarker)
	if err == nil {
		return assetsDir, nil
	}

	err = bindata.RestoreAssets(assetsDir, "linux")
	if err != nil {
		return "", err
	}

	ok, err := os.Create(okMarker)
	if err != nil {
		return "", err
	}

	err = ok.Close()
	if err != nil {
		return "", err
	}

	return assetsDir, nil
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger) (ifrit.Runner, error) {
	volumesImage := filepath.Join(cmd.WorkDir, "volumes.img")
	volumesDir := filepath.Join(cmd.WorkDir, "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	var fsStat syscall.Statfs_t
	err = syscall.Statfs(volumesDir, &fsStat)
	if err != nil {
		return nil, fmt.Errorf("failed to stat volumes filesystem: %s", err)
	}

	if fsStat.Type != btrfsFSType {
		filesystem := fs.New(logger.Session("fs"), volumesImage, volumesDir)

		err = filesystem.Create(fsStat.Blocks * uint64(fsStat.Bsize))
		if err != nil {
			logger.Error("falling-back-on-naive-driver", err)
			return cmd.naiveBaggageclaimRunner(logger)
		}
	}

	bc := &baggageclaimcmd.BaggageclaimCommand{
		BindIP:   baggageclaimcmd.IPFlag(cmd.Baggageclaim.BindIP.IP().String()),
		BindPort: cmd.Baggageclaim.BindPort,

		VolumesDir: baggageclaimcmd.DirFlag(volumesDir),

		Driver: "btrfs",

		ReapInterval: cmd.Baggageclaim.ReapInterval,

		Metrics: cmd.Metrics,
	}

	return bc.Runner(nil)
}

func (cmd *WorkerCommand) extractResources(assetsDir string) ([]atc.WorkerResourceType, error) {
	var resourceTypes []atc.WorkerResourceType

	binDir := filepath.Join(assetsDir, "bin")
	resourcesDir := filepath.Join(assetsDir, "resources")
	resourceImagesDir := filepath.Join(assetsDir, "resource-images")

	tarBin := filepath.Join(binDir, "tar")

	infos, err := ioutil.ReadDir(resourcesDir)
	if err != nil {
		return nil, err
	}

	for _, info := range infos {
		resourceType := info.Name()

		archive := filepath.Join(resourcesDir, resourceType, "rootfs.tar.gz")

		extractedDir := filepath.Join(resourceImagesDir, resourceType)

		imageDir := filepath.Join(extractedDir, "rootfs")
		okMarker := filepath.Join(extractedDir, "ok")

		var version string
		versionFile, err := os.Open(filepath.Join(resourcesDir, resourceType, "version"))
		if err != nil {
			return nil, err
		}

		_, err = fmt.Fscanf(versionFile, "%s", &version)
		if err != nil {
			return nil, err
		}

		defer versionFile.Close()

		_, err = os.Stat(okMarker)
		if err == os.ErrNotExist {
			err := os.RemoveAll(imageDir)
			if err != nil {
				return nil, err
			}

			err = os.MkdirAll(imageDir, 0755)
			if err != nil {
				return nil, err
			}

			tar := exec.Command(tarBin, "-zxf", archive, "-C", imageDir)
			tar.Stdout = os.Stdout
			tar.Stderr = os.Stderr

			err = tar.Run()
			if err != nil {
				return nil, err
			}

			ok, err := os.Create(okMarker)
			if err != nil {
				return nil, err
			}

			err = ok.Close()
			if err != nil {
				return nil, err
			}
		} else if err != nil {
			return nil, err
		}

		resourceTypes = append(resourceTypes, atc.WorkerResourceType{
			Type:    resourceType,
			Image:   imageDir,
			Version: version,
		})
	}

	return resourceTypes, nil
}
<commit_msg>fix assets dir<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/cloudfoundry-incubator/guardian/guardiancmd"
	"github.com/concourse/atc"
	"github.com/concourse/baggageclaim/baggageclaimcmd"
	"github.com/concourse/baggageclaim/fs"
	"github.com/concourse/bin/bindata"
	"github.com/jessevdk/go-flags"
	"github.com/pivotal-golang/lager"
	"github.com/tedsuo/ifrit"
)

const btrfsFSType = 0x9123683e

type GardenBackend guardiancmd.GuardianCommand

func (cmd WorkerCommand) lessenRequirements(command *flags.Command) {
	command.FindOptionByLongName("garden-depot").Required = false
	command.FindOptionByLongName("garden-graph").Required = false
	command.FindOptionByLongName("garden-runc-bin").Required = false
	command.FindOptionByLongName("garden-dadoo-bin").Required = false
	command.FindOptionByLongName("garden-init-bin").Required = false
	command.FindOptionByLongName("garden-iodaemon-bin").Required = false
	command.FindOptionByLongName("garden-kawasaki-bin").Required = false
	command.FindOptionByLongName("garden-nstar-bin").Required = false
	command.FindOptionByLongName("garden-tar-bin").Required = false
}

func (cmd *WorkerCommand) gardenRunner(logger lager.Logger, args []string) (atc.Worker, ifrit.Runner, error) {
	err := cmd.checkRoot()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	assetsDir, err := cmd.restoreVersionedAssets()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	btrfsToolsDir := filepath.Join(assetsDir, "btrfs")
	iptablesDir := filepath.Join(assetsDir, "iptables")

	err = os.Setenv(
		"PATH",
		strings.Join(
			[]string{
				btrfsToolsDir,
				filepath.Join(iptablesDir, "sbin"),
				filepath.Join(iptablesDir, "bin"),
				os.Getenv("PATH"),
			},
			string(os.PathListSeparator),
		),
	)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	depotDir := filepath.Join(cmd.WorkDir, "depot")

	// must be readable by other users so unprivileged containers can run their
	// own `initc' process
	err = os.MkdirAll(depotDir, 0755)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	cmd.Garden.Server.BindIP = guardiancmd.IPFlag(cmd.BindIP)

	cmd.Garden.Containers.Dir = guardiancmd.DirFlag(depotDir)

	cmd.Garden.Bin.Runc = filepath.Join(assetsDir, "bin", "runc")
	cmd.Garden.Bin.Dadoo = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "dadoo"))
	cmd.Garden.Bin.Init = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "init"))
	cmd.Garden.Bin.IODaemon = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "iodaemon"))
	cmd.Garden.Bin.Kawasaki = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "kawasaki"))
	cmd.Garden.Bin.NSTar = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "nstar"))
	cmd.Garden.Bin.Tar = guardiancmd.FileFlag(filepath.Join(assetsDir, "bin", "tar"))

	cmd.Garden.Network.AllowHostAccess = true

	worker := atc.Worker{
		Platform: "linux",
		Tags:     cmd.Tags,

		HTTPProxyURL:  cmd.HTTPProxy.String(),
		HTTPSProxyURL: cmd.HTTPSProxy.String(),
		NoProxy:       strings.Join(cmd.NoProxy, ","),
	}

	worker.ResourceTypes, err = cmd.extractResources(assetsDir)
	if err != nil {
		return atc.Worker{}, nil, err
	}

	worker.Name, err = cmd.workerName()
	if err != nil {
		return atc.Worker{}, nil, err
	}

	runner := guardiancmd.GuardianCommand(cmd.Garden)
	return worker, &runner, nil
}

func (cmd *WorkerCommand) restoreVersionedAssets() (string, error) {
	assetsDir := filepath.Join(cmd.WorkDir, Version)

	restoredDir := filepath.Join(assetsDir, "linux")

	okMarker := filepath.Join(assetsDir, "ok")

	_, err := os.Stat(okMarker)
	if err == nil {
		return restoredDir, nil
	}

	err = bindata.RestoreAssets(assetsDir, "linux")
	if err != nil {
		return "", err
	}

	ok, err := os.Create(okMarker)
	if err != nil {
		return "", err
	}

	err = ok.Close()
	if err != nil {
		return "", err
	}

	return restoredDir, nil
}

func (cmd *WorkerCommand) baggageclaimRunner(logger lager.Logger) (ifrit.Runner, error) {
	volumesImage := filepath.Join(cmd.WorkDir, "volumes.img")
	volumesDir := filepath.Join(cmd.WorkDir, "volumes")

	err := os.MkdirAll(volumesDir, 0755)
	if err != nil {
		return nil, err
	}

	var fsStat syscall.Statfs_t
	err = syscall.Statfs(volumesDir, &fsStat)
	if err != nil {
		return nil, fmt.Errorf("failed to stat volumes filesystem: %s", err)
	}

	if fsStat.Type != btrfsFSType {
		filesystem := fs.New(logger.Session("fs"), volumesImage, volumesDir)

		err = filesystem.Create(fsStat.Blocks * uint64(fsStat.Bsize))
		if err != nil {
			logger.Error("falling-back-on-naive-driver", err)
			return cmd.naiveBaggageclaimRunner(logger)
		}
	}

	bc := &baggageclaimcmd.BaggageclaimCommand{
		BindIP:   baggageclaimcmd.IPFlag(cmd.Baggageclaim.BindIP.IP().String()),
		BindPort: cmd.Baggageclaim.BindPort,

		VolumesDir: baggageclaimcmd.DirFlag(volumesDir),

		Driver: "btrfs",

		ReapInterval: cmd.Baggageclaim.ReapInterval,

		Metrics: cmd.Metrics,
	}

	return bc.Runner(nil)
}

func (cmd *WorkerCommand) extractResources(assetsDir string) ([]atc.WorkerResourceType, error) {
	var resourceTypes []atc.WorkerResourceType

	binDir := filepath.Join(assetsDir, "bin")
	resourcesDir := filepath.Join(assetsDir, "resources")
	resourceImagesDir := filepath.Join(assetsDir, "resource-images")

	tarBin := filepath.Join(binDir, "tar")

	infos, err := ioutil.ReadDir(resourcesDir)
	if err != nil {
		return nil, err
	}

	for _, info := range infos {
		resourceType := info.Name()

		archive := filepath.Join(resourcesDir, resourceType, "rootfs.tar.gz")

		extractedDir := filepath.Join(resourceImagesDir, resourceType)

		imageDir := filepath.Join(extractedDir, "rootfs")
		okMarker := filepath.Join(extractedDir, "ok")

		var version string
		versionFile, err := os.Open(filepath.Join(resourcesDir, resourceType, "version"))
		if err != nil {
			return nil, err
		}

		_, err = fmt.Fscanf(versionFile, "%s", &version)
		if err != nil {
			return nil, err
		}

		defer versionFile.Close()

		_, err = os.Stat(okMarker)
		if err == os.ErrNotExist {
			err := os.RemoveAll(imageDir)
			if err != nil {
				return nil, err
			}

			err = os.MkdirAll(imageDir, 0755)
			if err != nil {
				return nil, err
			}

			tar := exec.Command(tarBin, "-zxf", archive, "-C", imageDir)
			tar.Stdout = os.Stdout
			tar.Stderr = os.Stderr

			err = tar.Run()
			if err != nil {
				return nil, err
			}

			ok, err := os.Create(okMarker)
			if err != nil {
				return nil, err
			}

			err = ok.Close()
			if err != nil {
				return nil, err
			}
		} else if err != nil {
			return nil, err
		}

		resourceTypes = append(resourceTypes, atc.WorkerResourceType{
			Type:    resourceType,
			Image:   imageDir,
			Version: version,
		})
	}

	return resourceTypes, nil
}
<|endoftext|>


<commit_before>package control

import (
	"errors"

	"github.com/rancher/os/config"
	"github.com/rancher/os/pkg/compose"
	"github.com/rancher/os/pkg/log"

	"github.com/codegangsta/cli"
	"github.com/docker/libcompose/project/options"
	"golang.org/x/net/context"
)

func switchConsoleAction(c *cli.Context) error {
	if len(c.Args()) != 1 {
		return errors.New("Must specify exactly one existing container")
	}
	newConsole := c.Args()[0]

	cfg := config.LoadConfig()

	project, err := compose.GetProject(cfg, true, false)
	if err != nil {
		return err
	}

	if newConsole != "default" {
		if err = compose.LoadSpecialService(project, cfg, "console", newConsole); err != nil {
			return err
		}
	}

	if err = config.Set("rancher.console", newConsole); err != nil {
		log.Errorf("Failed to update 'rancher.console': %v", err)
	}

	if err = project.Up(context.Background(), options.Up{
		Log: true,
	}, "console"); err != nil {
		return err
	}

	if err = project.Restart(context.Background(), 10, "docker"); err != nil {
		log.Errorf("Failed to restart Docker: %v", err)
	}

	return nil
}
<commit_msg>Stop docker and console first to avoid zombie processes<commit_after>package control

import (
	"errors"

	"github.com/rancher/os/config"
	"github.com/rancher/os/pkg/compose"
	"github.com/rancher/os/pkg/log"

	"github.com/codegangsta/cli"
	"github.com/docker/libcompose/project/options"
	"golang.org/x/net/context"
)

func switchConsoleAction(c *cli.Context) error {
	if len(c.Args()) != 1 {
		return errors.New("Must specify exactly one existing container")
	}
	newConsole := c.Args()[0]

	cfg := config.LoadConfig()

	project, err := compose.GetProject(cfg, true, false)
	if err != nil {
		return err
	}

	// stop docker and console to avoid zombie process
	if err = project.Stop(context.Background(), 10, "docker"); err != nil {
		log.Errorf("Failed to stop Docker: %v", err)
	}
	if err = project.Stop(context.Background(), 10, "console"); err != nil {
		log.Errorf("Failed to stop console: %v", err)
	}

	if newConsole != "default" {
		if err = compose.LoadSpecialService(project, cfg, "console", newConsole); err != nil {
			return err
		}
	}

	if err = config.Set("rancher.console", newConsole); err != nil {
		log.Errorf("Failed to update 'rancher.console': %v", err)
	}

	if err = project.Up(context.Background(), options.Up{
		Log: true,
	}, "console"); err != nil {
		return err
	}

	if err = project.Start(context.Background(), "docker"); err != nil {
		log.Errorf("Failed to start Docker: %v", err)
	}

	return nil
}
<|endoftext|>