<commit_before>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file contains the built-in primitive functions.

package golisp

import (
    "errors"
    "fmt"
)

func RegisterSpecialFormPrimitives() {
    MakePrimitiveFunction("cond", -1, CondImpl)
    MakePrimitiveFunction("case", -1, CaseImpl)
    MakePrimitiveFunction("if", -1, IfImpl)
    MakePrimitiveFunction("lambda", -1, LambdaImpl)
    MakePrimitiveFunction("define", -1, DefineImpl)
    MakePrimitiveFunction("defmacro", -1, DefmacroImpl)
    MakePrimitiveFunction("let", -1, LetImpl)
    MakePrimitiveFunction("begin", -1, BeginImpl)
    MakePrimitiveFunction("do", -1, DoImpl)
    MakePrimitiveFunction("apply", 2, ApplyImpl)
    MakePrimitiveFunction("eval", 1, EvalImpl)
    MakePrimitiveFunction("->", -1, ChainImpl)
    MakePrimitiveFunction("=>", -1, TapImpl)
}

func CondImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    var condition *Data
    for c := args; NotNilP(c); c = Cdr(c) {
        clause := Car(c)
        if !PairP(clause) {
            err = errors.New("Cond expect a sequence of clauses that are lists")
            return
        }
        condition, err = Eval(Car(clause), env)
        if err != nil {
            return
        }
        if BooleanValue(condition) || StringValue(Car(clause)) == "else" {
            for e := Cdr(clause); NotNilP(e); e = Cdr(e) {
                result, err = Eval(Car(e), env)
                if err != nil {
                    return
                }
            }
            return
        }
    }
    return
}

func evalList(l *Data, env *SymbolTableFrame) (result *Data, err error) {
    for sexpr := l; NotNilP(sexpr); sexpr = Cdr(sexpr) {
        result, err = Eval(Car(sexpr), env)
        if err != nil {
            return
        }
    }
    return
}

func CaseImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    var keyValue *Data

    keyValue, err = Eval(Car(args), env)
    if err != nil {
        return
    }

    for clauseCell := Cdr(args); NotNilP(clauseCell); clauseCell = Cdr(clauseCell) {
        clause := Car(clauseCell)
        if !PairP(clause) {
             err = errors.New("Case requires non-atomic clauses")
             return
         }
         if ListP(Car(clause)) {
             for v := Car(clause); NotNilP(v); v = Cdr(v) {
                 if IsEqual(Car(v), keyValue) {
                     return evalList(Cdr(clause), env)
                 }
             }
         } else if IsEqual(Car(clause), SymbolWithName("else")) {
             return evalList(Cdr(clause), env)
         }
    }

    return
}

func IfImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    if Length(args) < 2 || Length(args) > 3 {
        err = errors.New(fmt.Sprintf("IF requires 2 or 3 arguments. Received %d.", Length(args)))
        return
    }

    c, err := Eval(Car(args), env)
    if err != nil {
        return
    }
    condition := BooleanValue(c)
    thenClause := Second(args)
    elseClause := Third(args)

    if condition {
        return Eval(thenClause, env)
    } else {
        return Eval(elseClause, env)
    }
}

func LambdaImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    params := Car(args)
    body := Cdr(args)
    return FunctionWithNameParamsBodyAndParent("anonymous", params, body, env), nil
}

func DefineImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    var value *Data
    thing := Car(args)
    if SymbolP(thing) {
        value, err = Eval(Cadr(args), env)
        if err != nil {
            return
        }
    } else if PairP(thing) {
        name := Car(thing)
        params := Cdr(thing)
        thing = name
        if !SymbolP(name) {
            err = errors.New("Function name has to be a symbol")
            return
        }
        body := Cdr(args)
        value = FunctionWithNameParamsBodyAndParent(StringValue(name), params, body, env)
    } else {
        err = errors.New("Invalid definition")
        return
    }
    env.BindLocallyTo(thing, value)
    return value, nil
}

func DefmacroImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    var value *Data
    thing := Car(args)
    if PairP(thing) {
        name := Car(thing)
        params := Cdr(thing)
        thing = name
        if !SymbolP(name) {
            err = errors.New("Macro name has to be a symbol")
            return
        }
        body := Cadr(args)
        value = MacroWithNameParamsBodyAndParent(StringValue(name), params, body, env)
    } else {
        err = errors.New("Invalid macro definition")
        return
    }
    env.BindLocallyTo(thing, value)
    return value, nil
}

func bindLetLocals(bindingForms *Data, env *SymbolTableFrame) (err error) {
    var name *Data
    var value *Data

    for cell := bindingForms; NotNilP(cell); cell = Cdr(cell) {
        bindingPair := Car(cell)
        if !PairP(bindingPair) {
            err = errors.New("Let requires a list of bindings (with are pairs) as it's first argument")
            return
        }
        name = Car(bindingPair)
        if !SymbolP(name) {
            err = errors.New("First part of a let binding pair must be a symbol")
        }
        value, err = Eval(Cadr(bindingPair), env)
        if err != nil {
            return
        }
        env.BindLocallyTo(name, value)
    }
    return
}

func LetImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    if Length(args) < 1 {
        err = errors.New("Let requires at least a list of bindings")
        return
    }

    if !PairP(Car(args)) {
        err = errors.New("Let requires a list of bindings as it's first argument")
        return
    }

    localFrame := NewSymbolTableFrameBelow(env)
    bindLetLocals(Car(args), localFrame)

    for cell := Cdr(args); NotNilP(cell); cell = Cdr(cell) {
        sexpr := Car(cell)
        result, err = Eval(sexpr, localFrame)
        if err != nil {
            return
        }
    }

    return
}

func BeginImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    for cell := args; NotNilP(cell); cell = Cdr(cell) {
        sexpr := Car(cell)
        result, err = Eval(sexpr, env)
        if err != nil {
            return
        }
    }
    return
}

func rebindDoLocals(bindingForms *Data, env *SymbolTableFrame) (err error) {
    var name *Data
    var value *Data

    for cell := bindingForms; NotNilP(cell); cell = Cdr(cell) {
        bindingTuple := Car(cell)
        name = First(bindingTuple)
        if NotNilP(Third(bindingTuple)) {
            value, err = Eval(Third(bindingTuple), env)
            if err != nil {
                return
            }
            env.BindLocallyTo(name, value)
        }
    }
    return
}

func DoImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    if Length(args) < 2 {
        err = errors.New("Do requires at least a list of bindings and a test clause")
        return
    }

    bindings := Car(args)
    if !PairP(bindings) {
        err = errors.New("Do requires a list of bindings as it's first argument")
        return
    }

    testClause := Cadr(args)
    if !PairP(testClause) {
        err = errors.New("Do requires a list as it's second argument")
        return
    }

    localFrame := NewSymbolTableFrameBelow(env)
    bindLetLocals(bindings, localFrame)

    body := Cddr(args)

    var shouldExit *Data

    for true {
        shouldExit, err = Eval(Car(testClause), localFrame)
        if err != nil {
            return
        }

        if BooleanValue(shouldExit) {
            for cell := Cdr(testClause); NotNilP(cell); cell = Cdr(cell) {
                sexpr := Car(cell)
                result, err = Eval(sexpr, localFrame)
                if err != nil {
                    return
                }
            }
            return
        }

        for cell := body; NotNilP(cell); cell = Cdr(cell) {
            sexpr := Car(cell)
            result, err = Eval(sexpr, localFrame)
            if err != nil {
                return
            }
        }

        rebindDoLocals(bindings, localFrame)
    }
    return
}

func ApplyImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    f, err := Eval(Car(args), env)
    if err != nil {
        return
    }

    vals, err := Eval(Cadr(args), env)
    if err != nil {
        return
    }

    return Apply(f, vals, env)
}

func EvalImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    val, err := Eval(Car(args), env)
    if err != nil {
        return
    }

    return Eval(val, env)
}

func ChainImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    if Length(args) == 0 {
        err = errors.New("-> requires at least an initial value.")
        return
    }

    var value *Data

    value, err = Eval(Car(args), env)
    if err != nil {
        return
    }

    for cell := Cdr(args); NotNilP(cell); cell = Cdr(cell) {
        sexpr := Car(cell)
        var newExpr *Data
        if ListP(sexpr) {
            newExpr = Cons(Car(sexpr), Cons(value, Cdr(sexpr)))
        } else {
            newExpr = Cons(sexpr, Cons(value, nil))
        }
        value, err = Eval(newExpr, env)
        if err != nil {
            return
        }
    }
    result = value
    return
}

func TapImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
    if Length(args) == 0 {
        err = errors.New("tap requires at least an initial value.")
        return
    }

    var value *Data

    value, err = Eval(Car(args), env)
    if err != nil {
        return
    }
    result = value

    for cell := Cdr(args); NotNilP(cell); cell = Cdr(cell) {
        sexpr := Car(cell)
        var newExpr *Data
        if ListP(sexpr) {
            newExpr = Cons(Car(sexpr), Cons(value, Cdr(sexpr)))
        } else {
            newExpr = Cons(sexpr, Cons(value, nil))
        }
        _, err = Eval(newExpr, env)
        if err != nil {
            return
        }
    }
    return
}
<commit_msg>Fix apply to work as it does in scheme. Formatting was redone for some reason.<commit_after>// Copyright 2014 SteelSeries ApS.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This package implements a basic LISP interpretor for embedding in a go program for scripting.
// This file contains the built-in primitive functions.

package golisp

import (
	"errors"
	"fmt"
)

func RegisterSpecialFormPrimitives() {
	MakePrimitiveFunction("cond", -1, CondImpl)
	MakePrimitiveFunction("case", -1, CaseImpl)
	MakePrimitiveFunction("if", -1, IfImpl)
	MakePrimitiveFunction("lambda", -1, LambdaImpl)
	MakePrimitiveFunction("define", -1, DefineImpl)
	MakePrimitiveFunction("defmacro", -1, DefmacroImpl)
	MakePrimitiveFunction("let", -1, LetImpl)
	MakePrimitiveFunction("begin", -1, BeginImpl)
	MakePrimitiveFunction("do", -1, DoImpl)
	MakePrimitiveFunction("apply", -1, ApplyImpl)
	MakePrimitiveFunction("eval", 1, EvalImpl)
	MakePrimitiveFunction("->", -1, ChainImpl)
	MakePrimitiveFunction("=>", -1, TapImpl)
}

func CondImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	var condition *Data
	for c := args; NotNilP(c); c = Cdr(c) {
		clause := Car(c)
		if !PairP(clause) {
			err = errors.New("Cond expect a sequence of clauses that are lists")
			return
		}
		condition, err = Eval(Car(clause), env)
		if err != nil {
			return
		}
		if BooleanValue(condition) || StringValue(Car(clause)) == "else" {
			for e := Cdr(clause); NotNilP(e); e = Cdr(e) {
				result, err = Eval(Car(e), env)
				if err != nil {
					return
				}
			}
			return
		}
	}
	return
}

func evalList(l *Data, env *SymbolTableFrame) (result *Data, err error) {
	for sexpr := l; NotNilP(sexpr); sexpr = Cdr(sexpr) {
		result, err = Eval(Car(sexpr), env)
		if err != nil {
			return
		}
	}
	return
}

func CaseImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	var keyValue *Data

	keyValue, err = Eval(Car(args), env)
	if err != nil {
		return
	}

	for clauseCell := Cdr(args); NotNilP(clauseCell); clauseCell = Cdr(clauseCell) {
		clause := Car(clauseCell)
		if !PairP(clause) {
			err = errors.New("Case requires non-atomic clauses")
			return
		}
		if ListP(Car(clause)) {
			for v := Car(clause); NotNilP(v); v = Cdr(v) {
				if IsEqual(Car(v), keyValue) {
					return evalList(Cdr(clause), env)
				}
			}
		} else if IsEqual(Car(clause), SymbolWithName("else")) {
			return evalList(Cdr(clause), env)
		}
	}

	return
}

func IfImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if Length(args) < 2 || Length(args) > 3 {
		err = errors.New(fmt.Sprintf("IF requires 2 or 3 arguments. Received %d.", Length(args)))
		return
	}

	c, err := Eval(Car(args), env)
	if err != nil {
		return
	}
	condition := BooleanValue(c)
	thenClause := Second(args)
	elseClause := Third(args)

	if condition {
		return Eval(thenClause, env)
	} else {
		return Eval(elseClause, env)
	}
}

func LambdaImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	params := Car(args)
	body := Cdr(args)
	return FunctionWithNameParamsBodyAndParent("anonymous", params, body, env), nil
}

func DefineImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	var value *Data
	thing := Car(args)
	if SymbolP(thing) {
		value, err = Eval(Cadr(args), env)
		if err != nil {
			return
		}
	} else if PairP(thing) {
		name := Car(thing)
		params := Cdr(thing)
		thing = name
		if !SymbolP(name) {
			err = errors.New("Function name has to be a symbol")
			return
		}
		body := Cdr(args)
		value = FunctionWithNameParamsBodyAndParent(StringValue(name), params, body, env)
	} else {
		err = errors.New("Invalid definition")
		return
	}
	env.BindLocallyTo(thing, value)
	return value, nil
}

func DefmacroImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	var value *Data
	thing := Car(args)
	if PairP(thing) {
		name := Car(thing)
		params := Cdr(thing)
		thing = name
		if !SymbolP(name) {
			err = errors.New("Macro name has to be a symbol")
			return
		}
		body := Cadr(args)
		value = MacroWithNameParamsBodyAndParent(StringValue(name), params, body, env)
	} else {
		err = errors.New("Invalid macro definition")
		return
	}
	env.BindLocallyTo(thing, value)
	return value, nil
}

func bindLetLocals(bindingForms *Data, env *SymbolTableFrame) (err error) {
	var name *Data
	var value *Data

	for cell := bindingForms; NotNilP(cell); cell = Cdr(cell) {
		bindingPair := Car(cell)
		if !PairP(bindingPair) {
			err = errors.New("Let requires a list of bindings (with are pairs) as it's first argument")
			return
		}
		name = Car(bindingPair)
		if !SymbolP(name) {
			err = errors.New("First part of a let binding pair must be a symbol")
		}
		value, err = Eval(Cadr(bindingPair), env)
		if err != nil {
			return
		}
		env.BindLocallyTo(name, value)
	}
	return
}

func LetImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if Length(args) < 1 {
		err = errors.New("Let requires at least a list of bindings")
		return
	}

	if !PairP(Car(args)) {
		err = errors.New("Let requires a list of bindings as it's first argument")
		return
	}

	localFrame := NewSymbolTableFrameBelow(env)
	bindLetLocals(Car(args), localFrame)

	for cell := Cdr(args); NotNilP(cell); cell = Cdr(cell) {
		sexpr := Car(cell)
		result, err = Eval(sexpr, localFrame)
		if err != nil {
			return
		}
	}

	return
}

func BeginImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	for cell := args; NotNilP(cell); cell = Cdr(cell) {
		sexpr := Car(cell)
		result, err = Eval(sexpr, env)
		if err != nil {
			return
		}
	}
	return
}

func rebindDoLocals(bindingForms *Data, env *SymbolTableFrame) (err error) {
	var name *Data
	var value *Data

	for cell := bindingForms; NotNilP(cell); cell = Cdr(cell) {
		bindingTuple := Car(cell)
		name = First(bindingTuple)
		if NotNilP(Third(bindingTuple)) {
			value, err = Eval(Third(bindingTuple), env)
			if err != nil {
				return
			}
			env.BindLocallyTo(name, value)
		}
	}
	return
}

func DoImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if Length(args) < 2 {
		err = errors.New("Do requires at least a list of bindings and a test clause")
		return
	}

	bindings := Car(args)
	if !PairP(bindings) {
		err = errors.New("Do requires a list of bindings as it's first argument")
		return
	}

	testClause := Cadr(args)
	if !PairP(testClause) {
		err = errors.New("Do requires a list as it's second argument")
		return
	}

	localFrame := NewSymbolTableFrameBelow(env)
	bindLetLocals(bindings, localFrame)

	body := Cddr(args)

	var shouldExit *Data

	for true {
		shouldExit, err = Eval(Car(testClause), localFrame)
		if err != nil {
			return
		}

		if BooleanValue(shouldExit) {
			for cell := Cdr(testClause); NotNilP(cell); cell = Cdr(cell) {
				sexpr := Car(cell)
				result, err = Eval(sexpr, localFrame)
				if err != nil {
					return
				}
			}
			return
		}

		for cell := body; NotNilP(cell); cell = Cdr(cell) {
			sexpr := Car(cell)
			result, err = Eval(sexpr, localFrame)
			if err != nil {
				return
			}
		}

		rebindDoLocals(bindings, localFrame)
	}
	return
}

func ApplyImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if Length(args) < 1 {
		err = errors.New("apply requires at least one argument")
		return
	}

	f, err := Eval(Car(args), env)
	if err != nil {
		return
	}

	if !FunctionP(f) {
		err = errors.New(fmt.Sprintf("apply requires a function as it's first argument, but got %s.", String(f)))
	}

	ary := make([]*Data, 0, Length(args)-1)

	var v *Data
	for c := Cdr(args); NotNilP(c); c = Cdr(c) {
		v, err = Eval(Car(c), env)
		if err != nil {
			return
		}
		ary = append(ary, v)
	}

	var argList *Data
	if ListP(ary[len(ary)-1]) {
		if len(ary) > 1 {
			argList = ArrayToListWithTail(ary[0:len(ary)-1], ary[len(ary)-1])
		} else {
			argList = ary[0]
		}
	} else {
		argList = Cdr(args)
	}

	return Apply(f, argList, env)
}

func EvalImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	val, err := Eval(Car(args), env)
	if err != nil {
		return
	}

	return Eval(val, env)
}

func ChainImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if Length(args) == 0 {
		err = errors.New("-> requires at least an initial value.")
		return
	}

	var value *Data

	value, err = Eval(Car(args), env)
	if err != nil {
		return
	}

	for cell := Cdr(args); NotNilP(cell); cell = Cdr(cell) {
		sexpr := Car(cell)
		var newExpr *Data
		if ListP(sexpr) {
			newExpr = Cons(Car(sexpr), Cons(value, Cdr(sexpr)))
		} else {
			newExpr = Cons(sexpr, Cons(value, nil))
		}
		value, err = Eval(newExpr, env)
		if err != nil {
			return
		}
	}
	result = value
	return
}

func TapImpl(args *Data, env *SymbolTableFrame) (result *Data, err error) {
	if Length(args) == 0 {
		err = errors.New("tap requires at least an initial value.")
		return
	}

	var value *Data

	value, err = Eval(Car(args), env)
	if err != nil {
		return
	}
	result = value

	for cell := Cdr(args); NotNilP(cell); cell = Cdr(cell) {
		sexpr := Car(cell)
		var newExpr *Data
		if ListP(sexpr) {
			newExpr = Cons(Car(sexpr), Cons(value, Cdr(sexpr)))
		} else {
			newExpr = Cons(sexpr, Cons(value, nil))
		}
		_, err = Eval(newExpr, env)
		if err != nil {
			return
		}
	}
	return
}
<|endoftext|>


<commit_before>package commands

import (
	"appstax-cli/appstax/account"
	"appstax-cli/appstax/config"
	"appstax-cli/appstax/fail"
	"appstax-cli/appstax/log"
	"appstax-cli/appstax/session"
	"appstax-cli/appstax/template"
	"appstax-cli/appstax/term"
	"fmt"
	"github.com/codegangsta/cli"
	"os"
	"strings"
)

func DoInit(c *cli.Context) {
	useOptions(c)
	loginIfNeeded()

	app, err := selectApp()
	if err != nil {
		return
	}

	tpl := selectTemplate()

	publicDir := "./public"
	serverDir := "./server"
	if tpl.Name == "none" {
		term.Section()
		publicDir = selectPublicDir()
	}
	writeConfig(app, publicDir, serverDir)

	if !strings.HasPrefix(tpl.Name, "ios/") {
		createPublicDir()
	}

	if tpl.Name != "none" {
		term.Section()
		term.Println("Setting up template... ")
		template.Install(tpl)
		term.Println("Done.")
	}

	term.Section()
	selectSubdomain(app.AppID, false)

	term.Section()
	term.Println("All done!")
	term.Println("Now run 'appstax deploy' when you are ready to upload your public files.")
}

func selectApp() (account.App, error) {
	apps, _ := account.GetUserApps()
	selected := -1
	if len(apps) == 0 {
		term.Section()
		term.Println("You have not created any apps yet! Create one now:")
	} else {
		term.Section()
		term.Println("Choose which app to configure or create a new one:")
		for i, app := range apps {
			term.Printf("  %d) %s\n", i+1, app.AppName)
		}
		term.Printf("  %d) Create a new app\n", len(apps)+1)
		term.Section()
		for selected < 0 || selected > len(apps) {
			selected = -1 + term.GetInt(fmt.Sprintf("Please select (1-%d)", len(apps)+1))
		}
	}
	if selected >= 0 && selected < len(apps) {
		return apps[selected], nil
	} else {
		return createApp()
	}
}

func createApp() (account.App, error) {
	app := account.App{}
	term.Section()
	app.AppName = term.GetString("App name")
	app.AppDescription = term.GetString("Description")
	app.AccountID = session.ReadAccountID()
	app.PaymentPlan = "PROTOTYPE"

	app, err := account.SaveNewApp(app)
	if err != nil {
		term.Section()
		term.Println(err.Error())
	} else {
		term.Section()
		term.Printf("Successfully created app '%s'\n", app.AppName)
	}

	return app, err
}

func selectTemplate() template.Template {
	templates := template.All()

	term.Section()
	term.Println("Choose a template for you app:")
	for i, template := range templates {
		term.Printf("  %d) %s\n", i+1, template.Label)
	}

	term.Section()
	for {
		selected := -1 + term.GetInt(fmt.Sprintf("Please select (1-%d)", len(templates)))
		if selected >= 0 && selected < len(templates) {
			return templates[selected]
		}
	}
}

func selectPublicDir() string {
	dir := term.GetString("Select deployable directory [default: ./public]")
	if dir == "" {
		dir = "./public"
	}
	return dir
}

func selectSubdomainIfNeeded() {
	app, err := account.GetCurrentApp()
	fail.Handle(err)
	if app.HostingSubdomain == "" {
		selectSubdomain(app.AppID, true)
	}
}

func selectSubdomain(appID string, required bool) {
	app, _ := account.GetAppByID(appID)
	log.Debugf("Subdomain app: %v", app)
	for {
		if required {
			app.HostingSubdomain = term.GetString("Choose a *.appstax.io subdomain for web hosting")
		} else {
			term.Println("Choose a *.appstax.io subdomain for web hosting:")
			term.Println("(Leave this blank if you wish to decide this later.)")
			app.HostingSubdomain = term.GetString("Subdomain")
		}

		if app.HostingSubdomain != "" {
			err1 := account.SaveApp(app)
			if err1 != nil {
				term.Println(err1.Error())
			}
			err2 := account.AddCorsOrigin(appID, fmt.Sprintf("http://%s.appstax.io", app.HostingSubdomain))
			if err2 != nil {
				term.Println(err2.Error())
			}
			if err1 == nil && err2 == nil {
				term.Printf("Successfully configured %s.appstax.io\n", app.HostingSubdomain)
				return
			}
		} else if !required {
			return
		}
	}
}

func createPublicDir() {
	dir := config.Read().PublicDir
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		err = os.MkdirAll(dir, 0700)
		fail.Handle(err)
		log.Debugf("Created public directory '%s'", dir)
	} else {
		log.Debugf("Not creating public directory. '%s' already exists.", dir)
	}
}
<commit_msg>Don't ask for public dir when setting up ios templates.<commit_after>package commands

import (
	"appstax-cli/appstax/account"
	"appstax-cli/appstax/config"
	"appstax-cli/appstax/fail"
	"appstax-cli/appstax/log"
	"appstax-cli/appstax/session"
	"appstax-cli/appstax/template"
	"appstax-cli/appstax/term"
	"fmt"
	"github.com/codegangsta/cli"
	"os"
	"strings"
)

func DoInit(c *cli.Context) {
	useOptions(c)
	loginIfNeeded()

	app, err := selectApp()
	if err != nil {
		return
	}

	tpl := selectTemplate()

	publicDir := "./public"
	serverDir := "./server"
	if tpl.Name == "none" {
		term.Section()
		publicDir = selectPublicDir()
	}
	writeConfig(app, publicDir, serverDir)

	if !strings.HasPrefix(tpl.Name, "ios/") {
		createPublicDir()
	}

	if tpl.Name != "none" {
		term.Section()
		term.Println("Setting up template... ")
		template.Install(tpl)
		term.Println("Done.")
	}

	if !strings.HasPrefix(tpl.Name, "ios/") {
		term.Section()
		selectSubdomain(app.AppID, false)
	}

	term.Section()
	term.Println("All done!")
	if !strings.HasPrefix(tpl.Name, "ios/") {
		term.Println("Now run 'appstax deploy' when you are ready to upload your public files.")
	}
}

func selectApp() (account.App, error) {
	apps, _ := account.GetUserApps()
	selected := -1
	if len(apps) == 0 {
		term.Section()
		term.Println("You have not created any apps yet! Create one now:")
	} else {
		term.Section()
		term.Println("Choose which app to configure or create a new one:")
		for i, app := range apps {
			term.Printf("  %d) %s\n", i+1, app.AppName)
		}
		term.Printf("  %d) Create a new app\n", len(apps)+1)
		term.Section()
		for selected < 0 || selected > len(apps) {
			selected = -1 + term.GetInt(fmt.Sprintf("Please select (1-%d)", len(apps)+1))
		}
	}
	if selected >= 0 && selected < len(apps) {
		return apps[selected], nil
	} else {
		return createApp()
	}
}

func createApp() (account.App, error) {
	app := account.App{}
	term.Section()
	app.AppName = term.GetString("App name")
	app.AppDescription = term.GetString("Description")
	app.AccountID = session.ReadAccountID()
	app.PaymentPlan = "PROTOTYPE"

	app, err := account.SaveNewApp(app)
	if err != nil {
		term.Section()
		term.Println(err.Error())
	} else {
		term.Section()
		term.Printf("Successfully created app '%s'\n", app.AppName)
	}

	return app, err
}

func selectTemplate() template.Template {
	templates := template.All()

	term.Section()
	term.Println("Choose a template for you app:")
	for i, template := range templates {
		term.Printf("  %d) %s\n", i+1, template.Label)
	}

	term.Section()
	for {
		selected := -1 + term.GetInt(fmt.Sprintf("Please select (1-%d)", len(templates)))
		if selected >= 0 && selected < len(templates) {
			return templates[selected]
		}
	}
}

func selectPublicDir() string {
	dir := term.GetString("Select deployable directory [default: ./public]")
	if dir == "" {
		dir = "./public"
	}
	return dir
}

func selectSubdomainIfNeeded() {
	app, err := account.GetCurrentApp()
	fail.Handle(err)
	if app.HostingSubdomain == "" {
		selectSubdomain(app.AppID, true)
	}
}

func selectSubdomain(appID string, required bool) {
	app, _ := account.GetAppByID(appID)
	log.Debugf("Subdomain app: %v", app)
	for {
		if required {
			app.HostingSubdomain = term.GetString("Choose a *.appstax.io subdomain for web hosting")
		} else {
			term.Println("Choose a *.appstax.io subdomain for web hosting:")
			term.Println("(Leave this blank if you wish to decide this later.)")
			app.HostingSubdomain = term.GetString("Subdomain")
		}

		if app.HostingSubdomain != "" {
			err1 := account.SaveApp(app)
			if err1 != nil {
				term.Println(err1.Error())
			}
			err2 := account.AddCorsOrigin(appID, fmt.Sprintf("http://%s.appstax.io", app.HostingSubdomain))
			if err2 != nil {
				term.Println(err2.Error())
			}
			if err1 == nil && err2 == nil {
				term.Printf("Successfully configured %s.appstax.io\n", app.HostingSubdomain)
				return
			}
		} else if !required {
			return
		}
	}
}

func createPublicDir() {
	dir := config.Read().PublicDir
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		err = os.MkdirAll(dir, 0700)
		fail.Handle(err)
		log.Debugf("Created public directory '%s'", dir)
	} else {
		log.Debugf("Not creating public directory. '%s' already exists.", dir)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes 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 factory

import (
	"context"
	"fmt"
	"net"
	"net/url"
	"path"
	"sync"
	"sync/atomic"
	"time"

	grpcprom "github.com/grpc-ecosystem/go-grpc-prometheus"
	"go.etcd.io/etcd/clientv3"
	"go.etcd.io/etcd/pkg/transport"
	"google.golang.org/grpc"

	"k8s.io/apimachinery/pkg/runtime"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apiserver/pkg/server/egressselector"
	"k8s.io/apiserver/pkg/storage"
	"k8s.io/apiserver/pkg/storage/etcd3"
	"k8s.io/apiserver/pkg/storage/etcd3/metrics"
	"k8s.io/apiserver/pkg/storage/storagebackend"
	"k8s.io/apiserver/pkg/storage/value"
	"k8s.io/component-base/metrics/legacyregistry"
	"k8s.io/klog/v2"
)

const (
	// The short keepalive timeout and interval have been chosen to aggressively
	// detect a failed etcd server without introducing much overhead.
	keepaliveTime    = 30 * time.Second
	keepaliveTimeout = 10 * time.Second

	// dialTimeout is the timeout for failing to establish a connection.
	// It is set to 20 seconds as times shorter than that will cause TLS connections to fail
	// on heavily loaded arm64 CPUs (issue #64649)
	dialTimeout = 20 * time.Second

	dbMetricsMonitorJitter = 0.5
)

func init() {
	// grpcprom auto-registers (via an init function) their client metrics, since we are opting out of
	// using the global prometheus registry and using our own wrapped global registry,
	// we need to explicitly register these metrics to our global registry here.
	// For reference: https://github.com/kubernetes/kubernetes/pull/81387
	legacyregistry.RawMustRegister(grpcprom.DefaultClientMetrics)
	dbMetricsMonitors = make(map[string]struct{})
}

func newETCD3HealthCheck(c storagebackend.Config) (func() error, error) {
	// constructing the etcd v3 client blocks and times out if etcd is not available.
	// retry in a loop in the background until we successfully create the client, storing the client or error encountered

	clientValue := &atomic.Value{}

	clientErrMsg := &atomic.Value{}
	clientErrMsg.Store("etcd client connection not yet established")

	go wait.PollUntil(time.Second, func() (bool, error) {
		client, err := newETCD3Client(c.Transport)
		if err != nil {
			clientErrMsg.Store(err.Error())
			return false, nil
		}
		clientValue.Store(client)
		clientErrMsg.Store("")
		return true, nil
	}, wait.NeverStop)

	return func() error {
		if errMsg := clientErrMsg.Load().(string); len(errMsg) > 0 {
			return fmt.Errorf(errMsg)
		}
		client := clientValue.Load().(*clientv3.Client)
		healthcheckTimeout := storagebackend.DefaultHealthcheckTimeout
		if c.HealthcheckTimeout != time.Duration(0) {
			healthcheckTimeout = c.HealthcheckTimeout
		}
		ctx, cancel := context.WithTimeout(context.Background(), healthcheckTimeout)
		defer cancel()
		// See https://github.com/etcd-io/etcd/blob/c57f8b3af865d1b531b979889c602ba14377420e/etcdctl/ctlv3/command/ep_command.go#L118
		_, err := client.Get(ctx, path.Join("/", c.Prefix, "health"))
		if err == nil {
			return nil
		}
		return fmt.Errorf("error getting data from etcd: %v", err)
	}, nil
}

func newETCD3Client(c storagebackend.TransportConfig) (*clientv3.Client, error) {
	tlsInfo := transport.TLSInfo{
		CertFile:      c.CertFile,
		KeyFile:       c.KeyFile,
		TrustedCAFile: c.TrustedCAFile,
	}
	tlsConfig, err := tlsInfo.ClientConfig()
	if err != nil {
		return nil, err
	}
	// NOTE: Client relies on nil tlsConfig
	// for non-secure connections, update the implicit variable
	if len(c.CertFile) == 0 && len(c.KeyFile) == 0 && len(c.TrustedCAFile) == 0 {
		tlsConfig = nil
	}
	networkContext := egressselector.Etcd.AsNetworkContext()
	var egressDialer utilnet.DialFunc
	if c.EgressLookup != nil {
		egressDialer, err = c.EgressLookup(networkContext)
		if err != nil {
			return nil, err
		}
	}
	dialOptions := []grpc.DialOption{
		grpc.WithBlock(), // block until the underlying connection is up
		grpc.WithUnaryInterceptor(grpcprom.UnaryClientInterceptor),
		grpc.WithStreamInterceptor(grpcprom.StreamClientInterceptor),
	}
	if egressDialer != nil {
		dialer := func(ctx context.Context, addr string) (net.Conn, error) {
			u, err := url.Parse(addr)
			if err != nil {
				return nil, err
			}
			return egressDialer(ctx, "tcp", u.Host)
		}
		dialOptions = append(dialOptions, grpc.WithContextDialer(dialer))
	}
	cfg := clientv3.Config{
		DialTimeout:          dialTimeout,
		DialKeepAliveTime:    keepaliveTime,
		DialKeepAliveTimeout: keepaliveTimeout,
		DialOptions:          dialOptions,
		Endpoints:            c.ServerList,
		TLS:                  tlsConfig,
	}

	return clientv3.New(cfg)
}

type runningCompactor struct {
	interval time.Duration
	cancel   context.CancelFunc
	client   *clientv3.Client
	refs     int
}

var (
	// compactorsMu guards access to compactors map
	compactorsMu sync.Mutex
	compactors   = map[string]*runningCompactor{}
	// dbMetricsMonitorsMu guards access to dbMetricsMonitors map
	dbMetricsMonitorsMu sync.Mutex
	dbMetricsMonitors   map[string]struct{}
)

// startCompactorOnce start one compactor per transport. If the interval get smaller on repeated calls, the
// compactor is replaced. A destroy func is returned. If all destroy funcs with the same transport are called,
// the compactor is stopped.
func startCompactorOnce(c storagebackend.TransportConfig, interval time.Duration) (func(), error) {
	compactorsMu.Lock()
	defer compactorsMu.Unlock()

	key := fmt.Sprintf("%v", c) // gives: {[server1 server2] keyFile certFile caFile}
	if compactor, foundBefore := compactors[key]; !foundBefore || compactor.interval > interval {
		compactorClient, err := newETCD3Client(c)
		if err != nil {
			return nil, err
		}

		if foundBefore {
			// replace compactor
			compactor.cancel()
			compactor.client.Close()
		} else {
			// start new compactor
			compactor = &runningCompactor{}
			compactors[key] = compactor
		}

		ctx, cancel := context.WithCancel(context.Background())

		compactor.interval = interval
		compactor.cancel = cancel
		compactor.client = compactorClient

		etcd3.StartCompactor(ctx, compactorClient, interval)
	}

	compactors[key].refs++

	return func() {
		compactorsMu.Lock()
		defer compactorsMu.Unlock()

		compactor := compactors[key]
		compactor.refs--
		if compactor.refs == 0 {
			compactor.cancel()
			compactor.client.Close()
			delete(compactors, key)
		}
	}, nil
}

func newETCD3Storage(c storagebackend.Config, newFunc func() runtime.Object) (storage.Interface, DestroyFunc, error) {
	stopCompactor, err := startCompactorOnce(c.Transport, c.CompactionInterval)
	if err != nil {
		return nil, nil, err
	}

	client, err := newETCD3Client(c.Transport)
	if err != nil {
		stopCompactor()
		return nil, nil, err
	}

	stopDBSizeMonitor, err := startDBSizeMonitorPerEndpoint(client, c.DBMetricPollInterval)
	if err != nil {
		return nil, nil, err
	}

	var once sync.Once
	destroyFunc := func() {
		// we know that storage destroy funcs are called multiple times (due to reuse in subresources).
		// Hence, we only destroy once.
		// TODO: fix duplicated storage destroy calls higher level
		once.Do(func() {
			stopCompactor()
			stopDBSizeMonitor()
			client.Close()
		})
	}
	transformer := c.Transformer
	if transformer == nil {
		transformer = value.IdentityTransformer
	}
	return etcd3.New(client, c.Codec, newFunc, c.Prefix, transformer, c.Paging, c.LeaseManagerConfig), destroyFunc, nil
}

// startDBSizeMonitorPerEndpoint starts a loop to monitor etcd database size and update the
// corresponding metric etcd_db_total_size_in_bytes for each etcd server endpoint.
func startDBSizeMonitorPerEndpoint(client *clientv3.Client, interval time.Duration) (func(), error) {
	if interval == 0 {
		return func() {}, nil
	}
	dbMetricsMonitorsMu.Lock()
	defer dbMetricsMonitorsMu.Unlock()

	ctx, cancel := context.WithCancel(context.Background())
	for _, ep := range client.Endpoints() {
		if _, found := dbMetricsMonitors[ep]; found {
			continue
		}
		dbMetricsMonitors[ep] = struct{}{}
		endpoint := ep
		klog.V(4).Infof("Start monitoring storage db size metric for endpoint %s with polling interval %v", endpoint, interval)
		go wait.JitterUntilWithContext(ctx, func(context.Context) {
			epStatus, err := client.Maintenance.Status(ctx, endpoint)
			if err != nil {
				klog.V(4).Infof("Failed to get storage db size for ep %s: %v", endpoint, err)
				metrics.UpdateEtcdDbSize(endpoint, -1)
			} else {
				metrics.UpdateEtcdDbSize(endpoint, epStatus.DbSize)
			}
		}, interval, dbMetricsMonitorJitter, true)
	}

	return func() {
		cancel()
	}, nil
}
<commit_msg>use PermitWithoutStream=true for etcd: send pings even without active streams<commit_after>/*
Copyright 2016 The Kubernetes 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 factory

import (
	"context"
	"fmt"
	"net"
	"net/url"
	"path"
	"sync"
	"sync/atomic"
	"time"

	grpcprom "github.com/grpc-ecosystem/go-grpc-prometheus"
	"go.etcd.io/etcd/clientv3"
	"go.etcd.io/etcd/pkg/transport"
	"google.golang.org/grpc"

	"k8s.io/apimachinery/pkg/runtime"
	utilnet "k8s.io/apimachinery/pkg/util/net"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/apiserver/pkg/server/egressselector"
	"k8s.io/apiserver/pkg/storage"
	"k8s.io/apiserver/pkg/storage/etcd3"
	"k8s.io/apiserver/pkg/storage/etcd3/metrics"
	"k8s.io/apiserver/pkg/storage/storagebackend"
	"k8s.io/apiserver/pkg/storage/value"
	"k8s.io/component-base/metrics/legacyregistry"
	"k8s.io/klog/v2"
)

const (
	// The short keepalive timeout and interval have been chosen to aggressively
	// detect a failed etcd server without introducing much overhead.
	keepaliveTime    = 30 * time.Second
	keepaliveTimeout = 10 * time.Second

	// dialTimeout is the timeout for failing to establish a connection.
	// It is set to 20 seconds as times shorter than that will cause TLS connections to fail
	// on heavily loaded arm64 CPUs (issue #64649)
	dialTimeout = 20 * time.Second

	dbMetricsMonitorJitter = 0.5
)

func init() {
	// grpcprom auto-registers (via an init function) their client metrics, since we are opting out of
	// using the global prometheus registry and using our own wrapped global registry,
	// we need to explicitly register these metrics to our global registry here.
	// For reference: https://github.com/kubernetes/kubernetes/pull/81387
	legacyregistry.RawMustRegister(grpcprom.DefaultClientMetrics)
	dbMetricsMonitors = make(map[string]struct{})
}

func newETCD3HealthCheck(c storagebackend.Config) (func() error, error) {
	// constructing the etcd v3 client blocks and times out if etcd is not available.
	// retry in a loop in the background until we successfully create the client, storing the client or error encountered

	clientValue := &atomic.Value{}

	clientErrMsg := &atomic.Value{}
	clientErrMsg.Store("etcd client connection not yet established")

	go wait.PollUntil(time.Second, func() (bool, error) {
		client, err := newETCD3Client(c.Transport)
		if err != nil {
			clientErrMsg.Store(err.Error())
			return false, nil
		}
		clientValue.Store(client)
		clientErrMsg.Store("")
		return true, nil
	}, wait.NeverStop)

	return func() error {
		if errMsg := clientErrMsg.Load().(string); len(errMsg) > 0 {
			return fmt.Errorf(errMsg)
		}
		client := clientValue.Load().(*clientv3.Client)
		healthcheckTimeout := storagebackend.DefaultHealthcheckTimeout
		if c.HealthcheckTimeout != time.Duration(0) {
			healthcheckTimeout = c.HealthcheckTimeout
		}
		ctx, cancel := context.WithTimeout(context.Background(), healthcheckTimeout)
		defer cancel()
		// See https://github.com/etcd-io/etcd/blob/c57f8b3af865d1b531b979889c602ba14377420e/etcdctl/ctlv3/command/ep_command.go#L118
		_, err := client.Get(ctx, path.Join("/", c.Prefix, "health"))
		if err == nil {
			return nil
		}
		return fmt.Errorf("error getting data from etcd: %v", err)
	}, nil
}

func newETCD3Client(c storagebackend.TransportConfig) (*clientv3.Client, error) {
	tlsInfo := transport.TLSInfo{
		CertFile:      c.CertFile,
		KeyFile:       c.KeyFile,
		TrustedCAFile: c.TrustedCAFile,
	}
	tlsConfig, err := tlsInfo.ClientConfig()
	if err != nil {
		return nil, err
	}
	// NOTE: Client relies on nil tlsConfig
	// for non-secure connections, update the implicit variable
	if len(c.CertFile) == 0 && len(c.KeyFile) == 0 && len(c.TrustedCAFile) == 0 {
		tlsConfig = nil
	}
	networkContext := egressselector.Etcd.AsNetworkContext()
	var egressDialer utilnet.DialFunc
	if c.EgressLookup != nil {
		egressDialer, err = c.EgressLookup(networkContext)
		if err != nil {
			return nil, err
		}
	}
	dialOptions := []grpc.DialOption{
		grpc.WithBlock(), // block until the underlying connection is up
		grpc.WithUnaryInterceptor(grpcprom.UnaryClientInterceptor),
		grpc.WithStreamInterceptor(grpcprom.StreamClientInterceptor),
	}
	if egressDialer != nil {
		dialer := func(ctx context.Context, addr string) (net.Conn, error) {
			u, err := url.Parse(addr)
			if err != nil {
				return nil, err
			}
			return egressDialer(ctx, "tcp", u.Host)
		}
		dialOptions = append(dialOptions, grpc.WithContextDialer(dialer))
	}
	cfg := clientv3.Config{
		DialTimeout:          dialTimeout,
		DialKeepAliveTime:    keepaliveTime,
		DialKeepAliveTimeout: keepaliveTimeout,
		PermitWithoutStream:  true,
		DialOptions:          dialOptions,
		Endpoints:            c.ServerList,
		TLS:                  tlsConfig,
	}

	return clientv3.New(cfg)
}

type runningCompactor struct {
	interval time.Duration
	cancel   context.CancelFunc
	client   *clientv3.Client
	refs     int
}

var (
	// compactorsMu guards access to compactors map
	compactorsMu sync.Mutex
	compactors   = map[string]*runningCompactor{}
	// dbMetricsMonitorsMu guards access to dbMetricsMonitors map
	dbMetricsMonitorsMu sync.Mutex
	dbMetricsMonitors   map[string]struct{}
)

// startCompactorOnce start one compactor per transport. If the interval get smaller on repeated calls, the
// compactor is replaced. A destroy func is returned. If all destroy funcs with the same transport are called,
// the compactor is stopped.
func startCompactorOnce(c storagebackend.TransportConfig, interval time.Duration) (func(), error) {
	compactorsMu.Lock()
	defer compactorsMu.Unlock()

	key := fmt.Sprintf("%v", c) // gives: {[server1 server2] keyFile certFile caFile}
	if compactor, foundBefore := compactors[key]; !foundBefore || compactor.interval > interval {
		compactorClient, err := newETCD3Client(c)
		if err != nil {
			return nil, err
		}

		if foundBefore {
			// replace compactor
			compactor.cancel()
			compactor.client.Close()
		} else {
			// start new compactor
			compactor = &runningCompactor{}
			compactors[key] = compactor
		}

		ctx, cancel := context.WithCancel(context.Background())

		compactor.interval = interval
		compactor.cancel = cancel
		compactor.client = compactorClient

		etcd3.StartCompactor(ctx, compactorClient, interval)
	}

	compactors[key].refs++

	return func() {
		compactorsMu.Lock()
		defer compactorsMu.Unlock()

		compactor := compactors[key]
		compactor.refs--
		if compactor.refs == 0 {
			compactor.cancel()
			compactor.client.Close()
			delete(compactors, key)
		}
	}, nil
}

func newETCD3Storage(c storagebackend.Config, newFunc func() runtime.Object) (storage.Interface, DestroyFunc, error) {
	stopCompactor, err := startCompactorOnce(c.Transport, c.CompactionInterval)
	if err != nil {
		return nil, nil, err
	}

	client, err := newETCD3Client(c.Transport)
	if err != nil {
		stopCompactor()
		return nil, nil, err
	}

	stopDBSizeMonitor, err := startDBSizeMonitorPerEndpoint(client, c.DBMetricPollInterval)
	if err != nil {
		return nil, nil, err
	}

	var once sync.Once
	destroyFunc := func() {
		// we know that storage destroy funcs are called multiple times (due to reuse in subresources).
		// Hence, we only destroy once.
		// TODO: fix duplicated storage destroy calls higher level
		once.Do(func() {
			stopCompactor()
			stopDBSizeMonitor()
			client.Close()
		})
	}
	transformer := c.Transformer
	if transformer == nil {
		transformer = value.IdentityTransformer
	}
	return etcd3.New(client, c.Codec, newFunc, c.Prefix, transformer, c.Paging, c.LeaseManagerConfig), destroyFunc, nil
}

// startDBSizeMonitorPerEndpoint starts a loop to monitor etcd database size and update the
// corresponding metric etcd_db_total_size_in_bytes for each etcd server endpoint.
func startDBSizeMonitorPerEndpoint(client *clientv3.Client, interval time.Duration) (func(), error) {
	if interval == 0 {
		return func() {}, nil
	}
	dbMetricsMonitorsMu.Lock()
	defer dbMetricsMonitorsMu.Unlock()

	ctx, cancel := context.WithCancel(context.Background())
	for _, ep := range client.Endpoints() {
		if _, found := dbMetricsMonitors[ep]; found {
			continue
		}
		dbMetricsMonitors[ep] = struct{}{}
		endpoint := ep
		klog.V(4).Infof("Start monitoring storage db size metric for endpoint %s with polling interval %v", endpoint, interval)
		go wait.JitterUntilWithContext(ctx, func(context.Context) {
			epStatus, err := client.Maintenance.Status(ctx, endpoint)
			if err != nil {
				klog.V(4).Infof("Failed to get storage db size for ep %s: %v", endpoint, err)
				metrics.UpdateEtcdDbSize(endpoint, -1)
			} else {
				metrics.UpdateEtcdDbSize(endpoint, epStatus.DbSize)
			}
		}, interval, dbMetricsMonitorJitter, true)
	}

	return func() {
		cancel()
	}, nil
}
<|endoftext|>


<commit_before>package notebook

import (
    "errors"
)

var ErrorEndOfNotesReached = errors.New("The end of notes was reached")

// Notes is an interface holding a
// list of notes
type Notes interface {
    // Next moves to the next note
    Next() error

    // Value returns the current note with its name
    Value() (string, Note)
}
<commit_msg>fix(notebook): fixes the return of the Notes-related function Value<commit_after>package notebook

import (
    "errors"
)

var ErrorEndOfNotesReached = errors.New("The end of notes was reached")

// Notes is an interface holding a
// list of notes
type Notes interface {
    // Next moves to the next note
    Next() error

    // Value returns the current note with its name
    Value() (string, *Note)
}
<|endoftext|>


<commit_before>package certs

import (
	"crypto/rand"
	"crypto/rsa"

	"github.com/xenolf/lego/acme"
)

const (
	rsaKeySize = 2048
)

// Create creates a new certificate
func (c *Cert) Create() {
	privateKey, err := rsa.GenerateKey(rand.Reader, rsaKeySize)
	if err != nil {
		c.ErrChan <- err
		return
	}

	var u = &user{
		Email: c.Email,
		key:   privateKey,
	}
	client, err := acme.NewClient(c.AcmeServer, u, acme.RSA2048)
	if err != nil {
		c.ErrChan <- err
		return
	}

	reg, err := client.Register()
	if err != nil {
		c.ErrChan <- err
		return
	}
	u.Registration = reg

	err = client.AgreeToTOS()
	if err != nil {
		c.ErrChan <- err
		return
	}

	client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSSNI01})
	challenge := &challengeProvider{
		ComChan:       c.ComChan,
		ChallengeChan: c.ChallengeChan,
		ErrChan:       c.ErrChan,
	}
	client.SetChallengeProvider(acme.HTTP01, challenge)

	certificate, errs := client.ObtainCertificate(c.Domains, false, nil)
	if len(errs) > 0 {
		for _, e := range errs {
			c.ErrChan <- e
		}
	}

	c.CertChan <- certificate
}
<commit_msg>bundle the certificates<commit_after>package certs

import (
	"crypto/rand"
	"crypto/rsa"

	"github.com/xenolf/lego/acme"
)

const (
	rsaKeySize = 2048
)

// Create creates a new certificate
func (c *Cert) Create() {
	privateKey, err := rsa.GenerateKey(rand.Reader, rsaKeySize)
	if err != nil {
		c.ErrChan <- err
		return
	}

	var u = &user{
		Email: c.Email,
		key:   privateKey,
	}
	client, err := acme.NewClient(c.AcmeServer, u, acme.RSA2048)
	if err != nil {
		c.ErrChan <- err
		return
	}

	reg, err := client.Register()
	if err != nil {
		c.ErrChan <- err
		return
	}
	u.Registration = reg

	err = client.AgreeToTOS()
	if err != nil {
		c.ErrChan <- err
		return
	}

	client.ExcludeChallenges([]acme.Challenge{acme.DNS01, acme.TLSSNI01})
	challenge := &challengeProvider{
		ComChan:       c.ComChan,
		ChallengeChan: c.ChallengeChan,
		ErrChan:       c.ErrChan,
	}
	client.SetChallengeProvider(acme.HTTP01, challenge)

	certificate, errs := client.ObtainCertificate(c.Domains, true, nil)
	if len(errs) > 0 {
		for _, e := range errs {
			c.ErrChan <- e
		}
	}

	c.CertChan <- certificate
}
<|endoftext|>


<commit_before>// Exercise 1.5: Change the Lissajous programi's color palette to green on black, for added authenticity.
package main

import (
	"image"
	"image/color"
	"image/gif"
	"io"
	"math"
	"math/rand"
	"os"
)

import (
	"log"
	"net/http"
	"time"
)

var palette = []color.Color{
	color.RGBA{0x00, 0xff, 0x00, 0xff}, // Green
	color.Black,
}

const (
	greenIndex = 0 // first color in palette
	blackIndex = 1 // next color in palette
)

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	if len(os.Args) > 1 && os.Args[1] == "web" {
		handler := func(w http.ResponseWriter, r *http.Request) {
			lissajous(w)
		}
		http.HandleFunc("/", handler)
		log.Fatal(http.ListenAndServe("0.0.0.0:8000", nil))
		return
	}
	lissajous(os.Stdout)
}

func lissajous(out io.Writer) {
	const (
		cycles  = 5     // number of complete x oscillator revolutions
		res     = 0.001 // angular resolution
		size    = 100   // image canvas covers [-size..+size]
		nframes = 64    // number of animation frames
		delay   = 8     // delay between frames in 10ms units
	)
	freq := rand.Float64() * 3.0 // relative frequency of y oscillator
	anim := gif.GIF{LoopCount: nframes}
	phase := 0.0 // phase difference
	for i := 0; i < nframes; i++ {
		rect := image.Rect(0, 0, 2*size+1, 2*size+1)
		img := image.NewPaletted(rect, palette)
		for t := 0.0; t < cycles*2*math.Pi; t += res {
			x := math.Sin(t)
			y := math.Sin(t*freq + phase)
			img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),
				blackIndex)
		}
		phase += 0.1
		anim.Delay = append(anim.Delay, delay)
		anim.Image = append(anim.Image, img)
	}
	gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors
}
<commit_msg>corrected Exercise 1.5 spelling mistake<commit_after>// Exercise 1.5: Change the Lissajous program's color palette to green on black, for added authenticity.
package main

import (
	"image"
	"image/color"
	"image/gif"
	"io"
	"math"
	"math/rand"
	"os"
)

import (
	"log"
	"net/http"
	"time"
)

var palette = []color.Color{
	color.RGBA{0x00, 0xff, 0x00, 0xff}, // Green
	color.Black,
}

const (
	greenIndex = 0 // first color in palette
	blackIndex = 1 // next color in palette
)

func main() {
	rand.Seed(time.Now().UTC().UnixNano())

	if len(os.Args) > 1 && os.Args[1] == "web" {
		handler := func(w http.ResponseWriter, r *http.Request) {
			lissajous(w)
		}
		http.HandleFunc("/", handler)
		log.Fatal(http.ListenAndServe("0.0.0.0:8000", nil))
		return
	}
	lissajous(os.Stdout)
}

func lissajous(out io.Writer) {
	const (
		cycles  = 5     // number of complete x oscillator revolutions
		res     = 0.001 // angular resolution
		size    = 100   // image canvas covers [-size..+size]
		nframes = 64    // number of animation frames
		delay   = 8     // delay between frames in 10ms units
	)
	freq := rand.Float64() * 3.0 // relative frequency of y oscillator
	anim := gif.GIF{LoopCount: nframes}
	phase := 0.0 // phase difference
	for i := 0; i < nframes; i++ {
		rect := image.Rect(0, 0, 2*size+1, 2*size+1)
		img := image.NewPaletted(rect, palette)
		for t := 0.0; t < cycles*2*math.Pi; t += res {
			x := math.Sin(t)
			y := math.Sin(t*freq + phase)
			img.SetColorIndex(size+int(x*size+0.5), size+int(y*size+0.5),
				blackIndex)
		}
		phase += 0.1
		anim.Delay = append(anim.Delay, delay)
		anim.Image = append(anim.Image, img)
	}
	gif.EncodeAll(out, &anim) // NOTE: ignoring encoding errors
}
<|endoftext|>


<commit_before>package isolated

import (
	. "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers"
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("domains command", func() {
	Describe("help", func() {
		It("appears in cf help -a", func() {
			session := helpers.CF("help", "-a")
			Eventually(session).Should(Exit(0))
			Expect(session).To(HaveCommandInCategoryWithDescription("domains", "DOMAINS", "List domains in the target org"))
		})

		When("--help flag is set", func() {
			It("displays command usage to output", func() {
				session := helpers.CF("domains", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say(`\s+domains - List domains in the target org`))

				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say(`\s+cf domains`))

				Eventually(session).Should(Say("EXAMPLES:"))
				Eventually(session).Should(Say(`\s+cf domains`))
				Eventually(session).Should(Say(`\s+cf domains --labels 'environment in \(production,staging\),tier in \(backend\)'`))
				Eventually(session).Should(Say(`\s+cf domains --labels 'env=dev,!chargeback-code,tier in \(backend,worker\)'`))

				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say(`--labels\s+Selector to filter domains by labels`))

				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say(`\s+create-private-domain, create-route, create-shared-domain, routes, set-label`))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("user is not logged in", func() {
		BeforeEach(func() {
			helpers.LogoutCF()
		})

		It("displays an error message and fails", func() {
			session := helpers.CF("domains")
			Eventually(session).Should(Say("FAILED"))
			Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in."))
			Eventually(session).Should(Exit(1))
		})
	})

	When("a random argument is passed to the command", func() {
		It("displays an error message and fails", func() {
			session := helpers.CF("domains", "random-arg")
			Eventually(session).Should(Say("FAILED"))
			Eventually(session.Err).Should(Say(`Incorrect Usage: unexpected argument "random-arg"`))
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say(`\s+domains - List domains in the target org`))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say(`\s+cf domains`))
			Eventually(session).Should(Say("OPTIONS:"))
			Eventually(session).Should(Say(`--labels\s+Selector to filter domains by labels`))
			Eventually(session).Should(Say("SEE ALSO:"))
			Eventually(session).Should(Say(`\s+create-private-domain, create-route, create-shared-domain, routes`))
			Eventually(session).Should(Exit(1))
		})
	})

	When("logged in", func() {
		var userName string

		BeforeEach(func() {
			userName, _ = helpers.GetCredentials()
		})

		When("no org is targeted", func() {
			BeforeEach(func() {
				helpers.LoginCF()
			})

			It("displays an error message and fails", func() {
				session := helpers.CF("domains")
				Eventually(session).Should(Say("FAILED"))
				Eventually(session.Err).Should(Say(`No org targeted, use 'cf target -o ORG' to target an org.`))
				Eventually(session).Should(Exit(1))
			})
		})

		When("an org is targeted", func() {
			var (
				orgName       string
				spaceName     string
				sharedDomain1 helpers.Domain
				sharedDomain2 helpers.Domain
			)

			BeforeEach(func() {
				orgName = helpers.NewOrgName()
				spaceName = helpers.NewSpaceName()
				helpers.SetupCF(orgName, spaceName)

				sharedDomain1 = helpers.NewDomain(orgName, helpers.NewDomainName("a"))
				sharedDomain1.CreateShared()

				sharedDomain2 = helpers.NewDomain(orgName, helpers.NewDomainName("b"))
				sharedDomain2.CreateShared()
				Eventually(helpers.CF("set-label", "domain", sharedDomain1.Name, "keyfor1=valuefor1")).Should(Exit(0))
			})
			AfterEach(func() {
				Eventually(helpers.CF("delete-shared-domain", sharedDomain1.Name, "-f")).Should(Exit(0))
				Eventually(helpers.CF("delete-shared-domain", sharedDomain2.Name, "-f")).Should(Exit(0))
				Eventually(helpers.CF("delete-space", spaceName, "-f")).Should(Exit(0))
				Eventually(helpers.CF("delete-org", orgName, "-f")).Should(Exit(0))
			})

			When("the targeted org has shared domains", func() {

				It("displays the shared domains and denotes that they are shared", func() {
					session := helpers.CF("domains")
					Eventually(session).Should(Exit(0))

					Expect(session).Should(Say(`Getting domains in org %s as %s\.\.\.`, orgName, userName))
					Expect(session).Should(Say(`name\s+availability\s+internal`))
					Expect(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
					Expect(session).Should(Say(`%s\s+shared\s+`, sharedDomain2.Name))
				})

				It("displays the shared domains and denotes that they are shared for matching labels only", func() {
					session := helpers.CF("domains", "--labels", "keyfor1=valuefor1")
					Eventually(session).Should(Exit(0))

					Expect(session).Should(Say(`Getting domains in org %s as %s\.\.\.`, orgName, userName))
					Expect(session).Should(Say(`name\s+availability\s+internal`))
					Expect(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
					Expect(session).ShouldNot(Say(`%s\s+shared\s+`, sharedDomain2.Name))
				})

				When("the shared domain is internal", func() {
					var internalDomainName string

					BeforeEach(func() {
						internalDomainName = helpers.NewDomainName()
						internalDomain := helpers.NewDomain(orgName, internalDomainName)
						internalDomain.CreateInternal()
					})
					AfterEach(func() {
						Eventually(helpers.CF("delete-shared-domain", internalDomainName, "-f")).Should(Exit(0))
					})

					It("displays the internal flag on the shared domain", func() {
						session := helpers.CF("domains")
						Eventually(session).Should(Exit(0))

						Expect(session).Should(Say(`Getting domains in org %s as %s`, orgName, userName))
						Expect(session).Should(Say(`name\s+availability\s+internal`))
						Expect(session).Should(Say(`%s\s+shared\s+true`, internalDomainName))
					})

					It("displays the shared domains and denotes that they are shared for matching labels only", func() {
						session := helpers.CF("domains", "--labels", "keyfor1=valuefor1")
						Eventually(session).Should(Exit(0))

						Expect(session).Should(Say(`Getting domains in org %s as %s\.\.\.`, orgName, userName))
						Expect(session).Should(Say(`name\s+availability\s+internal`))
						Expect(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
						Expect(session).ShouldNot(Say(`%s\s+shared\s+`, sharedDomain2.Name))
						Expect(session).ShouldNot(Say(internalDomainName))

					})
				})
			})

			When("the targeted org has a private domain", func() {
				var privateDomain1, privateDomain2 helpers.Domain

				BeforeEach(func() {
					privateDomain1 = helpers.NewDomain(orgName, helpers.NewDomainName("a"))
					privateDomain1.Create()

					privateDomain2 = helpers.NewDomain(orgName, helpers.NewDomainName("b"))
					privateDomain2.Create()

					Eventually(helpers.CF("set-label", "domain", privateDomain2.Name, "keyfor2=valuefor2")).Should(Exit(0))
				})
				AfterEach(func() {
					Eventually(helpers.CF("delete-private-domain", privateDomain1.Name, "-f")).Should(Exit(0))
					Eventually(helpers.CF("delete-private-domain", privateDomain2.Name, "-f")).Should(Exit(0))
				})

				It("displays the private domains", func() {
					session := helpers.CF("domains")

					Eventually(session).Should(Exit(0))
					Expect(session).Should(Say(`Getting domains in org %s as %s`, orgName, userName))
					Expect(session).Should(Say(`name\s+availability\s+internal`))
					Expect(session).Should(Say(`%s\s+private\s+`, privateDomain1.Name))
					Expect(session).Should(Say(`%s\s+private\s+`, privateDomain2.Name))
				})

				It("filters private domains by label", func() {
					session := helpers.CF("domains", "--labels", "keyfor2=valuefor2")

					Eventually(session).Should(Exit(0))
					Expect(session).Should(Say(`Getting domains in org %s as %s`, orgName, userName))
					Expect(session).Should(Say(`name\s+availability\s+internal`))
					Expect(session).ShouldNot(Say(`%s\s+private\s+`, privateDomain1.Name))
					Expect(session).Should(Say(`%s\s+private\s+`, privateDomain2.Name))
				})

				When("targeting a different org", func() {
					var (
						newOrgName     string
						newSpaceName   string
						privateDomain3 helpers.Domain
					)

					BeforeEach(func() {
						newOrgName = helpers.NewOrgName()
						newSpaceName = helpers.NewSpaceName()
						helpers.SetupCF(newOrgName, newSpaceName)

						privateDomain3 = helpers.NewDomain(newOrgName, helpers.NewDomainName("c"))
						privateDomain3.Create()
					})
					AfterEach(func() {
						Eventually(helpers.CF("delete-private-domain", privateDomain3.Name, "-f")).Should(Exit(0))
						Eventually(helpers.CF("delete-space", newSpaceName, "-f")).Should(Exit(0))
						Eventually(helpers.CF("delete-org", newOrgName, "-f")).Should(Exit(0))
						// Outer after-eaches require the initial org/space to be targetted
						helpers.TargetOrgAndSpace(orgName, spaceName)
					})

					It("should not display the private domains of other orgs", func() {
						session := helpers.CF("domains")

						Eventually(session).Should(Say(`Getting domains in org %s as %s`, newOrgName, userName))
						Eventually(session).Should(Say(`name\s+availability\s+internal`))

						Consistently(session).ShouldNot(Say(`%s`, privateDomain1.Name))
						Consistently(session).ShouldNot(Say(`%s`, privateDomain2.Name))

						Eventually(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
						Eventually(session).Should(Say(`%s\s+shared\s+`, sharedDomain2.Name))
						Eventually(session).Should(Say(`%s\s+private\s+`, privateDomain3.Name))
						Eventually(session).Should(Exit(0))
					})
				})

				When("logged in as a user that cannot see private domains", func() {
					var userName string

					BeforeEach(func() {
						userName = helpers.SwitchToOrgRole(orgName, "BillingManager")
						helpers.TargetOrg(orgName)
					})
					JustAfterEach(func() {
						// waiting AfterEach blocks are designed to run in as admin
						helpers.LoginCF()
						helpers.TargetOrg(orgName)
					})

					It("only prints the shared domains", func() {
						session := helpers.CF("domains")

						Eventually(session).Should(Say(`Getting domains in org %s as %s`, orgName, userName))
						Eventually(session).Should(Say(`name\s+availability\s+internal`))
						Eventually(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
						Eventually(session).Should(Say(`%s\s+shared\s+`, sharedDomain2.Name))

						Consistently(session).ShouldNot(Say(privateDomain1.Name))
						Consistently(session).ShouldNot(Say(privateDomain2.Name))

						Eventually(session).Should(Exit(0))
					})
				})
			})
		})
	})
})
<commit_msg>Try re-authenticating in client-credentials mode<commit_after>package isolated

import (
	. "code.cloudfoundry.org/cli/cf/util/testhelpers/matchers"
	"code.cloudfoundry.org/cli/integration/helpers"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/onsi/gomega/gbytes"
	. "github.com/onsi/gomega/gexec"
)

var _ = Describe("domains command", func() {
	Describe("help", func() {
		It("appears in cf help -a", func() {
			session := helpers.CF("help", "-a")
			Eventually(session).Should(Exit(0))
			Expect(session).To(HaveCommandInCategoryWithDescription("domains", "DOMAINS", "List domains in the target org"))
		})

		When("--help flag is set", func() {
			It("displays command usage to output", func() {
				session := helpers.CF("domains", "--help")
				Eventually(session).Should(Say("NAME:"))
				Eventually(session).Should(Say(`\s+domains - List domains in the target org`))

				Eventually(session).Should(Say("USAGE:"))
				Eventually(session).Should(Say(`\s+cf domains`))

				Eventually(session).Should(Say("EXAMPLES:"))
				Eventually(session).Should(Say(`\s+cf domains`))
				Eventually(session).Should(Say(`\s+cf domains --labels 'environment in \(production,staging\),tier in \(backend\)'`))
				Eventually(session).Should(Say(`\s+cf domains --labels 'env=dev,!chargeback-code,tier in \(backend,worker\)'`))

				Eventually(session).Should(Say("OPTIONS:"))
				Eventually(session).Should(Say(`--labels\s+Selector to filter domains by labels`))

				Eventually(session).Should(Say("SEE ALSO:"))
				Eventually(session).Should(Say(`\s+create-private-domain, create-route, create-shared-domain, routes, set-label`))
				Eventually(session).Should(Exit(0))
			})
		})
	})

	When("user is not logged in", func() {
		BeforeEach(func() {
			helpers.LogoutCF()
		})

		It("displays an error message and fails", func() {
			session := helpers.CF("domains")
			Eventually(session).Should(Say("FAILED"))
			Eventually(session.Err).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in."))
			Eventually(session).Should(Exit(1))
		})
	})

	When("a random argument is passed to the command", func() {
		It("displays an error message and fails", func() {
			session := helpers.CF("domains", "random-arg")
			Eventually(session).Should(Say("FAILED"))
			Eventually(session.Err).Should(Say(`Incorrect Usage: unexpected argument "random-arg"`))
			Eventually(session).Should(Say("NAME:"))
			Eventually(session).Should(Say(`\s+domains - List domains in the target org`))
			Eventually(session).Should(Say("USAGE:"))
			Eventually(session).Should(Say(`\s+cf domains`))
			Eventually(session).Should(Say("OPTIONS:"))
			Eventually(session).Should(Say(`--labels\s+Selector to filter domains by labels`))
			Eventually(session).Should(Say("SEE ALSO:"))
			Eventually(session).Should(Say(`\s+create-private-domain, create-route, create-shared-domain, routes`))
			Eventually(session).Should(Exit(1))
		})
	})

	When("no org is targeted", func() {
		BeforeEach(func() {
			helpers.LoginCF()
		})

		It("displays an error message and fails", func() {
			session := helpers.CF("domains")
			Eventually(session).Should(Say("FAILED"))
			Eventually(session.Err).Should(Say(`No org targeted, use 'cf target -o ORG' to target an org.`))
			Eventually(session).Should(Exit(1))
		})
	})

	When("logged in", func() {
		var (
			userName      string
			orgName       string
			spaceName     string
			sharedDomain1 helpers.Domain
			sharedDomain2 helpers.Domain
		)

		BeforeEach(func() {
			userName, _ = helpers.GetCredentials()
			orgName = helpers.NewOrgName()
			spaceName = helpers.NewSpaceName()
			helpers.SetupCF(orgName, spaceName)

			sharedDomain1 = helpers.NewDomain(orgName, helpers.NewDomainName("a"))
			sharedDomain1.CreateShared()

			sharedDomain2 = helpers.NewDomain(orgName, helpers.NewDomainName("b"))
			sharedDomain2.CreateShared()
			Eventually(helpers.CF("set-label", "domain", sharedDomain1.Name, "keyfor1=valuefor1")).Should(Exit(0))
		})

		AfterEach(func() {
			if helpers.ClientCredentialsTestMode() {
				// We have observed pipeline failures at this step, where client credentials get rejected
				// when trying to delete domains. When logged in as a client, we don't automatically
				// reautheneticate, so if your access token expires, requests will fail. Here, we try
				// manually re-authenticating in client-credentials mode.
				helpers.LoginCFWithClientCredentials()
			}

			Eventually(helpers.CF("delete-shared-domain", sharedDomain1.Name, "-f")).Should(Exit(0))
			Eventually(helpers.CF("delete-shared-domain", sharedDomain2.Name, "-f")).Should(Exit(0))
			Eventually(helpers.CF("delete-space", spaceName, "-f")).Should(Exit(0))
			Eventually(helpers.CF("delete-org", orgName, "-f")).Should(Exit(0))
		})

		It("displays the shared domains and denotes that they are shared", func() {
			session := helpers.CF("domains")
			Eventually(session).Should(Exit(0))

			Expect(session).Should(Say(`Getting domains in org %s as %s\.\.\.`, orgName, userName))
			Expect(session).Should(Say(`name\s+availability\s+internal`))
			Expect(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
			Expect(session).Should(Say(`%s\s+shared\s+`, sharedDomain2.Name))
		})

		It("displays the shared domains and denotes that they are shared for matching labels only", func() {
			session := helpers.CF("domains", "--labels", "keyfor1=valuefor1")
			Eventually(session).Should(Exit(0))

			Expect(session).Should(Say(`Getting domains in org %s as %s\.\.\.`, orgName, userName))
			Expect(session).Should(Say(`name\s+availability\s+internal`))
			Expect(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
			Expect(session).ShouldNot(Say(`%s\s+shared\s+`, sharedDomain2.Name))
		})

		When("the shared domain is internal", func() {
			var internalDomainName string

			BeforeEach(func() {
				internalDomainName = helpers.NewDomainName()
				internalDomain := helpers.NewDomain(orgName, internalDomainName)
				internalDomain.CreateInternal()
			})

			AfterEach(func() {
				Eventually(helpers.CF("delete-shared-domain", internalDomainName, "-f")).Should(Exit(0))
			})

			It("displays the internal flag on the shared domain", func() {
				session := helpers.CF("domains")
				Eventually(session).Should(Exit(0))

				Expect(session).Should(Say(`Getting domains in org %s as %s`, orgName, userName))
				Expect(session).Should(Say(`name\s+availability\s+internal`))
				Expect(session).Should(Say(`%s\s+shared\s+true`, internalDomainName))
			})

			It("displays the shared domains and denotes that they are shared for matching labels only", func() {
				session := helpers.CF("domains", "--labels", "keyfor1=valuefor1")
				Eventually(session).Should(Exit(0))

				Expect(session).Should(Say(`Getting domains in org %s as %s\.\.\.`, orgName, userName))
				Expect(session).Should(Say(`name\s+availability\s+internal`))
				Expect(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
				Expect(session).ShouldNot(Say(`%s\s+shared\s+`, sharedDomain2.Name))
				Expect(session).ShouldNot(Say(internalDomainName))
			})
		})

		When("the targeted org has a private domain", func() {
			var privateDomain1, privateDomain2 helpers.Domain

			BeforeEach(func() {
				privateDomain1 = helpers.NewDomain(orgName, helpers.NewDomainName("a"))
				privateDomain1.Create()

				privateDomain2 = helpers.NewDomain(orgName, helpers.NewDomainName("b"))
				privateDomain2.Create()

				Eventually(helpers.CF("set-label", "domain", privateDomain2.Name, "keyfor2=valuefor2")).Should(Exit(0))
			})

			AfterEach(func() {
				Eventually(helpers.CF("delete-private-domain", privateDomain1.Name, "-f")).Should(Exit(0))
				Eventually(helpers.CF("delete-private-domain", privateDomain2.Name, "-f")).Should(Exit(0))
			})

			It("displays the private domains", func() {
				session := helpers.CF("domains")

				Eventually(session).Should(Exit(0))
				Expect(session).Should(Say(`Getting domains in org %s as %s`, orgName, userName))
				Expect(session).Should(Say(`name\s+availability\s+internal`))
				Expect(session).Should(Say(`%s\s+private\s+`, privateDomain1.Name))
				Expect(session).Should(Say(`%s\s+private\s+`, privateDomain2.Name))
			})

			It("filters private domains by label", func() {
				session := helpers.CF("domains", "--labels", "keyfor2=valuefor2")

				Eventually(session).Should(Exit(0))
				Expect(session).Should(Say(`Getting domains in org %s as %s`, orgName, userName))
				Expect(session).Should(Say(`name\s+availability\s+internal`))
				Expect(session).ShouldNot(Say(`%s\s+private\s+`, privateDomain1.Name))
				Expect(session).Should(Say(`%s\s+private\s+`, privateDomain2.Name))
			})

			When("targeting a different org", func() {
				var (
					newOrgName     string
					newSpaceName   string
					privateDomain3 helpers.Domain
				)

				BeforeEach(func() {
					newOrgName = helpers.NewOrgName()
					newSpaceName = helpers.NewSpaceName()
					helpers.SetupCF(newOrgName, newSpaceName)

					privateDomain3 = helpers.NewDomain(newOrgName, helpers.NewDomainName("c"))
					privateDomain3.Create()
				})

				AfterEach(func() {
					Eventually(helpers.CF("delete-private-domain", privateDomain3.Name, "-f")).Should(Exit(0))
					Eventually(helpers.CF("delete-space", newSpaceName, "-f")).Should(Exit(0))
					Eventually(helpers.CF("delete-org", newOrgName, "-f")).Should(Exit(0))
					// Outer after-eaches require the initial org/space to be targetted
					helpers.TargetOrgAndSpace(orgName, spaceName)
				})

				It("should not display the private domains of other orgs", func() {
					session := helpers.CF("domains")

					Eventually(session).Should(Say(`Getting domains in org %s as %s`, newOrgName, userName))
					Eventually(session).Should(Say(`name\s+availability\s+internal`))

					Consistently(session).ShouldNot(Say(`%s`, privateDomain1.Name))
					Consistently(session).ShouldNot(Say(`%s`, privateDomain2.Name))

					Eventually(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
					Eventually(session).Should(Say(`%s\s+shared\s+`, sharedDomain2.Name))
					Eventually(session).Should(Say(`%s\s+private\s+`, privateDomain3.Name))
					Eventually(session).Should(Exit(0))
				})
			})

			When("logged in as a user that cannot see private domains", func() {
				var userName string

				BeforeEach(func() {
					userName = helpers.SwitchToOrgRole(orgName, "BillingManager")
					helpers.TargetOrg(orgName)
				})

				JustAfterEach(func() {
					// waiting AfterEach blocks are designed to run in as admin
					helpers.LoginCF()
					helpers.TargetOrg(orgName)
				})

				It("only prints the shared domains", func() {
					session := helpers.CF("domains")

					Eventually(session).Should(Say(`Getting domains in org %s as %s`, orgName, userName))
					Eventually(session).Should(Say(`name\s+availability\s+internal`))
					Eventually(session).Should(Say(`%s\s+shared\s+`, sharedDomain1.Name))
					Eventually(session).Should(Say(`%s\s+shared\s+`, sharedDomain2.Name))

					Consistently(session).ShouldNot(Say(privateDomain1.Name))
					Consistently(session).ShouldNot(Say(privateDomain2.Name))

					Eventually(session).Should(Exit(0))
				})
			})
		})
	})
})
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "log"
  "os"
  "os/exec"
  "strings"
  "path/filepath"
  "crypto/sha1"
  "encoding/json"
  "io/ioutil"
  "syscall"
)

type Result struct {
  // Dreck! Die Felder muessen mit Grossbuchstaben anfangen
  // da sie sonst der feine Herr Golang nicht exportiert
  Output string `json:"output"`
  Exitcode int `json:"exitcode"`
  Serial int `json:"serial"`
}

func main() {
  args := os.Args
  xcmd := args[1]
  params := args[2:len(args)]
  var statefilesdir string;
  var result Result

  sha1_hash := fmt.Sprintf("%x", sha1.Sum([]byte(strings.Join(args, ""))))
  if (os.Getenv("OMD_ROOT") != "") {
    statefilesdir = filepath.Join(os.Getenv("OMD_ROOT"),
        "var", "tmp", "stabilize");

  } else {
    statefilesdir = filepath.Join("/", "var", "tmp", "stabilize");
  }
  os.MkdirAll(statefilesdir, 0755)
  statefile := filepath.Join(statefilesdir, sha1_hash)

  cmd := exec.Command(xcmd, params).CombinedOutput()

  if err := cmd.Start(); err != nil {
    log.Fatalf("cmd.Start: %v")
  }

  if err := cmd.Wait(); err != nil {
    if exiterr, ok := err.(*exec.ExitError); ok {
      // The program has exited with an exit code != 0

      // There is no plattform independent way to retrieve
      // the exit code, but the following will work on Unix
      if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
        log.Printf("Exit Status: %d", status.ExitStatus())
      }
    } else {
      log.Fatalf("cmd.Wait: %v", err)
    }
  }

  output = err
  fmt.Printf("The date is %s\n", output)
  var errors = []string{
      "Return code of 127 is out of bounds - plugin may be missing",
      "Return code of 254 is out of bounds",
      "Return code of 255 is out of bounds",
      "Service Check Timed Out",
      "could not start controlmaster",
      "Could not open pipe: /usr/bin/ssh",
  }
  var error_found = false
  for i:= 0; i < len(errors); i++ {
    if strings.Index(string(output), errors[i]) != -1 {
      error_found = true
      fmt.Printf("plugin error ->%s\n", errors[i])
      break
    }
  }

  raw, err := ioutil.ReadFile(statefile)
  if err != nil {
    result = Result{string(output), 0}
    // error
  } else {
    json.Unmarshal(raw, &result)
  }

  // load json, output, serial
  // else record.output = output, recore.serial = max+1
  if error_found {
    fmt.Printf("no error write to %s\n", statefile)
    // if serial < max, print output, save output with serial++
    // else print error output
    if record.serial > 2 {

    }
  } else {
    // save output,
    fmt.Printf("no plugin error write good %s\n", statefile)
    // save with serial 0
    // record.serial = 0
    json_result, err := json.Marshal(result)
    fmt.Printf("file written %s\n", string(json_result))
    if err != nil {
      fmt.Println("error:", err)
    }
    err = ioutil.WriteFile(statefile, json_result, 0644)
    if err != nil {
      fmt.Printf("file write fail %s\n", err)
    } else {
      fmt.Printf("file written %s\n", statefile)
    }
  }
}

<commit_msg>back to no-exitcode<commit_after>package main

import (
  "fmt"
  "os"
  "os/exec"
  "strings"
  "path/filepath"
  "crypto/sha1"
  "encoding/json"
  "io/ioutil"
  //"syscall"
)

type Result struct {
  // Dreck! Die Felder muessen mit Grossbuchstaben anfangen
  // da sie sonst der feine Herr Golang nicht exportiert
  Output string `json:"output"`
  Exitcode int `json:"exitcode"`
  Serial int `json:"serial"`
}

func main() {
  args := os.Args
  cmd := args[1]
  params := args[2:len(args)]
  var statefilesdir string;
  var result Result

  sha1_hash := fmt.Sprintf("%x", sha1.Sum([]byte(strings.Join(args, ""))))
  if (os.Getenv("OMD_ROOT") != "") {
    statefilesdir = filepath.Join(os.Getenv("OMD_ROOT"),
        "var", "tmp", "stabilize");

  } else {
    statefilesdir = filepath.Join("/", "var", "tmp", "stabilize");
  }
  os.MkdirAll(statefilesdir, 0755)
  statefile := filepath.Join(statefilesdir, sha1_hash)

  output, err := exec.Command(cmd, params...).CombinedOutput()

  //if err := cmd.Start(); err != nil {
    //log.Fatalf("cmd.Start: %v")
  //}

  //if err := cmd.Wait(); err != nil {
    //if exiterr, ok := err.(*exec.ExitError); ok {
      // The program has exited with an exit code != 0

      // There is no plattform independent way to retrieve
      // the exit code, but the following will work on Unix
      //if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
        //log.Printf("Exit Status: %d", status.ExitStatus())
      //}
    //} else {
      //log.Fatalf("cmd.Wait: %v", err)
    //}
  //}

  fmt.Printf("The date is %s\n", output)
  var errors = []string{
      "Return code of 127 is out of bounds - plugin may be missing",
      "Return code of 254 is out of bounds",
      "Return code of 255 is out of bounds",
      "Service Check Timed Out",
      "could not start controlmaster",
      "Could not open pipe: /usr/bin/ssh",
  }
  var error_found = false
  for i:= 0; i < len(errors); i++ {
    if strings.Index(string(output), errors[i]) != -1 {
      error_found = true
      fmt.Printf("plugin error ->%s\n", errors[i])
      break
    }
  }

  raw, err := ioutil.ReadFile(statefile)
  if err != nil {
    result = Result{string(output), 0, 0}
    // error
  } else {
    json.Unmarshal(raw, &result)
  }

  // load json, output, serial
  // else record.output = output, recore.serial = max+1
  if error_found {
    fmt.Printf("no error write to %s\n", statefile)
    // if serial < max, print output, save output with serial++
    // else print error output
    if result.Serial > 2 {
      fmt.Printf("%s\n", output)
    }
  } else {
    // save output,
    fmt.Printf("no plugin error write good %s\n", statefile)
    // save with serial 0
    // record.serial = 0
    json_result, err := json.Marshal(result)
    fmt.Printf("file written %s\n", string(json_result))
    if err != nil {
      fmt.Println("error:", err)
    }
    err = ioutil.WriteFile(statefile, json_result, 0644)
    if err != nil {
      fmt.Printf("file write fail %s\n", err)
    } else {
      fmt.Printf("file written %s\n", statefile)
    }
  }
}

<|endoftext|>


<commit_before>package checker

import (
	"archive/tar"
	"bytes"
	"context"
	"fmt"
	"math/rand"
	"strconv"
	"time"

	"github.com/Sirupsen/logrus"
	"github.com/fsouza/go-dockerclient"
	"github.com/molecul/qa_portal/model"
)

type Task struct {
	Docker    *docker.Client
	Test      *model.Test
	Challenge *model.Challenge
	Container *docker.Container
	Result    struct {
		ExitCode int
		Stdout   bytes.Buffer
		Stderr   bytes.Buffer
	}
}

func (c *Checker) NewTask(challenge *model.Challenge, test *model.Test) *Task {
	return &Task{
		Docker:    c.Docker,
		Test:      test,
		Challenge: challenge,
	}
}

func (task *Task) dockerInjectFiles(fnameDataMap map[string][]byte) error {
	tarBuf := new(bytes.Buffer)
	tw := tar.NewWriter(tarBuf)
	for fname, fdata := range fnameDataMap {
		if err := tw.WriteHeader(&tar.Header{
			Name: fname,
			Mode: 0644,
			Size: int64(len(fdata)),
		}); err != nil {
			return fmt.Errorf("Error writing file '%s' header to tar archive: %v", fname, err)
		}

		if _, err := tw.Write(fdata); err != nil {
			return fmt.Errorf("Error writing file '%s' to tar archive: %v", fname, err)
		}
	}

	if err := task.Docker.UploadToContainer(task.Container.ID, docker.UploadToContainerOptions{
		InputStream: tarBuf,
		Path:        "/",
	}); err != nil {
		return fmt.Errorf("Error uploading tar archive to container: %v", err)
	}
	return nil
}

func (task *Task) dockerInjectFile(targetFileName string, data []byte) error {
	return task.dockerInjectFiles(map[string][]byte{targetFileName: data})
}

func (task *Task) dockerLoadLogs() error {
	if err := task.Docker.Logs(docker.LogsOptions{
		Container:    task.Container.ID,
		Stdout:       true,
		Stderr:       true,
		OutputStream: &task.Result.Stdout,
		ErrorStream:  &task.Result.Stderr,
		RawTerminal:  true,
	}); err != nil {
		return fmt.Errorf("Error collecting logs from container: %v", err)
	}
	return nil
}

func (task *Task) runTask(ctx context.Context) (err error) {
	createOptions := docker.CreateContainerOptions{
		Name: fmt.Sprintf("qachecker-%v", task.Test.ID),
		Config: &docker.Config{
			Tty:             true,
			NetworkDisabled: true,
			Image:           task.Challenge.Image,
			Entrypoint:      []string{"/bin/bash", "-c"},
			Env: []string{
				"CHECKER_CHALLENGE=" + task.Challenge.InternalName,
				"CHECKER_TEST=" + strconv.FormatInt(task.Test.ID, 10),
				"CHECKER_FILE=" + task.Challenge.TargetPath,
			},
		},
		HostConfig: &docker.HostConfig{
		// TODO We really need this?
		// AutoRemove: true,
		},
	}
	if task.Challenge.Cmd != "" {
		createOptions.Config.Cmd = []string{task.Challenge.Cmd}
	}

	if task.Container, err = task.Docker.CreateContainer(createOptions); err != nil {
		return fmt.Errorf("Error creating container: %v", err)
	}

	defer func() {
		logrus.Infof("autoremove %s", task.Container.ID)
		task.Docker.RemoveContainer(docker.RemoveContainerOptions{
			ID:    task.Container.ID,
			Force: true,
		})
	}()

	// TODO Change input file to real file data
	if err = task.dockerInjectFile(task.Challenge.TargetPath, []byte(task.Test.InputFile)); err != nil {
		return err
	}

	if err = task.Docker.StartContainerWithContext(task.Container.ID, &docker.HostConfig{}, ctx); err != nil {
		return fmt.Errorf("Error when starting docker container: %v", err)
	}

	task.Result.ExitCode, err = task.Docker.WaitContainerWithContext(task.Container.ID, ctx)
	if err != nil {
		task.dockerLoadLogs()
		return fmt.Errorf("Error wait container: %v", err)
	}

	return task.dockerLoadLogs()
}

func (task *Task) Do(ctx context.Context) (err error) {
	err = task.runTask(ctx)

	return err
}
<commit_msg>Remove unused imports.<commit_after>package checker

import (
	"archive/tar"
	"bytes"
	"context"
	"fmt"
	"strconv"

	"github.com/Sirupsen/logrus"
	"github.com/fsouza/go-dockerclient"
	"github.com/molecul/qa_portal/model"
)

type Task struct {
	Docker    *docker.Client
	Test      *model.Test
	Challenge *model.Challenge
	Container *docker.Container
	Result    struct {
		ExitCode int
		Stdout   bytes.Buffer
		Stderr   bytes.Buffer
	}
}

func (c *Checker) NewTask(challenge *model.Challenge, test *model.Test) *Task {
	return &Task{
		Docker:    c.Docker,
		Test:      test,
		Challenge: challenge,
	}
}

func (task *Task) dockerInjectFiles(fnameDataMap map[string][]byte) error {
	tarBuf := new(bytes.Buffer)
	tw := tar.NewWriter(tarBuf)
	for fname, fdata := range fnameDataMap {
		if err := tw.WriteHeader(&tar.Header{
			Name: fname,
			Mode: 0644,
			Size: int64(len(fdata)),
		}); err != nil {
			return fmt.Errorf("Error writing file '%s' header to tar archive: %v", fname, err)
		}

		if _, err := tw.Write(fdata); err != nil {
			return fmt.Errorf("Error writing file '%s' to tar archive: %v", fname, err)
		}
	}

	if err := task.Docker.UploadToContainer(task.Container.ID, docker.UploadToContainerOptions{
		InputStream: tarBuf,
		Path:        "/",
	}); err != nil {
		return fmt.Errorf("Error uploading tar archive to container: %v", err)
	}
	return nil
}

func (task *Task) dockerInjectFile(targetFileName string, data []byte) error {
	return task.dockerInjectFiles(map[string][]byte{targetFileName: data})
}

func (task *Task) dockerLoadLogs() error {
	if err := task.Docker.Logs(docker.LogsOptions{
		Container:    task.Container.ID,
		Stdout:       true,
		Stderr:       true,
		OutputStream: &task.Result.Stdout,
		ErrorStream:  &task.Result.Stderr,
		RawTerminal:  true,
	}); err != nil {
		return fmt.Errorf("Error collecting logs from container: %v", err)
	}
	return nil
}

func (task *Task) runTask(ctx context.Context) (err error) {
	createOptions := docker.CreateContainerOptions{
		Name: fmt.Sprintf("qachecker-%v", task.Test.ID),
		Config: &docker.Config{
			Tty:             true,
			NetworkDisabled: true,
			Image:           task.Challenge.Image,
			Entrypoint:      []string{"/bin/bash", "-c"},
			Env: []string{
				"CHECKER_CHALLENGE=" + task.Challenge.InternalName,
				"CHECKER_TEST=" + strconv.FormatInt(task.Test.ID, 10),
				"CHECKER_FILE=" + task.Challenge.TargetPath,
			},
		},
		HostConfig: &docker.HostConfig{
		// TODO We really need this?
		// AutoRemove: true,
		},
	}
	if task.Challenge.Cmd != "" {
		createOptions.Config.Cmd = []string{task.Challenge.Cmd}
	}

	if task.Container, err = task.Docker.CreateContainer(createOptions); err != nil {
		return fmt.Errorf("Error creating container: %v", err)
	}

	defer func() {
		logrus.Infof("autoremove %s", task.Container.ID)
		task.Docker.RemoveContainer(docker.RemoveContainerOptions{
			ID:    task.Container.ID,
			Force: true,
		})
	}()

	// TODO Change input file to real file data
	if err = task.dockerInjectFile(task.Challenge.TargetPath, []byte(task.Test.InputFile)); err != nil {
		return err
	}

	if err = task.Docker.StartContainerWithContext(task.Container.ID, &docker.HostConfig{}, ctx); err != nil {
		return fmt.Errorf("Error when starting docker container: %v", err)
	}

	task.Result.ExitCode, err = task.Docker.WaitContainerWithContext(task.Container.ID, ctx)
	if err != nil {
		task.dockerLoadLogs()
		return fmt.Errorf("Error wait container: %v", err)
	}

	return task.dockerLoadLogs()
}

func (task *Task) Do(ctx context.Context) (err error) {
	err = task.runTask(ctx)

	return err
}
<|endoftext|>


<commit_before>// Copyright 2021 The Kubeflow 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 validation

import (
	"fmt"

	xgboostv1 "github.com/kubeflow/tf-operator/pkg/apis/xgboost/v1"

	commonv1 "github.com/kubeflow/common/pkg/apis/common/v1"

	torchv1 "github.com/kubeflow/tf-operator/pkg/apis/pytorch/v1"
)

func ValidateV1XGBoostJobSpec(c *xgboostv1.XGBoostJobSpec) error {
	if c.XGBReplicaSpecs == nil {
		return fmt.Errorf("XGBoostJobSpec is not valid")
	}
	masterExists := false
	for rType, value := range c.XGBReplicaSpecs {
		if value == nil || len(value.Template.Spec.Containers) == 0 {
			return fmt.Errorf("XGBoostJobSpec is not valid: containers definition expected in %v", rType)
		}
		// Make sure the replica type is valid.
		validReplicaTypes := []commonv1.ReplicaType{xgboostv1.XGBoostReplicaTypeMaster, xgboostv1.XGBoostReplicaTypeWorker}

		isValidReplicaType := false
		for _, t := range validReplicaTypes {
			if t == rType {
				isValidReplicaType = true
				break
			}
		}

		if !isValidReplicaType {
			return fmt.Errorf("XGBoostReplicaType is %v but must be one of %v", rType, validReplicaTypes)
		}

		//Make sure the image is defined in the container
		defaultContainerPresent := false
		for _, container := range value.Template.Spec.Containers {
			if container.Image == "" {
				msg := fmt.Sprintf("XGBoostReplicaType is not valid: Image is undefined in the container of %v", rType)
				return fmt.Errorf(msg)
			}
			if container.Name == xgboostv1.DefaultContainerName {
				defaultContainerPresent = true
			}
		}
		//Make sure there has at least one container named "pytorch"
		if !defaultContainerPresent {
			msg := fmt.Sprintf("XGBoostReplicaType is not valid: There is no container named %s in %v", torchv1.DefaultContainerName, rType)
			return fmt.Errorf(msg)
		}
		if rType == xgboostv1.XGBoostReplicaTypeMaster {
			masterExists = true
			if value.Replicas != nil && int(*value.Replicas) != 1 {
				return fmt.Errorf("XGBoostReplicaType is not valid: There must be only 1 master replica")
			}
		}

	}

	if !masterExists {
		return fmt.Errorf("XGBoostReplicaType is not valid: Master ReplicaSpec must be present")
	}
	return nil

}
<commit_msg>Fix XGBoost container name in log message (#1362)<commit_after>// Copyright 2021 The Kubeflow 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 validation

import (
	"fmt"

	xgboostv1 "github.com/kubeflow/tf-operator/pkg/apis/xgboost/v1"

	commonv1 "github.com/kubeflow/common/pkg/apis/common/v1"
)

func ValidateV1XGBoostJobSpec(c *xgboostv1.XGBoostJobSpec) error {
	if c.XGBReplicaSpecs == nil {
		return fmt.Errorf("XGBoostJobSpec is not valid")
	}
	masterExists := false
	for rType, value := range c.XGBReplicaSpecs {
		if value == nil || len(value.Template.Spec.Containers) == 0 {
			return fmt.Errorf("XGBoostJobSpec is not valid: containers definition expected in %v", rType)
		}
		// Make sure the replica type is valid.
		validReplicaTypes := []commonv1.ReplicaType{xgboostv1.XGBoostReplicaTypeMaster, xgboostv1.XGBoostReplicaTypeWorker}

		isValidReplicaType := false
		for _, t := range validReplicaTypes {
			if t == rType {
				isValidReplicaType = true
				break
			}
		}

		if !isValidReplicaType {
			return fmt.Errorf("XGBoostReplicaType is %v but must be one of %v", rType, validReplicaTypes)
		}

		//Make sure the image is defined in the container
		defaultContainerPresent := false
		for _, container := range value.Template.Spec.Containers {
			if container.Image == "" {
				msg := fmt.Sprintf("XGBoostReplicaType is not valid: Image is undefined in the container of %v", rType)
				return fmt.Errorf(msg)
			}
			if container.Name == xgboostv1.DefaultContainerName {
				defaultContainerPresent = true
			}
		}
		//Make sure there has at least one container named "xgboost"
		if !defaultContainerPresent {
			msg := fmt.Sprintf("XGBoostReplicaType is not valid: There is no container named %s in %v", xgboostv1.DefaultContainerName, rType)
			return fmt.Errorf(msg)
		}
		if rType == xgboostv1.XGBoostReplicaTypeMaster {
			masterExists = true
			if value.Replicas != nil && int(*value.Replicas) != 1 {
				return fmt.Errorf("XGBoostReplicaType is not valid: There must be only 1 master replica")
			}
		}

	}

	if !masterExists {
		return fmt.Errorf("XGBoostReplicaType is not valid: Master ReplicaSpec must be present")
	}
	return nil

}
<|endoftext|>