digitalocean_api/api/load_balancer.rs
1use self::load_balancer_fields::{ForwardingRule, HealthCheck, StickySessions};
2use super::Region;
3use super::{ApiLinks, ApiMeta};
4use super::{HasPagination, HasResponse, HasValue};
5use crate::method::{Create, Delete, Get, List, Update};
6use crate::request::LoadBalancerRequest;
7use crate::request::Request;
8use crate::{ROOT_URL, STATIC_URL_ERROR};
9use chrono::{DateTime, Utc};
10use getset::{Getters, Setters};
11use serde::Deserialize;
12use serde::Serialize;
13use std::fmt::Display;
14use std::net::IpAddr;
15use url::Url;
16
17const LOAD_BALANCERS_SEGMENT: &str = "load_balancers";
18const DROPLETS_SEGMENT: &str = "droplets";
19const FORWARDING_RULES_SEGMENT: &str = "forwarding_rules";
20
21/// Load Balancers provide a way to distribute traffic across multiple
22/// Droplets.
23///
24/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#load-balancers)
25#[derive(Deserialize, Serialize, Debug, Clone, Getters, Setters)]
26#[get = "pub"]
27pub struct LoadBalancer {
28 /// A unique ID that can be used to identify and reference a Load Balancer.
29 id: String,
30
31 /// A human-readable name for a Load Balancer instance.
32 name: String,
33
34 /// An attribute containing the public-facing IP address of the Load
35 /// Balancer.
36 ip: IpAddr,
37
38 /// The load balancing algorithm used to determine which backend Droplet
39 /// will be selected by a client. It must be either "round_robin" or
40 /// "least_connections".
41 algorithm: String,
42
43 /// A status string indicating the current state of the Load Balancer.
44 /// This can be "new", "active", or "errored".
45 status: String,
46
47 /// A time value given in ISO8601 combined date and time format that
48 /// represents when the Load Balancer was created.
49 created_at: DateTime<Utc>,
50
51 /// An object specifying the forwarding rules for a Load Balancer.
52 forwarding_rules: Vec<ForwardingRule>,
53
54 /// An object specifying health check settings for the Load Balancer.
55 health_check: HealthCheck,
56
57 /// An object specifying sticky sessions settings for the Load Balancer.
58 sticky_sessions: StickySessions,
59
60 /// The region where the Load Balancer instance is located.
61 region: Region,
62
63 /// The name of a Droplet tag corresponding to Droplets assigned to the
64 /// Load Balancer.
65 tag: String,
66
67 /// An array containing the IDs of the Droplets assigned to the Load
68 /// Balancer.
69 droplet_ids: Vec<usize>,
70
71 /// A boolean value indicating whether HTTP requests to the Load Balancer
72 /// on port 80 will be redirected to HTTPS on port 443.
73 redirect_http_to_https: bool,
74}
75
76/// Fields which exists inside Droplets.
77pub mod load_balancer_fields {
78 use serde::Serialize;
79
80 use serde::Deserialize;
81
82 /// This exists in the `forwarding_rules` field of a droplet.
83 ///
84 /// Forwarding rules determine how traffic will be routed from the Load
85 /// Balancer to the Droplets assigned to it. They can be used to configure
86 /// the type of traffic (HTTP, HTTPS, or TCP) and to map ports on the Load
87 /// Balancer to ports on the Droplets. For SSL encrypted traffic, you may
88 /// also configure whether to use SSL termination at the Load Balancer (by
89 /// specifying an SSL certificate) or to pass the encrypted traffic
90 /// through to the Droplet. Currently, each Load Balancer may have up to 15
91 /// forwarding rules.
92 #[derive(Deserialize, Serialize, Debug, Clone)]
93 pub struct ForwardingRule {
94 /// The protocol used for traffic to the Load Balancer. The possible
95 /// values are: "http", "https", or "tcp".
96 pub entry_protocol: String,
97
98 /// The port on which the Load Balancer instance will listen.
99 pub entry_port: usize,
100
101 /// The protocol used for traffic from the Load Balancer to the backend
102 /// Droplets. The possible values are: "http", "https", or "tcp".
103 pub target_protocol: String,
104
105 /// An integer representing the port on the backend Droplets to which
106 /// the Load Balancer will send traffic.
107 pub target_port: usize,
108
109 /// The ID of the TLS certificate used for SSL termination if enabled.
110 pub certificate_id: Option<String>,
111
112 /// A boolean value indicating whether SSL encrypted traffic will be
113 /// passed through to the backend Droplets.
114 pub tls_passthrough: bool,
115 }
116
117 impl ForwardingRule {
118 pub fn new<S: AsRef<str>>(
119 entry_protocol: S,
120 entry_port: usize,
121 target_protocol: S,
122 target_port: usize,
123 ) -> Self {
124 ForwardingRule {
125 entry_protocol: entry_protocol.as_ref().to_string(),
126 entry_port,
127 target_protocol: target_protocol.as_ref().to_string(),
128 target_port,
129 certificate_id: None,
130 tls_passthrough: false,
131 }
132 }
133
134 pub fn certificate_id<S: AsRef<str>>(mut self, certificate_id: Option<S>) -> Self {
135 self.certificate_id = certificate_id.map(|v| v.as_ref().to_string());
136 self
137 }
138
139 pub fn tls_passthrough(mut self, tls_passthrough: bool) -> Self {
140 self.tls_passthrough = tls_passthrough;
141 self
142 }
143 }
144
145 impl<S: AsRef<str>> From<(S, usize, S, usize)> for ForwardingRule {
146 fn from(val: (S, usize, S, usize)) -> Self {
147 ForwardingRule::new(val.0, val.1, val.2, val.3)
148 }
149 }
150
151 impl<S: AsRef<str>> From<(S, usize, S, usize, Option<S>)> for ForwardingRule {
152 fn from(val: (S, usize, S, usize, Option<S>)) -> Self {
153 ForwardingRule::new(val.0, val.1, val.2, val.3).certificate_id(val.4)
154 }
155 }
156
157 impl<S: AsRef<str>> From<(S, usize, S, usize, Option<S>, bool)> for ForwardingRule {
158 fn from(val: (S, usize, S, usize, Option<S>, bool)) -> Self {
159 ForwardingRule::new(val.0, val.1, val.2, val.3)
160 .certificate_id(val.4)
161 .tls_passthrough(val.5)
162 }
163 }
164
165 /// This exists in the `health_check` field of a droplet.
166 ///
167 /// Health checks are used to tell if a Droplet is responding and should
168 /// receive traffic. The Load Balancer will automatically stop sending
169 /// traffic to unresponsive Droplets. You may specify the protocol, port,
170 /// and path for a health check as well as additional setting such as the
171 /// check interval and response timeout.
172 #[derive(Deserialize, Serialize, Debug, Clone)]
173 pub struct HealthCheck {
174 /// The protocol used for health checks sent to the backend Droplets.
175 /// The possible values are "http" or "tcp".
176 pub protocol: String,
177
178 /// An integer representing the port on the backend Droplets on which
179 /// the health check will attempt a connection.
180 pub port: usize,
181
182 /// The path on the backend Droplets to which the Load Balancer
183 /// instance will send a request.
184 pub path: String,
185
186 /// The number of seconds between between two consecutive health
187 /// checks.
188 pub check_interval_seconds: usize,
189
190 /// The number of seconds the Load Balancer instance will wait for a
191 /// response until marking a health check as failed.
192 pub response_timeout_seconds: usize,
193
194 /// The number of times a health check must fail for a backend Droplet
195 /// to be marked "unhealthy" and be removed from the pool.
196 pub unhealthy_threshold: usize,
197
198 /// The number of times a health check must pass for a backend Droplet
199 /// to be marked "healthy" and be re-added to the pool.
200 pub healthy_threshold: usize,
201 }
202
203 /// This exists in the `sticky_sessions` field of a droplet.
204 ///
205 /// When sticky sessions are in use, follow up requests from a client will
206 /// be sent to the same Droplet as the original request. Both the name of
207 /// the cookie and the TTL are configurable.
208 #[derive(Deserialize, Serialize, Debug, Clone)]
209 pub struct StickySessions {
210 /// An attribute indicating how and if requests from a client will be
211 /// persistently served by the same backend Droplet. The possible
212 /// values are "cookies" or "none".
213 ///
214 /// *Note:* Since `type` is a keyword in Rust `kind` is used instead.
215 #[serde(rename = "type")]
216 pub kind: String,
217
218 /// The name of the cookie sent to the client. This attribute is only
219 /// returned when using "cookies" for the sticky sessions type.
220 pub cookie_name: Option<String>,
221
222 /// The number of seconds until the cookie set by the Load Balancer
223 /// expires. This attribute is only returned when using "cookies" for
224 /// the sticky sessions type.
225 pub cookie_ttl_seconds: Option<String>,
226 }
227}
228
229impl LoadBalancer {
230 /// Be sure to include a forwarding rule by chaining `.forwarding_rule()` onto this.
231 ///
232 /// **Note:** It may contain one of the droplets_ids or tag attributes as they are mutually exclusive.
233 ///
234 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-load-balancer)
235 pub fn create<S>(name: S, region: S) -> LoadBalancerRequest<Create, LoadBalancer>
236 where
237 S: AsRef<str> + Serialize + Display,
238 {
239 let mut url = ROOT_URL.clone();
240 url.path_segments_mut()
241 .expect(STATIC_URL_ERROR)
242 .push(LOAD_BALANCERS_SEGMENT);
243
244 let mut req = Request::new(url);
245 req.set_body(json!({
246 "name": name,
247 "region": region,
248 "forwarding_rules": [],
249 }));
250 req
251 }
252
253 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#retrieve-an-existing-load-balancer)
254 pub fn get<S>(id: S) -> LoadBalancerRequest<Get, LoadBalancer>
255 where
256 S: AsRef<str> + Serialize + Display,
257 {
258 let mut url = ROOT_URL.clone();
259 url.path_segments_mut()
260 .expect(STATIC_URL_ERROR)
261 .push(LOAD_BALANCERS_SEGMENT)
262 .push(id.as_ref());
263
264 Request::new(url)
265 }
266
267 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-all-load-balancers)
268 pub fn list() -> LoadBalancerRequest<List, Vec<LoadBalancer>> {
269 let mut url = ROOT_URL.clone();
270 url.path_segments_mut()
271 .expect(STATIC_URL_ERROR)
272 .push(LOAD_BALANCERS_SEGMENT);
273
274 Request::new(url)
275 }
276
277 /// **Note:** Any attribute that is not provided will be reset to its default value.
278 ///
279 /// **Note:** It may contain one of the droplets_ids or tag attributes as they are mutually exclusive.
280 ///
281 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
282 pub fn update<S>(id: S) -> LoadBalancerRequest<Update, LoadBalancer>
283 where
284 S: AsRef<str> + Serialize + Display,
285 {
286 let mut url = ROOT_URL.clone();
287 url.path_segments_mut()
288 .expect(STATIC_URL_ERROR)
289 .push(LOAD_BALANCERS_SEGMENT)
290 .push(id.as_ref());
291
292 Request::new(url)
293 }
294 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#delete-a-load-balancer)
295 pub fn delete<S>(id: S) -> LoadBalancerRequest<Delete, ()>
296 where
297 S: AsRef<str> + Serialize + Display,
298 {
299 let mut url = ROOT_URL.clone();
300 url.path_segments_mut()
301 .expect(STATIC_URL_ERROR)
302 .push(LOAD_BALANCERS_SEGMENT)
303 .push(id.as_ref());
304
305 Request::new(url)
306 }
307}
308
309impl LoadBalancerRequest<Create, LoadBalancer> {
310 /// The load balancing algorithm used to determine which backend Droplet
311 /// will be selected by a client. It must be either "round_robin" or
312 /// "least_connections". The default value is "round_robin".
313 ///
314 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-load-balancer)
315 pub fn algorithm<S>(mut self, val: S) -> LoadBalancerRequest<Create, LoadBalancer>
316 where
317 S: Display + Serialize,
318 {
319 self.body_mut()["algorithm"] = json!(val);
320 self
321 }
322
323 /// An array of objects specifying the forwarding rules for a Load
324 /// Balancer. At least one forwarding rule is required when creating a new
325 /// Load Balancer instance.
326 ///
327 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-load-balancer)
328 pub fn forwarding_rule<T>(mut self, val: T) -> LoadBalancerRequest<Create, LoadBalancer>
329 where
330 T: Into<ForwardingRule>,
331 {
332 if !self.body_mut()["forwarding_rules"].is_array() {
333 self.body_mut()["forwarding_rules"] = json!([]);
334 }
335
336 {
337 let rules = self.body_mut()["forwarding_rules"].as_array_mut().expect(
338 "forwarding_rules \
339 should always \
340 be an array.\
341 ",
342 );
343
344 rules.push(json!(val.into()));
345 }
346 self
347 }
348
349 /// The (optional) health check settings.
350 ///
351 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-load-balancer)
352 #[allow(clippy::too_many_arguments)]
353 pub fn health_check<S: AsRef<str> + Display + Serialize>(
354 mut self,
355 protocol: S,
356 port: usize,
357 path: Option<S>,
358 check_interval_seconds: Option<usize>,
359 response_timeout_seconds: Option<usize>,
360 unhealthy_threshold: Option<usize>,
361 healthy_threshold: Option<usize>,
362 ) -> LoadBalancerRequest<Create, LoadBalancer> {
363 self.body_mut()["health_check"] = json!({
364 "protocol": protocol,
365 "port": port,
366 });
367
368 if let Some(path) = path {
369 self.body_mut()["health_check"]["path"] = json!(path);
370 }
371
372 if let Some(check_interval_seconds) = check_interval_seconds {
373 self.body_mut()["health_check"]["check_interval_seconds"] =
374 json!(check_interval_seconds);
375 }
376
377 if let Some(response_timeout_seconds) = response_timeout_seconds {
378 self.body_mut()["health_check"]["response_timeout_seconds"] =
379 json!(response_timeout_seconds);
380 }
381
382 if let Some(unhealthy_threshold) = unhealthy_threshold {
383 self.body_mut()["health_check"]["unhealthy_threshold"] = json!(unhealthy_threshold);
384 }
385
386 if let Some(healthy_threshold) = healthy_threshold {
387 self.body_mut()["health_check"]["healthy_threshold"] = json!(healthy_threshold);
388 }
389
390 self
391 }
392
393 /// The (optional) sticky sessions settings. `kind` must be `cookies` or
394 /// `none`. If `kind` is `cookies` then `cookie_name` and
395 /// `cookie_ttl_seconds` should be set as well.
396 ///
397 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-load-balancer)
398 pub fn sticky_sessions<S: AsRef<str> + Display + Serialize>(
399 mut self,
400 kind: S,
401 cookie_name: Option<S>,
402 cookie_ttl_seconds: Option<usize>,
403 ) -> LoadBalancerRequest<Create, LoadBalancer> {
404 self.body_mut()["sticky_sessions"] = json!({
405 "type": kind,
406 });
407
408 if let Some(cookie_name) = cookie_name {
409 self.body_mut()["sticky_sessions"]["cookie_name"] = json!(cookie_name);
410 }
411
412 if let Some(cookie_ttl_seconds) = cookie_ttl_seconds {
413 self.body_mut()["sticky_sessions"]["cookie_ttl_seconds"] = json!(cookie_ttl_seconds);
414 }
415
416 self
417 }
418
419 /// A boolean value indicating whether HTTP requests to the Load Balancer
420 /// on port 80 will be redirected to HTTPS on port 443. Default value is false.
421 ///
422 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-load-balancer)
423 pub fn redirect_http_to_https(
424 mut self,
425 setting: bool,
426 ) -> LoadBalancerRequest<Create, LoadBalancer> {
427 self.body_mut()["redirect_http_to_https"] = json!(setting);
428 self
429 }
430
431 /// The IDs of the Droplets to be assigned to the Load Balancer.
432 ///
433 /// **Note:** Not intended to be used alongside the `tag` function.
434 ///
435 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-load-balancer)
436 pub fn droplets(mut self, ids: Vec<usize>) -> LoadBalancerRequest<Create, LoadBalancer> {
437 self.body_mut()["droplet_ids"] = json!(ids);
438 self
439 }
440
441 /// The name of a Droplet tag corresponding to Droplets to be assigned to
442 /// the Load Balancer.
443 ///
444 /// **Note:** Not intended to be used alongside the `droplets` function.
445 ///
446 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-load-balancer)
447 pub fn tag<S>(mut self, tag: S) -> LoadBalancerRequest<Create, LoadBalancer>
448 where
449 S: AsRef<str> + Display + Serialize,
450 {
451 self.body_mut()["tag"] = json!(tag);
452 self
453 }
454}
455
456impl LoadBalancerRequest<Update, LoadBalancer> {
457 /// A human-readable name for a Load Balancer instance.
458 ///
459 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
460 pub fn name<S>(mut self, val: S) -> LoadBalancerRequest<Update, LoadBalancer>
461 where
462 S: Display + Serialize,
463 {
464 self.body_mut()["name"] = json!(val);
465 self
466 }
467
468 /// The region where the Load Balancer instance will be located.
469 ///
470 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
471 pub fn region<S>(mut self, val: S) -> LoadBalancerRequest<Update, LoadBalancer>
472 where
473 S: Display + Serialize,
474 {
475 self.body_mut()["region"] = json!(val);
476 self
477 }
478
479 /// The load balancing algorithm used to determine which backend Droplet
480 /// will be selected by a client. It must be either "round_robin" or
481 /// "least_connections". The default value is "round_robin".
482 ///
483 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
484 pub fn algorithm<S>(mut self, val: S) -> LoadBalancerRequest<Update, LoadBalancer>
485 where
486 S: Display + Serialize,
487 {
488 self.body_mut()["algorithm"] = json!(val);
489 self
490 }
491
492 /// An array of objects specifying the forwarding rules for a Load
493 /// Balancer. At least one forwarding rule is required when creating a new
494 /// Load Balancer instance.
495 ///
496 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
497 pub fn forwarding_rule<T>(mut self, val: T) -> LoadBalancerRequest<Update, LoadBalancer>
498 where
499 T: Into<ForwardingRule>,
500 {
501 if !self.body_mut()["forwarding_rules"].is_array() {
502 self.body_mut()["forwarding_rules"] = json!([]);
503 }
504
505 {
506 let rules = self.body_mut()["forwarding_rules"].as_array_mut().expect(
507 "forwarding_rules \
508 should always \
509 be an array.\
510 ",
511 );
512
513 rules.push(json!(val.into()));
514 }
515 self
516 }
517
518 /// The (optional) health check settings.
519 ///
520 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
521 #[allow(clippy::too_many_arguments)]
522 pub fn health_check<S: AsRef<str> + Display + Serialize>(
523 mut self,
524 protocol: S,
525 port: usize,
526 path: Option<S>,
527 check_interval_seconds: Option<usize>,
528 response_timeout_seconds: Option<usize>,
529 unhealthy_threshold: Option<usize>,
530 healthy_threshold: Option<usize>,
531 ) -> LoadBalancerRequest<Update, LoadBalancer> {
532 self.body_mut()["health_check"] = json!({
533 "protocol": protocol,
534 "port": port,
535 });
536
537 if let Some(path) = path {
538 self.body_mut()["health_check"]["path"] = json!(path);
539 }
540
541 if let Some(check_interval_seconds) = check_interval_seconds {
542 self.body_mut()["health_check"]["check_interval_seconds"] =
543 json!(check_interval_seconds);
544 }
545
546 if let Some(response_timeout_seconds) = response_timeout_seconds {
547 self.body_mut()["health_check"]["response_timeout_seconds"] =
548 json!(response_timeout_seconds);
549 }
550
551 if let Some(unhealthy_threshold) = unhealthy_threshold {
552 self.body_mut()["health_check"]["unhealthy_threshold"] = json!(unhealthy_threshold);
553 }
554
555 if let Some(healthy_threshold) = healthy_threshold {
556 self.body_mut()["health_check"]["healthy_threshold"] = json!(healthy_threshold);
557 }
558
559 self
560 }
561
562 /// The (optional) sticky sessions settings. `kind` must be `cookies` or
563 /// `none`. If `kind` is `cookies` then `cookie_name` and
564 /// `cookie_ttl_seconds` should be set as well.
565 ///
566 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
567 pub fn sticky_sessions<S: AsRef<str> + Display + Serialize>(
568 mut self,
569 kind: S,
570 cookie_name: Option<S>,
571 cookie_ttl_seconds: Option<usize>,
572 ) -> LoadBalancerRequest<Update, LoadBalancer> {
573 self.body_mut()["sticky_sessions"] = json!({
574 "type": kind,
575 });
576
577 if let Some(cookie_name) = cookie_name {
578 self.body_mut()["sticky_sessions"]["cookie_name"] = json!(cookie_name);
579 }
580
581 if let Some(cookie_ttl_seconds) = cookie_ttl_seconds {
582 self.body_mut()["sticky_sessions"]["cookie_ttl_seconds"] = json!(cookie_ttl_seconds);
583 }
584
585 self
586 }
587
588 /// A boolean value indicating whether HTTP requests to the Load Balancer
589 /// on port 80 will be redirected to HTTPS on port 443. Default value is false.
590 ///
591 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
592 pub fn redirect_http_to_https(
593 mut self,
594 setting: bool,
595 ) -> LoadBalancerRequest<Update, LoadBalancer> {
596 self.body_mut()["redirect_http_to_https"] = json!(setting);
597 self
598 }
599
600 /// The IDs of the Droplets to be assigned to the Load Balancer.
601 ///
602 /// **Note:** Not intended to be used alongside the `tag` function.
603 ///
604 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
605 pub fn droplets(mut self, ids: Vec<usize>) -> LoadBalancerRequest<Update, LoadBalancer> {
606 self.body_mut()["droplet_ids"] = json!(ids);
607 self
608 }
609
610 /// The name of a Droplet tag corresponding to Droplets to be assigned to
611 /// the Load Balancer.
612 ///
613 /// **Note:** Not intended to be used alongside the `droplets` function.
614 ///
615 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#update-a-load-balancer)
616 pub fn tag<S>(mut self, tag: S) -> LoadBalancerRequest<Update, LoadBalancer>
617 where
618 S: AsRef<str> + Display + Serialize,
619 {
620 self.body_mut()["tag"] = json!(tag);
621 self
622 }
623}
624
625impl LoadBalancerRequest<Get, LoadBalancer> {
626 /// Add droplets (by id) to the load balancer.
627 ///
628 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#add-droplets-to-a-load-balancer)
629 pub fn add_droplets(mut self, ids: Vec<usize>) -> LoadBalancerRequest<Create, ()> {
630 self.url_mut()
631 .path_segments_mut()
632 .expect(STATIC_URL_ERROR)
633 .push(DROPLETS_SEGMENT);
634
635 self.set_body(json!({
636 "droplet_ids": ids,
637 }));
638
639 self.transmute()
640 }
641
642 /// Remove droplets (by id) from the load balancer.
643 ///
644 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#remove-droplets-from-a-load-balancer)
645 pub fn remove_droplets(mut self, ids: Vec<usize>) -> LoadBalancerRequest<Delete, ()> {
646 self.url_mut()
647 .path_segments_mut()
648 .expect(STATIC_URL_ERROR)
649 .push(DROPLETS_SEGMENT);
650
651 self.set_body(json!({
652 "droplet_ids": ids,
653 }));
654
655 self.transmute()
656 }
657
658 /// Add a forwarding rule to the Load Balancer.
659 ///
660 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#add-forwarding-rules-to-a-load-balancer)
661 pub fn add_forwarding_rules<T>(mut self, items: Vec<T>) -> LoadBalancerRequest<Create, ()>
662 where
663 T: Into<ForwardingRule>,
664 {
665 self.url_mut()
666 .path_segments_mut()
667 .expect(STATIC_URL_ERROR)
668 .push(FORWARDING_RULES_SEGMENT);
669
670 if !self.body_mut()["forwarding_rules"].is_array() {
671 self.body_mut()["forwarding_rules"] = json!([]);
672 }
673
674 {
675 let rules = self.body_mut()["forwarding_rules"].as_array_mut().expect(
676 "forwarding_rules \
677 should always \
678 be an array.\
679 ",
680 );
681
682 for item in items {
683 let rule: ForwardingRule = item.into();
684 rules.push(json!(rule));
685 }
686 }
687
688 self.transmute()
689 }
690
691 /// Remove a forwarding rule to the Load Balancer.
692 ///
693 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#remove-forwarding-rules-from-a-load-balancer)
694 pub fn remove_forwarding_rules<T>(mut self, items: Vec<T>) -> LoadBalancerRequest<Delete, ()>
695 where
696 T: Into<ForwardingRule>,
697 {
698 self.url_mut()
699 .path_segments_mut()
700 .expect(STATIC_URL_ERROR)
701 .push(FORWARDING_RULES_SEGMENT);
702
703 if !self.body_mut()["forwarding_rules"].is_array() {
704 self.body_mut()["forwarding_rules"] = json!([]);
705 }
706
707 {
708 let rules = self.body_mut()["forwarding_rules"].as_array_mut().expect(
709 "forwarding_rules \
710 should always \
711 be an array.\
712 ",
713 );
714
715 for item in items {
716 let rule: ForwardingRule = item.into();
717 rules.push(json!(rule));
718 }
719 }
720
721 self.transmute()
722 }
723}
724
725/// Response type returned from Digital Ocean.
726#[derive(Deserialize, Serialize, Debug, Clone)]
727pub struct LoadBalancerResponse {
728 load_balancer: LoadBalancer,
729}
730
731impl HasResponse for LoadBalancer {
732 type Response = LoadBalancerResponse;
733}
734
735impl HasValue for LoadBalancerResponse {
736 type Value = LoadBalancer;
737
738 fn value(self) -> LoadBalancer {
739 self.load_balancer
740 }
741}
742
743/// Response type returned from Digital Ocean.
744#[derive(Deserialize, Serialize, Debug, Clone)]
745pub struct LoadBalancerListResponse {
746 load_balancers: Vec<LoadBalancer>,
747 links: ApiLinks,
748 meta: ApiMeta,
749}
750
751impl HasResponse for Vec<LoadBalancer> {
752 type Response = LoadBalancerListResponse;
753}
754
755impl HasPagination for LoadBalancerListResponse {
756 fn next_page(&self) -> Option<Url> {
757 self.links.next()
758 }
759}
760
761impl HasValue for LoadBalancerListResponse {
762 type Value = Vec<LoadBalancer>;
763
764 fn value(self) -> Vec<LoadBalancer> {
765 self.load_balancers
766 }
767}