Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/bindings/rust/src/cmap.rs b/bindings/rust/src/cmap.rs
index f35f58f9..93539db3 100644
--- a/bindings/rust/src/cmap.rs
+++ b/bindings/rust/src/cmap.rs
@@ -1,898 +1,898 @@
// libcmap interface for Rust
// Copyright (c) 2021 Red Hat, Inc.
//
// All rights reserved.
//
// Author: Christine Caulfield (ccaulfi@redhat.com)
//
#![allow(clippy::type_complexity)]
// For the code generated by bindgen
use crate::sys::cmap as ffi;
use num_enum::TryFromPrimitive;
use std::any::type_name;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::ffi::CString;
use std::fmt;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr::copy_nonoverlapping;
use std::sync::Mutex;
use crate::string_from_bytes;
use crate::{CsError, DispatchFlags, Result};
// Maps:
/// "Maps" available to [initialize]
pub enum Map {
Icmap,
Stats,
}
bitflags! {
/// Tracker types for cmap, both passed into [track_add]
/// and returned from its callback.
pub struct TrackType: i32
{
const DELETE = 1;
const MODIFY = 2;
const ADD = 4;
const PREFIX = 8;
}
}
impl fmt::Display for TrackType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.contains(TrackType::DELETE) {
write!(f, "DELETE ")?
}
if self.contains(TrackType::MODIFY) {
write!(f, "MODIFY ")?
}
if self.contains(TrackType::ADD) {
write!(f, "ADD ")?
}
if self.contains(TrackType::PREFIX) {
write!(f, "PREFIX ")
} else {
Ok(())
}
}
}
#[derive(Copy, Clone)]
/// A handle returned from [initialize], needs to be passed to all other cmap API calls
pub struct Handle {
cmap_handle: u64,
}
#[derive(Copy, Clone)]
/// A handle for a specific CMAP tracker. returned from [track_add].
/// There may be multiple TrackHandles per [Handle]
pub struct TrackHandle {
track_handle: u64,
notify_callback: NotifyCallback,
}
// Used to convert CMAP handles into one of ours, for callbacks
lazy_static! {
static ref TRACKHANDLE_HASH: Mutex<HashMap<u64, TrackHandle>> = Mutex::new(HashMap::new());
static ref HANDLE_HASH: Mutex<HashMap<u64, Handle>> = Mutex::new(HashMap::new());
}
/// Initialize a connection to the cmap subsystem.
/// map specifies which cmap "map" to use.
/// Returns a [Handle] into the cmap library
pub fn initialize(map: Map) -> Result<Handle> {
let mut handle: ffi::cmap_handle_t = 0;
let c_map = match map {
Map::Icmap => ffi::CMAP_MAP_ICMAP,
Map::Stats => ffi::CMAP_MAP_STATS,
};
unsafe {
let res = ffi::cmap_initialize_map(&mut handle, c_map);
if res == ffi::CS_OK {
let rhandle = Handle {
cmap_handle: handle,
};
HANDLE_HASH.lock().unwrap().insert(handle, rhandle);
Ok(rhandle)
} else {
Err(CsError::from_c(res))
}
}
}
/// Finish with a connection to corosync.
/// Takes a [Handle] as returned from [initialize]
pub fn finalize(handle: Handle) -> Result<()> {
let res = unsafe { ffi::cmap_finalize(handle.cmap_handle) };
if res == ffi::CS_OK {
HANDLE_HASH.lock().unwrap().remove(&handle.cmap_handle);
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// Return a file descriptor to use for poll/select on the CMAP handle.
/// Takes a [Handle] as returned from [initialize],
/// returns a C file descriptor as i32
pub fn fd_get(handle: Handle) -> Result<i32> {
let c_fd: *mut c_int = &mut 0 as *mut _ as *mut c_int;
let res = unsafe { ffi::cmap_fd_get(handle.cmap_handle, c_fd) };
if res == ffi::CS_OK {
Ok(c_fd as i32)
} else {
Err(CsError::from_c(res))
}
}
/// Dispatch any/all active CMAP callbacks.
/// Takes a [Handle] as returned from [initialize],
/// flags [DispatchFlags] tells it how many items to dispatch before returning
pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
let res = unsafe { ffi::cmap_dispatch(handle.cmap_handle, flags as u32) };
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// Get the current 'context' value for this handle
/// The context value is an arbitrary value that is always passed
/// back to callbacks to help identify the source
pub fn context_get(handle: Handle) -> Result<u64> {
let (res, context) = unsafe {
let mut context: u64 = 0;
let c_context: *mut c_void = &mut context as *mut _ as *mut c_void;
let r = ffi::cmap_context_get(handle.cmap_handle, c_context as *mut *const c_void);
(r, context)
};
if res == ffi::CS_OK {
Ok(context)
} else {
Err(CsError::from_c(res))
}
}
/// Set the current 'context' value for this handle
/// The context value is an arbitrary value that is always passed
/// back to callbacks to help identify the source.
/// Normally this is set in [initialize], but this allows it to be changed
pub fn context_set(handle: Handle, context: u64) -> Result<()> {
let res = unsafe {
let c_context = context as *mut c_void;
ffi::cmap_context_set(handle.cmap_handle, c_context)
};
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// The type of data returned from [get] or in a
/// tracker callback or iterator, part of the [Data] struct
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u32)]
pub enum DataType {
Int8 = ffi::CMAP_VALUETYPE_INT8,
UInt8 = ffi::CMAP_VALUETYPE_UINT8,
Int16 = ffi::CMAP_VALUETYPE_INT16,
UInt16 = ffi::CMAP_VALUETYPE_UINT16,
Int32 = ffi::CMAP_VALUETYPE_INT32,
UInt32 = ffi::CMAP_VALUETYPE_UINT32,
Int64 = ffi::CMAP_VALUETYPE_INT64,
UInt64 = ffi::CMAP_VALUETYPE_UINT64,
Float = ffi::CMAP_VALUETYPE_FLOAT,
Double = ffi::CMAP_VALUETYPE_DOUBLE,
String = ffi::CMAP_VALUETYPE_STRING,
Binary = ffi::CMAP_VALUETYPE_BINARY,
Unknown = 999,
}
fn cmap_to_enum(cmap_type: u32) -> DataType {
match DataType::try_from(cmap_type) {
Ok(e) => e,
Err(_) => DataType::Unknown,
}
}
/// Data returned from the cmap::get() call and tracker & iterators.
/// Contains the data itself and the type of that data.
pub enum Data {
Int8(i8),
UInt8(u8),
Int16(i16),
UInt16(u16),
Int32(i32),
UInt32(u32),
Int64(i64),
UInt64(u64),
Float(f32),
Double(f64),
String(String),
Binary(Vec<u8>),
Unknown,
}
impl fmt::Display for DataType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DataType::Int8 => write!(f, "Int8"),
DataType::UInt8 => write!(f, "UInt8"),
DataType::Int16 => write!(f, "Int16"),
DataType::UInt16 => write!(f, "UInt16"),
DataType::Int32 => write!(f, "Int32"),
DataType::UInt32 => write!(f, "UInt32"),
DataType::Int64 => write!(f, "Int64"),
DataType::UInt64 => write!(f, "UInt64"),
DataType::Float => write!(f, "Float"),
DataType::Double => write!(f, "Double"),
DataType::String => write!(f, "String"),
DataType::Binary => write!(f, "Binary"),
DataType::Unknown => write!(f, "Unknown"),
}
}
}
impl fmt::Display for Data {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
- Data::Int8(v) => write!(f, "{} (Int8)", v),
- Data::UInt8(v) => write!(f, "{} (UInt8)", v),
- Data::Int16(v) => write!(f, "{} (Int16)", v),
- Data::UInt16(v) => write!(f, "{} (UInt16)", v),
- Data::Int32(v) => write!(f, "{} (Int32)", v),
- Data::UInt32(v) => write!(f, "{} (UInt32)", v),
- Data::Int64(v) => write!(f, "{} (Int64)", v),
- Data::UInt64(v) => write!(f, "{} (UInt64)", v),
- Data::Float(v) => write!(f, "{} (Float)", v),
- Data::Double(v) => write!(f, "{} (Double)", v),
- Data::String(v) => write!(f, "{} (String)", v),
- Data::Binary(v) => write!(f, "{:?} (Binary)", v),
+ Data::Int8(v) => write!(f, "{v} (Int8)"),
+ Data::UInt8(v) => write!(f, "{v} (UInt8)"),
+ Data::Int16(v) => write!(f, "{v} (Int16)"),
+ Data::UInt16(v) => write!(f, "{v} (UInt16)"),
+ Data::Int32(v) => write!(f, "{v} (Int32)"),
+ Data::UInt32(v) => write!(f, "{v} (UInt32)"),
+ Data::Int64(v) => write!(f, "{v} (Int64)"),
+ Data::UInt64(v) => write!(f, "{v} (UInt64)"),
+ Data::Float(v) => write!(f, "{v} (Float)"),
+ Data::Double(v) => write!(f, "{v} (Double)"),
+ Data::String(v) => write!(f, "{v} (String)"),
+ Data::Binary(v) => write!(f, "{v:?} (Binary)"),
Data::Unknown => write!(f, "Unknown)"),
}
}
}
const CMAP_KEYNAME_MAXLENGTH: usize = 255;
fn string_to_cstring_validated(key: &str, maxlen: usize) -> Result<CString> {
if maxlen > 0 && key.chars().count() >= maxlen {
return Err(CsError::CsErrInvalidParam);
}
match CString::new(key) {
Ok(n) => Ok(n),
Err(_) => Err(CsError::CsErrLibrary),
}
}
fn set_value(
handle: Handle,
key_name: &str,
datatype: DataType,
value: *mut c_void,
length: usize,
) -> Result<()> {
let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let res = unsafe {
ffi::cmap_set(
handle.cmap_handle,
csname.as_ptr(),
value,
length,
datatype as u32,
)
};
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
// Returns type and size
fn generic_to_cmap<T>(_value: T) -> (DataType, usize) {
match type_name::<T>() {
"u8" => (DataType::UInt8, 1),
"i8" => (DataType::Int8, 1),
"u16" => (DataType::UInt16, 2),
"i16" => (DataType::Int16, 2),
"u32" => (DataType::UInt32, 4),
"i32" => (DataType::Int32, 4),
"u64" => (DataType::UInt64, 4),
"f32" => (DataType::Float, 4),
"f64" => (DataType::Double, 8),
"&str" => (DataType::String, 0),
// Binary not currently supported here
_ => (DataType::Unknown, 0),
}
}
fn is_numeric_type(dtype: DataType) -> bool {
matches!(
dtype,
DataType::UInt8
| DataType::Int8
| DataType::UInt16
| DataType::Int16
| DataType::UInt32
| DataType::Int32
| DataType::UInt64
| DataType::Int64
| DataType::Float
| DataType::Double
)
}
/// Function to set a generic numeric value
/// This doesn't work for strings or binaries
pub fn set_number<T: Copy>(handle: Handle, key_name: &str, value: T) -> Result<()> {
let (c_type, c_size) = generic_to_cmap(value);
if is_numeric_type(c_type) {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, c_type, c_value as *mut c_void, c_size)
} else {
Err(CsError::CsErrNotSupported)
}
}
pub fn set_u8(handle: Handle, key_name: &str, value: u8) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::UInt8, c_value as *mut c_void, 1)
}
/// Sets an i8 value into cmap
pub fn set_i8(handle: Handle, key_name: &str, value: i8) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::Int8, c_value as *mut c_void, 1)
}
/// Sets a u16 value into cmap
pub fn set_u16(handle: Handle, key_name: &str, value: u16) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(
handle,
key_name,
DataType::UInt16,
c_value as *mut c_void,
2,
)
}
/// Sets an i16 value into cmap
pub fn set_i16(handle: Handle, key_name: &str, value: i16) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::Int16, c_value as *mut c_void, 2)
}
/// Sets a u32 value into cmap
pub fn set_u32(handle: Handle, key_name: &str, value: u32) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::UInt32, c_value, 4)
}
/// Sets an i32 value into cmap
pub fn set_i132(handle: Handle, key_name: &str, value: i32) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::Int32, c_value as *mut c_void, 4)
}
/// Sets a u64 value into cmap
pub fn set_u64(handle: Handle, key_name: &str, value: u64) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(
handle,
key_name,
DataType::UInt64,
c_value as *mut c_void,
8,
)
}
/// Sets an i64 value into cmap
pub fn set_i164(handle: Handle, key_name: &str, value: i64) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::Int64, c_value as *mut c_void, 8)
}
/// Sets a string value into cmap
pub fn set_string(handle: Handle, key_name: &str, value: &str) -> Result<()> {
let v_string = string_to_cstring_validated(value, 0)?;
set_value(
handle,
key_name,
DataType::String,
v_string.as_ptr() as *mut c_void,
value.chars().count(),
)
}
/// Sets a binary value into cmap
pub fn set_binary(handle: Handle, key_name: &str, value: &[u8]) -> Result<()> {
set_value(
handle,
key_name,
DataType::Binary,
value.as_ptr() as *mut c_void,
value.len(),
)
}
/// Sets a [Data] type into cmap
pub fn set(handle: Handle, key_name: &str, data: &Data) -> Result<()> {
let (datatype, datalen, c_value) = match data {
Data::Int8(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Int8, 1, cv)
}
Data::UInt8(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::UInt8, 1, cv)
}
Data::Int16(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Int16, 2, cv)
}
Data::UInt16(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::UInt8, 2, cv)
}
Data::Int32(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Int32, 4, cv)
}
Data::UInt32(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::UInt32, 4, cv)
}
Data::Int64(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Int64, 8, cv)
}
Data::UInt64(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::UInt64, 8, cv)
}
Data::Float(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Float, 4, cv)
}
Data::Double(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Double, 8, cv)
}
Data::String(v) => {
let cv = string_to_cstring_validated(v, 0)?;
// Can't let cv go out of scope
return set_value(
handle,
key_name,
DataType::String,
cv.as_ptr() as *mut c_void,
v.chars().count(),
);
}
Data::Binary(v) => {
// Vec doesn't return quite the right types.
return set_value(
handle,
key_name,
DataType::Binary,
v.as_ptr() as *mut c_void,
v.len(),
);
}
Data::Unknown => return Err(CsError::CsErrInvalidParam),
};
set_value(handle, key_name, datatype, c_value, datalen)
}
// Local function to parse out values from the C mess
// Assumes the c_value is complete. So cmap::get() will need to check the size
// and re-get before calling us with a resized buffer
fn c_to_data(value_size: usize, c_key_type: u32, c_value: *const u8) -> Result<Data> {
unsafe {
match cmap_to_enum(c_key_type) {
DataType::UInt8 => {
let mut ints = [0u8; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::UInt8(ints[0]))
}
DataType::Int8 => {
let mut ints = [0i8; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Int8(ints[0]))
}
DataType::UInt16 => {
let mut ints = [0u16; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::UInt16(ints[0]))
}
DataType::Int16 => {
let mut ints = [0i16; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Int16(ints[0]))
}
DataType::UInt32 => {
let mut ints = [0u32; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::UInt32(ints[0]))
}
DataType::Int32 => {
let mut ints = [0i32; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Int32(ints[0]))
}
DataType::UInt64 => {
let mut ints = [0u64; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::UInt64(ints[0]))
}
DataType::Int64 => {
let mut ints = [0i64; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Int64(ints[0]))
}
DataType::Float => {
let mut ints = [0f32; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Float(ints[0]))
}
DataType::Double => {
let mut ints = [0f64; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Double(ints[0]))
}
DataType::String => {
let mut ints = Vec::<u8>::new();
ints.resize(value_size, 0u8);
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
// -1 here so CString doesn't see the NUL
let cs = match CString::new(&ints[0..value_size - 1_usize]) {
Ok(c1) => c1,
Err(_) => return Err(CsError::CsErrLibrary),
};
match cs.into_string() {
Ok(s) => Ok(Data::String(s)),
Err(_) => Err(CsError::CsErrLibrary),
}
}
DataType::Binary => {
let mut ints = Vec::<u8>::new();
ints.resize(value_size, 0u8);
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Binary(ints))
}
DataType::Unknown => Ok(Data::Unknown),
}
}
}
const INITIAL_SIZE: usize = 256;
/// Get a value from cmap, returned as a [Data] struct, so could be anything
pub fn get(handle: Handle, key_name: &str) -> Result<Data> {
let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let mut value_size: usize = 16;
let mut c_key_type: u32 = 0;
let mut c_value = Vec::<u8>::new();
// First guess at a size for Strings and Binaries. Expand if needed
c_value.resize(INITIAL_SIZE, 0u8);
unsafe {
let res = ffi::cmap_get(
handle.cmap_handle,
csname.as_ptr(),
c_value.as_mut_ptr() as *mut c_void,
&mut value_size,
&mut c_key_type,
);
if res == ffi::CS_OK {
if value_size > INITIAL_SIZE {
// Need to try again with a bigger buffer
c_value.resize(value_size, 0u8);
let res2 = ffi::cmap_get(
handle.cmap_handle,
csname.as_ptr(),
c_value.as_mut_ptr() as *mut c_void,
&mut value_size,
&mut c_key_type,
);
if res2 != ffi::CS_OK {
return Err(CsError::from_c(res2));
}
}
// Convert to Rust type and return as a Data enum
c_to_data(value_size, c_key_type, c_value.as_ptr())
} else {
Err(CsError::from_c(res))
}
}
}
/// increment the value in a cmap key (must be a numeric type)
pub fn inc(handle: Handle, key_name: &str) -> Result<()> {
let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let res = unsafe { ffi::cmap_inc(handle.cmap_handle, csname.as_ptr()) };
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// decrement the value in a cmap key (must be a numeric type)
pub fn dec(handle: Handle, key_name: &str) -> Result<()> {
let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let res = unsafe { ffi::cmap_dec(handle.cmap_handle, csname.as_ptr()) };
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
// Callback for CMAP notify events from corosync, convert params to Rust and pass on.
extern "C" fn rust_notify_fn(
cmap_handle: ffi::cmap_handle_t,
cmap_track_handle: ffi::cmap_track_handle_t,
event: i32,
key_name: *const ::std::os::raw::c_char,
new_value: ffi::cmap_notify_value,
old_value: ffi::cmap_notify_value,
user_data: *mut ::std::os::raw::c_void,
) {
// If cmap_handle doesn't match then throw away the callback.
if let Some(r_cmap_handle) = HANDLE_HASH.lock().unwrap().get(&cmap_handle) {
if let Some(h) = TRACKHANDLE_HASH.lock().unwrap().get(&cmap_track_handle) {
let r_keyname = match string_from_bytes(key_name, CMAP_KEYNAME_MAXLENGTH) {
Ok(s) => s,
Err(_) => return,
};
let r_old = match c_to_data(old_value.len, old_value.type_, old_value.data as *const u8)
{
Ok(v) => v,
Err(_) => return,
};
let r_new = match c_to_data(new_value.len, new_value.type_, new_value.data as *const u8)
{
Ok(v) => v,
Err(_) => return,
};
if let Some(cb) = h.notify_callback.notify_fn {
(cb)(
r_cmap_handle,
h,
TrackType { bits: event },
&r_keyname,
&r_old,
&r_new,
user_data as u64,
);
}
}
}
}
/// Callback function called every time a tracker reports a change in a tracked value
#[derive(Copy, Clone)]
pub struct NotifyCallback {
pub notify_fn: Option<
fn(
handle: &Handle,
track_handle: &TrackHandle,
event: TrackType,
key_name: &str,
new_value: &Data,
old_value: &Data,
user_data: u64,
),
>,
}
/// Track changes in cmap values, multiple [TrackHandle]s per [Handle] are allowed
pub fn track_add(
handle: Handle,
key_name: &str,
track_type: TrackType,
notify_callback: &NotifyCallback,
user_data: u64,
) -> Result<TrackHandle> {
let c_name = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let mut c_trackhandle = 0u64;
let res = unsafe {
ffi::cmap_track_add(
handle.cmap_handle,
c_name.as_ptr(),
track_type.bits,
Some(rust_notify_fn),
user_data as *mut c_void,
&mut c_trackhandle,
)
};
if res == ffi::CS_OK {
let rhandle = TrackHandle {
track_handle: c_trackhandle,
notify_callback: *notify_callback,
};
TRACKHANDLE_HASH
.lock()
.unwrap()
.insert(c_trackhandle, rhandle);
Ok(rhandle)
} else {
Err(CsError::from_c(res))
}
}
/// Remove a tracker frm this [Handle]
pub fn track_delete(handle: Handle, track_handle: TrackHandle) -> Result<()> {
let res = unsafe { ffi::cmap_track_delete(handle.cmap_handle, track_handle.track_handle) };
if res == ffi::CS_OK {
TRACKHANDLE_HASH
.lock()
.unwrap()
.remove(&track_handle.track_handle);
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// Create one of these to start iterating over cmap values.
pub struct CmapIterStart {
iter_handle: u64,
cmap_handle: u64,
}
pub struct CmapIntoIter {
cmap_handle: u64,
iter_handle: u64,
}
/// Value returned from the iterator. contains the key name and the [Data]
pub struct CmapIter {
key_name: String,
data: Data,
}
impl CmapIter {
pub fn key_name(&self) -> &str {
&self.key_name
}
pub fn data(&self) -> &Data {
&self.data
}
}
impl fmt::Debug for CmapIter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", self.key_name, self.data)
}
}
impl Iterator for CmapIntoIter {
type Item = CmapIter;
fn next(&mut self) -> Option<CmapIter> {
let mut c_key_name = [0u8; CMAP_KEYNAME_MAXLENGTH + 1];
let mut c_value_len = 0usize;
let mut c_value_type = 0u32;
let res = unsafe {
ffi::cmap_iter_next(
self.cmap_handle,
self.iter_handle,
c_key_name.as_mut_ptr() as *mut c_char,
&mut c_value_len,
&mut c_value_type,
)
};
if res == ffi::CS_OK {
// Return the Data for this iteration
let mut c_value = Vec::<u8>::new();
c_value.resize(c_value_len, 0u8);
let res = unsafe {
ffi::cmap_get(
self.cmap_handle,
c_key_name.as_ptr() as *mut c_char,
c_value.as_mut_ptr() as *mut c_void,
&mut c_value_len,
&mut c_value_type,
)
};
if res == ffi::CS_OK {
match c_to_data(c_value_len, c_value_type, c_value.as_ptr()) {
Ok(d) => {
let r_keyname = match string_from_bytes(
c_key_name.as_ptr() as *mut c_char,
CMAP_KEYNAME_MAXLENGTH,
) {
Ok(s) => s,
Err(_) => return None,
};
Some(CmapIter {
key_name: r_keyname,
data: d,
})
}
Err(_) => None,
}
} else {
// cmap_get returned error
None
}
} else if res == ffi::CS_ERR_NO_SECTIONS {
// End of list
unsafe {
// Yeah, we don't check this return code. There's nowhere to report it.
ffi::cmap_iter_finalize(self.cmap_handle, self.iter_handle)
};
None
} else {
None
}
}
}
impl CmapIterStart {
/// Create a new [CmapIterStart] object for iterating over a list of cmap keys
pub fn new(cmap_handle: Handle, prefix: &str) -> Result<CmapIterStart> {
let mut iter_handle: u64 = 0;
let res = unsafe {
let c_prefix = string_to_cstring_validated(prefix, CMAP_KEYNAME_MAXLENGTH)?;
ffi::cmap_iter_init(cmap_handle.cmap_handle, c_prefix.as_ptr(), &mut iter_handle)
};
if res == ffi::CS_OK {
Ok(CmapIterStart {
cmap_handle: cmap_handle.cmap_handle,
iter_handle,
})
} else {
Err(CsError::from_c(res))
}
}
}
impl IntoIterator for CmapIterStart {
type Item = CmapIter;
type IntoIter = CmapIntoIter;
fn into_iter(self) -> Self::IntoIter {
CmapIntoIter {
iter_handle: self.iter_handle,
cmap_handle: self.cmap_handle,
}
}
}
diff --git a/bindings/rust/tests/src/bin/cfg-test.rs b/bindings/rust/tests/src/bin/cfg-test.rs
index 02eda099..cd70d388 100644
--- a/bindings/rust/tests/src/bin/cfg-test.rs
+++ b/bindings/rust/tests/src/bin/cfg-test.rs
@@ -1,136 +1,135 @@
// Test the CFG library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::{cfg, NodeId};
use std::thread::spawn;
fn dispatch_thread(handle: cfg::Handle) {
loop {
if cfg::dispatch(handle, corosync::DispatchFlags::One).is_err() {
return;
}
}
}
// Test the shutdown callback
fn shutdown_check_fn(handle: &cfg::Handle, _flags: u32) {
println!("in shutdown callback");
// DON'T shutdown corosync - we're just testing
if let Err(e) = cfg::reply_to_shutdown(*handle, cfg::ShutdownReply::No) {
- println!("Error in CFG replyto_shutdown: {}", e);
+ println!("Error in CFG replyto_shutdown: {e}");
}
}
fn main() {
// Initialise the callbacks data
let cb = cfg::Callbacks {
corosync_cfg_shutdown_callback_fn: Some(shutdown_check_fn),
};
let handle = match cfg::initialize(&cb) {
Ok(h) => {
println!("cfg initialized.");
h
}
Err(e) => {
- println!("Error in CFG init: {}", e);
+ println!("Error in CFG init: {e}");
return;
}
};
// Open two handles to CFG so that the second one can refuse shutdown
let handle2 = match cfg::initialize(&cb) {
Ok(h) => {
println!("cfg2 initialized.");
h
}
Err(e) => {
- println!("Error in CFG init: {}", e);
+ println!("Error in CFG init: {e}");
return;
}
};
match cfg::track_start(handle2, cfg::TrackFlags::None) {
Ok(_) => {
// Run handle2 dispatch in its own thread
spawn(move || dispatch_thread(handle2));
}
Err(e) => {
- println!("Error in CFG track_start: {}", e);
+ println!("Error in CFG track_start: {e}");
}
};
let local_nodeid = {
match cfg::local_get(handle) {
Ok(n) => {
- println!("Local nodeid is {}", n);
+ println!("Local nodeid is {n}");
Some(n)
}
Err(e) => {
- println!("Error in CFG local_get: {}", e);
+ println!("Error in CFG local_get: {e}");
None
}
}
};
// Test node_status_get.
// node status for the local node looks odd (cos it's the loopback connection), so
// we try for a node ID one less or more than us just to get output that looks
// sensible to the user.
if let Some(our_nodeid) = local_nodeid {
let us_plus1 = NodeId::from(u32::from(our_nodeid) + 1);
let us_less1 = NodeId::from(u32::from(our_nodeid) - 1);
let mut res = cfg::node_status_get(handle, us_plus1, cfg::NodeStatusVersion::V1);
if let Err(e) = res {
- println!("Error from node_status_get on nodeid {}: {}", us_plus1, e);
+ println!("Error from node_status_get on nodeid {us_plus1}: {e}");
res = cfg::node_status_get(handle, us_less1, cfg::NodeStatusVersion::V1);
};
match res {
Ok(ns) => {
println!("Node Status for nodeid {}", ns.nodeid);
println!(" reachable: {}", ns.reachable);
println!(" remote: {}", ns.remote);
println!(" onwire_min: {}", ns.onwire_min);
println!(" onwire_max: {}", ns.onwire_max);
println!(" onwire_ver: {}", ns.onwire_ver);
for (ls_num, ls) in ns.link_status.iter().enumerate() {
if ls.enabled {
- println!(" Link {}", ls_num);
+ println!(" Link {ls_num}");
println!(" connected: {}", ls.connected);
println!(" mtu: {}", ls.mtu);
println!(" src: {}", ls.src_ipaddr);
println!(" dst: {}", ls.dst_ipaddr);
}
}
}
Err(e) => {
println!(
- "Error in CFG node_status get: {} (tried nodeids {} & {})",
- e, us_plus1, us_less1
+ "Error in CFG node_status get: {e} (tried nodeids {us_plus1} & {us_less1})"
);
}
}
}
// This should not shutdown corosync because the callback on handle2 will refuse it.
match cfg::try_shutdown(handle, cfg::ShutdownFlags::Request) {
Ok(_) => {
println!("CFG try_shutdown suceeded, should return busy");
}
Err(e) => {
if e != corosync::CsError::CsErrBusy {
- println!("Error in CFG try_shutdown: {}", e);
+ println!("Error in CFG try_shutdown: {e}");
}
}
}
// Wait for events
loop {
if cfg::dispatch(handle, corosync::DispatchFlags::One).is_err() {
break;
}
}
println!("ERROR: Corosync quit");
}
diff --git a/bindings/rust/tests/src/bin/cmap-test.rs b/bindings/rust/tests/src/bin/cmap-test.rs
index 5747ba35..f4356536 100644
--- a/bindings/rust/tests/src/bin/cmap-test.rs
+++ b/bindings/rust/tests/src/bin/cmap-test.rs
@@ -1,198 +1,195 @@
// Test the CMAP library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::cmap;
fn track_notify_fn(
_handle: &cmap::Handle,
_track_handle: &cmap::TrackHandle,
event: cmap::TrackType,
key_name: &str,
old_value: &cmap::Data,
new_value: &cmap::Data,
user_data: u64,
) {
println!("Track notify callback");
- println!(
- "Key: {}, event: {}, user_data: {}",
- key_name, event, user_data
- );
- println!(" Old value: {}", old_value);
- println!(" New value: {}", new_value);
+ println!("Key: {key_name}, event: {event}, user_data: {user_data}");
+ println!(" Old value: {old_value}");
+ println!(" New value: {new_value}");
}
fn main() {
let handle = match cmap::initialize(cmap::Map::Icmap) {
Ok(h) => {
println!("cmap initialized.");
h
}
Err(e) => {
- println!("Error in CMAP (Icmap) init: {}", e);
+ println!("Error in CMAP (Icmap) init: {e}");
return;
}
};
// Test some SETs
if let Err(e) = cmap::set_u32(handle, "test.test_uint32", 456) {
- println!("Error in CMAP set_u32: {}", e);
+ println!("Error in CMAP set_u32: {e}");
return;
};
if let Err(e) = cmap::set_i16(handle, "test.test_int16", -789) {
- println!("Error in CMAP set_i16: {}", e);
+ println!("Error in CMAP set_i16: {e}");
return;
};
if let Err(e) = cmap::set_number(handle, "test.test_num_1", 6809u32) {
- println!("Error in CMAP set_number(u32): {}", e);
+ println!("Error in CMAP set_number(u32): {e}");
return;
};
// NOT PI (just to avoid clippy whingeing)
if let Err(e) = cmap::set_number(handle, "test.test_num_2", 3.24159265) {
- println!("Error in CMAP set_number(f32): {}", e);
+ println!("Error in CMAP set_number(f32): {e}");
return;
};
if let Err(e) = cmap::set_string(handle, "test.test_string", "Hello from Rust") {
- println!("Error in CMAP set_string: {}", e);
+ println!("Error in CMAP set_string: {e}");
return;
};
let test_d = cmap::Data::UInt64(0xdeadbeefbacecafe);
if let Err(e) = cmap::set(handle, "test.test_data", &test_d) {
- println!("Error in CMAP set_data: {}", e);
+ println!("Error in CMAP set_data: {e}");
return;
};
// let test_d2 = cmap::Data::UInt32(6809);
let test_d2 = cmap::Data::String("Test string in data 12345".to_string());
if let Err(e) = cmap::set(handle, "test.test_again", &test_d2) {
- println!("Error in CMAP set_data2: {}", e);
+ println!("Error in CMAP set_data2: {e}");
return;
};
// get them back again
match cmap::get(handle, "test.test_uint32") {
Ok(v) => {
- println!("GOT uint32 {}", v);
+ println!("GOT uint32 {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_int16") {
Ok(v) => {
- println!("GOT uint16 {}", v);
+ println!("GOT uint16 {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_num_1") {
Ok(v) => {
- println!("GOT num {}", v);
+ println!("GOT num {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_num_2") {
Ok(v) => {
- println!("GOT num {}", v);
+ println!("GOT num {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_string") {
Ok(v) => {
- println!("GOT string {}", v);
+ println!("GOT string {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_data") {
Ok(v) => match v {
- cmap::Data::UInt64(u) => println!("GOT data value {:x}", u),
- _ => println!("ERROR type was not UInt64, got {}", v),
+ cmap::Data::UInt64(u) => println!("GOT data value {u:x}"),
+ _ => println!("ERROR type was not UInt64, got {v}"),
},
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
// Test an iterator
match cmap::CmapIterStart::new(handle, "totem.") {
Ok(cmap_iter) => {
for i in cmap_iter {
- println!("ITER: {:?}", i);
+ println!("ITER: {i:?}");
}
println!();
}
Err(e) => {
- println!("Error in CMAP iter start: {}", e);
+ println!("Error in CMAP iter start: {e}");
}
}
// Close this handle
if let Err(e) = cmap::finalize(handle) {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
};
// Test notifications on the stats map
let handle = match cmap::initialize(cmap::Map::Stats) {
Ok(h) => h,
Err(e) => {
- println!("Error in CMAP (Stats) init: {}", e);
+ println!("Error in CMAP (Stats) init: {e}");
return;
}
};
let cb = cmap::NotifyCallback {
notify_fn: Some(track_notify_fn),
};
let _track_handle = match cmap::track_add(
handle,
"stats.srp.memb_merge_detect_tx",
cmap::TrackType::MODIFY | cmap::TrackType::ADD | cmap::TrackType::DELETE,
&cb,
997u64,
) {
Ok(th) => th,
Err(e) => {
- println!("Error in CMAP track_add {}", e);
+ println!("Error in CMAP track_add {e}");
return;
}
};
// Wait for events
let mut event_num = 0;
loop {
if let Err(e) = cmap::dispatch(handle, corosync::DispatchFlags::One) {
- println!("Error from CMAP dispatch: {}", e);
+ println!("Error from CMAP dispatch: {e}");
}
// Just do 5
event_num += 1;
if event_num > 5 {
break;
}
}
}
diff --git a/bindings/rust/tests/src/bin/cpg-test.rs b/bindings/rust/tests/src/bin/cpg-test.rs
index f5f336c4..df83c2d5 100644
--- a/bindings/rust/tests/src/bin/cpg-test.rs
+++ b/bindings/rust/tests/src/bin/cpg-test.rs
@@ -1,146 +1,142 @@
// Test the CPG library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::{cpg, NodeId};
use std::str;
fn deliver_fn(
_handle: &cpg::Handle,
group_name: String,
nodeid: NodeId,
pid: u32,
msg: &[u8],
msg_len: usize,
) {
println!(
- "TEST deliver_fn called for {}, from nodeid/pid {}/{}. len={}",
- group_name, nodeid, pid, msg_len
+ "TEST deliver_fn called for {group_name}, from nodeid/pid {nodeid}/{pid}. len={msg_len}"
);
// Print as text if it's valid UTF8
match str::from_utf8(msg) {
- Ok(s) => println!(" {}", s),
+ Ok(s) => println!(" {s}"),
Err(_) => {
for i in msg {
- print!("{:02x} ", i);
+ print!("{i:02x} ");
}
println!();
}
}
}
fn confchg_fn(
_handle: &cpg::Handle,
group_name: &str,
member_list: Vec<cpg::Address>,
left_list: Vec<cpg::Address>,
joined_list: Vec<cpg::Address>,
) {
- println!("TEST confchg_fn called for {}", group_name);
- println!(" members: {:?}", member_list);
- println!(" left: {:?}", left_list);
- println!(" joined: {:?}", joined_list);
+ println!("TEST confchg_fn called for {group_name}");
+ println!(" members: {member_list:?}");
+ println!(" left: {left_list:?}");
+ println!(" joined: {joined_list:?}");
}
fn totem_confchg_fn(_handle: &cpg::Handle, ring_id: cpg::RingId, member_list: Vec<NodeId>) {
println!(
"TEST totem_confchg_fn called for {}/{}",
ring_id.nodeid, ring_id.seq
);
- println!(" members: {:?}", member_list);
+ println!(" members: {member_list:?}");
}
fn main() {
// Initialise the model data
let md = cpg::ModelData::ModelV1(cpg::Model1Data {
flags: cpg::Model1Flags::None,
deliver_fn: Some(deliver_fn),
confchg_fn: Some(confchg_fn),
totem_confchg_fn: Some(totem_confchg_fn),
});
let handle = match cpg::initialize(&md, 99_u64) {
Ok(h) => h,
Err(e) => {
- println!("Error in CPG init: {}", e);
+ println!("Error in CPG init: {e}");
return;
}
};
if let Err(e) = cpg::join(handle, "TEST") {
- println!("Error in CPG join: {}", e);
+ println!("Error in CPG join: {e}");
return;
}
match cpg::local_get(handle) {
Ok(n) => {
- println!("Local nodeid is {}", n);
+ println!("Local nodeid is {n}");
}
Err(e) => {
- println!("Error in CPG local_get: {}", e);
+ println!("Error in CPG local_get: {e}");
}
}
// Test membership_get()
match cpg::membership_get(handle, "TEST") {
Ok(m) => {
- println!(" members: {:?}", m);
+ println!(" members: {m:?}");
println!();
}
Err(e) => {
- println!("Error in CPG membership_get: {}", e);
+ println!("Error in CPG membership_get: {e}");
}
}
// Test context APIs
let set_context: u64 = 0xabcdbeefcafe;
if let Err(e) = cpg::context_set(handle, set_context) {
- println!("Error in CPG context_set: {}", e);
+ println!("Error in CPG context_set: {e}");
return;
}
// NOTE This will fail on 32 bit systems because void* is not u64
match cpg::context_get(handle) {
Ok(c) => {
if c != set_context {
- println!(
- "Error: context_get() returned {:x}, context should be {:x}",
- c, set_context
- );
+ println!("Error: context_get() returned {c:x}, context should be {set_context:x}");
}
}
Err(e) => {
- println!("Error in CPG context_get: {}", e);
+ println!("Error in CPG context_get: {e}");
}
}
// Test iterator
match cpg::CpgIterStart::new(handle, "", cpg::CpgIterType::All) {
Ok(cpg_iter) => {
for i in cpg_iter {
- println!("ITER: {:?}", i);
+ println!("ITER: {i:?}");
}
println!();
}
Err(e) => {
- println!("Error in CPG iter start: {}", e);
+ println!("Error in CPG iter start: {e}");
}
}
// We should receive our own message (at least) in the event loop
if let Err(e) = cpg::mcast_joined(
handle,
cpg::Guarantee::TypeAgreed,
&"This is a test".to_string().into_bytes(),
) {
- println!("Error in CPG mcast_joined: {}", e);
+ println!("Error in CPG mcast_joined: {e}");
}
// Wait for events
loop {
if cpg::dispatch(handle, corosync::DispatchFlags::One).is_err() {
break;
}
}
println!("ERROR: Corosync quit");
}
diff --git a/bindings/rust/tests/src/bin/quorum-test.rs b/bindings/rust/tests/src/bin/quorum-test.rs
index c65bfba8..5797b7d0 100644
--- a/bindings/rust/tests/src/bin/quorum-test.rs
+++ b/bindings/rust/tests/src/bin/quorum-test.rs
@@ -1,86 +1,83 @@
// Test the QUORUM library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::{quorum, NodeId};
fn quorum_fn(
_handle: &quorum::Handle,
quorate: bool,
ring_id: quorum::RingId,
member_list: Vec<NodeId>,
) {
- println!("TEST quorum_fn called. quorate = {}", quorate);
+ println!("TEST quorum_fn called. quorate = {quorate}");
println!(" ring_id: {}/{}", ring_id.nodeid, ring_id.seq);
- println!(" members: {:?}", member_list);
+ println!(" members: {member_list:?}");
}
fn nodelist_fn(
_handle: &quorum::Handle,
ring_id: quorum::RingId,
member_list: Vec<NodeId>,
joined_list: Vec<NodeId>,
left_list: Vec<NodeId>,
) {
println!(
"TEST nodelist_fn called for {}/{}",
ring_id.nodeid, ring_id.seq
);
- println!(" members: {:?}", member_list);
- println!(" joined: {:?}", joined_list);
- println!(" left: {:?}", left_list);
+ println!(" members: {member_list:?}");
+ println!(" joined: {joined_list:?}");
+ println!(" left: {left_list:?}");
}
fn main() {
// Initialise the model data
let md = quorum::ModelData::ModelV1(quorum::Model1Data {
flags: quorum::Model1Flags::None,
quorum_notification_fn: Some(quorum_fn),
nodelist_notification_fn: Some(nodelist_fn),
});
let handle = match quorum::initialize(&md, 99_u64) {
Ok((h, t)) => {
println!("Quorum initialized; type = {}", t as u32);
h
}
Err(e) => {
- println!("Error in QUORUM init: {}", e);
+ println!("Error in QUORUM init: {e}");
return;
}
};
// Test context APIs
let set_context: u64 = 0xabcdbeefcafe;
if let Err(e) = quorum::context_set(handle, set_context) {
- println!("Error in QUORUM context_set: {}", e);
+ println!("Error in QUORUM context_set: {e}");
return;
}
// NOTE This will fail on 32 bit systems because void* is not u64
match quorum::context_get(handle) {
Ok(c) => {
if c != set_context {
- println!(
- "Error: context_get() returned {:x}, context should be {:x}",
- c, set_context
- );
+ println!("Error: context_get() returned {c:x}, context should be {set_context:x}");
}
}
Err(e) => {
- println!("Error in QUORUM context_get: {}", e);
+ println!("Error in QUORUM context_get: {e}");
}
}
if let Err(e) = quorum::trackstart(handle, corosync::TrackFlags::Changes) {
- println!("Error in QUORUM trackstart: {}", e);
+ println!("Error in QUORUM trackstart: {e}");
return;
}
// Wait for events
loop {
if quorum::dispatch(handle, corosync::DispatchFlags::One).is_err() {
break;
}
}
println!("ERROR: Corosync quit");
}
diff --git a/bindings/rust/tests/src/bin/votequorum-test.rs b/bindings/rust/tests/src/bin/votequorum-test.rs
index 59c50b2e..cf9746b6 100644
--- a/bindings/rust/tests/src/bin/votequorum-test.rs
+++ b/bindings/rust/tests/src/bin/votequorum-test.rs
@@ -1,123 +1,117 @@
// Test the VOTEQUORUM library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::votequorum;
fn quorum_fn(
_handle: &votequorum::Handle,
_context: u64,
quorate: bool,
member_list: Vec<votequorum::Node>,
) {
- println!("TEST votequorum_quorum_fn called. quorate = {}", quorate);
- println!(" members: {:?}", member_list);
+ println!("TEST votequorum_quorum_fn called. quorate = {quorate}");
+ println!(" members: {member_list:?}");
}
fn nodelist_fn(
_handle: &votequorum::Handle,
_context: u64,
ring_id: votequorum::RingId,
member_list: Vec<corosync::NodeId>,
) {
println!(
"TEST nodelist_fn called for {}/{}",
ring_id.nodeid, ring_id.seq
);
- println!(" members: {:?}", member_list);
+ println!(" members: {member_list:?}");
}
fn expectedvotes_fn(_handle: &votequorum::Handle, _context: u64, expected_votes: u32) {
- println!("TEST expected_votes_fn called: value is {}", expected_votes);
+ println!("TEST expected_votes_fn called: value is {expected_votes}");
}
fn main() {
// Initialise the model data
let cb = votequorum::Callbacks {
quorum_notification_fn: Some(quorum_fn),
nodelist_notification_fn: Some(nodelist_fn),
expectedvotes_notification_fn: Some(expectedvotes_fn),
};
let handle = match votequorum::initialize(&cb) {
Ok(h) => {
println!("Votequorum initialized.");
h
}
Err(e) => {
- println!("Error in VOTEQUORUM init: {}", e);
+ println!("Error in VOTEQUORUM init: {e}");
return;
}
};
// Test context APIs
let set_context: u64 = 0xabcdbeefcafe;
if let Err(e) = votequorum::context_set(handle, set_context) {
- println!("Error in VOTEQUORUM context_set: {}", e);
+ println!("Error in VOTEQUORUM context_set: {e}");
}
// NOTE This will fail on 32 bit systems because void* is not u64
match votequorum::context_get(handle) {
Ok(c) => {
if c != set_context {
- println!(
- "Error: context_get() returned {:x}, context should be {:x}",
- c, set_context
- );
+ println!("Error: context_get() returned {c:x}, context should be {set_context:x}");
}
}
Err(e) => {
- println!("Error in VOTEQUORUM context_get: {}", e);
+ println!("Error in VOTEQUORUM context_get: {e}");
}
}
const QDEVICE_NAME: &str = "RustQdevice";
if let Err(e) = votequorum::qdevice_register(handle, QDEVICE_NAME) {
- println!("Error in VOTEQUORUM qdevice_register: {}", e);
+ println!("Error in VOTEQUORUM qdevice_register: {e}");
}
match votequorum::get_info(handle, corosync::NodeId::from(1u32)) {
Ok(i) => {
println!("Node info for nodeid 1");
println!(" nodeid: {}", i.node_id);
println!(" node_state: {:?}", i.node_state);
println!(" node_votes: {}", i.node_votes);
println!(" node_expected: {}", i.node_expected_votes);
println!(" highest_expected: {}", i.highest_expected);
println!(" quorum: {}", i.quorum);
println!(" flags: {:x}", i.flags);
println!(" qdevice_votes: {}", i.qdevice_votes);
println!(" qdevice_name: {}", i.qdevice_name);
if i.qdevice_name != QDEVICE_NAME {
println!(
"qdevice names do not match: s/b: \"{}\" is: \"{}\"",
QDEVICE_NAME, i.qdevice_name
);
}
}
Err(e) => {
- println!(
- "Error in VOTEQUORUM get_info: {} (check nodeid 1 has been online)",
- e
- );
+ println!("Error in VOTEQUORUM get_info: {e} (check nodeid 1 has been online)");
}
}
if let Err(e) = votequorum::qdevice_unregister(handle, QDEVICE_NAME) {
- println!("Error in VOTEQUORUM qdevice_unregister: {}", e);
+ println!("Error in VOTEQUORUM qdevice_unregister: {e}");
}
if let Err(e) = votequorum::trackstart(handle, 99_u64, corosync::TrackFlags::Changes) {
- println!("Error in VOTEQUORUM trackstart: {}", e);
+ println!("Error in VOTEQUORUM trackstart: {e}");
return;
}
// Wait for events
loop {
if votequorum::dispatch(handle, corosync::DispatchFlags::One).is_err() {
break;
}
}
println!("ERROR: Corosync quit");
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Feb 25, 4:57 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1464681
Default Alt Text
(55 KB)

Event Timeline