horizon/doc/source/topics/tables.rst
David Lyle 5984e34862 Adding RBAC policy system and checks for identity
Adding file based RBAC engine for Horizon using copies of nova and
keystone policy.json files

Policy engine builds on top of oslo incubator policy.py, fileutils
was also pulled from oslo incubator as a dependency of policy.py

When Horizon runs and a policy check is made, a path and mapping of
services to policy files is used to load the rules into the policy
engine.  Each check is mapped to a service type and validated.  This
extra level of mapping is required because the policy.json files
may each contain a 'default' rule or unqualified (no service name
include) rule.  Additionally, maintaining separate policy.json
files per service will allow easier syncing with the service
projects.

The engine allows for compound 'and' checks at this time.  E.g.,
the way the Create User action is written, multiple APIs are
called to read data (roles, projects) and more are required to
update data (grants, user).

Other workflows e.g., Edit Project,  should have separate save
actions per step as they are unrelated.  Only the applicable
policy checks to that step were added.  The separating unrelated
steps saves will should be future work.

The underlying engine supports more rule types that are used in the
underlying policy.json files.

Policy checks were added for all actions on tables in the Identity
Panel only.  And the service policy files imported are limited in
this commit to reduce scope of the change.

Additionally, changes were made to the base action class to add
support or setting policy rules and an overridable method for
determining the policy check target. This reduces the need for
redundant code in each action policy check.

Note, the benefit Horizon has is that the underlying APIs will
correct us if we get it wrong, so if a policy file is not found for
a particular service, permission is assumed and the actual API call
to the service will fail if the action isn't authorized for that user.

Finally, adding documentation regarding policy enforcement.

Implements: blueprint rbac

Change-Id: I4a4a71163186b973229a0461b165c16936bc10e5
2013-08-26 10:32:28 -06:00

6.1 KiB

DataTables Topic Guide

Horizon provides the horizon.tables module to provide a convenient, reusable API for building data-driven displays and interfaces. The core components of this API fall into three categories: DataTables, Actions, and Class-based Views.

For a detailed API information check out the DataTables Reference Guide </ref/tables>.

Tables

The majority of interface in a dashboard-style interface ends up being tabular displays of the various resources the dashboard interacts with. The ~horizon.tables.DataTable class exists so you don't have to reinvent the wheel each time.

Creating your own tables

Creating a table is fairly simple:

  1. Create a subclass of ~horizon.tables.DataTable.
  2. Define columns on it using ~horizon.tables.Column.
  3. Create an inner Meta class to contain the special options for this table.
  4. Define any actions for the table, and add them to ~horizon.tables.DataTableOptions.table_actions or ~horizon.tables.DataTableOptions.row_actions.

Examples of this can be found in any of the tables.py modules included in the reference modules under horizon.dashboards.

Connecting a table to a view

Once you've got your table set up the way you like it, the next step is to wire it up to a view. To make this as easy as possible Horizon provides the ~horizon.tables.DataTableView class-based view which can be subclassed to display your table with just a couple lines of code. At it's simplest it looks like this:

from horizon import tables
from .tables import MyTable


class MyTableView(tables.DataTableView):
    table_class = MyTable
    template_name = "my_app/my_table_view.html"

    def get_data(self):
        return my_api.objects.list()

In the template you would just need to include the following to render the table:

{{ table.render }}

That's it! Easy, right?

Actions

Actions comprise any manipulations that might happen on the data in the table or the table itself. For example, this may be the standard object CRUD, linking to related views based on the object's id, filtering the data in the table, or fetching updated data when appropriate.

When actions get run

There are two points in the request-response cycle in which actions can take place; prior to data being loaded into the table, and after the data is loaded. When you're using one of the pre-built class-based views for working with your tables the pseudo-workflow looks like this:

  1. The request enters view.
  2. The table class is instantiated without data.
  3. Any "preemptive" actions are checked to see if they should run.
  4. Data is fetched and loaded into the table.
  5. All other actions are checked to see if they should run.
  6. If none of the actions have caused an early exit from the view, the standard response from the view is returned (usually the rendered table).

The benefit of the multi-step table instantiation is that you can use preemptive actions which don't need access to the entire collection of data to save yourself on processing overhead, API calls, etc.

Basic actions

At their simplest, there are three types of actions: actions which act on the data in the table, actions which link to related resources, and actions that alter which data is displayed. These correspond to ~horizon.tables.Action, ~horizon.tables.LinkAction, and ~horizon.tables.FilterAction.

Writing your own actions generally starts with subclassing one of those action classes and customizing the designated attributes and methods.

Shortcut actions

There are several common tasks for which Horizon provides pre-built shortcut classes. These include ~horizon.tables.BatchAction, and ~horizon.tables.DeleteAction. Each of these abstracts away nearly all of the boilerplate associated with writing these types of actions and provides consistent error handling, logging, and user-facing interaction.

It is worth noting that BatchAction and DeleteAction are extensions of the standard Action class.

Preemptive actions

Action classes which have their ~horizon.tables.Action.preempt attribute set to True will be evaluated before any data is loaded into the table. As such, you must be careful not to rely on any table methods that require data, such as ~horizon.tables.DataTable.get_object_display or ~horizon.tables.DataTable.get_object_by_id. The advantage of preemptive actions is that you can avoid having to do all the processing, API calls, etc. associated with loading data into the table for actions which don't require access to that information.

Policy checks on actions

The ~horizon.tables.Action.policy_rules attribute, when set, will validate access to the action using the policy rules specified. The attribute is a list of scope/rule pairs. Where the scope is the service type defining the rule and the rule is a rule from the corresponding service policy.json file. The format of horizon.tables.Action.policy_rules looks like:

(("identity", "identity:get_user"),)

Multiple checks can be made for the same action by merely adding more tuples to the list. The policy check will use information stored in the session about the user and the result of ~horizon.tables.Action.get_policy_target (which can be overridden in the derived action class) to determine if the user can execute the action. If the user does not have access to the action, the action is not added to the table.

If ~horizon.tables.Action.policy_rules is not set, no policy checks will be made to determine if the action should be visible and will be displayed solely based on the result of ~horizon.tables.Action.allowed.

For more information on policy based Role Based Access Control see: Horizon Policy Enforcement (RBAC: Role Based Access Control) </topics/policy>.