Skip to content

Commit

Permalink
Merge pull request #34 from alecmocatta/docker
Browse files Browse the repository at this point in the history
Add Kubernetes as a backend
  • Loading branch information
alecmocatta authored Sep 16, 2019
2 parents ad775d0 + 23a821f commit b32f3ba
Show file tree
Hide file tree
Showing 23 changed files with 636 additions and 213 deletions.
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
/*/
!/constellation-internal/
!/examples/
!/src/
!/tests/
!/Cargo.toml
!/build.rs
2 changes: 2 additions & 0 deletions .mergify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pull_request_rules:
conditions:
- base=master
- status-success=tests
- status-success=ci/dockercloud
- label!=work-in-progress
- "#approved-reviews-by>=1"
- "#review-requested=0"
Expand All @@ -17,6 +18,7 @@ pull_request_rules:
conditions:
- base=master
- status-success=tests
- status-success=ci/dockercloud
- label!=work-in-progress
- author=alecmocatta # https://github.com/Mergifyio/mergify-engine/issues/451
- "#review-requested=0"
Expand Down
19 changes: 13 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[package]
name = "constellation-rs"
version = "0.1.5"
version = "0.1.6"
license = "Apache-2.0"
authors = ["Alec Mocatta <[email protected]>"]
categories = ["development-tools","network-programming","concurrency","asynchronous","command-line-utilities"]
Expand All @@ -12,14 +12,11 @@ Constellation is a framework for Rust (nightly) that aides in the writing, debug
"""
repository = "https://github.com/alecmocatta/constellation"
homepage = "https://github.com/alecmocatta/constellation"
documentation = "https://docs.rs/constellation-rs/0.1.5"
documentation = "https://docs.rs/constellation-rs/0.1.6"
readme = "README.md"
edition = "2018"
autotests = true

[lib]
name = "constellation"

[badges]
azure-devops = { project = "alecmocatta/constellation", pipeline = "tests" }
maintenance = { status = "actively-developed" }
Expand All @@ -30,16 +27,18 @@ nightly = ["palaver/nightly", "relative/nightly"]
distribute_binaries = ["constellation-internal/distribute_binaries"]
fringe = ["serde_pipe/fringe"]
no_alloc = ["constellation-internal/no_alloc"]
kubernetes = ["distribute_binaries", "kube", "openssl"]

[dependencies]
constellation-internal = { path = "constellation-internal", version = "=0.1.5" }
constellation-internal = { path = "constellation-internal", version = "=0.1.6" }
atty = "0.2"
backtrace = "0.3"
bincode = "1.0"
crossbeam = "0.7"
docopt = "1.0"
either = "1.5"
futures-preview = "0.3.0-alpha.18"
kube = { version = "0.16", features = ["openapi"], optional = true }
log = "0.4"
notifier = { version = "0.1", features = ["tcp_typed"] }
once_cell = "1.0"
Expand All @@ -54,6 +53,9 @@ serde_pipe = "0.1"
tcp_typed = "0.1"
toml = "0.5"

# dependency of kube; ensure it's vendored to simplify cross-compilation
openssl = { version = "0.10", features = ["vendored"], optional = true }

[target.'cfg(unix)'.dependencies]
nix = "0.15"

Expand All @@ -73,6 +75,11 @@ systemstat = "0.1"
[patch.crates-io]
systemstat = { git = "https://github.com/alecmocatta/systemstat" }

###

[lib]
name = "constellation"

# Hopefully we won't need to exhaustively list in future:
# https://github.com/rust-lang/cargo/issues/5766 or https://github.com/rust-lang/rust/issues/50297

Expand Down
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
FROM rustlang/rust:nightly as build
WORKDIR /usr/src

# Install musl-gcc
RUN apt-get update && apt-get install -y --no-install-recommends musl-tools

# Download the target for static linking.
RUN rustup target add x86_64-unknown-linux-musl

# Create a dummy project and build the app's dependencies.
# If the Cargo.toml and Cargo.lock files have not changed,
# we can use the docker build cache and skip this slow step.
RUN USER=root cargo init && USER=root cargo new --lib constellation-internal
COPY Cargo.toml ./
RUN sed -i '/^###$/q' Cargo.toml
COPY constellation-internal/Cargo.toml ./constellation-internal/
RUN cargo generate-lockfile
RUN cargo build --bins --features kubernetes --target x86_64-unknown-linux-musl --release

# Copy the source and build the application.
COPY . ./
RUN touch ./constellation-internal/src/lib.rs
RUN cargo build --locked --frozen --offline --bin constellation --features kubernetes --target x86_64-unknown-linux-musl --release

# Copy the statically-linked binary into a scratch container.
FROM scratch
COPY --from=build /usr/src/target/x86_64-unknown-linux-musl/release/constellation .
USER 1000
ENTRYPOINT ["./constellation"]
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</p>

<p align="center">
<a href="https://docs.rs/constellation-rs/0.1.5">Docs</a>
<a href="https://docs.rs/constellation-rs/0.1.6">Docs</a>
</p>

Constellation is a framework for Rust (nightly) that aides in the writing, debugging and deployment of distributed programs. It draws heavily from [Erlang/OTP](https://en.wikipedia.org/wiki/Erlang_(programming_language)), [MPI](https://en.wikipedia.org/wiki/Message_Passing_Interface), and [CSP](https://en.wikipedia.org/wiki/Communicating_sequential_processes); and leverages the Rust ecosystem where it can including [serde](https://serde.rs/) + [bincode](https://github.com/servo/bincode) for network serialization, and [mio](https://github.com/tokio-rs/mio) and [futures-rs](https://github.com/rust-lang-nursery/futures-rs) for asynchronous channels over TCP.
Expand All @@ -27,13 +27,13 @@ For leveraging Constellation directly, read on.

## Constellation framework

* Constellation is a framework that's initialised with a call to [`init()`](https://docs.rs/constellation-rs/0.1.5/constellation/fn.init.html) at the beginning of your program.
* You can [`spawn(closure)`](https://docs.rs/constellation-rs/0.1.5/constellation/fn.spawn.html) new processes, which run `closure`.
* Constellation is a framework that's initialised with a call to [`init()`](https://docs.rs/constellation-rs/0.1.6/constellation/fn.init.html) at the beginning of your program.
* You can [`spawn(closure)`](https://docs.rs/constellation-rs/0.1.6/constellation/fn.spawn.html) new processes, which run `closure`.
* `spawn(closure)` returns the Pid of the new process.
* You can communicate between processes by creating channels with [`Sender::new(remote_pid)`](https://docs.rs/constellation-rs/0.1.5/constellation/struct.Sender.html#method.new) and [`Receiver::new(remote_pid)`](https://docs.rs/constellation-rs/0.1.5/constellation/struct.Receiver.html#method.new).
* Channels can be used asynchronously with [`sender.send(value).await`](https://docs.rs/constellation-rs/0.1.5/constellation/struct.Sender.html#method.send) and [`receiver.recv().await`](https://docs.rs/constellation-rs/0.1.5/constellation/struct.Receiver.html#method.recv).
* You can communicate between processes by creating channels with [`Sender::new(remote_pid)`](https://docs.rs/constellation-rs/0.1.6/constellation/struct.Sender.html#method.new) and [`Receiver::new(remote_pid)`](https://docs.rs/constellation-rs/0.1.6/constellation/struct.Receiver.html#method.new).
* Channels can be used asynchronously with [`sender.send(value).await`](https://docs.rs/constellation-rs/0.1.6/constellation/struct.Sender.html#method.send) and [`receiver.recv().await`](https://docs.rs/constellation-rs/0.1.6/constellation/struct.Receiver.html#method.recv).
* [futures-rs](https://github.com/rust-lang-nursery/futures-rs) provides useful functions and adapters including `select()` and `join()` for working with channels.
* You can also block on channels with the [`.block()`](https://docs.rs/constellation-rs/0.1.5/constellation/trait.FutureExt1.html#method.block) convenience method: `sender.send().block()` and `receiver.recv().block()`.
* You can also block on channels with the [`.block()`](https://docs.rs/constellation-rs/0.1.6/constellation/trait.FutureExt1.html#method.block) convenience method: `sender.send().block()` and `receiver.recv().block()`.
* For more information on asynchronous programming in Rust check out the [Async Book](https://rust-lang.github.io/async-book/index.html)!

Here's a simple example recursively spawning processes to distribute the task of finding Fibonacci numbers:
Expand Down Expand Up @@ -248,7 +248,7 @@ Please file an issue if you experience any other requirements.

## API

[see Rust doc](https://docs.rs/constellation-rs/0.1.5)
[see Rust doc](https://docs.rs/constellation-rs/0.1.6)

## Testing

Expand Down
2 changes: 1 addition & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
endpoint: alecmocatta
default:
rust_toolchain: nightly
rust_lint_toolchain: nightly-2019-08-22
rust_lint_toolchain: nightly-2019-09-13
rust_flags: ''
rust_features: 'no_alloc;no_alloc distribute_binaries'
rust_target_check: ''
Expand Down
4 changes: 2 additions & 2 deletions constellation-internal/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "constellation-internal"
version = "0.1.5"
version = "0.1.6"
license = "Apache-2.0"
authors = ["Alec Mocatta <[email protected]>"]
categories = ["development-tools","network-programming","concurrency","asynchronous"]
Expand All @@ -10,7 +10,7 @@ Common components for the `constellation` framework.
"""
repository = "https://github.com/alecmocatta/constellation"
homepage = "https://github.com/alecmocatta/constellation"
documentation = "https://docs.rs/constellation-internal/0.1.5"
documentation = "https://docs.rs/constellation-internal/0.1.6"
edition = "2018"

[features]
Expand Down
1 change: 1 addition & 0 deletions constellation-internal/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ impl<A: Write, B: Write> Formatter<A, B> {
}
}

#[allow(clippy::too_many_lines)]
pub fn write(&mut self, event: &DeployOutputEvent) {
match *event {
DeployOutputEvent::Spawn(pid_, new_pid) => {
Expand Down
103 changes: 95 additions & 8 deletions constellation-internal/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![doc(html_root_url = "https://docs.rs/constellation-internal/0.1.5")]
#![doc(html_root_url = "https://docs.rs/constellation-internal/0.1.6")]
#![warn(
// missing_copy_implementations,
missing_debug_implementations,
Expand Down Expand Up @@ -30,7 +30,7 @@ use nix::{fcntl, libc, sys::signal, unistd};
use palaver::file::{copy, memfd_create};
use serde::{Deserialize, Serialize};
use std::{
convert::TryInto, env, ffi::{CString, OsString}, fmt::{self, Debug, Display}, fs::File, io::{self, Read, Seek, Write}, net, ops, os::unix::{
convert::{TryFrom, TryInto}, env, error::Error, ffi::{CString, OsString}, fmt::{self, Debug, Display}, fs::File, io::{self, Read, Seek, Write}, net, ops, os::unix::{
ffi::OsStringExt, io::{AsRawFd, FromRawFd, IntoRawFd}
}, process::abort, sync::{Arc, Mutex}
};
Expand Down Expand Up @@ -278,8 +278,8 @@ pub enum Format {
/// ```
/// # use constellation_internal::Resources;
/// pub const RESOURCES_DEFAULT: Resources = Resources {
/// mem: 1024 * 1024 * 1024, // 1 GiB
/// cpu: 65536 / 16, // 1/16th of a logical CPU core
/// mem: 100 * 1024 * 1024, // 100 MiB
/// cpu: 65536 / 16, // 1/16th of a logical CPU core
/// };
/// ```
#[derive(Copy, Clone, PartialEq, Serialize, Deserialize, Debug)]
Expand All @@ -299,15 +299,102 @@ impl Default for Resources {
/// ```
/// # use constellation_internal::Resources;
/// pub const RESOURCES_DEFAULT: Resources = Resources {
/// mem: 1024 * 1024 * 1024, // 1 GiB
/// cpu: 65536 / 16, // 1/16th of a logical CPU core
/// mem: 100 * 1024 * 1024, // 100 MiB
/// cpu: 65536 / 16, // 1/16th of a logical CPU core
/// };
/// ```
pub const RESOURCES_DEFAULT: Resources = Resources {
mem: 1024 * 1024 * 1024, // 1 GiB
cpu: 65536 / 16, // 1/16th of a logical CPU core
mem: 100 * 1024 * 1024, // 100 MiB
cpu: 65536 / 16, // 1/16th of a logical CPU core
};

/// An error returned by the [`try_spawn()`](try_spawn) method detailing the reason if known.
#[allow(missing_copy_implementations)]
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum TrySpawnError {
/// [`try_spawn()`](try_spawn) failed because the new process couldn't be allocated.
NoCapacity,
/// [`try_spawn()`](try_spawn) failed because `constellation::init()` is not called immediately inside main().
Recce,
/// [`try_spawn()`](try_spawn) failed for unknown reasons.
Unknown,
#[doc(hidden)]
__Nonexhaustive, // https://github.com/rust-lang/rust/issues/44109
}

/// An error returned by the [`spawn()`](spawn) method detailing the reason if known.
#[allow(missing_copy_implementations)]
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum SpawnError {
/// [`spawn()`](spawn) failed because `constellation::init()` is not called immediately inside main().
Recce,
/// [`spawn()`](spawn) failed for unknown reasons.
Unknown,
#[doc(hidden)]
__Nonexhaustive,
}
impl From<SpawnError> for TrySpawnError {
fn from(error: SpawnError) -> Self {
match error {
SpawnError::Recce => Self::Recce,
SpawnError::Unknown => Self::Unknown,
SpawnError::__Nonexhaustive => unreachable!(),
}
}
}
impl TryFrom<TrySpawnError> for SpawnError {
type Error = ();

fn try_from(error: TrySpawnError) -> Result<Self, Self::Error> {
match error {
TrySpawnError::NoCapacity => Err(()),
TrySpawnError::Recce => Ok(Self::Recce),
TrySpawnError::Unknown => Ok(Self::Unknown),
TrySpawnError::__Nonexhaustive => unreachable!(),
}
}
}
impl Display for TrySpawnError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NoCapacity => write!(
f,
"try_spawn() failed because the new process couldn't be allocated"
),
Self::Recce => write!(
f,
"try_spawn() because constellation::init() is not called immediately inside main()"
),
Self::Unknown => write!(f, "try_spawn() failed for unknown reasons"),
Self::__Nonexhaustive => unreachable!(),
}
}
}
impl Debug for TrySpawnError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(self, f)
}
}
impl Display for SpawnError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Recce => write!(
f,
"spawn() because constellation::init() is not called immediately inside main()"
),
Self::Unknown => write!(f, "spawn() failed for unknown reasons"),
Self::__Nonexhaustive => unreachable!(),
}
}
}
impl Debug for SpawnError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Display::fmt(self, f)
}
}
impl Error for TrySpawnError {}
impl Error for SpawnError {}

#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(/*tag = "event", */rename_all = "lowercase")]
pub enum FabricOutputEvent {
Expand Down
Loading

0 comments on commit b32f3ba

Please sign in to comment.