Compare commits

..

No commits in common. "143f892c52828c38e5c8ce0b4f9f4076e25a158d" and "a3cf021fc6111366ec17e82d0bcd57a2d9906174" have entirely different histories.

7 changed files with 92 additions and 100 deletions

1
.gitignore vendored
View File

@ -1,3 +1,2 @@
/target /target
/data/ /data/
*.tar.gz

View File

@ -8,9 +8,12 @@ pipeline:
repo: 'chewingbever/site' repo: 'chewingbever/site'
tag: tag:
- 'latest' - 'latest'
- "${CI_COMMIT_TAG}"
secrets: secrets:
- 'docker_username' - 'docker_username'
- 'docker_password' - 'docker_password'
when:
event: tag
deploy: deploy:
image: 'curlimages/curl' image: 'curlimages/curl'
@ -18,3 +21,5 @@ pipeline:
- 'webhook' - 'webhook'
commands: commands:
- curl -XPOST --fail -s "$WEBHOOK" - curl -XPOST --fail -s "$WEBHOOK"
when:
event: tag

36
Cargo.lock generated
View File

@ -265,6 +265,25 @@ dependencies = [
"wasi 0.10.2+wasi-snapshot-preview1", "wasi 0.10.2+wasi-snapshot-preview1",
] ]
[[package]]
name = "h2"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.11.2" version = "0.11.2"
@ -333,6 +352,7 @@ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2",
"http", "http",
"http-body", "http-body",
"httparse", "httparse",
@ -771,20 +791,6 @@ name = "serde"
version = "1.0.136" version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
@ -837,7 +843,6 @@ dependencies = [
"hyper", "hyper",
"metrics", "metrics",
"metrics-exporter-prometheus", "metrics-exporter-prometheus",
"serde",
"serde_json", "serde_json",
"tar", "tar",
"tokio", "tokio",
@ -975,6 +980,7 @@ dependencies = [
"futures-sink", "futures-sink",
"pin-project-lite", "pin-project-lite",
"tokio", "tokio",
"tracing",
] ]
[[package]] [[package]]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "site-backend" name = "site-backend"
version = "0.1.4" version = "0.1.3"
edition = "2021" edition = "2021"
publish = false publish = false
@ -11,8 +11,8 @@ name = "site"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
axum = { version = "0.5.1" } axum = { version = "0.5.1", features = ["http2"] }
hyper = { version = "0.14.18" } hyper = { version = "0.14.18", features = ["full"] }
tokio = { version = "1.17.0", features = ["full"] } tokio = { version = "1.17.0", features = ["full"] }
tracing = "0.1.32" tracing = "0.1.32"
tracing-subscriber = {version = "0.3.10", features = ["env-filter"] } tracing-subscriber = {version = "0.3.10", features = ["env-filter"] }
@ -25,4 +25,3 @@ uuid = { version = "1.0.0-alpha.1", features = ["v4"] }
serde_json = "1.0.79" serde_json = "1.0.79"
metrics = "0.18.1" metrics = "0.18.1"
metrics-exporter-prometheus = "0.9.0" metrics-exporter-prometheus = "0.9.0"
serde = { version = "1.0", features = ["derive"] }

8
curl
View File

@ -1,8 +0,0 @@
#!/usr/bin/env sh
curl \
-XPOST \
-T test.tar.gz \
-H 'Authorization: Bearer test' \
-v \
http://localhost:3000/api/deploy?dir=docs

View File

@ -1,27 +1,19 @@
use std::{collections::HashSet, io::ErrorKind, path::Path}; use std::{collections::HashSet, io::ErrorKind, path::Path};
use axum::{ use axum::{
extract::{BodyStream, Extension, Query}, extract::{BodyStream, Extension},
http::StatusCode, http::StatusCode,
response::IntoResponse, response::IntoResponse,
}; };
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use futures_util::TryStreamExt; use futures_util::TryStreamExt;
use serde::Deserialize;
use tar::Archive; use tar::Archive;
use tokio_util::io::StreamReader; use tokio_util::io::StreamReader;
use crate::DEFAULT_STATIC_DIR_NAME; use crate::STATIC_DIR_NAME;
#[derive(Deserialize)]
pub struct StaticDirParams
{
dir: Option<String>,
}
pub async fn post_deploy( pub async fn post_deploy(
Extension(data_dir): Extension<String>, Extension(data_dir): Extension<String>,
Query(params): Query<StaticDirParams>,
res: BodyStream, res: BodyStream,
) -> impl IntoResponse ) -> impl IntoResponse
{ {
@ -34,53 +26,46 @@ pub async fn post_deploy(
let mut file = tokio::fs::File::create(&file_path).await.unwrap(); let mut file = tokio::fs::File::create(&file_path).await.unwrap();
tokio::io::copy(&mut read, &mut file).await; tokio::io::copy(&mut read, &mut file).await;
let mut static_path = Path::new(&data_dir).join(DEFAULT_STATIC_DIR_NAME);
if params.dir.is_some() {
static_path = static_path.join(params.dir.unwrap());
}
// Make sure the static directory exists
tokio::fs::create_dir_all(&static_path).await;
let fp_clone = file_path.clone();
// Extract the contents of the tarball synchronously // Extract the contents of the tarball synchronously
let res = match tokio::task::spawn_blocking(move || {
match tokio::task::spawn_blocking(move || process_archive(&fp_clone, &static_path)).await { let file = match std::fs::File::open(file_path) {
Ok(_) => StatusCode::OK, Ok(v) => v,
Err(_) => StatusCode::INTERNAL_SERVER_ERROR, Err(_) => return StatusCode::INTERNAL_SERVER_ERROR,
}; };
// Remove archive file after use
tokio::fs::remove_file(&file_path).await;
res
}
fn process_archive(archive_path: &Path, static_dir: &Path) -> Result<(), ()>
{
let file = std::fs::File::open(archive_path).map_err(|_| ())?;
let tar = GzDecoder::new(file); let tar = GzDecoder::new(file);
let mut archive = Archive::new(tar); let mut archive = Archive::new(tar);
let mut paths = HashSet::new(); let mut paths = HashSet::new();
let entries = archive.entries().map_err(|_| ())?; let entries = match archive.entries() {
Ok(e) => e,
Err(_) => return StatusCode::INTERNAL_SERVER_ERROR,
};
// Extract each entry into the output directory // Extract each entry into the output directory
let static_dir = Path::new(&data_dir).join(STATIC_DIR_NAME);
for entry_res in entries { for entry_res in entries {
let mut entry = entry_res.map_err(|_| ())?; if let Ok(mut entry) = entry_res {
entry.unpack_in(static_dir).map_err(|_| ())?; if let Err(_) = entry.unpack_in(&static_dir) {
return StatusCode::INTERNAL_SERVER_ERROR;
}
if let Ok(path) = entry.path() { if let Ok(path) = entry.path() {
paths.insert(path.into_owned()); paths.insert(path.into_owned());
} }
} else {
return StatusCode::INTERNAL_SERVER_ERROR;
}
} }
// Remove any old files that weren't present in new archive // Remove any old files that weren't present in new archive
let mut items = vec![]; let mut items = vec![];
// Start by populating the vec with the initial files // Start by populating the vec with the initial files
let iter = static_dir.read_dir().map_err(|_| ())?; let iter = match static_dir.read_dir() {
Ok(v) => v,
Err(_) => return StatusCode::INTERNAL_SERVER_ERROR,
};
iter.filter_map(|r| r.ok()) iter.filter_map(|r| r.ok())
.for_each(|e| items.push(e.path())); .for_each(|e| items.push(e.path()));
@ -101,5 +86,11 @@ fn process_archive(archive_path: &Path, static_dir: &Path) -> Result<(), ()>
} }
} }
Ok(()) StatusCode::OK
})
.await
{
Ok(s) => s,
Err(_) => StatusCode::INTERNAL_SERVER_ERROR,
}
} }

View File

@ -14,7 +14,7 @@ mod api;
mod matrix; mod matrix;
mod metrics; mod metrics;
const DEFAULT_STATIC_DIR_NAME: &str = "static"; const STATIC_DIR_NAME: &str = "static";
#[tokio::main] #[tokio::main]
async fn main() async fn main()
@ -30,7 +30,7 @@ async fn main()
// Get required variables from env vars // Get required variables from env vars
let api_key = std::env::var("API_KEY").expect("No API_KEY was provided."); let api_key = std::env::var("API_KEY").expect("No API_KEY was provided.");
let data_dir = std::env::var("DATA_DIR").expect("No DATA_DIR was provided."); let data_dir = std::env::var("DATA_DIR").expect("No DATA_DIR was provided.");
let static_dir = format!("{}/{}", data_dir, DEFAULT_STATIC_DIR_NAME); let static_dir = format!("{}/{}", data_dir, STATIC_DIR_NAME);
std::fs::create_dir_all(&static_dir); std::fs::create_dir_all(&static_dir);