Compare commits
2 Commits
0d89375fbd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00c45ecba5 | ||
|
|
d0dddb32e6 |
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
target/
|
||||
runner_state.json
|
||||
register_token
|
||||
instance_url
|
||||
1496
Cargo.lock
generated
Normal file
1496
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
2
Cargo.toml
Normal file
2
Cargo.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[workspace]
|
||||
members = ["nomact"]
|
||||
29
nomact/Cargo.toml
Normal file
29
nomact/Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "nomact"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
tonic = { version = "0.14" }
|
||||
prost = { version = "0.14" }
|
||||
tonic-prost = { version = "0.14" }
|
||||
prost-types = { version = "0.14" }
|
||||
tonic-web = { version = "0.14" }
|
||||
hyper = { version = "1.8" }
|
||||
hyper-util = { version = "0.1" }
|
||||
hyper-rustls = { version = "0.27" }
|
||||
rustls = { version = "0.23" }
|
||||
tower = { version = "0.5" }
|
||||
http-body = { version = "1.0" }
|
||||
|
||||
tokio = { version = "1.49", features = ["rt", "net", "fs"] }
|
||||
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1.0" }
|
||||
serde_yaml = { version = "0.9" }
|
||||
|
||||
tracing = { version = "0.1", features = ["attributes"] }
|
||||
tracing-subscriber = { version = "0.3", features = [] }
|
||||
|
||||
[build-dependencies]
|
||||
tonic-prost-build = { version = "0.14" }
|
||||
17
nomact/build.rs
Normal file
17
nomact/build.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
tonic_prost_build::configure()
|
||||
.build_server(false)
|
||||
.compile_protos(
|
||||
&["../actions-proto-def/proto/runner/v1/services.proto"],
|
||||
&["../actions-proto-def/proto"],
|
||||
)?;
|
||||
|
||||
tonic_prost_build::configure()
|
||||
.build_server(false)
|
||||
.compile_protos(
|
||||
&["../actions-proto-def/proto/ping/v1/services.proto"],
|
||||
&["../actions-proto-def/proto"],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
115
nomact/src/lib.rs
Normal file
115
nomact/src/lib.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use std::vec;
|
||||
|
||||
pub mod runner {
|
||||
tonic::include_proto!("runner.v1");
|
||||
}
|
||||
|
||||
pub mod ping {
|
||||
tonic::include_proto!("ping.v1");
|
||||
}
|
||||
|
||||
pub struct RegisterConfig {
|
||||
pub name: String,
|
||||
pub register_token: String,
|
||||
pub instance: hyper::Uri,
|
||||
pub version: String,
|
||||
pub labels: Vec<String>,
|
||||
pub ephemeral: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||
pub struct RegisteredRunner {
|
||||
pub uuid: String,
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
pub fn instance_to_api_url(instance: hyper::Uri) -> hyper::Uri {
|
||||
let mut parts = instance.into_parts();
|
||||
parts.path_and_query = Some("/api/actions".try_into().unwrap());
|
||||
hyper::Uri::from_parts(parts).unwrap()
|
||||
}
|
||||
|
||||
pub async fn register(conf: RegisterConfig) -> Result<RegisteredRunner, ()> {
|
||||
use hyper_rustls::ConfigBuilderExt;
|
||||
|
||||
let tls = rustls::ClientConfig::builder()
|
||||
.with_native_roots()
|
||||
.unwrap()
|
||||
.with_no_client_auth();
|
||||
// Prepare the HTTPS connector
|
||||
let https = hyper_rustls::HttpsConnectorBuilder::new()
|
||||
.with_tls_config(tls)
|
||||
.https_or_http()
|
||||
.enable_http1()
|
||||
.build();
|
||||
|
||||
// Must use hyper directly...
|
||||
let client = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new())
|
||||
.build(https);
|
||||
|
||||
let svc = tower::ServiceBuilder::new()
|
||||
.layer(tonic_web::GrpcWebClientLayer::new())
|
||||
.service(client);
|
||||
|
||||
let uri = instance_to_api_url(conf.instance);
|
||||
|
||||
let mut client = runner::runner_service_client::RunnerServiceClient::with_origin(svc, uri);
|
||||
|
||||
let request = tonic::Request::new(runner::RegisterRequest {
|
||||
name: conf.name,
|
||||
token: conf.register_token,
|
||||
version: conf.version,
|
||||
labels: conf.labels,
|
||||
ephemeral: conf.ephemeral,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let response = client.register(request).await.unwrap();
|
||||
|
||||
match response.into_inner().runner {
|
||||
Some(runner) => Ok(RegisteredRunner {
|
||||
uuid: runner.uuid,
|
||||
token: runner.token,
|
||||
}),
|
||||
None => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run_task<T>(
|
||||
client: &mut runner::runner_service_client::RunnerServiceClient<T>,
|
||||
task: runner::Task,
|
||||
) where
|
||||
T: tonic::client::GrpcService<tonic::body::Body>,
|
||||
T::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
|
||||
T::ResponseBody: http_body::Body<Data = prost::bytes::Bytes> + std::marker::Send + 'static,
|
||||
<T::ResponseBody as http_body::Body>::Error:
|
||||
Into<Box<dyn std::error::Error + Send + Sync + 'static>> + std::marker::Send,
|
||||
{
|
||||
tracing::debug!(?task, "Run-Task");
|
||||
|
||||
let workflow = core::str::from_utf8(task.workflow_payload()).unwrap();
|
||||
tracing::info!("Raw-Workflow: {}", workflow);
|
||||
|
||||
let task_id = task.id;
|
||||
let task_workflow = core::str::from_utf8(task.workflow_payload()).unwrap();
|
||||
let task_context = task.context.as_ref();
|
||||
let task_secrets = &task.secrets;
|
||||
let task_needs = &task.needs;
|
||||
let task_vars = &task.vars;
|
||||
|
||||
let workflow = serde_yaml::from_slice::<serde_yaml::Value>(task.workflow_payload());
|
||||
tracing::info!("Workflow: {:?}", &workflow);
|
||||
|
||||
let update_req = tonic::Request::new(runner::UpdateTaskRequest {
|
||||
outputs: std::collections::HashMap::new(),
|
||||
state: Some(runner::TaskState {
|
||||
id: task.id,
|
||||
result: runner::Result::Failure.into(),
|
||||
started_at: None,
|
||||
stopped_at: None,
|
||||
steps: vec![],
|
||||
}),
|
||||
});
|
||||
let resp = client.update_task(update_req).await.unwrap();
|
||||
tracing::info!(resp = tracing::field::debug(resp.get_ref()), "Update Task State");
|
||||
}
|
||||
122
nomact/src/main.rs
Normal file
122
nomact/src/main.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use hyper_rustls::ConfigBuilderExt;
|
||||
use tracing_subscriber::layer::SubscriberExt;
|
||||
|
||||
use nomact::runner;
|
||||
|
||||
fn main() {
|
||||
let registry = tracing_subscriber::registry().with(tracing_subscriber::fmt::layer());
|
||||
tracing::subscriber::set_global_default(registry).unwrap();
|
||||
|
||||
tracing::info!("Starting...");
|
||||
|
||||
let rt = tokio::runtime::Builder::new_current_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let register_token = include_str!("../../register_token");
|
||||
let instance_url = include_str!("../../instance_url");
|
||||
let name = "Testing";
|
||||
|
||||
let runner = rt.block_on(async move {
|
||||
let path = "./runner_state.json";
|
||||
match tokio::fs::try_exists(path).await {
|
||||
Ok(true) => {
|
||||
tracing::info!("Using already registered runner");
|
||||
|
||||
let content = tokio::fs::read(path).await.unwrap();
|
||||
serde_json::from_slice::<nomact::RegisteredRunner>(&content).unwrap()
|
||||
}
|
||||
_ => {
|
||||
tracing::info!("Registering new runner");
|
||||
|
||||
let runner = nomact::register(nomact::RegisterConfig {
|
||||
name: name.into(),
|
||||
register_token: register_token.into(),
|
||||
instance: hyper::Uri::from_static(instance_url),
|
||||
version: "0.0.1".into(),
|
||||
labels: Vec::new(),
|
||||
ephemeral: false,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
tracing::info!(?runner, "Registered Runner");
|
||||
|
||||
let serialized = serde_json::to_vec(&runner).unwrap();
|
||||
tokio::fs::write(path, serialized).await.unwrap();
|
||||
|
||||
runner
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rt.block_on(async move {
|
||||
let tls = rustls::ClientConfig::builder()
|
||||
.with_native_roots()
|
||||
.unwrap()
|
||||
.with_no_client_auth();
|
||||
// Prepare the HTTPS connector
|
||||
let https = hyper_rustls::HttpsConnectorBuilder::new()
|
||||
.with_tls_config(tls)
|
||||
.https_or_http()
|
||||
.enable_http1()
|
||||
.build();
|
||||
|
||||
// Must use hyper directly...
|
||||
let client =
|
||||
hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new())
|
||||
.build(https);
|
||||
|
||||
let svc = tower::ServiceBuilder::new()
|
||||
.layer(tonic_web::GrpcWebClientLayer::new())
|
||||
.service(client);
|
||||
|
||||
let mut client = runner::runner_service_client::RunnerServiceClient::with_origin(
|
||||
tonic::service::interceptor::InterceptedService::new(
|
||||
svc,
|
||||
move |mut req: tonic::Request<()>| {
|
||||
req.metadata_mut()
|
||||
.insert("x-runner-uuid", runner.uuid.as_str().try_into().unwrap());
|
||||
req.metadata_mut()
|
||||
.insert("x-runner-token", runner.token.as_str().try_into().unwrap());
|
||||
|
||||
Ok(req)
|
||||
},
|
||||
),
|
||||
nomact::instance_to_api_url(hyper::Uri::from_static(instance_url))
|
||||
);
|
||||
|
||||
let request = tonic::Request::new(runner::DeclareRequest {
|
||||
version: "0.0.2".into(),
|
||||
labels: vec![
|
||||
"ubuntu-latest".into(),
|
||||
"ubuntu-22.04".into(),
|
||||
"ubuntu-20.04".into(),
|
||||
],
|
||||
});
|
||||
|
||||
let response = client.declare(request).await.unwrap();
|
||||
tracing::info!(runner = tracing::field::debug(response.get_ref().runner.as_ref()), "Declare current runner state");
|
||||
|
||||
|
||||
|
||||
let mut task_id = 0;
|
||||
loop {
|
||||
tracing::info!("Checking for new Task");
|
||||
|
||||
let request = tonic::Request::new(runner::FetchTaskRequest {
|
||||
tasks_version: task_id,
|
||||
});
|
||||
|
||||
let response = client.fetch_task(request).await.unwrap();
|
||||
|
||||
task_id = response.get_ref().tasks_version;
|
||||
|
||||
if let Some(task) = response.into_inner().task {
|
||||
nomact::run_task(&mut client, task).await;
|
||||
}
|
||||
|
||||
tokio::time::sleep(std::time::Duration::from_secs(30)).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user