|
|
@@ -2,6 +2,11 @@ package costmodel
|
|
|
|
|
|
import (
|
|
|
"fmt"
|
|
|
+ "math"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+
|
|
|
"github.com/opencost/opencost/pkg/cloud"
|
|
|
"github.com/opencost/opencost/pkg/env"
|
|
|
"github.com/opencost/opencost/pkg/kubecost"
|
|
|
@@ -9,10 +14,6 @@ import (
|
|
|
"github.com/opencost/opencost/pkg/prom"
|
|
|
"github.com/opencost/opencost/pkg/util/timeutil"
|
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
|
- "math"
|
|
|
- "strconv"
|
|
|
- "strings"
|
|
|
- "time"
|
|
|
)
|
|
|
|
|
|
// This is a bit of a hack to work around garbage data from cadvisor
|
|
|
@@ -1859,7 +1860,8 @@ func applyPVCsToPods(window kubecost.Window, podMap map[podKey]*pod, podPVCMap m
|
|
|
// If pod does not exist or the pod does not have any allocations
|
|
|
// get unmounted pod for cluster
|
|
|
if !ok2 || len(pod.Allocations) == 0 {
|
|
|
- pod = getUnmountedPodForCluster(window, podMap, pvc.Cluster)
|
|
|
+ // Get namespace unmounted pod, as pvc will have a namespace
|
|
|
+ pod = getUnmountedPodForNamespace(window, podMap, pvc.Cluster, pvc.Namespace)
|
|
|
}
|
|
|
for _, alloc := range pod.Allocations {
|
|
|
s, e := pod.Start, pod.End
|
|
|
@@ -1909,6 +1911,8 @@ func applyUnmountedPVs(window kubecost.Window, podMap map[podKey]*pod, pvMap map
|
|
|
}
|
|
|
|
|
|
if !mounted {
|
|
|
+
|
|
|
+ // a pv without a pvc will not have a namespace, so get the cluster unmounted pod
|
|
|
pod := getUnmountedPodForCluster(window, podMap, pv.Cluster)
|
|
|
|
|
|
// Calculate pv Cost
|
|
|
@@ -1935,7 +1939,9 @@ func applyUnmountedPVs(window kubecost.Window, podMap map[podKey]*pod, pvMap map
|
|
|
func applyUnmountedPVCs(window kubecost.Window, podMap map[podKey]*pod, pvcMap map[pvcKey]*pvc) {
|
|
|
for _, pvc := range pvcMap {
|
|
|
if !pvc.Mounted && pvc.Volume != nil {
|
|
|
- pod := getUnmountedPodForCluster(window, podMap, pvc.Cluster)
|
|
|
+
|
|
|
+ // Get namespace unmounted pod, as pvc will have a namespace
|
|
|
+ pod := getUnmountedPodForNamespace(window, podMap, pvc.Cluster, pvc.Namespace)
|
|
|
|
|
|
// Calculate pv Cost
|
|
|
|
|
|
@@ -1994,6 +2000,37 @@ func getUnmountedPodForCluster(window kubecost.Window, podMap map[podKey]*pod, c
|
|
|
return thisPod
|
|
|
}
|
|
|
|
|
|
+// getUnmountedPodForNamespace is as getUnmountedPodForCluster, but keys allocation property pod/namespace field off namespace
|
|
|
+// This creates or adds allocations to an unmounted pod in the specified namespace, rather than in __unmounted__
|
|
|
+func getUnmountedPodForNamespace(window kubecost.Window, podMap map[podKey]*pod, cluster string, namespace string) *pod {
|
|
|
+ container := kubecost.UnmountedSuffix
|
|
|
+ podName := fmt.Sprintf("%s-unmounted-pvcs", namespace)
|
|
|
+ node := ""
|
|
|
+
|
|
|
+ thisPodKey := newPodKey(cluster, namespace, podName)
|
|
|
+ // Initialize pod and container if they do not already exist
|
|
|
+ thisPod, ok := podMap[thisPodKey]
|
|
|
+ if !ok {
|
|
|
+ thisPod = &pod{
|
|
|
+ Window: window.Clone(),
|
|
|
+ Start: *window.Start(),
|
|
|
+ End: *window.End(),
|
|
|
+ Key: thisPodKey,
|
|
|
+ Allocations: map[string]*kubecost.Allocation{},
|
|
|
+ }
|
|
|
+
|
|
|
+ thisPod.appendContainer(container)
|
|
|
+ thisPod.Allocations[container].Properties.Cluster = cluster
|
|
|
+ thisPod.Allocations[container].Properties.Node = node
|
|
|
+ thisPod.Allocations[container].Properties.Namespace = namespace
|
|
|
+ thisPod.Allocations[container].Properties.Pod = podName
|
|
|
+ thisPod.Allocations[container].Properties.Container = container
|
|
|
+
|
|
|
+ podMap[thisPodKey] = thisPod
|
|
|
+ }
|
|
|
+ return thisPod
|
|
|
+}
|
|
|
+
|
|
|
func calculateStartAndEnd(result *prom.QueryResult, resolution time.Duration) (time.Time, time.Time) {
|
|
|
s := time.Unix(int64(result.Values[0].Timestamp), 0).UTC()
|
|
|
// subtract resolution from start time to cover full time period
|