use anyhow::Result;
use aws_sdk_autoscaling::types::AutoScalingGroup;
use aws_sdk_eks::types::{Addon, Cluster, FargateProfile, Nodegroup};
use k8s_openapi::api::core::v1::ConfigMap;
use crate::{
eks::resources::{self as eks_resources, AddonVersion, ClusterInsight, LaunchTemplate, VpcSubnet},
k8s::resources::{self as k8s_resources, ENIConfig, Node, StdPdb, StdResource},
};
pub trait AwsClients {
fn get_cluster(&self, name: &str) -> impl std::future::Future<Output = Result<Cluster>> + Send;
fn get_subnet_ips(&self, subnet_ids: Vec<String>)
-> impl std::future::Future<Output = Result<Vec<VpcSubnet>>> + Send;
fn get_addons(&self, cluster_name: &str) -> impl std::future::Future<Output = Result<Vec<Addon>>> + Send;
fn get_addon_versions(
&self,
name: &str,
kubernetes_version: &str,
) -> impl std::future::Future<Output = Result<AddonVersion>> + Send;
fn get_eks_managed_nodegroups(
&self,
cluster_name: &str,
) -> impl std::future::Future<Output = Result<Vec<Nodegroup>>> + Send;
fn get_self_managed_nodegroups(
&self,
cluster_name: &str,
) -> impl std::future::Future<Output = Result<Vec<AutoScalingGroup>>> + Send;
fn get_fargate_profiles(
&self,
cluster_name: &str,
) -> impl std::future::Future<Output = Result<Vec<FargateProfile>>> + Send;
fn get_launch_template(&self, id: &str) -> impl std::future::Future<Output = Result<LaunchTemplate>> + Send;
fn get_service_quota_usage(
&self,
service_code: &str,
quota_code: &str,
) -> impl std::future::Future<Output = Result<(String, f64, String)>> + Send;
fn get_ec2_on_demand_vcpu_count(&self) -> impl std::future::Future<Output = Result<f64>> + Send;
fn get_ebs_volume_storage(&self, volume_type: &str) -> impl std::future::Future<Output = Result<f64>> + Send;
fn get_cluster_insights(
&self,
cluster_name: &str,
) -> impl std::future::Future<Output = Result<Vec<ClusterInsight>>> + Send;
}
pub trait K8sClients {
fn get_nodes(&self) -> impl std::future::Future<Output = Result<Vec<Node>>> + Send;
fn get_configmap(
&self,
namespace: &str,
name: &str,
) -> impl std::future::Future<Output = Result<Option<ConfigMap>>> + Send;
fn get_eniconfigs(&self) -> impl std::future::Future<Output = Result<Vec<ENIConfig>>> + Send;
fn get_resources(&self) -> impl std::future::Future<Output = Result<Vec<StdResource>>> + Send;
fn get_pod_disruption_budgets(&self) -> impl std::future::Future<Output = Result<Vec<StdPdb>>> + Send;
}
pub struct RealAwsClients {
eks: aws_sdk_eks::Client,
ec2: aws_sdk_ec2::Client,
asg: aws_sdk_autoscaling::Client,
sq: aws_sdk_servicequotas::Client,
}
impl RealAwsClients {
pub fn new(config: &aws_config::SdkConfig) -> Self {
Self {
eks: aws_sdk_eks::Client::new(config),
ec2: aws_sdk_ec2::Client::new(config),
asg: aws_sdk_autoscaling::Client::new(config),
sq: aws_sdk_servicequotas::Client::new(config),
}
}
}
impl AwsClients for RealAwsClients {
async fn get_cluster(&self, name: &str) -> Result<Cluster> {
eks_resources::get_cluster(&self.eks, name).await
}
async fn get_subnet_ips(&self, subnet_ids: Vec<String>) -> Result<Vec<VpcSubnet>> {
eks_resources::get_subnet_ips(&self.ec2, subnet_ids).await
}
async fn get_addons(&self, cluster_name: &str) -> Result<Vec<Addon>> {
eks_resources::get_addons(&self.eks, cluster_name).await
}
async fn get_addon_versions(&self, name: &str, kubernetes_version: &str) -> Result<AddonVersion> {
eks_resources::get_addon_versions(&self.eks, name, kubernetes_version).await
}
async fn get_eks_managed_nodegroups(&self, cluster_name: &str) -> Result<Vec<Nodegroup>> {
eks_resources::get_eks_managed_nodegroups(&self.eks, cluster_name).await
}
async fn get_self_managed_nodegroups(&self, cluster_name: &str) -> Result<Vec<AutoScalingGroup>> {
eks_resources::get_self_managed_nodegroups(&self.asg, cluster_name).await
}
async fn get_fargate_profiles(&self, cluster_name: &str) -> Result<Vec<FargateProfile>> {
eks_resources::get_fargate_profiles(&self.eks, cluster_name).await
}
async fn get_launch_template(&self, id: &str) -> Result<LaunchTemplate> {
eks_resources::get_launch_template(&self.ec2, id).await
}
async fn get_service_quota_usage(&self, service_code: &str, quota_code: &str) -> Result<(String, f64, String)> {
eks_resources::get_service_quota(&self.sq, service_code, quota_code).await
}
async fn get_ec2_on_demand_vcpu_count(&self) -> Result<f64> {
eks_resources::get_ec2_on_demand_vcpu_count(&self.ec2).await
}
async fn get_ebs_volume_storage(&self, volume_type: &str) -> Result<f64> {
eks_resources::get_ebs_volume_storage(&self.ec2, volume_type).await
}
async fn get_cluster_insights(&self, cluster_name: &str) -> Result<Vec<ClusterInsight>> {
eks_resources::get_cluster_insights(&self.eks, cluster_name).await
}
}
pub struct RealK8sClients {
client: kube::Client,
}
impl RealK8sClients {
pub async fn new(cluster_name: &str) -> Result<Self> {
match kube::Client::try_default().await {
Ok(client) => Ok(Self { client }),
Err(e) => {
anyhow::bail!(
"Unable to connect to cluster: {e}\n\n\
Ensure kubeconfig file is present and updated to connect to the cluster.\n\
Try: aws eks update-kubeconfig --name {cluster_name}"
);
}
}
}
}
impl K8sClients for RealK8sClients {
async fn get_nodes(&self) -> Result<Vec<Node>> {
k8s_resources::get_nodes(&self.client).await
}
async fn get_configmap(&self, namespace: &str, name: &str) -> Result<Option<ConfigMap>> {
k8s_resources::get_configmap(&self.client, namespace, name).await
}
async fn get_eniconfigs(&self) -> Result<Vec<ENIConfig>> {
k8s_resources::get_eniconfigs(&self.client).await
}
async fn get_resources(&self) -> Result<Vec<StdResource>> {
k8s_resources::get_resources(&self.client).await
}
async fn get_pod_disruption_budgets(&self) -> Result<Vec<StdPdb>> {
k8s_resources::get_pod_disruption_budgets(&self.client).await
}
}