api2/config/datastore: change create datastore api call to a worker
so that longer running creates (e.g. a slow storage), does not run in a timeout and we can follow its creation Signed-off-by: Dominik Csapak <d.csapak@proxmox.com> Signed-off-by: Dietmar Maurer <dietmar@proxmox.com>
This commit is contained in:
		
				
					committed by
					
						 Dietmar Maurer
						Dietmar Maurer
					
				
			
			
				
	
			
			
			
						parent
						
							062cf75cdf
						
					
				
				
					commit
					4708f4fc21
				
			| @ -5,6 +5,7 @@ use serde_json::Value; | ||||
| use ::serde::{Deserialize, Serialize}; | ||||
|  | ||||
| use proxmox::api::{api, Router, RpcEnvironment, Permission}; | ||||
| use proxmox::api::section_config::SectionConfigData; | ||||
| use proxmox::api::schema::parse_property_string; | ||||
| use proxmox::tools::fs::open_file_locked; | ||||
|  | ||||
| @ -13,7 +14,7 @@ use crate::backup::*; | ||||
| use crate::config::cached_user_info::CachedUserInfo; | ||||
| use crate::config::datastore::{self, DataStoreConfig, DIR_NAME_SCHEMA}; | ||||
| use crate::config::acl::{PRIV_DATASTORE_ALLOCATE, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY}; | ||||
| use crate::server::jobstate; | ||||
| use crate::server::{jobstate, WorkerTask}; | ||||
|  | ||||
| #[api( | ||||
|     input: { | ||||
| @ -50,6 +51,25 @@ pub fn list_datastores( | ||||
|     Ok(list.into_iter().filter(filter_by_privs).collect()) | ||||
| } | ||||
|  | ||||
| pub(crate) fn do_create_datastore( | ||||
|     _lock: std::fs::File, | ||||
|     mut config: SectionConfigData, | ||||
|     datastore: DataStoreConfig, | ||||
| ) -> Result<(), Error> { | ||||
|     let path: PathBuf = datastore.path.clone().into(); | ||||
|  | ||||
|     let backup_user = crate::backup::backup_user()?; | ||||
|     let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid)?; | ||||
|  | ||||
|     config.set_data(&datastore.name, "datastore", &datastore)?; | ||||
|  | ||||
|     datastore::save_config(&config)?; | ||||
|  | ||||
|     jobstate::create_state_file("prune", &datastore.name)?; | ||||
|     jobstate::create_state_file("garbage_collection", &datastore.name)?; | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| // fixme: impl. const fn get_object_schema(datastore::DataStoreConfig::API_SCHEMA), | ||||
| // but this need support for match inside const fn | ||||
| @ -116,31 +136,30 @@ pub fn list_datastores( | ||||
|     }, | ||||
| )] | ||||
| /// Create new datastore config. | ||||
| pub fn create_datastore(param: Value) -> Result<(), Error> { | ||||
| pub fn create_datastore( | ||||
|     param: Value, | ||||
|     rpcenv: &mut dyn RpcEnvironment, | ||||
| ) -> Result<String, Error> { | ||||
|  | ||||
|     let _lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?; | ||||
|     let lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?; | ||||
|  | ||||
|     let datastore: datastore::DataStoreConfig = serde_json::from_value(param)?; | ||||
|  | ||||
|     let (mut config, _digest) = datastore::config()?; | ||||
|     let (config, _digest) = datastore::config()?; | ||||
|  | ||||
|     if config.sections.get(&datastore.name).is_some() { | ||||
|         bail!("datastore '{}' already exists.", datastore.name); | ||||
|     } | ||||
|  | ||||
|     let path: PathBuf = datastore.path.clone().into(); | ||||
|     let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; | ||||
|  | ||||
|     let backup_user = crate::backup::backup_user()?; | ||||
|     let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid)?; | ||||
|  | ||||
|     config.set_data(&datastore.name, "datastore", &datastore)?; | ||||
|  | ||||
|     datastore::save_config(&config)?; | ||||
|  | ||||
|     jobstate::create_state_file("prune", &datastore.name)?; | ||||
|     jobstate::create_state_file("garbage_collection", &datastore.name)?; | ||||
|  | ||||
|     Ok(()) | ||||
|     WorkerTask::new_thread( | ||||
|         "create-datastore", | ||||
|         Some(datastore.name.to_string()), | ||||
|         auth_id, | ||||
|         false, | ||||
|         move |_worker| do_create_datastore(lock, config, datastore), | ||||
|     ) | ||||
| } | ||||
|  | ||||
| #[api( | ||||
|  | ||||
| @ -5,6 +5,7 @@ use ::serde::{Deserialize, Serialize}; | ||||
| use proxmox::api::{api, Permission, RpcEnvironment, RpcEnvironmentType}; | ||||
| use proxmox::api::section_config::SectionConfigData; | ||||
| use proxmox::api::router::Router; | ||||
| use proxmox::tools::fs::open_file_locked; | ||||
|  | ||||
| use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}; | ||||
| use crate::tools::disks::{ | ||||
| @ -16,7 +17,7 @@ use crate::tools::systemd::{self, types::*}; | ||||
| use crate::server::WorkerTask; | ||||
|  | ||||
| use crate::api2::types::*; | ||||
| use crate::config::datastore::DataStoreConfig; | ||||
| use crate::config::datastore::{self, DataStoreConfig}; | ||||
|  | ||||
| #[api( | ||||
|     properties: { | ||||
| @ -179,7 +180,17 @@ pub fn create_datastore_disk( | ||||
|             systemd::start_unit(&mount_unit_name)?; | ||||
|  | ||||
|             if add_datastore { | ||||
|                 crate::api2::config::datastore::create_datastore(json!({ "name": name, "path": mount_point }))? | ||||
|                 let lock = open_file_locked(datastore::DATASTORE_CFG_LOCKFILE, std::time::Duration::new(10, 0), true)?; | ||||
|                 let datastore: DataStoreConfig = | ||||
|                     serde_json::from_value(json!({ "name": name, "path": mount_point }))?; | ||||
|  | ||||
|                 let (config, _digest) = datastore::config()?; | ||||
|  | ||||
|                 if config.sections.get(&datastore.name).is_some() { | ||||
|                     bail!("datastore '{}' already exists.", datastore.name); | ||||
|                 } | ||||
|  | ||||
|                 crate::api2::config::datastore::create_datastore_impl(lock, config, datastore)?; | ||||
|             } | ||||
|  | ||||
|             Ok(()) | ||||
|  | ||||
| @ -14,12 +14,14 @@ use proxmox::api::{ | ||||
|     }, | ||||
| }; | ||||
| use proxmox::api::router::Router; | ||||
| use proxmox::tools::fs::open_file_locked; | ||||
|  | ||||
| use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY}; | ||||
| use crate::tools::disks::{ | ||||
|     zpool_list, zpool_status, parse_zpool_status_config_tree, vdev_list_to_tree, | ||||
|     DiskUsageType, | ||||
| }; | ||||
| use crate::config::datastore::{self, DataStoreConfig}; | ||||
|  | ||||
| use crate::server::WorkerTask; | ||||
|  | ||||
| @ -372,7 +374,17 @@ pub fn create_zpool( | ||||
|             } | ||||
|  | ||||
|             if add_datastore { | ||||
|                 crate::api2::config::datastore::create_datastore(json!({ "name": name, "path": mount_point }))? | ||||
|                 let lock = datastore::lock_config()?;  | ||||
|                 let datastore: DataStoreConfig = | ||||
|                     serde_json::from_value(json!({ "name": name, "path": mount_point }))?; | ||||
|  | ||||
|                 let (config, _digest) = datastore::config()?; | ||||
|  | ||||
|                 if config.sections.get(&datastore.name).is_some() { | ||||
|                     bail!("datastore '{}' already exists.", datastore.name); | ||||
|                 } | ||||
|  | ||||
|                 crate::api2::config::datastore::do_create_datastore(lock, config, datastore)?; | ||||
|             } | ||||
|  | ||||
|             Ok(()) | ||||
|  | ||||
| @ -75,6 +75,7 @@ Ext.define('PBS.DataStoreEdit', { | ||||
|     isAdd: true, | ||||
|  | ||||
|     bodyPadding: 0, | ||||
|     showProgress: true, | ||||
|  | ||||
|     cbindData: function(initialConfig) { | ||||
| 	var me = this; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user