13
13
from flask import (
14
14
Flask , render_template , abort , url_for ,
15
15
Response , stream_with_context , redirect ,
16
- request , session , jsonify
16
+ request , session , jsonify , flash
17
+ )
18
+ from flask_login import (
19
+ LoginManager , login_required ,
20
+ login_user , logout_user
17
21
)
18
22
from jinja2 .utils import contextfunction
19
23
20
24
from pypuppetdb .QueryBuilder import *
21
25
22
- from puppetboard .forms import QueryForm
26
+ from puppetboard .forms import QueryForm , LoginForm
23
27
from puppetboard .utils import (get_or_abort , yield_or_stop ,
24
28
get_db_version )
25
29
from puppetboard .dailychart import get_daily_reports_chart
30
+ from puppetboard .models import db , Users
31
+ from sqlalchemy .exc import OperationalError
26
32
27
33
import werkzeug .exceptions as ex
28
34
import CommonMark
51
57
]
52
58
53
59
app = get_app ()
60
+ login_manager = LoginManager ()
61
+ login_manager .init_app (app )
62
+ login_manager .login_view = "login"
63
+ if not app .config ['LOGIN_DISABLED' ]:
64
+ try :
65
+ users = Users .query .all ()
66
+ except OperationalError :
67
+ db .create_all ()
68
+ users = Users .query .all ()
69
+ if len (users ) < 1 :
70
+ admin_user = Users (username = 'admin' , password = 'admin123' )
71
+ db .session .add (admin_user )
72
+ db .session .commit ()
54
73
graph_facts = app .config ['GRAPH_FACTS' ]
55
74
numeric_level = getattr (logging , app .config ['LOGLEVEL' ].upper (), None )
56
75
@@ -88,6 +107,7 @@ def now(format='%m/%d/%Y %H:%M:%S'):
88
107
89
108
@app .route ('/' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
90
109
@app .route ('/<env>/' )
110
+ @login_required
91
111
def index (env ):
92
112
"""This view generates the index page and displays a set of metrics and
93
113
latest reports on nodes fetched from PuppetDB.
@@ -200,6 +220,7 @@ def index(env):
200
220
201
221
@app .route ('/nodes' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
202
222
@app .route ('/<env>/nodes' )
223
+ @login_required
203
224
def nodes (env ):
204
225
"""Fetch all (active) nodes from PuppetDB and stream a table displaying
205
226
those nodes.
@@ -285,6 +306,7 @@ def inventory_facts():
285
306
286
307
@app .route ('/inventory' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
287
308
@app .route ('/<env>/inventory' )
309
+ @login_required
288
310
def inventory (env ):
289
311
"""Fetch all (active) nodes from PuppetDB and stream a table displaying
290
312
those nodes along with a set of facts about them.
@@ -306,6 +328,7 @@ def inventory(env):
306
328
@app .route ('/inventory/json' ,
307
329
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
308
330
@app .route ('/<env>/inventory/json' )
331
+ @login_required
309
332
def inventory_ajax (env ):
310
333
"""Backend endpoint for inventory table"""
311
334
draw = int (request .args .get ('draw' , 0 ))
@@ -344,6 +367,7 @@ def inventory_ajax(env):
344
367
@app .route ('/node/<node_name>' ,
345
368
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
346
369
@app .route ('/<env>/node/<node_name>' )
370
+ @login_required
347
371
def node (env , node_name ):
348
372
"""Display a dashboard for a node showing as much data as we have on that
349
373
node. This includes facts and reports but not Resources as that is too
@@ -378,6 +402,7 @@ def node(env, node_name):
378
402
@app .route ('/reports/<node_name>' ,
379
403
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
380
404
@app .route ('/<env>/reports/<node_name>' )
405
+ @login_required
381
406
def reports (env , node_name ):
382
407
"""Query and Return JSON data to reports Jquery datatable
383
408
@@ -401,6 +426,7 @@ def reports(env, node_name):
401
426
@app .route ('/reports/<node_name>/json' ,
402
427
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
403
428
@app .route ('/<env>/reports/<node_name>/json' )
429
+ @login_required
404
430
def reports_ajax (env , node_name ):
405
431
"""Query and Return JSON data to reports Jquery datatable
406
432
@@ -509,6 +535,7 @@ def reports_ajax(env, node_name):
509
535
@app .route ('/report/<node_name>/<report_id>' ,
510
536
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
511
537
@app .route ('/<env>/report/<node_name>/<report_id>' )
538
+ @login_required
512
539
def report (env , node_name , report_id ):
513
540
"""Displays a single report including all the events associated with that
514
541
report and their status.
@@ -560,6 +587,7 @@ def report(env, node_name, report_id):
560
587
561
588
@app .route ('/facts' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
562
589
@app .route ('/<env>/facts' )
590
+ @login_required
563
591
def facts (env ):
564
592
"""Displays an alphabetical list of all facts currently known to
565
593
PuppetDB.
@@ -609,6 +637,7 @@ def facts(env):
609
637
@app .route ('/fact/<fact>/<value>' ,
610
638
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
611
639
@app .route ('/<env>/fact/<fact>/<value>' )
640
+ @login_required
612
641
def fact (env , fact , value ):
613
642
"""Fetches the specific fact(/value) from PuppetDB and displays per
614
643
node for which this fact is known.
@@ -655,6 +684,7 @@ def fact(env, fact, value):
655
684
'fact' : None , 'value' : None })
656
685
@app .route ('/<env>/node/<node>/facts/json' ,
657
686
defaults = {'fact' : None , 'value' : None })
687
+ @login_required
658
688
def fact_ajax (env , node , fact , value ):
659
689
"""Fetches the specific facts matching (node/fact/value) from PuppetDB and
660
690
return a JSON table
@@ -747,6 +777,7 @@ def fact_ajax(env, node, fact, value):
747
777
@app .route ('/query' , methods = ('GET' , 'POST' ),
748
778
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
749
779
@app .route ('/<env>/query' , methods = ('GET' , 'POST' ))
780
+ @login_required
750
781
def query (env ):
751
782
"""Allows to execute raw, user created querries against PuppetDB. This is
752
783
currently highly experimental and explodes in interesting ways since none
@@ -792,6 +823,7 @@ def query(env):
792
823
793
824
@app .route ('/metrics' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
794
825
@app .route ('/<env>/metrics' )
826
+ @login_required
795
827
def metrics (env ):
796
828
"""Lists all available metrics that PuppetDB is aware of.
797
829
@@ -812,6 +844,7 @@ def metrics(env):
812
844
@app .route ('/metric/<path:metric>' ,
813
845
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
814
846
@app .route ('/<env>/metric/<path:metric>' )
847
+ @login_required
815
848
def metric (env , metric ):
816
849
"""Lists all information about the metric of the given name.
817
850
@@ -839,6 +872,7 @@ def metric(env, metric):
839
872
@app .route ('/catalogs/compare/<compare>' ,
840
873
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
841
874
@app .route ('/<env>/catalogs/compare/<compare>' )
875
+ @login_required
842
876
def catalogs (env , compare ):
843
877
"""Lists all nodes with a compiled catalog.
844
878
@@ -867,6 +901,7 @@ def catalogs(env, compare):
867
901
@app .route ('/catalogs/compare/<compare>/json' ,
868
902
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
869
903
@app .route ('/<env>/catalogs/compare/<compare>/json' )
904
+ @login_required
870
905
def catalogs_ajax (env , compare ):
871
906
"""Server data to catalogs as JSON to Jquery datatables
872
907
"""
@@ -926,6 +961,7 @@ def catalogs_ajax(env, compare):
926
961
@app .route ('/catalog/<node_name>' ,
927
962
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
928
963
@app .route ('/<env>/catalog/<node_name>' )
964
+ @login_required
929
965
def catalog_node (env , node_name ):
930
966
"""Fetches from PuppetDB the compiled catalog of a given node.
931
967
@@ -950,6 +986,7 @@ def catalog_node(env, node_name):
950
986
@app .route ('/catalogs/compare/<compare>...<against>' ,
951
987
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
952
988
@app .route ('/<env>/catalogs/compare/<compare>...<against>' )
989
+ @login_required
953
990
def catalog_compare (env , compare , against ):
954
991
"""Compares the catalog of one node, parameter compare, with that of
955
992
with that of another node, parameter against.
@@ -978,6 +1015,7 @@ def catalog_compare(env, compare, against):
978
1015
979
1016
@app .route ('/radiator' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
980
1017
@app .route ('/<env>/radiator' )
1018
+ @login_required
981
1019
def radiator (env ):
982
1020
"""This view generates a simplified monitoring page
983
1021
akin to the radiator view in puppet dashboard
@@ -1077,6 +1115,7 @@ def radiator(env):
1077
1115
@app .route ('/daily_reports_chart.json' ,
1078
1116
defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
1079
1117
@app .route ('/<env>/daily_reports_chart.json' )
1118
+ @login_required
1080
1119
def daily_reports_chart (env ):
1081
1120
"""Return JSON data to generate a bar chart of daily runs.
1082
1121
@@ -1104,3 +1143,39 @@ def offline_static(filename):
1104
1143
1105
1144
return Response (response = render_template ('static/%s' % filename ),
1106
1145
status = 200 , mimetype = mimetype )
1146
+
1147
+
1148
+ @app .route ("/login" , methods = ["GET" , "POST" ])
1149
+ def login ():
1150
+ form = LoginForm (meta = {
1151
+ 'csrf_secret' : app .config ['SECRET_KEY' ],
1152
+ 'csrf_context' : session })
1153
+ if form .validate_on_submit ():
1154
+ user = Users .query .filter_by (username = form .username .data ).first ()
1155
+ if user and user .password == form .password .data :
1156
+ login_user (user , remember = form .remember .data )
1157
+ return redirect (url_for ('index' ))
1158
+ else :
1159
+ flash ('Login failed.' , 'error' )
1160
+ return render_template ('login.html' , form = form )
1161
+
1162
+
1163
+ @app .route ("/users" )
1164
+ @login_required
1165
+ def users ():
1166
+ users = Users .query .all ()
1167
+ return render_template ('users.html' , users = users )
1168
+
1169
+
1170
+ @app .route ("/logout" )
1171
+ @login_required
1172
+ def logout ():
1173
+ logout_user ()
1174
+ flash ('You have been logged out.' , 'info' )
1175
+ return redirect (url_for ('login' ))
1176
+
1177
+
1178
+ @login_manager .user_loader
1179
+ def load_user (user_id ):
1180
+ return Users .query .filter_by (id = int (user_id )).first ()
1181
+
0 commit comments