func Scale(app string, sync bool, types []string) error { var size string scaleParams := &api.AppsScaleParams{} for _, t := range types { splitT := strings.Split(t, ":") if len(splitT) != 2 && len(splitT) != 3 { return errgo.Newf("%s is invalid, format is <type>:<amount>[:<size>]", t) } typeName, typeAmount := splitT[0], splitT[1] if len(splitT) == 3 { size = splitT[2] } amount, err := strconv.ParseInt(typeAmount, 10, 32) if err != nil { return errgo.Newf("%s in %s should be an integer", typeAmount, t) } scaleParams.Containers = append(scaleParams.Containers, api.Container{Name: typeName, Amount: int(amount), Size: size}) } res, err := api.AppsScale(app, scaleParams) if err != nil { return errgo.Mask(err) } defer res.Body.Close() if res.StatusCode == 422 { var scaleUnprocessableEntity ScaleUnprocessableEntity err = api.ParseJSON(res, &scaleUnprocessableEntity) if err != nil { return errgo.Mask(err) } return scaleUnprocessableEntity } var scaleRes ScaleRes err = api.ParseJSON(res, &scaleRes) if err != nil { return errgo.Mask(err) } fmt.Printf("Your application is being scaled to:\n") for _, ct := range scaleRes.Containers { fmt.Println(io.Indent(fmt.Sprintf("%s: %d - %s", ct.Name, ct.Amount, ct.Size), 2)) } if !sync { return nil } err = handleOperation(app, res) if err != nil { return errgo.Mask(err) } fmt.Println("Your application has been scaled.") return nil }
func Run(opts RunOpts) error { if opts.CmdEnv == nil { opts.CmdEnv = []string{} } if opts.Files == nil { opts.Files = []string{} } if opts.StdinCopyFunc == nil { opts.StdinCopyFunc = io.Copy } if opts.StdoutCopyFunc == nil { opts.StdoutCopyFunc = io.Copy } env, err := buildEnv(opts.CmdEnv) if err != nil { return errgo.Mask(err, errgo.Any) } err = validateFiles(opts.Files) if err != nil { return errgo.Mask(err, errgo.Any) } res, err := api.Run(opts.App, opts.Cmd, env) if err != nil { return errgo.Mask(err, errgo.Any) } runStruct := make(map[string]interface{}) api.ParseJSON(res, &runStruct) debug.Printf("%+v\n", runStruct) if res.StatusCode == http.StatusNotFound { return errgo.Newf("application %s not found", opts.App) } attachURL, ok := runStruct["attach_url"].(string) if !ok { return errgo.New("unexpected answer from server") } debug.Println("Run Service URL is", attachURL) if len(opts.Files) > 0 { err := uploadFiles(attachURL+"/files", opts.Files) if err != nil { return err } } res, socket, err := connectToRunServer(attachURL) if err != nil { return errgo.Mask(err, errgo.Any) } if res.StatusCode != http.StatusOK { return errgo.Newf("Fail to attach: %s", res.Status) } if err := term.MakeRaw(os.Stdin); err != nil { return errgo.Mask(err, errgo.Any) } stopSignalsMonitoring := make(chan bool) defer close(stopSignalsMonitoring) go func() { signals.CatchQuitSignals = false signals := run.NotifiedSignals() defer close(signals) go run.NofityTermSizeUpdate(signals) for { select { case s := <-signals: run.HandleSignal(s, socket, attachURL) case <-stopSignalsMonitoring: signal.Stop(signals) return } } }() go opts.StdinCopyFunc(socket, os.Stdin) _, err = opts.StdinCopyFunc(os.Stdout, socket) stopSignalsMonitoring <- true if err := term.Restore(os.Stdin); err != nil { return errgo.Mask(err, errgo.Any) } return nil }