digitalocean_api/api/droplet.rs
1use self::droplet_fields::{Kernel, Networks, NextBackupWindow};
2use super::snapshot::Snapshot;
3use super::{ApiLinks, ApiMeta};
4use super::{HasPagination, HasResponse, HasValue};
5use super::{Image, Region, Size};
6use crate::method::{Create, Delete, Get, List};
7use crate::request::Request;
8use crate::request::{DropletRequest, SnapshotRequest};
9use crate::{ROOT_URL, STATIC_URL_ERROR};
10use chrono::{DateTime, Utc};
11use getset::{Getters, Setters};
12use serde::Deserialize;
13use serde::Serialize;
14use std::fmt::Display;
15use url::Url;
16
17const DROPLETS_SEGMENT: &str = "droplets";
18const REPORTS_SEGMENT: &str = "reports";
19const DROPLET_NEIGHBORS_SEGMENT: &str = "droplet_neighbors";
20const NEIGHBORS_SEGMENT: &str = "neighbors";
21const SNAPSHOTS_SEGMENT: &str = "snapshots";
22const BACKUPS_SEGMENT: &str = "backups";
23
24/// A Droplet is a DigitalOcean virtual machine. By sending requests to the
25/// Droplet endpoint, you can list, create, or delete Droplets.
26///
27/// Some of the attributes will have an object value. The region and image
28/// objects will all contain the standard attributes of their associated types.
29/// Find more information about each of these objects in their respective
30/// sections.
31///
32/// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#domains)
33#[derive(Deserialize, Serialize, Debug, Clone, Getters, Setters)]
34#[get = "pub"]
35pub struct Droplet {
36 /// A unique identifier for each Droplet instance. This is automatically
37 /// generated upon Droplet creation.
38 id: usize,
39
40 /// The human-readable name set for the Droplet instance.
41 name: String,
42
43 /// Memory of the Droplet in megabytes.
44 memory: usize,
45
46 /// The number of virtual CPUs.
47 vcpus: usize,
48
49 /// The size of the Droplet's disk in gigabytes.
50 disk: usize,
51
52 /// A boolean value indicating whether the Droplet has been locked,
53 /// preventing actions by users.
54 locked: bool,
55
56 /// A time value given in ISO8601 combined date and time format that
57 /// represents when the Droplet was created.
58 created_at: DateTime<Utc>,
59
60 /// A status string indicating the state of the Droplet instance. This may
61 /// be "new", "active", "off", or "archive".
62 status: String,
63
64 /// An array of backup IDs of any backups that have been taken of the
65 /// Droplet instance. Droplet backups are enabled at the time of the
66 /// instance creation.
67 backup_ids: Vec<usize>,
68
69 /// An array of snapshot IDs of any snapshots created from the Droplet
70 /// instance.
71 snapshot_ids: Vec<usize>,
72
73 /// An array of features enabled on this Droplet.
74 features: Vec<String>,
75
76 /// The region that the Droplet instance is deployed in. When setting a
77 /// region, the value should be the slug identifier for the region. When
78 /// you query a Droplet, the entire region object will be returned.
79 region: Region,
80
81 /// The base image used to create the Droplet instance. When setting an
82 /// image, the value is set to the image id or slug. When querying the
83 /// Droplet, the entire image object will be returned.
84 image: Image,
85
86 /// The current size object describing the Droplet. When setting a size,
87 /// the value is set to the size slug. When querying the Droplet, the
88 /// entire size object will be returned. Note that the disk volume of a
89 /// Droplet may not match the size's disk due to Droplet resize actions.
90 /// The disk attribute on the Droplet should always be referenced.
91 size: Size,
92
93 /// The unique slug identifier for the size of this Droplet.
94 size_slug: String,
95
96 /// The details of the network that are configured for the Droplet
97 /// instance. This is an object that contains keys for IPv4 and IPv6.
98 /// The value of each of these is an array that contains objects describing
99 /// an individual IP resource allocated to the Droplet. These will define
100 /// attributes like the IP address, netmask, and gateway of the specific
101 /// network depending on the type of network it is.
102 networks: Networks,
103
104 /// The current kernel. This will initially be set to the kernel of the
105 /// base image when the Droplet is created.
106 kernel: Option<Kernel>,
107
108 /// The details of the Droplet's backups feature, if backups are configured
109 /// for the Droplet. This object contains keys for the start and end times
110 /// of the window during which the backup will start.
111 next_backup_window: Option<NextBackupWindow>,
112
113 /// An array of Tags the Droplet has been tagged with.
114 tags: Vec<String>,
115
116 /// A flat array including the unique identifier for each Block Storage
117 /// volume attached to the Droplet.
118 volume_ids: Vec<String>,
119}
120
121/// Fields which exists inside Droplets.
122pub mod droplet_fields {
123 use chrono::{DateTime, Utc};
124 use serde::Deserialize;
125 use serde::Serialize;
126 use std::net::{Ipv4Addr, Ipv6Addr};
127
128 /// This exists in the `networks` field of a droplet.
129 #[derive(Deserialize, Serialize, Debug, Clone)]
130 pub struct Networks {
131 pub v4: Vec<NetworkV4>,
132 pub v6: Vec<NetworkV6>,
133 }
134
135 /// These exist in the `networks` field of a droplet.
136 #[derive(Deserialize, Serialize, Debug, Clone)]
137 pub struct NetworkV4 {
138 pub gateway: Ipv4Addr,
139 pub ip_address: Ipv4Addr,
140 pub netmask: Ipv4Addr,
141 /// *Note:* Since `type` is a keyword in Rust `kind` is used instead.
142 #[serde(rename = "type")]
143 pub kind: String,
144 }
145
146 /// These exist in the `networks` field of a droplet.
147 #[derive(Deserialize, Serialize, Debug, Clone)]
148 pub struct NetworkV6 {
149 pub gateway: Ipv6Addr,
150 pub ip_address: Ipv6Addr,
151 pub netmask: usize,
152 /// *Note:* Since `type` is a keyword in Rust `kind` is used instead.
153 #[serde(rename = "type")]
154 pub kind: String,
155 }
156
157 /// This exists in the `next_backup_window` field of a droplet.
158 #[derive(Deserialize, Serialize, Debug, Clone)]
159 pub struct NextBackupWindow {
160 pub end: DateTime<Utc>,
161 pub start: DateTime<Utc>,
162 }
163
164 /// This exists in the `kernel` field of a droplet.
165 #[derive(Deserialize, Serialize, Debug, Clone)]
166 pub struct Kernel {
167 pub id: usize,
168 pub name: String,
169 pub version: String,
170 }
171}
172
173impl Droplet {
174 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
175 pub fn create<S, D>(name: S, region: S, size: S, image: D) -> DropletRequest<Create, Droplet>
176 where
177 S: AsRef<str> + Serialize + Display,
178 D: Serialize + Display,
179 {
180 let mut url = ROOT_URL.clone();
181 url.path_segments_mut()
182 .expect(STATIC_URL_ERROR)
183 .push(DROPLETS_SEGMENT);
184
185 let mut req = Request::new(url);
186 req.set_body(json!({
187 "name": name,
188 "region": region,
189 "size": size,
190 "image": format!("{}", image),
191 }));
192 req
193 }
194
195 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-multiple-droplets)
196 pub fn create_multiple<S, D>(
197 names: Vec<S>,
198 region: S,
199 size: S,
200 image: D,
201 ) -> DropletRequest<Create, Vec<Droplet>>
202 where
203 S: AsRef<str> + Serialize + Display,
204 D: Serialize + Display,
205 {
206 let mut url = ROOT_URL.clone();
207 url.path_segments_mut()
208 .expect(STATIC_URL_ERROR)
209 .push(DROPLETS_SEGMENT);
210
211 let mut req = Request::new(url);
212 req.set_body(json!({
213 "names": names,
214 "region": region,
215 "size": size,
216 "image": format!("{}", image),
217 }));
218 req
219 }
220
221 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#retrieve-an-existing-droplet-by-id)
222 pub fn get(id: usize) -> DropletRequest<Get, Droplet> {
223 let mut url = ROOT_URL.clone();
224 url.path_segments_mut()
225 .expect(STATIC_URL_ERROR)
226 .push(DROPLETS_SEGMENT)
227 .push(&id.to_string());
228
229 Request::new(url)
230 }
231
232 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-all-droplets)
233 pub fn list() -> DropletRequest<List, Vec<Droplet>> {
234 let mut url = ROOT_URL.clone();
235 url.path_segments_mut()
236 .expect(STATIC_URL_ERROR)
237 .push(DROPLETS_SEGMENT);
238
239 Request::new(url)
240 }
241
242 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#listing-droplets-by-tag)
243 pub fn list_by_tag<S: AsRef<str> + Serialize>(name: S) -> DropletRequest<List, Vec<Droplet>> {
244 let mut url = ROOT_URL.clone();
245 url.path_segments_mut()
246 .expect(STATIC_URL_ERROR)
247 .push(DROPLETS_SEGMENT);
248
249 url.query_pairs_mut().append_pair("tag_name", name.as_ref());
250
251 Request::new(url)
252 }
253
254 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#delete-a-droplet)
255 pub fn delete(id: usize) -> DropletRequest<Delete, ()> {
256 let mut url = ROOT_URL.clone();
257 url.path_segments_mut()
258 .expect(STATIC_URL_ERROR)
259 .push(DROPLETS_SEGMENT)
260 .push(&id.to_string());
261
262 Request::new(url)
263 }
264
265 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#deleting-droplets-by-tag)
266 pub fn delete_by_tag<S: AsRef<str> + Serialize>(name: S) -> DropletRequest<Delete, ()> {
267 let mut url = ROOT_URL.clone();
268 url.path_segments_mut()
269 .expect(STATIC_URL_ERROR)
270 .push(DROPLETS_SEGMENT);
271
272 url.query_pairs_mut().append_pair("tag_name", name.as_ref());
273
274 Request::new(url)
275 }
276
277 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-all-droplet-neighbors)
278 pub fn neighbors() -> DropletRequest<Get, Vec<Vec<Droplet>>> {
279 let mut url = ROOT_URL.clone();
280 url.path_segments_mut()
281 .expect(STATIC_URL_ERROR)
282 .push(REPORTS_SEGMENT)
283 .push(DROPLET_NEIGHBORS_SEGMENT);
284
285 Request::new(url)
286 }
287}
288
289impl DropletRequest<Create, Droplet> {
290 /// An array containing the IDs or fingerprints of the SSH keys that you
291 /// wish to embed in the Droplet's root account upon creation.
292 ///
293 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
294 pub fn ssh_keys<D>(mut self, val: Vec<D>) -> Self
295 where
296 D: Display + Serialize,
297 {
298 self.body_mut()["ssh_keys"] = json!(val);
299 self
300 }
301
302 /// A boolean indicating whether automated backups should be enabled for
303 /// the Droplet. Automated backups can only be enabled when the Droplet is
304 /// created.
305 ///
306 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
307 pub fn backups(mut self, val: bool) -> Self {
308 self.body_mut()["backups"] = json!(val);
309 self
310 }
311
312 /// A boolean indicating whether IPv6 is enabled on the Droplet.
313 ///
314 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
315 pub fn ipv6(mut self, val: bool) -> Self {
316 self.body_mut()["ipv6"] = json!(val);
317 self
318 }
319
320 /// A boolean indicating whether private networking is enabled for the
321 /// Droplet. Private networking is currently only available in certain
322 /// regions.
323 ///
324 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
325 pub fn private_networking(mut self, val: bool) -> Self {
326 self.body_mut()["private_networking"] = json!(val);
327 self
328 }
329
330 /// A string containing 'user data' which may be used to configure the
331 /// Droplet on first boot, often a 'cloud-config' file or Bash script.
332 /// It must be plain text and may not exceed 64 KiB in size.
333 ///
334 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
335 pub fn user_data(mut self, val: bool) -> Self {
336 self.body_mut()["user_data"] = json!(val);
337 self
338 }
339
340 /// A boolean indicating whether to install the DigitalOcean agent
341 /// for monitoring.
342 ///
343 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
344 pub fn monitoring(mut self, val: bool) -> Self {
345 self.body_mut()["monitoring"] = json!(val);
346 self
347 }
348
349 /// A flat array including the unique string identifier for each Block
350 /// Storage volume to be attached to the Droplet. At the moment a volume
351 /// can only be attached to a single Droplet.
352 ///
353 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
354 pub fn volumes(mut self, val: Vec<String>) -> Self {
355 self.body_mut()["volumes"] = json!(val);
356 self
357 }
358
359 /// A flat array of tag names as strings to apply to the Droplet after it
360 /// is created. Tag names can either be existing or new tags.
361 ///
362 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
363 pub fn tags(mut self, val: Vec<String>) -> Self {
364 self.body_mut()["tags"] = json!(val);
365 self
366 }
367}
368
369impl DropletRequest<Create, Vec<Droplet>> {
370 /// An array containing the IDs or fingerprints of the SSH keys that you
371 /// wish to embed in the Droplet's root account upon creation.
372 ///
373 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
374 pub fn ssh_keys<D>(mut self, val: Vec<D>) -> Self
375 where
376 D: Display + Serialize,
377 {
378 self.body_mut()["ssh_keys"] = json!(val);
379 self
380 }
381
382 /// A boolean indicating whether automated backups should be enabled for
383 /// the Droplet. Automated backups can only be enabled when the Droplet is
384 /// created.
385 ///
386 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
387 pub fn backups(mut self, val: bool) -> Self {
388 self.body_mut()["backups"] = json!(val);
389 self
390 }
391
392 /// A boolean indicating whether IPv6 is enabled on the Droplet.
393 ///
394 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
395 pub fn ipv6(mut self, val: bool) -> Self {
396 self.body_mut()["ipv6"] = json!(val);
397 self
398 }
399
400 /// A boolean indicating whether private networking is enabled for the
401 /// Droplet. Private networking is currently only available in certain
402 /// regions.
403 ///
404 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
405 pub fn private_networking(mut self, val: bool) -> Self {
406 self.body_mut()["private_networking"] = json!(val);
407 self
408 }
409
410 /// A string containing 'user data' which may be used to configure the
411 /// Droplet on first boot, often a 'cloud-config' file or Bash script.
412 /// It must be plain text and may not exceed 64 KiB in size.
413 ///
414 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
415 pub fn user_data(mut self, val: bool) -> Self {
416 self.body_mut()["user_data"] = json!(val);
417 self
418 }
419
420 /// A boolean indicating whether to install the DigitalOcean agent
421 /// for monitoring.
422 ///
423 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
424 pub fn monitoring(mut self, val: bool) -> Self {
425 self.body_mut()["monitoring"] = json!(val);
426 self
427 }
428
429 /// A flat array including the unique string identifier for each Block
430 /// Storage volume to be attached to the Droplet. At the moment a volume
431 /// can only be attached to a single Droplet.
432 ///
433 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
434 pub fn volumes(mut self, val: Vec<String>) -> Self {
435 self.body_mut()["volumes"] = json!(val);
436 self
437 }
438
439 /// A flat array of tag names as strings to apply to the Droplet after it
440 /// is created. Tag names can either be existing or new tags.
441 ///
442 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#create-a-new-droplet)
443 pub fn tags(mut self, val: Vec<String>) -> Self {
444 self.body_mut()["tags"] = json!(val);
445 self
446 }
447}
448
449impl DropletRequest<Get, Droplet> {
450 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-snapshots-for-a-droplet)
451 pub fn snapshots(mut self) -> SnapshotRequest<List, Vec<Snapshot>> {
452 self.url_mut()
453 .path_segments_mut()
454 .expect(STATIC_URL_ERROR)
455 .push(SNAPSHOTS_SEGMENT);
456
457 self.transmute()
458 }
459
460 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-backups-for-a-droplet)
461 pub fn backups(mut self) -> SnapshotRequest<List, Vec<Snapshot>> {
462 self.url_mut()
463 .path_segments_mut()
464 .expect(STATIC_URL_ERROR)
465 .push(BACKUPS_SEGMENT);
466
467 self.transmute()
468 }
469
470 /// [Digital Ocean Documentation.](https://developers.digitalocean.com/documentation/v2/#list-neighbors-for-a-droplet)
471 pub fn neighbors(mut self) -> DropletRequest<List, Vec<Droplet>> {
472 self.url_mut()
473 .path_segments_mut()
474 .expect(STATIC_URL_ERROR)
475 .push(NEIGHBORS_SEGMENT);
476
477 self.transmute()
478 }
479}
480
481/// Response type returned from Digital Ocean.
482#[derive(Deserialize, Serialize, Debug, Clone)]
483pub struct DropletResponse {
484 droplet: Droplet,
485}
486
487impl HasResponse for Droplet {
488 type Response = DropletResponse;
489}
490
491impl HasValue for DropletResponse {
492 type Value = Droplet;
493
494 fn value(self) -> Droplet {
495 self.droplet
496 }
497}
498
499/// Response type returned from Digital Ocean.
500#[derive(Deserialize, Serialize, Debug, Clone)]
501pub struct DropletListResponse {
502 droplets: Vec<Droplet>,
503 links: ApiLinks,
504 meta: ApiMeta,
505}
506
507impl HasResponse for Vec<Droplet> {
508 type Response = DropletListResponse;
509}
510
511impl HasPagination for DropletListResponse {
512 fn next_page(&self) -> Option<Url> {
513 self.links.next()
514 }
515}
516
517impl HasValue for DropletListResponse {
518 type Value = Vec<Droplet>;
519
520 fn value(self) -> Vec<Droplet> {
521 self.droplets
522 }
523}
524
525/// Response type returned from Digital Ocean
526#[derive(Deserialize, Serialize, Debug, Clone)]
527pub struct DropletNeighborsResponse {
528 neighbors: Vec<Vec<Droplet>>,
529}
530
531impl HasResponse for Vec<Vec<Droplet>> {
532 type Response = DropletNeighborsResponse;
533}
534
535impl HasValue for DropletNeighborsResponse {
536 type Value = Vec<Vec<Droplet>>;
537
538 fn value(self) -> Vec<Vec<Droplet>> {
539 self.neighbors
540 }
541}