diff --git a/migrations/8__add_google_cloud_provider.sql b/migrations/8__add_google_cloud_provider.sql new file mode 100644 index 0000000..d9c3f88 --- /dev/null +++ b/migrations/8__add_google_cloud_provider.sql @@ -0,0 +1,2 @@ +INSERT INTO providers (id, display_name, required_variables, supports_spot) VALUES + ('gcp', 'Google Cloud Platform', 'GOOGLE_APPLICATION_CREDENTIALS', 1); diff --git a/src/integrations/cloud_interface.rs b/src/integrations/cloud_interface.rs index 1d9ebb2..e6f6862 100644 --- a/src/integrations/cloud_interface.rs +++ b/src/integrations/cloud_interface.rs @@ -1,5 +1,5 @@ use crate::database::models::{Cluster, InstanceType, MachineImage, Node}; -use crate::integrations::providers::{aws::AwsInterface, vultr::VultrInterface}; +use crate::integrations::providers::{aws::AwsInterface, gcp::GcpInterface, vultr::VultrInterface}; use crate::utils::ProgressTracker; use anyhow::{Error, Result}; @@ -59,6 +59,7 @@ pub trait CloudResourceManager { pub enum CloudProvider { Aws(AwsInterface), Vultr(VultrInterface), + Gcp(GcpInterface), } impl CloudInfoProvider for CloudProvider { @@ -66,6 +67,7 @@ impl CloudInfoProvider for CloudProvider { match self { CloudProvider::Aws(aws) => aws.fetch_regions(tracker).await, CloudProvider::Vultr(vultr) => vultr.fetch_regions(tracker).await, + CloudProvider::Gcp(gcp) => gcp.fetch_regions(tracker).await, } } @@ -77,6 +79,7 @@ impl CloudInfoProvider for CloudProvider { match self { CloudProvider::Aws(aws) => aws.fetch_zones(region, tracker).await, CloudProvider::Vultr(vultr) => vultr.fetch_zones(region, tracker).await, + CloudProvider::Gcp(gcp) => gcp.fetch_zones(region, tracker).await, } } @@ -88,6 +91,7 @@ impl CloudInfoProvider for CloudProvider { match self { CloudProvider::Aws(aws) => aws.fetch_instance_types(region, tracker).await, CloudProvider::Vultr(vultr) => vultr.fetch_instance_types(region, tracker).await, + CloudProvider::Gcp(gcp) => gcp.fetch_instance_types(region, tracker).await, } } @@ -102,6 +106,7 @@ impl CloudInfoProvider for CloudProvider { CloudProvider::Vultr(vultr) => { vultr.fetch_prices(region, instance_types, tracker).await } + CloudProvider::Gcp(gcp) => gcp.fetch_prices(region, instance_types, tracker).await, } } @@ -113,6 +118,7 @@ impl CloudInfoProvider for CloudProvider { match self { CloudProvider::Aws(aws) => aws.fetch_machine_image(region, image_id).await, CloudProvider::Vultr(vultr) => vultr.fetch_machine_image(region, image_id).await, + CloudProvider::Gcp(gcp) => gcp.fetch_machine_image(region, image_id).await, } } } @@ -127,6 +133,7 @@ impl CloudResourceManager for CloudProvider { match self { CloudProvider::Aws(aws) => aws.spawn_cluster(pool, cluster, nodes).await, CloudProvider::Vultr(vultr) => vultr.spawn_cluster(pool, cluster, nodes).await, + CloudProvider::Gcp(gcp) => gcp.spawn_cluster(pool, cluster, nodes).await, } } @@ -139,6 +146,7 @@ impl CloudResourceManager for CloudProvider { match self { CloudProvider::Aws(aws) => aws.terminate_cluster(pool, cluster, nodes).await, CloudProvider::Vultr(vultr) => vultr.terminate_cluster(pool, cluster, nodes).await, + CloudProvider::Gcp(gcp) => gcp.terminate_cluster(pool, cluster, nodes).await, } } @@ -158,6 +166,10 @@ impl CloudResourceManager for CloudProvider { .simulate_cluster_failure(pool, cluster, node_private_ip) .await } + CloudProvider::Gcp(gcp) => { + gcp.simulate_cluster_failure(pool, cluster, node_private_ip) + .await + } } } } diff --git a/src/integrations/providers/gcp/interface.rs b/src/integrations/providers/gcp/interface.rs new file mode 100644 index 0000000..823c0e3 --- /dev/null +++ b/src/integrations/providers/gcp/interface.rs @@ -0,0 +1,20 @@ +use crate::database::models::{ConfigVar, ConfigVarFinder}; + +use anyhow::{Result, bail}; +use reqwest::{Client as HttpClient, header}; +use serde_json::Value as JsonValue; +use tracing::error; + +pub struct GcpInterface { + pub config_vars: Vec, +} + +/// TODO: Decide over using the Rust SDK or the REST API... +/// Rust SDK: https://github.com/googleapis/google-cloud-rust/tree/main +/// REST API: https://cloud.google.com/compute/docs/authentication?hl=pt-br#rest +/// +/// If using the API, check the Vultr code for an example on how to use the `reqwest` http +/// client for requests. +/// If using the Rust SDK, check the SDK own documentation and the AWS code to get an idea of +/// how to implement this method. +impl GcpInterface {} diff --git a/src/integrations/providers/gcp/mod.rs b/src/integrations/providers/gcp/mod.rs new file mode 100644 index 0000000..2809230 --- /dev/null +++ b/src/integrations/providers/gcp/mod.rs @@ -0,0 +1,5 @@ +mod interface; +mod resource_catalog; +mod resource_manager; + +pub use interface::GcpInterface; diff --git a/src/integrations/providers/gcp/resource_catalog.rs b/src/integrations/providers/gcp/resource_catalog.rs new file mode 100644 index 0000000..23ca955 --- /dev/null +++ b/src/integrations/providers/gcp/resource_catalog.rs @@ -0,0 +1,39 @@ +use crate::database::models::{InstanceType, MachineImage}; +use crate::integrations::CloudInfoProvider; +use crate::utils::ProgressTracker; + +use anyhow::{Result, bail}; +use std::collections::HashMap; + +use super::interface::GcpInterface; + +impl CloudInfoProvider for GcpInterface { + async fn fetch_regions(&self, _tracker: &ProgressTracker) -> Result> { + bail!("Not implemented") + } + + async fn fetch_zones(&self, _region: &str, _tracker: &ProgressTracker) -> Result> { + bail!("Not implemented") + } + + async fn fetch_instance_types( + &self, + _region: &str, + _tracker: &ProgressTracker, + ) -> Result> { + bail!("Not implemented") + } + + async fn fetch_prices( + &self, + _region: &str, + _instance_types: &[String], + _tracker: &ProgressTracker, + ) -> Result> { + bail!("Not implemented") + } + + async fn fetch_machine_image(&self, _region: &str, _image_id: &str) -> Result { + bail!("Not implemented") + } +} diff --git a/src/integrations/providers/gcp/resource_manager.rs b/src/integrations/providers/gcp/resource_manager.rs new file mode 100644 index 0000000..2dc2854 --- /dev/null +++ b/src/integrations/providers/gcp/resource_manager.rs @@ -0,0 +1,36 @@ +use crate::database::models::{Cluster, Node}; +use crate::integrations::CloudResourceManager; + +use anyhow::{Result, bail}; +use sqlx::sqlite::SqlitePool; + +use super::interface::GcpInterface; + +impl CloudResourceManager for GcpInterface { + async fn spawn_cluster( + &self, + _pool: &SqlitePool, + _cluster: Cluster, + _nodes: Vec, + ) -> Result<()> { + bail!("Not implemented") + } + + async fn terminate_cluster( + &self, + _pool: &SqlitePool, + _cluster: Cluster, + _nodes: Vec, + ) -> Result<()> { + bail!("Not implemented") + } + + async fn simulate_cluster_failure( + &self, + _pool: &SqlitePool, + _cluster: Cluster, + _node_private_ip: &str, + ) -> Result<()> { + bail!("Not implemented") + } +} diff --git a/src/integrations/providers/mod.rs b/src/integrations/providers/mod.rs index 5e8140d..239a31f 100644 --- a/src/integrations/providers/mod.rs +++ b/src/integrations/providers/mod.rs @@ -1,2 +1,3 @@ pub mod aws; +pub mod gcp; pub mod vultr;