mirror of
https://github.com/GothenburgBitFactory/taskchampion-sync-server.git
synced 2025-06-26 10:54:29 +02:00
Allow specifying configuration params in env vars (#83)
This commit is contained in:
parent
5ffd179dcc
commit
7f51d2fa1f
6 changed files with 191 additions and 44 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -1585,6 +1585,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"taskchampion-sync-server-core",
|
"taskchampion-sync-server-core",
|
||||||
"taskchampion-sync-server-storage-sqlite",
|
"taskchampion-sync-server-storage-sqlite",
|
||||||
|
"temp-env",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
@ -1617,6 +1618,15 @@ dependencies = [
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "temp-env"
|
||||||
|
version = "0.3.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96374855068f47402c3121c6eed88d29cb1de8f3ab27090e273e420bdabcf050"
|
||||||
|
dependencies = [
|
||||||
|
"parking_lot",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.16.0"
|
version = "3.16.0"
|
||||||
|
|
|
@ -14,7 +14,7 @@ thiserror = "2.0"
|
||||||
futures = "^0.3.25"
|
futures = "^0.3.25"
|
||||||
serde_json = "^1.0"
|
serde_json = "^1.0"
|
||||||
serde = { version = "^1.0.147", features = ["derive"] }
|
serde = { version = "^1.0.147", features = ["derive"] }
|
||||||
clap = { version = "^4.5.6", features = ["string"] }
|
clap = { version = "^4.5.6", features = ["string", "env"] }
|
||||||
log = "^0.4.17"
|
log = "^0.4.17"
|
||||||
env_logger = "^0.11.5"
|
env_logger = "^0.11.5"
|
||||||
rusqlite = { version = "0.32", features = ["bundled"] }
|
rusqlite = { version = "0.32", features = ["bundled"] }
|
||||||
|
@ -22,3 +22,4 @@ chrono = { version = "^0.4.38", features = ["serde"] }
|
||||||
actix-rt = "2"
|
actix-rt = "2"
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
pretty_assertions = "1"
|
pretty_assertions = "1"
|
||||||
|
temp-env = "0.3"
|
||||||
|
|
12
README.md
12
README.md
|
@ -73,12 +73,18 @@ The server is configured with command-line options. See
|
||||||
|
|
||||||
The `--listen` option specifies the interface and port the server listens on.
|
The `--listen` option specifies the interface and port the server listens on.
|
||||||
It must contain an IP-Address or a DNS name and a port number. This option is
|
It must contain an IP-Address or a DNS name and a port number. This option is
|
||||||
mandatory, but can be repeated to specify multiple interfaces or ports.
|
mandatory, but can be repeated to specify multiple interfaces or ports. This
|
||||||
|
value can be specified in environment variable `LISTEN`, as a comma-separated
|
||||||
|
list of values.
|
||||||
|
|
||||||
The `--data-dir` option specifies where the server should store its data.
|
The `--data-dir` option specifies where the server should store its data. This
|
||||||
|
value can be specified in the environment variable `DATA_DIR`.
|
||||||
|
|
||||||
By default, the server allows all client IDs. To limit the accepted client IDs,
|
By default, the server allows all client IDs. To limit the accepted client IDs,
|
||||||
such as when running a personal server, use `--allow-client-id <client-id>`.
|
specify them in the environment variable `CLIENT_ID`, as a comma-separated list
|
||||||
|
of UUIDs. Client IDs can be specified with `--allow-client-id`, but this should
|
||||||
|
not be used on shared systems, as command line arguments are visible to all
|
||||||
|
users on the system.
|
||||||
|
|
||||||
The server only logs errors by default. To add additional logging output, set
|
The server only logs errors by default. To add additional logging output, set
|
||||||
environment variable `RUST_LOG` to `info` to get a log message for every
|
environment variable `RUST_LOG` to `info` to get a log message for every
|
||||||
|
|
|
@ -56,9 +56,10 @@ services:
|
||||||
volume:
|
volume:
|
||||||
nocopy: true
|
nocopy: true
|
||||||
subpath: tss
|
subpath: tss
|
||||||
command: --data-dir /tss/taskchampion-sync-server --listen 0.0.0.0:8080
|
|
||||||
environment:
|
environment:
|
||||||
- RUST_LOG=info
|
- "RUST_LOG=info"
|
||||||
|
- "DATA_DIR=/tss/taskchampion-sync-server"
|
||||||
|
- "LISTEN=0.0.0.0:8080"
|
||||||
depends_on:
|
depends_on:
|
||||||
mkdir:
|
mkdir:
|
||||||
condition: service_completed_successfully
|
condition: service_completed_successfully
|
||||||
|
|
|
@ -24,3 +24,4 @@ chrono.workspace = true
|
||||||
actix-rt.workspace = true
|
actix-rt.workspace = true
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
pretty_assertions.workspace = true
|
pretty_assertions.workspace = true
|
||||||
|
temp-env.workspace = true
|
||||||
|
|
|
@ -23,29 +23,36 @@ fn command() -> Command {
|
||||||
.arg(
|
.arg(
|
||||||
arg!(-l --listen <ADDRESS>)
|
arg!(-l --listen <ADDRESS>)
|
||||||
.help("Address and Port on which to listen on. Can be an IP Address or a DNS name followed by a colon and a port e.g. localhost:8080")
|
.help("Address and Port on which to listen on. Can be an IP Address or a DNS name followed by a colon and a port e.g. localhost:8080")
|
||||||
|
.value_delimiter(',')
|
||||||
.value_parser(ValueParser::string())
|
.value_parser(ValueParser::string())
|
||||||
|
.env("LISTEN")
|
||||||
.action(ArgAction::Append)
|
.action(ArgAction::Append)
|
||||||
.required(true),
|
.required(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
arg!(-d --"data-dir" <DIR> "Directory in which to store data")
|
arg!(-d --"data-dir" <DIR> "Directory in which to store data")
|
||||||
.value_parser(ValueParser::os_string())
|
.value_parser(ValueParser::os_string())
|
||||||
|
.env("DATA_DIR")
|
||||||
.default_value("/var/lib/taskchampion-sync-server"),
|
.default_value("/var/lib/taskchampion-sync-server"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
arg!(-C --"allow-client-id" <CLIENT_ID> "Client IDs to allow (can be repeated; if not specified, all clients are allowed)")
|
arg!(-C --"allow-client-id" <CLIENT_ID> "Client IDs to allow (can be repeated; if not specified, all clients are allowed)")
|
||||||
|
.value_delimiter(',')
|
||||||
.value_parser(value_parser!(Uuid))
|
.value_parser(value_parser!(Uuid))
|
||||||
|
.env("CLIENT_ID")
|
||||||
.action(ArgAction::Append)
|
.action(ArgAction::Append)
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
arg!(--"snapshot-versions" <NUM> "Target number of versions between snapshots")
|
arg!(--"snapshot-versions" <NUM> "Target number of versions between snapshots")
|
||||||
.value_parser(value_parser!(u32))
|
.value_parser(value_parser!(u32))
|
||||||
|
.env("SNAPSHOT_VERSIONS")
|
||||||
.default_value(default_snapshot_versions),
|
.default_value(default_snapshot_versions),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
arg!(--"snapshot-days" <NUM> "Target number of days between snapshots")
|
arg!(--"snapshot-days" <NUM> "Target number of days between snapshots")
|
||||||
.value_parser(value_parser!(i64))
|
.value_parser(value_parser!(i64))
|
||||||
|
.env("SNAPSHOT_DAYS")
|
||||||
.default_value(default_snapshot_days),
|
.default_value(default_snapshot_days),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -95,6 +102,7 @@ mod test {
|
||||||
use actix_web::{self, App};
|
use actix_web::{self, App};
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use taskchampion_sync_server_core::InMemoryStorage;
|
use taskchampion_sync_server_core::InMemoryStorage;
|
||||||
|
use temp_env::{with_var, with_var_unset, with_vars, with_vars_unset};
|
||||||
|
|
||||||
/// Get the list of allowed client IDs
|
/// Get the list of allowed client IDs
|
||||||
fn allowed(matches: &ArgMatches) -> Option<Vec<Uuid>> {
|
fn allowed(matches: &ArgMatches) -> Option<Vec<Uuid>> {
|
||||||
|
@ -103,14 +111,53 @@ mod test {
|
||||||
.map(|ids| ids.copied().collect::<Vec<_>>())
|
.map(|ids| ids.copied().collect::<Vec<_>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_listen_two() {
|
||||||
|
with_var_unset("LISTEN", || {
|
||||||
|
let matches = command().get_matches_from([
|
||||||
|
"tss",
|
||||||
|
"--listen",
|
||||||
|
"localhost:8080",
|
||||||
|
"--listen",
|
||||||
|
"otherhost:9090",
|
||||||
|
]);
|
||||||
|
assert_eq!(
|
||||||
|
matches
|
||||||
|
.get_many::<String>("listen")
|
||||||
|
.unwrap()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<String>>(),
|
||||||
|
vec!["localhost:8080".to_string(), "otherhost:9090".to_string()]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_listen_two_env() {
|
||||||
|
with_var("LISTEN", Some("localhost:8080,otherhost:9090"), || {
|
||||||
|
let matches = command().get_matches_from(["tss"]);
|
||||||
|
assert_eq!(
|
||||||
|
matches
|
||||||
|
.get_many::<String>("listen")
|
||||||
|
.unwrap()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<String>>(),
|
||||||
|
vec!["localhost:8080".to_string(), "otherhost:9090".to_string()]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_allowed_client_ids_none() {
|
fn command_allowed_client_ids_none() {
|
||||||
|
with_var_unset("CLIENT_ID", || {
|
||||||
let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]);
|
let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]);
|
||||||
assert_eq!(allowed(&matches), None);
|
assert_eq!(allowed(&matches), None);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_allowed_client_ids_one() {
|
fn command_allowed_client_ids_one() {
|
||||||
|
with_var_unset("CLIENT_ID", || {
|
||||||
let matches = command().get_matches_from([
|
let matches = command().get_matches_from([
|
||||||
"tss",
|
"tss",
|
||||||
"--listen",
|
"--listen",
|
||||||
|
@ -125,10 +172,30 @@ mod test {
|
||||||
)
|
)
|
||||||
.unwrap()])
|
.unwrap()])
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_allowed_client_ids_one_env() {
|
||||||
|
with_var(
|
||||||
|
"CLIENT_ID",
|
||||||
|
Some("711d5cf3-0cf0-4eb8-9eca-6f7f220638c0"),
|
||||||
|
|| {
|
||||||
|
let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]);
|
||||||
|
assert_eq!(
|
||||||
|
allowed(&matches),
|
||||||
|
Some(vec![Uuid::parse_str(
|
||||||
|
"711d5cf3-0cf0-4eb8-9eca-6f7f220638c0"
|
||||||
|
)
|
||||||
|
.unwrap()])
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_allowed_client_ids_two() {
|
fn command_allowed_client_ids_two() {
|
||||||
|
with_var_unset("CLIENT_ID", || {
|
||||||
let matches = command().get_matches_from([
|
let matches = command().get_matches_from([
|
||||||
"tss",
|
"tss",
|
||||||
"--listen",
|
"--listen",
|
||||||
|
@ -145,10 +212,30 @@ mod test {
|
||||||
Uuid::parse_str("bbaf4b61-344a-4a39-a19e-8caa0669b353").unwrap()
|
Uuid::parse_str("bbaf4b61-344a-4a39-a19e-8caa0669b353").unwrap()
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_allowed_client_ids_two_env() {
|
||||||
|
with_var(
|
||||||
|
"CLIENT_ID",
|
||||||
|
Some("711d5cf3-0cf0-4eb8-9eca-6f7f220638c0,bbaf4b61-344a-4a39-a19e-8caa0669b353"),
|
||||||
|
|| {
|
||||||
|
let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]);
|
||||||
|
assert_eq!(
|
||||||
|
allowed(&matches),
|
||||||
|
Some(vec![
|
||||||
|
Uuid::parse_str("711d5cf3-0cf0-4eb8-9eca-6f7f220638c0").unwrap(),
|
||||||
|
Uuid::parse_str("bbaf4b61-344a-4a39-a19e-8caa0669b353").unwrap()
|
||||||
|
])
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_data_dir() {
|
fn command_data_dir() {
|
||||||
|
with_var_unset("DATA_DIR", || {
|
||||||
let matches = command().get_matches_from([
|
let matches = command().get_matches_from([
|
||||||
"tss",
|
"tss",
|
||||||
"--data-dir",
|
"--data-dir",
|
||||||
|
@ -157,6 +244,47 @@ mod test {
|
||||||
"localhost:8080",
|
"localhost:8080",
|
||||||
]);
|
]);
|
||||||
assert_eq!(matches.get_one::<OsString>("data-dir").unwrap(), "/foo/bar");
|
assert_eq!(matches.get_one::<OsString>("data-dir").unwrap(), "/foo/bar");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_data_dir_env() {
|
||||||
|
with_var("DATA_DIR", Some("/foo/bar"), || {
|
||||||
|
let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]);
|
||||||
|
assert_eq!(matches.get_one::<OsString>("data-dir").unwrap(), "/foo/bar");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_snapshot() {
|
||||||
|
with_vars_unset(["SNAPSHOT_DAYS", "SNAPSHOT_VERSIONS"], || {
|
||||||
|
let matches = command().get_matches_from([
|
||||||
|
"tss",
|
||||||
|
"--listen",
|
||||||
|
"localhost:8080",
|
||||||
|
"--snapshot-days",
|
||||||
|
"13",
|
||||||
|
"--snapshot-versions",
|
||||||
|
"20",
|
||||||
|
]);
|
||||||
|
assert_eq!(*matches.get_one::<i64>("snapshot-days").unwrap(), 13i64);
|
||||||
|
assert_eq!(*matches.get_one::<u32>("snapshot-versions").unwrap(), 20u32);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn command_snapshot_env() {
|
||||||
|
with_vars(
|
||||||
|
[
|
||||||
|
("SNAPSHOT_DAYS", Some("13")),
|
||||||
|
("SNAPSHOT_VERSIONS", Some("20")),
|
||||||
|
],
|
||||||
|
|| {
|
||||||
|
let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]);
|
||||||
|
assert_eq!(*matches.get_one::<i64>("snapshot-days").unwrap(), 13i64);
|
||||||
|
assert_eq!(*matches.get_one::<u32>("snapshot-versions").unwrap(), 20u32);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue