Skip to content

Commit 7d401b7

Browse files
chore: create routes module (#38)
* working deployment of pods * use internal ports * cleanup, use config struct, create server * add templates for pods/configmaps/services * use template yaml rather than json for deployments * add missed template yaml * add route to delete deployment * make services nodeport type * rename var * fix error handling on deletion * deploy configmaps for chain coordinator * yaml for cluster config * add user/password to devnet config * remove mounts from kind.yaml * helpful scripts * gitignore * rename file * provide example json * initial pass at readme * add some metatdata to cargo.toml * add license * update readme * add todo * rename package import * Apply suggestions from code review Co-authored-by: Charlie <2747302+CharlieC3@users.noreply.github.com> * add module to parse template files * use new template file parser * set context on automated kubectl command * Switch to ApacheV2 license * convert consts to i32 * add error handling for resource creation/deletion * add context to kubectl commands * set up proxy server * bind server to 0.0.0.0 * create k8s manager struct * add proxy routing to downstream pods * add tests * deps updatee * remove NodePort type from services * create template to deploy devnet-api-server to k8s * docker file for devnet api * update port for stacks-devnet-api service * use deployed pods! * use Always imagePullPolicy for newer images * build docker image in release mode * remove sleep! * add back sleep :( * started logging implementation * add more logging * fix port number * fix types for deleteing resources * remove delete_namespace func * feat: add route to get network info (#21) * add modules to manage k8s resources * update delete devnet to use utils * add strum deps * add struct for devnet info response * add struct for stacksv2info response * helper function to fetch status from a pod * helper function to get stacks v2 info route * function to query/assemble devnet info * remove get_proxy_data * add route to get devnet info * rename struct * add pvc module * update delete devnet to use pvc mod * rename utils -> resources * add ports to service * use service ports enum * revert server port number * refactor template parser to use new resource enums * fix service url * improve logging * add content type to response * add to ClusterRole resource list * fix event/db ports for stacks api config * fix service url * fix url to get v2 info * add helper to get user facing port * get user facing port for proxy requests * fix test * fix proxy url * add config.rs * add deps * use new config.rs * compute address from mnemonic * better error handling * add control port * change configmap typing * update config * add deps * make pox_2_activation optional * deps * add back deps * add todo for unavailable import * add note to todo for explorer disable flags * make explorer disables optional * remove print statements * remove unused field * move routes into separate module * add back unused field * add examples for new network config * add open api file * remove comment * remove todo's * add struct for validated user data * base64 encode contract * fix broken config * update json example * remove blank space * fix openapi spec a bit * delete openapi file --------- Co-authored-by: Charlie <2747302+CharlieC3@users.noreply.github.com>
1 parent 07e917c commit 7d401b7

File tree

3 files changed

+224
-188
lines changed

3 files changed

+224
-188
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mod template_parser;
3232
use template_parser::get_yaml_from_resource;
3333

3434
pub mod resources;
35+
pub mod routes;
3536
use crate::resources::configmap::StacksDevnetConfigmap;
3637
use crate::resources::pod::StacksDevnetPod;
3738
use crate::resources::service::{get_service_url, StacksDevnetService};

src/main.rs

Lines changed: 15 additions & 188 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use hiro_system_kit::slog;
22
use hyper::server::conn::AddrStream;
33
use hyper::service::{make_service_fn, service_fn};
4-
use hyper::{Body, Client, Method, Request, Response, Server, StatusCode, Uri};
5-
use stacks_devnet_api::config::StacksDevnetConfig;
6-
use stacks_devnet_api::resources::service::{
7-
get_service_from_path_part, get_service_url, get_user_facing_port,
4+
use hyper::{Body, Method, Request, Response, Server, StatusCode};
5+
use stacks_devnet_api::routes::{
6+
get_standardized_path_parts, handle_delete_devnet, handle_get_devnet, handle_new_devnet,
7+
handle_try_proxy_service, API_PATH,
88
};
99
use stacks_devnet_api::{Context, StacksDevnetApiK8sManager};
1010
use std::net::IpAddr;
11-
use std::str::FromStr;
1211
use std::{convert::Infallible, net::SocketAddr};
1312

1413
#[tokio::main]
@@ -46,86 +45,6 @@ async fn main() {
4645
}
4746
}
4847

49-
fn mutate_request_for_proxy(
50-
mut request: Request<Body>,
51-
forward_url: &str,
52-
path_to_forward: &str,
53-
) -> Request<Body> {
54-
let query = match request.uri().query() {
55-
Some(query) => format!("?{}", query),
56-
None => String::new(),
57-
};
58-
59-
*request.uri_mut() = {
60-
let forward_uri = format!("http://{}/{}{}", forward_url, path_to_forward, query);
61-
Uri::from_str(forward_uri.as_str())
62-
}
63-
.unwrap();
64-
request
65-
}
66-
67-
async fn proxy(request: Request<Body>, ctx: &Context) -> Result<Response<Body>, Infallible> {
68-
let client = Client::new();
69-
70-
ctx.try_log(|logger| slog::info!(logger, "forwarding request to {}", request.uri()));
71-
match client.request(request).await {
72-
Ok(response) => Ok(response),
73-
Err(e) => {
74-
let msg = format!("error proxying request: {}", e.to_string());
75-
ctx.try_log(|logger| slog::error!(logger, "{}", msg));
76-
Ok(Response::builder()
77-
.status(StatusCode::INTERNAL_SERVER_ERROR)
78-
.body(Body::try_from(msg).unwrap())
79-
.unwrap())
80-
}
81-
}
82-
}
83-
84-
const API_PATH: &str = "/api/v1/";
85-
#[derive(Default, PartialEq, Debug)]
86-
struct PathParts {
87-
route: String,
88-
network: Option<String>,
89-
subroute: Option<String>,
90-
remainder: Option<String>,
91-
}
92-
fn get_standardized_path_parts(path: &str) -> PathParts {
93-
let path = path.replace(API_PATH, "");
94-
let path = path.trim_matches('/');
95-
let parts: Vec<&str> = path.split("/").collect();
96-
97-
match parts.len() {
98-
0 => PathParts {
99-
route: String::new(),
100-
..Default::default()
101-
},
102-
1 => PathParts {
103-
route: parts[0].into(),
104-
..Default::default()
105-
},
106-
2 => PathParts {
107-
route: parts[0].into(),
108-
network: Some(parts[1].into()),
109-
..Default::default()
110-
},
111-
3 => PathParts {
112-
route: parts[0].into(),
113-
network: Some(parts[1].into()),
114-
subroute: Some(parts[2].into()),
115-
..Default::default()
116-
},
117-
_ => {
118-
let remainder = parts[3..].join("/");
119-
PathParts {
120-
route: parts[0].into(),
121-
network: Some(parts[1].into()),
122-
subroute: Some(parts[2].into()),
123-
remainder: Some(remainder),
124-
}
125-
}
126-
}
127-
}
128-
12948
async fn handle_request(
13049
_client_ip: IpAddr,
13150
request: Request<Body>,
@@ -146,47 +65,7 @@ async fn handle_request(
14665

14766
if path == "/api/v1/networks" {
14867
return match method {
149-
&Method::POST => {
150-
let body = hyper::body::to_bytes(request.into_body()).await;
151-
if body.is_err() {
152-
let msg = "failed to parse request body";
153-
ctx.try_log(|logger| slog::error!(logger, "{}", msg));
154-
return Ok(Response::builder()
155-
.status(StatusCode::INTERNAL_SERVER_ERROR)
156-
.body(Body::try_from(msg).unwrap())
157-
.unwrap());
158-
}
159-
let body = body.unwrap();
160-
let config: Result<StacksDevnetConfig, _> = serde_json::from_slice(&body);
161-
match config {
162-
Ok(config) => match config.to_validated_config(ctx) {
163-
Ok(config) => match k8s_manager.deploy_devnet(config).await {
164-
Ok(_) => Ok(Response::builder()
165-
.status(StatusCode::OK)
166-
.body(Body::empty())
167-
.unwrap()),
168-
Err(e) => Ok(Response::builder()
169-
.status(StatusCode::from_u16(e.code).unwrap())
170-
.body(Body::try_from(e.message).unwrap())
171-
.unwrap()),
172-
},
173-
Err(e) => Ok(Response::builder()
174-
.status(StatusCode::from_u16(e.code).unwrap())
175-
.body(Body::try_from(e.message).unwrap())
176-
.unwrap()),
177-
},
178-
Err(e) => Ok(Response::builder()
179-
.status(StatusCode::BAD_REQUEST)
180-
.body(
181-
Body::try_from(format!(
182-
"invalid configuration to create network: {}",
183-
e
184-
))
185-
.unwrap(),
186-
)
187-
.unwrap()),
188-
}
189-
}
68+
&Method::POST => handle_new_devnet(request, k8s_manager, ctx).await,
19069
_ => Ok(Response::builder()
19170
.status(StatusCode::METHOD_NOT_ALLOWED)
19271
.body(Body::try_from("network creation must be a POST request").unwrap())
@@ -233,50 +112,8 @@ async fn handle_request(
233112
// so it must be a request to DELETE a network or GET network info
234113
if path_parts.subroute.is_none() {
235114
return match method {
236-
&Method::DELETE => match k8s_manager.delete_devnet(&network).await {
237-
Ok(_) => Ok(Response::builder()
238-
.status(StatusCode::OK)
239-
.body(Body::empty())
240-
.unwrap()),
241-
Err(e) => Ok(Response::builder()
242-
.status(StatusCode::INTERNAL_SERVER_ERROR)
243-
.body(
244-
Body::try_from(format!(
245-
"error deleting network {}: {}",
246-
&network,
247-
e.to_string()
248-
))
249-
.unwrap(),
250-
)
251-
.unwrap()),
252-
},
253-
&Method::GET => match k8s_manager.get_devnet_info(&network).await {
254-
Ok(devnet_info) => match serde_json::to_vec(&devnet_info) {
255-
Ok(body) => Ok(Response::builder()
256-
.status(StatusCode::OK)
257-
.header("Content-Type", "application/json")
258-
.body(Body::from(body))
259-
.unwrap()),
260-
Err(e) => {
261-
let msg = format!(
262-
"failed to form response body: NAMESPACE: {}, ERROR: {}",
263-
&network,
264-
e.to_string()
265-
);
266-
ctx.try_log(|logger: &hiro_system_kit::Logger| {
267-
slog::error!(logger, "{}", msg)
268-
});
269-
Ok(Response::builder()
270-
.status(StatusCode::from_u16(500).unwrap())
271-
.body(Body::try_from(msg).unwrap())
272-
.unwrap())
273-
}
274-
},
275-
Err(e) => Ok(Response::builder()
276-
.status(StatusCode::from_u16(e.code).unwrap())
277-
.body(Body::try_from(e.message).unwrap())
278-
.unwrap()),
279-
},
115+
&Method::DELETE => handle_delete_devnet(k8s_manager, &network).await,
116+
&Method::GET => handle_get_devnet(k8s_manager, &network, ctx).await,
280117
_ => Ok(Response::builder()
281118
.status(StatusCode::METHOD_NOT_ALLOWED)
282119
.body(Body::empty())
@@ -291,22 +128,8 @@ async fn handle_request(
291128
.unwrap());
292129
} else {
293130
let remaining_path = path_parts.remainder.unwrap_or(String::new());
294-
295-
let service = get_service_from_path_part(&subroute);
296-
return match service {
297-
Some(service) => {
298-
let base_url = get_service_url(&network, service.clone());
299-
let port = get_user_facing_port(service).unwrap();
300-
let forward_url = format!("{}:{}", base_url, port);
301-
let proxy_request =
302-
mutate_request_for_proxy(request, &forward_url, &remaining_path);
303-
proxy(proxy_request, &ctx).await
304-
}
305-
None => Ok(Response::builder()
306-
.status(StatusCode::BAD_REQUEST)
307-
.body(Body::try_from("invalid request path").unwrap())
308-
.unwrap()),
309-
};
131+
return handle_try_proxy_service(&remaining_path, &subroute, &network, request, &ctx)
132+
.await;
310133
}
311134
}
312135

@@ -321,8 +144,12 @@ mod tests {
321144
use super::*;
322145
use hyper::body;
323146
use k8s_openapi::api::core::v1::Namespace;
324-
use stacks_devnet_api::resources::service::{
325-
get_service_port, ServicePort, StacksDevnetService,
147+
use stacks_devnet_api::{
148+
resources::service::{
149+
get_service_from_path_part, get_service_port, get_service_url, ServicePort,
150+
StacksDevnetService,
151+
},
152+
routes::{get_standardized_path_parts, mutate_request_for_proxy, PathParts},
326153
};
327154
use tower_test::mock::{self, Handle};
328155

0 commit comments

Comments
 (0)