Skip to content

Commit

Permalink
dev
Browse files Browse the repository at this point in the history
  • Loading branch information
jpinsonneau committed Nov 26, 2024
1 parent 765ca7c commit 1f56e27
Show file tree
Hide file tree
Showing 17 changed files with 429 additions and 150 deletions.
313 changes: 213 additions & 100 deletions config/sample-config.yaml

Large diffs are not rendered by default.

29 changes: 29 additions & 0 deletions pkg/handler/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,35 @@ func (h *Handlers) GetClusters(ctx context.Context) func(w http.ResponseWriter,
}
}

func (h *Handlers) GetUDNs(ctx context.Context) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
namespace := params.Get(namespaceKey)
isDev := namespace != ""

clients, err := newClients(h.Cfg, r.Header, false, namespace)
if err != nil {
writeError(w, http.StatusInternalServerError, err.Error())
return
}
var code int
startTime := time.Now()
defer func() {
metrics.ObserveHTTPCall("GetUDNs", code, startTime)
}()

// Fetch and merge values for K8S_ClusterName
values, code, err := h.getLabelValues(ctx, clients, fields.UDN, isDev)
if err != nil {
writeError(w, code, err.Error())
return
}

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

func (h *Handlers) GetZones(ctx context.Context) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
params := r.URL.Query()
Expand Down
1 change: 1 addition & 0 deletions pkg/model/fields/fields.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
SrcZone = Src + Zone
DstZone = Dst + Zone
Cluster = "K8S_ClusterName"
UDN = "UDN"
Layer = "K8S_FlowLayer"
Packets = "Packets"
Proto = "Proto"
Expand Down
1 change: 1 addition & 0 deletions pkg/server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func setupRoutes(ctx context.Context, cfg *config.Config, authChecker auth.Check
// Common endpoints
api.HandleFunc("/flow/metrics", h.GetTopology(ctx))
api.HandleFunc("/resources/clusters", h.GetClusters(ctx))
api.HandleFunc("/resources/udns", h.GetUDNs(ctx))
api.HandleFunc("/resources/zones", h.GetZones(ctx))
api.HandleFunc("/resources/namespaces", h.GetNamespaces(ctx))
api.HandleFunc("/resources/names", h.GetNames(ctx))
Expand Down
3 changes: 3 additions & 0 deletions scripts/update-config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ yq eval-all --inplace 'select(fileIndex==0).frontend.columns = select(fileIndex=
echo " - filters..."
yq eval-all --inplace 'select(fileIndex==0).frontend.filters = select(fileIndex==1).filters | select(fileIndex==0)' ./config/sample-config.yaml ./tmp/config.yaml

echo " - scopes..."
yq eval-all --inplace 'select(fileIndex==0).frontend.scopes = select(fileIndex==1).scopes | select(fileIndex==0)' ./config/sample-config.yaml ./tmp/config.yaml

echo " - fields..."
yq eval-all --inplace 'select(fileIndex==0).frontend.fields = select(fileIndex==1).fields | select(fileIndex==0)' ./config/sample-config.yaml ./tmp/config.yaml

Expand Down
34 changes: 34 additions & 0 deletions web/console-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,40 @@
}
}
},
{
"type": "console.tab/horizontalNav",
"properties": {
"model": {
"version": "v1",
"group": "k8s.ovn.org",
"kind": "ClusterUserDefinedNetwork"
},
"component": {
"$codeRef": "netflowTab.default"
},
"page": {
"name": "%plugin__netobserv-plugin~Network Traffic%",
"href": "netflow"
}
}
},
{
"type": "console.tab/horizontalNav",
"properties": {
"model": {
"version": "v1",
"group": "k8s.ovn.org",
"kind": "UserDefinedNetwork"
},
"component": {
"$codeRef": "netflowTab.default"
},
"page": {
"name": "%plugin__netobserv-plugin~Network Traffic%",
"href": "netflow"
}
}
},
{
"type": "console.tab",
"properties": {
Expand Down
1 change: 1 addition & 0 deletions web/locales/en/plugin__netobserv-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"IP": "IP",
"No information available for this content. Change scope to get more details.": "No information available for this content. Change scope to get more details.",
"Cluster name": "Cluster name",
"UDN": "UDN",
"Source": "Source",
"Destination": "Destination",
"Stats": "Stats",
Expand Down
2 changes: 2 additions & 0 deletions web/src/api/ipfix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ export interface Fields {
_IsFirst?: string;
/** In conversation tracking, a counter of flow logs per conversation */
numFlowLogs?: number;
/** User Defined Network identifier */
UdnId?: string;
}

export type Field = keyof Fields | keyof Labels;
1 change: 1 addition & 0 deletions web/src/api/loki.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export interface TopologyMetricPeer {
namespace?: string;
host?: string;
cluster?: string;
udn?: string;
}

export type GenericMetric = {
Expand Down
10 changes: 10 additions & 0 deletions web/src/api/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,16 @@ export const getClusters = (forcedNamespace?: string): Promise<string[]> => {
});
};

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

export const getZones = (forcedNamespace?: string): Promise<string[]> => {
const params = { namespace: forcedNamespace };
return axios.get(ContextSingleton.getHost() + '/api/resources/zones', { params }).then(r => {
Expand Down
8 changes: 8 additions & 0 deletions web/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ export const pages = [
{
id: 'dev-tab',
name: 'Dev tab'
},
{
id: 'udn-tab',
name: 'UDN tab'
}
];

Expand Down Expand Up @@ -94,6 +98,10 @@ export class App extends React.Component<{}, AppState> {
}}
/>
);
case 'udn-tab':
return (
<NetflowTrafficTab obj={{ kind: 'UserDefinedNetwork', metadata: { name: 'my-udn', namespace: 'default' } }} />
);
default:
return <NetflowTrafficParent />;
}
Expand Down
136 changes: 87 additions & 49 deletions web/src/components/drawer/element/element-panel-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,39 @@ export const ElementPanelContent: React.FC<ElementPanelContentProps> = ({
[filterDefinitions, filters, setFilters, t]
);

const udnName = React.useCallback(
(d: NodeData) => {
if (!d.peer.udn) {
return <></>;
}
const fields = createPeer({ udn: d.peer.udn });
const isFiltered = isElementFiltered(fields, filters, filterDefinitions);
return (
<TextContent id="udn" className="record-field-container">
<Text component={TextVariants.h4}>{t('UDN')}</Text>
<Flex>
<FlexItem flex={{ default: 'flex_1' }}>{d.peer.udn}</FlexItem>
<FlexItem>
<Button
id={'udn-filter'}
variant="plain"
className="overflow-button"
icon={isFiltered ? <TimesIcon /> : <FilterIcon />}
onClick={() => toggleElementFilter(fields, isFiltered, filters, setFilters, filterDefinitions)}
/>
</FlexItem>
</Flex>
</TextContent>
);
},
[filterDefinitions, filters, setFilters, t]
);

if (element instanceof BaseNode && data) {
return (
<>
{clusterName(data)}
{udnName(data)}
<ElementFields
id="node-info"
data={data}
Expand All @@ -93,60 +122,69 @@ export const ElementPanelContent: React.FC<ElementPanelContentProps> = ({
// Edge A to B (prefering neutral naming here as there is no assumption about what is source, what is destination
const aData: NodeData = element.getSource().getData();
const bData: NodeData = element.getTarget().getData();
const combinedData = Object.assign({}, aData, bData);
return (
<Accordion asDefinitionList={false}>
<div className="record-group-container" key={'source'} data-test-id={'source'}>
<AccordionItem data-test-id={'source'}>
{
<AccordionToggle
<>
{clusterName(combinedData)}
{udnName(combinedData)}
<Accordion asDefinitionList={false}>
<div className="record-group-container" key={'source'} data-test-id={'source'}>
<AccordionItem data-test-id={'source'}>
{
<AccordionToggle
className="borderless-accordion"
onClick={() => toggle('source')}
isExpanded={!hidden.includes('source')}
id={'source'}
>
{t('Source')}
</AccordionToggle>
}
<AccordionContent
className="borderless-accordion"
onClick={() => toggle('source')}
isExpanded={!hidden.includes('source')}
id={'source'}
id="source-content"
isHidden={hidden.includes('source')}
>
{t('Source')}
</AccordionToggle>
}
<AccordionContent className="borderless-accordion" id="source-content" isHidden={hidden.includes('source')}>
<ElementFields
id="source-info"
data={aData}
activeFilters={filters}
setFilters={setFilters}
filterDefinitions={filterDefinitions}
/>
</AccordionContent>
</AccordionItem>
</div>
<div className="record-group-container" key={'destination'} data-test-id={'destination'}>
<Divider />
<AccordionItem data-test-id={'destination'}>
{
<AccordionToggle
<ElementFields
id="source-info"
data={aData}
activeFilters={filters}
setFilters={setFilters}
filterDefinitions={filterDefinitions}
/>
</AccordionContent>
</AccordionItem>
</div>
<div className="record-group-container" key={'destination'} data-test-id={'destination'}>
<Divider />
<AccordionItem data-test-id={'destination'}>
{
<AccordionToggle
className="borderless-accordion"
onClick={() => toggle('destination')}
isExpanded={!hidden.includes('destination')}
id={'destination'}
>
{t('Destination')}
</AccordionToggle>
}
<AccordionContent
className="borderless-accordion"
onClick={() => toggle('destination')}
isExpanded={!hidden.includes('destination')}
id={'destination'}
id="destination-content"
isHidden={hidden.includes('destination')}
>
{t('Destination')}
</AccordionToggle>
}
<AccordionContent
className="borderless-accordion"
id="destination-content"
isHidden={hidden.includes('destination')}
>
<ElementFields
id="destination-info"
data={bData}
activeFilters={filters}
setFilters={setFilters}
filterDefinitions={filterDefinitions}
/>
</AccordionContent>
</AccordionItem>
</div>
</Accordion>
<ElementFields
id="destination-info"
data={bData}
activeFilters={filters}
setFilters={setFilters}
filterDefinitions={filterDefinitions}
/>
</AccordionContent>
</AccordionItem>
</div>
</Accordion>
</>
);
}
return <></>;
Expand Down
14 changes: 14 additions & 0 deletions web/src/components/drawer/record/record-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,20 @@ export const RecordField: React.FC<RecordFieldProps> = ({
: emptyText()
);
}
case ColumnsId.udn: {
const id = value as string;
let child: JSX.Element | undefined;
// TODO: define how to split the UDN ID
// an alternative could be to use `calculated: kubeObject(K8S_UDN_Type,K8S_UDN_Namespace,K8S_UDN_Name,0)`
// from config within 3 separated fields
if (id.includes('.')) {
const parts = id.split('.');
child = kubeObjContent(parts[1], 'UserDefinedNetwork', parts[0]);
} else {
child = kubeObjContent(id, 'ClusterUserDefinedNetwork', undefined);
}
return singleContainer(child);
}
default:
if (value === undefined) {
return emptyText();
Expand Down
9 changes: 9 additions & 0 deletions web/src/utils/autocomplete-cache.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class AutoCompleteCache {
private clusters: string[] | undefined = undefined;
private udns: string[] | undefined = undefined;
private zones: string[] | undefined = undefined;
private namespaces: string[] | undefined = undefined;
// Kinds are hard-coded for now.
Expand All @@ -16,6 +17,14 @@ class AutoCompleteCache {
this.clusters = cs;
}

getUDNs() {
return this.udns;
}

setUDNs(nets: string[]) {
this.udns = nets;
}

getZones() {
return this.zones;
}
Expand Down
1 change: 1 addition & 0 deletions web/src/utils/columns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export enum ColumnsId {
endtime = 'EndTime',
type = 'K8S_Type',
clustername = 'ClusterName',
udn = 'UDN',
srczone = 'SrcZone',
dstzone = 'DstZone',
srctype = 'SrcK8S_Type',
Expand Down
3 changes: 3 additions & 0 deletions web/src/utils/filter-definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
getProtocolOptions,
getResourceOptions,
getTCPFlagsOptions,
getUDNOptions,
getZoneOptions,
noOption
} from './filter-options';
Expand Down Expand Up @@ -263,6 +264,8 @@ export const getFilterDefinitions = (
validate = k8sNameValidation;
} else if (d.id.includes('cluster')) {
getOptions = getClusterOptions;
} else if (d.id.includes('udn')) {
getOptions = getUDNOptions;
} else if (d.id.includes('zone')) {
getOptions = getZoneOptions;
} else if (d.id.includes('name')) {
Expand Down
Loading

0 comments on commit 1f56e27

Please sign in to comment.