|
| 1 | +// This Source Code Form is subject to the terms of the Mozilla Public |
| 2 | +// License, v. 2.0. If a copy of the MPL was not distributed with this |
| 3 | +// file, You can obtain one at https://mozilla.org/MPL/2.0/. |
| 4 | + |
| 5 | +//! Types from API version 2026_03_14_00 that cannot live in `nexus-types-versions` |
| 6 | +//! because they convert to/from `omicron-common` types (orphan rule). |
| 7 | +
|
| 8 | +use api_identity::ObjectIdentity; |
| 9 | +use omicron_common::api::external; |
| 10 | +use omicron_common::api::external::Error; |
| 11 | +use omicron_common::api::external::IdentityMetadata; |
| 12 | +use omicron_common::api::external::L4PortRange; |
| 13 | +use omicron_common::api::external::Name; |
| 14 | +use omicron_common::api::external::ObjectIdentity; |
| 15 | +use omicron_common::api::external::VpcFirewallIcmpFilter; |
| 16 | +use omicron_common::api::external::VpcFirewallRuleAction; |
| 17 | +use omicron_common::api::external::VpcFirewallRuleDirection; |
| 18 | +use omicron_common::api::external::VpcFirewallRuleHostFilter; |
| 19 | +use omicron_common::api::external::VpcFirewallRulePriority; |
| 20 | +use omicron_common::api::external::VpcFirewallRuleStatus; |
| 21 | +use omicron_common::api::external::VpcFirewallRuleTarget; |
| 22 | +use schemars::JsonSchema; |
| 23 | +use serde::Deserialize; |
| 24 | +use serde::Serialize; |
| 25 | +use uuid::Uuid; |
| 26 | + |
| 27 | +/// The protocols that may be specified in a firewall rule's filter. |
| 28 | +// |
| 29 | +// This is the version of the enum without `Icmp6`, for API versions up |
| 30 | +// through `MULTICAST_DROP_MVLAN`. |
| 31 | +#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, JsonSchema)] |
| 32 | +#[serde(rename_all = "snake_case")] |
| 33 | +#[serde(tag = "type", content = "value")] |
| 34 | +pub enum VpcFirewallRuleProtocol { |
| 35 | + Tcp, |
| 36 | + Udp, |
| 37 | + Icmp(Option<VpcFirewallIcmpFilter>), |
| 38 | +} |
| 39 | + |
| 40 | +impl From<VpcFirewallRuleProtocol> for external::VpcFirewallRuleProtocol { |
| 41 | + fn from(p: VpcFirewallRuleProtocol) -> Self { |
| 42 | + match p { |
| 43 | + VpcFirewallRuleProtocol::Tcp => Self::Tcp, |
| 44 | + VpcFirewallRuleProtocol::Udp => Self::Udp, |
| 45 | + VpcFirewallRuleProtocol::Icmp(v) => Self::Icmp(v), |
| 46 | + } |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +/// Filters reduce the scope of a firewall rule. |
| 51 | +// |
| 52 | +// This is the version of the filter without `Icmp6` protocol support, for API |
| 53 | +// versions up through `MULTICAST_DROP_MVLAN`. |
| 54 | +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema)] |
| 55 | +pub struct VpcFirewallRuleFilter { |
| 56 | + /// If present, host filters match the "other end" of traffic from the |
| 57 | + /// target's perspective: for an inbound rule, they match the source of |
| 58 | + /// traffic. For an outbound rule, they match the destination. |
| 59 | + #[schemars(length(max = 256))] |
| 60 | + pub hosts: Option<Vec<VpcFirewallRuleHostFilter>>, |
| 61 | + |
| 62 | + /// If present, the networking protocols this rule applies to. |
| 63 | + #[schemars(length(max = 256))] |
| 64 | + pub protocols: Option<Vec<VpcFirewallRuleProtocol>>, |
| 65 | + |
| 66 | + /// If present, the destination ports or port ranges this rule applies to. |
| 67 | + #[schemars(length(max = 256))] |
| 68 | + pub ports: Option<Vec<L4PortRange>>, |
| 69 | +} |
| 70 | + |
| 71 | +impl TryFrom<external::VpcFirewallRuleFilter> for VpcFirewallRuleFilter { |
| 72 | + type Error = Error; |
| 73 | + |
| 74 | + fn try_from(f: external::VpcFirewallRuleFilter) -> Result<Self, Error> { |
| 75 | + let protocols = f |
| 76 | + .protocols |
| 77 | + .map(|ps| { |
| 78 | + ps.into_iter() |
| 79 | + .map(|p| match p { |
| 80 | + external::VpcFirewallRuleProtocol::Tcp => { |
| 81 | + Ok(VpcFirewallRuleProtocol::Tcp) |
| 82 | + } |
| 83 | + external::VpcFirewallRuleProtocol::Udp => { |
| 84 | + Ok(VpcFirewallRuleProtocol::Udp) |
| 85 | + } |
| 86 | + external::VpcFirewallRuleProtocol::Icmp(v) => { |
| 87 | + Ok(VpcFirewallRuleProtocol::Icmp(v)) |
| 88 | + } |
| 89 | + external::VpcFirewallRuleProtocol::Icmp6(_) => { |
| 90 | + Err(Error::invalid_value( |
| 91 | + "vpc_firewall_rule_protocol", |
| 92 | + format!("unrecognized protocol: {p}"), |
| 93 | + )) |
| 94 | + } |
| 95 | + }) |
| 96 | + .collect::<Result<Vec<_>, _>>() |
| 97 | + }) |
| 98 | + .transpose()?; |
| 99 | + Ok(Self { hosts: f.hosts, protocols, ports: f.ports }) |
| 100 | + } |
| 101 | +} |
| 102 | + |
| 103 | +impl From<VpcFirewallRuleFilter> for external::VpcFirewallRuleFilter { |
| 104 | + fn from(f: VpcFirewallRuleFilter) -> Self { |
| 105 | + Self { |
| 106 | + hosts: f.hosts, |
| 107 | + protocols: f |
| 108 | + .protocols |
| 109 | + .map(|ps| ps.into_iter().map(Into::into).collect()), |
| 110 | + ports: f.ports, |
| 111 | + } |
| 112 | + } |
| 113 | +} |
| 114 | + |
| 115 | +/// A single rule in a VPC firewall. |
| 116 | +// |
| 117 | +// This is the version of the rule without `Icmp6` protocol support, for API |
| 118 | +// versions up through `MULTICAST_DROP_MVLAN`. |
| 119 | +#[derive(ObjectIdentity, Clone, Debug, Deserialize, Serialize, JsonSchema)] |
| 120 | +pub struct VpcFirewallRule { |
| 121 | + /// Common identifying metadata |
| 122 | + #[serde(flatten)] |
| 123 | + pub identity: IdentityMetadata, |
| 124 | + /// Whether this rule is in effect |
| 125 | + pub status: VpcFirewallRuleStatus, |
| 126 | + /// Whether this rule is for incoming or outgoing traffic |
| 127 | + pub direction: VpcFirewallRuleDirection, |
| 128 | + /// Determine the set of instances that the rule applies to |
| 129 | + pub targets: Vec<VpcFirewallRuleTarget>, |
| 130 | + /// Reductions on the scope of the rule |
| 131 | + pub filters: VpcFirewallRuleFilter, |
| 132 | + /// Whether traffic matching the rule should be allowed or dropped |
| 133 | + pub action: VpcFirewallRuleAction, |
| 134 | + /// The relative priority of this rule |
| 135 | + pub priority: VpcFirewallRulePriority, |
| 136 | + /// The VPC to which this rule belongs |
| 137 | + pub vpc_id: Uuid, |
| 138 | +} |
| 139 | + |
| 140 | +impl TryFrom<external::VpcFirewallRule> for VpcFirewallRule { |
| 141 | + type Error = Error; |
| 142 | + |
| 143 | + fn try_from(r: external::VpcFirewallRule) -> Result<Self, Error> { |
| 144 | + Ok(Self { |
| 145 | + identity: r.identity, |
| 146 | + status: r.status, |
| 147 | + direction: r.direction, |
| 148 | + targets: r.targets, |
| 149 | + filters: r.filters.try_into()?, |
| 150 | + action: r.action, |
| 151 | + priority: r.priority, |
| 152 | + vpc_id: r.vpc_id, |
| 153 | + }) |
| 154 | + } |
| 155 | +} |
| 156 | + |
| 157 | +/// Collection of a VPC's firewall rules. |
| 158 | +// |
| 159 | +// This is the version of the collection without `Icmp6` protocol support, for |
| 160 | +// API versions up through `MULTICAST_DROP_MVLAN`. |
| 161 | +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] |
| 162 | +pub struct VpcFirewallRules { |
| 163 | + pub rules: Vec<VpcFirewallRule>, |
| 164 | +} |
| 165 | + |
| 166 | +impl TryFrom<external::VpcFirewallRules> for VpcFirewallRules { |
| 167 | + type Error = Error; |
| 168 | + |
| 169 | + fn try_from(r: external::VpcFirewallRules) -> Result<Self, Error> { |
| 170 | + let rules = r |
| 171 | + .rules |
| 172 | + .into_iter() |
| 173 | + .map(VpcFirewallRule::try_from) |
| 174 | + .collect::<Result<Vec<_>, _>>()?; |
| 175 | + Ok(Self { rules }) |
| 176 | + } |
| 177 | +} |
| 178 | + |
| 179 | +/// A single rule in a VPC firewall update request. |
| 180 | +// |
| 181 | +// This is the version of the update without `Icmp6` protocol support, for API |
| 182 | +// versions up through `MULTICAST_DROP_MVLAN`. |
| 183 | +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, JsonSchema)] |
| 184 | +pub struct VpcFirewallRuleUpdate { |
| 185 | + /// Name of the rule, unique to this VPC |
| 186 | + pub name: Name, |
| 187 | + /// Human-readable free-form text about a resource |
| 188 | + pub description: String, |
| 189 | + /// Whether this rule is in effect |
| 190 | + pub status: VpcFirewallRuleStatus, |
| 191 | + /// Whether this rule is for incoming or outgoing traffic |
| 192 | + pub direction: VpcFirewallRuleDirection, |
| 193 | + /// Determine the set of instances that the rule applies to |
| 194 | + #[schemars(length(max = 256))] |
| 195 | + pub targets: Vec<VpcFirewallRuleTarget>, |
| 196 | + /// Reductions on the scope of the rule |
| 197 | + pub filters: VpcFirewallRuleFilter, |
| 198 | + /// Whether traffic matching the rule should be allowed or dropped |
| 199 | + pub action: VpcFirewallRuleAction, |
| 200 | + /// The relative priority of this rule |
| 201 | + pub priority: VpcFirewallRulePriority, |
| 202 | +} |
| 203 | + |
| 204 | +impl From<VpcFirewallRuleUpdate> for external::VpcFirewallRuleUpdate { |
| 205 | + fn from(u: VpcFirewallRuleUpdate) -> Self { |
| 206 | + Self { |
| 207 | + name: u.name, |
| 208 | + description: u.description, |
| 209 | + status: u.status, |
| 210 | + direction: u.direction, |
| 211 | + targets: u.targets, |
| 212 | + filters: u.filters.into(), |
| 213 | + action: u.action, |
| 214 | + priority: u.priority, |
| 215 | + } |
| 216 | + } |
| 217 | +} |
| 218 | + |
| 219 | +/// Updated list of firewall rules. Will replace all existing rules. |
| 220 | +// |
| 221 | +// This is the version of the params without `Icmp6` protocol support, for API |
| 222 | +// versions up through `MULTICAST_DROP_MVLAN`. |
| 223 | +#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)] |
| 224 | +pub struct VpcFirewallRuleUpdateParams { |
| 225 | + #[schemars(length(max = 1024))] |
| 226 | + #[serde(default)] |
| 227 | + pub rules: Vec<VpcFirewallRuleUpdate>, |
| 228 | +} |
| 229 | + |
| 230 | +impl From<VpcFirewallRuleUpdateParams> |
| 231 | + for external::VpcFirewallRuleUpdateParams |
| 232 | +{ |
| 233 | + fn from(p: VpcFirewallRuleUpdateParams) -> Self { |
| 234 | + Self { rules: p.rules.into_iter().map(Into::into).collect() } |
| 235 | + } |
| 236 | +} |
0 commit comments