Skip to content
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

feat: controller error handling #97

Merged
merged 8 commits into from
May 10, 2023
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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions controller/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ rstest = "0.16.0"
uuid = { version = "1.3.1", features = ["serde", "v4"] }
backoff = { version = "0.4.0", features = ["tokio"]}
rand = "0.8.4"
thiserror = "1.0.40"
anyhow = "1.0.71"

# Instrumentation
tracing = { workspace = true }
Expand Down
48 changes: 30 additions & 18 deletions controller/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use tiny_http::{Request, Server as TinyServer};

use tracing::{event, Level};

use super::RikError;

pub struct Server {
internal_sender: Sender<ApiChannel>,
}
Expand All @@ -20,11 +22,11 @@ impl Server {
Server { internal_sender }
}

pub fn run(&self, db: Arc<RikDataBase>) {
self.run_server(db);
pub fn run(&self, db: Arc<RikDataBase>) -> Result<(), RikError> {
self.run_server(db)
}

fn run_server(&self, db: Arc<RikDataBase>) {
fn run_server(&self, db: Arc<RikDataBase>) -> Result<(), RikError> {
let host = String::from("0.0.0.0");
dotenv().ok();
let port: usize = match std::env::var("PORT") {
Expand All @@ -41,28 +43,38 @@ impl Server {
let db = db.clone();
let internal_sender = self.internal_sender.clone();

let guard = thread::spawn(move || loop {
let router = routes::Router::new();
let connection = db.open().unwrap();
let guard = thread::spawn(move || -> Result<(), RikError> {
loop {
let router = routes::Router::new();
let connection = db.open().map_err(RikError::DatabaseError)?;

let mut req: Request = server.recv().unwrap();
let mut req: Request = server.recv().unwrap();

if let Some(res) = router.handle(&mut req, &connection, &internal_sender) {
req.respond(res).unwrap();
continue;
if let Some(res) = router.handle(&mut req, &connection, &internal_sender) {
req.respond(res).unwrap();
continue;
}
event!(
Level::INFO,
"Route {} ({}) could not be found",
req.url(),
req.method()
);
req.respond(tiny_http::Response::empty(tiny_http::StatusCode::from(404)))
.unwrap();
}
event!(
Level::INFO,
"Route {} ({}) could not be found",
req.url(),
req.method()
);
req.respond(tiny_http::Response::empty(tiny_http::StatusCode::from(404)))
.unwrap();
});

guards.push(guard);
}

for guard in guards {
guard
.join()
.expect("Couldn't join on the associated thread")?
}

event!(Level::INFO, "Server running on http://{}:{}", host, port);
Ok(())
}
}
46 changes: 22 additions & 24 deletions controller/src/api/external/routes/instance.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
use definition::workload::WorkloadDefinition;
use route_recognizer;
use rusqlite::Connection;
use std::io;
use std::str::FromStr;
use std::sync::mpsc::Sender;
use tracing::{event, Level};

use crate::api;
use crate::api::external::routes::ContentType;
use crate::api::external::services::element::elements_set_right_name;
use crate::api::external::services::instance::send_create_instance;
use crate::api::types::element::OnlyId;
use crate::api::types::instance::InstanceDefinition;
use crate::api::{ApiChannel, Crud};
use crate::core::instance::Instance;
use crate::database::RikRepository;
use tiny_http::Header;

use super::HttpResult;

pub fn get(
_: &mut tiny_http::Request,
_: &route_recognizer::Params,
connection: &Connection,
_: &Sender<ApiChannel>,
) -> Result<tiny_http::Response<io::Cursor<Vec<u8>>>, api::RikError> {
) -> HttpResult {
if let Ok(mut instances) = RikRepository::find_all(connection, "/instance") {
instances = elements_set_right_name(instances.clone());
let instances_json = serde_json::to_string(&instances).unwrap();
let instances_json = serde_json::to_string(&instances)?;

event!(Level::INFO, "instances.get, instances found");
Ok(tiny_http::Response::from_string(instances_json)
.with_header(tiny_http::Header::from_str("Content-Type: application/json").unwrap())
.with_header::<Header>(ContentType::JSON.into())
.with_status_code(tiny_http::StatusCode::from(200)))
} else {
Ok(tiny_http::Response::from_string("Cannot find instances")
Expand All @@ -39,9 +41,9 @@ pub fn create(
_: &route_recognizer::Params,
connection: &Connection,
internal_sender: &Sender<ApiChannel>,
) -> Result<tiny_http::Response<io::Cursor<Vec<u8>>>, api::RikError> {
) -> HttpResult {
let mut content = String::new();
req.as_reader().read_to_string(&mut content).unwrap();
req.as_reader().read_to_string(&mut content)?;

let mut instance: InstanceDefinition = serde_json::from_str(&content)?;

Expand Down Expand Up @@ -99,8 +101,8 @@ pub fn create(
}

Ok(
tiny_http::Response::from_string(serde_json::to_string(&instance_names).unwrap())
.with_header(tiny_http::Header::from_str("Content-Type: application/json").unwrap())
tiny_http::Response::from_string(serde_json::to_string(&instance_names)?)
.with_header::<Header>(ContentType::JSON.into())
.with_status_code(tiny_http::StatusCode::from(201)),
)
}
Expand All @@ -110,14 +112,13 @@ pub fn delete(
_: &route_recognizer::Params,
connection: &Connection,
internal_sender: &Sender<ApiChannel>,
) -> Result<tiny_http::Response<io::Cursor<Vec<u8>>>, api::RikError> {
) -> HttpResult {
let mut content = String::new();
req.as_reader().read_to_string(&mut content).unwrap();
req.as_reader().read_to_string(&mut content)?;
let OnlyId { id: delete_id } = serde_json::from_str(&content)?;

if let Ok(instance) = RikRepository::find_one(connection, &delete_id, "/instance") {
let instance_def: InstanceDefinition =
serde_json::from_value(instance.value.clone()).unwrap();
let instance_def: InstanceDefinition = serde_json::from_value(instance.value.clone())?;

let workload_def_rs =
RikRepository::find_one(connection, &instance_def.workload_id, "/workload");
Expand All @@ -134,16 +135,13 @@ pub fn delete(
))
.with_status_code(tiny_http::StatusCode::from(404)));
}
let workload_def: WorkloadDefinition =
serde_json::from_value(workload_def_rs.unwrap().value).unwrap();
internal_sender
.send(ApiChannel {
action: Crud::Delete,
workload_id: Some(instance_def.workload_id),
workload_definition: Some(workload_def),
instance_id: Some(delete_id),
})
.unwrap();
let workload_def: WorkloadDefinition = serde_json::from_value(workload_def_rs?.value)?;
internal_sender.send(ApiChannel {
action: Crud::Delete,
workload_id: Some(instance_def.workload_id),
workload_definition: Some(workload_def),
instance_id: Some(delete_id),
})?;

event!(
Level::INFO,
Expand Down
21 changes: 19 additions & 2 deletions controller/src/api/external/routes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use route_recognizer;
use rusqlite::Connection;
use std::io;
use std::str::FromStr;
use std::sync::mpsc::Sender;
use tiny_http::Method;
use tiny_http::Response;
use tracing::{event, Level};

use crate::api;
use crate::api::ApiChannel;

mod instance;
Expand All @@ -17,7 +18,23 @@ type Handler = fn(
&route_recognizer::Params,
&Connection,
&Sender<ApiChannel>,
) -> Result<tiny_http::Response<io::Cursor<Vec<u8>>>, api::RikError>;
) -> Result<tiny_http::Response<io::Cursor<Vec<u8>>>, anyhow::Error>;

type HttpResult<T = io::Cursor<Vec<u8>>> = Result<Response<T>, anyhow::Error>;

pub enum ContentType {
JSON,
}

MaloPolese marked this conversation as resolved.
Show resolved Hide resolved
impl Into<tiny_http::Header> for ContentType {
fn into(self) -> tiny_http::Header {
match self {
ContentType::JSON => {
tiny_http::Header::from_str("Content-Type: application/json").unwrap()
}
}
}
}

pub struct Router {
routes: Vec<(tiny_http::Method, route_recognizer::Router<Handler>)>,
Expand Down
24 changes: 12 additions & 12 deletions controller/src/api/external/routes/tenant.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use route_recognizer;
use rusqlite::Connection;
use std::io;
use std::str::FromStr;
use std::sync::mpsc::Sender;
use tiny_http::Header;
use tracing::{event, Level};

use crate::api;
use super::HttpResult;
use crate::api::external::routes::ContentType;
use crate::api::external::services::element::elements_set_right_name;
use crate::api::types::element::OnlyId;
use crate::api::types::tenant::Tenant;
Expand All @@ -17,13 +17,13 @@ pub fn get(
_: &route_recognizer::Params,
connection: &Connection,
_: &Sender<ApiChannel>,
) -> Result<tiny_http::Response<io::Cursor<Vec<u8>>>, api::RikError> {
) -> HttpResult {
if let Ok(mut tenants) = RikRepository::find_all(connection, "/tenant") {
tenants = elements_set_right_name(tenants.clone());
let tenants_json = serde_json::to_string(&tenants).unwrap();
let tenants_json = serde_json::to_string(&tenants)?;
event!(Level::INFO, "tenants.get, tenants found");
Ok(tiny_http::Response::from_string(tenants_json)
.with_header(tiny_http::Header::from_str("Content-Type: application/json").unwrap())
.with_header::<Header>(ContentType::JSON.into())
.with_status_code(tiny_http::StatusCode::from(200)))
} else {
Ok(tiny_http::Response::from_string("Cannot find tenant")
Expand All @@ -36,15 +36,15 @@ pub fn create(
_: &route_recognizer::Params,
connection: &Connection,
_: &Sender<ApiChannel>,
) -> Result<tiny_http::Response<io::Cursor<Vec<u8>>>, api::RikError> {
) -> HttpResult {
let mut content = String::new();
req.as_reader().read_to_string(&mut content).unwrap();
req.as_reader().read_to_string(&mut content)?;
let tenant: Tenant = serde_json::from_str(&content)?;

if RikRepository::insert(connection, &tenant.name, &tenant.value).is_ok() {
event!(Level::INFO, "Create tenant");
Ok(tiny_http::Response::from_string(content)
.with_header(tiny_http::Header::from_str("Content-Type: application/json").unwrap())
.with_header::<Header>(ContentType::JSON.into())
.with_status_code(tiny_http::StatusCode::from(200)))
} else {
event!(Level::ERROR, "Cannot create tenant");
Expand All @@ -58,13 +58,13 @@ pub fn delete(
_: &route_recognizer::Params,
connection: &Connection,
_: &Sender<ApiChannel>,
) -> Result<tiny_http::Response<io::Cursor<Vec<u8>>>, api::RikError> {
) -> HttpResult {
let mut content = String::new();
req.as_reader().read_to_string(&mut content).unwrap();
req.as_reader().read_to_string(&mut content)?;
let OnlyId { id: delete_id } = serde_json::from_str(&content)?;

if let Ok(tenant) = RikRepository::find_one(connection, &delete_id, "/tenant") {
RikRepository::delete(connection, &tenant.id).unwrap();
RikRepository::delete(connection, &tenant.id)?;
event!(Level::INFO, "Delete tenant");
Ok(tiny_http::Response::from_string("").with_status_code(tiny_http::StatusCode::from(204)))
} else {
Expand Down
27 changes: 11 additions & 16 deletions controller/src/api/external/routes/workload.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::api;
use super::HttpResult;
use crate::api::external::routes::ContentType;
use crate::api::external::services::element::elements_set_right_name;
use crate::api::types::element::OnlyId;
use crate::api::{ApiChannel, Crud};
Expand All @@ -8,14 +9,10 @@ use definition::workload::WorkloadDefinition;
use route_recognizer;
use rusqlite::Connection;
use serde_json::json;
use std::io;
use std::str::FromStr;
use std::sync::mpsc::Sender;
use tiny_http::Response;
use tiny_http::Header;
use tracing::{event, Level};

type HttpResult<T = io::Cursor<Vec<u8>>> = Result<Response<T>, api::RikError>;

pub fn get(
_: &mut tiny_http::Request,
_: &route_recognizer::Params,
Expand All @@ -24,11 +21,11 @@ pub fn get(
) -> HttpResult {
if let Ok(mut workloads) = RikRepository::find_all(connection, "/workload") {
workloads = elements_set_right_name(workloads.clone());
let workloads_json = serde_json::to_string(&workloads).unwrap();
let workloads_json = serde_json::to_string(&workloads)?;
event!(Level::INFO, "workloads.get, workloads found");

Ok(tiny_http::Response::from_string(workloads_json)
.with_header(tiny_http::Header::from_str("Content-Type: application/json").unwrap())
.with_header::<Header>(ContentType::JSON.into())
.with_status_code(tiny_http::StatusCode::from(200)))
} else {
Ok(tiny_http::Response::from_string("Cannot find workloads")
Expand Down Expand Up @@ -65,7 +62,7 @@ pub fn get_instances(
let instances_json = json!({ "instances": instances }).to_string();

return Ok(tiny_http::Response::from_string(instances_json)
.with_header(tiny_http::Header::from_str("Content-Type: application/json").unwrap())
.with_header::<Header>(ContentType::JSON.into())
.with_status_code(tiny_http::StatusCode::from(200)));
}

Expand Down Expand Up @@ -101,19 +98,17 @@ pub fn create(
.with_status_code(tiny_http::StatusCode::from(404)));
}

if let Ok(inserted_id) = RikRepository::insert(
connection,
&name,
&serde_json::to_string(&workload).unwrap(),
) {
if let Ok(inserted_id) =
RikRepository::insert(connection, &name, &serde_json::to_string(&workload)?)
{
let workload_id: OnlyId = OnlyId { id: inserted_id };
event!(
Level::INFO,
"workload.create, workload successfully created"
);
Ok(
tiny_http::Response::from_string(serde_json::to_string(&workload_id).unwrap())
.with_header(tiny_http::Header::from_str("Content-Type: application/json").unwrap())
tiny_http::Response::from_string(serde_json::to_string(&workload_id)?)
.with_header::<Header>(ContentType::JSON.into())
.with_status_code(tiny_http::StatusCode::from(200)),
)
} else {
Expand Down
Loading
Loading