## Overview
-The PVC-Snapshotter Tool is a Rust-based utility that allows Kubernetes users to backup and restore Persistent Volume Claim (PVC) snapshots. The tool provides robust mechanisms to back up data to AWS Elastic Block Store (EBS) and restore it to any Kubernetes namespace. This tool is designed to work with Kubernetes VolumeSnapshot resources, making backup and restoration operations seamless.
+The SnapKube Tool is a Rust-based utility that allows Kubernetes users to backup and restore Persistent Volume Claim (PVC) snapshots. The tool provides robust mechanisms to back up data to AWS Elastic Block Store (EBS) and restore it to any Kubernetes namespace. This tool is designed to work with Kubernetes VolumeSnapshot resources, making backup and restoration operations seamless.
The tool supports three primary modes of operation:
@@ -33,12 +33,6 @@ The tool supports three primary modes of operation:
Restore: Restore PVCs from existing snapshots.
Full: Run both backup and restore operations in a single process.
-
-
-> [!NOTE]
-> Average percentage of time saved by PVC-Snapshotter compared to [Velero](https://github.com/vmware-tanzu/velero): **X%**.
-
-
## Features
- **Backup**: Create Kubernetes VolumeSnapshots from existing PVCs
- **Restore**: Restore PVCs to any namespace from a VolumeSnapshot
@@ -48,7 +42,7 @@ The tool supports three primary modes of operation:
- **Error Handling**: Robust error handling and retries to ensure operations complete reliably
## Prerequisites
-Before using PVC-Snapshotter, please ensure you have the following:
+Before using SnapKube, please ensure you have the following:
- You need Rust installed to compile the tool. Install Rust via rustup
- An AWS Account with the appropriate access policy
- AWS EBS CSI Driver: Required to be installed in your Kubernetes cluster, which is a CSI Driver to manage the lifecycle of EBS Volumes
@@ -61,7 +55,7 @@ In order to use the tool as a client, you can use `cargo`.
The tool provides 3 features for running it, which are `backup` `restore`, and `full` (default).
```shell
-Usage: pvc-snapshotter-client full [OPTIONS] --source-ns --target-ns --volume-snapshot-class --volume-snapshot-name-prefix --target-snapshot-content-name-prefix --storage-class-name
+Usage: snap-kube-client full [OPTIONS] --source-ns --target-ns --volume-snapshot-class --volume-snapshot-name-prefix --target-snapshot-content-name-prefix --storage-class-name
Options:
--region
diff --git a/pvc-snapshotter-client/Cargo.toml b/pvc-snapshotter-client/Cargo.toml
index a11dedf..fc0aa77 100644
--- a/pvc-snapshotter-client/Cargo.toml
+++ b/pvc-snapshotter-client/Cargo.toml
@@ -1,14 +1,14 @@
[package]
-name = "pvc-snapshotter-client"
+name = "snap-kube-client"
version = "0.1.0"
edition = "2021"
license = "MIT"
-description = "The pvc-snapshotter-client is a Rust tool that can backup and restore k8s PVCs using EBS snapshots"
+description = "The snap-kube-client is a Rust tool that can backup and restore k8s PVCs using EBS snapshots"
readme = "../README.md"
-homepage = "https://github.com/nikoshet/pvc-snapshotter"
-repository = "https://github.com/nikoshet/pvc-snapshotter"
+homepage = "https://github.com/nikoshet/snap-kube"
+repository = "https://github.com/nikoshet/snap-kube"
keywords = ["k8s", "pvc", "snapshot", "ebs", "backup", "restore", "aws"]
-documentation = "https://docs.rs/pvc-snapshotter-client"
+documentation = "https://docs.rs/snap-kube-client"
[dependencies]
anyhow.workspace = true
@@ -27,7 +27,8 @@ serde_json.workspace = true
tokio.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
-pvc-snapshotter.workspace = true
+snap-kube.workspace = true
+mockall = "0.13.0"
[features]
default = ["full"]
diff --git a/pvc-snapshotter-client/src/main.rs b/pvc-snapshotter-client/src/main.rs
index a1bf1a0..668c195 100644
--- a/pvc-snapshotter-client/src/main.rs
+++ b/pvc-snapshotter-client/src/main.rs
@@ -2,11 +2,11 @@ use anyhow::Result;
use clap::{Parser, Subcommand};
use colored::Colorize;
#[cfg(feature = "backup")]
-use pvc_snapshotter::backup::{backup_operator::BackupOperator, backup_payload::BackupPayload};
+use snap_kube::backup::{backup_operator::BackupOperator, backup_payload::BackupPayload};
#[cfg(feature = "restore")]
-use pvc_snapshotter::k8s_ops::vsc::retain_policy::VSCRetainPolicy;
+use snap_kube::k8s_ops::vsc::retain_policy::VSCRetainPolicy;
#[cfg(feature = "restore")]
-use pvc_snapshotter::restore::{
+use snap_kube::restore::{
restore_operator::RestoreOperator, restore_payload::RestorePayload,
};
use tracing::info;
diff --git a/src/backup/backup_operator.rs b/src/backup/backup_operator.rs
index 11e805b..c936d2f 100644
--- a/src/backup/backup_operator.rs
+++ b/src/backup/backup_operator.rs
@@ -2,14 +2,15 @@ use super::backup_payload::BackupPayload;
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,
- vs::volume_snapshots_operator::VolumeSnapshotOperator,
+ pvc::persistent_volume_claims::{check_if_pvc_exists, get_pvcs_available, KubePvcApi},
+ vs::{
+ volume_snapshots::wait_untill_snapshot_is_ready,
+ volume_snapshots_operator::VolumeSnapshotOperator,
+ },
vsc::retain_policy::VSCRetainPolicy,
},
};
use anyhow::{bail, Result};
-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,
@@ -34,7 +35,9 @@ impl BackupOperator {
// Define the VolumeSnapshot and VolumeSnapshotContent APIs
let restore_k8s_apis_struct = BackupKubernetesApisStruct {
source_vs_api: Api::namespaced(k8s_client.clone(), backup_payload.source_ns()),
- source_pvcs_api: Api::namespaced(k8s_client.clone(), backup_payload.source_ns()),
+ source_pvcs_api: KubePvcApi {
+ api: Api::namespaced(k8s_client.clone(), backup_payload.source_ns()),
+ },
vsc_api: Api::all(k8s_client.clone()),
};
@@ -102,6 +105,6 @@ impl BackupOperator {
/// A struct for holding the Kubernetes APIs for the backup operation
struct BackupKubernetesApisStruct {
source_vs_api: Api,
- source_pvcs_api: Api,
+ source_pvcs_api: KubePvcApi,
vsc_api: Api,
}
diff --git a/src/k8s_ops/pvc/persistent_volume_claims.rs b/src/k8s_ops/pvc/persistent_volume_claims.rs
index 2b1fb9c..f2435b7 100644
--- a/src/k8s_ops/pvc/persistent_volume_claims.rs
+++ b/src/k8s_ops/pvc/persistent_volume_claims.rs
@@ -1,14 +1,51 @@
use anyhow::Result;
+use async_trait::async_trait;
use k8s_openapi::api::core::v1::PersistentVolumeClaim;
-use kube::api::ListParams;
+use kube::{api::ListParams, Api};
use tracing::info;
+#[cfg(test)]
+use mockall::automock;
+
+#[cfg_attr(test, automock)]
+#[async_trait]
+pub trait PvcApiTrait {
+ async fn list_pvcs(&self) -> Result>;
+ async fn get(&self, name: &str) -> Result;
+ async fn create(&self, pvc: PersistentVolumeClaim) -> Result;
+}
+
+pub struct KubePvcApi {
+ pub api: Api,
+}
+
+/// Implement the PvcApi trait for PVC Api
+/// This will allow us to call the functions defined in the PvcApi trait on an instance of KubePvcApi.
+/// This is useful for testing, as we can mock the KubePvcApi struct and implement the PvcApi trait
+/// to return mock data.
+/// This way, we can test the functions that use the KubePvcApi struct without actually making
+/// calls to the Kubernetes API.
+#[async_trait]
+impl PvcApiTrait for KubePvcApi {
+ async fn list_pvcs(&self) -> Result> {
+ let pvcs = self.api.list(&ListParams::default()).await?;
+ Ok(pvcs.items)
+ }
+
+ async fn get(&self, name: &str) -> Result {
+ let pvc = self.api.get(name).await?;
+ Ok(pvc)
+ }
+
+ async fn create(&self, pvc: PersistentVolumeClaim) -> Result {
+ let pvc = self.api.create(&Default::default(), &pvc).await?;
+ Ok(pvc)
+ }
+}
+
/// Get the list of PersistentVolumeClaims available
-pub async fn get_pvcs_available(
- target_pvc_api: &kube::Api,
-) -> Result> {
- let lp = ListParams::default();
- let pvc_list: Vec<_> = match target_pvc_api.list(&lp).await {
+pub async fn get_pvcs_available(pvc_api: &impl PvcApiTrait) -> Result> {
+ let pvc_list: Vec<_> = match pvc_api.list_pvcs().await {
Ok(pvc) => pvc,
Err(e) => panic!("Failed to list PVCs: {}", e),
}
@@ -20,7 +57,8 @@ pub async fn get_pvcs_available(
}
pub async fn check_if_pvc_exists(
- target_pvc_api: &kube::Api,
+ target_pvc_api: &impl PvcApiTrait,
+ //&kube::Api,
pvc_name: &str,
should_exist: bool,
) -> Result