Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
David Kempe
Meerkat
Commits
770eb1ca
Commit
770eb1ca
authored
Nov 30, 2020
by
MaxSol1
Browse files
wip:perf data mode
parent
50e8f983
Changes
6
Hide whitespace changes
Inline
Side-by-side
backend/dashboard.go
View file @
770eb1ca
...
...
@@ -81,6 +81,8 @@ type Option struct {
UnknownSound
string
`json:"unknownSound"`
CriticalSound
string
`json:"criticalSound"`
MuteAlerts
bool
`json:"muteAlerts"`
PerfDataMode
bool
`json:"perfDataMode"`
PerfDataSelection
string
`json:"perfDataSelection"`
}
//Rect helper struct for positions
...
...
backend/icinga.go
View file @
770eb1ca
...
...
@@ -59,6 +59,132 @@ type icingaObject struct {
Groups
[]
string
`json:"groups"`
}
type
icingaAPILastCheckResults
struct
{
CheckResults
[]
results
`json:"results"`
}
type
results
struct
{
Attributes
icingaCheckAttributes
`json:"attrs"`
Joins
joins
`json:"joins,omitempty"`
Meta
types
`json:"meta,omitempty"`
Name
string
`json:"name"`
Type
string
`json:"type"`
}
type
joins
struct
{
}
type
types
struct
{
}
type
icingaCheckAttributes
struct
{
Attributes
checkResult
`json:"last_check_result"`
}
type
checkResult
struct
{
Active
bool
`json:"active"`
CheckSource
string
`json:"check_source"`
Command
[]
string
`json:"command"`
ExecutionEnd
float64
`json:"execution_end"`
ExecutionStart
float64
`json:"execution_start"`
ExitStatus
float64
`json:"exit_status"`
Output
string
`json:"output"`
PerformanceData
[]
string
`json:"performance_data"`
ScheduleEnd
float64
`json:"schedule_end"`
ScheduleStart
float64
`json:"schedule_start"`
State
float64
`json:"state"`
TTL
float64
`json:"ttl"`
Type
string
`json:"type"`
VarsAfter
varsAfter
`json:"vars_after"`
VarsBefore
varsBefore
`json:"vars_before"`
}
type
varsAfter
struct
{
Attempt
float64
`json:"attempt"`
Reachable
bool
`json:"reachable"`
State
float64
`json:"state"`
StateType
float64
`json:"state_type"`
}
type
varsBefore
struct
{
Attempt
float64
`json:"attempt"`
Reachable
bool
`json:"reachable"`
State
float64
`json:"state"`
StateType
float64
`json:"state_type"`
}
func
handleCheckResult
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
service
:=
r
.
URL
.
Query
()
.
Get
(
"service"
)
attrs
:=
r
.
URL
.
Query
()
.
Get
(
"attrs"
)
fmt
.
Println
(
service
)
if
service
==
""
{
http
.
Error
(
w
,
"No unique queue name specified"
,
http
.
StatusBadRequest
)
return
}
client
:=
&
http
.
Client
{}
//Disable TLS verification if config says so
if
config
.
IcingaInsecureTLS
{
client
.
Transport
=
&
http
.
Transport
{
TLSClientConfig
:
&
tls
.
Config
{
InsecureSkipVerify
:
true
},
}
}
//Create HTTP request
req_url
,
err
:=
url
.
Parse
(
config
.
IcingaURL
)
if
err
!=
nil
{
log
.
Printf
(
"Failed to parse IcingaURL: %w"
,
err
)
http
.
Error
(
w
,
"Server Error"
,
http
.
StatusInternalServerError
)
return
}
req_url
.
Path
=
path
.
Join
(
req_url
.
Path
,
"/v1/objects/services"
,
service
)
req_url
.
RawQuery
=
strings
.
ReplaceAll
(
url
.
Values
{
"attrs"
:
[]
string
{
attrs
}}
.
Encode
(),
"+"
,
"%20"
)
req
,
err
:=
http
.
NewRequest
(
"GET"
,
req_url
.
String
(),
nil
)
req
.
Header
.
Set
(
"Accept"
,
"application/json"
)
req
.
SetBasicAuth
(
config
.
IcingaUsername
,
config
.
IcingaPassword
)
fmt
.
Println
(
req
)
if
err
!=
nil
{
fmt
.
Println
(
"Failed to create HTTP request: %w"
,
err
)
http
.
Error
(
w
,
"Error creating http request: "
+
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
//Make request
res
,
err
:=
client
.
Do
(
req
)
if
err
!=
nil
{
fmt
.
Println
(
"Icinga2 API error: %w"
,
err
.
Error
())
http
.
Error
(
w
,
"Icinga2 API error: "
+
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
fmt
.
Println
(
res
)
fmt
.
Println
(
"Response status:"
,
res
.
Status
)
fmt
.
Println
(
res
.
Body
)
defer
res
.
Body
.
Close
()
var
checkResults
icingaAPILastCheckResults
dec
:=
json
.
NewDecoder
(
res
.
Body
)
err
=
dec
.
Decode
(
&
checkResults
)
if
err
!=
nil
{
log
.
Printf
(
"Error decoding Icinga2 API response: %w"
,
err
)
http
.
Error
(
w
,
"Error decoding Icinga2 API response: "
+
err
.
Error
(),
http
.
StatusInternalServerError
)
return
}
enc
:=
json
.
NewEncoder
(
w
)
enc
.
Encode
(
checkResults
)
}
func
handleIcingaCheckState
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
object_type
:=
r
.
URL
.
Query
()
.
Get
(
"object_type"
)
filter
:=
r
.
URL
.
Query
()
.
Get
(
"filter"
)
...
...
@@ -95,7 +221,7 @@ func handleIcingaCheckState(w http.ResponseWriter, r *http.Request) {
return
}
req_url
.
Path
=
path
.
Join
(
req_url
.
Path
,
"/v1/objects"
,
object_type
+
"s"
)
req_url
.
Path
=
path
.
Join
(
req_url
.
Path
,
"/v1/objects"
,
object_type
+
"s"
)
req_url
.
RawQuery
=
strings
.
ReplaceAll
(
url
.
Values
{
"filter"
:
[]
string
{
filter
}}
.
Encode
(),
"+"
,
"%20"
)
req
,
err
:=
http
.
NewRequest
(
"GET"
,
req_url
.
String
(),
nil
)
...
...
@@ -105,6 +231,8 @@ func handleIcingaCheckState(w http.ResponseWriter, r *http.Request) {
return
}
fmt
.
Println
(
req
)
req
.
SetBasicAuth
(
config
.
IcingaUsername
,
config
.
IcingaPassword
)
//Make request
...
...
@@ -119,6 +247,7 @@ func handleIcingaCheckState(w http.ResponseWriter, r *http.Request) {
var
results
icingaAPIResults
dec
:=
json
.
NewDecoder
(
res
.
Body
)
err
=
dec
.
Decode
(
&
results
)
if
err
!=
nil
{
log
.
Printf
(
"Error decoding Icinga2 API response: %w"
,
err
)
http
.
Error
(
w
,
"Error decoding Icinga2 API response: "
+
err
.
Error
(),
http
.
StatusInternalServerError
)
...
...
backend/main.go
View file @
770eb1ca
...
...
@@ -93,6 +93,7 @@ func main() {
r
.
Get
(
"/icinga/{check-type}/{object-id}"
,
handleIcingaCheck
)
r
.
Get
(
"/icinga/check_state"
,
handleIcingaCheckState
)
r
.
Get
(
"/icinga/check_result"
,
handleCheckResult
)
r
.
Post
(
"/upload"
,
handleUpload
)
r
.
Handle
(
"/dashboards-data/*"
,
http
.
StripPrefix
(
"/dashboards-data/"
,
http
.
FileServer
(
http
.
Dir
(
"./dashboards-data"
))))
...
...
frontend/src/elements/card.jsx
View file @
770eb1ca
...
...
@@ -6,6 +6,8 @@ import { icingaResultCodeToCheckState, icingaCheckTypeFromId, IcingaCheckList }
//The rendered view (in the actual dashboard) of the Card Element
export
function
CheckCard
({
options
,
slug
,
dashboard
})
{
const
[
checkState
,
setCheckState
]
=
useState
(
false
);
const
[
perfData
,
setPerfData
]
=
useState
(
null
);
const
[
perfValue
,
setPerfValue
]
=
useState
(
null
);
let
ok
=
false
;
let
warning
=
false
;
...
...
@@ -81,9 +83,33 @@ export function CheckCard({options, slug, dashboard}) {
});
}
const
perfDataSelected
=
async
(
perfData
)
=>
{
let
waitPerf
=
await
perfData
;
for
(
const
[
key
,
value
]
of
Object
.
entries
(
waitPerf
))
{
if
(
options
.
perfDataSelection
===
key
)
{
setPerfValue
(
value
)
}
}
}
//Setup check refresher
useEffect
(()
=>
{
if
(
options
.
objectType
!==
null
&&
options
.
filter
!==
null
)
{
meerkat
.
getCheckResult
(
options
.
id
).
then
(
async
c
=>
{
let
perfData
=
c
.
results
[
0
].
attrs
.
last_check_result
.
performance_data
.
join
().
replace
(
'
,
'
,
'
;
'
).
split
(
'
;
'
);
if
(
typeof
perfData
!==
"
undefined
"
)
{
let
arrPerf
=
[];
for
(
var
i
=
0
;
i
<
perfData
.
length
;
i
++
){
if
(
perfData
[
i
].
includes
(
'
=
'
))
{
arrPerf
.
push
(
perfData
[
i
].
replace
(
'
,
'
,
''
));
}
}
let
objPerf
=
Object
.
fromEntries
(
arrPerf
.
map
(
s
=>
s
.
split
(
'
=
'
)));
setPerfData
(
objPerf
);
perfDataSelected
(
objPerf
);
console
.
log
(
objPerf
)
}
});
initState
();
updateState
();
const
intervalID
=
window
.
setInterval
(
updateState
,
30
*
1000
)
...
...
@@ -93,7 +119,11 @@ export function CheckCard({options, slug, dashboard}) {
return
<
div
class
=
{
"
check-content card
"
+
checkState
}
>
<
div
class
=
"check-state"
style
=
{
`font-size:
${
options
.
statusFontSize
}
px`
}
>
{
checkState
===
null
?
'
Unconfigured
'
:
checkState
}
{
/* {checkState === null ? 'Unconfigured' : checkState} */
}
{
/* {perfValue === null ? 'Unconfigured' : perfValue} */
}
{
/* {perfDataSelected()} */
}
{
/* <br/> */
}
{
perfValue
?
perfValue
:
checkState
}
</
div
>
</
div
>
}
...
...
@@ -115,12 +145,74 @@ export function CheckCardOptions({options, updateOptions}) {
<
label
for
=
"status-font-size"
>
Status Font Size
</
label
>
<
input
class
=
"form-control"
id
=
"status-font-size"
name
=
"status-font-size"
type
=
"number"
min
=
"0"
onInput
=
{
e
=>
updateOptions
({
statusFontSize
:
Number
(
e
.
currentTarget
.
value
)})
}
/>
<
PerfDataOptions
options
=
{
options
}
updateOptions
=
{
updateOptions
}
/>
<
br
/>
<
button
class
=
"rounded btn-primary btn-large"
onClick
=
{
onClickAdvanced
}
>
{
showAdvanced
?
'
Hide Options
'
:
'
Advanced Options
'
}
</
button
>
<
AdvancedCheckOptions
options
=
{
options
}
updateOptions
=
{
updateOptions
}
display
=
{
showAdvanced
}
/>
</
div
>
}
const
PerfDataOptions
=
({
options
,
updateOptions
})
=>
{
const
[
showPerfOptions
,
setShowPerf
]
=
useState
(
null
)
const
[
perfData
,
setPerfData
]
=
useState
(
null
);
useEffect
(()
=>
{
options
.
perfDataMode
?
setShowPerf
(
true
)
:
setShowPerf
(
false
);
clearPerfData
();
setShowPerf
(
false
)
meerkat
.
getCheckResult
(
options
.
id
).
then
(
async
c
=>
{
let
erfData
=
c
.
results
[
0
].
attrs
.
last_check_result
.
performance_data
console
.
log
(
erfData
)
let
perfData
=
c
.
results
[
0
].
attrs
.
last_check_result
.
performance_data
.
join
().
replace
(
'
,
'
,
'
;
'
).
split
(
'
;
'
);
if
(
typeof
perfData
!==
"
undefined
"
)
{
let
arrPerf
=
[];
for
(
var
i
=
0
;
i
<
perfData
.
length
;
i
++
){
if
(
perfData
[
i
].
includes
(
'
=
'
))
{
arrPerf
.
push
(
perfData
[
i
].
replace
(
'
,
'
,
''
));
}
}
let
objPerf
=
Object
.
fromEntries
(
arrPerf
.
map
(
s
=>
s
.
split
(
'
=
'
)));
setPerfData
(
objPerf
)
}
});
},
[
options
.
perfDataMode
])
const
clearPerfData
=
()
=>
{
if
(
!
options
.
perfDataMode
)
{
updateOptions
({
perfDataSelection
:
''
})
}
}
const
perfDataMode
=
(
e
)
=>
{
let
perfDataModeChecked
=
options
.
perfDataMode
;
perfDataModeChecked
=
!
perfDataModeChecked
;
updateOptions
({
perfDataMode
:
perfDataModeChecked
})
}
if
(
perfData
===
null
)
{
return
<
div
><
label
>
No Performance Data Available
</
label
><
br
/></
div
>
}
return
<
div
>
<
label
class
=
"status-font-size"
>
Performance Data Mode
</
label
>
<
input
type
=
"checkbox"
defaultChecked
=
{
options
.
perfDataMode
}
onChange
=
{
e
=>
perfDataMode
(
e
)
}
class
=
"form-control perf-data-mode"
/>
{
options
.
perfDataMode
||
showPerfOptions
?
<
select
onInput
=
{
e
=>
updateOptions
({
perfDataSelection
:
e
.
currentTarget
.
value
})
}
>
<
option
value
=
{
null
}
selected
disabled
>
Choose away...
</
option
>
{
Object
.
keys
(
perfData
).
map
(
perf
=>
(
<
option
key
=
{
perf
}
value
=
{
perf
}
>
{
perf
.
toUpperCase
()
}
</
option
>
))
}
</
select
>
:
null
}
</
div
>
}
const
AdvancedCheckOptions
=
({
options
,
updateOptions
,
display
})
=>
{
const
handleAudioFile
=
async
(
fieldName
,
files
)
=>
{
const
res
=
await
meerkat
.
uploadFile
(
files
[
0
]);
...
...
frontend/src/meerkat.js
View file @
770eb1ca
...
...
@@ -30,6 +30,16 @@ export async function getIcingaObjectState(objectType, filter) {
}
}
export
async
function
getCheckResult
(
service
,
attrs
=
"
last_check_result
"
)
{
const
res
=
await
fetch
(
`/icinga/check_result?service=
${
encodeURIComponent
(
service
)}
;attrs=
${
encodeURIComponent
(
attrs
)}
`
);
if
(
res
.
status
!==
200
)
{
return
console
.
log
(
"
query succesful
"
);
}
else
{
return
res
.
json
();
}
}
export
async
function
getAllDashboards
()
{
const
res
=
await
fetch
(
'
/dashboard
'
)
const
data
=
await
res
.
json
();
...
...
frontend/style.css
View file @
770eb1ca
...
...
@@ -536,6 +536,13 @@ input[type=checkbox].form-control.mute-sounds {
position
:
absolute
;
}
input
[
type
=
checkbox
]
.form-control.perf-data-mode
{
float
:
right
;
margin-left
:
14em
;
margin-top
:
-3em
;
position
:
absolute
;
}
.dashboard.view-only
.check
{
cursor
:
default
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment