From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <pdm-devel-bounces@lists.proxmox.com> Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 8E86B1FF164 for <inbox@lore.proxmox.com>; Fri, 28 Feb 2025 16:18:43 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 5C61911EFC; Fri, 28 Feb 2025 16:18:38 +0100 (CET) From: Stefan Hanreich <s.hanreich@proxmox.com> To: pdm-devel@lists.proxmox.com Date: Fri, 28 Feb 2025 16:17:43 +0100 Message-Id: <20250228151803.158984-7-s.hanreich@proxmox.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20250228151803.158984-1-s.hanreich@proxmox.com> References: <20250228151803.158984-1-s.hanreich@proxmox.com> MIME-Version: 1.0 X-SPAM-LEVEL: Spam detection results: 0 AWL -1.380 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment KAM_LAZY_DOMAIN_SECURITY 1 Sending domain does not have any anti-forgery methods KAM_MAILER 2 Automated Mailer Tag Left in Email POISEN_SPAM_PILL 0.1 Meta: its spam POISEN_SPAM_PILL_1 0.1 random spam to be learned in bayes POISEN_SPAM_PILL_3 0.1 random spam to be learned in bayes RDNS_NONE 0.793 Delivered to internal network by a host with no rDNS SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_NONE 0.001 SPF: sender does not publish an SPF Record Subject: [pdm-devel] [PATCH proxmox-api-types 06/12] sdn: generate controller endpoints X-BeenThere: pdm-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Datacenter Manager development discussion <pdm-devel.lists.proxmox.com> List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pdm-devel>, <mailto:pdm-devel-request@lists.proxmox.com?subject=unsubscribe> List-Archive: <http://lists.proxmox.com/pipermail/pdm-devel/> List-Post: <mailto:pdm-devel@lists.proxmox.com> List-Help: <mailto:pdm-devel-request@lists.proxmox.com?subject=help> List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel>, <mailto:pdm-devel-request@lists.proxmox.com?subject=subscribe> Reply-To: Proxmox Datacenter Manager development discussion <pdm-devel@lists.proxmox.com> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: pdm-devel-bounces@lists.proxmox.com Sender: "pdm-devel" <pdm-devel-bounces@lists.proxmox.com> Signed-off-by: Stefan Hanreich <s.hanreich@proxmox.com> --- pve-api-types/src/generated/code.rs | 37 ++- pve-api-types/src/generated/types.rs | 413 +++++++++++++++++++++++++++ 2 files changed, 449 insertions(+), 1 deletion(-) diff --git a/pve-api-types/src/generated/code.rs b/pve-api-types/src/generated/code.rs index f5a993c..5283df4 100644 --- a/pve-api-types/src/generated/code.rs +++ b/pve-api-types/src/generated/code.rs @@ -109,7 +109,6 @@ /// - /cluster/replication /// - /cluster/replication/{id} /// - /cluster/sdn -/// - /cluster/sdn/controllers /// - /cluster/sdn/controllers/{controller} /// - /cluster/sdn/dns /// - /cluster/sdn/dns/{dns} @@ -399,6 +398,11 @@ pub trait PveClient { Err(Error::Other("cluster_status not implemented")) } + /// Create a new sdn controller object. + async fn create_controller(&self, params: CreateController) -> Result<(), Error> { + Err(Error::Other("create_controller not implemented")) + } + /// Generate a new API token for a specific user. NOTE: returns API token /// value, which needs to be stored as it cannot be retrieved afterwards! async fn create_token( @@ -451,6 +455,16 @@ pub trait PveClient { Err(Error::Other("get_task_status not implemented")) } + /// SDN controllers index. + async fn list_controllers( + &self, + pending: Option<bool>, + running: Option<bool>, + ty: Option<ListControllersType>, + ) -> Result<Vec<SdnController>, Error> { + Err(Error::Other("list_controllers not implemented")) + } + /// Authentication domain index. async fn list_domains(&self) -> Result<Vec<ListRealm>, Error> { Err(Error::Other("list_domains not implemented")) @@ -727,6 +741,12 @@ where Ok(self.0.get(url).await?.expect_json()?.data) } + /// Create a new sdn controller object. + async fn create_controller(&self, params: CreateController) -> Result<(), Error> { + let url = "/api2/extjs/cluster/sdn/controllers"; + self.0.post(url, ¶ms).await?.nodata() + } + /// Generate a new API token for a specific user. NOTE: returns API token /// value, which needs to be stored as it cannot be retrieved afterwards! async fn create_token( @@ -813,6 +833,21 @@ where Ok(self.0.get(url).await?.expect_json()?.data) } + /// SDN controllers index. + async fn list_controllers( + &self, + pending: Option<bool>, + running: Option<bool>, + ty: Option<ListControllersType>, + ) -> Result<Vec<SdnController>, Error> { + let (mut query, mut sep) = (String::new(), '?'); + add_query_bool(&mut query, &mut sep, "pending", pending); + add_query_bool(&mut query, &mut sep, "running", running); + add_query_arg(&mut query, &mut sep, "type", &ty); + let url = &format!("/api2/extjs/cluster/sdn/controllers{query}"); + Ok(self.0.get(url).await?.expect_json()?.data) + } + /// Authentication domain index. async fn list_domains(&self) -> Result<Vec<ListRealm>, Error> { let url = "/api2/extjs/access/domains"; diff --git a/pve-api-types/src/generated/types.rs b/pve-api-types/src/generated/types.rs index 871707a..92dc968 100644 --- a/pve-api-types/src/generated/types.rs +++ b/pve-api-types/src/generated/types.rs @@ -830,6 +830,140 @@ pub enum ClusterResourceType { serde_plain::derive_display_from_serialize!(ClusterResourceType); serde_plain::derive_fromstr_from_deserialize!(ClusterResourceType); +const_regex! { + +CREATE_CONTROLLER_CONTROLLER_RE = r##"^[a-z][a-z0-9_-]*[a-z0-9]$"##; +CREATE_CONTROLLER_ISIS_IFACES_RE = r##"^[a-zA-Z][a-zA-Z0-9_]{1,20}([:\.]\d+)?$"##; +CREATE_CONTROLLER_ISIS_NET_RE = r##"^[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\.[a-fA-F0-9]{2}$"##; +CREATE_CONTROLLER_NODE_RE = r##"^(?i:[a-z0-9](?i:[a-z0-9\-]*[a-z0-9])?)$"##; + +} + +#[api( + properties: { + asn: { + maximum: 4294967295, + minimum: 0, + optional: true, + type: Integer, + }, + "bgp-multipath-as-path-relax": { + default: false, + optional: true, + }, + controller: { + format: &ApiStringFormat::Pattern(&CREATE_CONTROLLER_CONTROLLER_RE), + type: String, + }, + ebgp: { + default: false, + optional: true, + }, + "ebgp-multihop": { + optional: true, + type: Integer, + }, + "isis-domain": { + optional: true, + type: String, + }, + "isis-ifaces": { + format: &ApiStringFormat::Pattern(&CREATE_CONTROLLER_ISIS_IFACES_RE), + optional: true, + type: String, + }, + "isis-net": { + format: &ApiStringFormat::Pattern(&CREATE_CONTROLLER_ISIS_NET_RE), + optional: true, + type: String, + }, + "lock-secret": { + optional: true, + type: String, + }, + loopback: { + optional: true, + type: String, + }, + node: { + format: &ApiStringFormat::Pattern(&CREATE_CONTROLLER_NODE_RE), + optional: true, + type: String, + }, + peers: { + format: &ApiStringFormat::VerifyFn(verifiers::verify_ip), + optional: true, + type: String, + }, + type: { + type: ListControllersType, + }, + }, +)] +/// Object. +#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)] +pub struct CreateController { + /// autonomous system number + #[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub asn: Option<u32>, + + /// Consider different AS paths of equal length for multipath computation. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")] + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "bgp-multipath-as-path-relax")] + pub bgp_multipath_as_path_relax: Option<bool>, + + /// The SDN controller object identifier. + pub controller: String, + + /// Enable eBGP (remote-as external). + #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ebgp: Option<bool>, + + /// Set maximum amount of hops for eBGP peers. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_i64")] + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "ebgp-multihop")] + pub ebgp_multihop: Option<i64>, + + /// Name of the IS-IS domain. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "isis-domain")] + pub isis_domain: Option<String>, + + /// Comma-separated list of interfaces where IS-IS should be active. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "isis-ifaces")] + pub isis_ifaces: Option<String>, + + /// Network Entity title for this node in the IS-IS network. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "isis-net")] + pub isis_net: Option<String>, + + /// the secret for unlocking the global SDN configuration + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "lock-secret")] + pub lock_secret: Option<String>, + + /// Name of the loopback/dummy interface that provides the Router-IP. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub loopback: Option<String>, + + /// The cluster node name. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub node: Option<String>, + + /// peers address list. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub peers: Option<String>, + + #[serde(rename = "type")] + pub ty: ListControllersType, +} + #[api( properties: { comment: { @@ -1380,6 +1514,26 @@ mod list_storages_content { } } +#[api] +/// Only list sdn controllers of specific type +#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] +pub enum ListControllersType { + #[serde(rename = "bgp")] + /// bgp. + Bgp, + #[serde(rename = "evpn")] + /// evpn. + Evpn, + #[serde(rename = "faucet")] + /// faucet. + Faucet, + #[serde(rename = "isis")] + /// isis. + Isis, +} +serde_plain::derive_display_from_serialize!(ListControllersType); +serde_plain::derive_fromstr_from_deserialize!(ListControllersType); + #[api] /// Only list specific interface types. #[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] @@ -9195,6 +9349,265 @@ mod storage_info_content { } } +const_regex! { + +SDN_CONTROLLER_ISIS_IFACES_RE = r##"^[a-zA-Z][a-zA-Z0-9_]{1,20}([:\.]\d+)?$"##; +SDN_CONTROLLER_ISIS_NET_RE = r##"^[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\.[a-fA-F0-9]{2}$"##; + +} + +#[api( + properties: { + asn: { + maximum: 4294967295, + minimum: 0, + optional: true, + type: Integer, + }, + "bgp-multipath-as-relax": { + default: false, + optional: true, + }, + controller: { + type: String, + }, + digest: { + optional: true, + type: String, + }, + ebgp: { + default: false, + optional: true, + }, + "ebgp-multihop": { + optional: true, + type: Integer, + }, + "isis-domain": { + optional: true, + type: String, + }, + "isis-ifaces": { + format: &ApiStringFormat::Pattern(&SDN_CONTROLLER_ISIS_IFACES_RE), + optional: true, + type: String, + }, + "isis-net": { + format: &ApiStringFormat::Pattern(&SDN_CONTROLLER_ISIS_NET_RE), + optional: true, + type: String, + }, + loopback: { + optional: true, + type: String, + }, + node: { + optional: true, + type: String, + }, + peers: { + optional: true, + type: String, + }, + pending: { + optional: true, + type: SdnControllerPending, + }, + state: { + optional: true, + type: SdnObjectState, + }, + type: { + type: ListControllersType, + }, + }, +)] +/// Object. +#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)] +pub struct SdnController { + /// The local ASN of the controller. BGP & EVPN only. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub asn: Option<u32>, + + /// Consider different AS paths of equal length for multipath computation. + /// BGP only. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")] + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "bgp-multipath-as-relax")] + pub bgp_multipath_as_relax: Option<bool>, + + /// Name of the controller. + pub controller: String, + + /// Digest of the controller section. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub digest: Option<String>, + + /// Enable eBGP (remote-as external). BGP only. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ebgp: Option<bool>, + + /// Set maximum amount of hops for eBGP peers. Needs ebgp set to 1. BGP + /// only. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_i64")] + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "ebgp-multihop")] + pub ebgp_multihop: Option<i64>, + + /// Name of the IS-IS domain. IS-IS only. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "isis-domain")] + pub isis_domain: Option<String>, + + /// Comma-separated list of interfaces where IS-IS should be active. IS-IS + /// only. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "isis-ifaces")] + pub isis_ifaces: Option<String>, + + /// Network Entity title for this node in the IS-IS network. IS-IS only. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "isis-net")] + pub isis_net: Option<String>, + + /// Name of the loopback/dummy interface that provides the Router-IP. BGP + /// only. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub loopback: Option<String>, + + /// Node(s) where this controller is active. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub node: Option<String>, + + /// Comma-separated list of the peers IP addresses. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub peers: Option<String>, + + /// Changes that have not yet been applied to the running configuration. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub pending: Option<SdnControllerPending>, + + #[serde(default, skip_serializing_if = "Option::is_none")] + pub state: Option<SdnObjectState>, + + #[serde(rename = "type")] + pub ty: ListControllersType, +} + +const_regex! { + +SDN_CONTROLLER_PENDING_ISIS_IFACES_RE = r##"^[a-zA-Z][a-zA-Z0-9_]{1,20}([:\.]\d+)?$"##; +SDN_CONTROLLER_PENDING_ISIS_NET_RE = r##"^[a-fA-F0-9]{2}(\.[a-fA-F0-9]{4}){3,9}\.[a-fA-F0-9]{2}$"##; + +} + +#[api( + properties: { + asn: { + maximum: 4294967295, + minimum: 0, + optional: true, + type: Integer, + }, + "bgp-multipath-as-relax": { + default: false, + optional: true, + }, + ebgp: { + default: false, + optional: true, + }, + "ebgp-multihop": { + optional: true, + type: Integer, + }, + "isis-domain": { + optional: true, + type: String, + }, + "isis-ifaces": { + format: &ApiStringFormat::Pattern(&SDN_CONTROLLER_PENDING_ISIS_IFACES_RE), + optional: true, + type: String, + }, + "isis-net": { + format: &ApiStringFormat::Pattern(&SDN_CONTROLLER_PENDING_ISIS_NET_RE), + optional: true, + type: String, + }, + loopback: { + optional: true, + type: String, + }, + node: { + optional: true, + type: String, + }, + peers: { + optional: true, + type: String, + }, + }, +)] +/// Changes that have not yet been applied to the running configuration. +#[derive(Clone, Debug, PartialEq, serde::Deserialize, serde::Serialize)] +pub struct SdnControllerPending { + /// The local ASN of the controller. BGP & EVPN only. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_u32")] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub asn: Option<u32>, + + /// Consider different AS paths of equal length for multipath computation. + /// BGP only. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")] + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "bgp-multipath-as-relax")] + pub bgp_multipath_as_relax: Option<bool>, + + /// Enable eBGP (remote-as external). BGP only. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_bool")] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub ebgp: Option<bool>, + + /// Set maximum amount of hops for eBGP peers. Needs ebgp set to 1. BGP + /// only. + #[serde(deserialize_with = "proxmox_login::parse::deserialize_i64")] + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "ebgp-multihop")] + pub ebgp_multihop: Option<i64>, + + /// Name of the IS-IS domain. IS-IS only. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "isis-domain")] + pub isis_domain: Option<String>, + + /// Comma-separated list of interfaces where IS-IS should be active. IS-IS + /// only. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "isis-ifaces")] + pub isis_ifaces: Option<String>, + + /// Network Entity title for this node in the IS-IS network. IS-IS only. + #[serde(default, skip_serializing_if = "Option::is_none")] + #[serde(rename = "isis-net")] + pub isis_net: Option<String>, + + /// Name of the loopback/dummy interface that provides the Router-IP. BGP + /// only. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub loopback: Option<String>, + + /// Node(s) where this controller is active. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub node: Option<String>, + + /// Comma-separated list of the peers IP addresses. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub peers: Option<String>, +} + #[api] /// The state of an SDN object. #[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] -- 2.39.5 _______________________________________________ pdm-devel mailing list pdm-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pdm-devel