use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
pub use v20201231::Job;
pub use v20201231::JobStatus;
pub use v20201231::JobStatusValue;
pub use v20201231::QueryParams;
pub use v20201231::Snapshot;
pub use v20201231::Status;
pub use v20201231::StatusValue;
pub use v20201231::AwsReplicaCreateRealm;
pub use v20201231::AzureReplicaCreateRealm;
pub use v20201231::ReplicaCreateRealm;
pub use v20201231::AwsReplicaCreate;
pub use v20201231::AzureReplicaCreate;
pub use v20201231::SnapshotCreate;
pub use v20201231::AwsSnapshotExport;
pub use v20201231::SnapshotExport;
pub use v20201231::VendorSnapshotExport;
pub use v20201231::AwsSnapshotExportCreate;
pub use v20201231::SnapshotExportCreate;
pub use v20201231::AwsSnapshot;
pub use v20201231::Realm;
pub use v20201231::RealmCreate;
pub use v20201231::RealmType;
pub use v20201231::RealmTypeCreate;
pub use v20201231::Realms;
pub use v20201231::Version as InternalVersion;
use crate::v20201231;
mod convert;
pub const VERSION: &str = "2021-02-28";
pub static AWS_SUPPORTED_REGIONS: &[&str] = &[
"ap-northeast-1",
"ap-northeast-2",
"ap-south-1",
"ap-southeast-1",
"ap-southeast-2",
"ca-central-1",
"eu-central-1",
"eu-north-1",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"sa-east-1",
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2",
];
pub static AZURE_SUPPORTED_REGIONS: &[&str] = &[
"centralus",
"eastus",
"eastus2",
"francecentral",
"japaneast",
"northeurope",
"southeastasia",
"uksouth",
"westeurope",
"westus2",
];
#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct VolumeCreate {
pub id: Option<Uuid>,
pub name: String,
pub size_gb: Option<u64>,
pub description: Option<String>,
pub replicas: Vec<ReplicaCreate>,
pub source: Option<VolumeSourceCreate>,
}
#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct VolumeCreateExt {
pub id: Option<Uuid>,
pub name: String,
pub size_gb: Option<u64>,
pub description: Option<String>,
pub replicas: Vec<ReplicaCreateExt>,
pub source: Option<VolumeSourceExt>,
}
impl From<ReplicaCreate> for ReplicaCreateExt {
fn from(create: ReplicaCreate) -> Self {
let ReplicaCreate {
name,
description,
realm,
primary,
} = create;
Self {
name,
description,
realm,
primary,
private_link: None,
snapshots: vec![],
}
}
}
impl From<ReplicaCreateExt> for ReplicaCreate {
fn from(create: ReplicaCreateExt) -> Self {
let ReplicaCreateExt {
name,
description,
realm,
primary,
..
} = create;
Self {
name,
description,
realm,
primary,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct PrivateLinkNlb {
pub private_link_endpoint_id: String,
pub vendor_nlb: VendorPrivateLinkNlb,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum VendorPrivateLinkNlb {
Aws(AwsPrivateLink),
Azure(AzurePrivateLink),
}
impl Default for VendorPrivateLinkNlb {
fn default() -> Self {
Self::Aws(AwsPrivateLink::default())
}
}
#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct AwsPrivateLink {
pub service_id: String,
pub subnet: String,
pub vpc: String,
pub target_group: String,
#[serde(default)]
pub resources: Vec<String>,
}
#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct AzurePrivateLink {
pub service_id: String,
pub backend_subnet_id: String,
pub loadbalancer_id: String,
#[serde(default)]
pub resources: Vec<String>,
}
#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct ReplicaCreateExt {
#[serde(default)]
pub name: String,
#[serde(default)]
pub description: Option<String>,
#[serde(flatten)]
pub realm: ReplicaCreateRealm,
#[serde(default)]
pub primary: bool,
#[serde(default)]
pub private_link: Option<PrivateLinkNlb>,
#[serde(default)]
pub snapshots: Vec<SnapshotExt>,
}
#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct ReplicaCreate {
#[serde(default)]
pub name: String,
#[serde(default)]
pub description: Option<String>,
#[serde(flatten)]
pub realm: ReplicaCreateRealm,
#[serde(default)]
pub primary: bool,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum VolumeSourceCreate {
AwsSnapshot(AwsSnapshot),
AzureSnapshot(AzureSnapshotCreate),
Snapshot(ServiceSnapshot),
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct ServiceSnapshot {
pub volume: String,
pub snapshot_name: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct AzureSnapshotCreate {
url: String,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum VolumeSource {
AwsSnapshot(AwsSnapshot),
AzureSnapshot(AzureSnapshot),
Snapshot(ServiceSnapshot),
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub struct AzureSnapshot;
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum VolumeSourceExt {
AwsSnapshot(AwsSnapshot),
NativeDevices(HashMap<String, Option<String>>),
AzureUrl(String),
Snapshot(ServiceSnapshot),
}
impl From<VolumeSourceCreate> for VolumeSourceExt {
fn from(volume_source: VolumeSourceCreate) -> Self {
match volume_source {
VolumeSourceCreate::AwsSnapshot(snapshot) => Self::AwsSnapshot(snapshot),
VolumeSourceCreate::AzureSnapshot(AzureSnapshotCreate { url }) => Self::AzureUrl(url),
VolumeSourceCreate::Snapshot(snapshot) => Self::Snapshot(snapshot),
}
}
}
#[derive(Default, Clone, Debug, Deserialize, Serialize)]
pub struct Volume {
pub name: String,
pub id: Uuid,
pub description: String,
pub size_gb: u64,
pub source: Option<VolumeSource>,
pub replicas: Vec<Replica>,
pub iqn: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub job: Option<Uuid>,
pub created: Option<DateTime<Utc>>,
pub modified: Option<DateTime<Utc>>,
pub status: Status,
}
#[derive(Default, Clone, Debug, Deserialize, Serialize)]
pub struct Replica {
#[serde(default)]
pub name: String,
pub description: String,
#[serde(flatten)]
pub realm: ReplicaRealm,
#[serde(default)]
pub primary: bool,
pub iscsi_portal: Option<String>,
#[serde(default)]
pub status: Status,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum ReplicaRealm {
Aws {
realm: String,
region: String,
subnet: String,
},
Azure {
realm: String,
resource_group: String,
subnet: String,
region: String,
},
}
impl Default for ReplicaRealm {
fn default() -> Self {
Self::Aws {
realm: String::default(),
region: String::default(),
subnet: String::default(),
}
}
}
#[derive(Default, Clone, Debug, Deserialize, Serialize)]
pub struct VolumeExt {
pub name: String,
pub id: Uuid,
pub description: String,
pub size_gb: u64,
pub iops: u64,
pub source: Option<VolumeSource>,
pub replicas: Vec<ReplicaExt>,
pub iqn: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub job: Option<Uuid>,
pub created: Option<DateTime<Utc>>,
pub modified: Option<DateTime<Utc>>,
pub status: Status,
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct SnapshotExt {
#[serde(flatten)]
pub snapshot: Snapshot,
pub vendor: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ReplicaExt {
#[serde(flatten)]
pub replica: Replica,
pub snapshots: Vec<SnapshotExt>,
pub private_link: Option<PrivateLinkNlb>,
}
pub type NodeId = String;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct VolumeNode {
pub upstream: Option<NodeId>,
pub downstream: Vec<NodeId>,
pub ip_address: Option<String>,
pub realm: ReplicaRealm,
pub replica: String,
}
#[derive(Default, Clone, Debug, Deserialize, Serialize)]
pub struct VolumeTopology {
pub id: Uuid,
pub primary: Option<NodeId>,
pub nodes: HashMap<NodeId, VolumeNode>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct JobAccepted {
pub job_id: Uuid,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Error {
pub http_code: u16,
pub http_status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<serde_json::Value>,
pub message: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum WsEvent {
Job(Job),
Volume(Volume),
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Version {
pub api: ApiVersion,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ApiVersion {
pub latest: String,
pub supported: Vec<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn show_volume_create_aws_2() {
let volume_aws_x2 = VolumeCreate {
id: None,
name: "volume-aws-x2".into(),
description: None,
size_gb: None,
replicas: vec![
ReplicaCreate {
name: "west".into(),
description: Some("westside".into()),
primary: true,
realm: ReplicaCreateRealm::Aws(AwsReplicaCreateRealm {
realm: "aws".into(),
region: "us-west-2".into(),
subnet: "subnet-00a719b41a68a3beb".into(),
}),
},
ReplicaCreate {
name: "east".into(),
description: Some("westside".into()),
primary: true,
realm: ReplicaCreateRealm::Aws(AwsReplicaCreateRealm {
realm: "aws".into(),
region: "us-east-2".into(),
subnet: "subnet-0ce209ae7321ec243".into(),
}),
},
],
source: Some(VolumeSourceCreate::AwsSnapshot(AwsSnapshot {
id: "snap-0d99a968836a36ed3".into(),
realm: "aws".into(),
region: "us-west-2".into(),
})),
};
let volume_aws_x2 = serde_json::to_string_pretty(&volume_aws_x2).unwrap();
println!("{}", volume_aws_x2);
}
#[test]
fn show_volume_create_azure_2() {
let volume_azure_x2 = VolumeCreate {
id: None,
name: "volume-azure-x2".into(),
description: None,
size_gb: Some(103u64),
replicas: vec![
ReplicaCreate {
name: "west".into(),
description: Some("westside".into()),
primary: true,
realm: ReplicaCreateRealm::Azure(AzureReplicaCreateRealm {
realm: "azure".into(),
resource_group: "resource_group".into(),
subnet: "subnet-00a719b41a68a3beb".into(),
}),
},
ReplicaCreate {
name: "east".into(),
description: Some("westside".into()),
primary: true,
realm: ReplicaCreateRealm::Azure(AzureReplicaCreateRealm {
realm: "azure".into(),
resource_group: "resource_group".into(),
subnet: "subnet-0ce209ae7321ec243".into(),
}),
},
],
source: Some(VolumeSourceCreate::AzureSnapshot(AzureSnapshotCreate {
url: "https://md-pxpcl3qrnbv1.blob.core.windows.net/\
w3h2z300djwc/abcd?sv=2018-03-28&sr=b&si=ca4e4b21-d73b-4a7c-805e-6ab1abb6817e\
&sig=fsel0fc8nZIOBi2326WIXC1qhqvrq%2Fo7xqqEnEgGrDk%3D"
.into(),
})),
};
let volume_azure_x2 = serde_json::to_string_pretty(&volume_azure_x2).unwrap();
println!("{}", volume_azure_x2);
}
#[test]
fn show_volume_create_aws_ext_2() {
let volume_aws_x2 = VolumeCreateExt {
id: None,
name: "volume-aws-x2".into(),
description: None,
size_gb: None,
replicas: vec![
ReplicaCreateExt {
name: "west".into(),
description: Some("westside".into()),
primary: true,
realm: ReplicaCreateRealm::Aws(AwsReplicaCreateRealm {
realm: "aws".into(),
region: "us-west-2".into(),
subnet: "subnet-00a719b41a68a3beb".into(),
}),
private_link: Some(PrivateLinkNlb {
private_link_endpoint_id: "private_link_endpoint_id_a".into(),
vendor_nlb: VendorPrivateLinkNlb::Aws(AwsPrivateLink {
service_id: "service_a".into(),
subnet: "subnet_a".into(),
vpc: "vpc_a".into(),
target_group: "target_group_a".into(),
resources: vec!["stack_a".into()],
}),
}),
snapshots: vec![],
},
ReplicaCreateExt {
name: "east".into(),
description: Some("westside".into()),
primary: true,
realm: ReplicaCreateRealm::Aws(AwsReplicaCreateRealm {
realm: "aws".into(),
region: "us-east-2".into(),
subnet: "subnet-0ce209ae7321ec243".into(),
}),
private_link: Some(PrivateLinkNlb {
private_link_endpoint_id: "private_link_endpoint_id_b".into(),
vendor_nlb: VendorPrivateLinkNlb::Aws(AwsPrivateLink {
service_id: "service_b".into(),
subnet: "subnet_b".into(),
vpc: "vpc_b".into(),
target_group: "target_group_b".into(),
resources: vec!["stack_b".into()],
}),
}),
snapshots: vec![],
},
],
source: Some(VolumeSourceExt::NativeDevices(
[("west", Some("east-device")), ("east", Some("east-device"))]
.iter()
.map(|(name, dev)| ((*name).to_owned(), dev.map(<_>::to_owned)))
.collect(),
)),
};
let volume_aws_x2 = serde_json::to_string_pretty(&volume_aws_x2).unwrap();
println!("{}", volume_aws_x2);
}
#[test]
fn show_volume_create_azure_ext_2() {
let volume_azure_x2 = VolumeCreateExt {
id: None,
name: "volume-azure-x2".into(),
description: None,
size_gb: Some(103u64),
replicas: vec![
ReplicaCreateExt {
name: "west".into(),
description: Some("westside".into()),
primary: true,
realm: ReplicaCreateRealm::Azure(AzureReplicaCreateRealm {
realm: "azure".into(),
resource_group: "resource_group".into(),
subnet: "subnet-00a719b41a68a3beb".into(),
}),
private_link: Some(PrivateLinkNlb {
private_link_endpoint_id: "private_link_endpoint_id_b".into(),
vendor_nlb: VendorPrivateLinkNlb::Azure(AzurePrivateLink {
service_id: "service_a".into(),
backend_subnet_id: "backend_subnet_id_a".into(),
loadbalancer_id: "loadbalancer_id_a".into(),
resources: vec!["stack_a".into()],
}),
}),
snapshots: vec![],
},
ReplicaCreateExt {
name: "east".into(),
description: Some("westside".into()),
primary: true,
realm: ReplicaCreateRealm::Azure(AzureReplicaCreateRealm {
realm: "azure".into(),
resource_group: "resource_group".into(),
subnet: "subnet-0ce209ae7321ec243".into(),
}),
private_link: Some(PrivateLinkNlb {
private_link_endpoint_id: "private_link_endpoint_id_b".into(),
vendor_nlb: VendorPrivateLinkNlb::Azure(AzurePrivateLink {
service_id: "service_b".into(),
backend_subnet_id: "backend_subnet_id_b".into(),
loadbalancer_id: "loadbalancer_id_b".into(),
resources: vec!["stack_b".into()],
}),
}),
snapshots: vec![],
},
],
source: Some(VolumeSourceExt::NativeDevices(
[("west", Some("east-device")), ("east", Some("east-device"))]
.iter()
.map(|(name, dev)| ((*name).to_owned(), dev.map(<_>::to_owned)))
.collect(),
)),
};
let volume_azure_x2 = serde_json::to_string_pretty(&volume_azure_x2).unwrap();
println!("{}", volume_azure_x2);
}
}