def puppet_nodes(): """Handles the Puppet nodes list page""" # Check user permissions if not does_user_have_permission("puppet.nodes.view"): abort(403) # Get a cursor to the database curd = g.db.cursor(mysql.cursors.DictCursor) # Get Puppet nodes from the database curd.execute( "SELECT `puppet_nodes`.`certname` AS `certname`, `puppet_nodes`.`env` AS `env`, `systems`.`id` AS `id`, `systems`.`name` AS `name` FROM `puppet_nodes` LEFT JOIN `systems` ON `puppet_nodes`.`id` = `systems`.`id` ORDER BY `puppet_nodes`.`certname` " ) results = curd.fetchall() # Get node statuses try: statuses = cortex.lib.puppet.puppetdb_get_node_statuses() except Exception as ex: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(ex).__name__ + " - " + str(ex), ) for row in results: if row["certname"] in statuses: row["status"] = statuses[row["certname"]] else: row["status"] = "unknown" # Render return render_template("puppet/nodes.html", active="puppet", data=results, title="Puppet Nodes")
def puppet_dashboard_status(status): """This view is responsible for listing puppet nodes but only those matching a certain status in PuppetDB.""" # Check user permissions (note this is the nodes permission rather than dashboard) if not does_user_have_permission("puppet.nodes.view"): abort(403) # For the purposes of the dashboard, unreported is the same as unknown if status == "unreported": status = "unknown" # Page Titles to use page_title_map = { "unchanged": "Normal", "changed": "Changed", "noop": "Disabled", "failed": "Failed", "unknown": "Unknown/Unreported", "all": "Registered", } # If we have an invalid status, return 404 if status not in page_title_map: abort(404) # Connect to PuppetDB try: db = cortex.lib.puppet.puppetdb_connect() except Exception as ex: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(ex).__name__ + " - " + str(ex), ) # Get information about all the nodes, including their status nodes = db.nodes(with_status=True) # Create a filterd array nodes_of_type = [] # Iterate over nodes and do the filtering if status != "all": for node in nodes: # If the status matches... if node.status == status: nodes_of_type.append(node) # Or if the required status is 'unknown' and it's not one of the normal statii elif status == "unknown" and node.status not in ["unchanged", "changed", "noop", "failed"]: nodes_of_type.append(node) else: nodes_of_type = nodes return render_template( "puppet/dashboard-status.html", active="puppet", title="Puppet Dashboard", nodes=nodes_of_type, status=page_title_map[status], )
def error500(error): # Record the error in the log logerr() # Return a standard error page return stderr("Internal Error","An internal server error occured",500)
def puppet_radiator(): """Handles the Puppet radiator view page. Similar to the dashboard.""" ## No permissions check: this is accessible without logging in try: stats = cortex.lib.puppet.puppetdb_get_node_stats() except Exception as ex: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(ex).__name__ + " - " + str(ex), ) return render_template("puppet/radiator.html", stats=stats, active="puppet")
def puppet_dashboard(): """Handles the Puppet dashboard page.""" # Check user permissions if not does_user_have_permission("puppet.dashboard.view"): abort(403) try: stats = cortex.lib.puppet.puppetdb_get_node_stats() except Exception as ex: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(ex).__name__ + " - " + str(ex), ) return render_template("puppet/dashboard.html", stats=stats, active="puppet", title="Puppet Dashboard")
def puppet_report(report_hash): """Displays an individual report for a Puppet node""" # Connect to Puppet DB and query for a report with the given hash try: db = cortex.lib.puppet.puppetdb_connect() except Exception as ex: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(ex).__name__ + " - " + str(ex), ) reports = db.reports(query='["=", "hash", "' + report_hash + '"]') # 'reports' is a generator. Get the next (first and indeed, only item) from the generator try: report = next(reports) except StopIteration, e: # If we get a StopIteration error, then we've not got any data # returned from the reports generator, so the report didn't # exist, hence we should 404 return abort(404)
def puppet_radiator(): """Handles the Puppet radiator view page. Similar to the dashboard.""" ## No permissions check: this is accessible without logging in try: stats = cortex.lib.puppet.puppetdb_get_node_stats() except Exception as e: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(e).__name__ + " - " + str(e)) # create dictionary to hold the values the radiator needs top_level_stats = {} for s in stats: #'count' value in the dictionary is the value we need top_level_stats[s] = stats[s]['count'] return render_template('puppet/radiator.html', stats=top_level_stats, active='puppet')
def puppet_dashboard(): """Handles the Puppet dashboard page.""" # Check user permissions if not does_user_have_permission("puppet.dashboard.view"): abort(403) environments = cortex.lib.puppet.get_puppet_environments() try: stats = cortex.lib.puppet.puppetdb_get_node_stats( environments=[env["environment_name"] for env in environments], ) except Exception as ex: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(ex).__name__ + " - " + str(ex)) return render_template('puppet/dashboard.html', title="Puppet Dashboard", active="puppet", stats=stats)
def puppet_reports(node): """Handles the Puppet reports page for a node""" # Get the system (we need to know the ID for permissions checking) system = cortex.lib.systems.get_system_by_puppet_certname(node) if system is None: abort(404) ## Check if the user is allowed to view the reports of this node if not does_user_have_system_permission(system['id'], "view.puppet", "systems.all.view.puppet"): abort(403) try: # Connect to PuppetDB and get the reports db = cortex.lib.puppet.puppetdb_connect() reports = db.node(node).reports() except HTTPError as he: # If we get a 404 response from PuppetDB if he.response.status_code == 404: # Still display the page but with a nice error reports = None else: raise (he) except Exception as e: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(e).__name__ + " - " + str(e)) return render_template('puppet/reports.html', reports=reports, active='puppet', title=node + " - Puppet Reports", nodename=node, pactive="reports", system=system)
def error_handler(error): """Handles generic exceptions within the application, displaying the traceback if the application is running in debug mode.""" # Record the error in the log logerr() ## If we're handling a workflow view handler we don't need to show the fatal ## error screen, instead we'll use a standard error screen. the fatal error ## screen exists in case a flaw occurs which prevents rendering of the ## layout - but that can't happen with a workflow. if 'workflow' in g: if g.workflow: app.logger.warn("Workflow error occured") return stderr("Workflow error","An error occured in the workflow function - " + type(error).__name__ + ": " + str(error)) # Get the traceback if app.debug: debug = traceback.format_exc() else: debug = "Ask your system administrator to consult the error log for this application." # Output a fatal error return fatalerr(debug=debug)
dbnode = None facts = None try: # Connect to PuppetDB, get the node information and then it's related facts db = cortex.lib.puppet.puppetdb_connect() dbnode = db.node(node) facts = dbnode.facts() except HTTPError, he: # If we get a 404 from the PuppetDB API if he.response.status_code == 404: # We will continue to render the page, just with no facts and display a nice error facts = None else: raise(he) except Exception, e: return stderr("Unable to connect to PuppetDB","Unable to connect to the Puppet database. The error was: " + type(ex).__name__ + " - " + str(ex)) # Turn the facts generator in to a dictionary facts_dict = {} if facts != None: for fact in facts: facts_dict[fact.name] = fact.value # Load the system data - we don't care if it fails (i.e its not in the systems table) system = cortex.lib.systems.get_system_by_puppet_certname(node) # Render return render_template('puppet/facts.html', facts=facts_dict, node=dbnode, active='puppet', title=node + " - Puppet Facts", nodename=node, pactive="facts", system=system)
def error403(error): return stderr( "Permission Denied", "You do not have permission to access that page or perform that action.", 403, template="no.html")
def error400(error): return stderr("Bad Request", "Your request was invalid", 400)
def error405(error): return stderr("Not allowed", "Your web browser sent the wrong HTTP method", 405, template="no.html")
def error404(error): return stderr("Not found", "I could not find what you requested", 404)
facts = None try: # Connect to PuppetDB, get the node information and then it's related facts db = cortex.lib.puppet.puppetdb_connect() dbnode = db.node(node) facts = dbnode.facts() except HTTPError, he: # If we get a 404 from the PuppetDB API if he.response.status_code == 404: # We will continue to render the page, just with no facts and display a nice error facts = None else: raise (he) except Exception, e: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(ex).__name__ + " - " + str(ex), ) # Turn the facts generator in to a dictionary facts_dict = {} if facts != None: for fact in facts: facts_dict[fact.name] = fact.value # Load the system data - we don't care if it fails (i.e its not in the systems table) system = cortex.lib.systems.get_system_by_puppet_certname(node) # Render return render_template( "puppet/facts.html",
def error400(error): return stderr("Bad Request","Your request was invalid",400)
def error403(error): return stderr("Permission Denied","You do not have permission to access that page or perform that action.",403,template="no.html")
def error404(error): return stderr("Not found","I could not find what you requested",404)
def puppet_nodes(status=None): """Handles the Puppet nodes list page""" # Check user permissions if not does_user_have_permission("puppet.nodes.view"): abort(403) # Get a cursor to the database curd = g.db.cursor(mysql.cursors.DictCursor) # Get Puppet nodes from the database curd.execute( 'SELECT `puppet_nodes`.`certname` AS `certname`, `puppet_nodes`.`env` AS `env`, `systems`.`id` AS `id`, `systems`.`name` AS `name`, `systems`.`allocation_comment` AS `allocation_comment` FROM `puppet_nodes` LEFT JOIN `systems` ON `puppet_nodes`.`id` = `systems`.`id` ORDER BY `puppet_nodes`.`certname` ' ) results = curd.fetchall() # Get node statuses try: statuses = cortex.lib.puppet.puppetdb_get_node_statuses() except Exception as e: return stderr( "Unable to connect to PuppetDB", "Unable to connect to the Puppet database. The error was: " + type(e).__name__ + " - " + str(e)) data = [] for row in results: if row['certname'] in statuses: row['status'] = statuses[row['certname']]['status'] row['clientnoop'] = statuses[row['certname']]['clientnoop'] else: row['status'] = 'unknown' row['clientnoop'] = 'unknown' if status == None or status == 'all': data.append(row) elif status == 'unchanged' and row['status'] == 'unchanged': data.append(row) elif status == 'changed' and row['status'] == 'changed': data.append(row) elif status == 'noop' and row['status'] == 'noop': data.append(row) elif status == 'failed' and row['status'] == 'failed': data.append(row) elif status == 'unknown' and row['status'] not in [ 'unchanged', 'changed', 'noop', 'failed' ]: data.append(row) # Page Title Map title = 'Puppet Nodes' page_title_map = { 'unchanged': 'Normal', 'changed': 'Changed', 'noop': 'Disabled', 'failed': 'Failed', 'unknown': 'Unknown/Unreported', 'all': 'Registered' } if status != None and status in page_title_map: title = title + ' - {}'.format(page_title_map.get(status)) # Render return render_template('puppet/nodes.html', active='puppet', data=data, title=title, hide_unknown=True)
def puppet_environments(environment_id=None): """Show the Puppet documentation""" # Handle POST request if request.method == "POST" and all(k in request.form for k in ["action", "environment_id"]): environment_id = request.form["environment_id"] if request.form["action"] == "delete_environment": if not does_user_have_puppet_permission( environment_id, "delete", "puppet.environments.all.delete"): abort(403) elif "puppet" not in app.workflows: return stderr( "Unable to delete Puppet environment", "Error deleting Puppet environment, the workflow 'puppet' is required in order to delete Puppet environments, but was not found in app.workflows." ) else: # Task Options options = { "actions": [{ "id": "environment.delete", "desc": "Deleting Puppet Environment" }], "values": { "environment_id": environment_id }, } # Everything should be good - start a task. neocortex = cortex.lib.core.neocortex_connect() task_id = neocortex.create_task( "puppet", session["username"], options, description="Delete Puppet Environment") # Redirect to the status page for the task return redirect(url_for("task_status", task_id=task_id)) else: abort(400) # Handle GET request # Get the database cursor curd = g.db.cursor(mysql.cursors.DictCursor) environments, permissions, nodes = [], [], [] if environment_id and does_user_have_puppet_permission( environment_id, "view", "puppet.environments.all.view"): curd.execute( "SELECT * FROM `puppet_environments` WHERE `id`=%s LIMIT 1", (environment_id, )) environments = curd.fetchall() curd.execute( "SELECT * FROM `p_puppet_perms_view` WHERE `environment_id`=%s ORDER BY `who`", (environment_id, )) permissions = curd.fetchall() elif environment_id is None: if does_user_have_permission("puppet.environments.all.view"): environments = cortex.lib.puppet.get_puppet_environments() elif does_user_have_any_puppet_permission("view"): environments = cortex.lib.puppet.get_puppet_environments( environment_permission="view") else: abort(403) else: abort(403) # If no results could be found if not environments: abort(404) # If if environment_id: curd.execute( "SELECT `puppet_nodes`.`certname` AS `certname`, `puppet_nodes`.`env` AS `env`, `systems`.`id` AS `id`, `systems`.`name` AS `name`, `systems`.`allocation_comment` AS `allocation_comment` FROM `puppet_nodes` LEFT JOIN `systems` ON `puppet_nodes`.`id` = `systems`.`id` WHERE `puppet_nodes`.`env`=%s ORDER BY `puppet_nodes`.`certname`", (environments[0]["environment_name"], )) nodes = curd.fetchall() return render_template("puppet/environments.html", active="puppet", title="Puppet Environments", environment_id=environment_id, environments=environments, permissions=permissions, nodes=nodes)
def error405(error): return stderr("Not allowed","Your web browser sent the wrong HTTP method",405,template="no.html")