forked from github-starred/komodo
run arbitrary command on periphery
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use anyhow::Context;
|
||||
use mungos::{Collection, Mungos};
|
||||
use types::{Build, Deployment, Group, Procedure, Server, SystemStatsRecord, Update, User};
|
||||
use types::{Action, Build, Deployment, Group, Procedure, Server, SystemStatsRecord, Update, User};
|
||||
|
||||
pub async fn users_collection(mungos: &Mungos, db_name: &str) -> anyhow::Result<Collection<User>> {
|
||||
let coll = mungos.collection(db_name, "users");
|
||||
@@ -92,6 +92,17 @@ pub async fn procedures_collection(
|
||||
Ok(coll)
|
||||
}
|
||||
|
||||
pub async fn actions_collection(
|
||||
mungos: &Mungos,
|
||||
db_name: &str,
|
||||
) -> anyhow::Result<Collection<Action>> {
|
||||
let coll = mungos.collection(db_name, "actions");
|
||||
coll.create_unique_index("name")
|
||||
.await
|
||||
.context("failed at creating entity_id index")?;
|
||||
Ok(coll)
|
||||
}
|
||||
|
||||
pub async fn groups_collection(
|
||||
mungos: &Mungos,
|
||||
db_name: &str,
|
||||
|
||||
@@ -2,13 +2,14 @@ use std::time::Duration;
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use collections::{
|
||||
builds_collection, deployments_collection, groups_collection, procedures_collection,
|
||||
server_stats_collection, servers_collection, updates_collection, users_collection,
|
||||
actions_collection, builds_collection, deployments_collection, groups_collection,
|
||||
procedures_collection, server_stats_collection, servers_collection, updates_collection,
|
||||
users_collection,
|
||||
};
|
||||
use mungos::{Collection, Mungos};
|
||||
use types::{
|
||||
Build, Deployment, Group, MongoConfig, PermissionLevel, Procedure, Server, SystemStatsRecord,
|
||||
Update, User,
|
||||
Action, Build, Deployment, Group, MongoConfig, PermissionLevel, Procedure, Server,
|
||||
SystemStatsRecord, Update, User,
|
||||
};
|
||||
|
||||
mod collections;
|
||||
@@ -19,6 +20,7 @@ pub struct DbClient {
|
||||
pub deployments: Collection<Deployment>,
|
||||
pub builds: Collection<Build>,
|
||||
pub procedures: Collection<Procedure>,
|
||||
pub actions: Collection<Action>,
|
||||
pub groups: Collection<Group>,
|
||||
pub updates: Collection<Update>,
|
||||
pub stats: Collection<SystemStatsRecord>,
|
||||
@@ -49,6 +51,9 @@ impl DbClient {
|
||||
procedures: procedures_collection(&mungos, db_name)
|
||||
.await
|
||||
.expect("failed to make procedures collection"),
|
||||
actions: actions_collection(&mungos, db_name)
|
||||
.await
|
||||
.expect("failed to make actions collection"),
|
||||
groups: groups_collection(&mungos, db_name)
|
||||
.await
|
||||
.expect("failed to make groups collection"),
|
||||
|
||||
12
lib/periphery_client/src/command.rs
Normal file
12
lib/periphery_client/src/command.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
use anyhow::Context;
|
||||
use types::{Command, Log, Server};
|
||||
|
||||
use crate::PeripheryClient;
|
||||
|
||||
impl PeripheryClient {
|
||||
pub async fn run_command(&self, server: &Server, command: &Command) -> anyhow::Result<Log> {
|
||||
self.post_json(server, &format!("/command"), command)
|
||||
.await
|
||||
.context("failed to run command on periphery")
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ use tokio_tungstenite::{connect_async, MaybeTlsStream, WebSocketStream};
|
||||
use types::{Server, SystemStats, SystemStatsQuery};
|
||||
|
||||
mod build;
|
||||
mod command;
|
||||
mod container;
|
||||
mod git;
|
||||
mod image;
|
||||
|
||||
63
lib/types/src/action.rs
Normal file
63
lib/types/src/action.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
use bson::serde_helpers::hex_string_as_object_id;
|
||||
use derive_builder::Builder;
|
||||
use diff::Diff;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
|
||||
use crate::{diff::*, Command};
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, Diff, Builder)]
|
||||
#[diff(attr(#[derive(Debug, Serialize)]))]
|
||||
pub struct Action {
|
||||
#[serde(
|
||||
default,
|
||||
rename = "_id",
|
||||
skip_serializing_if = "String::is_empty",
|
||||
with = "hex_string_as_object_id"
|
||||
)]
|
||||
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
|
||||
#[builder(setter(skip))]
|
||||
pub id: String,
|
||||
|
||||
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
|
||||
pub name: String,
|
||||
|
||||
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
|
||||
pub path: String,
|
||||
|
||||
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
|
||||
pub command: String,
|
||||
|
||||
// run action on all servers in this array
|
||||
#[serde(default)]
|
||||
#[diff(attr(#[serde(skip_serializing_if = "vec_diff_no_change")]))]
|
||||
pub server_ids: Vec<String>,
|
||||
|
||||
// run action on all servers in the group
|
||||
#[serde(default)]
|
||||
#[diff(attr(#[serde(skip_serializing_if = "vec_diff_no_change")]))]
|
||||
pub group_ids: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
|
||||
pub run_on_all: bool,
|
||||
|
||||
#[serde(default, skip_serializing_if = "String::is_empty")]
|
||||
#[diff(attr(#[serde(skip)]))]
|
||||
#[builder(setter(skip))]
|
||||
pub created_at: String,
|
||||
#[serde(default)]
|
||||
#[diff(attr(#[serde(skip)]))]
|
||||
#[builder(setter(skip))]
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
impl From<Action> for Command {
|
||||
fn from(value: Action) -> Command {
|
||||
Command {
|
||||
path: value.path,
|
||||
command: value.command,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ pub use bollard::service::{ImageSummary, Network};
|
||||
|
||||
pub mod traits;
|
||||
|
||||
mod action;
|
||||
mod build;
|
||||
mod config;
|
||||
mod deployment;
|
||||
@@ -21,6 +22,7 @@ mod server;
|
||||
mod update;
|
||||
mod user;
|
||||
|
||||
pub use action::*;
|
||||
pub use build::*;
|
||||
pub use config::*;
|
||||
pub use deployment::*;
|
||||
@@ -40,7 +42,9 @@ pub type PermissionsMap = HashMap<String, PermissionLevel>;
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Diff)]
|
||||
#[diff(attr(#[derive(Debug, PartialEq, Serialize)]))]
|
||||
pub struct Command {
|
||||
#[serde(default)]
|
||||
pub path: String,
|
||||
#[serde(default)]
|
||||
pub command: String,
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{Display, EnumString};
|
||||
use typeshare::typeshare;
|
||||
|
||||
use crate::PermissionsMap;
|
||||
use crate::{diff::*, PermissionsMap};
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, Diff, Builder)]
|
||||
@@ -19,8 +19,16 @@ pub struct Procedure {
|
||||
)]
|
||||
#[builder(setter(skip))]
|
||||
pub id: String,
|
||||
|
||||
#[diff(attr(#[serde(skip_serializing_if = "Option::is_none")]))]
|
||||
pub name: String,
|
||||
|
||||
#[serde(default)]
|
||||
#[diff(attr(#[serde(skip_serializing_if = "vec_diff_no_change")]))]
|
||||
pub stages: Vec<ProcedureStage>,
|
||||
|
||||
#[serde(default)]
|
||||
#[diff(attr(#[serde(skip_serializing_if = "vec_diff_no_change")]))]
|
||||
pub webhook_branches: Vec<String>,
|
||||
|
||||
#[serde(default)]
|
||||
|
||||
19
periphery/src/api/command.rs
Normal file
19
periphery/src/api/command.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
use axum::{routing::post, Json, Router};
|
||||
use helpers::run_monitor_command;
|
||||
use types::Command;
|
||||
|
||||
pub fn router() -> Router {
|
||||
Router::new().route(
|
||||
"/",
|
||||
post(|Json(Command { path, command })| async move {
|
||||
let command = if path.is_empty() {
|
||||
command
|
||||
} else {
|
||||
let path = path.replace("~", &std::env::var("HOME").unwrap());
|
||||
format!("cd {path} && {command}")
|
||||
};
|
||||
let log = run_monitor_command("run command", command).await;
|
||||
Json(log)
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -17,6 +17,7 @@ use crate::PeripheryConfigExtension;
|
||||
|
||||
mod accounts;
|
||||
mod build;
|
||||
mod command;
|
||||
mod container;
|
||||
mod git;
|
||||
mod image;
|
||||
@@ -27,6 +28,7 @@ pub fn router(config: PeripheryConfigExtension) -> Router {
|
||||
Router::new()
|
||||
.route("/health", get(|| async {}))
|
||||
.route("/accounts/:account_type", get(accounts::get_accounts))
|
||||
.nest("/command", command::router())
|
||||
.nest("/container", container::router())
|
||||
.nest("/network", network::router())
|
||||
.nest(
|
||||
|
||||
Reference in New Issue
Block a user