cleanup config api, add remotes config cli interface
This commit is contained in:
		@ -3,19 +3,26 @@ use std::path::PathBuf;
 | 
			
		||||
use failure::*;
 | 
			
		||||
use serde_json::Value;
 | 
			
		||||
 | 
			
		||||
use proxmox::api::{ApiHandler, ApiMethod, Router, RpcEnvironment};
 | 
			
		||||
use proxmox::api::schema::*;
 | 
			
		||||
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment};
 | 
			
		||||
 | 
			
		||||
use crate::api2::types::*;
 | 
			
		||||
use crate::backup::*;
 | 
			
		||||
use crate::config::datastore;
 | 
			
		||||
 | 
			
		||||
pub const GET: ApiMethod = ApiMethod::new(
 | 
			
		||||
    &ApiHandler::Sync(&get_datastore_list),
 | 
			
		||||
    &ObjectSchema::new("Directory index.", &[])
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
fn get_datastore_list(
 | 
			
		||||
#[api(
 | 
			
		||||
    input: {
 | 
			
		||||
        properties: {},
 | 
			
		||||
    },
 | 
			
		||||
    returns: {
 | 
			
		||||
        description: "List the configured datastores.",
 | 
			
		||||
        type: Array,
 | 
			
		||||
        items: {
 | 
			
		||||
            type: datastore::DataStoreConfig,
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
)]
 | 
			
		||||
/// List all datastores
 | 
			
		||||
pub fn list_datastores(
 | 
			
		||||
    _param: Value,
 | 
			
		||||
    _info: &ApiMethod,
 | 
			
		||||
    _rpcenv: &mut dyn RpcEnvironment,
 | 
			
		||||
@ -26,90 +33,83 @@ fn get_datastore_list(
 | 
			
		||||
    Ok(config.convert_to_array("name"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const POST: ApiMethod = ApiMethod::new(
 | 
			
		||||
    &ApiHandler::Sync(&create_datastore),
 | 
			
		||||
    &ObjectSchema::new(
 | 
			
		||||
        "Create new datastore.",
 | 
			
		||||
        &[
 | 
			
		||||
            ("comment", true, &StringSchema::new("Comment for this Datastore").schema()),
 | 
			
		||||
            ("name", false, &DATASTORE_SCHEMA),
 | 
			
		||||
            ("path", false, &StringSchema::new("Directory path. The directory path is created if it does not already exist.").schema()),
 | 
			
		||||
        ],
 | 
			
		||||
    )
 | 
			
		||||
).protected(true);
 | 
			
		||||
 | 
			
		||||
fn create_datastore(
 | 
			
		||||
    param: Value,
 | 
			
		||||
    _info: &ApiMethod,
 | 
			
		||||
    _rpcenv: &mut dyn RpcEnvironment,
 | 
			
		||||
) -> Result<Value, Error> {
 | 
			
		||||
#[api(
 | 
			
		||||
    protected: true,
 | 
			
		||||
    input: {
 | 
			
		||||
        properties: {
 | 
			
		||||
            name: {
 | 
			
		||||
                schema: DATASTORE_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
            comment: {
 | 
			
		||||
                optional: true,
 | 
			
		||||
                schema: datastore::COMMENT_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
            path: {
 | 
			
		||||
                schema: datastore::DIR_NAME_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
)]
 | 
			
		||||
/// Create new datastore config.
 | 
			
		||||
pub fn create_datastore(name: String, param: Value) -> Result<(), Error> {
 | 
			
		||||
 | 
			
		||||
    // fixme: locking ?
 | 
			
		||||
 | 
			
		||||
    let datastore: datastore::DataStoreConfig = serde_json::from_value(param.clone())?;
 | 
			
		||||
 | 
			
		||||
    let mut config = datastore::config()?;
 | 
			
		||||
 | 
			
		||||
    let name = param["name"].as_str().unwrap();
 | 
			
		||||
 | 
			
		||||
    if let Some(_) = config.sections.get(name) {
 | 
			
		||||
    if let Some(_) = config.sections.get(&name) {
 | 
			
		||||
        bail!("datastore '{}' already exists.", name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let path: PathBuf = param["path"].as_str().unwrap().into();
 | 
			
		||||
    let backup_user = crate::backup::backup_user()?;
 | 
			
		||||
    let _store = ChunkStore::create(name, path, backup_user.uid, backup_user.gid)?;
 | 
			
		||||
 | 
			
		||||
    let mut datastore = serde_json::Map::new();
 | 
			
		||||
    datastore.insert("path".to_string(), param["path"].clone());
 | 
			
		||||
    if let Some(comment) = param.get("comment") {
 | 
			
		||||
        if comment.as_str().unwrap().find(|c: char| c.is_control()).is_some() {
 | 
			
		||||
    if let Some(ref comment) = datastore.comment {
 | 
			
		||||
        if comment.find(|c: char| c.is_control()).is_some() {
 | 
			
		||||
            bail!("comment must not contain control characters!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        datastore.insert("comment".to_string(), comment.clone());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    config.set_data(name, "datastore", Value::Object(datastore));
 | 
			
		||||
    let path: PathBuf = datastore.path.clone().into();
 | 
			
		||||
 | 
			
		||||
    let backup_user = crate::backup::backup_user()?;
 | 
			
		||||
    let _store = ChunkStore::create(&name, path, backup_user.uid, backup_user.gid)?;
 | 
			
		||||
 | 
			
		||||
    config.set_data(&name, "datastore", serde_json::to_value(datastore)?);
 | 
			
		||||
 | 
			
		||||
    datastore::save_config(&config)?;
 | 
			
		||||
 | 
			
		||||
    Ok(Value::Null)
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const DELETE: ApiMethod = ApiMethod::new(
 | 
			
		||||
    &ApiHandler::Sync(&delete_datastore),
 | 
			
		||||
    &ObjectSchema::new(
 | 
			
		||||
        "Remove a datastore configuration.",
 | 
			
		||||
        &[
 | 
			
		||||
            ("name", false, &DATASTORE_SCHEMA),
 | 
			
		||||
        ],
 | 
			
		||||
    )
 | 
			
		||||
).protected(true);
 | 
			
		||||
 | 
			
		||||
fn delete_datastore(
 | 
			
		||||
    param: Value,
 | 
			
		||||
    _info: &ApiMethod,
 | 
			
		||||
    _rpcenv: &mut dyn RpcEnvironment,
 | 
			
		||||
) -> Result<Value, Error> {
 | 
			
		||||
    println!("This is a test {}", param);
 | 
			
		||||
#[api(
 | 
			
		||||
    protected: true,
 | 
			
		||||
    input: {
 | 
			
		||||
        properties: {
 | 
			
		||||
            name: {
 | 
			
		||||
                schema: DATASTORE_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
)]
 | 
			
		||||
/// Remove a datastore configuration.
 | 
			
		||||
pub fn delete_datastore(name: String) -> Result<(), Error> {
 | 
			
		||||
 | 
			
		||||
    // fixme: locking ?
 | 
			
		||||
    // fixme: check digest ?
 | 
			
		||||
 | 
			
		||||
    let mut config = datastore::config()?;
 | 
			
		||||
 | 
			
		||||
    let name = param["name"].as_str().unwrap();
 | 
			
		||||
 | 
			
		||||
    match config.sections.get(name) {
 | 
			
		||||
        Some(_) => { config.sections.remove(name); },
 | 
			
		||||
    match config.sections.get(&name) {
 | 
			
		||||
        Some(_) => { config.sections.remove(&name); },
 | 
			
		||||
        None => bail!("datastore '{}' does not exist.", name),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    datastore::save_config(&config)?;
 | 
			
		||||
 | 
			
		||||
    Ok(Value::Null)
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const ROUTER: Router = Router::new()
 | 
			
		||||
    .get(&GET)
 | 
			
		||||
    .post(&POST)
 | 
			
		||||
    .delete(&DELETE);
 | 
			
		||||
    .get(&API_METHOD_LIST_DATASTORES)
 | 
			
		||||
    .post(&API_METHOD_CREATE_DATASTORE)
 | 
			
		||||
    .delete(&API_METHOD_DELETE_DATASTORE);
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@ pub fn list_remotes(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[api(
 | 
			
		||||
    protected: true,
 | 
			
		||||
    input: {
 | 
			
		||||
        properties: {
 | 
			
		||||
            name: {
 | 
			
		||||
@ -72,6 +73,7 @@ pub fn create_remote(name: String, param: Value) -> Result<(), Error> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[api(
 | 
			
		||||
    protected: true,
 | 
			
		||||
    input: {
 | 
			
		||||
        properties: {
 | 
			
		||||
            name: {
 | 
			
		||||
 | 
			
		||||
@ -113,6 +113,7 @@ pub const UPID_SCHEMA: Schema = StringSchema::new("Unique Process/Task ID.")
 | 
			
		||||
 | 
			
		||||
pub const DATASTORE_SCHEMA: Schema = StringSchema::new("Datastore name.")
 | 
			
		||||
    .format(&PROXMOX_SAFE_ID_FORMAT)
 | 
			
		||||
    .min_length(3)
 | 
			
		||||
    .max_length(32)
 | 
			
		||||
    .schema();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -44,18 +44,40 @@ fn connect() -> Result<HttpClient, Error> {
 | 
			
		||||
    Ok(client)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn remotes_commands() -> CommandLineInterface {
 | 
			
		||||
 | 
			
		||||
    use proxmox_backup::api2;
 | 
			
		||||
 | 
			
		||||
    let cmd_def = CliCommandMap::new()
 | 
			
		||||
        .insert("list", CliCommand::new(&api2::config::remotes::API_METHOD_LIST_REMOTES))
 | 
			
		||||
        .insert(
 | 
			
		||||
            "create",
 | 
			
		||||
            // fixme: howto handle password parameter?
 | 
			
		||||
            CliCommand::new(&api2::config::remotes::API_METHOD_CREATE_REMOTE)
 | 
			
		||||
                .arg_param(&["name"])
 | 
			
		||||
        )
 | 
			
		||||
        .insert(
 | 
			
		||||
            "remove",
 | 
			
		||||
            CliCommand::new(&api2::config::remotes::API_METHOD_DELETE_REMOTE)
 | 
			
		||||
                .arg_param(&["name"])
 | 
			
		||||
                .completion_cb("name", config::remotes::complete_remote_name)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    cmd_def.into()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn datastore_commands() -> CommandLineInterface {
 | 
			
		||||
 | 
			
		||||
    use proxmox_backup::api2;
 | 
			
		||||
 | 
			
		||||
    let cmd_def = CliCommandMap::new()
 | 
			
		||||
        .insert("list", CliCommand::new(&api2::config::datastore::GET))
 | 
			
		||||
        .insert("list", CliCommand::new(&api2::config::datastore::API_METHOD_LIST_DATASTORES))
 | 
			
		||||
        .insert("create",
 | 
			
		||||
                CliCommand::new(&api2::config::datastore::POST)
 | 
			
		||||
                CliCommand::new(&api2::config::datastore::API_METHOD_CREATE_DATASTORE)
 | 
			
		||||
                .arg_param(&["name", "path"])
 | 
			
		||||
        )
 | 
			
		||||
        .insert("remove",
 | 
			
		||||
                CliCommand::new(&api2::config::datastore::DELETE)
 | 
			
		||||
                CliCommand::new(&api2::config::datastore::API_METHOD_DELETE_DATASTORE)
 | 
			
		||||
                .arg_param(&["name"])
 | 
			
		||||
                .completion_cb("name", config::datastore::complete_datastore_name)
 | 
			
		||||
        );
 | 
			
		||||
@ -360,8 +382,7 @@ fn cert_mgmt_cli() -> CommandLineInterface {
 | 
			
		||||
                schema: DATASTORE_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
            remote: {
 | 
			
		||||
                description: "Remote name.", // fixme: remote ID schema
 | 
			
		||||
                type: String,
 | 
			
		||||
                schema: crate::config::remotes::REMOTE_ID_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
            "remote-store": {
 | 
			
		||||
                schema: DATASTORE_SCHEMA,
 | 
			
		||||
@ -407,6 +428,7 @@ fn main() {
 | 
			
		||||
 | 
			
		||||
    let cmd_def = CliCommandMap::new()
 | 
			
		||||
        .insert("datastore", datastore_commands())
 | 
			
		||||
        .insert("remotes", remotes_commands())
 | 
			
		||||
        .insert("garbage-collection", garbage_collection_commands())
 | 
			
		||||
        .insert("cert", cert_mgmt_cli())
 | 
			
		||||
        .insert("task", task_mgmt_cli())
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ use serde::{Serialize, Deserialize};
 | 
			
		||||
use proxmox::api::{api, schema::*};
 | 
			
		||||
use proxmox::tools::{fs::replace_file, fs::CreateOptions};
 | 
			
		||||
 | 
			
		||||
use crate::api2::types::*;
 | 
			
		||||
use crate::section_config::{SectionConfig, SectionConfigData, SectionConfigPlugin};
 | 
			
		||||
 | 
			
		||||
lazy_static! {
 | 
			
		||||
@ -16,9 +17,6 @@ lazy_static! {
 | 
			
		||||
 | 
			
		||||
pub const DIR_NAME_SCHEMA: Schema = StringSchema::new("Directory name").schema();
 | 
			
		||||
pub const COMMENT_SCHEMA: Schema = StringSchema::new("Datastore comment").schema();
 | 
			
		||||
pub const DATASTORE_ID_SCHEMA: Schema = StringSchema::new("DataStore ID schema.")
 | 
			
		||||
    .min_length(3)
 | 
			
		||||
    .schema();
 | 
			
		||||
 | 
			
		||||
#[api(
 | 
			
		||||
    properties: {
 | 
			
		||||
@ -45,7 +43,7 @@ fn init() -> SectionConfig {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let plugin = SectionConfigPlugin::new("datastore".to_string(), obj_schema);
 | 
			
		||||
    let mut config = SectionConfig::new(&DATASTORE_ID_SCHEMA);
 | 
			
		||||
    let mut config = SectionConfig::new(&DATASTORE_SCHEMA);
 | 
			
		||||
    config.register_plugin(plugin);
 | 
			
		||||
 | 
			
		||||
    config
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user