implement more periphery routes + periphery client

This commit is contained in:
beckerinj
2022-11-13 02:14:36 -05:00
parent d4a775025f
commit 475f6774bf
11 changed files with 230 additions and 92 deletions

1
Cargo.lock generated
View File

@@ -1463,6 +1463,7 @@ name = "periphery_client"
version = "0.1.0"
dependencies = [
"anyhow",
"helpers",
"reqwest",
"serde",
"serde_json",

View File

@@ -1,59 +1,69 @@
use std::{path::PathBuf, str::FromStr};
use ::run_command::async_run_command;
use anyhow::{anyhow, Context};
use anyhow::anyhow;
use async_timing_util::unix_timestamp_ms;
use types::{Build, Deployment, GithubToken, Log};
use serde::{Deserialize, Serialize};
use types::{Build, Command, Deployment, GithubToken, GithubUsername, Log};
use crate::run_monitor_command;
pub async fn clone_build_repo(
Build {
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CloneArgs {
name: String,
repo: Option<String>,
branch: Option<String>,
on_clone: Option<Command>,
pub github_account: Option<GithubUsername>,
}
impl From<&Deployment> for CloneArgs {
fn from(d: &Deployment) -> Self {
CloneArgs {
name: d.name.clone(),
repo: d.repo.clone(),
branch: d.branch.clone(),
on_clone: d.on_clone.clone(),
github_account: d.github_account.clone(),
}
}
}
impl From<&Build> for CloneArgs {
fn from(b: &Build) -> Self {
CloneArgs {
name: b.name.clone(),
repo: b.repo.clone(),
branch: b.branch.clone(),
on_clone: b.on_clone.clone(),
github_account: b.github_account.clone(),
}
}
}
pub async fn clone_repo(
clone_args: impl Into<CloneArgs>,
repo_dir: &str,
access_token: Option<GithubToken>,
) -> anyhow::Result<Vec<Log>> {
let CloneArgs {
name,
repo,
branch,
on_clone,
..
}: &Build,
destination: &str,
access_token: Option<GithubToken>,
) -> anyhow::Result<Vec<Log>> {
} = clone_args.into();
let repo = repo.as_ref().ok_or(anyhow!("build has no repo attached"))?;
let clone_log = clone(repo, destination, branch, access_token).await;
let mut repo_dir = PathBuf::from_str(repo_dir)?;
repo_dir.push(name);
let destination = repo_dir.display().to_string();
let clone_log = clone(repo, &destination, &branch, access_token).await;
let mut logs = vec![clone_log];
if let Some(command) = on_clone {
let mut path = PathBuf::from_str(destination)
.context("failed to parse destination path to pathbuf")?;
path.push(&command.path);
repo_dir.push(&command.path);
let on_clone_log = run_monitor_command(
"on clone",
format!("cd {} && {}", path.display(), command.command),
)
.await;
logs.push(on_clone_log);
}
Ok(logs)
}
pub async fn clone_deployment_repo(
Deployment {
repo,
branch,
on_clone,
..
}: &Deployment,
destination: &str,
access_token: Option<GithubToken>,
) -> anyhow::Result<Vec<Log>> {
let repo = repo.as_ref().ok_or(anyhow!("build has no repo attached"))?;
let clone_log = clone(repo, destination, branch, access_token).await;
let mut logs = vec![clone_log];
if let Some(command) = on_clone {
let mut path = PathBuf::from_str(destination)
.context("failed to parse destination path to pathbuf")?;
path.push(&command.path);
let on_clone_log = run_monitor_command(
"on clone",
format!("cd {} && {}", path.display(), command.command),
format!("cd {} && {}", repo_dir.display(), command.command),
)
.await;
logs.push(on_clone_log);

View File

@@ -7,6 +7,7 @@ edition = "2021"
[dependencies]
types = { path = "../types" }
helpers = { path = "../helpers" }
reqwest = { version = "0.11", features = ["json"] }
serde = "1.0"
serde_json = "1.0"

View File

@@ -0,0 +1,58 @@
use serde_json::json;
use types::{BasicContainerInfo, Deployment, Log, Server};
use crate::PeripheryClient;
impl PeripheryClient {
pub async fn container_list(&self, server: &Server) -> anyhow::Result<Vec<BasicContainerInfo>> {
self.get_json(server, "/container/list").await
}
pub async fn container_start(
&self,
server: &Server,
container_name: &str,
) -> anyhow::Result<Log> {
self.post_json(
server,
&format!("/container/start"),
&json!({ "name": container_name }),
)
.await
}
pub async fn container_stop(
&self,
server: &Server,
container_name: &str,
) -> anyhow::Result<Log> {
self.post_json(
server,
&format!("/container/stop"),
&json!({ "name": container_name }),
)
.await
}
pub async fn container_remove(
&self,
server: &Server,
container_name: &str,
) -> anyhow::Result<Log> {
self.post_json(
server,
&format!("/container/remove"),
&json!({ "name": container_name }),
)
.await
}
pub async fn deploy(&self, server: &Server, deployment: &Deployment) -> anyhow::Result<Log> {
self.post_json(server, &format!("/container/deploy"), deployment)
.await
}
pub async fn container_prune(&self, server: &Server) -> anyhow::Result<Log> {
self.post_json(server, "container/prune", &json!({})).await
}
}

View File

@@ -0,0 +1,15 @@
use helpers::git::CloneArgs;
use types::{Log, Server};
use crate::PeripheryClient;
impl PeripheryClient {
pub async fn clone(
&self,
server: &Server,
clone_args: impl Into<CloneArgs>,
) -> anyhow::Result<Vec<Log>> {
let clone_args: CloneArgs = clone_args.into();
self.post_json(server, "/git/clone", &clone_args).await
}
}

View File

@@ -1,8 +1,12 @@
use anyhow::{anyhow, Context};
use reqwest::StatusCode;
use serde::{de::DeserializeOwned, Serialize};
use serde_json::json;
use types::{BasicContainerInfo, Deployment, Log, Server};
use types::Server;
mod container;
mod git;
mod network;
mod stats;
pub struct PeripheryClient {
http_client: reqwest::Client,
@@ -15,52 +19,12 @@ impl PeripheryClient {
}
}
pub async fn container_list(&self, server: &Server) -> anyhow::Result<Vec<BasicContainerInfo>> {
self.get_json(server, "/container/list").await
pub async fn get_github_accounts(&self, server: &Server) -> anyhow::Result<Vec<String>> {
self.get_json(server, "/accounts/github").await
}
pub async fn container_start(
&self,
server: &Server,
container_name: &str,
) -> anyhow::Result<Log> {
self.post_json(
server,
&format!("/container/start"),
&json!({ "name": container_name }),
)
.await
}
pub async fn container_stop(
&self,
server: &Server,
container_name: &str,
) -> anyhow::Result<Log> {
self.post_json(
server,
&format!("/container/stop"),
&json!({ "name": container_name }),
)
.await
}
pub async fn container_remove(
&self,
server: &Server,
container_name: &str,
) -> anyhow::Result<Log> {
self.post_json(
server,
&format!("/container/remove"),
&json!({ "name": container_name }),
)
.await
}
pub async fn deploy(&self, server: &Server, deployment: &Deployment) -> anyhow::Result<Log> {
self.post_json(server, &format!("/container/deploy"), deployment)
.await
pub async fn get_docker_accounts(&self, server: &Server) -> anyhow::Result<Vec<String>> {
self.get_json(server, "/accounts/docker").await
}
async fn get_json<R: DeserializeOwned>(

View File

@@ -0,0 +1,32 @@
use serde_json::json;
use types::{Log, Server};
use crate::PeripheryClient;
impl PeripheryClient {
pub async fn network_create(
&self,
server: &Server,
name: &str,
driver: Option<String>,
) -> anyhow::Result<Log> {
self.post_json(
server,
"/network/create",
&json!({
"name": name,
"driver": driver
}),
)
.await
}
pub async fn network_delete(&self, server: &Server, name: &str) -> anyhow::Result<Log> {
self.post_json(server, "/network/delete", &json!({ "name": name }))
.await
}
pub async fn network_prune(&self, server: &Server) -> anyhow::Result<Log> {
self.post_json(server, "/network/prune", &json!({})).await
}
}

View File

@@ -0,0 +1,13 @@
use types::{Server, SystemStats};
use crate::PeripheryClient;
impl PeripheryClient {
pub async fn get_system_stats(&self, server: &Server) -> anyhow::Result<SystemStats> {
self.get_json(server, "/stats/system").await
}
pub async fn get_docker_stats(&self, server: &Server) -> anyhow::Result<SystemStats> {
self.get_json(server, "/stats/docker").await
}
}

View File

@@ -301,12 +301,18 @@ pub struct PeripheryConfig {
pub docker_accounts: DockerAccounts,
#[serde(default)]
pub github_accounts: GithubAccounts,
#[serde(default = "default_repo_dir")]
pub repo_dir: String,
}
fn default_periphery_port() -> u16 {
9001
}
fn default_repo_dir() -> String {
"/repos".to_string()
}
#[derive(Deserialize, Debug)]
pub struct UserCredentials {
pub username: String,

View File

@@ -1,10 +1,11 @@
port = 9001 # optional.
is_builder = false
port = 9001 # optional. 9001 is default
is_builder = false # optional. false is default
repo_dir = "/repos" # optional. /repos is default
[github_accounts]
[github_accounts] # optional
github_username1 = "github_token1"
github_username2 = "github_token2"
[docker_accounts]
[docker_accounts] # optional
docker_username1 = "docker_token1"
docker_username2 = "docker_token2"

View File

@@ -1,5 +1,42 @@
use axum::Router;
use anyhow::anyhow;
use axum::{routing::post, Extension, Json, Router};
use helpers::{
git::{self, CloneArgs},
handle_anyhow_error,
};
use types::{Build, Deployment, GithubToken, Log, PeripheryConfig};
use crate::PeripheryConfigExtension;
pub fn router() -> Router {
Router::new()
Router::new().route(
"/clone",
post(|config, clone_args| async move {
clone(config, clone_args).await.map_err(handle_anyhow_error)
}),
)
}
async fn clone(
Extension(config): PeripheryConfigExtension,
Json(clone_args): Json<CloneArgs>,
) -> anyhow::Result<Json<Vec<Log>>> {
let access_token = get_github_token(&clone_args.github_account, &config)?;
let logs = git::clone_repo(clone_args, &config.repo_dir, access_token).await?;
Ok(Json(logs))
}
fn get_github_token(
github_account: &Option<String>,
config: &PeripheryConfig,
) -> anyhow::Result<Option<GithubToken>> {
match github_account {
Some(account) => match config.github_accounts.get(account) {
Some(token) => Ok(Some(token.to_owned())),
None => Err(anyhow!(
"did not find token in config for github account {account} "
)),
},
None => Ok(None),
}
}