diff --git a/cmd/agent/container/setup_loft_platform_access.go b/cmd/agent/container/setup_loft_platform_access.go index 312188254..688caaa36 100644 --- a/cmd/agent/container/setup_loft_platform_access.go +++ b/cmd/agent/container/setup_loft_platform_access.go @@ -1,7 +1,10 @@ package container import ( + "fmt" + "github.com/loft-sh/devpod/cmd/flags" + "github.com/loft-sh/devpod/pkg/credentials" "github.com/loft-sh/devpod/pkg/loftconfig" "github.com/loft-sh/log" @@ -30,8 +33,13 @@ func NewSetupLoftPlatformAccessCmd(flags *flags.GlobalFlags) *cobra.Command { } setupLoftPlatformAccessCmd.Flags().StringVar(&cmd.Context, "context", "", "context to use") + _ = setupLoftPlatformAccessCmd.Flags().MarkDeprecated("context", "Information should be provided by services server, don't use this flag anymore") + setupLoftPlatformAccessCmd.Flags().StringVar(&cmd.Provider, "provider", "", "provider to use") + _ = setupLoftPlatformAccessCmd.Flags().MarkDeprecated("provider", "Information should be provided by services server, don't use this flag anymore") + setupLoftPlatformAccessCmd.Flags().IntVar(&cmd.Port, "port", 0, "If specified, will use the given port") + _ = setupLoftPlatformAccessCmd.Flags().MarkDeprecated("port", "") return setupLoftPlatformAccessCmd } @@ -41,7 +49,16 @@ func NewSetupLoftPlatformAccessCmd(flags *flags.GlobalFlags) *cobra.Command { func (c *SetupLoftPlatformAccessCmd) Run(_ *cobra.Command, args []string) error { logger := log.Default.ErrorStreamOnly() - loftConfig, err := loftconfig.GetLoftConfig(c.Context, c.Provider, c.Port, logger) + port, err := credentials.GetPort() + if err != nil { + return fmt.Errorf("get port: %w", err) + } + // backwards compatibility, remove in future release + if c.Port > 0 { + port = c.Port + } + + loftConfig, err := loftconfig.GetLoftConfig(c.Context, c.Provider, port, logger) if err != nil { return err } @@ -51,12 +68,16 @@ func (c *SetupLoftPlatformAccessCmd) Run(_ *cobra.Command, args []string) error return nil } - if err := loftconfig.AuthDevpodCliToPlatform(loftConfig, logger); err != nil { - return err + err = loftconfig.AuthDevpodCliToPlatform(loftConfig, logger) + if err != nil { + // log error but don't return to allow other CLIs to install as well + logger.Warn("unable to authenticate devpod cli: %v", err) } - if err := loftconfig.AuthVClusterCliToPlatform(loftConfig, logger); err != nil { - return err + err = loftconfig.AuthVClusterCliToPlatform(loftConfig, logger) + if err != nil { + // log error but don't return to allow other CLIs to install as well + logger.Warn("unable to authenticate vcluster cli: %v", err) } return nil diff --git a/cmd/ssh.go b/cmd/ssh.go index e1c9a2103..88857d5cd 100644 --- a/cmd/ssh.go +++ b/cmd/ssh.go @@ -1,6 +1,7 @@ package cmd import ( + "bytes" "context" "encoding/base64" "fmt" @@ -181,7 +182,7 @@ func (cmd *SSHCmd) startProxyTunnel( }) }, func(ctx context.Context, containerClient *ssh.Client) error { - return cmd.startTunnel(ctx, devPodConfig, containerClient, client.Workspace(), log) + return cmd.startTunnel(ctx, devPodConfig, containerClient, client, log) }, ) } @@ -295,7 +296,7 @@ func (cmd *SSHCmd) jumpContainer( unlockOnce.Do(client.Unlock) // start ssh tunnel - return cmd.startTunnel(ctx, devPodConfig, containerClient, client.Workspace(), log) + return cmd.startTunnel(ctx, devPodConfig, containerClient, client, log) }, devPodConfig, envVars) } @@ -403,7 +404,7 @@ func (cmd *SSHCmd) forwardPorts( return <-errChan } -func (cmd *SSHCmd) startTunnel(ctx context.Context, devPodConfig *config.Config, containerClient *ssh.Client, workspaceName string, log log.Logger) error { +func (cmd *SSHCmd) startTunnel(ctx context.Context, devPodConfig *config.Config, containerClient *ssh.Client, workspaceClient client2.BaseWorkspaceClient, log log.Logger) error { // check if we should forward ports if len(cmd.ForwardPorts) > 0 { return cmd.forwardPorts(ctx, containerClient, log) @@ -416,7 +417,7 @@ func (cmd *SSHCmd) startTunnel(ctx context.Context, devPodConfig *config.Config, // start port-forwarding etc. if !cmd.Proxy && cmd.StartServices { - go cmd.startServices(ctx, devPodConfig, containerClient, cmd.GitUsername, cmd.GitToken, log) + go cmd.startServices(ctx, devPodConfig, containerClient, cmd.GitUsername, cmd.GitToken, workspaceClient.WorkspaceConfig(), log) } // start ssh @@ -437,7 +438,7 @@ func (cmd *SSHCmd) startTunnel(ctx context.Context, devPodConfig *config.Config, } } - workdir := filepath.Join("/workspaces", workspaceName) + workdir := filepath.Join("/workspaces", workspaceClient.Workspace()) if cmd.WorkDir != "" { workdir = cmd.WorkDir } @@ -468,8 +469,11 @@ func (cmd *SSHCmd) startTunnel(ctx context.Context, devPodConfig *config.Config, log.Error(err) } }() - } + go func() { + cmd.setupPlatformAccess(ctx, containerClient, log) + }() + } return devssh.Run(ctx, containerClient, command, os.Stdin, os.Stdout, writer, envVars) } @@ -489,12 +493,22 @@ func (cmd *SSHCmd) startTunnel(ctx context.Context, devPodConfig *config.Config, ) } +func (cmd *SSHCmd) setupPlatformAccess(ctx context.Context, sshClient *ssh.Client, log log.Logger) { + buf := &bytes.Buffer{} + command := fmt.Sprintf("'%s' agent container setup-loft-platform-access", agent.ContainerDevPodHelperLocation) + err := devssh.Run(ctx, sshClient, command, nil, buf, buf, nil) + if err != nil { + log.Debugf("Failed to setup platform access: %s%v", buf.String(), err) + } +} + func (cmd *SSHCmd) startServices( ctx context.Context, devPodConfig *config.Config, containerClient *ssh.Client, gitUsername, gitToken string, + workspace *provider.Workspace, log log.Logger, ) { if cmd.User != "" { @@ -507,6 +521,7 @@ func (cmd *SSHCmd) startServices( nil, gitUsername, gitToken, + workspace, log, ) if err != nil { @@ -709,7 +724,7 @@ func (cmd *SSHCmd) jumpLocalProxyContainer(ctx context.Context, devPodConfig *co } go startSSHKeepAlive(ctx, containerClient, cmd.SSHKeepAliveInterval, log) - + go cmd.setupPlatformAccess(ctx, containerClient, log) go func() { if err := cmd.startRunnerServices(ctx, devPodConfig, containerClient, log); err != nil { log.Error(err) diff --git a/cmd/up.go b/cmd/up.go index a4d1f1c94..ca6b4f0c3 100644 --- a/cmd/up.go +++ b/cmd/up.go @@ -20,7 +20,6 @@ import ( "github.com/loft-sh/devpod/pkg/client/clientimplementation" "github.com/loft-sh/devpod/pkg/command" "github.com/loft-sh/devpod/pkg/config" - "github.com/loft-sh/devpod/pkg/credentials" config2 "github.com/loft-sh/devpod/pkg/devcontainer/config" "github.com/loft-sh/devpod/pkg/devcontainer/sshtunnel" dpFlags "github.com/loft-sh/devpod/pkg/flags" @@ -199,15 +198,6 @@ func (cmd *UpCmd) Run( } } - // setup loft platform access - context := devPodConfig.Current() - if cmd.SetupLoftPlatformAccess { - err = setupLoftPlatformAccess(devPodConfig.DefaultContext, context.DefaultProvider, user, client, log) - if err != nil { - return err - } - } - // setup dotfiles in the container err = setupDotfiles(cmd.DotfilesSource, cmd.DotfilesScript, client, devPodConfig, log) if err != nil { @@ -896,6 +886,7 @@ func startBrowserTunnel( extraPorts, gitUsername, gitToken, + client.WorkspaceConfig(), logger, ) if err != nil { @@ -1115,42 +1106,6 @@ func setupGitSSHSignature(signingKey string, client client2.BaseWorkspaceClient, return nil } -func setupLoftPlatformAccess(context, provider, user string, client client2.BaseWorkspaceClient, log log.Logger) error { - log.Infof("Setting up platform access") - execPath, err := os.Executable() - if err != nil { - return err - } - - port, err := credentials.GetPort() - if err != nil { - return fmt.Errorf("get port: %w", err) - } - - command := fmt.Sprintf("\"%s\" agent container setup-loft-platform-access --context %s --provider %s --port %d", agent.ContainerDevPodHelperLocation, context, provider, port) - - log.Debugf("Executing command: %v", command) - var errb bytes.Buffer - cmd := exec.Command( - execPath, - "ssh", - "--start-services=true", - "--user", - user, - "--context", - client.Context(), - client.Workspace(), - "--command", command, - ) - cmd.Stderr = &errb - err = cmd.Run() - if err != nil { - log.Debugf("failed to set up platform access in workspace: %s", errb.String()) - } - - return nil -} - func performGpgForwarding( client client2.BaseWorkspaceClient, log log.Logger, diff --git a/pkg/agent/tunnelserver/tunnelserver.go b/pkg/agent/tunnelserver/tunnelserver.go index 18855613c..0505a54bb 100644 --- a/pkg/agent/tunnelserver/tunnelserver.go +++ b/pkg/agent/tunnelserver/tunnelserver.go @@ -30,11 +30,12 @@ import ( "google.golang.org/grpc/reflection" ) -func RunServicesServer(ctx context.Context, reader io.Reader, writer io.WriteCloser, allowGitCredentials, allowDockerCredentials bool, forwarder netstat.Forwarder, log log.Logger, options ...Option) error { +func RunServicesServer(ctx context.Context, reader io.Reader, writer io.WriteCloser, allowGitCredentials, allowDockerCredentials bool, forwarder netstat.Forwarder, workspace *provider2.Workspace, log log.Logger, options ...Option) error { opts := append(options, []Option{ WithForwarder(forwarder), WithAllowGitCredentials(allowGitCredentials), WithAllowDockerCredentials(allowDockerCredentials), + WithWorkspace(workspace), }...) tunnelServ := New(log, opts...) @@ -255,9 +256,17 @@ func (t *tunnelServer) LoftConfig(ctx context.Context, message *tunnel.Message) return nil, perrors.Wrap(err, "loft platform config request") } - response, err := loftconfig.Read(loftConfigRequest) - if err != nil { - return nil, perrors.Wrap(err, "read loft config") + var response *loftconfig.LoftConfigResponse + if t.workspace != nil { + response, err = loftconfig.ReadFromWorkspace(t.workspace) + if err != nil { + return nil, fmt.Errorf("read loft config: %w", err) + } + } else { + response, err = loftconfig.Read(loftConfigRequest) + if err != nil { + return nil, fmt.Errorf("read loft config: %w", err) + } } out, err := json.Marshal(response) diff --git a/pkg/loftconfig/config.go b/pkg/loftconfig/config.go index e8bdc0c22..7142f0e91 100644 --- a/pkg/loftconfig/config.go +++ b/pkg/loftconfig/config.go @@ -13,7 +13,7 @@ func AuthDevpodCliToPlatform(config *client.Config, logger log.Logger) error { out, err := cmd.CombinedOutput() if err != nil { logger.Debugf("Failed executing `devpod pro login`: %w, output: %s", err, out) - return fmt.Errorf("error executing 'devpod pro login' command") + return fmt.Errorf("error executing 'devpod pro login' command: %w", err) } return nil @@ -30,7 +30,7 @@ func AuthVClusterCliToPlatform(config *client.Config, logger log.Logger) error { out, err := cmd.CombinedOutput() if err != nil { logger.Debugf("Failed executing `vcluster login` : %w, output: %s", err, out) - return fmt.Errorf("error executing 'vcluster login' command") + return fmt.Errorf("error executing 'vcluster login' command: %w", err) } return nil diff --git a/pkg/loftconfig/server.go b/pkg/loftconfig/server.go index e68f19ccd..511c51a34 100644 --- a/pkg/loftconfig/server.go +++ b/pkg/loftconfig/server.go @@ -14,7 +14,9 @@ const ( ) type LoftConfigRequest struct { - Context string + // Deprecated. Do not use anymore + Context string + // Deprecated. Do not use anymore Provider string } @@ -23,7 +25,25 @@ type LoftConfigResponse struct { } func Read(request *LoftConfigRequest) (*LoftConfigResponse, error) { - providerDir, err := provider.GetProviderDir(request.Context, request.Provider) + loftConfig, err := readConfig(request.Context, request.Provider) + if err != nil { + return nil, err + } + + return &LoftConfigResponse{LoftConfig: loftConfig}, nil +} + +func ReadFromWorkspace(workspace *provider.Workspace) (*LoftConfigResponse, error) { + loftConfig, err := readConfig(workspace.Context, workspace.Provider.Name) + if err != nil { + return nil, err + } + + return &LoftConfigResponse{LoftConfig: loftConfig}, nil +} + +func readConfig(contextName string, providerName string) (*client.Config, error) { + providerDir, err := provider.GetProviderDir(contextName, providerName) if err != nil { return nil, err } @@ -33,7 +53,7 @@ func Read(request *LoftConfigRequest) (*LoftConfigResponse, error) { // Check if given context and provider have Loft Platform configuration if _, err := os.Stat(configPath); os.IsNotExist(err) { // If not just return empty response - return &LoftConfigResponse{}, nil + return &client.Config{}, nil } content, err := os.ReadFile(configPath) @@ -47,5 +67,5 @@ func Read(request *LoftConfigRequest) (*LoftConfigResponse, error) { return nil, err } - return &LoftConfigResponse{LoftConfig: loftConfig}, nil + return loftConfig, nil } diff --git a/pkg/tunnel/services.go b/pkg/tunnel/services.go index 97eabb3be..2570e70d9 100644 --- a/pkg/tunnel/services.go +++ b/pkg/tunnel/services.go @@ -20,6 +20,7 @@ import ( "github.com/loft-sh/devpod/pkg/gitsshsigning" "github.com/loft-sh/devpod/pkg/ide/openvscode" "github.com/loft-sh/devpod/pkg/netstat" + "github.com/loft-sh/devpod/pkg/provider" devssh "github.com/loft-sh/devpod/pkg/ssh" "github.com/loft-sh/log" "github.com/pkg/errors" @@ -38,6 +39,7 @@ func RunInContainer( extraPorts []string, gitUsername, gitToken string, + workspace *provider.Workspace, log log.Logger, ) error { // calculate exit after timeout @@ -98,6 +100,7 @@ func RunInContainer( configureGitCredentials, configureDockerCredentials, forwarder, + workspace, log, tunnelserver.WithGitCredentialsOverride(gitUsername, gitToken), )