Skip to content

Commit 707f91a

Browse files
authored
cli: fix 'failed to lookup tunnel' with a name given (microsoft#166507)
Fixes microsoft/vscode-remote-tunnels#563 If a new tunnel `--name` was provided but the existing tunnel was deleted, the CLI would error out with a lookup failed message. Instead it now recreates it like it normally would.
1 parent a1d4263 commit 707f91a

File tree

2 files changed

+97
-65
lines changed

2 files changed

+97
-65
lines changed

cli/src/tunnels/dev_tunnels.rs

Lines changed: 94 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::util::input::prompt_placeholder;
1212
use crate::{debug, info, log, spanf, trace, warning};
1313
use async_trait::async_trait;
1414
use futures::TryFutureExt;
15+
use lazy_static::lazy_static;
1516
use rand::prelude::IteratorRandom;
1617
use regex::Regex;
1718
use reqwest::StatusCode;
@@ -121,7 +122,7 @@ impl AccessTokenProvider for LookupAccessTokenProvider {
121122

122123
match tunnel_lookup {
123124
Ok(tunnel) => Ok(get_host_token_from_tunnel(&tunnel)),
124-
Err(e) => Err(wrap(e, "failed to lookup tunnel")),
125+
Err(e) => Err(wrap(e, "failed to lookup tunnel for host token")),
125126
}
126127
}
127128
}
@@ -212,6 +213,14 @@ fn is_valid_name(name: &str) -> Result<(), InvalidTunnelName> {
212213
Ok(())
213214
}
214215

216+
lazy_static! {
217+
static ref HOST_TUNNEL_REQUEST_OPTIONS: TunnelRequestOptions = TunnelRequestOptions {
218+
include_ports: true,
219+
token_scopes: vec!["host".to_string()],
220+
..Default::default()
221+
};
222+
}
223+
215224
/// Structure optionally passed into `start_existing_tunnel` to forward an existing tunnel.
216225
#[derive(Clone, Debug)]
217226
pub struct ExistingTunnel {
@@ -260,6 +269,7 @@ impl DevTunnels {
260269
Ok(())
261270
}
262271

272+
/// Renames the current tunnel to the new name.
263273
pub async fn rename_tunnel(&mut self, name: &str) -> Result<(), AnyError> {
264274
is_valid_name(name)?;
265275

@@ -269,7 +279,7 @@ impl DevTunnels {
269279
Some(t) => t,
270280
None => {
271281
debug!(self.log, "No code server tunnel found, creating new one");
272-
let (persisted, _) = self.create_tunnel(name).await?;
282+
let (persisted, _) = self.create_tunnel(name, NO_REQUEST_OPTIONS).await?;
273283
self.launcher_tunnel.save(Some(persisted))?;
274284
return Ok(());
275285
}
@@ -282,7 +292,7 @@ impl DevTunnels {
282292
self.log.span("dev-tunnel.tag.get"),
283293
self.client.get_tunnel(&locator, NO_REQUEST_OPTIONS)
284294
)
285-
.map_err(|e| wrap(e, "failed to lookup tunnel"))?;
295+
.map_err(|e| wrap(e, "failed to lookup original tunnel"))?;
286296

287297
full_tunnel.tags = vec![name.to_string(), VSCODE_CLI_TUNNEL_TAG.to_string()];
288298
spanf!(
@@ -297,6 +307,70 @@ impl DevTunnels {
297307
Ok(())
298308
}
299309

310+
/// Updates the name of the existing persisted tunnel to the new name.
311+
/// Gracefully creates a new tunnel if the previous one was deleted.
312+
async fn update_tunnel_name(
313+
&mut self,
314+
persisted: PersistedTunnel,
315+
name: &str,
316+
) -> Result<(Tunnel, PersistedTunnel), AnyError> {
317+
self.check_is_name_free(name).await?;
318+
319+
debug!(self.log, "Tunnel name changed, applying updates...");
320+
321+
let (mut full_tunnel, mut persisted, is_new) = self
322+
.get_or_create_tunnel(persisted, Some(name), NO_REQUEST_OPTIONS)
323+
.await?;
324+
if is_new {
325+
return Ok((full_tunnel, persisted));
326+
}
327+
328+
full_tunnel.tags = vec![name.to_string(), VSCODE_CLI_TUNNEL_TAG.to_string()];
329+
330+
let new_tunnel = spanf!(
331+
self.log,
332+
self.log.span("dev-tunnel.tag.update"),
333+
self.client.update_tunnel(&full_tunnel, NO_REQUEST_OPTIONS)
334+
)
335+
.map_err(|e| wrap(e, "failed to rename tunnel"))?;
336+
337+
persisted.name = name.to_string();
338+
self.launcher_tunnel.save(Some(persisted.clone()))?;
339+
340+
Ok((new_tunnel, persisted))
341+
}
342+
343+
/// Gets the persisted tunnel from the service, or creates a new one.
344+
/// If `create_with_new_name` is given, the new tunnel has that name
345+
/// instead of the one previously persisted.
346+
async fn get_or_create_tunnel(
347+
&mut self,
348+
persisted: PersistedTunnel,
349+
create_with_new_name: Option<&str>,
350+
options: &TunnelRequestOptions,
351+
) -> Result<(Tunnel, PersistedTunnel, /* is_new */ bool), AnyError> {
352+
let tunnel_lookup = spanf!(
353+
self.log,
354+
self.log.span("dev-tunnel.tag.get"),
355+
self.client.get_tunnel(&persisted.locator(), options)
356+
);
357+
358+
match tunnel_lookup {
359+
Ok(ft) => Ok((ft, persisted, false)),
360+
Err(HttpError::ResponseError(e))
361+
if e.status_code == StatusCode::NOT_FOUND
362+
|| e.status_code == StatusCode::FORBIDDEN =>
363+
{
364+
let (persisted, tunnel) = self
365+
.create_tunnel(create_with_new_name.unwrap_or(&persisted.name), options)
366+
.await?;
367+
self.launcher_tunnel.save(Some(persisted.clone()))?;
368+
Ok((tunnel, persisted, true))
369+
}
370+
Err(e) => Err(wrap(e, "failed to lookup tunnel").into()),
371+
}
372+
}
373+
300374
/// Starts a new tunnel for the code server on the port. Unlike `start_new_tunnel`,
301375
/// this attempts to reuse or create a tunnel of a preferred name or of a generated friendly tunnel name.
302376
pub async fn start_new_launcher_tunnel(
@@ -308,64 +382,23 @@ impl DevTunnels {
308382
Some(mut persisted) => {
309383
if let Some(name) = preferred_name {
310384
if persisted.name.ne(&name) {
311-
self.check_is_name_free(&name).await?;
312-
let mut full_tunnel = spanf!(
313-
self.log,
314-
self.log.span("dev-tunnel.tag.get"),
315-
self.client
316-
.get_tunnel(&persisted.locator(), NO_REQUEST_OPTIONS)
317-
)
318-
.map_err(|e| wrap(e, "failed to lookup tunnel"))?;
319-
320-
info!(self.log, "Updating name of existing tunnel");
321-
322-
full_tunnel.tags =
323-
vec![name.to_string(), VSCODE_CLI_TUNNEL_TAG.to_string()];
324-
if spanf!(
325-
self.log,
326-
self.log.span("dev-tunnel.tag.update"),
327-
self.client.update_tunnel(&full_tunnel, NO_REQUEST_OPTIONS)
328-
)
329-
.is_ok()
330-
{
331-
persisted.name = name.to_string();
332-
self.launcher_tunnel.save(Some(persisted.clone()))?;
333-
}
385+
(_, persisted) = self.update_tunnel_name(persisted, &name).await?;
334386
}
335387
}
336388

337-
let tunnel_lookup = spanf!(
338-
self.log,
339-
self.log.span("dev-tunnel.tag.get"),
340-
self.client.get_tunnel(
341-
&persisted.locator(),
342-
&TunnelRequestOptions {
343-
include_ports: true,
344-
token_scopes: vec!["host".to_string()],
345-
..Default::default()
346-
}
347-
)
348-
);
349-
350-
match tunnel_lookup {
351-
Ok(ft) => (ft, persisted),
352-
Err(HttpError::ResponseError(e))
353-
if e.status_code == StatusCode::NOT_FOUND
354-
|| e.status_code == StatusCode::FORBIDDEN =>
355-
{
356-
let (persisted, tunnel) = self.create_tunnel(&persisted.name).await?;
357-
self.launcher_tunnel.save(Some(persisted.clone()))?;
358-
(tunnel, persisted)
359-
}
360-
Err(e) => return Err(AnyError::from(wrap(e, "failed to lookup tunnel"))),
361-
}
389+
let (tunnel, persisted, _) = self
390+
.get_or_create_tunnel(persisted, None, &HOST_TUNNEL_REQUEST_OPTIONS)
391+
.await?;
392+
(tunnel, persisted)
362393
}
363394
None => {
364395
debug!(self.log, "No code server tunnel found, creating new one");
365396
let name = self
366397
.get_name_for_tunnel(preferred_name, use_random_name)
367398
.await?;
368-
let (persisted, full_tunnel) = self.create_tunnel(&name).await?;
399+
let (persisted, full_tunnel) = self
400+
.create_tunnel(&name, &HOST_TUNNEL_REQUEST_OPTIONS)
401+
.await?;
369402
self.launcher_tunnel.save(Some(persisted.clone()))?;
370403
(full_tunnel, persisted)
371404
}
@@ -419,7 +452,11 @@ impl DevTunnels {
419452
.await
420453
}
421454

422-
async fn create_tunnel(&mut self, name: &str) -> Result<(PersistedTunnel, Tunnel), AnyError> {
455+
async fn create_tunnel(
456+
&mut self,
457+
name: &str,
458+
options: &TunnelRequestOptions,
459+
) -> Result<(PersistedTunnel, Tunnel), AnyError> {
423460
info!(self.log, "Creating tunnel with the name: {}", name);
424461

425462
let mut tried_recycle = false;
@@ -433,7 +470,7 @@ impl DevTunnels {
433470
let result = spanf!(
434471
self.log,
435472
self.log.span("dev-tunnel.create"),
436-
self.client.create_tunnel(&new_tunnel, NO_REQUEST_OPTIONS)
473+
self.client.create_tunnel(&new_tunnel, options)
437474
);
438475

439476
match result {
@@ -446,9 +483,9 @@ impl DevTunnels {
446483
}
447484

448485
return Err(AnyError::from(TunnelCreationFailed(
449-
name.to_string(),
450-
"You've exceeded the 10 machine limit for the port fowarding service. Please remove other machines before trying to add this machine.".to_string(),
451-
)));
486+
name.to_string(),
487+
"You've exceeded the 10 machine limit for the port fowarding service. Please remove other machines before trying to add this machine.".to_string(),
488+
)));
452489
}
453490
Err(e) => {
454491
return Err(AnyError::from(TunnelCreationFailed(

cli/src/util/zipper.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,7 @@ where
5454
let mut archive = zip::ZipArchive::new(file)
5555
.map_err(|e| wrap(e, format!("failed to open zip archive {}", path.display())))?;
5656

57-
let skip_segments_no = if should_skip_first_segment(&mut archive) {
58-
1
59-
} else {
60-
0
61-
};
62-
57+
let skip_segments_no = usize::from(should_skip_first_segment(&mut archive));
6358
for i in 0..archive.len() {
6459
reporter.report_progress(i as u64, archive.len() as u64);
6560
let mut file = archive
@@ -83,7 +78,7 @@ where
8378
}
8479

8580
if let Some(p) = outpath.parent() {
86-
fs::create_dir_all(&p)
81+
fs::create_dir_all(p)
8782
.map_err(|e| wrap(e, format!("could not create dir for {}", outpath.display())))?;
8883
}
8984

@@ -138,7 +133,7 @@ fn apply_permissions(file: &ZipFile, outpath: &Path) -> Result<(), WrappedError>
138133
use std::os::unix::fs::PermissionsExt;
139134

140135
if let Some(mode) = file.unix_mode() {
141-
fs::set_permissions(&outpath, fs::Permissions::from_mode(mode)).map_err(|e| {
136+
fs::set_permissions(outpath, fs::Permissions::from_mode(mode)).map_err(|e| {
142137
wrap(
143138
e,
144139
format!("error setting permissions on {}", outpath.display()),

0 commit comments

Comments
 (0)