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:
parent
062cf75cdf
commit
4708f4fc21
|
@ -5,6 +5,7 @@ use serde_json::Value;
|
||||||
use ::serde::{Deserialize, Serialize};
|
use ::serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
use proxmox::api::{api, Router, RpcEnvironment, Permission};
|
||||||
|
use proxmox::api::section_config::SectionConfigData;
|
||||||
use proxmox::api::schema::parse_property_string;
|
use proxmox::api::schema::parse_property_string;
|
||||||
use proxmox::tools::fs::open_file_locked;
|
use proxmox::tools::fs::open_file_locked;
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@ use crate::backup::*;
|
||||||
use crate::config::cached_user_info::CachedUserInfo;
|
use crate::config::cached_user_info::CachedUserInfo;
|
||||||
use crate::config::datastore::{self, DataStoreConfig, DIR_NAME_SCHEMA};
|
use crate::config::datastore::{self, DataStoreConfig, DIR_NAME_SCHEMA};
|
||||||
use crate::config::acl::{PRIV_DATASTORE_ALLOCATE, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY};
|
use crate::config::acl::{PRIV_DATASTORE_ALLOCATE, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_MODIFY};
|
||||||
use crate::server::jobstate;
|
use crate::server::{jobstate, WorkerTask};
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
input: {
|
input: {
|
||||||
|
@ -50,6 +51,25 @@ pub fn list_datastores(
|
||||||
Ok(list.into_iter().filter(filter_by_privs).collect())
|
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),
|
// fixme: impl. const fn get_object_schema(datastore::DataStoreConfig::API_SCHEMA),
|
||||||
// but this need support for match inside const fn
|
// but this need support for match inside const fn
|
||||||
|
@ -116,31 +136,30 @@ pub fn list_datastores(
|
||||||
},
|
},
|
||||||
)]
|
)]
|
||||||
/// Create new datastore config.
|
/// 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 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() {
|
if config.sections.get(&datastore.name).is_some() {
|
||||||
bail!("datastore '{}' already exists.", datastore.name);
|
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()?;
|
WorkerTask::new_thread(
|
||||||
let _store = ChunkStore::create(&datastore.name, path, backup_user.uid, backup_user.gid)?;
|
"create-datastore",
|
||||||
|
Some(datastore.name.to_string()),
|
||||||
config.set_data(&datastore.name, "datastore", &datastore)?;
|
auth_id,
|
||||||
|
false,
|
||||||
datastore::save_config(&config)?;
|
move |_worker| do_create_datastore(lock, config, datastore),
|
||||||
|
)
|
||||||
jobstate::create_state_file("prune", &datastore.name)?;
|
|
||||||
jobstate::create_state_file("garbage_collection", &datastore.name)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
|
|
|
@ -5,6 +5,7 @@ use ::serde::{Deserialize, Serialize};
|
||||||
use proxmox::api::{api, Permission, RpcEnvironment, RpcEnvironmentType};
|
use proxmox::api::{api, Permission, RpcEnvironment, RpcEnvironmentType};
|
||||||
use proxmox::api::section_config::SectionConfigData;
|
use proxmox::api::section_config::SectionConfigData;
|
||||||
use proxmox::api::router::Router;
|
use proxmox::api::router::Router;
|
||||||
|
use proxmox::tools::fs::open_file_locked;
|
||||||
|
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
||||||
use crate::tools::disks::{
|
use crate::tools::disks::{
|
||||||
|
@ -16,7 +17,7 @@ use crate::tools::systemd::{self, types::*};
|
||||||
use crate::server::WorkerTask;
|
use crate::server::WorkerTask;
|
||||||
|
|
||||||
use crate::api2::types::*;
|
use crate::api2::types::*;
|
||||||
use crate::config::datastore::DataStoreConfig;
|
use crate::config::datastore::{self, DataStoreConfig};
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -179,7 +180,17 @@ pub fn create_datastore_disk(
|
||||||
systemd::start_unit(&mount_unit_name)?;
|
systemd::start_unit(&mount_unit_name)?;
|
||||||
|
|
||||||
if add_datastore {
|
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(())
|
Ok(())
|
||||||
|
|
|
@ -14,12 +14,14 @@ use proxmox::api::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use proxmox::api::router::Router;
|
use proxmox::api::router::Router;
|
||||||
|
use proxmox::tools::fs::open_file_locked;
|
||||||
|
|
||||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
|
||||||
use crate::tools::disks::{
|
use crate::tools::disks::{
|
||||||
zpool_list, zpool_status, parse_zpool_status_config_tree, vdev_list_to_tree,
|
zpool_list, zpool_status, parse_zpool_status_config_tree, vdev_list_to_tree,
|
||||||
DiskUsageType,
|
DiskUsageType,
|
||||||
};
|
};
|
||||||
|
use crate::config::datastore::{self, DataStoreConfig};
|
||||||
|
|
||||||
use crate::server::WorkerTask;
|
use crate::server::WorkerTask;
|
||||||
|
|
||||||
|
@ -372,7 +374,17 @@ pub fn create_zpool(
|
||||||
}
|
}
|
||||||
|
|
||||||
if add_datastore {
|
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(())
|
Ok(())
|
||||||
|
|
|
@ -75,6 +75,7 @@ Ext.define('PBS.DataStoreEdit', {
|
||||||
isAdd: true,
|
isAdd: true,
|
||||||
|
|
||||||
bodyPadding: 0,
|
bodyPadding: 0,
|
||||||
|
showProgress: true,
|
||||||
|
|
||||||
cbindData: function(initialConfig) {
|
cbindData: function(initialConfig) {
|
||||||
var me = this;
|
var me = this;
|
||||||
|
|
Loading…
Reference in New Issue