diff --git a/WORKSPACE.yaml b/WORKSPACE.yaml index 0f1f20660cd92b..8d67278ff9baa9 100644 --- a/WORKSPACE.yaml +++ b/WORKSPACE.yaml @@ -7,7 +7,7 @@ defaultArgs: publishToNPM: true publishToJBMarketplace: true localAppVersion: unknown - codeCommit: a22e18bcce821d889b541107a695dd93835c7cc7 + codeCommit: 0180d69921094cacdaa8d4b6ef007a0783a95e3b codeVersion: 1.75.0 codeQuality: stable noVerifyJBPlugin: false @@ -22,6 +22,7 @@ defaultArgs: jbBackendVersion: "latest" REPLICATED_API_TOKEN: "" REPLICATED_APP: "" + dockerVersion: 20.10.17 provenance: enabled: true slsa: true diff --git a/components/docker-up/BUILD.yaml b/components/docker-up/BUILD.yaml index 5759d8797377a5..b5920968e38455 100644 --- a/components/docker-up/BUILD.yaml +++ b/components/docker-up/BUILD.yaml @@ -8,9 +8,12 @@ packages: - dependencies.sh deps: - components/common-go:lib + argdeps: + - dockerVersion env: - CGO_ENABLED=0 - GOOS=linux + - DOCKER_VERSION=${dockerVersion} prep: - ["mv", "docker-up/main.go", "."] - ["rmdir", "docker-up"] diff --git a/components/docker-up/dependencies.sh b/components/docker-up/dependencies.sh index 6db2f31555c9f1..023d861d10cfb1 100755 --- a/components/docker-up/dependencies.sh +++ b/components/docker-up/dependencies.sh @@ -5,10 +5,9 @@ set -euo pipefail -DOCKER_VERSION=20.10.17 DOCKER_COMPOSE_VERSION=2.8.0-gitpod.0 RUNC_VERSION=v1.1.4 -curl -o docker.tgz -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz -curl -o docker-compose -fsSL https://github.com/gitpod-io/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64 -curl -o runc -fsSL https://github.com/opencontainers/runc/releases/download/${RUNC_VERSION}/runc.amd64 +curl -o docker.tgz -fsSL "https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz" +curl -o docker-compose -fsSL "https://github.com/gitpod-io/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64" +curl -o runc -fsSL "https://github.com/opencontainers/runc/releases/download/${RUNC_VERSION}/runc.amd64" diff --git a/components/gitpod-cli/.gitignore b/components/gitpod-cli/.gitignore new file mode 100644 index 00000000000000..454b09ce111077 --- /dev/null +++ b/components/gitpod-cli/.gitignore @@ -0,0 +1 @@ +gitpod-cli diff --git a/components/gitpod-cli/cmd/rebuild.go b/components/gitpod-cli/cmd/rebuild.go index f4f41929e6155a..e5450f320369e0 100644 --- a/components/gitpod-cli/cmd/rebuild.go +++ b/components/gitpod-cli/cmd/rebuild.go @@ -5,8 +5,12 @@ package cmd import ( + "bufio" "context" + "encoding/json" "fmt" + "io" + "net/url" "os" "os/exec" "os/signal" @@ -15,53 +19,51 @@ import ( "syscall" "time" + "github.com/gitpod-io/gitpod/common-go/log" "github.com/gitpod-io/gitpod/gitpod-cli/pkg/supervisor" "github.com/gitpod-io/gitpod/gitpod-cli/pkg/utils" - "github.com/gitpod-io/gitpod/supervisor/api" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/gitpod-io/gitpod/supervisor/api" + prefixed "github.com/x-cray/logrus-prefixed-formatter" ) -func TerminateExistingContainer(ctx context.Context) error { - cmd := exec.CommandContext(ctx, "docker", "ps", "-q", "-f", "label=gp-rebuild") +func stopDebugContainer(ctx context.Context, dockerPath string) { + cmd := exec.CommandContext(ctx, dockerPath, "ps", "-q", "-f", "label=gp-rebuild") containerIds, err := cmd.Output() if err != nil { - return err + return } for _, id := range strings.Split(string(containerIds), "\n") { if len(id) == 0 { continue } - - cmd = exec.CommandContext(ctx, "docker", "stop", id) - err := cmd.Run() - if err != nil { - return err - } - - cmd = exec.CommandContext(ctx, "docker", "rm", "-f", id) - err = cmd.Run() - if err != nil { - return err - } + _ = exec.CommandContext(ctx, dockerPath, "stop", id).Run() + _ = exec.CommandContext(ctx, dockerPath, "rm", "-f", id).Run() } - - return nil } func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClient, event *utils.AnalyticsEvent) (string, error) { - wsInfo, err := supervisorClient.Info.WorkspaceInfo(ctx, &api.WorkspaceInfoRequest{}) + logLevel, err := logrus.ParseLevel(rebuildOpts.LogLevel) if err != nil { - return utils.Outcome_SystemErr, err + event.Data.ErrorCode = utils.RebuildErrorCode_InvaligLogLevel + return utils.Outcome_UserErr, err } - tmpDir, err := os.MkdirTemp("", "gp-rebuild-*") + // 1. validate configuration + wsInfo, err := supervisorClient.Info.WorkspaceInfo(ctx, &api.WorkspaceInfoRequest{}) if err != nil { return utils.Outcome_SystemErr, err } - defer os.RemoveAll(tmpDir) - gitpodConfig, err := utils.ParseGitpodConfig(wsInfo.CheckoutLocation) + checkoutLocation := rebuildOpts.WorkspaceFolder + if checkoutLocation == "" { + checkoutLocation = wsInfo.CheckoutLocation + } + + gitpodConfig, err := utils.ParseGitpodConfig(checkoutLocation) if err != nil { fmt.Println("The .gitpod.yml file cannot be parsed: please check the file and try again") fmt.Println("") @@ -85,11 +87,11 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie var baseimage string switch img := gitpodConfig.Image.(type) { case nil: - baseimage = "" + baseimage = "FROM gitpod/workspace-full:latest" case string: baseimage = "FROM " + img case map[interface{}]interface{}: - dockerfilePath := filepath.Join(wsInfo.CheckoutLocation, img["file"].(string)) + dockerfilePath := filepath.Join(checkoutLocation, img["file"].(string)) if _, err := os.Stat(dockerfilePath); os.IsNotExist(err) { fmt.Println("Your .gitpod.yml points to a Dockerfile that doesn't exist: " + dockerfilePath) @@ -124,24 +126,33 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie return utils.Outcome_UserErr, nil } - tmpDockerfile := filepath.Join(tmpDir, "Dockerfile") + // 2. build image + tmpDir, err := os.MkdirTemp("", "gp-rebuild-*") + if err != nil { + return utils.Outcome_SystemErr, err + } + defer os.RemoveAll(tmpDir) - err = os.WriteFile(tmpDockerfile, []byte(baseimage), 0644) + dockerFile := filepath.Join(tmpDir, "Dockerfile") + err = os.WriteFile(dockerFile, []byte(baseimage), 0644) if err != nil { fmt.Println("Could not write the temporary Dockerfile") return utils.Outcome_SystemErr, err } dockerPath, err := exec.LookPath("docker") + if err == nil { + // smoke test user docker cli + err = exec.CommandContext(ctx, dockerPath, "--version").Run() + } if err != nil { - fmt.Println("Docker is not installed in your workspace") - event.Set("ErrorCode", utils.RebuildErrorCode_DockerNotFound) - return utils.Outcome_SystemErr, err + dockerPath = "/.supervisor/gitpod-docker-cli" } - tag := "gp-rebuild-temp-build" + imageTag := "gp-rebuild-temp-build" - dockerCmd := exec.CommandContext(ctx, dockerPath, "build", "-f", tmpDockerfile, "-t", tag, wsInfo.CheckoutLocation) + fmt.Println("Building the workspace image...") + dockerCmd := exec.CommandContext(ctx, dockerPath, "build", "-t", imageTag, "-f", dockerFile, checkoutLocation) dockerCmd.Stdout = os.Stdout dockerCmd.Stderr = os.Stderr @@ -159,60 +170,265 @@ func runRebuild(ctx context.Context, supervisorClient *supervisor.SupervisorClie ImageBuildDuration := time.Since(imageBuildStartTime).Milliseconds() event.Set("ImageBuildDuration", ImageBuildDuration) - err = TerminateExistingContainer(ctx) + // 3. start debug + fmt.Println("") + runLog := log.New() + runLog.Logger.SetLevel(logrus.TraceLevel) + runLog.Logger.SetFormatter(&prefixed.TextFormatter{ + TimestampFormat: "2006-01-02 15:04:05", + FullTimestamp: true, + ForceFormatting: true, + ForceColors: true, + }) + runLog.Logger.SetOutput(os.Stdout) + runLog.Info("Starting the debug workspace...") + + if wsInfo.DebugWorkspaceType != api.DebugWorkspaceType_noDebug { + runLog.Error("It is not possible to restart the debug workspace while you are currently inside it.") + event.Set("ErrorCode", utils.RebuildErrorCode_AlreadyInDebug) + return utils.Outcome_UserErr, nil + } + stopDebugContainer(ctx, dockerPath) + + workspaceUrl, err := url.Parse(wsInfo.WorkspaceUrl) + if err != nil { + return utils.Outcome_SystemErr, err + } + workspaceUrl.Host = "debug-" + workspaceUrl.Host + + workspaceLocation := gitpodConfig.WorkspaceLocation + if workspaceLocation == "" { + workspaceLocation = checkoutLocation + } + + // TODO what about auto derived by server, i.e. JB for prebuilds? we should move them into the workspace then + tasks, err := json.Marshal(gitpodConfig.Tasks) + if err != nil { + return utils.Outcome_SystemErr, err + } + + workspaceType := api.DebugWorkspaceType_regular + contentSource := api.ContentSource_from_other + if rebuildOpts.Prebuild { + workspaceType = api.DebugWorkspaceType_prebuild + } else if rebuildOpts.From == "prebuild" { + contentSource = api.ContentSource_from_prebuild + } else if rebuildOpts.From == "snapshot" { + contentSource = api.ContentSource_from_backup + } + debugEnvs, err := supervisorClient.Control.CreateDebugEnv(ctx, &api.CreateDebugEnvRequest{ + WorkspaceType: workspaceType, + ContentSource: contentSource, + WorkspaceUrl: workspaceUrl.String(), + CheckoutLocation: checkoutLocation, + WorkspaceLocation: workspaceLocation, + Tasks: string(tasks), + LogLevel: logLevel.String(), + }) + if err != nil { + return utils.Outcome_SystemErr, err + } + + // TODO project? - should not it be covered by gp env? + // Should we allow to provide additiona envs to test such, i.e. gp rebuild -e foo=bar + userEnvs, err := exec.CommandContext(ctx, "gp", "env").CombinedOutput() if err != nil { return utils.Outcome_SystemErr, err } - welcomeMessage := strings.Join([]string{ - "\n\nYou are now connected to the container.", - "Check if all tools and libraries you need are properly installed.", - "When you are done, type \"exit\" to return to your Gitpod workspace.\n", - }, "\n") + var envs string + for _, env := range debugEnvs.Envs { + envs += env + "\n" + } + envs += string(userEnvs) + + envFile := filepath.Join(tmpDir, ".env") + err = os.WriteFile(envFile, []byte(envs), 0644) + if err != nil { + return utils.Outcome_SystemErr, err + } - dockerRunCmd := exec.CommandContext(ctx, + // we don't pass context on purporse to handle graceful shutdown + // and output all logs properly below + runCmd := exec.Command( dockerPath, "run", "--rm", - "-v", "/workspace:/workspace", + "--user", "root", + "--privileged", "--label", "gp-rebuild=true", - "-it", tag, - "sh", - "-c", - fmt.Sprintf(` - echo "%s"; - cd "%s"; - if [ -x "$(command -v $SHELL)" ]; then - $SHELL; - else - if [ -x "$(command -v bash)" ]; then - bash; - else - sh; - fi; - fi; - `, welcomeMessage, wsInfo.CheckoutLocation), + "--env-file", envFile, + + // ports + "-p", "24999:22999", // supervisor + "-p", "25000:23000", // Web IDE + "-p", "25001:23001", // SSH + // 23002 dekstop IDE port, but it is covered by debug workspace proxy + "-p", "25003:23003", // debug workspace proxy + + // volumes + "-v", "/workspace:/workspace", + "-v", "/.supervisor:/.supervisor", + "-v", "/var/run/docker.sock:/var/run/docker.sock", + "-v", "/ide:/ide", + "-v", "/ide-desktop:/ide-desktop", + "-v", "/ide-desktop-plugins:/ide-desktop-plugins", // TODO refactor to keep all IDE deps under ide or ide-desktop + + imageTag, + "/.supervisor/supervisor", "init", ) - dockerRunCmd.Stdout = os.Stdout - dockerRunCmd.Stderr = os.Stderr - dockerRunCmd.Stdin = os.Stdin + debugSupervisor, err := supervisor.New(ctx, &supervisor.SupervisorClientOption{ + Address: "localhost:24999", + }) + if err != nil { + return utils.Outcome_SystemErr, err + } + + go func() { + debugSupervisor.WaitForIDEReady(ctx) + if ctx.Err() != nil { + return + } - err = dockerRunCmd.Start() + ssh := "ssh 'debug-" + wsInfo.WorkspaceId + "@" + workspaceUrl.Host + ".ssh." + wsInfo.WorkspaceClusterHost + "'" + sep := strings.Repeat("=", len(ssh)) + runLog.Infof(`The Debug Workspace is UP! +%s + +Open in Browser at: +%s + +Connect using SSH keys (https://gitpod.io/keys): +%s + +%s`, sep, workspaceUrl, ssh, sep) + err := notify(ctx, supervisorClient, workspaceUrl.String(), "The Debug Workspace is UP.") + if err != nil && ctx.Err() == nil { + log.WithError(err).Error("failed to notify") + } + }() + + pipeLogs := func(input io.Reader, ideLevel logrus.Level) { + reader := bufio.NewReader(input) + for { + line, _, err := reader.ReadLine() + if err != nil { + return + } + if len(line) == 0 { + continue + } + msg := make(logrus.Fields) + err = json.Unmarshal(line, &msg) + if err != nil { + if ideLevel > logLevel { + continue + } + + runLog.WithFields(msg).Log(ideLevel, string(line)) + } else { + wsLevel, err := logrus.ParseLevel(fmt.Sprintf("%v", msg["level"])) + if err != nil { + wsLevel = logrus.DebugLevel + } + if wsLevel == logrus.FatalLevel { + wsLevel = logrus.ErrorLevel + } + if wsLevel > logLevel { + continue + } + + message := fmt.Sprintf("%v", msg["message"]) + delete(msg, "message") + delete(msg, "level") + delete(msg, "time") + delete(msg, "severity") + delete(msg, "@type") + + component := fmt.Sprintf("%v", msg["component"]) + if wsLevel != logrus.DebugLevel && wsLevel != logrus.TraceLevel { + delete(msg, "file") + delete(msg, "func") + delete(msg, "serviceContext") + delete(msg, "component") + } else if component == "grpc" { + continue + } + + runLog.WithFields(msg).Log(wsLevel, message) + } + } + } + + stdout, err := runCmd.StdoutPipe() if err != nil { - fmt.Println("Failed to run docker container") + return utils.Outcome_SystemErr, err + } + go pipeLogs(stdout, logrus.InfoLevel) + + stderr, err := runCmd.StderrPipe() + if err != nil { + return utils.Outcome_SystemErr, err + } + go pipeLogs(stderr, logrus.ErrorLevel) + + err = runCmd.Start() + if err != nil { + fmt.Println("Failed to run a debug workspace") event.Set("ErrorCode", utils.RebuildErrorCode_DockerRunFailed) return utils.Outcome_UserErr, err } - _ = dockerRunCmd.Wait() + stopped := make(chan struct{}) + go func() { + _ = runCmd.Wait() + close(stopped) + }() + + select { + case <-ctx.Done(): + fmt.Println("") + logrus.Info("Gracefully stopping the debug workspace...") + stopDebugContainer(context.Background(), dockerPath) + case <-stopped: + } return utils.Outcome_Success, nil } -var buildCmd = &cobra.Command{ +func notify(ctx context.Context, supervisorClient *supervisor.SupervisorClient, workspaceUrl, message string) error { + response, err := supervisorClient.Notification.Notify(ctx, &api.NotifyRequest{ + Level: api.NotifyRequest_INFO, + Message: message, + Actions: []string{"Open"}, + }) + if err != nil { + return err + } + if response.Action == "Open" { + gpPath, err := exec.LookPath("gp") + if err != nil { + return err + } + gpCmd := exec.CommandContext(ctx, gpPath, "preview", "--external", workspaceUrl) + gpCmd.Stdout = os.Stdout + gpCmd.Stderr = os.Stderr + return gpCmd.Run() + } + return nil +} + +var rebuildOpts struct { + WorkspaceFolder string + LogLevel string + From string + Prebuild bool +} + +var rebuildCmd = &cobra.Command{ Use: "rebuild", - Short: "Re-builds the workspace image (useful to debug a workspace custom image)", + Short: "[experimental] Re-builds the workspace (useful to debug a workspace configuration)", Hidden: false, Run: func(cmd *cobra.Command, args []string) { ctx, cancel := context.WithCancel(context.Background()) @@ -255,5 +471,21 @@ var buildCmd = &cobra.Command{ } func init() { - rootCmd.AddCommand(buildCmd) + ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) + defer cancel() + + var workspaceFolder string + client, err := supervisor.New(ctx) + if err == nil { + wsInfo, err := client.Info.WorkspaceInfo(ctx, &api.WorkspaceInfoRequest{}) + if err == nil { + workspaceFolder = wsInfo.CheckoutLocation + } + } + + rootCmd.AddCommand(rebuildCmd) + rebuildCmd.PersistentFlags().StringVarP(&rebuildOpts.WorkspaceFolder, "workspace-folder", "w", workspaceFolder, "Path to the workspace folder.") + rebuildCmd.PersistentFlags().StringVarP(&rebuildOpts.LogLevel, "log", "", "error", "Log level to use. Allowed values are 'error', 'warn', 'info', 'debug', 'trace'.") + rebuildCmd.PersistentFlags().StringVarP(&rebuildOpts.From, "from", "", "", "Starts from 'prebuild' or 'snapshot'.") + rebuildCmd.PersistentFlags().BoolVarP(&rebuildOpts.Prebuild, "prebuild", "", false, "starts as a prebuild workspace (--from is ignored).") } diff --git a/components/gitpod-cli/go.mod b/components/gitpod-cli/go.mod index 7916e13310854c..d98e3fc802cee6 100644 --- a/components/gitpod-cli/go.mod +++ b/components/gitpod-cli/go.mod @@ -10,7 +10,7 @@ require ( github.com/gitpod-io/gitpod/supervisor/api v0.0.0-00010101000000-000000000000 github.com/go-errors/errors v1.4.2 github.com/golang/mock v1.6.0 - github.com/google/go-cmp v0.5.8 + github.com/google/go-cmp v0.5.9 github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2 github.com/gorilla/handlers v1.5.1 @@ -20,13 +20,23 @@ require ( github.com/sirupsen/logrus v1.8.1 github.com/sourcegraph/jsonrpc2 v0.0.0-20200429184054-15c2290dcb37 github.com/spf13/cobra v1.1.3 - golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d - golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 + golang.org/x/sys v0.3.0 + golang.org/x/term v0.3.0 golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f google.golang.org/grpc v1.49.0 gopkg.in/yaml.v2 v2.4.0 ) +require ( + github.com/mattn/go-colorable v0.0.9 // indirect + github.com/mattn/go-isatty v0.0.3 // indirect + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect + github.com/onsi/ginkgo v1.16.5 // indirect + github.com/onsi/gomega v1.24.2 // indirect + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect + google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect +) + require ( github.com/cenkalti/backoff/v4 v4.1.3 // indirect github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect @@ -39,9 +49,10 @@ require ( github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect - golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect - golang.org/x/text v0.3.7 // indirect google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect + github.com/x-cray/logrus-prefixed-formatter v0.5.2 + golang.org/x/net v0.4.0 // indirect + golang.org/x/text v0.5.0 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/segmentio/analytics-go.v3 v3.1.0 // indirect ) diff --git a/components/gitpod-cli/go.sum b/components/gitpod-cli/go.sum index 3068c3fbd2bf7f..f82ce4cd3fce60 100644 --- a/components/gitpod-cli/go.sum +++ b/components/gitpod-cli/go.sum @@ -51,6 +51,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= @@ -59,6 +61,7 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -72,6 +75,12 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -79,9 +88,11 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -124,6 +135,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -143,11 +155,15 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= +github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -160,9 +176,20 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.24.2 h1:J/tulyYK6JwBldPViHJReihxxZ+22FHs0piGjQAvoUE= +github.com/onsi/gomega v1.24.2/go.mod h1:gs3J10IS7Z7r7eXRoNJIrNqU4ToQukCJhFtKrWgHWnk= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -211,12 +238,16 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= +github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -230,6 +261,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -248,9 +281,11 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -263,9 +298,11 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -274,10 +311,12 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -289,21 +328,27 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d h1:Zu/JngovGLVi6t2J3nmAf3AoTDwuzw85YZ3b9o4yU7s= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM= -golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -324,6 +369,7 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -356,6 +402,12 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.49.0 h1:WTLtQzmQori5FUH25Pq4WT22oCsv8USpQ+F6rqtsmxw= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= @@ -365,13 +417,18 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U= gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/components/gitpod-cli/hot-swap.sh b/components/gitpod-cli/hot-swap.sh new file mode 100755 index 00000000000000..3cb25b65763dbb --- /dev/null +++ b/components/gitpod-cli/hot-swap.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Copyright (c) 2022 Gitpod GmbH. All rights reserved. +# Licensed under the GNU Affero General Public License (AGPL). +# See License.AGPL.txt in the project root for license information. + +set -Eeuo pipefail + +component=${PWD##*/} +workspaceUrl=$(echo "${1}" |sed -e "s/\/$//") +echo "URL: $workspaceUrl" + +workspaceDesc=$(gpctl workspaces describe "$workspaceUrl" -o=json) + +podName=$(echo "$workspaceDesc" | jq .runtime.pod_name -r) +echo "Pod: $podName" + +workspaceId=$(echo "$workspaceDesc" | jq .metadata.meta_id -r) +echo "ID: $workspaceId" + +clusterHost=$(kubectl exec -it "$podName" -- printenv GITPOD_WORKSPACE_CLUSTER_HOST |sed -e "s/\s//g") +echo "Cluster Host: $clusterHost" + +# prepare ssh +ownerToken=$(kubectl get pod "$podName" -o=json | jq ".metadata.annotations.\"gitpod\/ownerToken\"" -r) +sshConfig=$(mktemp) +echo "Host $workspaceId" > "$sshConfig" +echo " Hostname \"$workspaceId.ssh.$clusterHost\"" >> "$sshConfig" +echo " User \"$workspaceId#$ownerToken\"" >> "$sshConfig" + +# build +go build . +echo "$component built" + +# upload +uploadDest="/.supervisor/$component" +echo "Upload Dest: $uploadDest" +ssh -F "$sshConfig" "$workspaceId" "sudo chown -R gitpod:gitpod /.supervisor && rm $uploadDest 2> /dev/null" +echo "Permissions granted" +scp -F "$sshConfig" -r "./$component" "$workspaceId":"$uploadDest" +echo "Swap complete" diff --git a/components/gitpod-cli/pkg/supervisor/client.go b/components/gitpod-cli/pkg/supervisor/client.go index 034ea6c3cb6652..9a4549613fc790 100644 --- a/components/gitpod-cli/pkg/supervisor/client.go +++ b/components/gitpod-cli/pkg/supervisor/client.go @@ -21,9 +21,11 @@ type SupervisorClient struct { conn *grpc.ClientConn closeOnce sync.Once - Status api.StatusServiceClient - Terminal api.TerminalServiceClient - Info api.InfoServiceClient + Status api.StatusServiceClient + Terminal api.TerminalServiceClient + Info api.InfoServiceClient + Notification api.NotificationServiceClient + Control api.ControlServiceClient } type SupervisorClientOption struct { @@ -43,10 +45,12 @@ func New(ctx context.Context, options ...*SupervisorClientOption) (*SupervisorCl } return &SupervisorClient{ - conn: conn, - Status: api.NewStatusServiceClient(conn), - Terminal: api.NewTerminalServiceClient(conn), - Info: api.NewInfoServiceClient(conn), + conn: conn, + Status: api.NewStatusServiceClient(conn), + Terminal: api.NewTerminalServiceClient(conn), + Info: api.NewInfoServiceClient(conn), + Notification: api.NewNotificationServiceClient(conn), + Control: api.NewControlServiceClient(conn), }, nil } diff --git a/components/gitpod-cli/pkg/utils/trackEvent.go b/components/gitpod-cli/pkg/utils/trackEvent.go index 53236a11ad67ed..7b8a5459971adb 100644 --- a/components/gitpod-cli/pkg/utils/trackEvent.go +++ b/components/gitpod-cli/pkg/utils/trackEvent.go @@ -33,6 +33,8 @@ const ( RebuildErrorCode_MalformedGitpodYaml = "rebuild_malformed_gitpod_yaml" RebuildErrorCode_MissingGitpodYaml = "rebuild_missing_gitpod_yaml" RebuildErrorCode_NoCustomImage = "rebuild_no_custom_image" + RebuildErrorCode_AlreadyInDebug = "rebuild_already_in_debug" + RebuildErrorCode_InvaligLogLevel = "rebuild_invalid_log_level" ) type TrackCommandUsageParams struct { diff --git a/components/ide/code-desktop/status/main.go b/components/ide/code-desktop/status/main.go index d246f5c66e67c8..b3e28fbe227e68 100644 --- a/components/ide/code-desktop/status/main.go +++ b/components/ide/code-desktop/status/main.go @@ -41,7 +41,6 @@ func main() { errlog := log.New(os.Stderr, "VS Code Desktop status: ", log.LstdFlags) http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) { - wsInfo, err := GetWSInfo(context.Background()) if err != nil { errlog.Printf("cannot get workspace info: %v\n", err) @@ -49,14 +48,20 @@ func main() { } type Query struct { - InstanceId string `json:"instanceId"` - WorkspaceId string `json:"workspaceId"` - GitpodHost string `json:"gitpodHost"` + InstanceId string `json:"instanceId"` + WorkspaceId string `json:"workspaceId"` + GitpodHost string `json:"gitpodHost"` + DebugWorkspace bool `json:"debugWorkspace"` + } + debugWorkspace := false + if wsInfo.GetDebugWorkspaceType() != supervisor.DebugWorkspaceType_noDebug { + debugWorkspace = true } query := &Query{ - InstanceId: wsInfo.InstanceId, - WorkspaceId: wsInfo.WorkspaceId, - GitpodHost: wsInfo.GitpodHost, + InstanceId: wsInfo.InstanceId, + WorkspaceId: wsInfo.WorkspaceId, + GitpodHost: wsInfo.GitpodHost, + DebugWorkspace: debugWorkspace, } b, err := json.Marshal(query) if err != nil { diff --git a/components/ide/code/codehelper/main.go b/components/ide/code/codehelper/main.go index e391078ca5a922..38251f9660fa5b 100644 --- a/components/ide/code/codehelper/main.go +++ b/components/ide/code/codehelper/main.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "errors" + "fmt" "net/url" "os" "path/filepath" @@ -24,6 +25,7 @@ import ( "github.com/gitpod-io/gitpod/common-go/util" gitpod "github.com/gitpod-io/gitpod/gitpod-protocol" supervisor "github.com/gitpod-io/gitpod/supervisor/api" + "github.com/sirupsen/logrus" ) var ( @@ -34,8 +36,9 @@ var ( ) const ( - Code = "/ide/bin/gitpod-code" - ProductJsonLocation = "/ide/product.json" + Code = "/ide/bin/gitpod-code" + ProductJsonLocation = "/ide/product.json" + WebWorkbenchMainLocation = "/ide/out/vs/workbench/workbench.web.main.js" ) func main() { @@ -57,11 +60,32 @@ func main() { } phaseDone() + if err := prepareWebWorkbenchMain(wsInfo); err != nil { + log.WithError(err).Error("failed to prepare web workbench") + } + // code server args install extension with id args := []string{} if enableDebug { args = append(args, "--inspect", "--log=trace") + } else { + switch log.Log.Logger.GetLevel() { + case logrus.PanicLevel: + args = append(args, "--log=critical") + case logrus.FatalLevel: + args = append(args, "--log=critical") + case logrus.ErrorLevel: + args = append(args, "--log=error") + case logrus.WarnLevel: + args = append(args, "--log=warn") + case logrus.InfoLevel: + args = append(args, "--log=info") + case logrus.DebugLevel: + args = append(args, "--log=debug") + case logrus.TraceLevel: + args = append(args, "--log=trace") + } } args = append(args, "--install-builtin-extension", "gitpod.gitpod-theme") @@ -204,14 +228,43 @@ func replaceOpenVSXUrl() error { if err != nil { return errors.New("failed to read product.json: " + err.Error()) } + b = replaceOpenVSX(b) + if err := os.WriteFile(ProductJsonLocation, b, 0644); err != nil { + return errors.New("failed to write product.json: " + err.Error()) + } + return nil +} + +// TODO it is be applied as well by blobserve if served for regular workspace location +// reconsider how to configure in all modes, i.e. regular, debug, dev +func prepareWebWorkbenchMain(wsInfo *supervisor.WorkspaceInfoResponse) error { + phase := phaseLogging("prepareWebWorkbenchMain") + defer phase() + b, err := os.ReadFile(WebWorkbenchMainLocation) + if err != nil { + return errors.New("failed to read " + WebWorkbenchMainLocation + ": " + err.Error()) + } + url, err := url.Parse(wsInfo.GitpodHost) + if err != nil { + return errors.New("failed to parse " + wsInfo.GitpodHost + ": " + err.Error()) + } + domain := url.Hostname() + b = bytes.ReplaceAll(b, []byte("vscode-cdn.net"), []byte(domain)) + b = bytes.ReplaceAll(b, []byte("ide.gitpod.io/code/markeplace.json"), []byte(fmt.Sprintf("ide.%s/code/marketplace.json", domain))) + + b = replaceOpenVSX(b) + + if err := os.WriteFile(WebWorkbenchMainLocation, b, 0644); err != nil { + return errors.New("failed to write " + WebWorkbenchMainLocation + ": " + err.Error()) + } + return nil +} + +func replaceOpenVSX(b []byte) []byte { registryUrl := os.Getenv("VSX_REGISTRY_URL") if registryUrl != "" { b = bytes.ReplaceAll(b, []byte("https://open-vsx.org"), []byte(registryUrl)) } b = bytes.ReplaceAll(b, []byte("{{extensionsGalleryItemUrl}}"), []byte("https://open-vsx.org/vscode/item")) - b = bytes.ReplaceAll(b, []byte("{{trustedDomain}}"), []byte("https://open-vsx.org")) - if err := os.WriteFile(ProductJsonLocation, b, 0644); err != nil { - return errors.New("failed to write product.json: " + err.Error()) - } - return nil + return bytes.ReplaceAll(b, []byte("{{trustedDomain}}"), []byte("https://open-vsx.org")) } diff --git a/components/ide/jetbrains/launcher/main.go b/components/ide/jetbrains/launcher/main.go index 78aaf5be8380e3..05fe287ec4832d 100644 --- a/components/ide/jetbrains/launcher/main.go +++ b/components/ide/jetbrains/launcher/main.go @@ -301,10 +301,11 @@ func resolveGatewayLink(backendPort string, wsInfo *supervisor.WorkspaceInfoResp if err != nil { return "", err } + debugWorkspace := wsInfo.DebugWorkspaceType != supervisor.DebugWorkspaceType_noDebug link := url.URL{ Scheme: "jetbrains-gateway", Host: "connect", - Fragment: fmt.Sprintf("gitpodHost=%s&workspaceId=%s&backendPort=%s", gitpodUrl.Hostname(), wsInfo.WorkspaceId, backendPort), + Fragment: fmt.Sprintf("gitpodHost=%s&workspaceId=%s&backendPort=%s&debugWorkspace=%t", gitpodUrl.Hostname(), wsInfo.WorkspaceId, backendPort, debugWorkspace), } return link.String(), nil } diff --git a/components/supervisor-api/control.proto b/components/supervisor-api/control.proto index da150720ef625c..d84ac8d678d4d7 100644 --- a/components/supervisor-api/control.proto +++ b/components/supervisor-api/control.proto @@ -6,6 +6,9 @@ syntax = "proto3"; package supervisor; +import "status.proto"; +import "info.proto"; + option go_package = "github.com/gitpod-io/gitpod/supervisor/api"; option java_package = "io.gitpod.supervisor.api"; @@ -17,6 +20,9 @@ service ControlService { // CreateSSHKeyPair Create a pair of SSH Keys and put them in ~/.ssh/authorized_keys, this will only be generated once in the entire workspace lifecycle rpc CreateSSHKeyPair(CreateSSHKeyPairRequest) returns (CreateSSHKeyPairResponse) {} + + // CreateDebugEnv creates a debug workspace envs + rpc CreateDebugEnv(CreateDebugEnvRequest) returns (CreateDebugEnvResponse) {} } message ExposePortRequest { @@ -32,3 +38,24 @@ message CreateSSHKeyPairResponse { // Return privateKey for ws-proxy string private_key = 1; } + +message CreateDebugEnvRequest { + // workspace_type indicates whether it is a regular or prebuild workspace + DebugWorkspaceType workspace_type = 1; + // content_source indicates where the workspace content came from + ContentSource content_source = 2; + // workspace_url is an URL for which the workspace is accessed. + string workspace_url = 3; + // JSON serialized tasks to run + string tasks = 4; + // checkout_location is the path where we initialized the workspace content + string checkout_location = 5; + // workspace_location is the location of the IDE workspace + string workspace_location = 6; + // logLevel to use in a debug workspace. + string logLevel = 7; +} + +message CreateDebugEnvResponse { + repeated string envs = 1; +} diff --git a/components/supervisor-api/go/control.pb.go b/components/supervisor-api/go/control.pb.go index 1f37faa119eed6..a473819564a95a 100644 --- a/components/supervisor-api/go/control.pb.go +++ b/components/supervisor-api/go/control.pb.go @@ -196,38 +196,219 @@ func (x *CreateSSHKeyPairResponse) GetPrivateKey() string { return "" } +type CreateDebugEnvRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // workspace_type indicates whether it is a regular or prebuild workspace + WorkspaceType DebugWorkspaceType `protobuf:"varint,1,opt,name=workspace_type,json=workspaceType,proto3,enum=supervisor.DebugWorkspaceType" json:"workspace_type,omitempty"` + // content_source indicates where the workspace content came from + ContentSource ContentSource `protobuf:"varint,2,opt,name=content_source,json=contentSource,proto3,enum=supervisor.ContentSource" json:"content_source,omitempty"` + // workspace_url is an URL for which the workspace is accessed. + WorkspaceUrl string `protobuf:"bytes,3,opt,name=workspace_url,json=workspaceUrl,proto3" json:"workspace_url,omitempty"` + // JSON serialized tasks to run + Tasks string `protobuf:"bytes,4,opt,name=tasks,proto3" json:"tasks,omitempty"` + // checkout_location is the path where we initialized the workspace content + CheckoutLocation string `protobuf:"bytes,5,opt,name=checkout_location,json=checkoutLocation,proto3" json:"checkout_location,omitempty"` + // workspace_location is the location of the IDE workspace + WorkspaceLocation string `protobuf:"bytes,6,opt,name=workspace_location,json=workspaceLocation,proto3" json:"workspace_location,omitempty"` + // logLevel to use in a debug workspace. + LogLevel string `protobuf:"bytes,7,opt,name=logLevel,proto3" json:"logLevel,omitempty"` +} + +func (x *CreateDebugEnvRequest) Reset() { + *x = CreateDebugEnvRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_control_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateDebugEnvRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateDebugEnvRequest) ProtoMessage() {} + +func (x *CreateDebugEnvRequest) ProtoReflect() protoreflect.Message { + mi := &file_control_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateDebugEnvRequest.ProtoReflect.Descriptor instead. +func (*CreateDebugEnvRequest) Descriptor() ([]byte, []int) { + return file_control_proto_rawDescGZIP(), []int{4} +} + +func (x *CreateDebugEnvRequest) GetWorkspaceType() DebugWorkspaceType { + if x != nil { + return x.WorkspaceType + } + return DebugWorkspaceType_noDebug +} + +func (x *CreateDebugEnvRequest) GetContentSource() ContentSource { + if x != nil { + return x.ContentSource + } + return ContentSource_from_other +} + +func (x *CreateDebugEnvRequest) GetWorkspaceUrl() string { + if x != nil { + return x.WorkspaceUrl + } + return "" +} + +func (x *CreateDebugEnvRequest) GetTasks() string { + if x != nil { + return x.Tasks + } + return "" +} + +func (x *CreateDebugEnvRequest) GetCheckoutLocation() string { + if x != nil { + return x.CheckoutLocation + } + return "" +} + +func (x *CreateDebugEnvRequest) GetWorkspaceLocation() string { + if x != nil { + return x.WorkspaceLocation + } + return "" +} + +func (x *CreateDebugEnvRequest) GetLogLevel() string { + if x != nil { + return x.LogLevel + } + return "" +} + +type CreateDebugEnvResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Envs []string `protobuf:"bytes,1,rep,name=envs,proto3" json:"envs,omitempty"` +} + +func (x *CreateDebugEnvResponse) Reset() { + *x = CreateDebugEnvResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_control_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateDebugEnvResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateDebugEnvResponse) ProtoMessage() {} + +func (x *CreateDebugEnvResponse) ProtoReflect() protoreflect.Message { + mi := &file_control_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateDebugEnvResponse.ProtoReflect.Descriptor instead. +func (*CreateDebugEnvResponse) Descriptor() ([]byte, []int) { + return file_control_proto_rawDescGZIP(), []int{5} +} + +func (x *CreateDebugEnvResponse) GetEnvs() []string { + if x != nil { + return x.Envs + } + return nil +} + var File_control_proto protoreflect.FileDescriptor var file_control_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x0a, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x22, 0x2d, 0x0a, 0x11, 0x45, - 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, - 0x70, 0x6f, 0x72, 0x74, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x14, 0x0a, 0x12, 0x45, 0x78, - 0x70, 0x6f, 0x73, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x19, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, - 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x18, 0x43, + 0x0a, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x1a, 0x0c, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0a, 0x69, 0x6e, 0x66, 0x6f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2d, 0x0a, 0x11, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, + 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x4a, 0x04, + 0x08, 0x02, 0x10, 0x03, 0x22, 0x14, 0x0a, 0x12, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, 0x6f, + 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x0a, 0x17, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, + 0x53, 0x48, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, + 0x65, 0x79, 0x22, 0xd3, 0x02, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x62, + 0x75, 0x67, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x0e, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, + 0x72, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x40, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x61, + 0x73, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x61, 0x73, 0x6b, 0x73, + 0x12, 0x2b, 0x0a, 0x11, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x6f, 0x75, 0x74, 0x5f, 0x6c, 0x6f, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x63, 0x68, 0x65, + 0x63, 0x6b, 0x6f, 0x75, 0x74, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, + 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, + 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x2c, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x44, 0x65, 0x62, 0x75, 0x67, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x6e, 0x76, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x04, 0x65, 0x6e, 0x76, 0x73, 0x32, 0x9b, 0x02, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x45, 0x78, 0x70, + 0x6f, 0x73, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, + 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, + 0x73, 0x6f, 0x72, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x12, 0x23, 0x2e, 0x73, + 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, - 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, - 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x32, 0xc0, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x0a, 0x45, - 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x2e, 0x73, 0x75, 0x70, 0x65, - 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, 0x6f, 0x72, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, - 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x45, 0x78, 0x70, 0x6f, 0x73, 0x65, 0x50, 0x6f, 0x72, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5f, 0x0a, 0x10, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x12, 0x23, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x0e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x44, 0x65, 0x62, 0x75, 0x67, 0x45, 0x6e, 0x76, 0x12, 0x21, 0x2e, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, + 0x65, 0x62, 0x75, 0x67, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, - 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x50, 0x61, 0x69, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x46, 0x0a, 0x18, 0x69, - 0x6f, 0x2e, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, - 0x73, 0x6f, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, - 0x74, 0x70, 0x6f, 0x64, 0x2f, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2f, - 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x65, 0x44, 0x65, 0x62, 0x75, 0x67, 0x45, 0x6e, 0x76, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x42, 0x46, 0x0a, 0x18, 0x69, 0x6f, 0x2e, 0x67, 0x69, 0x74, 0x70, 0x6f, + 0x64, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x61, 0x70, 0x69, + 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, + 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2f, 0x73, 0x75, + 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -242,23 +423,31 @@ func file_control_proto_rawDescGZIP() []byte { return file_control_proto_rawDescData } -var file_control_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_control_proto_msgTypes = make([]protoimpl.MessageInfo, 6) var file_control_proto_goTypes = []interface{}{ (*ExposePortRequest)(nil), // 0: supervisor.ExposePortRequest (*ExposePortResponse)(nil), // 1: supervisor.ExposePortResponse (*CreateSSHKeyPairRequest)(nil), // 2: supervisor.CreateSSHKeyPairRequest (*CreateSSHKeyPairResponse)(nil), // 3: supervisor.CreateSSHKeyPairResponse + (*CreateDebugEnvRequest)(nil), // 4: supervisor.CreateDebugEnvRequest + (*CreateDebugEnvResponse)(nil), // 5: supervisor.CreateDebugEnvResponse + (DebugWorkspaceType)(0), // 6: supervisor.DebugWorkspaceType + (ContentSource)(0), // 7: supervisor.ContentSource } var file_control_proto_depIdxs = []int32{ - 0, // 0: supervisor.ControlService.ExposePort:input_type -> supervisor.ExposePortRequest - 2, // 1: supervisor.ControlService.CreateSSHKeyPair:input_type -> supervisor.CreateSSHKeyPairRequest - 1, // 2: supervisor.ControlService.ExposePort:output_type -> supervisor.ExposePortResponse - 3, // 3: supervisor.ControlService.CreateSSHKeyPair:output_type -> supervisor.CreateSSHKeyPairResponse - 2, // [2:4] is the sub-list for method output_type - 0, // [0:2] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 6, // 0: supervisor.CreateDebugEnvRequest.workspace_type:type_name -> supervisor.DebugWorkspaceType + 7, // 1: supervisor.CreateDebugEnvRequest.content_source:type_name -> supervisor.ContentSource + 0, // 2: supervisor.ControlService.ExposePort:input_type -> supervisor.ExposePortRequest + 2, // 3: supervisor.ControlService.CreateSSHKeyPair:input_type -> supervisor.CreateSSHKeyPairRequest + 4, // 4: supervisor.ControlService.CreateDebugEnv:input_type -> supervisor.CreateDebugEnvRequest + 1, // 5: supervisor.ControlService.ExposePort:output_type -> supervisor.ExposePortResponse + 3, // 6: supervisor.ControlService.CreateSSHKeyPair:output_type -> supervisor.CreateSSHKeyPairResponse + 5, // 7: supervisor.ControlService.CreateDebugEnv:output_type -> supervisor.CreateDebugEnvResponse + 5, // [5:8] is the sub-list for method output_type + 2, // [2:5] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_control_proto_init() } @@ -266,6 +455,8 @@ func file_control_proto_init() { if File_control_proto != nil { return } + file_status_proto_init() + file_info_proto_init() if !protoimpl.UnsafeEnabled { file_control_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExposePortRequest); i { @@ -315,6 +506,30 @@ func file_control_proto_init() { return nil } } + file_control_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateDebugEnvRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_control_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateDebugEnvResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -322,7 +537,7 @@ func file_control_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_control_proto_rawDesc, NumEnums: 0, - NumMessages: 4, + NumMessages: 6, NumExtensions: 0, NumServices: 1, }, diff --git a/components/supervisor-api/go/control_grpc.pb.go b/components/supervisor-api/go/control_grpc.pb.go index 0bddf5e344ddac..405172e0f2c8e2 100644 --- a/components/supervisor-api/go/control_grpc.pb.go +++ b/components/supervisor-api/go/control_grpc.pb.go @@ -30,6 +30,8 @@ type ControlServiceClient interface { ExposePort(ctx context.Context, in *ExposePortRequest, opts ...grpc.CallOption) (*ExposePortResponse, error) // CreateSSHKeyPair Create a pair of SSH Keys and put them in ~/.ssh/authorized_keys, this will only be generated once in the entire workspace lifecycle CreateSSHKeyPair(ctx context.Context, in *CreateSSHKeyPairRequest, opts ...grpc.CallOption) (*CreateSSHKeyPairResponse, error) + // CreateDebugEnv creates a debug workspace envs + CreateDebugEnv(ctx context.Context, in *CreateDebugEnvRequest, opts ...grpc.CallOption) (*CreateDebugEnvResponse, error) } type controlServiceClient struct { @@ -58,6 +60,15 @@ func (c *controlServiceClient) CreateSSHKeyPair(ctx context.Context, in *CreateS return out, nil } +func (c *controlServiceClient) CreateDebugEnv(ctx context.Context, in *CreateDebugEnvRequest, opts ...grpc.CallOption) (*CreateDebugEnvResponse, error) { + out := new(CreateDebugEnvResponse) + err := c.cc.Invoke(ctx, "/supervisor.ControlService/CreateDebugEnv", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ControlServiceServer is the server API for ControlService service. // All implementations must embed UnimplementedControlServiceServer // for forward compatibility @@ -66,6 +77,8 @@ type ControlServiceServer interface { ExposePort(context.Context, *ExposePortRequest) (*ExposePortResponse, error) // CreateSSHKeyPair Create a pair of SSH Keys and put them in ~/.ssh/authorized_keys, this will only be generated once in the entire workspace lifecycle CreateSSHKeyPair(context.Context, *CreateSSHKeyPairRequest) (*CreateSSHKeyPairResponse, error) + // CreateDebugEnv creates a debug workspace envs + CreateDebugEnv(context.Context, *CreateDebugEnvRequest) (*CreateDebugEnvResponse, error) mustEmbedUnimplementedControlServiceServer() } @@ -79,6 +92,9 @@ func (UnimplementedControlServiceServer) ExposePort(context.Context, *ExposePort func (UnimplementedControlServiceServer) CreateSSHKeyPair(context.Context, *CreateSSHKeyPairRequest) (*CreateSSHKeyPairResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateSSHKeyPair not implemented") } +func (UnimplementedControlServiceServer) CreateDebugEnv(context.Context, *CreateDebugEnvRequest) (*CreateDebugEnvResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateDebugEnv not implemented") +} func (UnimplementedControlServiceServer) mustEmbedUnimplementedControlServiceServer() {} // UnsafeControlServiceServer may be embedded to opt out of forward compatibility for this service. @@ -128,6 +144,24 @@ func _ControlService_CreateSSHKeyPair_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } +func _ControlService_CreateDebugEnv_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateDebugEnvRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServiceServer).CreateDebugEnv(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/supervisor.ControlService/CreateDebugEnv", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServiceServer).CreateDebugEnv(ctx, req.(*CreateDebugEnvRequest)) + } + return interceptor(ctx, in, info, handler) +} + // ControlService_ServiceDesc is the grpc.ServiceDesc for ControlService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -143,6 +177,10 @@ var ControlService_ServiceDesc = grpc.ServiceDesc{ MethodName: "CreateSSHKeyPair", Handler: _ControlService_CreateSSHKeyPair_Handler, }, + { + MethodName: "CreateDebugEnv", + Handler: _ControlService_CreateDebugEnv_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "control.proto", diff --git a/components/supervisor-api/go/info.pb.go b/components/supervisor-api/go/info.pb.go index a94e14e6c19eed..fdc2aba3e2315a 100644 --- a/components/supervisor-api/go/info.pb.go +++ b/components/supervisor-api/go/info.pb.go @@ -25,6 +25,55 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type DebugWorkspaceType int32 + +const ( + DebugWorkspaceType_noDebug DebugWorkspaceType = 0 + DebugWorkspaceType_regular DebugWorkspaceType = 1 + DebugWorkspaceType_prebuild DebugWorkspaceType = 2 +) + +// Enum value maps for DebugWorkspaceType. +var ( + DebugWorkspaceType_name = map[int32]string{ + 0: "noDebug", + 1: "regular", + 2: "prebuild", + } + DebugWorkspaceType_value = map[string]int32{ + "noDebug": 0, + "regular": 1, + "prebuild": 2, + } +) + +func (x DebugWorkspaceType) Enum() *DebugWorkspaceType { + p := new(DebugWorkspaceType) + *p = x + return p +} + +func (x DebugWorkspaceType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DebugWorkspaceType) Descriptor() protoreflect.EnumDescriptor { + return file_info_proto_enumTypes[0].Descriptor() +} + +func (DebugWorkspaceType) Type() protoreflect.EnumType { + return &file_info_proto_enumTypes[0] +} + +func (x DebugWorkspaceType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DebugWorkspaceType.Descriptor instead. +func (DebugWorkspaceType) EnumDescriptor() ([]byte, []int) { + return file_info_proto_rawDescGZIP(), []int{0} +} + type WorkspaceInfoRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -101,7 +150,10 @@ type WorkspaceInfoResponse struct { IdePort uint32 `protobuf:"varint,14,opt,name=ide_port,json=idePort,proto3" json:"ide_port,omitempty"` // workspace_class denotes the class of the workspace WorkspaceClass *WorkspaceInfoResponse_WorkspaceClass `protobuf:"bytes,15,opt,name=workspace_class,json=workspaceClass,proto3" json:"workspace_class,omitempty"` - OwnerId string `protobuf:"bytes,16,opt,name=owner_id,json=ownerId,proto3" json:"owner_id,omitempty"` + // owner_id is user id who owns the workspace + OwnerId string `protobuf:"bytes,16,opt,name=owner_id,json=ownerId,proto3" json:"owner_id,omitempty"` + // debug_workspace_type indicates whether it is a regular or prebuild debug workspace + DebugWorkspaceType DebugWorkspaceType `protobuf:"varint,17,opt,name=debug_workspace_type,json=debugWorkspaceType,proto3,enum=supervisor.DebugWorkspaceType" json:"debug_workspace_type,omitempty"` } func (x *WorkspaceInfoResponse) Reset() { @@ -255,6 +307,13 @@ func (x *WorkspaceInfoResponse) GetOwnerId() string { return "" } +func (x *WorkspaceInfoResponse) GetDebugWorkspaceType() DebugWorkspaceType { + if x != nil { + return x.DebugWorkspaceType + } + return DebugWorkspaceType_noDebug +} + type isWorkspaceInfoResponse_WorkspaceLocation interface { isWorkspaceInfoResponse_WorkspaceLocation() } @@ -460,7 +519,7 @@ var file_info_proto_rawDesc = []byte{ 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x16, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x87, + 0x61, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xd9, 0x08, 0x0a, 0x15, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, @@ -510,22 +569,31 @@ var file_info_proto_rawDesc = []byte{ 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, - 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x1a, 0x3b, 0x0a, 0x09, 0x47, 0x69, 0x74, 0x70, 0x6f, 0x64, - 0x41, 0x50, 0x49, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, - 0x6f, 0x73, 0x74, 0x1a, 0x36, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, - 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x1a, 0x65, 0x0a, 0x0e, 0x57, - 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, - 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, - 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x42, 0x14, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, - 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x7f, 0x0a, 0x0b, 0x49, 0x6e, 0x66, 0x6f, + 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x50, 0x0a, 0x14, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x11, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, + 0x72, 0x2e, 0x44, 0x65, 0x62, 0x75, 0x67, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x12, 0x64, 0x65, 0x62, 0x75, 0x67, 0x57, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x1a, 0x3b, 0x0a, 0x09, 0x47, 0x69, 0x74, 0x70, + 0x6f, 0x64, 0x41, 0x50, 0x49, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x68, 0x6f, 0x73, 0x74, 0x1a, 0x36, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x6f, 0x72, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x1a, 0x65, 0x0a, + 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x14, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2a, 0x3c, 0x0a, 0x12, 0x44, 0x65, + 0x62, 0x75, 0x67, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x0b, 0x0a, 0x07, 0x6e, 0x6f, 0x44, 0x65, 0x62, 0x75, 0x67, 0x10, 0x00, 0x12, 0x0b, 0x0a, + 0x07, 0x72, 0x65, 0x67, 0x75, 0x6c, 0x61, 0x72, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x70, 0x72, + 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x10, 0x02, 0x32, 0x7f, 0x0a, 0x0b, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x70, 0x0a, 0x0d, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x2e, 0x73, 0x75, 0x70, 0x65, 0x72, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, @@ -553,25 +621,28 @@ func file_info_proto_rawDescGZIP() []byte { return file_info_proto_rawDescData } +var file_info_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_info_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_info_proto_goTypes = []interface{}{ - (*WorkspaceInfoRequest)(nil), // 0: supervisor.WorkspaceInfoRequest - (*WorkspaceInfoResponse)(nil), // 1: supervisor.WorkspaceInfoResponse - (*WorkspaceInfoResponse_GitpodAPI)(nil), // 2: supervisor.WorkspaceInfoResponse.GitpodAPI - (*WorkspaceInfoResponse_Repository)(nil), // 3: supervisor.WorkspaceInfoResponse.Repository - (*WorkspaceInfoResponse_WorkspaceClass)(nil), // 4: supervisor.WorkspaceInfoResponse.WorkspaceClass + (DebugWorkspaceType)(0), // 0: supervisor.DebugWorkspaceType + (*WorkspaceInfoRequest)(nil), // 1: supervisor.WorkspaceInfoRequest + (*WorkspaceInfoResponse)(nil), // 2: supervisor.WorkspaceInfoResponse + (*WorkspaceInfoResponse_GitpodAPI)(nil), // 3: supervisor.WorkspaceInfoResponse.GitpodAPI + (*WorkspaceInfoResponse_Repository)(nil), // 4: supervisor.WorkspaceInfoResponse.Repository + (*WorkspaceInfoResponse_WorkspaceClass)(nil), // 5: supervisor.WorkspaceInfoResponse.WorkspaceClass } var file_info_proto_depIdxs = []int32{ - 2, // 0: supervisor.WorkspaceInfoResponse.gitpod_api:type_name -> supervisor.WorkspaceInfoResponse.GitpodAPI - 3, // 1: supervisor.WorkspaceInfoResponse.repository:type_name -> supervisor.WorkspaceInfoResponse.Repository - 4, // 2: supervisor.WorkspaceInfoResponse.workspace_class:type_name -> supervisor.WorkspaceInfoResponse.WorkspaceClass - 0, // 3: supervisor.InfoService.WorkspaceInfo:input_type -> supervisor.WorkspaceInfoRequest - 1, // 4: supervisor.InfoService.WorkspaceInfo:output_type -> supervisor.WorkspaceInfoResponse - 4, // [4:5] is the sub-list for method output_type - 3, // [3:4] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 3, // 0: supervisor.WorkspaceInfoResponse.gitpod_api:type_name -> supervisor.WorkspaceInfoResponse.GitpodAPI + 4, // 1: supervisor.WorkspaceInfoResponse.repository:type_name -> supervisor.WorkspaceInfoResponse.Repository + 5, // 2: supervisor.WorkspaceInfoResponse.workspace_class:type_name -> supervisor.WorkspaceInfoResponse.WorkspaceClass + 0, // 3: supervisor.WorkspaceInfoResponse.debug_workspace_type:type_name -> supervisor.DebugWorkspaceType + 1, // 4: supervisor.InfoService.WorkspaceInfo:input_type -> supervisor.WorkspaceInfoRequest + 2, // 5: supervisor.InfoService.WorkspaceInfo:output_type -> supervisor.WorkspaceInfoResponse + 5, // [5:6] is the sub-list for method output_type + 4, // [4:5] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_info_proto_init() } @@ -650,13 +721,14 @@ func file_info_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_info_proto_rawDesc, - NumEnums: 0, + NumEnums: 1, NumMessages: 5, NumExtensions: 0, NumServices: 1, }, GoTypes: file_info_proto_goTypes, DependencyIndexes: file_info_proto_depIdxs, + EnumInfos: file_info_proto_enumTypes, MessageInfos: file_info_proto_msgTypes, }.Build() File_info_proto = out.File diff --git a/components/supervisor-api/info.proto b/components/supervisor-api/info.proto index 5c6605da802c89..0b9290f11b912c 100644 --- a/components/supervisor-api/info.proto +++ b/components/supervisor-api/info.proto @@ -94,4 +94,13 @@ message WorkspaceInfoResponse { // owner_id is user id who owns the workspace string owner_id = 16; + + // debug_workspace_type indicates whether it is a regular or prebuild debug workspace + DebugWorkspaceType debug_workspace_type = 17; +} + +enum DebugWorkspaceType { + noDebug = 0; + regular = 1; + prebuild = 2; } diff --git a/components/supervisor/.gitignore b/components/supervisor/.gitignore index 00282adb62ace2..bd452240480f68 100644 --- a/components/supervisor/.gitignore +++ b/components/supervisor/.gitignore @@ -1 +1 @@ -./supervisor +supervisor diff --git a/components/supervisor/BUILD.yaml b/components/supervisor/BUILD.yaml index 14268dc9a2b7cc..d0a88ba85e29f6 100644 --- a/components/supervisor/BUILD.yaml +++ b/components/supervisor/BUILD.yaml @@ -30,9 +30,11 @@ packages: - components/gitpod-cli:app argdeps: - imageRepoBase + - dockerVersion config: buildArgs: VERSION: ${version} + DOCKER_VERSION: ${dockerVersion} dockerfile: leeway.Dockerfile metadata: helm-component: workspace.supervisor diff --git a/components/supervisor/cmd/debug-proxy.go b/components/supervisor/cmd/debug-proxy.go new file mode 100644 index 00000000000000..525275c4de9c22 --- /dev/null +++ b/components/supervisor/cmd/debug-proxy.go @@ -0,0 +1,56 @@ +// Copyright (c) 2023 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License.AGPL.txt in the project root for license information. + +package cmd + +import ( + "fmt" + "net/http" + "net/http/httputil" + "net/url" + "strconv" + + "github.com/gitpod-io/gitpod/common-go/log" + "github.com/spf13/cobra" +) + +func NewSingleHostReverseProxy(target *url.URL) *httputil.ReverseProxy { + director := func(req *http.Request) { + req.URL.Scheme = target.Scheme + req.URL.Host = target.Host + if _, ok := req.Header["User-Agent"]; !ok { + // explicitly disable User-Agent so it's not set to default value + req.Header.Set("User-Agent", "") + } + req.Header.Del("X-WS-Proxy-Debug-Port") + } + return &httputil.ReverseProxy{Director: director} +} + +var debugProxyCmd = &cobra.Command{ + Use: "debug-proxy", + Short: "forward request to debug workspace", + Run: func(cmd *cobra.Command, args []string) { + log.Fatal(http.ListenAndServe(":23003", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + portStr := r.Header.Get("X-WS-Proxy-Debug-Port") + port, err := strconv.Atoi(portStr) + if err != nil || port < 1 || port > 65535 { + w.WriteHeader(502) + return + } + dst, err := url.Parse("http://localhost:" + portStr) + if err != nil { + w.WriteHeader(502) + return + } + fmt.Printf("%+v\n", dst) + proxy := NewSingleHostReverseProxy(dst) + proxy.ServeHTTP(w, r) + }))) + }, +} + +func init() { + rootCmd.AddCommand(debugProxyCmd) +} diff --git a/components/supervisor/cmd/init.go b/components/supervisor/cmd/init.go index e08e9cbe0b2f25..2db13c91a8eb8d 100644 --- a/components/supervisor/cmd/init.go +++ b/components/supervisor/cmd/init.go @@ -51,6 +51,16 @@ var initCmd = &cobra.Command{ if err != nil { supervisorPath = "/.supervisor/supervisor" } + + debugProxyCtx, stopDebugProxy := context.WithCancel(context.Background()) + if os.Getenv("SUPERVISOR_DEBUG_WORKSPACE_TYPE") != "" { + err = exec.CommandContext(debugProxyCtx, supervisorPath, "debug-proxy").Start() + if err != nil { + log.WithError(err).Fatal("cannot run debug workspace proxy") + } + } + defer stopDebugProxy() + runCommand := exec.Command(supervisorPath, "run") runCommand.Args[0] = "supervisor" runCommand.Stdin = os.Stdin diff --git a/components/supervisor/frontend/src/debug.ts b/components/supervisor/frontend/src/debug.ts deleted file mode 100644 index ca545563eeb74f..00000000000000 --- a/components/supervisor/frontend/src/debug.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (c) 2022 Gitpod GmbH. All rights reserved. - * Licensed under the GNU Affero General Public License (AGPL). - * See License.AGPL.txt in the project root for license information. - */ - -import { DisposableCollection } from "@gitpod/gitpod-protocol/lib/util/disposable"; -import * as IDEFrontendService from "./ide/ide-frontend-service-impl"; -import * as IDEWorker from "./ide/ide-worker"; -import * as IDEWebSocket from "./ide/ide-web-socket"; -import { SupervisorServiceClient } from "./ide/supervisor-service-client"; - -Object.assign(window, { gitpod: {} }); -IDEWorker.install(); -IDEWebSocket.install(); -IDEWebSocket.connectWorkspace(); -const ideService = IDEFrontendService.create(); -const loadingIDE = new Promise((resolve) => window.addEventListener("DOMContentLoaded", resolve, { once: true })); -const toStop = new DisposableCollection(); - -(async () => { - const supervisorServiceClient = SupervisorServiceClient.get(); - const [ideStatus] = await Promise.all([ - supervisorServiceClient.ideReady, - supervisorServiceClient.contentReady, - loadingIDE, - ]); - // TODO(desktop support) - // const isDesktopIde = ideStatus && ideStatus.desktop && ideStatus.desktop.link; - // if (!isDesktopIde) { - toStop.push(ideService.start()); - // } -})(); diff --git a/components/supervisor/frontend/src/index.ts b/components/supervisor/frontend/src/index.ts index 0e1cd181fce9f4..7770ce0082375d 100644 --- a/components/supervisor/frontend/src/index.ts +++ b/components/supervisor/frontend/src/index.ts @@ -9,9 +9,270 @@ * all other IDE scripts should go afterwards, head element should not have scripts */ -import { workspaceUrl } from "./shared/urls"; -if (workspaceUrl.debugWorkspace) { - require("./debug"); -} else { - require("./regular"); +import { IDEMetricsServiceClient, MetricsName } from "./ide/ide-metrics-service-client"; +IDEMetricsServiceClient.addCounter(MetricsName.SupervisorFrontendClientTotal).catch(() => {}); + +//#region supervisor frontend error capture +function isElement(obj: any): obj is Element { + return typeof obj.getAttribute === "function"; } + +window.addEventListener("error", (event) => { + const labels: Record = {}; + let resourceSource: string | null | undefined; + if (isElement(event.target)) { + // We take a look at what is the resource that was attempted to load; + resourceSource = event.target.getAttribute("src") || event.target.getAttribute("href"); + // If the event has a `target`, it means that it wasn't a script error + if (resourceSource) { + if (resourceSource.match(new RegExp(/\/build\/ide\/code:.+\/__files__\//g))) { + // TODO(ak) reconsider how to hide knowledge of VS Code from supervisor frontend, i.e instrument amd loader instead + labels["resource"] = "vscode-web-workbench"; + } + labels["error"] = "LoadError"; + } + } + if (event.error) { + IDEMetricsServiceClient.reportError(event.error).catch(() => {}); + } else if (labels["error"] == "LoadError") { + let error = new Error("LoadError"); + IDEMetricsServiceClient.reportError(error, { + resource: labels["resource"], + url: resourceSource ?? "", + }).catch(() => {}); + } + IDEMetricsServiceClient.addCounter(MetricsName.SupervisorFrontendErrorTotal, labels).catch(() => {}); +}); +//#endregion + +require("../src/shared/index.css"); + +import { WorkspaceInstancePhase } from "@gitpod/gitpod-protocol"; +import { DisposableCollection } from "@gitpod/gitpod-protocol/lib/util/disposable"; +import * as heartBeat from "./ide/heart-beat"; +import * as IDEFrontendService from "./ide/ide-frontend-service-impl"; +import * as IDEWorker from "./ide/ide-worker"; +import * as IDEWebSocket from "./ide/ide-web-socket"; +import { SupervisorServiceClient } from "./ide/supervisor-service-client"; +import * as LoadingFrame from "./shared/loading-frame"; + +window.gitpod = {}; +IDEWorker.install(); +IDEWebSocket.install(); +const ideService = IDEFrontendService.create(); +const loadingIDE = new Promise((resolve) => window.addEventListener("DOMContentLoaded", resolve, { once: true })); +const toStop = new DisposableCollection(); + +document.body.style.visibility = "hidden"; +LoadingFrame.load().then(async (loading) => { + const frontendDashboardServiceClient = loading.frontendDashboardServiceClient; + await frontendDashboardServiceClient.initialize(); + + if (frontendDashboardServiceClient.latestStatus.workspaceType !== "regular") { + return; + } + + document.title = frontendDashboardServiceClient.latestStatus.workspaceDescription ?? "gitpod"; + window.gitpod.loggedUserID = frontendDashboardServiceClient.latestStatus.loggedUserId; + + (async () => { + const supervisorServiceClient = SupervisorServiceClient.get(); + + let hideDesktopIde = false; + const hideDesktopIdeEventListener = frontendDashboardServiceClient.onOpenBrowserIDE(() => { + hideDesktopIdeEventListener.dispose(); + hideDesktopIde = true; + toStop.push(ideService.start()); + }); + toStop.push(hideDesktopIdeEventListener); + + //#region gitpod browser telemetry + // TODO(ak) get rid of it + // it is bad usage of window.postMessage + // VS Code should use Segment directly here and publish to production/staging untrusted + // supervisor frontend should not care about IDE specifics + window.addEventListener("message", async (event) => { + const type = event.data.type; + if (type === "vscode_telemetry") { + const { event: eventName, properties } = event.data; + frontendDashboardServiceClient.trackEvent({ + event: eventName, + properties, + }); + } + }); + //#endregion + + type DesktopIDEStatus = { link: string; label: string; clientID?: string; kind?: String }; + let isDesktopIde: undefined | boolean = undefined; + let ideStatus: undefined | { desktop: DesktopIDEStatus } = undefined; + + //#region current-frame + let current: HTMLElement = loading.frame; + let desktopRedirected = false; + let currentInstanceId = ""; + const nextFrame = () => { + const { instanceId, ideUrl, statusPhase } = frontendDashboardServiceClient.latestStatus ?? {}; + + if (instanceId) { + // refresh web page when instanceId changed + if (currentInstanceId !== "") { + if (instanceId !== currentInstanceId && ideUrl !== "") { + currentInstanceId = instanceId; + window.location.href = ideUrl!; + } + } else { + currentInstanceId = instanceId; + } + if (statusPhase === "running") { + if (!hideDesktopIde) { + if (isDesktopIde == undefined) { + return loading.frame; + } + if (isDesktopIde && !!ideStatus) { + trackDesktopIDEReady(ideStatus.desktop); + frontendDashboardServiceClient.setState({ + desktopIDE: { + link: ideStatus.desktop.link, + label: ideStatus.desktop.label || "Open Desktop IDE", + clientID: ideStatus.desktop.clientID!, + }, + }); + if (!desktopRedirected) { + desktopRedirected = true; + frontendDashboardServiceClient.openDesktopIDE(ideStatus.desktop.link); + } + return loading.frame; + } + } + if (ideService.state === "ready") { + return document.body; + } + } + } + return loading.frame; + }; + const updateCurrentFrame = () => { + const newCurrent = nextFrame(); + if (current === newCurrent) { + return; + } + current.style.visibility = "hidden"; + newCurrent.style.visibility = "visible"; + if (current === document.body) { + while (document.body.firstChild && document.body.firstChild !== newCurrent) { + document.body.removeChild(document.body.firstChild); + } + while (document.body.lastChild && document.body.lastChild !== newCurrent) { + document.body.removeChild(document.body.lastChild); + } + } + current = newCurrent; + }; + + const updateLoadingState = () => { + frontendDashboardServiceClient.setState({ + ideFrontendFailureCause: ideService.failureCause?.message, + }); + }; + const trackStatusRenderedEvent = ( + phase: string, + properties?: { + [prop: string]: any; + }, + ) => { + frontendDashboardServiceClient.trackEvent({ + event: "status_rendered", + properties: { + phase, + ...properties, + }, + }); + }; + let trackedDesktopIDEReady = false; + const trackDesktopIDEReady = ({ clientID, kind }: DesktopIDEStatus) => { + if (trackedDesktopIDEReady) { + return; + } + trackedDesktopIDEReady = true; + trackStatusRenderedEvent("desktop-ide-ready", { clientID, kind }); + }; + const trackIDEStatusRenderedEvent = () => { + let error: string | undefined; + if (ideService.failureCause) { + error = `${ideService.failureCause.message}\n${ideService.failureCause.stack}`; + } + trackStatusRenderedEvent(`ide-${ideService.state}`, { error }); + }; + + updateCurrentFrame(); + updateLoadingState(); + trackIDEStatusRenderedEvent(); + frontendDashboardServiceClient.onStatusUpdate(() => updateCurrentFrame()); + ideService.onDidChange(() => { + updateLoadingState(); + updateCurrentFrame(); + trackIDEStatusRenderedEvent(); + }); + supervisorServiceClient.ideReady + .then((newIdeStatus) => { + ideStatus = newIdeStatus; + isDesktopIde = !!ideStatus && !!ideStatus.desktop && !!ideStatus.desktop.link; + updateCurrentFrame(); + }) + .catch((error) => console.error(`Unexpected error from supervisorServiceClient.ideReady: ${error}`)); + window.addEventListener("unload", () => trackStatusRenderedEvent("window-unload"), { capture: true }); + //#endregion + + //#region heart-beat + heartBeat.track(window); + const updateHeartBeat = () => { + if (frontendDashboardServiceClient.latestStatus?.statusPhase === "running") { + heartBeat.schedule(frontendDashboardServiceClient); + } else { + heartBeat.cancel(); + } + }; + updateHeartBeat(); + frontendDashboardServiceClient.onStatusUpdate(() => updateHeartBeat()); + //#endregion + })(); + + (async () => { + //#region ide lifecycle + function isWorkspaceInstancePhase(phase: WorkspaceInstancePhase): boolean { + return frontendDashboardServiceClient.latestStatus?.statusPhase === phase; + } + if (!isWorkspaceInstancePhase("running")) { + await new Promise((resolve) => { + frontendDashboardServiceClient.onStatusUpdate((status) => { + if (status.statusPhase === "running") { + resolve(); + } + }); + }); + } + const supervisorServiceClient = SupervisorServiceClient.get(); + const [ideStatus] = await Promise.all([ + supervisorServiceClient.ideReady, + supervisorServiceClient.contentReady, + loadingIDE, + ]); + if (isWorkspaceInstancePhase("stopping") || isWorkspaceInstancePhase("stopped")) { + return; + } + toStop.pushAll([ + IDEWebSocket.connectWorkspace(), + frontendDashboardServiceClient.onStatusUpdate((status) => { + if (status.statusPhase === "stopping" || status.statusPhase === "stopped") { + toStop.dispose(); + } + }), + ]); + const isDesktopIde = ideStatus && ideStatus.desktop && ideStatus.desktop.link; + if (!isDesktopIde) { + toStop.push(ideService.start()); + } + //#endregion + })(); +}); diff --git a/components/supervisor/frontend/src/regular.ts b/components/supervisor/frontend/src/regular.ts deleted file mode 100644 index 6213d253738c3e..00000000000000 --- a/components/supervisor/frontend/src/regular.ts +++ /dev/null @@ -1,274 +0,0 @@ -/** - * Copyright (c) 2020 Gitpod GmbH. All rights reserved. - * Licensed under the GNU Affero General Public License (AGPL). - * See License.AGPL.txt in the project root for license information. - */ - -import { IDEMetricsServiceClient, MetricsName } from "./ide/ide-metrics-service-client"; -IDEMetricsServiceClient.addCounter(MetricsName.SupervisorFrontendClientTotal).catch(() => {}); - -//#region supervisor frontend error capture -function isElement(obj: any): obj is Element { - return typeof obj.getAttribute === "function"; -} - -window.addEventListener("error", (event) => { - const labels: Record = {}; - let resourceSource: string | null | undefined; - if (isElement(event.target)) { - // We take a look at what is the resource that was attempted to load; - resourceSource = event.target.getAttribute("src") || event.target.getAttribute("href"); - // If the event has a `target`, it means that it wasn't a script error - if (resourceSource) { - if (resourceSource.match(new RegExp(/\/build\/ide\/code:.+\/__files__\//g))) { - // TODO(ak) reconsider how to hide knowledge of VS Code from supervisor frontend, i.e instrument amd loader instead - labels["resource"] = "vscode-web-workbench"; - } - labels["error"] = "LoadError"; - } - } - if (event.error) { - IDEMetricsServiceClient.reportError(event.error).catch(() => {}); - } else if (labels["error"] == "LoadError") { - let error = new Error("LoadError"); - IDEMetricsServiceClient.reportError(error, { - resource: labels["resource"], - url: resourceSource ?? "", - }).catch(() => {}); - } - IDEMetricsServiceClient.addCounter(MetricsName.SupervisorFrontendErrorTotal, labels).catch(() => {}); -}); -//#endregion - -require("../src/shared/index.css"); - -import { WorkspaceInstancePhase } from "@gitpod/gitpod-protocol"; -import { DisposableCollection } from "@gitpod/gitpod-protocol/lib/util/disposable"; -import * as heartBeat from "./ide/heart-beat"; -import * as IDEFrontendService from "./ide/ide-frontend-service-impl"; -import * as IDEWorker from "./ide/ide-worker"; -import * as IDEWebSocket from "./ide/ide-web-socket"; -import { SupervisorServiceClient } from "./ide/supervisor-service-client"; -import * as LoadingFrame from "./shared/loading-frame"; -import { startUrl } from "./shared/urls"; - -window.gitpod = {}; -IDEWorker.install(); -IDEWebSocket.install(); -const ideService = IDEFrontendService.create(); -const loadingIDE = new Promise((resolve) => window.addEventListener("DOMContentLoaded", resolve, { once: true })); -const toStop = new DisposableCollection(); - -document.body.style.visibility = "hidden"; -LoadingFrame.load().then(async (loading) => { - const frontendDashboardServiceClient = loading.frontendDashboardServiceClient; - await frontendDashboardServiceClient.initialize(); - - if (frontendDashboardServiceClient.latestStatus.workspaceType !== "regular") { - return; - } - - document.title = frontendDashboardServiceClient.latestStatus.workspaceDescription ?? "gitpod"; - window.gitpod.loggedUserID = frontendDashboardServiceClient.latestStatus.loggedUserId; - - (async () => { - const supervisorServiceClient = SupervisorServiceClient.get(); - - let hideDesktopIde = false; - const hideDesktopIdeEventListener = frontendDashboardServiceClient.onOpenBrowserIDE(() => { - hideDesktopIdeEventListener.dispose(); - hideDesktopIde = true; - toStop.push(ideService.start()); - }); - toStop.push(hideDesktopIdeEventListener); - - //#region gitpod browser telemetry - // TODO(ak) get rid of it - // it is bad usage of window.postMessage - // VS Code should use Segment directly here and publish to production/staging untrusted - // supervisor frontend should not care about IDE specifics - window.addEventListener("message", async (event) => { - const type = event.data.type; - if (type === "vscode_telemetry") { - const { event: eventName, properties } = event.data; - frontendDashboardServiceClient.trackEvent({ - event: eventName, - properties, - }); - } - }); - //#endregion - - type DesktopIDEStatus = { link: string; label: string; clientID?: string; kind?: String }; - let isDesktopIde: undefined | boolean = undefined; - let ideStatus: undefined | { desktop: DesktopIDEStatus } = undefined; - - //#region current-frame - let current: HTMLElement = loading.frame; - let desktopRedirected = false; - let currentInstanceId = ""; - const nextFrame = () => { - const { instanceId, ideUrl, statusPhase } = frontendDashboardServiceClient.latestStatus ?? {}; - - if (instanceId) { - // refresh web page when instanceId changed - if (currentInstanceId !== "") { - if (instanceId !== currentInstanceId && ideUrl !== "") { - currentInstanceId = instanceId; - window.location.href = ideUrl!; - } - } else { - currentInstanceId = instanceId; - } - if (statusPhase === "running") { - if (!hideDesktopIde) { - if (isDesktopIde == undefined) { - return loading.frame; - } - if (isDesktopIde && !!ideStatus) { - trackDesktopIDEReady(ideStatus.desktop); - frontendDashboardServiceClient.setState({ - desktopIDE: { - link: ideStatus.desktop.link, - label: ideStatus.desktop.label || "Open Desktop IDE", - clientID: ideStatus.desktop.clientID!, - }, - }); - if (!desktopRedirected) { - desktopRedirected = true; - frontendDashboardServiceClient.openDesktopIDE(ideStatus.desktop.link); - } - return loading.frame; - } - } - if (ideService.state === "ready") { - return document.body; - } - } - } - return loading.frame; - }; - const updateCurrentFrame = () => { - const newCurrent = nextFrame(); - if (current === newCurrent) { - return; - } - current.style.visibility = "hidden"; - newCurrent.style.visibility = "visible"; - if (current === document.body) { - while (document.body.firstChild && document.body.firstChild !== newCurrent) { - document.body.removeChild(document.body.firstChild); - } - while (document.body.lastChild && document.body.lastChild !== newCurrent) { - document.body.removeChild(document.body.lastChild); - } - } - current = newCurrent; - }; - - const updateLoadingState = () => { - frontendDashboardServiceClient.setState({ - ideFrontendFailureCause: ideService.failureCause?.message, - }); - }; - const trackStatusRenderedEvent = ( - phase: string, - properties?: { - [prop: string]: any; - }, - ) => { - frontendDashboardServiceClient.trackEvent({ - event: "status_rendered", - properties: { - phase, - ...properties, - }, - }); - }; - let trackedDesktopIDEReady = false; - const trackDesktopIDEReady = ({ clientID, kind }: DesktopIDEStatus) => { - if (trackedDesktopIDEReady) { - return; - } - trackedDesktopIDEReady = true; - trackStatusRenderedEvent("desktop-ide-ready", { clientID, kind }); - }; - const trackIDEStatusRenderedEvent = () => { - let error: string | undefined; - if (ideService.failureCause) { - error = `${ideService.failureCause.message}\n${ideService.failureCause.stack}`; - } - trackStatusRenderedEvent(`ide-${ideService.state}`, { error }); - }; - - updateCurrentFrame(); - updateLoadingState(); - trackIDEStatusRenderedEvent(); - frontendDashboardServiceClient.onStatusUpdate(() => updateCurrentFrame()); - ideService.onDidChange(() => { - updateLoadingState(); - updateCurrentFrame(); - trackIDEStatusRenderedEvent(); - }); - supervisorServiceClient.ideReady - .then((newIdeStatus) => { - ideStatus = newIdeStatus; - isDesktopIde = !!ideStatus && !!ideStatus.desktop && !!ideStatus.desktop.link; - updateCurrentFrame(); - }) - .catch((error) => console.error(`Unexpected error from supervisorServiceClient.ideReady: ${error}`)); - window.addEventListener("unload", () => trackStatusRenderedEvent("window-unload"), { capture: true }); - //#endregion - - //#region heart-beat - heartBeat.track(window); - const updateHeartBeat = () => { - if (frontendDashboardServiceClient.latestStatus?.statusPhase === "running") { - heartBeat.schedule(frontendDashboardServiceClient); - } else { - heartBeat.cancel(); - } - }; - updateHeartBeat(); - frontendDashboardServiceClient.onStatusUpdate(() => updateHeartBeat()); - //#endregion - })(); - - (async () => { - //#region ide lifecycle - function isWorkspaceInstancePhase(phase: WorkspaceInstancePhase): boolean { - return frontendDashboardServiceClient.latestStatus?.statusPhase === phase; - } - if (!isWorkspaceInstancePhase("running")) { - await new Promise((resolve) => { - frontendDashboardServiceClient.onStatusUpdate((status) => { - if (status.statusPhase === "running") { - resolve(); - } - }); - }); - } - const supervisorServiceClient = SupervisorServiceClient.get(); - const [ideStatus] = await Promise.all([ - supervisorServiceClient.ideReady, - supervisorServiceClient.contentReady, - loadingIDE, - ]); - if (isWorkspaceInstancePhase("stopping") || isWorkspaceInstancePhase("stopped")) { - return; - } - toStop.pushAll([ - IDEWebSocket.connectWorkspace(), - frontendDashboardServiceClient.onStatusUpdate((status) => { - if (status.statusPhase === "stopping" || status.statusPhase === "stopped") { - toStop.dispose(); - } - }), - ]); - const isDesktopIde = ideStatus && ideStatus.desktop && ideStatus.desktop.link; - if (!isDesktopIde) { - toStop.push(ideService.start()); - } - //#endregion - })(); -}); diff --git a/components/supervisor/frontend/src/shared/frontend-dashboard-service.ts b/components/supervisor/frontend/src/shared/frontend-dashboard-service.ts index 7e232ff5e46191..1c6cd020b7f8e9 100644 --- a/components/supervisor/frontend/src/shared/frontend-dashboard-service.ts +++ b/components/supervisor/frontend/src/shared/frontend-dashboard-service.ts @@ -7,7 +7,7 @@ import { IDEFrontendDashboardService } from "@gitpod/gitpod-protocol/lib/frontend-dashboard-service"; import { RemoteTrackMessage } from "@gitpod/gitpod-protocol/lib/analytics"; import { Emitter } from "@gitpod/gitpod-protocol/lib/util/event"; -import { serverUrl } from "./urls"; +import { workspaceUrl, serverUrl } from "./urls"; export class FrontendDashboardServiceClient implements IDEFrontendDashboardService.IClient { public latestStatus!: IDEFrontendDashboardService.Status; @@ -47,6 +47,8 @@ export class FrontendDashboardServiceClient implements IDEFrontendDashboardServi } trackEvent(msg: RemoteTrackMessage): void { + const debugWorkspace = workspaceUrl.debugWorkspace; + msg.properties = { ...msg.properties, debugWorkspace }; this.serverWindow.postMessage( { type: "ide-track-event", msg } as IDEFrontendDashboardService.TrackEventData, serverUrl.url.origin, diff --git a/components/supervisor/hot-swap.sh b/components/supervisor/hot-swap.sh index fbbf7737b8c6e1..3cb25b65763dbb 100755 --- a/components/supervisor/hot-swap.sh +++ b/components/supervisor/hot-swap.sh @@ -5,9 +5,6 @@ set -Eeuo pipefail -# This script swaps the backend startup endpoint with a built one -# in a workspace and restarts the JB backend. - component=${PWD##*/} workspaceUrl=$(echo "${1}" |sed -e "s/\/$//") echo "URL: $workspaceUrl" @@ -39,5 +36,5 @@ uploadDest="/.supervisor/$component" echo "Upload Dest: $uploadDest" ssh -F "$sshConfig" "$workspaceId" "sudo chown -R gitpod:gitpod /.supervisor && rm $uploadDest 2> /dev/null" echo "Permissions granted" -scp -F "$sshConfig" -r "./supervisor" "$workspaceId":"$uploadDest" +scp -F "$sshConfig" -r "./$component" "$workspaceId":"$uploadDest" echo "Swap complete" diff --git a/components/supervisor/leeway.Dockerfile b/components/supervisor/leeway.Dockerfile index c83cc0f25f3334..2ea3733f4e404a 100644 --- a/components/supervisor/leeway.Dockerfile +++ b/components/supervisor/leeway.Dockerfile @@ -2,6 +2,17 @@ # Licensed under the GNU Affero General Public License (AGPL). # See License.AGPL.txt in the project root for license information. +FROM alpine:3.16 as docker_cli_builder + +RUN apk add wget tar + +ARG DOCKER_VERSION + +RUN mkdir /gp-docker \ + && cd /gp-docker \ + && wget https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz \ + && tar -zxvf docker-${DOCKER_VERSION}.tgz docker/docker + FROM scratch # BEWARE: This must be the first layer in the image, s.t. that blobserve @@ -19,6 +30,8 @@ WORKDIR "/.supervisor/ssh" COPY components-supervisor-openssh--app/usr/sbin/sshd . COPY components-supervisor-openssh--app/usr/bin/ssh-keygen . +COPY --from=docker_cli_builder /gp-docker/docker/docker /.supervisor/gitpod-docker-cli + ARG __GIT_COMMIT ARG VERSION diff --git a/components/supervisor/pkg/ports/exposed-ports.go b/components/supervisor/pkg/ports/exposed-ports.go index 0486a40f684413..f08a192366e519 100644 --- a/components/supervisor/pkg/ports/exposed-ports.go +++ b/components/supervisor/pkg/ports/exposed-ports.go @@ -140,7 +140,7 @@ func (g *GitpodExposedPorts) Observe(ctx context.Context) (<-chan []ExposedPort, res[uint32(p.Port)] = ExposedPort{ LocalPort: uint32(p.Port), Public: p.Visibility == "public", - URL: p.URL, + URL: g.getPortUrl(uint32(p.Port)), } } exposedPort := make([]ExposedPort, 0, len(res)) diff --git a/components/supervisor/pkg/ports/ports.go b/components/supervisor/pkg/ports/ports.go index d2fe62a1b2a60d..e1555dd359e702 100644 --- a/components/supervisor/pkg/ports/ports.go +++ b/components/supervisor/pkg/ports/ports.go @@ -174,46 +174,62 @@ func (pm *Manager) Run(ctx context.Context, wg *sync.WaitGroup) { forceUpdate = true case exposed = <-exposedUpdates: if exposed == nil { - log.Error("exposed ports observer stopped") + if ctx.Err() == nil { + log.Error("exposed ports observer stopped unexpectedly") + } return } case served = <-servedUpdates: if served == nil { - log.Error("served ports observer stopped") + if ctx.Err() == nil { + log.Error("served ports observer stopped unexpectedly") + } return } case configured = <-configUpdates: if configured == nil { - log.Error("configured ports observer stopped") + if ctx.Err() == nil { + log.Error("configured ports observer stopped unexpectedly") + } return } case tunneled = <-tunneledUpdates: if tunneled == nil { - log.Error("tunneled ports observer stopped") + if ctx.Err() == nil { + log.Error("tunneled ports observer stopped unexpectedly") + } return } case err := <-exposedErrors: if err == nil { - log.Error("exposed ports observer stopped") + if ctx.Err() == nil { + log.Error("exposed ports observer stopped unexpectedly") + } return } log.WithError(err).Warn("error while observing exposed ports") case err := <-servedErrors: if err == nil { - log.Error("served ports observer stopped") + if ctx.Err() == nil { + log.Error("served ports observer stopped unexpectedly") + } return } log.WithError(err).Warn("error while observing served ports") case err := <-configErrors: if err == nil { - log.Error("port configs observer stopped") + if ctx.Err() == nil { + log.Error("port configs observer stopped unexpectedly") + } return } log.WithError(err).Warn("error while observing served port configs") case err := <-tunneledErrors: if err == nil { - log.Error("tunneled ports observer stopped") + if ctx.Err() == nil { + log.Error("tunneled ports observer stopped unexpectedly") + } return } log.WithError(err).Warn("error while observing tunneled ports") diff --git a/components/supervisor/pkg/serverapi/publicapi.go b/components/supervisor/pkg/serverapi/publicapi.go index fbf3a6a1737b1f..67ac746790b45f 100644 --- a/components/supervisor/pkg/serverapi/publicapi.go +++ b/components/supervisor/pkg/serverapi/publicapi.go @@ -340,7 +340,7 @@ func (s *Service) publicAPIInstanceUpdate(ctx context.Context, errChan chan erro resp, err := resp.Recv() if err != nil { code := status.Code(err) - if err != io.EOF && code != codes.Unavailable && code != codes.Canceled { + if err != io.EOF && ctx.Err() == nil && code != codes.Unavailable && code != codes.Canceled { log.WithField("method", "StreamWorkspaceStatus").WithError(err).Error("failed to receive status update") } if ctx.Err() != nil || code == codes.Canceled { diff --git a/components/supervisor/pkg/supervisor/config.go b/components/supervisor/pkg/supervisor/config.go index 85f0816a0d8cd2..4de1fc9698a0a9 100644 --- a/components/supervisor/pkg/supervisor/config.go +++ b/components/supervisor/pkg/supervisor/config.go @@ -18,6 +18,7 @@ import ( env "github.com/Netflix/go-env" "golang.org/x/xerrors" + csapi "github.com/gitpod-io/gitpod/content-service/api" gitpod "github.com/gitpod-io/gitpod/gitpod-protocol" "github.com/gitpod-io/gitpod/supervisor/api" ) @@ -83,9 +84,6 @@ type StaticConfig struct { // APIEndpointPort is the port where to serve the API endpoint on APIEndpointPort int `json:"apiEndpointPort"` - // HostAPIEndpointPort is the port where to the host API endpoint served - HostAPIEndpointPort *int `json:"hostAPIEndpointPort,omitempty"` - // SSHPort is the port we run the SSH server on SSHPort int `json:"sshPort"` } @@ -288,6 +286,12 @@ type WorkspaceConfig struct { // OwnerId is the user id who owns the workspace OwnerId string `env:"GITPOD_OWNER_ID"` + + // DebugWorkspaceType indicates whether it is a regular or prebuild debug workspace + DebugWorkspaceType api.DebugWorkspaceType `env:"SUPERVISOR_DEBUG_WORKSPACE_TYPE"` + + // DebugWorkspaceContenSource indicates where the debug workspace content came from + DebugWorkspaceContenSource api.ContentSource `env:"SUPERVISOR_DEBUG_WORKSPACE_CONTENT_SOURCE"` } // WorkspaceGitpodToken is a list of tokens that should be added to supervisor's token service. @@ -390,11 +394,31 @@ func (c WorkspaceConfig) GitpodAPIEndpoint() (endpoint, host string, err error) return } +// isPrebuild returns true if the workspace is prebuild. +func (c WorkspaceConfig) isPrebuild() bool { + return c.GitpodHeadless == "true" || c.DebugWorkspaceType == api.DebugWorkspaceType_prebuild +} + // getGitpodTasks returns true if the workspace is headless. func (c WorkspaceConfig) isHeadless() bool { return c.GitpodHeadless == "true" } +// isDebugWorkspace returns true if the workspace is in debug mode. +func (c WorkspaceConfig) isDebugWorkspace() bool { + return c.DebugWorkspaceType != api.DebugWorkspaceType_noDebug +} + +var contentSources = map[api.ContentSource]csapi.WorkspaceInitSource{ + api.ContentSource_from_other: csapi.WorkspaceInitFromOther, + api.ContentSource_from_backup: csapi.WorkspaceInitFromBackup, + api.ContentSource_from_prebuild: csapi.WorkspaceInitFromPrebuild, +} + +func (c WorkspaceConfig) GetDebugWorkspaceContentSource() csapi.WorkspaceInitSource { + return contentSources[c.DebugWorkspaceContenSource] +} + // getGitpodTasks parses gitpod tasks. func (c WorkspaceConfig) getGitpodTasks() (tasks *[]TaskConfig, err error) { if c.GitpodTasks == "" { diff --git a/components/supervisor/pkg/supervisor/services.go b/components/supervisor/pkg/supervisor/services.go index 3a3710f81b248c..f5e6db73f52902 100644 --- a/components/supervisor/pkg/supervisor/services.go +++ b/components/supervisor/pkg/supervisor/services.go @@ -8,6 +8,7 @@ import ( "bytes" "context" "errors" + "fmt" "io" "os" "path/filepath" @@ -653,6 +654,7 @@ func (is *InfoService) WorkspaceInfo(context.Context, *api.WorkspaceInfoRequest) IdePort: uint32(is.cfg.IDEPort), WorkspaceClass: &api.WorkspaceInfoResponse_WorkspaceClass{Id: is.cfg.WorkspaceClass}, OwnerId: is.cfg.OwnerId, + DebugWorkspaceType: is.cfg.DebugWorkspaceType, } if is.cfg.WorkspaceClassInfo != nil { resp.WorkspaceClass.DisplayName = is.cfg.WorkspaceClassInfo.DisplayName @@ -777,6 +779,44 @@ func (ss *ControlService) CreateSSHKeyPair(context.Context, *api.CreateSSHKeyPai }, err } +// CreateDebugEnv creates a debug workspace envs +func (c *ControlService) CreateDebugEnv(ctx context.Context, req *api.CreateDebugEnvRequest) (*api.CreateDebugEnvResponse, error) { + var envs []string + for _, env := range os.Environ() { + if env == "" { + continue + } + parts := strings.SplitN(env, "=", 2) + key := parts[0] + if strings.HasPrefix(key, "THEIA_") || + strings.HasPrefix(key, "GITPOD_") || + // TODO IDE - get rid of env vars in images, use supervisor api as a mediator to support many IDEs running in the same worksapce? + // TODO PATH - use well defined locations to pick up binaries, i.e. /ide/bin or /ide-desktop/bin in supervisor? + key == "VSX_REGISTRY_URL" || + key == "EDITOR" || + key == "VISUAL" || + key == "GP_OPEN_EDITOR" || + key == "GIT_EDITOR" || + key == "GP_PREVIEW_BROWSER" || + key == "GP_EXTERNAL_BROWSER" || + key == "JETBRAINS_BACKEND_QUALIFIER" { + envs = append(envs, env) + } + } + envs = append(envs, fmt.Sprintf("SUPERVISOR_DEBUG_WORKSPACE_TYPE=%d", req.GetWorkspaceType())) + envs = append(envs, fmt.Sprintf("SUPERVISOR_DEBUG_WORKSPACE_CONTENT_SOURCE=%d", req.GetContentSource())) + envs = append(envs, fmt.Sprintf("LOG_LEVEL=%s", req.GetLogLevel())) + envs = append(envs, fmt.Sprintf("GITPOD_TASKS=%s", req.GetTasks())) + envs = append(envs, fmt.Sprintf("GITPOD_WORKSPACE_URL=%s", req.GetWorkspaceUrl())) + envs = append(envs, fmt.Sprintf("GITPOD_REPO_ROOT=%s", req.GetWorkspaceLocation())) + envs = append(envs, fmt.Sprintf("GITPOD_REPO_ROOTS=%s", req.GetWorkspaceLocation())) + envs = append(envs, fmt.Sprintf("THEIA_WORKSPACE_ROOT=%s", req.GetCheckoutLocation())) + envs = append(envs, fmt.Sprintf("GITPOD_PREVENT_METADATA_ACCESS=%s", "false")) + return &api.CreateDebugEnvResponse{ + Envs: envs, + }, nil +} + // ContentState signals the workspace content state. type ContentState interface { MarkContentReady(src csapi.WorkspaceInitSource) diff --git a/components/supervisor/pkg/supervisor/ssh.go b/components/supervisor/pkg/supervisor/ssh.go index 7f2bd534a7ebb0..e2b8ab74add575 100644 --- a/components/supervisor/pkg/supervisor/ssh.go +++ b/components/supervisor/pkg/supervisor/ssh.go @@ -18,6 +18,7 @@ import ( "golang.org/x/xerrors" "github.com/gitpod-io/gitpod/common-go/log" + "github.com/sirupsen/logrus" ) func newSSHServer(ctx context.Context, cfg *Config, envvars []string) (*sshServer, error) { @@ -85,7 +86,8 @@ func (s *sshServer) handleConn(ctx context.Context, conn net.Conn) { return } - args := []string{ + var args []string + args = append(args, "-ieD", "-f/dev/null", "-oProtocol 2", "-oAllowUsers gitpod", @@ -95,13 +97,33 @@ func (s *sshServer) handleConn(ctx context.Context, conn net.Conn) { "-oLoginGraceTime 20", "-oPrintLastLog no", "-oPermitUserEnvironment yes", - "-oHostKey " + s.sshkey, + "-oHostKey "+s.sshkey, "-oPidFile /dev/null", "-oUseDNS no", // Disable DNS lookups. "-oSubsystem sftp internal-sftp", "-oStrictModes no", // don't care for home directory and file permissions - "-oLogLevel DEBUG", // enabled DEBUG mode by default + ) + // TODO enabled DEBUG mode by default - reconsider it + sshdLogLevel := "DEBUG" + if s.cfg.isDebugWorkspace() { + switch log.Log.Logger.GetLevel() { + case logrus.PanicLevel: + sshdLogLevel = "FATAL" + case logrus.FatalLevel: + sshdLogLevel = "FATAL" + case logrus.ErrorLevel: + sshdLogLevel = "ERROR" + case logrus.WarnLevel: + sshdLogLevel = "INFO" + case logrus.InfoLevel: + sshdLogLevel = "INFO" + case logrus.DebugLevel: + sshdLogLevel = "VERBOSE" + case logrus.TraceLevel: + sshdLogLevel = "DEBUG" + } } + args = append(args, "-oLogLevel "+sshdLogLevel) envs := make([]string, 0) for _, env := range s.envvars { diff --git a/components/supervisor/pkg/supervisor/supervisor.go b/components/supervisor/pkg/supervisor/supervisor.go index bac7f762476f23..6bd33bdbf8d47a 100644 --- a/components/supervisor/pkg/supervisor/supervisor.go +++ b/components/supervisor/pkg/supervisor/supervisor.go @@ -31,7 +31,6 @@ import ( "syscall" "time" - grpc_proxy "github.com/adamthesax/grpc-proxy/proxy" "github.com/gorilla/websocket" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" @@ -43,10 +42,7 @@ import ( "golang.org/x/crypto/ssh" "golang.org/x/xerrors" "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/metadata" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/emptypb" "github.com/gitpod-io/gitpod/common-go/analytics" "github.com/gitpod-io/gitpod/common-go/log" @@ -77,6 +73,7 @@ const ( gitpodGID = 33333 gitpodGroupName = "gitpod" desktopIDEPort = 24000 + debugProxyPort = 23003 ) var ( @@ -239,6 +236,9 @@ func Run(options ...RunOption) { if cfg.DesktopIDE != nil { internalPorts = append(internalPorts, desktopIDEPort) } + if cfg.isDebugWorkspace() { + internalPorts = append(internalPorts, debugProxyPort) + } endpoint, host, err := cfg.GitpodAPIEndpoint() if err != nil { @@ -268,7 +268,7 @@ func Run(options ...RunOption) { if cfg.DesktopIDE != nil { desktopIdeReady = &ideReadyState{cond: sync.NewCond(&sync.Mutex{})} } - if !cfg.isHeadless() && !opts.RunGP { + if !cfg.isHeadless() && !opts.RunGP && !cfg.isDebugWorkspace() { go trackReadiness(ctx, telemetry, cfg, cstate, ideReady, desktopIdeReady) } tokenService.provider[KindGit] = []tokenProvider{NewGitTokenProvider(gitpodService, cfg.WorkspaceConfig, notificationService)} @@ -293,30 +293,28 @@ func Run(options ...RunOption) { ) topService := NewTopService() + if !opts.RunGP { + topService.Observe(ctx) + } + + if !cfg.isHeadless() && !opts.RunGP && !cfg.isDebugWorkspace() { + go analyseConfigChanges(ctx, cfg, telemetry, gitpodConfigService) + go analysePerfChanges(ctx, cfg, telemetry, topService) + } supervisorMetrics := metrics.NewMetrics() var metricsReporter *metrics.GrpcMetricsReporter - if opts.RunGP { - cstate.MarkContentReady(csapi.WorkspaceInitFromOther) - } else { - topService.Observe(ctx) - - if !cfg.isHeadless() && !opts.RunGP { - go analyseConfigChanges(ctx, cfg, telemetry, gitpodConfigService) - go analysePerfChanges(ctx, cfg, telemetry, topService) - } - if !strings.Contains("ephemeral", cfg.WorkspaceClusterHost) { - _, gitpodHost, err := cfg.GitpodAPIEndpoint() - if err != nil { - log.WithError(err).Error("grpc metrics: failed to parse gitpod host") - } else { - metricsReporter = metrics.NewGrpcMetricsReporter(gitpodHost) - if err := supervisorMetrics.Register(metricsReporter.Registry); err != nil { - log.WithError(err).Error("could not register supervisor metrics") - } - if err := gitpodService.RegisterMetrics(metricsReporter.Registry); err != nil { - log.WithError(err).Error("could not register public api metrics") - } + if !opts.RunGP && !cfg.isDebugWorkspace() && !strings.Contains("ephemeral", cfg.WorkspaceClusterHost) { + _, gitpodHost, err := cfg.GitpodAPIEndpoint() + if err != nil { + log.WithError(err).Error("grpc metrics: failed to parse gitpod host") + } else { + metricsReporter = metrics.NewGrpcMetricsReporter(gitpodHost) + if err := supervisorMetrics.Register(metricsReporter.Registry); err != nil { + log.WithError(err).Error("could not register supervisor metrics") + } + if err := gitpodService.RegisterMetrics(metricsReporter.Registry); err != nil { + log.WithError(err).Error("could not register public api metrics") } } } @@ -362,7 +360,7 @@ func Run(options ...RunOption) { } apiServices = append(apiServices, additionalServices...) - if !cfg.isHeadless() { + if !cfg.isPrebuild() { // We need to checkout dotfiles first, because they may be changing the path which affects the IDE. // TODO(cw): provide better feedback if the IDE start fails because of the dotfiles (provide any feedback at all). installDotfiles(ctx, cfg, tokenService, childProcEnvvars) @@ -381,13 +379,17 @@ func Run(options ...RunOption) { shutdown = make(chan ShutdownReason, 1) ) - if !opts.RunGP { + if opts.RunGP { + cstate.MarkContentReady(csapi.WorkspaceInitFromOther) + } else if cfg.isDebugWorkspace() { + cstate.MarkContentReady(cfg.GetDebugWorkspaceContentSource()) + } else { wg.Add(1) go startContentInit(ctx, cfg, &wg, cstate, supervisorMetrics) } wg.Add(1) - go startAPIEndpoint(ctx, cfg, &wg, apiServices, tunneledPortsService, metricsReporter, opts.RunGP, apiEndpointOpts...) + go startAPIEndpoint(ctx, cfg, &wg, apiServices, tunneledPortsService, metricsReporter, apiEndpointOpts...) wg.Add(1) go startSSHServer(ctx, cfg, &wg, childProcEnvvars) @@ -396,7 +398,7 @@ func Run(options ...RunOption) { tasksSuccessChan := make(chan taskSuccess, 1) go taskManager.Run(ctx, &wg, tasksSuccessChan) - if !opts.RunGP { + if !opts.RunGP && !cfg.isDebugWorkspace() { wg.Add(1) go socketActivationForDocker(ctx, &wg, termMux) } @@ -420,7 +422,7 @@ func Run(options ...RunOption) { }() } - if !cfg.isHeadless() && !opts.RunGP { + if !cfg.isPrebuild() && !opts.RunGP && !cfg.isDebugWorkspace() { go func() { for _, repoRoot := range strings.Split(cfg.RepoRoots, ",") { <-cstate.ContentReady() @@ -1139,7 +1141,7 @@ func isBlacklistedEnvvar(name string) bool { return false } -func startAPIEndpoint(ctx context.Context, cfg *Config, wg *sync.WaitGroup, services []RegisterableService, tunneled *ports.TunneledPortsService, metricsReporter *metrics.GrpcMetricsReporter, runGP bool, opts ...grpc.ServerOption) { +func startAPIEndpoint(ctx context.Context, cfg *Config, wg *sync.WaitGroup, services []RegisterableService, tunneled *ports.TunneledPortsService, metricsReporter *metrics.GrpcMetricsReporter, opts ...grpc.ServerOption) { defer wg.Done() defer log.Debug("startAPIEndpoint shutdown") @@ -1150,35 +1152,6 @@ func startAPIEndpoint(ctx context.Context, cfg *Config, wg *sync.WaitGroup, serv var unaryInterceptors []grpc.UnaryServerInterceptor var streamInterceptors []grpc.StreamServerInterceptor - if cfg.HostAPIEndpointPort != nil { - url := fmt.Sprintf("localhost:%d", *cfg.HostAPIEndpointPort) - conn, err := grpc.DialContext(ctx, url, grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - log.WithError(err).Fatal("cannot access host supervisor") - } - noProxy := func(fullMethod string) bool { - return strings.Contains(fullMethod, "TasksStatus") || - strings.Contains(fullMethod, "TerminalService") || - strings.Contains(fullMethod, "InfoService") || - strings.Contains(fullMethod, "CreateSSHKeyPair") - } - unaryInterceptors = append(unaryInterceptors, func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { - if noProxy(info.FullMethod) { - return handler(ctx, req) - } - md, _ := metadata.FromIncomingContext(ctx) - resp := &emptypb.Empty{} - respErr := conn.Invoke(metadata.NewOutgoingContext(ctx, md.Copy()), info.FullMethod, req, resp) - return resp, respErr - }) - streamProxy := grpc_proxy.TransparentHandler(grpc_proxy.DefaultDirector(conn)) - streamInterceptors = append(streamInterceptors, func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { - if noProxy(info.FullMethod) { - return handler(srv, ss) - } - return streamProxy(srv, ss) - }) - } if cfg.DebugEnable { unaryInterceptors = append(unaryInterceptors, grpc_logrus.UnaryServerInterceptor(log.Log)) @@ -1250,24 +1223,12 @@ func startAPIEndpoint(ctx context.Context, cfg *Config, wg *sync.WaitGroup, serv routes.Handle("/", httputil.NewSingleHostReverseProxy(ideURL)) routes.Handle("/_supervisor/frontend/", http.StripPrefix("/_supervisor/frontend", http.FileServer(http.Dir(cfg.StaticConfig.FrontendLocation)))) - var hostProxy *httputil.ReverseProxy - if runGP && cfg.HostAPIEndpointPort != nil { - hostProxy = httputil.NewSingleHostReverseProxy(&url.URL{ - Scheme: "http", - Host: fmt.Sprintf("localhost:%d", *cfg.HostAPIEndpointPort), - }) - } routes.Handle("/_supervisor/v1/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.Contains(r.Header.Get("Content-Type"), "application/grpc") { websocket.IsWebSocketUpgrade(r) http.StripPrefix("/_supervisor/v1", grpcWebServer).ServeHTTP(w, r) - } else if hostProxy == nil || - strings.HasPrefix(r.URL.Path, "/_supervisor/v1/terminal") || - strings.HasPrefix(r.URL.Path, "/_supervisor/v1/info/workspace") || - strings.HasPrefix(r.URL.Path, "/_supervisor/v1/status/tasks") { - http.StripPrefix("/_supervisor", restMux).ServeHTTP(w, r) } else { - hostProxy.ServeHTTP(w, r) + http.StripPrefix("/_supervisor", restMux).ServeHTTP(w, r) } })) diff --git a/components/supervisor/pkg/supervisor/tasks.go b/components/supervisor/pkg/supervisor/tasks.go index 12463a08fde91b..3a625bf3aa7317 100644 --- a/components/supervisor/pkg/supervisor/tasks.go +++ b/components/supervisor/pkg/supervisor/tasks.go @@ -224,7 +224,7 @@ func (tm *tasksManager) init(ctx context.Context) { successChan: make(chan taskSuccess, 1), title: presentation.Name, } - task.command = getCommand(task, tm.config.isHeadless(), tm.contentSource, tm.storeLocation) + task.command = getCommand(task, tm.config.isHeadless(), tm.config.isPrebuild(), tm.contentSource, tm.storeLocation) if tm.config.isHeadless() && task.command == "exit" { task.State = api.TaskState_closed task.successChan <- taskSuccessful @@ -355,14 +355,14 @@ func (tm *tasksManager) Run(ctx context.Context, wg *sync.WaitGroup, successChan } } - if tm.config.isHeadless() && tm.reporter != nil { + if tm.config.isPrebuild() && tm.reporter != nil { tm.reporter.done(success) } successChan <- success } -func getCommand(task *task, isHeadless bool, contentSource csapi.WorkspaceInitSource, storeLocation string) string { - commands := getCommands(task, isHeadless, contentSource, storeLocation) +func getCommand(task *task, isHeadless bool, isPrebuild bool, contentSource csapi.WorkspaceInitSource, storeLocation string) string { + commands := getCommands(task, isPrebuild, contentSource, storeLocation) command := composeCommand(composeCommandOptions{ commands: commands, format: "{\n%s\n}", @@ -413,8 +413,8 @@ func getHistfileCommand(task *task, commands []*string, contentSource csapi.Work return " HISTFILE=" + histfile + " history -r" } -func getCommands(task *task, isHeadless bool, contentSource csapi.WorkspaceInitSource, storeLocation string) []*string { - if isHeadless { +func getCommands(task *task, isPrebuild bool, contentSource csapi.WorkspaceInitSource, storeLocation string) []*string { + if isPrebuild { // prebuild return []*string{task.config.Before, task.config.Init, task.config.Prebuild} } @@ -438,7 +438,7 @@ func prebuildLogFileName(task *task, storeLocation string) string { } func (tm *tasksManager) watch(task *task, term *terminal.Term) { - if !tm.config.isHeadless() { + if !tm.config.isPrebuild() { return } diff --git a/components/supervisor/pkg/supervisor/tasks_test.go b/components/supervisor/pkg/supervisor/tasks_test.go index c5a33b7afeb927..25cb85ffa7fc94 100644 --- a/components/supervisor/pkg/supervisor/tasks_test.go +++ b/components/supervisor/pkg/supervisor/tasks_test.go @@ -298,7 +298,7 @@ func TestGetTask(t *testing.T) { for _, test := range tests { t.Run(test.Name, func(t *testing.T) { - command := getCommand(&task{config: test.Task, TaskStatus: api.TaskStatus{Id: "0"}}, test.IsHeadless, test.ContentSource, "/") + command := getCommand(&task{config: test.Task, TaskStatus: api.TaskStatus{Id: "0"}}, test.IsHeadless, test.IsHeadless, test.ContentSource, "/") if diff := cmp.Diff(test.Expectation, command); diff != "" { t.Errorf("unexpected getCommand() (-want +got):\n%s", diff) } diff --git a/components/supervisor/pkg/supervisor/top.go b/components/supervisor/pkg/supervisor/top.go index aaafbf4e886a7b..57299773686d30 100644 --- a/components/supervisor/pkg/supervisor/top.go +++ b/components/supervisor/pkg/supervisor/top.go @@ -51,15 +51,15 @@ func (t *TopService) Observe(ctx context.Context) { go func() { for { data, err := t.top(ctx) - if err != nil { - log.WithField("error", err).Errorf("failed to retrieve resource status from upstream, trying again in %d seconds...", uint32(delay.Seconds())) - } else { + if err == nil { delay = minReconnectionDelay t.data = data t.readyOnce.Do(func() { close(t.ready) }) + } else if ctx.Err() == nil { + log.WithField("error", err).Errorf("failed to retrieve resource status from upstream, trying again in %d seconds...", uint32(delay.Seconds())) } select { case <-ctx.Done():