From dbd4f26564457913d924c4b41b2e441c26e403e1 Mon Sep 17 00:00:00 2001 From: Nuno Diegues Date: Mon, 19 Apr 2021 18:05:34 +0100 Subject: [PATCH] Add create/delete/list for Load Balancers (#139) Co-authored-by: Nuno Diegues --- cloudflare/src/endpoints/dns.rs | 1 + .../src/endpoints/load_balancing/create_lb.rs | 63 +++++++++++ .../src/endpoints/load_balancing/delete_lb.rs | 30 +++++ .../src/endpoints/load_balancing/list_lb.rs | 22 ++++ .../src/endpoints/load_balancing/mod.rs | 103 +++++++++++++++++- 5 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 cloudflare/src/endpoints/load_balancing/create_lb.rs create mode 100644 cloudflare/src/endpoints/load_balancing/delete_lb.rs create mode 100644 cloudflare/src/endpoints/load_balancing/list_lb.rs diff --git a/cloudflare/src/endpoints/dns.rs b/cloudflare/src/endpoints/dns.rs index 2eb55a6c..495fe422 100644 --- a/cloudflare/src/endpoints/dns.rs +++ b/cloudflare/src/endpoints/dns.rs @@ -163,6 +163,7 @@ pub enum DnsContent { NS { content: String }, MX { content: String, priority: u16 }, TXT { content: String }, + SRV { content: String }, } #[derive(Deserialize, Debug)] diff --git a/cloudflare/src/endpoints/load_balancing/create_lb.rs b/cloudflare/src/endpoints/load_balancing/create_lb.rs new file mode 100644 index 00000000..66ea1199 --- /dev/null +++ b/cloudflare/src/endpoints/load_balancing/create_lb.rs @@ -0,0 +1,63 @@ +use crate::endpoints::load_balancing::{LbPoolId, SteeringPolicy, SessionAffinityAttributes, LbPoolMapping, SessionAffinity, LoadBalancer}; +use crate::framework::endpoint::{Endpoint, Method}; + +/// Create Load Balancer +/// https://api.cloudflare.com/#load-balancers-create-load-balancer +#[derive(Debug)] +pub struct CreateLoadBalancer<'a> { + /// The Zone to which this Load Balancer shall belong. + pub zone_identifier: &'a str, + /// Optional parameters for the API call + pub params: Params<'a>, +} + +/// Mandatory parameters for creating a Load Balancer. +#[serde_with::skip_serializing_none] +#[derive(Serialize, Clone, Debug)] +pub struct Params<'a> { + /// A short name (tag) for the load balancer. + /// Only alphanumeric characters, hyphens and underscores are allowed. + /// E.g. "lb-user-facing" + pub name: &'a str, + /// The list of LB Pools (by their IDs) ordered by their failover priority. + pub default_pools: &'a [LbPoolId], + /// The LB Pool ID to use when all other pools are detected as unhealthy. + pub fallback_pool: &'a LbPoolId, + #[serde(flatten)] + pub optional_params: Option>, +} + +/// Optional parameters for creating a Load Balancer. +#[serde_with::skip_serializing_none] +#[derive(Serialize, Clone, Debug, Default)] +pub struct OptionalParams<'a> { + pub description: Option<&'a str>, + /// Time to live (TTL) of the DNS entry for the IP address returned by this load balancer. This + /// only applies to gray-clouded (unproxied) load balancers. + pub ttl: Option, + /// A mapping of Cloudflare PoP identifiers to a list of pool IDs (ordered by their failover + /// priority) for the PoP (datacenter). Any PoPs not explicitly defined will fall back to using + /// default_pools. + pub pop_pools: Option, + /// A mapping of region/country codes to a list of pool IDs (ordered by their failover priority) + /// for the given region. Any regions not explicitly defined will fall back to using + /// default_pools. + pub region_pools: Option, + pub proxied: Option, + pub steering_policy: Option, + pub session_affinity: Option, + pub session_affinity_attributes: Option, + pub session_affinity_ttl: Option, +} + +impl<'a> Endpoint> for CreateLoadBalancer<'a> { + fn method(&self) -> Method { + Method::Post + } + fn path(&self) -> String { + format!("zones/{}/load_balancers", self.zone_identifier) + } + fn body(&self) -> Option> { + Some(self.params.clone()) + } +} diff --git a/cloudflare/src/endpoints/load_balancing/delete_lb.rs b/cloudflare/src/endpoints/load_balancing/delete_lb.rs new file mode 100644 index 00000000..796f32ca --- /dev/null +++ b/cloudflare/src/endpoints/load_balancing/delete_lb.rs @@ -0,0 +1,30 @@ +use crate::framework::endpoint::{Endpoint, Method}; +use crate::framework::response::ApiResult; + +/// Delete Load Balancer +/// https://api.cloudflare.com/#load-balancers-delete-load-balancer +#[derive(Debug)] +pub struct DeleteLoadBalancer<'a> { + /// The Zone to which this Load Balancer belongs. + pub zone_identifier: &'a str, + /// Which load balancer to delete. + pub identifier: &'a str, +} + +impl<'a> Endpoint for DeleteLoadBalancer<'a> { + fn method(&self) -> Method { + Method::Delete + } + fn path(&self) -> String { + format!( + "zones/{}/load_balancers/{}", + self.zone_identifier, self.identifier + ) + } +} + +#[derive(Deserialize, Clone, Debug)] +pub struct Response { + id: String, +} +impl ApiResult for Response {} diff --git a/cloudflare/src/endpoints/load_balancing/list_lb.rs b/cloudflare/src/endpoints/load_balancing/list_lb.rs new file mode 100644 index 00000000..dd3b2ebd --- /dev/null +++ b/cloudflare/src/endpoints/load_balancing/list_lb.rs @@ -0,0 +1,22 @@ +use crate::endpoints::load_balancing::LoadBalancer; +use crate::framework::endpoint::{Endpoint, Method}; +use crate::framework::response::ApiResult; + +/// List Load Balancers +/// https://api.cloudflare.com/#load-balancers-list-load-balancers +#[derive(Debug)] +pub struct ListLoadBalancers<'a> { + /// The Zone to list Load Balancers from. + pub zone_identifier: &'a str, +} + +impl<'a> Endpoint, ()> for ListLoadBalancers<'a> { + fn method(&self) -> Method { + Method::Get + } + fn path(&self) -> String { + format!("zones/{}/load_balancers", self.zone_identifier) + } +} + +impl ApiResult for Vec {} diff --git a/cloudflare/src/endpoints/load_balancing/mod.rs b/cloudflare/src/endpoints/load_balancing/mod.rs index e4e8b191..08c7bad4 100644 --- a/cloudflare/src/endpoints/load_balancing/mod.rs +++ b/cloudflare/src/endpoints/load_balancing/mod.rs @@ -1,14 +1,115 @@ +pub mod create_lb; pub mod create_pool; +pub mod delete_lb; pub mod delete_pool; +pub mod list_lb; pub mod pool_details; use crate::framework::response::ApiResult; use chrono::offset::Utc; use chrono::DateTime; -use std::collections::HashSet; +use std::collections::{HashSet, HashMap}; use std::hash::{Hash, Hasher}; use std::net::IpAddr; +#[derive(Eq, PartialEq, Deserialize, Serialize, Clone, Debug)] +pub struct LoadBalancer { + pub id: String, + pub created_on: DateTime, + pub modified_on: DateTime, + pub description: String, + /// The DNS hostname to associate with your Load Balancer. If this hostname already exists as a + /// DNS record in Cloudflare's DNS, the Load Balancer will take precedence and the DNS record + /// will not be used. + pub name: String, + pub enabled: bool, + /// Time to live (TTL) of the DNS entry for the IP address returned by this load balancer. This + /// only applies to gray-clouded (unproxied) load balancers. + #[serde(default = "LoadBalancer::default_ttl")] + pub ttl: u32, + /// The pool ID to use when all other pools are detected as unhealthy. + pub fallback_pool: LbPoolId, + /// A list of pool IDs ordered by their failover priority. Pools defined here are used by + /// default, or when region_pools are not configured for a given region. + pub default_pools: Vec, + /// A mapping of region/country codes to a list of pool IDs (ordered by their failover priority) + /// for the given region. Any regions not explicitly defined will fall back to using + /// default_pools. + pub region_pools: LbPoolMapping, + /// A mapping of Cloudflare PoP identifiers to a list of pool IDs (ordered by their failover + /// priority) for the PoP (datacenter). Any PoPs not explicitly defined will fall back to using + /// default_pools. + pub pop_pools: LbPoolMapping, + pub proxied: bool, + pub steering_policy: SteeringPolicy, + pub session_affinity: SessionAffinity, + pub session_affinity_attributes: SessionAffinityAttributes, + #[serde(default = "LoadBalancer::default_session_affinity_ttl")] + pub session_affinity_ttl: u32, +} + +impl LoadBalancer { + fn default_ttl() -> u32 { + 30 + } + fn default_session_affinity_ttl() -> u32 { + 5000 + } +} + +type LbPoolId = String; +type LbPoolMapping = HashMap>; + +#[derive(Eq, PartialEq, Deserialize, Serialize, Clone, Debug)] +#[serde(rename_all = "lowercase")] +pub enum SteeringPolicy { + /// Empty policy maps to `Geo` if `region_pools` or `pop_pools` are used, or otherwise `Off`. + #[serde(rename = "")] + Nil, + Off, + Geo, + Random, + DynamicLatency, +} + +#[derive(Eq, PartialEq, Deserialize, Serialize, Clone, Debug)] +#[serde(rename_all = "lowercase")] +pub enum SessionAffinity { + /// Empty has the same behaviour as `None`. + #[serde(rename = "")] + Nil, + None, + Cookie, + IpCookie +} + +#[derive(Eq, PartialEq, Deserialize, Serialize, Clone, Debug)] +pub struct SessionAffinityAttributes { + pub samesite: SameSite, + pub secure: Secure, + pub drain_duration: u32, +} + +#[derive(Eq, PartialEq, Deserialize, Serialize, Clone, Debug)] +pub enum SameSite { + /// `Auto` maps to `Lax` if Always Use HTTPS is set, or `None` otherwise. + Auto, + Lax, + None, + Strict, +} + +#[derive(Eq, PartialEq, Deserialize, Serialize, Clone, Debug)] +pub enum Secure { + /// `Auto` maps to `Always` if Always Use HTTPS is set, or `Never` otherwise. + Auto, + Always, + Never +} + +impl ApiResult for LoadBalancer {} + + /// A pool is a set of origins that requests could be routed to (e.g. each of your data centers or /// regions have its own pool). /// Requests will be routed to particular pools according to your steering policy, and then balanced