Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions crates/catalog-driver-sql/src/endpoint_group.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

use std::collections::HashMap;

use sea_orm::entity::*;
use serde_json::Value;
use tracing::error;
use uuid::Uuid;

use openstack_keystone_core::catalog::CatalogProviderError;
use openstack_keystone_core_types::catalog::*;

use crate::entity::endpoint_group as db_endpoint_group;

mod create;
mod delete;
mod get;
mod list;
mod update;

pub use create::create;
pub use delete::delete;
pub use get::get;
pub use list::list;
pub use update::update;

impl TryFrom<db_endpoint_group::Model> for EndpointGroup {
type Error = CatalogProviderError;

/// Tries to convert a database endpoint group model into a domain endpoint
/// group.
///
/// # Parameters
/// - `value`: The database endpoint group model.
///
/// # Returns
/// A `Result` containing the `EndpointGroup`, or a `CatalogProviderError`.
fn try_from(value: db_endpoint_group::Model) -> Result<Self, Self::Error> {
let mut builder = EndpointGroupBuilder::default();
builder.id(value.id.clone());
builder.name(value.name.clone());
if let Some(description) = &value.description {
builder.description(description.clone());
}

if value.filters != "{}" {
match serde_json::from_str::<HashMap<String, Value>>(&value.filters) {
Ok(val) => {
builder.filters(val);
}
Err(e) => {
error!("failed to deserialize endpoint group filters: {e}");
}
}
}

Ok(builder.build()?)
}
}

impl TryFrom<EndpointGroupCreate> for db_endpoint_group::ActiveModel {
type Error = CatalogProviderError;

/// Tries to convert endpoint group creation parameters into a database
/// active model.
///
/// # Parameters
/// - `value`: The endpoint group creation parameters.
///
/// # Returns
/// A `Result` containing the `ActiveModel`, or a `CatalogProviderError`.
fn try_from(value: EndpointGroupCreate) -> Result<Self, Self::Error> {
Ok(Self {
id: Set(value
.id
.unwrap_or_else(|| Uuid::new_v4().simple().to_string())),
name: Set(value.name),
description: Set(value.description),
filters: Set(serde_json::to_string(&value.filters)?),
})
}
}

#[cfg(test)]
pub(crate) mod tests {
use crate::entity::endpoint_group;

pub fn get_endpoint_group_mock<I: Into<String>>(id: I) -> endpoint_group::Model {
endpoint_group::Model {
id: id.into(),
name: "group".into(),
description: Some("description".into()),
filters: r#"{"interface":"public"}"#.into(),
}
}
}
75 changes: 75 additions & 0 deletions crates/catalog-driver-sql/src/endpoint_group/create.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
//! # Create endpoint group

use sea_orm::DatabaseConnection;
use sea_orm::entity::*;

use openstack_keystone_core::catalog::CatalogProviderError;
use openstack_keystone_core::error::DbContextExt;
use openstack_keystone_core_types::catalog::{EndpointGroup, EndpointGroupCreate};

use crate::entity::endpoint_group as db_endpoint_group;

/// Creates a new endpoint group.
///
/// # Parameters
/// - `db`: The database connection.
/// - `endpoint_group`: The endpoint group creation parameters.
///
/// # Returns
/// A `Result` containing the created `EndpointGroup`, or an `Error`.
pub async fn create(
db: &DatabaseConnection,
endpoint_group: EndpointGroupCreate,
) -> Result<EndpointGroup, CatalogProviderError> {
TryInto::<db_endpoint_group::ActiveModel>::try_into(endpoint_group)?
.insert(db)
.await
.context("creating endpoint group")?
.try_into()
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;

use sea_orm::{DatabaseBackend, MockDatabase};
use serde_json::json;

use super::super::tests::get_endpoint_group_mock;
use super::*;

#[tokio::test]
async fn test_create() {
let db = MockDatabase::new(DatabaseBackend::Postgres)
.append_query_results([vec![get_endpoint_group_mock("eg-1")]])
.into_connection();

let req = EndpointGroupCreate {
id: Some("eg-1".into()),
name: "group".into(),
description: Some("description".into()),
filters: HashMap::from([("interface".into(), json!("public"))]),
};

let created = create(&db, req).await.unwrap();
assert_eq!(created.id, "eg-1");
assert_eq!(created.name, "group");
assert_eq!(
created.filters,
HashMap::from([("interface".to_string(), json!("public"))])
);
}
}
60 changes: 60 additions & 0 deletions crates/catalog-driver-sql/src/endpoint_group/delete.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
//! # Delete Endpoint Group

use sea_orm::DatabaseConnection;
use sea_orm::entity::*;

use openstack_keystone_core::catalog::CatalogProviderError;
use openstack_keystone_core::error::DbContextExt;

use crate::entity::prelude::EndpointGroup as DbEndpointGroup;

/// Deletes an existing endpoint group.
///
/// # Parameters
/// - `db`: The database connection.
/// - `id`: The endpoint group ID.
///
/// # Returns
/// A `Result` indicating success or an `Error`.
pub async fn delete<S: AsRef<str>>(
db: &DatabaseConnection,
id: S,
) -> Result<(), CatalogProviderError> {
DbEndpointGroup::delete_by_id(id.as_ref())
.exec(db)
.await
.context("deleting endpoint group")?;
Ok(())
}

#[cfg(test)]
mod tests {
use sea_orm::{DatabaseBackend, MockDatabase, MockExecResult};

use super::*;

#[tokio::test]
async fn test_delete() {
let db = MockDatabase::new(DatabaseBackend::Postgres)
.append_exec_results([MockExecResult {
rows_affected: 1,
..Default::default()
}])
.into_connection();

delete(&db, "eg-1").await.unwrap();
}
}
73 changes: 73 additions & 0 deletions crates/catalog-driver-sql/src/endpoint_group/get.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
//! # Get endpoint group

use sea_orm::DatabaseConnection;
use sea_orm::entity::*;

use openstack_keystone_core::catalog::CatalogProviderError;
use openstack_keystone_core::error::DbContextExt;
use openstack_keystone_core_types::catalog::EndpointGroup;

use crate::entity::prelude::EndpointGroup as DbEndpointGroup;

/// Gets an endpoint group by ID.
///
/// # Parameters
/// - `db`: The database connection.
/// - `id`: The ID of the endpoint group to retrieve.
///
/// # Returns
/// A `Result` containing an `Option` with the `EndpointGroup` if found, or an
/// `Error`.
pub async fn get<I: AsRef<str>>(
db: &DatabaseConnection,
id: I,
) -> Result<Option<EndpointGroup>, CatalogProviderError> {
DbEndpointGroup::find_by_id(id.as_ref())
.one(db)
.await
.context("fetching endpoint group by ID")?
.map(TryInto::try_into)
.transpose()
}

#[cfg(test)]
mod tests {
use sea_orm::{DatabaseBackend, MockDatabase};

use super::super::tests::get_endpoint_group_mock;
use super::*;
use crate::entity::endpoint_group;

#[tokio::test]
async fn test_get() {
let db = MockDatabase::new(DatabaseBackend::Postgres)
.append_query_results([vec![get_endpoint_group_mock("eg-1")]])
.into_connection();

let eg = get(&db, "eg-1").await.unwrap().expect("group found");
assert_eq!(eg.id, "eg-1");
assert_eq!(eg.name, "group");
}

#[tokio::test]
async fn test_get_not_found() {
let db = MockDatabase::new(DatabaseBackend::Postgres)
.append_query_results([Vec::<endpoint_group::Model>::new()])
.into_connection();

assert!(get(&db, "missing").await.unwrap().is_none());
}
}
77 changes: 77 additions & 0 deletions crates/catalog-driver-sql/src/endpoint_group/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
//! # List endpoint groups

use sea_orm::DatabaseConnection;
use sea_orm::entity::*;
use sea_orm::query::*;

use openstack_keystone_core::catalog::CatalogProviderError;
use openstack_keystone_core::error::DbContextExt;
use openstack_keystone_core_types::catalog::*;

use crate::entity::{
endpoint_group as db_endpoint_group, prelude::EndpointGroup as DbEndpointGroup,
};

/// Lists endpoint groups.
///
/// # Parameters
/// - `db`: The database connection.
/// - `params`: The parameters for listing endpoint groups.
///
/// # Returns
/// A `Result` containing a vector of `EndpointGroup`s, or a
/// `CatalogProviderError`.
pub async fn list(
db: &DatabaseConnection,
params: &EndpointGroupListParameters,
) -> Result<Vec<EndpointGroup>, CatalogProviderError> {
let mut select = DbEndpointGroup::find();

if let Some(name) = &params.name {
select = select.filter(db_endpoint_group::Column::Name.eq(name));
}

select
.all(db)
.await
.context("fetching endpoint groups")?
.into_iter()
.map(TryInto::<EndpointGroup>::try_into)
.collect()
}

#[cfg(test)]
mod tests {
use sea_orm::{DatabaseBackend, MockDatabase};

use super::super::tests::get_endpoint_group_mock;
use super::*;

#[tokio::test]
async fn test_list() {
let db = MockDatabase::new(DatabaseBackend::Postgres)
.append_query_results([vec![
get_endpoint_group_mock("eg-1"),
get_endpoint_group_mock("eg-2"),
]])
.into_connection();

let groups = list(&db, &EndpointGroupListParameters::default())
.await
.unwrap();
assert_eq!(groups.len(), 2);
}
}
Loading
Loading