Merge "Add ability to configure nfs_mount_options   - updated test pillars"
diff --git a/README.rst b/README.rst
index b93b061..1fa5f8c 100644
--- a/README.rst
+++ b/README.rst
@@ -29,6 +29,7 @@
         cross_az_attach: false
         workers: 8
         report_interval: 60
+        dhcp_domain: novalocal
         bind:
           public_address: 10.0.0.122
           public_name: openstack.domain.com
@@ -1063,19 +1064,21 @@
 ---------------------
 By default communication between Nova and Galera is unsecure.
 
+nova:
+  controller:
+    database:
+      x509:
+        enabled: True
+
 You able to set custom certificates in pillar:
-controller:
-  database:
-    x509:
-      enabled: True
 
 nova:
   controller:
     database:
       x509:
-        cacert (certificate content)
-        cert (certificate content)
-        key (certificate content)
+        cacert: (certificate content)
+        cert: (certificate content)
+        key: (certificate content)
 
 You can read more about it here:
     https://docs.openstack.org/security-guide/databases/database-access-control.html
diff --git a/nova/_ssl/mysql.sls b/nova/_ssl/mysql.sls
index 3f44e2a..3d715e9 100644
--- a/nova/_ssl/mysql.sls
+++ b/nova/_ssl/mysql.sls
@@ -1,10 +1,14 @@
 {% from "nova/map.jinja" import controller with context %}
 
+nova_ssl_mysql:
+  test.show_notification:
+    - text: "Running nova._ssl.mysql"
+
 {%- if controller.database.get('x509',{}).get('enabled',False) %}
 
-  {%- set ca_file=controller.database.x509.get('ca_file') %}
-  {%- set key_file=controller.database.x509.get('key_file') %}
-  {%- set cert_file=controller.database.x509.get('cert_file') %}
+  {%- set ca_file=controller.database.x509.ca_file %}
+  {%- set key_file=controller.database.x509.key_file %}
+  {%- set cert_file=controller.database.x509.cert_file %}
 
 mysql_nova_ssl_x509_ca:
   {%- if controller.database.x509.cacert is defined %}
@@ -12,6 +16,8 @@
     - name: {{ ca_file }}
     - contents_pillar: nova:controller:database:x509:cacert
     - mode: 444
+    - user: nova
+    - group: nova
     - makedirs: true
   {%- else %}
   file.exists:
@@ -24,6 +30,8 @@
     - name: {{ cert_file }}
     - contents_pillar: nova:controller:database:x509:cert
     - mode: 440
+    - user: nova
+    - group: nova
     - makedirs: true
   {%- else %}
   file.exists:
@@ -36,13 +44,24 @@
     - name: {{ key_file }}
     - contents_pillar: nova:controller:database:x509:key
     - mode: 400
+    - user: nova
+    - group: nova
     - makedirs: true
   {%- else %}
   file.exists:
     - name: {{ key_file }}
   {%- endif %}
 
-{% elif controller.database.get('ssl',{}).get('enabled',False) %}
+mysql_nova_ssl_x509_set_user_and_group:
+  file.managed:
+    - names:
+      - {{ ca_file }}
+      - {{ cert_file }}
+      - {{ key_file }}
+    - user: nova
+    - group: nova
+
+  {% elif controller.database.get('ssl',{}).get('enabled',False) %}
 mysql_ca_nova_controller:
   {%- if controller.database.ssl.cacert is defined %}
   file.managed:
diff --git a/nova/compute.sls b/nova/compute.sls
index 1b8c149..4cfe44f 100644
--- a/nova/compute.sls
+++ b/nova/compute.sls
@@ -50,6 +50,19 @@
     - libvirtd
 {%- endif %}
 
+user_libvirt-qemu:
+  user.present:
+  - name: libvirt-qemu
+  - groups:
+    - nova
+
+/var/lib/nova:
+  file.directory:
+    - user: nova
+    - group: nova
+    - dir_mode: 0750
+    - makedirs: True
+
 /var/lib/nova/.ssh/id_rsa:
   file.managed:
   - user: nova
diff --git a/nova/controller.sls b/nova/controller.sls
index 19caa45..2b5d515 100644
--- a/nova/controller.sls
+++ b/nova/controller.sls
@@ -1,7 +1,5 @@
 {% from "nova/map.jinja" import controller with context %}
 
-{%- set mysql_x509_ssl_enabled = controller.database.get('x509',{}).get('enabled',False) or controller.database.get('ssl',{}).get('enabled',False) %}
-
 {%- if controller.get('enabled') %}
 
 include:
@@ -12,9 +10,7 @@
   # TODO(vsaienko) we need to run online dbsync only once after upgrade
   # Move to appropriate upgrade phase
   - nova.db.online_sync
-  {%- if mysql_x509_ssl_enabled %}
   - nova._ssl.mysql
-  {%- endif %}
 
 {%- if grains.os_family == 'Debian' %}
 debconf-set-prerequisite:
@@ -64,6 +60,7 @@
   - system: True
   - require_in:
     - pkg: nova_controller_packages
+    - sls: nova._ssl.mysql
 {%- if controller.version not in ["juno", "kilo", "liberty", "mitaka", "newton"] %}
     - pkg: nova_placement_package
 {%- endif %}
@@ -173,6 +170,7 @@
   - template: jinja
   - require:
     - pkg: nova_controller_packages
+    - sls: nova._ssl.mysql
   - require_in:
     - sls: nova.db.offline_sync
     - sls: nova.db.online_sync
@@ -216,6 +214,8 @@
     - template: jinja
     - user: nova
     - group: nova
+    - require_in:
+      - sls: nova.db.offline_sync
     - require:
       - pkg: nova_controller_packages
 {%- if controller.logging.log_handlers.get('fluentd').get('enabled', False) %}
@@ -432,9 +432,7 @@
   {%- endif %}
   - require:
     - sls: nova.db.offline_sync
-    {%- if mysql_x509_ssl_enabled %}
     - sls: nova._ssl.mysql
-    {%- endif %}
   - watch:
     - file: /etc/nova/nova.conf
     - file: /etc/nova/api-paste.ini
@@ -451,11 +449,9 @@
   {%- endif %}
   - require:
     - sls: nova.db.offline_sync
+    - sls: nova._ssl.mysql
   - require_in:
     - sls: nova.db.online_sync
-    {%- if mysql_x509_ssl_enabled %}
-    - sls: nova._ssl.mysql
-    {%- endif %}
   - watch:
     - file: /etc/nova/nova.conf
     - file: /etc/nova/api-paste.ini
diff --git a/nova/files/grafana_dashboards/openstack_tenants_prometheus.json b/nova/files/grafana_dashboards/openstack_tenants_prometheus.json
new file mode 100644
index 0000000..607524e
--- /dev/null
+++ b/nova/files/grafana_dashboards/openstack_tenants_prometheus.json
@@ -0,0 +1,971 @@
+{%- raw %}
+{
+  "annotations": {
+    "list": [
+      {
+        "$$hashKey": "object:3956",
+        "builtIn": 1,
+        "datasource": "prometheus",
+        "enable": true,
+        "hide": true,
+        "iconColor": "rgba(0, 211, 255, 1)",
+        "limit": 100,
+        "name": "Annotations & Alerts",
+        "showIn": 0,
+        "type": "dashboard"
+      }
+    ]
+  },
+  "editable": true,
+  "gnetId": null,
+  "graphTooltip": 0,
+  "id": null,
+  "iteration": 1536224134023,
+  "links": [],
+  "panels": [
+    {
+      "collapsed": false,
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 0
+      },
+      "id": 38,
+      "panels": [],
+      "title": "Projects overview @ $project",
+      "type": "row"
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 12,
+        "x": 0,
+        "y": 1
+      },
+      "id": 36,
+      "legend": {
+        "alignAsTable": true,
+        "avg": false,
+        "current": true,
+        "hideEmpty": false,
+        "max": false,
+        "min": false,
+        "rightSide": true,
+        "show": true,
+        "sort": "current",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "$$hashKey": "object:4031",
+          "expr": "sum(libvirt_domain_info_virtual_cpus{project_name=~\"$project\"}) by (project_name)",
+          "format": "time_series",
+          "intervalFactor": 2,
+          "legendFormat": "{{project_name}} total",
+          "refId": "A"
+        },
+        {
+          "$$hashKey": "object:4032",
+          "expr": "sum(rate(libvirt_domain_info_cpu_time_seconds_total{project_name=~\"$project\"}[$rate_interval])) by (project_name)",
+          "format": "time_series",
+          "intervalFactor": 1,
+          "legendFormat": "{{project_name}} usage",
+          "refId": "B"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "CPU",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "decimals": null,
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": "0",
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 12,
+        "x": 12,
+        "y": 1
+      },
+      "id": 39,
+      "legend": {
+        "alignAsTable": true,
+        "avg": false,
+        "current": true,
+        "max": false,
+        "min": false,
+        "rightSide": true,
+        "show": true,
+        "sort": "current",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(libvirt_domain_info_memory_usage_bytes{project_name=~\"$project\"}) by (project_name)",
+          "format": "time_series",
+          "intervalFactor": 2,
+          "legendFormat": "{{project_name}}",
+          "refId": "A"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Memory Usage",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "decbytes",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": "0",
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 12,
+        "x": 0,
+        "y": 6
+      },
+      "id": 40,
+      "legend": {
+        "alignAsTable": true,
+        "avg": true,
+        "current": false,
+        "hideEmpty": false,
+        "max": false,
+        "min": false,
+        "rightSide": true,
+        "show": true,
+        "sort": "current",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(rate(libvirt_domain_block_stats_read_bytes_total{project_name=~\"$project\"}[$rate_interval])) by (project_name)",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "{{project_name}} read",
+          "refId": "A"
+        },
+        {
+          "expr": "sum(rate(libvirt_domain_block_stats_write_bytes_total{project_name=~\"$project\"}[$rate_interval])) by (project_name)",
+          "format": "time_series",
+          "intervalFactor": 2,
+          "legendFormat": "{{project_name}} write",
+          "refId": "C"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Disks I/O",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "Bps",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": "0",
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 12,
+        "x": 12,
+        "y": 6
+      },
+      "id": 41,
+      "legend": {
+        "alignAsTable": true,
+        "avg": true,
+        "current": false,
+        "hideEmpty": false,
+        "max": false,
+        "min": false,
+        "rightSide": true,
+        "show": true,
+        "sort": "current",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [
+        {
+          "alias": "/tx.*/",
+          "transform": "negative-Y"
+        }
+      ],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(rate(libvirt_domain_interface_stats_receive_bytes_total{project_name=~\"$project\"}[$rate_interval])) by (project_name)",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "{{project_name}} rx",
+          "refId": "A"
+        },
+        {
+          "expr": "sum(rate(libvirt_domain_interface_stats_transmit_bytes_total{project_name=~\"$project\"}[$rate_interval])) by (project_name)",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "{{project_name}} tx",
+          "refId": "C"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Network RX/TX",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "Bps",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "collapsed": false,
+      "gridPos": {
+        "h": 1,
+        "w": 24,
+        "x": 0,
+        "y": 11
+      },
+      "id": 43,
+      "panels": [],
+      "title": "Users overview @ $user",
+      "type": "row"
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 12,
+        "x": 0,
+        "y": 12
+      },
+      "id": 44,
+      "legend": {
+        "alignAsTable": true,
+        "avg": false,
+        "current": true,
+        "hideEmpty": false,
+        "max": false,
+        "min": false,
+        "rightSide": true,
+        "show": true,
+        "sort": "current",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "$$hashKey": "object:4174",
+          "expr": "sum(libvirt_domain_info_virtual_cpus{project_name=~\"$project\",user_name=~\"$user\"}) by (user_name)",
+          "format": "time_series",
+          "intervalFactor": 2,
+          "legendFormat": "{{user_name}} total",
+          "refId": "A"
+        },
+        {
+          "$$hashKey": "object:4196",
+          "expr": "sum(rate(libvirt_domain_info_cpu_time_seconds_total{project_name=~\"$project\",user_name=~\"$user\"}[$rate_interval])) by (user_name)",
+          "format": "time_series",
+          "intervalFactor": 1,
+          "legendFormat": "{{user_name}} usage",
+          "refId": "B"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "CPU",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "decimals": null,
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": "0",
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 12,
+        "x": 12,
+        "y": 12
+      },
+      "id": 45,
+      "legend": {
+        "alignAsTable": true,
+        "avg": false,
+        "current": true,
+        "max": false,
+        "min": false,
+        "rightSide": true,
+        "show": true,
+        "sort": "current",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(libvirt_domain_info_memory_usage_bytes{project_name=~\"$project\",user_name=~\"$user\"}) by (user_name)",
+          "format": "time_series",
+          "intervalFactor": 2,
+          "legendFormat": "{{user_name}}",
+          "refId": "A"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Memory Usage",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "decbytes",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": "0",
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 12,
+        "x": 0,
+        "y": 17
+      },
+      "id": 46,
+      "legend": {
+        "alignAsTable": true,
+        "avg": true,
+        "current": false,
+        "hideEmpty": false,
+        "max": false,
+        "min": false,
+        "rightSide": true,
+        "show": true,
+        "sort": "current",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(rate(libvirt_domain_block_stats_read_bytes_total{project_name=~\"$project\",user_name=~\"$user\"}[$rate_interval])) by (user_name)",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "{{user_name}} read",
+          "refId": "A"
+        },
+        {
+          "expr": "sum(rate(libvirt_domain_block_stats_write_bytes_total{project_name=~\"$project\",user_name=~\"$user\"}[$rate_interval])) by (user_name)",
+          "format": "time_series",
+          "intervalFactor": 2,
+          "legendFormat": "{{user_name}} write",
+          "refId": "C"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Disks I/O",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "Bps",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": "0",
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    },
+    {
+      "aliasColors": {},
+      "bars": false,
+      "dashLength": 10,
+      "dashes": false,
+      "datasource": null,
+      "fill": 1,
+      "gridPos": {
+        "h": 5,
+        "w": 12,
+        "x": 12,
+        "y": 17
+      },
+      "id": 47,
+      "legend": {
+        "alignAsTable": true,
+        "avg": true,
+        "current": false,
+        "hideEmpty": false,
+        "max": false,
+        "min": false,
+        "rightSide": true,
+        "show": true,
+        "sort": "current",
+        "sortDesc": true,
+        "total": false,
+        "values": true
+      },
+      "lines": true,
+      "linewidth": 1,
+      "links": [],
+      "nullPointMode": "null",
+      "percentage": false,
+      "pointradius": 5,
+      "points": false,
+      "renderer": "flot",
+      "seriesOverrides": [
+        {
+          "alias": "/tx.*/",
+          "transform": "negative-Y"
+        }
+      ],
+      "spaceLength": 10,
+      "stack": false,
+      "steppedLine": false,
+      "targets": [
+        {
+          "expr": "sum(rate(libvirt_domain_interface_stats_receive_bytes_total{project_name=~\"$project\",user_name=~\"$user\"}[$rate_interval])) by (user_name)",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "{{user_name}} rx",
+          "refId": "A"
+        },
+        {
+          "expr": "sum(rate(libvirt_domain_interface_stats_transmit_bytes_total{project_name=~\"$project\",user_name=~\"$user\"}[$rate_interval])) by (user_name)",
+          "format": "time_series",
+          "instant": false,
+          "intervalFactor": 2,
+          "legendFormat": "{{user_name}} tx",
+          "refId": "C"
+        }
+      ],
+      "thresholds": [],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Network RX/TX",
+      "tooltip": {
+        "shared": true,
+        "sort": 0,
+        "value_type": "individual"
+      },
+      "type": "graph",
+      "xaxis": {
+        "buckets": null,
+        "mode": "time",
+        "name": null,
+        "show": true,
+        "values": []
+      },
+      "yaxes": [
+        {
+          "format": "Bps",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        },
+        {
+          "format": "short",
+          "label": null,
+          "logBase": 1,
+          "max": null,
+          "min": null,
+          "show": true
+        }
+      ],
+      "yaxis": {
+        "align": false,
+        "alignLevel": null
+      }
+    }
+  ],
+  "refresh": "1m",
+  "schemaVersion": 16,
+  "style": "dark",
+  "tags": [
+    "openstack"
+  ],
+  "templating": {
+    "list": [
+      {
+        "allValue": null,
+        "current": {
+          "tags": [],
+          "text": "admin",
+          "value": [
+            "admin"
+          ]
+        },
+        "datasource": "prometheus",
+        "hide": 0,
+        "includeAll": false,
+        "label": null,
+        "multi": true,
+        "name": "project",
+        "options": [],
+        "query": "label_values(libvirt_domain_info_virtual_cpus,project_name)",
+        "refresh": 1,
+        "regex": "",
+        "sort": 1,
+        "tagValuesQuery": "",
+        "tags": [],
+        "tagsQuery": "",
+        "type": "query",
+        "useTags": false
+      },
+      {
+        "allValue": null,
+        "current": {
+          "selected": false,
+          "tags": [],
+          "text": "admin",
+          "value": [
+            "admin"
+          ]
+        },
+        "datasource": "prometheus",
+        "hide": 0,
+        "includeAll": true,
+        "label": null,
+        "multi": true,
+        "name": "user",
+        "options": [],
+        "query": "label_values(libvirt_domain_info_virtual_cpus{project_name=~\"$project\"},user_name)",
+        "refresh": 1,
+        "regex": "",
+        "sort": 1,
+        "tagValuesQuery": "",
+        "tags": [],
+        "tagsQuery": "",
+        "type": "query",
+        "useTags": false
+      },
+      {
+        "allValue": null,
+        "current": {
+          "tags": [],
+          "text": "3m",
+          "value": "3m"
+        },
+        "hide": 0,
+        "includeAll": false,
+        "label": null,
+        "multi": false,
+        "name": "rate_interval",
+        "options": [
+          {
+            "$$hashKey": "object:4409",
+            "selected": false,
+            "text": "1m",
+            "value": "1m"
+          },
+          {
+            "$$hashKey": "object:4410",
+            "selected": true,
+            "text": "3m",
+            "value": "3m"
+          },
+          {
+            "$$hashKey": "object:4411",
+            "selected": false,
+            "text": "5m",
+            "value": "5m"
+          },
+          {
+            "$$hashKey": "object:4412",
+            "selected": false,
+            "text": "10m",
+            "value": "10m"
+          },
+          {
+            "$$hashKey": "object:4413",
+            "selected": false,
+            "text": "15m",
+            "value": "15m"
+          }
+        ],
+        "query": "1m,3m,5m,10m,15m",
+        "type": "custom"
+      }
+    ]
+  },
+  "time": {
+    "from": "now-1h",
+    "to": "now"
+  },
+  "timepicker": {
+    "refresh_intervals": [
+      "5s",
+      "10s",
+      "30s",
+      "1m",
+      "5m",
+      "15m",
+      "30m",
+      "1h",
+      "2h",
+      "1d"
+    ],
+    "time_options": [
+      "5m",
+      "15m",
+      "1h",
+      "6h",
+      "12h",
+      "24h",
+      "2d",
+      "7d",
+      "30d"
+    ]
+  },
+  "timezone": "",
+  "title": "Openstack - Tenants",
+  "uid": null,
+  "version": 1
+}
+{%- endraw %}
diff --git a/nova/files/juno/nova-compute.conf.Debian b/nova/files/juno/nova-compute.conf.Debian
index b5693e7..7f2e4a0 100644
--- a/nova/files/juno/nova-compute.conf.Debian
+++ b/nova/files/juno/nova-compute.conf.Debian
@@ -100,8 +100,8 @@
 rpc_thread_pool_size = 70
 report_interval = 5
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ compute.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ compute.get('block_device_allocate_retries_interval', '10') }}
 
 resume_guests_state_on_host_boot = True
 service_down_time = 90
diff --git a/nova/files/juno/nova-controller.conf.Debian b/nova/files/juno/nova-controller.conf.Debian
index 0cdffdc..2f886fe 100644
--- a/nova/files/juno/nova-controller.conf.Debian
+++ b/nova/files/juno/nova-controller.conf.Debian
@@ -127,8 +127,8 @@
 rpc_thread_pool_size = 70
 report_interval = 5
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ controller.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ controller.get('block_device_allocate_retries_interval', '10') }}
 
 [keystone_authtoken]
 signing_dirname=/tmp/keystone-signing-nova
diff --git a/nova/files/kilo/nova-compute.conf.Debian b/nova/files/kilo/nova-compute.conf.Debian
index d76e9a1..8d17f05 100644
--- a/nova/files/kilo/nova-compute.conf.Debian
+++ b/nova/files/kilo/nova-compute.conf.Debian
@@ -89,8 +89,8 @@
 rpc_thread_pool_size = 70
 report_interval = {{ compute.get('report_interval', '60') }}
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ compute.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ compute.get('block_device_allocate_retries_interval', '10') }}
 
 resume_guests_state_on_host_boot = True
 service_down_time = 90
diff --git a/nova/files/kilo/nova-controller.conf.Debian b/nova/files/kilo/nova-controller.conf.Debian
index 64a40d8..29ba5ca 100644
--- a/nova/files/kilo/nova-controller.conf.Debian
+++ b/nova/files/kilo/nova-controller.conf.Debian
@@ -116,8 +116,8 @@
 rpc_thread_pool_size = 70
 report_interval = 5
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ controller.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ controller.get('block_device_allocate_retries_interval', '10') }}
 
 [oslo_concurrency]
 
diff --git a/nova/files/liberty/nova-compute.conf.Debian b/nova/files/liberty/nova-compute.conf.Debian
index de611f7..5369573 100644
--- a/nova/files/liberty/nova-compute.conf.Debian
+++ b/nova/files/liberty/nova-compute.conf.Debian
@@ -97,8 +97,8 @@
 rpc_thread_pool_size = 70
 report_interval = {{ compute.get('report_interval', '60') }}
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ compute.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ compute.get('block_device_allocate_retries_interval', '10') }}
 
 resume_guests_state_on_host_boot = {{ compute.get('resume_guests_state_on_host_boot', True) }}
 service_down_time = 90
diff --git a/nova/files/liberty/nova-controller.conf.Debian b/nova/files/liberty/nova-controller.conf.Debian
index 64d8c85..392b48c 100644
--- a/nova/files/liberty/nova-controller.conf.Debian
+++ b/nova/files/liberty/nova-controller.conf.Debian
@@ -111,8 +111,8 @@
 rpc_thread_pool_size = 70
 report_interval = 5
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ controller.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ controller.get('block_device_allocate_retries_interval', '10') }}
 
 [oslo_concurrency]
 
diff --git a/nova/files/mitaka/nova-compute.conf.Debian b/nova/files/mitaka/nova-compute.conf.Debian
index 4b22b31..0563049 100644
--- a/nova/files/mitaka/nova-compute.conf.Debian
+++ b/nova/files/mitaka/nova-compute.conf.Debian
@@ -74,8 +74,8 @@
 executor_thread_pool_size = 70
 report_interval = {{ compute.get('report_interval', '60') }}
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ compute.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ compute.get('block_device_allocate_retries_interval', '10') }}
 
 resume_guests_state_on_host_boot = {{ compute.get('resume_guests_state_on_host_boot', True) }}
 service_down_time = 90
diff --git a/nova/files/mitaka/nova-controller.conf.Debian b/nova/files/mitaka/nova-controller.conf.Debian
index 5f568da..d5c4e65 100644
--- a/nova/files/mitaka/nova-controller.conf.Debian
+++ b/nova/files/mitaka/nova-controller.conf.Debian
@@ -15,6 +15,9 @@
 dhcpbridge = /usr/bin/nova-dhcpbridge
 dhcpbridge_flagfile = /etc/nova/nova.conf
 force_dhcp_release = True
+{%- if controller.dhcp_domain is defined %}
+dhcp_domain = {{ controller.dhcp_domain }}
+{%- endif %}
 injected_network_template = /usr/share/nova/interfaces.template
 libvirt_nonblocking = True
 vif_plugging_is_fatal = False
@@ -73,8 +76,8 @@
 rpc_thread_pool_size = 70
 report_interval = 5
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ controller.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ controller.get('block_device_allocate_retries_interval', '10') }}
 
 {%- if controller.host is defined %}
 host={{ controller.host }}
diff --git a/nova/files/newton/nova-compute.conf.Debian b/nova/files/newton/nova-compute.conf.Debian
index b0d8f9c..69e48e8 100644
--- a/nova/files/newton/nova-compute.conf.Debian
+++ b/nova/files/newton/nova-compute.conf.Debian
@@ -93,8 +93,8 @@
 executor_thread_pool_size = 70
 report_interval = {{ compute.get('report_interval', '60') }}
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ compute.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ compute.get('block_device_allocate_retries_interval', '10') }}
 
 resume_guests_state_on_host_boot = {{ compute.get('resume_guests_state_on_host_boot', True) }}
 service_down_time = 90
diff --git a/nova/files/newton/nova-controller.conf.Debian b/nova/files/newton/nova-controller.conf.Debian
index 26c38a1..124b5d7 100644
--- a/nova/files/newton/nova-controller.conf.Debian
+++ b/nova/files/newton/nova-controller.conf.Debian
@@ -15,6 +15,9 @@
 dhcpbridge = /usr/bin/nova-dhcpbridge
 dhcpbridge_flagfile = /etc/nova/nova.conf
 force_dhcp_release = True
+{%- if controller.dhcp_domain is defined %}
+dhcp_domain = {{ controller.dhcp_domain }}
+{%- endif %}
 injected_network_template = /usr/share/nova/interfaces.template
 libvirt_nonblocking = True
 vif_plugging_is_fatal = False
@@ -80,8 +83,8 @@
 rpc_thread_pool_size = 70
 report_interval = 5
 
-block_device_allocate_retries=600
-block_device_allocate_retries_interval=10
+block_device_allocate_retries={{ controller.get('block_device_allocate_retries', '600') }}
+block_device_allocate_retries_interval={{ controller.get('block_device_allocate_retries_interval', '10') }}
 
 {%- set rabbit_port = controller.message_queue.get('port', 5671 if controller.message_queue.get('ssl',{}).get('enabled', False) else 5672) %}
 
diff --git a/nova/files/ocata/nova-compute.conf.Debian b/nova/files/ocata/nova-compute.conf.Debian
index 2a8def4..7df3b8b 100644
--- a/nova/files/ocata/nova-compute.conf.Debian
+++ b/nova/files/ocata/nova-compute.conf.Debian
@@ -757,7 +757,7 @@
 # * For any value > 0, total attempts are (value + 1)
 #  (integer value)
 #block_device_allocate_retries=60
-block_device_allocate_retries=600
+block_device_allocate_retries={{ compute.get('block_device_allocate_retries', '600') }}
 
 #
 # Number of greenthreads available for use to sync power states.
@@ -961,7 +961,7 @@
 #  (integer value)
 # Minimum value: 0
 #block_device_allocate_retries_interval=3
-block_device_allocate_retries_interval=10
+block_device_allocate_retries_interval={{ compute.get('block_device_allocate_retries_interval', '10') }}
 
 #
 # Interval between sending the scheduler a list of current instance UUIDs to
diff --git a/nova/files/ocata/nova-controller.conf.Debian b/nova/files/ocata/nova-controller.conf.Debian
index e1042fa..6c568f9 100644
--- a/nova/files/ocata/nova-controller.conf.Debian
+++ b/nova/files/ocata/nova-controller.conf.Debian
@@ -708,7 +708,7 @@
 # * For any value > 0, total attempts are (value + 1)
 #  (integer value)
 #block_device_allocate_retries=60
-block_device_allocate_retries=600
+block_device_allocate_retries={{ controller.get('block_device_allocate_retries', '600') }}
 
 #
 # Number of greenthreads available for use to sync power states.
@@ -910,7 +910,7 @@
 #  (integer value)
 # Minimum value: 0
 #block_device_allocate_retries_interval=3
-block_device_allocate_retries_interval=10
+block_device_allocate_retries_interval={{ controller.get('block_device_allocate_retries_interval', '10') }}
 
 #
 # Interval between sending the scheduler a list of current instance UUIDs to
@@ -2272,6 +2272,9 @@
 # Reason:
 # nova-network is deprecated, as are any related configuration options.
 #dhcp_domain=novalocal
+{%- if controller.dhcp_domain is defined %}
+dhcp_domain = {{ controller.dhcp_domain }}
+{%- endif %}
 
 # DEPRECATED:
 # This option allows you to specify the L3 management library to be used.
diff --git a/nova/files/pike/nova-compute.conf.Debian b/nova/files/pike/nova-compute.conf.Debian
index 4a65aa2..35ec91a 100644
--- a/nova/files/pike/nova-compute.conf.Debian
+++ b/nova/files/pike/nova-compute.conf.Debian
@@ -761,7 +761,7 @@
 # * For any value > 0, total attempts are (value + 1)
 #  (integer value)
 #block_device_allocate_retries=60
-block_device_allocate_retries=600
+block_device_allocate_retries={{ compute.get('block_device_allocate_retries', '600') }}
 
 #
 # Number of greenthreads available for use to sync power states.
@@ -965,7 +965,7 @@
 #  (integer value)
 # Minimum value: 0
 #block_device_allocate_retries_interval=3
-block_device_allocate_retries_interval=10
+block_device_allocate_retries_interval={{ compute.get('block_device_allocate_retries_interval', '10') }}
 
 #
 # Interval between sending the scheduler a list of current instance UUIDs to
diff --git a/nova/files/pike/nova-controller.conf.Debian b/nova/files/pike/nova-controller.conf.Debian
index 940e71f..34451c2 100644
--- a/nova/files/pike/nova-controller.conf.Debian
+++ b/nova/files/pike/nova-controller.conf.Debian
@@ -2,7 +2,7 @@
 
 {%- set connection_x509_ssl_option = '' %}
 {%- if controller.database.get('x509',{}).get('enabled',False) %}
-  {%- set connection_x509_ssl_option = '&ssl_ca=' ~ controller.database.x509.get('ca_file') ~ '&ssl_cert=' ~ controller.database.x509.get('cert_file') ~ '&ssl_key=' ~ controller.database.x509.get('key_file') %}
+  {%- set connection_x509_ssl_option = '&ssl_ca=' ~ controller.database.x509.ca_file ~ '&ssl_cert=' ~ controller.database.x509.cert_file ~ '&ssl_key=' ~ controller.database.x509.key_file %}
 {%- elif controller.database.get('ssl',{}).get('enabled',False) %}
   {%- set connection_x509_ssl_option = '&ssl_ca=' ~ controller.database.ssl.get('cacert_file', controller.cacert_file) %}
 {%- endif %}
@@ -721,7 +721,7 @@
 # * For any value > 0, total attempts are (value + 1)
 #  (integer value)
 #block_device_allocate_retries=60
-block_device_allocate_retries=600
+block_device_allocate_retries={{ controller.get('block_device_allocate_retries', '600') }}
 
 #
 # Number of greenthreads available for use to sync power states.
@@ -923,7 +923,7 @@
 #  (integer value)
 # Minimum value: 0
 #block_device_allocate_retries_interval=3
-block_device_allocate_retries_interval=10
+block_device_allocate_retries_interval={{ controller.get('block_device_allocate_retries_interval', '10') }}
 
 #
 # Interval between sending the scheduler a list of current instance UUIDs to
@@ -3447,7 +3447,7 @@
 db_retry_interval = 1
 connection_debug = 10
 pool_timeout = 120
-connection = {{ controller.database.engine }}+pymysql://{{ controller.database.user }}:{{ controller.database.password }}@{{ controller.database.host }}/{{ controller.database.name }}_api?charset=utf8{{ connection_x509_ssl_option }}
+connection = {{ controller.database.engine }}+pymysql://{{ controller.database.user }}:{{ controller.database.password }}@{{ controller.database.host }}/{{ controller.database.name }}_api?charset=utf8{{ connection_x509_ssl_option|string }}
 
 # The SQLAlchemy connection string to use to connect to the database. (string
 # value)
@@ -4496,7 +4496,7 @@
 db_retry_interval = 1
 connection_debug = 10
 pool_timeout = 120
-connection = {{ controller.database.engine }}+pymysql://{{ controller.database.user }}:{{ controller.database.password }}@{{ controller.database.host }}/{{ controller.database.name }}?charset=utf8{{ connection_x509_ssl_option }}
+connection = {{ controller.database.engine }}+pymysql://{{ controller.database.user }}:{{ controller.database.password }}@{{ controller.database.host }}/{{ controller.database.name }}?charset=utf8{{ connection_x509_ssl_option|string }}
 
 # If True, SQLite uses synchronous mode. (boolean value)
 # Deprecated group/name - [DEFAULT]/sqlite_synchronous
diff --git a/nova/meta/grafana.yml b/nova/meta/grafana.yml
index 0fc3ac3..b189d5e 100644
--- a/nova/meta/grafana.yml
+++ b/nova/meta/grafana.yml
@@ -34,6 +34,10 @@
     datasource: prometheus
     format: json
     template: nova/files/grafana_dashboards/openstack_overview_prometheus.json
+  openstack_tenants_prometheus:
+    datasource: prometheus
+    format: json
+    template: nova/files/grafana_dashboards/openstack_tenants_prometheus.json
   nova_influxdb:
     datasource: influxdb
     format: json