1313from flask import (
1414 Flask , render_template , abort , url_for ,
1515 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
1721)
1822from jinja2 .utils import contextfunction
1923
2024from pypuppetdb .QueryBuilder import *
2125
22- from puppetboard .forms import QueryForm
26+ from puppetboard .forms import QueryForm , LoginForm
2327from puppetboard .utils import (get_or_abort , yield_or_stop ,
2428 get_db_version )
2529from puppetboard .dailychart import get_daily_reports_chart
30+ from puppetboard .models import db , Users
31+ from sqlalchemy .exc import OperationalError
2632
2733import werkzeug .exceptions as ex
2834import CommonMark
5157]
5258
5359app = 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 ()
5473graph_facts = app .config ['GRAPH_FACTS' ]
5574numeric_level = getattr (logging , app .config ['LOGLEVEL' ].upper (), None )
5675
@@ -88,6 +107,7 @@ def now(format='%m/%d/%Y %H:%M:%S'):
88107
89108@app .route ('/' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
90109@app .route ('/<env>/' )
110+ @login_required
91111def index (env ):
92112 """This view generates the index page and displays a set of metrics and
93113 latest reports on nodes fetched from PuppetDB.
@@ -200,6 +220,7 @@ def index(env):
200220
201221@app .route ('/nodes' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
202222@app .route ('/<env>/nodes' )
223+ @login_required
203224def nodes (env ):
204225 """Fetch all (active) nodes from PuppetDB and stream a table displaying
205226 those nodes.
@@ -285,6 +306,7 @@ def inventory_facts():
285306
286307@app .route ('/inventory' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
287308@app .route ('/<env>/inventory' )
309+ @login_required
288310def inventory (env ):
289311 """Fetch all (active) nodes from PuppetDB and stream a table displaying
290312 those nodes along with a set of facts about them.
@@ -306,6 +328,7 @@ def inventory(env):
306328@app .route ('/inventory/json' ,
307329 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
308330@app .route ('/<env>/inventory/json' )
331+ @login_required
309332def inventory_ajax (env ):
310333 """Backend endpoint for inventory table"""
311334 draw = int (request .args .get ('draw' , 0 ))
@@ -344,6 +367,7 @@ def inventory_ajax(env):
344367@app .route ('/node/<node_name>' ,
345368 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
346369@app .route ('/<env>/node/<node_name>' )
370+ @login_required
347371def node (env , node_name ):
348372 """Display a dashboard for a node showing as much data as we have on that
349373 node. This includes facts and reports but not Resources as that is too
@@ -378,6 +402,7 @@ def node(env, node_name):
378402@app .route ('/reports/<node_name>' ,
379403 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
380404@app .route ('/<env>/reports/<node_name>' )
405+ @login_required
381406def reports (env , node_name ):
382407 """Query and Return JSON data to reports Jquery datatable
383408
@@ -401,6 +426,7 @@ def reports(env, node_name):
401426@app .route ('/reports/<node_name>/json' ,
402427 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
403428@app .route ('/<env>/reports/<node_name>/json' )
429+ @login_required
404430def reports_ajax (env , node_name ):
405431 """Query and Return JSON data to reports Jquery datatable
406432
@@ -509,6 +535,7 @@ def reports_ajax(env, node_name):
509535@app .route ('/report/<node_name>/<report_id>' ,
510536 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
511537@app .route ('/<env>/report/<node_name>/<report_id>' )
538+ @login_required
512539def report (env , node_name , report_id ):
513540 """Displays a single report including all the events associated with that
514541 report and their status.
@@ -560,6 +587,7 @@ def report(env, node_name, report_id):
560587
561588@app .route ('/facts' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
562589@app .route ('/<env>/facts' )
590+ @login_required
563591def facts (env ):
564592 """Displays an alphabetical list of all facts currently known to
565593 PuppetDB.
@@ -609,6 +637,7 @@ def facts(env):
609637@app .route ('/fact/<fact>/<value>' ,
610638 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
611639@app .route ('/<env>/fact/<fact>/<value>' )
640+ @login_required
612641def fact (env , fact , value ):
613642 """Fetches the specific fact(/value) from PuppetDB and displays per
614643 node for which this fact is known.
@@ -655,6 +684,7 @@ def fact(env, fact, value):
655684 'fact' : None , 'value' : None })
656685@app .route ('/<env>/node/<node>/facts/json' ,
657686 defaults = {'fact' : None , 'value' : None })
687+ @login_required
658688def fact_ajax (env , node , fact , value ):
659689 """Fetches the specific facts matching (node/fact/value) from PuppetDB and
660690 return a JSON table
@@ -747,6 +777,7 @@ def fact_ajax(env, node, fact, value):
747777@app .route ('/query' , methods = ('GET' , 'POST' ),
748778 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
749779@app .route ('/<env>/query' , methods = ('GET' , 'POST' ))
780+ @login_required
750781def query (env ):
751782 """Allows to execute raw, user created querries against PuppetDB. This is
752783 currently highly experimental and explodes in interesting ways since none
@@ -792,6 +823,7 @@ def query(env):
792823
793824@app .route ('/metrics' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
794825@app .route ('/<env>/metrics' )
826+ @login_required
795827def metrics (env ):
796828 """Lists all available metrics that PuppetDB is aware of.
797829
@@ -812,6 +844,7 @@ def metrics(env):
812844@app .route ('/metric/<path:metric>' ,
813845 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
814846@app .route ('/<env>/metric/<path:metric>' )
847+ @login_required
815848def metric (env , metric ):
816849 """Lists all information about the metric of the given name.
817850
@@ -839,6 +872,7 @@ def metric(env, metric):
839872@app .route ('/catalogs/compare/<compare>' ,
840873 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
841874@app .route ('/<env>/catalogs/compare/<compare>' )
875+ @login_required
842876def catalogs (env , compare ):
843877 """Lists all nodes with a compiled catalog.
844878
@@ -867,6 +901,7 @@ def catalogs(env, compare):
867901@app .route ('/catalogs/compare/<compare>/json' ,
868902 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
869903@app .route ('/<env>/catalogs/compare/<compare>/json' )
904+ @login_required
870905def catalogs_ajax (env , compare ):
871906 """Server data to catalogs as JSON to Jquery datatables
872907 """
@@ -926,6 +961,7 @@ def catalogs_ajax(env, compare):
926961@app .route ('/catalog/<node_name>' ,
927962 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
928963@app .route ('/<env>/catalog/<node_name>' )
964+ @login_required
929965def catalog_node (env , node_name ):
930966 """Fetches from PuppetDB the compiled catalog of a given node.
931967
@@ -950,6 +986,7 @@ def catalog_node(env, node_name):
950986@app .route ('/catalogs/compare/<compare>...<against>' ,
951987 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
952988@app .route ('/<env>/catalogs/compare/<compare>...<against>' )
989+ @login_required
953990def catalog_compare (env , compare , against ):
954991 """Compares the catalog of one node, parameter compare, with that of
955992 with that of another node, parameter against.
@@ -978,6 +1015,7 @@ def catalog_compare(env, compare, against):
9781015
9791016@app .route ('/radiator' , defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
9801017@app .route ('/<env>/radiator' )
1018+ @login_required
9811019def radiator (env ):
9821020 """This view generates a simplified monitoring page
9831021 akin to the radiator view in puppet dashboard
@@ -1077,6 +1115,7 @@ def radiator(env):
10771115@app .route ('/daily_reports_chart.json' ,
10781116 defaults = {'env' : app .config ['DEFAULT_ENVIRONMENT' ]})
10791117@app .route ('/<env>/daily_reports_chart.json' )
1118+ @login_required
10801119def daily_reports_chart (env ):
10811120 """Return JSON data to generate a bar chart of daily runs.
10821121
@@ -1104,3 +1143,38 @@ def offline_static(filename):
11041143
11051144 return Response (response = render_template ('static/%s' % filename ),
11061145 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 ()
0 commit comments