Merge branch 'main' into krilltest

This commit is contained in:
Ximon Eighteen
2026-08-04 14:13:26 +02:00
91 changed files with 1595 additions and 1099 deletions
+3
View File
@@ -263,6 +263,9 @@ depends = "$auto, passwd, libssl3, adduser"
[package.metadata.deb.variants.ubuntu-noble]
depends = "$auto, passwd, libssl3"
[package.metadata.deb.variants.ubuntu-resolute]
depends = "$auto, passwd, libssl3"
# Cross compilation variants:
# Note: we have to specifiy dependencies manually because we don't run cargo-deb
# on the target platform and so it cannot determine the dependencies correctly
+18
View File
@@ -4,14 +4,32 @@
Breaking changes
* The `storage_uri` (aliased as `data_dir`) configuration file option is
now mandatory and will not default to `./data` or the content of an
environment variable any more. ([#1383])
New
* Support for Ubuntu Resolute Raccoon (26.04). ([#1378])
Improvements
* TLS keys are now stored with the mode set to 0600 on Unix systems.
([#1376])
Bug fixes
Other changes
* Upgraded the bundled Krill UI to [version 0.10.0][krill-ui 0.1.0].
This primarily adds a new ASPA UI. ([#1373])
[#1373]: https://github.com/NLnetLabs/krill/pull/1373
[#1376]: https://github.com/NLnetLabs/krill/pull/1376
[#1378]: https://github.com/NLnetLabs/krill/pull/1378
[#1383]: https://github.com/NLnetLabs/krill/pull/1383
[krill-ui 0.10.0]: https://github.com/NLnetLabs/krill-ui/releases/tag/v0.10.0
## 0.16.0 ‘Früher war mehr Lametta’
+1 -1
View File
@@ -52,7 +52,7 @@
# For backward compatibility 'data_dir' is accepted as an
# alternative to 'storage_uri'.
#
### storage_uri = "./data"
storage_uri = "file:///var/lib/krill/data"
# TLS Keys Dir
#
+1 -1
View File
@@ -22,7 +22,7 @@
# For backward compatibility 'data_dir' is accepted as an
# alternative to 'storage_uri'.
#
### storage_uri = "./data"
storage_uri = "file:///var/lib/krill/data"
# TLS Keys Dir
#
+5 -6
View File
@@ -136,13 +136,12 @@ krillc config
-------------
This subcommand is implemented on the CLI only and is intended to help
generate a configuration file which can be used for your Krill server.
manage the configuration file used for your Krill server.
We currently support two subcommands for this: ``krillc config simple`` and
``krillc config user``. The first can be used to generate general server
configuration. The second can be used to generate user (``id``) entries to
use if you want to have multiple local users access the Krill UI by their own
name and password.
The command ``krillc config user --id <userid>``, will prompt you for a
password, and generates a string that can be added to your krill.conf
file to enable local multi-user login as described in the
:ref:`multi-user config file provider documentation<_doc_krill_multi_user_config_file_provider>`.
.. _cmd_krillc_health:
+2 -1
View File
@@ -111,9 +111,10 @@ public rsyncd and HTTPS web server available.
.. group-tab:: Ubuntu
To install a Routinator package, you need the 64-bit version of one of
To install a Krill package, you need the 64-bit version of one of
these Ubuntu versions:
- Ubuntu Noble 26.04 (LTS)
- Ubuntu Noble 24.04 (LTS)
- Ubuntu Jammy 22.04 (LTS)
- Ubuntu Focal 20.04 (LTS)
@@ -370,8 +370,10 @@ steps must be taken:
configuration settings that Krill offers. For example to use the Amazon
Cognito logout endpoint you have to configure that manually.
.. tip:: The ``krill.conf`` file contains example configurations for
providers that Krill has been tested with.
.. tip:: The ``krill-multi-user.conf`` file contains example configurations for
providers that Krill has been tested with. If you installed krill using
a binary package, it can be found on github under the `defaults
directory <https://github.com/NLnetLabs/krill/tree/main/defaults>`_.
Using Keycloak
""""""""""""""
+1
View File
@@ -7,6 +7,7 @@ pkg:
image:
- "ubuntu:jammy" # ubuntu/22.04
- "ubuntu:noble" # ubuntu/24.04
- "ubuntu:resolute" # ubuntu/26.04
- "debian:bullseye" # debian/11
- "debian:bookworm" # debian/12
- "debian:trixie" # debian/13
+3 -7
View File
@@ -5,9 +5,9 @@ pkg:
- "krillup"
- "krillta"
image:
- "ubuntu:focal" # ubuntu/20.04
- "ubuntu:jammy" # ubuntu/22.04
- "ubuntu:noble" # ubuntu/24.04
- "ubuntu:resolute" # ubuntu/26.04
- "debian:bullseye" # debian/11
- "debian:bookworm" # debian/12
- "debian:trixie" # debian/13
@@ -48,11 +48,7 @@ include:
image: "debian:bullseye"
target: "armv7-unknown-linux-gnueabihf"
# Exclude upgrade testing on Ubuntu Noble as no prior released versions exist to upgrade from.
# Exclude upgrade testing on Ubuntu Resolute as no prior released versions exist to upgrade from.
exclude:
- image: "almalinux:9"
mode: "upgrade-from-published"
- image: "ubuntu:noble"
mode: "upgrade-from-published"
- image: "debian:trixie"
- image: "ubuntu:resolute"
mode: "upgrade-from-published"
+5 -4
View File
@@ -2231,7 +2231,7 @@ mod test {
use bytes::Bytes;
use rpki::crypto::PublicKeyFormat;
use crate::api::ta::TrustAnchorLocator;
use crate::commons::crypto::OpenSslSigner;
use crate::commons::crypto::{OpenSslSigner, OpenSslSignerConfig};
use crate::commons::test;
use super::*;
@@ -2255,9 +2255,10 @@ mod test {
#[test]
fn mft_uri() {
test::test_in_memory(|storage_uri| {
let signer =
OpenSslSigner::build(storage_uri, "dummy", None).unwrap();
test::test_in_memory(|storage| {
let signer = OpenSslSigner::build(
storage, &OpenSslSignerConfig::default(), "dummy", None
).unwrap();
let key_id = signer.create_key(PublicKeyFormat::Rsa).unwrap();
let pub_key = signer.get_key_info(&key_id).unwrap();
+7 -7
View File
@@ -223,7 +223,7 @@ impl fmt::Display for RoaPayload {
impl fmt::Debug for RoaPayload {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RoaPayload({})", &self)
write!(f, "RoaPayload({})", self)
}
}
@@ -558,8 +558,8 @@ impl From<BgpAnalysisSuggestion> for RoaConfigurationUpdates {
for announcement in suggestion.not_found
.into_iter()
.chain(suggestion.invalid_asn.into_iter())
.chain(suggestion.invalid_length.into_iter())
.chain(suggestion.invalid_asn)
.chain(suggestion.invalid_length)
{
added.push(RoaConfiguration {
payload: announcement.into(),
@@ -793,7 +793,7 @@ impl fmt::Display for TypedPrefix {
impl fmt::Debug for TypedPrefix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self)
write!(f, "{}", self)
}
}
@@ -906,7 +906,7 @@ impl fmt::Display for Ipv4Prefix {
impl fmt::Debug for Ipv4Prefix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self)
write!(f, "{}", self)
}
}
@@ -1011,7 +1011,7 @@ impl fmt::Display for Ipv6Prefix {
impl fmt::Debug for Ipv6Prefix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self)
write!(f, "{}", self)
}
}
@@ -1080,7 +1080,7 @@ impl fmt::Display for AsNumber {
impl fmt::Debug for AsNumber {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &self)
write!(f, "{}", self)
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ pub struct RtaContentRequest {
impl fmt::Display for RtaContentRequest {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "resources: {}", &self.resources)?;
writeln!(f, "resources: {}", self.resources)?;
writeln!(
f,
"validity, {}-{}",
+1 -1
View File
@@ -151,7 +151,7 @@ impl From<(&'static str, &'static str)> for ErrorResponse {
impl fmt::Display for ErrorResponse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", &serde_json::to_string(&self).unwrap())
write!(f, "{}", serde_json::to_string(&self).unwrap())
}
}
+8 -5
View File
@@ -5,8 +5,8 @@ use std::path::PathBuf;
use clap::Parser;
use log::info;
use log::LevelFilter;
use url::Url;
use krill::constants;
use krill::commons::storage::{StorageSystem, StorageUri};
use krill::config::{Config, LogType};
use krill::server::properties::PropertiesManager;
use krill::upgrades::{prepare_upgrade_data_migrations, UpgradeMode};
@@ -33,9 +33,9 @@ fn main() {
match options.command {
Command::Prepare(_prepare) => {
let storage = StorageSystem::new(config.storage_uri.clone());
let properties_manager = match PropertiesManager::create(
&config.storage_uri,
config.use_history_cache,
&storage, config.use_history_cache,
) {
Ok(mgr) => mgr,
Err(e) => {
@@ -57,6 +57,7 @@ fn main() {
match prepare_upgrade_data_migrations(
UpgradeMode::PrepareOnly,
&storage,
&config,
&properties_manager,
) {
@@ -93,7 +94,9 @@ fn main() {
}
}
Command::Migrate(cmd) => {
if let Err(e) = migrate(config, cmd.target) {
let storage = StorageSystem::new(cmd.target);
if let Err(e) = migrate(config, &storage) {
eprintln!("*** Error Migrating DATA ***");
eprintln!("{e}");
eprintln!();
@@ -153,6 +156,6 @@ pub struct Prepare;
pub struct Migrate {
/// The storage target as a URI string.
#[arg(short, long, value_name = "URI")]
pub target: Url,
pub target: StorageUri,
}
+4 -3
View File
@@ -15,7 +15,7 @@ use crate::commons::crypto::KrillSigner;
use crate::commons::actor::Actor;
use crate::commons::error::Error as KrillError;
use crate::commons::eventsourcing::{AggregateStore, AggregateStoreError};
use crate::commons::storage::Ident;
use crate::commons::storage::{Ident, StorageSystem};
use crate::commons::httpclient;
use crate::tasigner::{
Config, TrustAnchorProxySignerExchanges,
@@ -122,13 +122,14 @@ pub struct TrustAnchorSignerManager {
impl TrustAnchorSignerManager {
pub fn create(config: Config) -> Result<Self, SignerClientError> {
let storage = StorageSystem::new(config.storage_uri.clone());
let store = AggregateStore::create(
&config.storage_uri,
&storage,
const { Ident::make("signer") },
config.use_history_cache,
).map_err(SignerClientError::other)?;
let ta_handle = CaHandle::new("ta".into());
let signer = config.signer()?;
let signer = config.signer(&storage)?;
let actor = crate::constants::ACTOR_DEF_KRILLTA;
Ok(TrustAnchorSignerManager {
@@ -26,7 +26,6 @@ use rpki::{
Cert, Crl, Manifest, Roa,
},
};
use url::Url;
use crate::{
commons::{
@@ -40,6 +39,7 @@ use crate::{
CryptoResult, OpenSslSigner, SignSupport,
},
error::Error,
storage::StorageSystem,
KrillResult,
},
constants::ID_CERTIFICATE_VALIDITY_YEARS,
@@ -83,7 +83,7 @@ use crate::commons::crypto::{
type SignerBuilderFn = fn(
&SignerType,
SignerFlags,
&Url,
&StorageSystem,
&str,
std::time::Duration,
&Option<Arc<SignerMapper>>,
@@ -91,7 +91,7 @@ type SignerBuilderFn = fn(
#[derive(Debug)]
pub struct KrillSignerBuilder<'a> {
storage_uri: Url,
storage: &'a StorageSystem,
probe_interval: Duration,
signer_configs: &'a [SignerConfig],
default_signer: Option<&'a SignerConfig>,
@@ -100,12 +100,12 @@ pub struct KrillSignerBuilder<'a> {
impl<'a> KrillSignerBuilder<'a> {
pub fn new(
storage_uri: &Url,
storage: &'a StorageSystem,
probe_interval: Duration,
signer_configs: &'a [SignerConfig],
) -> Self {
Self {
storage_uri: storage_uri.clone(),
storage,
probe_interval,
signer_configs,
default_signer: None,
@@ -174,7 +174,7 @@ impl<'a> KrillSignerBuilder<'a> {
}
KrillSigner::build(
&self.storage_uri,
self.storage,
self.probe_interval,
self.signer_configs,
default_signer,
@@ -190,7 +190,7 @@ pub struct KrillSigner {
impl KrillSigner {
fn build(
storage_uri: &Url,
storage: &StorageSystem,
probe_interval: Duration,
signer_configs: &[SignerConfig],
default_signer: &SignerConfig,
@@ -199,10 +199,10 @@ impl KrillSigner {
#[cfg(not(feature = "hsm"))]
let signer_mapper = None;
#[cfg(feature = "hsm")]
let signer_mapper = Some(Arc::new(SignerMapper::build(storage_uri)?));
let signer_mapper = Some(Arc::new(SignerMapper::build(storage)?));
let signers = Self::build_signers(
signer_builder,
storage_uri,
storage,
probe_interval,
&signer_mapper,
signer_configs,
@@ -420,7 +420,7 @@ impl KrillSigner {
impl KrillSigner {
fn build_signers(
signer_builder: SignerBuilderFn,
storage_uri: &Url,
storage: &StorageSystem,
probe_interval: std::time::Duration,
mapper: &Option<Arc<SignerMapper>>,
configs: &[SignerConfig],
@@ -450,7 +450,7 @@ impl KrillSigner {
let signer = (signer_builder)(
&config.signer_type,
flags,
storage_uri,
storage,
&config.name,
probe_interval,
mapper,
@@ -466,7 +466,7 @@ impl KrillSigner {
fn signer_builder(
r#type: &SignerType,
flags: SignerFlags,
storage_uri: &Url,
storage: &StorageSystem,
name: &str,
#[cfg(feature = "hsm")] probe_interval: Duration,
#[cfg(not(feature = "hsm"))] _probe_interval: Duration,
@@ -474,10 +474,9 @@ fn signer_builder(
) -> KrillResult<SignerProvider> {
match r#type {
SignerType::OpenSsl(conf) => {
let storage_uri =
conf.keys_storage_uri.as_ref().unwrap_or(storage_uri);
let signer =
OpenSslSigner::build(storage_uri, name, mapper.clone())?;
let signer = OpenSslSigner::build(
storage, conf, name, mapper.clone()
)?;
Ok(SignerProvider::OpenSsl(flags, signer))
}
#[cfg(feature = "hsm")]
@@ -517,6 +516,7 @@ pub mod tests {
commons::crypto::signers::mocksigner::{
MockSigner, MockSignerCallCounts,
},
commons::storage::StorageSystem,
commons::test,
config::Config,
};
@@ -528,7 +528,7 @@ pub mod tests {
fn mock_signer_builder(
r#type: &SignerType,
flags: SignerFlags,
_storage_uri: &Url,
_storage: &StorageSystem,
name: &str,
_probe_interval: Duration,
mapper: &Option<Arc<SignerMapper>>,
@@ -549,14 +549,15 @@ pub mod tests {
fn config_fragment_to_config_object(
fragment: &str,
) -> Result<Config, toml::de::Error> {
let mut config_str = r#"admin_token = "***""#.to_string();
let mut config_str =
"admin_token = \"***\"\nstorage_uri = \"/tmp/krill\"".to_string();
config_str.push_str(fragment);
toml::from_str(&config_str)
}
fn build_krill_signer_from_config(
signers_config_fragment: &str,
storage_uri: &Url,
storage: &StorageSystem,
mapper: Arc<SignerMapper>,
) -> KrillResult<Vec<SignerProvider>> {
let mut config =
@@ -569,7 +570,7 @@ pub mod tests {
let probe_interval = std::time::Duration::from_secs(1);
KrillSigner::build_signers(
mock_signer_builder,
storage_uri,
storage,
probe_interval,
&mapper,
&config.signers,
@@ -612,10 +613,10 @@ pub mod tests {
/// it was before HSM support was added.
#[test]
pub fn no_signers_equals_one_openssl_signer_for_backward_compatibility() {
test::test_in_memory(|storage_uri| {
let mapper = Arc::new(SignerMapper::build(storage_uri).unwrap());
test::test_in_memory(|storage| {
let mapper = Arc::new(SignerMapper::build(storage).unwrap());
let signers =
build_krill_signer_from_config("", storage_uri, mapper)
build_krill_signer_from_config("", storage, mapper)
.unwrap();
assert_eq!(signers.len(), 1);
let signer = &signers[0];
@@ -627,8 +628,8 @@ pub mod tests {
#[test]
pub fn signer_name_is_respected() {
test::test_in_memory(|storage_uri| {
let mapper = Arc::new(SignerMapper::build(storage_uri).unwrap());
test::test_in_memory(|storage| {
let mapper = Arc::new(SignerMapper::build(storage).unwrap());
let signers_config_fragment = r#"
[[signers]]
type = "OpenSSL"
@@ -636,7 +637,7 @@ pub mod tests {
"#;
let signers = build_krill_signer_from_config(
signers_config_fragment,
storage_uri,
storage,
mapper,
)
.unwrap();
@@ -657,8 +658,8 @@ pub mod tests {
/// signer.
#[test]
pub fn single_openssl_signer_is_made_the_default_all_signer() {
test::test_in_memory(|storage_uri| {
let mapper = Arc::new(SignerMapper::build(storage_uri).unwrap());
test::test_in_memory(|storage| {
let mapper = Arc::new(SignerMapper::build(storage).unwrap());
let signers_config_fragment = r#"
[[signers]]
type = "OpenSSL"
@@ -666,7 +667,7 @@ pub mod tests {
"#;
let signers = build_krill_signer_from_config(
signers_config_fragment,
storage_uri,
storage,
mapper,
)
.unwrap();
@@ -679,8 +680,8 @@ pub mod tests {
#[test]
pub fn create_openssl_signer_for_one_off_signing() {
test::test_in_memory(|storage_uri| {
let mapper = Arc::new(SignerMapper::build(storage_uri).unwrap());
test::test_in_memory(|storage| {
let mapper = Arc::new(SignerMapper::build(storage).unwrap());
let signer_config_fragment = r#"
[[signers]]
@@ -690,7 +691,7 @@ pub mod tests {
"#;
let signers = build_krill_signer_from_config(
signer_config_fragment,
storage_uri,
storage,
mapper.clone(),
)
.unwrap();
@@ -715,7 +716,7 @@ pub mod tests {
"#;
let signers = build_krill_signer_from_config(
signer_config_fragment,
storage_uri,
storage,
mapper,
)
.unwrap();
@@ -733,8 +734,8 @@ pub mod tests {
#[test]
pub fn one_off_signer_is_respected() {
test::test_in_memory(|storage_uri| {
let mapper = Arc::new(SignerMapper::build(storage_uri).unwrap());
test::test_in_memory(|storage| {
let mapper = Arc::new(SignerMapper::build(storage).unwrap());
let signer_config_fragment = r#"
one_off_signer = "KMIP"
@@ -746,7 +747,7 @@ pub mod tests {
"#;
let signers = build_krill_signer_from_config(
signer_config_fragment,
storage_uri,
storage,
mapper.clone(),
)
.unwrap();
@@ -768,7 +769,7 @@ pub mod tests {
"#;
let signers = build_krill_signer_from_config(
signer_config_fragment,
storage_uri,
storage,
mapper,
)
.unwrap();
@@ -781,8 +782,8 @@ pub mod tests {
#[test]
pub fn default_signer_is_respected() {
test::test_in_memory(|storage_uri| {
let mapper = Arc::new(SignerMapper::build(storage_uri).unwrap());
test::test_in_memory(|storage| {
let mapper = Arc::new(SignerMapper::build(storage).unwrap());
let signer_config_fragment = r#"
default_signer = "Signer 2"
@@ -798,7 +799,7 @@ pub mod tests {
"#;
let signers = build_krill_signer_from_config(
signer_config_fragment,
storage_uri,
storage,
mapper,
)
.unwrap();
@@ -818,8 +819,8 @@ pub mod tests {
#[test]
pub fn default_signer_and_one_off_signer_are_respected() {
test::test_in_memory(|storage_uri| {
let mapper = Arc::new(SignerMapper::build(storage_uri).unwrap());
test::test_in_memory(|storage| {
let mapper = Arc::new(SignerMapper::build(storage).unwrap());
let signer_config_fragment = r#"
default_signer = "Signer 2"
@@ -836,7 +837,7 @@ pub mod tests {
"#;
let signers = build_krill_signer_from_config(
signer_config_fragment,
storage_uri,
storage,
mapper,
)
.unwrap();
@@ -856,8 +857,8 @@ pub mod tests {
#[test]
pub fn historic_signers_are_permitted() {
test::test_in_memory(|storage_uri| {
let mapper = Arc::new(SignerMapper::build(storage_uri).unwrap());
test::test_in_memory(|storage| {
let mapper = Arc::new(SignerMapper::build(storage).unwrap());
let signer_config_fragment = r#"
default_signer = "Signer 2"
@@ -880,7 +881,7 @@ pub mod tests {
"#;
let signers = build_krill_signer_from_config(
signer_config_fragment,
storage_uri,
storage,
mapper,
)
.unwrap();
@@ -8,7 +8,6 @@ use rpki::{
crypto::{KeyIdentifier, PublicKey},
};
use serde::{Deserialize, Serialize};
use url::Url;
use crate::{
commons::{
@@ -19,6 +18,7 @@ use crate::{
InitCommandDetails, InitEvent, SentCommand, SentInitCommand,
WithStorableDetails,
},
storage::StorageSystem,
KrillResult,
},
constants::{ACTOR_DEF_KRILL, SIGNERS_NS},
@@ -446,11 +446,9 @@ impl std::fmt::Debug for SignerMapper {
impl SignerMapper {
/// Build a SignerMapper that will read/write its data in a subdirectory
/// of the given work dir.
pub fn build(storage_uri: &Url) -> KrillResult<SignerMapper> {
pub fn build(storage: &StorageSystem) -> KrillResult<SignerMapper> {
let store = AggregateStore::<SignerInfo>::create(
storage_uri,
SIGNERS_NS,
true,
storage, SIGNERS_NS, true,
)?;
Ok(SignerMapper { store })
}
@@ -713,7 +713,7 @@ impl KmipSigner {
if !matches!(algorithm, PublicKeyFormat::Rsa) {
return Err(SignerError::KmipError(format!(
"Algorithm {:?} not supported while creating key",
&algorithm
algorithm
)));
}
@@ -924,7 +924,7 @@ impl KmipSigner {
if let Err(err) = &res {
warn!(
"[{}] Failed to destroy KMIP public key '{}': {}",
self.name, &kmip_key_pair_ids.public_key_id, err
self.name, kmip_key_pair_ids.public_key_id, err
);
}
@@ -942,7 +942,7 @@ impl KmipSigner {
deactivated = false;
warn!(
"[{}] Failed to revoke KMIP private key '{}': {}",
self.name, &kmip_key_pair_ids.private_key_id, err
self.name, kmip_key_pair_ids.private_key_id, err
);
}
@@ -966,7 +966,7 @@ impl KmipSigner {
if let Err(err) = &res3 {
warn!(
"[{}] Failed to destroy KMIP private key '{}': {}",
self.name, &kmip_key_pair_ids.private_key_id, err
self.name, kmip_key_pair_ids.private_key_id, err
);
}
@@ -938,8 +938,8 @@ impl Pkcs11Signer {
if !matches!(algorithm, PublicKeyFormat::Rsa) {
return Err(SignerError::Pkcs11Error(format!(
"Algorithm {:?} not supported while creating key",
&algorithm
)))?;
algorithm
)).into());
}
let mech = Mechanism::RsaPkcsKeyPairGen;
@@ -1135,7 +1135,7 @@ impl Pkcs11Signer {
1 => Ok(results[0]),
_ => Err(KeyError::Signer(SignerError::Pkcs11Error(format!(
"More than one {} found with id {}",
&human_key_class, cka_id_hex_str
human_key_class, cka_id_hex_str
)))),
}
}
@@ -19,7 +19,6 @@ use rpki::crypto::{
RpkiSignatureAlgorithm, Signature, SignatureAlgorithm, SigningError,
};
use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
use url::Url;
use crate::{
commons::{
@@ -27,21 +26,23 @@ use crate::{
dispatch::signerinfo::SignerMapper, signers::error::SignerError,
SignerHandle,
},
storage::{Ident, KeyValueStore},
storage::{
Ident, KeyValueStore, StorageSystem, StorageUri, OpenStoreError,
},
},
constants::KEYS_NS,
};
//------------ OpenSslSigner -------------------------------------------------
#[derive(Clone, Debug, Default, Deserialize, Hash, PartialEq, Eq)]
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
pub struct OpenSslSignerConfig {
#[serde(default)]
pub keys_storage_uri: Option<Url>,
pub keys_storage_uri: Option<StorageUri>,
}
impl OpenSslSignerConfig {
pub fn new(storage_uri: Url) -> Self {
pub fn new(storage_uri: StorageUri) -> Self {
Self {
keys_storage_uri: Some(storage_uri),
}
@@ -69,18 +70,19 @@ impl OpenSslSigner {
/// SignerMapper only knows about keys created by the OpenSslSigner if
/// the OpenSslSigner registers the new keys in the mapper.
pub fn build(
storage_uri: &Url,
storage: &StorageSystem,
conf: &OpenSslSignerConfig,
name: &str,
mapper: Option<Arc<SignerMapper>>,
) -> Result<Self, SignerError> {
let keys_store = Self::init_keys_store(storage_uri)?;
) -> Result<Self, OpenStoreError> {
let keys_store = Self::init_keys_store(storage, conf)?;
let s = OpenSslSigner {
name: name.to_string(),
info: Some(format!(
"OpenSSL Soft Signer [version: {}, keys store: {}]",
openssl::version::version(),
storage_uri,
storage.default_uri(),
)),
handle: RwLock::new(None), // will be set later
mapper,
@@ -137,11 +139,13 @@ impl OpenSslSigner {
impl OpenSslSigner {
fn init_keys_store(
storage_uri: &Url,
) -> Result<KeyValueStore, SignerError> {
let store = KeyValueStore::create(storage_uri, KEYS_NS)
.map_err(|_| SignerError::InvalidStorage(storage_uri.clone()))?;
Ok(store)
storage: &StorageSystem,
conf: &OpenSslSignerConfig,
) -> Result<KeyValueStore, OpenStoreError> {
match &conf.keys_storage_uri {
Some(uri) => storage.open_uri(uri, KEYS_NS),
None => storage.open(KEYS_NS)
}
}
fn build_key(&self) -> Result<KeyIdentifier, SignerError> {
@@ -385,10 +389,19 @@ pub mod tests {
use super::*;
fn build_signer(storage: &StorageSystem) -> OpenSslSigner {
OpenSslSigner::build(
storage,
&OpenSslSignerConfig::default(),
"dummy",
None
).unwrap()
}
#[test]
fn should_return_subject_public_key_info() {
test::test_in_memory(|storage_uri| {
let s = OpenSslSigner::build(storage_uri, "dummy", None).unwrap();
test::test_in_memory(|storage| {
let s = build_signer(storage);
let ki = s.create_key(PublicKeyFormat::Rsa).unwrap();
s.get_key_info(&ki).unwrap();
s.destroy_key(&ki).unwrap();
@@ -410,14 +423,13 @@ pub mod tests {
#[test]
fn import_existing_pkcs1_openssl_key() {
test::test_in_memory(|storage_uri| {
test::test_in_memory(|storage| {
// The following key was generated using OpenSSL on the command
// line
let pem = include_str!(
"../../../../../test-resources/ta/example-pkcs1.pem"
);
let signer =
OpenSslSigner::build(storage_uri, "dummy", None).unwrap();
let signer = build_signer(storage);
let ki = signer.import_key(pem).unwrap();
signer.get_key_info(&ki).unwrap();
@@ -427,14 +439,13 @@ pub mod tests {
#[test]
fn import_existing_pkcs8_openssl_key() {
test::test_in_memory(|storage_uri| {
test::test_in_memory(|storage| {
// The following key was generated using OpenSSL on the command
// line
let pem = include_str!(
"../../../../../test-resources/ta/example-pkcs8.pem"
);
let signer =
OpenSslSigner::build(storage_uri, "dummy", None).unwrap();
let signer = build_signer(storage);
let ki = signer.import_key(pem).unwrap();
signer.get_key_info(&ki).unwrap();
+1 -1
View File
@@ -163,7 +163,7 @@ impl Display for ApiAuthError {
| ApiAuthError::ApiAuthTransientError(err)
| ApiAuthError::ApiAuthSessionExpired(err)
| ApiAuthError::ApiInsufficientRights(err) => {
write!(f, "{}", &err)
write!(f, "{err}")
}
}
}
+9 -9
View File
@@ -12,12 +12,13 @@ use rpki::ca::idexchange::MyHandle;
use rpki::repository::x509::Time;
use serde::Serialize;
use serde::de::DeserializeOwned;
use url::Url;
use crate::api::history::{
CommandHistory, CommandHistoryCriteria, CommandHistoryRecord
};
use crate::commons::error::KrillIoError;
use crate::commons::storage::{Ident, KeyValueError, KeyValueStore};
use crate::commons::storage::{
Ident, KeyValueError, KeyValueStore, OpenStoreError, StorageSystem,
};
use super::agg::{Aggregate, Command, InitCommand, StoredCommand};
@@ -67,12 +68,12 @@ impl<A: Aggregate> AggregateStore<A> {
/// If `use_history_cache` is `true`, the new store will cache any
/// history cache record created for any instance.
pub fn create(
storage_uri: &Url,
storage: &StorageSystem,
namespace: &Ident,
use_history_cache: bool,
) -> Result<Self, AggregateStoreError> {
) -> Result<Self, OpenStoreError> {
Ok(Self::create_from_kv(
KeyValueStore::create(storage_uri, namespace)?, use_history_cache
storage.open(namespace)?, use_history_cache
))
}
@@ -81,13 +82,12 @@ impl<A: Aggregate> AggregateStore<A> {
/// If `use_history_cache` is `true`, the new store will cache any
/// history cache record created for any instance.
pub fn create_upgrade_store(
storage_uri: &Url,
storage: &StorageSystem,
namespace: &Ident,
use_history_cache: bool,
) -> Result<Self, AggregateStoreError> {
) -> Result<Self, OpenStoreError> {
Ok(Self::create_from_kv(
KeyValueStore::create_upgrade_store(storage_uri, namespace)?,
use_history_cache,
storage.open_upgrade(namespace)?, use_history_cache,
))
}
+6 -5
View File
@@ -10,8 +10,9 @@ use std::sync::{Arc, RwLock};
use log::{error, warn, trace};
use rpki::ca::idexchange::MyHandle;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::commons::storage::{Ident, KeyValueError, KeyValueStore};
use crate::commons::storage::{
Ident, KeyValueError, KeyValueStore, OpenStoreError, StorageSystem,
};
use super::store::Storable;
@@ -135,11 +136,11 @@ pub struct WalStore<T: WalSupport> {
impl<T: WalSupport> WalStore<T> {
/// Creates a new store using the given storage URL and namespace.
pub fn create(
storage_uri: &Url,
storage: &StorageSystem,
namespace: &Ident,
) -> Result<Self, WalStoreError> {
) -> Result<Self, OpenStoreError> {
Ok(WalStore {
kv: KeyValueStore::create(storage_uri, namespace)?,
kv: storage.open(namespace)?,
cache: RwLock::new(HashMap::new()),
})
}
+40 -2
View File
@@ -4,8 +4,10 @@
use std::{fmt, fs, io};
use std::borrow::Cow;
use std::fs::File;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
#[cfg(unix)]
use std::os::unix::fs::OpenOptionsExt;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use bytes::Bytes;
@@ -55,6 +57,19 @@ pub fn remove_dir_all(dir: &Path) -> Result<(), KrillIoError> {
/// Creates a new File or opens an exiting one. If the file did not exist, the
/// path will be created if it did not exist yet.
pub fn create_file_with_path(path: &Path) -> Result<File, KrillIoError> {
create_file(path, false)
}
/// Creates a new File or opens an exiting one. If the file did not exist, the
/// path will be created if it did not exist yet.
pub fn create_private_file_with_path(path: &Path) -> Result<File, KrillIoError> {
create_file(path, true)
}
/// Creates a file.
///
/// If `private` is `true`, will set the file mode to `0o600` on Unix.
fn create_file(path: &Path, private: bool) -> Result<File, KrillIoError> {
if
!path.exists()
&& let Some(parent) = path.parent()
@@ -70,7 +85,15 @@ pub fn create_file_with_path(path: &Path) -> Result<File, KrillIoError> {
)
})?;
}
File::create(path).map_err(|e| {
let mut options = OpenOptions::new();
options.create(true);
options.read(true);
options.write(true);
#[cfg(unix)]
if private {
options.mode(0o600);
}
options.open(path).map_err(|e| {
KrillIoError::new(
format!("Could not create file: {}", path.to_string_lossy()),
e,
@@ -99,6 +122,21 @@ pub fn save(content: &[u8], full_path: &Path) -> Result<(), KrillIoError> {
Ok(())
}
/// Saves a file, creating parent dirs as needed
pub fn save_private(content: &[u8], full_path: &Path) -> Result<(), KrillIoError> {
let mut f = create_private_file_with_path(full_path)?;
f.write_all(content).map_err(|e| {
KrillIoError::new(
format!("Could not write to: {}", full_path.to_string_lossy()),
e,
)
})?;
trace!("Saved file: {}", full_path.to_string_lossy());
Ok(())
}
/// Saves an object to json - unwraps any json errors!
pub fn save_json<O: Serialize>(
object: &O,
+30 -25
View File
@@ -2,9 +2,9 @@
use std::{cmp, error, fmt};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use url::Url;
use crate::commons::storage::{
Ident, KeyValueError, KeyValueStore, Transaction
Ident, KeyValueError, KeyValueStore, OpenStoreError, StorageSystem,
Transaction,
};
//------------ Configuration -------------------------------------------------
@@ -51,11 +51,11 @@ impl Queue {
impl Queue {
/// Creates a new queue.
pub fn create(
storage_uri: &Url,
storage: &StorageSystem,
namespace: &Ident,
) -> Result<Self, Error> {
) -> Result<Self, OpenStoreError> {
Ok(Queue {
store: KeyValueStore::create(storage_uri, namespace)?,
store: storage.open(namespace)?,
})
}
@@ -452,14 +452,14 @@ mod tests {
use std::thread;
use std::time::Duration;
use serde_json::Value;
use url::Url;
use super::*;
fn queue_store(ns: &str) -> Queue {
Queue::create(
&Url::parse("memory://").unwrap(),
Ident::from_str(ns).unwrap()
).unwrap()
fn storage_system() -> StorageSystem {
StorageSystem::new_memory(None)
}
fn queue_store(storage: &StorageSystem, ns: &str) -> Queue {
Queue::create(storage, Ident::from_str(ns).unwrap()).unwrap()
}
#[test]
@@ -479,12 +479,13 @@ mod tests {
#[test]
fn queue_thread_workers() {
let queue = queue_store("queue_thread_workers");
let storage = storage_system();
let queue = queue_store(&storage, "queue_thread_workers");
queue.store.wipe().unwrap();
thread::scope(|s| {
let create = s.spawn(|| {
let queue = queue_store("queue_thread_workers");
s.spawn(|| {
let queue = queue_store(&storage, "queue_thread_workers");
for i in 1..=10 {
let name = Ident::builder(
@@ -498,19 +499,20 @@ mod tests {
None,
ScheduleMode::FinishOrReplaceExisting,
).unwrap();
println!("> Scheduled job {}", &name);
println!("> Scheduled job {}", name);
}
});
create.join().unwrap();
});
let keys = queue.store.execute(None, |tran| {
tran.list_keys(Queue::pending_scope())
}).unwrap();
assert_eq!(keys.len(), 10);
let keys = queue.store.execute(None, |tran| {
tran.list_keys(Queue::pending_scope())
}).unwrap();
assert_eq!(keys.len(), 10);
thread::scope(|s| {
for _ in 1..=10 {
s.spawn(move || {
let queue = queue_store("queue_thread_workers");
s.spawn(|| {
let queue = queue_store(&storage, "queue_thread_workers");
while queue.pending_tasks_remaining().unwrap() > 0 {
if let Some((task_name, _))
@@ -535,7 +537,8 @@ mod tests {
#[test]
fn test_reschedule_long_running() {
let queue = queue_store("test_reschedule_long_running");
let storage = storage_system();
let queue = queue_store(&storage, "test_reschedule_long_running");
queue.store.wipe().unwrap();
let name = const { Ident::make("job") };
@@ -570,7 +573,8 @@ mod tests {
#[test]
fn test_reschedule_finished_task() {
let queue = queue_store("test_reschedule_finished_task");
let storage = storage_system();
let queue = queue_store(&storage, "test_reschedule_finished_task");
queue.store.wipe().unwrap();
let name = const { Ident::make("task") };
@@ -611,7 +615,8 @@ mod tests {
#[test]
fn test_schedule_with_existing_task() {
let queue = queue_store("test_schedule_with_existing_task");
let storage = storage_system();
let queue = queue_store(&storage, "test_reschedule_finished_task");
queue.store.wipe().unwrap();
let name = const { Ident::make("task") };
+191 -67
View File
@@ -1,6 +1,6 @@
//! Filesystem-based storage.
use std::{fmt, fs, io};
use std::{error, fmt, fs, io};
use std::borrow::Cow;
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
@@ -28,6 +28,98 @@ const LOCK_FILE_DIR: &str = ".locks";
pub const LOCK_FILE_NAME: &str = "lockfile.lock";
//------------ System --------------------------------------------------------
#[derive(Debug, Default)]
pub struct System(());
impl System {
pub fn location(&self, uri: &Uri) -> Result<Location, Error> {
Ok(Location { base: uri.path.clone() })
}
}
//------------ Location ------------------------------------------------------
#[derive(Debug)]
pub struct Location {
/// The base directory.
///
/// All the namespaces plus a few extra repositories are under this
/// directory.
base: PathBuf,
}
impl Location {
pub fn open(
&self, namespace: &Ident,
) -> Result<Store, Error> {
Store::new(&self.base, namespace)
}
pub fn is_empty(
&self, namespace: &Ident,
) -> Result<bool, Error> {
self.open(namespace)?.is_empty()
}
pub fn migrate(
&self, src_ns: &Ident, dst_ns: &Ident
) -> Result<(), Error> {
let src_store = self.open(src_ns)?;
let dst_root = self.base.join(dst_ns.as_str());
// Try removing the destination directory. If it isn’t there, that’s
// fine. Otherwise we error out.
if let Err(err) = fs::remove_dir(&dst_root)
&& err.kind() != io::ErrorKind::NotFound
{
return Err(Error::other(format!(
"target dir {} exists and cannot be removed ({})",
dst_root.display(), err
)));
}
// The source store must not have any lock files.
#[allow(clippy::collapsible_if)]
if src_store.locks.exists() {
if src_store.locks
.read_dir()
.map_err(|err| {
Error::io(
format!(
"cannot read directory '{}'",
src_store.locks.display(),
),
err
)
})?
.next()
.is_some()
{
return Err(Error::other(format!(
"store at '{}' has pending locks",
src_store.root.display(),
)));
}
}
fs::rename(&src_store.root, &dst_root).map_err(|err| {
Error::io(
format!(
"cannot rename dir from {} to {}",
src_store.root.display(),
dst_root.display(),
),
err
)
})?;
Ok(())
}
}
//------------ Store ---------------------------------------------------------
@@ -75,16 +167,9 @@ pub struct Store {
}
impl Store {
pub fn from_uri(
uri: &Url, namespace: &Ident,
) -> Result<Option<Self>, Error> {
if uri.scheme() != "local" {
return Ok(None)
}
let path = PathBuf::from(format!(
"{}{}", uri.host_str().unwrap_or_default(), uri.path()
));
fn new(
path: &Path, namespace: &Ident,
) -> Result<Self, Error> {
let root = path.join(namespace.as_str());
let tmp = path.join(TMP_FILE_DIR);
let mut locks = path.join(LOCK_FILE_DIR);
@@ -100,7 +185,7 @@ impl Store {
)
})?;
Ok(Some(Self { root, tmp, locks }))
Ok(Self { root, tmp, locks })
}
pub fn execute<F, T>(
@@ -109,9 +194,18 @@ impl Store {
where
F: for<'a> Fn(&mut SuperTransaction<'a>) -> Result<T, SuperError>
{
let mut file_lock = FileLock::create(self.scope_lock_path(scope))?;
let _write_lock = file_lock.write()?;
op(&mut SuperTransaction::from(self))
if scope.is_none() {
let mut file_lock = FileLock::create(self.scope_lock_path(scope))?;
let _write_lock = file_lock.write()?;
op(&mut SuperTransaction::from(self))
}
else {
let mut root_lock = FileLock::create(self.scope_lock_path(None))?;
let _root_lock = root_lock.read()?;
let mut file_lock = FileLock::create(self.scope_lock_path(scope))?;
let _write_lock = file_lock.write()?;
op(&mut SuperTransaction::from(self))
}
}
/// Returns the path for the given key.
@@ -263,8 +357,7 @@ impl Store {
));
}
};
if
file_type.is_file()
if file_type.is_file()
&& let Some(name) =
item.file_name().into_string().ok().and_then(|name| {
Ident::boxed_from_string(name).ok()
@@ -320,8 +413,7 @@ impl Store {
));
}
};
if
file_type.is_dir()
if file_type.is_dir()
&& let Some(name) =
item.file_name().into_string().ok().and_then(|name| {
Ident::boxed_from_string(name).ok()
@@ -500,54 +592,6 @@ impl Store {
Ok(())
}
pub fn migrate_namespace(
&mut self, namespace: &Ident,
) -> Result<(), Error> {
let root_parent = self.root.parent().ok_or_else(|| {
Error::other(
format!("cannot get parent dir for: {}", self.root.display())
)
})?;
let new_root = root_parent.join(namespace.as_str());
if new_root.exists() {
// If the target directory already exists, then it must be empty.
if new_root
.read_dir()
.map_err(|err| {
Error::io(
format!(
"cannot read directory '{}'",
new_root.display(),
),
err
)
})?
.next()
.is_some()
{
return Err(Error::other(format!(
"target dir {} already exists and is not empty",
new_root.display(),
)));
}
}
fs::rename(&self.root, &new_root).map_err(|err| {
Error::io(
format!(
"cannot rename dir from {} to {}",
self.root.display(),
new_root.display(),
),
err
)
})?;
self.root = new_root;
Ok(())
}
/// Creates the given directory if necessary.
fn create_dirs(path: Option<&Path>) -> Result<(), Error> {
if let Some(path) = path {
@@ -609,6 +653,12 @@ impl FileLock {
Ok(FileLock { lock: fd_lock::RwLock::new(lock_file) })
}
fn read(&mut self) -> Result<fd_lock::RwLockReadGuard<'_, File>, Error> {
self.lock
.read()
.map_err(|e| Error::other(format!("Cannot get file lock: {e}")))
}
fn write(&mut self) -> Result<fd_lock::RwLockWriteGuard<'_, File>, Error> {
self.lock
.write()
@@ -617,6 +667,50 @@ impl FileLock {
}
//------------ Uri -----------------------------------------------------------
#[derive(Clone, Debug, PartialEq)]
pub struct Uri {
path: PathBuf,
}
impl Uri {
pub fn new(path: PathBuf) -> Self {
Self { path }
}
pub fn parse_uri(uri: &Url) -> Result<Option<Uri>, UriError> {
if uri.scheme() != "file" && uri.scheme() != "local" {
return Ok(None)
}
if !uri.authority().is_empty() {
return Err(UriError::HasAuthority(uri.authority().into()))
}
Self::parse_str(uri.path()).map(Some)
}
pub fn parse_str(s: &str) -> Result<Uri, UriError> {
let path = PathBuf::from(s);
if !path.is_absolute() {
return Err(UriError::RelativePath(path))
}
Ok(Self { path })
}
pub fn path(&self) -> &Path {
&self.path
}
}
impl fmt::Display for Uri {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "file://{}", self.path.display())
}
}
//------------ Error ---------------------------------------------------------
#[derive(Debug)]
@@ -711,3 +805,33 @@ impl fmt::Display for Error {
}
}
impl error::Error for Error { }
//------------ UriError ------------------------------------------------------
#[derive(Debug)]
pub enum UriError {
HasAuthority(String),
MissingPath,
RelativePath(PathBuf),
}
impl fmt::Display for UriError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::HasAuthority(host) => {
write!(f, "non-local path with host '{host}'")
}
Self::MissingPath => {
write!(f, "missing path")
}
Self::RelativePath(path) => {
write!(f, "{} is not absolute.", path.display())
}
}
}
}
impl error::Error for UriError { }
+177 -113
View File
@@ -1,11 +1,10 @@
//! In-memory storage.
use std::{error, fmt, mem, thread};
use std::collections::{HashMap, HashSet};
use std::{error, fmt, mem};
use std::collections::HashMap;
use std::ops::DerefMut;
use std::sync::{Arc, Mutex, MutexGuard};
use std::time::Duration;
use lazy_static::lazy_static;
use std::str::FromStr;
use std::sync::{Arc, Mutex, MutexGuard, RwLock};
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use serde_json::Value;
@@ -17,6 +16,77 @@ use super::{
};
//------------ System --------------------------------------------------------
#[derive(Debug, Default)]
pub struct System {
locations: Mutex<HashMap<Option<u64>, Location>>,
}
impl System {
pub fn location(&self, uri: &Uri) -> Result<Location, Error> {
let mut locations = self.locations.lock().expect("poisoned lock");
Ok(locations.entry(uri.path).or_default().clone())
}
}
//------------ Location ------------------------------------------------------
#[derive(Clone, Debug, Default)]
pub struct Location {
namespaces: Arc<Mutex<HashMap<Box<Ident>, Arc<MemoryNamespace>>>>,
}
impl Location {
pub fn open(
&self, namespace: &Ident,
) -> Result<Store, Error> {
let mut namespaces = self.namespaces.lock().expect("poisoned lock");
Ok(Store::new(
namespaces.entry(namespace.into()).or_default().clone()
))
}
pub fn is_empty(
&self, namespace: &Ident,
) -> Result<bool, Error> {
let namespaces = self.namespaces.lock().expect("poisoned lock");
let Some(namespace) = namespaces.get(namespace) else {
return Ok(true)
};
Ok(namespace.scopes().is_empty())
}
pub fn migrate(
&self, src_ns: &Ident, dst_ns: &Ident
) -> Result<(), Error> {
let mut namespaces = self.namespaces.lock().expect("poisoned lock");
{
let Some(src) = namespaces.get(src_ns).cloned() else {
return Err(Error::MissingSourceNamespace(src_ns.into()))
};
src.try_clear_locks()?;
let dst = namespaces.entry(dst_ns.into()).or_default().clone();
dst.try_clear_locks()?;
let mut dst_scopes = dst.scopes();
if !dst_scopes.is_empty() {
return Err(Error::NonemptyTargetNamespace(dst_ns.into()))
}
mem::swap(dst_scopes.deref_mut(), src.scopes().deref_mut());
}
namespaces.remove(src_ns);
Ok(())
}
}
//------------ Store ---------------------------------------------------------
#[derive(Debug)]
@@ -25,23 +95,8 @@ pub struct Store {
}
impl Store {
pub fn wipe_all() {
MEMORY.wipe_all()
}
pub fn from_uri(
uri: &Url, namespace: &Ident,
) -> Result<Option<Self>, Error> {
if uri.scheme() != "memory" {
return Ok(None)
}
Ok(Some(Store {
namespace: MEMORY.get_namespace(
uri.host_str().unwrap_or_default().into(),
namespace.into()
)
}))
fn new(namespace: Arc<MemoryNamespace>) -> Self {
Store { namespace }
}
pub fn execute<F, T>(
@@ -50,25 +105,34 @@ impl Store {
where
F: for<'a> Fn(&mut SuperTransaction<'a>) -> Result<T, SuperError>
{
let wait = Duration::from_millis(10);
let tries = 1000;
for i in 0..tries {
if self.namespace.locks().insert(scope.map(Into::into)) {
// The scope was not yet present. We’ve won and can go on.
break
}
else if i >= tries {
return Err(Error::ScopeLocked(scope.map(Into::into)).into())
}
thread::sleep(wait);
match scope {
Some(scope) => self.execute_scoped(scope.into(), op),
None => self.execute_global(op),
}
}
let res = op(&mut SuperTransaction::from(self));
fn execute_global<F, T>(
&self, op: F
) -> Result<T, SuperError>
where
F: for<'a> Fn(&mut SuperTransaction<'a>) -> Result<T, SuperError>
{
let _lock = self.namespace.get_lock(None);
let _lock = _lock.write().expect("poisoned lock");
op(&mut SuperTransaction::from(self))
}
self.namespace.locks().remove(&scope.map(Into::into));
res
fn execute_scoped<F, T>(
&self, scope: Box<Ident>, op: F
) -> Result<T, SuperError>
where
F: for<'a> Fn(&mut SuperTransaction<'a>) -> Result<T, SuperError>
{
let _root_lock = self.namespace.get_lock(None);
let _root_lock = _root_lock.read().expect("poisoned lock");
let _lock = self.namespace.get_lock(Some(scope));
let _lock = _lock.write().expect("poisoned lock");
op(&mut SuperTransaction::from(self))
}
}
@@ -211,34 +275,6 @@ impl Store {
self.namespace.scopes().clear();
Ok(())
}
pub fn migrate_namespace(
&mut self, target: &Ident
) -> Result<(), Error> {
if !self.namespace.locks().is_empty() {
return Err(Error::PendingLocks);
}
let mut namespaces = MEMORY.namespaces.lock().expect("poisoned lock");
let new_key = (self.namespace.ns_key.0.clone(), target.into());
let new = namespaces.entry(new_key.clone()).or_insert_with(|| {
MemoryNamespace::new(new_key).into()
}).clone();
// Check that new is empty.
let mut new_values = new.scopes();
if !new_values.is_empty() {
return Err(Error::NonemptyTargetNamespace(target.into()))
}
// Swap out the values.
mem::swap(new_values.deref_mut(), self.namespace.scopes().deref_mut());
// Delete our namespace
namespaces.remove(&self.namespace.ns_key);
self.namespace = new.clone();
Ok(())
}
}
@@ -341,71 +377,77 @@ impl MemoryScopes {
//------------ MemoryNamespace -----------------------------------------------
#[derive(Debug)]
#[derive(Debug, Default)]
struct MemoryNamespace {
ns_key: NsKey,
scopes: Mutex<MemoryScopes>,
locks: Mutex<HashSet<Option<Box<Ident>>>>,
#[allow(clippy::type_complexity)]
locks: Mutex<HashMap<Option<Box<Ident>>, Arc<RwLock<()>>>>,
}
impl MemoryNamespace {
fn new(ns_key: NsKey) -> Self {
Self {
ns_key,
scopes: Default::default(),
locks: Default::default(),
}
}
fn scopes(&self) -> MutexGuard<'_, MemoryScopes> {
self.scopes.lock().expect("poisoned lock")
}
fn locks(&self) -> MutexGuard<'_, HashSet<Option<Box<Ident>>>> {
fn get_lock(&self, scope: Option<Box<Ident>>) -> Arc<RwLock<()>> {
self.locks().entry(scope).or_default().clone()
}
#[allow(clippy::type_complexity)]
fn locks(
&self
) -> MutexGuard<'_, HashMap<Option<Box<Ident>>, Arc<RwLock<()>>>> {
self.locks.lock().expect("poisoned lock")
}
}
fn try_clear_locks(&self) -> Result<(), Error> {
// Try to get a write lock on every present lock. If that succeeds,
// clear the hash map.
//------------ NsKey ---------------------------------------------------------
/// The key for a store.
///
/// The first component is the URI, the second the namespace within that URI.
type NsKey = (String, Box<Ident>);
//------------ Memory --------------------------------------------------------
/// The place where data is actually stored.
#[derive(Debug, Default)]
struct Memory {
namespaces: Mutex<HashMap<NsKey, Arc<MemoryNamespace>>>,
}
impl Memory {
fn wipe_all(&self) {
self.namespaces.lock().expect("poisoned lock").clear();
}
fn get_namespace(
&self,
prefix: String,
namespace: Box<Ident>,
) -> Arc<MemoryNamespace> {
let ns_key = (prefix, namespace);
let mut namespaces = self.namespaces.lock().expect("poisoned lock");
namespaces.entry(ns_key.clone()).or_insert_with(|| {
MemoryNamespace::new(ns_key).into()
}).clone()
let mut locks = self.locks();
for lock in locks.values() {
drop(lock.try_write().map_err(|_| Error::PendingLocks)?);
}
locks.clear();
Ok(())
}
}
//------------ MEMORY --------------------------------------------------------
//------------ Uri -----------------------------------------------------------
lazy_static! {
static ref MEMORY: Memory = Memory::default();
#[derive(Clone, Debug, PartialEq)]
pub struct Uri {
path: Option<u64>,
}
impl Uri {
pub fn new(seed: Option<u64>) -> Self {
Uri { path: seed }
}
pub fn parse_uri(uri: &Url) -> Result<Option<Uri>, UriError> {
if uri.scheme() != "memory" {
return Ok(None)
}
if uri.path().is_empty() {
return Ok(Some(Uri { path: None }))
}
if let Ok(path) = u64::from_str(uri.path()) {
return Ok(Some(Uri { path: Some(path) }))
}
Err(UriError::BadPath(uri.path().into()))
}
}
impl fmt::Display for Uri {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("memory:")?;
if let Some(path) = self.path {
write!(f, "{path}")?
}
Ok(())
}
}
@@ -430,6 +472,7 @@ pub enum Error {
},
NoScope(Box<Ident>),
TargetScopeExists(Box<Ident>),
MissingSourceNamespace(Box<Ident>),
NonemptyTargetNamespace(Box<Ident>),
PendingLocks,
}
@@ -511,6 +554,9 @@ impl fmt::Display for Error {
Error::TargetScopeExists(scope) => {
write!(f, "target scope '{scope}' exists")
}
Error::MissingSourceNamespace(ns) => {
write!(f, "missing source namespace '{ns}'")
}
Error::NonemptyTargetNamespace(ns) => {
write!(f, "non-empty target namespace '{ns}'")
}
@@ -523,3 +569,21 @@ impl fmt::Display for Error {
impl error::Error for Error { }
//------------ UriError ------------------------------------------------------
#[derive(Debug)]
pub enum UriError {
BadPath(String),
}
impl fmt::Display for UriError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::BadPath(path) => write!(f, "invalid memory path '{path}'"),
}
}
}
impl error::Error for UriError { }
+226 -29
View File
@@ -12,15 +12,117 @@ pub(super) mod memory; // Test code wants to access the Store directly.
//============ Backend Enum ==================================================
use std::fmt;
use std::{error, fmt};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use url::Url;
use super::Ident;
use super::{Ident, KeyValueError};
macro_rules! store {
( $( ( $variant:ident, $module:ident ) )* ) => {
//------------ BackendSystem -----------------------------------------
#[derive(Debug, Default)]
pub struct BackendSystem {
$(
$module: self::$module::System,
)*
}
impl BackendSystem {
fn location(
&self, uri: &StorageUri
) -> Result<Location, KeyValueError> {
match &uri.0 {
$(
UriInner::$variant(uri) => {
Ok(Location::$variant(
self.$module.location(uri).map_err(|err| {
KeyValueError::Inner(
Error(ErrorInner::$variant(err))
)
})?
))
}
)*
}
}
pub fn open(
&self, storage_uri: &StorageUri, namespace: &Ident,
) -> Result<Backend, KeyValueError> {
Ok(self.location(storage_uri)?.open(namespace)?)
}
pub fn is_empty(
&self, storage_uri: &StorageUri, namespace: &Ident,
) -> Result<bool, KeyValueError> {
Ok(self.location(storage_uri)?.is_empty(namespace)?)
}
pub fn migrate(
&self,
storage_uri: &StorageUri,
src_ns: &Ident,
dst_ns: &Ident
) -> Result<(), KeyValueError> {
Ok(self.location(storage_uri)?.migrate(src_ns, dst_ns)?)
}
}
//------------ Location ----------------------------------------------
#[derive(Debug)]
enum Location {
$(
$variant( self::$module::Location ),
)*
}
impl Location {
fn open(
&self, namespace: &Ident,
) -> Result<Backend, Error> {
match self {
$(
Self::$variant(inner) => {
Ok(Backend(StoreInner::$variant(
inner.open(namespace)?
)))
}
)*
}
}
fn is_empty(
&self, namespace: &Ident,
) -> Result<bool, Error> {
match self {
$(
Self::$variant(inner) => {
Ok(inner.is_empty(namespace)?)
}
)*
}
}
fn migrate(
&self, src_ns: &Ident, dst_ns: &Ident
) -> Result<(), Error> {
match self {
$(
Self::$variant(inner) => {
Ok(inner.migrate(src_ns, dst_ns)?)
}
)*
}
}
}
//------------ Backend -----------------------------------------------
@@ -35,21 +137,6 @@ macro_rules! store {
}
impl Backend {
pub fn new(
storage_uri: &Url, namespace: &Ident,
) -> Result<Option<Self>, Error> {
$(
if let Some(inner) =
self::$module::Store::from_uri(
storage_uri, namespace
)? {
return Ok(Some(Backend(StoreInner::$variant(inner))))
}
)*
Ok(None)
}
pub fn execute<F, T>(
&self, scope: Option<&Ident>, op: F
) -> Result<T, Error>
@@ -98,18 +185,6 @@ macro_rules! store {
)*
}
}
pub fn migrate_namespace(
&mut self, to: &Ident,
) -> Result<(), Error> {
match &mut self.0 {
$(
StoreInner::$variant(inner) => {
Ok(inner.migrate_namespace(to)?)
}
)*
}
}
}
@@ -295,6 +370,89 @@ macro_rules! store {
pub type Value = serde_json::Value;
//------------ StorageUri --------------------------------------------
#[derive(Clone, Debug, PartialEq)]
pub struct StorageUri(UriInner);
#[derive(Clone, Debug, PartialEq)]
enum UriInner {
$(
$variant(self::$module::Uri),
)*
}
impl StorageUri {
pub fn memory(seed: Option<u64>) -> Self {
Self(UriInner::Memory(self::memory::Uri::new(seed)))
}
pub fn disk(path: PathBuf) -> Self {
Self(UriInner::Disk(self::disk::Uri::new(path)))
}
pub fn data_dir(&self) -> Option<&Path> {
if let UriInner::Disk(inner) = &self.0 {
Some(inner.path())
}
else {
None
}
}
}
impl<'de> serde::Deserialize<'de> for StorageUri {
fn deserialize<D: serde::Deserializer<'de>>(
deserializer: D
) -> Result<Self, D::Error> {
Self::from_str(&String::deserialize(deserializer)?).map_err(
serde::de::Error::custom
)
}
}
impl FromStr for StorageUri {
type Err = ParseStorageUriError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match Url::parse(s) {
Ok(url) => {
$(
if let Some(res) =
self::$module::Uri::parse_uri(&url)?
{
return Ok(StorageUri(UriInner::$variant(res)))
}
)*
Err(ParseStorageUriError(
UriErrorInner::UnknownScheme(
url.scheme().into()
)
))
}
Err(_) => {
self::disk::Uri::parse_str(s).map(|disk| {
Self(UriInner::Disk(disk))
}).map_err(|err| {
ParseStorageUriError(UriErrorInner::Disk(err))
})
}
}
}
}
impl fmt::Display for StorageUri {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.0 {
$(
UriInner::$variant(inner) => inner.fmt(f),
)*
}
}
}
//------------ Error -------------------------------------------------
#[derive(Debug)]
@@ -324,6 +482,45 @@ macro_rules! store {
}
}
}
impl error::Error for Error { }
//------------ ParseStorageUriError ----------------------------------
#[derive(Debug)]
pub struct ParseStorageUriError(UriErrorInner);
#[derive(Debug)]
enum UriErrorInner {
UnknownScheme(String),
$(
$variant(self::$module::UriError),
)*
}
$(
impl From<self::$module::UriError> for ParseStorageUriError {
fn from(src: self::$module::UriError) -> Self {
Self(UriErrorInner::$variant(src))
}
}
)*
impl fmt::Display for ParseStorageUriError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.0 {
UriErrorInner::UnknownScheme(scheme) => {
write!(f, "unknown scheme '{scheme}'")
}
$(
UriErrorInner::$variant(err) => err.fmt(f),
)*
}
}
}
impl error::Error for ParseStorageUriError { }
}
}
+8 -2
View File
@@ -1,8 +1,14 @@
//! Persistent storage of data.
pub use self::backends::{Backend, Transaction, Error};
pub use self::backends::{
StorageUri, ParseStorageUriError, Transaction, Error,
};
pub use self::ident::{Ident, IdentBuilder, IdentError};
pub use self::store::{KeyValueStore, KeyValueError};
pub use self::store::{
KeyValueStore, KeyValueError, OpenStoreError, StorageSystem,
};
use self::backends::{Backend, BackendSystem};
mod backends;
mod ident;
+176 -69
View File
@@ -1,12 +1,152 @@
//! The publicly exposed key-value store.
use std::fmt;
use std::{error, fmt};
use std::path::PathBuf;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use url::Url;
use crate::commons::storage;
use crate::commons::storage::{Backend, Ident, Transaction};
use crate::commons::error::Error;
use crate::commons::storage::{
Backend, BackendSystem, Ident, StorageUri, Transaction
};
//------------ StorageSystem -------------------------------------------------
/// The system that provides the key-value stores.
#[derive(Debug)]
pub struct StorageSystem {
/// The storage URI to use by default.
default_uri: StorageUri,
/// The storage systems of the various supported backends.
backend: BackendSystem,
}
impl StorageSystem {
/// Creates a new storage system.
///
/// The provided URI will be used as the default storage URI.
pub fn new(
default_uri: StorageUri
) -> Self {
Self {
default_uri,
backend: Default::default(),
}
}
/// Creates a new memory storage system using the given seed.
///
/// This is primarily used for testing.
pub fn new_memory(seed: Option<u64>) -> Self {
Self::new(StorageUri::memory(seed))
}
/// Creates a new disk storage system using the given path.
pub fn new_disk(path: PathBuf) -> Self {
Self::new(StorageUri::disk(path))
}
/// Opens the default store with the given namespace.
pub fn open(
&self, namespace: &Ident
) -> Result<KeyValueStore, OpenStoreError> {
self.open_uri(&self.default_uri, namespace)
}
/// Opens a store for upgrades for the given namespace.
///
/// Prefixes the namespace with `"upgrade_"`.
pub fn open_upgrade(
&self, namespace: &Ident
) -> Result<KeyValueStore, OpenStoreError> {
self.open_uri(
&self.default_uri,
&KeyValueStore::prefixed_namespace(
namespace, const { Ident::make("upgrade") }
)
)
}
/// Opens a store with the given storage URI and namespace.
pub fn open_uri(
&self, storage_uri: &StorageUri, namespace: &Ident
) -> Result<KeyValueStore, OpenStoreError> {
Ok(KeyValueStore {
inner: self.backend.open(
storage_uri, namespace
).map_err(|err| {
OpenStoreError(err)
})?
})
}
/// Returns the default URI of the storage system.
pub fn default_uri(&self) -> &StorageUri {
&self.default_uri
}
/// Checks whether the given namespace is empty.
pub fn is_empty(&self, namespace: &Ident) -> Result<bool, KeyValueError> {
self.backend.is_empty(&self.default_uri, namespace)
}
/// Checks whether the upgrade store for the given namespace is empty.
pub fn is_upgrade_empty(
&self, namespace: &Ident
) -> Result<bool, KeyValueError> {
self.is_empty(
&KeyValueStore::prefixed_namespace(
namespace, const { Ident::make("upgrade") }
)
)
}
/// Archives the given namespace.
///
/// The namespace is moved to a namespace prefixed with `"archive"`. If
/// such a namespace already exists, it is removed.
pub fn migrate_to_archive(
&self, namespace: &Ident
) -> Result<(), KeyValueError> {
let archive_ns = KeyValueStore::prefixed_namespace(
namespace, const { Ident::make("archive") }
);
// Wipe any existing archive, before archiving this store.
// We don't want to keep too much old data. See issue: #1088.
self.open(&archive_ns)?.wipe()?;
self.backend.migrate(
&self.default_uri, namespace, &archive_ns
)?;
Ok(())
}
/// Migrates an upgrade namespace to the normal namespace.
///
/// This moves the namespace prefixed by `"upgrade"` to the namespace.
/// Fails if the given namespace is not empty.
pub fn migrate_to_current(
&self, namespace: &Ident
) -> Result<(), KeyValueError> {
if !self.is_empty(namespace)? {
return Err(KeyValueError::Other(format!(
"Abort migrate upgraded store for {namespace} to current. \
The current store was not archived."
)))
}
let upgrade_ns = KeyValueStore::prefixed_namespace(
namespace, const { Ident::make("upgrade") }
);
self.backend.migrate(
&self.default_uri, &upgrade_ns, namespace
)?;
Ok(())
}
}
//------------ KeyValueStore -------------------------------------------------
@@ -27,18 +167,6 @@ pub struct KeyValueStore {
}
impl KeyValueStore {
/// Creates a new store.
pub fn create(
storage_uri: &Url,
namespace: &Ident,
) -> Result<Self, KeyValueError> {
Ok(Self {
inner: Backend::new(storage_uri, namespace)?.ok_or_else(|| {
KeyValueError::UnknownScheme(storage_uri.scheme().into())
})?
})
}
/// Returns whether the store has no entries.
pub fn is_empty(&self) -> Result<bool, KeyValueError> {
// NOTE: this is not done using `self.execute` as this would result
@@ -171,21 +299,6 @@ impl KeyValueStore {
// # Migration Support
impl KeyValueStore {
/// Creates a new KeyValueStore for upgrades.
///
/// Adds the implicit prefix "upgrade_" to the given namespace.
pub fn create_upgrade_store(
storage_uri: &Url,
namespace: &Ident,
) -> Result<Self, KeyValueError> {
Self::create(
storage_uri,
&Self::prefixed_namespace(
namespace, const { Ident::make("upgrade") }
)
)
}
fn prefixed_namespace(
namespace: &Ident,
prefix: &Ident,
@@ -197,44 +310,6 @@ impl KeyValueStore {
).finish()
}
/// Archive this store (i.e. for this namespace). Deletes
/// any existing archive for this namespace if present.
pub fn migrate_to_archive(
&mut self,
storage_uri: &Url,
namespace: &Ident,
) -> Result<(), KeyValueError> {
let archive_ns = Self::prefixed_namespace(
namespace, const { Ident::make("archive") }
);
// Wipe any existing archive, before archiving this store.
// We don't want to keep too much old data. See issue: #1088.
KeyValueStore::create(storage_uri, &archive_ns)?.wipe()?;
self.inner.migrate_namespace(&archive_ns)?;
Ok(())
}
/// Make this (upgrade) store the current store.
///
/// Fails if there is a non-empty current store.
pub fn migrate_to_current(
&mut self,
storage_uri: &Url,
namespace: &Ident,
) -> Result<(), KeyValueError> {
let current_store = KeyValueStore::create(storage_uri, namespace)?;
if !current_store.is_empty()? {
Err(KeyValueError::Other(format!(
"Abort migrate upgraded store for {namespace} to current. The current store was not archived."
)))
} else {
self.inner
.migrate_namespace(namespace)
.map_err(KeyValueError::Inner)
}
}
/// Import all data from the given KV store into this
///
/// The closure `keep` is given each scope and decides whether it should
@@ -269,6 +344,32 @@ impl KeyValueStore {
}
//============ Error Types ===================================================
//
// These need cleaning up.
//------------ OpenStoreError ------------------------------------------------
/// An error occured while opening a store.
#[derive(Debug)]
pub struct OpenStoreError(KeyValueError);
impl fmt::Display for OpenStoreError{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
}
}
impl error::Error for OpenStoreError { }
impl From<OpenStoreError> for Error {
fn from(src: OpenStoreError) -> Error {
Error::custom(format_args!("{}", src))
}
}
//------------ KeyValueError -------------------------------------------------
/// This type defines possible Errors for KeyStore
@@ -292,6 +393,12 @@ impl From<storage::Error> for KeyValueError {
}
}
impl From<OpenStoreError> for KeyValueError {
fn from(src: OpenStoreError) -> Self {
src.0
}
}
impl fmt::Display for KeyValueError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
+19 -48
View File
@@ -4,11 +4,8 @@
//! requires a wee bit of macro magic.
#![cfg(test)]
use std::sync::{Mutex, MutexGuard};
use lazy_static::lazy_static;
use tempfile::{TempDir, tempdir};
use url::Url;
use super::{Ident, KeyValueStore};
use super::{Ident, KeyValueStore, StorageSystem, StorageUri};
//------------ Macro to Construct Tests --------------------------------------
@@ -73,7 +70,7 @@ const CONTENT_4: u32 = 45;
// All the test functions.
//
// The all need to have the same signature taking one argument as an
// They all need to have the same signature taking one argument as an
// `impl Harness` and return unit. Each function will be transformed into a
// test function for each of the backends (currently memory and disk). The
// harness will give it access to a temporary test store atop that given
@@ -130,12 +127,9 @@ testfns! {
fn drop_global_key(harness: impl Harness) {
let store = harness.store(NAMESPACE);
assert!(store.drop_key(None, KEY).is_err());
store.store(None, KEY, &CONTENT).unwrap();
assert!(store.has(None, KEY).unwrap());
store.drop_key(None, KEY).unwrap();
assert!(!store.has(None, KEY).unwrap());
}
@@ -301,7 +295,7 @@ testfns! {
trait Harness {
/// Returns the URL of the backend.
#[allow(dead_code)]
fn url(&self) -> Url;
fn uri(&self) -> &StorageUri;
/// Creates a new store for the given namespace.
fn store(&self, namespace: &Ident) -> KeyValueStore;
@@ -311,48 +305,25 @@ trait Harness {
//------------ MemoryHarness -------------------------------------------------
/// The test harness for the memory backend.
///
/// Because there is only a single shared memory store for the whole process,
/// we can only run a single test using it at the same time and need to wipe
/// it clean before the test. This is why there are a lock and a guard here.
struct MemoryHarness<'a> {
_guard: MutexGuard<'a, ()>,
struct MemoryHarness {
storage: StorageSystem,
}
lazy_static! {
static ref MEMORY_LOCK: Mutex<()> = Mutex::new(());
}
impl<'a> MemoryHarness<'a> {
impl MemoryHarness {
fn new() -> Self {
loop {
let _guard = match MEMORY_LOCK.lock() {
Ok(guard) => guard,
Err(_) => {
// If a thread panicked, the lock gets poisoned. But we
// know that a panicked thread (and its test) has ended,
// so we can clear the poison and try to acquire the
// lock again.
MEMORY_LOCK.clear_poison();
continue;
}
};
super::backends::memory::Store::wipe_all();
return Self { _guard }
Self {
storage: StorageSystem::new_memory(None)
}
}
}
impl<'a> Harness for MemoryHarness<'a> {
fn url(&self) -> Url {
Url::parse("memory:").unwrap()
impl Harness for MemoryHarness {
fn uri(&self) -> &StorageUri {
self.storage.default_uri()
}
fn store(&self, namespace: &Ident) -> KeyValueStore {
KeyValueStore::create(
&Url::parse("memory:").unwrap(),
namespace,
).unwrap()
self.storage.open(namespace).unwrap()
}
}
@@ -365,25 +336,25 @@ impl<'a> Harness for MemoryHarness<'a> {
/// removed automatically when the harness is dropped.
struct DiskHarness {
_dir: TempDir,
url: Url,
storage: StorageSystem,
}
impl DiskHarness {
fn new() -> Self {
let _dir = tempdir().unwrap();
let url = format!("local://{}", _dir.path().display());
let url = Url::parse(&url).unwrap();
Self { _dir, url }
let storage = StorageSystem::new_disk(_dir.path().into());
Self { _dir, storage }
}
}
impl Harness for DiskHarness {
fn url(&self) -> Url {
self.url.clone()
fn uri(&self) -> &StorageUri {
self.storage.default_uri()
}
fn store(&self, namespace: &Ident) -> KeyValueStore {
KeyValueStore::create(&self.url, namespace).unwrap()
self.storage.open(namespace).unwrap()
}
}
+6 -15
View File
@@ -6,19 +6,19 @@ use std::str::FromStr;
use bytes::Bytes;
use rpki::uri;
use rpki::ca::idcert::IdCert;
use url::Url;
use crate::api::roa::{ConfiguredRoa, RoaConfiguration, RoaPayload};
use crate::commons::storage::StorageSystem;
/// This method returns an in-memory Key-Value store and then runs the test
/// provided in the closure using it
pub fn test_in_memory<F>(op: F)
where
F: FnOnce(&Url),
F: FnOnce(&StorageSystem),
{
let storage_uri = mem_storage();
let storage = mem_storage();
op(&storage_uri);
op(&storage);
}
/// This method sets up a test directory with a random name (a number)
@@ -35,17 +35,8 @@ where
op(dir.path().into());
}
fn random_hex_string() -> String {
let mut bytes = [0; 8];
openssl::rand::rand_bytes(&mut bytes).unwrap();
hex::encode(bytes)
}
pub fn mem_storage() -> Url {
let mut bytes = [0; 8];
openssl::rand::rand_bytes(&mut bytes).unwrap();
Url::parse(&format!("memory://{}", random_hex_string())).unwrap()
pub fn mem_storage() -> StorageSystem {
StorageSystem::new_memory(Some(rand::random()))
}
pub fn rsync(s: &str) -> uri::Rsync {
+33 -79
View File
@@ -18,7 +18,6 @@ use rpki::{
};
use serde::de;
use serde::{Deserialize, Deserializer, Serialize};
use url::Url;
#[cfg(unix)]
use std::collections::HashMap;
@@ -30,9 +29,8 @@ use crate::{
commons::{
ext_serde,
crypto::{OpenSslSignerConfig, SignSupport},
error::{Error, KrillIoError},
storage::{Ident, KeyValueStore},
KrillResult,
error::KrillIoError,
storage::StorageUri,
},
constants::*,
daemon::{
@@ -91,13 +89,6 @@ impl ConfigDefaults {
users
}
pub fn storage_uri() -> Url {
env::var(KRILL_ENV_STORAGE_URI)
.ok()
.and_then(|s| Url::parse(&s).ok())
.unwrap_or_else(|| Url::parse("local://./data").unwrap())
}
pub fn log_level() -> LevelFilter {
match env::var(KRILL_ENV_LOG_LEVEL) {
Ok(level) => match LevelFilter::from_str(&level) {
@@ -473,21 +464,6 @@ where
).map(|oom| oom.into())
}
pub fn deserialize_storage_uri<'de, D>(
deserializer: D,
) -> Result<Url, D::Error>
where
D: Deserializer<'de>,
{
let url = String::deserialize(deserializer)?;
match Url::parse(&url) {
Ok(url) => Ok(url),
Err(_) => {
Url::parse(&format!("local://{url}/")).map_err(de::Error::custom)
}
}
}
fn deserialize_minutes_duration<'de, D: Deserializer<'de>>(
deserializer: D
) -> Result<Duration, D::Error> {
@@ -530,10 +506,8 @@ pub struct Config {
// Deserialize this field from data_dir or storage_uri
#[serde(
alias = "data_dir",
default = "ConfigDefaults::storage_uri",
deserialize_with = "deserialize_storage_uri"
)]
pub storage_uri: Url,
pub storage_uri: StorageUri,
#[serde(default = "ConfigDefaults::dflt_true")]
pub use_history_cache: bool,
@@ -948,36 +922,10 @@ pub struct Benchmark {
/// # Accessors
impl Config {
/// General purpose KV store, can be used to track server settings
/// etc not specific to any Aggregate or WalSupport type
pub fn general_key_value_store(&self) -> KrillResult<KeyValueStore> {
KeyValueStore::create(&self.storage_uri, PROPERTIES_NS)
.map_err(Error::KeyValueError)
}
pub fn key_value_store(
&self,
namespace: &Ident,
) -> KrillResult<KeyValueStore> {
KeyValueStore::create(&self.storage_uri, namespace)
.map_err(Error::KeyValueError)
}
/// Returns the data directory if disk was used for storage.
/// This will always be true for upgrades of pre 0.14.0 versions
fn data_dir(&self) -> Option<PathBuf> {
if self.storage_uri.scheme() != "local" {
None
} else {
Some(
Path::new(&format!(
"{}{}",
self.storage_uri.host_str().unwrap_or(""),
self.storage_uri.path()
))
.to_path_buf(),
)
}
fn data_dir(&self) -> Option<&Path> {
self.storage_uri.data_dir()
}
pub fn tls_keys_dir(&self) -> &PathBuf {
@@ -1156,7 +1104,7 @@ impl Config {
impl Config {
#[cfg(test)]
fn test_config(
storage_uri: &Url,
storage_uri: &StorageUri,
data_dir: Option<&Path>,
enable_testbed: bool,
enable_ca_refresh: bool,
@@ -1347,7 +1295,7 @@ impl Config {
#[cfg(test)]
pub fn test(
test_storage: &Url,
test_storage: &StorageUri,
test_dir: Option<&Path>,
enable_testbed: bool,
enable_ca_refresh: bool,
@@ -1367,7 +1315,9 @@ impl Config {
}
#[cfg(test)]
pub fn pubd_test(storage_uri: &Url, data_dir: Option<&Path>) -> Self {
pub fn pubd_test(
storage_uri: &StorageUri, data_dir: Option<&Path>
) -> Self {
let mut config = Self::test_config(
storage_uri,
data_dir,
@@ -1439,29 +1389,26 @@ impl Config {
}
if self.tls_keys_dir.is_none() {
if let Some(mut data_dir) = self.data_dir() {
data_dir.push(HTTPS_SUB_DIR);
self.tls_keys_dir = Some(data_dir);
if let Some(data_dir) = self.data_dir() {
self.tls_keys_dir = Some(data_dir.join(HTTPS_SUB_DIR));
} else {
return Err(ConfigError::other("'tls_keys_dir' is not configured, but 'storage_uri' is not a local directory, please configure an 'tls_keys_dir'"));
return Err(ConfigError::other("'tls_keys_dir' is not configured, but 'storage_uri' is not a local directory, please configure a 'tls_keys_dir'"));
}
}
if self.repo_dir.is_none() {
if let Some(mut data_dir) = self.data_dir() {
data_dir.push(REPOSITORY_DIR);
self.repo_dir = Some(data_dir);
if let Some(data_dir) = self.data_dir() {
self.repo_dir = Some(data_dir.join(REPOSITORY_DIR));
} else {
return Err(ConfigError::other("'repo_dir' is not configured, but 'storage_uri' is not a local directory, please configure an 'repo_dir'"));
return Err(ConfigError::other("'repo_dir' is not configured, but 'storage_uri' is not a local directory, please configure a 'repo_dir'"));
}
}
if self.pid_file.is_none() {
if let Some(mut data_dir) = self.data_dir() {
data_dir.push("krill.pid");
self.pid_file = Some(data_dir);
if let Some(data_dir) = self.data_dir() {
self.pid_file = Some(data_dir.join("krill.pid"));
} else {
return Err(ConfigError::other("'pid_file' is not configured, but 'storage_uri' is not a local directory, please configure an 'pid_file'"));
return Err(ConfigError::other("'pid_file' is not configured, but 'storage_uri' is not a local directory, please configure a 'pid_file'"));
}
}
@@ -2183,7 +2130,10 @@ mod tests {
use log::Level as LL;
fn void_logger_from_krill_config(config: &str) -> Box<dyn log::Log> {
let c: Config = toml::from_str(config).unwrap();
let config = format!(
"storage_uri = \"file:///tmp\"\n{}", config
);
let c: Config = toml::from_str(&config).unwrap();
let void_output = fern::Output::writer(Box::new(io::sink()), "");
let (_, void_logger) =
c.fern_logger().chain(void_output).into_log();
@@ -2317,7 +2267,10 @@ mod tests {
fn parse_and_process_config_str(
config_str: &str,
) -> Result<Config, ConfigError> {
let mut c: Config = toml::from_str(config_str).unwrap();
let config_str = format!(
"storage_uri = \"local:///tmp/\"\n{config_str}"
);
let mut c: Config = toml::from_str(&config_str).unwrap();
c.process()?;
Ok(c)
}
@@ -2526,7 +2479,8 @@ mod tests {
#[test]
fn data_dir_for_storage() {
fn test_uri(uri: &str, expected_path: &str) {
let storage_uri = Url::parse(uri).unwrap();
eprintln!("{uri}");
let storage_uri = StorageUri::from_str(uri).unwrap();
let config = Config::test_config(
&storage_uri,
None,
@@ -2541,9 +2495,9 @@ mod tests {
}
test_uri("local:///tmp/test", "/tmp/test");
test_uri("local://./data", "./data");
test_uri("local://data", "data");
test_uri("local://data/test", "data/test");
test_uri("local:///tmp/test", "/tmp/test");
assert!(StorageUri::from_str("local://tmp/data").is_err());
assert!(StorageUri::from_str("local://./data").is_err());
test_uri("local:/data", "/data");
test_uri("local:/data/test", "/data/test");
}
}
+12 -5
View File
@@ -9,6 +9,7 @@ use crate::api::admin::Token;
use crate::commons::KrillResult;
use crate::commons::actor::Actor;
use crate::commons::error::ApiAuthError;
use crate::commons::storage::StorageSystem;
use crate::config::{AuthType, Config};
#[cfg(unix)]
use crate::daemon::http::auth::providers::unix_user;
@@ -203,7 +204,11 @@ impl Authorizer {
///
/// The authorizer will be created according to information provided via
/// `config`.
pub fn new(config: &Config) -> KrillResult<Self> {
#[allow(unused_variables)]
pub fn new(
storage: &StorageSystem,
config: &Config,
) -> KrillResult<Self> {
let (primary_provider, legacy_provider) = match config.auth_type {
AuthType::AdminToken => {
(admin_token::AuthProvider::new(config).into(), None)
@@ -211,14 +216,16 @@ impl Authorizer {
#[cfg(feature = "multi-user")]
AuthType::ConfigFile => {
(
config_file::AuthProvider::new(config)?.into(),
config_file::AuthProvider::new(storage, config)?.into(),
Some(admin_token::AuthProvider::new(config))
)
}
#[cfg(feature = "multi-user")]
AuthType::OpenIDConnect => {
(
openid_connect::AuthProvider::new(config)?.into(),
openid_connect::AuthProvider::new(
storage, config
)?.into(),
Some(admin_token::AuthProvider::new(config))
)
}
@@ -248,7 +255,7 @@ impl Authorizer {
pub async fn authenticate_request(
&self, request: &HyperRequest
) -> (AuthInfo, Option<Token>) {
trace!("Determining actor for request {:?}", &request);
trace!("Determining actor for request {:?}", request);
// Try the legacy provider first, if any.
let authenticate_res = match &self.legacy_provider {
@@ -300,7 +307,7 @@ impl Authorizer {
let user = self.primary_provider.login(request).await?;
if log_enabled!(log::Level::Trace) {
trace!("User logged in: {:?}", &user);
trace!("User logged in: {:?}", user);
} else {
info!("User logged in: {}, role: {}", user.id(), user.role());
}
+6 -8
View File
@@ -26,8 +26,7 @@ use serde::{Deserialize, Serialize};
use crate::commons::ext_serde;
use crate::commons::KrillResult;
use crate::commons::error::{ApiAuthError, Error};
use crate::commons::storage::Ident;
use crate::config::Config;
use crate::commons::storage::{Ident, StorageSystem};
const CHACHA20_KEY_BIT_LEN: usize = 256;
const CHACHA20_KEY_BYTE_LEN: usize = CHACHA20_KEY_BIT_LEN / 8;
@@ -58,8 +57,7 @@ impl NonceState {
let mut sender_unique: [u8; 4] = [0; 4];
openssl::rand::rand_bytes(&mut sender_unique).map_err(|err| {
Error::Custom(format!(
"Unable to generate a random sender id: {}",
&err
"Unable to generate a random sender id: {}", err
))
})?;
@@ -121,7 +119,7 @@ pub(crate) fn encrypt(
plaintext,
&mut tag,
)
.map_err(|err| Error::Custom(format!("Encryption error: {}", &err)))?;
.map_err(|err| Error::Custom(format!("Encryption error: {}", err)))?;
let mut payload =
Vec::with_capacity(nonce.len() + tag.len() + cipher_text.len());
@@ -159,13 +157,13 @@ pub(crate) fn decrypt(
)
.map_err(|err| {
ApiAuthError::ApiInvalidCredentials(
format!("Decryption error: {}", &err)
format!("Decryption error: {}", err)
)
})
}
pub(crate) fn crypt_init(config: &Config) -> KrillResult<CryptState> {
let store = config.key_value_store(CRYPT_STATE_NS)?;
pub(crate) fn crypt_init(storage: &StorageSystem) -> KrillResult<CryptState> {
let store = storage.open(CRYPT_STATE_NS)?;
if let Some(state) = store.get(None, CRYPT_STATE_KEY)? {
Ok(state)
@@ -12,6 +12,7 @@ use crate::api::admin::Token;
use crate::commons::httpclient;
use crate::commons::KrillResult;
use crate::commons::error::{ApiAuthError, Error};
use crate::commons::storage::StorageSystem;
use crate::constants::{PW_HASH_LOG_N, PW_HASH_P, PW_HASH_R};
use crate::config::Config;
use crate::daemon::http::auth::crypt;
@@ -56,13 +57,14 @@ pub struct AuthProvider {
impl AuthProvider {
/// Creates an auth provider from the given config.
pub fn new(
storage: &StorageSystem,
config: &Config,
) -> KrillResult<Self> {
let users = config.auth_users.as_ref().ok_or_else(|| {
Error::ConfigError("Missing [auth_users] config section!".into())
})?.clone();
let roles = config.auth_roles.clone();
let session_key = Self::init_session_key(config)?;
let session_key = Self::init_session_key(storage)?;
Ok(Self {
users,
@@ -78,9 +80,11 @@ impl AuthProvider {
}
fn init_session_key(config: &Config) -> KrillResult<crypt::CryptState> {
fn init_session_key(
storage: &StorageSystem
) -> KrillResult<crypt::CryptState> {
debug!("Initializing login session encryption key");
crypt::crypt_init(config)
crypt::crypt_init(storage)
}
/// Parse HTTP Basic Authorization header
@@ -62,6 +62,7 @@ use crate::{
commons::{
httpclient,
error::{ApiAuthError, Error},
storage::StorageSystem,
util::sha256,
KrillResult,
},
@@ -183,8 +184,11 @@ pub struct AuthProvider {
}
impl AuthProvider {
pub fn new(config: &Config) -> KrillResult<Self> {
let session_key = Self::init_session_key(config)?;
pub fn new(
storage: &StorageSystem,
config: &Config,
) -> KrillResult<Self> {
let session_key = Self::init_session_key(storage)?;
let Some(oidc_conf) = config.auth_openidconnect.as_ref() else {
return Err(Error::ConfigError(
@@ -259,7 +263,7 @@ impl AuthProvider {
info!(
"OpenID Connect: Discovering provider details using issuer {}",
&issuer.as_str()
issuer.as_str()
);
// Contact the OpenID Connect: identity provider discovery endpoint to
@@ -579,7 +583,7 @@ impl AuthProvider {
trace!(
"OpenID Connect: Revoking token for user: \"{}\"",
&session.user_id
session.user_id
);
trace!("OpenID Connect: Submitting RFC-7009 section 2 Token Revocation request");
let lock_guard = self.get_connection().await.map_err(|err| {
@@ -664,7 +668,7 @@ impl AuthProvider {
debug!(
"OpenID Connect: Refreshing token for user: \"{}\"",
&session.user_id
session.user_id
);
trace!("OpenID Connect: Submitting RFC-6749 section 6 Access Token Refresh request");
@@ -754,9 +758,9 @@ impl AuthProvider {
}
}
fn init_session_key(config: &Config) -> KrillResult<CryptState> {
fn init_session_key(storage: &StorageSystem) -> KrillResult<CryptState> {
debug!("Initializing session encryption key");
crypt::crypt_init(config)
crypt::crypt_init(storage)
}
fn extract_cookie(
@@ -785,7 +789,7 @@ impl AuthProvider {
Ok(parsed_cookies) => {
trace!(
"OpenID Connect: parsed cookies={:?}",
&parsed_cookies
parsed_cookies
);
// Even with the helper crate we have to do some
// work... Why doesn't it
@@ -921,7 +925,7 @@ impl AuthProvider {
"OpenID Connect: CSRF token mismatch",
Some(&format!(
"cookie CSRF hash={:?}, request CSRF hash={:?}",
&cookie_csrf_hash,
cookie_csrf_hash,
request_csrf_hash.to_vec()
)),
)),
@@ -1461,7 +1465,7 @@ impl AuthProvider {
let (authorize_url, _csrf_state, _nonce) = request.url();
debug!("OpenID Connect: Login URL will be {:?}", &authorize_url);
debug!("OpenID Connect: Login URL will be {:?}", authorize_url);
let res_body = authorize_url.as_str().as_bytes().to_vec();
let mut res = HttpResponse::text_no_cache(res_body).into_response();
@@ -1868,7 +1872,7 @@ impl AuthProvider {
trace!(
"Telling Lagosta to direct the user to logout at: {}",
&go_to_url
go_to_url
);
Ok(HttpResponse::text_no_cache(go_to_url.into()))
}
+4 -4
View File
@@ -65,7 +65,7 @@ impl<S> ClientSession<S> {
trace!(
"Login session status check: user_id={}, \
status={:?}, max age={} secs, cur age={} secs",
&self.user_id, &status, max_age_secs, cur_age_secs
self.user_id, status, max_age_secs, cur_age_secs
);
return status;
@@ -166,7 +166,7 @@ impl<S> LoginSessionCache<S> {
secrets
};
debug!("Creating token for session: {:?}", &session);
debug!("Creating token for session: {:?}", session);
let session_json_str =
serde_json::to_string(&session).map_err(|err| {
@@ -231,7 +231,7 @@ impl<S> LoginSessionCache<S> {
) -> Result<ClientSession<S>, ApiAuthError>
where S: Clone + DeserializeOwned {
if let Some(session) = self.lookup_session(&token).await {
trace!("Session cache hit for session id {}", &session.user_id);
trace!("Session cache hit for session id {}", session.user_id);
return Ok(session);
}
else {
@@ -262,7 +262,7 @@ impl<S> LoginSessionCache<S> {
trace!(
"Session cache miss, deserialized session id {}",
&session.user_id
session.user_id
);
if add_to_cache {
+4 -4
View File
@@ -74,7 +74,7 @@ mod multi_user {
request.check_get()?;
trace!(
"Authentication callback invoked: {:?}", &request.hyper()
"Authentication callback invoked: {:?}", request.hyper()
);
let (server, request) = request.proceed_raw();
@@ -121,9 +121,9 @@ mod multi_user {
Ok(format!(
"/ui/login?token={}&id={}&attributes={}",
&url_encode(user.token())?,
&url_encode(user.id())?,
&url_encode(attributes)?,
url_encode(user.token())?,
url_encode(user.id())?,
url_encode(attributes)?,
))
}
}
+1 -1
View File
@@ -360,7 +360,7 @@ impl HttpResponse {
) {
let header_name = const { HeaderName::from_static("authorization") };
let header_value = match HeaderValue::from_maybe_shared(
Bytes::from(format!("Bearer {}", &token))
Bytes::from(format!("Bearer {}", token))
) {
Ok(value) => value,
Err(_) => {
+2 -4
View File
@@ -41,7 +41,7 @@ impl HttpServer {
krill: KrillManager,
runtime: &runtime::Handle,
) -> KrillResult<Arc<Self>> {
let authorizer = Authorizer::new(krill.config())?;
let authorizer = Authorizer::new(krill.storage(), krill.config())?;
authorizer.spawn_sweep(runtime);
Ok(Self {
krill,
@@ -136,9 +136,7 @@ impl RequestLogger {
trace!(
"Request: method={} path={} headers={:?}",
&req_method,
&req_path,
&req.headers()
req_method, req_path, req.headers()
);
RequestLogger {
+1 -1
View File
@@ -128,7 +128,7 @@ impl HttpsSigner {
fn save_private_key(&self, tls_keys_dir: &Path) -> Result<(), Error> {
let key_file_path = key_file_path(tls_keys_dir);
let bytes = Bytes::from(self.private.private_key_to_pem_pkcs8()?);
file::save(&bytes, &key_file_path)?;
file::save_private(&bytes, &key_file_path)?;
Ok(())
}
+28 -22
View File
@@ -22,6 +22,7 @@ use tokio::task::JoinSet;
use tokio_rustls::TlsAcceptor;
use crate::commons::file;
use crate::commons::error::{Error, Error as KrillError};
use crate::commons::storage::StorageSystem;
use crate::commons::version::KrillVersion;
use crate::config::Config;
use crate::constants::{KRILL_ENV_UPGRADE_ONLY, KRILL_SERVER_APP};
@@ -61,16 +62,17 @@ pub fn start_krill_daemon(
write_pid_file_or_die(&config);
test_data_dirs_or_die(&config);
let storage = StorageSystem::new(config.storage_uri.clone());
// Set up the runtime properties manager, so that we can check
// the version used for the current data in storage
let properties_manager = PropertiesManager::create(
&config.storage_uri,
config.use_history_cache,
&storage, config.use_history_cache,
)?;
// Call upgrade, this will only do actual work if needed.
let upgrade_report = prepare_upgrade_data_migrations(
UpgradeMode::PrepareToFinalise, &config, &properties_manager
UpgradeMode::PrepareToFinalise, &storage, &config, &properties_manager
).map_err(|e| {
match e {
UpgradeError::CodeOlderThanData(_,_) => {
@@ -88,7 +90,7 @@ pub fn start_krill_daemon(
if let Some(report) = &upgrade_report {
finalise_data_migration(
report.versions(), &config, &properties_manager
report.versions(), &storage, &properties_manager
).map_err(|e| {
Error::Custom(format!(
"Finishing prepared migration failed unexpectedly. Please \
@@ -116,7 +118,9 @@ pub fn start_krill_daemon(
)
})?;
let mut krill = StartupManager::new(config, tokio.handle().clone())?;
let mut krill = StartupManager::new(
config, storage, tokio.handle().clone()
)?;
// Setup testbed if necessary.
krill.prepare_testbed()?;
@@ -234,14 +238,6 @@ fn single_http_listener(
"Failed to configure TCP socket '{addr}': {err}"
)));
}
let listener = match TokioTcpListener::from_std(listener) {
Ok(listener) => listener,
Err(err) => {
return Err(Error::Custom(format!(
"Failed to prepare TCP socket '{addr}': {err}"
)));
}
};
let tls = if server.config().https_mode().is_disable_https() {
None
@@ -271,6 +267,15 @@ fn single_http_listener(
join.spawn_on(
async move {
let listener = match TokioTcpListener::from_std(listener) {
Ok(listener) => listener,
Err(err) => {
error!(
"Failed to prepare TCP socket '{addr}': {err}"
);
return;
}
};
loop {
// Break here already if `signal_exit` is true.
if *signal_exit.borrow_and_update() {
@@ -388,15 +393,6 @@ fn single_unix_listener(
path.display(), err,
)));
}
let listener = match TokioUnixListener::from_std(listener) {
Ok(listener) => listener,
Err(err) => {
return Err(Error::Custom(format!(
"Failed to prepare Unix socket '{}': {}",
path.display(), err,
)));
}
};
let conn_builder = conn::auto::Builder::new(TokioExecutor::new());
let graceful = GracefulShutdown::new();
@@ -410,6 +406,16 @@ fn single_unix_listener(
join.spawn_on(
async move {
let listener = match TokioUnixListener::from_std(listener) {
Ok(listener) => listener,
Err(err) => {
error!(
"Failed to prepare Unix socket '{}': {}",
path.display(), err,
);
return;
}
};
loop {
// Break here already if `signal_exit` is true.
if *signal_exit.borrow_and_update() {
+5 -5
View File
@@ -1306,7 +1306,7 @@ impl CertAuth {
"Updating resource class name mapping for\
child '{}, but parent does not have any resource class \
called '{}', or at least not yet.",
child_handle, &mapping.name_in_parent
child_handle, mapping.name_in_parent
);
}
@@ -1907,7 +1907,7 @@ impl CertAuth {
info!(
"Updating Entitlements for CA: {}, Removing RC: {}",
&self.handle, &rcn
self.handle, rcn
);
res.push(CertAuthEvent::ResourceClassRemoved {
@@ -2079,7 +2079,7 @@ impl CertAuth {
)? {
info!(
"Started key roll for ca: {}, rc: {}, under parent: {}",
&self.handle,
self.handle,
rcn,
rc.parent_handle()
);
@@ -2104,7 +2104,7 @@ impl CertAuth {
)? {
info!(
"Activated key for ca: {}, rc: {}, under parent: {}",
&self.handle,
self.handle,
rcn,
rc.parent_handle()
);
@@ -2128,7 +2128,7 @@ impl CertAuth {
info!(
"Finished key roll for ca: {}, rc: {}, under parent: {}",
&self.handle,
self.handle,
rcn,
my_rc.parent_handle()
);
+8 -15
View File
@@ -53,6 +53,7 @@ use crate::commons::actor::Actor;
use crate::commons::cmslogger::CmsLogger;
use crate::commons::error::{Error, Error as KrillError};
use crate::commons::eventsourcing::{Aggregate, AggregateStore, SentCommand};
use crate::commons::storage::StorageSystem;
use crate::constants::{
CASERVER_NS, STATUS_NS, TA_PROXY_SERVER_NS, TA_SIGNER_SERVER_NS, TA_NAME,
ta_handle,
@@ -116,13 +117,12 @@ impl CaManager {
/// Return an error if any of the various stores cannot be initialized.
pub fn new(
config: &Config,
storage: &StorageSystem,
) -> KrillResult<Self> {
// Create the AggregateStore for the event-sourced `CertAuth`
// structures that handle most CA functions.
let ca_store = AggregateStore::<CertAuth>::create(
&config.storage_uri,
CASERVER_NS,
config.use_history_cache,
storage, CASERVER_NS, config.use_history_cache,
)?;
if let Err(e) = ca_store.warm() {
@@ -151,16 +151,13 @@ impl CaManager {
// and issued certificates from the `CertAuth` and is responsible
// for manifests and CRL generation.
let ca_objects_store = Arc::new(CaObjectsStore::create(
&config.storage_uri,
config.issuance_timing,
storage, config.issuance_timing,
)?);
// Create TA proxy store if we need it.
let ta_proxy_store = if config.ta_proxy_enabled() {
Some(AggregateStore::<TrustAnchorProxy>::create(
&config.storage_uri,
TA_PROXY_SERVER_NS,
config.use_history_cache,
storage, TA_PROXY_SERVER_NS, config.use_history_cache,
)?)
}
else {
@@ -169,9 +166,7 @@ impl CaManager {
let ta_signer_store = if config.ta_signer_enabled() {
Some(AggregateStore::create(
&config.storage_uri,
TA_SIGNER_SERVER_NS,
config.use_history_cache,
storage, TA_SIGNER_SERVER_NS, config.use_history_cache,
)?)
}
else {
@@ -181,9 +176,7 @@ impl CaManager {
// Create the status store which will maintain the last known
// connection status between each CA and their parent(s) and
// repository.
let status_store = CaStatusStore::create(
&config.storage_uri, STATUS_NS
)?;
let status_store = CaStatusStore::create(storage, STATUS_NS)?;
Ok(CaManager {
ca_store,
@@ -782,7 +775,7 @@ impl CaManager {
actor: &Actor,
krill: &KrillRuntime,
) -> KrillResult<ParentResponse> {
info!("CA '{}' process add child request: {}", &ca, &req);
info!("CA '{}' process add child request: {}", ca, req);
if ca.as_str() != TA_NAME {
self.process_ca_command(ca.clone(), actor,
CertAuthCommandDetails::ChildAdd(
+4 -5
View File
@@ -14,7 +14,6 @@ use rpki::repository::manifest::{FileAndHash, Manifest, ManifestContent};
use rpki::repository::sigobj::SignedObjectBuilder;
use rpki::repository::x509::{Name, Serial, Time, Validity};
use serde::{Deserialize, Serialize};
use url::Url;
use crate::api::admin::{PublishedFile, RepositoryContact};
use crate::api::ca::{
CertInfo, IssuedCertificate, ObjectName, ReceivedCert, Revocation,
@@ -24,7 +23,7 @@ use crate::api::roa::RoaInfo;
use crate::commons::KrillResult;
use crate::commons::crypto::KrillSigner;
use crate::commons::error::Error;
use crate::commons::storage::{Ident, KeyValueStore};
use crate::commons::storage::{Ident, KeyValueStore, StorageSystem};
use crate::constants::CA_OBJECTS_NS;
use crate::config::IssuanceTimingConfig;
use crate::server::runtime::KrillRuntime;
@@ -70,10 +69,10 @@ pub struct CaObjectsStore {
impl CaObjectsStore {
/// Creates a new CA objects store using the given configuration.
pub fn create(
storage_uri: &Url,
storage: &StorageSystem,
issuance_timing: IssuanceTimingConfig,
) -> KrillResult<Self> {
let store = KeyValueStore::create(storage_uri, CA_OBJECTS_NS)?;
let store = storage.open(CA_OBJECTS_NS)?;
Ok(CaObjectsStore {
store,
issuance_timing,
@@ -573,7 +572,7 @@ impl CaObjects {
let hours = timing.publish_hours_before_next();
let mut required = false;
for (_, resource_class_objects) in self.classes.iter_mut() {
for resource_class_objects in self.classes.values_mut() {
if force || resource_class_objects.requires_re_issuance(hours) {
required = true;
resource_class_objects.reissue(timing, signer)?;
+3 -4
View File
@@ -9,7 +9,6 @@ use rpki::ca::idexchange::{CaHandle, ChildHandle, ParentHandle, ServiceUri};
use rpki::ca::provisioning::ResourceClassListResponse as Entitlements;
use rpki::ca::publication::PublishDelta;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::api::ca::{
ChildConnectionStats, ChildStatus, ChildrenConnectionStats, ParentStatus,
ParentStatuses, RepoStatus,
@@ -18,7 +17,7 @@ use crate::api::status::ErrorResponse;
use crate::commons::httpclient;
use crate::commons::KrillResult;
use crate::commons::error::Error;
use crate::commons::storage::{Ident, KeyValueStore};
use crate::commons::storage::{Ident, KeyValueStore, StorageSystem};
const PARENTS_PREFIX: &Ident = Ident::make("parents-");
const CHILDREN_PREFIX: &Ident = Ident::make("children-");
@@ -64,10 +63,10 @@ pub struct CaStatusStore {
impl CaStatusStore {
/// Creates a new status store with the givn storage URI and namespace.
pub fn create(
storage_uri: &Url,
storage: &StorageSystem,
namespace: &Ident,
) -> KrillResult<Self> {
let store = KeyValueStore::create(storage_uri, namespace)?;
let store = storage.open(namespace)?;
let cache = RwLock::new(HashMap::new());
let store = Self { store, cache };
+6 -4
View File
@@ -1,4 +1,5 @@
use log::{debug, warn};
use crate::commons::storage::StorageSystem;
use crate::constants::CASERVER_NS;
use crate::server::ca::certauth::CertAuth;
use crate::server::ca::publishing::CaObjectsStore;
@@ -7,12 +8,13 @@ use crate::upgrades::UpgradeResult;
use crate::upgrades::data_migration::check_agg_store;
pub fn check_ca_objects(config: &Config) -> UpgradeResult<()> {
let ca_store = check_agg_store::<CertAuth>(config, CASERVER_NS, "CAs")?;
pub fn check_ca_objects(
storage: &StorageSystem, config: &Config
) -> UpgradeResult<()> {
let ca_store = check_agg_store::<CertAuth>(storage, CASERVER_NS, "CAs")?;
let ca_objects_store = CaObjectsStore::create(
&config.storage_uri,
config.issuance_timing,
storage, config.issuance_timing,
)?;
let cas_with_objects = ca_objects_store.cas()?;
+9 -22
View File
@@ -7,13 +7,12 @@ use crate::api::aspa::ProviderAsn;
use crate::commons::eventsourcing::{
AggregateStore, StoredCommand, StoredCommandBuilder
};
use crate::commons::storage::{Ident, KeyValueStore};
use crate::commons::storage::{Ident, KeyValueStore, StorageSystem};
use crate::constants::{CASERVER_NS, CA_OBJECTS_NS};
use crate::server::ca::certauth::CertAuth;
use crate::server::ca::commands::CertAuthStorableCommand;
use crate::server::ca::events::{CertAuthEvent, CertAuthInitEvent};
use crate::server::ca::publishing::CaObjects;
use crate::config::Config;
use crate::upgrades::{
AspaMigrationConfigUpdates, AspaMigrationConfigs, CommandMigrationEffect,
UpgradeAggregateStorePre0_14, UpgradeError, UpgradeMode, UpgradeResult,
@@ -50,22 +49,15 @@ impl CasMigration {
/// Upgrades the CAs based on the upgrade mode and config.
pub fn upgrade(
mode: UpgradeMode,
config: &Config,
storage: &StorageSystem,
) -> UpgradeResult<AspaMigrationConfigs> {
Self {
current_kv_store: KeyValueStore::create(
&config.storage_uri, CASERVER_NS
)?,
new_kv_store: KeyValueStore::create_upgrade_store(
&config.storage_uri,
CASERVER_NS,
)?,
current_kv_store: storage.open(CASERVER_NS)?,
new_kv_store: storage.open_upgrade(CASERVER_NS)?,
new_agg_store: AggregateStore::<CertAuth>::create_upgrade_store(
&config.storage_uri,
CASERVER_NS,
config.use_history_cache,
storage, CASERVER_NS, false,
)?,
ca_objects_migration: CaObjectsMigration::create(config)?,
ca_objects_migration: CaObjectsMigration::create(storage)?,
}
.upgrade(mode)
}
@@ -253,15 +245,10 @@ struct CaObjectsMigration {
impl CaObjectsMigration {
/// Creates a new migration from the configuration.
fn create(config: &Config) -> Result<Self, UpgradeError> {
fn create(storage: &StorageSystem) -> Result<Self, UpgradeError> {
Ok(CaObjectsMigration {
current_store: KeyValueStore::create(
&config.storage_uri, CA_OBJECTS_NS
)?,
new_store: KeyValueStore::create_upgrade_store(
&config.storage_uri,
CA_OBJECTS_NS,
)?
current_store: storage.open(CA_OBJECTS_NS)?,
new_store: storage.open_upgrade(CA_OBJECTS_NS)?
})
}
+5 -12
View File
@@ -10,10 +10,9 @@ use crate::upgrades::{
use crate::{
commons::{
eventsourcing::AggregateStore,
storage::KeyValueStore,
storage::{KeyValueStore, StorageSystem},
},
constants::CASERVER_NS,
config::Config,
upgrades::UpgradeResult,
};
@@ -36,19 +35,13 @@ pub struct CasMigration {
impl CasMigration {
pub fn upgrade(
mode: UpgradeMode,
config: &Config,
storage: &StorageSystem,
) -> UpgradeResult<AspaMigrationConfigs> {
let current_kv_store =
KeyValueStore::create(&config.storage_uri, CASERVER_NS)?;
let new_kv_store = KeyValueStore::create_upgrade_store(
&config.storage_uri,
CASERVER_NS,
)?;
let current_kv_store = storage.open(CASERVER_NS)?;
let new_kv_store = storage.open_upgrade(CASERVER_NS)?;
let new_agg_store = AggregateStore::<CertAuth>::create_upgrade_store(
&config.storage_uri,
CASERVER_NS,
config.use_history_cache,
storage, CASERVER_NS, false
)?;
CasMigration {
+8 -2
View File
@@ -18,6 +18,7 @@ use crate::api::status::ErrorResponse;
use crate::commons::actor::Actor;
use crate::commons::error::KrillError;
use crate::commons::eventsourcing::AggregateStoreError;
use crate::commons::storage::StorageSystem;
use crate::config::Config;
use crate::constants::{TA_NAME, ta_handle, testbed_ca_handle};
use crate::server::ca::CaStatus;
@@ -45,11 +46,11 @@ impl StartupManager {
/// While the Tokio runtime provided isn’t used, we need the handle
/// already to pass it to the Krill runtime.
pub fn new(
config: Config, tokio: TokioHandle
config: Config, storage: StorageSystem, tokio: TokioHandle
) -> Result<Self, KrillError> {
Ok(Self {
thread_pool: ThreadPool::new(&config)?,
runtime: KrillRuntime::new(config, tokio)?,
runtime: KrillRuntime::new(config, storage, tokio)?,
})
}
@@ -225,6 +226,11 @@ impl KrillManager {
self.krill_runtime.config()
}
/// Returns a reference to the storage system.
pub fn storage(&self) -> &StorageSystem {
self.krill_runtime.storage()
}
/// Returns the system actor.
pub fn system_actor(&self) -> &Actor {
self.krill_runtime.system_actor()
+3 -4
View File
@@ -10,12 +10,11 @@ use rpki::ca::idexchange::{CaHandle, ParentHandle};
use rpki::ca::provisioning::{ResourceClassName, RevocationRequest};
use rpki::repository::x509::Time;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::api::ca::Timestamp;
use crate::commons::{Error, KrillResult};
use crate::commons::eventsourcing::Aggregate;
use crate::commons::queue::{Queue, ScheduleMode};
use crate::commons::storage::Ident;
use crate::commons::storage::{Ident, StorageSystem};
use crate::constants::{TASK_QUEUE_NS, ta_handle};
use crate::server::ca::{CertAuth, CertAuthEvent};
use crate::server::taproxy::{TrustAnchorProxy, TrustAnchorProxyEvent};
@@ -285,9 +284,9 @@ pub struct TaskQueue {
}
impl TaskQueue {
pub fn new(storage_uri: &Url) -> KrillResult<Self> {
pub fn new(storage: &StorageSystem) -> KrillResult<Self> {
Ok(TaskQueue {
q: Queue::create(storage_uri, TASK_QUEUE_NS)?,
q: Queue::create(storage, TASK_QUEUE_NS)?,
})
}
}
+11 -9
View File
@@ -20,7 +20,6 @@ use std::{fmt, str::FromStr, sync::Arc};
use log::{log_enabled, trace};
use rpki::ca::idexchange::MyHandle;
use serde::{Deserialize, Serialize};
use url::Url;
use crate::{
commons::{
@@ -30,6 +29,7 @@ use crate::{
self, Aggregate, AggregateStore, Event, InitCommandDetails,
InitEvent, SentCommand, SentInitCommand, WithStorableDetails,
},
storage::StorageSystem,
version::KrillVersion,
KrillResult,
},
@@ -300,17 +300,19 @@ pub struct PropertiesManager {
impl PropertiesManager {
pub fn create(
storage_uri: &Url,
storage: &StorageSystem,
use_history_cache: bool,
) -> KrillResult<Self> {
let main_key = MyHandle::from_str(PROPERTIES_DFLT_NAME).unwrap();
AggregateStore::create(storage_uri, PROPERTIES_NS, use_history_cache)
.map(|store| PropertiesManager {
store,
main_key,
system_actor: ACTOR_DEF_KRILL,
})
.map_err(Error::AggregateStoreError)
let store = AggregateStore::create(
storage, PROPERTIES_NS, use_history_cache
)?;
Ok(PropertiesManager {
store,
main_key,
system_actor: ACTOR_DEF_KRILL,
})
}
pub fn is_initialized(&self) -> bool {
+7 -6
View File
@@ -25,10 +25,10 @@ use crate::commons::eventsourcing::{
Aggregate, AggregateStore, CommandDetails, Event, InitCommandDetails,
InitEvent, SentCommand, SentInitCommand, WithStorableDetails,
};
use crate::commons::storage::StorageSystem;
use crate::constants::{
ACTOR_DEF_KRILL, PUBSERVER_DFLT, PUBSERVER_NS, TA_NAME
};
use crate::config::Config;
use super::publishers::Publisher;
@@ -50,12 +50,13 @@ pub struct RepositoryAccessProxy {
}
impl RepositoryAccessProxy {
/// Creates a new repository access proxy from the config.
pub fn create(config: &Config) -> KrillResult<Self> {
/// Creates a new repository access proxy
pub fn create(
storage: &StorageSystem,
use_history_cache: bool
) -> KrillResult<Self> {
let store = AggregateStore::<RepositoryAccess>::create(
&config.storage_uri,
PUBSERVER_NS,
config.use_history_cache,
storage, PUBSERVER_NS, use_history_cache,
)?;
let key = MyHandle::from_str(PUBSERVER_DFLT).unwrap();
+4 -3
View File
@@ -16,8 +16,9 @@ use crate::commons::error::Error;
use crate::commons::eventsourcing::{
WalChange, WalCommand, WalSet, WalStore, WalSupport,
};
use crate::commons::storage::StorageSystem;
use crate::constants::PUBSERVER_CONTENT_NS;
use crate::config::{Config, RrdpUpdatesConfig};
use crate::config::RrdpUpdatesConfig;
use super::rrdp::{
CurrentObjects, DeltaElements, RrdpServer, RrdpSession, RrdpSessionReset,
RrdpUpdated, RrdpUpdateNeeded,
@@ -46,9 +47,9 @@ pub struct RepositoryContentProxy {
impl RepositoryContentProxy {
/// Creates a new repository content proxy.
pub fn create(config: &Config) -> KrillResult<Self> {
pub fn create(storage: &StorageSystem) -> KrillResult<Self> {
let store = Arc::new(WalStore::create(
&config.storage_uri, PUBSERVER_CONTENT_NS,
storage, PUBSERVER_CONTENT_NS,
)?);
store.warm()?;
+50 -43
View File
@@ -17,6 +17,7 @@ use crate::commons::KrillResult;
use crate::commons::actor::Actor;
use crate::commons::cmslogger::CmsLogger;
use crate::commons::error::Error;
use crate::commons::storage::StorageSystem;
use crate::config::{Config, RrdpUpdatesConfig};
use crate::server::mq::{now, Task};
use crate::server::runtime::KrillRuntime;
@@ -43,10 +44,15 @@ pub struct RepositoryManager {
impl RepositoryManager {
/// Builds the repository manager.
pub fn new(config: &Config) -> Result<Self, Error> {
pub fn new(
config: &Config,
storage: &StorageSystem,
) -> Result<Self, Error> {
Ok(RepositoryManager {
access: RepositoryAccessProxy::create(config)?,
content: RepositoryContentProxy::create(config)?,
access: RepositoryAccessProxy::create(
storage, config.use_history_cache
)?,
content: RepositoryContentProxy::create(storage)?,
rrdp_updates_config: config.rrdp_updates_config,
})
}
@@ -356,6 +362,7 @@ mod tests {
use crate::commons::file;
use crate::commons::crypto::{KrillSignerBuilder, OpenSslSignerConfig};
use crate::commons::file::CurrentFile;
use crate::commons::storage::StorageUri;
use crate::commons::test::{self, https, rsync};
use crate::constants::{
ACTOR_DEF_TEST, RRDP_FIRST_SERIAL, enable_test_mode
@@ -365,36 +372,6 @@ mod tests {
use crate::server::pubd::rrdp::{PublicationDeltaError, RrdpServer};
use super::*;
fn publisher_alice(storage_uri: &Url) -> Publisher {
// When the "hsm" feature is enabled we could be running the tests
// with PKCS#11 as the default signer type. In that case, if
// the backend signer is SoftHSMv2, attempting to create a second
// instance of KrillSigner in the same process will fail
// because it will attempt to login to SoftHSMv2 a second time which
// SoftHSMv2 does not support. To work around this issue we
// therefore explicitly request that the second KrillSigner instance
// that we create here uses OpenSSL as its backend signer.
let signer = {
let signer_type =
SignerType::OpenSsl(OpenSslSignerConfig::default());
let signer_config =
SignerConfig::new("Alice".to_string(), signer_type);
let signer_configs = &[signer_config];
KrillSignerBuilder::new(
storage_uri,
Duration::from_secs(1),
signer_configs,
)
.build()
.unwrap()
};
let id_cert = signer.create_self_signed_id_cert().unwrap();
let base_uri =
uri::Rsync::from_str("rsync://localhost/repo/alice/").unwrap();
Publisher::new(id_cert.into(), base_uri)
}
fn make_publisher_req(
handle: &str,
@@ -410,20 +387,19 @@ mod tests {
struct TestServer {
krill: KrillRuntime,
storage_uri: Url,
data_dir: tempfile::TempDir,
tokio: tokio::runtime::Runtime,
}
impl TestServer {
fn new() -> Self {
let storage_uri = test::mem_storage();
let storage = test::mem_storage();
let data_dir = tempfile::tempdir().unwrap();
let tokio = tokio::runtime::Runtime::new().unwrap();
enable_test_mode();
let mut config = Config::test(
&storage_uri,
storage.default_uri(),
Some(data_dir.path()),
true,
false,
@@ -434,7 +410,7 @@ mod tests {
config.process().unwrap();
let krill = KrillRuntime::new(
config, tokio.handle().clone()
config, storage, tokio.handle().clone()
).unwrap();
let uris = PublicationServerUris {
rrdp_base_uri: https("https://localhost/repo/rrdp/"),
@@ -443,19 +419,50 @@ mod tests {
krill.repo_manager().init(uris, &krill).unwrap();
Self { krill, storage_uri, data_dir, tokio }
Self { krill, data_dir, tokio }
}
fn repo(&self) -> &RepositoryManager {
self.krill.repo_manager()
}
fn publisher_alice(&self) -> Publisher {
// When the "hsm" feature is enabled we could be running the tests
// with PKCS#11 as the default signer type. In that case, if
// the backend signer is SoftHSMv2, attempting to create a second
// instance of KrillSigner in the same process will fail
// because it will attempt to login to SoftHSMv2 a second time which
// SoftHSMv2 does not support. To work around this issue we
// therefore explicitly request that the second KrillSigner instance
// that we create here uses OpenSSL as its backend signer.
let signer = {
let signer_type =
SignerType::OpenSsl(OpenSslSignerConfig::default());
let signer_config =
SignerConfig::new("Alice".to_string(), signer_type);
let signer_configs = &[signer_config];
KrillSignerBuilder::new(
self.krill.storage(),
Duration::from_secs(1),
signer_configs,
)
.build()
.unwrap()
};
let id_cert = signer.create_self_signed_id_cert().unwrap();
let base_uri =
uri::Rsync::from_str("rsync://localhost/repo/alice/").unwrap();
Publisher::new(id_cert.into(), base_uri)
}
}
#[test]
fn should_add_publisher() {
let server = TestServer::new();
let alice = publisher_alice(&server.storage_uri);
let alice = server.publisher_alice();
let alice_handle = Handle::from_str("alice").unwrap();
let publisher_req =
@@ -477,7 +484,7 @@ mod tests {
fn should_not_add_publisher_twice() {
let server = TestServer::new();
let alice = publisher_alice(&server.storage_uri);
let alice = server.publisher_alice();
let alice_handle = Handle::from_str("alice").unwrap();
let publisher_req =
@@ -500,7 +507,7 @@ mod tests {
fn should_list_files() {
let server = TestServer::new();
let alice = publisher_alice(&server.storage_uri);
let alice = server.publisher_alice();
let alice_handle = Handle::from_str("alice").unwrap();
let publisher_req =
@@ -525,7 +532,7 @@ mod tests {
assert!(session_dir_contains_serial(&session, RRDP_FIRST_SERIAL));
// set up server with default repository, and publisher alice
let alice = publisher_alice(&server.storage_uri);
let alice = server.publisher_alice();
let alice_handle = Handle::from_str("alice").unwrap();
let publisher_req =
@@ -762,7 +769,7 @@ mod tests {
let server = TestServer::new();
// set up server with default repository, and publisher alice
let alice = publisher_alice(&server.storage_uri);
let alice = server.publisher_alice();
let alice_handle = Handle::from_str("alice").unwrap();
let publisher_req =
+11 -15
View File
@@ -9,18 +9,19 @@ use log::info;
use rpki::ca::idexchange::MyHandle;
use crate::commons::KrillResult;
use crate::commons::eventsourcing::WalStore;
use crate::commons::storage::{Ident, KeyValueStore};
use crate::commons::storage::{Ident, StorageSystem};
use crate::constants::PUBSERVER_CONTENT_NS;
use crate::config::Config;
use crate::server::pubd::content::RepositoryContent;
use self::pre_0_13_0::OldRepositoryContent;
/// Migrate v0.12.x RepositoryContent to the new 0.13.0+ format.
/// Apply any open WAL changes to the source first.
pub fn migrate_0_12_pubd_objects(config: &Config) -> KrillResult<bool> {
pub fn migrate_0_12_pubd_objects(
storage: &StorageSystem
) -> KrillResult<bool> {
let old_store: WalStore<OldRepositoryContent> = WalStore::create(
&config.storage_uri, PUBSERVER_CONTENT_NS
storage, PUBSERVER_CONTENT_NS
)?;
let repo_content_handle = MyHandle::new("0".into());
@@ -29,10 +30,7 @@ pub fn migrate_0_12_pubd_objects(config: &Config) -> KrillResult<bool> {
old_store.get_latest(&repo_content_handle)?.as_ref().clone();
let repo_content: RepositoryContent =
old_repo_content.try_into()?;
let upgrade_store = KeyValueStore::create_upgrade_store(
&config.storage_uri,
PUBSERVER_CONTENT_NS,
)?;
let upgrade_store = storage.open_upgrade( PUBSERVER_CONTENT_NS)?;
upgrade_store.store(
Some(const { Ident::make("0") }),
const { Ident::make("snapshot.json") },
@@ -46,10 +44,10 @@ pub fn migrate_0_12_pubd_objects(config: &Config) -> KrillResult<bool> {
/// The format of the RepositoryContent did not change in 0.12, but
/// the location and way of storing it did. So, migrate if present.
pub fn migrate_pre_0_12_pubd_objects(config: &Config) -> KrillResult<()> {
let old_store = KeyValueStore::create(
&config.storage_uri, PUBSERVER_CONTENT_NS
)?;
pub fn migrate_pre_0_12_pubd_objects(
storage: &StorageSystem
) -> KrillResult<()> {
let old_store = storage.open(PUBSERVER_CONTENT_NS)?;
if let Ok(Some(old_repo_content)) =
old_store.get::<OldRepositoryContent>(
None, const { Ident::make("0.json") }
@@ -58,9 +56,7 @@ pub fn migrate_pre_0_12_pubd_objects(config: &Config) -> KrillResult<()> {
info!("Found pre 0.12.0 RC2 publication server data. Migrating..");
let repo_content: RepositoryContent = old_repo_content.try_into()?;
let upgrade_store = KeyValueStore::create_upgrade_store(
&config.storage_uri, PUBSERVER_CONTENT_NS,
)?;
let upgrade_store = storage.open_upgrade(PUBSERVER_CONTENT_NS)?;
upgrade_store.store(
Some(const { Ident::make("0") }),
const { Ident::make("snapshot.json") },
@@ -1,10 +1,9 @@
use rpki::ca::idexchange::MyHandle;
use rpki::repository::x509::Time;
use crate::commons::eventsourcing::{AggregateStore, StoredCommandBuilder};
use crate::commons::storage::{Ident, KeyValueStore};
use crate::commons::storage::{Ident, KeyValueStore, StorageSystem};
use crate::commons::version::KrillVersion;
use crate::constants::PUBSERVER_NS;
use crate::config::Config;
use crate::server::pubd::access::{
RepositoryAccess, RepositoryAccessEvent, RepositoryAccessInitEvent,
StorableRepositoryCommand,
@@ -32,19 +31,15 @@ pub struct PublicationServerRepositoryAccessMigration {
impl PublicationServerRepositoryAccessMigration {
pub fn upgrade(
mode: UpgradeMode,
config: &Config,
storage: &StorageSystem,
versions: &UpgradeVersions,
) -> UpgradeResult<()> {
let current_kv_store =
KeyValueStore::create(&config.storage_uri, PUBSERVER_NS)?;
let new_kv_store = KeyValueStore::create_upgrade_store(
&config.storage_uri,
PUBSERVER_NS,
)?;
let current_kv_store = storage.open(PUBSERVER_NS)?;
let new_kv_store = storage.open_upgrade(PUBSERVER_NS)?;
let new_agg_store = AggregateStore::create_upgrade_store(
&config.storage_uri,
storage,
PUBSERVER_NS,
config.use_history_cache,
false,
)?;
let store_migration = PublicationServerRepositoryAccessMigration {
+20 -4
View File
@@ -19,6 +19,7 @@ use tokio::sync::{mpsc as tokio_mpsc, oneshot};
use crate::commons::actor::Actor;
use crate::commons::crypto::{KrillSigner, KrillSignerBuilder};
use crate::commons::error::KrillError;
use crate::commons::storage::StorageSystem;
use crate::config::Config;
use crate::constants::{ACTOR_DEF_KRILL, KRILL_SERVER_APP};
use super::bgp::BgpAnalyser;
@@ -49,6 +50,7 @@ impl KrillRuntime {
/// async tasks onto.
pub fn new(
config: Config,
storage: StorageSystem,
tokio: runtime::Handle,
) -> Result<Self, KrillError> {
let service_uri = config.service_uri();
@@ -60,7 +62,7 @@ impl KrillRuntime {
// used to update signer name references to resolve to the
// corresponding signer configurations.
let signer = KrillSignerBuilder::new(
&config.storage_uri,
&storage,
Duration::from_secs(config.signer_probe_retry_seconds),
&config.signers,
).with_default_signer(
@@ -69,14 +71,15 @@ impl KrillRuntime {
config.one_off_signer()
).build()?;
let tasks = TaskQueue::new(&config.storage_uri)?;
let repo_manager = RepositoryManager::new(&config)?;
let ca_manager = CaManager::new(&config)?;
let tasks = TaskQueue::new(&storage)?;
let repo_manager = RepositoryManager::new(&config, &storage)?;
let ca_manager = CaManager::new(&config, &storage)?;
let bgp_analyser = BgpAnalyser::new(&config);
Ok(Self(Arc::new(Components {
config,
service_uri,
storage,
repo_manager,
ca_manager,
tasks,
@@ -97,6 +100,11 @@ impl KrillRuntime {
&self.0.service_uri
}
/// Returns a reference to the storage system.
pub fn storage(&self) -> &StorageSystem {
&self.0.storage
}
/// Returns the repository manager.
pub fn repo_manager(&self) -> &RepositoryManager {
&self.0.repo_manager
@@ -165,6 +173,11 @@ impl SlowKrillRuntime {
self.runtime().service_uri()
}
/// Returns a reference to the storage system.
pub fn storage(&self) -> &StorageSystem {
self.runtime().storage()
}
/// Returns the repository manager.
pub fn repo_manager(&self) -> &RepositoryManager {
self.runtime().repo_manager()
@@ -235,6 +248,9 @@ struct Components {
/// value which may be missing.
service_uri: uri::Https,
/// The storage system used by all components.
storage: StorageSystem,
/// Publication server with configured publishers
repo_manager: RepositoryManager,
+10 -11
View File
@@ -7,7 +7,6 @@ use std::time::Duration;
use log::{debug, error, info, warn};
use rpki::ca::idexchange::{CaHandle, ParentHandle};
use rpki::ca::provisioning::{ResourceClassName, RevocationRequest};
use url::Url;
use crate::{
api::ca::Timestamp,
@@ -15,7 +14,7 @@ use crate::{
crypto::dispatch::signerinfo::SignerInfo,
error::{Error, FatalError},
eventsourcing::{Aggregate, AggregateStore, WalStore, WalSupport},
storage::Ident,
storage::{Ident, StorageSystem},
version::KrillVersion,
},
constants::{
@@ -524,10 +523,10 @@ fn renew_objects_if_needed(
// Call update_snapshots on all AggregateStores and WalStores
fn update_snapshots(krill: &KrillRuntime) -> Result<TaskResult, FatalError> {
fn update_aggregate_store_snapshots<A: Aggregate>(
storage_uri: &Url,
storage: &StorageSystem,
namespace: &Ident,
) {
match AggregateStore::<A>::create(storage_uri, namespace, false) {
match AggregateStore::<A>::create(storage, namespace, false) {
Err(e) => {
// Note: this is highly unlikely.. probably something else
// is broken and Krill would
@@ -555,10 +554,10 @@ fn update_snapshots(krill: &KrillRuntime) -> Result<TaskResult, FatalError> {
}
fn update_wal_store_snapshots<W: WalSupport>(
storage_uri: &Url,
storage: &StorageSystem,
namespace: &Ident,
) {
match WalStore::<W>::create(storage_uri, namespace) {
match WalStore::<W>::create(storage, namespace) {
Err(e) => {
// Note: this is highly unlikely.. probably something else
// is broken and Krill would
@@ -583,19 +582,19 @@ fn update_snapshots(krill: &KrillRuntime) -> Result<TaskResult, FatalError> {
}
update_aggregate_store_snapshots::<CertAuth>(
&krill.config().storage_uri, CASERVER_NS,
krill.storage(), CASERVER_NS,
);
update_aggregate_store_snapshots::<SignerInfo>(
&krill.config().storage_uri, SIGNERS_NS,
krill.storage(), SIGNERS_NS,
);
update_aggregate_store_snapshots::<Properties>(
&krill.config().storage_uri, PROPERTIES_NS,
krill.storage(), PROPERTIES_NS,
);
update_aggregate_store_snapshots::<RepositoryAccess>(
&krill.config().storage_uri, PUBSERVER_NS,
krill.storage(), PUBSERVER_NS,
);
update_wal_store_snapshots::<RepositoryContent>(
&krill.config().storage_uri, PUBSERVER_CONTENT_NS,
krill.storage(), PUBSERVER_CONTENT_NS,
);
Ok(TaskResult::FollowUp(Task::UpdateSnapshots, in_hours(24)))
+8 -6
View File
@@ -6,10 +6,10 @@ use std::{
use log::LevelFilter;
use serde::Deserialize;
use url::Url;
use crate::{
commons::crypto::{KrillSigner, KrillSignerBuilder, OpenSslSignerConfig},
commons::storage::{StorageSystem, StorageUri},
constants::OPENSSL_ONE_OFF_SIGNER_NAME,
config::{LogType, SignerConfig, SignerReference, SignerType},
};
@@ -93,9 +93,8 @@ impl TaTimingConfig {
pub struct Config {
#[serde(
alias = "data_dir",
deserialize_with = "crate::config::deserialize_storage_uri"
)]
pub storage_uri: Url,
pub storage_uri: StorageUri,
#[serde(default)]
pub use_history_cache: bool,
@@ -228,7 +227,9 @@ impl Config {
}
// Signer support
pub fn signer(&self) -> Result<KrillSigner, ConfigError> {
pub fn signer(
&self, storage: &StorageSystem
) -> Result<KrillSigner, ConfigError> {
// Assumes that Config::verify() has already ensured that the signer
// configuration is valid and that Config::resolve() has been
// used to update signer name references to resolve to the
@@ -236,7 +237,7 @@ impl Config {
let probe_interval =
std::time::Duration::from_secs(self.signer_probe_retry_seconds);
let signer = KrillSignerBuilder::new(
&self.storage_uri,
storage,
probe_interval,
&self.signers,
)
@@ -381,7 +382,8 @@ mod tests {
let config_string =
include_str!("../../test-resources/ta/ta.conf");
let config = Config::parse_str(config_string).unwrap();
config.signer().unwrap();
let storage = StorageSystem::new(config.storage_uri.clone());
config.signer(&storage).unwrap();
})
}
}
+44 -42
View File
@@ -4,18 +4,17 @@ use std::{str::FromStr};
use log::info;
use rpki::crypto::KeyIdentifier;
use url::Url;
use crate::{
commons::{
crypto::{
dispatch::signerinfo::SignerInfo,
OpenSslSigner,
OpenSslSigner, OpenSslSignerConfig,
},
eventsourcing::{
Aggregate, AggregateStore, WalStore, WalSupport,
},
storage::{Ident, KeyValueStore},
storage::{Ident, StorageSystem, StorageUri},
},
constants::{
KEYS_NS, PROPERTIES_NS, PUBSERVER_CONTENT_NS,
@@ -37,7 +36,9 @@ use crate::{
use super::UpgradeResult;
pub fn migrate(mut config: Config, target_storage: Url) -> UpgradeResult<()> {
pub fn migrate(
config: Config, target_storage: &StorageSystem
) -> UpgradeResult<()> {
// Copy the source data from config unmodified into the target_storage
info!("-----------------------------------------------------------");
info!(" Krill Data Migration");
@@ -46,19 +47,19 @@ pub fn migrate(mut config: Config, target_storage: Url) -> UpgradeResult<()> {
info!("-----------------------------------------------------------");
info!("STEP 1: Copy data");
info!("");
info!("From: {}", &config.storage_uri);
info!(" To: {}", &target_storage);
info!("From: {}", config.storage_uri);
info!(" To: {}", target_storage.default_uri());
info!("-----------------------------------------------------------");
info!("");
copy_data_for_migration(&config, &target_storage)?;
copy_data_for_migration(target_storage, &config.storage_uri)?;
// Update the config file with the new target_storage
// and perform a normal data migration - the source data
// could be for an older version of Krill.
config.storage_uri = target_storage;
let properties_manager =
PropertiesManager::create(&config.storage_uri, false)?;
let properties_manager = PropertiesManager::create(
target_storage, false
)?;
info!("-----------------------------------------------------------");
info!("STEP 2: Upgrade data to current Krill version (if needed)");
@@ -66,12 +67,13 @@ pub fn migrate(mut config: Config, target_storage: Url) -> UpgradeResult<()> {
info!("");
if let Some(upgrade) = prepare_upgrade_data_migrations(
crate::upgrades::UpgradeMode::PrepareToFinalise,
target_storage,
&config,
&properties_manager,
)? {
finalise_data_migration(
upgrade.versions(),
&config,
target_storage,
&properties_manager,
)?;
}
@@ -92,53 +94,53 @@ pub fn migrate(mut config: Config, target_storage: Url) -> UpgradeResult<()> {
// That said, it's a pretty easy check to perform and it kind of makes
// sense to do it to now, even if it would be to point users at deeper
// source data issues.
verify_target_data(&config)
verify_target_data(target_storage, &config)
}
fn verify_target_data(config: &Config) -> UpgradeResult<()> {
check_agg_store::<Properties>(config, PROPERTIES_NS, "Properties")?;
check_agg_store::<SignerInfo>(config, SIGNERS_NS, "Signer")?;
fn verify_target_data(
storage: &StorageSystem, config: &Config
) -> UpgradeResult<()> {
check_agg_store::<Properties>(storage, PROPERTIES_NS, "Properties")?;
check_agg_store::<SignerInfo>(storage, SIGNERS_NS, "Signer")?;
check_ca_objects(config)?;
check_ca_objects(storage, config)?;
check_agg_store::<RepositoryAccess>(
config,
storage,
PUBSERVER_NS,
"Publication Server Access",
)?;
check_wal_store::<RepositoryContent>(
config,
storage,
PUBSERVER_CONTENT_NS,
"Publication Server Objects",
)?;
check_agg_store::<TrustAnchorProxy>(
config,
storage,
TA_PROXY_SERVER_NS,
"TA Proxy",
)?;
check_agg_store::<TrustAnchorSigner>(
config,
storage,
TA_SIGNER_SERVER_NS,
"TA Signer",
)?;
check_openssl_keys(config)?;
check_openssl_keys(storage)?;
Ok(())
}
fn check_openssl_keys(config: &Config) -> UpgradeResult<()> {
fn check_openssl_keys(storage: &StorageSystem) -> UpgradeResult<()> {
info!("");
info!("Verify: OpenSSL keys");
let open_ssl_signer = OpenSslSigner::build(
&config.storage_uri,
"test",
None,
storage, &OpenSslSignerConfig::default(), "test", None,
)
.map_err(|e| {
UpgradeError::Custom(format!("Cannot create openssl signer: {e}"))
})?;
let keys_key_store = KeyValueStore::create(&config.storage_uri, KEYS_NS)?;
let keys_key_store = storage.open(KEYS_NS)?;
for key in keys_key_store.keys(None, "")? {
let key_id =
@@ -159,14 +161,14 @@ fn check_openssl_keys(config: &Config) -> UpgradeResult<()> {
}
pub fn check_agg_store<A: Aggregate>(
config: &Config,
storage: &StorageSystem,
ns: &Ident,
name: &str,
) -> UpgradeResult<AggregateStore<A>> {
info!("");
info!("Verify: {name}");
let store: AggregateStore<A> =
AggregateStore::create(&config.storage_uri, ns, false)?;
AggregateStore::create(storage, ns, false)?;
if !store.list()?.is_empty() {
store.warm()?;
info!("Ok");
@@ -177,13 +179,13 @@ pub fn check_agg_store<A: Aggregate>(
}
fn check_wal_store<W: WalSupport>(
config: &Config,
storage: &StorageSystem,
ns: &Ident,
name: &str,
) -> UpgradeResult<()> {
info!("");
info!("Verify: {name}");
let store: WalStore<W> = WalStore::create(&config.storage_uri, ns)?;
let store: WalStore<W> = WalStore::create(storage, ns)?;
if !store.list()?.is_empty() {
store.warm()?;
info!("Ok");
@@ -194,8 +196,8 @@ fn check_wal_store<W: WalSupport>(
}
fn copy_data_for_migration(
config: &Config,
target_storage: &Url,
target_storage: &StorageSystem,
source_storage: &StorageUri,
) -> UpgradeResult<()> {
const NAMESPACES: &[&Ident] = &[
Ident::make("ca_objects"),
@@ -209,13 +211,11 @@ fn copy_data_for_migration(
Ident::make("ta_signer"),
];
for namespace in NAMESPACES {
let source_kv_store = KeyValueStore::create(
&config.storage_uri, namespace
let source_kv_store = target_storage.open_uri(
source_storage, namespace
)?;
if !source_kv_store.is_empty()? {
let target_kv_store = KeyValueStore::create(
target_storage, namespace
)?;
let target_kv_store = target_storage.open(namespace)?;
target_kv_store.import(&source_kv_store)?;
}
}
@@ -225,6 +225,7 @@ fn copy_data_for_migration(
#[cfg(test)]
pub mod tests {
use std::env;
use std::path::PathBuf;
use log::LevelFilter;
use crate::commons::test;
@@ -232,10 +233,11 @@ pub mod tests {
#[test]
fn test_data_migration() {
// Create a config file that uses test data for its storage_uri
let test_sources_base = "test-resources/migrations/v0_9_5/";
let test_sources_url =
Url::parse(&format!("local://{test_sources_base}")).unwrap();
let test_sources_url = StorageUri::disk(
env::current_dir().unwrap().join(
"test-resources/migrations/v0_9_5/"
)
);
let bogus_path = PathBuf::from("/dev/null"); // needed for tls_dir etc, but will be ignored here
let mut config = Config::test(
@@ -253,7 +255,7 @@ pub mod tests {
// Create an in-memory target store to migrate to
let target_store = test::mem_storage();
migrate(config, target_store).unwrap();
migrate(config, &target_store).unwrap();
}
}
+73 -83
View File
@@ -23,7 +23,10 @@ use crate::{
Storable, StoredCommand, WalStoreError,
WithStorableDetails,
},
storage::{Ident, KeyValueError, KeyValueStore},
storage::{
Ident, KeyValueError, KeyValueStore, OpenStoreError,
StorageSystem,
},
version::KrillVersion,
KrillResult,
},
@@ -222,6 +225,12 @@ impl From<AggregateStoreError> for UpgradeError {
}
}
impl From<OpenStoreError> for UpgradeError {
fn from(e: OpenStoreError) -> Self {
UpgradeError::custom(e)
}
}
impl From<WalStoreError> for UpgradeError {
fn from(e: WalStoreError) -> Self {
UpgradeError::WalStoreError(e)
@@ -570,7 +579,7 @@ pub trait UpgradeAggregateStorePre0_14 {
// Verify migration
info!(
"Will verify the migration by rebuilding '{}' from migrated commands",
&scope
scope
);
let _latest = self.preparation_aggregate_store().save_snapshot(&handle).map_err(|e| {
UpgradeError::Custom(format!(
@@ -810,8 +819,10 @@ pub trait UpgradeAggregateStorePre0_14 {
/// started, it will call this again - to do the final preparation for a
/// migration - knowing that no changes are added to the event history at this
/// time. After this, the migration will be finalised.
#[allow(unused_variables)]
pub fn prepare_upgrade_data_migrations(
mode: UpgradeMode,
storage: &StorageSystem,
config: &Config,
properties_manager: &PropertiesManager,
) -> UpgradeResult<Option<UpgradeReport>> {
@@ -824,9 +835,9 @@ pub fn prepare_upgrade_data_migrations(
// just do at startup. It is done here, because in effect it *is* a data
// migration.
#[cfg(feature = "hsm")]
record_preexisting_openssl_keys_in_signer_mapper(config)?;
record_preexisting_openssl_keys_in_signer_mapper(storage, config)?;
match upgrade_versions(config, properties_manager)? {
match upgrade_versions(storage, properties_manager)? {
None => Ok(None),
Some(versions) => {
info!(
@@ -841,9 +852,7 @@ pub fn prepare_upgrade_data_migrations(
// easily be migrated to the new setup in 0.13.0.
// Well.. it could be done, if there would be a strong use
// case to put in the effort, but there really isn't.
let ca_kv_store = KeyValueStore::create(
&config.storage_uri, CASERVER_NS
)?;
let ca_kv_store = storage.open(CASERVER_NS)?;
if ca_kv_store.has_scope(const { Ident::make("ta") })? {
return Err(UpgradeError::OldTaMigration);
}
@@ -860,19 +869,19 @@ pub fn prepare_upgrade_data_migrations(
}
else if versions.from < KrillVersion::candidate(0, 10, 0, 1) {
// Complex migrations involving command / event conversions
pubd::pre_0_10_0::PublicationServerRepositoryAccessMigration::upgrade(mode, config, &versions)?;
pubd::pre_0_10_0::PublicationServerRepositoryAccessMigration::upgrade(mode, storage, &versions)?;
let aspa_configs =
ca::pre_0_10_0::CasMigration::upgrade(mode, config)?;
ca::pre_0_10_0::CasMigration::upgrade(mode, storage)?;
// The way that pubd objects were stored was changed as well
// (since 0.13.0)
pubd::migrate_pre_0_12_pubd_objects(config)?;
pubd::migrate_pre_0_12_pubd_objects(storage)?;
// Migrate remaining aggregate stores used in < 0.10.0 to the
// new format in 0.14.0 where we combine
// commands and events into a single key-value pair.
pre_0_14_0::UpgradeAggregateStoreSignerInfo::upgrade(
SIGNERS_NS, mode, config,
SIGNERS_NS, mode, storage,
)?;
Ok(Some(UpgradeReport::new(aspa_configs, true, versions)))
@@ -888,38 +897,38 @@ pub fn prepare_upgrade_data_migrations(
);
// The pubd objects storage changed in 0.13.0
pubd::migrate_pre_0_12_pubd_objects(config)?;
pubd::migrate_pre_0_12_pubd_objects(storage)?;
// Migrate aggregate stores used in < 0.12.0 to the new format
// in 0.14.0 where we combine commands and
// events into a single key-value pair.
pre_0_14_0::UpgradeAggregateStoreSignerInfo::upgrade(
SIGNERS_NS, mode, config,
SIGNERS_NS, mode, storage,
)?;
let aspa_configs =
ca::pre_0_14_0::CasMigration::upgrade(mode, config)?;
ca::pre_0_14_0::CasMigration::upgrade(mode, storage)?;
pubd::pre_0_14_0::UpgradeAggregateStoreRepositoryAccess::upgrade(
PUBSERVER_NS,
mode,
config,
storage
)?;
Ok(Some(UpgradeReport::new(aspa_configs, true, versions)))
} else if versions.from < KrillVersion::candidate(0, 13, 0, 0) {
pubd::migrate_0_12_pubd_objects(config)?;
pubd::migrate_0_12_pubd_objects(storage)?;
// Migrate aggregate stores used in < 0.13.0 to the new format
// in 0.14.0 where we combine commands and
// events into a single key-value pair.
pre_0_14_0::UpgradeAggregateStoreSignerInfo::upgrade(
SIGNERS_NS, mode, config,
SIGNERS_NS, mode, storage,
)?;
let aspa_configs =
ca::pre_0_14_0::CasMigration::upgrade(mode, config)?;
ca::pre_0_14_0::CasMigration::upgrade(mode, storage)?;
pubd::pre_0_14_0::UpgradeAggregateStoreRepositoryAccess::upgrade(
PUBSERVER_NS,
mode,
config,
storage,
)?;
Ok(Some(UpgradeReport::new(aspa_configs, true, versions)))
@@ -928,24 +937,24 @@ pub fn prepare_upgrade_data_migrations(
// in 0.14.0 where we combine commands and
// events into a single key-value pair.
let aspa_configs =
ca::pre_0_14_0::CasMigration::upgrade(mode, config)?;
ca::pre_0_14_0::CasMigration::upgrade(mode, storage)?;
pubd::pre_0_14_0::UpgradeAggregateStoreRepositoryAccess::upgrade(
PUBSERVER_NS,
mode,
config,
storage,
)?;
pre_0_14_0::UpgradeAggregateStoreSignerInfo::upgrade(
SIGNERS_NS, mode, config,
SIGNERS_NS, mode, storage,
)?;
pre_0_14_0::UpgradeAggregateStoreTrustAnchorSigner::upgrade(
TA_SIGNER_SERVER_NS,
mode,
config,
storage,
)?;
pre_0_14_0::UpgradeAggregateStoreTrustAnchorProxy::upgrade(
TA_PROXY_SERVER_NS,
mode,
config,
storage,
)?;
Ok(Some(UpgradeReport::new(aspa_configs, true, versions)))
@@ -967,7 +976,7 @@ pub fn prepare_upgrade_data_migrations(
/// - make the prepared data current
pub fn finalise_data_migration(
upgrade: &UpgradeVersions,
config: &Config,
storage: &StorageSystem,
properties_manager: &PropertiesManager,
) -> KrillResult<()> {
// For each NS
@@ -998,24 +1007,19 @@ pub fn finalise_data_migration(
] {
// Check if there is a non-empty upgrade store for this namespace
// that would need to be migrated.
let mut upgrade_store =
KeyValueStore::create_upgrade_store(&config.storage_uri, ns)?;
if !upgrade_store.is_empty()? {
info!("Migrate new data for {ns} and archive old");
let mut current_store =
KeyValueStore::create(&config.storage_uri, ns)?;
if !current_store.is_empty()? {
current_store.migrate_to_archive(&config.storage_uri, ns)?;
if !storage.is_upgrade_empty(ns)? {
if !storage.is_empty(ns)? {
info!("Archiving old data for {ns}.");
storage.migrate_to_archive(ns)?;
}
upgrade_store.migrate_to_current(&config.storage_uri, ns)?;
info!("Migrate new data for {ns}.");
storage.migrate_to_current(ns)?;
} else {
// No migration needed, but check if we have a current store
// for this namespace that still includes a version file. If
// so, remove it.
let current_store = KeyValueStore::create(
&config.storage_uri, ns
)?;
let current_store = storage.open(ns)?;
if current_store.has(None, VERSION_KEY)? {
debug!("Removing excess version key in ns: {ns}");
current_store.drop_key(None, VERSION_KEY)?;
@@ -1052,10 +1056,10 @@ pub fn finalise_data_migration(
/// adding the keys one by one to the mapping in the signer store, if any.
#[cfg(feature = "hsm")]
fn record_preexisting_openssl_keys_in_signer_mapper(
storage: &StorageSystem,
config: &Config,
) -> Result<(), UpgradeError> {
let signers_key_store =
KeyValueStore::create(&config.storage_uri, SIGNERS_NS)?;
let signers_key_store = storage.open(SIGNERS_NS)?;
if signers_key_store.is_empty()? {
let mut num_recorded_keys = 0;
// If the key value store for the "signers" namespace is empty, then
@@ -1063,19 +1067,16 @@ fn record_preexisting_openssl_keys_in_signer_mapper(
// from a previous krill installation (earlier version, or a custom
// build that has the hsm feature disabled.)
let keys_key_store =
KeyValueStore::create(&config.storage_uri, KEYS_NS)?;
let keys_key_store = storage.open(KEYS_NS)?;
info!(
"Mapping OpenSSL signer keys, using uri: {}",
config.storage_uri
storage.default_uri()
);
let probe_interval =
std::time::Duration::from_secs(config.signer_probe_retry_seconds);
let krill_signer = crate::commons::crypto::KrillSignerBuilder::new(
&config.storage_uri,
probe_interval,
&config.signers,
storage, probe_interval, &config.signers,
)
.with_default_signer(config.default_signer())
.with_one_off_signer(config.one_off_signer())
@@ -1180,7 +1181,7 @@ pub fn post_start_upgrade(
/// - if the code is the same version then we do not upgrade
/// - if the code is older then we need to error out
fn upgrade_versions(
config: &Config,
storage: &StorageSystem,
properties_manager: &PropertiesManager,
) -> Result<Option<UpgradeVersions>, UpgradeError> {
if properties_manager.is_initialized() {
@@ -1217,7 +1218,7 @@ fn upgrade_versions(
PUBSERVER_NS,
PUBSERVER_CONTENT_NS,
] {
let kv_store = KeyValueStore::create(&config.storage_uri, ns)?;
let kv_store = storage.open(ns)?;
if let Some(key_store_version) =
kv_store.get::<KrillVersion>(None, VERSION_KEY)?
{
@@ -1254,8 +1255,7 @@ mod tests {
use std::path::PathBuf;
use log::LevelFilter;
use tempfile::tempdir;
use url::Url;
use crate::commons::storage::Ident;
use crate::commons::storage::{Ident, StorageUri};
use crate::commons::test;
use crate::server::ca::{CaStatus, CaStatusStore};
use super::*;
@@ -1282,42 +1282,39 @@ mod tests {
copy_folder(base_dir, &temp_dir);
// Copy data for the given names spaces into memory for testing.
let mem_storage_base_uri = test::mem_storage();
let mem_storage = test::mem_storage();
// This is needed for tls_dir etc, but will be ignored here.
let bogus_path = PathBuf::from("/dev/null");
let mut config = Config::test(
&mem_storage_base_uri,
mem_storage.default_uri(),
Some(&bogus_path),
false, false, false, false,
);
config.log_level = LevelFilter::Trace;
let _ = config.init_logging();
let source_url = Url::parse(&format!(
"local://{}", temp_dir.path().to_str().unwrap()
)).unwrap();
let source_url = StorageUri::disk(temp_dir.path().into());
for ns in namespaces {
let namespace = Ident::from_str(ns).unwrap();
let source_store = KeyValueStore::create(
let source_store = mem_storage.open_uri(
&source_url, namespace
).unwrap();
let target_store = KeyValueStore::create(
&mem_storage_base_uri, namespace
).unwrap();
let target_store = mem_storage.open(namespace).unwrap();
target_store.import(&source_store).unwrap();
}
let properties_manager = PropertiesManager::create(
&config.storage_uri,
&mem_storage,
config.use_history_cache,
).unwrap();
prepare_upgrade_data_migrations(
UpgradeMode::PrepareOnly,
&mem_storage,
&config,
&properties_manager,
).unwrap().unwrap();
@@ -1326,13 +1323,14 @@ mod tests {
// again.
let report = prepare_upgrade_data_migrations(
UpgradeMode::PrepareToFinalise,
&mem_storage,
&config,
&properties_manager,
).unwrap().unwrap();
finalise_data_migration(
report.versions(),
&config,
&mem_storage,
&properties_manager,
).unwrap();
}
@@ -1461,25 +1459,19 @@ mod tests {
).unwrap();
// Copy test data into test storage
let mem_storage_base_uri = test::mem_storage();
let mem_storage = test::mem_storage();
let source_url = Url::parse(&format!(
"local://{}", temp_dir.path().to_str().unwrap()
)).unwrap();
let source_store = KeyValueStore::create(
&source_url, KEYS_NS
).unwrap();
let source_storage = StorageSystem::new_disk(temp_dir.path().into());
let source_store = source_storage.open(KEYS_NS).unwrap();
let target_store = KeyValueStore::create(
&mem_storage_base_uri, KEYS_NS
).unwrap();
let target_store = mem_storage.open(KEYS_NS).unwrap();
target_store.import(&source_store).unwrap();
// This is needed for tls_dir etc, but will be ignored here.
let bogus_path = PathBuf::from("/dev/null");
let mut config = Config::test(
&mem_storage_base_uri,
mem_storage.default_uri(),
Some(&bogus_path),
false, false, false, false,
);
@@ -1488,7 +1480,7 @@ mod tests {
if do_upgrade {
record_preexisting_openssl_keys_in_signer_mapper(
&config
&mem_storage, &config,
).unwrap();
}
@@ -1500,7 +1492,7 @@ mod tests {
config.signer_probe_retry_seconds
);
let krill_signer = crate::commons::crypto::KrillSignerBuilder::new(
&mem_storage_base_uri,
&mem_storage,
probe_interval,
&config.signers,
).with_default_signer(
@@ -1554,16 +1546,15 @@ mod tests {
"test-resources/status_store/migration-0.9.5/";
let temp_dir = tempdir().unwrap();
copy_folder(source_dir_path_str, &temp_dir);
let source_dir_url = Url::parse(
&format!("local://{}", &temp_dir.path().to_str().unwrap()))
.unwrap();
let source_dir_url = StorageUri::disk(temp_dir.path().into());
let source_store =
KeyValueStore::create(&source_dir_url, STATUS_NS).unwrap();
let test_storage = test::mem_storage();
let test_storage_uri = test::mem_storage();
let status_kv_store =
KeyValueStore::create(&test_storage_uri, STATUS_NS).unwrap();
let source_store = test_storage.open_uri(
&source_dir_url, STATUS_NS
).unwrap();
let status_kv_store = test_storage.open(STATUS_NS).unwrap();
// copy the source KV store (files) into the test KV store (in memory)
status_kv_store.import(&source_store).unwrap();
@@ -1578,8 +1569,7 @@ mod tests {
// Initialise the StatusStore using the new (in memory) storage,
// and migrate the data.
let store =
CaStatusStore::create(&test_storage_uri, STATUS_NS).unwrap();
let store = CaStatusStore::create(&test_storage, STATUS_NS).unwrap();
let testbed = CaHandle::from_str("testbed").unwrap();
// Get the migrated status for testbed and verify that it's equivalent
+6 -11
View File
@@ -17,9 +17,8 @@ use crate::{
Aggregate, AggregateStore, Storable,
StoredCommand, StoredCommandBuilder, WithStorableDetails,
},
storage::{Ident, KeyValueStore},
storage::{Ident, KeyValueStore, StorageSystem},
},
config::Config,
server::{
properties::Properties,
},
@@ -299,23 +298,19 @@ impl<A: Aggregate> GenericUpgradeAggregateStore<A> {
pub fn upgrade(
name_space: &Ident,
mode: UpgradeMode,
config: &Config,
storage: &StorageSystem,
) -> UpgradeResult<AspaMigrationConfigs> {
let current_kv_store =
KeyValueStore::create(&config.storage_uri, name_space)?;
let current_kv_store = storage.open(name_space)?;
if current_kv_store.scopes()?.is_empty() {
// nothing to do here
Ok(AspaMigrationConfigs::default())
} else {
let new_kv_store = KeyValueStore::create_upgrade_store(
&config.storage_uri,
name_space,
)?;
let new_kv_store = storage.open_upgrade(name_space)?;
let new_agg_store = AggregateStore::<A>::create_upgrade_store(
&config.storage_uri,
storage,
name_space,
config.use_history_cache,
false,
)?;
let store_migration = GenericUpgradeAggregateStore {
+7 -7
View File
@@ -5,7 +5,6 @@ use std::collections::HashMap;
use std::env;
use std::str::FromStr;
use std::time::Duration;
use url::Url;
use log::LevelFilter;
use log::{debug, error};
use reqwest::StatusCode;
@@ -23,6 +22,7 @@ use krill::api;
use krill::api::admin::Token;
use krill::commons::httpclient;
use krill::commons::crypto::OpenSslSignerConfig;
use krill::commons::storage::StorageUri;
use krill::cli::client::{KrillClient, ServerUri};
use krill::constants::REPOSITORY_DIR;
use krill::config::{
@@ -39,7 +39,7 @@ use krill::tasigner::TaTimingConfig;
/// A test config builder.
pub struct TestConfig {
storage_uri: Url,
storage_uri: StorageUri,
data_dir: TempDir,
port: u16,
enable_testbed: bool,
@@ -52,7 +52,7 @@ impl TestConfig {
pub fn mem_storage() -> Self {
let data_dir = TempDir::new().unwrap();
Self::new(
Url::parse(
StorageUri::from_str(
&format!(
"memory://{}", hex::encode(rand::random::<[u8; 8]>())
)
@@ -64,14 +64,14 @@ impl TestConfig {
pub fn file_storage() -> Self {
let data_dir = TempDir::new().unwrap();
Self::new(
Url::parse(
StorageUri::from_str(
&format!("local://{}/data/", data_dir.path().display())
).unwrap() ,
data_dir,
)
}
fn new(storage_uri: Url, data_dir: TempDir) -> Self {
fn new(storage_uri: StorageUri, data_dir: TempDir) -> Self {
Self {
storage_uri,
data_dir,
@@ -889,8 +889,8 @@ pub async fn sleep_seconds(secs: u64) {
sleep(Duration::from_secs(secs)).await
}
pub async fn sleep_millis(secs: u64) {
sleep(Duration::from_millis(secs)).await
pub async fn sleep_millis(millisecs: u64) {
sleep(Duration::from_millis(millisecs)).await
}
/// Checks if a result has certain non-200 HTTP status code.
+3 -1
View File
@@ -56,17 +56,19 @@ async fn functional_old_data() {
// XXX Wait for Krill to process pending tasks.
eprintln!(">>>> Wait a bit for Krill to catch up.");
common::sleep_millis(1000).await;
common::sleep_millis(3000).await;
eprintln!(">>>> Make TA proxy signer request.");
let request =
server.client().ta_proxy_signer_make_request().await.unwrap();
assert_eq!(request.ta_renew_time.unwrap().year(), 2026);
assert_eq!(request.renew_times[0].1.year(), 2039);
common::sleep_millis(1000).await;
eprintln!(">>>> Sign TA proxy signer request.");
let response = signer.process(request.into(), None).unwrap();
assert_eq!(response.content().child_responses.len(), 1);
common::sleep_millis(1000).await;
eprintln!(">>>> Process TA proxy signer response.");
server.client().ta_proxy_signer_response(response).await.unwrap();
+1 -1
View File
@@ -1 +1 @@
0.9
0.10.0
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#ffffff" d="M495 59.6C516.9 81.47 516.9 116.9 495 138.8L182.3 451.6C170.9 462.9 156.9 471.2 141.5 475.8L20.52 511.4C14.9 513 8.827 511.5 4.687 507.3C.5466 503.2-1.002 497.1 .6506 491.5L36.23 370.5C40.76 355.1 49.09 341.1 60.44 329.7L373.2 16.97C395.1-4.897 430.5-4.897 452.4 16.97L495 59.6zM341 94.4L417.6 170.1L472.4 116.2C481.8 106.8 481.8 91.6 472.4 82.23L429.8 39.6C420.4 30.23 405.2 30.23 395.8 39.6L341 94.4zM318.4 117L83.07 352.4C75.5 359.9 69.95 369.3 66.93 379.6L39.63 472.4L132.4 445.1C142.7 442.1 152.1 436.5 159.6 428.9L394.1 193.6L318.4 117z" /></svg>

Before

Width:  |  Height:  |  Size: 638 B

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -5,8 +5,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Krill-RPKI</title>
<link rel="icon" href="/assets/favicon-f84116cb.ico">
<script type="module" crossorigin src="/assets/index-17d9117e.js"></script>
<link rel="stylesheet" href="/assets/index-d02216b4.css">
<script type="module" crossorigin src="/assets/index-ce7af331.js"></script>
<link rel="stylesheet" href="/assets/index-35ed2154.css">
</head>
<body>
<div id="root"></div>