1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package scale
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"time"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
KindDeployment = "Deployment"
KindStatefulSet = "StatefulSet"
KindDaemonSet = "DaemonSet"
KindJob = "Job"
KindReplicaSet = "ReplicaSet"
)
type WorkloadKey struct {
Kind string `json:"kind"`
Namespace string `json:"namespace"`
Name string `json:"name"`
}
func (k WorkloadKey) String() string {
return k.Kind + "/" + k.Namespace + "/" + k.Name
}
type BaselineEntry struct {
WorkloadKey
SpecHash string `json:"specHash"`
}
type Baseline struct {
Manager string `json:"manager"`
MeasuredAt time.Time `json:"measuredAt"`
Workloads []BaselineEntry `json:"workloads"`
}
func SpecHash(spec any) (string, error) {
raw, err := json.Marshal(spec)
if err != nil {
return "", fmt.Errorf("scale: encoding a workload spec to hash it: %w", err)
}
sum := sha256.Sum256(raw)
return hex.EncodeToString(sum[:]), nil
}
func (b Baseline) Holds(k WorkloadKey, spec any) bool {
for _, e := range b.Workloads {
if e.WorkloadKey != k {
continue
}
h, err := SpecHash(spec)
return err == nil && h == e.SpecHash
}
return false
}
func Narrow(o Observation, replicaSets []appsv1.ReplicaSet, b Baseline) Observation {
present := map[WorkloadKey]bool{}
out := Observation{Placement: o.Placement, UnreconciledCustomResources: o.UnreconciledCustomResources}
for _, d := range o.Deployments {
k := WorkloadKey{Kind: KindDeployment, Namespace: d.Namespace, Name: d.Name}
present[k] = true
if !b.Holds(k, d.Spec) {
out.Deployments = append(out.Deployments, d)
}
}
for _, s := range o.StatefulSets {
k := WorkloadKey{Kind: KindStatefulSet, Namespace: s.Namespace, Name: s.Name}
present[k] = true
if !b.Holds(k, s.Spec) {
out.StatefulSets = append(out.StatefulSets, s)
}
}
for _, d := range o.DaemonSets {
k := WorkloadKey{Kind: KindDaemonSet, Namespace: d.Namespace, Name: d.Name}
present[k] = true
if !b.Holds(k, d.Spec) {
out.DaemonSets = append(out.DaemonSets, d)
}
}
for _, j := range o.Jobs {
k := WorkloadKey{Kind: KindJob, Namespace: j.Namespace, Name: j.Name}
present[k] = true
if !b.Holds(k, j.Spec) {
out.Jobs = append(out.Jobs, j)
}
}
deploymentOf := deploymentsOfReplicaSets(replicaSets)
for _, p := range o.Pods {
if k, ok := workloadOf(&p, deploymentOf); ok && present[k] {
continue
}
out.Pods = append(out.Pods, p)
}
return out
}
func workloadOf(p *corev1.Pod, deploymentOf map[WorkloadKey]WorkloadKey) (WorkloadKey, bool) {
c := metav1.GetControllerOf(p)
if c == nil {
return WorkloadKey{}, false
}
k := WorkloadKey{Kind: c.Kind, Namespace: p.Namespace, Name: c.Name}
if c.Kind == KindReplicaSet {
d, ok := deploymentOf[k]
return d, ok
}
return k, true
}