Skip to content

Commit

Permalink
feat: make deployer only answer its own project
Browse files Browse the repository at this point in the history
  • Loading branch information
chesedo committed Nov 8, 2022
1 parent b4055af commit 3c8ede6
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 3 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ This prevents `gateway` from starting up. Now you can start deployer only using:

```bash
provisioner_address=$(docker inspect --format '{{(index .NetworkSettings.Networks "shuttle_default").IPAddress}}' shuttle_prod_hello-world-rocket-app_run)
cargo run -p shuttle-deployer -- --provisioner-address $provisioner_address --provisioner-port 8000 --proxy-fqdn local.rs --admin-secret test-key
cargo run -p shuttle-deployer -- --provisioner-address $provisioner_address --provisioner-port 8000 --proxy-fqdn local.rs --admin-secret test-key --project <project_name>
```

The `--admin-secret` can safely be changed to your api-key to make testing easier.
The `--admin-secret` can safely be changed to your api-key to make testing easier. While `<project_name>` needs to match the name of the project that will be deployed to this deployer. This is the `Cargo.toml` or `Shuttle.toml` name for the project.

### Using Podman instead of Docker
If you are using Podman over Docker, then expose a rootless socket of Podman using the following command:
Expand Down
6 changes: 5 additions & 1 deletion deployer/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{net::SocketAddr, path::PathBuf};

use clap::Parser;
use fqdn::FQDN;
use shuttle_common::Port;
use shuttle_common::{project::ProjectName, Port};

/// Program to handle the deploys for a single project
/// Handling includes, building, testing, and running each service
Expand Down Expand Up @@ -33,6 +33,10 @@ pub struct Args {
#[clap(long, default_value = "0.0.0.0:8000")]
pub proxy_address: SocketAddr,

/// Project being served by this deployer
#[clap(long)]
pub project: ProjectName,

/// Secret that will be used to perform admin tasks on this deployer
#[clap(long)]
pub admin_secret: String,
Expand Down
7 changes: 7 additions & 0 deletions deployer/src/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use axum::body::{Body, BoxBody};
use axum::extract::ws::{self, WebSocket};
use axum::extract::{Extension, Path, Query};
use axum::http::{Request, Response};
use axum::middleware::from_extractor;
use axum::routing::{get, Router};
use axum::{extract::BodyStream, Json};
use bytes::BufMut;
Expand All @@ -13,6 +14,7 @@ use futures::StreamExt;
use opentelemetry::global;
use opentelemetry_http::HeaderExtractor;
use shuttle_common::models::secret;
use shuttle_common::project::ProjectName;
use shuttle_common::LogItem;
use tower_http::auth::RequireAuthorizationLayer;
use tower_http::trace::TraceLayer;
Expand All @@ -28,11 +30,14 @@ use std::time::Duration;

pub use {self::error::Error, self::error::Result};

mod project;

pub fn make_router(
persistence: Persistence,
deployment_manager: DeploymentManager,
proxy_fqdn: FQDN,
admin_secret: String,
project_name: ProjectName,
) -> Router<Body> {
Router::new()
.route("/projects/:project_name/services", get(list_services))
Expand Down Expand Up @@ -78,6 +83,8 @@ pub fn make_router(
},
),
)
.route_layer(from_extractor::<project::ProjectNameGuard>())
.layer(Extension(project_name))
}

async fn list_services(
Expand Down
44 changes: 44 additions & 0 deletions deployer/src/handlers/project.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use std::collections::HashMap;

use async_trait::async_trait;
use axum::extract::{FromRequest, Path, RequestParts};
use hyper::StatusCode;
use shuttle_common::project::ProjectName;

/// Gaurd to ensure request are for the project served by this deployer
/// Note: this guard needs the `ProjectName` extension to be set
pub struct ProjectNameGuard;

#[async_trait]
impl<B> FromRequest<B> for ProjectNameGuard
where
B: Send,
{
type Rejection = StatusCode;

async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
// We expect some path parameters
let Path(path): Path<HashMap<String, String>> = match req.extract().await {
Ok(path) => path,
Err(_) => return Err(StatusCode::NOT_FOUND),
};

// All our routes have the `project_name` parameter
let project_name = match path.get("project_name") {
Some(project_name) => project_name,
None => return Err(StatusCode::INTERNAL_SERVER_ERROR),
};

// This extractor requires the ProjectName extension to be set
let expected_project_name: &ProjectName = match req.extensions().get() {
Some(expected) => expected,
None => return Err(StatusCode::INTERNAL_SERVER_ERROR),
};

if project_name == expected_project_name.as_str() {
Ok(ProjectNameGuard)
} else {
Err(StatusCode::BAD_REQUEST)
}
}
}
1 change: 1 addition & 0 deletions deployer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub async fn start(
deployment_manager,
args.proxy_fqdn,
args.admin_secret,
args.project,
);
let make_service = router.into_make_service();

Expand Down
2 changes: 2 additions & 0 deletions gateway/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,8 @@ impl ProjectCreating {
"Cmd": [
"--admin-secret",
initial_key,
"--project",
project_name,
"--api-address",
format!("0.0.0.0:{RUNTIME_API_PORT}"),
"--provisioner-address",
Expand Down

0 comments on commit 3c8ede6

Please sign in to comment.