diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs index 86495443..9e9b2e23 100644 --- a/src/api2/admin/datastore.rs +++ b/src/api2/admin/datastore.rs @@ -485,9 +485,9 @@ fn get_datastore_list( _rpcenv: &mut dyn RpcEnvironment, ) -> Result { - let config = datastore::config()?; + let (config, _digest) = datastore::config()?; - Ok(config.convert_to_array("store")) + Ok(config.convert_to_array("store", None)) } #[sortable] diff --git a/src/api2/config/datastore.rs b/src/api2/config/datastore.rs index adc9cf1c..ef979de6 100644 --- a/src/api2/config/datastore.rs +++ b/src/api2/config/datastore.rs @@ -28,9 +28,9 @@ pub fn list_datastores( _rpcenv: &mut dyn RpcEnvironment, ) -> Result { - let config = datastore::config()?; + let (config, digest) = datastore::config()?; - Ok(config.convert_to_array("name")) + Ok(config.convert_to_array("name", Some(&digest))) } #[api( @@ -57,7 +57,7 @@ pub fn create_datastore(name: String, param: Value) -> Result<(), Error> { let datastore: datastore::DataStoreConfig = serde_json::from_value(param.clone())?; - let mut config = datastore::config()?; + let (mut config, _digest) = datastore::config()?; if let Some(_) = config.sections.get(&name) { bail!("datastore '{}' already exists.", name); @@ -91,7 +91,7 @@ pub fn delete_datastore(name: String) -> Result<(), Error> { // fixme: locking ? // fixme: check digest ? - let mut config = datastore::config()?; + let (mut config, _digest) = datastore::config()?; match config.sections.get(&name) { Some(_) => { config.sections.remove(&name); }, diff --git a/src/api2/config/remotes.rs b/src/api2/config/remotes.rs index a33daea6..871ab998 100644 --- a/src/api2/config/remotes.rs +++ b/src/api2/config/remotes.rs @@ -25,9 +25,9 @@ pub fn list_remotes( _rpcenv: &mut dyn RpcEnvironment, ) -> Result { - let config = remotes::config()?; + let (config, digest) = remotes::config()?; - Ok(config.convert_to_array("name")) + Ok(config.convert_to_array("name", Some(&digest))) } #[api( @@ -60,7 +60,7 @@ pub fn create_remote(name: String, param: Value) -> Result<(), Error> { let remote: remotes::Remote = serde_json::from_value(param.clone())?; - let mut config = remotes::config()?; + let (mut config, _digest) = remotes::config()?; if let Some(_) = config.sections.get(&name) { bail!("remote '{}' already exists.", name); @@ -89,7 +89,7 @@ pub fn delete_remote(name: String) -> Result<(), Error> { // fixme: locking ? // fixme: check digest ? - let mut config = remotes::config()?; + let (mut config, _digest) = remotes::config()?; match config.sections.get(&name) { Some(_) => { config.sections.remove(&name); }, diff --git a/src/backup/datastore.rs b/src/backup/datastore.rs index ea844d24..76c36094 100644 --- a/src/backup/datastore.rs +++ b/src/backup/datastore.rs @@ -35,17 +35,14 @@ impl DataStore { pub fn lookup_datastore(name: &str) -> Result, Error> { - let config = datastore::config()?; - let (_, store_config) = config.sections.get(name) - .ok_or(format_err!("no such datastore '{}'", name))?; - - let path = store_config["path"].as_str().unwrap(); + let (config, _digest) = datastore::config()?; + let config: datastore::DataStoreConfig = config.lookup("datastore", name)?; let mut map = DATASTORE_MAP.lock().unwrap(); if let Some(datastore) = map.get(name) { // Compare Config - if changed, create new Datastore object! - if datastore.chunk_store.base == PathBuf::from(path) { + if datastore.chunk_store.base == PathBuf::from(&config.path) { return Ok(datastore.clone()); } } @@ -60,7 +57,7 @@ impl DataStore { pub fn open(store_name: &str) -> Result { - let config = datastore::config()?; + let (config, _digest) = datastore::config()?; let (_, store_config) = config.sections.get(store_name) .ok_or(format_err!("no such datastore '{}'", store_name))?; diff --git a/src/bin/proxmox-backup-manager.rs b/src/bin/proxmox-backup-manager.rs index d68d2df7..cc5e697d 100644 --- a/src/bin/proxmox-backup-manager.rs +++ b/src/bin/proxmox-backup-manager.rs @@ -406,7 +406,7 @@ async fn pull_datastore( let mut client = connect()?; - let remote_config = remotes::config()?; + let (remote_config, _digest) = remotes::config()?; let remote: Remote = remote_config.lookup("remote", &remote)?; let args = json!({ @@ -451,7 +451,7 @@ pub fn complete_remote_datastore_name(_arg: &str, param: &HashMap SectionConfig { const DATASTORE_CFG_FILENAME: &str = "/etc/proxmox-backup/datastore.cfg"; -pub fn config() -> Result { +pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> { let content = match std::fs::read_to_string(DATASTORE_CFG_FILENAME) { Ok(c) => c, Err(err) => { @@ -63,7 +63,9 @@ pub fn config() -> Result { } }; - CONFIG.parse(DATASTORE_CFG_FILENAME, &content) + let digest = openssl::sha::sha256(content.as_bytes()); + let data = CONFIG.parse(DATASTORE_CFG_FILENAME, &content)?; + Ok((data, digest)) } pub fn save_config(config: &SectionConfigData) -> Result<(), Error> { @@ -86,7 +88,7 @@ pub fn save_config(config: &SectionConfigData) -> Result<(), Error> { // shell completion helper pub fn complete_datastore_name(_arg: &str, _param: &HashMap) -> Vec { match config() { - Ok(data) => data.sections.iter().map(|(id, _)| id.to_string()).collect(), + Ok((data, _digest)) => data.sections.iter().map(|(id, _)| id.to_string()).collect(), Err(_) => return vec![], } } diff --git a/src/config/remotes.rs b/src/config/remotes.rs index bbefea49..2b2c0305 100644 --- a/src/config/remotes.rs +++ b/src/config/remotes.rs @@ -62,7 +62,7 @@ fn init() -> SectionConfig { const REMOTES_CFG_FILENAME: &str = "/etc/proxmox-backup/remotes.cfg"; -pub fn config() -> Result { +pub fn config() -> Result<(SectionConfigData, [u8;32]), Error> { let content = match std::fs::read_to_string(REMOTES_CFG_FILENAME) { Ok(c) => c, Err(err) => { @@ -74,7 +74,9 @@ pub fn config() -> Result { } }; - CONFIG.parse(REMOTES_CFG_FILENAME, &content) + let digest = openssl::sha::sha256(content.as_bytes()); + let data = CONFIG.parse(REMOTES_CFG_FILENAME, &content)?; + Ok((data, digest)) } pub fn save_config(config: &SectionConfigData) -> Result<(), Error> { @@ -97,7 +99,7 @@ pub fn save_config(config: &SectionConfigData) -> Result<(), Error> { // shell completion helper pub fn complete_remote_name(_arg: &str, _param: &HashMap) -> Vec { match config() { - Ok(data) => data.sections.iter().map(|(id, _)| id.to_string()).collect(), + Ok((data, _digest)) => data.sections.iter().map(|(id, _)| id.to_string()).collect(), Err(_) => return vec![], } } diff --git a/src/section_config.rs b/src/section_config.rs index 4f520d1c..50fd81cc 100644 --- a/src/section_config.rs +++ b/src/section_config.rs @@ -84,12 +84,20 @@ impl SectionConfigData { self.order.push_back(section_id.to_string()); } - pub fn convert_to_array(&self, id_prop: &str) -> Value { + pub fn convert_to_array(&self, id_prop: &str, digest: Option<&[u8;32]>) -> Value { let mut list: Vec = vec![]; + let digest: Value = match digest { + Some(v) => proxmox::tools::digest_to_hex(v).into(), + None => Value::Null, + }; + for (section_id, (_, data)) in &self.sections { let mut item = data.clone(); item.as_object_mut().unwrap().insert(id_prop.into(), section_id.clone().into()); + if !digest.is_null() { + item.as_object_mut().unwrap().insert("digest".into(), digest.clone()); + } list.push(item); }