Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
4088c73
working deployment of pods
MicaiahReid May 16, 2023
a8e34fa
use internal ports
MicaiahReid May 16, 2023
f881e21
cleanup, use config struct, create server
MicaiahReid May 17, 2023
46995ab
add templates for pods/configmaps/services
MicaiahReid May 17, 2023
262af78
use template yaml rather than json for deployments
MicaiahReid May 17, 2023
e69c272
add missed template yaml
MicaiahReid May 18, 2023
2407988
add route to delete deployment
MicaiahReid May 18, 2023
abf2e17
make services nodeport type
MicaiahReid May 19, 2023
81ef8c4
rename var
MicaiahReid May 19, 2023
1f6d98d
fix error handling on deletion
MicaiahReid May 19, 2023
fc24c8a
deploy configmaps for chain coordinator
MicaiahReid May 19, 2023
02f5062
yaml for cluster config
MicaiahReid May 19, 2023
915e594
add user/password to devnet config
MicaiahReid May 30, 2023
9dd2936
remove mounts from kind.yaml
MicaiahReid May 30, 2023
fbe70bf
helpful scripts
MicaiahReid May 30, 2023
7e3d621
gitignore
MicaiahReid May 30, 2023
3e4e78b
rename file
MicaiahReid May 30, 2023
472a28e
provide example json
MicaiahReid May 30, 2023
c363f9d
initial pass at readme
MicaiahReid May 30, 2023
c408d9f
add some metatdata to cargo.toml
MicaiahReid May 30, 2023
104eb8d
add license
MicaiahReid May 30, 2023
5bc68fb
update readme
MicaiahReid May 31, 2023
3c28e14
add todo
MicaiahReid May 31, 2023
ffb4410
rename package import
MicaiahReid May 31, 2023
e715b46
Apply suggestions from code review
MicaiahReid Jun 1, 2023
409a6d6
add module to parse template files
MicaiahReid Jun 1, 2023
74f1004
use new template file parser
MicaiahReid Jun 1, 2023
e687519
set context on automated kubectl command
MicaiahReid Jun 1, 2023
d27fd5c
Switch to ApacheV2 license
MicaiahReid Jun 1, 2023
c619bd1
convert consts to i32
MicaiahReid Jun 1, 2023
3600770
add error handling for resource creation/deletion
MicaiahReid Jun 1, 2023
3866a64
add context to kubectl commands
MicaiahReid Jun 2, 2023
982175e
set up proxy server
MicaiahReid Jun 2, 2023
4dfd1fc
bind server to 0.0.0.0
MicaiahReid Jun 5, 2023
06d0038
create k8s manager struct
MicaiahReid Jun 7, 2023
0e4823c
add proxy routing to downstream pods
MicaiahReid Jun 7, 2023
c60fa30
add tests
MicaiahReid Jun 7, 2023
3c9d6d6
deps updatee
MicaiahReid Jun 7, 2023
1761fbd
remove NodePort type from services
MicaiahReid Jun 7, 2023
ddfe03f
create template to deploy devnet-api-server to k8s
MicaiahReid Jun 7, 2023
e572b48
docker file for devnet api
MicaiahReid Jun 7, 2023
f629c18
update port for stacks-devnet-api service
MicaiahReid Jun 7, 2023
285dc0d
use deployed pods!
MicaiahReid Jun 7, 2023
cc15a43
Merge branch 'main' into http-proxy
MicaiahReid Jun 7, 2023
0ef407b
use Always imagePullPolicy for newer images
MicaiahReid Jun 7, 2023
6bc424f
build docker image in release mode
MicaiahReid Jun 8, 2023
3d480a0
remove sleep!
MicaiahReid Jun 8, 2023
3f1b47b
add back sleep :(
MicaiahReid Jun 8, 2023
fd94b0e
started logging implementation
MicaiahReid Jun 12, 2023
790773d
add more logging
MicaiahReid Jun 13, 2023
5cf7e1b
fix port number
MicaiahReid Jun 13, 2023
87ca8dd
fix types for deleteing resources
MicaiahReid Jun 14, 2023
f07a082
remove delete_namespace func
MicaiahReid Jun 14, 2023
75eb8bc
Merge branch 'main' into feat/logging
MicaiahReid Jun 20, 2023
117bcdf
feat: add route to get network info (#21)
MicaiahReid Jun 20, 2023
67a3fd5
fix event/db ports for stacks api config
MicaiahReid Jun 22, 2023
9a1d94f
fix service url
MicaiahReid Jun 22, 2023
8a9e0a0
fix url to get v2 info
MicaiahReid Jun 22, 2023
1abe6bf
add helper to get user facing port
MicaiahReid Jun 22, 2023
454ba10
get user facing port for proxy requests
MicaiahReid Jun 22, 2023
d1528ba
fix test
MicaiahReid Jun 22, 2023
a986ac7
fix proxy url
MicaiahReid Jun 22, 2023
2329639
add config.rs
MicaiahReid Jun 26, 2023
ebb2456
add deps
MicaiahReid Jun 26, 2023
6f28238
use new config.rs
MicaiahReid Jun 26, 2023
c8499c1
compute address from mnemonic
MicaiahReid Jun 26, 2023
b04d32d
better error handling
MicaiahReid Jun 26, 2023
2bacfd0
add control port
MicaiahReid Jun 26, 2023
f3ad5fa
change configmap typing
MicaiahReid Jul 5, 2023
42e440a
update config
MicaiahReid Jul 5, 2023
36a1c49
add deps
MicaiahReid Jul 5, 2023
af6d5af
make pox_2_activation optional
MicaiahReid Jul 5, 2023
04b5dc0
deps
MicaiahReid Jul 6, 2023
4c76960
add back deps
MicaiahReid Jul 11, 2023
821dffa
add todo for unavailable import
MicaiahReid Jul 11, 2023
12f5455
add note to todo for explorer disable flags
MicaiahReid Jul 11, 2023
d71b8ea
make explorer disables optional
MicaiahReid Jul 11, 2023
dbd100b
remove print statements
MicaiahReid Jul 11, 2023
dd85d73
remove unused field
MicaiahReid Jul 11, 2023
80a36aa
move routes into separate module
MicaiahReid Jul 11, 2023
7c38816
add back unused field
MicaiahReid Jul 11, 2023
b949aba
add examples for new network config
MicaiahReid Jul 11, 2023
29d03f5
Merge branch 'main' into feat/config
MicaiahReid Jul 11, 2023
c1373a6
add open api file
MicaiahReid Jul 11, 2023
09b1ae9
remove comment
MicaiahReid Jul 23, 2023
8c163a5
remove todo's
MicaiahReid Jul 23, 2023
544beb2
add struct for validated user data
MicaiahReid Jul 23, 2023
cbe5cc2
base64 encode contract
MicaiahReid Jul 23, 2023
3744de4
fix broken config
MicaiahReid Jul 23, 2023
2899e1c
update json example
MicaiahReid Jul 23, 2023
e2af9eb
remove blank space
MicaiahReid Jul 23, 2023
3bca765
Merge branch 'main' into feat/config
MicaiahReid Jul 23, 2023
2b88f3a
Merge branch 'feat/config' into routes-mod
MicaiahReid Jul 23, 2023
cdbd253
fix openapi spec a bit
MicaiahReid Jul 24, 2023
2fbadf8
delete openapi file
MicaiahReid Jul 24, 2023
2f1c28d
Merge branch 'main' into routes-mod
MicaiahReid Jul 24, 2023
7c45294
create Responder module
MicaiahReid Jul 25, 2023
ab84299
import responder module
MicaiahReid Jul 25, 2023
30075eb
use responder to respond to all requests
MicaiahReid Jul 25, 2023
719c70a
read config file to set headers
MicaiahReid Jul 28, 2023
10fd4aa
enable OPTIONS method
MicaiahReid Jul 28, 2023
a649af7
set path to find Config
MicaiahReid Jul 30, 2023
a489bfc
add configmap to volume for stacks-devnet-api
MicaiahReid Jul 30, 2023
d452836
set default config
MicaiahReid Jul 30, 2023
9ed96ec
scripts to deploy/redeploy api
MicaiahReid Jul 30, 2023
8a2e6be
only read config on startup
MicaiahReid Jul 30, 2023
6d72673
update readme
MicaiahReid Jul 30, 2023
b6e5bcf
Merge branch 'main' into responder
MicaiahReid Jul 30, 2023
1a4d0d9
newline
MicaiahReid Jul 30, 2023
87e194b
newlines
MicaiahReid Jul 30, 2023
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
5 changes: 3 additions & 2 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ clarity-repl = "1.6.4"
clarinet-files = "1.0.0"
chainhook-types = "1.0.1"
clarinet-deployments = "1.0.1"
toml = "0.5.9"

[dev-dependencies]
tower-test = "0.4.0"
2 changes: 2 additions & 0 deletions Config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
allowed_origins = ["*"]
allowed_methods = ["DELETE", "GET", "OPTIONS", "POST", "HEAD"]
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ brew install kind

You should now be ready to deploy this service to your local Kubernetes cluster!

## Configuration
The `Config.toml` at the root directory of the project can be used to control some settings. This same file can be used to update both the stable and development build. The following settings are supported:
- `allowed_origins` - this setting is an array of strings and is used to set what origins are allowed in cross-origin requests. For example, `allowed_origins = ["*"]` allows any origins to make requests to this service, while `allowed_origins = ["localhost:3002", "dev.platform.so"]` will only allow requests from the two specified hosts.
- `allowed_methods` - this setting is an array of strings that sets what HTTP methods can be made to this server.

## Deploying the Stable Version
In your terminal, rum
In your terminal, run
```
kubectl --context kind-kind apply -f ./templates/stacks-devnet-api.template.yaml
./scripts/deploy-api.sh
```
to install the [latest version of this service](https://quay.io/repository/hirosystems/stacks-devnet-api?tab=history) that has been deployed to docker (or, to quay for now). This service should now be fully running on your Kubernetes cluster. See the [usage](#usage) sections for steps on how to use the service.

Expand Down Expand Up @@ -52,14 +57,9 @@ spec:
+ imagePullPolicy: Never
```

If a version of this tool has already been deployed to your local cluster, you'll need to delete the existing pod. You'll need to do this every time you redeploy the service:
```
kubectl --context kind-kind delete pod stacks-devnet-api --namespace devnet
```

Finally, run
```
kubectl --context kind-kind apply -f ./templates/stacks-devnet-api.template.yaml
./scripts/redeploy-api.sh
```
to deploy to your local cluster.

Expand Down
2 changes: 2 additions & 0 deletions scripts/deploy-api.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
kubectl --context kind-kind create configmap stacks-devnet-api-conf --from-file=./Config.toml --namespace devnet && \
kubectl --context kind-kind apply -f ./templates/stacks-devnet-api.template.yaml
3 changes: 3 additions & 0 deletions scripts/redeploy-api.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kubectl --context kind-kind delete configmap stacks-devnet-api-conf --namespace devnet & \
kubectl --context kind-kind delete pod stacks-devnet-api --namespace devnet && \
./scripts/deploy-api.sh
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mod template_parser;
use template_parser::get_yaml_from_resource;

pub mod resources;
pub mod responder;
pub mod routes;
use crate::resources::configmap::StacksDevnetConfigmap;
use crate::resources::pod::StacksDevnetPod;
Expand Down
144 changes: 89 additions & 55 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use hiro_system_kit::slog;
use hyper::server::conn::AddrStream;
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Method, Request, Response, Server, StatusCode};
use hyper::{Body, Method, Request, Response, Server};
use stacks_devnet_api::responder::{Responder, ResponderConfig};
use stacks_devnet_api::routes::{
get_standardized_path_parts, handle_delete_devnet, handle_get_devnet, handle_new_devnet,
handle_try_proxy_service, API_PATH,
Expand All @@ -24,14 +25,27 @@ async fn main() {
tracer: false,
};
let k8s_manager = StacksDevnetApiK8sManager::default(&ctx).await;
let config_path = if cfg!(debug_assertions) {
"./Config.toml"
} else {
"/etc/config/Config.toml"
};
let config = ResponderConfig::from_path(config_path);

let make_svc = make_service_fn(|conn: &AddrStream| {
let k8s_manager = k8s_manager.clone();
let ctx = ctx.clone();
let remote_addr = conn.remote_addr().ip();
let config = config.clone();
async move {
Ok::<_, Infallible>(service_fn(move |req| {
handle_request(remote_addr, req, k8s_manager.clone(), ctx.clone())
handle_request(
remote_addr,
req,
k8s_manager.clone(),
config.clone(),
ctx.clone(),
)
}))
}
});
Expand All @@ -49,6 +63,7 @@ async fn handle_request(
_client_ip: IpAddr,
request: Request<Body>,
k8s_manager: StacksDevnetApiK8sManager,
config: ResponderConfig,
ctx: Context,
) -> Result<Response<Body>, Infallible> {
let uri = request.uri();
Expand All @@ -63,86 +78,75 @@ async fn handle_request(
)
});

let responder = Responder::new(config, request.headers().clone()).unwrap();
if method == &Method::OPTIONS {
return responder.ok();
}
if path == "/api/v1/networks" {
return match method {
&Method::POST => handle_new_devnet(request, k8s_manager, ctx).await,
_ => Ok(Response::builder()
.status(StatusCode::METHOD_NOT_ALLOWED)
.body(Body::try_from("network creation must be a POST request").unwrap())
.unwrap()),
&Method::POST => handle_new_devnet(request, k8s_manager, responder, ctx).await,
_ => responder.err_method_not_allowed("network creation must be a POST request".into()),
};
} else if path.starts_with(API_PATH) {
let path_parts = get_standardized_path_parts(uri.path());

if path_parts.route != "network" {
return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::try_from("invalid request path").unwrap())
.unwrap());
return responder.err_bad_request("invalid request path".into());
}
// the api path must be followed by a network id
if path_parts.network.is_none() {
return Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::try_from("no network id provided").unwrap())
.unwrap());
return responder.err_bad_request("no network id provided".into());
}
let network = path_parts.network.unwrap();

// verify that we have a valid namespace and the network actually exists
let exists = match k8s_manager.check_namespace_exists(&network).await {
Ok(exists) => exists,
Err(e) => {
return Ok(Response::builder()
.status(StatusCode::from_u16(e.code).unwrap())
.body(Body::try_from(e.message).unwrap())
.unwrap());
return responder.respond(e.code, e.message);
}
};
if !exists {
let msg = format!("network {} does not exist", &network);
ctx.try_log(|logger| slog::warn!(logger, "{}", msg));
return Ok(Response::builder()
.status(StatusCode::from_u16(404).unwrap())
.body(Body::try_from(msg).unwrap())
.unwrap());
return responder.err_not_found(msg);
}

// the path only contained the network path and network id,
// so it must be a request to DELETE a network or GET network info
if path_parts.subroute.is_none() {
return match method {
&Method::DELETE => handle_delete_devnet(k8s_manager, &network).await,
&Method::GET => handle_get_devnet(k8s_manager, &network, ctx).await,
_ => Ok(Response::builder()
.status(StatusCode::METHOD_NOT_ALLOWED)
.body(Body::empty())
.unwrap()),
&Method::DELETE => handle_delete_devnet(k8s_manager, &network, responder).await,
&Method::GET => handle_get_devnet(k8s_manager, &network, responder, ctx).await,
_ => {
responder.err_method_not_allowed("can only GET/DELETE at provided route".into())
}
};
}
let subroute = path_parts.subroute.unwrap();
if subroute == "commands" {
return Ok(Response::builder()
.status(StatusCode::NOT_IMPLEMENTED)
.body(Body::empty())
.unwrap());
return responder.err_not_implemented("commands route in progress".into());
} else {
let remaining_path = path_parts.remainder.unwrap_or(String::new());
return handle_try_proxy_service(&remaining_path, &subroute, &network, request, &ctx)
.await;
return handle_try_proxy_service(
&remaining_path,
&subroute,
&network,
request,
responder,
&ctx,
)
.await;
}
}

Ok(Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::try_from("invalid request path").unwrap())
.unwrap())
responder.err_bad_request("invalid request path".into())
}

#[cfg(test)]
mod tests {
use super::*;
use hyper::body;
use hyper::{body, StatusCode};
use k8s_openapi::api::core::v1::Namespace;
use stacks_devnet_api::{
resources::service::{
Expand Down Expand Up @@ -211,9 +215,15 @@ mod tests {
for path in invalid_paths {
let request_builder = Request::builder().uri(path).method("GET");
let request: Request<Body> = request_builder.body(Body::empty()).unwrap();
let mut response = handle_request(client_ip, request, k8s_manager.clone(), ctx.clone())
.await
.unwrap();
let mut response = handle_request(
client_ip,
request,
k8s_manager.clone(),
ResponderConfig::default(),
ctx.clone(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
let body = response.body_mut();
let bytes = body::to_bytes(body).await.unwrap().to_vec();
Expand Down Expand Up @@ -241,9 +251,15 @@ mod tests {

let request_builder = Request::builder().uri(path).method("GET");
let request: Request<Body> = request_builder.body(Body::empty()).unwrap();
let mut response = handle_request(client_ip, request, k8s_manager.clone(), ctx)
.await
.unwrap();
let mut response = handle_request(
client_ip,
request,
k8s_manager.clone(),
ResponderConfig::default(),
ctx,
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
let body = response.body_mut();
let bytes = body::to_bytes(body).await.unwrap().to_vec();
Expand All @@ -270,9 +286,15 @@ mod tests {

let request_builder = Request::builder().uri(path).method("GET");
let request: Request<Body> = request_builder.body(Body::empty()).unwrap();
let mut response = handle_request(client_ip, request, k8s_manager.clone(), ctx)
.await
.unwrap();
let mut response = handle_request(
client_ip,
request,
k8s_manager.clone(),
ResponderConfig::default(),
ctx,
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
let body = response.body_mut();
let bytes = body::to_bytes(body).await.unwrap().to_vec();
Expand Down Expand Up @@ -301,9 +323,15 @@ mod tests {
for method in methods {
let request_builder = Request::builder().uri(path).method(method);
let request: Request<Body> = request_builder.body(Body::empty()).unwrap();
let mut response = handle_request(client_ip, request, k8s_manager.clone(), ctx.clone())
.await
.unwrap();
let mut response = handle_request(
client_ip,
request,
k8s_manager.clone(),
ResponderConfig::default(),
ctx.clone(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::METHOD_NOT_ALLOWED);
let body = response.body_mut();
let bytes = body::to_bytes(body).await.unwrap().to_vec();
Expand All @@ -330,9 +358,15 @@ mod tests {

let request_builder = Request::builder().uri(path).method("POST");
let request: Request<Body> = request_builder.body(Body::empty()).unwrap();
let mut response = handle_request(client_ip, request, k8s_manager.clone(), ctx)
.await
.unwrap();
let mut response = handle_request(
client_ip,
request,
k8s_manager.clone(),
ResponderConfig::default(),
ctx,
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
let body = response.body_mut();
let bytes = body::to_bytes(body).await.unwrap().to_vec();
Expand Down
Loading