mod api_error;
mod create_instance_builder;
mod data;
mod error;
use api_error::UpcloudApiErrorRoot;
use data::{
UpcloudAccountRoot, UpcloudAccountsListRoot, UpcloudPlanListRoot, UpcloudPricesListRoot,
UpcloudServerListRoot, UpcloudServerRoot, UpcloudServerTemplateListRoot, UpcloudZoneListRoot,
};
use serde::Serialize;
use serde_json::json;
pub use create_instance_builder::CreateInstanceBuilder;
pub use data::{
UpcloudAccount, UpcloudAccountsListItem, UpcloudLabel, UpcloudLabelList, UpcloudPlan,
UpcloudPrice, UpcloudPricesZone, UpcloudServer, UpcloudServerTemplate, UpcloudTagList,
UpcloudZone,
};
pub use error::UpcloudError;
#[derive(Clone)]
pub struct UpcloudApi {
username: String,
password: String,
}
impl<'a> UpcloudApi {
pub fn new<S1, S2>(username: S1, password: S2) -> UpcloudApi
where
S1: Into<String>,
S2: Into<String>,
{
UpcloudApi {
username: username.into(),
password: password.into(),
}
}
#[cfg(feature = "blocking")]
fn get(&self, url: &str) -> Result<reqwest::blocking::Response, UpcloudError> {
let client = reqwest::blocking::Client::new();
let resp = client
.get(url)
.basic_auth(&self.username, Some(&self.password))
.send()?;
let status = resp.status();
if status.is_client_error() {
let result: UpcloudApiErrorRoot = resp.json()?;
Err(UpcloudError::Api(result.error.error_message))
} else {
Ok(resp.error_for_status()?)
}
}
async fn get_async(&self, url: &str) -> Result<reqwest::Response, UpcloudError> {
let client = reqwest::Client::new();
let resp = client
.get(url)
.basic_auth(&self.username, Some(&self.password))
.send()
.await?;
let status = resp.status();
if status.is_client_error() {
let result: UpcloudApiErrorRoot = resp.json().await?;
Err(UpcloudError::Api(result.error.error_message))
} else {
Ok(resp.error_for_status()?)
}
}
#[cfg(feature = "blocking")]
fn post<T>(&self, url: &str, json: T) -> Result<reqwest::blocking::Response, UpcloudError>
where
T: Serialize + Sized,
{
let client = reqwest::blocking::Client::new();
let resp = client
.post(url)
.basic_auth(&self.username, Some(&self.password))
.json(&json)
.send()?;
let status = resp.status();
if status.is_client_error() {
let result: UpcloudApiErrorRoot = resp.json()?;
Err(UpcloudError::Api(result.error.error_message))
} else {
Ok(resp.error_for_status()?)
}
}
async fn post_async<T>(&self, url: &str, json: T) -> Result<reqwest::Response, UpcloudError>
where
T: Serialize + Sized,
{
let client = reqwest::Client::new();
let resp = client
.post(url)
.basic_auth(&self.username, Some(&self.password))
.json(&json)
.send()
.await?;
let status = resp.status();
if status.is_client_error() {
let result: UpcloudApiErrorRoot = resp.json().await?;
Err(UpcloudError::Api(result.error.error_message))
} else {
Ok(resp.error_for_status()?)
}
}
#[cfg(feature = "blocking")]
fn delete(&self, url: &str) -> Result<reqwest::blocking::Response, UpcloudError> {
let client = reqwest::blocking::Client::new();
let resp = client
.delete(url)
.basic_auth(&self.username, Some(&self.password))
.send()?;
let status = resp.status();
if status.is_client_error() {
let result: UpcloudApiErrorRoot = resp.json()?;
Err(UpcloudError::Api(result.error.error_message))
} else {
Ok(resp.error_for_status()?)
}
}
async fn delete_async(&self, url: &str) -> Result<reqwest::Response, UpcloudError> {
let client = reqwest::Client::new();
let resp = client
.delete(url)
.basic_auth(&self.username, Some(&self.password))
.send()
.await?;
let status = resp.status();
if status.is_client_error() {
let result: UpcloudApiErrorRoot = resp.json().await?;
Err(UpcloudError::Api(result.error.error_message))
} else {
Ok(resp.error_for_status()?)
}
}
#[cfg(feature = "blocking")]
pub fn get_account_info(&self) -> Result<UpcloudAccount, UpcloudError> {
Ok(self
.get("https://api.Upcloud.com/1.3/account")?
.json::<UpcloudAccountRoot>()?
.account)
}
pub async fn get_account_info_async(&self) -> Result<UpcloudAccount, UpcloudError> {
Ok(self
.get_async("https://api.Upcloud.com/1.3/account")
.await?
.json::<UpcloudAccountRoot>()
.await?
.account)
}
#[cfg(feature = "blocking")]
pub fn get_account_list(&self) -> Result<Vec<UpcloudAccountsListItem>, UpcloudError> {
Ok(self
.get("https://api.Upcloud.com/1.3/account/list")?
.json::<UpcloudAccountsListRoot>()?
.accounts
.account)
}
pub async fn get_account_list_async(
&self,
) -> Result<Vec<UpcloudAccountsListItem>, UpcloudError> {
Ok(self
.get_async("https://api.Upcloud.com/1.3/account/list")
.await?
.json::<UpcloudAccountsListRoot>()
.await?
.accounts
.account)
}
#[cfg(feature = "blocking")]
pub fn get_prices(&self) -> Result<Vec<UpcloudPricesZone>, UpcloudError> {
Ok(self
.get("https://api.Upcloud.com/1.3/price")?
.json::<UpcloudPricesListRoot>()?
.prices
.zone)
}
pub async fn get_prices_async(&self) -> Result<Vec<UpcloudPricesZone>, UpcloudError> {
Ok(self
.get_async("https://api.Upcloud.com/1.3/price")
.await?
.json::<UpcloudPricesListRoot>()
.await?
.prices
.zone)
}
#[cfg(feature = "blocking")]
pub fn get_zones(&self) -> Result<Vec<UpcloudZone>, UpcloudError> {
Ok(self
.get("https://api.Upcloud.com/1.3/zone")?
.json::<UpcloudZoneListRoot>()?
.zones
.zone)
}
pub async fn get_zones_async(&self) -> Result<Vec<UpcloudZone>, UpcloudError> {
Ok(self
.get_async("https://api.Upcloud.com/1.3/zone")
.await?
.json::<UpcloudZoneListRoot>()
.await?
.zones
.zone)
}
#[cfg(feature = "blocking")]
pub fn get_plans(&self) -> Result<Vec<UpcloudPlan>, UpcloudError> {
Ok(self
.get("https://api.Upcloud.com/1.3/plan")?
.json::<UpcloudPlanListRoot>()?
.plans
.plan)
}
pub async fn get_plans_async(&self) -> Result<Vec<UpcloudPlan>, UpcloudError> {
Ok(self
.get_async("https://api.Upcloud.com/1.3/plan")
.await?
.json::<UpcloudPlanListRoot>()
.await?
.plans
.plan)
}
#[cfg(feature = "blocking")]
pub fn get_servers(&self) -> Result<Vec<UpcloudServer>, UpcloudError> {
Ok(self
.get("https://api.Upcloud.com/1.3/server")?
.json::<UpcloudServerListRoot>()?
.servers
.server)
}
pub async fn get_servers_async(&self) -> Result<Vec<UpcloudServer>, UpcloudError> {
Ok(self
.get_async("https://api.Upcloud.com/1.3/server")
.await?
.json::<UpcloudServerListRoot>()
.await?
.servers
.server)
}
#[cfg(feature = "blocking")]
pub fn get_server_details(&self, machine_id: &str) -> Result<UpcloudServer, UpcloudError> {
Ok(self
.get(&format!("https://api.Upcloud.com/1.3/server/{uuid}", uuid = machine_id))?
.json::<UpcloudServerRoot>()?
.server)
}
pub async fn get_server_details_async(&self, machine_id: &str) -> Result<UpcloudServer, UpcloudError> {
Ok(self
.get_async(&format!("https://api.Upcloud.com/1.3/server/{uuid}", uuid = machine_id))
.await?
.json::<UpcloudServerRoot>()
.await?
.server)
}
#[cfg(feature = "blocking")]
pub fn get_server_templates(&self) -> Result<Vec<UpcloudServerTemplate>, UpcloudError> {
Ok(self
.get("https://api.Upcloud.com/1.3/storage/template")?
.json::<UpcloudServerTemplateListRoot>()?
.storages
.storage)
}
pub async fn get_server_templates_async(
&self,
) -> Result<Vec<UpcloudServerTemplate>, UpcloudError> {
Ok(self
.get_async("https://api.Upcloud.com/1.3/storage/template")
.await?
.json::<UpcloudServerTemplateListRoot>()
.await?
.storages
.storage)
}
pub fn create_instance<S1, S2, S3, S4, S5>(
&self,
region_id: S1,
plan_id: S2,
os_id: S3,
title: S4,
hostname: S5,
) -> CreateInstanceBuilder
where
S1: Into<String> + Serialize,
S2: Into<String> + Serialize,
S3: Into<String> + Serialize,
S4: Into<String> + Serialize,
S5: Into<String> + Serialize,
{
CreateInstanceBuilder::new(self.clone(), region_id, plan_id, os_id, title, hostname)
}
#[cfg(feature = "blocking")]
pub fn delete_instance(&self, machine_uuid: &str) -> Result<(), UpcloudError> {
self.delete(&format!(
"https://api.Upcloud.com/1.3/server/{uuid}?storages=true&backups=delete",
uuid = machine_uuid
))?;
Ok(())
}
pub async fn delete_instance_async(&self, machine_uuid: &str) -> Result<(), UpcloudError> {
self.delete_async(&format!(
"https://api.Upcloud.com/1.3/server/{uuid}?storages=true&backups=delete",
uuid = machine_uuid
))
.await?;
Ok(())
}
#[cfg(feature = "blocking")]
pub fn stop_instance(&self, machine_uuid: &str) -> Result<UpcloudServer, UpcloudError> {
let server = self
.post(
&format!(
"https://api.Upcloud.com/1.3/server/{uuid}/stop",
uuid = machine_uuid
),
json! ({
"stop_server": {
"stop_type": "hard"
}
}),
)?
.json::<UpcloudServerRoot>()?
.server;
Ok(server)
}
pub async fn stop_instance_async(
&self,
machine_uuid: &str,
) -> Result<UpcloudServer, UpcloudError> {
let server = self
.post_async(
&format!(
"https://api.Upcloud.com/1.3/server/{uuid}/stop",
uuid = machine_uuid
),
json! ({
"stop_server": {
"stop_type": "hard"
}
}),
)
.await?
.json::<UpcloudServerRoot>()
.await?
.server;
Ok(server)
}
}