feat: Add disown database commands to the database CLI

pull/24376/head
Carol (Nichols || Goulding) 2021-11-08 16:02:15 -05:00
parent e160954b57
commit b1e81186d3
No known key found for this signature in database
GPG Key ID: E907EE5A736F87D4
3 changed files with 287 additions and 2 deletions

View File

@ -7,8 +7,8 @@ use influxdb_iox_client::{
flight,
format::QueryOutputFormat,
management::{
self, generated_types::*, CreateDatabaseError, DeleteDatabaseError, GetDatabaseError,
ListDatabaseError, RestoreDatabaseError,
self, generated_types::*, CreateDatabaseError, DeleteDatabaseError, DisownDatabaseError,
GetDatabaseError, ListDatabaseError, RestoreDatabaseError,
},
write::{self, WriteError},
};
@ -37,6 +37,9 @@ pub enum Error {
#[error("Error deleting database: {0}")]
DeleteDatabaseError(#[from] DeleteDatabaseError),
#[error("Error disowning database: {0}")]
DisownDatabaseError(#[from] DisownDatabaseError),
#[error("Error restoring database: {0}")]
RestoreDatabaseError(#[from] RestoreDatabaseError),
@ -187,6 +190,23 @@ struct Delete {
name: String,
}
/// Disown a database from its current server owner
#[derive(Debug, StructOpt)]
struct Disown {
/// The name of the database to disown
name: String,
/// Optionally, the UUID of the database to delete. This must match the UUID of the current
/// database with the given name, or the disown operation will result in an error.
#[structopt(short, long)]
uuid: Option<String>,
/// Optionally, context for this operation, to be stored in the database's owner file as a
/// historical record
#[structopt(short, long)]
context: Option<String>,
}
/// Restore a deleted database
#[derive(Debug, StructOpt)]
struct Restore {
@ -206,6 +226,7 @@ enum Command {
Partition(partition::Config),
Recover(recover::Config),
Delete(Delete),
Disown(Disown),
Restore(Restore),
}
@ -348,6 +369,14 @@ pub async fn command(connection: Connection, config: Config) -> Result<()> {
println!("Deleted database {}", command.name);
println!("{}", uuid);
}
Command::Disown(command) => {
let mut client = management::Client::new(connection);
let uuid = client
.disown_database(&command.name, command.uuid, command.context)
.await?;
println!("Disowned database {}", command.name);
println!("{}", uuid);
}
Command::Restore(command) => {
let mut client = management::Client::new(connection);
client.restore_database(&command.uuid).await?;

View File

@ -388,6 +388,248 @@ async fn delete_restore_database() {
)));
}
#[tokio::test]
async fn disown_database() {
let server_fixture = ServerFixture::create_shared(ServerType::Database).await;
let addr = server_fixture.grpc_base();
let db_name = rand_name();
let db = &db_name;
// Create a database on one server
let stdout = String::from_utf8(
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("create")
.arg(db)
.arg("--host")
.arg(addr)
.assert()
.success()
.stdout(predicate::str::contains("Created"))
.get_output()
.stdout
.clone(),
)
.unwrap();
let created_uuid = stdout.lines().last().unwrap().trim();
// Disown database returns the UUID
let stdout = String::from_utf8(
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("disown")
.arg(db)
.arg("--host")
.arg(addr)
.assert()
.success()
.stdout(predicate::str::contains(format!(
"Disowned database {}",
db
)))
.get_output()
.stdout
.clone(),
)
.unwrap();
let deleted_uuid = stdout.lines().last().unwrap().trim();
assert_eq!(created_uuid, deleted_uuid);
// Disowned database is no longer in this server's database list
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("list")
.arg("--host")
.arg(addr)
.assert()
.success()
.stdout(predicate::str::contains(db).not());
// Disowning the same database again is an error
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("disown")
.arg(db)
.arg("--host")
.arg(addr)
.assert()
.failure()
.stderr(predicate::str::contains(format!(
"Could not find database {}",
db
)));
// Create another database
let stdout = String::from_utf8(
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("create")
.arg(db)
.arg("--host")
.arg(addr)
.assert()
.success()
.stdout(predicate::str::contains("Created"))
.get_output()
.stdout
.clone(),
)
.unwrap();
let created_uuid = stdout.lines().last().unwrap().trim();
// If an optional UUID is specified, don't disown the database if the UUID doesn't match
let incorrect_uuid = Uuid::new_v4();
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("disown")
.arg(db)
.arg("--uuid")
.arg(incorrect_uuid.to_string())
.arg("--host")
.arg(addr)
.assert()
.failure()
.stderr(predicate::str::contains(format!(
"Could not disown {}: the UUID specified ({}) does not match the current UUID ({})",
db, incorrect_uuid, created_uuid,
)));
// Error if the UUID specified is not in a valid UUID format
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("disown")
.arg(db)
.arg("--uuid")
.arg("foo")
.arg("--host")
.arg(addr)
.assert()
.failure()
.stderr(predicate::str::contains("Invalid UUID"));
// If an optional UUID is specified, disown the database if the UUID does match
let stdout = String::from_utf8(
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("disown")
.arg(db)
.arg("--uuid")
.arg(created_uuid)
.arg("--host")
.arg(addr)
.assert()
.success()
.stdout(predicate::str::contains(format!(
"Disowned database {}",
db
)))
.get_output()
.stdout
.clone(),
)
.unwrap();
let deleted_uuid = stdout.lines().last().unwrap().trim();
assert_eq!(created_uuid, deleted_uuid);
// Create another database
let stdout = String::from_utf8(
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("create")
.arg(db)
.arg("--host")
.arg(addr)
.assert()
.success()
.stdout(predicate::str::contains("Created"))
.get_output()
.stdout
.clone(),
)
.unwrap();
let created_uuid = stdout.lines().last().unwrap().trim();
// Can optionally specify a context and not a UUID
let stdout = String::from_utf8(
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("disown")
.arg(db)
.arg("--context")
.arg("this database is being a noisy neighbor")
.arg("--host")
.arg(addr)
.assert()
.success()
.stdout(predicate::str::contains(format!(
"Disowned database {}",
db
)))
.get_output()
.stdout
.clone(),
)
.unwrap();
let deleted_uuid = stdout.lines().last().unwrap().trim();
assert_eq!(created_uuid, deleted_uuid);
// Create another database
let stdout = String::from_utf8(
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("create")
.arg(db)
.arg("--host")
.arg(addr)
.assert()
.success()
.stdout(predicate::str::contains("Created"))
.get_output()
.stdout
.clone(),
)
.unwrap();
let created_uuid = stdout.lines().last().unwrap().trim();
// Can optionally specify a context AND a UUID
let stdout = String::from_utf8(
Command::cargo_bin("influxdb_iox")
.unwrap()
.arg("database")
.arg("disown")
.arg(db)
.arg("--uuid")
.arg(created_uuid)
.arg("--context")
.arg("\"this database is rarely used\"")
.arg("--host")
.arg(addr)
.assert()
.success()
.stdout(predicate::str::contains(format!(
"Disowned database {}",
db
)))
.get_output()
.stdout
.clone(),
)
.unwrap();
let deleted_uuid = stdout.lines().last().unwrap().trim();
assert_eq!(created_uuid, deleted_uuid);
}
#[tokio::test]
async fn test_get_chunks() {
let server_fixture = ServerFixture::create_shared(ServerType::Database).await;

View File

@ -146,6 +146,10 @@ pub enum DeleteDatabaseError {
ServerError(tonic::Status),
}
/// Errors returned by Client::disown_database
#[derive(Debug, Error)]
pub enum DisownDatabaseError {}
/// Errors returned by Client::restore_database
#[derive(Debug, Error)]
pub enum RestoreDatabaseError {
@ -697,6 +701,16 @@ impl Client {
Ok(uuid)
}
/// Disown database
pub async fn disown_database(
&mut self,
db_name: impl Into<String> + Send,
uuid: Option<String>,
context: Option<String>,
) -> Result<Uuid, DisownDatabaseError> {
unimplemented!()
}
/// Restore database
pub async fn restore_database(
&mut self,