Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions coman/src/app/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ use crate::{
login_popup::LoginPopup, resource_usage::ResourceUsage, system_select_popup::SystemSelectPopup,
workload_details::WorkloadDetails, workload_list::WorkloadList, workload_log::WorkloadLog,
},
config::Config,
cscs::{
handlers::{cscs_login, cscs_system_set},
handlers::{cscs_login, cscs_system_set, get_available_compute_platforms},
ports::{BackgroundTask, JobLogAction, JobResourceUsageAction},
},
trace_dbg,
Expand Down Expand Up @@ -509,7 +510,43 @@ where
let error_tx = self.error_tx.clone();
tokio::spawn(async move {
match cscs_login(client_id, client_secret).await {
Ok(_) => event_tx.send(UserEvent::Cscs(CscsEvent::LoggedIn)).await.unwrap(),
Ok(_) => {
Comment thread
Panaetius marked this conversation as resolved.
let mut config = match Config::new() {
Ok(config) => config,
Err(e) => {
error_tx
.send(format!(
"{:?}",
Err::<(), Report>(e).wrap_err("Couldn't create config object")
))
.await
.unwrap();
return;
}
};
let source = config.value_source("cscs.current_platform");
Comment thread
Panaetius marked this conversation as resolved.
if !source.1 && !source.2 {
// don't override platform if it's already set
if let Ok(available_platforms) = get_available_compute_platforms().await
Comment thread
Panaetius marked this conversation as resolved.
&& !available_platforms.is_empty()
&& let Err(e) = config.set(
"cscs.current_platform",
available_platforms[0].to_string(),
true,
)
{
error_tx
.send(format!(
"{:?}",
Err::<(), Report>(e).wrap_err("Couldn't set currnt platform")
))
.await
.unwrap();
return;
}
}
event_tx.send(UserEvent::Cscs(CscsEvent::LoggedIn)).await.unwrap()
Comment thread
Panaetius marked this conversation as resolved.
}
Err(e) => error_tx
.send(format!(
"{:?}",
Expand Down
12 changes: 7 additions & 5 deletions coman/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use color_eyre::{
use directories::ProjectDirs;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use strum_macros::{EnumIter, EnumString, VariantNames};
use strum_macros::{EnumIter, EnumString, VariantArray, VariantNames};
Comment thread
Panaetius marked this conversation as resolved.
use toml_edit::DocumentMut;

const DEFAULT_CONFIG_TOML: &str = include_str!("../.config/config.toml");
Expand All @@ -33,7 +33,9 @@ pub struct SystemDescription {
pub architecture: Vec<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize, Default, strum::Display, EnumString, VariantNames, EnumIter)]
#[derive(
Comment thread
Panaetius marked this conversation as resolved.
Clone, Debug, Serialize, Deserialize, Default, strum::Display, EnumString, VariantNames, VariantArray, EnumIter,
)]
#[strum(serialize_all = "lowercase")]
#[allow(clippy::upper_case_acronyms)]
pub enum ComputePlatform {
Expand Down Expand Up @@ -333,15 +335,15 @@ impl Config {
}

// Returns tuple of bool saying whether a values is set in (default, global, project local) config
pub fn value_source(&self, key_path: &str) -> Result<(bool, bool, bool)> {
Ok((
pub fn value_source(&self, key_path: &str) -> (bool, bool, bool) {
Comment thread
Panaetius marked this conversation as resolved.
(
Comment thread
Panaetius marked this conversation as resolved.
self.default_layer.get(key_path).is_some(),
self.global_layer.get(key_path).unwrap_or_default().is_some(),
self.project_layer
.as_ref()
.map(|l| l.get(key_path).unwrap_or_default().is_some())
.unwrap_or(false),
))
)
}
}

Expand Down
33 changes: 30 additions & 3 deletions coman/src/cscs/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@ use bytesize::ByteSize;
use color_eyre::{Result, eyre::Context};
use eyre::eyre;
use futures::StreamExt;
use inquire::{Password, Text};
use inquire::{Password, Select, Text};
use itertools::Itertools;
use reqwest::Url;
use strum::VariantArray;
use tokio::{
fs::File,
io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt, BufReader},
};

use crate::{
cli::app::JobIdOrName,
config::ComputePlatform,
config::{ComputePlatform, Config},
cscs::{
api_client::{client::JobStartOptions, types::JobStatus},
handlers::{
cscs_file_delete, cscs_file_download, cscs_file_list, cscs_file_upload, cscs_job_cancel, cscs_job_details,
cscs_job_list, cscs_job_log, cscs_job_start, cscs_login, cscs_port_forward, cscs_resource_usage,
cscs_system_list, cscs_system_set,
cscs_system_list, cscs_system_set, get_available_compute_platforms,
},
},
};
Expand All @@ -39,6 +40,32 @@ pub(crate) async fn cli_cscs_login() -> Result<()> {
}
Err(e) => Err(e).wrap_err("couldn't get acccess token")?,
};

// select compute platform
let mut config = Config::new()?;

let source = config.value_source("cscs.current_platform");
if !source.1 && !source.2 {
Comment thread
Panaetius marked this conversation as resolved.
let available_platforms: Vec<_> = get_available_compute_platforms()
.await
.unwrap_or(<ComputePlatform as VariantArray>::VARIANTS.to_vec())
.iter()
.map(|c| c.to_string())
.collect();
let platform = Select::new("Compute Platform:", available_platforms).prompt()?;

config.set("cscs.current_platform", platform, true)?;
}

// select cscs account
let source = config.value_source("cscs.account");
if !source.1
&& !source.2
&& let Ok(Some(account)) = Text::new("CSCS Account:").prompt_skippable()
&& !account.is_empty()
{
config.set("cscs.account", account, true)?;
}
Ok(())
}
pub(crate) async fn cli_cscs_job_list(system: Option<String>, platform: Option<ComputePlatform>) -> Result<()> {
Expand Down
32 changes: 17 additions & 15 deletions coman/src/cscs/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,28 +80,30 @@ async fn get_access_token() -> Result<Secret> {
let token = client_credentials_login(client_id, client_secret).await?;
Ok(token.0)
}

pub(crate) async fn cscs_login(client_id: String, client_secret: String) -> Result<()> {
let client_id_secret = Secret::new(client_id);
store_secret(CLIENT_ID_SECRET_NAME, client_id_secret.clone()).await?;
let client_secret_secret = Secret::new(client_secret);
store_secret(CLIENT_SECRET_SECRET_NAME, client_secret_secret.clone()).await?;
let token = client_credentials_login(client_id_secret, client_secret_secret).await?;

// figure out what platform the user has access to and set it in config
let mut config = Config::new()?;
let source = config.value_source("cscs.current_platform")?;
if source.1 || source.2 {
// don't override setting if it's already provided
return Ok(());
}
for platform in ComputePlatform::iter() {
let api_client = CscsApi::new(token.0.0.clone(), Some(platform.clone())).unwrap();
if (api_client.list_systems().await).is_ok() {
config.set("cscs.current_platform", platform.to_string(), true)?;
break;
client_credentials_login(client_id_secret, client_secret_secret)
Comment thread
Panaetius marked this conversation as resolved.
.await
.map(|_| ())
}
pub(crate) async fn get_available_compute_platforms() -> Result<Vec<ComputePlatform>> {
match get_access_token().await {
Ok(access_token) => {
let mut platforms = Vec::new();
for platform in ComputePlatform::iter() {
let api_client = CscsApi::new(access_token.0.clone(), Some(platform.clone()))?;
if (api_client.list_systems().await).is_ok() {
platforms.push(platform);
}
}
Ok(platforms)
Comment thread
Panaetius marked this conversation as resolved.
}
Err(e) => Err(e),
}
Ok(())
}

#[allow(dead_code)]
Expand Down