Add's support for Juniper Contrail packaging + test-kitchen (#2)

* Add's support for Juniper packaging
 - handle vendor packaging differences
 - map.jina loaded from yaml
 - test kitchen validation on Travis
 - multiple test/pillars fixtures
 - .kitchen.vagrant.yml for tests not passing on docker
 - fix, remove virtual package name as full is required

* Fix epcim complains about non reclass usage test

Change-Id: I7b4892cce1063f583b045954b6b64b30d3b01a65

* Update contrail-vrouter-agent.conf for lbaas

* Juniper: Allow downgrades while installing pkgs on controller nodes; precreate cassandra data dir
diff --git a/.kitchen.vagrant.yml b/.kitchen.vagrant.yml
new file mode 100644
index 0000000..3629138
--- /dev/null
+++ b/.kitchen.vagrant.yml
@@ -0,0 +1,52 @@
+---
+driver:
+  name: vagrant
+  vm_hostname: opencontrail.ci.local
+  use_sudo: false
+  customize:
+    memory: 512
+
+
+provisioner:
+  name: salt_solo
+  salt_install: bootstrap
+  salt_bootstrap_url: https://bootstrap.saltstack.com
+  salt_version: latest
+  require_chef: false
+  formula: opencontrail
+  log_level: info
+  state_top:
+    base:
+      "*":
+        - opencontrail
+  pillars:
+    top.sls:
+      base:
+        "*":
+          - opencontrail
+  grains:
+    noservices: True
+
+platforms:
+  - name: ubuntu-14.04
+  - name: ubuntu-16.04
+
+suites:
+
+  - name: tor
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/tor.sls
+
+  - name: vrouter_kubernetes
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/vrouter_kubernetes.sls
+
+  - name: vrouter
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/vrouter.sls
+
+
+# vim: ft=yaml sw=2 ts=2 sts=2 tw=125
diff --git a/.kitchen.yml b/.kitchen.yml
new file mode 100644
index 0000000..52aeb8b
--- /dev/null
+++ b/.kitchen.yml
@@ -0,0 +1,125 @@
+---
+driver:
+  name: docker
+  hostname: opencontrail
+  use_sudo: true
+
+provisioner:
+  name: salt_solo
+  salt_install: bootstrap
+  salt_bootstrap_url: https://bootstrap.saltstack.com
+  salt_version: latest
+  require_chef: false
+  log_level: error
+  formula: opencontrail
+  grains:
+    noservices: True
+  vendor_repo:
+    - type: apt
+      url: http://apt-mk.mirantis.com/trusty
+      key_url: http://apt-mk.mirantis.com/public.gpg
+      components: oc303 extra
+      distribution: nightly
+  dependencies:
+    - name: linux
+      repo: git
+      source: https://github.com/salt-formulas/salt-formula-linux
+  state_top:
+    base:
+      "*":
+        - linux
+        - opencontrail
+  pillars:
+    top.sls:
+      base:
+        "*":
+          - linux_repo_cassandra
+          - linux_repo_mos
+          - linux
+          - opencontrail
+          - opencontrail_juniper
+    linux.sls:
+      linux:
+        system:
+          enabled: true
+          name: opencontrail
+        network:
+          enabled: true
+          hostname: opencontrail
+          interface:
+            vhost0:
+              enabled: True
+              type: eth
+    opencontrail_juniper.sls: {}
+  pillars-from-files:
+    linux_repo_mos.sls: tests/pillar/repo_mos8.sls
+    linux_repo_cassandra.sls: tests/pillar/repo_cassandra.sls
+
+verifier:
+  name: inspec
+  sudo: true
+
+platforms:
+  - name: <%= ENV['PLATFORM'] || 'ubuntu-trusty' %>
+    driver_config:
+      image: <%= ENV['PLATFORM'] || 'trevorj/salty-whales:trusty' %>
+      platform: ubuntu
+
+suites:
+
+  - name: analytics
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/analytics.sls
+
+  - name: cluster
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/cluster.sls
+
+  - name: control
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/control.sls
+
+  - name: single
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/single.sls
+
+
+# Note: require juniper contrail repo available
+  - name: vendor-juniper
+    provisioner:
+      vendor_repo:
+        - type: apt
+          url: http://aptly.local/contrail
+          key_url: http://aptly.local/public.gpg
+          components: main
+          distribution: trusty
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/control.sls
+      pillars:
+        opencontrail_juniper.sls:
+          opencontrail:
+            common:
+              vendor: juniper
+
+# Note: Following suites not pass on docker platform
+#       the scope of the test may be limited.
+  - name: tor
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/tor.sls
+
+  - name: vrouter_kubernetes
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/vrouter_kubernetes.sls
+
+  - name: vrouter
+    provisioner:
+      pillars-from-files:
+        opencontrail.sls: tests/pillar/vrouter.sls
+
+# vim: ft=yaml sw=2 ts=2 sts=2 tw=125
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..bc2d556
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,42 @@
+sudo: required
+services:
+  - docker
+
+install:
+  - pip install PyYAML
+  - pip install virtualenv
+  - |
+    test -e Gemfile || cat <<EOF > Gemfile
+    source 'https://rubygems.org'
+    gem 'rake'
+    gem 'test-kitchen'
+    gem 'kitchen-docker'
+    gem 'kitchen-vagrant'
+    gem 'kitchen-inspec'
+    gem 'inspec'
+    gem 'kitchen-salt', :git => 'https://github.com/epcim/kitchen-salt.git', :branch => 'dependencis-pkg-repo2'
+    #Waiting for PR#78
+    #gem 'kitchen-salt', '>=0.2.25'
+  - bundle install
+
+env:
+  matrix:
+   - SUITE=analytics
+   - SUITE=control
+   - SUITE=cluster
+   - SUITE=single
+   #- SUITE=vendor-juniper
+   #- SUITE=tor
+   #- SUITE=vrouter_kubernetes
+   #- SUITE=vrouter
+   #- PLATFORM=trevorj/salty-whales:xenial SUITE=analytics
+   #- PLATFORM=trevorj/salty-whales:xenial SUITE=control
+   #- PLATFORM=trevorj/salty-whales:xenial SUITE=cluster
+   #...
+
+before_script:
+  - make test | tail
+
+script:
+  - test ! -e .kitchen.yml || bundle exec kitchen verify $SUITE
+
diff --git a/README.rst b/README.rst
index 4dcf94d..a17fe13 100644
--- a/README.rst
+++ b/README.rst
@@ -11,6 +11,27 @@
 Virtualization (NFV) use cases.
 
 
+Package source
+==============
+Formula support OpenContrail as well as Juniper Contrail package repository in the backend.
+
+Differences withing the configuration and state run are controlled by
+``opencontrail.common.vendor: [opencontrail|juniper]`` pillar attribute.
+
+Default value is set to ``opencontrail``.
+
+Juniper releases tested with this formula:
+ - 3.0.2.x
+
+To use Juniper Contrail repository as a source of packages override pillar as in this example:
+
+.. code-block:: yaml
+
+    opencontrail:
+      common:
+        vendor: juniper
+
+
 Sample pillars
 ==============
 
diff --git a/opencontrail/collector.sls b/opencontrail/collector.sls
index f749e39..b8525fb 100644
--- a/opencontrail/collector.sls
+++ b/opencontrail/collector.sls
@@ -7,6 +7,7 @@
 opencontrail_collector_packages:
   pkg.installed:
   - names: {{ collector.pkgs }}
+  - force_yes: True
 
 /etc/contrail/contrail-analytics-nodemgr.conf:
   file.managed:
diff --git a/opencontrail/config.sls b/opencontrail/config.sls
index 91425c1..d53daa5 100644
--- a/opencontrail/config.sls
+++ b/opencontrail/config.sls
@@ -1,4 +1,4 @@
-{%- from "opencontrail/map.jinja" import config with context %}
+{%- from "opencontrail/map.jinja" import common,config with context %}
 {%- if config.enabled %}
 
 include:
@@ -7,6 +7,7 @@
 opencontrail_config_packages:
   pkg.installed:
   - names: {{ config.pkgs }}
+  - force_yes: True
 
 /etc/ifmap-server/authorization.properties:
   file.managed:
@@ -154,7 +155,7 @@
     - service: opencontrail_config_services
 {%- endif %}
 
-{%- if not grains.get('virtual_subtype', None) == "Docker" %}
+{%- if not common.vendor == "juniper" or not grains.get('virtual_subtype', None) == "Docker" %}
 
 /etc/contrail/supervisord_config_files/ifmap.ini:
   file.absent:
diff --git a/opencontrail/control.sls b/opencontrail/control.sls
index 086f603..6c1b9ac 100644
--- a/opencontrail/control.sls
+++ b/opencontrail/control.sls
@@ -7,6 +7,7 @@
 opencontrail_control_packages:
   pkg.installed:
   - names: {{ control.pkgs }}
+  - force_yes: True
 
 /etc/contrail/contrail-control-nodemgr.conf:
   file.managed:
@@ -91,4 +92,5 @@
 
 {%- endif %}
 
-{%- endif %}
\ No newline at end of file
+{%- endif %}
+
diff --git a/opencontrail/database.sls b/opencontrail/database.sls
index 4a50e8a..2d48ab4 100644
--- a/opencontrail/database.sls
+++ b/opencontrail/database.sls
@@ -62,6 +62,7 @@
 opencontrail_database_packages:
   pkg.installed:
   - names: {{ database.pkgs }}
+  - force_yes: True
 {% if grains.os_family == "Debian" %}
   - require:
     - file: {{ database.cassandra_config }}cassandra.yaml
@@ -126,6 +127,23 @@
     - enable: None
 {% endif %}
 
+/var/lib/cassandra/data:
+  file.directory:
+  - user: cassandra
+  - group: cassandra
+  - makedirs: True
+{%- if not grains.get('noservices', False) %}
+  - require_in:
+    - service: opencontrail_database_services
+{%- endif %}
+
+/var/lib/cassandra:
+  file.directory:
+  - user: cassandra
+  - group: cassandra
+  - require:
+    - file: /var/lib/cassandra/data
+
 {%- if not grains.get('noservices', False) %}
 
 zookeeper_service:
diff --git a/opencontrail/files/3.0/config.global.js b/opencontrail/files/3.0/config.global.js
index 178343a..402cc35 100644
--- a/opencontrail/files/3.0/config.global.js
+++ b/opencontrail/files/3.0/config.global.js
@@ -1,4 +1,4 @@
-{%- from "opencontrail/map.jinja" import web with context %}
+{%- from "opencontrail/map.jinja" import common,web with context %}
 /*
  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
  */
@@ -31,14 +31,14 @@
  *
  * true  - These values should be taken from this config
  *         file.
- * false - These values should be taken from auth catalog list 
+ * false - These values should be taken from auth catalog list
  *
 *****************************************************************************/
 config.serviceEndPointFromConfig = true;
 
 /****************************************************************************
  * This boolean flag indicates if serviceEndPointFromConfig is set as false,
- * then to take IP/Port/Protocol/Version information from auth catalog, 
+ * then to take IP/Port/Protocol/Version information from auth catalog,
  * should publicURL OR internalURL will be used.
  *
  * true  - publicURL in endpoint will be used to retrieve IP/Port/Protocol/
@@ -67,7 +67,7 @@
  *      IP to connect to for this Server.
  * port:
  *      Port to connect to for this server
- * authProtocol:        
+ * authProtocol:
  *      Specify authProtocol either 'http' or 'https'
  * apiVersion:
  *      REST API Version for this server to connect to.
@@ -81,7 +81,7 @@
  *      Not applicable for cnfg/analytics as of now
  * strictSSL:
  *      If true, requires certificates to be valid
- * ca: 
+ * ca:
  *      An authority certificate to check the remote host against,
  *      if you do not want to specify then use ''
 *****************************************************************************/
@@ -115,10 +115,10 @@
 config.identityManager.port = '5000';
 config.identityManager.authProtocol = 'http';
 /******************************************************************************
- * Note: config.identityManager.apiVersion is not controlled by boolean flag 
+ * Note: config.identityManager.apiVersion is not controlled by boolean flag
  * config.serviceEndPointFromConfig. If specified apiVersion here, then these
  * API versions will be used while using REST API to identityManager.
- * If want to use with default apiVersion(v2.0), then can specify it as 
+ * If want to use with default apiVersion(v2.0), then can specify it as
  * empty array.
 ******************************************************************************/
 config.identityManager.apiVersion = ['v{{ web.identity.version }}'];
@@ -159,7 +159,11 @@
 config.vcenter.dvsswitch = 'vswitch';           //dvsswitch name
 config.vcenter.strictSSL = false;               //Validate the certificate or ignore
 config.vcenter.ca = '';                         //specify the certificate key file
+{%- if common.vendor == "juniper" %}
+config.vcenter.wsdl = '/usr/src/contrail/contrail-web-core/webroot/js/vim.wsdl';
+{%- else %}
 config.vcenter.wsdl = '/var/lib/contrail-webui/contrail-web-core/webroot/js/vim.wsdl';
+{%- endif %}
 
 /* Discovery Service */
 config.discoveryService = {};
@@ -181,7 +185,11 @@
 /* WebUI Redis Server */
 config.redis_server_port = '6379';
 config.redis_server_ip = '{{ web.cache.host }}';
+{%- if common.vendor == "juniper" %}
+config.redis_dump_file = '/var/lib/redis/dump.rdb';
+{%- else %}
 config.redis_dump_file = '/var/lib/redis/dump-webui.rdb';
+{%- endif %}
 config.redis_password = '';
 
 /* Cassandra Server */
@@ -197,7 +205,7 @@
 /* IP List to listen on */
 config.webui_addresses = ['0.0.0.0'];
 
-/* Is insecure access to WebUI? 
+/* Is insecure access to WebUI?
  * If set as false, then all http request will be redirected
  * to https, if set true, then no https request will be processed, but only http
  * request
@@ -222,34 +230,32 @@
 /* Redis DB index for Web-UI */
 config.redisDBIndex = 3;
 
-{% if grains.os_family == "Debian" %}
+config.featurePkg = {};
+config.featurePkg.webController = {};
+
+{%- if common.vendor == "juniper" %}
+/* Logo File: Use complete path of logo file location */
+config.logo_file = '/usr/src/contrail/contrail-web-core/webroot/img/juniper-networks-logo.png';
+
+/* Favicon File: Use complete path of favicon file location */
+config.favicon_file = '/usr/src/contrail/contrail-web-core/webroot/img/juniper-networks-favicon.ico';
+
+/* Add new feature Package Config details below */
+config.featurePkg.webController.path = '/usr/src/contrail/contrail-web-controller';
+config.featurePkg.webController.enable = true;
+
+{%- else %}
 /* Logo File: Use complete path of logo file location */
 config.logo_file = '/var/lib/contrail-webui/contrail-web-core/webroot/img/opencontrail-logo.png';
 
 /* Favicon File: Use complete path of favicon file location */
 config.favicon_file = '/var/lib/contrail-webui/contrail-web-core/webroot/img/juniper-networks-favicon.ico';
 
-config.featurePkg = {};
 /* Add new feature Package Config details below */
-config.featurePkg.webController = {};
 config.featurePkg.webController.path = '/var/lib/contrail-webui/contrail-web-controller';
 config.featurePkg.webController.enable = true;
 
-{% elif grains.os_family == "RedHat" %}
-
-config.logo_file = '/usr/src/contrail/contrail-web-core/webroot/img/juniper-networks-logo.png';
-
-/* Favicon File: Use complete path of favicon file location */
-config.favicon_file = '/usr/src/contrail/contrail-web-core/webroot/img/juniper-networks-favicon.ico';
-
-config.featurePkg = {};
-/* Add new feature Package Config details below */
-config.featurePkg.webController = {};
-config.featurePkg.webController.path = '/usr/src/contrail/contrail-web-controller';
-config.featurePkg.webController.enable = true;
-
-
-{% endif %}
+{%- endif %}
 
 /* Enable/disable Stat Query Links in Sidebar*/
 config.qe = {};
@@ -264,7 +270,7 @@
 /******************************************************************************
  * Boolean flag getDomainProjectsFromApiServer indicates wheather the project
  * list should come from API Server or Identity Manager.
- * If Set 
+ * If Set
  *      - true, then project list will come from API Server
  *      - false, then project list will come from Identity Manager
  * Default: false
@@ -274,7 +280,7 @@
 /*****************************************************************************
 * Boolean flag L2_enable indicates the default forwarding-mode of a network.
 * Allowed values : true / false
-* Set this flag to true if all the networks are to be L2 networks, 
+* Set this flag to true if all the networks are to be L2 networks,
 * set to false otherwise.
 *****************************************************************************/
 config.network = {};
diff --git a/opencontrail/files/3.0/contrail-tor-agent.conf b/opencontrail/files/3.0/contrail-tor-agent.conf
index bfdfa68..598a6d5 100644
--- a/opencontrail/files/3.0/contrail-tor-agent.conf
+++ b/opencontrail/files/3.0/contrail-tor-agent.conf
@@ -1,6 +1,5 @@
 {%- from "opencontrail/map.jinja" import tor with context %}
 {%- from "opencontrail/map.jinja" import compute with context %}
-{%- from "linux/map.jinja" import system with context %}
 {%- set port = tor.bind.port + number %}
 #
 # Vnswad configuration options
@@ -13,7 +12,7 @@
 # server=10.0.0.1 10.0.0.2
 
 [DEFAULT]
-agent_name={{ system.name }}-{{ number }}
+agent_name={{ pillar.linux.system.name }}-{{ number }}
 # Everything in this section is optional
 
 # IP address and port to be used to connect to collector. If these are not
diff --git a/opencontrail/files/3.0/contrail-vrouter-agent.conf b/opencontrail/files/3.0/contrail-vrouter-agent.conf
index 911fb02..9aadf56 100644
--- a/opencontrail/files/3.0/contrail-vrouter-agent.conf
+++ b/opencontrail/files/3.0/contrail-vrouter-agent.conf
@@ -1,4 +1,4 @@
-{%- from "opencontrail/map.jinja" import compute with context %}
+{%- from "opencontrail/map.jinja" import common,compute with context %}
 #
 # Vnswad configuration options
 #
@@ -226,4 +226,4 @@
 
 [SERVICES]
 # bgp_as_a_service_port_range - reserving set of ports to be used.
-# bgp_as_a_service_port_range=30000-35000
\ No newline at end of file
+# bgp_as_a_service_port_range=30000-35000
diff --git a/opencontrail/map.jinja b/opencontrail/map.jinja
index 5ff3153..1d2bfe2 100644
--- a/opencontrail/map.jinja
+++ b/opencontrail/map.jinja
@@ -1,102 +1,227 @@
+{%- set vendor = salt['pillar.get']('opencontrail:common:vendor', 'opencontrail') %}
 
-{% set common = salt['grains.filter_by']({
-    'Debian': {
-        'source': {'engine': 'pkg', 'address': 'http://'},
-        'pkgs': ['dpkg-dev','contrail-utils', 'contrail-nodemgr', 'gettext-base'],
-    },
-    'RedHat': {
-        'source': {'engine': 'pkg', 'address': 'http://'},
-        'pkgs': ['contrail-utils', 'contrail-nodemgr'],
-    },
-}, merge=pillar.opencontrail.get('common', {})) %}
+{%- load_yaml as base_defaults %}
+{%- if vendor in ['opencontrail'] %}
+common:
+  Debian:
+    vendor: opencontrail
+    source: {'engine': 'pkg', 'address': 'http://'}
+    pkgs:
+         ['dpkg-dev', 'contrail-utils', 'contrail-nodemgr', 'gettext-base']
+  RedHat:
+    vendor: opencontrail
+    source: {'engine': 'pkg', 'address': 'http://'}
+    pkgs:
+        ['contrail-utils', 'contrail-nodemgr']
+collector:
+  Debian:
+    pkgs:
+        ['contrail-analytics', 'python-cassandra']
+    redis_config: '/etc/redis/redis.conf'
+    services:
+        ['supervisor-analytics', 'redis-server']
+  RedHat:
+    pkgs:
+        ['contrail-analytics']
+    redis_config: '/etc/redis.conf'
+    services:
+        ['supervisor-analytics', 'redis']
+compute:
+  Debian:
+    pkgs:
+        ['contrail-utils', 'iproute2', 'haproxy']
+    services:
+        ['supervisor-vrouter']
+    dpkg:
+        enabled: False
+  RedHat:
+    pkgs:
+        ['contrail-openstack-vrouter', 'contrail-utils', 'haproxy', 'contrail-vrouter-source']
+    services:
+        ['supervisor-vrouter']
+    dpkg:
+        enabled: False
+config:
+  Debian:
+    pkgs:
+        ['contrail-config-openstack', 'ifmap-server']
+    services:
+        ['supervisor-config']
+  RedHat:
+    pkgs:
+        ['contrail-openstack-config']
+    services:
+        ['supervisor-config']
+control:
+  Debian:
+    pkgs:
+        ['contrail-control', 'contrail-dns']
+    services:
+        ['contrail-control', 'supervisor-control']
+  RedHat:
+    pkgs:
+         ['contrail-openstack-control']
+    services:
+         ['contrail-control', 'supervisor-control']
+database:
+  Debian:
+    pkgs:
+         ['cassandra', 'zookeeper', 'supervisor', 'openjdk-7-jre-headless', 'contrail-database']
+    cassandra_config: '/etc/cassandra/'
+    services:
+         ['supervisord-contrail-database', 'zookeeper']
+  RedHat:
+    pkgs:
+         ['contrail-openstack-database', 'zookeeper', 'supervisor', 'java-1.7.0-openjdk-headless']
+    cassandra_config: '/etc/cassandra/conf/'
+    services:
+         ['supervisord-contrail-database', 'zookeeper']
+web:
+  Debian:
+    pkgs:
+         ['contrail-web-controller', 'nodejs-legacy', 'gettext-base']
+    services:
+         ['contrail-webui-webserver', 'contrail-webui-jobserver']
+    database:
+      engine: cassandra
+      port: 9160
+  RedHat:
+    pkgs:
+         ['contrail-web-controller']
+    services:
+         ['supervisor-webui']
+    database:
+      engine: cassandra
+      port: 9160
+client:
+  Debian:
+    pkgs:
+         ['python-contrail']
+  RedHat:
+    pkgs:
+         []
+tor:
+  Debian:
+    agents: 1
+    bind:
+      port: 8086
 
-{% set collector = salt['grains.filter_by']({
-    'Debian': {
-        'pkgs': ['contrail-analytics', 'python-cassandra'],
-        'redis_config': '/etc/redis/redis.conf',
-        'services': ['supervisor-analytics','redis-server']
-    },
-    'RedHat': {
-        'pkgs': ['contrail-analytics'],
-        'redis_config': '/etc/redis.conf',
-        'services': ['supervisor-analytics','redis']
-    },
-}, merge=pillar.opencontrail.get('collector', {})) %}
+{%- elif vendor == 'juniper' -%}
 
-{% set compute = salt['grains.filter_by']({
-    'Debian': {
-        'pkgs': ['contrail-utils', 'iproute2', 'haproxy'],
-        'services': ['supervisor-vrouter'],
-        'dpdk': {
-            'enabled': False
-        }
-    },
-    'RedHat': {
-        'pkgs': ['contrail-openstack-vrouter', 'contrail-utils', 'haproxy', 'contrail-vrouter-source'],
-        'services': ['supervisor-vrouter'],
-        'dpdk': {
-            'enabled': False
-        }
-    },
-}, merge=pillar.opencontrail.get('compute', {})) %}
+common:
+  Debian:
+    vendor: juniper
+    source: {'engine': 'pkg', 'address': 'http://'}
+    pkgs:
+         ['dpkg-dev', 'contrail-utils', 'contrail-nodemgr', 'gettext-base']
+  RedHat:
+    vendor: juniper
+    source: {'engine': 'pkg', 'address': 'http://'}
+    pkgs:
+         ['contrail-utils', 'contrail-nodemgr']
+collector:
+  Debian:
+    pkgs:
+         ['contrail-analytics', 'python-cassandra-driver']
+    redis_config: '/etc/redis/redis.conf'
+    services:
+        ['supervisor-analytics', 'redis-server']
+  RedHat:
+    pkgs:
+         ['contrail-analytics', 'python-cassandra-driver']
+    redis_config: '/etc/redis.conf'
+    services:
+        ['supervisor-analytics', 'redis']
+compute:
+  Debian:
+    pkgs:
+         ['contrail-utils', 'iproute2', 'haproxy']
+    services:
+        ['supervisor-vrouter']
+    dpkg:
+        enabled: False
+  RedHat:
+    pkgs:
+         ['contrail-openstack-vrouter', 'contrail-utils', 'haproxy', 'contrail-vrouter-source']
+    services:
+        ['supervisor-vrouter']
+    dpkg:
+        enabled: False
+config:
+  Debian:
+    pkgs:
+         ['contrail-config-openstack', 'ifmap-server']
+    services:
+        ['supervisor-config']
+  RedHat:
+    pkgs:
+         ['contrail-openstack-config']
+    services:
+        ['supervisor-config']
+control:
+  Debian:
+    pkgs:
+         ['contrail-control', 'contrail-dns']
+    services:
+         ['contrail-control', 'supervisor-control']
+  RedHat:
+    pkgs:
+         ['contrail-openstack-control']
+    services:
+         ['contrail-control', 'supervisor-control']
+database:
+  Debian:
+    pkgs:
+         ['cassandra', 'zookeeper', 'supervisor', 'openjdk-7-jre-headless', 'contrail-openstack-database']
+    cassandra_config: '/etc/cassandra/'
+    services:
+         ['supervisord-contrail-database', 'zookeeper']
+  RedHat:
+    pkgs:
+         ['contrail-openstack-database', 'zookeeper', 'supervisor', 'java-1.7.0-openjdk-headless']
+    cassandra_config: '/etc/cassandra/conf/'
+    services:
+         ['supervisord-contrail-database', 'zookeeper']
+web:
+  Debian:
+    pkgs:
+         ['contrail-web-controller', 'contrail-openstack-webui', 'nodejs', 'gettext-base']
+    services:
+         ['supervisor-webui']
+    database:
+      engine: cassandra
+      port: 9160
+  RedHat:
+    pkgs:
+         ['contrail-web-controller']
+    services:
+         ['supervisor-webui']
+    database:
+      engine: cassandra
+      port: 9160
+client:
+  Debian:
+    pkgs:
+         ['python-contrail']
+  RedHat:
+    pkgs:
+         []
+tor:
+  Debian:
+    agents: 1
+    bind:
+     port: 8086
 
-{% set config = salt['grains.filter_by']({
-    'Debian': {
-        'pkgs': ['contrail-config-openstack','ifmap-server'],
-        'services': ['supervisor-config']
-    },
-    'RedHat': {
-        'pkgs': ['contrail-openstack-config'],
-        'services': ['supervisor-config']
-    },
-}, merge=pillar.opencontrail.get('config', {})) %}
+{%- endif %}
+{%- endload %}
 
-{% set control = salt['grains.filter_by']({
-    'Debian': {
-        'pkgs': ['contrail-control','contrail-dns'],
-        'services': ['contrail-control', 'supervisor-control']
-    },
-    'RedHat': {
-        'pkgs': ['contrail-openstack-control'],
-        'services': ['contrail-control', 'supervisor-control']
-    },
-}, merge=pillar.opencontrail.get('control', {})) %}
+{% set common    = salt['grains.filter_by'](base_defaults['common'], merge=salt['pillar.get']('opencontrail:common', {}), base='common') %}
+{% set collector = salt['grains.filter_by'](base_defaults['collector'], merge=salt['pillar.get']('opencontrail:collector', {}), base='collector') %}
+{% set compute   = salt['grains.filter_by'](base_defaults['compute'], merge=salt['pillar.get']('opencontrail:compute', {}), base='compute') %}
+{% set config    = salt['grains.filter_by'](base_defaults['config'], merge=salt['pillar.get']('opencontrail:config', {}), base='config') %}
+{% set control   = salt['grains.filter_by'](base_defaults['control'], merge=salt['pillar.get']('opencontrail:control', {}), base='control') %}
+{% set database  = salt['grains.filter_by'](base_defaults['database'], merge=salt['pillar.get']('opencontrail:database', {}), base='database') %}
+{% set web       = salt['grains.filter_by'](base_defaults['web'], merge=salt['pillar.get']('opencontrail:web', {}), base='web') %}
+{% set client    = salt['grains.filter_by'](base_defaults['client'], merge=salt['pillar.get']('opencontrail:client', {}), base='client') %}
+{% set tor       = salt['grains.filter_by'](base_defaults['tor'], merge=salt['pillar.get']('opencontrail:tor', {}), base='tor') %}
 
-{% set database = salt['grains.filter_by']({
-    'Debian': {
-        'pkgs': ['cassandra', 'zookeeper', 'supervisor', 'openjdk-7-jre-headless','contrail-database'],
-        'cassandra_config': '/etc/cassandra/',
-        'services': ['supervisord-contrail-database','zookeeper']
-    },
-    'RedHat': {
-        'pkgs': ['contrail-openstack-database', 'zookeeper', 'supervisor', 'java-1.7.0-openjdk-headless'],
-        'cassandra_config': '/etc/cassandra/conf/',
-        'services': ['supervisord-contrail-database','zookeeper']
-    },
-}, merge=pillar.opencontrail.get('database', {})) %}
-
-{% set web = salt['grains.filter_by']({
-    'Debian': {
-        'pkgs': ['contrail-web-controller', 'nodejs-legacy', 'gettext-base'],
-        'services': ['contrail-webui-webserver','contrail-webui-jobserver']
-    },
-    'RedHat': {
-        'pkgs': ['contrail-web-controller'],
-        'services': ['supervisor-webui']
-    },
-}, merge=pillar.opencontrail.get('web', {})) %}
-
-{% set tor = salt['grains.filter_by']({
-    'Debian': {
-        'agents': 1,
-        'bind': {
-           'port': 8086
-        }
-    },
-}, merge=salt['pillar.get']('opencontrail:tor')) %}
-
-{% set client = salt['grains.filter_by']({
-    'Debian': {
-        'pkgs': ['python-contrail'],
-    }
-}, merge=pillar.opencontrail.get('client', {})) %}
diff --git a/opencontrail/web.sls b/opencontrail/web.sls
index 0a5f2da..7d9105b 100644
--- a/opencontrail/web.sls
+++ b/opencontrail/web.sls
@@ -4,6 +4,7 @@
 opencontrail_web_packages:
   pkg.installed:
   - names: {{ web.pkgs }}
+  - force_yes: True
 
 /etc/contrail/config.global.js:
   file.managed:
@@ -42,4 +43,4 @@
 
 {%- endif %}
 
-{%- endif %}
\ No newline at end of file
+{%- endif %}
diff --git a/tests/pillar/cluster.sls b/tests/pillar/cluster.sls
index 29e22c9..ada4df8 100644
--- a/tests/pillar/cluster.sls
+++ b/tests/pillar/cluster.sls
@@ -68,6 +68,7 @@
   control:
     version: 3.0
     enabled: true
+    name: ntw-01
     bind:
       address: 127.0.0.1
     discovery:
@@ -126,6 +127,8 @@
   web:
     version: 3.0
     enabled: True
+    network:
+      host: 127.0.0.1
     bind:
       address: 127.0.0.1
     master:
diff --git a/tests/pillar/control.sls b/tests/pillar/control.sls
index 3ba9d34..1ae5ac9 100644
--- a/tests/pillar/control.sls
+++ b/tests/pillar/control.sls
@@ -65,6 +65,7 @@
   control:
     version: 3.0
     enabled: true
+    name: ntw-01
     bind:
       address: 127.0.0.1
     discovery:
@@ -79,7 +80,7 @@
     - host: 127.0.0.1
       id: 3
   database:
-    version: 127.0.0.1
+    version: 3.0
     cassandra:
       version: 2
     enabled: true
@@ -105,6 +106,8 @@
   web:
     version: 3.0
     enabled: True
+    network:
+      host: 127.0.0.1
     bind:
       address: 127.0.0.1
     analytics:
diff --git a/tests/pillar/repo_cassandra.sls b/tests/pillar/repo_cassandra.sls
new file mode 100644
index 0000000..8ece8a8
--- /dev/null
+++ b/tests/pillar/repo_cassandra.sls
@@ -0,0 +1,9 @@
+linux:
+  system:
+    repo:
+      cassandra-21x:
+        source: "deb [arch=amd64] http://www.apache.org/dist/cassandra/debian 21x main"
+        architectures: amd64
+        key_server: pool.sks-keyservers.net
+        key_id: A278B781FE4B2BDA
+
diff --git a/tests/pillar/repo_mos8.sls b/tests/pillar/repo_mos8.sls
new file mode 100644
index 0000000..3b53e53
--- /dev/null
+++ b/tests/pillar/repo_mos8.sls
@@ -0,0 +1,23 @@
+linux:
+  system:
+    repo:
+      mirantis_openstack:
+        source: "deb [arch=amd64] http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/ mos8.0 main restricted"
+        architectures: amd64
+        key_url: "http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/archive-mos8.0.key"
+      #mirantis_openstack_hotfix:
+        #source: "deb http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/ mos8.0-hotfix main restricted"
+        #architectures: amd64
+        #key_url: "http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/archive-mos8.0.key"
+      #mirantis_openstack_proposed:
+        #source: "deb http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/ mos8.0-proposed main restricted"
+        #architectures: amd64
+        #key_url: "http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/archive-mos8.0.key"
+      #mirantis_openstack_security:
+        #source: "deb http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/ mos8.0-security main restricted"
+        #architectures: amd64
+        #key_url: "http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/archive-mos8.0.key"
+      #mirantis_openstack_updates:
+        #source: "deb http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/ mos8.0-updates main restricted"
+        #architectures: amd64
+        #key_url: "http://mirror.fuel-infra.org/mos-repos/ubuntu/8.0-mu-3/archive-mos8.0.key"
diff --git a/tests/pillar/repo_mos9.sls b/tests/pillar/repo_mos9.sls
new file mode 100644
index 0000000..90df22d
--- /dev/null
+++ b/tests/pillar/repo_mos9.sls
@@ -0,0 +1,19 @@
+linux:
+  system:
+    repo:
+      mirantis_openstack:
+        source: "deb [arch=amd64] http://mirror.fuel-infra.org/mos-repos/ubuntu/9.0/ mos9.0 main restricted"
+        architectures: amd64
+        key_url: "http://mirror.fuel-infra.org/mos-repos/ubuntu/9.0/archive-mos9.0.key"
+      #mirantis_openstack_hotfix:
+        #source: "deb http://mirror.fuel-infra.org/mos-repos/ubuntu/9.0/ mos9.0-hotfix main restricted"
+        #architectures: amd64
+        #key_url: "http://mirror.fuel-infra.org/mos-repos/ubuntu/9.0/archive-mos9.0.key"
+      #mirantis_openstack_security:
+        #source: "deb http://mirror.fuel-infra.org/mos-repos/ubuntu/9.0/ mos9.0-security main restricted"
+        #architectures: amd64
+        #key_url: "http://mirror.fuel-infra.org/mos-repos/ubuntu/9.0/archive-mos9.0.key"
+      #mirantis_openstack_updates:
+        #source: "deb http://mirror.fuel-infra.org/mos-repos/ubuntu/9.0/ mos9.0-updates main restricted"
+        #architectures: amd64
+        #key_url: "http://mirror.fuel-infra.org/mos-repos/ubuntu/9.0/archive-mos9.0.key"
diff --git a/tests/pillar/single.sls b/tests/pillar/single.sls
index faba0dc..e04824e 100644
--- a/tests/pillar/single.sls
+++ b/tests/pillar/single.sls
@@ -54,6 +54,7 @@
     - host: 127.0.0.1
       id: 1
   control:
+    name: ntw-01
     version: 3.0
     enabled: true
     bind:
@@ -102,6 +103,8 @@
   web:
     version: 3.0
     enabled: True
+    network:
+      host: 127.0.0.1
     bind:
       address: 127.0.0.1
     analytics:
diff --git a/tests/pillar/tor.sls b/tests/pillar/tor.sls
index a14ce11..04ecba0 100644
--- a/tests/pillar/tor.sls
+++ b/tests/pillar/tor.sls
@@ -21,3 +21,15 @@
       address: 127.0.0.1
     device:
       host: 127.0.0.1
+  compute:
+    enabled: true
+    version: 3.0
+    discovery:
+      host: 127.0.0.1
+    interface:
+      address: 127.0.0.1
+      dev: eth0
+      gateway: 127.0.0.1
+      mask: /24
+      dns: 127.0.0.1
+      mtu: 9000
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 8c07e58..a4cac88 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -44,6 +44,7 @@
     [ ! -d ${SALT_PILLAR_DIR} ] && mkdir -p ${SALT_PILLAR_DIR}
     echo "base:" > ${SALT_PILLAR_DIR}/top.sls
     for pillar in ${PILLARDIR}/*; do
+        grep ${FORMULA_NAME}: ${pillar} &>/dev/null || continue
         state_name=$(basename ${pillar%.sls})
         echo -e "  ${state_name}:\n    - ${state_name}" >> ${SALT_PILLAR_DIR}/top.sls
     done
@@ -56,6 +57,7 @@
 
     echo "base:" > ${SALT_FILE_DIR}/top.sls
     for pillar in ${PILLARDIR}/*.sls; do
+        grep ${FORMULA_NAME}: ${pillar} &>/dev/null || continue
         state_name=$(basename ${pillar%.sls})
         echo -e "  ${state_name}:\n    - ${FORMULA_NAME}" >> ${SALT_FILE_DIR}/top.sls
     done
@@ -126,6 +128,7 @@
 
 run() {
     for pillar in ${PILLARDIR}/*.sls; do
+        grep ${FORMULA_NAME}: ${pillar} &>/dev/null || continue
         state_name=$(basename ${pillar%.sls})
         salt_run --id=${state_name} state.show_sls ${FORMULA_NAME} || (log_err "Execution of ${FORMULA_NAME}.${state_name} failed"; exit 1)
     done