Merge pull request #17 from salt-formulas/fix/missing_space_if_multiple_backends

missing_space_if_multiple_backends
diff --git a/.kitchen.yml b/.kitchen.yml
index bf95612..be889a8 100644
--- a/.kitchen.yml
+++ b/.kitchen.yml
@@ -14,6 +14,10 @@
   formula: cinder
   grains:
     noservices: True
+  dependencies:
+    - name: keystone
+      repo: git
+      source: https://github.com/salt-formulas/salt-formula-keystone
   state_top:
     base:
       "*":
diff --git a/README.rst b/README.rst
index 971f76c..3dd21a6 100644
--- a/README.rst
+++ b/README.rst
@@ -169,6 +169,18 @@
         wipe_method: shred
         ...
 
+Configuration of policy.json file
+
+.. code-block:: yaml
+
+    cinder:
+      controller:
+        ....
+        policy:
+          'volume:delete': 'rule:admin_or_owner'
+          # Add key without value to remove line from policy.json
+          'volume:extend':
+
 
 Default Cinder setup with iSCSI target
 
@@ -268,6 +280,36 @@
             options: rw,sync
 
 
+Cinder setup with NetApp
+
+.. code-block:: yaml
+
+    cinder:
+      controller:
+        backend:
+          netapp:
+            engine: netapp
+            type_name: netapp
+            user: openstack
+            vserver: vm1
+            server_hostname: 172.18.2.3
+            password: password
+            storage_protocol: nfs
+            transport_type: https
+            lun_space_reservation: enabled
+            use_multipath_for_image_xfer: True
+            devices:
+              - 172.18.1.2:/vol_1
+              - 172.18.1.2:/vol_2
+              - 172.18.1.2:/vol_3
+              - 172.18.1.2:/vol_4
+      compute:
+        backend:
+          netapp:
+            engine: netapp
+            storage_protocol: nfs
+
+
 Cinder setup with Hitachi VPS
 
 .. code-block:: yaml
diff --git a/_grains/cinder_policy.py b/_grains/cinder_policy.py
new file mode 100644
index 0000000..a2d265e
--- /dev/null
+++ b/_grains/cinder_policy.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+import salt.config
+import salt.loader
+
+
+def main():
+    path = "/etc/cinder/policy.json"
+    __opts__ = salt.config.minion_config('/etc/salt/minion')
+    keystone_policy_mod = salt.loader.raw_mod(__opts__, 'keystone_policy', None)
+    if keystone_policy_mod:
+        result = keystone_policy_mod['keystone_policy.rule_list'](path)
+        if result and 'Error' not in result:
+            return {'cinder_policy': result}
+    return {}
+
diff --git a/cinder/compute.sls b/cinder/compute.sls
new file mode 100644
index 0000000..bcede64
--- /dev/null
+++ b/cinder/compute.sls
@@ -0,0 +1,20 @@
+{%- from "cinder/map.jinja" import compute with context %}
+{%- if compute.get('enabled', False) %}
+
+include:
+- cinder.user
+
+{%- for backend_name, backend in compute.get('backend', {}).iteritems() %}
+
+{%- if backend.engine is defined and backend.engine == 'nfs' or (backend.engine == 'netapp' and backend.storage_protocol == 'nfs') %}
+
+cinder_netapp_compute_packages:
+  pkg.installed:
+    - pkgs:
+      - nfs-common
+
+{%- endif %}
+
+{%- endfor %}
+
+{%- endif %}
diff --git a/cinder/controller.sls b/cinder/controller.sls
index a50a3ca..4d8c334 100644
--- a/cinder/controller.sls
+++ b/cinder/controller.sls
@@ -22,6 +22,30 @@
   - require:
     - pkg: cinder_controller_packages
 
+{%- for name, rule in controller.get('policy', {}).iteritems() %}
+
+{%- if rule != None %}
+rule_{{ name }}_present:
+  keystone_policy.rule_present:
+  - path: /etc/cinder/policy.json
+  - name: {{ name }}
+  - rule: {{ rule }}
+  - require:
+    - pkg: cinder_controller_packages
+
+{%- else %}
+
+rule_{{ name }}_absent:
+  keystone_policy.rule_absent:
+  - path: /etc/cinder/policy.json
+  - name: {{ name }}
+  - require:
+    - pkg: cinder_controller_packages
+
+{%- endif %}
+
+{%- endfor %}
+
 {%- if controller.version == 'ocata' %}
 
 /etc/apache2/conf-available/cinder-wsgi.conf:
@@ -31,28 +55,30 @@
   - require:
     - pkg: cinder_controller_packages
 
-{%- if not grains.get('noservices', False) %}
 cinder_api_service:
   service.running:
   - name: apache2
   - enable: true
+  {% if grains.noservices is defined %}
+  - onlyif: {% if grains.get('noservices', "True") %}"True"{% else %}False{% endif %}
+  {% endif %}
   - watch:
     - file: /etc/cinder/cinder.conf
     - file: /etc/cinder/api-paste.ini
     - file: /etc/apache2/conf-available/cinder-wsgi.conf
-{%- endif %}
 
 {%- else %}
 
-{%- if not grains.get('noservices', False) %}
 cinder_api_service:
   service.running:
   - name: cinder-api
   - enable: true
+  {% if grains.noservices is defined %}
+  - onlyif: {% if grains.get('noservices', "True") %}"True"{% else %}False{% endif %}
+  {% endif %}
   - watch:
     - file: /etc/cinder/cinder.conf
     - file: /etc/cinder/api-paste.ini
-{%- endif %}
 
 {%- endif %}
 
@@ -68,12 +94,13 @@
 
 {%- endif %}
 
-{%- if not grains.get('noservices', False) %}
-
 cinder_controller_services:
   service.running:
   - names: {{ controller.services }}
   - enable: true
+  {% if grains.noservices is defined %}
+  - onlyif: {% if grains.get('noservices', "True") %}"True"{% else %}False{% endif %}
+  {% endif %}
   - watch:
     - file: /etc/cinder/cinder.conf
     - file: /etc/cinder/api-paste.ini
@@ -81,14 +108,18 @@
 cinder_syncdb:
   cmd.run:
   - name: cinder-manage db sync
+  {% if grains.noservices is defined %}
+  - onlyif: {% if grains.get('noservices', "True") %}"True"{% else %}False{% endif %}
+  {% endif %}
   - require:
     - service: cinder_controller_services
 
 {# new way #}
+{%- if not grains.get('noservices', False) %}
 
 {%- for backend_name, backend in controller.get('backend', {}).iteritems() %}
 
-{%- if backend.engine is defined and backend.engine == 'nfs' %}
+{%- if backend.engine is defined and backend.engine == 'nfs' or (backend.engine == 'netapp' and backend.storage_protocol == 'nfs') %}
 /etc/cinder/nfs_shares_{{ backend_name }}:
   file.managed:
   - source: salt://cinder/files/{{ controller.version }}/nfs_shares
@@ -98,6 +129,20 @@
   - require:
     - pkg: cinder_controller_packages
 
+cinder_netapp_packages:
+  pkg.installed:
+    - pkgs:
+      - nfs-common
+
+{%- endif %}
+
+{%- if backend.get('use_multipath_for_image_xfer', False) %}
+
+cinder_netapp_add_packages:
+  pkg.installed:
+    - pkgs:
+      - multipath-tools
+
 {%- endif %}
 
 cinder_type_create_{{ backend_name }}:
@@ -158,4 +203,4 @@
 
 {%- endif %}
 
-{%- endif %}
\ No newline at end of file
+{%- endif %}
diff --git a/cinder/files/backend/_netapp.conf b/cinder/files/backend/_netapp.conf
new file mode 100644
index 0000000..be77604
--- /dev/null
+++ b/cinder/files/backend/_netapp.conf
@@ -0,0 +1,32 @@
+
+
+[{{ backend_name }}]
+netapp_login={{ backend.user }}
+netapp_controller_ips={{ backend.get('controller_ip', '') }}
+netapp_lun_ostype={{ backend.get('lun_ostype', 'linux') }}
+netapp_vserver={{ backend.vserver }}
+netapp_server_port={{ backend.get('server_port', '443') }}
+nfs_shares_config=/etc/cinder/nfs_shares_{{ backend_name }}
+netapp_sa_password={{ backend.get('sa_password', '') }}
+thres_avl_size_perc_start={{ backend.get('avl_size_perc_start', '20') }}
+reserved_percentage={{ backend.get('reserved_percentage', '0') }}
+volume_driver=cinder.volume.drivers.netapp.common.NetAppDriver
+netapp_enable_multiattach={{ backend.get('enable_multiattach', False) }}
+netapp_storage_protocol={{ backend.storage_protocol }}
+max_oversubscription_ratio={{ backend.get('max_oversubscription_ratio', '1.0') }}
+backend_host=str:netapp
+netapp_storage_family={{ backend.get('storage_family', 'ontap_cluster') }}
+volume_backend_name={{ backend_name }}
+nfs_mount_options={{ backend.get('nfs_mount_options', '') }}
+thres_avl_size_perc_stop={{ backend.get('avl_size_perc_stop', '60') }}
+netapp_vfiler={{ backend.get('vfiler', '') }}
+netapp_server_hostname={{ backend.server_hostname }}
+netapp_host_type={{ backend.get('host_type', 'linux') }}
+expiry_thres_minutes={{ backend.get('expiry_thres_minutes', '720') }}
+netapp_pool_name_search_pattern={{ backend.get('pool_name_search_pattern', '(.+)') }}
+netapp_transport_type={{ backend.get('transport_type', 'http') }}
+netapp_password={{ backend.password }}
+netapp_webservice_path={{ backend.get('webservice_path', '/devmgr/v2') }}
+netapp_lun_space_reservation={{ backend.get('lun_space_reservation', 'disabled') }}
+use_multipath_for_image_xfer={{ backend.get('use_multipath_for_image_xfer', False) }}
+netapp_copyoffload_tool_path={{ backend.get('copyoffload_tool_path', '') }}
diff --git a/cinder/init.sls b/cinder/init.sls
index 967b134..9a15d91 100644
--- a/cinder/init.sls
+++ b/cinder/init.sls
@@ -3,6 +3,9 @@
 {% if pillar.cinder.controller is defined %}
 - cinder.controller
 {% endif %}
+{% if pillar.cinder.compute is defined %}
+- cinder.compute
+{% endif %}
 {% if pillar.cinder.volume is defined %}
 - cinder.volume
-{% endif %}
\ No newline at end of file
+{% endif %}
diff --git a/cinder/map.jinja b/cinder/map.jinja
index 340eb9b..0755d54 100644
--- a/cinder/map.jinja
+++ b/cinder/map.jinja
@@ -64,3 +64,37 @@
         }
     },
 }, merge=pillar.cinder.get('volume', {})) %}
+
+{% set compute = salt['grains.filter_by']({
+    'Debian': {
+        'pkgs': [],
+        'services': [],
+        'wipe_method': 'none',
+        'notification': False,
+        'cors': {},
+        'audit': {
+          'enabled': false
+        },
+        'backup': {
+          'pkgs': [],
+          'services': [],
+          'engine': None
+        }
+    },
+    'RedHat': {
+        'pkgs': [],
+        'services': [],
+        'wipe_method': 'none',
+        'notification': False,
+        'cors': {},
+        'audit': {
+          'enabled': false
+        },
+        'backup': {
+          'pkgs': [],
+          'services': [],
+          'engine': None
+        }
+
+    },
+}, merge=pillar.cinder.get('compute', {})) %}
diff --git a/cinder/volume.sls b/cinder/volume.sls
index b4bc0f8..ee5d9ea 100644
--- a/cinder/volume.sls
+++ b/cinder/volume.sls
@@ -15,10 +15,8 @@
   - group: cinder
   - require:
     - pkg: cinder_volume_packages
-  {%- if not grains.get('noservices', False) %}
   - require_in:
     - service: cinder_volume_services
-  {%- endif %}
 
 {%- if not pillar.cinder.get('controller', {}).get('enabled', False) %}
 
@@ -46,6 +44,9 @@
   service.running:
   - names: {{ volume.backup.services }}
   - enable: true
+  {% if grains.noservices is defined %}
+  - onlyif: {% if grains.get('noservices', "True") %}"True"{% else %}False{% endif %}
+  {% endif %}
   - watch:
     - file: /etc/cinder/cinder.conf
     - file: /etc/cinder/api-paste.ini
@@ -54,18 +55,17 @@
 
 {%- endif %}
 
-{%- if not grains.get('noservices', False) %}
-
 cinder_volume_services:
   service.running:
   - names: {{ volume.services }}
   - enable: true
+  {% if grains.noservices is defined %}
+  - onlyif: {% if grains.get('noservices', "True") %}"True"{% else %}False{% endif %}
+  {% endif %}
   - watch:
     - file: /etc/cinder/cinder.conf
     - file: /etc/cinder/api-paste.ini
 
-{%- endif %}
-
 {# new way #}
 
 {%- if volume.backend is defined %}
@@ -90,22 +90,20 @@
   - require:
     - pkg: cinder_iscsi_packages_{{ loop.index }}
 
-{%- if not grains.get('noservices', False) %}
-
 cinder_scsi_service:
   service.running:
   - names:
     - iscsitarget
     - open-iscsi
   - enable: true
+  {% if grains.noservices is defined %}
+  - onlyif: {% if grains.get('noservices', "True") %}"True"{% else %}False{% endif %}
+  {% endif %}
   - watch:
     - file: /etc/default/iscsitarget
 
 {%- endif %}
 
-
-{%- endif %}
-
 {%- if backend.engine == 'hitachi_vsp' %}
 
 {%- if grains.os_family == 'Debian' and volume.version == 'juno' %}
@@ -178,21 +176,20 @@
   - require:
     - pkg: cinder_iscsi_packages
 
-{%- if not grains.get('noservices', False) %}
-
 cinder_scsi_service:
   service.running:
   - names:
     - iscsitarget
     - open-iscsi
   - enable: true
+  {% if grains.noservices is defined %}
+  - onlyif: {% if grains.get('noservices', "True") %}"True"{% else %}False{% endif %}
+  {% endif %}
   - watch:
     - file: /etc/default/iscsitarget
 
 {%- endif %}
 
-{%- endif %}
-
 {%- if volume.storage.engine == 'hitachi_vsp' %}
 
 {%- if grains.os_family == 'Debian' and volume.version == 'juno' %}
diff --git a/metadata.yml b/metadata.yml
index a16c24e..3a8709d 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,3 +1,6 @@
 name: "cinder"
 version: "2016.4.1"
 source: "https://github.com/salt-formulas/salt-formula-cinder"
+dependencies:
+  - name: keystone
+    source: "https://github.com/salt-formulas/salt-formula-keystone"
diff --git a/metadata/service/compute/single.yml b/metadata/service/compute/single.yml
new file mode 100644
index 0000000..097e874
--- /dev/null
+++ b/metadata/service/compute/single.yml
@@ -0,0 +1,8 @@
+applications:
+- cinder
+classes:
+- service.cinder.support
+parameters:
+  cinder:
+    compute:
+      enabled: true
diff --git a/metadata/service/volume/local.yml b/metadata/service/volume/local.yml
new file mode 100644
index 0000000..592f010
--- /dev/null
+++ b/metadata/service/volume/local.yml
@@ -0,0 +1,44 @@
+applications:
+- cinder
+classes:
+- service.cinder.support
+parameters:
+  _param:
+    keystone_cinder_endpoint_type: internalURL
+  cinder:
+    volume:
+      enabled: true
+      version: ${_param:cinder_version}
+      osapi:
+        host: ${_param:cluster_local_address}
+      database:
+        engine: mysql
+        host: ${_param:single_address}
+        port: 3306
+        name: cinder
+        user: cinder
+        password: ${_param:mysql_cinder_password}
+      identity:
+        engine: keystone
+        region: RegionOne
+        host: ${_param:single_address}
+        port: 35357
+        tenant: service
+        user: cinder
+        password: ${_param:keystone_cinder_password}
+        endpoint_type: ${_param:keystone_cinder_endpoint_type}
+      glance:
+        host: ${_param:single_address}
+        port: 9292
+      message_queue:
+        engine: rabbitmq
+        host: ${_param:single_address}
+        port: 5672
+        user: openstack
+        password: ${_param:rabbitmq_openstack_password}
+        virtual_host: '/openstack'
+      cache:
+        engine: memcached
+        members:
+          host: ${_param:single_address}
+
diff --git a/tests/pillar/ceph_single.sls b/tests/pillar/ceph_single.sls
index 79838a2..d996ad2 100644
--- a/tests/pillar/ceph_single.sls
+++ b/tests/pillar/ceph_single.sls
@@ -40,6 +40,9 @@
       name: cinder
       user: cinder
       password: pwd
+    policy:
+      'volume:delete': 'rule:admin_or_owner'
+      'volume:extend':
   volume:
     enabled: true
     version: liberty
diff --git a/tests/pillar/control_cluster.sls b/tests/pillar/control_cluster.sls
index 62bb44b..4ab6e8e 100644
--- a/tests/pillar/control_cluster.sls
+++ b/tests/pillar/control_cluster.sls
@@ -51,3 +51,6 @@
     audit:
       filter_factory: 'keystonemiddleware.audit:filter_factory'
       map_file: '/etc/pycadf/cinder_api_audit_map.conf'
+    policy:
+      'volume:delete': 'rule:admin_or_owner'
+      'volume:extend':
diff --git a/tests/pillar/control_single.sls b/tests/pillar/control_single.sls
index ef2136a..ac8db5a 100644
--- a/tests/pillar/control_single.sls
+++ b/tests/pillar/control_single.sls
@@ -36,3 +36,6 @@
         port: 22
         user: username
         password: pass
+    policy:
+      'volume:delete': 'rule:admin_or_owner'
+      'volume:extend':
diff --git a/tests/pillar/netapp.sls b/tests/pillar/netapp.sls
new file mode 100644
index 0000000..7a7baa0
--- /dev/null
+++ b/tests/pillar/netapp.sls
@@ -0,0 +1,31 @@
+cinder:
+  controller:
+    enabled: true
+    version: mitaka
+    backend:
+      netapp:
+        engine: netapp
+        type_name: netapp
+        user: openstack
+        vserver: vm1
+        server_hostname: 172.18.2.3
+        password: password
+        storage_protocol: nfs
+        transport_type: https
+        netapp_lun_space_reservation: enabled
+        use_multipath_for_image_xfer: True
+        devices:
+          - 172.18.2.2:/vol_1
+          - 172.18.2.2:/vol_2
+          - 172.18.2.2:/vol_3
+          - 172.18.2.2:/vol_4
+  volume:
+    enabled: true
+    version: mitaka
+  compute:
+    enabled: true
+    version: mitaka
+    backend:
+      netapp:
+        engine: netapp
+        storage_protocol: nfs