mod api_error;
mod builder;
mod data;
mod linode_error;
use api_error::LinodeApiError;
use data::linode_availability::LinodeAvailabilityListRoot;
use data::linode_instance::LinodeInstanceListRoot;
use data::linode_region::LinodeRegionListRoot;
use data::PostEmpty;
use data::{linode_os::LinodeOsListRoot, linode_types::LinodeTypeListRoot};
use serde::Serialize;
pub use builder::create_instance::LinodeCreateInstanceBuilder;
pub use data::linode_availability::LinodeAvailability;
pub use data::linode_instance::{
LinodeInstance, LinodeInstanceAlerts, LinodeInstanceBackupSchedule, LinodeInstanceBackups,
LinodeInstanceSpecs,
};
pub use data::linode_os::LinodeOs;
pub use data::linode_region::{LinodeRegion, LinodeRegionResolver};
pub use data::linode_types::{
LinodeType, LinodeTypeAddon, LinodeTypeAddons, LinodeTypePrice, LinodeTypeRegionPrice,
};
pub use linode_error::LinodeError;
#[derive(Clone)]
pub struct LinodeApi {
token: String,
}
impl<'a> LinodeApi {
pub fn new<S>(token: S) -> LinodeApi
where
S: Into<String>,
{
LinodeApi {
token: token.into(),
}
}
async fn get_async(&self, url: &str) -> Result<reqwest::Response, LinodeError> {
let client = reqwest::Client::new();
let resp = client
.get(url)
.bearer_auth(&self.token)
.send()
.await
.map_err(|e| LinodeError::Reqwest(e))?;
let status = resp.status();
if status.is_client_error() {
let result: LinodeApiError = resp.json().await?;
Err(LinodeError::Api(result))
} else {
Ok(resp.error_for_status()?)
}
}
#[cfg(feature = "blocking")]
fn get(&self, url: &str) -> Result<reqwest::blocking::Response, LinodeError> {
let client = reqwest::blocking::Client::new();
let resp = client.get(url).bearer_auth(&self.token).send()?;
let status = resp.status();
if status.is_client_error() {
let result: LinodeApiError = resp.json()?;
Err(LinodeError::Api(result))
} else {
Ok(resp.error_for_status()?)
}
}
async fn post_async<T>(&self, url: &str, json: T) -> Result<reqwest::Response, LinodeError>
where
T: Serialize + Sized,
{
let client = reqwest::Client::new();
let resp = client
.post(url)
.bearer_auth(&self.token)
.json(&json)
.send()
.await?;
let status = resp.status();
if status.is_client_error() {
let result: LinodeApiError = resp.json().await?;
Err(LinodeError::Api(result))
} else {
Ok(resp.error_for_status()?)
}
}
#[cfg(feature = "blocking")]
fn post<T>(&self, url: &str, json: T) -> Result<reqwest::blocking::Response, LinodeError>
where
T: Serialize + Sized,
{
let client = reqwest::blocking::Client::new();
let resp = client
.post(url)
.bearer_auth(&self.token)
.json(&json)
.send()?;
let status = resp.status();
if status.is_client_error() {
let result: LinodeApiError = resp.json()?;
Err(LinodeError::Api(result))
} else {
Ok(resp.error_for_status()?)
}
}
async fn delete_async(&self, url: &str) -> Result<reqwest::Response, LinodeError> {
let client = reqwest::Client::new();
let resp = client.delete(url).bearer_auth(&self.token).send().await?;
let status = resp.status();
if status.is_client_error() {
let result: LinodeApiError = resp.json().await?;
Err(LinodeError::Api(result))
} else {
Ok(resp.error_for_status()?)
}
}
#[cfg(feature = "blocking")]
fn delete(&self, url: &str) -> Result<reqwest::blocking::Response, LinodeError> {
let client = reqwest::blocking::Client::new();
let resp = client.delete(url).bearer_auth(&self.token).send()?;
let status = resp.status();
if status.is_client_error() {
let result: LinodeApiError = resp.json()?;
Err(LinodeError::Api(result))
} else {
Ok(resp.error_for_status()?)
}
}
pub async fn list_os_async(&self) -> Result<Vec<LinodeOs>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get_async(&format!(
"https://api.linode.com/v4/images?page={page}",
page = page
))
.await?
.json::<LinodeOsListRoot>()
.await?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
#[cfg(feature = "blocking")]
pub fn list_os(&self) -> Result<Vec<LinodeOs>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get(&format!(
"https://api.linode.com/v4/images?page={page}",
page = page
))?
.json::<LinodeOsListRoot>()?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
pub async fn list_types_async(&self) -> Result<Vec<LinodeType>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get_async(&format!(
"https://api.linode.com/v4/linode/types?page={page}",
page = page
))
.await?
.json::<LinodeTypeListRoot>()
.await?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
#[cfg(feature = "blocking")]
pub fn list_types(&self) -> Result<Vec<LinodeType>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get(&format!(
"https://api.linode.com/v4/linode/types?page={page}",
page = page
))?
.json::<LinodeTypeListRoot>()?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
pub async fn list_regions_async(&self) -> Result<Vec<LinodeRegion>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get_async(&format!(
"https://api.linode.com/v4/regions?page={page}",
page = page
))
.await?
.json::<LinodeRegionListRoot>()
.await?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
#[cfg(feature = "blocking")]
pub fn list_regions(&self) -> Result<Vec<LinodeRegion>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get(&format!(
"https://api.linode.com/v4/regions?page={page}",
page = page
))?
.json::<LinodeRegionListRoot>()?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
pub async fn list_availability_async(&self) -> Result<Vec<LinodeAvailability>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get_async(&format!(
"https://api.linode.com/v4/regions/availability?page={page}",
page = page
))
.await?
.json::<LinodeAvailabilityListRoot>()
.await?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
#[cfg(feature = "blocking")]
pub fn list_availability(&self) -> Result<Vec<LinodeAvailability>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get(&format!(
"https://api.linode.com/v4/regions/availability?page={page}",
page = page
))?
.json::<LinodeAvailabilityListRoot>()?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
pub async fn list_instances_async(&self) -> Result<Vec<LinodeInstance>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get_async(&format!(
"https://api.linode.com/v4/linode/instances?page={page}",
page = page
))
.await?
.json::<LinodeInstanceListRoot>()
.await?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
#[cfg(feature = "blocking")]
pub fn list_instances(&self) -> Result<Vec<LinodeInstance>, LinodeError> {
let mut list = vec![];
let mut page = 1;
loop {
let result = self
.get(&format!(
"https://api.linode.com/v4/linode/instances?page={page}",
page = page
))?
.json::<LinodeInstanceListRoot>()?;
if result.data.len() > 0 {
list.extend(result.data.into_iter());
}
page += 1;
if page > result.pages {
break;
}
}
Ok(list)
}
pub async fn get_instance_async(
&self,
instance_id: u64,
) -> Result<LinodeInstance, LinodeError> {
let instance = self
.get_async(&format!(
"https://api.linode.com/v4/linode/instances/{instance_id}",
instance_id = instance_id,
))
.await?
.json::<LinodeInstance>()
.await?;
Ok(instance)
}
#[cfg(feature = "blocking")]
pub fn get_instance(&self, instance_id: u64) -> Result<LinodeInstance, LinodeError> {
let instance = self
.get(&format!(
"https://api.linode.com/v4/linode/instances/{instance_id}",
instance_id = instance_id,
))?
.json::<LinodeInstance>()?;
Ok(instance)
}
pub async fn delete_instance_async(&self, instance_id: u64) -> Result<(), LinodeError> {
self.delete_async(&format!(
"https://api.linode.com/v4/linode/instances/{instance_id}",
instance_id = instance_id,
))
.await?
.error_for_status()?;
Ok(())
}
#[cfg(feature = "blocking")]
pub fn delete_instance(&self, instance_id: u64) -> Result<(), LinodeError> {
self.delete(&format!(
"https://api.linode.com/v4/linode/instances/{instance_id}",
instance_id = instance_id,
))?
.error_for_status()?;
Ok(())
}
pub async fn shutdown_instance_async(&self, instance_id: u64) -> Result<(), LinodeError> {
self.post_async(
&format!(
"https://api.linode.com/v4/linode/instances/{instance_id}/shutdown",
instance_id = instance_id,
),
PostEmpty {},
)
.await?
.error_for_status()?;
Ok(())
}
#[cfg(feature = "blocking")]
pub fn shutdown_instance(&self, instance_id: u64) -> Result<(), LinodeError> {
self.post(
&format!(
"https://api.linode.com/v4/linode/instances/{instance_id}/shutdown",
instance_id = instance_id,
),
PostEmpty {},
)?
.error_for_status()?;
Ok(())
}
pub fn create_instance(&self, region: &str, ltype: &str) -> LinodeCreateInstanceBuilder {
LinodeCreateInstanceBuilder::new(self.clone(), region, ltype)
}
}