Skip to content

Commit

Permalink
feat(gateway): more descriptive project not found error (#1452)
Browse files Browse the repository at this point in the history
  • Loading branch information
fatfingers23 committed Dec 7, 2023
1 parent 501e6c8 commit 850368e
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 27 deletions.
12 changes: 7 additions & 5 deletions common/src/models/error.rs
Expand Up @@ -39,7 +39,7 @@ pub enum ErrorKind {
Forbidden,
UserNotFound,
UserAlreadyExists,
ProjectNotFound,
ProjectNotFound(String),
InvalidProjectName(InvalidProjectName),
ProjectAlreadyExists,
/// Contains a message describing a running state of the project.
Expand Down Expand Up @@ -77,10 +77,12 @@ impl From<ErrorKind> for ApiError {
ErrorKind::BadHost => (StatusCode::BAD_REQUEST, "The 'Host' header is invalid"),
ErrorKind::UserNotFound => (StatusCode::NOT_FOUND, "User not found"),
ErrorKind::UserAlreadyExists => (StatusCode::BAD_REQUEST, "User already exists"),
ErrorKind::ProjectNotFound => (
StatusCode::NOT_FOUND,
"Project not found. Make sure you are the owner of this project name. Run `cargo shuttle project start` to create a new project.",
),
ErrorKind::ProjectNotFound(project_name) => {
return Self {
message: format!("Project '{}' not found. Make sure you are the owner of this project name. Run `cargo shuttle project start` to create a new project.", project_name),
status_code: StatusCode::NOT_FOUND.as_u16(),
}
},
ErrorKind::ProjectNotReady => (
StatusCode::SERVICE_UNAVAILABLE,
// "not ready" is matched against in cargo-shuttle for giving further instructions on project deletion
Expand Down
2 changes: 1 addition & 1 deletion gateway/src/auth.rs
Expand Up @@ -87,7 +87,7 @@ where
if user.projects.contains(&scope) || user.claim.scopes.contains(&Scope::Admin) {
Ok(Self { user, scope })
} else {
Err(Error::from(ErrorKind::ProjectNotFound))
Err(Error::from(ErrorKind::ProjectNotFound(scope.to_string())))
}
}
}
36 changes: 19 additions & 17 deletions gateway/src/proxy.rs
Expand Up @@ -23,6 +23,7 @@ use once_cell::sync::Lazy;
use opentelemetry::global;
use opentelemetry_http::HeaderInjector;
use shuttle_common::backends::headers::XShuttleProject;
use shuttle_common::models::error::InvalidProjectName;
use tokio::sync::mpsc::Sender;
use tower::{Service, ServiceBuilder};
use tower_sanitize_path::SanitizePath;
Expand Down Expand Up @@ -110,23 +111,24 @@ impl UserProxy {
.headers()
.typed_get::<Host>()
.map(|host| fqdn!(host.hostname()))
.ok_or_else(|| Error::from_kind(ErrorKind::ProjectNotFound))?;

let project_name =
if fqdn.is_subdomain_of(&self.public) && fqdn.depth() - self.public.depth() == 1 {
fqdn.labels()
.next()
.unwrap()
.to_owned()
.parse()
.map_err(|_| Error::from_kind(ErrorKind::ProjectNotFound))?
} else if let Ok(CustomDomain { project_name, .. }) =
self.gateway.project_details_for_custom_domain(&fqdn).await
{
project_name
} else {
return Err(Error::from_kind(ErrorKind::ProjectNotFound));
};
.ok_or_else(|| Error::from_kind(ErrorKind::BadHost))?;

let project_name = if fqdn.is_subdomain_of(&self.public)
&& fqdn.depth() - self.public.depth() == 1
{
fqdn.labels()
.next()
.unwrap()
.to_owned()
.parse()
.map_err(|_| Error::from_kind(ErrorKind::InvalidProjectName(InvalidProjectName)))?
} else if let Ok(CustomDomain { project_name, .. }) =
self.gateway.project_details_for_custom_domain(&fqdn).await
{
project_name
} else {
return Err(Error::from_kind(ErrorKind::CustomDomainNotFound));
};

req.headers_mut()
.typed_insert(XShuttleProject(project_name.to_string()));
Expand Down
8 changes: 4 additions & 4 deletions gateway/src/service.rs
Expand Up @@ -388,7 +388,7 @@ impl GatewayService {
))
}),
})
.ok_or_else(|| Error::from_kind(ErrorKind::ProjectNotFound))
.ok_or_else(|| Error::from_kind(ErrorKind::ProjectNotFound(project_name.to_string())))
}

pub async fn project_name_exists(&self, project_name: &ProjectName) -> Result<bool, Error> {
Expand Down Expand Up @@ -472,7 +472,7 @@ impl GatewayService {
.fetch_optional(&self.db)
.await?
.map(|row| row.get("account_name"))
.ok_or_else(|| Error::from(ErrorKind::ProjectNotFound))
.ok_or_else(|| Error::from(ErrorKind::ProjectNotFound(project_name.to_string())))
}

pub async fn control_key_from_project_name(
Expand All @@ -484,7 +484,7 @@ impl GatewayService {
.fetch_optional(&self.db)
.await?
.map(|row| row.try_get("initial_key").unwrap())
.ok_or_else(|| Error::from(ErrorKind::ProjectNotFound))?;
.ok_or_else(|| Error::from(ErrorKind::ProjectNotFound(project_name.to_string())))?;
Ok(control_key)
}

Expand Down Expand Up @@ -1266,7 +1266,7 @@ pub mod tests {
assert!(matches!(
svc.find_project(&matrix).await,
Err(Error {
kind: ErrorKind::ProjectNotFound,
kind: ErrorKind::ProjectNotFound(_),
..
})
));
Expand Down

0 comments on commit 850368e

Please sign in to comment.