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

First pass at port API needed for port UI #85117

Merged
merged 14 commits into from
Dec 10, 2019
Merged

Conversation

alexr00
Copy link
Member

@alexr00 alexr00 commented Nov 19, 2019

@alexr00 alexr00 self-assigned this Nov 19, 2019
@roblourens
Copy link
Member

Hey @Chuxel, we were talking about this and I wanted to see what you think - is there any reason to prefer ssh-forwarded ports over ports forwarded by vscode?

The SSH extension can declare that it has already forwarded some ports (like ones declared in the SSH config file) but I don't think we need a way for the SSH extension to actually implement the port forward.

src/vs/vscode.proposed.d.ts Outdated Show resolved Hide resolved
src/vs/vscode.proposed.d.ts Outdated Show resolved Hide resolved
* Allows ports that have been forwarded in a workspace to be restored next time that workspace is opened.
* Alternative to this: have API for getting all the ports then an event when they change so that the extension can save and restore ports(as it can do today).
*/
restorePorts: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to distinguish between the vscode server port which shouldn't be restored, and others. The alternative suggestion might be better so the extension can differentiate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I understand, the vscode server port must be forwarded by the extension. This API deliberately doesn't provide a way to tell the core about that port, so it won't know about it to restore it.

What other ports shouldn't be restored?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO restorePorts: boolean should be a user setting, not something a provider gets to decide.

Copy link

@fara-nak fara-nak Nov 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were talking about this with Sri today, that if we switch to using this feature, how would you support the ports that already been shared in a session but because user closed the VSO(hence vscode), the ports have been killed. so I assume this restorePorts would solve this issue, am I right? but then where do you save the forwarded port to forward them for next session? would that be part of candidates?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fara-nak Instead of having restorePorts in the API, I'd like to make it a setting. So when the user opens a workspace again the ports are automatically re-forwarded.

@Chuxel
Copy link
Member

Chuxel commented Nov 19, 2019

Hey @Chuxel, we were talking about this and I wanted to see what you think - is there any reason to prefer ssh-forwarded ports over ports forwarded by vscode?

The SSH extension can declare that it has already forwarded some ports (like ones declared in the SSH config file) but I don't think we need a way for the SSH extension to actually implement the port forward.

@roblourens I think using a common mechanism should work.

Playing this out a bit - The main kinds of things that come to mind are around proxies, authentication, etc, but at this point we should be already connected to the other side and we've already authenticated.

The SSH protocol itself allows you to do things like reverse forwarding and allowing connections from things other than localhost, but any dynamic code we have in place today doesn't support that anyway. That seems better to add advanced config to the actual SSH config file.

The one subtlety that bit us on Containers is that "publish" is different than an actual forward. Our forwarding mechanism works even if a host only accepts connections from localhost while publishing via Docker will not (hosts have to use 0.0.0.0 or '*'). I don't think that applies to SSH given we forward localhost as I recall.

UX wise, it probably makes sense to distinguish between the ones forwarded via SSH and a common mechanism like we'll need to for containers just in case we need to explain it.

Copy link
Collaborator

@mjbvz mjbvz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Direction looks good.

I think we do need an embedder specific API to support this properly for VSO. We can hold off on trying to implement it API until we have a good proposal here though since VSO is in no rush to adopt this.

Also keep in mind that the embedder API for port forwarding will have a few different requirements (such the forwarded endpoint being a https resource instead of just localhost). Not sure if these are something we need to support in our extension API as well or not

src/vs/vscode.proposed.d.ts Outdated Show resolved Hide resolved
Copy link
Member Author

@alexr00 alexr00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Chuxel and @roblourens If the SSH extension wanted to provide it's own forwarding, it could do so with forwardPort in RemoteAuthorityResolver, but it doesn't have too. If that implementation is provided, then all port forwarding would happen through there. If not provided, all would happen through the common mechanism in the core. The ports in the SSH config file would be sent to the core through toForward and forwarded by the core(or the provided implementation in forwardPort.

It makes sense to have the option to show this in the UI. To distinguish how the port is forwarded, I just added a forwardMechanism to Port.

@mjbvz For the embedder API, I don't think the port number vs. https address will mater here since we can change how this is handled in the tunnel service (or before it reaches the tunnel service). For SSH and containers, a port number is enough. I'll need to confirm for VS Online (not embedder version).

* An array of ports to be forwarded once connected. For example,
* if the extension wants to have a configuration file with some default ports, they could be passed through for forwarding here.
*/
toForward?: { remote: number, local: number, name: string, closeable?: boolean }[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference between toForward and candidates ? Why is here a type inlined instead of using Port. Perhaps Port should have the closeable property too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

candidates are ports that the user might want to forward. We will show them in the port UI to make it easy/obvious that these might be useful ports. toForward are ports that the extension knows should definitely be forwarded. toForward ports will be forwarded.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that closeable or name is appropriate in the other places. A candidate port doesn't need a name, because the user hasn't taken action on it yet. Same for a published port. Similarly, candidate and published ports aren't closeable. I'm also not sure that when an extension implements forwardPort they should be allowed to decide if that port that they're forwarding is closeable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then toForward should be removed and the extension can call in a loop asExternalUri.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

asExternalUri doesn't allow the extension to give the port a name or choose a specific port.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then should we just add separate port forwarding API, i.e. acknowledge that asExternalUri is not sufficient and add something more powerful?

Copy link
Member Author

@alexr00 alexr00 Nov 21, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the use of asExternalUri is different from toForward:

  • Any extension can call asExternalUri to get a usable uri. Generally, I expect that extension calling asExternalUri only care that they have a usable uri, not the specifics of how they get that usable uri. We don't actually want them to care about specifics. They should "just work"
  • Only a resolver can use toForward since it is used as part of the remote session setup. The session setup knows that it is remote, so it's the resolver's job to care about specifics such as port numbers.

@alexandrudima does that seem reasonable? I'm open to expanding the API, but I think we actually want to keep it narrow here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the functionality desire that a resolver can forward ports, there are two ways to go about it:

  1. Add PortInformation.toForward as is proposed here. This is an expansion of the current API. This means that only resolvers can forward ports, but then they cannot stop the forwarding because toForward is provided by them once and then resolvers cannot call Dispose on something to stop them. So if a config file changes, it is not possible for a resolver to react to it and stop forwarding the current ports and begin forwarding the new ports.

  2. Add vscode.workspace.forwardPort(...): Port. This means we do not add PortInformation.toForward. This is also an expansion of the current API. But this means any extension, including resolvers, can forward ports. Extensions end up forwarding ports today only as a side-effect of calling asExternalUri, so extensions already have the "access" to do port forwarding. Since Port extends Disposable, an extension could stop a certain port forwarding by calling Dispose. So if a config file changes, a resolver could potentially react to it and stop forwarding the current ports and begin forwarding the new ports.

I don't agree with the argument that PortInformation.toForward is somehow leading to a smaller or less expanded API compared to adding vscode.workspace.forwardPort(...): Port. IMHO they are both API expansions, with different characteristics.


Finally, I think candidates: Port[] is typed in a funny way in this proposal. A resolver would need to return Port objects as candidates, but what does it mean to call dispose() on such candidates?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just FYI, today we let the user to choose port number and the name they desire, and they can dispose the port anytime they want.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fara-nak thanks for taking a look! Choosing a name and port number will be exposed through the UI.

@mjbvz
Copy link
Collaborator

mjbvz commented Nov 21, 2019

@alexr00 Makes sense. I agree we can change our internal TunnelService to be more flexible when we need to support the embedder case as well

@alexr00
Copy link
Member Author

alexr00 commented Nov 25, 2019

Some notes about the changes just pushed:

  • Keeping candidates because we don't want to automatically forward ports just because the extension knows they're useful.
  • Keeping published because it isn't the same as forwarded and we want to differentiate. Full discussion here: Remote Explorer shows container published ports as "forwarded", which is misleading vscode-remote-release#1809
  • Changing from toForward to a workspace.forwardPort so that extensions that have forwarded ports in settings can respond to settings changes if they want. Also just gives more flexibility.
  • Separate interface for Tunnel and Port so that candidates and published make more sense.
  • Added localAddress to Port and Tunnel.
  • Removed restorePorts with the expectation that it becomes a setting instead.

@alexr00
Copy link
Member Author

alexr00 commented Nov 29, 2019

Updated again to incorporate further feedback. I think the current state will cover all known use cases, and no longer has the containers specific "published". Instead, I've changed it to detected so that if SSH, for example, wants to find list all open SSH tunnels and show them it can us the same detected API for it.

* The localAddress should be the complete local address for connecting to the port. Tunnels provided through
* detected are read-only from the forwarded ports UI.
*/
detected?: { remotePort: number, localAddress: string }[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

complete local address for connecting to the port like a URL or just localhost:1234?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just localhost:1234, I'll add an example to the comment.

@alexr00 alexr00 force-pushed the alexr00/PortForwardingAPI branch from c544068 to 309c8df Compare December 10, 2019 14:42
@alexr00 alexr00 merged commit 9566da2 into master Dec 10, 2019
@alexr00 alexr00 deleted the alexr00/PortForwardingAPI branch December 10, 2019 14:44
@alexr00
Copy link
Member Author

alexr00 commented Dec 10, 2019

Thank you for all the feedback! Proposal is merged in to vscode.proposed.d.ts and will continue to evolve as it's used.

@github-actions github-actions bot locked and limited conversation to collaborators Mar 27, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants