mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-10 17:43:23 +01:00
Fix #29
This commit is contained in:
parent
6b88191dc5
commit
a09c3d3880
@ -8,7 +8,7 @@
|
||||
, { machine = "Yetmore", actor = "FailBash"}
|
||||
]
|
||||
, actors =
|
||||
{ Shelly_1234 = { module = "Shelly", params =
|
||||
{ Shelly1234 = { module = "Shelly", params =
|
||||
{ topic = "Topic1234" }}
|
||||
, Bash = { module = "Process", params =
|
||||
{ cmd = "./examples/actor.sh"
|
||||
@ -22,10 +22,10 @@
|
||||
{ cmd = "./examples/fail-actor.sh"
|
||||
}}
|
||||
}
|
||||
, init_connections = [] : List { machine : Text, initiator : Text }
|
||||
--, init_connections = [{ machine = "Testmachine", initiator = "Initiator" }]
|
||||
, initiators = {=}
|
||||
--{ Initiator = { module = "Dummy", params = {=} } }
|
||||
--, init_connections = [] : List { machine : Text, initiator : Text }
|
||||
, init_connections = [{ machine = "Testmachine", initiator = "Initiator" }]
|
||||
, initiators = --{=}
|
||||
{ Initiator = { module = "Dummy", params = { uid = "Testuser" } } }
|
||||
, listens =
|
||||
[ { address = "127.0.0.1", port = Some 59661 }
|
||||
, { address = "::1", port = Some 59661 }
|
||||
|
@ -6,46 +6,13 @@ use capnp::Error;
|
||||
|
||||
use futures::FutureExt;
|
||||
|
||||
use crate::db::access::{PrivilegesBuf, PermRule};
|
||||
use crate::db::access::{PrivilegesBuf, PermRule, Perms};
|
||||
use crate::db::user::UserId;
|
||||
use crate::db::machine::{Status, MachineState};
|
||||
use crate::machine::Machine as NwMachine;
|
||||
use crate::schema::machine_capnp::machine::*;
|
||||
use crate::schema::machine_capnp::machine::MachineState as APIMState;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Perms {
|
||||
pub disclose: bool,
|
||||
pub read: bool,
|
||||
pub write: bool,
|
||||
pub manage: bool,
|
||||
}
|
||||
|
||||
impl Perms {
|
||||
pub fn get_for<'a, I: Iterator<Item=&'a PermRule>>(privs: &'a PrivilegesBuf, rules: I) -> Self {
|
||||
let mut disclose = false;
|
||||
let mut read = false;
|
||||
let mut write = false;
|
||||
let mut manage = false;
|
||||
for rule in rules {
|
||||
if rule.match_perm(&privs.disclose) {
|
||||
disclose = true;
|
||||
}
|
||||
if rule.match_perm(&privs.read) {
|
||||
read = true;
|
||||
}
|
||||
if rule.match_perm(&privs.write) {
|
||||
write = true;
|
||||
}
|
||||
if rule.match_perm(&privs.manage) {
|
||||
manage = true;
|
||||
}
|
||||
}
|
||||
|
||||
Self { disclose, read, write, manage }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Machine {
|
||||
userid: UserId,
|
||||
|
@ -13,7 +13,7 @@ use crate::schema::machinesystem_capnp::machine_system;
|
||||
use crate::schema::machinesystem_capnp::machine_system::info as machines;
|
||||
use crate::network::Network;
|
||||
use crate::db::user::UserId;
|
||||
use crate::db::access::{PermRule, admin_perm, Permission};
|
||||
use crate::db::access::{PermRule, admin_perm, Permission, Perms};
|
||||
use crate::connection::Session;
|
||||
use crate::machine::Machine as NwMachine;
|
||||
|
||||
|
@ -5,9 +5,9 @@ use std::collections::HashMap;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::machine::MachineDescription;
|
||||
use crate::db::machine::MachineIdentifier;
|
||||
use crate::db::access::*;
|
||||
use crate::machine::MachineDescription;
|
||||
|
||||
pub fn read(path: &Path) -> Result<Config> {
|
||||
serde_dhall::from_file(path)
|
||||
|
@ -25,12 +25,13 @@ pub mod access;
|
||||
pub mod machine;
|
||||
|
||||
pub type MachineDB = machine::internal::Internal;
|
||||
pub type UserDB = user::Internal;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Databases {
|
||||
pub access: Arc<access::AccessControl>,
|
||||
pub machine: Arc<MachineDB>,
|
||||
pub userdb: Arc<user::Internal>,
|
||||
pub userdb: Arc<UserDB>,
|
||||
}
|
||||
|
||||
const LMDB_MAX_DB: u32 = 16;
|
||||
|
@ -11,6 +11,7 @@ use std::path::Path;
|
||||
use std::fs;
|
||||
use std::iter::FromIterator;
|
||||
use std::convert::{TryFrom, Into};
|
||||
use std::fmt::{Display, Formatter, Write};
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
@ -22,6 +23,81 @@ use crate::config::Config;
|
||||
use crate::db::user::UserData;
|
||||
pub use internal::Internal;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Perms {
|
||||
pub disclose: bool,
|
||||
pub read: bool,
|
||||
pub write: bool,
|
||||
pub manage: bool,
|
||||
}
|
||||
|
||||
impl Display for Perms {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
fn part(f: &mut Formatter<'_>, fst: &mut bool, n: &'static str) -> fmt::Result {
|
||||
if *fst {
|
||||
*fst = false;
|
||||
f.write_char(' ')?;
|
||||
} else {
|
||||
f.write_str("| ")?;
|
||||
}
|
||||
f.write_str(n)?;
|
||||
f.write_char(' ')
|
||||
}
|
||||
|
||||
let mut fst = true;
|
||||
f.write_char('(')?;
|
||||
|
||||
if self.disclose {
|
||||
part(f, &mut fst, "DISCLOSE")?;
|
||||
}
|
||||
if self.read {
|
||||
part(f, &mut fst, "READ")?;
|
||||
}
|
||||
if self.write {
|
||||
part(f, &mut fst, "WRITE")?;
|
||||
}
|
||||
if self.manage {
|
||||
part(f, &mut fst, "MANAGE")?;
|
||||
}
|
||||
|
||||
f.write_char(')')
|
||||
}
|
||||
}
|
||||
|
||||
impl Perms {
|
||||
pub fn get_for<'a, I: Iterator<Item=&'a PermRule>>(privs: &'a PrivilegesBuf, rules: I) -> Self {
|
||||
let mut disclose = false;
|
||||
let mut read = false;
|
||||
let mut write = false;
|
||||
let mut manage = false;
|
||||
for rule in rules {
|
||||
if rule.match_perm(&privs.disclose) {
|
||||
disclose = true;
|
||||
}
|
||||
if rule.match_perm(&privs.read) {
|
||||
read = true;
|
||||
}
|
||||
if rule.match_perm(&privs.write) {
|
||||
write = true;
|
||||
}
|
||||
if rule.match_perm(&privs.manage) {
|
||||
manage = true;
|
||||
}
|
||||
}
|
||||
|
||||
Self { disclose, read, write, manage }
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
disclose: false,
|
||||
read: false,
|
||||
write: false,
|
||||
manage: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AccessControl {
|
||||
internal: HashMap<RoleIdentifier, Role>,
|
||||
}
|
||||
@ -566,6 +642,27 @@ impl TryFrom<String> for PermRule {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn display_perm() {
|
||||
let mut perm = Perms {
|
||||
disclose: false,
|
||||
read: false,
|
||||
write: false,
|
||||
manage: false
|
||||
};
|
||||
println!("{}", perm);
|
||||
assert_eq!("()", format!("{}", perm));
|
||||
|
||||
perm.disclose = true;
|
||||
println!("{}", perm);
|
||||
assert_eq!("( DISCLOSE )", format!("{}", perm));
|
||||
|
||||
perm.read = true;
|
||||
perm.write = true;
|
||||
println!("{}", perm);
|
||||
assert_eq!("( DISCLOSE | READ | WRITE )", format!("{}", perm));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn permission_ord_test() {
|
||||
assert!(PermissionBuf::from_string("bffh.perm".to_string())
|
||||
|
@ -12,7 +12,7 @@ use paho_mqtt::AsyncClient;
|
||||
use futures::future::BoxFuture;
|
||||
|
||||
use futures_signals::signal::{Signal, Mutable, MutableSignalCloned};
|
||||
use crate::machine::{Machine, ReturnToken};
|
||||
use crate::machine::Machine;
|
||||
use crate::db::machine::MachineState;
|
||||
use crate::db::user::{User, UserId, UserData};
|
||||
|
||||
@ -22,7 +22,7 @@ use crate::error::Result;
|
||||
use crate::config::Config;
|
||||
|
||||
pub trait Sensor {
|
||||
fn run_sensor(&mut self) -> BoxFuture<'static, (Option<User>, MachineState)>;
|
||||
fn run_sensor(&mut self) -> BoxFuture<'static, (Option<UserId>, MachineState)>;
|
||||
}
|
||||
|
||||
type BoxSensor = Box<dyn Sensor + Send>;
|
||||
@ -31,10 +31,9 @@ pub struct Initiator {
|
||||
log: Logger,
|
||||
signal: MutableSignalCloned<Option<Machine>>,
|
||||
machine: Option<Machine>,
|
||||
future: Option<BoxFuture<'static, (Option<User>, MachineState)>>,
|
||||
future: Option<BoxFuture<'static, (Option<UserId>, MachineState)>>,
|
||||
// TODO: Prepare the init for async state change requests.
|
||||
state_change_fut: Option<BoxFuture<'static, Result<ReturnToken>>>,
|
||||
token: Option<ReturnToken>,
|
||||
state_change_fut: Option<BoxFuture<'static, Result<()>>>,
|
||||
sensor: BoxSensor,
|
||||
}
|
||||
|
||||
@ -46,7 +45,6 @@ impl Initiator {
|
||||
machine: None,
|
||||
future: None,
|
||||
state_change_fut: None,
|
||||
token: None,
|
||||
sensor: sensor,
|
||||
}
|
||||
}
|
||||
@ -92,13 +90,11 @@ impl Future for Initiator {
|
||||
debug!(this.log, "State change blocked");
|
||||
return Poll::Pending;
|
||||
},
|
||||
Poll::Ready(Ok(tok)) => {
|
||||
Poll::Ready(Ok(rt)) => {
|
||||
debug!(this.log, "State change returned ok");
|
||||
// Explicity drop the future
|
||||
let _ = this.state_change_fut.take();
|
||||
|
||||
// Store the given return token for future use
|
||||
this.token.replace(tok);
|
||||
}
|
||||
Poll::Ready(Err(e)) => {
|
||||
info!(this.log, "State change returned err: {}", e);
|
||||
@ -117,7 +113,7 @@ impl Future for Initiator {
|
||||
debug!(this.log, "Sensor returned a new state");
|
||||
this.future.take();
|
||||
let f = this.machine.as_mut().map(|machine| {
|
||||
machine.request_state_change(user.as_ref(), state)
|
||||
machine.request_state_change(user.as_ref(), state).unwrap()
|
||||
});
|
||||
this.state_change_fut = f;
|
||||
}
|
||||
@ -151,12 +147,12 @@ fn load_single(
|
||||
log: &Logger,
|
||||
name: &String,
|
||||
module_name: &String,
|
||||
_params: &HashMap<String, String>
|
||||
params: &HashMap<String, String>
|
||||
) -> Option<BoxSensor>
|
||||
{
|
||||
match module_name.as_ref() {
|
||||
"Dummy" => {
|
||||
Some(Box::new(Dummy::new(log)))
|
||||
Some(Box::new(Dummy::new(log, params)))
|
||||
},
|
||||
_ => {
|
||||
error!(log, "No initiator found with name \"{}\", configured as \"{}\"",
|
||||
@ -169,34 +165,47 @@ fn load_single(
|
||||
pub struct Dummy {
|
||||
log: Logger,
|
||||
step: bool,
|
||||
userid: Option<UserId>,
|
||||
}
|
||||
|
||||
impl Dummy {
|
||||
pub fn new(log: &Logger) -> Self {
|
||||
Self { log: log.new(o!("module" => "Dummy Initiator")), step: false }
|
||||
pub fn new(log: &Logger, params: &HashMap<String, String>) -> Self {
|
||||
let userid = if let Some(uid) = params.get("uid") {
|
||||
Some(UserId::new(uid.clone(),
|
||||
params.get("subuid").map(String::from),
|
||||
params.get("realm").map(String::from)
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let log = log.new(o!("module" => "Dummy Initiator"));
|
||||
debug!(log, "Constructed dummy initiator with params: {:?}", params);
|
||||
|
||||
Self { log, step: false, userid }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl Sensor for Dummy {
|
||||
fn run_sensor(&mut self)
|
||||
-> BoxFuture<'static, (Option<User>, MachineState)>
|
||||
-> BoxFuture<'static, (Option<UserId>, MachineState)>
|
||||
{
|
||||
let step = self.step;
|
||||
self.step = !step;
|
||||
|
||||
info!(self.log, "Kicking off new dummy initiator state change: {}", step);
|
||||
info!(self.log, "Kicking off new dummy initiator state change: {}, {:?}",
|
||||
if step { "free" } else { "used" },
|
||||
&self.userid
|
||||
);
|
||||
|
||||
let userid = self.userid.clone();
|
||||
let f = async move {
|
||||
Timer::after(std::time::Duration::from_secs(1)).await;
|
||||
if step {
|
||||
return (None, MachineState::free());
|
||||
return (userid.clone(), MachineState::free());
|
||||
} else {
|
||||
let user = User::new(
|
||||
UserId::new("test".to_string(), None, None),
|
||||
UserData::new(vec![crate::db::access::RoleIdentifier::local_from_str("lmdb".to_string(), "testrole".to_string())], 0),
|
||||
);
|
||||
let id = user.id.clone();
|
||||
return (Some(user), MachineState::used(Some(id)));
|
||||
return (userid.clone(), MachineState::used(userid.clone()));
|
||||
}
|
||||
};
|
||||
|
||||
|
173
src/machine.rs
173
src/machine.rs
@ -23,10 +23,11 @@ use slog::Logger;
|
||||
|
||||
use crate::error::{Result, Error};
|
||||
|
||||
use crate::db::{access, Databases, MachineDB};
|
||||
use crate::db::access::AccessControl;
|
||||
use crate::db::{access, Databases, MachineDB, UserDB};
|
||||
use crate::db::access::{AccessControl, Perms};
|
||||
use crate::db::machine::{MachineIdentifier, MachineState, Status};
|
||||
use crate::db::user::{User, UserData, UserId};
|
||||
use crate::Error::Denied;
|
||||
|
||||
use crate::network::MachineMap;
|
||||
use crate::space;
|
||||
@ -64,6 +65,8 @@ pub struct Machine {
|
||||
pub desc: MachineDescription,
|
||||
|
||||
access_control: Arc<AccessControl>,
|
||||
userdb: Arc<UserDB>,
|
||||
log: Logger,
|
||||
|
||||
inner: Arc<Mutex<Inner>>,
|
||||
}
|
||||
@ -73,7 +76,9 @@ impl Machine {
|
||||
inner: Inner,
|
||||
id: MachineIdentifier,
|
||||
desc: MachineDescription,
|
||||
access_control: Arc<AccessControl>
|
||||
access_control: Arc<AccessControl>,
|
||||
userdb: Arc<UserDB>,
|
||||
log: Logger,
|
||||
) -> Self
|
||||
{
|
||||
Self {
|
||||
@ -81,6 +86,8 @@ impl Machine {
|
||||
inner: Arc::new(Mutex::new(inner)),
|
||||
desc,
|
||||
access_control,
|
||||
userdb,
|
||||
log,
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,9 +97,12 @@ impl Machine {
|
||||
state: MachineState,
|
||||
db: Arc<MachineDB>,
|
||||
access_control: Arc<AccessControl>,
|
||||
userdb: Arc<UserDB>,
|
||||
log: &Logger,
|
||||
) -> Machine
|
||||
{
|
||||
Self::new(Inner::new(id.clone(), state, db), id, desc, access_control)
|
||||
let log = log.new(o!("machine" => id.clone()));
|
||||
Self::new(Inner::new(id.clone(), state, db), id, desc, access_control, userdb, log)
|
||||
}
|
||||
|
||||
pub fn do_state_change(&self, new_state: MachineState)
|
||||
@ -109,13 +119,110 @@ impl Machine {
|
||||
Box::pin(f)
|
||||
}
|
||||
|
||||
pub fn request_state_change(&mut self, user: Option<&User>, new_state: MachineState)
|
||||
-> BoxFuture<'static, Result<ReturnToken>>
|
||||
pub fn request_state_change(&mut self, userid: Option<&UserId>, new_state: MachineState)
|
||||
-> Result<BoxFuture<'static, Result<()>>>
|
||||
{
|
||||
let inner = self.inner.clone();
|
||||
Box::pin(async move {
|
||||
Ok(ReturnToken::new(inner))
|
||||
})
|
||||
let perms = if let Some(userid) = userid {
|
||||
if let Some(user) = self.userdb.get_user(&userid.uid)? {
|
||||
let roles = self.access_control.collect_permrules(&user.data)?;
|
||||
Perms::get_for(&self.desc.privs, roles.iter())
|
||||
} else {
|
||||
Perms::empty()
|
||||
}
|
||||
} else {
|
||||
Perms::empty()
|
||||
};
|
||||
|
||||
debug!(self.log, "State change requested: {:?}, {:?}, {}",
|
||||
&userid,
|
||||
new_state,
|
||||
perms,
|
||||
);
|
||||
|
||||
if perms.manage {
|
||||
Ok(Box::pin(async move {
|
||||
let mut guard = inner.lock().await;
|
||||
guard.do_state_change(new_state);
|
||||
Ok(())
|
||||
}))
|
||||
} else if perms.write {
|
||||
let userid = userid.map(|u| u.clone());
|
||||
let f = async move {
|
||||
let mut guard = inner.lock().await;
|
||||
// Match (current state, new state) for permission
|
||||
if
|
||||
match (guard.read_state().lock_ref().state.clone(), &new_state.state) {
|
||||
// Going from available to used by the person requesting is okay.
|
||||
(Status::Free, Status::InUse(who))
|
||||
// Check that the person requesting does not request for somebody else.
|
||||
// *That* is manage privilege.
|
||||
if who.as_ref() == userid.as_ref() => true,
|
||||
|
||||
// Reserving things for ourself is okay.
|
||||
(Status::Free, Status::Reserved(whom))
|
||||
if userid.as_ref() == Some(whom) => true,
|
||||
|
||||
// Returning things we've been using is okay. This includes both if
|
||||
// they're being freed or marked as to be checked.
|
||||
(Status::InUse(who), Status::Free | Status::ToCheck(_))
|
||||
if who.as_ref() == userid.as_ref() => true,
|
||||
|
||||
// Un-reserving things we reserved is okay
|
||||
(Status::Reserved(whom), Status::Free)
|
||||
if userid.as_ref() == Some(&whom) => true,
|
||||
// Using things that we've reserved is okay. But the person requesting
|
||||
// that has to be the person that reserved the machine. Otherwise
|
||||
// somebody could make a machine reserved by a different user as used by
|
||||
// that different user but use it themself.
|
||||
(Status::Reserved(whom), Status::InUse(who))
|
||||
if userid.as_ref() == Some(&whom)
|
||||
&& who.as_ref() == Some(&whom)
|
||||
=> true,
|
||||
|
||||
// Default is deny.
|
||||
_ => false
|
||||
}
|
||||
{
|
||||
// Permission granted
|
||||
guard.do_state_change(new_state);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Denied)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Box::pin(f))
|
||||
} else {
|
||||
let userid = userid.map(|u| u.clone());
|
||||
let f = async move {
|
||||
let mut guard = inner.lock().await;
|
||||
// Match (current state, new state) for permission
|
||||
if
|
||||
match (guard.read_state().lock_ref().state.clone(), &new_state.state) {
|
||||
// Returning things we've been using is okay. This includes both if
|
||||
// they're being freed or marked as to be checked.
|
||||
(Status::InUse(who), Status::Free | Status::ToCheck(_))
|
||||
if who.as_ref() == userid.as_ref() => true,
|
||||
|
||||
// Un-reserving things we reserved is okay
|
||||
(Status::Reserved(whom), Status::Free)
|
||||
if userid.as_ref() == Some(&whom) => true,
|
||||
|
||||
// Default is deny.
|
||||
_ => false
|
||||
}
|
||||
{
|
||||
// Permission granted
|
||||
guard.do_state_change(new_state);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Denied)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Box::pin(f))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_status(&self) -> Status {
|
||||
@ -244,39 +351,6 @@ impl Inner {
|
||||
}
|
||||
}
|
||||
|
||||
//pub type ReturnToken = futures::channel::oneshot::Sender<()>;
|
||||
pub struct ReturnToken {
|
||||
f: Option<BoxFuture<'static, ()>>,
|
||||
}
|
||||
|
||||
impl ReturnToken {
|
||||
pub fn new(inner: Arc<Mutex<Inner>>) -> Self {
|
||||
let f = async move {
|
||||
let mut guard = inner.lock().await;
|
||||
guard.reset_state();
|
||||
};
|
||||
|
||||
Self { f: Some(Box::pin(f)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Future for ReturnToken {
|
||||
type Output = (); // FIXME: This should probably be a Result<(), Error>
|
||||
|
||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||
let mut this = &mut *self;
|
||||
|
||||
match this.f.as_mut().map(|f| Future::poll(Pin::new(f), cx)) {
|
||||
None => Poll::Ready(()), // TODO: Is it saner to return Pending here? This can only happen after the future completed
|
||||
Some(Poll::Pending) => Poll::Pending,
|
||||
Some(Poll::Ready(())) => {
|
||||
let _ = this.f.take(); // Remove the future to not poll after completion
|
||||
Poll::Ready(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
/// A description of a machine
|
||||
///
|
||||
@ -309,20 +383,23 @@ pub fn load(config: &crate::config::Config, db: Databases, log: &Logger)
|
||||
{
|
||||
let mut map = config.machines.clone();
|
||||
let access_control = db.access;
|
||||
let db = db.machine;
|
||||
let machinedb = db.machine;
|
||||
let userdb = db.userdb;
|
||||
|
||||
let it = map.drain()
|
||||
.map(|(k,v)| {
|
||||
// TODO: Read state from the state db
|
||||
if let Some(state) = db.get(&k).unwrap() {
|
||||
if let Some(state) = machinedb.get(&k).unwrap() {
|
||||
debug!(log, "Loading old state from db for {}: {:?}", &k, &state);
|
||||
(k.clone(),
|
||||
Machine::construct(
|
||||
k,
|
||||
v,
|
||||
state,
|
||||
db.clone(),
|
||||
access_control.clone()
|
||||
machinedb.clone(),
|
||||
access_control.clone(),
|
||||
userdb.clone(),
|
||||
log,
|
||||
))
|
||||
} else {
|
||||
debug!(log, "No old state found in db for {}, creating new.", &k);
|
||||
@ -331,8 +408,10 @@ pub fn load(config: &crate::config::Config, db: Databases, log: &Logger)
|
||||
k,
|
||||
v,
|
||||
MachineState::new(),
|
||||
db.clone(),
|
||||
machinedb.clone(),
|
||||
access_control.clone(),
|
||||
userdb.clone(),
|
||||
log,
|
||||
))
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user