Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
nikoshet committed Oct 16, 2024
1 parent 5e3d834 commit 73ce2d3
Show file tree
Hide file tree
Showing 17 changed files with 771 additions and 504 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ edition = "2021"

[dependencies]
anyhow = "1.0.89"
async-trait = "0.1.83"
aws-config = "1.5.7"
aws-sdk-ec2 = "1.75.0"
clap = { version = "4.5.20", features = ["derive"] }
Expand Down
200 changes: 101 additions & 99 deletions src/backup/backup_operator.rs
Original file line number Diff line number Diff line change
@@ -1,96 +1,70 @@
use crate::{
aws_ops::ebs::create_ebs_client,
k8s_ops::{
pvc::persistent_volume_claims::{check_if_pvc_exists, get_pvcs_available},
vs::volume_snapshots::{wait_untill_snapshot_is_ready, VolumeSnapshotOperator},
vsc::retain_policy::VSCRetainPolicy,
},
};
use anyhow::{bail, Result};
use async_trait::async_trait;
use k8s_openapi::api::core::v1::PersistentVolumeClaim;
use kube::{api::PostParams, Api, Client};
use kube_custom_resources_rs::snapshot_storage_k8s_io::v1::{
volumesnapshotcontents::VolumeSnapshotContent,
volumesnapshots::{VolumeSnapshot, VolumeSnapshotStatus},
};
use tracing::info;

use crate::{
aws_ops::ebs::create_ebs_client,
k8s_ops::volume_snapshots::{
construct_volume_snapshot_resource, wait_untill_snapshot_is_ready,
},
};

/// A struct for holding the Kubernetes APIs for the backup operation
struct SourceKubernetesApisStruct {
source_vs_api: Api<VolumeSnapshot>,
vsc_api: Api<VolumeSnapshotContent>,
}

/// A struct for backing up a PVC to a VolumeSnapshot
pub struct BackupOperator {
region: String,
source_ns: String,
volume_snapshot_class: String,
pvc_name: String,
volume_snapshot_name: String,
}

impl BackupOperator {
/// Creates a new BackupOperator instance
///
/// # Arguments
///
/// * `region` - Region where the EBS volumes are stored
/// * `source_ns` - Source namespace
/// * `volume_snapshot_class` - VolumeSnapshotClass name
/// * `pvc_name` - PVC name
/// * `volume_snapshot_name` - VolumeSnapshot name
#[async_trait]
/// This trait represents the BackupOperator
pub trait BackupOperator {
/// Backs up a PVC to a VolumeSnapshot
///
/// # Returns
///
/// BackupOperator instance
/// Result
///
/// # Example
///
/// ```
/// use crate::backup::backup_operator::BackupOperator;
/// let backup_operator = BackupOperator::new(
/// use crate::backup::backup_operator::BackupOperatorImpl;
/// let backup_operator = BackupOperatorImpl::new(
/// "eu-west-1".to_string(),
/// "source-ns".to_string(),
/// "volume-snapshot-class".to_string(),
/// "pvc-name".to_string(),
/// false,
/// "volume-snapshot-name".to_string(),
/// );
/// backup_operator.backup().await?;
/// ```
async fn backup(&self) -> Result<()>;
}

impl BackupOperatorImpl {
pub fn new(
region: String,
source_ns: String,
volume_snapshot_class: String,
pvc_name: String,
include_all: bool,
volume_snapshot_name: String,
) -> Self {
BackupOperator {
Self {
region,
source_ns,
volume_snapshot_class,
pvc_name,
include_all,
volume_snapshot_name,
}
}
}

/// Backs up a PVC to a VolumeSnapshot
///
/// # Returns
///
/// Result
///
/// # Example
///
/// ```
/// use crate::backup::backup_operator::BackupOperator;
/// let backup_operator = BackupOperator::new(
/// "eu-west-1".to_string(),
/// "source-ns".to_string(),
/// "volume-snapshot-class".to_string(),
/// "pvc-name".to_string(),
/// "volume-snapshot-name".to_string(),
/// );
/// backup_operator.backup().await?;
/// ```
pub async fn backup(&self) -> Result<()> {
#[async_trait]
impl BackupOperator for BackupOperatorImpl {
async fn backup(&self) -> Result<()> {
// Create a Kubernetes client
let k8s_client = Client::try_default().await?;

Expand All @@ -100,55 +74,83 @@ impl BackupOperator {
// Define the VolumeSnapshot and VolumeSnapshotContent APIs
let source_kubernetes_apis_struct = SourceKubernetesApisStruct {
source_vs_api: Api::namespaced(k8s_client.clone(), &self.source_ns),
source_pvcs_api: Api::namespaced(k8s_client.clone(), &self.source_ns),
vsc_api: Api::all(k8s_client.clone()),
};

// Create a VolumeSnapshot resource on Source Namespace
// let vs_creator_source_ns = VolumeSnapshotCreator::new(
// ...
// );
// vs_creator_source_ns.create().await?;
let volume_snapshot = construct_volume_snapshot_resource(
self.volume_snapshot_name.to_string(),
self.source_ns.to_string(),
self.volume_snapshot_class.to_string(),
Some(self.pvc_name.to_string()),
None,
None,
None,
);
// Check if we will backup all PVCs in the namespace
if self.include_all && self.pvc_name.is_empty() {
let pvcs = get_pvcs_available(&source_kubernetes_apis_struct.source_pvcs_api).await?;
info!("Available PVCs: {:?}", pvcs);
bail!("Include all PVCs is not implemented yet");
} else {
// We will backup a single PVC
// Check if the PVC exists
check_if_pvc_exists(
&source_kubernetes_apis_struct.source_pvcs_api,
&self.pvc_name,
)
.await?;

let pp = PostParams::default();
let status: VolumeSnapshotStatus = match source_kubernetes_apis_struct
.source_vs_api
.create(&pp, &volume_snapshot)
.await
{
Ok(snapshot) => {
info!("Created VolumeSnapshot: {:?}", snapshot);
wait_untill_snapshot_is_ready(
source_kubernetes_apis_struct.source_vs_api,
source_kubernetes_apis_struct.vsc_api,
ebs_client.await.unwrap(),
&self.volume_snapshot_name,
)
.await?
}
Err(e) => {
bail!("Failed to create VolumeSnapshot: {}", e);
}
};
let vs_operator = VolumeSnapshotOperator::new(
self.volume_snapshot_name.to_string(),
self.source_ns.to_string(),
self.volume_snapshot_class.to_string(),
Some(self.pvc_name.to_string()),
None,
);

let bound_vsc_name = status.bound_volume_snapshot_content_name.unwrap();
let restore_size = status.restore_size.unwrap();
info!(
"{}",
format!(
"VolumeSnapshot is ready! Bound vsc name: {}, restore_size: {}",
bound_vsc_name, restore_size
)
);
let volume_snapshot =
vs_operator.construct_volume_snapshot_resource(None, None, VSCRetainPolicy::Delete);

let pp = PostParams::default();
let status: VolumeSnapshotStatus = match source_kubernetes_apis_struct
.source_vs_api
.create(&pp, &volume_snapshot)
.await
{
Ok(snapshot) => {
info!("Created VolumeSnapshot: {:?}", snapshot);
wait_untill_snapshot_is_ready(
source_kubernetes_apis_struct.source_vs_api,
source_kubernetes_apis_struct.vsc_api,
ebs_client.await.unwrap(),
&self.volume_snapshot_name,
)
.await?
}
Err(e) => {
bail!("Failed to create VolumeSnapshot: {}", e);
}
};

let bound_vsc_name = status.bound_volume_snapshot_content_name.unwrap();
let restore_size = status.restore_size.unwrap();
info!(
"{}",
format!(
"VolumeSnapshot is ready! Bound vsc name: {}, restore_size: {}",
bound_vsc_name, restore_size
)
);
}
Ok(())
}
}

/// A struct for holding the Kubernetes APIs for the backup operation
struct SourceKubernetesApisStruct {
source_vs_api: Api<VolumeSnapshot>,
source_pvcs_api: Api<PersistentVolumeClaim>,
vsc_api: Api<VolumeSnapshotContent>,
}

/// A struct for backing up a PVC to a VolumeSnapshot
pub struct BackupOperatorImpl {
region: String,
source_ns: String,
volume_snapshot_class: String,
pvc_name: String,
include_all: bool,
volume_snapshot_name: String,
}
6 changes: 3 additions & 3 deletions src/k8s_ops/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pub mod persistent_volume_claims;
pub mod volume_snapshot_contents;
pub mod volume_snapshots;
pub mod pvc;
pub mod vs;
pub mod vsc;
77 changes: 0 additions & 77 deletions src/k8s_ops/persistent_volume_claims.rs

This file was deleted.

2 changes: 2 additions & 0 deletions src/k8s_ops/pvc/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod persistent_volume_claims;
pub mod persistent_volume_claims_payload;
Loading

0 comments on commit 73ce2d3

Please sign in to comment.