Environment model level

Environment model is a mapping of the hardware objects specified
in the inventory on the cluster model objects.

Based on the inventory, environment model provides ability to use
flexible underlay configuration per each node.

Using 'roles' for nodes allows to map the additional components
on the basic cluster configuration using only inventory labels
or tags (creating the inventory file for this template from the
customer's inventory depends on each specific case and may require
additional translation code).

* environment_inventory: collection of already existing
  hardware and virtual inventories for different lab configuration
* environment_template: cookiecutter template to generate
  environment model with any required configuration

Change-Id: I3c97957f94f472b634ece5d218fdc14fed185058
Reviewed-on: https://review.gerrithub.io/374868
Reviewed-by: Dennis Dmitriev <dis.xcom@gmail.com>
Tested-by: Dennis Dmitriev <dis.xcom@gmail.com>
diff --git a/tcp_tests/environment/environment_inventory/lab03_physical_inventory.yaml b/tcp_tests/environment/environment_inventory/lab03_physical_inventory.yaml
new file mode 100644
index 0000000..d6805f8
--- /dev/null
+++ b/tcp_tests/environment/environment_inventory/lab03_physical_inventory.yaml
@@ -0,0 +1,95 @@
+nodes:
+    # Physical nodes
+
+    kvm01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: infra_kvm_node01
+      roles:
+      - infra_kvm
+      - linux_system_codename_xenial
+      interfaces:
+        enp3s0f0:
+          role: management_single
+        enp3s0f1:
+          role: control_bond0
+
+    kvm02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: infra_kvm_node02
+      roles:
+      - infra_kvm
+      - linux_system_codename_xenial
+      interfaces:
+        eno1:
+          role: management_single
+        eno2:
+          role: control_bond0
+
+    kvm03.mcp11-ovs-dpdk.local:
+      reclass_storage_name: infra_kvm_node03
+      roles:
+      - infra_kvm
+      - linux_system_codename_xenial
+      interfaces:
+        eno1:
+          role: management_single
+        eno2:
+          role: control_bond0
+
+    cmp001.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_compute_node01
+      roles:
+      - openstack_compute
+      - linux_system_codename_xenial
+      interfaces:
+        enp3s0f0:
+          role: management_single
+        enp3s0f1:
+          role: control_bond0
+        enp5s0f0:
+          role: control_bond0
+        enp5s0f1:
+          role: private_dpdk_ovs
+          dpdk_pci: '0000:05:00.1'
+        enp5s0f2:
+          role: private_dpdk_ovs
+          dpdk_pci: '0000:05:00.2'
+
+    cmp002.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_compute_node02
+      roles:
+      - openstack_compute
+      - linux_system_codename_xenial
+      interfaces:
+        eno1:
+          role: management_single
+        eth0:
+          role: control_bond0
+        eth3:
+          role: control_bond0
+        eth2:
+          role: private_dpdk_ovs
+          dpdk_pci: '0000:05:00.1'
+        eth4:
+          role: private_dpdk_ovs
+          dpdk_pci: '0000:0b:00.0'
+
+    gtw01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_gateway_node01
+      roles:
+      - openstack_gateway
+      - linux_system_codename_xenial
+      interfaces:
+        enp2s0f0:
+          role: management_single
+        enp2s0f1:
+          role: control_floating_bond0_ovs
+
+    gtw02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_gateway_node02
+      roles:
+      - openstack_gateway
+      - linux_system_codename_xenial
+      interfaces:
+        enp2s0f0:
+          role: management_single
+        enp2s0f1:
+          role: control_floating_bond0_ovs
diff --git a/tcp_tests/environment/environment_inventory/vcp_os_sl_inventory.yaml b/tcp_tests/environment/environment_inventory/vcp_os_sl_inventory.yaml
new file mode 100644
index 0000000..78c6ba6
--- /dev/null
+++ b/tcp_tests/environment/environment_inventory/vcp_os_sl_inventory.yaml
@@ -0,0 +1,209 @@
+nodes:
+    # Virtual Control Plane nodes
+
+    ctl01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_control_node01
+      roles:
+      - openstack_control_leader
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    ctl02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_control_node02
+      roles:
+      - openstack_control
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    ctl03.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_control_node03
+      roles:
+      - openstack_control
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    dbs01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_database_node01
+      roles:
+      - openstack_database_leader
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    dbs02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_database_node01
+      roles:
+      - openstack_database
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    dbs03.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_database_node01
+      roles:
+      - openstack_database
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    msg01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_message_queue_node01
+      roles:
+      - openstack_message_queue
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    msg02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_message_queue_node02
+      roles:
+      - openstack_message_queue
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    msg03.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_message_queue_node03
+      roles:
+      - openstack_message_queue
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    mdb01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_telemetry_node01
+      roles:
+      - openstack_telemetry
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    mdb02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_telemetry_node02
+      roles:
+      - openstack_telemetry
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    mdb03.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_telemetry_node03
+      roles:
+      - openstack_telemetry
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    prx01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_proxy_node01
+      roles:
+      - openstack_proxy
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    prx02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_proxy_node02
+      roles:
+      - openstack_proxy
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    mon01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: stacklight_monitor_node01
+      roles:
+      - stacklight_monitor_leader
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    mon02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: stacklight_monitor_node02
+      roles:
+      - stacklight_monitor
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    mon03.mcp11-ovs-dpdk.local:
+      reclass_storage_name: stacklight_monitor_node03
+      roles:
+      - stacklight_monitor
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    mtr01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: stacklight_telemetry_node01
+      roles:
+      - stacklight_telemetry
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    mtr02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: stacklight_telemetry_node02
+      roles:
+      - stacklight_telemetry
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    mtr03.mcp11-ovs-dpdk.local:
+      reclass_storage_name: stacklight_telemetry_node03
+      roles:
+      - stacklight_telemetry
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    log01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: stacklight_log_node01
+      roles:
+      - stacklight_log_leader
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    log02.mcp11-ovs-dpdk.local:
+      reclass_storage_name: stacklight_log_node02
+      roles:
+      - stacklight_log
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+
+    log03.mcp11-ovs-dpdk.local:
+      reclass_storage_name: stacklight_log_node03
+      roles:
+      - stacklight_log
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
diff --git a/tcp_tests/environment/environment_template/readme.txt b/tcp_tests/environment/environment_template/readme.txt
new file mode 100644
index 0000000..1804bb0
--- /dev/null
+++ b/tcp_tests/environment/environment_template/readme.txt
@@ -0,0 +1,111 @@
+Render the template
+-------------------
+
+Use reclass_tools from [1] to render the template.
+
+<env_name> : any name for newly created environment model
+<path_to_template> : path to the directory with the cookiecutter template, for example 'tcp-qa/tcp_tests/environment/environment_template'
+<destination_path> : path to directory where will be created the new environment model
+<inventory_fileN> : path to the YAML with the inventory data. Can be specified multiple times to use different parts of the inventory. VCP inventory must be specified for current workflow (when all linux.network.interface are deleted)
+
+
+```
+reclass-tools render -e <env_name> -t <path_to_template> -o <destination_path> -c <inventory_file1> -c <inventory_file2> [...] -c <inventory_fileN>
+```
+
+To attach the environment model to any cluster, use the instructions from [1]
+
+[1] https://github.com/dis-xcom/reclass_tools
+
+
+Template architecture
+---------------------
+
+```
+└── environment_template
+    ├── {{ cookiecutter._env_name }}
+    │   ├── init.yml
+    │   ├── linux_network_interface.yml
+    │   ├── linux_system_codename_trusty.yml
+    │   ├── linux_system_codename_xenial.yml
+    │   ├── {# interfaces #} -> ../{# interfaces #}
+    │   └── {# roles #} -> ../{# roles #}
+    ├── {# interfaces #}
+    │   └── ...
+    └── {# roles #}
+        └── ...
+```
+
+* {{ cookiecutter._env_name }} : folder that will be used to generate the new Environment model, contains:
+
+  - init.yml : file that will be filled with reclass:storage:node pillars generated using inventory files. This is the main file that must be
+               included to cfg01.* node before generating the reclass inventory with the salt state 'reclass.storage'.
+
+  - linux_network_interface.yml : it is a workaround to make possible to pass the linux:network:interface configuration separatelly for each node.
+                                  This is because reclass.storage state works only with parameters:_param:* pillars and cannot be used
+                                  to add any other pillar data to parameters:* (for example, parameters:linux:network:interface).
+                                  So, linux network interface configuration is stored in the intermediate variable parameters:_param:linux_network_interfaces
+                                  for each node, and then included to the parameters:linux:network:interface using this file as a class attached
+                                  to each node by default.
+  - linux_system_codename_*.yml : A class with a single variable. Allows to specify the specific linux version using only node role.
+
+  - {# interfaces #} : symlink to the {# interfaces #} folder outside of the cookiecutter template directory, to not pass it's content to the
+                       resulting model during the model rendering.
+
+  - {# roles #} : symlink to the {# roles #} folder outside of the cookiecutter template directory, to not pass it's content to the
+                  resulting model during the model rendering.
+
+* {# interfaces #} : Interface role means the name of the file that will be included and rendered.
+                     Contains *text* patterns of YAML file that are included to the init.yml under linux_network_interface: parameters
+                     using Jinja.
+                     Each pattern provides the mapping of the physical interfaces which have the same role on some logical networking objects
+                     (OVS, bonds, bridges, ...). These networking objects provide the Underlay interfaces used for upcoming cluster architecture.
+
+* {# roles #} : Node roles mean the name of the files that will be included and rendered under the 'classes:' object.
+                Contains *text* patterns of YAML file that are included to the init.yml and must provide only the
+                list of the classes for the specific node.
+
+In the init.yml is defined a dict variable 'params' that is accessible from files in {# interfaces #} and {# roles #}.
+'params' may be used by Jinja expressions in these folders to generate some additional dynamic 'parameters:_param' pillars that cannot be specified
+as a fixed value in a class.
+
+If you need to specify a fixed values, please do the following:
+- add a new class file *.yml file next to the init.yml with the necessary *FIXED* parameters (example: linux_system_codename_xenial.yml)
+- add a node role to the {# roles #} directory that will include your environment.{{ cookiecutter._env_name }}.<class file from first step>
+- use the created node role in the inventory for required nodes
+
+
+Inventory examples
+------------------
+
+Inventory must include all the nodes, physical or virtual.
+'reclass_storage_name' is used for back compatibility until some parameters
+are still inherited from the cluster/system level of the reclass:storage pillars.
+
+Physical node example:
+```
+nodes:
+    kvm01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: infra_kvm_node01
+      roles:
+      - infra_kvm
+      - linux_system_codename_xenial
+      interfaces:
+        enp3s0f0:
+          role: management_single
+        enp3s0f1:
+          role: control_bond0
+```
+
+Virtual Control Plane node example:
+```
+nodes:
+    ctl01.mcp11-ovs-dpdk.local:
+      reclass_storage_name: openstack_control_node01
+      roles:
+      - openstack_control_leader
+      - linux_system_codename_xenial
+      interfaces:
+        ens3:
+          role: control_vcp_single
+```
diff --git "a/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/.cookiecutter_compute.yml" "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/.cookiecutter_compute.yml"
new file mode 100644
index 0000000..6fbf04f
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/.cookiecutter_compute.yml"
@@ -0,0 +1,226 @@
+classes:
+{%- if cookiecutter.get('local_repositories', 'False') == 'True' %}
+- system.linux.system.repo_local.ubuntu
+- system.linux.system.repo_local.mcp.openstack
+- system.linux.system.repo_local.mcp.extra
+{%- if cookiecutter.openstack_network_engine == 'opencontrail' %}
+- system.linux.system.repo_local.mcp.contrail
+{%- endif %}
+{%- else %}
+- system.linux.system.repo.ubuntu
+- system.linux.system.repo.saltstack.xenial
+- system.linux.system.repo.mcp.openstack
+- system.linux.system.repo.mcp.extra
+{%- if cookiecutter.openstack_network_engine == 'opencontrail' %}
+- system.linux.system.repo.mcp.contrail
+{%- endif %}
+{%- endif %}
+{%- if cookiecutter.get('openstack_nova_compute_nfv_req_enabled', 'False') == 'True' or cookiecutter.get('openstack_nfv_dpdk_enabled', 'False') == 'True' %}
+- system.nova.compute.nfv.hugepages
+- system.nova.compute.nfv.cpu_pinning
+{%- endif %}
+- system.nova.compute.cluster
+{%- if cookiecutter.openstack_network_engine == 'opencontrail' %}
+- system.opencontrail.compute.cluster
+- system.opencontrail.client.cluster
+- system.opencontrail.client.resource.virtual_router
+{%- elif cookiecutter.openstack_network_engine == 'ovs' %}
+- system.neutron.compute.cluster
+{%- endif %}
+- system.ceilometer.agent.cluster
+- cluster.{{ cookiecutter.cluster_name }}.infra
+parameters:
+  _param:
+    cluster_vip_address: ${_param:openstack_control_address}
+    cluster_local_address: ${_param:single_address}
+    cluster_node01_hostname: ${_param:openstack_control_node01_hostname}
+    cluster_node01_address: ${_param:openstack_control_node01_address}
+    cluster_node02_hostname: ${_param:openstack_control_node02_hostname}
+    cluster_node02_address: ${_param:openstack_control_node02_address}
+    cluster_node03_hostname: ${_param:openstack_control_node03_hostname}
+    cluster_node03_address: ${_param:openstack_control_node03_address}
+{%- if cookiecutter.openstack_network_engine == 'opencontrail' %}
+    opencontrail_compute_address: ${_param:tenant_address}
+{%- endif %}
+    nova_vncproxy_url: https://${_param:cluster_public_host}:6080
+    primary_first_nic: {{ cookiecutter.compute_primary_first_nic }}
+    primary_second_nic: {{ cookiecutter.compute_primary_second_nic }}
+
+  linux:
+    network:
+      host:
+        hostname:
+          address: ${_param:single_address}
+          names:
+          - ${linux:network:hostname}
+          - ${linux:network:fqdn}
+      interface:
+  {%- if not cookiecutter.get('openstack_nfv_dpdk_enabled', 'False') == 'True' %}
+        eth1:
+          mtu: 9000
+          enabled: true
+          type: slave
+          proto: manual
+          name: ${_param:primary_first_nic}
+          master: bond0
+        eth2:
+          mtu: 9000
+          enabled: true
+          type: slave
+          proto: manual
+          name: ${_param:primary_second_nic}
+          master: bond0
+    {%- if cookiecutter.openstack_network_engine == 'ovs' %}
+      {%- if not cookiecutter.openstack_ovs_dvr_enabled == 'True' %}
+        {%- if cookiecutter.openstack_ovs_encapsulation_type == 'vxlan' %}
+        bond0:
+          enabled: true
+          proto: manual
+          type: bond
+          use_interfaces:
+          - ${_param:primary_second_nic}
+          - ${_param:primary_first_nic}
+          slaves: ${_param:primary_second_nic} ${_param:primary_first_nic}
+          mode: {{ cookiecutter.compute_bond_mode }}
+        bond0.1:
+          name: bond0.${_param:control_vlan}
+          enabled: true
+          type: vlan
+          proto: static
+          address: ${_param:single_address}
+          netmask: ${_param:control_network_netmask}
+          use_interfaces:
+          - bond0
+        bond0.2:
+          name: bond0.${_param:tenant_vlan}
+          enabled: true
+          type: vlan
+          proto: manual
+          use_interfaces:
+          - bond0
+        br-mesh:
+          enabled: true
+          type: bridge
+          address: ${_param:tenant_address}
+          netmask: ${_param:tenant_network_netmask}
+          use_interfaces:
+          - bond0.${_param:tenant_vlan}
+        {%- elif cookiecutter.openstack_ovs_encapsulation_type == 'vlan' %}
+        bond0:
+          enabled: true
+          proto: manual
+          ovs_bridge: br-prv
+          ovs_type: OVSPort
+          type: bond
+          use_interfaces:
+          - ${_param:primary_second_nic} ${_param:primary_first_nic}
+          slaves: ${_param:primary_first_nic}
+          mode: {{ cookiecutter.compute_bond_mode }}
+        br-prv:
+          enabled: true
+          type: ovs_bridge
+        br-mgmt:
+          enabled: true
+          type: ovs_port
+          bridge: br-prv
+          proto: static
+          ovs_options: tag=${_param:control_vlan}
+          address: ${_param:single_address}
+          netmask: ${_param:control_network_netmask}
+        {%- endif %}
+      {%- elif cookiecutter.openstack_ovs_dvr_enabled == 'True' %}
+        bond0:
+          enabled: true
+          proto: manual
+          ovs_bridge: br-floating
+          ovs_type: OVSPort
+          type: bond
+          use_interfaces:
+          - ${_param:primary_first_nic}
+          - ${_param:primary_second_nic}
+          slaves: ${_param:primary_first_nic} ${_param:primary_second_nic}
+          mode: {{ cookiecutter.compute_bond_mode }}
+        br-floating:
+          enabled: true
+          type: ovs_bridge
+        br-mgmt:
+          enabled: true
+          type: ovs_port
+          bridge: br-floating
+          proto: static
+          ovs_options: tag=${_param:control_vlan}
+          address: ${_param:single_address}
+          netmask: ${_param:control_network_netmask}
+        {%- if cookiecutter.openstack_ovs_encapsulation_type == 'vxlan' %}
+        br-mesh:
+          enabled: true
+          type: ovs_port
+          bridge: br-floating
+          proto: static
+          ovs_options: tag=${_param:tenant_vlan}
+          address: ${_param:tenant_address}
+          netmask: ${_param:tenant_network_netmask}
+        {%- elif cookiecutter.openstack_ovs_encapsulation_type == 'vlan' %}
+        br-prv:
+          enabled: true
+          type: ovs_bridge
+        floating-to-prv:
+          enabled: true
+          type: ovs_port
+          port_type: patch
+          bridge: br-floating
+          peer: prv-to-floating
+        prv-to-floating:
+          enabled: true
+          type: ovs_port
+          port_type: patch
+          bridge: br-prv
+          peer: floating-to-prv
+        {%- endif %}
+      {%- endif %}
+      bridge: openvswitch
+    {%- elif cookiecutter.openstack_network_engine == 'opencontrail' %}
+        bond0:
+          mtu: 9000
+          enabled: true
+          proto: manual
+          type: bond
+          use_interfaces:
+          - ${_param:primary_first_nic}
+          - ${_param:primary_second_nic}
+          slaves: ${_param:primary_first_nic} ${_param:primary_second_nic}
+          mode: {{ cookiecutter.compute_bond_mode }}
+        bond0.1:
+          mtu: 9000
+          name: bond0.${_param:control_vlan}
+          enabled: true
+          proto: static
+          type: vlan
+          use_interfaces:
+          - bond0
+          address: ${_param:single_address}
+          netmask: ${_param:control_network_netmask}
+        bond0.2:
+          mtu: 9000
+          name: bond0.${_param:tenant_vlan}
+          enabled: true
+          proto: manual
+          type: vlan
+          use_interfaces:
+          - bond0
+        vhost0:
+          enabled: true
+          type: eth
+          mtu: 9000
+          address: ${_param:tenant_address}
+          netmask: ${_param:tenant_network_netmask}
+          gateway: ${_param:tenant_network_gateway}
+          pre_up_cmds:
+          - /usr/lib/contrail/if-vhost0
+          use_interfaces:
+          - bond0.${_param:tenant_vlan}
+          name_servers:
+          - ${_param:dns_server01}
+          - ${_param:dns_server02}
+    {%- endif %}
+  {%- endif %}
diff --git "a/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/.cookiecutter_gateway.yml" "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/.cookiecutter_gateway.yml"
new file mode 100644
index 0000000..0a3c62e
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/.cookiecutter_gateway.yml"
@@ -0,0 +1,88 @@
+{%- if cookiecutter.openstack_network_engine == 'ovs' %}
+classes:
+{%- if cookiecutter.get('local_repositories', 'False') == 'True' %}
+- system.linux.system.repo_local.mcp.openstack
+- system.linux.system.repo_local.mcp.extra
+- system.linux.system.repo_local.saltstack.xenial
+{%- else %}
+- system.linux.system.repo.mcp.openstack
+- system.linux.system.repo.mcp.extra
+- system.linux.system.repo.saltstack.xenial
+{%- endif %}
+- system.neutron.gateway.cluster
+- cluster.{{ cookiecutter.cluster_name }}.infra
+parameters:
+  _param:
+    interface_mtu: 1500
+    cluster_vip_address: ${_param:openstack_control_address}
+
+    linux_system_codename: xenial
+    keepalived_vip_interface: br-ctl
+    keepalived_vip_virtual_router_id: 69
+    primary_first_nic: {{ cookiecutter.gateway_primary_first_nic }}
+    primary_second_nic: {{ cookiecutter.gateway_primary_second_nic }}
+  linux:
+    network:
+      bridge: openvswitch
+      interface:
+        eth1:
+          enabled: true
+          type: slave
+          proto: manual
+          name: ${_param:primary_first_nic}
+          master: bond0
+        eth2:
+          enabled: true
+          type: slave
+          proto: manual
+          name: ${_param:primary_second_nic}
+          master: bond0
+        bond0:
+          enabled: true
+          proto: manual
+          ovs_bridge: br-floating
+          ovs_type: OVSPort
+          type: bond
+          use_interfaces:
+          - ${_param:primary_first_nic}
+          - ${_param:primary_second_nic}
+          slaves: ${_param:primary_first_nic} ${_param:primary_second_nic}
+          mode: active-backup
+        br-floating:
+          enabled: true
+          type: ovs_bridge
+        br-ctl:
+          enabled: true
+          type: ovs_port
+          bridge: br-floating
+          proto: static
+          ovs_options: tag=${_param:control_vlan}
+          address: ${_param:single_address}
+          netmask: ${_param:control_network_netmask}
+        {%- if cookiecutter.openstack_ovs_encapsulation_type == 'vxlan' %}
+        br-mesh:
+          enabled: true
+          type: ovs_port
+          bridge: br-floating
+          proto: static
+          ovs_options: tag=${_param:tenant_vlan}
+          address: ${_param:tenant_address}
+          netmask: ${_param:tenant_network_netmask}
+        {%- elif cookiecutter.openstack_ovs_encapsulation_type == 'vlan' %}
+        br-prv:
+          enabled: true
+          type: ovs_bridge
+        floating-to-prv:
+          enabled: true
+          type: ovs_port
+          port_type: patch
+          bridge: br-floating
+          peer: prv-to-floating
+        prv-to-floating:
+          enabled: true
+          type: ovs_port
+          port_type: patch
+          bridge: br-prv
+          peer: floating-to-prv
+        {%- endif %}
+{%- endif %}
diff --git "a/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/control_bond0" "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/control_bond0"
new file mode 100644
index 0000000..38874e5
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/control_bond0"
@@ -0,0 +1,42 @@
+
+              # {{ interfaces_role }}
+              {%- for interface_name, interface in interfaces.items() %}
+              {{ interface_name }}:
+                enabled: true
+                name: {{ interface_name }}
+                proto: manual
+                type: eth
+                ipflush_onchange: true
+              {%- endfor %}
+              bond0:
+                enabled: true
+                mode: active-backup
+                proto: manual
+                slaves: {{ ' '.join(interfaces.keys()) }}
+                type: bond
+                use_interfaces:
+                {%- for interface_name in interfaces.keys() %}
+                - {{ interface_name }}
+                {%- endfor %}
+                require_interfaces:
+                {%- for interface_name in interfaces.keys() %}
+                - {{ interface_name }}
+                {%- endfor %}
+              bond0.2416:
+                enabled: true
+                proto: manual
+                type: vlan
+                use_interfaces:
+                - bond0
+                require_interfaces:
+                - bond0
+              br_ctl:
+                address: ${_param:_esc}{_param:single_address}
+                enabled: true
+                netmask: 255.255.255.0
+                proto: static
+                type: bridge
+                use_interfaces:
+                - bond0.2416
+                require_interfaces:
+                - bond0.2416
diff --git "a/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/control_floating_bond0_ovs" "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/control_floating_bond0_ovs"
new file mode 100644
index 0000000..e13b2ea
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/control_floating_bond0_ovs"
@@ -0,0 +1,61 @@
+
+              # {{ interfaces_role }}
+              {%- for interface_name, interface in interfaces.items() %}
+              {{ interface_name }}:
+                enabled: true
+                master: bond0  # ?
+                name: {{ interface_name }}
+                proto: manual
+                type: slave  # ?
+                ipflush_onchange: true
+              {%- endfor %}
+              bond0:
+                enabled: true
+                mode: active-backup
+                ovs_bridge: br-floating
+                ovs_type: OVSPort
+                proto: manual
+                slaves: {{ ' '.join(interfaces.keys()) }}
+                type: bond
+                use_interfaces:
+                {%- for interface_name in interfaces.keys() %}
+                - {{ interface_name }}
+                {%- endfor %}
+                require_interfaces:
+                {%- for interface_name in interfaces.keys() %}
+                - {{ interface_name }}
+                {%- endfor %}
+              br-floating:
+                enabled: true
+                type: ovs_bridge
+              br-prv:
+                enabled: true
+                type: ovs_bridge
+              br_ctl:
+                address: ${_param:_esc}{_param:single_address}
+                bridge: br-floating
+                enabled: true
+                netmask: 255.255.255.0
+                ovs_options: tag=2416
+                proto: static
+                type: ovs_port
+                require_interfaces:
+                - br-floating
+              floating-to-prv:
+                bridge: br-floating
+                enabled: true
+                peer: prv-to-floating
+                port_type: patch
+                type: ovs_port
+                require_interfaces:
+                - br-prv
+                - br-floating
+              prv-to-floating:
+                bridge: br-prv
+                enabled: true
+                peer: floating-to-prv
+                port_type: patch
+                type: ovs_port
+                require_interfaces:
+                - br-prv
+                - br-floating
diff --git "a/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/control_vcp_single" "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/control_vcp_single"
new file mode 100644
index 0000000..39c0808
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/control_vcp_single"
@@ -0,0 +1,4 @@
+
+              # {{ interfaces_role }}
+              {%- set interface_name = interfaces.keys()[0] %}
+              {{ interface_name }}: ${_param:_esc}{_param:linux_single_interface}
diff --git "a/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/management_single" "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/management_single"
new file mode 100644
index 0000000..f09890f
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/management_single"
@@ -0,0 +1,21 @@
+
+              # {{ interfaces_role }}
+              {%- set interface_name = interfaces.keys()[0] %}
+              {{ interface_name }}:
+                enabled: true
+                name: {{ interface_name }}
+                proto: manual
+                type: eth
+                ipflush_onchange: true
+              br_mgm:
+                address: ${_param:_esc}{_param:deploy_address}
+                enabled: true
+                gateway: 172.16.49.1
+                name_servers:
+                - 8.8.8.8
+                - 8.8.4.4
+                netmask: 255.255.255.192
+                proto: static
+                type: bridge
+                use_interfaces:
+                - {{ interface_name }}
diff --git "a/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/private_dpdk_ovs" "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/private_dpdk_ovs"
new file mode 100644
index 0000000..de0e46d
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 interfaces \043\175/private_dpdk_ovs"
@@ -0,0 +1,22 @@
+
+              # {{ interfaces_role }}
+              {%- for interface_name, interface in interfaces.items() %}
+              {{ interface_name }}:
+                bond: dpdkbond1
+                driver: igb_uio
+                enabled: true
+                n_rxq: 2
+                name: {{ interface_name }}
+                pci: '{{ interface['dpdk_pci'] }}'
+                type: dpdk_ovs_port
+              {%- endfor %}
+              dpdkbond1:
+                bridge: br-prv
+                enabled: true
+                mode: active-backup
+                type: dpdk_ovs_bond
+              br-prv:
+                address: ${_param:_esc}{_param:tenant_address}
+                enabled: true
+                netmask: 255.255.255.0
+                type: dpdk_ovs_bridge
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/infra_config" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/infra_config"
new file mode 100644
index 0000000..310b092
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/infra_config"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.infra.config
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/infra_kvm" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/infra_kvm"
new file mode 100644
index 0000000..93774b0
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/infra_kvm"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.infra.kvm
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/linux_network_interface" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/linux_network_interface"
new file mode 100644
index 0000000..9ab7824
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/linux_network_interface"
@@ -0,0 +1,23 @@
+{#- Collect interface roles and params into the following dict:
+ # interface_role:             # filename that will be included
+ #  interface_name:            # interface (eth0)
+ #    interface_param1: value  # optional parameters or empty dict
+ #    interface_param2: value
+ #    ...
+ #}
+{%- set interface_roles = {} %}
+{%- for interface_name, interface in node['interfaces'].items() %}
+  {%- if interface['role'] not in interface_roles %}
+    {%- set _ = interface_roles.update({interface['role']: {}}) %}
+  {%- endif %}
+  {%- set _ = interface_roles[interface['role']].update({interface_name: {}}) %}
+  {%- for param_name, param in interface.items() %}
+    {%- set _ = interface_roles[interface['role']][interface_name].update({param_name: param}) %}
+  {%- endfor %}
+{%- endfor %}
+{%- set _ = params.update({'linux_network_interfaces': "\n"}) %}
+{%- for interfaces_role, interfaces in interface_roles.items() %}
+  {%- import ("{# interfaces #}/" + interfaces_role) as interface with context %}
+  {%- set _ = params.update({'linux_network_interfaces': params['linux_network_interfaces'] + interface|string }) %}
+{%- endfor %}
+          - environment.{{ cookiecutter._env_name }}.linux_network_interface
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/linux_system_codename_trusty" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/linux_system_codename_trusty"
new file mode 100644
index 0000000..183f22c
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/linux_system_codename_trusty"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - environment.{{ cookiecutter._env_name }}.linux_system_codename_trusty
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/linux_system_codename_xenial" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/linux_system_codename_xenial"
new file mode 100644
index 0000000..1ce5d52
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/linux_system_codename_xenial"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - environment.{{ cookiecutter._env_name }}.linux_system_codename_xenial
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_compute" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_compute"
new file mode 100644
index 0000000..6665b76
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_compute"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.compute
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_compute_dpdk" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_compute_dpdk"
new file mode 100644
index 0000000..1585758
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_compute_dpdk"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.compute.dpdk
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_compute_sriov" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_compute_sriov"
new file mode 100644
index 0000000..2e512c4
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_compute_sriov"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.compute.sriov
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_control" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_control"
new file mode 100644
index 0000000..dcf605c
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_control"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.control
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_control_leader" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_control_leader"
new file mode 100644
index 0000000..935fd62
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_control_leader"
@@ -0,0 +1,10 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.control
+          - cluster.${_param:cluster_name}.openstack.control_init
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_database" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_database"
new file mode 100644
index 0000000..68aff16
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_database"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.database
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_database_leader" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_database_leader"
new file mode 100644
index 0000000..fa435ae
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_database_leader"
@@ -0,0 +1,10 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.database
+          - cluster.${_param:cluster_name}.openstack.database_init
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_gateway" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_gateway"
new file mode 100644
index 0000000..9521c1d
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_gateway"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.gateway
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_message_queue" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_message_queue"
new file mode 100644
index 0000000..a506c90
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_message_queue"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.message_queue
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_proxy" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_proxy"
new file mode 100644
index 0000000..2cb0710
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_proxy"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.proxy
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_telemetry" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_telemetry"
new file mode 100644
index 0000000..67e284b
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/openstack_telemetry"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.openstack.telemetry
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_log" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_log"
new file mode 100644
index 0000000..698ffbe
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_log"
@@ -0,0 +1,10 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.stacklight.log
+          - cluster.${_param:cluster_name}.stacklight.log_curator
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_log_leader" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_log_leader"
new file mode 100644
index 0000000..48c4b1c
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_log_leader"
@@ -0,0 +1,11 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.stacklight.log
+          - cluster.${_param:cluster_name}.stacklight.log_curator
+          - system.elasticsearch.client.single
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_monitor" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_monitor"
new file mode 100644
index 0000000..726ba7c
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_monitor"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.stacklight.monitor
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_monitor_leader" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_monitor_leader"
new file mode 100644
index 0000000..5cc8cb5
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_monitor_leader"
@@ -0,0 +1,11 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.stacklight.monitor
+          - system.grafana.client.single
+          - system.kibana.client.single
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_telemetry" "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_telemetry"
new file mode 100644
index 0000000..8b17922
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\043 roles \043\175/stacklight_telemetry"
@@ -0,0 +1,9 @@
+{#-
+parameters:
+  reclass:
+    storage:
+      node:
+        <reclass_storage_node_name>:
+          classes:
+#}
+          - cluster.${_param:cluster_name}.stacklight.telemetry
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/init.yml" "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/init.yml"
new file mode 100644
index 0000000..a5a83c5
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/init.yml"
@@ -0,0 +1,21 @@
+parameters:
+  reclass:
+    storage:
+      node:
+      {%- for inventory_node_name, node in nodes.items()|sort %}
+        {{ node['reclass_storage_name'] }}:
+        {%- set params = {} %}
+          classes:
+          {#- Default role linux_network_interface is added to each node #}
+          {%- for role in node.get('roles', []) + ['linux_network_interface'] %}
+            {%- include ("{# roles #}/" + role) %}
+          {%- endfor %}
+
+        {%- if params %}
+          params:
+          {%- for param_name, param in params.items() %}
+            {{ param_name }}: {{ param }}
+          {%- endfor %}
+        {%- endif %}
+
+      {%- endfor %}
diff --git "a/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/linux_network_interface.yml" "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/linux_network_interface.yml"
new file mode 100644
index 0000000..8474d17
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/linux_network_interface.yml"
@@ -0,0 +1,6 @@
+parameters:
+  # _param:
+  # Put overrides for any environment-specific variables here
+  linux:
+    network:
+      interface: ${_param:linux_network_interfaces}
diff --git "a/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/linux_system_codename_trusty.yml" "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/linux_system_codename_trusty.yml"
new file mode 100644
index 0000000..1510a00
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/linux_system_codename_trusty.yml"
@@ -0,0 +1,3 @@
+parameters:
+  _param:
+    linux_system_codename: trusty
diff --git "a/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/linux_system_codename_xenial.yml" "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/linux_system_codename_xenial.yml"
new file mode 100644
index 0000000..c78c0b9
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/linux_system_codename_xenial.yml"
@@ -0,0 +1,3 @@
+parameters:
+  _param:
+    linux_system_codename: xenial
diff --git "a/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/\173\043 interfaces \043\175" "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/\173\043 interfaces \043\175"
new file mode 120000
index 0000000..c95e61c
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/\173\043 interfaces \043\175"
@@ -0,0 +1 @@
+../{# interfaces #}
\ No newline at end of file
diff --git "a/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/\173\043 roles \043\175" "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/\173\043 roles \043\175"
new file mode 120000
index 0000000..c52ceb2
--- /dev/null
+++ "b/tcp_tests/environment/environment_template/\173\173 cookiecutter._env_name \175\175/\173\043 roles \043\175"
@@ -0,0 +1 @@
+../{# roles #}
\ No newline at end of file