Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move some cloud functions to an extension #130

Merged
merged 1 commit into from
Oct 15, 2023
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
2 changes: 1 addition & 1 deletion crates/cloud/src/client_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use uuid::Uuid;

#[cfg_attr(feature = "mocks", mockall::automock)]
#[async_trait]
pub trait CloudClientInterface {
pub trait CloudClientInterface: Send + Sync {
async fn create_device_code(&self, client_id: Uuid) -> Result<DeviceCodeItem>;

async fn login(&self, token: String) -> Result<TokenInfo>;
Expand Down
76 changes: 76 additions & 0 deletions crates/cloud/src/cloud_client_extensions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use uuid::Uuid;

use crate::CloudClientInterface;

#[async_trait]
pub trait CloudClientExt {
async fn get_app_id(&self, app_name: &str) -> Result<Option<Uuid>>;
async fn get_revision_id(&self, app_id: Uuid, version: &str) -> Result<Uuid>;
async fn get_channel_id(&self, app_id: Uuid, channel_name: &str) -> Result<Uuid>;
}

#[async_trait]
impl<T: CloudClientInterface> CloudClientExt for T {
async fn get_app_id(&self, app_name: &str) -> Result<Option<Uuid>> {
let apps_vm = self
.list_apps(crate::DEFAULT_APPLIST_PAGE_SIZE, None)
.await
.context("Could not fetch apps")?;
let app = apps_vm.items.iter().find(|&x| x.name == app_name);
Ok(app.map(|a| a.id))
}

async fn get_revision_id(&self, app_id: Uuid, version: &str) -> Result<Uuid> {
let mut revisions = self.list_revisions().await?;

loop {
if let Some(revision) = revisions
.items
.iter()
.find(|&x| x.revision_number == version && x.app_id == app_id)
{
return Ok(revision.id);
}

if revisions.is_last_page {
break;
}

revisions = self.list_revisions_next(&revisions).await?;
}

Err(anyhow!(
"No revision with version {} and app id {}",
version,
app_id
))
}

async fn get_channel_id(&self, app_id: Uuid, channel_name: &str) -> Result<Uuid> {
let mut channels_vm = self.list_channels().await?;

loop {
if let Some(channel) = channels_vm
.items
.iter()
.find(|&x| x.app_id == app_id && x.name == channel_name)
{
return Ok(channel.id);
}

if channels_vm.is_last_page {
break;
}

channels_vm = self.list_channels_next(&channels_vm).await?;
}

Err(anyhow!(
"No channel with app_id {} and name {}",
app_id,
channel_name,
))
}
}
5 changes: 5 additions & 0 deletions crates/cloud/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
pub mod client;
mod client_interface;
mod cloud_client_extensions;

pub use client_interface::CloudClientInterface;
#[cfg(feature = "mocks")]
pub use client_interface::MockCloudClientInterface;
pub use cloud_client_extensions::CloudClientExt;

pub const DEFAULT_APPLIST_PAGE_SIZE: i32 = 50;
2 changes: 1 addition & 1 deletion src/commands/apps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::commands::{client_and_app_id, create_cloud_client};
use crate::opts::*;
use anyhow::{Context, Result};
use clap::{Args, Parser};
use cloud::CloudClientInterface;
use cloud::{CloudClientInterface, DEFAULT_APPLIST_PAGE_SIZE};
use cloud_openapi::models::{AppItem, AppItemPage, ValidationStatus};

#[derive(Parser, Debug)]
Expand Down
100 changes: 8 additions & 92 deletions src/commands/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use chrono::{DateTime, Utc};
use clap::Parser;
use cloud::{
client::{Client as CloudClient, ConnectionConfig},
CloudClientInterface,
CloudClientExt, CloudClientInterface,
};
use cloud_openapi::models::{
ChannelRevisionSelectionStrategy as CloudChannelRevisionSelectionStrategy, Database,
Expand All @@ -25,10 +25,7 @@ use url::Url;
use uuid::Uuid;

use crate::{
commands::{
get_app_id_cloud,
variables::{get_variables, set_variables},
},
commands::variables::{get_variables, set_variables},
random_name::RandomNameGenerator,
spin,
};
Expand Down Expand Up @@ -196,7 +193,7 @@ impl DeployCommand {
println!("Deploying...");

// Create or update app
let channel_id = match get_app_id_cloud(&client, &name).await? {
let channel_id = match client.get_app_id(&name).await? {
Some(app_id) => {
let labels = application.sqlite_databases();
if !labels.is_empty()
Expand All @@ -210,12 +207,10 @@ impl DeployCommand {
client
.add_revision(storage_id.clone(), version.clone())
.await?;
let existing_channel_id = self
.get_channel_id_cloud(&client, SPIN_DEPLOY_CHANNEL_NAME.to_string(), app_id)
.await?;
let active_revision_id = self
.get_revision_id_cloud(&client, version.clone(), app_id)
let existing_channel_id = client
.get_channel_id(app_id, SPIN_DEPLOY_CHANNEL_NAME)
.await?;
let active_revision_id = client.get_revision_id(app_id, &version).await?;
client
.patch_channel(
existing_channel_id,
Expand Down Expand Up @@ -259,9 +254,7 @@ impl DeployCommand {
.add_revision(storage_id.clone(), version.clone())
.await?;

let active_revision_id = self
.get_revision_id_cloud(&client, version.clone(), app_id)
.await?;
let active_revision_id = client.get_revision_id(app_id, &version).await?;

let channel_id = client
.add_channel(
Expand Down Expand Up @@ -398,7 +391,7 @@ impl DeployCommand {
}

// Are all remaining required variables satisfied by variables already in the cloud?
let extant_variables = match self.try_get_app_id_cloud(client, name.to_string()).await {
let extant_variables = match client.get_app_id(name).await {
Ok(Some(app_id)) => match get_variables(client, app_id).await {
Ok(variables) => variables,
Err(_) => {
Expand Down Expand Up @@ -427,83 +420,6 @@ impl DeployCommand {
Err(anyhow!("The application requires values for the following variable(s) which have not been set: {list_text}. Use the --variable flag to provide values."))
}

async fn try_get_app_id_cloud(
&self,
cloud_client: &CloudClient,
name: String,
) -> Result<Option<Uuid>> {
let apps_vm = cloud_client
.list_apps(DEFAULT_APPLIST_PAGE_SIZE, None)
.await?;
let app = apps_vm.items.iter().find(|&x| x.name == name.clone());
match app {
Some(a) => Ok(Some(a.id)),
None => Ok(None),
}
}

async fn get_revision_id_cloud(
&self,
cloud_client: &CloudClient,
version: String,
app_id: Uuid,
) -> Result<Uuid> {
let mut revisions = cloud_client.list_revisions().await?;

loop {
if let Some(revision) = revisions
.items
.iter()
.find(|&x| x.revision_number == version && x.app_id == app_id)
{
return Ok(revision.id);
}

if revisions.is_last_page {
break;
}

revisions = cloud_client.list_revisions_next(&revisions).await?;
}

Err(anyhow!(
"No revision with version {} and app id {}",
version,
app_id
))
}

async fn get_channel_id_cloud(
&self,
cloud_client: &CloudClient,
name: String,
app_id: Uuid,
) -> Result<Uuid> {
let mut channels_vm = cloud_client.list_channels().await?;

loop {
if let Some(channel) = channels_vm
.items
.iter()
.find(|&x| x.app_id == app_id && x.name == name.clone())
{
return Ok(channel.id);
}

if channels_vm.is_last_page {
break;
}

channels_vm = cloud_client.list_channels_next(&channels_vm).await?;
}

Err(anyhow!(
"No channel with app_id {} and name {}",
app_id,
name
))
}

async fn push_oci(
&self,
application: DeployableApp,
Expand Down
18 changes: 4 additions & 14 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ pub mod login;
pub mod sqlite;
pub mod variables;

use crate::{commands::deploy::login_connection, opts::DEFAULT_APPLIST_PAGE_SIZE};
use crate::commands::deploy::login_connection;
use anyhow::{Context, Result};
use cloud::{
client::{Client as CloudClient, ConnectionConfig},
CloudClientInterface,
CloudClientExt,
};
use uuid::Uuid;

Expand All @@ -23,23 +23,13 @@ pub(crate) async fn create_cloud_client(deployment_env_id: Option<&str>) -> Resu
Ok(CloudClient::new(connection_config))
}

pub(crate) async fn get_app_id_cloud(
cloud_client: &CloudClient,
name: &str,
) -> Result<Option<Uuid>> {
let apps_vm = CloudClient::list_apps(cloud_client, DEFAULT_APPLIST_PAGE_SIZE, None)
.await
.context("Could not fetch apps")?;
let app = apps_vm.items.iter().find(|&x| x.name == name);
Ok(app.map(|a| a.id))
}

async fn client_and_app_id(
deployment_env_id: Option<&str>,
app: &str,
) -> Result<(CloudClient, Uuid)> {
let client = create_cloud_client(deployment_env_id).await?;
let app_id = get_app_id_cloud(&client, app)
let app_id = client
.get_app_id(app)
.await
.with_context(|| format!("Error finding app_id for app '{}'", app))?
.with_context(|| format!("Could not find app '{}'", app))?;
Expand Down
1 change: 0 additions & 1 deletion src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@ pub const CLOUD_URL_ENV: &str = "CLOUD_URL";
pub const DEPLOYMENT_ENV_NAME_ENV: &str = "FERMYON_DEPLOYMENT_ENVIRONMENT";
pub const TOKEN: &str = "TOKEN";
pub const SPIN_AUTH_TOKEN: &str = "SPIN_AUTH_TOKEN";
pub const DEFAULT_APPLIST_PAGE_SIZE: i32 = 50;