Merge "Unhardcode service user/group uid/gid values Warn to not change nova uid/gid values after user is created"
diff --git a/.kitchen.yml b/.kitchen.yml
index c3e27e9..418d93e 100644
--- a/.kitchen.yml
+++ b/.kitchen.yml
@@ -32,11 +32,7 @@
         "*":
           - linux_repo_openstack
           - nova
-    nova:
-      controller:
-        version: <%= ENV['OS_VERSION'] || 'mitaka' %>
-      compute:
-        version: <%= ENV['OS_VERSION'] || 'mitaka' %>
+          - release
   pillars-from-files:
     linux_repo_openstack.sls: tests/pillar/repo_mcp_openstack_<%= ENV['OS_VERSION'] || 'mitaka' %>.sls
 
@@ -56,10 +52,20 @@
     provisioner:
       pillars-from-files:
         nova.sls: tests/pillar/compute_cluster.sls
+      pillars:
+        release.sls:
+          nova:
+            compute:
+              version: <%= ENV['OS_VERSION'] || 'mitaka' %>
 
   - name: control_cluster
     provisioner:
       pillars-from-files:
         nova.sls: tests/pillar/control_cluster.sls
+      pillars:
+        release.sls:
+          nova:
+            controller:
+              version: <%= ENV['OS_VERSION'] || 'mitaka' %>
 
 # vim: ft=yaml sw=2 ts=2 sts=2 tw=125
diff --git a/README.rst b/README.rst
index 1ae8d07..db620b6 100644
--- a/README.rst
+++ b/README.rst
@@ -273,6 +273,25 @@
 Client role
 -----------
 
+Nova configured with NFS
+
+.. code-block:: yaml
+
+    nova:
+      compute:
+        instances_path: /mnt/nova/instances
+
+    linux:
+      storage:
+        enabled: true
+        mount:
+          nfs_nova:
+            enabled: true
+            path: ${nova:compute:instances_path}
+            device: 172.31.35.145:/data
+            file_system: nfs
+            opts: rw,vers=3
+
 Nova flavors
 
 .. code-block:: yaml
diff --git a/_states/novang.py b/_states/novang.py
index 3433d16..d5bcb35 100644
--- a/_states/novang.py
+++ b/_states/novang.py
@@ -68,13 +68,14 @@
     api_db_version = __salt__['cmd.shell']('nova-manage api_db version 2>/dev/null')
     try:
         api_db_version = int(api_db_version)
+        version = int(version)
     except:
         # nova is not installed
         ret = _no_change('api_db --version', None, test=True)
         return ret
     if api_db_version < version:
         try:
-            __salt__['cmd.shell']('nova-manage api_db sync --version ' + version)
+            __salt__['cmd.shell']('nova-manage api_db sync --version ' + str(version))
             ret['result'] = True
             ret['comment'] = 'Nova-manage api_db sync --version {0} was successfuly executed'.format(version)
             ret['changes']['api_db'] = 'api_db sync --version {0}'.format(version)
@@ -96,6 +97,7 @@
     db_version = __salt__['cmd.shell']('nova-manage db version 2>/dev/null')
     try:
         db_version = int(db_version)
+        version = int(version)
     except:
         # nova is not installed
         ret = _no_change('db --version', None, test=True)
@@ -103,7 +105,7 @@
 
     if db_version < version:
         try:
-            __salt__['cmd.shell']('nova-manage db sync --version ' + version)
+            __salt__['cmd.shell']('nova-manage db sync --version ' + str(version))
             ret['result'] = True
             ret['comment'] = 'Nova-manage db sync --version {0} was successfuly executed'.format(version)
             ret['changes']['db'] = 'db sync --version {0}'.format(version)
@@ -113,6 +115,37 @@
             ret['changes']['db'] = 'Failed to execute db sync --version {0}'.format(version)
     return ret
 
+def online_data_migrations_present(name=None, api_db_version="20", db_version="334"):
+    '''
+    Ensures that online_data_migrations are enforced if specific version of api_db and db is present
+    '''
+    ret = {'name': 'online_data_migrations',
+           'changes': {},
+           'result': True,
+           'comment': 'Current api_db version != {0} a db version != {1}.'.format(api_db_version, db_version)}
+    cur_api_db_version = __salt__['cmd.shell']('nova-manage api_db version 2>/dev/null')
+    cur_db_version = __salt__['cmd.shell']('nova-manage db version 2>/dev/null')
+    try:
+        cur_api_db_version = int(cur_api_db_version)
+        cur_db_version = int(cur_db_version)
+        api_db_version = int(api_db_version)
+        db_version = int(db_version)
+    except:
+        # nova is not installed
+        ret = _no_change('online_data_migrations', None, test=True)
+        return ret
+    if cur_api_db_version == api_db_version and cur_db_version == db_version:
+        try:
+            __salt__['cmd.shell']('nova-manage db online_data_migrations')
+            ret['result'] = True
+            ret['comment'] = 'nova-manage db online_data_migrations was successfuly executed'
+            ret['changes']['online_data_migrations'] = 'online_data_migrations on api_db version {0} and db version {1}'.format(api_db_version, db_version)
+        except:
+            ret['result'] = False
+            ret['comment'] = 'Error while executing nova-manage db online_data_migrations'
+            ret['changes']['online_data_migrations'] = 'Failed to execute online_data_migrations on api_db version {0} and db version {1}'.format(api_db_version, db_version)
+    return ret
+
 def quota_present(tenant_name, profile, name=None, **kwargs):
     '''
     Ensures that the nova quota exists
diff --git a/nova/compute.sls b/nova/compute.sls
index 178f770..f2e9f18 100644
--- a/nova/compute.sls
+++ b/nova/compute.sls
@@ -1,5 +1,6 @@
 {%- from "nova/map.jinja" import compute with context %}
-{%- if compute.enabled %}
+
+{%- if compute.get('enabled') %}
 
 nova_compute_packages:
   pkg.installed:
@@ -63,7 +64,7 @@
 
 {%- endif %}
 
-{%- if pillar.nova.controller is not defined %}
+{%- if not pillar.nova.get('controller',{}).get('enabled') %}
 /etc/nova/nova.conf:
   file.managed:
   - source: salt://nova/files/{{ compute.version }}/nova-compute.conf.{{ grains.os_family }}
diff --git a/nova/controller.sls b/nova/controller.sls
index 2b19ba1..73cc55d 100644
--- a/nova/controller.sls
+++ b/nova/controller.sls
@@ -1,6 +1,6 @@
 {% from "nova/map.jinja" import controller with context %}
 
-{%- if controller.enabled %}
+{%- if controller.get('enabled') %}
 
 {%- if grains.os_family == 'Debian' %}
 debconf-set-prerequisite:
@@ -71,6 +71,20 @@
   - require:
     - pkg: nova_controller_packages
 
+{% if controller.get('policy', {}) and controller.version not in ['liberty', 'mitaka', 'newton'] %}
+{# nova no longer ships with a default policy.json #}
+
+/etc/nova/policy.json:
+  file.managed:
+    - contents: '{}'
+    - replace: False
+    - user: nova
+    - group: nova
+    - require:
+      - pkg: nova_controller_packages
+
+{% endif %}
+
 {%- for name, rule in controller.get('policy', {}).iteritems() %}
 
 {%- if rule != None %}
@@ -81,6 +95,9 @@
   - rule: {{ rule }}
   - require:
     - pkg: nova_controller_packages
+    {% if controller.version not in ['liberty', 'mitaka', 'newton'] %}
+    - file: /etc/nova/policy.json
+    {% endif%}
 
 {%- else %}
 
@@ -90,6 +107,9 @@
   - name: {{ name }}
   - require:
     - pkg: nova_controller_packages
+    {% if controller.version not in ['liberty', 'mitaka', 'newton'] %}
+    - file: /etc/nova/policy.json
+    {% endif%}
 
 {%- endif %}
 
@@ -119,13 +139,29 @@
   - require:
     - file: /etc/nova/nova.conf
 
+{#- the following db online_data_migrations executes only if the current db version == 334 && api_db version == 20 #}
+
+online_data_migrations_for_apidb20_and_db334:
+  novang.online_data_migrations_present:
+  - api_db_version: "20"
+  - db_version: "334"
+  - require:
+    - novang: nova_controller_api_db_sync_version_20
+    - novang: nova_controller_db_sync_version_334
+
 nova_controller_map_cell0:
   cmd.run:
   - name: nova-manage cell_v2 map_cell0
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
 
 nova_cell1_create:
   cmd.run:
   - name: nova-manage cell_v2 create_cell --name=cell1
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - unless: 'nova-manage cell_v2 list_cells | grep cell1'
 
 nova_placement_service_mask:
@@ -155,6 +191,9 @@
 nova_controller_discover_hosts:
   cmd.run:
   - name: nova-manage cell_v2 discover_hosts
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - require:
     - cmd: nova_controller_map_cell0
     - cmd: nova_cell1_create
@@ -162,6 +201,9 @@
 nova_controller_map_instances:
   novang.map_instances:
   - name: 'cell1'
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - require:
     - cmd: nova_controller_discover_hosts
     - pkg: nova_controller_packages
@@ -184,6 +226,9 @@
   cmd.run:
   - names:
     - nova-manage db sync
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - require:
     - file: /etc/nova/nova.conf
 
@@ -192,6 +237,9 @@
 nova_controller_online_data_migrations:
   cmd.run:
   - name: nova-manage db online_data_migrations
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - require:
     - cmd: nova_controller_syncdb
 
@@ -203,6 +251,9 @@
   service.running:
   - enable: true
   - name: apache2
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - require:
     - cmd: nova_controller_syncdb
   - watch:
@@ -216,6 +267,9 @@
   service.running:
   - enable: true
   - names: {{ controller.services }}
+  {%- if grains.get('noservices') %}
+  - onlyif: /bin/false
+  {%- endif %}
   - require:
     - cmd: nova_controller_syncdb
   - watch:
diff --git a/nova/files/juno/nova-compute.conf.Debian b/nova/files/juno/nova-compute.conf.Debian
index bb4dba5..2220177 100644
--- a/nova/files/juno/nova-compute.conf.Debian
+++ b/nova/files/juno/nova-compute.conf.Debian
@@ -107,6 +107,8 @@
 
 {% endif %}
 
+instances_path = {{ compute.instances_path }}
+
 {%- if compute.notification is defined %}
 notification_driver = {{ compute.notification.driver }}
 
diff --git a/nova/files/kilo/nova-compute.conf.Debian b/nova/files/kilo/nova-compute.conf.Debian
index fcf3ae3..c3e197a 100644
--- a/nova/files/kilo/nova-compute.conf.Debian
+++ b/nova/files/kilo/nova-compute.conf.Debian
@@ -96,6 +96,8 @@
 
 {% endif %}
 
+instances_path = {{ compute.instances_path }}
+
 {%- if compute.notification is defined %}
 notification_driver = {{ compute.notification.driver }}
 
diff --git a/nova/files/liberty/nova-compute.conf.Debian b/nova/files/liberty/nova-compute.conf.Debian
index 283f9c4..21654cd 100644
--- a/nova/files/liberty/nova-compute.conf.Debian
+++ b/nova/files/liberty/nova-compute.conf.Debian
@@ -100,6 +100,8 @@
 instance_usage_audit_period = hour
 {% endif %}
 
+instances_path = {{ compute.instances_path }}
+
 {%- if compute.get('notification', {}).notify_on is defined %}
 {%- for key, value in compute.notification.notify_on.iteritems() %}
 notify_on_{{ key }} = {{ value }}
diff --git a/nova/files/mitaka/nova-compute.conf.Debian b/nova/files/mitaka/nova-compute.conf.Debian
index 7e94913..94b8f18 100644
--- a/nova/files/mitaka/nova-compute.conf.Debian
+++ b/nova/files/mitaka/nova-compute.conf.Debian
@@ -63,6 +63,8 @@
 instance_usage_audit_period = hour
 {%- endif %}
 
+instances_path = {{ compute.instances_path }}
+
 {%- if compute.get('notification', {}).notify_on is defined %}
 {%- for key, value in compute.notification.notify_on.iteritems() %}
 notify_on_{{ key }} = {{ value }}
diff --git a/nova/files/newton/nova-compute.conf.Debian b/nova/files/newton/nova-compute.conf.Debian
index 8b44941..464e346 100644
--- a/nova/files/newton/nova-compute.conf.Debian
+++ b/nova/files/newton/nova-compute.conf.Debian
@@ -80,6 +80,8 @@
 instance_usage_audit_period = hour
 {%- endif %}
 
+instances_path = {{ compute.instances_path }}
+
 {%- if compute.get('notification', {}).notify_on is defined %}
 {%- for key, value in compute.notification.notify_on.iteritems() %}
 notify_on_{{ key }} = {{ value }}
diff --git a/nova/files/ocata/nova-compute.conf.Debian b/nova/files/ocata/nova-compute.conf.Debian
index 42d913b..08e7d77 100644
--- a/nova/files/ocata/nova-compute.conf.Debian
+++ b/nova/files/ocata/nova-compute.conf.Debian
@@ -646,6 +646,7 @@
 #   Any string representing directory path.
 #  (string value)
 #instances_path=$state_path/instances
+instances_path = {{ compute.instances_path }}
 
 #
 # This option enables periodic compute.instance.exists notifications. Each
diff --git a/nova/map.jinja b/nova/map.jinja
index 8e19b15..3b66daf 100644
--- a/nova/map.jinja
+++ b/nova/map.jinja
@@ -48,6 +48,7 @@
         'bind': compute_bind_defaults,
         'debug': false,
         'libvirt': [],
+        'instances_path': '$state_path/instances',
         'notification': false,
         'availability_zone': None,
         'aggregates': [],
diff --git a/tests/pillar/control_cluster.sls b/tests/pillar/control_cluster.sls
index 84da744..9744dd1 100644
--- a/tests/pillar/control_cluster.sls
+++ b/tests/pillar/control_cluster.sls
@@ -42,7 +42,7 @@
       password: password
       virtual_host: '/openstack'
     glance:
-      host: 
+      host:
       port: 9292
     network:
       engine: neutron
@@ -59,7 +59,6 @@
       filter_factory: 'keystonemiddleware.audit:filter_factory'
       map_file: '/etc/pycadf/nova_api_audit_map.conf'
     policy:
-      context_is_admin: 'role:admin or role:administrator'
+      'context_is_admin': 'role:admin or role:administrator'
       'compute:create': 'rule:admin_or_owner'
       'compute:create:attach_network':
-
diff --git a/tests/pillar/control_single.sls b/tests/pillar/control_single.sls
index ce33f8c..78eaa40 100644
--- a/tests/pillar/control_single.sls
+++ b/tests/pillar/control_single.sls
@@ -57,6 +57,6 @@
       - host: 127.0.0.1
         port: 11211
     policy:
-      context_is_admin: 'role:admin or role:administrator'
+      'context_is_admin': 'role:admin or role:administrator'
       'compute:create': 'rule:admin_or_owner'
       'compute:create:attach_network':