func (p *taskPlugin) setupDisplay() error { // Setup display if not disabled if p.opts.DisableDisplay { return nil } debug("Setting up interactive display") // Create display server p.displayServer = NewDisplayServer( p.sandbox, p.log.WithField("interactive", "display"), ) u := p.context.AttachWebHook(p.displayServer) p.displaysURL = u p.displaySocketURL = urlProtocolToWebsocket(u) query := url.Values{} query.Set("v", "1") query.Set("taskId", p.context.TaskID) query.Set("runId", fmt.Sprintf("%d", p.context.RunID)) query.Set("socketUrl", p.displaySocketURL) query.Set("displaysUrl", p.displaysURL) // TODO: Make this an option the engine can specify in ListDisplays // Probably requires changing display list result to contain websocket // URLs. Hence, introducing v=2, so leaving it for later. query.Set("shared", "true") return runtime.CreateRedirectArtifact(runtime.RedirectArtifact{ Name: p.opts.ArtifactPrefix + "display.html", Mimetype: "text/html", URL: p.parent.config.DisplayToolURL + "?" + query.Encode(), Expires: p.context.TaskInfo.Deadline, }, p.context) }
func (p *taskPlugin) setupShell() error { // Setup shell if not disabled if p.opts.DisableShell { return nil } debug("Setting up interactive shell") // Create shell server and get a URL to reach it p.shellServer = NewShellServer( p.sandbox.NewShell, p.log.WithField("interactive", "shell"), ) u := p.context.AttachWebHook(p.shellServer) p.shellURL = urlProtocolToWebsocket(u) query := url.Values{} query.Set("v", "2") query.Set("taskId", p.context.TaskID) query.Set("runId", fmt.Sprintf("%d", p.context.RunID)) query.Set("socketUrl", p.shellURL) return runtime.CreateRedirectArtifact(runtime.RedirectArtifact{ Name: p.opts.ArtifactPrefix + "shell.html", Mimetype: "text/html", URL: p.parent.config.ShellToolURL + "?" + query.Encode(), Expires: p.context.TaskInfo.Deadline, }, p.context) }
func (tp *taskPlugin) Prepare(context *runtime.TaskContext) error { tp.context = context tp.url = tp.context.AttachWebHook(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // TODO (garndt): add support for range headers. Might not be used at all currently logReader, err := tp.context.NewLogReader() if err != nil { w.WriteHeader(500) w.Write([]byte("Error opening up live log")) return } defer logReader.Close() // Get an HTTP flusher if supported in the current context, or wrap in // a NopFlusher, if flushing isn't available. wf, ok := w.(ioext.WriteFlusher) if !ok { wf = ioext.NopFlusher(w) } ioext.CopyAndFlush(wf, logReader, 100*time.Millisecond) })) err := runtime.CreateRedirectArtifact(runtime.RedirectArtifact{ Name: "public/logs/live.log", Mimetype: "text/plain", URL: tp.url, Expires: tp.context.TaskInfo.Expires, }, tp.context) if err != nil { tp.context.LogError(fmt.Sprintf("Could not initialize live log plugin. Error: %s", err)) } return err }
func (tp *taskPlugin) Finished(success bool) error { file, err := tp.context.ExtractLog() if err != nil { return err } defer file.Close() tempFile, err := tp.environment.TemporaryStorage.NewFile() if err != nil { return err } defer tempFile.Close() zip := gzip.NewWriter(tempFile) if _, err = io.Copy(zip, file); err != nil { return err } if err = zip.Close(); err != nil { return err } _, err = tempFile.Seek(0, 0) if err != nil { return err } err = runtime.UploadS3Artifact(runtime.S3Artifact{ Name: "public/logs/live_backing.log", Mimetype: "text/plain", Expires: tp.context.TaskInfo.Expires, Stream: tempFile, AdditionalHeaders: map[string]string{ "Content-Encoding": "gzip", }, }, tp.context) if err != nil { return err } backingURL := fmt.Sprintf("https://queue.taskcluster.net/v1/task/%s/runs/%d/artifacts/public/logs/live_backing.log", tp.context.TaskInfo.TaskID, tp.context.TaskInfo.RunID) err = runtime.CreateRedirectArtifact(runtime.RedirectArtifact{ Name: "public/logs/live.log", Mimetype: "text/plain", URL: backingURL, Expires: tp.context.TaskInfo.Expires, }, tp.context) if err != nil { tp.log.Error(err) return err } return nil }