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