• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubevirt / hyperconverged-cluster-operator / 19075895534

04 Nov 2025 04:36PM UTC coverage: 76.775% (-0.5%) from 77.239%
19075895534

Pull #3835

github

web-flow
Merge 7ff4689c0 into f64d16a69
Pull Request #3835: [WIP] Add Cluster Memory Load Perses dashboard

0 of 62 new or added lines in 2 files covered. (0.0%)

7917 of 10312 relevant lines covered (76.77%)

1.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/controllers/observability/perses.go
1
package observability
2

3
import (
4
        "context"
5
        "encoding/json"
6
        "fmt"
7
        "io/fs"
8
        "os"
9
        "path/filepath"
10

11
        "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
12
        "k8s.io/apimachinery/pkg/runtime/schema"
13
        "sigs.k8s.io/controller-runtime/pkg/client"
14
        "sigs.k8s.io/yaml"
15
)
16

17
// persesAssetsDir is the directory (inside the repo image) containing Perses CR manifests (yaml).
18
// Each YAML should define a single resource: PersesDashboard or PersesDatasource.
19
const persesAssetsDir = "assets/dashboards/perses"
20

21
// ReconcilePersesResources applies all Perses resources shipped with the operator under assets/perses.
22
// It uses server-side apply to create/update resources idempotently without relying on cache reads.
NEW
23
func (r *Reconciler) ReconcilePersesResources(ctx context.Context) error {
×
NEW
24
        wd, err := os.Getwd()
×
NEW
25
        if err != nil {
×
NEW
26
                return fmt.Errorf("failed to get working dir: %w", err)
×
NEW
27
        }
×
28

NEW
29
        d := os.DirFS(wd)
×
NEW
30
        // If the directory does not exist, nothing to do.
×
NEW
31
        if _, err := fs.Stat(d, persesAssetsDir); err != nil {
×
NEW
32
                return nil
×
NEW
33
        }
×
34

NEW
35
        return fs.WalkDir(d, persesAssetsDir, func(path string, entry fs.DirEntry, err error) error {
×
NEW
36
                if err != nil {
×
NEW
37
                        return err
×
NEW
38
                }
×
NEW
39
                if entry.IsDir() {
×
NEW
40
                        return nil
×
NEW
41
                }
×
NEW
42
                if ext := filepath.Ext(entry.Name()); ext != ".yml" && ext != ".yaml" {
×
NEW
43
                        return nil
×
NEW
44
                }
×
45

NEW
46
                file, err := d.Open(path)
×
NEW
47
                if err != nil {
×
NEW
48
                        return fmt.Errorf("failed to open %s: %w", path, err)
×
NEW
49
                }
×
NEW
50
                defer file.Close()
×
NEW
51

×
NEW
52
                content, err := fs.ReadFile(d, path)
×
NEW
53
                if err != nil {
×
NEW
54
                        return fmt.Errorf("failed to read %s: %w", path, err)
×
NEW
55
                }
×
56

57
                // Decode YAML → JSON → map
NEW
58
                jsonBytes, err := yaml.YAMLToJSON(content)
×
NEW
59
                if err != nil {
×
NEW
60
                        return fmt.Errorf("failed to convert yaml to json for %s: %w", path, err)
×
NEW
61
                }
×
62

NEW
63
                var objMap map[string]any
×
NEW
64
                if err := json.Unmarshal(jsonBytes, &objMap); err != nil {
×
NEW
65
                        return fmt.Errorf("failed to unmarshal json for %s: %w", path, err)
×
NEW
66
                }
×
67

68
                // Enforce namespace to operator's namespace to ensure ownership & GC
69
                // If the manifest specifies a namespace, it will be overridden.
70
                // We only support namespaced resources here.
NEW
71
                metadata, _ := objMap["metadata"].(map[string]any)
×
NEW
72
                if metadata == nil {
×
NEW
73
                        metadata = map[string]any{}
×
NEW
74
                        objMap["metadata"] = metadata
×
NEW
75
                }
×
NEW
76
                metadata["namespace"] = r.namespace
×
NEW
77

×
NEW
78
                // Build Unstructured with GVK populated
×
NEW
79
                apiVersion, _ := objMap["apiVersion"].(string)
×
NEW
80
                kind, _ := objMap["kind"].(string)
×
NEW
81
                if apiVersion == "" || kind == "" {
×
NEW
82
                        return fmt.Errorf("missing apiVersion/kind in %s", path)
×
NEW
83
                }
×
84

NEW
85
                u := &unstructured.Unstructured{Object: objMap}
×
NEW
86
                u.SetGroupVersionKind(schema.FromAPIVersionAndKind(apiVersion, kind))
×
NEW
87

×
NEW
88
                // Apply with SSA so we don't need to read existing objects
×
NEW
89
                if err := r.Patch(ctx, u, client.Apply, client.FieldOwner("hyperconverged-operator"), client.ForceOwnership); err != nil {
×
NEW
90
                        return fmt.Errorf("failed to apply %s: %w", path, err)
×
NEW
91
                }
×
92

NEW
93
                return nil
×
94
        })
95
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc