func getLogFormat(format string) log15.Format { switch format { case "console": if term.IsTty(os.Stdout.Fd()) { return log15.TerminalFormat() } return log15.LogfmtFormat() case "text": return log15.LogfmtFormat() case "json": return log15.JsonFormat() default: return log15.LogfmtFormat() } }
func RunFormula(s scheduler.Scheduler, e executor.Executor, formula def.Formula, journal io.Writer) def.JobResult { jobLoggerFactory := func(_ def.JobID) io.Writer { // All job progress reporting, still copy to our shared journal stream. // This func might now be outdated; but we haven't decided what any of this // should look like if take a lurch toward supporting cluster farming. // (It might make sense to have a structural comms layer? Or, maybe plain // byte streams are best for sanity conservation. Either way: not today.) return journal } s.Configure(e, 1, jobLoggerFactory) // queue concept a bit misplaced here s.Start() // Set up a logger. log := log15.New() log.SetHandler(log15.StreamHandler(journal, log15.TerminalFormat())) id, jobChan := s.Schedule(formula) log = log.New(log15.Ctx{"JobID": id}) log.Info("Job queued") job := <-jobChan // TODO need better lifecycle events here. "starting" here means we might still be in provisioning stage. log.Info("Job starting") // Stream job output to terminal in real time _, err := io.Copy(journal, job.OutputReader()) if err != nil { log.Error("Error reading job stream", "error", err) panic(err) } result := job.Wait() if result.Error != nil { log.Error("Job execution errored", "error", result.Error.Message()) } else { log.Info("Job finished", log15.Ctx{ "exit": result.ExitCode, "outputs": result.Outputs, }) } return result }
func (e *Executor) Start(f def.Formula, id def.JobID, stdin io.Reader, journal io.Writer) def.Job { // Prepare the forumla for execution on this host def.ValidateAll(&f) job := basicjob.New(id) jobReady := make(chan struct{}) go func() { // Run the formula in a temporary directory flak.WithDir(func(dir string) { // spool our output to a muxed stream var strm streamer.Mux strm = streamer.CborFileMux(filepath.Join(dir, "log")) outS := strm.Appender(1) errS := strm.Appender(2) job.Streams = strm defer func() { // Regardless of how the job ends (or even if it fails the remaining setup), output streams must be terminated. outS.Close() errS.Close() }() // Job is ready to stream process output close(jobReady) // Set up a logger. Tag all messages with this jobid. logger := log15.New(log15.Ctx{"JobID": id}) logger.SetHandler(log15.StreamHandler(journal, log15.TerminalFormat())) job.Result = e.Run(f, job, dir, stdin, outS, errS, logger) }, e.workspacePath, "job", string(job.Id())) // Directory is clean; job complete close(job.WaitChan) }() <-jobReady return job }
func main() { app.Writer(os.Stdout) app.Version(VV) app.HelpFlag.Short('h') app.VersionFlag.Short('v') command := kingpin.MustParse(app.Parse(os.Args[1:])) err := ReadConfig(*configFile, *account) if !strings.HasPrefix(command, "config") && !strings.HasPrefix(command, "update") { // Makes sure the config file structure is valid if err != nil { fatalError("%s: Error reading config file: %s\n", filepath.Base(os.Args[0]), err.Error()) } // Make sure the config file auth token is valid. Check now so we don't have to // keep rechecking in code. _, err := Config.Account.Client15() if err != nil { fatalError("Authentication error: %s", err.Error()) } } // Handle logging logLevel := log15.LvlInfo if *debug { log.Logger.SetHandler( log15.LvlFilterHandler( log15.LvlDebug, log15.StderrHandler)) httpclient.DumpFormat = httpclient.Debug logLevel = log15.LvlDebug } handler := log15.LvlFilterHandler(logLevel, log15.StreamHandler(colorable.NewColorableStdout(), log15.TerminalFormat())) log15.Root().SetHandler(handler) if Config.GetBool("update.check") && !strings.HasPrefix(command, "update") { defer UpdateCheck(VV, os.Stderr) } switch command { case stShowCmd.FullCommand(): href, err := paramToHref("server_templates", *stShowNameOrHref, 0) if err != nil { fatalError("%s", err.Error()) } stShow(href) case stUploadCmd.FullCommand(): files, err := walkPaths(*stUploadPaths) if err != nil { fatalError("%s\n", err.Error()) } stUpload(files, *stUploadPrefix) case stDeleteCmd.FullCommand(): files, err := walkPaths(*stDeletePaths) if err != nil { fatalError("%s\n", err.Error()) } stDelete(files, *stDeletePrefix) case stDownloadCmd.FullCommand(): href, err := paramToHref("server_templates", *stDownloadNameOrHref, 0) if err != nil { fatalError("%s", err.Error()) } stDownload(href, *stDownloadTo, *stDownloadPublished, *stDownloadMciSettings, *stDownloadScriptPath) case stValidateCmd.FullCommand(): files, err := walkPaths(*stValidatePaths) if err != nil { fatalError("%s\n", err.Error()) } stValidate(files) case rightScriptShowCmd.FullCommand(): href, err := paramToHref("right_scripts", *rightScriptShowNameOrHref, 0) if err != nil { fatalError("%s", err.Error()) } rightScriptShow(href) case rightScriptUploadCmd.FullCommand(): files, err := walkPaths(*rightScriptUploadPaths) if err != nil { fatalError("%s\n", err.Error()) } rightScriptUpload(files, *rightScriptUploadForce, *rightScriptUploadPrefix) case rightScriptDeleteCmd.FullCommand(): files, err := walkPaths(*rightScriptDeletePaths) if err != nil { fatalError("%s\n", err.Error()) } rightScriptDelete(files, *rightScriptDeletePrefix) case rightScriptDownloadCmd.FullCommand(): href, err := paramToHref("right_scripts", *rightScriptDownloadNameOrHref, 0) if err != nil { fatalError("%s", err.Error()) } rightScriptDownload(href, *rightScriptDownloadTo) case rightScriptScaffoldCmd.FullCommand(): files, err := walkPaths(*rightScriptScaffoldPaths) if err != nil { fatalError("%s\n", err.Error()) } rightScriptScaffold(files, !*rightScriptScaffoldNoBackup, *rightScriptScaffoldForce) case rightScriptValidateCmd.FullCommand(): files, err := walkPaths(*rightScriptValidatePaths) if err != nil { fatalError("%s\n", err.Error()) } rightScriptValidate(files) case configAccountCmd.FullCommand(): err := Config.SetAccount(*configAccountName, *configAccountDefault, os.Stdin, os.Stdout) if err != nil { fatalError("%s\n", err.Error()) } case configShowCmd.FullCommand(): err := Config.ShowConfiguration(os.Stdout) if err != nil { fatalError("%s\n", err.Error()) } case updateListCmd.FullCommand(): err := UpdateList(VV, os.Stdout) if err != nil { fatalError("%s\n", err.Error()) } case updateApplyCmd.FullCommand(): err := UpdateApply(VV, os.Stdout, *updateApplyMajorVersion, "") if err != nil { fatalError("%s\n", err.Error()) } } }