diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..dd883ce
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,8 @@
+/*
+/*/
+!/constellation-internal/
+!/examples/
+!/src/
+!/tests/
+!/Cargo.toml
+!/build.rs
diff --git a/.mergify.yml b/.mergify.yml
index b88ad04..04f2049 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -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"
@@ -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"
diff --git a/Cargo.toml b/Cargo.toml
index 2245faf..45cb4dc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,7 @@
[package]
name = "constellation-rs"
-version = "0.1.5"
+version = "0.1.6"
license = "Apache-2.0"
authors = ["Alec Mocatta "]
categories = ["development-tools","network-programming","concurrency","asynchronous","command-line-utilities"]
@@ -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" }
@@ -30,9 +27,10 @@ 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"
@@ -40,6 +38,7 @@ 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"
@@ -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"
@@ -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
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..5617fea
--- /dev/null
+++ b/Dockerfile
@@ -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"]
diff --git a/README.md b/README.md
index e91a44d..57e859c 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
- Docs
+ Docs
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.
@@ -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:
@@ -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
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index a1ece06..ded804a 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -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: ''
diff --git a/constellation-internal/Cargo.toml b/constellation-internal/Cargo.toml
index 21fca1d..b28a76a 100644
--- a/constellation-internal/Cargo.toml
+++ b/constellation-internal/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "constellation-internal"
-version = "0.1.5"
+version = "0.1.6"
license = "Apache-2.0"
authors = ["Alec Mocatta "]
categories = ["development-tools","network-programming","concurrency","asynchronous"]
@@ -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]
diff --git a/constellation-internal/src/format.rs b/constellation-internal/src/format.rs
index 2006026..b1dfad3 100644
--- a/constellation-internal/src/format.rs
+++ b/constellation-internal/src/format.rs
@@ -82,6 +82,7 @@ impl Formatter {
}
}
+ #[allow(clippy::too_many_lines)]
pub fn write(&mut self, event: &DeployOutputEvent) {
match *event {
DeployOutputEvent::Spawn(pid_, new_pid) => {
diff --git a/constellation-internal/src/lib.rs b/constellation-internal/src/lib.rs
index 729071d..2e6f8af 100644
--- a/constellation-internal/src/lib.rs
+++ b/constellation-internal/src/lib.rs
@@ -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,
@@ -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}
};
@@ -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)]
@@ -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 for TrySpawnError {
+ fn from(error: SpawnError) -> Self {
+ match error {
+ SpawnError::Recce => Self::Recce,
+ SpawnError::Unknown => Self::Unknown,
+ SpawnError::__Nonexhaustive => unreachable!(),
+ }
+ }
+}
+impl TryFrom for SpawnError {
+ type Error = ();
+
+ fn try_from(error: TrySpawnError) -> Result {
+ 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 {
diff --git a/constellation-internal/src/msg.rs b/constellation-internal/src/msg.rs
index 0009412..31f8de0 100644
--- a/constellation-internal/src/msg.rs
+++ b/constellation-internal/src/msg.rs
@@ -9,6 +9,8 @@ where
A: FileOrVec,
B: FileOrVec,
{
+ /// Whether to wait for space to allocate the process, or just bail.
+ pub block: bool,
/// The resources required for this process.
pub resources: Resources,
/// The socket addresses required to bind to for this process.
@@ -148,7 +150,8 @@ mod serde {
where
S: Serializer,
{
- let mut state = serializer.serialize_tuple(6)?;
+ let mut state = serializer.serialize_tuple(7)?;
+ state.serialize_element(&self.block)?;
state.serialize_element(&self.resources)?;
state.serialize_element(&self.bind)?;
state.serialize_element(&self.args)?;
@@ -193,7 +196,8 @@ mod serde {
where
S: Serializer,
{
- let mut state = serializer.serialize_tuple(6)?;
+ let mut state = serializer.serialize_tuple(7)?;
+ state.serialize_element(&self.value.block)?;
state.serialize_element(&self.value.resources)?;
state.serialize_element(&self.value.bind)?;
state.serialize_element(&self.value.args)?;
@@ -274,7 +278,7 @@ mod serde {
// where
// D: Deserializer<'de>,
// {
- // deserializer.deserialize_tuple(6, FabricRequestVisitor)
+ // deserializer.deserialize_tuple(7, FabricRequestVisitor)
// }
// }
// struct FabricRequestVisitor;
@@ -288,27 +292,31 @@ mod serde {
// where
// V: SeqAccess<'de>,
// {
- // let resources = seq
+ // let block = seq
// .next_element()?
// .ok_or_else(|| de::Error::invalid_length(0, &self))?;
- // let bind = seq
+ // let resources = seq
// .next_element()?
// .ok_or_else(|| de::Error::invalid_length(1, &self))?;
- // let args: Vec = seq
+ // let bind = seq
// .next_element()?
// .ok_or_else(|| de::Error::invalid_length(2, &self))?;
- // let vars = seq
+ // let args: Vec = seq
// .next_element()?
// .ok_or_else(|| de::Error::invalid_length(3, &self))?;
+ // let vars = seq
+ // .next_element()?
+ // .ok_or_else(|| de::Error::invalid_length(4, &self))?;
// let arg = seq
// .next_element::()?
- // .ok_or_else(|| de::Error::invalid_length(4, &self))?
+ // .ok_or_else(|| de::Error::invalid_length(5, &self))?
// .into_vec();
// let binary = seq
// .next_element::()?
- // .ok_or_else(|| de::Error::invalid_length(5, &self))?
+ // .ok_or_else(|| de::Error::invalid_length(6, &self))?
// .into_vec();
// Ok(FabricRequest {
+ // block,
// resources,
// bind,
// args,
@@ -390,7 +398,7 @@ mod serde {
{
READER.with(|reader| {
deserializer.deserialize_tuple(
- 6,
+ 7,
FabricRequestSeed::new(unsafe { &mut **reader.borrow_mut().as_mut().unwrap() }),
)
})
@@ -411,18 +419,21 @@ mod serde {
where
V: SeqAccess<'de>,
{
- let resources = seq
+ let block = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
- let bind = seq
+ let resources = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
- let args: Vec = seq
+ let bind = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(2, &self))?;
- let vars = seq
+ let args: Vec = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(3, &self))?;
+ let vars = seq
+ .next_element()?
+ .ok_or_else(|| de::Error::invalid_length(4, &self))?;
let arg = A::next_element_seed(
&mut seq,
FileSeed {
@@ -432,7 +443,7 @@ mod serde {
seal: false,
},
)?
- .ok_or_else(|| de::Error::invalid_length(4, &self))?;
+ .ok_or_else(|| de::Error::invalid_length(5, &self))?;
#[cfg(feature = "distribute_binaries")]
let binary = B::next_element_seed(
&mut seq,
@@ -443,11 +454,12 @@ mod serde {
seal: true,
},
)?
- .ok_or_else(|| de::Error::invalid_length(5, &self))?;
+ .ok_or_else(|| de::Error::invalid_length(6, &self))?;
#[cfg(not(feature = "distribute_binaries"))]
let binary = seq.next_element()?
- .ok_or_else(|| de::Error::invalid_length(5, &self))?;
+ .ok_or_else(|| de::Error::invalid_length(6, &self))?;
Ok(FabricRequest {
+ block,
resources,
bind,
args,
diff --git a/docker.test.yml b/docker.test.yml
new file mode 100644
index 0000000..c58369e
--- /dev/null
+++ b/docker.test.yml
@@ -0,0 +1,3 @@
+sut:
+ build: .
+ command: "-V"
diff --git a/k8s.yaml b/k8s.yaml
new file mode 100644
index 0000000..9b247a0
--- /dev/null
+++ b/k8s.yaml
@@ -0,0 +1,123 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: constellation
+spec:
+ selector:
+ constellation: master
+ ports:
+ - name: constellation
+ protocol: TCP
+ port: 12321
+ targetPort: 12321
+ type: LoadBalancer
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: constellation
+spec:
+ replicas: 1
+ selector:
+ matchLabels: &labels
+ constellation: master
+ template:
+ metadata:
+ labels: *labels
+ spec:
+ containers:
+ - name: constellation
+ image: constellationrs/constellation:0.1.6
+ args:
+ - kube
+ - 0.0.0.0:32123
+ - 0.0.0.0:12321
+ - "1GiB"
+ - "1"
+ - "1"
+ env:
+ - name: CONSTELLATION_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.podIP
+ ports:
+ - name: constellation
+ containerPort: 32123
+ - name: constellation-b
+ containerPort: 12321
+ resources:
+ requests:
+ memory: "1Gi"
+ cpu: "1"
+ serviceAccountName: constellation-service-account
+ terminationGracePeriodSeconds: 1
+---
+apiVersion: apps/v1
+kind: ReplicaSet
+metadata:
+ name: constellation
+spec:
+ replicas: 0
+ selector:
+ matchLabels:
+ constellation: node
+ template:
+ metadata:
+ labels:
+ constellation: node
+ spec:
+ containers:
+ - name: constellation
+ image: constellationrs/constellation:0.1.6
+ args:
+ - 0.0.0.0:32123
+ env:
+ - name: CONSTELLATION_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.podIP
+ ports:
+ - name: constellation
+ containerPort: 32123
+ resources:
+ requests:
+ memory: "1Gi"
+ cpu: "1"
+ serviceAccountName: constellation-service-account
+ terminationGracePeriodSeconds: 1
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: constellation-service-account
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRole
+metadata:
+ name: constellation-role
+rules:
+ - apiGroups:
+ - ""
+ - apps
+ resources:
+ - pods
+ verbs: ["list", "watch"]
+ - apiGroups:
+ - ""
+ - apps
+ resources:
+ - replicasets/scale
+ verbs: ["patch"]
+---
+apiVersion: rbac.authorization.k8s.io/v1beta1
+kind: ClusterRoleBinding
+metadata:
+ name: constellation-role
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: constellation-role
+subjects:
+ - kind: ServiceAccount
+ name: constellation-service-account
+ namespace: default
diff --git a/src/bin/constellation/args.rs b/src/bin/constellation/args.rs
index 58f3e78..acf9dba 100644
--- a/src/bin/constellation/args.rs
+++ b/src/bin/constellation/args.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::too_many_lines)]
+
use serde::Deserialize;
use std::{error::Error, fs::File, io::Read, net::SocketAddr};
@@ -155,6 +157,34 @@ impl Args {
let format = format.unwrap_or(Format::Human);
let role: Role = match (&*args.next().unwrap(), args.peek()) {
("bridge", None) => Role::Bridge,
+ #[cfg(feature = "kubernetes")]
+ ("kube", _) => {
+ if let (
+ Some(Ok(master_bind)),
+ Some(Ok(bridge_bind)),
+ Some(Ok(mem)),
+ Some(Ok(cpu)),
+ Some(Ok(replicas)),
+ None,
+ ) = (
+ args.next().map(|x| x.parse::()),
+ args.next().map(|x| x.parse::()),
+ args.next().map(|x| parse_mem_size(&x)),
+ args.next().map(|x| parse_cpu_size(&x)),
+ args.next().map(|x| x.parse::()),
+ args.next(),
+ ) {
+ Role::KubeMaster {
+ master_bind,
+ bridge_bind,
+ mem,
+ cpu,
+ replicas,
+ }
+ } else {
+ return Err((format!("Invalid kubernetes master options, expecting , like 127.0.0.1:9999 127.0.0.1:8888 400GiB 34\n{}", USAGE), false));
+ }
+ }
(bind, Some(_)) if bind.parse::().is_ok() => {
let bind = bind.parse().unwrap();
let mut nodes = Vec::new();
diff --git a/src/bin/constellation/bridge.rs b/src/bin/constellation/bridge.rs
index 92b3be3..d0fbdaf 100644
--- a/src/bin/constellation/bridge.rs
+++ b/src/bin/constellation/bridge.rs
@@ -20,7 +20,8 @@ TODO: can lose processes such that ctrl+c doesn't kill them. i think if we kill
#![allow(
clippy::similar_names,
clippy::type_complexity,
- clippy::shadow_unrelated
+ clippy::shadow_unrelated,
+ clippy::too_many_lines
)]
use futures::{future::FutureExt, sink::SinkExt, stream::StreamExt};
@@ -36,7 +37,7 @@ use std::{
use constellation::FutureExt1;
use constellation_internal::{
- abort_on_unwind, abort_on_unwind_1, forbid_alloc, map_bincode_err, msg::{bincode_deserialize_from, bincode_serialize_into, BridgeRequest, FabricRequest}, BufferedStream, DeployInputEvent, DeployOutputEvent, ExitStatus, Fd, Pid, ProcessInputEvent, ProcessOutputEvent, Resources
+ abort_on_unwind, abort_on_unwind_1, forbid_alloc, map_bincode_err, msg::{bincode_deserialize_from, bincode_serialize_into, BridgeRequest, FabricRequest}, BufferedStream, DeployInputEvent, DeployOutputEvent, ExitStatus, Fd, Pid, ProcessInputEvent, ProcessOutputEvent, Resources, TrySpawnError
};
const SCHEDULER_FD: Fd = 4;
@@ -239,7 +240,10 @@ fn recce(
fn manage_connection(
stream: TcpStream,
- sender: mpsc::SyncSender<(FabricRequest, File>, mpsc::SyncSender