Skip to content

Commit a0c71ed

Browse files
Add DPT to OADP must gather (#1746)
* Add DPT to OADP must gather * minor fix * fix fmt verb and add yaml link * Add DPT to e2e tests * add lib/dpt.go * Fix CI tests * lint fix
1 parent 88b603e commit a0c71ed

File tree

8 files changed

+165
-3
lines changed

8 files changed

+165
-3
lines changed

must-gather/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/kubernetes-csi/external-snapshotter/client/v8 v8.0.0
99
github.com/migtools/oadp-non-admin v0.0.0-20250324123917-741ae3b7a67d
1010
github.com/openshift/api v0.0.0-20240912201240-0a8800162826
11-
github.com/openshift/oadp-operator v1.0.2-0.20250327225822-5cc21cec9653
11+
github.com/openshift/oadp-operator v1.0.2-0.20250506010707-2a52b7a20c4b
1212
github.com/openshift/oc v0.0.0-alpha.0.0.20250108103617-ae1bd9e4a75b
1313
github.com/operator-framework/api v0.26.0
1414
github.com/spf13/cobra v1.8.1

must-gather/go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ github.com/openshift/api v0.0.0-20240912201240-0a8800162826 h1:A8D9SN/hJUwAbdO0r
200200
github.com/openshift/api v0.0.0-20240912201240-0a8800162826/go.mod h1:OOh6Qopf21pSzqNVCB5gomomBXb8o5sGKZxG2KNpaXM=
201201
github.com/openshift/oadp-operator v1.0.2-0.20250327225822-5cc21cec9653 h1:p6t+nVTJsrT1FQSaL/n/sf9begEoLXfX08OVxfjdLYM=
202202
github.com/openshift/oadp-operator v1.0.2-0.20250327225822-5cc21cec9653/go.mod h1:tzlEfI5g4gomtv5dZ4qgEQSNSiwiOrsBj2P5nTqawPY=
203+
github.com/openshift/oadp-operator v1.0.2-0.20250506010707-2a52b7a20c4b h1:rz8ccMAPeFaFvxVfiD0k/GshGzU/uA10q/mJSLg6xWg=
204+
github.com/openshift/oadp-operator v1.0.2-0.20250506010707-2a52b7a20c4b/go.mod h1:IvBUP2qVUBst49SSzVhxajq4Bs1n/lm9K/kguhTltqI=
203205
github.com/openshift/oc v0.0.0-alpha.0.0.20250108103617-ae1bd9e4a75b h1:dBEu456jnnhr7KH1T+Mrna1DvFadk1qN+NEtLb8Nn8U=
204206
github.com/openshift/oc v0.0.0-alpha.0.0.20250108103617-ae1bd9e4a75b/go.mod h1:22L7FMouzG54z19RZ/o+RcMCLa8vCdvZ4jQ+u3iHWHw=
205207
github.com/openshift/velero v0.10.2-0.20250313160323-584cf1148a74 h1:ZHO0O6g1Enel2O4rAk7VfWLHlQKYkOcdWGAmoiZ3fQw=

must-gather/pkg/cli.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ For more information, check OADP must-gather documentation: https://docs.redhat.
156156
subscriptionList := &operatorsv1alpha1.SubscriptionList{}
157157

158158
dataProtectionApplicationList := &oadpv1alpha1.DataProtectionApplicationList{}
159+
dataProtectionTestList := &oadpv1alpha1.DataProtectionTestList{}
159160
cloudStorageList := &oadpv1alpha1.CloudStorageList{}
160161
backupStorageLocationList := &velerov1.BackupStorageLocationList{}
161162
volumeSnapshotLocationList := &velerov1.VolumeSnapshotLocationList{}
@@ -186,6 +187,7 @@ For more information, check OADP must-gather documentation: https://docs.redhat.
186187
subscriptionList,
187188

188189
dataProtectionApplicationList,
190+
dataProtectionTestList,
189191
cloudStorageList,
190192
backupStorageLocationList,
191193
volumeSnapshotLocationList,
@@ -314,6 +316,7 @@ For more information, check OADP must-gather documentation: https://docs.redhat.
314316
templates.ReplaceClusterInformationSection(outputPath, clusterID, clusterVersion, infrastructureList, nodeList)
315317
templates.ReplaceOADPOperatorInstallationSection(outputPath, importantCSVsByNamespace, importantSubscriptionsByNamespace, foundOADP, foundRelatedProducts, oldOADPError, oadpOperatorsText)
316318
templates.ReplaceDataProtectionApplicationsSection(outputPath, dataProtectionApplicationList)
319+
templates.ReplaceDataProtectionTestsSection(outputPath, dataProtectionTestList)
317320
templates.ReplaceCloudStoragesSection(outputPath, cloudStorageList)
318321
templates.ReplaceBackupStorageLocationsSection(outputPath, backupStorageLocationList)
319322
templates.ReplaceVolumeSnapshotLocationsSection(outputPath, volumeSnapshotLocationList)

must-gather/pkg/gvk/gvk.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ var (
3030
Version: "v1alpha1",
3131
Kind: "DataProtectionApplication",
3232
}
33+
DataProtectionTestGVK = schema.GroupVersionKind{
34+
Group: "oadp.openshift.io",
35+
Version: "v1alpha1",
36+
Kind: "DataProtectionTest",
37+
}
3338
CloudStorageGVK = schema.GroupVersionKind{
3439
Group: "oadp.openshift.io",
3540
Version: "v1alpha1",

must-gather/pkg/templates/summary.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ var (
4545
"CLUSTER_ID", "OCP_VERSION", "CLOUD", "ARCH", "CLUSTER_VERSION",
4646
"OADP_VERSIONS",
4747
"DATA_PROTECTION_APPLICATIONS",
48+
"DATA_PROTECTION_TESTS",
4849
"CLOUD_STORAGES",
4950
"BACKUP_STORAGE_LOCATIONS",
5051
"VOLUME_SNAPSHOT_LOCATIONS",
@@ -82,6 +83,7 @@ const summaryTemplate = `# OADP must-gather summary version <<MUST_GATHER_VERSIO
8283
- [Cluster information](#cluster-information)
8384
- [OADP operator installation information](#oadp-operator-installation-information)
8485
- [DataProtectionApplications (DPAs)](#dataprotectionapplications-dpas)
86+
- [DataProtectionTests (DPTs)](#dataprotectiontests-dpts)
8587
- [CloudStorages](#cloudstorages)
8688
- [BackupStorageLocations (BSLs)](#backupstoragelocations-bsls)
8789
- [VolumeSnapshotLocations (VSLs)](#volumesnapshotlocations-vsls)
@@ -127,6 +129,10 @@ const summaryTemplate = `# OADP must-gather summary version <<MUST_GATHER_VERSIO
127129
128130
<<DATA_PROTECTION_APPLICATIONS>>
129131
132+
### DataProtectionTests (DPTs)
133+
134+
<<DATA_PROTECTION_TESTS>>
135+
130136
### CloudStorages
131137
132138
<<CLOUD_STORAGES>>
@@ -387,6 +393,88 @@ func ReplaceDataProtectionApplicationsSection(outputPath string, dataProtectionA
387393
}
388394
}
389395

396+
func ReplaceDataProtectionTestsSection(outputPath string, dptList *oadpv1alpha1.DataProtectionTestList) {
397+
if dptList != nil && len(dptList.Items) != 0 {
398+
dataProtectionTestsByNamespace := map[string][]oadpv1alpha1.DataProtectionTest{}
399+
400+
for _, dpt := range dptList.Items {
401+
dataProtectionTestsByNamespace[dpt.Namespace] = append(dataProtectionTestsByNamespace[dpt.Namespace], dpt)
402+
}
403+
404+
summaryTemplateReplaces["DATA_PROTECTION_TESTS"] = ""
405+
summaryTemplateReplaces["DATA_PROTECTION_TESTS"] += "| Name | Phase | Last Tested | Upload Speed (MBps) | Encryption | Versioning | Snapshots | Age | YAML |\n"
406+
summaryTemplateReplaces["DATA_PROTECTION_TESTS"] += "| ---- | ----- | ----------- | ------------------- | ---------- | -----------| --------- | --- | ---- |\n"
407+
408+
for namespace, dpts := range dataProtectionTestsByNamespace {
409+
folder := fmt.Sprintf("namespaces/%s/oadp.openshift.io/dataprotectiontests", namespace)
410+
file := folder + "/dataprotectiontests.yaml"
411+
412+
list := &corev1.List{}
413+
list.GetObjectKind().SetGroupVersionKind(gvk.ListGVK)
414+
415+
for _, dpt := range dpts {
416+
dpt.GetObjectKind().SetGroupVersionKind(gvk.DataProtectionTestGVK)
417+
list.Items = append(list.Items, runtime.RawExtension{Object: &dpt})
418+
419+
// Fields
420+
name := dpt.Name
421+
422+
phase := "⚠️ Unknown"
423+
if dpt.Status.Phase != "" {
424+
phase = string(dpt.Status.Phase)
425+
}
426+
427+
lastTested := "N/A"
428+
if !dpt.Status.LastTested.IsZero() {
429+
lastTested = humanizeDurationSince(dpt.Status.LastTested.Time)
430+
}
431+
432+
uploadSpeed := "⚠️ N/A"
433+
if dpt.Status.UploadTest.SpeedMbps > 0 {
434+
uploadSpeed = fmt.Sprintf("%d", dpt.Status.UploadTest.SpeedMbps)
435+
}
436+
437+
encryption := dpt.Status.BucketMetadata.EncryptionAlgorithm
438+
if encryption == "" {
439+
encryption = "None"
440+
}
441+
442+
versioning := dpt.Status.BucketMetadata.VersioningStatus
443+
if versioning == "" {
444+
versioning = "None"
445+
}
446+
447+
snapshots := "N/A"
448+
if dpt.Status.SnapshotSummary != "" {
449+
snapshots = dpt.Status.SnapshotSummary
450+
}
451+
452+
age := humanizeDurationSince(dpt.CreationTimestamp.Time)
453+
454+
yamlLink := fmt.Sprintf("[`yaml`](%s)", file)
455+
456+
summaryTemplateReplaces["DATA_PROTECTION_TESTS"] += fmt.Sprintf(
457+
"| %s | %s | %s | %s | %s | %s | %s | %s | %s |\n",
458+
name, phase, lastTested, uploadSpeed, encryption, versioning, snapshots, age, yamlLink,
459+
)
460+
}
461+
462+
createYAML(outputPath, file, list)
463+
}
464+
} else {
465+
summaryTemplateReplaces["DATA_PROTECTION_TESTS"] = "❌ No DataProtectionTest was found in the cluster"
466+
summaryTemplateReplaces["ERRORS"] += "⚠️ No DataProtectionTest was found in the cluster\n\n"
467+
}
468+
}
469+
470+
func humanizeDurationSince(t time.Time) string {
471+
if t.IsZero() {
472+
return "N/A"
473+
}
474+
return time.Since(t).Round(time.Second).String()
475+
}
476+
477+
390478
func ReplaceCloudStoragesSection(outputPath string, cloudStorageList *oadpv1alpha1.CloudStorageList) {
391479
if cloudStorageList != nil && len(cloudStorageList.Items) != 0 {
392480
cloudStorageByNamespace := map[string][]oadpv1alpha1.CloudStorage{}
@@ -1574,6 +1662,7 @@ func ReplaceCustomResourceDefinitionsSection(outputPath string, clusterConfig *r
15741662
// CRD spec.names.plural : CRD spec.group
15751663
crds := map[string]string{
15761664
"dataprotectionapplications": gvk.DataProtectionApplicationGVK.Group,
1665+
"dataprotectiontests": gvk.DataProtectionTestGVK.Group,
15771666
"cloudstorages": gvk.CloudStorageGVK.Group,
15781667
"backupstoragelocations": gvk.BackupStorageLocationGVK.Group,
15791668
"volumesnapshotlocations": gvk.VolumeSnapshotLocationGVK.Group,

tests/e2e/backup_restore_suite_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,8 +295,16 @@ var _ = ginkgo.Describe("Backup and restore tests", ginkgo.Ordered, func() {
295295
// using kopia to collect more info (DaemonSet)
296296
waitOADPReadiness(lib.KOPIA)
297297

298+
log.Printf("Creating real DataProtectionTest before must-gather")
299+
bsls, err := dpaCR.ListBSLs()
300+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
301+
302+
bslName := bsls.Items[0].Name
303+
err = lib.CreateUploadTestOnlyDPT(dpaCR.Client, dpaCR.Namespace, bslName)
304+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
305+
298306
log.Printf("Running OADP must-gather")
299-
err := lib.RunMustGather(artifact_dir, dpaCR.Client)
307+
err = lib.RunMustGather(artifact_dir, dpaCR.Client)
300308
gomega.Expect(err).ToNot(gomega.HaveOccurred())
301309

302310
err = dpaCR.Delete()

tests/e2e/lib/dpt.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package lib
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"time"
8+
9+
"github.com/onsi/gomega"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/apimachinery/pkg/types"
12+
"sigs.k8s.io/controller-runtime/pkg/client"
13+
14+
"github.com/openshift/oadp-operator/api/v1alpha1"
15+
)
16+
17+
func CreateUploadTestOnlyDPT(c client.Client, namespace, bslName string) error {
18+
dpt := &v1alpha1.DataProtectionTest{
19+
ObjectMeta: metav1.ObjectMeta{
20+
Name: fmt.Sprintf("e2e-uploadtest-dpt-%d", time.Now().Unix()),
21+
Namespace: namespace,
22+
},
23+
Spec: v1alpha1.DataProtectionTestSpec{
24+
BackupLocationName: bslName,
25+
UploadSpeedTestConfig: &v1alpha1.UploadSpeedTestConfig{
26+
FileSize: "5MB",
27+
Timeout: metav1.Duration{Duration: 120 * time.Second},
28+
},
29+
},
30+
}
31+
32+
if err := c.Create(context.TODO(), dpt); err != nil {
33+
return fmt.Errorf("creating DataProtectionTest: %w", err)
34+
}
35+
36+
// Wait until DPT completes
37+
gomega.Eventually(func() bool {
38+
_ = c.Get(context.TODO(), types.NamespacedName{
39+
Name: dpt.Name,
40+
Namespace: namespace,
41+
}, dpt)
42+
return dpt.Status.Phase == "Complete" || dpt.Status.Phase == "Failed"
43+
}, time.Minute*3, time.Second*10).Should(gomega.BeTrue())
44+
45+
log.Printf("✅ DPT %s completed with phase: %s", dpt.Name, dpt.Status.Phase)
46+
return nil
47+
}

tests/e2e/virt_backup_restore_suite_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,16 @@ var _ = ginkgo.Describe("VM backup and restore tests", ginkgo.Ordered, func() {
218218
// using kopia to collect more info (DaemonSet)
219219
waitOADPReadiness(lib.KOPIA)
220220

221+
log.Printf("Creating real DataProtectionTest before must-gather")
222+
bsls, err := dpaCR.ListBSLs()
223+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
224+
225+
bslName := bsls.Items[0].Name
226+
err = lib.CreateUploadTestOnlyDPT(dpaCR.Client, dpaCR.Namespace, bslName)
227+
gomega.Expect(err).ToNot(gomega.HaveOccurred())
228+
221229
log.Printf("Running OADP must-gather")
222-
err := lib.RunMustGather(artifact_dir, dpaCR.Client)
230+
err = lib.RunMustGather(artifact_dir, dpaCR.Client)
223231
gomega.Expect(err).ToNot(gomega.HaveOccurred())
224232

225233
err = dpaCR.Delete()

0 commit comments

Comments
 (0)