cleanup config api, add remotes config cli interface

This commit is contained in:
Dietmar Maurer 2020-01-11 10:42:09 +01:00
parent 9e9bc6525e
commit 688fbe07a1
5 changed files with 96 additions and 73 deletions

View File

@ -3,19 +3,26 @@ use std::path::PathBuf;
use failure::*; use failure::*;
use serde_json::Value; use serde_json::Value;
use proxmox::api::{ApiHandler, ApiMethod, Router, RpcEnvironment}; use proxmox::api::{api, ApiMethod, Router, RpcEnvironment};
use proxmox::api::schema::*;
use crate::api2::types::*; use crate::api2::types::*;
use crate::backup::*; use crate::backup::*;
use crate::config::datastore; use crate::config::datastore;
pub const GET: ApiMethod = ApiMethod::new( #[api(
&ApiHandler::Sync(&get_datastore_list), input: {
&ObjectSchema::new("Directory index.", &[]) properties: {},
); },
returns: {
fn get_datastore_list( description: "List the configured datastores.",
type: Array,
items: {
type: datastore::DataStoreConfig,
},
},
)]
/// List all datastores
pub fn list_datastores(
_param: Value, _param: Value,
_info: &ApiMethod, _info: &ApiMethod,
_rpcenv: &mut dyn RpcEnvironment, _rpcenv: &mut dyn RpcEnvironment,
@ -26,90 +33,83 @@ fn get_datastore_list(
Ok(config.convert_to_array("name")) Ok(config.convert_to_array("name"))
} }
pub const POST: ApiMethod = ApiMethod::new( #[api(
&ApiHandler::Sync(&create_datastore), protected: true,
&ObjectSchema::new( input: {
"Create new datastore.", properties: {
&[ name: {
("comment", true, &StringSchema::new("Comment for this Datastore").schema()), schema: DATASTORE_SCHEMA,
("name", false, &DATASTORE_SCHEMA), },
("path", false, &StringSchema::new("Directory path. The directory path is created if it does not already exist.").schema()), comment: {
], optional: true,
) schema: datastore::COMMENT_SCHEMA,
).protected(true); },
path: {
fn create_datastore( schema: datastore::DIR_NAME_SCHEMA,
param: Value, },
_info: &ApiMethod, },
_rpcenv: &mut dyn RpcEnvironment, },
) -> Result<Value, Error> { )]
/// Create new datastore config.
pub fn create_datastore(name: String, param: Value) -> Result<(), Error> {
// fixme: locking ? // fixme: locking ?
let datastore: datastore::DataStoreConfig = serde_json::from_value(param.clone())?;
let mut config = datastore::config()?; 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); bail!("datastore '{}' already exists.", name);
} }
let path: PathBuf = param["path"].as_str().unwrap().into(); if let Some(ref comment) = datastore.comment {
let backup_user = crate::backup::backup_user()?; if comment.find(|c: char| c.is_control()).is_some() {
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() {
bail!("comment must not contain control characters!"); 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)?; datastore::save_config(&config)?;
Ok(Value::Null) Ok(())
} }
pub const DELETE: ApiMethod = ApiMethod::new( #[api(
&ApiHandler::Sync(&delete_datastore), protected: true,
&ObjectSchema::new( input: {
"Remove a datastore configuration.", properties: {
&[ name: {
("name", false, &DATASTORE_SCHEMA), schema: DATASTORE_SCHEMA,
], },
) },
).protected(true); },
)]
fn delete_datastore( /// Remove a datastore configuration.
param: Value, pub fn delete_datastore(name: String) -> Result<(), Error> {
_info: &ApiMethod,
_rpcenv: &mut dyn RpcEnvironment,
) -> Result<Value, Error> {
println!("This is a test {}", param);
// fixme: locking ? // fixme: locking ?
// fixme: check digest ? // fixme: check digest ?
let mut config = datastore::config()?; 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), None => bail!("datastore '{}' does not exist.", name),
} }
datastore::save_config(&config)?; datastore::save_config(&config)?;
Ok(Value::Null) Ok(())
} }
pub const ROUTER: Router = Router::new() pub const ROUTER: Router = Router::new()
.get(&GET) .get(&API_METHOD_LIST_DATASTORES)
.post(&POST) .post(&API_METHOD_CREATE_DATASTORE)
.delete(&DELETE); .delete(&API_METHOD_DELETE_DATASTORE);

View File

@ -30,6 +30,7 @@ pub fn list_remotes(
} }
#[api( #[api(
protected: true,
input: { input: {
properties: { properties: {
name: { name: {
@ -72,6 +73,7 @@ pub fn create_remote(name: String, param: Value) -> Result<(), Error> {
} }
#[api( #[api(
protected: true,
input: { input: {
properties: { properties: {
name: { name: {

View File

@ -113,6 +113,7 @@ pub const UPID_SCHEMA: Schema = StringSchema::new("Unique Process/Task ID.")
pub const DATASTORE_SCHEMA: Schema = StringSchema::new("Datastore name.") pub const DATASTORE_SCHEMA: Schema = StringSchema::new("Datastore name.")
.format(&PROXMOX_SAFE_ID_FORMAT) .format(&PROXMOX_SAFE_ID_FORMAT)
.min_length(3)
.max_length(32) .max_length(32)
.schema(); .schema();

View File

@ -44,18 +44,40 @@ fn connect() -> Result<HttpClient, Error> {
Ok(client) 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 { fn datastore_commands() -> CommandLineInterface {
use proxmox_backup::api2; use proxmox_backup::api2;
let cmd_def = CliCommandMap::new() 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", .insert("create",
CliCommand::new(&api2::config::datastore::POST) CliCommand::new(&api2::config::datastore::API_METHOD_CREATE_DATASTORE)
.arg_param(&["name", "path"]) .arg_param(&["name", "path"])
) )
.insert("remove", .insert("remove",
CliCommand::new(&api2::config::datastore::DELETE) CliCommand::new(&api2::config::datastore::API_METHOD_DELETE_DATASTORE)
.arg_param(&["name"]) .arg_param(&["name"])
.completion_cb("name", config::datastore::complete_datastore_name) .completion_cb("name", config::datastore::complete_datastore_name)
); );
@ -360,8 +382,7 @@ fn cert_mgmt_cli() -> CommandLineInterface {
schema: DATASTORE_SCHEMA, schema: DATASTORE_SCHEMA,
}, },
remote: { remote: {
description: "Remote name.", // fixme: remote ID schema schema: crate::config::remotes::REMOTE_ID_SCHEMA,
type: String,
}, },
"remote-store": { "remote-store": {
schema: DATASTORE_SCHEMA, schema: DATASTORE_SCHEMA,
@ -407,6 +428,7 @@ fn main() {
let cmd_def = CliCommandMap::new() let cmd_def = CliCommandMap::new()
.insert("datastore", datastore_commands()) .insert("datastore", datastore_commands())
.insert("remotes", remotes_commands())
.insert("garbage-collection", garbage_collection_commands()) .insert("garbage-collection", garbage_collection_commands())
.insert("cert", cert_mgmt_cli()) .insert("cert", cert_mgmt_cli())
.insert("task", task_mgmt_cli()) .insert("task", task_mgmt_cli())

View File

@ -6,6 +6,7 @@ use serde::{Serialize, Deserialize};
use proxmox::api::{api, schema::*}; use proxmox::api::{api, schema::*};
use proxmox::tools::{fs::replace_file, fs::CreateOptions}; use proxmox::tools::{fs::replace_file, fs::CreateOptions};
use crate::api2::types::*;
use crate::section_config::{SectionConfig, SectionConfigData, SectionConfigPlugin}; use crate::section_config::{SectionConfig, SectionConfigData, SectionConfigPlugin};
lazy_static! { lazy_static! {
@ -16,9 +17,6 @@ lazy_static! {
pub const DIR_NAME_SCHEMA: Schema = StringSchema::new("Directory name").schema(); pub const DIR_NAME_SCHEMA: Schema = StringSchema::new("Directory name").schema();
pub const COMMENT_SCHEMA: Schema = StringSchema::new("Datastore comment").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( #[api(
properties: { properties: {
@ -45,7 +43,7 @@ fn init() -> SectionConfig {
}; };
let plugin = SectionConfigPlugin::new("datastore".to_string(), obj_schema); 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.register_plugin(plugin);
config config