Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Benjamin "Ziirish" SANS
burp-ui
Commits
268b2fa7
Commit
268b2fa7
authored
Sep 13, 2014
by
Benjamin "Ziirish" SANS
Browse files
new backend 'multi' for
#14
parent
bfdf3d7e
Changes
23
Hide whitespace changes
Inline
Side-by-side
bin/burp-ui
View file @
268b2fa7
...
...
@@ -20,6 +20,8 @@ if __name__ == '__main__':
(
options
,
args
)
=
parser
.
parse_args
()
d
=
options
.
log
app
.
config
[
'DEBUG'
]
=
d
if
d
:
app
.
config
[
'TESTING'
]
=
True
if
options
.
config
:
if
os
.
path
.
isfile
(
options
.
config
):
...
...
burpui/__init__.py
View file @
268b2fa7
...
...
@@ -10,7 +10,7 @@ __license__ = 'BSD 3-clause'
from
flask
import
Flask
from
flask.ext.login
import
LoginManager
from
burpui.server
import
Server
as
BurpUI
from
burpui.server
import
BUI
Server
as
BurpUI
# First, we setup the app
app
=
Flask
(
__name__
)
...
...
burpui/misc/auth/ldap.py
View file @
268b2fa7
...
...
@@ -57,8 +57,8 @@ class LdapLoader:
query
=
'uid={0}'
.
format
(
uid
)
self
.
app
.
logger
.
info
(
'query: %s | base: %s'
,
query
,
self
.
base
)
r
=
self
.
ldap
.
search
(
query
,
base_dn
=
self
.
base
)
except
:
self
.
app
.
logger
.
info
(
'Ooops, LDAP lookup failed
'
)
except
Exception
,
e
:
self
.
app
.
logger
.
error
(
'Ooops, LDAP lookup failed
: %s'
,
str
(
e
)
)
return
None
return
r
[
0
][
'uid'
][
0
]
...
...
burpui/misc/backend/burp1.py
View file @
268b2fa7
...
...
@@ -145,7 +145,7 @@ class Burp(BUIbackend):
Utilities functions
"""
def
status
(
self
,
query
=
'
\n
'
):
def
status
(
self
,
query
=
'
\n
'
,
agent
=
None
):
"""
status connects to the burp status port, ask the given 'question' and
parses the output in an array
...
...
@@ -178,7 +178,7 @@ class Burp(BUIbackend):
self
.
logger
(
'error'
,
'Cannot contact burp server at %s:%s'
,
self
.
host
,
self
.
port
)
raise
BUIserverException
(
'Cannot contact burp server at {0}:{1}'
.
format
(
self
.
host
,
self
.
port
))
def
parse_backup_log
(
self
,
f
,
n
,
c
=
None
):
def
parse_backup_log
(
self
,
f
,
n
,
c
=
None
,
agent
=
None
):
"""
parse_backup_log parses the log.gz of a given backup and returns a dict
containing different stats used to render the charts in the reporting view
...
...
@@ -269,7 +269,7 @@ class Burp(BUIbackend):
break
return
backup
def
get_counters
(
self
,
name
=
None
):
def
get_counters
(
self
,
name
=
None
,
agent
=
None
):
"""
get_counters parses the stats of the live status for a given client and
returns a dict
...
...
@@ -310,7 +310,7 @@ class Burp(BUIbackend):
r
[
'timeleft'
]
=
-
1
return
r
def
is_backup_running
(
self
,
name
=
None
):
def
is_backup_running
(
self
,
name
=
None
,
agent
=
None
):
"""
is_backup_running returns True if the given client is currently running a
backup
...
...
@@ -327,7 +327,7 @@ class Burp(BUIbackend):
return
True
return
False
def
is_one_backup_running
(
self
):
def
is_one_backup_running
(
self
,
agent
=
None
):
"""
is_one_backup_running returns a list of clients name that are currently
running a backup
...
...
@@ -343,7 +343,7 @@ class Burp(BUIbackend):
self
.
running
=
r
return
r
def
get_all_clients
(
self
):
def
get_all_clients
(
self
,
agent
=
None
):
"""
get_all_clients returns a list of dict representing each clients with their
name, state and last backup date
...
...
@@ -370,7 +370,7 @@ class Burp(BUIbackend):
j
.
append
(
c
)
return
j
def
get_client
(
self
,
name
=
None
):
def
get_client
(
self
,
name
=
None
,
agent
=
None
):
"""
get_client returns a list of dict representing the backups (with its number
and date) of a given client
...
...
@@ -399,7 +399,7 @@ class Burp(BUIbackend):
r
.
reverse
()
return
r
def
get_tree
(
self
,
name
=
None
,
backup
=
None
,
root
=
None
):
def
get_tree
(
self
,
name
=
None
,
backup
=
None
,
root
=
None
,
agent
=
None
):
"""
get_tree returns a list of dict representing files/dir (with their attr)
within a given path
...
...
@@ -442,7 +442,7 @@ class Burp(BUIbackend):
r
.
append
(
t
)
return
r
def
restore_files
(
self
,
name
=
None
,
backup
=
None
,
files
=
None
):
def
restore_files
(
self
,
name
=
None
,
backup
=
None
,
files
=
None
,
agent
=
None
):
if
not
name
or
not
backup
or
not
files
:
return
None
flist
=
json
.
loads
(
files
)
...
...
burpui/misc/backend/interface.py
View file @
268b2fa7
...
...
@@ -6,28 +6,28 @@ class BUIbackend:
self
.
host
=
host
self
.
port
=
port
def
status
(
self
,
query
=
'
\n
'
):
def
status
(
self
,
query
=
'
\n
'
,
agent
=
None
):
raise
NotImplementedError
(
"Sorry, the current Backend does not implement this method!"
)
def
parse_backup_log
(
self
,
f
,
n
,
c
=
None
):
def
parse_backup_log
(
self
,
f
,
n
,
c
=
None
,
agent
=
None
):
raise
NotImplementedError
(
"Sorry, the current Backend does not implement this method!"
)
def
get_counters
(
self
,
name
=
None
):
def
get_counters
(
self
,
name
=
None
,
agent
=
None
):
raise
NotImplementedError
(
"Sorry, the current Backend does not implement this method!"
)
def
is_backup_running
(
self
,
name
=
None
):
def
is_backup_running
(
self
,
name
=
None
,
agent
=
None
):
raise
NotImplementedError
(
"Sorry, the current Backend does not implement this method!"
)
def
is_one_backup_running
(
self
):
def
is_one_backup_running
(
self
,
agent
=
None
):
raise
NotImplementedError
(
"Sorry, the current Backend does not implement this method!"
)
def
get_all_clients
(
self
):
def
get_all_clients
(
self
,
agent
=
None
):
raise
NotImplementedError
(
"Sorry, the current Backend does not implement this method!"
)
def
get_client
(
self
,
name
=
None
):
def
get_client
(
self
,
name
=
None
,
agent
=
None
):
raise
NotImplementedError
(
"Sorry, the current Backend does not implement this method!"
)
def
get_tree
(
self
,
name
=
None
,
backup
=
None
,
root
=
None
):
def
get_tree
(
self
,
name
=
None
,
backup
=
None
,
root
=
None
,
agent
=
None
):
raise
NotImplementedError
(
"Sorry, the current Backend does not implement this method!"
)
class
BUIserverException
(
Exception
):
...
...
burpui/misc/backend/multi.py
0 → 100644
View file @
268b2fa7
# -*- coding: utf8 -*-
import
re
import
socket
import
sys
import
json
import
struct
import
ConfigParser
from
burpui.misc.backend.interface
import
BUIbackend
,
BUIserverException
class
Burp
(
BUIbackend
):
def
__init__
(
self
,
app
=
None
,
conf
=
None
):
self
.
app
=
app
self
.
servers
=
{}
self
.
servers_status
=
{}
if
conf
:
config
=
ConfigParser
.
ConfigParser
()
with
open
(
conf
)
as
fp
:
config
.
readfp
(
fp
)
for
sec
in
config
.
sections
():
r
=
re
.
match
(
'^Agent:(.+)$'
,
sec
)
if
r
:
try
:
host
=
config
.
get
(
sec
,
'host'
)
port
=
config
.
getint
(
sec
,
'port'
)
password
=
config
.
get
(
sec
,
'password'
)
ssl
=
config
.
getboolean
(
sec
,
'ssl'
)
except
Exception
,
e
:
self
.
app
.
logger
.
error
(
str
(
e
))
self
.
servers
[
r
.
group
(
1
)]
=
NClient
(
app
,
host
,
port
,
password
,
ssl
)
self
.
app
.
logger
.
debug
(
self
.
servers
)
for
key
,
serv
in
self
.
servers
.
iteritems
():
self
.
servers_status
[
key
]
=
{
'clients'
:
[],
'alive'
:
serv
.
connected
}
if
not
serv
.
connected
:
continue
for
c
in
serv
.
get_all_clients
(
key
):
self
.
servers_status
[
key
][
'clients'
].
append
(
c
[
'name'
])
"""
Utilities functions
"""
def
status
(
self
,
query
=
'
\n
'
,
agent
=
None
):
"""
status connects to the burp status port, ask the given 'question' and
parses the output in an array
"""
return
self
.
servers
[
agent
].
status
(
query
)
def
parse_backup_log
(
self
,
f
,
n
,
c
=
None
,
agent
=
None
):
"""
parse_backup_log parses the log.gz of a given backup and returns a dict
containing different stats used to render the charts in the reporting view
"""
return
self
.
servers
[
agent
].
parse_backup_log
(
f
,
n
,
c
)
def
get_counters
(
self
,
name
=
None
,
agent
=
None
):
"""
get_counters parses the stats of the live status for a given client and
returns a dict
"""
return
self
.
servers
[
agent
].
get_counters
(
name
)
def
is_backup_running
(
self
,
name
=
None
,
agent
=
None
):
"""
is_backup_running returns True if the given client is currently running a
backup
"""
return
self
.
servers
[
agent
].
is_backup_running
(
name
)
def
is_one_backup_running
(
self
,
agent
=
None
):
"""
is_one_backup_running returns a list of clients name that are currently
running a backup
"""
return
self
.
servers
[
agent
].
is_one_backup_running
()
def
get_all_clients
(
self
,
agent
=
None
):
"""
get_all_clients returns a list of dict representing each clients with their
name, state and last backup date
"""
return
self
.
servers
[
agent
].
get_all_clients
()
def
get_client
(
self
,
name
=
None
,
agent
=
None
):
"""
get_client returns a list of dict representing the backups (with its number
and date) of a given client
"""
return
self
.
servers
[
agent
].
get_client
(
name
)
def
get_tree
(
self
,
name
=
None
,
backup
=
None
,
root
=
None
,
agent
=
None
):
"""
get_tree returns a list of dict representing files/dir (with their attr)
within a given path
"""
return
self
.
servers
[
agent
].
get_tree
(
name
,
backup
,
root
)
def
restore_files
(
self
,
name
=
None
,
backup
=
None
,
files
=
None
,
agent
=
None
):
pass
class
NClient
(
BUIbackend
):
def
__init__
(
self
,
app
=
None
,
host
=
None
,
port
=
None
,
password
=
None
,
ssl
=
None
):
self
.
host
=
host
self
.
port
=
port
self
.
password
=
password
self
.
ssl
=
ssl
self
.
nok
=
False
self
.
connected
=
False
self
.
app
=
app
self
.
conn
()
def
conn
(
self
):
try
:
self
.
sock
=
socket
.
socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
self
.
sock
.
connect
((
self
.
host
,
self
.
port
))
self
.
connected
=
True
self
.
app
.
logger
.
debug
(
'OK, connected to agent %s:%s'
,
self
.
host
,
self
.
port
)
except
Exception
,
e
:
self
.
connected
=
False
self
.
app
.
logger
.
error
(
'Could not connect to %s:%s => %s'
,
self
.
host
,
self
.
port
,
str
(
e
))
def
send_command
(
self
,
data
=
None
):
if
not
data
:
return
old_data
=
data
try
:
data
[
'password'
]
=
self
.
password
raw
=
json
.
dumps
(
data
)
length
=
len
(
raw
)
self
.
sock
.
sendall
(
struct
.
pack
(
'!Q'
,
length
))
self
.
sock
.
sendall
(
raw
)
self
.
app
.
logger
.
debug
(
"Sending: %s"
,
raw
)
res
=
self
.
sock
.
recv
(
10
)
self
.
app
.
logger
.
debug
(
"recv: '%s'"
,
res
)
if
'OK Result:'
!=
res
:
self
.
app
.
logger
.
debug
(
'Ooops, unsuccessful!'
)
self
.
nok
=
True
return
self
.
app
.
logger
.
debug
(
"Data sent successfully"
)
self
.
nok
=
False
except
Exception
,
e
:
self
.
app
.
logger
.
error
(
str
(
e
))
self
.
conn
()
self
.
nok
=
True
self
.
send_command
(
old_data
)
def
get_result
(
self
):
if
self
.
nok
:
return
None
self
.
app
.
logger
.
debug
(
'What now?'
)
lengthbuf
=
self
.
sock
.
recv
(
8
)
length
,
=
struct
.
unpack
(
'!Q'
,
lengthbuf
)
return
self
.
recvall
(
length
)
def
recvall
(
self
,
length
):
buf
=
b
''
bsize
=
1024
while
length
:
newbuf
=
self
.
sock
.
recv
(
1024
)
if
not
newbuf
:
return
None
buf
+=
newbuf
length
-=
len
(
newbuf
)
self
.
app
.
logger
.
debug
(
'result: %s'
,
buf
)
return
buf
"""
Utilities functions
"""
def
status
(
self
,
query
=
'
\n
'
,
agent
=
None
):
"""
status connects to the burp status port, ask the given 'question' and
parses the output in an array
"""
data
=
{
'func'
:
'status'
,
'args'
:
{
'query'
:
query
}}
self
.
send_command
(
data
)
return
json
.
loads
(
self
.
get_result
())
def
parse_backup_log
(
self
,
f
,
n
,
c
=
None
,
agent
=
None
):
"""
parse_backup_log parses the log.gz of a given backup and returns a dict
containing different stats used to render the charts in the reporting view
"""
data
=
{
'func'
:
'parse_backup_log'
,
'args'
:
{
'f'
:
f
,
'n'
:
n
,
'c'
:
c
}}
self
.
send_command
(
data
)
return
json
.
loads
(
self
.
get_result
())
def
get_counters
(
self
,
name
=
None
,
agent
=
None
):
"""
get_counters parses the stats of the live status for a given client and
returns a dict
"""
data
=
{
'func'
:
'get_counters'
,
'args'
:
{
'name'
:
name
}}
self
.
send_command
(
data
)
return
json
.
loads
(
self
.
get_result
())
def
is_backup_running
(
self
,
name
=
None
,
agent
=
None
):
"""
is_backup_running returns True if the given client is currently running a
backup
"""
data
=
{
'func'
:
'is_backup_running'
,
'args'
:
{
'name'
:
name
}}
self
.
send_command
(
data
)
return
json
.
loads
(
self
.
get_result
())
def
is_one_backup_running
(
self
,
agent
=
None
):
"""
is_one_backup_running returns a list of clients name that are currently
running a backup
"""
data
=
{
'func'
:
'is_one_backup_running'
,
'args'
:
None
}
self
.
send_command
(
data
)
return
json
.
loads
(
self
.
get_result
())
def
get_all_clients
(
self
,
agent
=
None
):
"""
get_all_clients returns a list of dict representing each clients with their
name, state and last backup date
"""
data
=
{
'func'
:
'get_all_clients'
,
'args'
:
None
}
self
.
send_command
(
data
)
return
json
.
loads
(
self
.
get_result
())
def
get_client
(
self
,
name
=
None
,
agent
=
None
):
"""
get_client returns a list of dict representing the backups (with its number
and date) of a given clientm
"""
data
=
{
'func'
:
'get_client'
,
'args'
:
{
'name'
:
name
}}
self
.
send_command
(
data
)
return
json
.
loads
(
self
.
get_result
())
def
get_tree
(
self
,
name
=
None
,
backup
=
None
,
root
=
None
,
agent
=
None
):
"""
get_tree returns a list of dict representing files/dir (with their attr)
within a given path
"""
data
=
{
'func'
:
'get_tree'
,
'args'
:
{
'name'
:
name
,
'backup'
:
backup
,
'root'
:
root
}}
self
.
send_command
(
data
)
return
json
.
loads
(
self
.
get_result
())
def
restore_files
(
self
,
name
=
None
,
backup
=
None
,
files
=
None
,
agent
=
None
):
return
None
burpui/routes.py
View file @
268b2fa7
...
...
@@ -15,15 +15,6 @@ def load_user(userid):
return
bui
.
uhandler
.
user
(
userid
)
return
None
@
app
.
route
(
'/test/download'
)
def
test_download
():
try
:
resp
=
send_file
(
'/tmp/monfichierr'
,
as_attachment
=
True
)
resp
.
set_cookie
(
'fileDownload'
,
'true'
)
return
resp
except
Exception
,
e
:
abort
(
500
)
@
app
.
route
(
'/api/restore/<name>/<int:backup>'
,
methods
=
[
'POST'
])
@
login_required
def
restore
(
name
=
None
,
backup
=
None
):
...
...
@@ -47,25 +38,32 @@ The whole API returns JSON-formated data
"""
@
app
.
route
(
'/api/running-clients.json'
)
@
app
.
route
(
'/api/<server>/running-clients.json'
)
@
login_required
def
running_clients
():
def
running_clients
(
server
=
None
):
"""
API: running_clients
:returns: a list of running clients
"""
r
=
bui
.
cli
.
is_one_backup_running
()
if
not
server
:
server
=
request
.
args
.
get
(
'server'
)
r
=
bui
.
cli
.
is_one_backup_running
(
agent
=
server
)
return
jsonify
(
results
=
r
)
@
app
.
route
(
'/api/render-live-template'
,
methods
=
[
'GET'
])
@
app
.
route
(
'/api/<server>/render-live-template'
,
methods
=
[
'GET'
])
@
app
.
route
(
'/api/render-live-template/<name>'
)
@
app
.
route
(
'/api/<server>/render-live-template/<name>'
)
@
login_required
def
render_live_tpl
(
name
=
None
):
def
render_live_tpl
(
server
=
None
,
name
=
None
):
"""
API: render_live_tpl
:param name: the client name if any. You can also use the GET parameter
'name' to achieve the same thing
:returns: HTML that should be included directly into the page
"""
if
not
server
:
server
=
request
.
args
.
get
(
'server'
)
c
=
request
.
args
.
get
(
'name'
)
if
not
name
and
not
c
:
abort
(
500
)
...
...
@@ -74,136 +72,166 @@ def render_live_tpl(name=None):
if
name
not
in
bui
.
cli
.
running
:
abort
(
404
)
try
:
counters
=
bui
.
cli
.
get_counters
(
name
)
counters
=
bui
.
cli
.
get_counters
(
name
,
agent
=
server
)
except
BUIserverException
:
counters
=
[]
return
render_template
(
'live-monitor-template.html'
,
cname
=
name
,
counters
=
counters
)
return
render_template
(
'live-monitor-template.html'
,
cname
=
name
,
counters
=
counters
,
server
=
server
)
@
app
.
route
(
'/api/servers.json'
)
@
login_required
def
servers_json
():
r
=
[]
for
serv
in
bui
.
cli
.
servers_status
:
r
.
append
({
'name'
:
serv
,
'clients'
:
len
(
bui
.
cli
.
servers_status
[
serv
][
'clients'
]),
'connected'
:
bui
.
cli
.
servers_status
[
serv
][
'alive'
]})
return
jsonify
(
results
=
r
)
@
app
.
route
(
'/api/live.json'
)
@
app
.
route
(
'/api/<server>/live.json'
)
@
login_required
def
live
():
def
live
(
server
=
None
):
"""
API: live
:returns: the live status of the server
"""
if
not
server
:
server
=
request
.
args
.
get
(
'server'
)
r
=
[]
for
c
in
bui
.
cli
.
is_one_backup_running
():
for
c
in
bui
.
cli
.
is_one_backup_running
(
agent
=
server
):
s
=
{}
s
[
'client'
]
=
c
try
:
s
[
'status'
]
=
bui
.
cli
.
get_counters
(
c
)
s
[
'status'
]
=
bui
.
cli
.
get_counters
(
c
,
agent
=
server
)
except
BUIserverException
:
s
[
'status'
]
=
[]
r
.
append
(
s
)
return
jsonify
(
results
=
r
)
@
app
.
route
(
'/api/running.json'
)
@
app
.
route
(
'/api/<server>/running.json'
)
@
login_required
def
backup_running
():
def
backup_running
(
server
=
None
):
"""
API: backup_running
:returns: true if at least one backup is running
"""
j
=
bui
.
cli
.
is_one_backup_running
()
if
not
server
:
server
=
request
.
args
.
get
(
'server'
)
j
=
bui
.
cli
.
is_one_backup_running
(
agent
=
server
)
r
=
len
(
j
)
>
0
return
jsonify
(
results
=
r
)
@
app
.
route
(
'/api/client-tree.json/<name>/<int:backup>'
,
methods
=
[
'GET'
])
@
app
.
route
(
'/api/<server>/client-tree.json/<name>/<int:backup>'
,
methods
=
[
'GET'
])
@
login_required
def
client_tree
(
name
=
None
,
backup
=
None
):
def
client_tree
(
server
=
None
,
name
=
None
,
backup
=
None
):
"""
WebService: return a specific client files tree
:param name: the client name (mandatory)
:param backup: the backup number (mandatory)
"""
if
not
server
:
server
=
request
.
args
.
get
(
'server'
)
j
=
[]
if
not
name
or
not
backup
:
return
jsonify
(
results
=
j
)
root
=
request
.
args
.
get
(
'root'
)
try
:
j
=
bui
.
cli
.
get_tree
(
name
,
backup
,
root
)
j
=
bui
.
cli
.
get_tree
(
name
,
backup
,
root
,
agent
=
server
)
except
BUIserverException
,
e
:
err
=
[[
2
,
str
(
e
)]]
return
jsonify
(
notif
=
err
)
return
jsonify
(
results
=
j
)
@
app
.
route
(
'/api/clients-report.json'
)
@
app
.
route
(
'/api/<server>/clients-report.json'
)
@
login_required
def
clients_report_json
():
def
clients_report_json
(
server
=
None
):
"""
WebService: return a JSON with global stats
"""
if
not
server
:
server
=
request
.
args
.
get
(
'server'
)
j
=
[]
try
:
clients
=
bui
.
cli
.
get_all_clients
()
clients
=
bui
.
cli
.
get_all_clients
(
agent
=
server
)
except
BUIserverException
,
e
:
err
=
[[
2
,
str
(
e
)]]
return
jsonify
(
notif
=
err
)
cl
=
[]
ba
=
[]
for
c
in
clients
:
client
=
bui
.
cli
.
get_client
(
c
[
'name'
])
client
=
bui
.
cli
.
get_client
(
c
[
'name'
]
,
agent
=
server
)
if
not
client
:
continue
f
=
bui
.
cli
.
status
(
'c:{0}:b:{1}:f:log.gz
\n
'
.
format
(
c
[
'name'
],
client
[
-
1
][
'number'
]))
cl
.
append
(
{
'name'
:
c
[
'name'
],
'stats'
:
bui
.
cli
.
parse_backup_log
(
f
,
client
[
-
1
][
'number'
])
}
)
f
=
bui
.
cli
.
status
(
'c:{0}:b:{1}:f:log.gz
\n
'
.
format
(
c
[
'name'
],
client
[
-
1
][
'number'
])
,
agent
=
server
)
cl
.
append
(
{
'name'
:
c
[
'name'
],
'stats'
:
bui
.
cli
.
parse_backup_log
(
f
,
client
[
-
1
][
'number'
]
,
agent
=
server
)
}
)
for
b
in
client
:
f
=
bui
.
cli
.
status
(
'c:{0}:b:{1}:f:log.gz
\n
'
.
format
(
c
[
'name'
],
b
[
'number'
]))
ba
.
append
(
bui
.
cli
.
parse_backup_log
(
f
,
b
[
'number'
],
c
[
'name'
]))
f
=
bui
.
cli
.
status
(
'c:{0}:b:{1}:f:log.gz
\n
'
.
format
(
c
[
'name'
],
b
[
'number'
])
,
agent
=
server
)
ba
.
append
(
bui
.
cli
.
parse_backup_log
(
f
,
b
[
'number'
],
c
[
'name'
])
,
agent
=
server
)
j
.
append
(
{
'clients'
:
cl
,
'backups'
:
sorted
(
ba
,
key
=
lambda
k
:
k
[
'end'
])
}
)
return
jsonify
(
results
=
j
)
@
app
.
route
(
'/api/client-stat.json/<name>'
)
@
app
.
route
(
'/api/<server>/client-stat.json/<name>'
)
@
app
.
route
(
'/api/client-stat.json/<name>/<int:backup>'
)
@
app
.
route
(
'/api/<server>/client-stat.json/<name>/<int:backup>'
)
@
login_required
def
client_stat_json
(
name
=
None
,
backup
=
None
):
def
client_stat_json
(
server
=
None
,
name
=
None
,
backup
=
None
):
"""
WebService: return a specific client detailed report
"""
if
not
server
:
server
=
request
.
args
.
get
(
'server'
)
j
=
[]
if
not
name
:
err
=
[[
1
,
'No client defined'
]]
return
jsonify
(
notif
=
err
)
if
backup
:
try
:
f
=
bui
.
cli
.
status
(
'c:{0}:b:{1}:f:log.gz
\n
'
.
format
(
name
,
backup
))
f
=
bui
.
cli
.
status
(
'c:{0}:b:{1}:f:log.gz
\n
'
.
format
(
name
,
backup
)
,
agent
=
server
)
except
BUIserverException
,
e
:
err
=
[[
2
,
str
(
e
)]]
return
jsonify
(
notif
=
err
)
j
=
bui
.
cli
.
parse_backup_log
(
f
,
backup
)
j
=
bui
.
cli
.
parse_backup_log
(
f
,
backup
,
agent
=
server
)
else
:
try
:
cl
=
bui
.
cli
.
get_client
(
name
)
cl
=
bui
.
cli
.
get_client
(
name
,