Skip to main content

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}