From d6361bee052bd472c36252a31c78ebbbbda7b14a Mon Sep 17 00:00:00 2001
From: Tzu-Mainn Chen <tzumainn@redhat.com>
Date: Tue, 7 Apr 2020 14:43:36 +0000
Subject: [PATCH] Added node multitenancy doc

Adds documentation surrounding the use of multi-tenancy. The
documentation explains possible updates to the policy file
to expose node APIs to a non-admin.

Change-Id: Ib1c327156acee8d34be74dd15c3d4003f7ef31df
---
 doc/source/admin/index.rst             |   1 +
 doc/source/admin/node-multitenancy.rst | 145 +++++++++++++++++++++++++
 doc/source/conf.py                     |   1 +
 3 files changed, 147 insertions(+)
 create mode 100644 doc/source/admin/node-multitenancy.rst

diff --git a/doc/source/admin/index.rst b/doc/source/admin/index.rst
index 90a36f124b..4815be3c3c 100644
--- a/doc/source/admin/index.rst
+++ b/doc/source/admin/index.rst
@@ -34,6 +34,7 @@ the services.
    Troubleshooting FAQ <troubleshooting>
    Power Sync with the Compute Service <power-sync>
    Agent Token <agent-token>
+   Node Multi-Tenancy <node-multitenancy>
 
 .. toctree::
   :hidden:
diff --git a/doc/source/admin/node-multitenancy.rst b/doc/source/admin/node-multitenancy.rst
new file mode 100644
index 0000000000..e6214049df
--- /dev/null
+++ b/doc/source/admin/node-multitenancy.rst
@@ -0,0 +1,145 @@
+==================
+Node Multi-Tenancy
+==================
+
+This guide explains the steps needed to enable node multi-tenancy. This
+feature enables non-admins to perform API actions on nodes, limited by
+policy configuration. The Bare Metal service supports two kinds of
+non-admin users:
+
+* Owner: owns specific nodes and performs administrative actions on them
+* Lessee: receives temporary and limited access to a node
+
+Setting the Owner and Lessee
+============================
+
+Non-administrative access to a node is controlled through a node's ``owner``
+or ``lessee`` attribute::
+
+  openstack baremetal node set --owner 080925ee2f464a2c9dce91ee6ea354e2  node-7
+  openstack baremetal node set --lessee 2a210e5ff114c8f2b6e994218f51a904  node-10
+
+
+Configuring the Bare Metal Service Policy
+=========================================
+
+By default, the Bare Metal service  policy is configured so that a node
+owner or lessee has no access to any node APIs. However, the policy
+:doc:`policy file </configuration/sample-policy>` contains rules that
+can be used to enable node API access::
+
+  # Owner of node
+  #"is_node_owner": "project_id:%(node.owner)s"
+
+  # Lessee of node
+  #"is_node_lessee": "project_id:%(node.lessee)s"
+
+An administrator can then modify the policy file to expose individual node
+APIs as follows::
+
+  # Change Node provision status
+  # PUT  /nodes/{node_ident}/states/provision
+  #"baremetal:node:set_provision_state": "rule:is_admin"
+  "baremetal:node:set_provision_state": "rule:is_admin or rule:is_node_owner or rule:is_node_lessee"
+
+  # Update Node records
+  # PATCH  /nodes/{node_ident}
+  #"baremetal:node:update": "rule:is_admin or rule:is_node_owner"
+
+In addition, it is safe to expose the ``baremetal:node:list`` rule, as the
+node list function now filters non-admins by owner and lessee::
+
+  # Retrieve multiple Node records, filtered by owner
+  # GET  /nodes
+  # GET  /nodes/detail
+  #"baremetal:node:list": "rule:baremetal:node:get"
+  "baremetal:node:list": ""
+
+Note that ``baremetal:node:list_all`` permits users to see all nodes
+regardless of owner/lessee, so it should remain restricted to admins.
+
+Ports
+-----
+
+Port APIs can be similarly exposed to node owners and lessees::
+
+  # Retrieve Port records
+  # GET  /ports/{port_id}
+  # GET  /nodes/{node_ident}/ports
+  # GET  /nodes/{node_ident}/ports/detail
+  # GET  /portgroups/{portgroup_ident}/ports
+  # GET  /portgroups/{portgroup_ident}/ports/detail
+  #"baremetal:port:get": "rule:is_admin or rule:is_observer"
+  "baremetal:port:get": "rule:is_admin or rule:is_observer or rule:is_node_owner or rule:is_node_lessee"
+
+  # Retrieve multiple Port records, filtered by owner
+  # GET  /ports
+  # GET  /ports/detail
+  #"baremetal:port:list": "rule:baremetal:port:get"
+  "baremetal:port:list": ""
+
+
+Allocations
+-----------
+
+Allocations respect node tenancy as well. A restricted allocation creates
+an allocation tied to a project, and that can only match nodes where that
+project is the owner or lessee. Here is a sample set of allocation policy
+rules that allow non-admins to use allocations effectively::
+
+  # Retrieve Allocation records
+  # GET  /allocations/{allocation_id}
+  # GET  /nodes/{node_ident}/allocation
+  #"baremetal:allocation:get": "rule:is_admin or rule:is_observer"
+  "baremetal:allocation:get": "rule:is_admin or rule:is_observer or rule:is_allocation_owner"
+
+  # Retrieve multiple Allocation records, filtered by owner
+  # GET  /allocations
+  #"baremetal:allocation:list": "rule:baremetal:allocation:get"
+  "baremetal:allocation:list": ""
+
+  # Retrieve multiple Allocation records
+  # GET  /allocations
+  #"baremetal:allocation:list_all": "rule:baremetal:allocation:get"
+
+  # Create Allocation records
+  # POST  /allocations
+  #"baremetal:allocation:create": "rule:is_admin"
+
+  # Create Allocation records that are restricted to an owner
+  # POST  /allocations
+  #"baremetal:allocation:create_restricted": "rule:baremetal:allocation:create"
+  "baremetal:allocation:create_restricted": ""
+
+  # Delete Allocation records
+  # DELETE  /allocations/{allocation_id}
+  # DELETE  /nodes/{node_ident}/allocation
+  #"baremetal:allocation:delete": "rule:is_admin"
+  "baremetal:allocation:delete": "rule:is_admin or rule:is_allocation_owner"
+
+  # Change name and extra fields of an allocation
+  # PATCH  /allocations/{allocation_id}
+  #"baremetal:allocation:update": "rule:is_admin"
+  "baremetal:allocation:update": "rule:is_admin or rule:is_allocation_owner"
+
+Deployment and Metalsmith
+-------------------------
+
+Provisioning a node requires a specific set of APIs to be made available.
+The following policy specifications are enough to allow a node owner to
+use :metalsmith-doc:`Metalsmith <index.html>` to deploy upon a node::
+
+  "baremetal:node:get": "rule:is_admin or rule:is_observer or rule:is_node_owner"
+  "baremetal:node:list": ""
+  "baremetal:node:update_extra": "rule:is_admin or rule:is_node_owner"
+  "baremetal:node:update_instance_info": "rule:is_admin or rule:is_node_owner"
+  "baremetal:node:validate": "rule:is_admin or rule:is_node_owner"
+  "baremetal:node:set_provision_state": "rule:is_admin or rule:is_node_owner"
+  "baremetal:node:vif:list": "rule:is_admin or rule:is_node_owner"
+  "baremetal:node:vif:attach": "rule:is_admin or rule:is_node_owner"
+  "baremetal:node:vif:detach": "rule:is_admin or rule:is_node_owner"
+  "baremetal:allocation:get": "rule:is_admin or rule:is_observer or rule:is_allocation_owner"
+  "baremetal:allocation:list": ""
+  "baremetal:allocation:create_restricted": ""
+  "baremetal:allocation:delete": "rule:is_admin or rule:is_allocation_owner"
+  "baremetal:allocation:update": "rule:is_admin or rule:is_allocation_owner"
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 02223e4bd8..ecbedec6ff 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -73,6 +73,7 @@ openstack_projects = [
     'ironic-ui',
     'keystone',
     'keystonemiddleware',
+    'metalsmith',
     'networking-baremetal',
     'neutron',
     'nova',