Skip to content

Commit

Permalink
Add retry configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
sosthene-nitrokey committed Jan 3, 2024
1 parent 4660f8a commit 8a2a438
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 31 deletions.
5 changes: 4 additions & 1 deletion p11nethsm.conf
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ slots:
danger_insecure_cert: true
# sha256_fingerprints:
# - "31:92:8E:A4:5E:16:5C:A7:33:44:E8:E9:8E:64:C4:AE:7B:2A:57:E5:77:43:49:F3:69:C9:8F:C4:2F:3A:3B:6E"
# timeout: 10
retries:
count: 10
delay_seconds: 1
timeout: 10
2 changes: 1 addition & 1 deletion pkcs11/src/api/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ mod tests {
device_error: 0,
enum_ctx: None,
flags: 0,
login_ctx: LoginCtx::new(None, None, vec![]),
login_ctx: LoginCtx::new(None, None, vec![], None),
slot_id: 0,
};

Expand Down
9 changes: 7 additions & 2 deletions pkcs11/src/api/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub extern "C" fn C_GetSlotInfo(

let mut flags = 0;

let mut login_ctx = LoginCtx::new(None, None, slot.instances.clone());
let mut login_ctx = LoginCtx::new(None, None, slot.instances.clone(), slot.retries);

let result = login_ctx.try_(
|conf| default_api::info_get(&conf),

Check failure on line 93 in pkcs11/src/api/token.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> pkcs11/src/api/token.rs:93:38 | 93 | |conf| default_api::info_get(&conf), | ^^^^^ help: change this to: `conf` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

Check failure on line 93 in pkcs11/src/api/token.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> pkcs11/src/api/token.rs:93:38 | 93 | |conf| default_api::info_get(&conf), | ^^^^^ help: change this to: `conf` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
Expand Down Expand Up @@ -160,7 +160,12 @@ pub extern "C" fn C_GetTokenInfo(
return cryptoki_sys::CKR_ARGUMENTS_BAD;
}

let mut login_ctx = LoginCtx::new(None, slot.administrator.clone(), slot.instances.clone());
let mut login_ctx = LoginCtx::new(
None,
slot.administrator.clone(),
slot.instances.clone(),
slot.retries,
);

let result = login_ctx.try_(
|conf| default_api::info_get(&conf),

Check failure on line 171 in pkcs11/src/api/token.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> pkcs11/src/api/token.rs:171:38 | 171 | |conf| default_api::info_get(&conf), | ^^^^^ help: change this to: `conf` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

Check failure on line 171 in pkcs11/src/api/token.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> pkcs11/src/api/token.rs:171:38 | 171 | |conf| default_api::info_get(&conf), | ^^^^^ help: change this to: `conf` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
Expand Down
2 changes: 1 addition & 1 deletion pkcs11/src/backend/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn update_slot_state(slot_id: CK_SLOT_ID, present: bool) {

pub fn fetch_slots_state() {
for (index, slot) in DEVICE.slots.iter().enumerate() {
let mut login_ctx = LoginCtx::new(None, None, slot.instances.clone());
let mut login_ctx = LoginCtx::new(None, None, slot.instances.clone(), slot.retries);
let status = login_ctx
.try_(
|conf| default_api::health_state_get(&conf),

Check failure on line 42 in pkcs11/src/backend/events.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> pkcs11/src/backend/events.rs:42:54 | 42 | |conf| default_api::health_state_get(&conf), | ^^^^^ help: change this to: `conf` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

Check failure on line 42 in pkcs11/src/backend/events.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> pkcs11/src/backend/events.rs:42:54 | 42 | |conf| default_api::health_state_get(&conf), | ^^^^^ help: change this to: `conf` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
Expand Down
68 changes: 45 additions & 23 deletions pkcs11/src/backend/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ use cryptoki_sys::{
CKR_USER_TYPE_INVALID, CKS_RO_PUBLIC_SESSION, CKS_RW_SO_FUNCTIONS, CKS_RW_USER_FUNCTIONS,
CKU_CONTEXT_SPECIFIC, CKU_SO, CKU_USER, CK_RV, CK_STATE, CK_USER_TYPE,
};
use log::{debug, error, trace};
use log::{debug, error, trace, warn};
use nethsm_sdk_rs::{
apis::{self, configuration::Configuration, default_api, ResponseContent},
models::UserRole,
ureq,
};
use std::{thread, time::Duration};

use crate::config::config_file::UserConfig;
use crate::config::config_file::{RetryConfig, UserConfig};

use super::{ApiError, Error};

Expand All @@ -21,6 +22,7 @@ pub struct LoginCtx {
instances: Vec<Configuration>,
index: usize,
ck_state: CK_STATE,
retries: Option<RetryConfig>,
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -64,6 +66,7 @@ impl LoginCtx {
operator: Option<UserConfig>,
administrator: Option<UserConfig>,
instances: Vec<Configuration>,
retries: Option<RetryConfig>,
) -> Self {
let mut ck_state = CKS_RO_PUBLIC_SESSION;

Expand All @@ -81,6 +84,7 @@ impl LoginCtx {
operator,
administrator,
instances,
retries,
index: 0,
ck_state,
}
Expand Down Expand Up @@ -193,35 +197,53 @@ impl LoginCtx {
F: FnOnce(&Configuration) -> Result<R, apis::Error<T>> + Clone,
{
// we loop for a maximum of instances.len() times
for _ in 0..self.instances.len() {
'instances: for _ in 0..self.instances.len() {
let conf = match self.get_config_user_mode(&user_mode) {
Some(conf) => conf,
None => continue,
};

let api_call_clone = api_call.clone();
match api_call_clone(&conf) {
Ok(result) => return Ok(result),

// If the server is in an unusable state, try the next one
Err(apis::Error::ResponseError(ResponseContent { status: 500, .. }))
| Err(apis::Error::ResponseError(ResponseContent { status: 501, .. }))
| Err(apis::Error::ResponseError(ResponseContent { status: 502, .. }))
| Err(apis::Error::ResponseError(ResponseContent { status: 503, .. }))
| Err(apis::Error::ResponseError(ResponseContent { status: 412, .. })) => {
continue;
}
let mut retry_count = 0;
let RetryConfig {
count: retry_limit,
delay_seconds,
} = self.retries.unwrap_or(RetryConfig {
count: 1,
delay_seconds: 0,
});

loop {
retry_count += 1;
let api_call_clone = api_call.clone();
match api_call_clone(&conf) {
Ok(result) => return Ok(result),

// If the server is in an unusable state, try the next one
Err(apis::Error::ResponseError(ResponseContent { status: 500, .. }))
| Err(apis::Error::ResponseError(ResponseContent { status: 501, .. }))
| Err(apis::Error::ResponseError(ResponseContent { status: 502, .. }))
| Err(apis::Error::ResponseError(ResponseContent { status: 503, .. }))
| Err(apis::Error::ResponseError(ResponseContent { status: 412, .. })) => {
continue 'instances;

Check warning on line 227 in pkcs11/src/backend/login.rs

View check run for this annotation

Codecov / codecov/patch

pkcs11/src/backend/login.rs#L227

Added line #L227 was not covered by tests
}

Err(apis::Error::Ureq(ureq::Error::Transport(err))) => {
if matches!(
err.kind(),
ureq::ErrorKind::Io | ureq::ErrorKind::ConnectionFailed
) {
return Err(ApiError::InstanceRemoved);
Err(apis::Error::Ureq(ureq::Error::Transport(err)))
if matches!(

Check warning on line 231 in pkcs11/src/backend/login.rs

View check run for this annotation

Codecov / codecov/patch

pkcs11/src/backend/login.rs#L231

Added line #L231 was not covered by tests
err.kind(),
ureq::ErrorKind::Io | ureq::ErrorKind::ConnectionFailed
) =>
{
if retry_count == retry_limit {
error!("Retry count exceeded, instance is unreachable: {err}");
return Err(ApiError::InstanceRemoved);
}

warn!("IO error connecting to the instance, {err}, retrying in {delay_seconds}s");
thread::sleep(Duration::from_secs(delay_seconds));

Check warning on line 242 in pkcs11/src/backend/login.rs

View check run for this annotation

Codecov / codecov/patch

pkcs11/src/backend/login.rs#L239-L242

Added lines #L239 - L242 were not covered by tests
}
// Otherwise, return the error
Err(err) => return Err(err.into()),
}
// Otherwise, return the error
Err(err) => return Err(err.into()),
}
}
Err(ApiError::NoInstance)
Expand Down
2 changes: 2 additions & 0 deletions pkcs11/src/backend/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ impl SessionManager {
0,
Arc::new(Slot {
administrator: None,
retries: None,
db: Arc::new(Mutex::new(Db::new())),
description: None,
instances: vec![],
Expand Down Expand Up @@ -125,6 +126,7 @@ impl Session {
slot.operator.clone(),
slot.administrator.clone(),
slot.instances.clone(),
slot.retries,
);

Self {
Expand Down
10 changes: 9 additions & 1 deletion pkcs11/src/config/config_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ pub struct P11Config {
pub slots: Vec<SlotConfig>,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct RetryConfig {
pub count: u32,
pub delay_seconds: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InstanceConfig {
pub url: String,
Expand All @@ -104,7 +110,9 @@ pub struct SlotConfig {
pub description: Option<String>,
pub instances: Vec<InstanceConfig>,
#[serde(default)]
pub timeout: Option<u64>,
pub retries: Option<RetryConfig>,
#[serde(default)]
pub timeout_seconds: Option<u64>,
}

// An user
Expand Down
3 changes: 2 additions & 1 deletion pkcs11/src/config/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use nethsm_sdk_rs::apis::configuration::Configuration;

use crate::backend::db::Db;

use super::config_file::UserConfig;
use super::config_file::{RetryConfig, UserConfig};

// stores the global configuration of the module
#[derive(Debug, Clone)]
Expand All @@ -22,6 +22,7 @@ pub struct ClusterInstance {
#[derive(Debug, Clone)]
pub struct Slot {
pub label: String,
pub retries: Option<RetryConfig>,
pub description: Option<String>,
pub instances: Vec<Configuration>,
pub operator: Option<UserConfig>,
Expand Down
3 changes: 2 additions & 1 deletion pkcs11/src/config/initialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ fn slot_from_config(slot: &SlotConfig) -> Result<Slot, InitializationError> {
.max_idle_connections(2)
.max_idle_connections_per_host(2);

if let Some(t) = slot.timeout {
if let Some(t) = slot.timeout_seconds {
builder = builder.timeout(Duration::from_secs(t));

Check warning on line 129 in pkcs11/src/config/initialization.rs

View check run for this annotation

Codecov / codecov/patch

pkcs11/src/config/initialization.rs#L129

Added line #L129 was not covered by tests
}

Expand All @@ -147,6 +147,7 @@ fn slot_from_config(slot: &SlotConfig) -> Result<Slot, InitializationError> {
instances,
administrator: slot.administrator.clone(),
operator: slot.operator.clone(),
retries: slot.retries,
db: Arc::new(Mutex::new(crate::backend::db::Db::new())),
})
}

0 comments on commit 8a2a438

Please sign in to comment.