dsh_api 0.9.0

DSH resource management API client
Documentation
//! # Client tenant
use crate::error::DshApiResult;
use crate::platform::DshPlatform;
use crate::{DshApiError, ENV_VAR_TENANT};
use log::{debug, info};
use serde::Serialize;
use std::env;
use std::fmt::{Display, Formatter};
use std::sync::LazyLock;

#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize)]
pub struct DshApiTenant {
  name: String,
  platform: DshPlatform,
}

impl DshApiTenant {
  /// # Create new DSH API tenant
  ///
  /// # Parameters
  /// * `name` - Client tenant's name.
  /// * `platform` - Target platform for the API.
  ///
  /// # Examples
  ///
  /// ```
  /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
  /// # use dsh_api::dsh_api_tenant::DshApiTenant;
  /// # use dsh_api::platform::DshPlatform;
  /// let name = "my-tenant";
  /// let platform = DshPlatform::try_from("nplz")?;
  /// let dsh_api_tenant = DshApiTenant::new(name, platform);
  /// assert_eq!(
  ///   dsh_api_tenant.platform().internal_domain("my-tenant"),
  ///   "my-tenant.marathon.mesos".to_string()
  /// );
  /// # Ok(())
  /// # }
  /// ```
  pub fn new<T>(name: T, platform: DshPlatform) -> Self
  where
    T: Into<String>,
  {
    Self { name: name.into(), platform }
  }

  /// # Create new DSH API tenant from tenant's name
  ///
  /// This factory function will attempt to create a `DshapiTenant` instance from the provided
  /// tenant's name.
  /// The platform will be read from the
  /// environment variable `DSH_API_PLATFORM`.
  /// The function will return an `Error<String>` if the environment variables are not set
  /// or contains illegal values.
  ///
  /// # Parameters
  /// * `tenant_name` - Tenant's name.
  ///
  /// # Returns
  /// * `Ok(tenant)` - Tenant struct.
  /// * `Err(error)` - Configuration error.
  ///
  /// # Examples
  ///
  /// ```no_run
  /// # use dsh_api::dsh_api_tenant::DshApiTenant;
  /// # use dsh_api::platform::DshPlatform;
  /// # use dsh_api::error::DshApiResult;
  /// # fn main() -> DshApiResult<()> {
  /// let tenant_name = "my-tenant";
  /// let dsh_api_tenant = DshApiTenant::from_tenant(tenant_name)?;
  /// println!("target platform: {}", dsh_api_tenant.platform());
  /// # Ok(())
  /// # }
  /// ```
  pub fn from_tenant<T>(tenant_name: T) -> DshApiResult<Self>
  where
    T: Into<String>,
  {
    let platform = DshPlatform::default();
    Ok(DshApiTenant::new(tenant_name, platform))
  }

  /// # Create new DSH API tenant from tenant's name and platform
  ///
  /// This factory function will attempt to create a `DshapiTenant` instance from the provided
  /// tenant's name.
  /// The function will return an `Error<String>` if the environment variable is not set.
  ///
  /// # Parameters
  /// * `tenant_name` - Tenant's name.
  /// * `platform` - Target platform for the API.
  ///
  /// # Returns
  /// * `Ok(tenant)` - Tenant struct.
  /// * `Err(error)` - Configuration error.
  ///
  /// # Examples
  ///
  /// ```
  /// # use dsh_api::dsh_api_tenant::DshApiTenant;
  /// # use dsh_api::platform::DshPlatform;
  /// # use dsh_api::error::DshApiResult;
  /// # fn main() -> DshApiResult<()> {
  /// let tenant_name = String::from("my-tenant");
  /// let platform = DshPlatform::try_from("nplz")?;
  /// let dsh_api_tenant = DshApiTenant::from_tenant_and_platform(tenant_name, platform)?;
  /// println!("{}@{}", dsh_api_tenant.name(), dsh_api_tenant.platform());
  /// # Ok(())
  /// # }
  /// ```
  pub fn from_tenant_and_platform<T>(tenant_name: T, platform: DshPlatform) -> DshApiResult<Self>
  where
    T: Into<String>,
  {
    Ok(DshApiTenant::new(tenant_name, platform))
  }

  /// # Create new DSH API tenant from platform
  ///
  /// This factory function will attempt to create a `DshapiTenant` instance from the provided
  /// `platform`. The tenant's name will be read from the environment variable.
  /// The function will return an `Error<String>` if the environment variables are not set.
  ///
  /// # Parameters
  /// * `platform` - Target platform for the API
  ///
  /// # Returns
  /// * `Ok(tenant)` - Tenant struct.
  /// * `Err(error)` - Configuration error.
  ///
  /// # Examples
  ///
  /// ```no_run
  /// # use dsh_api::dsh_api_tenant::DshApiTenant;
  /// # use dsh_api::platform::DshPlatform;
  /// # use dsh_api::error::DshApiResult;
  /// # fn main() -> DshApiResult<()> {
  /// let platform = DshPlatform::try_from("nplz")?;
  /// let dsh_api_tenant = DshApiTenant::from_platform(platform)?;
  /// println!("{}@{}", dsh_api_tenant.name(), dsh_api_tenant.platform());
  /// # Ok(())
  /// # }
  /// ```
  pub fn from_platform(platform: DshPlatform) -> DshApiResult<Self> {
    let tenant_name = match env::var(ENV_VAR_TENANT) {
      Ok(name) => name,
      Err(_) => return Err(DshApiError::configuration(format!("environment variable {} not set", ENV_VAR_TENANT))),
    };
    Ok(DshApiTenant::new(tenant_name, platform))
  }

  /// Returns the default tenant
  ///
  /// This method will read the tenant name and platform form the respective
  /// environment variables and will create a`DshApiTenant` if possible. It will return an
  /// `Error<String>` when one or more of these the environment variables is not set or
  /// contains an undefined value.
  ///
  /// # Returns
  /// * `Ok<tenant>` - When the environment variables are provided and contain valid values.
  /// * `Error<String>` - when one or more of the environment variables is not set or
  ///   contains an undefined value
  ///
  /// # Examples
  ///
  /// ```no_run
  /// # use dsh_api::dsh_api_tenant::DshApiTenant;
  /// # use dsh_api::error::DshApiResult;
  /// # fn main() -> DshApiResult<()> {
  /// let default_tenant = DshApiTenant::try_default()?;
  /// println!("{}@{}", default_tenant.name(), default_tenant.platform());
  /// # Ok(())
  /// # }
  /// ```
  pub fn try_default() -> DshApiResult<Self> {
    let tenant_name = get_default_tenant_name()?;
    let platform = DshPlatform::try_default()?;
    Ok(DshApiTenant::new(tenant_name, platform))
  }

  /// Returns the client's platform
  pub fn platform(&self) -> &DshPlatform {
    &self.platform
  }

  /// Returns the client's tenant name
  pub fn name(&self) -> &String {
    &self.name
  }
}

impl Default for DshApiTenant {
  /// Returns the default tenant
  ///
  /// This method will read the tenant name and platform form the respective
  /// environment variables and will create a`DshApiTenant` if possible.
  ///
  /// # Panics
  /// This method will panic if the environment variable is not set or
  /// if it contains an invalid platform name.
  fn default() -> Self {
    match Self::try_default() {
      Ok(dsh_api_tenant) => {
        info!("default dsh api tenant {} created", dsh_api_tenant);
        dsh_api_tenant
      }
      Err(error) => panic!("{}", error),
    }
  }
}

impl Display for DshApiTenant {
  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    write!(f, "{}@{}", self.name, self.platform)
  }
}

/// Lazily initialized default tenant
///
/// This method will read the tenant name and platform form the respective
/// environment variables and will create a`DshApiTenant` if possible.
///
/// # Panics
/// Referencing this value will panic if the environment variable is not set or
/// if it contains an invalid platform name.
pub static DEFAULT_DSH_API_TENANT: LazyLock<DshApiTenant> = LazyLock::new(DshApiTenant::default);

fn get_default_tenant_name() -> DshApiResult<String> {
  match env::var(ENV_VAR_TENANT) {
    Ok(tenant_name) => {
      debug!("tenant '{}' (environment variable '{}')", tenant_name, ENV_VAR_TENANT);
      Ok(tenant_name)
    }
    Err(_) => Err(DshApiError::configuration(format!("environment variable '{}' not set", ENV_VAR_TENANT))),
  }
}