Skip to content

Group name/version into a single distribution struct #1179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 14, 2022
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: 2 additions & 2 deletions nexus/src/app/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ impl super::Nexus {
),
volume_id: volume.id(),
url: Some(url.clone()),
distribution: params.distribution.into(),
version: params.version,
distribution: params.distribution.name.to_string(),
version: params.distribution.version,
digest: None, // not computed for URL type
block_size: db_block_size,
size: size.into(),
Expand Down
97 changes: 6 additions & 91 deletions nexus/src/external_api/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use serde::{
Deserialize, Deserializer, Serialize,
};
use std::net::IpAddr;
use std::str::FromStr;
use uuid::Uuid;

// Silos
Expand Down Expand Up @@ -617,93 +616,12 @@ pub enum ImageSource {
}

/// OS image distribution
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Distribution(String);

impl From<Distribution> for String {
fn from(distribution: Distribution) -> String {
distribution.0
}
}

impl TryFrom<String> for Distribution {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
if value.len() > 63 {
return Err(String::from(
"distribution may contain at most 63 characters",
));
}

let mut iter = value.chars();

let first = iter.next().ok_or_else(|| {
String::from("distribution requires at least one character")
})?;
if !first.is_ascii_lowercase() {
return Err(String::from(
"distribution must begin with an ASCII lowercase character",
));
}

let mut last = first;
for c in iter {
last = c;

if !c.is_ascii_lowercase() && !c.is_digit(10) && c != '-' {
return Err(format!(
"distribution contains invalid character: \"{}\" (allowed \
characters are lowercase ASCII, digits, and \"-\")",
c
));
}
}

if last == '-' {
return Err(String::from("distribution cannot end with \"-\""));
}

Ok(Distribution(value))
}
}

impl FromStr for Distribution {
type Err = String;
fn from_str(value: &str) -> Result<Self, String> {
Distribution::try_from(String::from(value))
}
}

impl JsonSchema for Distribution {
fn schema_name() -> String {
"Distribution".to_string()
}

fn json_schema(
_gen: &mut schemars::gen::SchemaGenerator,
) -> schemars::schema::Schema {
schemars::schema::Schema::Object(schemars::schema::SchemaObject {
metadata: Some(Box::new(schemars::schema::Metadata {
title: Some("OS image distribution".to_string()),
description: Some(
"Distribution must begin with a lower case ASCII letter, be \
composed exclusively of lowercase ASCII, uppercase \
ASCII, numbers, and '-', and may not end with a '-'."
.to_string(),
),
..Default::default()
})),
instance_type: Some(schemars::schema::SingleOrVec::Single(
Box::new(schemars::schema::InstanceType::String),
)),
string: Some(Box::new(schemars::schema::StringValidation {
max_length: Some(63),
min_length: None,
pattern: Some("[a-z](|[a-zA-Z0-9-]*[a-zA-Z0-9])".to_string()),
})),
..Default::default()
})
}
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
pub struct Distribution {
/// The name of the distribution (e.g. "alpine" or "ubuntu")
pub name: Name,
/// The version of the distribution (e.g. "3.10" or "18.04")
pub version: String,
}

/// Create-time parameters for an
Expand All @@ -717,9 +635,6 @@ pub struct GlobalImageCreate {
/// OS image distribution
pub distribution: Distribution,

/// image version
pub version: String,

/// block size in bytes
pub block_size: BlockSize,

Expand Down
6 changes: 4 additions & 2 deletions nexus/tests/integration_tests/endpoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,10 @@ lazy_static! {
description: String::from(""),
},
source: params::ImageSource::Url { url: HTTP_SERVER.url("/image.raw").to_string() },
distribution: params::Distribution::try_from(String::from("alpine")).unwrap(),
version: String::from("edge"),
distribution: params::Distribution {
name: "alpine".parse().unwrap(),
version: String::from("edge"),
},
block_size: params::BlockSize::try_from(4096).unwrap(),
};

Expand Down
42 changes: 28 additions & 14 deletions nexus/tests/integration_tests/images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,10 @@ async fn test_global_image_create(cptestctx: &ControlPlaneTestContext) {
source: params::ImageSource::Url {
url: server.url("/image.raw").to_string(),
},
distribution: "alpine".parse().unwrap(),
version: "edge".into(),
distribution: params::Distribution {
name: "alpine".parse().unwrap(),
version: "edge".into(),
},
block_size: params::BlockSize::try_from(512).unwrap(),
};

Expand Down Expand Up @@ -102,8 +104,10 @@ async fn test_global_image_create_url_404(cptestctx: &ControlPlaneTestContext) {
source: params::ImageSource::Url {
url: server.url("/image.raw").to_string(),
},
distribution: "alpine".parse().unwrap(),
version: "edge".into(),
distribution: params::Distribution {
name: "alpine".parse().unwrap(),
version: "edge".into(),
},
block_size: params::BlockSize::try_from(512).unwrap(),
};

Expand Down Expand Up @@ -137,8 +141,10 @@ async fn test_global_image_create_bad_url(cptestctx: &ControlPlaneTestContext) {
),
},
source: params::ImageSource::Url { url: "not_a_url".to_string() },
distribution: "alpine".parse().unwrap(),
version: "edge".into(),
distribution: params::Distribution {
name: "alpine".parse().unwrap(),
version: "edge".into(),
},
block_size: params::BlockSize::try_from(512).unwrap(),
};

Expand Down Expand Up @@ -185,8 +191,10 @@ async fn test_global_image_create_bad_content_length(
source: params::ImageSource::Url {
url: server.url("/image.raw").to_string(),
},
distribution: "alpine".parse().unwrap(),
version: "edge".into(),
distribution: params::Distribution {
name: "alpine".parse().unwrap(),
version: "edge".into(),
},
block_size: params::BlockSize::try_from(512).unwrap(),
};

Expand Down Expand Up @@ -234,8 +242,10 @@ async fn test_global_image_create_bad_image_size(
source: params::ImageSource::Url {
url: server.url("/image.raw").to_string(),
},
distribution: "alpine".parse().unwrap(),
version: "edge".into(),
distribution: params::Distribution {
name: "alpine".parse().unwrap(),
version: "edge".into(),
},
block_size: params::BlockSize::try_from(512).unwrap(),
};

Expand Down Expand Up @@ -283,8 +293,10 @@ async fn test_make_disk_from_global_image(cptestctx: &ControlPlaneTestContext) {
source: params::ImageSource::Url {
url: server.url("/alpine/edge.raw").to_string(),
},
distribution: "alpine".parse().unwrap(),
version: "edge".into(),
distribution: params::Distribution {
name: "alpine".parse().unwrap(),
version: "edge".into(),
},
block_size: params::BlockSize::try_from(512).unwrap(),
};

Expand Down Expand Up @@ -351,8 +363,10 @@ async fn test_make_disk_from_global_image_too_small(
source: params::ImageSource::Url {
url: server.url("/alpine/edge.raw").to_string(),
},
distribution: "alpine".parse().unwrap(),
version: "edge".into(),
distribution: params::Distribution {
name: "alpine".parse().unwrap(),
version: "edge".into(),
},
block_size: params::BlockSize::try_from(512).unwrap(),
};

Expand Down
32 changes: 21 additions & 11 deletions openapi/nexus.json
Original file line number Diff line number Diff line change
Expand Up @@ -5920,11 +5920,26 @@
]
},
"Distribution": {
"title": "OS image distribution",
"description": "Distribution must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'.",
"type": "string",
"pattern": "[a-z](|[a-zA-Z0-9-]*[a-zA-Z0-9])",
"maxLength": 63
"description": "OS image distribution",
"type": "object",
"properties": {
"name": {
"description": "The name of the distribution (e.g. \"alpine\" or \"ubuntu\")",
"allOf": [
{
"$ref": "#/components/schemas/Name"
}
]
},
"version": {
"description": "The version of the distribution (e.g. \"3.10\" or \"18.04\")",
"type": "string"
}
},
"required": [
"name",
"version"
]
},
"Error": {
"description": "Error information from a response.",
Expand Down Expand Up @@ -6144,19 +6159,14 @@
"$ref": "#/components/schemas/ImageSource"
}
]
},
"version": {
"description": "image version",
"type": "string"
}
},
"required": [
"block_size",
"description",
"distribution",
"name",
"source",
"version"
"source"
]
},
"GlobalImageResultsPage": {
Expand Down