diff --git a/cli/src/tunnels/dev_tunnels.rs b/cli/src/tunnels/dev_tunnels.rs index 94396e8997701..3bf8a331e74b4 100644 --- a/cli/src/tunnels/dev_tunnels.rs +++ b/cli/src/tunnels/dev_tunnels.rs @@ -562,6 +562,10 @@ impl DevTunnels { let tunnel = match self.get_existing_tunnel_with_name(name).await? { Some(e) => { + if tunnel_has_host_connection(&e) { + return Err(CodeError::TunnelActiveAndInUse(name.to_string()).into()); + } + let loc = TunnelLocator::try_from(&e).unwrap(); info!(self.log, "Adopting existing tunnel (ID={:?})", loc); spanf!( @@ -687,13 +691,7 @@ impl DevTunnels { let recyclable = existing_tunnels .iter() - .filter(|t| { - t.status - .as_ref() - .and_then(|s| s.host_connection_count.as_ref()) - .map(|c| c.get_count()) - .unwrap_or(0) == 0 - }) + .filter(|t| !tunnel_has_host_connection(t)) .choose(&mut rand::thread_rng()); match recyclable { @@ -764,12 +762,9 @@ impl DevTunnels { ) -> Result { let existing_tunnels = self.list_tunnels_with_tag(&[self.tag]).await?; let is_name_free = |n: &str| { - !existing_tunnels.iter().any(|v| { - v.status - .as_ref() - .and_then(|s| s.host_connection_count.as_ref().map(|c| c.get_count())) - .unwrap_or(0) > 0 && v.labels.iter().any(|t| t == n) - }) + !existing_tunnels + .iter() + .any(|v| tunnel_has_host_connection(v) && v.labels.iter().any(|t| t == n)) }; if let Some(machine_name) = preferred_name { @@ -1235,6 +1230,14 @@ fn privacy_to_tunnel_acl(privacy: PortPrivacy) -> TunnelAccessControl { } } +fn tunnel_has_host_connection(tunnel: &Tunnel) -> bool { + tunnel + .status + .as_ref() + .and_then(|s| s.host_connection_count.as_ref().map(|c| c.get_count() > 0)) + .unwrap_or_default() +} + #[cfg(test)] mod test { use super::*; diff --git a/cli/src/util/errors.rs b/cli/src/util/errors.rs index 6dbf91eb155b3..0659a0d17814d 100644 --- a/cli/src/util/errors.rs +++ b/cli/src/util/errors.rs @@ -513,7 +513,9 @@ pub enum CodeError { #[error("Could not check for update: {0}")] UpdateCheckFailed(String), #[error("Could not write connection token file: {0}")] - CouldNotCreateConnectionTokenFile(std::io::Error) + CouldNotCreateConnectionTokenFile(std::io::Error), + #[error("A tunnel with the name {0} exists and is in-use. Please pick a different name or stop the existing tunnel.")] + TunnelActiveAndInUse(String), } makeAnyError!(