members:
                 -
                   type: interface
-                  name: nic1
+                  name: {{ nics[role]['admin_network'] }}
                   # force the MAC address of the bridge to this interface
                   primary: true
                 {%- if 'public_network' in enabled_networks and vlans['public_network'] is number %}
                 {%- endif %}
             {%- else %}
               type: interface
-              name: nic1
+              name: {{ nics[role]['admin_network'] }}
             {%- endif %}
               use_dhcp: false
               dns_servers: {get_param: DnsServers}
                   next_hop: {get_param: ControlPlaneDefaultRoute}
                 {%- endif %}
 
-            {%- set nic_index = 2 %}
             {%- if 'private_network' in enabled_networks and vlans['private_network'] == 'native' %}
             {%- if ovs_dpdk_bridge == 'br-phy' and role == 'compute' %}
             -
               members:
                 -
                   type: interface
-                  name: nic{{ nic_index }}{% set nic_index = nic_index + 1 %}
+                  name: {{ nics[role]['private_network'] }}
                   # force the MAC address of the bridge to this interface
                   primary: true
             -
             {%- else %}
             -
               type: interface
-              name: nic{{ nic_index }}{% set nic_index = nic_index + 1 %}
+              name: {{ nics[role]['private_network'] }}
               use_dhcp: false
               addresses:
                 -
             {%- if 'public_network' in enabled_networks and external_net_type == 'interface' and vlans['public_network'] == 'native' %}
             -
               type: interface
-              name: nic{{ nic_index }}{% set nic_index = nic_index + 1 %}
+              name: {{ nics[role]['public_network'] }}
               {%- if role == 'controller' %}
               dns_servers: {get_param: DnsServers}
               {%- endif %}
               members:
                 -
                   type: interface
-                  name: nic{{ nic_index }}{% set nic_index = nic_index + 1 %}
+                  name: {{ nics[role]['public_network'] }}
                   # force the MAC address of the bridge to this interface
                   primary: true
               {%- if role == 'controller' %}
             {%- if 'storage_network' in enabled_networks and vlans['storage_network'] == 'native' %}
             -
               type: interface
-              name: nic{{ nic_index }}{% set nic_index = nic_index + 1 %}
+              name: {{ nics[role]['storage_network'] }}
               use_dhcp: false
               addresses:
                 -
             {%- if 'api_network' in enabled_networks and vlans['api_network'] == 'native' %}
             -
               type: interface
-              name: nic{{ nic_index }}{% set nic_index = nic_index + 1 %}
+              name: {{ nics[role]['api_network'] }}
               use_dhcp: false
               addresses:
                 -
 
   network_type: bridged
   bridged_interface: ''
   bond_interfaces: ''
+  compute_interface: nic1
+  controller_interface: nic1
   usable_ip_range: 192.0.2.11,192.0.2.99
   gateway: 192.0.2.1
   provisioner_ip: 192.0.2.1
   enabled: true
   vlan: native
   cidr: 11.0.0.0/24
+  compute_interface: nic2
+  controller_interface: nic2
 
 # "public" network is used for external connectivity.
 # The external network provides Internet access for virtual
   enabled: true
   network_type: ''
   bridged_interface: ''
+  compute_interface: nic3
+  controller_interface: nic3
   vlan: native
   cidr: 192.168.37.0/24
   gateway: 192.168.37.1
   enabled: true
   vlan: native
   cidr: 12.0.0.0/24
+  compute_interface: nic4
+  controller_interface: nic4
 
 #admin_network:
 #  enabled: true
 #  network_type: bridged                             #Indicates if this network will be bridged to an interface, or to a bond
 #  bridged_interface: ''                             #Interface to bridge to for installer VM
 #  bond_interfaces: ''                               #Interfaces to create bond with for installer VM
+#  compute_interface: nic4                           #Interface used for this network on the compute node.  Can either be logical nic name like "nic1" or real name like "eth1"
+#  controller_interface: nic4                        #Interface used for this network on the controller node.  Can either be logical nic name like "nic1" or real name like "eth1"
 #  vlan: native                                      #VLAN tag to use, native means none
 #  usable_ip_range: 192.0.2.11,192.0.2.99            #Usable ip range, if empty entire range is usable, ex. 192.168.1.10,192.168.1.20
 #  gateway: 192.0.2.1                                #Gateway (only needed when public_network is disabled), if empty it is auto-detected
 
 OPNFV_NETWORK_TYPES = [ADMIN_NETWORK, PRIVATE_NETWORK, PUBLIC_NETWORK,
                        STORAGE_NETWORK, API_NETWORK]
 DNS_SERVERS = ["8.8.8.8", "8.8.4.4"]
+ROLES = ['compute', 'controller']
 
             self.settings_obj = yaml.load(network_settings_file)
             self.network_isolation = network_isolation
             self.enabled_network_list = []
+            self.nics = {'compute': dict(), 'controller': dict()}
+            self.nics_specified = {'compute': False, 'controller': False}
             self._validate_input()
 
     def _validate_input(self):
                                           start_offset=21, end_offset=21)
                     self._config_optional_settings(network)
                     self.enabled_network_list.append(network)
+                    self._validate_overcloud_nic_order(network)
                 else:
                     logging.info("{} disabled, will collapse with "
                                  "admin_network".format(network))
         self.settings_obj['dns_servers'] = self.settings_obj.get(
             'dns_servers', constants.DNS_SERVERS)
 
+    def _validate_overcloud_nic_order(self, network):
+        """
+        Detects if nic order is specified per profile (compute/controller)
+        for network
+
+        If nic order is specified in a network for a profile, it should be
+        specified for every network with that profile other than admin_network
+
+        Duplicate nic names are also not allowed across different networks
+
+        :param network: network to detect if nic order present
+        :return: None
+        """
+
+        for role in constants.ROLES:
+            interface = role+'_interface'
+            nic_index = self.get_enabled_networks().index(network) + 1
+            if interface in self.settings_obj[network]:
+                if any(y == self.settings_obj[network][interface] for x, y in
+                       self.nics[role].items()):
+                    raise NetworkSettingsException("Duplicate {} already "
+                                                   "specified for "
+                                                   "another network"
+                                                   .format(self.settings_obj
+                                                           [network]
+                                                           [interface]))
+                self.nics[role][network] = self.settings_obj[network][
+                    interface]
+                self.nics_specified[role] = True
+                logging.info("{} nic order specified for network {"
+                             "}".format(role, network))
+            elif self.nics_specified[role]:
+                logging.error("{} nic order not specified for network {"
+                              "}".format(role, network))
+                raise NetworkSettingsException("Must specify {} for all "
+                                               "enabled networks (other than "
+                                               " admin) or not specify it for "
+                                               "any".format(interface))
+            else:
+                logging.info("{} nic order not specified for network {"
+                             "}. Will use logical default "
+                             "nic{}".format(interface, network, nic_index))
+                self.nics[role][network] = 'nic' + str(nic_index)
+                nic_index += 1
+
     def _config_required_settings(self, network):
         """
         Configures either CIDR or bridged_interface setting
 
 from apex import NetworkEnvironment
 from apex import DeploySettings
 from apex import ip_utils
-from apex.common.constants import OPNFV_NETWORK_TYPES
 from apex.common.constants import ADMIN_NETWORK
 
 
     """
     template_dir, template = args.template.rsplit('/', 1)
 
-    settings = NetworkSettings(args.net_settings_file,
-                               args.network_isolation).settings_obj
+    network_settings = NetworkSettings(args.net_settings_file,
+                                       args.network_isolation)
+    settings = network_settings.settings_obj
     env = Environment(loader=FileSystemLoader(template_dir))
     template = env.get_template(template)
 
     net_list.remove(ADMIN_NETWORK)
     vlans_vals = map(lambda x: settings[x]['vlan'], net_list)
     vlans = dict(zip(net_list, vlans_vals))
+    nics = network_settings.nics
 
     print(template.render(enabled_networks=args.enabled_networks,
                           role=args.role,
                           vlans=vlans,
                           external_net_type=args.ext_net_type,
                           external_net_af=args.address_family,
-                          ovs_dpdk_bridge=args.ovs_dpdk_bridge))
+                          ovs_dpdk_bridge=args.ovs_dpdk_bridge,
+                          nics=nics))
 
 
 def get_parser():
 
--- /dev/null
+# This configuration file defines Network Environment for a
+# Baremetal Deployment of OPNFV. It contains default values
+# for 4 following networks:
+#
+# - admin
+# - private*
+# - public
+# - storage*
+#
+# *) optional networks
+#
+# Any values missing from this configuration file will be
+# auto-detected by deployment script from the existing network
+# configuration of the jumphost.
+#
+# Optional networks will be consolidated with the admin network
+# if not explicitely configured.
+#
+# See short description of the networks in the comments below.
+#
+
+# DNS Servers for all nodes, comma delimited list
+dns_servers: ["8.8.8.8", "8.8.4.4"]
+
+# "admin" is the short name for Control Plane Network.
+# During OPNFV deployment it is used for node provisioning so
+# PXE boot should be enabled for the related interfaces on all
+# the nodes in the OPNFV cluster. After the deployment this
+# network is used as the OpenStack management network which
+# carries e.g. communication between its internal components.
+#
+admin_network:
+  enabled: true
+  network_type: bridged
+  bridged_interface: ''
+  bond_interfaces: ''
+  compute_interface: eth1
+  controller_interface: eth2
+  usable_ip_range: 192.0.2.11,192.0.2.99
+  gateway: 192.0.2.1
+  provisioner_ip: 192.0.2.1
+  cidr: 192.0.2.0/24
+  dhcp_range: 192.0.2.2,192.0.2.10
+  introspection_range: 192.0.2.100,192.0.2.120
+
+# "private" is an optional network used as underlying physical
+# network for virtual provider and tenant networks created by
+# users. Traffic between virtual machines is carried by this
+# network.
+#
+private_network:
+  enabled: true
+  vlan: native
+  cidr: 11.0.0.0/24
+  compute_interface: enp0s4
+  controller_interface: nic3
+
+# "public" network is used for external connectivity.
+# The external network provides Internet access for virtual
+# machines. If floating IP range is defined for this network,
+# floating IP addresses can be used for accessing virtual
+# machines from outside of OPNFV cluster. Also external REST
+# API calls use this network.
+#
+public_network:
+  enabled: true
+  network_type: ''
+  bridged_interface: ''
+  compute_interface: eth1
+  controller_interface: enp0s3
+  vlan: native
+  cidr: 192.168.37.0/24
+  gateway: 192.168.37.1
+  floating_ip_range: 192.168.37.200,192.168.37.220
+  usable_ip_range: 192.168.37.10,192.168.37.199
+  provisioner_ip: 192.168.37.1
+
+# "storage" is an optional network used by storage backends.
+# You can configure this network in order to reduce load on
+# Control Plane Network.
+#
+storage_network:
+  enabled: true
+  vlan: native
+  cidr: 12.0.0.0/24
+  compute_interface: eth5
+  controller_interface: eth6
+
+#admin_network:
+#  enabled: true
+#  network_type: bridged                             #Indicates if this network will be bridged to an interface, or to a bond
+#  bridged_interface: ''                             #Interface to bridge to for installer VM
+#  bond_interfaces: ''                               #Interfaces to create bond with for installer VM
+#  compute_interface: nic4                           #Interface used for this network on the compute node.  Can either be logical nic name like "nic1" or real name like "eth1"
+#  controller_interface: nic4                        #Interface used for this network on the controller node.  Can either be logical nic name like "nic1" or real name like "eth1"
+#  vlan: native                                      #VLAN tag to use, native means none
+#  usable_ip_range: 192.0.2.11,192.0.2.99            #Usable ip range, if empty entire range is usable, ex. 192.168.1.10,192.168.1.20
+#  gateway: 192.0.2.1                                #Gateway (only needed when public_network is disabled), if empty it is auto-detected
+#  provisioner_ip: 192.0.2.1                         #installer VM IP, if empty it is the next available IP in the admin subnet
+#  cidr: 192.0.2.0/24                                #subnet in CIDR format 192.168.1.0/24, if empty it will be auto-detected
+#  dhcp_range: 192.0.2.2,192.0.2.10                  #dhcp range for the admin network, if empty it will be automatically provisioned
+#  introspection_range: 192.0.2.100,192.0.2.120      #Range used for introspection phase (examining nodes)
+#private_network:
+#  enabled: false                                    #If disabled, internal api traffic will collapse to admin_network
+#public_network:
+#  enabled: true                                     #If disabled, public_network traffic will collapse to admin network
+#  network_type: ''
+#  bridged_interface: ''
+#  cidr: 192.168.37.0/24
+#  gateway: 192.168.37.1
+#  floating_ip_range: 192.168.37.200,192.168.37.220  #Range to allocate to floating IPs for the public network with Neutron
+#  usable_ip_range: 192.168.37.10,192.168.37.199     #Usable IP range on the public network, usually this is a shared subnet
+#  provisioner_ip: 192.168.37.1
+#storage_network:
+#  enabled: false                                    #If disabled, storage_network traffic will collapse to admin network
 
--- /dev/null
+# This configuration file defines Network Environment for a
+# Baremetal Deployment of OPNFV. It contains default values
+# for 4 following networks:
+#
+# - admin
+# - private*
+# - public
+# - storage*
+#
+# *) optional networks
+#
+# Any values missing from this configuration file will be
+# auto-detected by deployment script from the existing network
+# configuration of the jumphost.
+#
+# Optional networks will be consolidated with the admin network
+# if not explicitely configured.
+#
+# See short description of the networks in the comments below.
+#
+
+# DNS Servers for all nodes, comma delimited list
+dns_servers: ["8.8.8.8", "8.8.4.4"]
+
+# "admin" is the short name for Control Plane Network.
+# During OPNFV deployment it is used for node provisioning so
+# PXE boot should be enabled for the related interfaces on all
+# the nodes in the OPNFV cluster. After the deployment this
+# network is used as the OpenStack management network which
+# carries e.g. communication between its internal components.
+#
+admin_network:
+  enabled: true
+  network_type: bridged
+  bridged_interface: ''
+  bond_interfaces: ''
+  compute_interface: eth1
+  controller_interface: eth2
+  usable_ip_range: 192.0.2.11,192.0.2.99
+  gateway: 192.0.2.1
+  provisioner_ip: 192.0.2.1
+  cidr: 192.0.2.0/24
+  dhcp_range: 192.0.2.2,192.0.2.10
+  introspection_range: 192.0.2.100,192.0.2.120
+
+# "private" is an optional network used as underlying physical
+# network for virtual provider and tenant networks created by
+# users. Traffic between virtual machines is carried by this
+# network.
+#
+private_network:
+  enabled: true
+  vlan: native
+  cidr: 11.0.0.0/24
+  compute_interface: enp0s4
+  controller_interface: nic3
+
+# "public" network is used for external connectivity.
+# The external network provides Internet access for virtual
+# machines. If floating IP range is defined for this network,
+# floating IP addresses can be used for accessing virtual
+# machines from outside of OPNFV cluster. Also external REST
+# API calls use this network.
+#
+public_network:
+  enabled: true
+  network_type: ''
+  bridged_interface: ''
+  vlan: native
+  cidr: 192.168.37.0/24
+  gateway: 192.168.37.1
+  floating_ip_range: 192.168.37.200,192.168.37.220
+  usable_ip_range: 192.168.37.10,192.168.37.199
+  provisioner_ip: 192.168.37.1
+
+# "storage" is an optional network used by storage backends.
+# You can configure this network in order to reduce load on
+# Control Plane Network.
+#
+storage_network:
+  enabled: true
+  vlan: native
+  cidr: 12.0.0.0/24
+  compute_interface: eth5
+  controller_interface: eth6
+
+#admin_network:
+#  enabled: true
+#  network_type: bridged                             #Indicates if this network will be bridged to an interface, or to a bond
+#  bridged_interface: ''                             #Interface to bridge to for installer VM
+#  bond_interfaces: ''                               #Interfaces to create bond with for installer VM
+#  compute_interface: nic4                 #Interface used for this network on the compute node.  Can either be logical nic name like "nic1" or real name like "eth1"
+#  controller_interface: nic4              #Interface used for this network on the controller node.  Can either be logical nic name like "nic1" or real name like "eth1"
+#  vlan: native                                      #VLAN tag to use, native means none
+#  usable_ip_range: 192.0.2.11,192.0.2.99            #Usable ip range, if empty entire range is usable, ex. 192.168.1.10,192.168.1.20
+#  gateway: 192.0.2.1                                #Gateway (only needed when public_network is disabled), if empty it is auto-detected
+#  provisioner_ip: 192.0.2.1                         #installer VM IP, if empty it is the next available IP in the admin subnet
+#  cidr: 192.0.2.0/24                                #subnet in CIDR format 192.168.1.0/24, if empty it will be auto-detected
+#  dhcp_range: 192.0.2.2,192.0.2.10                  #dhcp range for the admin network, if empty it will be automatically provisioned
+#  introspection_range: 192.0.2.100,192.0.2.120      #Range used for introspection phase (examining nodes)
+#private_network:
+#  enabled: false                                    #If disabled, internal api traffic will collapse to admin_network
+#public_network:
+#  enabled: true                                     #If disabled, public_network traffic will collapse to admin network
+#  network_type: ''
+#  bridged_interface: ''
+#  cidr: 192.168.37.0/24
+#  gateway: 192.168.37.1
+#  floating_ip_range: 192.168.37.200,192.168.37.220  #Range to allocate to floating IPs for the public network with Neutron
+#  usable_ip_range: 192.168.37.10,192.168.37.199     #Usable IP range on the public network, usually this is a shared subnet
+#  provisioner_ip: 192.168.37.1
+#storage_network:
+#  enabled: false                                    #If disabled, storage_network traffic will collapse to admin network
 
--- /dev/null
+# This configuration file defines Network Environment for a
+# Baremetal Deployment of OPNFV. It contains default values
+# for 4 following networks:
+#
+# - admin
+# - private*
+# - public
+# - storage*
+#
+# *) optional networks
+#
+# Any values missing from this configuration file will be
+# auto-detected by deployment script from the existing network
+# configuration of the jumphost.
+#
+# Optional networks will be consolidated with the admin network
+# if not explicitely configured.
+#
+# See short description of the networks in the comments below.
+#
+
+# DNS Servers for all nodes, comma delimited list
+dns_servers: ["8.8.8.8", "8.8.4.4"]
+
+# "admin" is the short name for Control Plane Network.
+# During OPNFV deployment it is used for node provisioning so
+# PXE boot should be enabled for the related interfaces on all
+# the nodes in the OPNFV cluster. After the deployment this
+# network is used as the OpenStack management network which
+# carries e.g. communication between its internal components.
+#
+admin_network:
+  enabled: true
+  network_type: bridged
+  bridged_interface: ''
+  bond_interfaces: ''
+  usable_ip_range: 192.0.2.11,192.0.2.99
+  gateway: 192.0.2.1
+  provisioner_ip: 192.0.2.1
+  cidr: 192.0.2.0/24
+  dhcp_range: 192.0.2.2,192.0.2.10
+  introspection_range: 192.0.2.100,192.0.2.120
+
+# "private" is an optional network used as underlying physical
+# network for virtual provider and tenant networks created by
+# users. Traffic between virtual machines is carried by this
+# network.
+#
+private_network:
+  enabled: true
+  vlan: native
+  cidr: 11.0.0.0/24
+  compute_interface: enp0s4
+  controller_interface: nic3
+
+# "public" network is used for external connectivity.
+# The external network provides Internet access for virtual
+# machines. If floating IP range is defined for this network,
+# floating IP addresses can be used for accessing virtual
+# machines from outside of OPNFV cluster. Also external REST
+# API calls use this network.
+#
+public_network:
+  enabled: true
+  network_type: ''
+  bridged_interface: ''
+  compute_interface: nic1
+  controller_interface: enp0s3
+  vlan: native
+  cidr: 192.168.37.0/24
+  gateway: 192.168.37.1
+  floating_ip_range: 192.168.37.200,192.168.37.220
+  usable_ip_range: 192.168.37.10,192.168.37.199
+  provisioner_ip: 192.168.37.1
+
+# "storage" is an optional network used by storage backends.
+# You can configure this network in order to reduce load on
+# Control Plane Network.
+#
+storage_network:
+  enabled: true
+  vlan: native
+  cidr: 12.0.0.0/24
+  compute_interface: eth5
+  controller_interface: eth6
+
+#admin_network:
+#  enabled: true
+#  network_type: bridged                             #Indicates if this network will be bridged to an interface, or to a bond
+#  bridged_interface: ''                             #Interface to bridge to for installer VM
+#  bond_interfaces: ''                               #Interfaces to create bond with for installer VM
+#  overcloud_compute_interface: nic4                 #Interface used for this network on the compute node.  Can either be logical nic name like "nic1" or real name like "eth1"
+#  overcloud_controller_interface: nic4              #Interface used for this network on the controller node.  Can either be logical nic name like "nic1" or real name like "eth1"
+#  vlan: native                                      #VLAN tag to use, native means none
+#  usable_ip_range: 192.0.2.11,192.0.2.99            #Usable ip range, if empty entire range is usable, ex. 192.168.1.10,192.168.1.20
+#  gateway: 192.0.2.1                                #Gateway (only needed when public_network is disabled), if empty it is auto-detected
+#  provisioner_ip: 192.0.2.1                         #installer VM IP, if empty it is the next available IP in the admin subnet
+#  cidr: 192.0.2.0/24                                #subnet in CIDR format 192.168.1.0/24, if empty it will be auto-detected
+#  dhcp_range: 192.0.2.2,192.0.2.10                  #dhcp range for the admin network, if empty it will be automatically provisioned
+#  introspection_range: 192.0.2.100,192.0.2.120      #Range used for introspection phase (examining nodes)
+#private_network:
+#  enabled: false                                    #If disabled, internal api traffic will collapse to admin_network
+#public_network:
+#  enabled: true                                     #If disabled, public_network traffic will collapse to admin network
+#  network_type: ''
+#  bridged_interface: ''
+#  cidr: 192.168.37.0/24
+#  gateway: 192.168.37.1
+#  floating_ip_range: 192.168.37.200,192.168.37.220  #Range to allocate to floating IPs for the public network with Neutron
+#  usable_ip_range: 192.168.37.10,192.168.37.199     #Usable IP range on the public network, usually this is a shared subnet
+#  provisioner_ip: 192.168.37.1
+#storage_network:
+#  enabled: false                                    #If disabled, storage_network traffic will collapse to admin network
 
--- /dev/null
+# This configuration file defines Network Environment for a
+# Baremetal Deployment of OPNFV. It contains default values
+# for 4 following networks:
+#
+# - admin
+# - private*
+# - public
+# - storage*
+#
+# *) optional networks
+#
+# Any values missing from this configuration file will be
+# auto-detected by deployment script from the existing network
+# configuration of the jumphost.
+#
+# Optional networks will be consolidated with the admin network
+# if not explicitely configured.
+#
+# See short description of the networks in the comments below.
+#
+
+# DNS Servers for all nodes, comma delimited list
+dns_servers: ["8.8.8.8", "8.8.4.4"]
+
+# "admin" is the short name for Control Plane Network.
+# During OPNFV deployment it is used for node provisioning so
+# PXE boot should be enabled for the related interfaces on all
+# the nodes in the OPNFV cluster. After the deployment this
+# network is used as the OpenStack management network which
+# carries e.g. communication between its internal components.
+#
+admin_network:
+  enabled: true
+  network_type: bridged
+  bridged_interface: ''
+  bond_interfaces: ''
+  usable_ip_range: 192.0.2.11,192.0.2.99
+  gateway: 192.0.2.1
+  provisioner_ip: 192.0.2.1
+  cidr: 192.0.2.0/24
+  dhcp_range: 192.0.2.2,192.0.2.10
+  introspection_range: 192.0.2.100,192.0.2.120
+
+# "private" is an optional network used as underlying physical
+# network for virtual provider and tenant networks created by
+# users. Traffic between virtual machines is carried by this
+# network.
+#
+private_network:
+  enabled: true
+  vlan: native
+  cidr: 11.0.0.0/24
+
+# "public" network is used for external connectivity.
+# The external network provides Internet access for virtual
+# machines. If floating IP range is defined for this network,
+# floating IP addresses can be used for accessing virtual
+# machines from outside of OPNFV cluster. Also external REST
+# API calls use this network.
+#
+public_network:
+  enabled: true
+  network_type: ''
+  bridged_interface: ''
+  vlan: native
+  cidr: 192.168.37.0/24
+  gateway: 192.168.37.1
+  floating_ip_range: 192.168.37.200,192.168.37.220
+  usable_ip_range: 192.168.37.10,192.168.37.199
+  provisioner_ip: 192.168.37.1
+
+# "storage" is an optional network used by storage backends.
+# You can configure this network in order to reduce load on
+# Control Plane Network.
+#
+storage_network:
+  enabled: true
+  vlan: native
+  cidr: 12.0.0.0/24
+
+#admin_network:
+#  enabled: true
+#  network_type: bridged                             #Indicates if this network will be bridged to an interface, or to a bond
+#  bridged_interface: ''                             #Interface to bridge to for installer VM
+#  bond_interfaces: ''                               #Interfaces to create bond with for installer VM
+#  compute_interface: nic4                           #Interface used for this network on the compute node.  Can either be logical nic name like "nic1" or real name like "eth1"
+#  controller_interface: nic4                        #Interface used for this network on the controller node.  Can either be logical nic name like "nic1" or real name like "eth1"
+#  vlan: native                                      #VLAN tag to use, native means none
+#  usable_ip_range: 192.0.2.11,192.0.2.99            #Usable ip range, if empty entire range is usable, ex. 192.168.1.10,192.168.1.20
+#  gateway: 192.0.2.1                                #Gateway (only needed when public_network is disabled), if empty it is auto-detected
+#  provisioner_ip: 192.0.2.1                         #installer VM IP, if empty it is the next available IP in the admin subnet
+#  cidr: 192.0.2.0/24                                #subnet in CIDR format 192.168.1.0/24, if empty it will be auto-detected
+#  dhcp_range: 192.0.2.2,192.0.2.10                  #dhcp range for the admin network, if empty it will be automatically provisioned
+#  introspection_range: 192.0.2.100,192.0.2.120      #Range used for introspection phase (examining nodes)
+#private_network:
+#  enabled: false                                    #If disabled, internal api traffic will collapse to admin_network
+#public_network:
+#  enabled: true                                     #If disabled, public_network traffic will collapse to admin network
+#  network_type: ''
+#  bridged_interface: ''
+#  cidr: 192.168.37.0/24
+#  gateway: 192.168.37.1
+#  floating_ip_range: 192.168.37.200,192.168.37.220  #Range to allocate to floating IPs for the public network with Neutron
+#  usable_ip_range: 192.168.37.10,192.168.37.199     #Usable IP range on the public network, usually this is a shared subnet
+#  provisioner_ip: 192.168.37.1
+#storage_network:
+#  enabled: false                                    #If disabled, storage_network traffic will collapse to admin network
 
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
 
-from apex.network_settings import NetworkSettings
+from apex.network_settings import (
+    NetworkSettings,
+    NetworkSettingsException,
+)
 
-from nose.tools import assert_equal
-from nose.tools import assert_is_instance
+from nose.tools import (
+    assert_equal,
+    assert_is_instance,
+    assert_raises
+)
 
 
 class TestNetworkSettings(object):
         """This method is run once after _each_ test method is executed"""
 
     def test_init(self):
-        ns = NetworkSettings('../config/network/network_settings.yaml', True)
+        NetworkSettings('../config/network/network_settings.yaml', True)
 
     def test_dump_bash(self):
         ns = NetworkSettings('../config/network/network_settings.yaml', True)
     def test_get_network_settings(self):
         ns = NetworkSettings('../config/network/network_settings.yaml', True)
         assert_is_instance(ns.get_network_settings(), dict)
+        for role in ['controller', 'compute']:
+            nic_index = 1
+            for network in ['admin_network', 'private_network',
+                            'public_network', 'storage_network']:
+                nic = 'nic' + str(nic_index)
+                assert_equal(ns.nics[role][network], nic)
+                nic_index += 1
+
+    def test_get_network_settings_unspecified_nics(self):
+        ns = NetworkSettings(
+            '../tests/config/network_settings_nics_not_specified.yaml',
+            True)
+        assert_is_instance(ns.get_network_settings(), dict)
+        for role in ['controller', 'compute']:
+            nic_index = 1
+            for network in ['admin_network', 'private_network',
+                            'public_network', 'storage_network']:
+                nic = 'nic' + str(nic_index)
+                assert_equal(ns.nics[role][network], nic)
+                nic_index += 1
 
     def test_get_enabled_networks(self):
         ns = NetworkSettings('../config/network/network_settings.yaml', True)
         assert_is_instance(ns.get_enabled_networks(), list)
+
+    def test_negative_network_settings(self):
+        assert_raises(NetworkSettingsException, NetworkSettings,
+                      '../tests/config/network_settings_duplicate_nic.yaml',
+                      True)
+        assert_raises(NetworkSettingsException, NetworkSettings,
+                      '../tests/config/network_settings_nic1_reserved.yaml',
+                      True)
+        assert_raises(NetworkSettingsException, NetworkSettings,
+                      '../tests/config/network_settings_missing_required_nic'
+                      '.yaml', True)