Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"@kobsio/plugin-applications": "*",
"@kobsio/plugin-core": "*",
"@kobsio/plugin-dashboards": "*",
"@kobsio/plugin-prometheus": "*",
"@kobsio/plugin-resources": "*",
"@kobsio/plugin-teams": "*",
"@types/node": "^15.14.0",
Expand Down
2 changes: 2 additions & 0 deletions app/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import resourcesPlugin from '@kobsio/plugin-resources';
import teamsPlugin from '@kobsio/plugin-teams';
import applicationsPlugin from '@kobsio/plugin-applications';
import dashboardsPlugin from '@kobsio/plugin-dashboards';
import prometheusPlugin from '@kobsio/plugin-prometheus';

ReactDOM.render(
<React.StrictMode>
Expand All @@ -16,6 +17,7 @@ ReactDOM.render(
...teamsPlugin,
...applicationsPlugin,
...dashboardsPlugin,
...prometheusPlugin,
}} />
</React.StrictMode>,
document.getElementById('root')
Expand Down
15 changes: 8 additions & 7 deletions deploy/docker/kobs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ plugins:
topologyCacheDuration: 1m
teamsCacheDuration: 1m

prometheus:
- name: Prometheus
description: Prometheus can be used for the metrics of your application.
address: http://localhost:9090
username:
password:
token:
prometheus:
- name: prometheus
displayName: Prometheus
description: Prometheus can be used for the metrics of your application.
address: http://localhost:9090
username:
password:
token:

elasticsearch:
- name: Elasticsearch
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/go-chi/cors v1.2.0
github.com/go-chi/render v1.0.1
github.com/prometheus/client_golang v1.11.0
github.com/prometheus/common v0.26.0
github.com/sirupsen/logrus v1.8.1
github.com/spf13/pflag v1.0.5
gopkg.in/yaml.v2 v2.4.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
Expand Down Expand Up @@ -273,6 +274,7 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
Expand Down
42 changes: 42 additions & 0 deletions pkg/api/middleware/roundtripper/roundtripper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package roundtripper

import (
"net"
"net/http"
"time"
)

// DefaultRoundTripper is our default RoundTripper.
var DefaultRoundTripper http.RoundTripper = &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
TLSHandshakeTimeout: 10 * time.Second,
}

// BasicAuthTransport is the struct to add basic auth to a RoundTripper.
type BasicAuthTransport struct {
Transport http.RoundTripper
Username string
Password string
}

// RoundTrip implements the RoundTrip for our RoundTripper with basic auth support.
func (bat BasicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req.SetBasicAuth(bat.Username, bat.Password)
return bat.Transport.RoundTrip(req)
}

// TokenAuthTransporter is the struct to add token auth to a RoundTripper.
type TokenAuthTransporter struct {
Transport http.RoundTripper
Token string
}

// RoundTrip implements the RoundTrip for our RoundTripper with token auth support.
func (tat TokenAuthTransporter) RoundTrip(req *http.Request) (*http.Response, error) {
req.Header.Set("Authorization", "Bearer "+tat.Token)
return tat.Transport.RoundTrip(req)
}
3 changes: 3 additions & 0 deletions pkg/api/plugins/plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
// the plugins folder.
"github.com/kobsio/kobs/plugins/applications"
"github.com/kobsio/kobs/plugins/dashboards"
"github.com/kobsio/kobs/plugins/prometheus"
"github.com/kobsio/kobs/plugins/resources"
"github.com/kobsio/kobs/plugins/teams"
)
Expand All @@ -23,6 +24,7 @@ type Config struct {
Resources resources.Config `yaml:"resources"`
Teams teams.Config `yaml:"teams"`
Dashboards dashboards.Config `yaml:"dashboards"`
Prometheus prometheus.Config `yaml:"prometheus"`
}

// Router implements the router for the plugins package. This only registeres one route which is used to return all the
Expand Down Expand Up @@ -51,6 +53,7 @@ func Register(clusters *clusters.Clusters, config Config) chi.Router {
router.Mount(resources.Route, resources.Register(clusters, router.plugins, config.Resources))
router.Mount(teams.Route, teams.Register(clusters, router.plugins, config.Teams))
router.Mount(dashboards.Route, dashboards.Register(clusters, router.plugins, config.Dashboards))
router.Mount(prometheus.Route, prometheus.Register(clusters, router.plugins, config.Prometheus))

return router
}
4 changes: 2 additions & 2 deletions plugins/applications/src/components/page/Application.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import React from 'react';
import { UsersIcon } from '@patternfly/react-icons';

import { ExternalLink, Title } from '@kobsio/plugin-core';
import { Dashboards } from '@kobsio/plugin-dashboards';
import { DashboardsWrapper } from '@kobsio/plugin-dashboards';
import { IApplication } from '../../utils/interfaces';

interface IApplicationsParams {
Expand Down Expand Up @@ -128,7 +128,7 @@ const Application: React.FunctionComponent = () => {
</PageSection>

{data.dashboards ? (
<Dashboards defaults={data} references={data.dashboards} useDrawer={true} />
<DashboardsWrapper defaults={data} references={data.dashboards} useDrawer={true} />
) : (
<PageSection variant={PageSectionVariants.default}></PageSection>
)}
Expand Down
4 changes: 2 additions & 2 deletions plugins/applications/src/components/panel/details/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import React from 'react';
import { UsersIcon } from '@patternfly/react-icons';

import { ExternalLink, Title } from '@kobsio/plugin-core';
import { Dashboards } from '@kobsio/plugin-dashboards';
import { DashboardsWrapper } from '@kobsio/plugin-dashboards';
import DetailsLink from './DetailsLink';
import { IApplication } from '../../../utils/interfaces';

Expand Down Expand Up @@ -73,7 +73,7 @@ const Details: React.FunctionComponent<IDetailsProps> = ({ application, close }:
</div>

{application.dashboards ? (
<Dashboards defaults={application} references={application.dashboards} useDrawer={false} />
<DashboardsWrapper defaults={application} references={application.dashboards} useDrawer={false} />
) : null}

<p>&nbsp;</p>
Expand Down
31 changes: 30 additions & 1 deletion plugins/core/src/components/misc/Options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,26 @@ export type TTime =
| 'last7Days'
| 'last90Days';

// TTimeOptions is an array with all available type for TTime. It is used to verify that the value of a string is an
//valid option for the TTime type.
export const TTimeOptions = [
'custom',
'last12Hours',
'last15Minutes',
'last1Day',
'last1Hour',
'last1Year',
'last2Days',
'last30Days',
'last30Minutes',
'last3Hours',
'last5Minutes',
'last6Hours',
'last6Months',
'last7Days',
'last90Days',
];

// ITime is the interface for a time in the times map. It contains a label which should be displayed in the Options
// component and the seconds between the start and the end time.
interface ITime {
Expand Down Expand Up @@ -88,6 +108,7 @@ interface IOptionsProps {
timeEnd: number;
timeStart: number;
setOptions: (
refresh: boolean,
additionalFields: IOptionsAdditionalFields[] | undefined,
time: TTime,
timeEnd: number,
Expand Down Expand Up @@ -142,6 +163,7 @@ export const Options: React.FunctionComponent<IOptionsProps> = ({
setCustomTimeStartError('');
setCustomTimeEndError('');
setOptions(
false,
additionalFields,
'custom',
Math.floor(parsedTimeEnd.getTime() / 1000),
Expand All @@ -154,7 +176,13 @@ export const Options: React.FunctionComponent<IOptionsProps> = ({
// quick is the function for the quick select option. We always use the current time in seconds and substract the
// seconds specified in the quick select option.
const quick = (t: TTime): void => {
setOptions(additionalFields, t, Math.floor(Date.now() / 1000), Math.floor(Date.now() / 1000) - times[t].seconds);
setOptions(
false,
additionalFields,
t,
Math.floor(Date.now() / 1000),
Math.floor(Date.now() / 1000) - times[t].seconds,
);
setShow(false);
};

Expand All @@ -172,6 +200,7 @@ export const Options: React.FunctionComponent<IOptionsProps> = ({
const refreshTimes = (): void => {
if (time !== 'custom') {
setOptions(
true,
additionalFields,
time,
Math.floor(Date.now() / 1000),
Expand Down
2 changes: 1 addition & 1 deletion plugins/core/src/components/plugin/PluginCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ interface IPluginCardProps {
title: string;
description?: string;
transparent?: boolean;
children: React.ReactElement;
children: React.ReactElement | null;
actions?: React.ReactElement;
}

Expand Down
2 changes: 2 additions & 0 deletions plugins/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,7 @@ export * from './context/PluginsContext';
export * from './utils/manifests';
export * from './utils/resources';
export * from './utils/time';
export * from './utils/useDebounce';
export * from './utils/useDimensions';
export * from './utils/useWindowHeight';
export * from './utils/useWindowWidth';
17 changes: 17 additions & 0 deletions plugins/core/src/utils/useDebounce.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useEffect, useState } from 'react';

export const useDebounce = <T extends unknown>(value: T, delay: number): T => {
const [debouncedValue, setDebouncedValue] = useState<T>(value);

useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);

return (): void => {
clearTimeout(handler);
};
}, [value, delay]);

return debouncedValue;
};
34 changes: 34 additions & 0 deletions plugins/core/src/utils/useDimensions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useEffect, useLayoutEffect, useState } from 'react';

export interface IDimensions {
height: number;
width: number;
}

export const useDimensions = (targetRef: React.RefObject<HTMLDivElement>): IDimensions => {
const getDimensions = (): IDimensions => {
return {
height: targetRef.current ? targetRef.current.offsetHeight : 0,
width: targetRef.current ? targetRef.current.offsetWidth : 0,
};
};

const [dimensions, setDimensions] = useState(getDimensions);

const handleResize = (): void => {
setDimensions(getDimensions());
};

useEffect(() => {
window.addEventListener('resize', handleResize);
return (): void => window.removeEventListener('resize', handleResize);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useLayoutEffect(() => {
handleResize();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return dimensions;
};
43 changes: 42 additions & 1 deletion plugins/dashboards/src/components/dashboards/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,12 @@ const Dashboard: React.FunctionComponent<IDashboardProps> = ({
// that all child components should used the retunred data array instead of the formerly defined variables state,
// because it contains the current values and selected value for a variable. The variables state is mainly there to
// trigger this function everytime a new variable value is selected.
// Currently we support "core" variable, which can be used to select a cluster or plugin and we are supporting the
// Prometheus plugin. For the Prometheus plugin the user must specify the name of the Prometheus instance via the name
// parameter in the options. When the user changes the variables, we keep the old variable values, so that we not have
// to rerender all the panels in the dashboard.
const { isError, error, data, refetch } = useQuery<IVariableValues[], Error>(
['dashboard/variables', variables],
['dashboard/variables', variables, times],
async () => {
if (!variables) {
return [];
Expand All @@ -86,6 +90,41 @@ const Dashboard: React.FunctionComponent<IDashboardProps> = ({
}
}
}
} else {
const pluginDetails = pluginsContext.getPluginDetails(tmpVariables[i].plugin.name);

if (pluginDetails?.type === 'prometheus') {
const response = await fetch(`/api/plugins/prometheus/variable/${tmpVariables[i].plugin.name}`, {
body: JSON.stringify({
label: tmpVariables[i].plugin.options.label,
query: interpolate(tmpVariables[i].plugin.options.query, tmpVariables),
timeEnd: times.timeEnd,
timeStart: times.timeStart,
type: tmpVariables[i].plugin.options.type,
}),
method: 'post',
});
const json = await response.json();

if (response.status >= 200 && response.status < 300) {
if (json && Array.isArray(json) && json.length > 0) {
if (tmpVariables[i].plugin.options.allowAll) {
json.unshift(json.join('|'));
}

tmpVariables[i].values = json;
tmpVariables[i].value = json.includes(tmpVariables[i].value) ? tmpVariables[i].value : json[0];
} else {
throw new Error(`No values for variable ${tmpVariables[i].label || tmpVariables[i].name}`);
}
} else {
if (json.error) {
throw new Error(json.error);
} else {
throw new Error('An unknown error occured');
}
}
}
}
}

Expand All @@ -94,6 +133,7 @@ const Dashboard: React.FunctionComponent<IDashboardProps> = ({
throw err;
}
},
{ keepPreviousData: true },
);

// We do not use the dashboard.rows array directly to render the dashboard. Instead we are replacing all the variables
Expand Down Expand Up @@ -126,6 +166,7 @@ const Dashboard: React.FunctionComponent<IDashboardProps> = ({
</div>
);
}

return (
<React.Fragment>
<DashboardToolbar variables={data} setVariables={setVariables} times={times} setTimes={setTimes} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const DashboardToolbar: React.FunctionComponent<IDashboardToolbarProps> = ({
timeEnd={times.timeEnd}
timeStart={times.timeStart}
setOptions={(
refresh: boolean,
additionalFields: IOptionsAdditionalFields[] | undefined,
time: TTime,
timeEnd: number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const DashboardToolbarVariable: React.FunctionComponent<IDashboardToolbarVariabl
onSelect={onSelect}
selections={variable.value}
isOpen={show}
width={250}
>
{group}
</Select>
Expand Down
Loading