mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-15 11:19:07 +02:00
Premier lot de la migration vers Rust. Le binaire loki-rs : - serve : prend le port public (8090), lance `loki web 8091` en écoute locale et lui relaie tout — HTTP, flux SSE trame par trame, WebSocket. Les en-têtes de bout en bout passent intacts (Host, Authorization, Origin, Sec-Fetch-*, X-Forwarded-Proto : le Go en tire ses contrôles d'accès) ; X-Loki-Via entrant est effacé, un client ne doit jamais pouvoir se faire passer pour le tunnel. Go mort : relancé avec attente croissante, 502 lisible entre-temps. - self-update : lit la release « rolling », installe loki et loki-rs dans $LOKI_HOME/bin/<build>/ après vérification SHA-256, bascule par réécriture atomique de release.json. Les versions s'ordonnent par numéro de run CI ; une ABI d'image différente n'est jamais installée. Toute erreur laisse l'état précédent, le démarrage n'est jamais bloqué. Le HTTPS passe par curl (présent dans l'image) : pas de pile TLS ici. - which-bin : dossier d'où l'entrypoint prend les deux binaires, toujours ensemble. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
149 lines
4.3 KiB
Rust
149 lines
4.3 KiB
Rust
mod common;
|
|
|
|
use loki_rs::update::{self, Outcome, UpdateConfig, sha256_file, state};
|
|
use std::collections::HashMap;
|
|
use std::path::Path;
|
|
use std::time::Duration;
|
|
|
|
const GO: &[u8] = b"binaire go";
|
|
const RS: &[u8] = b"binaire rust";
|
|
|
|
fn sha(b: &[u8]) -> String {
|
|
let t = tempfile::NamedTempFile::new().unwrap();
|
|
std::fs::write(t.path(), b).unwrap();
|
|
sha256_file(t.path()).unwrap()
|
|
}
|
|
|
|
fn release(
|
|
build: u64,
|
|
abi: u32,
|
|
go: &[u8],
|
|
rs: &[u8],
|
|
sums_go: Option<&str>,
|
|
) -> HashMap<String, Vec<u8>> {
|
|
let sums = format!(
|
|
"{} loki-linux\n{} loki-rs-linux\n",
|
|
sums_go.map(str::to_string).unwrap_or_else(|| sha(go)),
|
|
sha(rs)
|
|
);
|
|
HashMap::from([
|
|
(
|
|
"manifest.json".into(),
|
|
format!(r#"{{"build":{build},"abi":{abi},"commit":"c{build}"}}"#).into_bytes(),
|
|
),
|
|
("SHA256SUMS".into(), sums.into_bytes()),
|
|
("loki-linux".into(), go.to_vec()),
|
|
("loki-rs-linux".into(), rs.to_vec()),
|
|
])
|
|
}
|
|
|
|
fn cfg(url: String, data_bin: &Path) -> UpdateConfig {
|
|
UpdateConfig {
|
|
enabled: true,
|
|
base_url: url,
|
|
data_bin: data_bin.to_path_buf(),
|
|
image_build: 3,
|
|
image_abi: 1,
|
|
small_timeout: Duration::from_secs(10),
|
|
big_timeout: Duration::from_secs(10),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn installe_puis_reconnait_a_jour() {
|
|
let srv = common::serve_files(release(7, 1, GO, RS, None));
|
|
let t = tempfile::tempdir().unwrap();
|
|
let c = cfg(srv.url(), t.path());
|
|
|
|
assert_eq!(update::run(&c), Outcome::Installed(7));
|
|
let dir = state::select_dir(t.path(), Path::new("/img"), 3, 1);
|
|
assert_eq!(dir, t.path().join("7"));
|
|
assert_eq!(std::fs::read(dir.join("loki")).unwrap(), GO);
|
|
assert_eq!(std::fs::read(dir.join("loki-rs")).unwrap(), RS);
|
|
assert!(!t.path().join(".tmp-download").exists());
|
|
|
|
assert_eq!(update::run(&c), Outcome::UpToDate(7));
|
|
}
|
|
|
|
#[test]
|
|
fn nouveau_build_remplace_et_nettoie_l_ancien() {
|
|
let t = tempfile::tempdir().unwrap();
|
|
let srv = common::serve_files(release(7, 1, GO, RS, None));
|
|
assert_eq!(
|
|
update::run(&cfg(srv.url(), t.path())),
|
|
Outcome::Installed(7)
|
|
);
|
|
let srv2 = common::serve_files(release(9, 1, b"go 9", b"rs 9", None));
|
|
assert_eq!(
|
|
update::run(&cfg(srv2.url(), t.path())),
|
|
Outcome::Installed(9)
|
|
);
|
|
assert!(!t.path().join("7").exists());
|
|
assert_eq!(
|
|
state::select_dir(t.path(), Path::new("/img"), 3, 1),
|
|
t.path().join("9")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn empreinte_fausse_ne_change_rien() {
|
|
let t = tempfile::tempdir().unwrap();
|
|
let srv = common::serve_files(release(7, 1, GO, RS, None));
|
|
assert_eq!(
|
|
update::run(&cfg(srv.url(), t.path())),
|
|
Outcome::Installed(7)
|
|
);
|
|
|
|
let bad = "0".repeat(64);
|
|
let srv2 = common::serve_files(release(9, 1, b"go 9", b"rs 9", Some(&bad)));
|
|
assert!(matches!(
|
|
update::run(&cfg(srv2.url(), t.path())),
|
|
Outcome::Failed(_)
|
|
));
|
|
assert_eq!(
|
|
state::select_dir(t.path(), Path::new("/img"), 3, 1),
|
|
t.path().join("7")
|
|
);
|
|
assert!(!t.path().join("9").exists());
|
|
assert!(!t.path().join(".tmp-download").exists());
|
|
}
|
|
|
|
#[test]
|
|
fn abi_differente_ne_telecharge_que_le_manifeste() {
|
|
let t = tempfile::tempdir().unwrap();
|
|
let srv = common::serve_files(release(7, 2, GO, RS, None));
|
|
assert_eq!(
|
|
update::run(&cfg(srv.url(), t.path())),
|
|
Outcome::AbiMismatch {
|
|
remote_abi: 2,
|
|
image_abi: 1
|
|
}
|
|
);
|
|
assert_eq!(srv.hits(), vec!["manifest.json".to_string()]);
|
|
}
|
|
|
|
#[test]
|
|
fn image_plus_recente_que_la_release() {
|
|
let t = tempfile::tempdir().unwrap();
|
|
let srv = common::serve_files(release(3, 1, GO, RS, None));
|
|
assert_eq!(update::run(&cfg(srv.url(), t.path())), Outcome::UpToDate(3));
|
|
}
|
|
|
|
#[test]
|
|
fn serveur_absent() {
|
|
let t = tempfile::tempdir().unwrap();
|
|
let mut c = cfg("http://127.0.0.1:9/rolling".into(), t.path());
|
|
c.small_timeout = Duration::from_secs(3);
|
|
assert!(matches!(update::run(&c), Outcome::Failed(_)));
|
|
}
|
|
|
|
#[test]
|
|
fn desactive_sans_requete() {
|
|
let t = tempfile::tempdir().unwrap();
|
|
let srv = common::serve_files(release(7, 1, GO, RS, None));
|
|
let mut c = cfg(srv.url(), t.path());
|
|
c.enabled = false;
|
|
assert_eq!(update::run(&c), Outcome::Disabled);
|
|
assert!(srv.hits().is_empty());
|
|
}
|