Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/packages/cluster/SERVER_PROVISIONING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ If `cluster-datacenter-scale` determines that there are less servers in a [pool]

- ### Creating a new server

1. Before the new server is provisioned, it checks if a [prebaked](#prebaking) image for the given [pool](#pool) already exists. If it does, the prebake image is copied to the newly created disk and no install procedure is required. If the prebake image does not exist, it will be created on a separate prebake server. The current server being created will be ssh'd into and run install scripts that are customized based on the [pool](#pool) this server is assigned to.
First, a hardware tier is chosen from the list of user-defined hardware in the [pool](#pool) config. If there is any failure in provisioning this chosen hardware (i.e. the specific tier ran out of capacity with the chosen provider), the next hardware choice will be chosen.

Before the new server is provisioned, we check if a [prebaked](#prebaking) image for the given [pool](#pool) already exists. If it does, the prebake image is copied to the newly created disk and no install procedure is required. If the prebake image does not exist, it will be created on a separate prebake server. The current server being created will be ssh'd into and will run install scripts that are customized based on the [pool](#pool) this server is a part of.

- ### [Prebaking](#prebaking)

Expand Down
8 changes: 6 additions & 2 deletions gen/secrets.baseline.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@
"path": "detect_secrets.filters.common.is_baseline_file",
"filename": "gen/secrets.baseline.json"
},
{
"path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies",
"min_level": 2
},
{
"path": "detect_secrets.filters.gibberish.should_exclude_secret",
"limit": 3.7
Expand Down Expand Up @@ -186,7 +190,7 @@
"filename": "lib/pools/Cargo.toml",
"hashed_secret": "094ac283ac093cc8b5dfcd1ac2540aca3eb8cecb",
"is_verified": false,
"line_number": 41
"line_number": 42
}
],
"lib/redis-util/Cargo.toml": [
Expand Down Expand Up @@ -244,5 +248,5 @@
}
]
},
"generated_at": "2024-04-11T21:32:47Z"
"generated_at": "2024-04-17T19:33:19Z"
}
4 changes: 1 addition & 3 deletions lib/api-helper/build/src/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ impl __RouterConfig {
};

match self.path_segments.last() {
Some(segment) if segment == prefix => {
tracing::debug!("matched");

Some(segment) if segment == prefix => {
self.path_segments.pop();
true
}
Expand Down
5 changes: 4 additions & 1 deletion lib/bolt/config/src/ns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,8 @@ pub struct Provisioning {
/// Whether or not to send a taint message in the next cluster update.
#[serde(default)]
pub taint: bool,
/// How many empty job servers to have at all times. Used in the simple provisioning algorithm.
/// How many empty job servers to have at all times. Used in the simple provisioning algorithm on Rivet
/// Enterprise.
#[serde(default = "default_job_server_provision_margin")]
pub job_server_provision_margin: u32,
#[serde(default)]
Expand All @@ -624,6 +625,7 @@ impl Default for ProvisioningAcmeDirectory {
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct ProvisioningCluster {
/// Identifier name of the default cluster.
name_id: String,
#[serde(default)]
pub datacenters: HashMap<String, ProvisioningDatacenter>,
Expand All @@ -632,6 +634,7 @@ pub struct ProvisioningCluster {
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(deny_unknown_fields)]
pub struct ProvisioningDatacenter {
/// Randomly generated ID for the given datacenter.
pub datacenter_id: Uuid,
pub display_name: String,
pub provider: ProvisioningProvider,
Expand Down
115 changes: 92 additions & 23 deletions lib/bolt/core/src/tasks/test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fmt;

use anyhow::*;
use futures_util::{StreamExt, TryStreamExt};
use futures_util::{FutureExt, StreamExt, TryStreamExt};
use rand::{seq::SliceRandom, thread_rng};
use reqwest::header;
use rivet_term::console::style;
Expand Down Expand Up @@ -569,6 +569,16 @@ struct Data {
id: u64,
}

#[derive(Debug, Deserialize)]
struct SshKeysListResponse {
data: Vec<SshKey>,
}

#[derive(Debug, Deserialize)]
struct SshKey {
id: u64,
}

// TODO: This only deletes linodes and firewalls, the ssh key still remains
async fn cleanup_servers(ctx: &ProjectContext) -> Result<()> {
if ctx.ns().rivet.provisioning.is_none() {
Expand All @@ -580,67 +590,93 @@ async fn cleanup_servers(ctx: &ProjectContext) -> Result<()> {

// Create client
let api_token = ctx.read_secret(&["linode", "token"]).await?;
let auth = format!("Bearer {}", api_token,);
let auth = format!("Bearer {}", api_token);
let mut headers = header::HeaderMap::new();
headers.insert(header::AUTHORIZATION, header::HeaderValue::from_str(&auth)?);
let client = reqwest::Client::builder()
.default_headers(headers)
.build()?;

// Fetch all objects with the tag "test"
// Fetch all objects with the tag "test" and ssh keys with "test-" in them
let test_tag = "test";
let res = client
.get(format!("https://api.linode.com/v4/tags/{test_tag}"))
.send()
.await?;
let (objects_res, ssh_keys_res) = tokio::try_join!(
async {
let res = client
.get(format!("https://api.linode.com/v4/tags/{test_tag}"))
.send()
.await?;

if !res.status().is_success() {
bail!(
"api request failed ({}):\n{}",
res.status(),
res.json::<ApiErrorResponse>().await?
);
}

if !res.status().is_success() {
bail!(
"api request failed ({}):\n{}",
res.status(),
res.json::<ApiErrorResponse>().await?
);
}
// Deserialize
Ok(res.json::<TaggedObjectsListResponse>().await?)
},
async {
let res = client
.get(format!("https://api.linode.com/v4/profile/sshkeys"))
.header(
"X-Filter",
format!(r#"{{ "label": {{ "+contains": "{test_tag}-" }} }}"#),
)
.send()
.await?;

if !res.status().is_success() {
bail!(
"api request failed ({}):\n{}",
res.status(),
res.json::<ApiErrorResponse>().await?
);
}

// Deserialize
let res = res.json::<TaggedObjectsListResponse>().await?;
// Deserialize
Ok(res.json::<SshKeysListResponse>().await?)
}
)?;

futures_util::stream::iter(res.data)
let deletions = objects_res
.data
.into_iter()
.map(|object| {
let client = client.clone();
let obj_type = object._type;
let id = object.data.id;

async move {
eprintln!("destroying {} {}", obj_type, id);
eprintln!("destroying {obj_type} {id}");

// Destroy resource
let res = match obj_type.as_str() {
"linode" => {
client
.delete(format!("https://api.linode.com/v4/linode/instances/{}", id))
.delete(format!("https://api.linode.com/v4/linode/instances/{id}"))
.send()
.await?
}
"firewall" => {
client
.delete(format!(
"https://api.linode.com/v4/networking/firewalls/{}",
id
"https://api.linode.com/v4/networking/firewalls/{id}"
))
.send()
.await?
}
_ => {
eprintln!("unknown type tagged with \"test\": {}", obj_type);
eprintln!("unknown type tagged with \"test\": {obj_type}");
return Ok(());
}
};

if !res.status().is_success() {
// Resource does not exist to be deleted, not an error
if res.status() == reqwest::StatusCode::NOT_FOUND {
eprintln!("{} {} doesn't exist, skipping", obj_type, id);
eprintln!("{obj_type} {id} doesn't exist, skipping");
return Ok(());
}

Expand All @@ -653,7 +689,40 @@ async fn cleanup_servers(ctx: &ProjectContext) -> Result<()> {

Ok(())
}
.boxed()
})
.chain(ssh_keys_res.data.into_iter().map(|key| {
let client = client.clone();
let id = key.id;

async move {
eprintln!("destroying key {id}");

let res = client
.delete(format!("https://api.linode.com/v4/profile/sshkeys/{id}"))
.send()
.await?;

if !res.status().is_success() {
// Resource does not exist to be deleted, not an error
if res.status() == reqwest::StatusCode::NOT_FOUND {
eprintln!("key {id} doesn't exist, skipping");
return Ok(());
}

bail!(
"api request failed ({}):\n{}",
res.status(),
res.json::<ApiErrorResponse>().await?
);
}

Ok(())
}
.boxed()
}));

futures_util::stream::iter(deletions)
.buffer_unordered(8)
.try_collect::<Vec<_>>()
.await?;
Expand Down
1 change: 1 addition & 0 deletions lib/pools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ features = [
"postgres",
"macros",
"uuid",
"ipnetwork",
"json",
"bit-vec",
]
Expand Down
41 changes: 0 additions & 41 deletions lib/util/core/src/math.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,3 @@
use std::cmp::Ordering;

fn _cmp_floats(a: f32, b: f32) -> Ordering {
a.partial_cmp(&b).unwrap_or_else(|| {
if a.is_nan() {
if b.is_nan() {
Ordering::Equal
} else {
Ordering::Less
}
} else {
Ordering::Greater
}
})
}

fn _cmp_floats_opt(a: Option<f32>, b: Option<f32>) -> Ordering {
match a.partial_cmp(&b) {
Some(ord) => ord,
None => {
if let (Some(a), Some(b)) = (a, b) {
if a.is_nan() {
if b.is_nan() {
Ordering::Equal
} else {
Ordering::Less
}
} else if b.is_nan() {
Ordering::Greater
} else {
// unreachable
Ordering::Less
}
} else {
// unreachable
Ordering::Less
}
}
}
}

/// Divide integers of any type, rounding up. Panics on dividing by 0.
#[macro_export]
macro_rules! div_up {
Expand Down
6 changes: 0 additions & 6 deletions lib/util/env/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use serde::Deserialize;
use uuid::Uuid;

#[derive(Debug, thiserror::Error)]
pub enum EnvVarError {
Expand Down Expand Up @@ -59,11 +58,6 @@ pub fn run_context() -> RunContext {
RUN_CONTEXT.clone().expect("RIVET_RUN_CONTEXT")
}

// Cluster id for provisioning servers
pub fn default_cluster_id() -> Uuid {
Uuid::nil()
}

/// The namespace this service is running in. This is derived from the `NAMESPACE` environment
/// variable.
pub fn namespace() -> &'static str {
Expand Down
1 change: 1 addition & 0 deletions proto/backend/cluster.proto
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ message Datacenter {

message Pool {
PoolType pool_type = 1;
// See docs on failover (/docs/packages/cluster/SERVER_PROVISIONING.md#creating-a-new-server)
repeated Hardware hardware = 2;
uint32 desired_count = 3;
uint32 max_count = 4;
Expand Down
Loading