Page MenuHomeDevCentral

No OneTemporary

diff --git a/Cargo.toml b/Cargo.toml
index fa8305e..d781616 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,28 +1,28 @@
[package]
name = "alkane"
-version = "0.1.0"
+version = "0.1.1"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
env_logger = "^0.10.0"
lazy_static = "^1.4.0"
limiting-factor = "^0.8.0"
log = "^0.4.17"
rocket = "^0.4.11"
rocket_codegen = "^0.4.11"
serde_yaml = "^0.9.21"
[dependencies.clap]
version = "~4.2.1"
features = ["derive"]
[dependencies.rocket_contrib]
version = "^0.4.11"
default-features = false
features = ["json"]
[dependencies.serde]
version = "^1.0.159"
features = ["derive"]
diff --git a/src/actions.rs b/src/actions.rs
index c2c28ba..a4f85f7 100644
--- a/src/actions.rs
+++ b/src/actions.rs
@@ -1,104 +1,111 @@
// -------------------------------------------------------------
// Alkane :: Actions
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Project: Nasqueron
// License: BSD-2-Clause
// -------------------------------------------------------------
use crate::command::ServerArgs;
use crate::config::AlkaneConfig;
use crate::db::Database;
use crate::deploy::AlkaneDeployError;
use crate::deploy::DeployError;
use crate::runner::store::RecipesStore;
use crate::runner::RecipeStatus;
use crate::server::kernel::run;
// -------------------------------------------------------------
// Actions only available in CLI
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pub fn serve(args: ServerArgs, config: AlkaneConfig) {
run(config, &args.mounting_point);
}
// -------------------------------------------------------------
// Actions available both for CLI and HTTP
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-pub fn initialize(
+fn run_deployment_action(
site_name: &str,
context: Option<String>,
config: &AlkaneConfig,
+ action: &str,
) -> Result<RecipeStatus, DeployError> {
let db = Database::from_config(config).ok_or_else(|| {
- let error = AlkaneDeployError::new("Can't initialize database");
+ let error = AlkaneDeployError::new("Can't initialize database", site_name, action);
DeployError::Alkane(error)
})?;
let recipes = RecipesStore::from_config(config).ok_or_else(|| {
- let error = AlkaneDeployError::new("Can't initialize recipes store");
+ let error = AlkaneDeployError::new("Can't initialize recipes store", site_name, action);
DeployError::Alkane(error)
})?;
let site = config
.get_site(site_name, context)
- .expect("Can't get site path.");
- let status = recipes.run_recipe(&site, "init");
- db.set_initialized(&site.name);
+ .ok_or_else(|| {
+ let error = AlkaneDeployError::new("Can't resolve site path", site_name, action);
+ DeployError::Alkane(error)
+ })?;
+
+ let status = recipes.run_recipe(&site, action);
+
+ if action == "init" {
+ db.set_initialized(&site.name);
+ }
Ok(status)
}
-pub fn update(
+pub fn initialize(
site_name: &str,
context: Option<String>,
config: &AlkaneConfig,
) -> Result<RecipeStatus, DeployError> {
- let recipes = RecipesStore::from_config(config).ok_or_else(|| {
- let error = AlkaneDeployError::new("Can't initialize recipes store");
- DeployError::Alkane(error)
- })?;
+ run_deployment_action(site_name, context, config, "init")
+}
- let site = config
- .get_site(site_name, context)
- .expect("Can't get site path.");
- let status = recipes.run_recipe(&site, "update");
- Ok(status)
+pub fn update(
+ site_name: &str,
+ context: Option<String>,
+ config: &AlkaneConfig,
+) -> Result<RecipeStatus, DeployError> {
+ run_deployment_action(site_name, context, config, "update")
}
pub fn deploy(
site_name: &str,
context: Option<String>,
config: &AlkaneConfig,
) -> Result<RecipeStatus, DeployError> {
if is_present(site_name, config) {
- update(site_name, context, config)
+ run_deployment_action(site_name, context, config, "update")
} else {
- initialize(site_name, context, config)
+ run_deployment_action(site_name, context, config, "init")
}
}
pub fn is_present(site_name: &str, config: &AlkaneConfig) -> bool {
match Database::from_config(&config) {
None => false,
Some(db) => db.is_initialized(site_name),
}
}
// -------------------------------------------------------------
// Tests
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn test_is_present() {
let config = AlkaneConfig::load().unwrap();
assert_eq!(true, is_present("foo.acme.tld", &config));
assert_eq!(false, is_present("notexisting.acme.tld", &config));
}
}
diff --git a/src/deploy.rs b/src/deploy.rs
index 1a3ca28..f5022f3 100644
--- a/src/deploy.rs
+++ b/src/deploy.rs
@@ -1,47 +1,63 @@
// -------------------------------------------------------------
// Alkane :: Deploy
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Project: Nasqueron
// License: BSD-2-Clause
// -------------------------------------------------------------
use std::error::Error;
use std::fmt::{Display, Formatter};
// -------------------------------------------------------------
// Errors during our own workflow deployment
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/// Represents an error during the workflow to run a deployment
#[derive(Debug)]
pub struct AlkaneDeployError {
pub message: String,
+
+ /// The name of the site to deploy
+ pub site_name: String,
+
+ /// The deployment action, "init" or "update"
+ pub action: String,
}
impl Display for AlkaneDeployError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- write!(f, "Alkane deploy error: {}", self.message)
+ write!(f, "Can't run deployment action '{}' for site '{}': {}", self.action, self.site_name, self.message)
}
}
impl Error for AlkaneDeployError {}
impl AlkaneDeployError {
- pub fn new<S>(message: S) -> Self
+ pub fn new<S>(message: S, site_name: S, action: S) -> Self
where
S: AsRef<str>,
{
Self {
message: message.as_ref().to_string(),
+ site_name: site_name.as_ref().to_string(),
+ action: action.as_ref().to_string(),
}
}
}
// -------------------------------------------------------------
// Errors that can occur during a deployment
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#[derive(Debug)]
pub enum DeployError {
Alkane(AlkaneDeployError),
}
+
+impl Display for DeployError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ match self {
+ DeployError::Alkane(error) => error.fmt(f),
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index f4fa11f..a7fd581 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,96 +1,96 @@
// -------------------------------------------------------------
// Alkane
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Project: Nasqueron
// License: BSD-2-Clause
// Description: Manage nginx and php-fpm Alkane PaaS
// -------------------------------------------------------------
#![feature(decl_macro)]
use std::process::exit;
use clap::Parser;
use crate::actions::*;
use crate::command::{AlkaneCommand, ToStatusCode};
use crate::config::AlkaneConfig;
use crate::deploy::DeployError;
use crate::runner::RecipeStatus;
// -------------------------------------------------------------
// Modules
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mod actions;
mod command;
mod config;
mod db;
mod deploy;
mod runner;
mod server;
mod services;
// -------------------------------------------------------------
// Application entry point
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fn main() {
env_logger::init();
let command = AlkaneCommand::parse(); // Will exit if argument is missing or --help/--version provided.
let config = match AlkaneConfig::load() {
Ok(config) => config,
Err(error) => {
eprintln!("Can't load configuration: {:?}", error);
exit(4);
}
};
match command {
AlkaneCommand::Server(args) => {
serve(args, config);
}
AlkaneCommand::Update(args) => {
let result = update(&args.site_name, None, &config);
deploy_exit(result);
}
AlkaneCommand::Init(args) => {
let result = initialize(&args.site_name, None, &config);
deploy_exit(result);
}
AlkaneCommand::Deploy(args) => {
let result = deploy(&args.site_name, None, &config);
deploy_exit(result);
}
AlkaneCommand::IsPresent(args) => {
let is_present = is_present(&args.site_name, &config);
if !args.quiet {
if is_present {
let path = config.get_site_path(&args.site_name).unwrap();
println!("{}", path);
} else {
eprintln!("Site is absent.")
}
}
exit(is_present.to_status_code());
}
}
}
fn deploy_exit(result: Result<RecipeStatus, DeployError>) {
match result {
Ok(status) => exit(status.to_status_code()),
Err(error) => {
- eprintln!("Can't deploy: {:?}", error);
+ eprintln!("{}", error);
exit(16);
}
}
}
diff --git a/src/server/requests.rs b/src/server/requests.rs
index e0bd3a9..ee3dd6a 100644
--- a/src/server/requests.rs
+++ b/src/server/requests.rs
@@ -1,97 +1,97 @@
// -------------------------------------------------------------
// Alkane :: Server :: Requests
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Project: Nasqueron
// License: BSD-2-Clause
// -------------------------------------------------------------
use limiting_factor::api::guards::RequestBody;
use limiting_factor::api::replies::{ApiJsonResponse, ApiResponse};
use log::{debug, info, warn};
use rocket::State;
use rocket_codegen::{get, post};
use crate::actions;
use crate::config::AlkaneConfig;
use crate::runner::RecipeStatus;
// -------------------------------------------------------------
// Monitoring
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#[get("/status")]
pub fn status() -> &'static str {
"ALIVE"
}
// -------------------------------------------------------------
// Alkane requests
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#[get("/is_present/<site_name>")]
pub fn is_present(site_name: String, config: State<AlkaneConfig>) -> ApiJsonResponse<bool> {
actions::is_present(&site_name, &config).into_json_response()
}
#[post("/init/<site_name>", data = "<context>")]
pub fn init(
site_name: String,
context: RequestBody,
config: State<AlkaneConfig>,
) -> ApiJsonResponse<RecipeStatus> {
info!("Deploying {}", &site_name);
let context = context.into_optional_string();
debug!("Context: {:?}", &context);
match actions::initialize(&site_name, context, &config) {
Ok(status) => status.into_json_response(),
Err(error) => {
- warn!("Deployment error: {:?}", error);
+ warn!("{}", error);
RecipeStatus::Error.into_json_response()
}
}
}
#[post("/update/<site_name>", data = "<context>")]
pub fn update(
site_name: String,
context: RequestBody,
config: State<AlkaneConfig>,
) -> ApiJsonResponse<RecipeStatus> {
info!("Deploying {}", &site_name);
let context = context.into_optional_string();
debug!("Context: {:?}", &context);
match actions::update(&site_name, context, &config) {
Ok(status) => status.into_json_response(),
Err(error) => {
- warn!("Deployment error: {:?}", error);
+ warn!("{}", error);
RecipeStatus::Error.into_json_response()
}
}
}
#[post("/deploy/<site_name>", data = "<context>")]
pub fn deploy(
site_name: String,
context: RequestBody,
config: State<AlkaneConfig>,
) -> ApiJsonResponse<RecipeStatus> {
info!("Deploying {}", &site_name);
let context = context.into_optional_string();
debug!("Context: {:?}", &context);
match actions::deploy(&site_name, context, &config) {
Ok(status) => status.into_json_response(),
Err(error) => {
- warn!("Deployment error: {:?}", error);
+ warn!("{}", error);
RecipeStatus::Error.into_json_response()
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 07:07 (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2256919
Default Alt Text
(12 KB)

Event Timeline