Skip to content

Commit

Permalink
Manage cluster name and zones
Browse files Browse the repository at this point in the history
  • Loading branch information
jpinsonneau committed Jan 29, 2024
1 parent 958be65 commit 9aacffa
Show file tree
Hide file tree
Showing 28 changed files with 521 additions and 78 deletions.
34 changes: 34 additions & 0 deletions config/sample-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ frontend:
filter: id
default: true
width: 15
- id: ClusterName
name: Cluster Name
field: K8S_ClusterName
filter: cluster_name
default: false
width: 15
- id: SrcK8S_Name
group: Source
name: Name
Expand Down Expand Up @@ -167,6 +173,13 @@ frontend:
calculated: getConcatenatedValue(SrcAddr,SrcPort)
default: false
width: 15
- id: SrcZone
group: Source
name: Zone
field: SrcK8S_Zone
filter: src_zone
default: false
width: 15
- id: DstK8S_Name
group: Destination
name: Name
Expand Down Expand Up @@ -279,6 +292,13 @@ frontend:
calculated: getConcatenatedValue(DstAddr,DstPort)
default: false
width: 15
- id: DstZone
group: Destination
name: Zone
field: DstK8S_Zone
filter: dst_zone
default: false
width: 15
- id: K8S_Name
name: Names
calculated: getSrcOrDstValue(SrcK8S_Name,DstK8S_Name)
Expand Down Expand Up @@ -472,6 +492,10 @@ frontend:
default: true
width: 5
filters:
- id: cluster_name
name: Cluster Name
component: autocomplete
hint: Specify a single cluster name.
- id: src_namespace
name: Namespace
component: autocomplete
Expand Down Expand Up @@ -576,6 +600,16 @@ frontend:
- Starting text like cluster, "cluster-*"
- Ending text like "*-registry"
- Pattern like "cluster-*-registry", "c*-*-r*y", -i*e-
- id: src_zone
name: Zone Name
component: autocomplete
category: source
hint: Specify a single zone.
- id: dst_zone
name: Zone Name
component: autocomplete
category: destination
hint: Specify a single zone.
- id: src_resource
name: Resource
component: autocomplete
Expand Down
4 changes: 4 additions & 0 deletions mocks/updateMocks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ curl 'http://localhost:3100/loki/api/v1/query_range?query=\{app=%22netobserv-flo
echo 'Getting metrics'
curl 'http://localhost:3100/loki/api/v1/query_range?query=topk(5,sum%20by(app)%20(rate(\{app=%22netobserv-flowcollector%22,FlowDirection=%221%22\}|~`Duplicate%22:false`|json|unwrap%20Packets|__error__=%22%22\[720s\])))&limit=5&step=360s'\
| jq > ./loki/flow_metrics_app.json
curl 'http://localhost:3100/loki/api/v1/query_range?query=topk(50,sum%20by(K8S_ClusterName)%20(rate(\{app=%22netobserv-flowcollector%22,FlowDirection=%221%22\}|~`Duplicate%22:false`|json|unwrap%20Packets|__error__=%22%22\[720s\])))&limit=50&step=360s'\
| jq > ./loki/flow_metrics_cluster.json
curl 'http://localhost:3100/loki/api/v1/query_range?query=topk(50,sum%20by(SrcK8S_Zone,DstK8S_Zone)%20(rate(\{app=%22netobserv-flowcollector%22,FlowDirection=%221%22\}|~`Duplicate%22:false`|json|unwrap%20Packets|__error__=%22%22\[720s\])))&limit=50&step=360s'\
| jq > ./loki/flow_metrics_zone.json
curl 'http://localhost:3100/loki/api/v1/query_range?query=topk(50,sum%20by(SrcK8S_HostName,DstK8S_HostName)%20(rate(\{app=%22netobserv-flowcollector%22,FlowDirection=%221%22\}|~`Duplicate%22:false`|json|unwrap%20Packets|__error__=%22%22\[720s\])))&limit=50&step=360s'\
| jq > ./loki/flow_metrics_host.json
curl 'http://localhost:3100/loki/api/v1/query_range?query=topk(50,sum%20by(SrcK8S_Namespace,DstK8S_Namespace)%20(rate(\{app=%22netobserv-flowcollector%22,FlowDirection=%221%22\}|~`Duplicate%22:false`|json|unwrap%20Packets|__error__=%22%22\[720s\])))&limit=50&step=360s'\
Expand Down
4 changes: 4 additions & 0 deletions pkg/handler/lokiclientmock/loki_client_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ func (o *LokiClientMock) Get(url string) ([]byte, int, error) {
path += "_state.json"
} else if strings.Contains(url, "by(PktDropLatestDropCause)") {
path += "_cause.json"
} else if strings.Contains(url, "by(K8S_ClusterName)") {
path += "_cluster.json"
} else if strings.Contains(url, "by(SrcK8S_Zone,DstK8S_Zone)") {
path += "zone.json"
} else if strings.Contains(url, "by(SrcK8S_HostName,DstK8S_HostName)") {
path += "_host.json"
} else if strings.Contains(url, "by(SrcK8S_Namespace,DstK8S_Namespace)") {
Expand Down
53 changes: 53 additions & 0 deletions pkg/handler/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,59 @@ import (
"github.com/netobserv/network-observability-console-plugin/pkg/utils"
)

func GetClusters(cfg *loki.Config) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
lokiClient := newLokiClient(cfg, r.Header, false)
var code int
startTime := time.Now()
defer func() {
metrics.ObserveHTTPCall("GetClusters", code, startTime)
}()

// Fetch and merge values for K8S_ClusterName
values, code, err := getLabelValues(cfg, lokiClient, fields.Cluster)
if err != nil {
writeError(w, code, "Error while fetching label cluster values from Loki: "+err.Error())
return
}

code = http.StatusOK
writeJSON(w, code, utils.NonEmpty(utils.Dedup(values)))
}
}

func GetZones(cfg *loki.Config) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
lokiClient := newLokiClient(cfg, r.Header, false)
var code int
startTime := time.Now()
defer func() {
metrics.ObserveHTTPCall("GetZones", code, startTime)
}()

// Initialize values explicitly to avoid null json when empty
values := []string{}

// Fetch and merge values for SrcK8S_Zone and DstK8S_Zone
values1, code, err := getLabelValues(cfg, lokiClient, fields.SrcZone)
if err != nil {
writeError(w, code, "Error while fetching label source zone values from Loki: "+err.Error())
return
}
values = append(values, values1...)

values2, code, err := getLabelValues(cfg, lokiClient, fields.DstZone)
if err != nil {
writeError(w, code, "Error while fetching label destination zone values from Loki: "+err.Error())
return
}
values = append(values, values2...)

code = http.StatusOK
writeJSON(w, code, utils.NonEmpty(utils.Dedup(values)))
}
}

func GetNamespaces(cfg *loki.Config) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
lokiClient := newLokiClient(cfg, r.Header, false)
Expand Down
61 changes: 40 additions & 21 deletions pkg/loki/topology_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,28 +77,20 @@ func NewTopologyQuery(cfg *Config, start, end, limit, rateInterval, step string,
}, nil
}

func getLabels(aggregate, groups string) string {
var fields []string
switch aggregate {
case "app":
fields = []string{"app"}
case "droppedState":
fields = []string{"PktDropLatestState"}
case "droppedCause":
fields = []string{"PktDropLatestDropCause"}
case "dnsRCode":
fields = []string{"DnsFlagsResponseCode"}
case "host":
fields = []string{"SrcK8S_HostName", "DstK8S_HostName"}
case "namespace":
fields = []string{"SrcK8S_Namespace", "DstK8S_Namespace"}
case "owner":
fields = []string{"SrcK8S_OwnerName", "SrcK8S_OwnerType", "DstK8S_OwnerName", "DstK8S_OwnerType", "SrcK8S_Namespace", "DstK8S_Namespace"}
default:
fields = []string{"SrcK8S_Name", "SrcK8S_Type", "SrcK8S_OwnerName", "SrcK8S_OwnerType", "SrcK8S_Namespace", "SrcAddr", "SrcK8S_HostName", "DstK8S_Name", "DstK8S_Type", "DstK8S_OwnerName", "DstK8S_OwnerType", "DstK8S_Namespace", "DstAddr", "DstK8S_HostName"}
}

func manageGroupLabels(fields []string, groups string) []string {
if len(groups) > 0 {
if strings.Contains(groups, "clusters") {
if !utils.Contains(fields, "K8S_ClusterName") {
fields = append(fields, "K8S_ClusterName")
}
}

if strings.Contains(groups, "zones") {
if !utils.Contains(fields, "SrcK8S_Zone") {
fields = append(fields, "SrcK8S_Zone", "DstK8S_Zone")
}
}

if strings.Contains(groups, "hosts") {
if !utils.Contains(fields, "SrcK8S_HostName") {
fields = append(fields, "SrcK8S_HostName", "DstK8S_HostName")
Expand All @@ -117,7 +109,34 @@ func getLabels(aggregate, groups string) string {
}
}
}
return fields
}

func getLabels(aggregate, groups string) string {
var fields []string
switch aggregate {
case "app":
fields = []string{"app"}
case "droppedState":
fields = []string{"PktDropLatestState"}
case "droppedCause":
fields = []string{"PktDropLatestDropCause"}
case "dnsRCode":
fields = []string{"DnsFlagsResponseCode"}
case "cluster":
fields = []string{"K8S_ClusterName"}
case "zone":
fields = []string{"SrcK8S_Zone", "DstK8S_Zone"}
case "host":
fields = []string{"SrcK8S_HostName", "DstK8S_HostName"}
case "namespace":
fields = []string{"SrcK8S_Namespace", "DstK8S_Namespace"}
case "owner":
fields = []string{"SrcK8S_OwnerName", "SrcK8S_OwnerType", "DstK8S_OwnerName", "DstK8S_OwnerType", "SrcK8S_Namespace", "DstK8S_Namespace"}
default:
fields = []string{"SrcK8S_Name", "SrcK8S_Type", "SrcK8S_OwnerName", "SrcK8S_OwnerType", "SrcK8S_Namespace", "SrcAddr", "SrcK8S_HostName", "DstK8S_Name", "DstK8S_Type", "DstK8S_OwnerName", "DstK8S_OwnerType", "DstK8S_Namespace", "DstAddr", "DstK8S_HostName"}
}
fields = manageGroupLabels(fields, groups)
return strings.Join(fields[:], ",")
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/model/fields/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ const (
HostName = "K8S_HostName"
SrcHostName = Src + HostName
DstHostName = Dst + HostName
Zone = "K8S_Zone"
SrcZone = Src + Zone
DstZone = Src + Zone
Cluster = "K8S_ClusterName"
Packets = "Packets"
PktDropPackets = "PktDropPackets"
Proto = "Proto"
Expand Down
2 changes: 2 additions & 0 deletions pkg/server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ func setupRoutes(cfg *Config, authChecker auth.Checker) *mux.Router {
api.HandleFunc("/loki/flow/records", handler.GetFlows(&cfg.Loki))
api.HandleFunc("/loki/flow/metrics", handler.GetTopology(&cfg.Loki))
api.HandleFunc("/loki/export", handler.ExportFlows(&cfg.Loki))
api.HandleFunc("/resources/clusters", handler.GetClusters(&cfg.Loki))
api.HandleFunc("/resources/zones", handler.GetZones(&cfg.Loki))
api.HandleFunc("/resources/namespaces", handler.GetNamespaces(&cfg.Loki))
api.HandleFunc("/resources/namespace/{namespace}/kind/{kind}/names", handler.GetNames(&cfg.Loki))
api.HandleFunc("/resources/kind/{kind}/names", handler.GetNames(&cfg.Loki))
Expand Down
17 changes: 15 additions & 2 deletions web/locales/en/plugin__netobserv-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,20 @@
"n/a": "n/a",
"View alert details": "View alert details",
"View health dashboard": "View health dashboard",
"Namespaces + Owners": "Namespaces + Owners",
"Clusters": "Clusters",
"Clusters + Nodes": "Clusters + Nodes",
"Clusters + Zones": "Clusters + Zones",
"Clusters + Namespaces": "Clusters + Namespaces",
"Clusters + Owners": "Clusters + Owners",
"Zones": "Zones",
"Zones + Nodes": "Zones + Nodes",
"Zones + Namespaces": "Zones + Namespaces",
"Zones + Owners": "Zones + Owners",
"Nodes": "Nodes",
"Nodes + Namespaces": "Nodes + Namespaces",
"Nodes + Owners": "Nodes + Owners",
"Nodes": "Nodes",
"Namespaces": "Namespaces",
"Namespaces + Owners": "Namespaces + Owners",
"Owners": "Owners",
"None": "None",
"3D": "3D",
Expand Down Expand Up @@ -82,6 +91,8 @@
"1 hour": "1 hour",
"2 hours": "2 hours",
"1 day": "1 day",
"Cluster": "Cluster",
"Zone": "Zone",
"Node": "Node",
"Namespace": "Namespace",
"Owner": "Owner",
Expand Down Expand Up @@ -269,6 +280,7 @@
"Unable to get flows": "Unable to get flows",
"Step into this {{name}}": "Step into this {{name}}",
"Filter by source or destination {{name}}": "Filter by source or destination {{name}}",
"Filter by {{name}}": "Filter by {{name}}",
"Unpin this element": "Unpin this element",
"Pin this element": "Pin this element",
"Name": "Name",
Expand All @@ -287,6 +299,7 @@
"Average rate": "Average rate",
"Latest time": "Latest time",
"Latest rate": "Latest rate",
"Cluster name": "Cluster name",
"Edge": "Edge",
"Drops": "Drops",
"Unable to get topology": "Unable to get topology",
Expand Down
6 changes: 6 additions & 0 deletions web/src/api/ipfix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ export interface Fields {
SrcK8S_HostName?: string;
/** Destination node name */
DstK8S_HostName?: string;
/** Source zone */
SrcK8S_Zone?: string;
/** Destination zone */
DstK8S_Zone?: string;
/** Cluster name */
K8S_ClusterName?: string;
/** L4 protocol */
Proto: number;
/** Flow direction of the first flow captured, only when using eBPF deduper 'merge' mode */
Expand Down
5 changes: 5 additions & 0 deletions web/src/api/loki.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,17 @@ export interface RawTopologyMetric {
DstK8S_OwnerName?: string;
DstK8S_OwnerType?: string;
DstK8S_Type?: string;
DstK8S_Zone?: string;
DstK8S_HostName?: string;
SrcAddr?: string;
SrcK8S_Name?: string;
SrcK8S_Namespace?: string;
SrcK8S_OwnerName?: string;
SrcK8S_OwnerType?: string;
SrcK8S_Type?: string;
SrcK8S_Zone?: string;
SrcK8S_HostName?: string;
K8S_ClusterName?: string;
PktDropLatestState?: string;
PktDropLatestDropCause?: string;
DnsFlagsResponseCode?: string;
Expand All @@ -85,6 +88,8 @@ export interface TopologyMetricPeer {
owner?: NameAndType;
resource?: NameAndType;
hostName?: string;
zone?: string;
clusterName?: string;
resourceKind?: string;
isAmbiguous: boolean;
getDisplayName: (inclNamespace: boolean, disambiguate: boolean) => string | undefined;
Expand Down
18 changes: 18 additions & 0 deletions web/src/api/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,24 @@ export const getExportFlowsURL = (params: FlowQuery, columns?: string[]): string
return `${ContextSingleton.getHost()}/api/loki/export?${exportQuery}`;
};

export const getClusters = (): Promise<string[]> => {
return axios.get(ContextSingleton.getHost() + '/api/resources/clusters').then(r => {
if (r.status >= 400) {
throw new Error(`${r.statusText} [code=${r.status}]`);
}
return r.data;
});
};

export const getZones = (): Promise<string[]> => {
return axios.get(ContextSingleton.getHost() + '/api/resources/zones').then(r => {
if (r.status >= 400) {
throw new Error(`${r.statusText} [code=${r.status}]`);
}
return r.data;
});
};

export const getNamespaces = (): Promise<string[]> => {
return axios.get(ContextSingleton.getHost() + '/api/resources/namespaces').then(r => {
if (r.status >= 400) {
Expand Down
Loading

0 comments on commit 9aacffa

Please sign in to comment.