integrate registry with GlobalConfig
This commit is contained in:
parent
d13d131130
commit
0cf7b5299d
2 changed files with 48 additions and 20 deletions
|
@ -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())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue