mirror of
https://github.com/weaveworks/scope.git
synced 2026-05-06 01:08:03 +00:00
148 lines
4.2 KiB
Go
148 lines
4.2 KiB
Go
package report
|
|
|
|
// Backwards-compatibility: code to read older reports and convert
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/ugorji/go/codec"
|
|
)
|
|
|
|
// For backwards-compatibility with probes that sent a map of latestControls data
|
|
type bcNode struct {
|
|
Node
|
|
LatestControls map[string]nodeControlDataLatestEntry `json:"latestControls,omitempty"`
|
|
}
|
|
|
|
type nodeControlDataLatestEntry struct {
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Value nodeControlData `json:"value"`
|
|
}
|
|
|
|
type nodeControlData struct {
|
|
Dead bool `json:"dead"`
|
|
}
|
|
|
|
// CodecDecodeSelf implements codec.Selfer
|
|
func (n *Node) CodecDecodeSelf(decoder *codec.Decoder) {
|
|
var in bcNode
|
|
decoder.Decode(&in)
|
|
*n = in.Node
|
|
if len(in.LatestControls) > 0 {
|
|
// Convert the map into a delimited string
|
|
cs := make([]string, 0, len(in.LatestControls))
|
|
var ts time.Time
|
|
for name, v := range in.LatestControls {
|
|
if !v.Value.Dead {
|
|
cs = append(cs, name)
|
|
// Pull out the newest timestamp to use for the whole set
|
|
if ts.Before(v.Timestamp) {
|
|
ts = v.Timestamp
|
|
}
|
|
}
|
|
}
|
|
n.Latest = n.Latest.Set(NodeActiveControls, ts, strings.Join(cs, ScopeDelim))
|
|
}
|
|
}
|
|
|
|
type _Node Node // just so we don't recurse inside CodecEncodeSelf
|
|
|
|
// CodecEncodeSelf implements codec.Selfer
|
|
func (n *Node) CodecEncodeSelf(encoder *codec.Encoder) {
|
|
encoder.Encode((*_Node)(n))
|
|
}
|
|
|
|
// Upgrade returns a new report based on a report received from the old probe.
|
|
//
|
|
func (r Report) Upgrade() Report {
|
|
return r.upgradePodNodes().upgradeNamespaces().upgradeDNSRecords()
|
|
}
|
|
|
|
func (r Report) upgradePodNodes() Report {
|
|
// At the same time the probe stopped reporting replicasets,
|
|
// it also started reporting deployments as pods' parents
|
|
if len(r.ReplicaSet.Nodes) == 0 {
|
|
return r
|
|
}
|
|
|
|
// For each pod, we check for any replica sets, and merge any deployments they point to
|
|
// into a replacement Parents value.
|
|
nodes := Nodes{}
|
|
for podID, pod := range r.Pod.Nodes {
|
|
if replicaSetIDs, ok := pod.Parents.Lookup(ReplicaSet); ok {
|
|
newParents := pod.Parents.Delete(ReplicaSet)
|
|
for _, replicaSetID := range replicaSetIDs {
|
|
if replicaSet, ok := r.ReplicaSet.Nodes[replicaSetID]; ok {
|
|
if deploymentIDs, ok := replicaSet.Parents.Lookup(Deployment); ok {
|
|
newParents = newParents.Add(Deployment, deploymentIDs)
|
|
}
|
|
}
|
|
}
|
|
// newParents contains a copy of the current parents without replicasets,
|
|
// PruneParents().WithParents() ensures replicasets are actually deleted
|
|
pod = pod.PruneParents().WithParents(newParents)
|
|
}
|
|
nodes[podID] = pod
|
|
}
|
|
r.Pod.Nodes = nodes
|
|
|
|
return r
|
|
}
|
|
|
|
func (r Report) upgradeNamespaces() Report {
|
|
if len(r.Namespace.Nodes) > 0 {
|
|
return r
|
|
}
|
|
|
|
namespaces := map[string]struct{}{}
|
|
for _, t := range []Topology{r.Pod, r.Service, r.Deployment, r.DaemonSet, r.StatefulSet, r.CronJob} {
|
|
for _, n := range t.Nodes {
|
|
if state, ok := n.Latest.Lookup(KubernetesState); ok && state == "deleted" {
|
|
continue
|
|
}
|
|
if namespace, ok := n.Latest.Lookup(KubernetesNamespace); ok {
|
|
namespaces[namespace] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
|
|
nodes := make(Nodes, len(namespaces))
|
|
for ns := range namespaces {
|
|
// Namespace ID:
|
|
// Probes did not use to report namespace ids, but since creating a report node requires an id,
|
|
// the namespace name, which is unique, is passed to `MakeNamespaceNodeID`
|
|
namespaceID := MakeNamespaceNodeID(ns)
|
|
nodes[namespaceID] = MakeNodeWith(namespaceID, map[string]string{KubernetesName: ns})
|
|
}
|
|
r.Namespace.Nodes = nodes
|
|
|
|
return r
|
|
}
|
|
|
|
func (r Report) upgradeDNSRecords() Report {
|
|
if len(r.DNS) > 0 {
|
|
return r
|
|
}
|
|
dns := make(DNSRecords)
|
|
for endpointID, endpoint := range r.Endpoint.Nodes {
|
|
_, addr, _, ok := ParseEndpointNodeID(endpointID)
|
|
snoopedNames, foundS := endpoint.Sets.Lookup(SnoopedDNSNames)
|
|
reverseNames, foundR := endpoint.Sets.Lookup(ReverseDNSNames)
|
|
if ok && (foundS || foundR) {
|
|
// Add address and names to report-level map
|
|
if existing, found := dns[addr]; found {
|
|
var sUnchanged, rUnchanged bool
|
|
snoopedNames, sUnchanged = snoopedNames.Merge(existing.Forward)
|
|
reverseNames, rUnchanged = reverseNames.Merge(existing.Reverse)
|
|
if sUnchanged && rUnchanged {
|
|
continue
|
|
}
|
|
}
|
|
dns[addr] = DNSRecord{Forward: snoopedNames, Reverse: reverseNames}
|
|
}
|
|
}
|
|
r.DNS = dns
|
|
return r
|
|
}
|