Skip to content

Commit

Permalink
*: split dumnati to commons, graph-builder, and policy-engine
Browse files Browse the repository at this point in the history
This changes splits dumnati to two binaries and a library crate.
No content changes are added and only directory structure changes.

Related: #3
Signed-off-by: Allen Bai <[email protected]>
  • Loading branch information
Allen Bai committed Jul 8, 2020
1 parent 1dba435 commit d3e77b6
Show file tree
Hide file tree
Showing 18 changed files with 1,367 additions and 2 deletions.
60 changes: 60 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
[workspace]

members = [
"commons",
"dumnati",
# "graph-builder",
# "policy-engine",
"graph-builder",
"policy-engine",
]
2 changes: 2 additions & 0 deletions commons/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/target
**/*.rs.bk
15 changes: 15 additions & 0 deletions commons/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "commons"
version = "0.1.0"
authors = ["Allen Bai <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
actix-web = "^2.0.0"
failure = "^0.1.1"
maplit = "^1.0"
prometheus = "^0.9"
serde = "^1.0.70"
serde_derive = "^1.0.70"
203 changes: 203 additions & 0 deletions commons/src/graph.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
use crate::metadata;
use failure::Fallible;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;

/// Single release entry in the Cincinnati update-graph.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CincinnatiPayload {
pub version: String,
pub metadata: HashMap<String, String>,
pub payload: String,
}

/// Cincinnati update-graph, a DAG with releases (nodes) and update paths (edges).
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Graph {
pub nodes: Vec<CincinnatiPayload>,
pub edges: Vec<(u64, u64)>,
}

impl Default for Graph {
fn default() -> Self {
Self {
nodes: vec![],
edges: vec![],
}
}
}

impl Graph {
/// Assemble a graph from release-index and updates metadata.
pub fn from_metadata(
releases: Vec<metadata::Release>,
updates: metadata::UpdatesJSON,
) -> Fallible<Self> {
let nodes: Vec<CincinnatiPayload> = releases
.into_iter()
.enumerate()
.map(|(age_index, entry)| {
let mut current = CincinnatiPayload {
version: entry.version,
payload: "".to_string(),
metadata: maplit::hashmap! {
metadata::AGE_INDEX.to_string() => age_index.to_string(),
},
};
for commit in entry.commits {
if commit.architecture.is_empty() || commit.checksum.is_empty() {
continue;
}
let key = format!("{}.{}", metadata::ARCH_PREFIX, commit.architecture);
let value = commit.checksum;
current.metadata.insert(key, value);
}

// Augment with dead-ends metadata.
Self::inject_deadend_reason(&updates, &mut current);

// Augment with barriers metadata.
Self::inject_barrier_reason(&updates, &mut current);

// Augment with rollouts metadata.
Self::inject_throttling_params(&updates, &mut current);

current
})
.collect();

// Compute the update graph.
let edges = Self::compute_edges(&nodes)?;

let graph = Graph { nodes, edges };
Ok(graph)
}

/// Compute edges based on graph metadata.
fn compute_edges(nodes: &[CincinnatiPayload]) -> Fallible<Vec<(u64, u64)>> {
use std::collections::BTreeSet;
use std::ops::Bound;

// Collect all rollouts and barriers.
let mut rollouts = BTreeSet::<u64>::new();
let mut barriers = BTreeSet::<u64>::new();
for (index, release) in nodes.iter().enumerate() {
if release.metadata.contains_key(metadata::ROLLOUT) {
rollouts.insert(index as u64);
}
if release.metadata.contains_key(metadata::BARRIER) {
barriers.insert(index as u64);
}
}

// Add edges targeting rollouts, back till the previous barrier.
let mut edges = vec![];
for (index, _release) in nodes.iter().enumerate().rev() {
let age = index as u64;
if !rollouts.contains(&age) {
continue;
}

let previous_barrier = barriers
.range((Bound::Unbounded, Bound::Excluded(age)))
.next_back()
.cloned()
.unwrap_or(0);

for i in previous_barrier..age {
edges.push((i, age))
}
}

// Add edges targeting barriers, back till the previous barrier.
let mut start = 0;
for target in barriers {
if rollouts.contains(&target) {
// This is an in-progress barrier. Rollout logic already took care
// of it, nothing to do here.
} else {
for i in start..target {
edges.push((i, target))
}
}
start = target;
}

Ok(edges)
}

fn inject_barrier_reason(updates: &metadata::UpdatesJSON, release: &mut CincinnatiPayload) {
for entry in &updates.releases {
if entry.version != release.version {
continue;
}

if let Some(barrier) = &entry.metadata.barrier {
let reason = if barrier.reason.is_empty() {
"generic"
} else {
&barrier.reason
};

release
.metadata
.insert(metadata::BARRIER.to_string(), true.to_string());
release
.metadata
.insert(metadata::BARRIER_REASON.to_string(), reason.to_string());
}
}
}

fn inject_deadend_reason(updates: &metadata::UpdatesJSON, release: &mut CincinnatiPayload) {
for entry in &updates.releases {
if entry.version != release.version {
continue;
}

if let Some(deadend) = &entry.metadata.deadend {
let reason = if deadend.reason.is_empty() {
"generic"
} else {
&deadend.reason
};

release
.metadata
.insert(metadata::DEADEND.to_string(), true.to_string());
release
.metadata
.insert(metadata::DEADEND_REASON.to_string(), reason.to_string());
}
}
}

fn inject_throttling_params(updates: &metadata::UpdatesJSON, release: &mut CincinnatiPayload) {
for entry in &updates.releases {
if entry.version != release.version {
continue;
}

if let Some(rollout) = &entry.metadata.rollout {
release
.metadata
.insert(metadata::ROLLOUT.to_string(), true.to_string());
if let Some(val) = rollout.start_epoch {
release
.metadata
.insert(metadata::START_EPOCH.to_string(), val.to_string());
}
if let Some(val) = rollout.start_percentage {
release
.metadata
.insert(metadata::START_VALUE.to_string(), val.to_string());
}
if let Some(minutes) = &rollout.duration_minutes {
release
.metadata
.insert(metadata::DURATION.to_string(), minutes.to_string());
}
}
}
}
}
6 changes: 6 additions & 0 deletions commons/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pub mod graph;
pub mod metadata;
pub mod metrics;

extern crate serde;
extern crate serde_derive;
Loading

0 comments on commit d3e77b6

Please sign in to comment.