From 72dfdfa0dfc2e668c061b1e08af4b3643323f076 Mon Sep 17 00:00:00 2001 From: Ryan Goodfellow Date: Mon, 2 Oct 2023 10:28:05 -0700 Subject: [PATCH] use mgd port settings apply bgp -> no-bgp -> bgp now working! --- .../src/db/datastore/switch_port.rs | 14 +- .../app/sagas/switch_port_settings_apply.rs | 191 +++++++++++------- package-manifest.toml | 8 +- tools/maghemite_ddm_openapi_version | 2 +- tools/maghemite_mg_openapi_version | 4 +- tools/maghemite_mgd_checksums | 4 +- 6 files changed, 132 insertions(+), 91 deletions(-) diff --git a/nexus/db-queries/src/db/datastore/switch_port.rs b/nexus/db-queries/src/db/datastore/switch_port.rs index f116511dac9..852fafa8e8d 100644 --- a/nexus/db-queries/src/db/datastore/switch_port.rs +++ b/nexus/db-queries/src/db/datastore/switch_port.rs @@ -606,20 +606,22 @@ impl DataStore { self as address_config, dsl as address_config_dsl, }; - let ps = diesel::delete( + let port_settings_addrs = diesel::delete( address_config_dsl::switch_port_settings_address_config, ) .filter(address_config::port_settings_id.eq(id)) .returning(SwitchPortAddressConfig::as_returning()) - .get_result_async(&conn) + .get_results_async(&conn) .await?; use db::schema::address_lot_rsvd_block::dsl as rsvd_block_dsl; - diesel::delete(rsvd_block_dsl::address_lot_rsvd_block) - .filter(rsvd_block_dsl::id.eq(ps.rsvd_address_lot_block_id)) - .execute_async(&conn) - .await?; + for ps in &port_settings_addrs { + diesel::delete(rsvd_block_dsl::address_lot_rsvd_block) + .filter(rsvd_block_dsl::id.eq(ps.rsvd_address_lot_block_id)) + .execute_async(&conn) + .await?; + } Ok(()) }) diff --git a/nexus/src/app/sagas/switch_port_settings_apply.rs b/nexus/src/app/sagas/switch_port_settings_apply.rs index f3df28bdff9..4ed41e8817b 100644 --- a/nexus/src/app/sagas/switch_port_settings_apply.rs +++ b/nexus/src/app/sagas/switch_port_settings_apply.rs @@ -17,11 +17,14 @@ use dpd_client::types::{ use dpd_client::{Ipv4Cidr, Ipv6Cidr}; use internal_dns::ServiceName; use ipnetwork::IpNetwork; +use mg_admin_client::types::{ApplyRequest, BgpPeerConfig, BgpRoute}; use nexus_db_queries::db::datastore::UpdatePrecondition; use nexus_db_queries::{authn, db}; use nexus_types::external_api::params; use omicron_common::api::external::{self, NameOrId}; -use omicron_common::api::internal::shared::SwitchLocation; +use omicron_common::api::internal::shared::{ + ParseSwitchLocationError, SwitchLocation, +}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::net::IpAddr; @@ -105,10 +108,10 @@ async fn spa_associate_switch_port( ); // first get the current association so we fall back to this on failure - let port = nexus - .get_switch_port(&opctx, params.switch_port_id) - .await - .map_err(ActionError::action_failed)?; + let port = + nexus.get_switch_port(&opctx, params.switch_port_id).await.map_err( + |e| ActionError::action_failed(format!("get switch port: {e}")), + )?; // update the switch port settings association nexus @@ -119,7 +122,11 @@ async fn spa_associate_switch_port( UpdatePrecondition::DontCare, ) .await - .map_err(ActionError::action_failed)?; + .map_err(|e| { + ActionError::action_failed(format!( + "set switch port settings id {e}" + )) + })?; Ok(port.port_settings_id) } @@ -141,7 +148,9 @@ async fn spa_get_switch_port_settings( &NameOrId::Id(params.switch_port_settings_id), ) .await - .map_err(ActionError::action_failed)?; + .map_err(|e| { + ActionError::action_failed(format!("get switch port settings: {e}")) + })?; Ok(port_settings) } @@ -228,20 +237,28 @@ async fn spa_ensure_switch_port_settings( let settings = sagactx .lookup::("switch_port_settings")?; - let port_id: PortId = PortId::from_str(¶ms.switch_port_name) - .map_err(|e| ActionError::action_failed(e.to_string()))?; + let port_id: PortId = + PortId::from_str(¶ms.switch_port_name).map_err(|e| { + ActionError::action_failed(format!("parse port id: {e}")) + })?; let dpd_client: Arc = select_dendrite_client(&sagactx).await?; - let dpd_port_settings = api_to_dpd_port_settings(&settings) - .map_err(ActionError::action_failed)?; + let dpd_port_settings = + api_to_dpd_port_settings(&settings).map_err(|e| { + ActionError::action_failed(format!( + "translate api port settings to dpd port settings: {e}", + )) + })?; retry_until_known_result(log, || async { dpd_client.port_settings_apply(&port_id, &dpd_port_settings).await }) .await - .map_err(|e| ActionError::action_failed(e.to_string()))?; + .map_err(|e| { + ActionError::action_failed(format!("dpd port settings apply {e}")) + })?; Ok(()) } @@ -284,10 +301,16 @@ async fn spa_undo_ensure_switch_port_settings( let settings = nexus .switch_port_settings_get(&opctx, &NameOrId::Id(id)) .await - .map_err(ActionError::action_failed)?; + .map_err(|e| { + ActionError::action_failed(format!("switch port settings get: {e}")) + })?; - let dpd_port_settings = api_to_dpd_port_settings(&settings) - .map_err(ActionError::action_failed)?; + let dpd_port_settings = + api_to_dpd_port_settings(&settings).map_err(|e| { + ActionError::action_failed(format!( + "translate api to dpd port settings {e}" + )) + })?; retry_until_known_result(log, || async { dpd_client.port_settings_apply(&port_id, &dpd_port_settings).await @@ -301,9 +324,7 @@ async fn spa_undo_ensure_switch_port_settings( async fn spa_ensure_switch_port_bgp_settings( sagactx: NexusActionContext, ) -> Result<(), ActionError> { - use mg_admin_client::types::{ - AddNeighborRequest, NewRouterRequest, Originate4Request, Prefix4, - }; + use mg_admin_client::types::Prefix4; let osagactx = sagactx.user_data(); let nexus = osagactx.nexus(); @@ -326,6 +347,8 @@ async fn spa_ensure_switch_port_bgp_settings( ActionError::action_failed(format!("select mg client: {e}")) })?; + let mut bgp_peer_configs = Vec::new(); + for peer in settings.bgp_peers { let config = nexus .bgp_config_get(&opctx, peer.bgp_config_id.into()) @@ -364,36 +387,6 @@ async fn spa_ensure_switch_port_bgp_settings( )), }?; - mg_client - .inner - .ensure_router(&NewRouterRequest { - asn: *config.asn, - id: u32::from(nexthop), - listen: "0.0.0.0:179".into(), //TODO(ry)(hardcode) - }) - .await - .map_err(|e| { - ActionError::action_failed(format!("ensure router: {e}")) - })?; - - mg_client - .inner - .ensure_neighbor(&AddNeighborRequest { - asn: *config.asn, - name: format!("{}", peer.addr.ip()), //TODO(ry)(user defined name) - host: format!("{}:179", peer.addr.ip()), - hold_time: 6, //TODO(ry)(hardocde) - idle_hold_time: 6, //TODO(ry)(hardocde) - delay_open: 0, //TODO(ry)(hardocde) - connect_retry: 0, //TODO(ry)(hardcode) - keepalive: 3, //TODO(ry)(hardcode) - resolution: 100, //TODO(ry)(hardcode) - }) - .await - .map_err(|e| { - ActionError::action_failed(format!("ensure neighbor: {e}")) - })?; - let mut prefixes = Vec::new(); for a in &announcements { let value = match a.network.ip() { @@ -405,19 +398,33 @@ async fn spa_ensure_switch_port_bgp_settings( prefixes.push(Prefix4 { value, length: a.network.prefix() }); } - mg_client - .inner - .originate4(&Originate4Request { - asn: *config.asn, - nexthop: nexthop, - prefixes: prefixes, - }) - .await - .map_err(|e| { - ActionError::action_failed(format!("bgp originate: {e}")) - })?; + let bpc = BgpPeerConfig { + asn: *config.asn, + name: format!("{}", peer.addr.ip()), //TODO(ry)(user defined name) + host: format!("{}:179", peer.addr.ip()), + hold_time: 6, //TODO(ry)(hardocde) + idle_hold_time: 6, //TODO(ry)(hardocde) + delay_open: 0, //TODO(ry)(hardocde) + connect_retry: 0, //TODO(ry)(hardcode) + keepalive: 3, //TODO(ry)(hardcode) + resolution: 100, //TODO(ry)(hardcode) + routes: vec![BgpRoute { nexthop, prefixes }], + }; + + bgp_peer_configs.push(bpc); } + mg_client + .inner + .bgp_apply(&ApplyRequest { + peer_group: params.switch_port_name.clone(), + peers: bgp_peer_configs, + }) + .await + .map_err(|e| { + ActionError::action_failed(format!("apply bgp settings: {e}")) + })?; + Ok(()) } async fn spa_undo_ensure_switch_port_bgp_settings( @@ -493,13 +500,20 @@ async fn spa_ensure_switch_port_uplink( let switch_port = nexus .get_switch_port(&opctx, params.switch_port_id) .await - .map_err(ActionError::action_failed)?; + .map_err(|e| { + ActionError::action_failed(format!( + "get switch port for uplink: {e}" + )) + })?; let switch_location: SwitchLocation = - switch_port - .switch_location - .parse() - .map_err(ActionError::action_failed)?; + switch_port.switch_location.parse().map_err( + |e: ParseSwitchLocationError| { + ActionError::action_failed(format!( + "get switch location for uplink: {e:?}", + )) + }, + )?; let sled_agent_addr = get_scrimlet_address(switch_location, nexus).await?; @@ -572,7 +586,11 @@ async fn spa_disassociate_switch_port( UpdatePrecondition::Value(params.switch_port_settings_id), ) .await - .map_err(ActionError::action_failed)?; + .map_err(|e| { + ActionError::action_failed(format!( + "set switch port settings id for disassociate: {e}" + )) + })?; Ok(()) } @@ -591,12 +609,21 @@ pub(crate) async fn select_dendrite_client( let switch_port = nexus .get_switch_port(&opctx, params.switch_port_id) .await - .map_err(ActionError::action_failed)?; + .map_err(|e| { + ActionError::action_failed(format!( + "get switch port for dendrite client selection {e}" + )) + })?; + let switch_location: SwitchLocation = - switch_port - .switch_location - .parse() - .map_err(ActionError::action_failed)?; + switch_port.switch_location.parse().map_err( + |e: ParseSwitchLocationError| { + ActionError::action_failed(format!( + "get switch location for uplink: {e:?}", + )) + }, + )?; + let dpd_client: Arc = osagactx .nexus() .dpd_clients @@ -624,12 +651,20 @@ pub(crate) async fn select_mg_client( let switch_port = nexus .get_switch_port(&opctx, params.switch_port_id) .await - .map_err(ActionError::action_failed)?; + .map_err(|e| { + ActionError::action_failed(format!( + "get switch port for mg client selection: {e}" + )) + })?; + let switch_location: SwitchLocation = - switch_port - .switch_location - .parse() - .map_err(ActionError::action_failed)?; + switch_port.switch_location.parse().map_err( + |e: ParseSwitchLocationError| { + ActionError::action_failed(format!( + "get switch location for uplink: {e:?}", + )) + }, + )?; let mg_client: Arc = osagactx .nexus() @@ -654,5 +689,9 @@ pub(crate) async fn get_scrimlet_address( .lookup_socket_v6(ServiceName::Scrimlet(location)) .await .map_err(|e| e.to_string()) - .map_err(ActionError::action_failed) + .map_err(|e| { + ActionError::action_failed(format!( + "scrimlet dns lookup failed {e}", + )) + }) } diff --git a/package-manifest.toml b/package-manifest.toml index 46c83c3dc57..0d2910e7e8a 100644 --- a/package-manifest.toml +++ b/package-manifest.toml @@ -415,7 +415,7 @@ source.repo = "maghemite" # `tools/maghemite_openapi_version`. Failing to do so will cause a failure when # building `ddm-admin-client` (which will instruct you to update # `tools/maghemite_openapi_version`). -source.commit = "d3bfea788b26ed7a5e609236d28433463adf8c37" +source.commit = "f1813a2a07a9857f862daeed2bebe51060734c69" # The SHA256 digest is automatically posted to: # https://buildomat.eng.oxide.computer/public/file/oxidecomputer/maghemite/image//maghemite.sha256.txt source.sha256 = "5a61c753d744621f02e4e4c0c32030545fd3f28ef72fd69f8d11fa1703e94755" @@ -431,7 +431,7 @@ source.repo = "maghemite" # `tools/maghemite_openapi_version`. Failing to do so will cause a failure when # building `ddm-admin-client` (which will instruct you to update # `tools/maghemite_openapi_version`). -source.commit = "d3bfea788b26ed7a5e609236d28433463adf8c37" +source.commit = "f1813a2a07a9857f862daeed2bebe51060734c69" # The SHA256 digest is automatically posted to: # https://buildomat.eng.oxide.computer/public/file/oxidecomputer/maghemite/image//mg-ddm.sha256.txt source.sha256 = "7c84a4ae14f561b17a61bcf96049d16c5c4ff2a023875e16128c24b493e09950" @@ -446,10 +446,10 @@ source.repo = "maghemite" # `tools/maghemite_openapi_version`. Failing to do so will cause a failure when # building `ddm-admin-client` (which will instruct you to update # `tools/maghemite_openapi_version`). -source.commit = "d3bfea788b26ed7a5e609236d28433463adf8c37" +source.commit = "f1813a2a07a9857f862daeed2bebe51060734c69" # The SHA256 digest is automatically posted to: # https://buildomat.eng.oxide.computer/public/file/oxidecomputer/maghemite/image//mg-ddm.sha256.txt -source.sha256 = "bc9da61e25e12b2c12966ba07e8932f471c5743d466d3d689f01abb47fbac384" +source.sha256 = "212c7d09958d8578dc1f6b5556e1d0dbfbbcc542aced90051195b25a4b20905e" output.type = "zone" output.intermediate_only = true diff --git a/tools/maghemite_ddm_openapi_version b/tools/maghemite_ddm_openapi_version index b5827103074..d1a6c7ad95c 100644 --- a/tools/maghemite_ddm_openapi_version +++ b/tools/maghemite_ddm_openapi_version @@ -1,2 +1,2 @@ -COMMIT="d3bfea788b26ed7a5e609236d28433463adf8c37" +COMMIT="f1813a2a07a9857f862daeed2bebe51060734c69" SHA2="9737906555a60911636532f00f1dc2866dc7cd6553beb106e9e57beabad41cdf" diff --git a/tools/maghemite_mg_openapi_version b/tools/maghemite_mg_openapi_version index 6d023ca8d5e..1e13f8c5501 100644 --- a/tools/maghemite_mg_openapi_version +++ b/tools/maghemite_mg_openapi_version @@ -1,2 +1,2 @@ -COMMIT="d3bfea788b26ed7a5e609236d28433463adf8c37" -SHA2="127ee63e85fbb8cec220976c82fb278b11c2c0a49eec2b136699092c257b8c27" +COMMIT="f1813a2a07a9857f862daeed2bebe51060734c69" +SHA2="5588abe9b0d206014b7e28739f81b2a1a683e19ddbb3265bb7eae7adbd11e2d5" diff --git a/tools/maghemite_mgd_checksums b/tools/maghemite_mgd_checksums index 613fb1f69ce..2fefd55292e 100644 --- a/tools/maghemite_mgd_checksums +++ b/tools/maghemite_mgd_checksums @@ -1,2 +1,2 @@ -CIDL_SHA256="bc9da61e25e12b2c12966ba07e8932f471c5743d466d3d689f01abb47fbac384" -MGD_LINUX_SHA256="345707d338f6619d70733851477076f65b5bbc108045c48036e46adc3c339472" +CIDL_SHA256="212c7d09958d8578dc1f6b5556e1d0dbfbbcc542aced90051195b25a4b20905e" +MGD_LINUX_SHA256="e77660ceb8c239d0d6f8d5614d40a5ef1e03df8503f12e2de3298f121e422d68"