Sleep after killing processes

next
Sayan Nandan 3 years ago
parent f04e026178
commit 0a5a7e7bf6
No known key found for this signature in database
GPG Key ID: 8BC07A0A4D41DD52

@ -0,0 +1,108 @@
/*
* Created on Thu Mar 17 2022
*
* This file is a part of Skytable
* Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source
* NoSQL database written by Sayan Nandan ("the Author") with the
* vision to provide flexibility in data modelling without compromising
* on performance, queryability or scalability.
*
* Copyright (c) 2022, Sayan Nandan <ohsayan@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use crate::util;
use crate::HarnessResult;
use std::{
path::{Path, PathBuf},
process::Command,
};
/// The binaries that will be present in a bundle
pub const BINARIES: [&str; 4] = ["skyd", "sky-bench", "skysh", "sky-migrate"];
/// The build mode
pub enum BuildMode {
Debug,
Release,
}
impl BuildMode {
/// Get the build mode as an argument to pass to `cargo`
pub const fn get_arg(&self) -> Option<&'static str> {
match self {
BuildMode::Debug => None,
BuildMode::Release => Some("--release"),
}
}
}
impl ToString for BuildMode {
fn to_string(&self) -> String {
match self {
BuildMode::Debug => "debug".to_owned(),
BuildMode::Release => "release".to_owned(),
}
}
}
/// Returns `{body}/{binary_name}(.exe if on windows)`
fn concat_path(binary_name: &str, body: impl AsRef<Path>) -> PathBuf {
let mut pb = PathBuf::from(body.as_ref());
#[cfg(windows)]
let binary_name = format!("{}.exe", binary_name);
pb.push(binary_name);
pb
}
/// Returns the paths of the files for the given target folder
pub fn get_files_index(target_folder: &PathBuf) -> Vec<PathBuf> {
let mut paths = Vec::with_capacity(3);
for binary in BINARIES {
paths.push(concat_path(binary, target_folder));
}
paths
}
/// Runs `cargo build` with the provided mode. `TARGET` is handled automatically
pub fn build(mode: BuildMode) -> HarnessResult<PathBuf> {
let mut build_args = vec!["build".to_owned()];
let mut target_folder = PathBuf::from("target");
match util::get_var(util::VAR_TARGET) {
Some(t) => {
build_args.push("--target".to_owned());
build_args.push(t.to_string());
target_folder.push(&t);
}
None => {}
};
target_folder.push(mode.to_string());
// assemble build args
for binary in BINARIES {
build_args.extend(["-p".to_owned(), binary.to_owned()])
}
if let Some(arg) = mode.get_arg() {
build_args.push(arg.to_owned());
}
let mut cmd = Command::new("cargo");
cmd.args(&build_args);
util::handle_child(
&format!("build {mode} binaries", mode = mode.to_string()),
cmd,
)?;
Ok(target_folder)
}

@ -24,34 +24,19 @@
*
*/
use crate::{util, HarnessError, HarnessResult};
use crate::{
build::{self, BuildMode},
util, HarnessError, HarnessResult,
};
use libsky::VERSION;
use std::fs;
use std::io::Read;
use std::io::Write;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use zip::{write::FileOptions, ZipWriter};
pub const BINARIES: [&str; 4] = ["skyd", "sky-bench", "skysh", "sky-migrate"];
fn concat_path(binary_name: &str, body: impl AsRef<Path>) -> PathBuf {
let mut pb = PathBuf::from(body.as_ref());
#[cfg(windows)]
let binary_name = format!("{}.exe", binary_name);
pb.push(binary_name);
pb
}
fn get_files_index(target_folder: &PathBuf) -> Vec<PathBuf> {
let mut paths = Vec::with_capacity(3);
for binary in BINARIES {
paths.push(concat_path(binary, target_folder));
}
paths
}
/// Returns the bundle name
fn get_bundle_name() -> String {
let mut filename = format!("sky-bundle-v{VERSION}");
match util::get_var(util::VAR_ARTIFACT) {
@ -65,41 +50,18 @@ fn get_bundle_name() -> String {
filename
}
/// Builds binaries in release mode and returns the target folder path
pub fn build_release() -> HarnessResult<PathBuf> {
let mut build_args = vec!["build".to_owned()];
let mut target_folder = PathBuf::from("target");
match util::get_var(util::VAR_TARGET) {
Some(t) => {
build_args.push("--target".to_owned());
build_args.push(t.to_string());
target_folder.push(&t);
}
None => {}
};
target_folder.push("release");
// assemble build args
for binary in BINARIES {
build_args.extend(["-p".to_owned(), binary.to_owned()])
}
build_args.push("--release".into());
let mut cmd = Command::new("cargo");
cmd.args(&build_args);
util::handle_child("build release binaries", cmd)?;
Ok(target_folder)
}
pub fn run_bundle() -> HarnessResult<()> {
let target_folder = self::build_release()?;
/// Create a bundle using the provided mode
pub fn bundle(mode: BuildMode) -> HarnessResult<()> {
let target_folder = build::build(mode)?;
// now package
package_binaries(target_folder)?;
Ok(())
}
/// Package the binaries into a ZIP file
fn package_binaries(target_folder: PathBuf) -> HarnessResult<()> {
// get the file index
let file_index = get_files_index(&target_folder);
let file_index = build::get_files_index(&target_folder);
// get the bundle file name
let bundle_file_name = get_bundle_name();
// create the bundle file

@ -24,6 +24,7 @@
*
*/
use crate::build::BuildMode;
use crate::linuxpkg::LinuxPackageType;
use crate::{HarnessError, HarnessResult};
use std::{env, process};
@ -42,16 +43,18 @@ SUBCOMMANDS:
pub enum HarnessWhat {
Test,
Bundle,
Bundle(BuildMode),
LinuxPackage(LinuxPackageType),
}
impl HarnessWhat {
const CLI_TEST: &'static str = "test";
const CLI_BUNDLE: &'static str = "bundle";
const CLI_BUNDLE_DEBUG: &'static str = "bundle-dbg";
const CLI_DEB: &'static str = "deb";
const CLI_ARG_HELP: &'static str = "--help";
const CLI_ARG_HELP_SHORT: &'static str = "-h";
/// Returns the target _harness mode_ from env
pub fn from_env() -> HarnessResult<Self> {
let args: Vec<String> = env::args().skip(1).collect();
if args.is_empty() {
@ -64,7 +67,8 @@ impl HarnessWhat {
}
let ret = match args[0].as_str() {
Self::CLI_TEST => HarnessWhat::Test,
Self::CLI_BUNDLE => HarnessWhat::Bundle,
Self::CLI_BUNDLE => HarnessWhat::Bundle(BuildMode::Release),
Self::CLI_BUNDLE_DEBUG => HarnessWhat::Bundle(BuildMode::Debug),
Self::CLI_ARG_HELP_SHORT | Self::CLI_ARG_HELP => display_help(),
Self::CLI_DEB => HarnessWhat::LinuxPackage(LinuxPackageType::Deb),
unknown_arg => return Err(HarnessError::UnknownCommand(unknown_arg.to_string())),

@ -30,9 +30,13 @@ use std::fmt;
pub type HarnessResult<T> = Result<T, HarnessError>;
#[derive(Debug)]
pub enum HarnessError {
/// Unknown command
UnknownCommand(String),
/// Bad arguments
BadArguments(String),
ChildError(&'static str, ExitCode),
/// Child process failure
ChildError(String, ExitCode),
/// Other error
Other(String),
}

@ -24,21 +24,25 @@
*
*/
use crate::bundle::build_release;
use crate::build::{self, BuildMode};
use crate::{util, HarnessResult};
use libsky::VERSION;
use std::process::Command;
/// The Linux package type
pub enum LinuxPackageType {
/// Debian packages
Deb,
}
impl LinuxPackageType {
/// Returns the extension
fn get_extension(&self) -> String {
match self {
Self::Deb => ".deb".to_owned(),
}
}
/// Returns the file name for the package
fn get_file_name(&self) -> String {
let mut filename = format!("skytable-v{VERSION}");
match util::get_var(util::VAR_ARTIFACT) {
@ -53,9 +57,10 @@ impl LinuxPackageType {
}
}
/// Creates a Linux package for the provided Linux package type
pub fn create_linuxpkg(package_type: LinuxPackageType) -> HarnessResult<()> {
info!("Building binaries for Linux package");
let _ = build_release()?;
let _ = build::build(BuildMode::Release)?;
info!("Creating Linux package");
let filename = package_type.get_file_name();
match package_type {

@ -28,6 +28,7 @@
extern crate log;
#[macro_use]
mod util;
mod build;
mod bundle;
mod cli;
mod error;
@ -56,7 +57,7 @@ fn runner() -> HarnessResult<()> {
presetup::install_deps()?;
match harness {
HarnessWhat::Test => test::run_test()?,
HarnessWhat::Bundle => bundle::run_bundle()?,
HarnessWhat::Bundle(bundle_mode) => bundle::bundle(bundle_mode)?,
HarnessWhat::LinuxPackage(pkg) => linuxpkg::create_linuxpkg(pkg)?,
}
Ok(())

@ -42,10 +42,13 @@ use std::io::Write;
use std::process::Child;
use std::process::Command;
/// The workspace root
const WORKSPACE_ROOT: &str = env!("ROOT_DIR");
#[cfg(windows)]
/// The powershell script hack to send CTRL+C using kernel32
const POWERSHELL_SCRIPT: &str = include_str!("../../ci/windows/stop.ps1");
/// Get the command to start the provided server1
pub fn get_run_server_cmd(server_id: &'static str, cmd_payload: &[String]) -> Command {
let mut cmd = Command::new("cargo");
cmd.args(cmd_payload);
@ -56,6 +59,7 @@ pub fn get_run_server_cmd(server_id: &'static str, cmd_payload: &[String]) -> Co
cmd
}
/// Start the servers returning handles to the child processes
pub fn start_servers(s1_cmd: Command, s2_cmd: Command) -> HarnessResult<(Child, Child)> {
info!("Starting server1 ...");
let s1 = util::get_child("start server1", s1_cmd)?;
@ -66,16 +70,24 @@ pub fn start_servers(s1_cmd: Command, s2_cmd: Command) -> HarnessResult<(Child,
Ok((s1, s2))
}
#[cfg(not(windows))]
/// Kill the servers (run the command and then sleep for 10s)
fn kill_servers() -> HarnessResult<()> {
util::handle_child("kill servers", cmd!("pkill", "skyd"))?;
kill_servers_inner()?;
// sleep
util::sleep_sec(10);
util::sleep_sec(20);
Ok(())
}
#[cfg(not(windows))]
/// Kill the servers using `pkill` (send SIGTERM)
fn kill_servers_inner() -> HarnessResult<()> {
util::handle_child("kill servers", cmd!("pkill", "skyd"))?;
Ok(())
}
#[cfg(windows)]
fn kill_servers() -> HarnessResult<()> {
/// HACK(@ohsayan): Kill the servers using a powershell hack
fn kill_servers_inner() -> HarnessResult<()> {
match powershell_script::run(POWERSHELL_SCRIPT, false) {
Ok(_) => Ok(()),
Err(e) => Err(HarnessError::Other(format!(
@ -84,6 +96,7 @@ fn kill_servers() -> HarnessResult<()> {
}
}
/// Run the test suite
pub fn run_test() -> HarnessResult<()> {
let ret = run_test_inner();
kill_servers()?;
@ -98,53 +111,10 @@ pub fn run_test() -> HarnessResult<()> {
ret
}
fn mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack> {
let rsa = Rsa::generate(2048)?;
let key_pair = PKey::from_rsa(rsa)?;
let mut x509_name = X509NameBuilder::new()?;
x509_name.append_entry_by_text("C", "US")?;
x509_name.append_entry_by_text("ST", "CA")?;
x509_name.append_entry_by_text("O", "Skytable")?;
x509_name.append_entry_by_text("CN", "sky-harness")?;
let x509_name = x509_name.build();
let mut cert_builder = X509::builder()?;
cert_builder.set_version(2)?;
let serial_number = {
let mut serial = BigNum::new()?;
serial.rand(159, MsbOption::MAYBE_ZERO, false)?;
serial.to_asn1_integer()?
};
cert_builder.set_serial_number(&serial_number)?;
cert_builder.set_subject_name(&x509_name)?;
cert_builder.set_issuer_name(&x509_name)?;
cert_builder.set_pubkey(&key_pair)?;
let not_before = Asn1Time::days_from_now(0)?;
cert_builder.set_not_before(&not_before)?;
let not_after = Asn1Time::days_from_now(365)?;
cert_builder.set_not_after(&not_after)?;
cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?;
cert_builder.append_extension(
KeyUsage::new()
.critical()
.key_cert_sign()
.crl_sign()
.build()?,
)?;
let subject_key_identifier =
SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
cert_builder.append_extension(subject_key_identifier)?;
cert_builder.sign(&key_pair, MessageDigest::sha256())?;
let cert = cert_builder.build();
Ok((cert, key_pair))
}
pub fn run_test_inner() -> HarnessResult<()> {
/// Actually run the tests. This will run:
/// - The standard test suite
/// - The persistence test suite
fn run_test_inner() -> HarnessResult<()> {
// first create the TLS keys
info!("Creating TLS key+cert");
let (cert, pkey) = mk_ca_cert().expect("Failed to create cert");
@ -211,3 +181,50 @@ pub fn run_test_inner() -> HarnessResult<()> {
Ok(())
}
/// Generate certificates
fn mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack> {
let rsa = Rsa::generate(2048)?;
let key_pair = PKey::from_rsa(rsa)?;
let mut x509_name = X509NameBuilder::new()?;
x509_name.append_entry_by_text("C", "US")?;
x509_name.append_entry_by_text("ST", "CA")?;
x509_name.append_entry_by_text("O", "Skytable")?;
x509_name.append_entry_by_text("CN", "sky-harness")?;
let x509_name = x509_name.build();
let mut cert_builder = X509::builder()?;
cert_builder.set_version(2)?;
let serial_number = {
let mut serial = BigNum::new()?;
serial.rand(159, MsbOption::MAYBE_ZERO, false)?;
serial.to_asn1_integer()?
};
cert_builder.set_serial_number(&serial_number)?;
cert_builder.set_subject_name(&x509_name)?;
cert_builder.set_issuer_name(&x509_name)?;
cert_builder.set_pubkey(&key_pair)?;
let not_before = Asn1Time::days_from_now(0)?;
cert_builder.set_not_before(&not_before)?;
let not_after = Asn1Time::days_from_now(365)?;
cert_builder.set_not_after(&not_after)?;
cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?;
cert_builder.append_extension(
KeyUsage::new()
.critical()
.key_cert_sign()
.crl_sign()
.build()?,
)?;
let subject_key_identifier =
SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
cert_builder.append_extension(subject_key_identifier)?;
cert_builder.sign(&key_pair, MessageDigest::sha256())?;
let cert = cert_builder.build();
Ok((cert, key_pair))
}

@ -39,13 +39,13 @@ pub fn get_var(var: &str) -> Option<String> {
env::var_os(var).map(|v| v.to_string_lossy().to_string())
}
pub fn handle_exitstatus(desc: &'static str, status: IoResult<ExitStatus>) -> HarnessResult<()> {
pub fn handle_exitstatus(desc: &str, status: IoResult<ExitStatus>) -> HarnessResult<()> {
match status {
Ok(status) => {
if status.success() {
Ok(())
} else {
Err(HarnessError::ChildError(desc, status.code()))
Err(HarnessError::ChildError(desc.to_owned(), status.code()))
}
}
Err(e) => Err(HarnessError::Other(format!(
@ -64,7 +64,7 @@ pub fn get_child(desc: impl ToString, mut input: Command) -> HarnessResult<Child
}
}
pub fn handle_child(desc: &'static str, input: Command) -> HarnessResult<()> {
pub fn handle_child(desc: &str, input: Command) -> HarnessResult<()> {
self::handle_exitstatus(desc, self::get_child(desc, input)?.wait())
}

Loading…
Cancel
Save