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 · 54 comments
Open

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

jenzopr opened this issue Oct 15, 2019 · 54 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.

@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"]
        }
    }
}

@madalinignisca
Copy link

I have been confused many times why I don't see environment variables changes on starting a new terminal on a remote ssh session in vscode. But I realized that the full profile is sourced on the start of the vscode remote process. I used to do what @sevillal mentioned in all my workspaces, and it works. The other way around, uglier to do, is to kill current remote server and reload the window.

I do not see why the argument "-l" would not be by default for remote ssh and for docker dev containers, as the same issue happens with it.

@magicoli
Copy link

magicoli commented Mar 28, 2024

In my case, both default profile and -l args must be specified, and userEnvProbe has no effect on the issue.

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

Side note: this issue is 5 years old, I can't believe there is not at least a clear settings section to avoid users having to crawl a dozen of web pages before finding the actual fix.

And I say "at least" because, in my point of view, opening an ssh session should by default behave the same way as on any other terminal client (I work with dozens of servers, and several OS platforms, they all behave as login screen when connecting terminal via ssh). This should never require tweaking anything else than vsocde itself (as suggested in some of the answers).

And if vscode really doesn't want to comply to standards, it should display a big red message like "Warning, you are about to open an interactive session via ssh. For some obscure reasons, we chose to ignore you use an interactive terminal and behave as if it was not. If you want vscode to behave as any other ssh interactive client, update preferences manually in settings.json".

@andrewmcdonald-oxb
Copy link

Is there any consensus on this yet? It's a surprise to find that .profile isn't sourced when using a VS Code remote terminal. In particular, that's where Ubuntu puts the addition of ~/.local into the user's path. I see the various workarounds above but it feels odd to have to use them. Doesn't this feel sufficiently important, and obscure to new/less experienced users, to call out strongly in the docs? I agree with the comment above about following the principle of least surprise.

@kevinrue
Copy link

In my case, both default profile and -l args must be specified, and userEnvProbe has no effect on the issue.

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

Weird, that used to work perfectly for me, but stopped working now (I only notice today but can't say for how long it's been the case).

Anyone else noticed it? Or did I potentially mess up something on my side?

@kevinrue
Copy link

Update: after several hours of baging my head against the wall, and checking the man page of /usr/bin/bash, I managed to restore the login shell in VScode by replacing -l by --login

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

Haven't heard back from IT yet why the -l option doesn't work anymore.

@tomsing1
Copy link

@kevinrue Thanks a lot for posting your solution, that worked for me as well.

@tbenst
Copy link

tbenst commented Jul 24, 2024

For me the fix of the latest ~/.bashrc not being read can be resolved by:

  1. exit vscode (remote - ssh)
  2. ssh to remote
  3. killall node (warning: only do if not running a node server ;)
  4. open vscode (remote - ssh)
  5. observe that in jupyter and terminal that your ENV variable is now present

@GyurkanM
Copy link

GyurkanM commented Sep 5, 2024

I fixed that by adding --login to settings.json, under terminal.integrated.profiles.linux,
"bash": { "path": "bash", "args": [ "--login" ], "icon": "terminal-bash" }
then select Terminal; Select Default Profile - bash --login.
It is strange that for MacOs you can see that terminal is started by default with --login parameter, strange decision, why not the same on linux terminals?

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