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

Expose Medusa backup size #1123

Merged
merged 1 commit into from
Nov 30, 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: 2 additions & 0 deletions CHANGELOG/CHANGELOG-1.11.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ Changelog for the K8ssandra Operator, new PRs should update the `unreleased` sec
When cutting a new release, update the `unreleased` heading to the tag being generated and date, like `## vX.Y.Z - YYYY-MM-DD` and create a new placeholder section for `unreleased` entries.

## unreleased

* [ENHANCEMENT] [#1122](https://github.com/k8ssandra/k8ssandra-operator/issues/1122) Expose backup size in MedusaBackup CRD
4 changes: 4 additions & 0 deletions apis/medusa/v1alpha1/medusabackup_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ type MedusaBackupStatus struct {
TotalNodes int32 `json:"totalNodes,omitempty"`
FinishedNodes int32 `json:"finishedNodes,omitempty"`
Nodes []*MedusaBackupNode `json:"nodes,omitempty"`
TotalFiles int64 `json:"totalFiles,omitempty"`
TotalSize string `json:"totalSize,omitempty"`
Status string `json:"status,omitempty"`
}

Expand All @@ -57,6 +59,8 @@ type MedusaBackupNode struct {
//+kubebuilder:printcolumn:name="Started",type=date,JSONPath=".status.startTime",description="Backup start time"
//+kubebuilder:printcolumn:name="Finished",type=date,JSONPath=".status.finishTime",description="Backup finish time"
//+kubebuilder:printcolumn:name="Nodes",type=string,JSONPath=".status.totalNodes",description="Total number of nodes at the time of the backup"
//+kubebuilder:printcolumn:name="Files",type=integer,JSONPath=".status.totalFiles",description="Total number of files in the backup"
//+kubebuilder:printcolumn:name="Size",type=string,JSONPath=".status.totalSize",description="Human-readable total size of the backup"
//+kubebuilder:printcolumn:name="Completed",type=string,JSONPath=".status.finishedNodes",description="Number of nodes that completed this backup"
//+kubebuilder:printcolumn:name="Status",type=string,JSONPath=".status.status",description="Backup completion status"

Expand Down
13 changes: 13 additions & 0 deletions config/crd/bases/medusa.k8ssandra.io_medusabackups.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ spec:
jsonPath: .status.totalNodes
name: Nodes
type: string
- description: Total number of files in the backup
jsonPath: .status.totalFiles
name: Files
type: integer
- description: Human-readable total size of the backup
jsonPath: .status.totalSize
name: Size
type: string
- description: Number of nodes that completed this backup
jsonPath: .status.finishedNodes
name: Completed
Expand Down Expand Up @@ -98,9 +106,14 @@ spec:
type: string
status:
type: string
totalFiles:
format: int64
type: integer
totalNodes:
format: int32
type: integer
totalSize:
type: string
type: object
type: object
served: true
Expand Down
12 changes: 12 additions & 0 deletions controllers/medusa/medusabackupjob_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,8 @@ func (r *MedusaBackupJobReconciler) createMedusaBackup(ctx context.Context, back
backupResource.Status.FinishTime = finishTime
backupResource.Status.TotalNodes = backupSummary.TotalNodes
backupResource.Status.FinishedNodes = backupSummary.FinishedNodes
backupResource.Status.TotalFiles = backupSummary.TotalObjects
backupResource.Status.TotalSize = humanize(backupSummary.TotalSize)
backupResource.Status.Nodes = make([]*medusav1alpha1.MedusaBackupNode, len(backupSummary.Nodes))
for i, node := range backupSummary.Nodes {
backupResource.Status.Nodes[i] = &medusav1alpha1.MedusaBackupNode{
Expand Down Expand Up @@ -336,3 +338,13 @@ func (r *MedusaBackupJobReconciler) SetupWithManager(mgr ctrl.Manager) error {
For(&medusav1alpha1.MedusaBackupJob{}, builder.WithPredicates(predicate.GenerationChangedPredicate{})).
Complete(r)
}

func humanize(bytes int64) string {
units := []string{"B", "KB", "MB", "GB", "TB", "PB"}
size := float64(bytes)
i := 0
for ; size >= 1024 && i < len(units)-1; i++ {
size /= 1024
}
return fmt.Sprintf("%.2f %s", size, units[i])
}
26 changes: 26 additions & 0 deletions controllers/medusa/medusabackupjob_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ const (
defaultBackupName = "backup1"
dc1PodPrefix = "192.168.1."
dc2PodPrefix = "192.168.2."
fakeBackupFileCount = int64(13)
fakeBackupByteSize = int64(42)
fakeBackupHumanSize = "42.00 B"
)

func testMedusaBackupDatacenter(t *testing.T, ctx context.Context, f *framework.Framework, namespace string) {
Expand Down Expand Up @@ -243,6 +246,8 @@ func createAndVerifyMedusaBackup(dcKey framework.ClusterKey, dc *cassdcapi.Cassa
require.Equal(medusaBackup.Status.TotalNodes, dc.Spec.Size, "backup total nodes doesn't match dc nodes")
require.Equal(medusaBackup.Status.FinishedNodes, dc.Spec.Size, "backup finished nodes doesn't match dc nodes")
require.Equal(len(medusaBackup.Status.Nodes), int(dc.Spec.Size), "backup topology doesn't match dc topology")
require.Equal(medusaBackup.Status.TotalFiles, fakeBackupFileCount, "backup total files doesn't match")
require.Equal(medusaBackup.Status.TotalSize, fakeBackupHumanSize, "backup total size doesn't match")
require.Equal(medusa.StatusType_SUCCESS.String(), medusaBackup.Status.Status, "backup status is not success")

require.Equal(int(dc.Spec.Size), len(medusaClientFactory.GetRequestedBackups(dc.DatacenterName())))
Expand Down Expand Up @@ -354,6 +359,8 @@ func (c *fakeMedusaClient) GetBackups(ctx context.Context) ([]*medusa.BackupSumm
FinishTime: 10,
TotalNodes: 3,
FinishedNodes: 3,
TotalObjects: fakeBackupFileCount,
TotalSize: fakeBackupByteSize,
Status: *medusa.StatusType_SUCCESS.Enum(),
Nodes: []*medusa.BackupNode{
{
Expand Down Expand Up @@ -502,3 +509,22 @@ func reconcileMedusaStandaloneDeployment(ctx context.Context, t *testing.T, f *f

require.NoError(t, err, "Failed to update Medusa Deployment status")
}

func TestHumanize(t *testing.T) {
t.Run("humanizeTrivialSizes", humanizeTrivialSizes)
t.Run("humanizeArbitrarySizes", humanizeArbitrarySizes)
}

func humanizeTrivialSizes(t *testing.T) {
assert.Equal(t, "1.00 B", humanize(1))
assert.Equal(t, "1.00 KB", humanize(1024))
assert.Equal(t, "1.00 MB", humanize(1024*1024))
assert.Equal(t, "1.00 GB", humanize(1024*1024*1024))
}

func humanizeArbitrarySizes(t *testing.T) {
assert.Equal(t, "127.50 KB", humanize(130557))
assert.Equal(t, "4.03 GB", humanize(4325130557))
assert.Equal(t, "7.67 TB", humanize(8434729356343))
assert.Equal(t, "1096.52 PB", humanize(1234567890123456790))
}
12 changes: 7 additions & 5 deletions docs/content/en/tasks/backup-restore/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ K8ssandra Operator will detect the `MedusaBackupJob` object creation and trigger
To monitor the backup completion, check if the `finishTime` is set in the `MedusaBackupJob` object status. Example:

```sh
% kubectl get medusabackupjob/medusa-backup1 -o yaml
% kubectl get medusabackupjob/backup1 -o yaml

kind: MedusaBackupJob
metadata:
Expand Down Expand Up @@ -159,7 +159,7 @@ medusa-backup1 19m 19m

All pods having completed the backup will be in the `finished` list.
At the end of the backup operation, a `MedusaBackup` custom resource will be created with the same name as the `MedusaBackupJob` object. It materializes the backup locally on the Kubernetes cluster.
The MedusaBackup object status contains the total number of node in the cluster at the time of the backup, the number of nodes that successfully achieved the backup, and the topology of the DC at the time of the backup:
The MedusaBackup object status contains the total number of node in the cluster at the time of the backup, the number of nodes that successfully achieved the backup, the topology of the DC at the time of the backup, the number of files backed up and their total size:

```yaml
apiVersion: medusa.k8ssandra.io/v1alpha1
Expand Down Expand Up @@ -189,6 +189,8 @@ status:
- -1058110708807841300
- -107256661843445790
status: SUCCESS
totalFiles: 120
totalSize: 127.67 KB
spec:
backupType: differential
cassandraDatacenter: dc1
Expand All @@ -199,9 +201,9 @@ The `kubectl get`` output for MedusaBackup objects will show a subset of this in

```sh
kubectl get MedusaBackup -A
NAME STARTED FINISHED NODES COMPLETED STATUS
backup1 29m 28m 2 2 SUCCESS
medusa-backup1 23m 23m 2 2 SUCCESS
NAME STARTED FINISHED NODES FILES SIZE COMPLETED STATUS
backup1 29m 28m 2 120 127.67 KB 2 SUCCESS
medusa-backup1 23m 23m 2 137 241.61 KB 2 SUCCESS
```

For a restore to be possible, a `MedusaBackup` object must exist.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ require (
github.com/stretchr/testify v1.8.2
go.uber.org/zap v1.24.0
google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.30.0
google.golang.org/protobuf v1.31.0
gopkg.in/resty.v1 v1.12.0
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.26.4
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1598,8 +1598,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20170511165959-379148ca0225/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
Expand Down
Loading
Loading