-
Notifications
You must be signed in to change notification settings - Fork 243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Cosmos] Control-Plane Over Data-Plane APIs (Database/Container CRUD) #1853
base: feature/track2
Are you sure you want to change the base?
Changes from all commits
edbfb84
273b0b0
7222e00
87c4ea5
1d34873
7b16078
0224c6c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<div class="warning"> | ||
analogrelay marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
This is a control-plane API and requires that you authenticate using a key. To use Entra ID to perform this operation, you must use the [Azure Resource Manager APIs](https://learn.microsoft.com/en-us/azure/templates/microsoft.documentdb/databaseaccounts). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this PR does the right thing for the point in time we're at, but just pointing out that I believe there is a plan to support these operations via Entra ID at some point in 2025, and also to integrate the dataplane RBAC with normal Azure RBAC. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, the intent is that this feature can be "removed" later. It will have to remain present, and continue to imply |
||
|
||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,42 +4,129 @@ use azure_data_cosmos::{ | |
clients::{ContainerClientMethods, DatabaseClientMethods}, | ||
CosmosClient, CosmosClientMethods, PartitionKey, | ||
}; | ||
use clap::Args; | ||
use clap::{Args, Subcommand}; | ||
|
||
/// Creates a new item. | ||
#[cfg(feature = "control_plane")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Annoyingly, it sees we need to conditionally-compile our |
||
use azure_data_cosmos::models::{ContainerProperties, PartitionKeyDefinition}; | ||
|
||
/// Creates a new item, database, or container. | ||
#[derive(Clone, Args)] | ||
pub struct CreateCommand { | ||
/// The database in which to create the item. | ||
database: String, | ||
#[command(subcommand)] | ||
subcommand: Subcommands, | ||
} | ||
|
||
#[derive(Clone, Subcommand)] | ||
pub enum Subcommands { | ||
/// Create an item in a container. | ||
Item { | ||
/// The database in which to create the item. | ||
database: String, | ||
|
||
/// The container in which to create the item. | ||
container: String, | ||
|
||
/// The partition key of the new item. | ||
#[clap(long, short)] | ||
partition_key: String, | ||
|
||
/// The JSON of the new item. | ||
#[clap(long, short)] | ||
json: String, | ||
}, | ||
|
||
/// The container in which to create the item. | ||
container: String, | ||
/// Create a database (does not support Entra ID). | ||
#[cfg(feature = "control_plane")] | ||
Database { | ||
/// The ID of the new database to create. | ||
id: String, | ||
}, | ||
|
||
/// The partition key of the new item. | ||
#[clap(long, short)] | ||
partition_key: String, | ||
/// Create a container (does not support Entra ID). | ||
#[cfg(feature = "control_plane")] | ||
Container { | ||
/// The ID of the database to create the container in. | ||
database: String, | ||
|
||
/// The JSON of the new item. | ||
#[clap(long, short)] | ||
json: String, | ||
/// The ID of the new container to create. | ||
#[clap(long, short)] | ||
id: Option<String>, | ||
|
||
/// The path to the partition key properties (supports up to 3). | ||
#[clap(long, short)] | ||
partition_key: Vec<String>, | ||
|
||
/// The JSON for a ContainerProperties value. The 'id' and 'partition key' options are ignored if this is set. | ||
#[clap(long)] | ||
json: Option<String>, | ||
}, | ||
} | ||
|
||
impl CreateCommand { | ||
pub async fn run(self, client: CosmosClient) -> Result<(), Box<dyn Error>> { | ||
let db_client = client.database_client(&self.database); | ||
let container_client = db_client.container_client(&self.container); | ||
|
||
let pk = PartitionKey::from(&self.partition_key); | ||
let item: serde_json::Value = serde_json::from_str(&self.json)?; | ||
|
||
let created = container_client | ||
.create_item(pk, item, None) | ||
.await? | ||
.deserialize_body() | ||
.await? | ||
.unwrap(); | ||
println!("Created item:"); | ||
println!("{:#?}", created); | ||
Ok(()) | ||
match self.subcommand { | ||
Subcommands::Item { | ||
database, | ||
container, | ||
partition_key, | ||
json, | ||
} => { | ||
let db_client = client.database_client(database); | ||
let container_client = db_client.container_client(container); | ||
|
||
let pk = PartitionKey::from(&partition_key); | ||
let item: serde_json::Value = serde_json::from_str(&json)?; | ||
|
||
let created = container_client | ||
.create_item(pk, item, None) | ||
.await? | ||
.deserialize_body() | ||
.await? | ||
.unwrap(); | ||
println!("Created item:"); | ||
println!("{:#?}", created); | ||
Ok(()) | ||
} | ||
|
||
#[cfg(feature = "control_plane")] | ||
Subcommands::Database { id } => { | ||
let db = client | ||
.create_database(id, None) | ||
.await? | ||
.deserialize_body() | ||
.await? | ||
.unwrap(); | ||
println!("Created database:"); | ||
println!("{:#?}", db); | ||
Ok(()) | ||
} | ||
|
||
#[cfg(feature = "control_plane")] | ||
Subcommands::Container { | ||
database, | ||
id, | ||
partition_key, | ||
json, | ||
} => { | ||
let properties = match json { | ||
Some(j) => serde_json::from_str(&j).unwrap(), | ||
None => ContainerProperties { | ||
id: id.expect("the ID is required when not using '--json'"), | ||
partition_key: PartitionKeyDefinition::new(partition_key), | ||
..Default::default() | ||
}, | ||
}; | ||
let container = client | ||
.database_client(database) | ||
.create_container(properties, None) | ||
.await? | ||
.deserialize_body() | ||
.await? | ||
.unwrap(); | ||
println!("Created container:"); | ||
println!("{:#?}", container); | ||
Ok(()) | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used
cfg-if
to simplify some conditional compilation inazure_data_cosmos
. It's a relatively low-impact crate, but I'm open to removing it and going back to a series of#[cfg(...)]
-attributed definitions if that's preferred. (cc @heaths )