Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remote-ssh: Add possibility to invoke a login shell #1671

Open
jenzopr opened this issue Oct 15, 2019 · 46 comments
Open

remote-ssh: Add possibility to invoke a login shell #1671

jenzopr opened this issue Oct 15, 2019 · 46 comments
Assignees
Labels
ssh Issue in vscode-remote SSH under-discussion Issue is under discussion for relevance, priority, approach

Comments

@jenzopr
Copy link

jenzopr commented Oct 15, 2019

Currently (vscode 1.38.1), a remote bash terminal only sources .bashrc, like an interactive shell that is not a login shell would do.
This breaks existing conda installations on the remote system, which rely on code in /etc/profile.d. I'd like to have the possibility to start an interactive shell with the --login option on the remote system. This way, profiles from /etc/profile and .profile would be sourced as well.

Please see the bash man page for how different files are sourced on bash invocation.

See #83 for reference as well.

@Tyriar
Copy link
Member

Tyriar commented Oct 16, 2019

@roblourens two ways we could solve this:

  • Allow users to specify they want a login shell and the ext host can be launched inside a shell using -l.
  • Call getUnixShellEnvironment in the ext host just like we do for the main process, normally the ex host inherits this "dev env" from the renderer but in remote-ssh it's inherited from the barebones ssh env which does not run as a login shell.

I'm leaning towards the former as the solution is inside the ssh ext and won't affect anything else. It could probably be called in a similar way to this how we use $SHELL:

https://github.com/microsoft/vscode/blob/f462eab9694a944fdd0c65dbe3fb7b2774ee3092/src/vs/code/node/shellEnv.ts#L33

There is of course then the problem of $SHELL potentially not POSIX-compliant and causing other issues.

@Tyriar Tyriar added the ssh Issue in vscode-remote SSH label Oct 16, 2019
@Codelica
Copy link

Option 1 sounds find to me. :) IMO from a user's point of view, it seems like a login shell should be the default though -- just to mirror how local VS Code behaves. I realize that would be a change at this point, but it seems like it would solve more random issues than it would create. (e.g. PATH isn't as expected so scripts fail, etc) But either way 👍

@Tyriar
Copy link
Member

Tyriar commented Oct 16, 2019

@Codelica I think we reason we didn't do that is because a regular ssh session does not run a login shell, so currently it's very similar to a regular ssh setup (unless you run bash -l inside the ssh session or something).

@Codelica
Copy link

By "regular ssh session", do you mean invoking a typical remote ssh connection from a terminal shell like:

ssh james@some-remote-host.domain.com

As that seems to always provide a login shell from what I've seen.

@Tyriar
Copy link
Member

Tyriar commented Oct 16, 2019

@Codelica yes, based on my testing it didn't. That's also the reason you're seeing this behavior, if it was a login shell I don't think this issue should exist.

@peter-b
Copy link

peter-b commented Oct 16, 2019

@Tyriar @Codelica I've also run into this problem when trying to get my team set up with the remote-ssh extension. We have a lot of environment that's set up in .profile rather than in .bashrc, and we rely fairly heavily on nested shells in our dev environment, so setting PATH etc. in .bashrc would be tricky to get right. Either of the proposed fixes would be very helpful.

@Tyriar
Copy link
Member

Tyriar commented Oct 16, 2019

@peter-b yeah you're doing it right. We can consider change this to be the default but we would need to do some thinking on what might break as a result of that.

@Codelica
Copy link

@Tyriar I believe any new SSH connection/session should give you an interactive login shell to start. But if you begin another shell in an existing session you then get an interactive non-login shell, which is what is at work here. I think. :)

When the Remote SSH plugin initially connects (to form the session, install what's needed, etc) I can see it is given a login shell sourcing .profile, etc. (which it may appreciate :) ). However any interactive VS Code terminal that the user brings up (once connected) just uses that established session, and is not a login shell. At least I think that's the case based on what I've seen.

While that technically may be "correct" behavior for bringing up an additional shell in an established remote session, it's different from how the VS Code terminal behaves when working locally -- which brings up a login shell each time. So I guess if the intent of the Remote SSH plugin is to "work on a remote host as if it's local", that feels like a disconnect.

That got long, but the answer here has more information if you're interested.

https://unix.stackexchange.com/questions/38175/difference-between-login-shell-and-non-login-shell

Thanks for considering this!

@roblourens
Copy link
Member

roblourens commented Oct 16, 2019

I'm a little confused - we do already set up the extension host environment based on a login shell. Essentially we spawn bash -ilc "node command to print environment" and that is the intial environment of the extension host, and terminals will inherit that environment. This is option 1 that @Tyriar describes and this is what I see in my testing.

So if you are setting PATH or other environment variables in your .profile, they should end up in the terminal environment as well. I am not familiar with conda so I wonder if you can give me a concrete example of what you are seeing.

In my case, I have export DOTPROFILE=yes in my .profile and I can run echo $DOTPROFILE in the vscode terminal and see that it is "yes".

Side note, since I had forgotten this: We only discover the environment once then cache it for the rest of the server's session. If you change your dot scripts and want to see that change reflected when you open a new vscode window, you will have to restart the remote server with the command "Kill VS Code Server on Host".

@peter-b
Copy link

peter-b commented Oct 17, 2019

Side note, since I had forgotten this: We only discover the environment once then cache it for the rest of the server's session. If you change your dot scripts and want to see that change reflected when you open a new vscode window, you will have to restart the remote server with the command "Kill VS Code Server on Host".

Hi @roblourens, this is the part that I was missing. It isn't at all obvious that this is the behaviour; it comes as a big surprise to me that VS Code continues to run on the remote server after the last window connected to it has been closed. Are you sure this behaviour is desirable?

@roblourens
Copy link
Member

So restarting the server fixes it for your case?

Are you sure this behaviour is desirable?

No, not at all. However, connecting to the remote is kind of slow already and I'm hesitatant to do anything that could make it slower, like starting a process to check the environment that won't change 99% of the time. Not sure what to do.

@jatin-code777
Copy link

In my case, I have export DOTPROFILE=yes in my .profile and I can run echo $DOTPROFILE in the vscode terminal and see that it is "yes".

Hi @roblourens, I do not have a conda environment or any similar setup. I still cannot see changes which sourcing .profile should reflect. The terminals open a non-login shell for me. Restarting the server does not fix anything.

@Tyriar Tyriar removed their assignment Oct 22, 2019
@roblourens
Copy link
Member

Can you give more details about what "changes" you have so I can reproduce it?

@jatin-code777
Copy link

jatin-code777 commented Oct 25, 2019

UPDATE:

Apologies. All of my tests below comply with what you have written here. I was a little confused.

So if you are setting PATH or other environment variables in your .profile, they should end up in the terminal environment as well. I am not familiar with conda so I wonder if you can give me a concrete example of what you are seeing.

In my case, I have export DOTPROFILE=yes in my .profile and I can run echo $DOTPROFILE in the vscode terminal and see that it is "yes".

Side note, since I had forgotten this: We only discover the environment once then cache it for the rest of the server's session. If you change your dot scripts and want to see that change reflected when you open a new vscode window, you will have to restart the remote server with the command "Kill VS Code Server on Host".

Either way, as it stands, The terminal given is not a login shell.
And as the issue name indicates, if possible, please provide a feature to automatically invoke a login shell in the terminal.

Thank you


@roblourens Okay, so I tried retesting and I'll tell you what occurred. Let me know if I should open another issue for this.

Test1

  • Add line to .profile: export vartest101="hello"
  • Have a local folder open in vscode
  • Connect to the host using the button on the bottom-left "Open a remote Window"
  • Open any folder on remote
  • Open terminal using Ctrl+` .
  • Run echo $vartest101
    Output : hello

Test2 (Run directly after Test1)

  • Changes to .profile (using external terminal ssh instance):
    Remove export vartest101="hello"
    Add vartest1="hello"
    Add export vartest2="hello"
  • Close former remote window
  • Connect to host using "Open a remote window" button
  • Open any folder on remote
  • Run commands on bash:
    echo $vartest101 Output: hello
    echo $vartest1 Output: (var isn't set)
    echo $vartest2 Output: (var isn't set)

Test3

  • Close local vscode window
  • Open new vscode window
  • Run Test2 (without Test1)
    Output:
    echo $vartest101 Output: (var isn't set)
    echo $vartest1 Output: (var isn't set)
    echo $vartest2 Output: hello

Implies .profile was sourced and the current terminal is a child process of a login shell.

Test4

  • Open a remote Window
  • Open any folder on remote
  • Open Terminal
  • Run: shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'
    Output: Not login shell

@roblourens
Copy link
Member

We have established that the .profile is sourced once but not again for each connection, and that it isn't a login shell. That is what your testing shows. But to me it still doesn't establish that there is a real problem here.

@jatin-code777
Copy link

Yes, I agree. There is no bug here, as I mentioned in the UPDATE section, all the tests comply with expected behavior.

Please consider this as a feature request to "Add possibility to invoke a login shell". Perhaps in the "Select Default Shell", there can be two options, one for plain bash and another for bash -l

Also, adding "terminal.integrated.shellArgs.linux": ["-l"] to the .vscode settings in the remote server folder does not affect the integrated terminal.

@alextakitani
Copy link

Is there any way to make terminals work as login shell? I'm a Ruby dev, without it RVM does not work.

@megakoresh
Copy link

Same if you are using a virtualenv or pyenv or really anything that relies on having a login shell session. Which is the case for a lot of development scenarios.

@rubensa
Copy link

rubensa commented Dec 7, 2019

I'm experiencing the same (.profile not being sourced in Integrated Terminal) but using Docker (not remote SSH connection).

I always use "bash -l" as the command to execute when I want an interactive shell on a Docker container.

So in my case following doc and adding:

"settings": {
   // Run interactive bash shell in VSCode Integrated Terminal
   "terminal.integrated.shellArgs.linux": ["-l"]
}

in devcontainer.json made the trick.

@easyas314
Copy link

So in my case following doc and adding:

"settings": {
   // Run interactive bash shell in VSCode Integrated Terminal
   "terminal.integrated.shellArgs.linux": ["-l"]
}

THAT'S the answer. I was having the same problems with the non-login shell terminals. This fixed it!

@thinkjrs
Copy link

I'm experiencing the same (.profile not being sourced in Integrated Terminal) but using Docker (not remote SSH connection).

I always use "bash -l" as the command to execute when I want an interactive shell on a Docker container.

So in my case following doc and adding:

"settings": {
   // Run interactive bash shell in VSCode Integrated Terminal
   "terminal.integrated.shellArgs.linux": ["-l"]
}

in devcontainer.json made the trick.

This unfortunately didn't work for me. I tried adding the bash flag to the user, workspace, and server settings (and their combinations) to no avail. Additionally, doing this caused my terminal to crash.

Would love to see this feature implemented as it would be very useful. Regardless, sending my thanks to the vscode dev team for such an outstanding dev experience ❤️

@PatrickLang
Copy link

PatrickLang commented Jan 3, 2020

I ended up here trying to get a working Go environment in remote-ssh with gimme. I run Visual Studio Code on Windows 10, and have source code and my Go environment in a remote Linux VM.

When I was connecting, I would get a message that go wasn't found. That's because I manage my Go environments with a tool called gimme which is sort of like virtualenv or rvm, but for Go.

When I started, I had eval $(gimme stable) in .profile. Visual Studio Code couldn't find go, so the plugin would fail to initialize.

Here's what i had to do to fix it.

  1. Move gimme from ~/.profile to ~/.bash_profile
  2. Close existing instances of vscode server. This is the non-obvious step. Just closing VSCode isn't enough. ps -aux | grep code then kill what you find.
  3. Connect again from the remote.

@dstjohn-at-viasat
Copy link

dstjohn-at-viasat commented Apr 14, 2020

Thank you, PatrickLang. Some clarity! I think your post illustrates the problem best. If I change my .profile or .bash_profile, then open a new terminal in the context of a remote-ssh workspace, I should see the consequences. Period. Please fix this dis-functional aspect of this otherwise awesome tool.

EDIT: additionally, I'm seeing all of the elements in my PATH, from .bash_profile, twice. More or less benign, but hacky looking.

@ches
Copy link

ches commented May 14, 2021

TL;DR: Many people are asking for every terminal to use a login shell, but we probably don't need that—we need them to fully and reliably inherit from a login shell. They do in local VS Code.

I use environment managers like pyenv that people mention in the thread. They work fine in local VS Code terminals, and as noted above, every local terminal in VS Code is not a login shell. (With defaults, if I am not mistaken).

@PavelSosin-320
Copy link

PavelSosin-320 commented May 14, 2021

This is not a VSCode issue. The user that uses ssh to connect to remote systemd-based Linux like Ubuntu, Debian, Centos, etc. that have adopted systemd a long time ago triggers PAM, logind service that creates a session, runs bash in the "Login" mode to create session's environment, creates user-level persistency, starts session-scope services, etc. The sshd in such systems runs by systemd unit and well aware of session management mechanism. It requires certain server-side configurations like sshd "differential" user.
After a successful ssh login user can execute systemctl without parameters to see the structure of the created session.
In the systemd-based systems, even the simplest ping may not work correctly if it can't communicate with resolved service via D-Bus.
I suppose the safest way is to modify user's shell using usermod --shell and invoke ssh auser@localhost.Then, let Linux's session management do its job. Thus Linux's session will be created correctly.

@Tyriar
Copy link
Member

Tyriar commented May 14, 2021

A lot of work has happened in Insiders around terminal environments and "shell environment" (login) usage in vscode. I think this may actually work as people want it now, could someone check this out on Insiders to see if you get the login shell environment when terminal.integrated.inheritEnv is true (default)?

This applies to the terminals at least, not sure about debugging/extensions/etc.

@ches
Copy link

ches commented May 14, 2021

@Tyriar Wow, right on queue. I've been running Insiders, when I commented here 12 hours ago my build was probably a few days old, and my remote login profile configs were not being inherited by integrated terminals with Remote SSH.

Updated just now:

Commit: 5246162662ffa9f16a70dc2b94f13b0d15511e64
Date: 2021-05-14T08:49:16.464Z (5 hrs ago)

Same remote machine, nothing changed other than the Insiders update, and it's now working as expected 🎉

Thanks, and hope it works for others' situations here too and is available to everyone soon.

@jatin-code777
Copy link

Hi @ches

Could you please give a minimal example showcasing what has changed? A behavior before vs before now. Would be really helpful to know

@Tyriar
Copy link
Member

Tyriar commented May 14, 2021

@jatin-code777 "terminal.integrated.inheritEnv": true (default) should create the terminal using a $SHELL -ilc login shell, false should use the base environment that the vscode server was launched with (not login)

@mihir3445
Copy link

mihir3445 commented Jun 14, 2021

"settings": {
   "terminal.integrated.shellArgs.linux": ["-l"]
}

is deprecated following can be used as replacement

"settings": {
  "terminal.integrated.defaultProfile.linux": "bash",
  "terminal.integrated.profiles.linux": {
  "bash": {
  "path": "bash",
  "args": ["-l"]
   }
   }
}

@Tyriar
Copy link
Member

Tyriar commented Jun 14, 2021

is deprecated following can be used as replacement

v1.57 should prompt to auto migrate to profiles when you launch a terminal

@rubensa
Copy link

rubensa commented Jun 15, 2021

I'm experiencing the same (.profile not being sourced in Integrated Terminal) but using Docker (not remote SSH connection).

I always use "bash -l" as the command to execute when I want an interactive shell on a Docker container.

So in my case following doc and adding:

"settings": {
   // Run interactive bash shell in VSCode Integrated Terminal
   "terminal.integrated.shellArgs.linux": ["-l"]
}

in devcontainer.json made the trick.

For some time now, these are my current settings (extract from devcontainer.json):

{
  // Indicates the type of shell VS Code should use to "probe" for user environment variables to use by default 
  // while debugging or running a task: none (default), interactiveShell, loginShell, or loginInteractiveShell.
  // Fire ~/.bashrc, ~/.zshrc before starting VS Code processes
  "userEnvProbe": "interactiveShell",
  // Adds default settings.json values into a container/machine specific settings file.
  "settings": {
    // Ensure VS Code uses the right shell for terminals and tasks.
    "terminal.integrated.defaultProfile.linux": "bash",
    "terminal.integrated.profiles.linux": {
      "bash": {
        "path": "/bin/bash",
        "args": [
          // Run interactive bash shell in VSCode integrated terminal
          "-i"
        ]
      }
    },
  }
}

@rbtcollins
Copy link

rbtcollins commented Sep 22, 2021

So this used to mostly work for me, and since the insiders update has suddenly stopped working :(. The "-l" in args workaround works for tools in the terminal, but I'm not sure yet whether gotools etc will work (I use pyenv, goenv, basilisk etc).

What is the current way the internals are meant to work?

@blackliner
Copy link

So, long story short, VScode remote-ssh will not source ~/.profile by default?

@hoishing
Copy link

hoishing commented Jan 2, 2022

@blackliner we need to explicitly set the ["-l"] argument in order to let bash invoked as a login shell. That is, sourcing the ~/.profile

"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.profiles.linux": {
  "bash": {
    "path": "bash",
    "args": ["-l"]
  }
}

@jabaa
Copy link

jabaa commented Feb 20, 2022

Isn't the actual problem, that the terminals don't inherit the environment variables correctly?

When I start my computer and login using my graphical desktop manager, ~/.profile or ~/.zprofile is sourced. When I open a terminal in a terminal emulator, it's a non-login shell, but it inherits the environment and contains the values from ~/.profile or ~/.zprofile.

When I connect to a remote machine through SSH, I get a login shell and ~/.profile or ~/.zprofile is sourced. When I open a new shell inside this connection, it's a non-login shell, but it inherits the environment and contains the values from ~/.profile or ~/.zprofile.

When I connect through Remote-SSH in VS Code, I expect a non-login shell, inheriting the environment and containing the values from ~/.profile or ~/.zprofile, but the values aren't set. The file ~/.profile resp. ~/.zprofile was sourced (I've tested with echo $(date) >> ~/timestamps) but the environment variables aren't inherited.

Setting the shell and arguments is a hacky workaround. Different users on the same system have different shells. Different systems have different shells. Users can change their login shell and the necessary configuration files.

@bavis-m
Copy link

bavis-m commented Apr 18, 2022

My problem (as mentioned in the dupe/closed issue above, #6627), is that the initial connection to the remote, where the code server is started up, is neither a login terminal, nor an interactive terminal, so I have no startup scripts that will get sourced where I can put relevant environment, such as adding the dotnet sdk to the path. I can't find anywhere where a command like bash -ilc ... is being run to generate the environment as @roblourens was suggesting. All I see is bash being run with no args directly as an ssh command (again, see my issue/logs above) which appears to start the server directly, and which returns my environment block with nothing from .profile sourced. I can get access to a login terminal by setting something up in terminal.integrated.profiles.linux, but I can't make it use this for the initial connection, and so my dotnet sdk paths are permanently broken when code server starts.

@phil-blain
Copy link

@bavis-m now that RemoteCommand works (see https://github.com/microsoft/vscode-docs/blob/main/remote-release-notes/v1_64.md#enable-remotecommand), you might want to try adding something like the following to your SSH config (on your local machine):

Host your-host
    RemoteCommand source $HOME/.profile && bash

This command (as far as I understand) will be used by the initial connection (thus the need for the trailing && bash) and manually sourcing your ~/.profile should make your tools available as you wish (as long as your ~/.profile is not explicitely trying to determine if the shell is interactive or not, i.e. it should not be checking for an existing PS1 or such).

Or even simpler, now that I think of it,

Host your-host
    RemoteCommand bash --login

Of course this workaround means that now every SSH connection to your-host (outside VSCode) will also use this command, which is not that great, but this can be worked around by adding the RemoteCommand under a specific your-host-vsc entry (or similar) in your SSH config, and connecting to that host in VSCode instead.

@gerritgriebel
Copy link

gerritgriebel commented Apr 29, 2022

Helps for opening a new shell:

"terminal.integrated.profiles.linux": {
    "bash": {
        "path": "/bin/bash",
        "args": ["-l"]
    }
},

But: when I leave more than one terminal open while closing vscode window and open it later only one terminal is restored and it is started without .bash_profile environment. Leaving one terminal open, starts on reopen one terminal with correct .bash_profile environment.

Edit: with vscode 1.79.2 i can no longer reproduce this issue, it seems to be solved for me.

@rbtcollins
Copy link

I wonder if the thing to do here is to fork the extension and make it follow the decades-old tradition of 'the shell at the top of the process hierarchy is a login shell', accepting that some folk will have customised things in a way that breaks, and then let folk migrate over to this setup that is consistent with local logins?

@nabheet
Copy link

nabheet commented Jun 8, 2022

Helps for opening a new shell:

"terminal.integrated.profiles.linux": {
    "bash": {
        "path": "/bin/bash",
        "args": ["-l"]
    }
},

But: when I leave more than one terminal open while closing vscode window and open it later only one terminal is restored and it is started without .bash_profile environment. Leaving one terminal open, starts on reopen one terminal with correct .bash_profile environment.

I can confirm this issue. Happening to me too.

@sevillal
Copy link

I am facing the same issue when connecting to Azure ML compute instance with Remote SSH. The Azure ML compute instances rely on /etc/profile config but since the terminals created in the remote connection are non-login /etc/profile is not sourced.

We can workaround it by manually changing the remote settings.json with:

{
    "terminal.integrated.defaultProfile.linux": "bash",
    "terminal.integrated.profiles.linux": {
        "bash": {
            "path": "bash",
            "icon": "terminal-bash",
            "args": ["-l"]
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ssh Issue in vscode-remote SSH under-discussion Issue is under discussion for relevance, priority, approach
Projects
None yet
Development

No branches or pull requests