integrate registry with GlobalConfig

This commit is contained in:
Ilion Beyst 2022-07-16 21:47:22 +02:00
parent d13d131130
commit 0cf7b5299d
2 changed files with 48 additions and 20 deletions

View file

@ -40,6 +40,9 @@ pub struct GlobalConfig {
pub bots_directory: String, pub bots_directory: String,
pub match_logs_directory: String, pub match_logs_directory: String,
pub maps_directory: String, pub maps_directory: String,
pub registry_directory: String,
pub registry_admin_password: String,
} }
pub async fn seed_simplebot(config: &GlobalConfig, pool: &ConnectionPool) { pub async fn seed_simplebot(config: &GlobalConfig, pool: &ConnectionPool) {
@ -109,7 +112,7 @@ pub fn get_config() -> Result<Configuration, ConfigError> {
.try_deserialize() .try_deserialize()
} }
async fn run_registry(db_pool: DbPool) { async fn run_registry(config: Arc<GlobalConfig>, db_pool: DbPool) {
// TODO: put in config // TODO: put in config
let addr = SocketAddr::from(([127, 0, 0, 1], 9001)); let addr = SocketAddr::from(([127, 0, 0, 1], 9001));
@ -117,6 +120,7 @@ async fn run_registry(db_pool: DbPool) {
.serve( .serve(
registry_service() registry_service()
.layer(Extension(db_pool)) .layer(Extension(db_pool))
.layer(Extension(config))
.into_make_service(), .into_make_service(),
) )
.await .await
@ -133,12 +137,15 @@ pub async fn run_app() {
bots_directory: "./data/bots".to_string(), bots_directory: "./data/bots".to_string(),
match_logs_directory: "./data/matches".to_string(), match_logs_directory: "./data/matches".to_string(),
maps_directory: "./data/maps".to_string(), maps_directory: "./data/maps".to_string(),
registry_directory: "./data/registry".to_string(),
registry_admin_password: "verysecretadminpassword".to_string(),
}); });
let db_pool = prepare_db(&configuration.database_url, &global_config).await; let db_pool = prepare_db(&configuration.database_url, &global_config).await;
tokio::spawn(run_ranker(global_config.clone(), db_pool.clone())); tokio::spawn(run_ranker(global_config.clone(), db_pool.clone()));
tokio::spawn(run_registry(db_pool.clone())); tokio::spawn(run_registry(global_config.clone(), db_pool.clone()));
let api_service = Router::new() let api_service = Router::new()
.nest("/api", api()) .nest("/api", api())

View file

@ -6,24 +6,22 @@ use axum::headers::authorization::Basic;
use axum::headers::Authorization; use axum::headers::Authorization;
use axum::response::{IntoResponse, Response}; use axum::response::{IntoResponse, Response};
use axum::routing::{get, head, post, put}; use axum::routing::{get, head, post, put};
use axum::{async_trait, Router}; use axum::{async_trait, Extension, Router};
use futures::StreamExt; use futures::StreamExt;
use hyper::StatusCode; use hyper::StatusCode;
use serde::Serialize; use serde::Serialize;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use tokio_util::io::ReaderStream; use tokio_util::io::ReaderStream;
use crate::db::bots::NewBotVersion; use crate::db::bots::NewBotVersion;
use crate::util::gen_alphanumeric; use crate::util::gen_alphanumeric;
use crate::{db, DatabaseConnection}; use crate::{db, DatabaseConnection, GlobalConfig};
use crate::db::users::{authenticate_user, Credentials, User}; use crate::db::users::{authenticate_user, Credentials, User};
// TODO: put this in a config file
const REGISTRY_PATH: &str = "./data/registry";
pub fn registry_service() -> Router { pub fn registry_service() -> Router {
Router::new() Router::new()
// The docker API requires this trailing slash // The docker API requires this trailing slash
@ -49,8 +47,6 @@ fn registry_api_v2() -> Router {
} }
const ADMIN_USERNAME: &str = "admin"; const ADMIN_USERNAME: &str = "admin";
// TODO: put this in some configuration
const ADMIN_PASSWORD: &str = "supersecretpassword";
type AuthorizationHeader = TypedHeader<Authorization<Basic>>; type AuthorizationHeader = TypedHeader<Authorization<Basic>>;
@ -105,8 +101,12 @@ where
password: basic.password(), password: basic.password(),
}; };
let Extension(config) = Extension::<Arc<GlobalConfig>>::from_request(req)
.await
.unwrap();
if credentials.username == ADMIN_USERNAME { if credentials.username == ADMIN_USERNAME {
if credentials.password == ADMIN_PASSWORD { if credentials.password == config.registry_admin_password {
Ok(RegistryAuth::Admin) Ok(RegistryAuth::Admin)
} else { } else {
Err(RegistryAuthError::InvalidCredentials) Err(RegistryAuthError::InvalidCredentials)
@ -162,11 +162,14 @@ async fn check_blob_exists(
db_conn: DatabaseConnection, db_conn: DatabaseConnection,
auth: RegistryAuth, auth: RegistryAuth,
Path((repository_name, raw_digest)): Path<(String, String)>, Path((repository_name, raw_digest)): Path<(String, String)>,
Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<impl IntoResponse, StatusCode> { ) -> Result<impl IntoResponse, StatusCode> {
check_access(&repository_name, &auth, &db_conn)?; check_access(&repository_name, &auth, &db_conn)?;
let digest = raw_digest.strip_prefix("sha256:").unwrap(); let digest = raw_digest.strip_prefix("sha256:").unwrap();
let blob_path = PathBuf::from(REGISTRY_PATH).join("sha256").join(&digest); let blob_path = PathBuf::from(&config.registry_directory)
.join("sha256")
.join(&digest);
if blob_path.exists() { if blob_path.exists() {
let metadata = std::fs::metadata(&blob_path).unwrap(); let metadata = std::fs::metadata(&blob_path).unwrap();
Ok((StatusCode::OK, [("Content-Length", metadata.len())])) Ok((StatusCode::OK, [("Content-Length", metadata.len())]))
@ -179,11 +182,14 @@ async fn get_blob(
db_conn: DatabaseConnection, db_conn: DatabaseConnection,
auth: RegistryAuth, auth: RegistryAuth,
Path((repository_name, raw_digest)): Path<(String, String)>, Path((repository_name, raw_digest)): Path<(String, String)>,
Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<impl IntoResponse, StatusCode> { ) -> Result<impl IntoResponse, StatusCode> {
check_access(&repository_name, &auth, &db_conn)?; check_access(&repository_name, &auth, &db_conn)?;
let digest = raw_digest.strip_prefix("sha256:").unwrap(); let digest = raw_digest.strip_prefix("sha256:").unwrap();
let blob_path = PathBuf::from(REGISTRY_PATH).join("sha256").join(&digest); let blob_path = PathBuf::from(&config.registry_directory)
.join("sha256")
.join(&digest);
if !blob_path.exists() { if !blob_path.exists() {
return Err(StatusCode::NOT_FOUND); return Err(StatusCode::NOT_FOUND);
} }
@ -197,13 +203,18 @@ async fn create_upload(
db_conn: DatabaseConnection, db_conn: DatabaseConnection,
auth: RegistryAuth, auth: RegistryAuth,
Path(repository_name): Path<String>, Path(repository_name): Path<String>,
Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<impl IntoResponse, StatusCode> { ) -> Result<impl IntoResponse, StatusCode> {
check_access(&repository_name, &auth, &db_conn)?; check_access(&repository_name, &auth, &db_conn)?;
let uuid = gen_alphanumeric(16); let uuid = gen_alphanumeric(16);
tokio::fs::File::create(PathBuf::from(REGISTRY_PATH).join("uploads").join(&uuid)) tokio::fs::File::create(
.await PathBuf::from(&config.registry_directory)
.unwrap(); .join("uploads")
.join(&uuid),
)
.await
.unwrap();
Ok(Response::builder() Ok(Response::builder()
.status(StatusCode::ACCEPTED) .status(StatusCode::ACCEPTED)
@ -222,11 +233,14 @@ async fn patch_upload(
auth: RegistryAuth, auth: RegistryAuth,
Path((repository_name, uuid)): Path<(String, String)>, Path((repository_name, uuid)): Path<(String, String)>,
mut stream: BodyStream, mut stream: BodyStream,
Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<impl IntoResponse, StatusCode> { ) -> Result<impl IntoResponse, StatusCode> {
check_access(&repository_name, &auth, &db_conn)?; check_access(&repository_name, &auth, &db_conn)?;
// TODO: support content range header in request // TODO: support content range header in request
let upload_path = PathBuf::from(REGISTRY_PATH).join("uploads").join(&uuid); let upload_path = PathBuf::from(&config.registry_directory)
.join("uploads")
.join(&uuid);
let mut file = tokio::fs::OpenOptions::new() let mut file = tokio::fs::OpenOptions::new()
.read(false) .read(false)
.write(true) .write(true)
@ -266,10 +280,13 @@ async fn put_upload(
Path((repository_name, uuid)): Path<(String, String)>, Path((repository_name, uuid)): Path<(String, String)>,
Query(params): Query<UploadParams>, Query(params): Query<UploadParams>,
mut stream: BodyStream, mut stream: BodyStream,
Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<impl IntoResponse, StatusCode> { ) -> Result<impl IntoResponse, StatusCode> {
check_access(&repository_name, &auth, &db_conn)?; check_access(&repository_name, &auth, &db_conn)?;
let upload_path = PathBuf::from(REGISTRY_PATH).join("uploads").join(&uuid); let upload_path = PathBuf::from(&config.registry_directory)
.join("uploads")
.join(&uuid);
let mut file = tokio::fs::OpenOptions::new() let mut file = tokio::fs::OpenOptions::new()
.read(false) .read(false)
.write(true) .write(true)
@ -293,7 +310,9 @@ async fn put_upload(
return Err(StatusCode::BAD_REQUEST); return Err(StatusCode::BAD_REQUEST);
} }
let target_path = PathBuf::from(REGISTRY_PATH).join("sha256").join(&digest); let target_path = PathBuf::from(&config.registry_directory)
.join("sha256")
.join(&digest);
tokio::fs::rename(&upload_path, &target_path).await.unwrap(); tokio::fs::rename(&upload_path, &target_path).await.unwrap();
Ok(Response::builder() Ok(Response::builder()
@ -314,10 +333,11 @@ async fn get_manifest(
db_conn: DatabaseConnection, db_conn: DatabaseConnection,
auth: RegistryAuth, auth: RegistryAuth,
Path((repository_name, reference)): Path<(String, String)>, Path((repository_name, reference)): Path<(String, String)>,
Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<impl IntoResponse, StatusCode> { ) -> Result<impl IntoResponse, StatusCode> {
check_access(&repository_name, &auth, &db_conn)?; check_access(&repository_name, &auth, &db_conn)?;
let manifest_path = PathBuf::from(REGISTRY_PATH) let manifest_path = PathBuf::from(&config.registry_directory)
.join("manifests") .join("manifests")
.join(&repository_name) .join(&repository_name)
.join(&reference) .join(&reference)
@ -339,10 +359,11 @@ async fn put_manifest(
auth: RegistryAuth, auth: RegistryAuth,
Path((repository_name, reference)): Path<(String, String)>, Path((repository_name, reference)): Path<(String, String)>,
mut stream: BodyStream, mut stream: BodyStream,
Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<impl IntoResponse, StatusCode> { ) -> Result<impl IntoResponse, StatusCode> {
let bot = check_access(&repository_name, &auth, &db_conn)?; let bot = check_access(&repository_name, &auth, &db_conn)?;
let repository_dir = PathBuf::from(REGISTRY_PATH) let repository_dir = PathBuf::from(&config.registry_directory)
.join("manifests") .join("manifests")
.join(&repository_name); .join(&repository_name);